mirror of
https://github.com/YunoHost/yunohost.git
synced 2024-09-03 20:06:10 +02:00
[enh] Regenerate configuration via hook scripts
This commit is contained in:
parent
442e578f0e
commit
b6c77c9e43
5 changed files with 140 additions and 107 deletions
|
@ -243,6 +243,10 @@ domain:
|
|||
authenticate: all
|
||||
authenticator: ldap-anonymous
|
||||
arguments:
|
||||
-r:
|
||||
full: --raw
|
||||
help: Return domains as a bash-usable list instead of JSON
|
||||
action: store_true
|
||||
-f:
|
||||
full: --filter
|
||||
help: LDAP filter used to search
|
||||
|
@ -879,18 +883,47 @@ service:
|
|||
Prints the differences between files if any.
|
||||
api: PUT /services/regenconf
|
||||
arguments:
|
||||
-n:
|
||||
full: --name
|
||||
-s:
|
||||
full: --service
|
||||
help: Regenerate configuration for a specfic service
|
||||
-f:
|
||||
full: --force
|
||||
help: Override the current configuration with the newly generated one, even if it has been modified
|
||||
action: store_true
|
||||
-k:
|
||||
full: --keep
|
||||
help: Save the current configuration to avoid further notifications
|
||||
|
||||
### service_safecopy()
|
||||
safecopy:
|
||||
action_help: >
|
||||
Check if the specific file has been modified and display differences.
|
||||
Stores the file hash in the services.yml file
|
||||
api: PUT /services/safecopy
|
||||
arguments:
|
||||
service:
|
||||
help: Service name attached to the conf file
|
||||
new_conf_file:
|
||||
help: Path to the desired conf file
|
||||
conf_file:
|
||||
help: Path to the targeted conf file
|
||||
-f:
|
||||
full: --force
|
||||
help: Override the current configuration with the newly generated one, even if it has been modified
|
||||
action: store_true
|
||||
|
||||
### service_saferemove()
|
||||
saferemove:
|
||||
action_help: >
|
||||
Check if the specific file has been modified before removing it.
|
||||
Backup the file in /home/yunohost.backup
|
||||
api: PUT /services/safecopy
|
||||
arguments:
|
||||
service:
|
||||
help: Service name attached to the conf file
|
||||
conf_file:
|
||||
help: Path to the targeted conf file
|
||||
-f:
|
||||
full: --force
|
||||
help: Force file deletion
|
||||
action: store_true
|
||||
|
||||
#############################
|
||||
# Firewall #
|
||||
|
|
57
data/hooks/conf_regen/15-nginx
Normal file
57
data/hooks/conf_regen/15-nginx
Normal file
|
@ -0,0 +1,57 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
force=$1
|
||||
|
||||
function safe_copy () {
|
||||
if $force; then
|
||||
sudo yunohost service safecopy \
|
||||
-s nginx \
|
||||
--force \
|
||||
$1 $2
|
||||
else
|
||||
sudo yunohost service safecopy \
|
||||
-s nginx \
|
||||
$1 $2
|
||||
fi
|
||||
}
|
||||
|
||||
cd /usr/share/yunohost/templates/nginx
|
||||
|
||||
# Copy plain single configuration files
|
||||
$files="ssowat.conf
|
||||
yunohost_admin.conf
|
||||
yunohost_admin.conf.inc
|
||||
yunohost_api.conf.inc
|
||||
yunohost_panel.conf.inc"
|
||||
|
||||
for file in files; do
|
||||
safe_copy $file /etc/nginx/conf.d/$file
|
||||
done
|
||||
|
||||
|
||||
# Copy 'yunohost.local' to the main domain conf directory
|
||||
main_domain=$(sudo yunohost tools maindomain)
|
||||
safe_copy yunohost_local.conf \
|
||||
/etc/nginx/conf.d/$main_domain.d/yunohost_local.conf
|
||||
|
||||
|
||||
need_restart=0
|
||||
|
||||
# Copy a configuration file for each YunoHost domain
|
||||
for domain in $(sudo yunohost domain list --raw); do
|
||||
sudo mkdir /etc/nginx/conf.d/$domain.d
|
||||
cat server.conf.sed \
|
||||
| sed "s/{{ domain }}/$domain/g" \
|
||||
| sudo tee $domain.conf
|
||||
if $(safe_copy $domain.conf /etc/nginx/conf.d/$domain.conf); then
|
||||
need_restart=1
|
||||
fi
|
||||
done
|
||||
|
||||
# Restart if need be
|
||||
if $need_restart; then
|
||||
service nginx restart
|
||||
else
|
||||
service nginx reload
|
||||
fi
|
|
@ -36,11 +36,12 @@ from urllib import urlopen
|
|||
from moulinette.core import MoulinetteError
|
||||
|
||||
|
||||
def domain_list(auth, filter=None, limit=None, offset=None):
|
||||
def domain_list(auth, raw=False, filter=None, limit=None, offset=None):
|
||||
"""
|
||||
List domains
|
||||
|
||||
Keyword argument:
|
||||
raw -- Return domains as a bash-usable list instead of JSON
|
||||
filter -- LDAP filter used to search
|
||||
offset -- Starting number for domain fetching
|
||||
limit -- Maximum number of domain fetched
|
||||
|
@ -61,7 +62,12 @@ def domain_list(auth, filter=None, limit=None, offset=None):
|
|||
if len(result) > offset and limit > 0:
|
||||
for domain in result[offset:offset+limit]:
|
||||
result_list.append(domain['virtualdomain'][0])
|
||||
return { 'domains': result_list }
|
||||
|
||||
if raw:
|
||||
for domain in result_list:
|
||||
print domain
|
||||
else:
|
||||
return { 'domains': result_list }
|
||||
|
||||
|
||||
def domain_add(auth, domain, dyndns=False):
|
||||
|
|
|
@ -185,6 +185,16 @@ def hook_callback(action, hooks=[], args=None):
|
|||
else:
|
||||
hooks_names = hook_list(action, list_by='name',
|
||||
show_info=True)['hooks']
|
||||
|
||||
# Add similar hooks to the list
|
||||
# For example: Having a 16-postfix hook in the list will execute a
|
||||
# xx-postfix_dkim as well
|
||||
for n in hooks:
|
||||
for key in hooks.keys():
|
||||
if key.startswith("%s_" % n) \
|
||||
and n not in hooks:
|
||||
hooks.append(n)
|
||||
|
||||
# Iterate over given hooks names list
|
||||
for n in hooks:
|
||||
try:
|
||||
|
|
|
@ -30,7 +30,6 @@ import glob
|
|||
import subprocess
|
||||
import errno
|
||||
import shutil
|
||||
import jinja2
|
||||
import difflib
|
||||
import hashlib
|
||||
|
||||
|
@ -270,26 +269,35 @@ def service_log(name, number=50):
|
|||
return result
|
||||
|
||||
|
||||
def service_regenconf(auth, name=None, force=False, keep=False):
|
||||
def service_regenconf(service=None, force=False):
|
||||
"""
|
||||
Regenerate the configuration file(s) for a service and compare the result
|
||||
with the existing configuration file.
|
||||
Prints the differences between files if any.
|
||||
|
||||
Keyword argument:
|
||||
name -- Regenerate configuration for a specfic service
|
||||
service -- Regenerate configuration for a specfic service
|
||||
force -- Override the current configuration with the newly generated
|
||||
one, even if it has been modified
|
||||
keep -- Save the current configuration to avoid further notifications
|
||||
|
||||
"""
|
||||
if name is not None:
|
||||
_regenerate_configuration_for(auth, name, force, keep)
|
||||
|
||||
|
||||
#TODO: Raise error when force + keep
|
||||
#TODO: Loop through all the services
|
||||
#TODO: Win message with regenerated configurations
|
||||
if force:
|
||||
arg_force = 1
|
||||
else:
|
||||
arg_force = 0
|
||||
|
||||
if service is None:
|
||||
# Regen ALL THE CONFIGURATIONS
|
||||
hook_callback('conf_regen', args=[arg_force])
|
||||
|
||||
msignals.display(m18n.n('services_configured'), 'success')
|
||||
else:
|
||||
if service not in _get_services().keys():
|
||||
raise MoulinetteError(errno.EINVAL, m18n.n('service_unknown', service))
|
||||
|
||||
hook_callback('conf_regen', [service] , args=[arg_force])
|
||||
|
||||
msignals.display(m18n.n('service_configured', service), 'success')
|
||||
|
||||
|
||||
def _run_service_command(action, service):
|
||||
|
@ -417,16 +425,15 @@ def _hash(filename):
|
|||
return 'no hash yet'
|
||||
|
||||
|
||||
def _safe_remove(conf_file, service=None, force=False, keep=False):
|
||||
def service_saferemove(service, conf_file, force=False):
|
||||
"""
|
||||
Check if the specific file has been modified before removing it.
|
||||
Backup the file in /home/yunohost.backup
|
||||
|
||||
Keyword argument:
|
||||
conf_file -- The file to write
|
||||
service -- Service name of the file to delete
|
||||
conf_file -- The file to write
|
||||
force -- Force file deletion
|
||||
keep -- Keep the current file and save its hash
|
||||
|
||||
"""
|
||||
deleted = False
|
||||
|
@ -487,24 +494,23 @@ def _safe_remove(conf_file, service=None, force=False, keep=False):
|
|||
return deleted
|
||||
|
||||
|
||||
def _safe_write(conf_file, new_conf='', service=None, force=False, keep=False):
|
||||
def service_safecopy(service, new_conf_file, conf_file, force=False):
|
||||
"""
|
||||
Check if the specific file has been modified and display differences.
|
||||
Stores the file hash in the services.yml file
|
||||
|
||||
Keyword argument:
|
||||
conf_file -- The file to write
|
||||
new_conf -- String containing the new content
|
||||
service -- Service name of the file to write
|
||||
service -- Service name attached to the conf file
|
||||
new_conf_file -- Path to the desired conf file
|
||||
conf_file -- Path to the targeted conf file
|
||||
force -- Force file overriding
|
||||
keep -- Keep the current file and save its hash
|
||||
|
||||
"""
|
||||
regenerated = False
|
||||
services = _get_services()
|
||||
|
||||
if os.path.exists(new_conf):
|
||||
filename = new_conf
|
||||
if os.path.exists(new_conf_file):
|
||||
filename = new_conf_file
|
||||
with open(filename, 'r') as f:
|
||||
new_conf = ''.join(f.readlines()).rstrip()
|
||||
|
||||
|
@ -537,8 +543,6 @@ def _safe_write(conf_file, new_conf='', service=None, force=False, keep=False):
|
|||
with open(conf_file, 'w') as f: f.write(new_conf)
|
||||
regenerated = True
|
||||
new_hash = _hash(conf_file)
|
||||
elif keep:
|
||||
new_hash = previous_hash[0:32] + ', but keep ' + current_hash
|
||||
elif len(diff) == 0:
|
||||
new_hash = _hash(conf_file)
|
||||
else:
|
||||
|
@ -565,80 +569,3 @@ def _safe_write(conf_file, new_conf='', service=None, force=False, keep=False):
|
|||
_save_services(services)
|
||||
|
||||
return regenerated
|
||||
|
||||
|
||||
def _regenerate_configuration_for(auth, service, force=False, keep=False):
|
||||
"""
|
||||
Handle all the different services' configurations of YunoHost
|
||||
|
||||
Keyword argument:
|
||||
service -- Service name to take care of
|
||||
force -- Force configuration overriding
|
||||
keep -- Keep the current configuration and save its hash
|
||||
|
||||
"""
|
||||
from yunohost.domain import domain_list
|
||||
|
||||
if service not in _get_services().keys() \
|
||||
or not os.path.isdir("%s/%s" % (template_dir, service)):
|
||||
raise MoulinetteError(errno.EINVAL, m18n.n('service_unknown', service))
|
||||
|
||||
# Set the service's template directory as Jinja Environment in order
|
||||
# to ease the template loading
|
||||
env = jinja2.Environment(
|
||||
loader=jinja2.FileSystemLoader("%s/%s" % (template_dir, service))
|
||||
)
|
||||
|
||||
domains = domain_list(auth)['domains']
|
||||
|
||||
with open('/etc/yunohost/current_host', 'r') as f:
|
||||
main_domain = f.readline().rstrip()
|
||||
|
||||
if service == 'nginx':
|
||||
|
||||
need_restart = False
|
||||
|
||||
# Copy plain files
|
||||
for filename in [
|
||||
'ssowat.conf',
|
||||
'yunohost_admin.conf',
|
||||
'yunohost_admin.conf.inc',
|
||||
'yunohost_api.conf.inc',
|
||||
'yunohost_panel.conf.inc',
|
||||
]:
|
||||
conf_file = '/etc/nginx/conf.d/%s' % filename
|
||||
new_conf = '%s/%s/%s' % (template_dir, service, filename)
|
||||
_safe_write(conf_file, new_conf, service, force, keep)
|
||||
|
||||
# We need one file and one folder per virtualhost
|
||||
for domain in domains:
|
||||
conf_file = '/etc/nginx/conf.d/%s.conf' % domain
|
||||
new_conf = env.get_template('server.conf.j2').render(domain=domain)
|
||||
need_restart = _safe_write(conf_file, new_conf, service, force, keep) \
|
||||
or need_restart
|
||||
try:
|
||||
os.makedirs('/etc/nginx/conf.d/%s.d' % domain)
|
||||
except OSError: pass
|
||||
|
||||
# Copy yunohost_local.conf for the main domain
|
||||
filename = 'yunohost_local.conf'
|
||||
conf_file = '/etc/nginx/conf.d/%s.d/%s' % (main_domain, filename)
|
||||
new_conf = '%s/%s/%s' % (template_dir, service, filename)
|
||||
_safe_write(conf_file, new_conf, service, force, keep)
|
||||
|
||||
# Backup and remove configuration for unexisting domains
|
||||
for conf_file in os.listdir('/etc/nginx/conf.d/'):
|
||||
if conf_file.endswith('.conf') and len(conf_file.split('.')) > 2 \
|
||||
and conf_file.replace('.conf', '') not in domains:
|
||||
_safe_remove('/etc/nginx/conf.d/'+ conf_file, service, force, keep)
|
||||
|
||||
# Restart Nginx
|
||||
if need_restart:
|
||||
_run_service_command('restart', service)
|
||||
else:
|
||||
_run_service_command('reload', service)
|
||||
|
||||
msignals.display(m18n.n('service_configured', service), 'success')
|
||||
|
||||
if service == 'postfix':
|
||||
pass
|
||||
|
|
Loading…
Add table
Reference in a new issue