From e8ef6b7d7c6fb0ee2b08107f2a79ed747c56b86b Mon Sep 17 00:00:00 2001 From: Abhijeet Kasurde Date: Wed, 25 Oct 2023 19:09:46 -0700 Subject: [PATCH] Consolidate systemd detection logic (#81809) * Add logic to consider the canary location for systemd files Fixes: #80975 Signed-off-by: Abhijeet Kasurde --- changelogs/fragments/80975-systemd-detect.yml | 3 ++ lib/ansible/module_utils/service.py | 33 +++++++++++++++++-- lib/ansible/modules/service.py | 21 ++---------- lib/ansible/modules/service_facts.py | 12 ++----- 4 files changed, 37 insertions(+), 32 deletions(-) create mode 100644 changelogs/fragments/80975-systemd-detect.yml diff --git a/changelogs/fragments/80975-systemd-detect.yml b/changelogs/fragments/80975-systemd-detect.yml new file mode 100644 index 00000000000..da4bbb986a9 --- /dev/null +++ b/changelogs/fragments/80975-systemd-detect.yml @@ -0,0 +1,3 @@ +--- +bugfixes: + - Consolidate systemd detection logic into one place (https://github.com/ansible/ansible/issues/80975). diff --git a/lib/ansible/module_utils/service.py b/lib/ansible/module_utils/service.py index 517a243e54e..3910ea0174d 100644 --- a/lib/ansible/module_utils/service.py +++ b/lib/ansible/module_utils/service.py @@ -110,8 +110,8 @@ def fail_if_missing(module, found, service, msg=''): This function will return an error or exit gracefully depending on check mode status and if the service is missing or not. - :arg module: is an AnsibleModule object, used for it's utility methods - :arg found: boolean indicating if services was found or not + :arg module: is an AnsibleModule object, used for it's utility methods + :arg found: boolean indicating if services were found or not :arg service: name of service :kw msg: extra info to append to error/success msg when missing ''' @@ -165,7 +165,7 @@ def daemonize(module, cmd): ''' Execute a command while detaching as a daemon, returns rc, stdout, and stderr. - :arg module: is an AnsibleModule object, used for it's utility methods + :arg module: is an AnsibleModule object, used for it's utility methods :arg cmd: is a list or string representing the command and options to run This is complex because daemonization is hard for people. @@ -274,3 +274,30 @@ def check_ps(module, pattern): if pattern in line: return True return False + + +def is_systemd_managed(module): + """ + Find out if the machine supports systemd or not + :arg module: is an AnsibleModule object, used for it's utility methods + + Returns True if the system supports systemd, False if not. + """ + # tools must be installed + if module.get_bin_path('systemctl'): + # This should show if systemd is the boot init system, if checking init failed to mark as systemd + # these mirror systemd's own sd_boot test http://www.freedesktop.org/software/systemd/man/sd_booted.html + for canary in ["/run/systemd/system/", "/dev/.run/systemd/", "/dev/.systemd/"]: + if os.path.exists(canary): + return True + + # If all else fails, check if init is the systemd command, using comm as cmdline could be symlink + try: + with open('/proc/1/comm', 'r') as init_proc: + init = init_proc.readline().strip() + return init == 'systemd' + except IOError: + # If comm doesn't exist, old kernel, no systemd + return False + + return False diff --git a/lib/ansible/modules/service.py b/lib/ansible/modules/service.py index 9dce857aff1..65eba3b768c 100644 --- a/lib/ansible/modules/service.py +++ b/lib/ansible/modules/service.py @@ -179,7 +179,7 @@ from ansible.module_utils.common.text.converters import to_bytes, to_text from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.common.locale import get_best_parsable_locale from ansible.module_utils.common.sys_info import get_platform_subclass -from ansible.module_utils.service import fail_if_missing +from ansible.module_utils.service import fail_if_missing, is_systemd_managed from ansible.module_utils.six import PY2, b @@ -484,24 +484,7 @@ class LinuxService(Service): # tools must be installed if location.get('systemctl', False): - - # this should show if systemd is the boot init system - # these mirror systemd's own sd_boot test http://www.freedesktop.org/software/systemd/man/sd_booted.html - for canary in ["/run/systemd/system/", "/dev/.run/systemd/", "/dev/.systemd/"]: - if os.path.exists(canary): - return True - - # If all else fails, check if init is the systemd command, using comm as cmdline could be symlink - try: - f = open('/proc/1/comm', 'r') - except IOError: - # If comm doesn't exist, old kernel, no systemd - return False - - for line in f: - if 'systemd' in line: - return True - + return is_systemd_managed(self.module) return False # Locate a tool to enable/disable a service diff --git a/lib/ansible/modules/service_facts.py b/lib/ansible/modules/service_facts.py index d04d4da5cff..d59cccf0715 100644 --- a/lib/ansible/modules/service_facts.py +++ b/lib/ansible/modules/service_facts.py @@ -94,6 +94,7 @@ import platform import re from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.common.locale import get_best_parsable_locale +from ansible.module_utils.service import is_systemd_managed class BaseService(object): @@ -244,16 +245,7 @@ class SystemctlScanService(BaseService): BAD_STATES = frozenset(['not-found', 'masked', 'failed']) def systemd_enabled(self): - # Check if init is the systemd command, using comm as cmdline could be symlink - try: - f = open('/proc/1/comm', 'r') - except IOError: - # If comm doesn't exist, old kernel, no systemd - return False - for line in f: - if 'systemd' in line: - return True - return False + return is_systemd_managed(self.module) def _list_from_units(self, systemctl_path, services):