"""Provides a common base for Apache proxies""" import argparse import os import shutil import subprocess from typing import Set from typing import Tuple from unittest import mock from certbot_apache._internal import entrypoint from certbot_compatibility_test import errors from certbot_compatibility_test import util from certbot_compatibility_test.configurators import common as configurators_common from certbot import configuration from certbot import errors as le_errors from certbot import util as certbot_util class Proxy(configurators_common.Proxy): """A common base for Apache test configurators""" def __init__(self, args: argparse.Namespace) -> None: """Initializes the plugin with the given command line args""" super().__init__(args) self.le_config.apache_le_vhost_ext = "-le-ssl.conf" self.modules = self.server_root = self.test_conf = self.version = None patch = mock.patch( "certbot_apache._internal.configurator.display_ops.select_vhost") mock_display = patch.start() mock_display.side_effect = le_errors.PluginError( "Unable to determine vhost") def load_config(self) -> str: """Loads the next configuration for the plugin to test""" config = super().load_config() self._all_names, self._test_names = _get_names(config) server_root = _get_server_root(config) shutil.rmtree("/etc/apache2") shutil.copytree(server_root, "/etc/apache2", symlinks=True) self._prepare_configurator() try: subprocess.check_call("apachectl -k restart".split()) except errors.Error: raise errors.Error( "Apache failed to load {0} before tests started".format( config)) return config def _prepare_configurator(self) -> None: """Prepares the Apache plugin for testing""" for k in entrypoint.ENTRYPOINT.OS_DEFAULTS.__dict__.keys(): setattr(self.le_config, "apache_" + k, getattr(entrypoint.ENTRYPOINT.OS_DEFAULTS, k)) self._configurator = entrypoint.ENTRYPOINT( config=configuration.NamespaceConfig(self.le_config), name="apache") self._configurator.prepare() def cleanup_from_tests(self) -> None: """Performs any necessary cleanup from running plugin tests""" super().cleanup_from_tests() mock.patch.stopall() def _get_server_root(config: str) -> str: """Returns the server root directory in config""" subdirs = [ name for name in os.listdir(config) if os.path.isdir(os.path.join(config, name))] if len(subdirs) != 1: errors.Error("Malformed configuration directory {0}".format(config)) return os.path.join(config, subdirs[0].rstrip()) def _get_names(config: str) -> Tuple[Set[str], Set[str]]: """Returns all and testable domain names in config""" all_names = set() non_ip_names = set() with open(os.path.join(config, "vhosts")) as f: for line in f: # If parsing a specific vhost if line[0].isspace(): words = line.split() if words[0] == "alias": all_names.add(words[1]) non_ip_names.add(words[1]) # If for port 80 and not IP vhost elif words[1] == "80" and not util.IP_REGEX.match(words[3]): all_names.add(words[3]) non_ip_names.add(words[3]) elif "NameVirtualHost" not in line: words = line.split() if (words[0].endswith("*") or words[0].endswith("80") and not util.IP_REGEX.match(words[1]) and words[1].find(".") != -1): all_names.add(words[1]) return ( certbot_util.get_filtered_names(all_names), certbot_util.get_filtered_names(non_ip_names) )