def __init__(self):
        self.loaded_plugins = {}
        self.errored_plugins = []

        self.resource_class_id_to_class = {}
        self.resource_class_class_to_id = {}

        from settings import INSTALLED_STORAGE_PLUGINS

        for plugin in INSTALLED_STORAGE_PLUGINS:
            try:
                self.load_plugin(plugin)
            except (ImportError, SyntaxError, ResourceProgrammingError,
                    PluginProgrammingError) as e:
                storage_plugin_log.error("Failed to load plugin '%s': %s" %
                                         (plugin, traceback.format_exc()))
                self.errored_plugins.append((plugin, e))

        for id, klass in self.resource_class_id_to_class.items():
            klass._meta.relations = list(klass._meta.orig_relations)

        def can_satisfy_relation(klass, attributes):
            for attribute in attributes:
                if not attribute in klass._meta.storage_attributes:
                    return False

            return True

        for id, klass in self.resource_class_id_to_class.items():
            for relation in klass._meta.relations:
                # If ('linux', 'ScsiDevice') form was used, substitute the real class
                if isinstance(relation, relations.Provide):
                    if isinstance(relation.provide_to, tuple):
                        prov_klass, prov_klass_id = self.get_plugin_resource_class(
                            *relation.provide_to)
                        relation.provide_to = prov_klass
                elif isinstance(relation, relations.Subscribe):
                    if isinstance(relation.subscribe_to, tuple):
                        sub_klass, sub_klass_id = self.get_plugin_resource_class(
                            *relation.subscribe_to)
                        relation.subscribe_to = sub_klass

                # Generate reverse-Subscribe relations
                if isinstance(relation, relations.Provide):
                    # Synthesize Subscribe objects on the objects which might
                    # be on the receiving event of a Provide relation.  The original
                    # Provide object plays no further role.
                    subscription = relations.Subscribe(klass,
                                                       relation.attributes,
                                                       relation.ignorecase)
                    if can_satisfy_relation(relation.provide_to,
                                            relation.attributes):
                        relation.provide_to._meta.relations.append(
                            subscription)
                    for sc in all_subclasses(relation.provide_to):
                        if can_satisfy_relation(sc, relation.attributes):
                            sc._meta.relations.append(subscription)
Exemplo n.º 2
0
 def __getattr__(self, key):
     if key.startswith("_") or not key in self._meta.storage_attributes:
         raise AttributeError("Unknown attribute %s" % key)
     else:
         try:
             return self._storage_dict[key]
         except KeyError:
             attr = self._meta.storage_attributes[key]
             if attr.optional:
                 return None
             elif attr.default is not None:
                 if callable(attr.default):
                     return attr.default(self._storage_dict)
                 else:
                     return attr.default
             else:
                 log.error("Missing attribute %s, %s" % (key, self._storage_dict))
                 raise AttributeError("attribute %s not found" % key)
    def load_plugin(self, module):
        """Load a BaseStoragePlugin class from a module given a
           python path like chroma_core.lib.lvm',
           or simply return it if it was already loaded.  Note that the
           BaseStoragePlugin within the module will not be instantiated when this
           returns, caller is responsible for instantiating it.

           @return A subclass of BaseStoragePlugin"""

        if module in self.loaded_plugins:
            raise PluginProgrammingError("Duplicate storage plugin module %s" % module)

        if module in sys.modules:
            storage_plugin_log.warning("Reloading module %s (okay if testing)" % module)
            mod = sys.modules[module]
        else:
            # Load the module
            try:
                mod = __import__(module)
            except (ImportError, ResourceProgrammingError, SyntaxError) as e:
                storage_plugin_log.error("Error importing %s: %s" % (module, e))
                raise

        components = module.split(".")

        plugin_name = module
        for comp in components[1:]:
            mod = getattr(mod, comp)
            plugin_name = comp
        plugin_module = mod

        self._validate_api_version(plugin_module)

        # Find all BaseStoragePlugin subclasses in the module
        from chroma_core.lib.storage_plugin.api.plugin import Plugin

        plugin_klasses = []
        import inspect

        for name, cls in inspect.getmembers(plugin_module):
            if (
                inspect.isclass(cls)
                and issubclass(cls, BaseStoragePlugin)
                and cls != BaseStoragePlugin
                and cls != Plugin
            ):
                plugin_klasses.append(cls)

        # Make sure we have exactly one BaseStoragePlugin subclass
        if len(plugin_klasses) > 1:
            raise PluginProgrammingError(
                "Module %s defines more than one BaseStoragePlugin: %s!" % (module, plugin_klasses)
            )
        elif len(plugin_klasses) == 0:
            raise PluginProgrammingError("Module %s does not define a BaseStoragePlugin!" % module)
        else:
            plugin_klass = plugin_klasses[0]

        # Hook in a logger to the BaseStoragePlugin subclass
        if not plugin_klass._log:
            import logging
            import settings

            log = logging.getLogger("storage_plugin_log_%s" % module)
            if module in settings.STORAGE_PLUGIN_DEBUG_PLUGINS or settings.STORAGE_PLUGIN_DEBUG:
                log.setLevel(logging.DEBUG)
            else:
                log.setLevel(logging.WARNING)
            plugin_klass._log = log
            plugin_klass._log_format = "[%%(asctime)s: %%(levelname)s/%s] %%(message)s" % module
        else:
            storage_plugin_log.warning("Double load of %s (okay if testing)" % plugin_name)

        try:
            self._load_plugin(plugin_module, plugin_name, plugin_klass)
        except ResourceProgrammingError as e:
            storage_plugin_log.error("Error loading %s: %s" % (plugin_name, e))
            raise
        else:
            return plugin_klass