We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
service_facts returns misleading state on systemd hosts
##### SUMMARY
The system module service_facts returns misleading state information on systemd hosts.

##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME
service_facts

##### ANSIBLE VERSION
```
ansible 2.5.2
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/home/USER/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.5 (default, Feb 20 2018, 09:19:12) [GCC 4.8.5 20150623 (Red Hat 4.8.5-28)]
```

##### CONFIGURATION
N/A

##### OS / ENVIRONMENT
Ansible controller: RHEL 7.5
Remote host: RHEL 7.4

##### STEPS TO REPRODUCE
The service_facts module returns one of two states for each service it discovers: either "running" or "stopped".  

```json
{
    "ansible_facts": {    
        "services": {
            "rsyncd.service": {
                "name": "rsyncd.service",
                "source": "systemd",
                "state": "stopped"
            },
            "rsyslog.service": {
                "name": "rsyslog.service",
                "source": "systemd",
                "state": "running"
            },
            ... 
        }  
    }
}
```

On systemd hosts, the module obtains state information via `systemctl list-unit-files --type=service` (see [line 181 in module source code](https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/system/service_facts.py#L181)). However, this command does not report running/stopped status. Instead, it reports enabled/disable status which is not the same thing. Enabled/disabled determines whether the service will be started by systemd _on reboot_, but says nothing about whether it is currently running or stopped.

Here are two examples:

**1. Service disabled & started:**

```bash
# On remote host
systemctl disable <service>
systemctl start <service>
systemctl status <service>
# systemctl reports: loaded, disabled, active/running
```

**2. Service enabled & stopped:**

```bash
# On remote host
systemctl enable <service>
systemctl stop <service>
systemctl status <service>
# systemctl reports: loaded, enabled, inactive/dead
```

**On the Ansible controller,** use the service_facts module to query the <service> just configured on the remote host.

##### EXPECTED RESULTS
**1. Service disabled & started:** service_facts should report "running"

**2. Service enabled & stopped:** service_facts should report "stopped"

##### ACTUAL RESULTS
**1. Service disabled & started:** service_facts reports "stopped"

**2. Service enabled & stopped:** service_facts reports "running"

These misleading reports are caused by the test in [line 186 of the source code](https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/system/service_facts.py#L186). The service_facts module explicitly tests whether the service is "enabled" and equates that with running/stopped, which is incorrect for systemd/systemctl.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `lib/ansible/modules/system/service_facts.py`
Content:
```
1 #!/usr/bin/python
2 # (c) 2017, Ansible Project
3 # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
4 
5 # originally copied from AWX's scan_services module to bring this functionality
6 # into Core
7 
8 from __future__ import absolute_import, division, print_function
9 __metaclass__ = type
10 
11 
12 ANSIBLE_METADATA = {'metadata_version': '1.1',
13                     'status': ['preview'],
14                     'supported_by': 'community'}
15 
16 DOCUMENTATION = '''
17 ---
18 module: service_facts
19 short_description: Return service state information as fact data
20 description:
21      - Return service state information as fact data for various service management utilities
22 version_added: "2.5"
23 requirements: ["Any of the following supported init systems: systemd, sysv, upstart"]
24 
25 author:
26   - Matthew Jones
27   - Adam Miller (@maxamillion)
28 '''
29 
30 EXAMPLES = '''
31 - name: populate service facts
32   service_facts:
33 
34 - debug:
35     var: ansible_facts.services
36 
37 '''
38 
39 RETURN = '''
40 ansible_facts:
41   description: facts to add to ansible_facts about the services on the system
42   returned: always
43   type: complex
44   contains:
45     "services": {
46       "network": {
47         "source": "sysv",
48         "state": "running",
49         "name": "network"
50       },
51       arp-ethers.service: {
52         "source": "systemd",
53         "state": "stopped",
54         "name": "arp-ethers.service"
55       }
56     }
57 '''
58 
59 
60 import re
61 from ansible.module_utils.basic import AnsibleModule
62 
63 
64 class BaseService(object):
65 
66     def __init__(self, module):
67         self.module = module
68         self.incomplete_warning = False
69 
70 
71 class ServiceScanService(BaseService):
72 
73     def gather_services(self):
74         services = {}
75         service_path = self.module.get_bin_path("service")
76         if service_path is None:
77             return None
78         initctl_path = self.module.get_bin_path("initctl")
79         chkconfig_path = self.module.get_bin_path("chkconfig")
80 
81         # sysvinit
82         if service_path is not None and chkconfig_path is None:
83             rc, stdout, stderr = self.module.run_command("%s --status-all 2>&1 | grep -E \"\\[ (\\+|\\-) \\]\"" % service_path, use_unsafe_shell=True)
84             for line in stdout.split("\n"):
85                 line_data = line.split()
86                 if len(line_data) < 4:
87                     continue  # Skipping because we expected more data
88                 service_name = " ".join(line_data[3:])
89                 if line_data[1] == "+":
90                     service_state = "running"
91                 else:
92                     service_state = "stopped"
93                 services[service_name] = {"name": service_name, "state": service_state, "source": "sysv"}
94 
95         # Upstart
96         if initctl_path is not None and chkconfig_path is None:
97             p = re.compile(r'^\s?(?P<name>.*)\s(?P<goal>\w+)\/(?P<state>\w+)(\,\sprocess\s(?P<pid>[0-9]+))?\s*$')
98             rc, stdout, stderr = self.module.run_command("%s list" % initctl_path)
99             real_stdout = stdout.replace("\r", "")
100             for line in real_stdout.split("\n"):
101                 m = p.match(line)
102                 if not m:
103                     continue
104                 service_name = m.group('name')
105                 service_goal = m.group('goal')
106                 service_state = m.group('state')
107                 if m.group('pid'):
108                     pid = m.group('pid')
109                 else:
110                     pid = None  # NOQA
111                 payload = {"name": service_name, "state": service_state, "goal": service_goal, "source": "upstart"}
112                 services[service_name] = payload
113 
114         # RH sysvinit
115         elif chkconfig_path is not None:
116             # print '%s --status-all | grep -E "is (running|stopped)"' % service_path
117             p = re.compile(
118                 r'(?P<service>.*?)\s+[0-9]:(?P<rl0>on|off)\s+[0-9]:(?P<rl1>on|off)\s+[0-9]:(?P<rl2>on|off)\s+'
119                 r'[0-9]:(?P<rl3>on|off)\s+[0-9]:(?P<rl4>on|off)\s+[0-9]:(?P<rl5>on|off)\s+[0-9]:(?P<rl6>on|off)')
120             rc, stdout, stderr = self.module.run_command('%s' % chkconfig_path, use_unsafe_shell=True)
121             # Check for special cases where stdout does not fit pattern
122             match_any = False
123             for line in stdout.split('\n'):
124                 if p.match(line):
125                     match_any = True
126             if not match_any:
127                 p_simple = re.compile(r'(?P<service>.*?)\s+(?P<rl0>on|off)')
128                 match_any = False
129                 for line in stdout.split('\n'):
130                     if p_simple.match(line):
131                         match_any = True
132                 if match_any:
133                     # Try extra flags " -l --allservices" needed for SLES11
134                     rc, stdout, stderr = self.module.run_command('%s -l --allservices' % chkconfig_path, use_unsafe_shell=True)
135                 elif '--list' in stderr:
136                     # Extra flag needed for RHEL5
137                     rc, stdout, stderr = self.module.run_command('%s --list' % chkconfig_path, use_unsafe_shell=True)
138             for line in stdout.split('\n'):
139                 m = p.match(line)
140                 if m:
141                     service_name = m.group('service')
142                     service_state = 'stopped'
143                     if m.group('rl3') == 'on':
144                         rc, stdout, stderr = self.module.run_command('%s %s status' % (service_path, service_name), use_unsafe_shell=True)
145                         service_state = rc
146                         if rc in (0,):
147                             service_state = 'running'
148                         # elif rc in (1,3):
149                         else:
150                             if 'root' in stderr or 'permission' in stderr.lower() or 'not in sudoers' in stderr.lower():
151                                 self.incomplete_warning = True
152                                 continue
153                             else:
154                                 service_state = 'stopped'
155                     service_data = {"name": service_name, "state": service_state, "source": "sysv"}
156                     services[service_name] = service_data
157         return services
158 
159 
160 class SystemctlScanService(BaseService):
161 
162     def systemd_enabled(self):
163         # Check if init is the systemd command, using comm as cmdline could be symlink
164         try:
165             f = open('/proc/1/comm', 'r')
166         except IOError:
167             # If comm doesn't exist, old kernel, no systemd
168             return False
169         for line in f:
170             if 'systemd' in line:
171                 return True
172         return False
173 
174     def gather_services(self):
175         services = {}
176         if not self.systemd_enabled():
177             return None
178         systemctl_path = self.module.get_bin_path("systemctl", opt_dirs=["/usr/bin", "/usr/local/bin"])
179         if systemctl_path is None:
180             return None
181         rc, stdout, stderr = self.module.run_command("%s list-unit-files --type=service | tail -n +2 | head -n -2" % systemctl_path, use_unsafe_shell=True)
182         for line in stdout.split("\n"):
183             line_data = line.split()
184             if len(line_data) != 2:
185                 continue
186             if line_data[1] == "enabled":
187                 state_val = "running"
188             else:
189                 state_val = "stopped"
190             services[line_data[0]] = {"name": line_data[0], "state": state_val, "source": "systemd"}
191         return services
192 
193 
194 def main():
195     module = AnsibleModule(argument_spec=dict())
196     service_modules = (ServiceScanService, SystemctlScanService)
197     all_services = {}
198     incomplete_warning = False
199     for svc_module in service_modules:
200         svcmod = svc_module(module)
201         svc = svcmod.gather_services()
202         if svc is not None:
203             all_services.update(svc)
204             if svcmod.incomplete_warning:
205                 incomplete_warning = True
206     if len(all_services) == 0:
207         results = dict(skipped=True, msg="Failed to find any services. Sometimes this is due to insufficient privileges.")
208     else:
209         results = dict(ansible_facts=dict(services=all_services))
210         if incomplete_warning:
211             results['msg'] = "WARNING: Could not find status for all services. Sometimes this is due to insufficient privileges."
212     module.exit_json(**results)
213 
214 
215 if __name__ == '__main__':
216     main()
217
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/lib/ansible/modules/system/service_facts.py b/lib/ansible/modules/system/service_facts.py
--- a/lib/ansible/modules/system/service_facts.py
+++ b/lib/ansible/modules/system/service_facts.py
@@ -178,16 +178,16 @@
         systemctl_path = self.module.get_bin_path("systemctl", opt_dirs=["/usr/bin", "/usr/local/bin"])
         if systemctl_path is None:
             return None
-        rc, stdout, stderr = self.module.run_command("%s list-unit-files --type=service | tail -n +2 | head -n -2" % systemctl_path, use_unsafe_shell=True)
-        for line in stdout.split("\n"):
-            line_data = line.split()
-            if len(line_data) != 2:
-                continue
-            if line_data[1] == "enabled":
+        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"
             else:
+                if 'failed' in line:
+                    service_name = line.split()[1]
                 state_val = "stopped"
-            services[line_data[0]] = {"name": line_data[0], "state": state_val, "source": "systemd"}
+            services[service_name] = {"name": service_name, "state": state_val, "source": "systemd"}
         return services

{"golden_diff": "diff --git a/lib/ansible/modules/system/service_facts.py b/lib/ansible/modules/system/service_facts.py\n--- a/lib/ansible/modules/system/service_facts.py\n+++ b/lib/ansible/modules/system/service_facts.py\n@@ -178,16 +178,16 @@\n         systemctl_path = self.module.get_bin_path(\"systemctl\", opt_dirs=[\"/usr/bin\", \"/usr/local/bin\"])\n         if systemctl_path is None:\n             return None\n-        rc, stdout, stderr = self.module.run_command(\"%s list-unit-files --type=service | tail -n +2 | head -n -2\" % systemctl_path, use_unsafe_shell=True)\n-        for line in stdout.split(\"\\n\"):\n-            line_data = line.split()\n-            if len(line_data) != 2:\n-                continue\n-            if line_data[1] == \"enabled\":\n+        rc, stdout, stderr = self.module.run_command(\"%s list-units --no-pager --type service --all\" % systemctl_path, use_unsafe_shell=True)\n+        for line in [svc_line for svc_line in stdout.split('\\n') if '.service' in svc_line and 'not-found' not in svc_line]:\n+            service_name = line.split()[0]\n+            if \"running\" in line:\n                 state_val = \"running\"\n             else:\n+                if 'failed' in line:\n+                    service_name = line.split()[1]\n                 state_val = \"stopped\"\n-            services[line_data[0]] = {\"name\": line_data[0], \"state\": state_val, \"source\": \"systemd\"}\n+            services[service_name] = {\"name\": service_name, \"state\": state_val, \"source\": \"systemd\"}\n         return services\n", "issue": "service_facts returns misleading state on systemd hosts\n##### SUMMARY\r\nThe system module service_facts returns misleading state information on systemd hosts.\r\n\r\n##### ISSUE TYPE\r\n - Bug Report\r\n\r\n##### COMPONENT NAME\r\nservice_facts\r\n\r\n##### ANSIBLE VERSION\r\n```\r\nansible 2.5.2\r\n  config file = /etc/ansible/ansible.cfg\r\n  configured module search path = [u'/home/USER/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']\r\n  ansible python module location = /usr/lib/python2.7/site-packages/ansible\r\n  executable location = /usr/bin/ansible\r\n  python version = 2.7.5 (default, Feb 20 2018, 09:19:12) [GCC 4.8.5 20150623 (Red Hat 4.8.5-28)]\r\n```\r\n\r\n##### CONFIGURATION\r\nN/A\r\n\r\n##### OS / ENVIRONMENT\r\nAnsible controller: RHEL 7.5\r\nRemote host: RHEL 7.4\r\n\r\n##### STEPS TO REPRODUCE\r\nThe service_facts module returns one of two states for each service it discovers: either \"running\" or \"stopped\".  \r\n\r\n```json\r\n{\r\n    \"ansible_facts\": {    \r\n        \"services\": {\r\n            \"rsyncd.service\": {\r\n                \"name\": \"rsyncd.service\",\r\n                \"source\": \"systemd\",\r\n                \"state\": \"stopped\"\r\n            },\r\n            \"rsyslog.service\": {\r\n                \"name\": \"rsyslog.service\",\r\n                \"source\": \"systemd\",\r\n                \"state\": \"running\"\r\n            },\r\n            ... \r\n        }  \r\n    }\r\n}\r\n```\r\n\r\nOn systemd hosts, the module obtains state information via `systemctl list-unit-files --type=service` (see [line 181 in module source code](https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/system/service_facts.py#L181)). However, this command does not report running/stopped status. Instead, it reports enabled/disable status which is not the same thing. Enabled/disabled determines whether the service will be started by systemd _on reboot_, but says nothing about whether it is currently running or stopped.\r\n\r\nHere are two examples:\r\n\r\n**1. Service disabled & started:**\r\n\r\n```bash\r\n# On remote host\r\nsystemctl disable <service>\r\nsystemctl start <service>\r\nsystemctl status <service>\r\n# systemctl reports: loaded, disabled, active/running\r\n```\r\n\r\n**2. Service enabled & stopped:**\r\n\r\n```bash\r\n# On remote host\r\nsystemctl enable <service>\r\nsystemctl stop <service>\r\nsystemctl status <service>\r\n# systemctl reports: loaded, enabled, inactive/dead\r\n```\r\n\r\n**On the Ansible controller,** use the service_facts module to query the <service> just configured on the remote host.\r\n\r\n##### EXPECTED RESULTS\r\n**1. Service disabled & started:** service_facts should report \"running\"\r\n\r\n**2. Service enabled & stopped:** service_facts should report \"stopped\"\r\n\r\n##### ACTUAL RESULTS\r\n**1. Service disabled & started:** service_facts reports \"stopped\"\r\n\r\n**2. Service enabled & stopped:** service_facts reports \"running\"\r\n\r\nThese misleading reports are caused by the test in [line 186 of the source code](https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/system/service_facts.py#L186). The service_facts module explicitly tests whether the service is \"enabled\" and equates that with running/stopped, which is incorrect for systemd/systemctl.\r\n\n", "before_files": [{"content": "#!/usr/bin/python\n# (c) 2017, Ansible Project\n# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)\n\n# originally copied from AWX's scan_services module to bring this functionality\n# into Core\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: service_facts\nshort_description: Return service state information as fact data\ndescription:\n     - Return service state information as fact data for various service management utilities\nversion_added: \"2.5\"\nrequirements: [\"Any of the following supported init systems: systemd, sysv, upstart\"]\n\nauthor:\n  - Matthew Jones\n  - Adam Miller (@maxamillion)\n'''\n\nEXAMPLES = '''\n- name: populate service facts\n  service_facts:\n\n- debug:\n    var: ansible_facts.services\n\n'''\n\nRETURN = '''\nansible_facts:\n  description: facts to add to ansible_facts about the services on the system\n  returned: always\n  type: complex\n  contains:\n    \"services\": {\n      \"network\": {\n        \"source\": \"sysv\",\n        \"state\": \"running\",\n        \"name\": \"network\"\n      },\n      arp-ethers.service: {\n        \"source\": \"systemd\",\n        \"state\": \"stopped\",\n        \"name\": \"arp-ethers.service\"\n      }\n    }\n'''\n\n\nimport re\nfrom ansible.module_utils.basic import AnsibleModule\n\n\nclass BaseService(object):\n\n    def __init__(self, module):\n        self.module = module\n        self.incomplete_warning = False\n\n\nclass ServiceScanService(BaseService):\n\n    def gather_services(self):\n        services = {}\n        service_path = self.module.get_bin_path(\"service\")\n        if service_path is None:\n            return None\n        initctl_path = self.module.get_bin_path(\"initctl\")\n        chkconfig_path = self.module.get_bin_path(\"chkconfig\")\n\n        # sysvinit\n        if service_path is not None and chkconfig_path is None:\n            rc, stdout, stderr = self.module.run_command(\"%s --status-all 2>&1 | grep -E \\\"\\\\[ (\\\\+|\\\\-) \\\\]\\\"\" % service_path, use_unsafe_shell=True)\n            for line in stdout.split(\"\\n\"):\n                line_data = line.split()\n                if len(line_data) < 4:\n                    continue  # Skipping because we expected more data\n                service_name = \" \".join(line_data[3:])\n                if line_data[1] == \"+\":\n                    service_state = \"running\"\n                else:\n                    service_state = \"stopped\"\n                services[service_name] = {\"name\": service_name, \"state\": service_state, \"source\": \"sysv\"}\n\n        # Upstart\n        if initctl_path is not None and chkconfig_path is None:\n            p = re.compile(r'^\\s?(?P<name>.*)\\s(?P<goal>\\w+)\\/(?P<state>\\w+)(\\,\\sprocess\\s(?P<pid>[0-9]+))?\\s*$')\n            rc, stdout, stderr = self.module.run_command(\"%s list\" % initctl_path)\n            real_stdout = stdout.replace(\"\\r\", \"\")\n            for line in real_stdout.split(\"\\n\"):\n                m = p.match(line)\n                if not m:\n                    continue\n                service_name = m.group('name')\n                service_goal = m.group('goal')\n                service_state = m.group('state')\n                if m.group('pid'):\n                    pid = m.group('pid')\n                else:\n                    pid = None  # NOQA\n                payload = {\"name\": service_name, \"state\": service_state, \"goal\": service_goal, \"source\": \"upstart\"}\n                services[service_name] = payload\n\n        # RH sysvinit\n        elif chkconfig_path is not None:\n            # print '%s --status-all | grep -E \"is (running|stopped)\"' % service_path\n            p = re.compile(\n                r'(?P<service>.*?)\\s+[0-9]:(?P<rl0>on|off)\\s+[0-9]:(?P<rl1>on|off)\\s+[0-9]:(?P<rl2>on|off)\\s+'\n                r'[0-9]:(?P<rl3>on|off)\\s+[0-9]:(?P<rl4>on|off)\\s+[0-9]:(?P<rl5>on|off)\\s+[0-9]:(?P<rl6>on|off)')\n            rc, stdout, stderr = self.module.run_command('%s' % chkconfig_path, use_unsafe_shell=True)\n            # Check for special cases where stdout does not fit pattern\n            match_any = False\n            for line in stdout.split('\\n'):\n                if p.match(line):\n                    match_any = True\n            if not match_any:\n                p_simple = re.compile(r'(?P<service>.*?)\\s+(?P<rl0>on|off)')\n                match_any = False\n                for line in stdout.split('\\n'):\n                    if p_simple.match(line):\n                        match_any = True\n                if match_any:\n                    # Try extra flags \" -l --allservices\" needed for SLES11\n                    rc, stdout, stderr = self.module.run_command('%s -l --allservices' % chkconfig_path, use_unsafe_shell=True)\n                elif '--list' in stderr:\n                    # Extra flag needed for RHEL5\n                    rc, stdout, stderr = self.module.run_command('%s --list' % chkconfig_path, use_unsafe_shell=True)\n            for line in stdout.split('\\n'):\n                m = p.match(line)\n                if m:\n                    service_name = m.group('service')\n                    service_state = 'stopped'\n                    if m.group('rl3') == 'on':\n                        rc, stdout, stderr = self.module.run_command('%s %s status' % (service_path, service_name), use_unsafe_shell=True)\n                        service_state = rc\n                        if rc in (0,):\n                            service_state = 'running'\n                        # elif rc in (1,3):\n                        else:\n                            if 'root' in stderr or 'permission' in stderr.lower() or 'not in sudoers' in stderr.lower():\n                                self.incomplete_warning = True\n                                continue\n                            else:\n                                service_state = 'stopped'\n                    service_data = {\"name\": service_name, \"state\": service_state, \"source\": \"sysv\"}\n                    services[service_name] = service_data\n        return services\n\n\nclass SystemctlScanService(BaseService):\n\n    def systemd_enabled(self):\n        # Check if init is the systemd command, using comm as cmdline could be symlink\n        try:\n            f = open('/proc/1/comm', 'r')\n        except IOError:\n            # If comm doesn't exist, old kernel, no systemd\n            return False\n        for line in f:\n            if 'systemd' in line:\n                return True\n        return False\n\n    def gather_services(self):\n        services = {}\n        if not self.systemd_enabled():\n            return None\n        systemctl_path = self.module.get_bin_path(\"systemctl\", opt_dirs=[\"/usr/bin\", \"/usr/local/bin\"])\n        if systemctl_path is None:\n            return None\n        rc, stdout, stderr = self.module.run_command(\"%s list-unit-files --type=service | tail -n +2 | head -n -2\" % systemctl_path, use_unsafe_shell=True)\n        for line in stdout.split(\"\\n\"):\n            line_data = line.split()\n            if len(line_data) != 2:\n                continue\n            if line_data[1] == \"enabled\":\n                state_val = \"running\"\n            else:\n                state_val = \"stopped\"\n            services[line_data[0]] = {\"name\": line_data[0], \"state\": state_val, \"source\": \"systemd\"}\n        return services\n\n\ndef main():\n    module = AnsibleModule(argument_spec=dict())\n    service_modules = (ServiceScanService, SystemctlScanService)\n    all_services = {}\n    incomplete_warning = False\n    for svc_module in service_modules:\n        svcmod = svc_module(module)\n        svc = svcmod.gather_services()\n        if svc is not None:\n            all_services.update(svc)\n            if svcmod.incomplete_warning:\n                incomplete_warning = True\n    if len(all_services) == 0:\n        results = dict(skipped=True, msg=\"Failed to find any services. Sometimes this is due to insufficient privileges.\")\n    else:\n        results = dict(ansible_facts=dict(services=all_services))\n        if incomplete_warning:\n            results['msg'] = \"WARNING: Could not find status for all services. Sometimes this is due to insufficient privileges.\"\n    module.exit_json(**results)\n\n\nif __name__ == '__main__':\n    main()\n", "path": "lib/ansible/modules/system/service_facts.py"}], "after_files": [{"content": "#!/usr/bin/python\n# (c) 2017, Ansible Project\n# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)\n\n# originally copied from AWX's scan_services module to bring this functionality\n# into Core\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: service_facts\nshort_description: Return service state information as fact data\ndescription:\n     - Return service state information as fact data for various service management utilities\nversion_added: \"2.5\"\nrequirements: [\"Any of the following supported init systems: systemd, sysv, upstart\"]\n\nauthor:\n  - Matthew Jones\n  - Adam Miller (@maxamillion)\n'''\n\nEXAMPLES = '''\n- name: populate service facts\n  service_facts:\n\n- debug:\n    var: ansible_facts.services\n\n'''\n\nRETURN = '''\nansible_facts:\n  description: facts to add to ansible_facts about the services on the system\n  returned: always\n  type: complex\n  contains:\n    \"services\": {\n      \"network\": {\n        \"source\": \"sysv\",\n        \"state\": \"running\",\n        \"name\": \"network\"\n      },\n      arp-ethers.service: {\n        \"source\": \"systemd\",\n        \"state\": \"stopped\",\n        \"name\": \"arp-ethers.service\"\n      }\n    }\n'''\n\n\nimport re\nfrom ansible.module_utils.basic import AnsibleModule\n\n\nclass BaseService(object):\n\n    def __init__(self, module):\n        self.module = module\n        self.incomplete_warning = False\n\n\nclass ServiceScanService(BaseService):\n\n    def gather_services(self):\n        services = {}\n        service_path = self.module.get_bin_path(\"service\")\n        if service_path is None:\n            return None\n        initctl_path = self.module.get_bin_path(\"initctl\")\n        chkconfig_path = self.module.get_bin_path(\"chkconfig\")\n\n        # sysvinit\n        if service_path is not None and chkconfig_path is None:\n            rc, stdout, stderr = self.module.run_command(\"%s --status-all 2>&1 | grep -E \\\"\\\\[ (\\\\+|\\\\-) \\\\]\\\"\" % service_path, use_unsafe_shell=True)\n            for line in stdout.split(\"\\n\"):\n                line_data = line.split()\n                if len(line_data) < 4:\n                    continue  # Skipping because we expected more data\n                service_name = \" \".join(line_data[3:])\n                if line_data[1] == \"+\":\n                    service_state = \"running\"\n                else:\n                    service_state = \"stopped\"\n                services[service_name] = {\"name\": service_name, \"state\": service_state, \"source\": \"sysv\"}\n\n        # Upstart\n        if initctl_path is not None and chkconfig_path is None:\n            p = re.compile(r'^\\s?(?P<name>.*)\\s(?P<goal>\\w+)\\/(?P<state>\\w+)(\\,\\sprocess\\s(?P<pid>[0-9]+))?\\s*$')\n            rc, stdout, stderr = self.module.run_command(\"%s list\" % initctl_path)\n            real_stdout = stdout.replace(\"\\r\", \"\")\n            for line in real_stdout.split(\"\\n\"):\n                m = p.match(line)\n                if not m:\n                    continue\n                service_name = m.group('name')\n                service_goal = m.group('goal')\n                service_state = m.group('state')\n                if m.group('pid'):\n                    pid = m.group('pid')\n                else:\n                    pid = None  # NOQA\n                payload = {\"name\": service_name, \"state\": service_state, \"goal\": service_goal, \"source\": \"upstart\"}\n                services[service_name] = payload\n\n        # RH sysvinit\n        elif chkconfig_path is not None:\n            # print '%s --status-all | grep -E \"is (running|stopped)\"' % service_path\n            p = re.compile(\n                r'(?P<service>.*?)\\s+[0-9]:(?P<rl0>on|off)\\s+[0-9]:(?P<rl1>on|off)\\s+[0-9]:(?P<rl2>on|off)\\s+'\n                r'[0-9]:(?P<rl3>on|off)\\s+[0-9]:(?P<rl4>on|off)\\s+[0-9]:(?P<rl5>on|off)\\s+[0-9]:(?P<rl6>on|off)')\n            rc, stdout, stderr = self.module.run_command('%s' % chkconfig_path, use_unsafe_shell=True)\n            # Check for special cases where stdout does not fit pattern\n            match_any = False\n            for line in stdout.split('\\n'):\n                if p.match(line):\n                    match_any = True\n            if not match_any:\n                p_simple = re.compile(r'(?P<service>.*?)\\s+(?P<rl0>on|off)')\n                match_any = False\n                for line in stdout.split('\\n'):\n                    if p_simple.match(line):\n                        match_any = True\n                if match_any:\n                    # Try extra flags \" -l --allservices\" needed for SLES11\n                    rc, stdout, stderr = self.module.run_command('%s -l --allservices' % chkconfig_path, use_unsafe_shell=True)\n                elif '--list' in stderr:\n                    # Extra flag needed for RHEL5\n                    rc, stdout, stderr = self.module.run_command('%s --list' % chkconfig_path, use_unsafe_shell=True)\n            for line in stdout.split('\\n'):\n                m = p.match(line)\n                if m:\n                    service_name = m.group('service')\n                    service_state = 'stopped'\n                    if m.group('rl3') == 'on':\n                        rc, stdout, stderr = self.module.run_command('%s %s status' % (service_path, service_name), use_unsafe_shell=True)\n                        service_state = rc\n                        if rc in (0,):\n                            service_state = 'running'\n                        # elif rc in (1,3):\n                        else:\n                            if 'root' in stderr or 'permission' in stderr.lower() or 'not in sudoers' in stderr.lower():\n                                self.incomplete_warning = True\n                                continue\n                            else:\n                                service_state = 'stopped'\n                    service_data = {\"name\": service_name, \"state\": service_state, \"source\": \"sysv\"}\n                    services[service_name] = service_data\n        return services\n\n\nclass SystemctlScanService(BaseService):\n\n    def systemd_enabled(self):\n        # Check if init is the systemd command, using comm as cmdline could be symlink\n        try:\n            f = open('/proc/1/comm', 'r')\n        except IOError:\n            # If comm doesn't exist, old kernel, no systemd\n            return False\n        for line in f:\n            if 'systemd' in line:\n                return True\n        return False\n\n    def gather_services(self):\n        services = {}\n        if not self.systemd_enabled():\n            return None\n        systemctl_path = self.module.get_bin_path(\"systemctl\", opt_dirs=[\"/usr/bin\", \"/usr/local/bin\"])\n        if systemctl_path is None:\n            return None\n        rc, stdout, stderr = self.module.run_command(\"%s list-units --no-pager --type service --all\" % systemctl_path, use_unsafe_shell=True)\n        for line in [svc_line for svc_line in stdout.split('\\n') if '.service' in svc_line and 'not-found' not in svc_line]:\n            service_name = line.split()[0]\n            if \"running\" in line:\n                state_val = \"running\"\n            else:\n                if 'failed' in line:\n                    service_name = line.split()[1]\n                state_val = \"stopped\"\n            services[service_name] = {\"name\": service_name, \"state\": state_val, \"source\": \"systemd\"}\n        return services\n\n\ndef main():\n    module = AnsibleModule(argument_spec=dict())\n    service_modules = (ServiceScanService, SystemctlScanService)\n    all_services = {}\n    incomplete_warning = False\n    for svc_module in service_modules:\n        svcmod = svc_module(module)\n        svc = svcmod.gather_services()\n        if svc is not None:\n            all_services.update(svc)\n            if svcmod.incomplete_warning:\n                incomplete_warning = True\n    if len(all_services) == 0:\n        results = dict(skipped=True, msg=\"Failed to find any services. Sometimes this is due to insufficient privileges.\")\n    else:\n        results = dict(ansible_facts=dict(services=all_services))\n        if incomplete_warning:\n            results['msg'] = \"WARNING: Could not find status for all services. Sometimes this is due to insufficient privileges.\"\n    module.exit_json(**results)\n\n\nif __name__ == '__main__':\n    main()\n", "path": "lib/ansible/modules/system/service_facts.py"}]}