Repository: certbot/certbot

Issue:
KeyError handle_modules with 0.27.0 on openSUSE
## My operating system is (include version):

openSUSE Leap 42.1

## I installed Certbot with (certbot-auto, OS package manager, pip, etc):

certbot-auto

## I ran this command and it produced this output:

````
kevdev36:~ # certbot-auto --version
Upgrading certbot-auto 0.26.1 to 0.27.0...
Replacing certbot-auto...
Creating virtual environment...
Installing Python packages...
Installation succeeded.
An unexpected error occurred:
KeyError: 'handle_modules'
Please see the logfile '/tmp/tmpMAZJox' for more details.
````

## Certbot's behavior differed from what I expected because:

It did not print the version.

## Here is a Certbot log showing the issue (if available):

/tmp/tmpMAZJox

````
2018-09-06 09:59:58,652:DEBUG:certbot.main:certbot version: 0.27.0
2018-09-06 09:59:58,652:DEBUG:certbot.main:Arguments: ['--version']
2018-09-06 09:59:58,653:DEBUG:certbot.main:Discovered plugins: PluginsRegistry(PluginEntryPoint#apache,PluginEntryPoint#manual,PluginEntryPoint#nginx,PluginEntryPoint#null,PluginEntryPoint#standalone,PluginEntryPoint#webroot)
2018-09-06 09:59:58,660:DEBUG:certbot.log:Exiting abnormally:
Traceback (most recent call last):
  File "/opt/eff.org/certbot/venv/bin/letsencrypt", line 11, in <module>
    sys.exit(main())
  File "/opt/eff.org/certbot/venv/lib/python2.7/site-packages/certbot/main.py", line 1345, in main
    args = cli.prepare_and_parse_args(plugins, cli_args)
  File "/opt/eff.org/certbot/venv/lib/python2.7/site-packages/certbot/cli.py", line 1243, in prepare_and_parse_args
    _plugins_parsing(helpful, plugins)
  File "/opt/eff.org/certbot/venv/lib/python2.7/site-packages/certbot/cli.py", line 1458, in _plugins_parsing
    helpful.add_plugin_args(plugins)
  File "/opt/eff.org/certbot/venv/lib/python2.7/site-packages/certbot/cli.py", line 840, in add_plugin_args
    plugin_ep.plugin_cls.inject_parser_options(parser_or_group, name)
  File "/opt/eff.org/certbot/venv/lib/python2.7/site-packages/certbot/plugins/common.py", line 81, in inject_parser_options
    return cls.add_parser_arguments(add)
  File "/opt/eff.org/certbot/venv/lib/python2.7/site-packages/certbot_apache/configurator.py", line 159, in add_parser_arguments
    add("handle-modules", default=cls.OS_DEFAULTS["handle_modules"],
KeyError: 'handle_modules'
2018-09-06 09:59:58,660:ERROR:certbot.log:An unexpected error occurred:
````

## Workaround

Downgrade to 0.26.1 and use `certbot-auto` with `--no-self-upgrade`.

````
kevdev36:~ # wget https://raw.githubusercontent.com/certbot/certbot/v0.26.1/certbot-auto
kevdev36:~ # chmod +x certbot-auto
kevdev36:~ # /opt/eff.org/certbot/venv/bin/pip install certbot==0.26.1 certbot-apache==0.26.1 certbot-nginx==0.26.1
kevdev36:~ # ./certbot-auto --no-self-upgrade --version
certbot 0.26.1
````


Discussion:
[DLoader on the forum seems to have found the issue](https://community.letsencrypt.org/t/error-during-renewal-keyerror-handle-modules/71500/4?u=mnordhoff):

> If you look at the “override_suse.py” file in the directory
>
> “/opt/eff.org/certbot/venv/lib/python2.7/site-packages/certbot_apache/"
>
> you will see that someone recently modified it to create the “handle_mods” element instead of the “handle_modules” element in the OS_DEFAULTS array.
>
> If you look in the other “override_” files, you will see that they all use the “handle_modules” element name.
>
> I changed “handle_mods=False” to “handle_modules=False” and it now works fine.

#6238 renamed `handle_mods` to `handle_modules` but missed one reference in `override_suse`.

https://github.com/certbot/certbot/blob/d39a354a659cbc3ee7ff177ea6bd42724b16c71e/certbot-apache/certbot_apache/override_suse.py#L26

Resolving patch:
diff --git a/certbot-apache/certbot_apache/override_suse.py b/certbot-apache/certbot_apache/override_suse.py
--- a/certbot-apache/certbot_apache/override_suse.py
+++ b/certbot-apache/certbot_apache/override_suse.py
@@ -23,7 +23,7 @@ class OpenSUSEConfigurator(configurator.ApacheConfigurator):
         enmod="a2enmod",
         dismod="a2dismod",
         le_vhost_ext="-le-ssl.conf",
-        handle_mods=False,
+        handle_modules=False,
         handle_sites=False,
         challenge_location="/etc/apache2/vhosts.d",
         MOD_SSL_CONF_SRC=pkg_resources.resource_filename(


Test patch:
diff --git a/certbot-apache/certbot_apache/tests/configurator_test.py b/certbot-apache/certbot_apache/tests/configurator_test.py
--- a/certbot-apache/certbot_apache/tests/configurator_test.py
+++ b/certbot-apache/certbot_apache/tests/configurator_test.py
@@ -115,6 +115,18 @@ def test_add_parser_arguments(self):  # pylint: disable=no-self-use
         # Weak test..
         ApacheConfigurator.add_parser_arguments(mock.MagicMock())
 
+    def test_add_parser_arguments_all_configurators(self):  # pylint: disable=no-self-use
+        from certbot_apache.entrypoint import OVERRIDE_CLASSES
+        for cls in OVERRIDE_CLASSES.values():
+            cls.add_parser_arguments(mock.MagicMock())
+
+    def test_all_configurators_defaults_defined(self):
+        from certbot_apache.entrypoint import OVERRIDE_CLASSES
+        from certbot_apache.configurator import ApacheConfigurator
+        parameters = set(ApacheConfigurator.OS_DEFAULTS.keys())
+        for cls in OVERRIDE_CLASSES.values():
+            self.assertTrue(parameters.issubset(set(cls.OS_DEFAULTS.keys())))
+
     def test_constant(self):
         self.assertTrue("debian_apache_2_4/multiple_vhosts/apache" in
                         self.config.option("server_root"))