We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
apache2_module: Relies on a2enmod / misleading error on CentOS
### Summary

The ansible `apache2_module` module relies on Debian-style (also sometimes called "Debianisms") binaries as `a2enmod` for managing `httpd`/`apache` modules. On CentOS this is not the case as this distribution doesn't use these binaries. 

On CentOS this module emits a misleading error:
````
None not found. Perhaps this system does not use None to manage apache
````

Responsible code:
https://github.com/ansible-collections/community.general/blob/da11a98cb734e99cc57f4ae6ec09d9199875c39b/plugins/modules/web_infrastructure/apache2_module.py#L207

### Issue Type

Bug Report

### Component Name

apache2_module

### Ansible Version

```console (paste below)
$ ansible --version

ansible 2.9.10
  config file = None
  configured module search path = ['/home/build/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/local/lib/python3.8/dist-packages/ansible
  executable location = /usr/local/bin/ansible
  python version = 3.8.10 (default, Jun  2 2021, 10:49:15) [GCC 9.4.0]
```


### Configuration

```console (paste below)
$ ansible-config dump --only-changed
(Empty)
```


### OS / Environment

WSL 2/Ubuntu 20.04 LTS (ansible client); CentOS 7.x (ansible target).

### Steps to Reproduce

<!--- Paste example playbooks or commands between quotes below -->
```yaml (paste below)
    - name: Enable mod_substitute
      apache2_module:
        name:  mod_substitute
        state: present
```


### Expected Results

`apache_module` ansible module manages the modules without errors.

### Actual Results

```console (paste below)
None not found. Perhaps this system does not use None to manage apache
```


### Code of Conduct

- [X] I agree to follow the Ansible Code of Conduct

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `plugins/modules/web_infrastructure/apache2_module.py`
Content:
```
1 #!/usr/bin/python
2 # -*- coding: utf-8 -*-
3 
4 # (c) 2013-2014, Christian Berendt <berendt@b1-systems.de>
5 # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
6 
7 from __future__ import absolute_import, division, print_function
8 __metaclass__ = type
9 
10 
11 DOCUMENTATION = '''
12 ---
13 module: apache2_module
14 author:
15     - Christian Berendt (@berendt)
16     - Ralf Hertel (@n0trax)
17     - Robin Roth (@robinro)
18 short_description: Enables/disables a module of the Apache2 webserver.
19 description:
20    - Enables or disables a specified module of the Apache2 webserver.
21 options:
22    name:
23      type: str
24      description:
25         - Name of the module to enable/disable as given to C(a2enmod/a2dismod).
26      required: true
27    identifier:
28      type: str
29      description:
30          - Identifier of the module as listed by C(apache2ctl -M).
31            This is optional and usually determined automatically by the common convention of
32            appending C(_module) to I(name) as well as custom exception for popular modules.
33      required: False
34    force:
35      description:
36         - Force disabling of default modules and override Debian warnings.
37      required: false
38      type: bool
39      default: False
40    state:
41      type: str
42      description:
43         - Desired state of the module.
44      choices: ['present', 'absent']
45      default: present
46    ignore_configcheck:
47      description:
48         - Ignore configuration checks about inconsistent module configuration. Especially for mpm_* modules.
49      type: bool
50      default: False
51 requirements: ["a2enmod","a2dismod"]
52 notes:
53   - This does not work on RedHat-based distributions. It does work on Debian- and SuSE-based distributions.
54     Whether it works on others depend on whether the C(a2enmod) and C(a2dismod) tools are available or not.
55 '''
56 
57 EXAMPLES = '''
58 - name: Enable the Apache2 module wsgi
59   community.general.apache2_module:
60     state: present
61     name: wsgi
62 
63 - name: Disables the Apache2 module wsgi
64   community.general.apache2_module:
65     state: absent
66     name: wsgi
67 
68 - name: Disable default modules for Debian
69   community.general.apache2_module:
70     state: absent
71     name: autoindex
72     force: True
73 
74 - name: Disable mpm_worker and ignore warnings about missing mpm module
75   community.general.apache2_module:
76     state: absent
77     name: mpm_worker
78     ignore_configcheck: True
79 
80 - name: Enable dump_io module, which is identified as dumpio_module inside apache2
81   community.general.apache2_module:
82     state: present
83     name: dump_io
84     identifier: dumpio_module
85 '''
86 
87 RETURN = '''
88 result:
89     description: message about action taken
90     returned: always
91     type: str
92 warnings:
93     description: list of warning messages
94     returned: when needed
95     type: list
96 rc:
97     description: return code of underlying command
98     returned: failed
99     type: int
100 stdout:
101     description: stdout of underlying command
102     returned: failed
103     type: str
104 stderr:
105     description: stderr of underlying command
106     returned: failed
107     type: str
108 '''
109 
110 import re
111 
112 # import module snippets
113 from ansible.module_utils.basic import AnsibleModule
114 
115 _re_threaded = re.compile(r'threaded: *yes')
116 
117 
118 def _run_threaded(module):
119     control_binary = _get_ctl_binary(module)
120     result, stdout, stderr = module.run_command([control_binary, "-V"])
121 
122     return bool(_re_threaded.search(stdout))
123 
124 
125 def _get_ctl_binary(module):
126     for command in ['apache2ctl', 'apachectl']:
127         ctl_binary = module.get_bin_path(command)
128         if ctl_binary is not None:
129             return ctl_binary
130 
131     module.fail_json(msg="Neither of apache2ctl nor apachctl found. At least one apache control binary is necessary.")
132 
133 
134 def _module_is_enabled(module):
135     control_binary = _get_ctl_binary(module)
136     result, stdout, stderr = module.run_command([control_binary, "-M"])
137 
138     if result != 0:
139         error_msg = "Error executing %s: %s" % (control_binary, stderr)
140         if module.params['ignore_configcheck']:
141             if 'AH00534' in stderr and 'mpm_' in module.params['name']:
142                 module.warnings.append(
143                     "No MPM module loaded! apache2 reload AND other module actions"
144                     " will fail if no MPM module is loaded immediately."
145                 )
146             else:
147                 module.warnings.append(error_msg)
148             return False
149         else:
150             module.fail_json(msg=error_msg)
151 
152     searchstring = ' ' + module.params['identifier']
153     return searchstring in stdout
154 
155 
156 def create_apache_identifier(name):
157     """
158     By convention if a module is loaded via name, it appears in apache2ctl -M as
159     name_module.
160 
161     Some modules don't follow this convention and we use replacements for those."""
162 
163     # a2enmod name replacement to apache2ctl -M names
164     text_workarounds = [
165         ('shib', 'mod_shib'),
166         ('shib2', 'mod_shib'),
167         ('evasive', 'evasive20_module'),
168     ]
169 
170     # re expressions to extract subparts of names
171     re_workarounds = [
172         ('php', re.compile(r'^(php\d)\.')),
173     ]
174 
175     for a2enmod_spelling, module_name in text_workarounds:
176         if a2enmod_spelling in name:
177             return module_name
178 
179     for search, reexpr in re_workarounds:
180         if search in name:
181             try:
182                 rematch = reexpr.search(name)
183                 return rematch.group(1) + '_module'
184             except AttributeError:
185                 pass
186 
187     return name + '_module'
188 
189 
190 def _set_state(module, state):
191     name = module.params['name']
192     force = module.params['force']
193 
194     want_enabled = state == 'present'
195     state_string = {'present': 'enabled', 'absent': 'disabled'}[state]
196     a2mod_binary = {'present': 'a2enmod', 'absent': 'a2dismod'}[state]
197     success_msg = "Module %s %s" % (name, state_string)
198 
199     if _module_is_enabled(module) != want_enabled:
200         if module.check_mode:
201             module.exit_json(changed=True,
202                              result=success_msg,
203                              warnings=module.warnings)
204 
205         a2mod_binary = [module.get_bin_path(a2mod_binary)]
206         if a2mod_binary is None:
207             module.fail_json(msg="%s not found. Perhaps this system does not use %s to manage apache" % (a2mod_binary, a2mod_binary))
208 
209         if not want_enabled and force:
210             # force exists only for a2dismod on debian
211             a2mod_binary.append('-f')
212 
213         result, stdout, stderr = module.run_command(a2mod_binary + [name])
214 
215         if _module_is_enabled(module) == want_enabled:
216             module.exit_json(changed=True,
217                              result=success_msg,
218                              warnings=module.warnings)
219         else:
220             msg = (
221                 'Failed to set module {name} to {state}:\n'
222                 '{stdout}\n'
223                 'Maybe the module identifier ({identifier}) was guessed incorrectly.'
224                 'Consider setting the "identifier" option.'
225             ).format(
226                 name=name,
227                 state=state_string,
228                 stdout=stdout,
229                 identifier=module.params['identifier']
230             )
231             module.fail_json(msg=msg,
232                              rc=result,
233                              stdout=stdout,
234                              stderr=stderr)
235     else:
236         module.exit_json(changed=False,
237                          result=success_msg,
238                          warnings=module.warnings)
239 
240 
241 def main():
242     module = AnsibleModule(
243         argument_spec=dict(
244             name=dict(required=True),
245             identifier=dict(type='str'),
246             force=dict(type='bool', default=False),
247             state=dict(default='present', choices=['absent', 'present']),
248             ignore_configcheck=dict(type='bool', default=False),
249         ),
250         supports_check_mode=True,
251     )
252 
253     module.warnings = []
254 
255     name = module.params['name']
256     if name == 'cgi' and _run_threaded(module):
257         module.fail_json(msg="Your MPM seems to be threaded. No automatic actions on module cgi possible.")
258 
259     if not module.params['identifier']:
260         module.params['identifier'] = create_apache_identifier(module.params['name'])
261 
262     if module.params['state'] in ['present', 'absent']:
263         _set_state(module, module.params['state'])
264 
265 
266 if __name__ == '__main__':
267     main()
268
```
--- 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/plugins/modules/web_infrastructure/apache2_module.py b/plugins/modules/web_infrastructure/apache2_module.py
--- a/plugins/modules/web_infrastructure/apache2_module.py
+++ b/plugins/modules/web_infrastructure/apache2_module.py
@@ -202,15 +202,17 @@
                              result=success_msg,
                              warnings=module.warnings)
 
-        a2mod_binary = [module.get_bin_path(a2mod_binary)]
-        if a2mod_binary is None:
+        a2mod_binary_path = module.get_bin_path(a2mod_binary)
+        if a2mod_binary_path is None:
             module.fail_json(msg="%s not found. Perhaps this system does not use %s to manage apache" % (a2mod_binary, a2mod_binary))
 
+        a2mod_binary_cmd = [a2mod_binary_path]
+
         if not want_enabled and force:
             # force exists only for a2dismod on debian
-            a2mod_binary.append('-f')
+            a2mod_binary_cmd.append('-f')
 
-        result, stdout, stderr = module.run_command(a2mod_binary + [name])
+        result, stdout, stderr = module.run_command(a2mod_binary_cmd + [name])
 
         if _module_is_enabled(module) == want_enabled:
             module.exit_json(changed=True,

{"golden_diff": "diff --git a/plugins/modules/web_infrastructure/apache2_module.py b/plugins/modules/web_infrastructure/apache2_module.py\n--- a/plugins/modules/web_infrastructure/apache2_module.py\n+++ b/plugins/modules/web_infrastructure/apache2_module.py\n@@ -202,15 +202,17 @@\n                              result=success_msg,\n                              warnings=module.warnings)\n \n-        a2mod_binary = [module.get_bin_path(a2mod_binary)]\n-        if a2mod_binary is None:\n+        a2mod_binary_path = module.get_bin_path(a2mod_binary)\n+        if a2mod_binary_path is None:\n             module.fail_json(msg=\"%s not found. Perhaps this system does not use %s to manage apache\" % (a2mod_binary, a2mod_binary))\n \n+        a2mod_binary_cmd = [a2mod_binary_path]\n+\n         if not want_enabled and force:\n             # force exists only for a2dismod on debian\n-            a2mod_binary.append('-f')\n+            a2mod_binary_cmd.append('-f')\n \n-        result, stdout, stderr = module.run_command(a2mod_binary + [name])\n+        result, stdout, stderr = module.run_command(a2mod_binary_cmd + [name])\n \n         if _module_is_enabled(module) == want_enabled:\n             module.exit_json(changed=True,\n", "issue": "apache2_module: Relies on a2enmod / misleading error on CentOS\n### Summary\n\nThe ansible `apache2_module` module relies on Debian-style (also sometimes called \"Debianisms\") binaries as `a2enmod` for managing `httpd`/`apache` modules. On CentOS this is not the case as this distribution doesn't use these binaries. \r\n\r\nOn CentOS this module emits a misleading error:\r\n````\r\nNone not found. Perhaps this system does not use None to manage apache\r\n````\r\n\r\nResponsible code:\r\nhttps://github.com/ansible-collections/community.general/blob/da11a98cb734e99cc57f4ae6ec09d9199875c39b/plugins/modules/web_infrastructure/apache2_module.py#L207\n\n### Issue Type\n\nBug Report\n\n### Component Name\n\napache2_module\n\n### Ansible Version\n\n```console (paste below)\r\n$ ansible --version\r\n\r\nansible 2.9.10\r\n  config file = None\r\n  configured module search path = ['/home/build/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']\r\n  ansible python module location = /usr/local/lib/python3.8/dist-packages/ansible\r\n  executable location = /usr/local/bin/ansible\r\n  python version = 3.8.10 (default, Jun  2 2021, 10:49:15) [GCC 9.4.0]\r\n```\r\n\n\n### Configuration\n\n```console (paste below)\r\n$ ansible-config dump --only-changed\r\n(Empty)\r\n```\r\n\n\n### OS / Environment\n\nWSL 2/Ubuntu 20.04 LTS (ansible client); CentOS 7.x (ansible target).\n\n### Steps to Reproduce\n\n<!--- Paste example playbooks or commands between quotes below -->\r\n```yaml (paste below)\r\n    - name: Enable mod_substitute\r\n      apache2_module:\r\n        name:  mod_substitute\r\n        state: present\r\n```\r\n\n\n### Expected Results\n\n`apache_module` ansible module manages the modules without errors.\n\n### Actual Results\n\n```console (paste below)\r\nNone not found. Perhaps this system does not use None to manage apache\r\n```\r\n\n\n### Code of Conduct\n\n- [X] I agree to follow the Ansible Code of Conduct\n", "before_files": [{"content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n\n# (c) 2013-2014, Christian Berendt <berendt@b1-systems.de>\n# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nDOCUMENTATION = '''\n---\nmodule: apache2_module\nauthor:\n    - Christian Berendt (@berendt)\n    - Ralf Hertel (@n0trax)\n    - Robin Roth (@robinro)\nshort_description: Enables/disables a module of the Apache2 webserver.\ndescription:\n   - Enables or disables a specified module of the Apache2 webserver.\noptions:\n   name:\n     type: str\n     description:\n        - Name of the module to enable/disable as given to C(a2enmod/a2dismod).\n     required: true\n   identifier:\n     type: str\n     description:\n         - Identifier of the module as listed by C(apache2ctl -M).\n           This is optional and usually determined automatically by the common convention of\n           appending C(_module) to I(name) as well as custom exception for popular modules.\n     required: False\n   force:\n     description:\n        - Force disabling of default modules and override Debian warnings.\n     required: false\n     type: bool\n     default: False\n   state:\n     type: str\n     description:\n        - Desired state of the module.\n     choices: ['present', 'absent']\n     default: present\n   ignore_configcheck:\n     description:\n        - Ignore configuration checks about inconsistent module configuration. Especially for mpm_* modules.\n     type: bool\n     default: False\nrequirements: [\"a2enmod\",\"a2dismod\"]\nnotes:\n  - This does not work on RedHat-based distributions. It does work on Debian- and SuSE-based distributions.\n    Whether it works on others depend on whether the C(a2enmod) and C(a2dismod) tools are available or not.\n'''\n\nEXAMPLES = '''\n- name: Enable the Apache2 module wsgi\n  community.general.apache2_module:\n    state: present\n    name: wsgi\n\n- name: Disables the Apache2 module wsgi\n  community.general.apache2_module:\n    state: absent\n    name: wsgi\n\n- name: Disable default modules for Debian\n  community.general.apache2_module:\n    state: absent\n    name: autoindex\n    force: True\n\n- name: Disable mpm_worker and ignore warnings about missing mpm module\n  community.general.apache2_module:\n    state: absent\n    name: mpm_worker\n    ignore_configcheck: True\n\n- name: Enable dump_io module, which is identified as dumpio_module inside apache2\n  community.general.apache2_module:\n    state: present\n    name: dump_io\n    identifier: dumpio_module\n'''\n\nRETURN = '''\nresult:\n    description: message about action taken\n    returned: always\n    type: str\nwarnings:\n    description: list of warning messages\n    returned: when needed\n    type: list\nrc:\n    description: return code of underlying command\n    returned: failed\n    type: int\nstdout:\n    description: stdout of underlying command\n    returned: failed\n    type: str\nstderr:\n    description: stderr of underlying command\n    returned: failed\n    type: str\n'''\n\nimport re\n\n# import module snippets\nfrom ansible.module_utils.basic import AnsibleModule\n\n_re_threaded = re.compile(r'threaded: *yes')\n\n\ndef _run_threaded(module):\n    control_binary = _get_ctl_binary(module)\n    result, stdout, stderr = module.run_command([control_binary, \"-V\"])\n\n    return bool(_re_threaded.search(stdout))\n\n\ndef _get_ctl_binary(module):\n    for command in ['apache2ctl', 'apachectl']:\n        ctl_binary = module.get_bin_path(command)\n        if ctl_binary is not None:\n            return ctl_binary\n\n    module.fail_json(msg=\"Neither of apache2ctl nor apachctl found. At least one apache control binary is necessary.\")\n\n\ndef _module_is_enabled(module):\n    control_binary = _get_ctl_binary(module)\n    result, stdout, stderr = module.run_command([control_binary, \"-M\"])\n\n    if result != 0:\n        error_msg = \"Error executing %s: %s\" % (control_binary, stderr)\n        if module.params['ignore_configcheck']:\n            if 'AH00534' in stderr and 'mpm_' in module.params['name']:\n                module.warnings.append(\n                    \"No MPM module loaded! apache2 reload AND other module actions\"\n                    \" will fail if no MPM module is loaded immediately.\"\n                )\n            else:\n                module.warnings.append(error_msg)\n            return False\n        else:\n            module.fail_json(msg=error_msg)\n\n    searchstring = ' ' + module.params['identifier']\n    return searchstring in stdout\n\n\ndef create_apache_identifier(name):\n    \"\"\"\n    By convention if a module is loaded via name, it appears in apache2ctl -M as\n    name_module.\n\n    Some modules don't follow this convention and we use replacements for those.\"\"\"\n\n    # a2enmod name replacement to apache2ctl -M names\n    text_workarounds = [\n        ('shib', 'mod_shib'),\n        ('shib2', 'mod_shib'),\n        ('evasive', 'evasive20_module'),\n    ]\n\n    # re expressions to extract subparts of names\n    re_workarounds = [\n        ('php', re.compile(r'^(php\\d)\\.')),\n    ]\n\n    for a2enmod_spelling, module_name in text_workarounds:\n        if a2enmod_spelling in name:\n            return module_name\n\n    for search, reexpr in re_workarounds:\n        if search in name:\n            try:\n                rematch = reexpr.search(name)\n                return rematch.group(1) + '_module'\n            except AttributeError:\n                pass\n\n    return name + '_module'\n\n\ndef _set_state(module, state):\n    name = module.params['name']\n    force = module.params['force']\n\n    want_enabled = state == 'present'\n    state_string = {'present': 'enabled', 'absent': 'disabled'}[state]\n    a2mod_binary = {'present': 'a2enmod', 'absent': 'a2dismod'}[state]\n    success_msg = \"Module %s %s\" % (name, state_string)\n\n    if _module_is_enabled(module) != want_enabled:\n        if module.check_mode:\n            module.exit_json(changed=True,\n                             result=success_msg,\n                             warnings=module.warnings)\n\n        a2mod_binary = [module.get_bin_path(a2mod_binary)]\n        if a2mod_binary is None:\n            module.fail_json(msg=\"%s not found. Perhaps this system does not use %s to manage apache\" % (a2mod_binary, a2mod_binary))\n\n        if not want_enabled and force:\n            # force exists only for a2dismod on debian\n            a2mod_binary.append('-f')\n\n        result, stdout, stderr = module.run_command(a2mod_binary + [name])\n\n        if _module_is_enabled(module) == want_enabled:\n            module.exit_json(changed=True,\n                             result=success_msg,\n                             warnings=module.warnings)\n        else:\n            msg = (\n                'Failed to set module {name} to {state}:\\n'\n                '{stdout}\\n'\n                'Maybe the module identifier ({identifier}) was guessed incorrectly.'\n                'Consider setting the \"identifier\" option.'\n            ).format(\n                name=name,\n                state=state_string,\n                stdout=stdout,\n                identifier=module.params['identifier']\n            )\n            module.fail_json(msg=msg,\n                             rc=result,\n                             stdout=stdout,\n                             stderr=stderr)\n    else:\n        module.exit_json(changed=False,\n                         result=success_msg,\n                         warnings=module.warnings)\n\n\ndef main():\n    module = AnsibleModule(\n        argument_spec=dict(\n            name=dict(required=True),\n            identifier=dict(type='str'),\n            force=dict(type='bool', default=False),\n            state=dict(default='present', choices=['absent', 'present']),\n            ignore_configcheck=dict(type='bool', default=False),\n        ),\n        supports_check_mode=True,\n    )\n\n    module.warnings = []\n\n    name = module.params['name']\n    if name == 'cgi' and _run_threaded(module):\n        module.fail_json(msg=\"Your MPM seems to be threaded. No automatic actions on module cgi possible.\")\n\n    if not module.params['identifier']:\n        module.params['identifier'] = create_apache_identifier(module.params['name'])\n\n    if module.params['state'] in ['present', 'absent']:\n        _set_state(module, module.params['state'])\n\n\nif __name__ == '__main__':\n    main()\n", "path": "plugins/modules/web_infrastructure/apache2_module.py"}], "after_files": [{"content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n\n# (c) 2013-2014, Christian Berendt <berendt@b1-systems.de>\n# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nDOCUMENTATION = '''\n---\nmodule: apache2_module\nauthor:\n    - Christian Berendt (@berendt)\n    - Ralf Hertel (@n0trax)\n    - Robin Roth (@robinro)\nshort_description: Enables/disables a module of the Apache2 webserver.\ndescription:\n   - Enables or disables a specified module of the Apache2 webserver.\noptions:\n   name:\n     type: str\n     description:\n        - Name of the module to enable/disable as given to C(a2enmod/a2dismod).\n     required: true\n   identifier:\n     type: str\n     description:\n         - Identifier of the module as listed by C(apache2ctl -M).\n           This is optional and usually determined automatically by the common convention of\n           appending C(_module) to I(name) as well as custom exception for popular modules.\n     required: False\n   force:\n     description:\n        - Force disabling of default modules and override Debian warnings.\n     required: false\n     type: bool\n     default: False\n   state:\n     type: str\n     description:\n        - Desired state of the module.\n     choices: ['present', 'absent']\n     default: present\n   ignore_configcheck:\n     description:\n        - Ignore configuration checks about inconsistent module configuration. Especially for mpm_* modules.\n     type: bool\n     default: False\nrequirements: [\"a2enmod\",\"a2dismod\"]\nnotes:\n  - This does not work on RedHat-based distributions. It does work on Debian- and SuSE-based distributions.\n    Whether it works on others depend on whether the C(a2enmod) and C(a2dismod) tools are available or not.\n'''\n\nEXAMPLES = '''\n- name: Enable the Apache2 module wsgi\n  community.general.apache2_module:\n    state: present\n    name: wsgi\n\n- name: Disables the Apache2 module wsgi\n  community.general.apache2_module:\n    state: absent\n    name: wsgi\n\n- name: Disable default modules for Debian\n  community.general.apache2_module:\n    state: absent\n    name: autoindex\n    force: True\n\n- name: Disable mpm_worker and ignore warnings about missing mpm module\n  community.general.apache2_module:\n    state: absent\n    name: mpm_worker\n    ignore_configcheck: True\n\n- name: Enable dump_io module, which is identified as dumpio_module inside apache2\n  community.general.apache2_module:\n    state: present\n    name: dump_io\n    identifier: dumpio_module\n'''\n\nRETURN = '''\nresult:\n    description: message about action taken\n    returned: always\n    type: str\nwarnings:\n    description: list of warning messages\n    returned: when needed\n    type: list\nrc:\n    description: return code of underlying command\n    returned: failed\n    type: int\nstdout:\n    description: stdout of underlying command\n    returned: failed\n    type: str\nstderr:\n    description: stderr of underlying command\n    returned: failed\n    type: str\n'''\n\nimport re\n\n# import module snippets\nfrom ansible.module_utils.basic import AnsibleModule\n\n_re_threaded = re.compile(r'threaded: *yes')\n\n\ndef _run_threaded(module):\n    control_binary = _get_ctl_binary(module)\n    result, stdout, stderr = module.run_command([control_binary, \"-V\"])\n\n    return bool(_re_threaded.search(stdout))\n\n\ndef _get_ctl_binary(module):\n    for command in ['apache2ctl', 'apachectl']:\n        ctl_binary = module.get_bin_path(command)\n        if ctl_binary is not None:\n            return ctl_binary\n\n    module.fail_json(msg=\"Neither of apache2ctl nor apachctl found. At least one apache control binary is necessary.\")\n\n\ndef _module_is_enabled(module):\n    control_binary = _get_ctl_binary(module)\n    result, stdout, stderr = module.run_command([control_binary, \"-M\"])\n\n    if result != 0:\n        error_msg = \"Error executing %s: %s\" % (control_binary, stderr)\n        if module.params['ignore_configcheck']:\n            if 'AH00534' in stderr and 'mpm_' in module.params['name']:\n                module.warnings.append(\n                    \"No MPM module loaded! apache2 reload AND other module actions\"\n                    \" will fail if no MPM module is loaded immediately.\"\n                )\n            else:\n                module.warnings.append(error_msg)\n            return False\n        else:\n            module.fail_json(msg=error_msg)\n\n    searchstring = ' ' + module.params['identifier']\n    return searchstring in stdout\n\n\ndef create_apache_identifier(name):\n    \"\"\"\n    By convention if a module is loaded via name, it appears in apache2ctl -M as\n    name_module.\n\n    Some modules don't follow this convention and we use replacements for those.\"\"\"\n\n    # a2enmod name replacement to apache2ctl -M names\n    text_workarounds = [\n        ('shib', 'mod_shib'),\n        ('shib2', 'mod_shib'),\n        ('evasive', 'evasive20_module'),\n    ]\n\n    # re expressions to extract subparts of names\n    re_workarounds = [\n        ('php', re.compile(r'^(php\\d)\\.')),\n    ]\n\n    for a2enmod_spelling, module_name in text_workarounds:\n        if a2enmod_spelling in name:\n            return module_name\n\n    for search, reexpr in re_workarounds:\n        if search in name:\n            try:\n                rematch = reexpr.search(name)\n                return rematch.group(1) + '_module'\n            except AttributeError:\n                pass\n\n    return name + '_module'\n\n\ndef _set_state(module, state):\n    name = module.params['name']\n    force = module.params['force']\n\n    want_enabled = state == 'present'\n    state_string = {'present': 'enabled', 'absent': 'disabled'}[state]\n    a2mod_binary = {'present': 'a2enmod', 'absent': 'a2dismod'}[state]\n    success_msg = \"Module %s %s\" % (name, state_string)\n\n    if _module_is_enabled(module) != want_enabled:\n        if module.check_mode:\n            module.exit_json(changed=True,\n                             result=success_msg,\n                             warnings=module.warnings)\n\n        a2mod_binary_path = module.get_bin_path(a2mod_binary)\n        if a2mod_binary_path is None:\n            module.fail_json(msg=\"%s not found. Perhaps this system does not use %s to manage apache\" % (a2mod_binary, a2mod_binary))\n\n        a2mod_binary_cmd = [a2mod_binary_path]\n\n        if not want_enabled and force:\n            # force exists only for a2dismod on debian\n            a2mod_binary_cmd.append('-f')\n\n        result, stdout, stderr = module.run_command(a2mod_binary_cmd + [name])\n\n        if _module_is_enabled(module) == want_enabled:\n            module.exit_json(changed=True,\n                             result=success_msg,\n                             warnings=module.warnings)\n        else:\n            msg = (\n                'Failed to set module {name} to {state}:\\n'\n                '{stdout}\\n'\n                'Maybe the module identifier ({identifier}) was guessed incorrectly.'\n                'Consider setting the \"identifier\" option.'\n            ).format(\n                name=name,\n                state=state_string,\n                stdout=stdout,\n                identifier=module.params['identifier']\n            )\n            module.fail_json(msg=msg,\n                             rc=result,\n                             stdout=stdout,\n                             stderr=stderr)\n    else:\n        module.exit_json(changed=False,\n                         result=success_msg,\n                         warnings=module.warnings)\n\n\ndef main():\n    module = AnsibleModule(\n        argument_spec=dict(\n            name=dict(required=True),\n            identifier=dict(type='str'),\n            force=dict(type='bool', default=False),\n            state=dict(default='present', choices=['absent', 'present']),\n            ignore_configcheck=dict(type='bool', default=False),\n        ),\n        supports_check_mode=True,\n    )\n\n    module.warnings = []\n\n    name = module.params['name']\n    if name == 'cgi' and _run_threaded(module):\n        module.fail_json(msg=\"Your MPM seems to be threaded. No automatic actions on module cgi possible.\")\n\n    if not module.params['identifier']:\n        module.params['identifier'] = create_apache_identifier(module.params['name'])\n\n    if module.params['state'] in ['present', 'absent']:\n        _set_state(module, module.params['state'])\n\n\nif __name__ == '__main__':\n    main()\n", "path": "plugins/modules/web_infrastructure/apache2_module.py"}]}