$OpenBSD: patch-lib_ansible_modules_system_service_facts_py,v 1.3 2020/07/01 22:12:09 pvk Exp $

Add OpenBSD support to the service_facts module

Index: lib/ansible/modules/system/service_facts.py
--- lib/ansible/modules/system/service_facts.py.orig
+++ lib/ansible/modules/system/service_facts.py
@@ -55,18 +55,18 @@ ansible_facts:
       type: complex
       contains:
         source:
-          description: Init system of the service. One of C(systemd), C(sysv), C(upstart).
+          description: Init system of the service. One of C(rcctl), C(systemd), C(sysv), C(upstart).
           returned: always
           type: str
           sample: sysv
         state:
-          description: State of the service. Either C(running), C(stopped), or C(unknown).
+          description: State of the service. Either C(failed), 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
+          returned: systemd systems, RedHat/SUSE flavored sysvinit/upstart or OpenBSD
           type: str
           sample: enabled
         name:
@@ -228,10 +228,55 @@ class SystemctlScanService(BaseService):
         return services
 
 
+class OpenBSDScanService(BaseService):
+    def query_rcctl(self, cmd):
+        svcs = []
+
+        rc, stdout, stderr = self.module.run_command("%s ls %s" % (self.rcctl_path, cmd))
+        if 'needs root privileges' in stderr.lower():
+            self.incomplete_warning = True
+            return []
+
+        for svc in stdout.split('\n'):
+            if svc is '':
+                continue
+            else:
+                svcs.append(svc)
+
+        return svcs
+
+    def gather_services(self):
+        services = {}
+        self.rcctl_path = self.module.get_bin_path("rcctl")
+        if self.rcctl_path is None:
+            return None
+
+        for svc in self.query_rcctl('all'):
+            services[svc] = {'name': svc, 'source': 'rcctl'}
+
+        for svc in self.query_rcctl('on'):
+            services[svc].update({'status': 'enabled'})
+
+        for svc in self.query_rcctl('started'):
+            services[svc].update({'state': 'running'})
+
+        # Based on the list of services that are enabled, determine which are disabled
+        [services[svc].update({'status': 'disabled'}) for svc in services if services[svc].get('status') is None]
+
+        # and do the same for those are aren't running
+        [services[svc].update({'state': 'stopped'}) for svc in services if services[svc].get('state') is None]
+
+        # Override the state for services which are marked as 'failed'
+        for svc in self.query_rcctl('failed'):
+            services[svc].update({'state': 'failed'})
+
+        return services
+
+
 def main():
     module = AnsibleModule(argument_spec=dict(), supports_check_mode=True)
     module.run_command_environ_update = dict(LANG="C", LC_ALL="C")
-    service_modules = (ServiceScanService, SystemctlScanService)
+    service_modules = (OpenBSDScanService, ServiceScanService, SystemctlScanService)
     all_services = {}
     incomplete_warning = False
     for svc_module in service_modules:
