service_facts, now more accurate on systemd (#75326) (#76018)

* service_facts, now more accurate on systemd

(cherry picked from commit 82bab063e7)
pull/76830/head
Brian Coca 3 years ago committed by GitHub
parent 6b4fcdf59f
commit a280645022
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,2 @@
minor_changes:
- service_facts now handles more states/statuses from systemd and in a more reliable way (failed, not-found, masked).

@ -1,7 +1,6 @@
#!/usr/bin/python
# Copyright: (c) 2017, Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
# originally copied from AWX's scan_services module to bring this functionality
# into Core
@ -199,24 +198,40 @@ class SystemctlScanService(BaseService):
return False
def gather_services(self):
BAD_STATES = frozenset(['not-found', 'masked', 'failed'])
services = {}
if not self.systemd_enabled():
return None
systemctl_path = self.module.get_bin_path("systemctl", opt_dirs=["/usr/bin", "/usr/local/bin"])
if systemctl_path is None:
return None
# list units as systemd sees them
rc, stdout, stderr = self.module.run_command("%s list-units --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]:
service_name = line.split()[0]
if "running" in line:
state_val = "running"
for line in [svc_line for svc_line in stdout.split('\n') if '.service' in svc_line]:
state_val = "stopped"
status_val = "unknown"
fields = line.split()
for bad in BAD_STATES:
if bad in fields: # dot is 0
status_val = bad
fields = fields[1:]
break
else:
if 'failed' in line:
service_name = line.split()[1]
state_val = "stopped"
services[service_name] = {"name": service_name, "state": state_val, "status": "unknown", "source": "systemd"}
# active/inactive
status_val = fields[2]
# array is normalize so predictable now
service_name = fields[0]
if fields[3] == "running":
state_val = "running"
services[service_name] = {"name": service_name, "state": state_val, "status": status_val, "source": "systemd"}
# now try unit files for complete picture and final 'status'
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]:
for line in [svc_line for svc_line in stdout.split('\n') if '.service' in svc_line]:
# there is one more column (VENDOR PRESET) from `systemctl list-unit-files` for systemd >= 245
try:
service_name, status_val = line.split()[:2]
@ -228,8 +243,9 @@ class SystemctlScanService(BaseService):
if not rc and stdout != '':
state = stdout.replace('ActiveState=', '').rstrip()
services[service_name] = {"name": service_name, "state": state, "status": status_val, "source": "systemd"}
else:
elif services[service_name]["status"] not in BAD_STATES:
services[service_name]["status"] = status_val
return services

Loading…
Cancel
Save