Repository: certbot/certbot

Issue:
The apache plugin shouldn't report itself as available if augeas is too old
We'll need this to ensure that as Apache 2.2 support is added, people who bootstrapped on wheezy, precise, or some other old OS, aren't getting a plugin that doesn't work.



Discussion:

Resolving patch:
diff --git a/letsencrypt-apache/letsencrypt_apache/configurator.py b/letsencrypt-apache/letsencrypt_apache/configurator.py
--- a/letsencrypt-apache/letsencrypt_apache/configurator.py
+++ b/letsencrypt-apache/letsencrypt_apache/configurator.py
@@ -158,6 +158,12 @@ def prepare(self):
             raise errors.NotSupportedError(
                 "Apache Version %s not supported.", str(self.version))
 
+        if not self._check_aug_version():
+            raise errors.NotSupportedError(
+                "Apache plugin support requires libaugeas0 and augeas-lenses "
+                "version 1.2.0 or higher, please make sure you have you have "
+                "those installed.")
+
         self.parser = parser.ApacheParser(
             self.aug, self.conf("server-root"), self.conf("vhost-root"),
             self.version)
@@ -169,6 +175,21 @@ def prepare(self):
 
         install_ssl_options_conf(self.mod_ssl_conf)
 
+    def _check_aug_version(self):
+        """ Checks that we have recent enough version of libaugeas.
+        If augeas version is recent enough, it will support case insensitive
+        regexp matching"""
+
+        self.aug.set("/test/path/testing/arg", "aRgUMeNT")
+        try:
+            matches = self.aug.match(
+                "/test//*[self::arg=~regexp('argument', 'i')]")
+        except RuntimeError:
+            self.aug.remove("/test/path")
+            return False
+        self.aug.remove("/test/path")
+        return matches
+
     def deploy_cert(self, domain, cert_path, key_path,
                     chain_path=None, fullchain_path=None):  # pylint: disable=unused-argument
         """Deploys certificate to specified virtual host.


Test patch:
diff --git a/letsencrypt-apache/letsencrypt_apache/tests/configurator_test.py b/letsencrypt-apache/letsencrypt_apache/tests/configurator_test.py
--- a/letsencrypt-apache/letsencrypt_apache/tests/configurator_test.py
+++ b/letsencrypt-apache/letsencrypt_apache/tests/configurator_test.py
@@ -65,6 +65,15 @@ def test_prepare_version(self, mock_exe_exists, _):
         self.assertRaises(
             errors.NotSupportedError, self.config.prepare)
 
+    @mock.patch("letsencrypt_apache.parser.ApacheParser")
+    @mock.patch("letsencrypt_apache.configurator.le_util.exe_exists")
+    def test_prepare_old_aug(self, mock_exe_exists, _):
+        mock_exe_exists.return_value = True
+        self.config.config_test = mock.Mock()
+        self.config._check_aug_version = mock.Mock(return_value=False) # pylint: disable=protected-access
+        self.assertRaises(
+            errors.NotSupportedError, self.config.prepare)
+
     def test_add_parser_arguments(self):  # pylint: disable=no-self-use
         from letsencrypt_apache.configurator import ApacheConfigurator
         # Weak test..
@@ -978,6 +987,13 @@ def test_make_addrs_sni_ready(self):
         self.assertTrue(self.config.parser.find_dir(
             "NameVirtualHost", "*:443", exclude=False))
 
+    def test_aug_version(self):
+        mock_match = mock.Mock(return_value=["something"])
+        self.config.aug.match = mock_match
+        self.assertEquals(self.config._check_aug_version(), ["something"]) # pylint: disable=protected-access
+        self.config.aug.match.side_effect = RuntimeError
+        self.assertFalse(self.config._check_aug_version()) # pylint: disable=protected-access
+
 
 if __name__ == "__main__":
     unittest.main()  # pragma: no cover