# Copyright 2016 OpenStack Foundation # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import collections import importlib import pkgutil import sys from oslo_config import cfg from oslo_config import types as conf_types from oslo_log import log as logging from oslo_versionedobjects import base as vo_base import six from glare.common import exception from glare.i18n import _, _LE from glare.objects import base CONF = cfg.CONF LOG = logging.getLogger(__name__) registry_options = [ cfg.ListOpt('enabled_artifact_types', default=['heat_templates', 'heat_environments', 'murano_packages', 'tosca_templates', 'images'], item_type=conf_types.String(), help=_("List of enabled artifact types that will be " "available to user")), cfg.ListOpt('custom_artifact_types_modules', default=[], item_type=conf_types.String(), help=_("List of custom user modules with artifact types that " "will be uploaded by Glare dynamically during service " "startup.")) ] CONF.register_opts(registry_options) def import_submodules(module): """Import all submodules of a module. :param module: Package name :return list of imported modules """ package = sys.modules[module] return [ importlib.import_module(module + '.' + name) for loader, name, is_pkg in pkgutil.walk_packages(package.__path__)] def import_modules_list(modules): custom_module_list = [] for module_name in modules: try: custom_module_list.append(importlib.import_module(module_name)) except Exception as e: LOG.exception(e) LOG.error(_LE("Cannot import custom artifact type from module " "%(module_name)%s. Error: %(error)s"), {'module_name': module_name, 'error': str(e)}) return custom_module_list def get_subclasses(module, base_class): subclasses = [] for name in dir(module): obj = getattr(module, name) try: if issubclass(obj, base_class) and obj != base_class: subclasses.append(obj) except TypeError: pass return subclasses class ArtifactRegistry(vo_base.VersionedObjectRegistry): """Artifact Registry is responsible for registration of artifacts and returning appropriate artifact types based on artifact type name. """ @classmethod def register_all_artifacts(cls): """Register all artifacts in Glare.""" # get all submodules in glare.objects # please note that we registering trusted modules first # and applying custom modules after that to allow custom modules # to specify custom logic inside modules = (import_submodules('glare.objects') + import_modules_list( CONF.custom_artifact_types_modules)) # get all versioned object classes in module supported_types = [] for module in modules: supported_types.extend(get_subclasses(module, base.BaseArtifact)) types = [t.partition(':')[0] for t in CONF.enabled_artifact_types] for type_name in set(types + ['all']): for af_type in supported_types: if type_name == af_type.get_type_name(): cls.register(af_type) break else: raise exception.TypeNotFound(name=type_name) @classmethod def get_artifact_type(cls, type_name): """Return artifact type based on artifact type name. :param type_name: name of artifact type :return: artifact class """ for name, af_type in six.iteritems(cls.obj_classes()): if af_type[0].get_type_name() == type_name: return af_type[0] raise exception.TypeNotFound(name=type_name) @classmethod def reset_registry(cls): """Resets all registered artifact type classes.""" cls._registry._obj_classes = collections.defaultdict(list)