From 33156712a9afa4b92eec0dd324c7e1301b69567d Mon Sep 17 00:00:00 2001 From: Adam Miller Date: Wed, 26 Dec 2018 07:24:03 -0600 Subject: [PATCH] Provide both service state and status when possible in service_facts (#49618) * Combine systemd units/unit-files output for service_facts Fixes #47118 Previously we were only taking the output of `systemd units` which would leave out information about the service units that were disabled, static, masked, etc. Now we're aggregating the results so that anything not active/inactive/dead at least is pulled as fact data with it's state provided. Signed-off-by: Adam Miller * provide state and status information about services Fixes #45730 Signed-off-by: Adam Miller --- ...acts-dont-hist-systemd-disabled-units.yaml | 3 ++ lib/ansible/modules/system/service_facts.py | 44 +++++++++++++------ 2 files changed, 33 insertions(+), 14 deletions(-) create mode 100644 changelogs/fragments/service-facts-dont-hist-systemd-disabled-units.yaml diff --git a/changelogs/fragments/service-facts-dont-hist-systemd-disabled-units.yaml b/changelogs/fragments/service-facts-dont-hist-systemd-disabled-units.yaml new file mode 100644 index 00000000000..2b4fcae97ff --- /dev/null +++ b/changelogs/fragments/service-facts-dont-hist-systemd-disabled-units.yaml @@ -0,0 +1,3 @@ +--- +minor_changes: + - "service_facts - provide service state and status information about disabled systemd service units" diff --git a/lib/ansible/modules/system/service_facts.py b/lib/ansible/modules/system/service_facts.py index d5d53165a59..ce61b0918e4 100644 --- a/lib/ansible/modules/system/service_facts.py +++ b/lib/ansible/modules/system/service_facts.py @@ -30,7 +30,6 @@ notes: using the string value of the service name as the key in order to obtain the fact data value like C(ansible_facts.services['zuul-gateway']) - author: - Adam Miller (@maxamillion) ''' @@ -61,10 +60,15 @@ ansible_facts: type: str sample: sysv state: - description: State of the service. Either C(running) or C(stopped). + description: State of the service. Either C(running), C(stopped), or C(unknown). returned: always type: str sample: running + status: + description: State of the service. Either C(enabled), C(disabled), or C(unknown). + returned: systemd systems or RedHat/SUSE flavored sysvinit/upstart + type: string + sample: enabled name: description: Name of the service. returned: always @@ -156,19 +160,21 @@ class ServiceScanService(BaseService): if m: service_name = m.group('service') service_state = 'stopped' + service_status = "disabled" if m.group('rl3') == 'on': - rc, stdout, stderr = self.module.run_command('%s %s status' % (service_path, service_name), use_unsafe_shell=True) - service_state = rc - if rc in (0,): - service_state = 'running' - # elif rc in (1,3): + service_status = "enabled" + rc, stdout, stderr = self.module.run_command('%s %s status' % (service_path, service_name), use_unsafe_shell=True) + service_state = rc + if rc in (0,): + service_state = 'running' + # elif rc in (1,3): + else: + if 'root' in stderr or 'permission' in stderr.lower() or 'not in sudoers' in stderr.lower(): + self.incomplete_warning = True + continue else: - if 'root' in stderr or 'permission' in stderr.lower() or 'not in sudoers' in stderr.lower(): - self.incomplete_warning = True - continue - else: - service_state = 'stopped' - service_data = {"name": service_name, "state": service_state, "source": "sysv"} + service_state = 'stopped' + service_data = {"name": service_name, "state": service_state, "status": service_status, "source": "sysv"} services[service_name] = service_data return services @@ -203,7 +209,17 @@ class SystemctlScanService(BaseService): if 'failed' in line: service_name = line.split()[1] state_val = "stopped" - services[service_name] = {"name": service_name, "state": state_val, "source": "systemd"} + services[service_name] = {"name": service_name, "state": state_val, "status": "unknown", "source": "systemd"} + rc, stdout, stderr = self.module.run_command("%s list-unit-files --no-pager --type service --all" % systemctl_path, use_unsafe_shell=True) + for line in [svc_line for svc_line in stdout.split('\n') if '.service' in svc_line and 'not-found' not in svc_line]: + try: + service_name, status_val = line.split() + except ValueError: + self.module.fail_json(msg="Malformed output discovered from systemd list-unit-files: {0}".format(line)) + if service_name not in services: + services[service_name] = {"name": service_name, "state": "unknown", "status": status_val, "source": "systemd"} + else: + services[service_name]["status"] = status_val return services