Several systemd fixes
Allow some operations on missing services Better sysv handling Rearranged error reporting fixed load error catching and order logic also minor doc/comment updates added warnings
This commit is contained in:
parent
7079fe41be
commit
44c07d7ca8
1 changed files with 59 additions and 50 deletions
|
@ -72,14 +72,10 @@ requirements:
|
|||
|
||||
EXAMPLES = '''
|
||||
# Example action to start service httpd, if not running
|
||||
- systemd:
|
||||
state: started
|
||||
name: httpd
|
||||
- systemd: state=started name=httpd
|
||||
|
||||
# Example action to stop service cron on debian, if running
|
||||
- systemd:
|
||||
name: cron
|
||||
state: stopped
|
||||
- systemd: name=cron state=stopped
|
||||
|
||||
# Example action to restart service cron on centos, in all cases, also issue daemon-reload to pick up config changes
|
||||
- systemd:
|
||||
|
@ -235,16 +231,15 @@ status:
|
|||
}
|
||||
'''
|
||||
|
||||
import os
|
||||
import glob
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils._text import to_bytes, to_native
|
||||
from ansible.module_utils.service import sysv_exists, sysv_is_enabled, fail_if_missing
|
||||
from ansible.module_utils._text import to_native
|
||||
|
||||
# ===========================================
|
||||
# Main control flow
|
||||
|
||||
def main():
|
||||
# init
|
||||
# initialize
|
||||
module = AnsibleModule(
|
||||
argument_spec = dict(
|
||||
name = dict(required=True, type='str', aliases=['unit', 'service']),
|
||||
|
@ -258,7 +253,6 @@ def main():
|
|||
required_one_of=[['state', 'enabled', 'masked', 'daemon_reload']],
|
||||
)
|
||||
|
||||
# initialize
|
||||
systemctl = module.get_bin_path('systemctl')
|
||||
if module.params['user']:
|
||||
systemctl = systemctl + " --user"
|
||||
|
@ -269,6 +263,7 @@ def main():
|
|||
'name': unit,
|
||||
'changed': False,
|
||||
'status': {},
|
||||
'warnings': [],
|
||||
}
|
||||
|
||||
# Run daemon-reload first, if requested
|
||||
|
@ -277,14 +272,19 @@ def main():
|
|||
if rc != 0:
|
||||
module.fail_json(msg='failure %d during daemon-reload: %s' % (rc, err))
|
||||
|
||||
#TODO: check if service exists
|
||||
# check service data
|
||||
(rc, out, err) = module.run_command("%s show '%s'" % (systemctl, unit))
|
||||
if rc != 0:
|
||||
module.fail_json(msg='failure %d running systemctl show for %r: %s' % (rc, unit, err))
|
||||
|
||||
found = False
|
||||
is_initd = sysv_exists(unit)
|
||||
is_systemd = False
|
||||
|
||||
# load return of systemctl show into dictionary for easy access and return
|
||||
k = None
|
||||
multival = []
|
||||
if out:
|
||||
k = None
|
||||
for line in to_native(out).split('\n'): # systemd can have multiline values delimited with {}
|
||||
if line.strip():
|
||||
if k is None:
|
||||
|
@ -304,17 +304,23 @@ def main():
|
|||
else:
|
||||
multival.append(line)
|
||||
|
||||
is_systemd = 'LoadState' in result['status'] and result['status']['LoadState'] != 'not-found'
|
||||
|
||||
if 'LoadState' in result['status'] and result['status']['LoadState'] == 'not-found':
|
||||
module.fail_json(msg='Could not find the requested service "%r": %s' % (unit, err))
|
||||
elif 'LoadError' in result['status']:
|
||||
module.fail_json(msg="Failed to get the service status '%s': %s" % (unit, result['status']['LoadError']))
|
||||
# Check for loading error
|
||||
if is_systemd and 'LoadError' in result['status']:
|
||||
module.fail_json(msg="Error loading unit file '%s': %s" % (unit, result['status']['LoadError']))
|
||||
|
||||
# mask/unmask the service, if requested
|
||||
|
||||
# Does service exist?
|
||||
found = is_systemd or is_initd
|
||||
if is_initd and not is_systemd:
|
||||
result['warnings'].append('The service (%s) is actually an init script but the system is managed by systemd' % unit)
|
||||
|
||||
# mask/unmask the service, if requested, can operate on services before they are installed
|
||||
if module.params['masked'] is not None:
|
||||
masked = (result['status']['LoadState'] == 'masked')
|
||||
# state is not masked unless systemd affirms otherwise
|
||||
masked = ('LoadState' in result['status'] and result['status']['LoadState'] == 'masked')
|
||||
|
||||
# Change?
|
||||
if masked != module.params['masked']:
|
||||
result['changed'] = True
|
||||
if module.params['masked']:
|
||||
|
@ -325,10 +331,21 @@ def main():
|
|||
if not module.check_mode:
|
||||
(rc, out, err) = module.run_command("%s %s '%s'" % (systemctl, action, unit))
|
||||
if rc != 0:
|
||||
# some versions of system CAN mask/unmask non existing services, we only fail on missing if they don't
|
||||
fail_if_missing(module, found, unit, "cannot %s" % (action))
|
||||
module.fail_json(msg="Unable to %s service %s: %s" % (action, unit, err))
|
||||
|
||||
|
||||
# Enable/disable service startup at boot if requested
|
||||
if module.params['enabled'] is not None:
|
||||
|
||||
if module.params['enabled']:
|
||||
action = 'enable'
|
||||
else:
|
||||
action = 'disable'
|
||||
|
||||
fail_if_missing(module, found, unit, "cannot %s" % (action))
|
||||
|
||||
# do we need to enable the service?
|
||||
enabled = False
|
||||
(rc, out, err) = module.run_command("%s is-enabled '%s'" % (systemctl, unit))
|
||||
|
@ -337,11 +354,8 @@ def main():
|
|||
if rc == 0:
|
||||
enabled = True
|
||||
elif rc == 1:
|
||||
# Deals with init scripts
|
||||
# if both init script and unit file exist stdout should have enabled/disabled, otherwise use rc entries
|
||||
initscript = '/etc/init.d/' + unit
|
||||
if os.path.exists(initscript) and os.access(initscript, os.X_OK) and \
|
||||
(not out.startswith('disabled') or bool(glob.glob('/etc/rc?.d/S??' + unit))):
|
||||
if is_initd and (not out.startswith('disabled') or sysv_is_enabled(unit)):
|
||||
enabled = True
|
||||
|
||||
# default to current state
|
||||
|
@ -350,19 +364,16 @@ def main():
|
|||
# Change enable/disable if needed
|
||||
if enabled != module.params['enabled']:
|
||||
result['changed'] = True
|
||||
if module.params['enabled']:
|
||||
action = 'enable'
|
||||
else:
|
||||
action = 'disable'
|
||||
|
||||
if not module.check_mode:
|
||||
(rc, out, err) = module.run_command("%s %s '%s'" % (systemctl, action, unit))
|
||||
if rc != 0:
|
||||
module.fail_json(msg="Unable to %s service %s: %s" % (action, unit, err))
|
||||
module.fail_json(msg="Unable to %s service %s: %s" % (action, unit, out + err))
|
||||
|
||||
result['enabled'] = not enabled
|
||||
|
||||
# set service state if requested
|
||||
if module.params['state'] is not None:
|
||||
fail_if_missing(module, found, unit, "cannot check nor set state")
|
||||
|
||||
# default to desired state
|
||||
result['state'] = module.params['state']
|
||||
|
@ -373,17 +384,15 @@ def main():
|
|||
if module.params['state'] == 'started':
|
||||
if result['status']['ActiveState'] != 'active':
|
||||
action = 'start'
|
||||
result['changed'] = True
|
||||
elif module.params['state'] == 'stopped':
|
||||
if result['status']['ActiveState'] == 'active':
|
||||
action = 'stop'
|
||||
result['changed'] = True
|
||||
else:
|
||||
action = module.params['state'][:-2] # remove 'ed' from restarted/reloaded
|
||||
result['state'] = 'started'
|
||||
result['changed'] = True
|
||||
|
||||
if action:
|
||||
result['changed'] = True
|
||||
if not module.check_mode:
|
||||
(rc, out, err) = module.run_command("%s %s '%s'" % (systemctl, action, unit))
|
||||
if rc != 0:
|
||||
|
|
Loading…
Reference in a new issue