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 <admiller@redhat.com>

* provide state and status information about services

Fixes #45730

Signed-off-by: Adam Miller <admiller@redhat.com>
This commit is contained in:
Adam Miller 2018-12-26 07:24:03 -06:00 committed by John R Barker
parent 9be3ebc596
commit 33156712a9
2 changed files with 33 additions and 14 deletions

View file

@ -0,0 +1,3 @@
---
minor_changes:
- "service_facts - provide service state and status information about disabled systemd service units"

View file

@ -30,7 +30,6 @@ notes:
using the string value of the service name as the key in order to obtain 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']) the fact data value like C(ansible_facts.services['zuul-gateway'])
author: author:
- Adam Miller (@maxamillion) - Adam Miller (@maxamillion)
''' '''
@ -61,10 +60,15 @@ ansible_facts:
type: str type: str
sample: sysv sample: sysv
state: 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 returned: always
type: str type: str
sample: running 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: name:
description: Name of the service. description: Name of the service.
returned: always returned: always
@ -156,7 +160,9 @@ class ServiceScanService(BaseService):
if m: if m:
service_name = m.group('service') service_name = m.group('service')
service_state = 'stopped' service_state = 'stopped'
service_status = "disabled"
if m.group('rl3') == 'on': if m.group('rl3') == 'on':
service_status = "enabled"
rc, stdout, stderr = self.module.run_command('%s %s status' % (service_path, service_name), use_unsafe_shell=True) rc, stdout, stderr = self.module.run_command('%s %s status' % (service_path, service_name), use_unsafe_shell=True)
service_state = rc service_state = rc
if rc in (0,): if rc in (0,):
@ -168,7 +174,7 @@ class ServiceScanService(BaseService):
continue continue
else: else:
service_state = 'stopped' service_state = 'stopped'
service_data = {"name": service_name, "state": service_state, "source": "sysv"} service_data = {"name": service_name, "state": service_state, "status": service_status, "source": "sysv"}
services[service_name] = service_data services[service_name] = service_data
return services return services
@ -203,7 +209,17 @@ class SystemctlScanService(BaseService):
if 'failed' in line: if 'failed' in line:
service_name = line.split()[1] service_name = line.split()[1]
state_val = "stopped" 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 return services