diff --git a/changelogs/fragments/systemd-offline.yml b/changelogs/fragments/systemd-offline.yml new file mode 100644 index 00000000000..2001694c4bb --- /dev/null +++ b/changelogs/fragments/systemd-offline.yml @@ -0,0 +1,3 @@ +bugfixes: +- systemd - don't require systemd to be running to enable/disable or mask/unmask + units diff --git a/lib/ansible/modules/system/systemd.py b/lib/ansible/modules/system/systemd.py index 4d8c4f52f7d..eaae69b7f25 100644 --- a/lib/ansible/modules/system/systemd.py +++ b/lib/ansible/modules/system/systemd.py @@ -404,14 +404,7 @@ def main(): # check service data, cannot error out on rc as it changes across versions, assume not found (rc, out, err) = module.run_command("%s show '%s'" % (systemctl, unit)) - if request_was_ignored(out) or request_was_ignored(err): - # fallback list-unit-files as show does not work on some systems (chroot) - # not used as primary as it skips some services (like those using init.d) and requires .service/etc notation - (rc, out, err) = module.run_command("%s list-unit-files '%s'" % (systemctl, unit)) - if rc == 0: - is_systemd = True - - elif rc == 0: + if rc == 0 and not (request_was_ignored(out) or request_was_ignored(err)): # load return of systemctl show into dictionary for easy access and return if out: result['status'] = parse_systemctl_show(to_native(out).split('\n')) @@ -424,8 +417,32 @@ def main(): if is_systemd and not is_masked and 'LoadError' in result['status']: module.fail_json(msg="Error loading unit file '%s': %s" % (unit, result['status']['LoadError'])) else: - # Check for systemctl command - module.run_command(systemctl, check_rc=True) + # list taken from man systemctl(1) for systemd 244 + valid_enabled_states = [ + "enabled", + "enabled-runtime", + "linked", + "linked-runtime", + "masked", + "masked-runtime", + "static", + "indirect", + "disabled", + "generated", + "transient"] + + (rc, out, err) = module.run_command("%s is-enabled '%s'" % (systemctl, unit)) + if out.strip() in valid_enabled_states: + is_systemd = True + else: + # fallback list-unit-files as show does not work on some systems (chroot) + # not used as primary as it skips some services (like those using init.d) and requires .service/etc notation + (rc, out, err) = module.run_command("%s list-unit-files '%s'" % (systemctl, unit)) + if rc == 0: + is_systemd = True + else: + # Check for systemctl command + module.run_command(systemctl, check_rc=True) # Does service exist? found = is_systemd or is_initd @@ -435,7 +452,8 @@ def main(): # mask/unmask the service, if requested, can operate on services before they are installed if module.params['masked'] is not None: # state is not masked unless systemd affirms otherwise - masked = ('LoadState' in result['status'] and result['status']['LoadState'] == 'masked') + (rc, out, err) = module.run_command("%s is-enabled '%s'" % (systemctl, unit)) + masked = out.strip() == "masked" if masked != module.params['masked']: result['changed'] = True