Repository: ansible/ansible

Issue:
apache2_module fails to disable module if module name does not match 'apache2ctl -M' output
##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME
apache2_module

##### ANSIBLE VERSION
<!--- Paste verbatim output from “ansible --version” between quotes below -->
```
ansible 2.2.0.0
  config file = /etc/ansible/ansible.cfg
  configured module search path = Default w/o overrides
```

##### CONFIGURATION


##### OS / ENVIRONMENT
Debian 8

##### SUMMARY
<!--- Explain the problem briefly -->

Ansible fails to disable a module with apache2_module if module .load file name does not match the output of `apache2ctl -M`.

For example. Current naming of mod_php for php7.0 and php7.1 have the .load files that are named php7.0.load and php7.1.load. 

Apache2_module uses `apache2ctl -M` to determine if the module is already enabled. `apace2ctl -M` will display the module name as "php7_module" for both php7.0 and php7.1. 

This causes situations, for example with disabling php7.1 module, where ansible does not register the module as enabled and thus will not disable it. It will only report the task result as unchanged. 

Currently in the source, there is a fix for Ubuntu Xenial (Will work with any php7.0 though) that will use the module prefix "php7" if the module to be enabled/disabled is named "php7.0", but this of course does not work for php7.1. 

```
    """
    Work around for Ubuntu Xenial listing php7_module as php7.0
    """
    if name == "php7.0":
        name = "php7"
```

To make a more permanent fix. apache2_module should use `a2query -m` instead of `apache2ctl -M` to determine if a module is already enabled. 

`apache2ctl -M` output (while mod_php 7.1 is enabled): 
```
$ apache2ctl -M
...
php7_module
```

`a2query -m` output (while mod_php 7.1 is enabled): 
```
$ a2query -m php7.1
php7.1 (enabled by site administrator)
```

By using `a2query -m` the module name used is the same when checking if the module is enabled and while actually disabling the module with `a2dismod`

##### STEPS TO REPRODUCE
```yaml
    - name: Disable mod_php 7.1
      apache2_module: name=php7.1 state=absent
```
##### EXPECTED RESULTS
```
TASK [Disable mod_php 7.1] ********************************************
changed: [testnode] => (item=php7.1)
```

##### ACTUAL RESULTS
```
TASK [Disable mod_php 7.1] ********************************************
ok: [testnode] => (item=php7.1)
```


Discussion:
cc @robinro @n0trax
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
@anssite Thanks for this report.

This is a known issue and similar to https://github.com/ansible/ansible-modules-core/issues/5779, https://github.com/ansible/ansible-modules-core/issues/4744

The workaround for php7.0 was already fairly ugly and I'd be happy to have a better/permanent solution. In my view the upstream should make sure the name reported in `apache2ctl -M` is identical to the one used in `a2enmod` and `a2query`. This works well for the vast majority of modules and the only deviations I'm aware of at the moment are php and shib. Please consider reporting this issue to the ubuntu php maintainers, so they can fix this upstream.

Your suggestion to use `a2query` does not work on opensuse. We could make the module distribution-specific and fix the issue on ubuntu/debian only.
@n0trax What's your view on using `a2query` on debian/ubuntu?

I'd be happy to discuss other potential solutions.
needs_contributor
@robinro Did not know that any of a2* tools exists in opensuse. I thought that they are just Debian/Ubuntu specific tools.

Since the module is already using tools that are mostly existing only in Debian/Ubuntu based systems. I would make sense to support fully Debian/Ubuntu and make special cases for those systems that are kinda using the a2* tools but have not implemented them fully. 

An upstream fix for the problem would be nice. But since every distro seems to have their own way to run apache2 and their naming schemes for php are a mess. I don't see it happening anytime soon. At least Debian/Ubuntu seems to be going to the direction with php that every major release now has it's own packaging (php7.0, php7.1, and so on ).

So eventually when php7.1 is released and is included in Debian and Ubuntu, this module will need a rewrite anyway to make it work. 



Resolving patch:
diff --git a/lib/ansible/modules/web_infrastructure/apache2_module.py b/lib/ansible/modules/web_infrastructure/apache2_module.py
--- a/lib/ansible/modules/web_infrastructure/apache2_module.py
+++ b/lib/ansible/modules/web_infrastructure/apache2_module.py
@@ -131,12 +131,6 @@ def _module_is_enabled(module):
 
     result, stdout, stderr = module.run_command("%s -M" % control_binary)
 
-    """
-    Work around for Ubuntu Xenial listing php7_module as php7.0
-    """
-    if name == "php7.0":
-        name = "php7"
-
     if result != 0:
         error_msg = "Error executing %s: %s" % (control_binary, stderr)
         if ignore_configcheck:
@@ -151,6 +145,19 @@ def _module_is_enabled(module):
         else:
             module.fail_json(msg=error_msg)
 
+    """
+    Work around for php modules; php7.x are always listed as php7_module
+    """
+    php_module = re.search(r'^(php\d)\.', name)
+    if php_module:
+        name = php_module.group(1)
+
+    """
+    Workaround for shib2; module is listed as mod_shib
+    """
+    if re.search(r'shib2', name):
+        return bool(re.search(r' mod_shib', stdout))
+
     return bool(re.search(r' ' + name + r'_module', stdout))
 
 def _set_state(module, state):


Test patch: