summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian Coca <brian.coca+git@gmail.com>2016-11-09 13:51:26 -0500
committerBrian Coca <brian.coca+git@gmail.com>2016-11-18 10:05:09 -0500
commit2f50979c34d998a5acf70652276e70dbeb70c74c (patch)
tree4e7db0126266489ec3a14371bf8183281983dc95
parent64db07f8986f0cd4a5913855de6bda7e3251252c (diff)
downloadansible-modules-core-2f50979c34d998a5acf70652276e70dbeb70c74c.tar.gz
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 (cherry picked from commit b835ae271734821c8e41ce8cd278a01266a2247b)
-rw-r--r--system/systemd.py103
1 files changed, 59 insertions, 44 deletions
diff --git a/system/systemd.py b/system/systemd.py
index fdaeae64..88e981e6 100644
--- a/system/systemd.py
+++ b/system/systemd.py
@@ -73,8 +73,10 @@ requirements:
EXAMPLES = '''
# Example action to start service httpd, if not running
- systemd: state=started name=httpd
+
# Example action to stop service cron on debian, if running
- 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: state=restarted daemon_reload=yes name=crond
# Example action to reload service httpd, in all cases
@@ -221,16 +223,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']),
@@ -244,7 +245,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"
@@ -255,6 +255,7 @@ def main():
'name': unit,
'changed': False,
'status': {},
+ 'warnings': [],
}
# Run daemon-reload first, if requested
@@ -263,44 +264,55 @@ 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 = []
- for line in to_native(out).split('\n'): # systemd can have multiline values delimited with {}
- if line.strip():
- if k is None:
- if '=' in line:
- k,v = line.split('=', 1)
- if v.lstrip().startswith('{'):
- if not v.rstrip().endswith('}'):
- multival.append(line)
- continue
- result['status'][k] = v.strip()
- k = None
- else:
- if line.rstrip().endswith('}'):
- result['status'][k] = '\n'.join(multival).strip()
- multival = []
- k = None
+ 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:
+ if '=' in line:
+ k,v = line.split('=', 1)
+ if v.lstrip().startswith('{'):
+ if not v.rstrip().endswith('}'):
+ multival.append(line)
+ continue
+ result['status'][k] = v.strip()
+ k = None
else:
- multival.append(line)
+ if line.rstrip().endswith('}'):
+ result['status'][k] = '\n'.join(multival).strip()
+ multival = []
+ k = None
+ else:
+ multival.append(line)
+
+ is_systemd = 'LoadState' in result['status'] and result['status']['LoadState'] != 'not-found'
+ # 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']))
- 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']))
- # 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']:
@@ -311,10 +323,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))
@@ -323,11 +346,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
@@ -336,19 +356,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']
@@ -359,17 +376,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: