def test_import_plugin_with_external_module_name(self): """ Verify import_plugin with external module name """ config.import_plugin('commissaire.storage.etcd', 'deliberately.bogus.package', commissaire.storage.etcd.PluginClass)
def refresh_managers(self): """ Fetches all ContainerManagerConfig records from the storage service, and instantiates the corresponding container manager plugins. This tries to reuse compatible container manager instances from previous calls to try and preserve any internal state. :raises ConfigurationError: on an invalid ContainerManagerConfig """ current_managers = {} container = self.storage.list(models.ContainerManagerConfigs) for config in container.container_managers: # This will raise ConfigurationError if the import fails. manager_type = import_plugin( config.type, 'commissaire.containermgr', ContainerManagerBase) manager = self.managers.pop(config.name, None) if isinstance(manager, manager_type): # If there's already a compatible manager, reuse it. # XXX Manager instances may not keep their option # dictionary so we can't detect option changes. current_managers[config.name] = manager else: current_managers[config.name] = manager_type(config.options) self.managers = current_managers
def _config_notification(self, event, model, message): """ Called when the service receives a notification from the storage service about a ContainerManagerConfig record. :param body: Decoded message body :type body: dict :param message: A message instance :type message: kombu.message.Message """ if event == client.NOTIFY_EVENT_DELETED: if model.name in self.managers: del self.managers[model.name] else: self.logger.warn( 'Delete notification for unknown manager: {}'.format( model.name)) return else: try: manager_type = import_plugin(model.type, 'commissaire.containermgr', ContainerManagerBase) manager = manager_type(model.options) except ConfigurationError as ex: self.logger.warn('Failed to create manager "{}": {}'.format( model.type, ex.args[0])) return self.managers[model.name] = manager
def register_store_handler(self, config): # pragma: no cover (temporary) """ Registers a new store handler type after extracting and validating information required for registration from the configuration data. :param config: A configuration dictionary :type config: dict """ if type(config) is not dict: raise ConfigurationError( 'Store handler format must be a JSON object, got a ' '{} instead: {}'.format(type(config).__name__, config)) # Import the handler class. try: module_name = config.pop('type') except KeyError: raise ConfigurationError( 'Store handler configuration missing "type" key: ' '{}'.format(config)) handler_type = import_plugin( module_name, 'commissaire.storage', StoreHandlerBase) # Match model types to type name patterns. matched_types = set() for pattern in config.pop('models', ['*']): matches = fnmatch.filter(self._model_types.keys(), pattern) if not matches: raise ConfigurationError( 'No match for model: {}'.format(pattern)) matched_types.update([self._model_types[name] for name in matches]) self._manager.register_store_handler( handler_type, config, *matched_types)
def inject_authentication(plugins): """ Injects authentication into the dispatcher's dispatch method. :param plugin: Name of the Authenticator plugin. :type plugin: str :param kwargs: Arguments for the Authenticator :type kwargs: dict or list :returns: A wrapped Dispatcher instance :rtype: commissaire.dispatcher.Dispatcher """ global DISPATCHER authn_manager = AuthenticationManager(DISPATCHER.dispatch) for module_name in plugins: authentication_class = import_plugin( module_name, 'commissaire_http.authentication', Authenticator) # NOTE: We set the app to None as we are not using the # authentication_class as the dispatcher itself authn_manager.authenticators.append( authentication_class(None, **plugins[module_name])) # If there are no authentication managers defined, append the default # which will deny all requests if len(authn_manager.authenticators) == 0: print('No authentication plugins found. Denying all requests.') authn_manager.authenticators.append(Authenticator(None)) # NOTE: We wrap only the dispatch method, not the entire # dispatcher instance. DISPATCHER.dispatch = authn_manager return DISPATCHER
def test_import_plugin_with_builtin_module_name(self): """ Verify import_plugin with built-in module name """ config.import_plugin('etcd', 'commissaire.storage', commissaire.storage.etcd.PluginClass)
def _register_store_handler(self, config): """ Registers a new store handler type after extracting and validating information required for registration from the configuration data. This will raise a ConfigurationError if any configuration parameters are invalid. :param config: A configuration dictionary :type config: dict :raises: commissaire.util.config.ConfigurationError """ if type(config) is not dict: raise ConfigurationError( 'Store handler format must be a JSON object, got a ' '{} instead: {}'.format(type(config).__name__, config)) # Import the handler class. try: module_name = config.pop('type') except KeyError: raise ConfigurationError( 'Store handler configuration missing "type" key: ' '{}'.format(config)) handler_type = import_plugin( module_name, 'commissaire.storage', StoreHandlerBase) # Match (non-secret) model types to type name patterns. matched_types = set() configurable_model_names = [ k for k, v in self._model_types.items() if not issubclass(v, models.SecretModel)] for pattern in config.pop('models', ['*']): matches = fnmatch.filter(configurable_model_names, pattern) if not matches: raise ConfigurationError( 'No match for model: {}'.format(pattern)) matched_types.update([self._model_types[name] for name in matches]) handler_type.check_config(config) definition = (handler_type, config, matched_types) name = config.get('name', '').strip() if not name: # If the store handler definition was not given a # name, derive a unique name from its module name. suffix = 1 name = handler_type.__module__ while name in self._definitions_by_name: name = '{}-{}'.format(handler_type.__module__, suffix) suffix += 1 config['name'] = name if name in self._definitions_by_name: raise ConfigurationError( 'Duplicate storage handlers named "{}"'.format(name)) for mt in matched_types: if mt in self._definitions_by_model_type: conflicting_type, _, _ = \ self._definitions_by_model_type[mt] raise ConfigurationError( 'Model "{}" already assigned to "{}"'.format( getattr(mt, '__name__', '?'), getattr(conflicting_type, '__module__', '?'))) # Add definition after all checks pass. self._definitions_by_name[name] = definition new_items = {mt: definition for mt in matched_types} self._definitions_by_model_type.update(new_items)