Fix bug #5328 apache module loading (#19355)

* Fix bug #5328 apache module loading

Currently, the apache2_module module parses apache configs
for correctness when enabling or disabling apache2 modules.

This behavior introduced a conflict condition when transitioning
between mpm modules, such as mpm_worker and mpm_event.

This change accounts for the specific error condition raised
by ``apachectl -M``:
``AH00534: apache2: Configuration error: No MPM loaded.``
When loading or unloading a module with a name that contains 'mpm_',
apache2_module will ignore the error raised by apachectl if stderr
contains 'AH00534'.

Fixes #5328

* Add AH00534 warning

* Added changes from PR #5629

* Modified ignore_configcheck behavior
This commit is contained in:
Michael Gugino 2016-12-14 16:18:19 -05:00 committed by Matt Davis
parent 0b440a9289
commit 250f862573

View file

@ -24,7 +24,10 @@ DOCUMENTATION = '''
---
module: apache2_module
version_added: 1.6
author: "Christian Berendt (@berendt)"
author:
- Christian Berendt (@berendt)
- Ralf Hertel (@n0trax)
- Robin Roth (@robinro)
short_description: enables/disables a module of the Apache2 webserver
description:
- Enables or disables a specified module of the Apache2 webserver.
@ -37,15 +40,20 @@ options:
description:
- force disabling of default modules and override Debian warnings
required: false
choices: ['yes', 'no']
default: no
choices: ['True', 'False']
default: False
version_added: "2.1"
state:
description:
- indicate the desired state of the resource
choices: ['present', 'absent']
default: present
ignore_configcheck:
description:
- Ignore configuration checks about inconsistent module configuration. Especially for mpm_* modules.
choices: ['True', 'False']
default: False
version_added: "2.3"
requirements: ["a2enmod","a2dismod"]
'''
@ -54,11 +62,43 @@ EXAMPLES = '''
- apache2_module:
state: present
name: wsgi
# disables the Apache2 module "wsgi"
- apache2_module:
state: absent
name: wsgi
# disable default modules for Debian
- apache2_module:
state: absent
name: autoindex
force: True
# disable mpm_worker and ignore warnings about missing mpm module
- apache2_module:
state: absent
name: mpm_worker
ignore_configcheck: True
'''
RETURN = '''
result:
description: message about action taken
returned: always
type: string
warnings:
description: list of warning messages
returned: when needed
type: list
rc:
description: return code of underlying command
returned: failed
type: int
stdout:
description: stdout of underlying command
returned: failed
type: string
stderr:
description: stderr of underlying command
returned: failed
type: string
'''
import re
@ -80,11 +120,14 @@ def _get_ctl_binary(module):
return ctl_binary
module.fail_json(
msg="None of httpd, apachectl or apach2ctl found. At least one apache control binary is necessary.")
msg="Neither of apache2ctl nor apachctl found."
" At least one apache control binary is necessary."
)
def _module_is_enabled(module):
control_binary = _get_ctl_binary(module)
name = module.params['name']
ignore_configcheck = module.params['ignore_configcheck']
result, stdout, stderr = module.run_command("%s -M" % control_binary)
@ -95,12 +138,20 @@ def _module_is_enabled(module):
name = "php7"
if result != 0:
module.fail_json(msg="Error executing %s: %s" % (control_binary, stderr))
if re.search(r' ' + name + r'_module', stdout):
return True
error_msg = "Error executing %s: %s" % (control_binary, stderr)
if ignore_configcheck:
if 'AH00534' in stderr and 'mpm_' in name:
module.warnings.append(
"No MPM module loaded! apache2 reload AND other module actions"
" will fail if no MPM module is loaded immediatly."
)
else:
module.warnings.append(error_msg)
return False
else:
module.fail_json(msg=error_msg)
return bool(re.search(r' ' + name + r'_module', stdout))
def _set_state(module, state):
name = module.params['name']
@ -113,7 +164,9 @@ def _set_state(module, state):
if _module_is_enabled(module) != want_enabled:
if module.check_mode:
module.exit_json(changed = True, result = success_msg)
module.exit_json(changed=True,
result=success_msg,
warnings=module.warnings)
a2mod_binary = module.get_bin_path(a2mod_binary)
if a2mod_binary is None:
@ -126,22 +179,32 @@ def _set_state(module, state):
result, stdout, stderr = module.run_command("%s %s" % (a2mod_binary, name))
if _module_is_enabled(module) == want_enabled:
module.exit_json(changed = True, result = success_msg)
module.exit_json(changed=True,
result=success_msg,
warnings=module.warnings)
else:
module.fail_json(msg="Failed to set module %s to %s: %s" % (name, state_string, stdout), rc=result, stdout=stdout, stderr=stderr)
module.fail_json(msg="Failed to set module %s to %s: %s" % (name, state_string, stdout),
rc=result,
stdout=stdout,
stderr=stderr)
else:
module.exit_json(changed = False, result = success_msg)
module.exit_json(changed=False,
result=success_msg,
warnings=module.warnings)
def main():
module = AnsibleModule(
argument_spec = dict(
name = dict(required=True),
force = dict(required=False, type='bool', default=False),
state = dict(default='present', choices=['absent', 'present'])
state = dict(default='present', choices=['absent', 'present']),
ignore_configcheck=dict(required=False, type='bool', default=False),
),
supports_check_mode = True,
)
module.warnings = []
name = module.params['name']
if name == 'cgi' and _run_threaded(module):
module.fail_json(msg="Your MPM seems to be threaded. No automatic actions on module %s possible." % name)