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
|
authenticate: all
|
||||||
authenticator: ldap-anonymous
|
authenticator: ldap-anonymous
|
||||||
arguments:
|
arguments:
|
||||||
|
-r:
|
||||||
|
full: --raw
|
||||||
|
help: Return domains as a bash-usable list instead of JSON
|
||||||
|
action: store_true
|
||||||
-f:
|
-f:
|
||||||
full: --filter
|
full: --filter
|
||||||
help: LDAP filter used to search
|
help: LDAP filter used to search
|
||||||
|
@ -879,18 +883,47 @@ service:
|
||||||
Prints the differences between files if any.
|
Prints the differences between files if any.
|
||||||
api: PUT /services/regenconf
|
api: PUT /services/regenconf
|
||||||
arguments:
|
arguments:
|
||||||
-n:
|
-s:
|
||||||
full: --name
|
full: --service
|
||||||
help: Regenerate configuration for a specfic service
|
help: Regenerate configuration for a specfic service
|
||||||
-f:
|
-f:
|
||||||
full: --force
|
full: --force
|
||||||
help: Override the current configuration with the newly generated one, even if it has been modified
|
help: Override the current configuration with the newly generated one, even if it has been modified
|
||||||
action: store_true
|
action: store_true
|
||||||
-k:
|
|
||||||
full: --keep
|
### service_safecopy()
|
||||||
help: Save the current configuration to avoid further notifications
|
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
|
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 #
|
# 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
|
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
|
List domains
|
||||||
|
|
||||||
Keyword argument:
|
Keyword argument:
|
||||||
|
raw -- Return domains as a bash-usable list instead of JSON
|
||||||
filter -- LDAP filter used to search
|
filter -- LDAP filter used to search
|
||||||
offset -- Starting number for domain fetching
|
offset -- Starting number for domain fetching
|
||||||
limit -- Maximum number of domain fetched
|
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:
|
if len(result) > offset and limit > 0:
|
||||||
for domain in result[offset:offset+limit]:
|
for domain in result[offset:offset+limit]:
|
||||||
result_list.append(domain['virtualdomain'][0])
|
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):
|
def domain_add(auth, domain, dyndns=False):
|
||||||
|
|
|
@ -185,6 +185,16 @@ def hook_callback(action, hooks=[], args=None):
|
||||||
else:
|
else:
|
||||||
hooks_names = hook_list(action, list_by='name',
|
hooks_names = hook_list(action, list_by='name',
|
||||||
show_info=True)['hooks']
|
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
|
# Iterate over given hooks names list
|
||||||
for n in hooks:
|
for n in hooks:
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -30,7 +30,6 @@ import glob
|
||||||
import subprocess
|
import subprocess
|
||||||
import errno
|
import errno
|
||||||
import shutil
|
import shutil
|
||||||
import jinja2
|
|
||||||
import difflib
|
import difflib
|
||||||
import hashlib
|
import hashlib
|
||||||
|
|
||||||
|
@ -270,26 +269,35 @@ def service_log(name, number=50):
|
||||||
return result
|
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
|
Regenerate the configuration file(s) for a service and compare the result
|
||||||
with the existing configuration file.
|
with the existing configuration file.
|
||||||
Prints the differences between files if any.
|
Prints the differences between files if any.
|
||||||
|
|
||||||
Keyword argument:
|
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
|
force -- Override the current configuration with the newly generated
|
||||||
one, even if it has been modified
|
one, even if it has been modified
|
||||||
keep -- Save the current configuration to avoid further notifications
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if name is not None:
|
if force:
|
||||||
_regenerate_configuration_for(auth, name, force, keep)
|
arg_force = 1
|
||||||
|
else:
|
||||||
|
arg_force = 0
|
||||||
#TODO: Raise error when force + keep
|
|
||||||
#TODO: Loop through all the services
|
if service is None:
|
||||||
#TODO: Win message with regenerated configurations
|
# 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):
|
def _run_service_command(action, service):
|
||||||
|
@ -417,16 +425,15 @@ def _hash(filename):
|
||||||
return 'no hash yet'
|
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.
|
Check if the specific file has been modified before removing it.
|
||||||
Backup the file in /home/yunohost.backup
|
Backup the file in /home/yunohost.backup
|
||||||
|
|
||||||
Keyword argument:
|
Keyword argument:
|
||||||
conf_file -- The file to write
|
|
||||||
service -- Service name of the file to delete
|
service -- Service name of the file to delete
|
||||||
|
conf_file -- The file to write
|
||||||
force -- Force file deletion
|
force -- Force file deletion
|
||||||
keep -- Keep the current file and save its hash
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
deleted = False
|
deleted = False
|
||||||
|
@ -487,24 +494,23 @@ def _safe_remove(conf_file, service=None, force=False, keep=False):
|
||||||
return deleted
|
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.
|
Check if the specific file has been modified and display differences.
|
||||||
Stores the file hash in the services.yml file
|
Stores the file hash in the services.yml file
|
||||||
|
|
||||||
Keyword argument:
|
Keyword argument:
|
||||||
conf_file -- The file to write
|
service -- Service name attached to the conf file
|
||||||
new_conf -- String containing the new content
|
new_conf_file -- Path to the desired conf file
|
||||||
service -- Service name of the file to write
|
conf_file -- Path to the targeted conf file
|
||||||
force -- Force file overriding
|
force -- Force file overriding
|
||||||
keep -- Keep the current file and save its hash
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
regenerated = False
|
regenerated = False
|
||||||
services = _get_services()
|
services = _get_services()
|
||||||
|
|
||||||
if os.path.exists(new_conf):
|
if os.path.exists(new_conf_file):
|
||||||
filename = new_conf
|
filename = new_conf_file
|
||||||
with open(filename, 'r') as f:
|
with open(filename, 'r') as f:
|
||||||
new_conf = ''.join(f.readlines()).rstrip()
|
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)
|
with open(conf_file, 'w') as f: f.write(new_conf)
|
||||||
regenerated = True
|
regenerated = True
|
||||||
new_hash = _hash(conf_file)
|
new_hash = _hash(conf_file)
|
||||||
elif keep:
|
|
||||||
new_hash = previous_hash[0:32] + ', but keep ' + current_hash
|
|
||||||
elif len(diff) == 0:
|
elif len(diff) == 0:
|
||||||
new_hash = _hash(conf_file)
|
new_hash = _hash(conf_file)
|
||||||
else:
|
else:
|
||||||
|
@ -565,80 +569,3 @@ def _safe_write(conf_file, new_conf='', service=None, force=False, keep=False):
|
||||||
_save_services(services)
|
_save_services(services)
|
||||||
|
|
||||||
return regenerated
|
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