Be able to give lock to son processes detached by systemctl (#367)

* Give lock to systemctl sons
* Get the 'need_lock' flag from services.yml
* Don't need the lock for enable/disable and other stuff
This commit is contained in:
Alexandre Aubin 2017-10-08 23:46:10 +02:00 committed by GitHub
parent 5ae558edc9
commit 9903c48f3a
2 changed files with 55 additions and 3 deletions

View file

@ -47,6 +47,7 @@ yunohost-api:
log: /var/log/yunohost/yunohost-api.log
yunohost-firewall:
status: service
need_lock: true
nslcd:
status: service
log: /var/log/syslog

View file

@ -39,10 +39,10 @@ from moulinette.utils import log, filesystem
from yunohost.hook import hook_callback
BASE_CONF_PATH = '/home/yunohost.conf'
BACKUP_CONF_DIR = os.path.join(BASE_CONF_PATH, 'backup')
PENDING_CONF_DIR = os.path.join(BASE_CONF_PATH, 'pending')
MOULINETTE_LOCK = "/var/run/moulinette_yunohost.lock"
logger = log.getActionLogger('yunohost.service')
@ -493,7 +493,8 @@ def _run_service_command(action, service):
service -- Service name
"""
if service not in _get_services().keys():
services = _get_services()
if service not in services.keys():
raise MoulinetteError(errno.EINVAL, m18n.n('service_unknown', service=service))
cmd = None
@ -505,8 +506,23 @@ def _run_service_command(action, service):
else:
raise ValueError("Unknown action '%s'" % action)
need_lock = (services[service].get('need_lock') or False) \
and action in ['start', 'stop', 'restart', 'reload']
try:
ret = subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT)
# Launch the command
logger.debug("Running '%s'" % cmd)
p = subprocess.Popen(cmd.split(), stderr=subprocess.STDOUT)
# If this command needs a lock (because the service uses yunohost
# commands inside), find the PID and add a lock for it
if need_lock:
PID = _give_lock(action, service, p)
# Wait for the command to complete
p.communicate()
# Remove the lock if one was given
if need_lock and PID != 0:
_remove_lock(PID)
except subprocess.CalledProcessError as e:
# TODO: Log output?
logger.warning(m18n.n('service_cmd_exec_failed', command=' '.join(e.cmd)))
@ -514,6 +530,41 @@ def _run_service_command(action, service):
return True
def _give_lock(action, service, p):
# Depending of the action, systemctl calls the PID differently :/
if action == "start" or action == "restart":
systemctl_PID_name = "MainPID"
else:
systemctl_PID_name = "ControlPID"
cmd_get_son_PID ="systemctl show %s -p %s" % (service, systemctl_PID_name)
son_PID = 0
# As long as we did not found the PID and that the command is still running
while son_PID == 0 and p.poll() == None:
# Call systemctl to get the PID
# Output of the command is e.g. ControlPID=1234
son_PID = subprocess.check_output(cmd_get_son_PID.split()) \
.strip().split("=")[1]
son_PID = int(son_PID)
time.sleep(1)
# If we found a PID
if son_PID != 0:
# Append the PID to the lock file
logger.debug("Giving a lock to PID %s for service %s !"
% (str(son_PID), service))
filesystem.append_to_file(MOULINETTE_LOCK, "\n%s" % str(son_PID))
return son_PID
def _remove_lock(PID_to_remove):
PIDs = filesystem.read_file(MOULINETTE_LOCK).split("\n")
PIDs_to_keep = [ PID for PID in PIDs if int(PID) != PID_to_remove ]
filesystem.write_to_file(MOULINETTE_LOCK, '\n'.join(PIDs_to_keep))
def _get_services():
"""
Get a dict of managed services with their parameters