Example #1
0
 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)
Example #2
0
    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
Example #4
0
    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)
Example #5
0
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
Example #6
0
 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)