def pick_plugin(config: configuration.NamespaceConfig, default: Optional[str], plugins: disco.PluginsRegistry, question: str, ifaces: Iterable[Type]) -> Optional[P]: """Pick plugin. :param certbot.configuration.NamespaceConfig config: Configuration :param str default: Plugin name supplied by user or ``None``. :param certbot._internal.plugins.disco.PluginsRegistry plugins: All plugins registered as entry points. :param str question: Question to be presented to the user in case multiple candidates are found. :param list ifaces: Interfaces that plugins must provide. :returns: Initialized plugin. :rtype: Plugin """ if default is not None: # throw more UX-friendly error if default not in plugins filtered = plugins.filter(lambda p_ep: p_ep.check_name(default)) else: if config.noninteractive_mode: # it's really bad to auto-select the single available plugin in # non-interactive mode, because an update could later add a second # available plugin raise errors.MissingCommandlineFlag( "Missing command line flags. For non-interactive execution, " "you will need to specify a plugin on the command line. Run " "with '--help plugins' to see a list of options, and see " "https://eff.org/letsencrypt-plugins for more detail on what " "the plugins do and how to use them.") filtered = plugins.visible().ifaces(ifaces) filtered.init(config) verified = filtered.verify(ifaces) verified.prepare() prepared = verified.available() if len(prepared) > 1: logger.debug("Multiple candidate plugins: %s", prepared) plugin_ep1 = choose_plugin(list(prepared.values()), question) if plugin_ep1 is None: return None return cast(P, plugin_ep1.init()) elif len(prepared) == 1: plugin_ep2 = list(prepared.values())[0] logger.debug("Single candidate plugin: %s", plugin_ep2) if plugin_ep2.misconfigured: return None return plugin_ep2.init() else: logger.debug("No candidate plugin") return None
def get_unprepared_installer( config: configuration.NamespaceConfig, plugins: disco.PluginsRegistry) -> Optional[interfaces.Installer]: """ Get an unprepared interfaces.Installer object. :param certbot.configuration.NamespaceConfig config: Configuration :param certbot._internal.plugins.disco.PluginsRegistry plugins: All plugins registered as entry points. :returns: Unprepared installer plugin or None :rtype: Plugin or None """ _, req_inst = cli_plugin_requests(config) if not req_inst: return None installers = plugins.filter(lambda p_ep: p_ep.check_name(req_inst)) installers.init(config) installers = installers.verify((interfaces.Installer, )) if len(installers) > 1: raise errors.PluginSelectionError( "Found multiple installers with the name %s, Certbot is unable to " "determine which one to use. Skipping." % req_inst) if installers: inst = list(installers.values())[0] logger.debug("Selecting plugin: %s", inst) return inst.init(config) raise errors.PluginSelectionError( "Could not select or initialize the requested installer %s." % req_inst)
def record_chosen_plugins(config: configuration.NamespaceConfig, plugins: disco.PluginsRegistry, auth: Optional[interfaces.Authenticator], inst: Optional[interfaces.Installer]) -> None: """Update the config entries to reflect the plugins we actually selected.""" config.authenticator = None if auth: auth_ep = plugins.find_init(auth) if auth_ep: config.authenticator = auth_ep.name config.installer = None if inst: inst_ep = plugins.find_init(inst) if inst_ep: config.installer = inst_ep.name logger.info("Plugins selected: Authenticator %s, Installer %s", config.authenticator, config.installer)
def test_find_all(self): from certbot._internal.plugins.disco import PluginsRegistry with mock.patch("certbot._internal.plugins.disco.pkg_resources") as mock_pkg: mock_pkg.iter_entry_points.side_effect = [iter([EP_SA]), iter([EP_WR])] plugins = PluginsRegistry.find_all() self.assertTrue(plugins["sa"].plugin_cls is standalone.Authenticator) self.assertTrue(plugins["sa"].entry_point is EP_SA) self.assertTrue(plugins["wr"].plugin_cls is webroot.Authenticator) self.assertTrue(plugins["wr"].entry_point is EP_WR)
def add_plugin_args(self, plugins: disco.PluginsRegistry) -> None: """ Let each of the plugins add its own command line arguments, which may or may not be displayed as help topics. """ for name, plugin_ep in plugins.items(): parser_or_group = self.add_group( name, description=plugin_ep.long_description) plugin_ep.plugin_cls.inject_parser_options(parser_or_group, name)
def setUp(self): super(GetUnpreparedInstallerTest, self).setUp() self.mock_apache_fail_ep = mock.Mock(description_with_name="afail") self.mock_apache_fail_ep.name = "afail" self.mock_apache_ep = mock.Mock(description_with_name="apache") self.mock_apache_ep.name = "apache" self.mock_apache_plugin = mock.MagicMock() self.mock_apache_ep.init.return_value = self.mock_apache_plugin self.plugins = PluginsRegistry({ "afail": self.mock_apache_fail_ep, "apache": self.mock_apache_ep, })
def setUp(self): super().setUp() self.mock_apache_fail_ep = mock.Mock(description_with_name="afail") self.mock_apache_fail_ep.check_name = lambda name: name == "afail" self.mock_apache_ep = mock.Mock(description_with_name="apache") self.mock_apache_ep.check_name = lambda name: name == "apache" self.mock_apache_plugin = mock.MagicMock() self.mock_apache_ep.init.return_value = self.mock_apache_plugin self.plugins = PluginsRegistry({ "afail": self.mock_apache_fail_ep, "apache": self.mock_apache_ep, })
def test_find_all(self): from certbot._internal.plugins.disco import PluginsRegistry with mock.patch("certbot._internal.plugins.disco.pkg_resources") as mock_pkg: mock_pkg.iter_entry_points.side_effect = [ iter([EP_SA]), iter([EP_WR, self.ep1]) ] with mock.patch.object(pkg_resources.EntryPoint, 'load') as mock_load: mock_load.side_effect = [ standalone.Authenticator, webroot.Authenticator, null.Installer, null.Installer] plugins = PluginsRegistry.find_all() self.assertIs(plugins["sa"].plugin_cls, standalone.Authenticator) self.assertIs(plugins["sa"].entry_point, EP_SA) self.assertIs(plugins["wr"].plugin_cls, webroot.Authenticator) self.assertIs(plugins["wr"].entry_point, EP_WR) self.assertIs(plugins["ep1"].plugin_cls, null.Installer) self.assertIs(plugins["ep1"].entry_point, self.ep1) self.assertIs(plugins["p1:ep1"].plugin_cls, null.Installer) self.assertIs(plugins["p1:ep1"].entry_point, self.ep1)
def test_no_available_installers(self): self.config.configurator = "apache" self.plugins = PluginsRegistry({}) self.assertRaises(errors.PluginSelectionError, self._call)
def _create_new_registry(cls, plugins): from certbot._internal.plugins.disco import PluginsRegistry return PluginsRegistry(plugins)