# 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 os from karbor import exception from karbor.i18n import _ from karbor.services.protection import bank_plugin from karbor.services.protection.checkpoint import CheckpointCollection from karbor import utils from oslo_config import cfg from oslo_log import log as logging provider_opts = [ cfg.MultiStrOpt('plugin', default='', help='plugins to use for protection'), cfg.StrOpt('bank', default='', help='bank plugin to use for storage'), cfg.StrOpt('description', default='', help='the description of provider'), cfg.StrOpt('name', default='', help='the name of provider'), cfg.StrOpt('id', default='', help='the provider id'), cfg.BoolOpt('enabled', default=False, help='enabled or not'), ] CONF = cfg.CONF LOG = logging.getLogger(__name__) PROTECTION_NAMESPACE = 'karbor.protections' CONF.register_opt(cfg.StrOpt('provider_config_dir', default='providers.d', help='Configuration directory for providers.' ' Absolute path, or relative to karbor ' ' configuration directory.')) class PluggableProtectionProvider(object): def __init__(self, provider_config): super(PluggableProtectionProvider, self).__init__() self._config = provider_config self._id = self._config.provider.id self._name = self._config.provider.name self._description = self._config.provider.description self._extended_info_schema = {'options_schema': {}, 'restore_schema': {}, 'saved_info_schema': {}} self.checkpoint_collection = None self._bank_plugin = None self._plugin_map = {} if (hasattr(self._config.provider, 'bank') and not self._config.provider.bank): raise ImportError(_("Empty bank")) self._load_bank(self._config.provider.bank) self._bank = bank_plugin.Bank(self._bank_plugin) self.checkpoint_collection = CheckpointCollection( self._bank) if hasattr(self._config.provider, 'plugin'): for plugin_name in self._config.provider.plugin: if not plugin_name: raise ImportError(_("Empty protection plugin")) self._register_plugin(plugin_name) @property def id(self): return self._id @property def name(self): return self._name @property def description(self): return self._description @property def extended_info_schema(self): return self._extended_info_schema @property def bank(self): return self._bank @property def plugins(self): return self._plugin_map def load_plugins(self): return { plugin_type: plugin_class(self._config) for plugin_type, plugin_class in self.plugins.items() } def _load_bank(self, bank_name): try: plugin = utils.load_plugin(PROTECTION_NAMESPACE, bank_name, self._config) except Exception: LOG.exception("Load bank plugin: '%s' failed.", bank_name) raise else: self._bank_plugin = plugin def _register_plugin(self, plugin_name): try: plugin = utils.load_class(PROTECTION_NAMESPACE, plugin_name) except Exception: LOG.exception("Load protection plugin: '%s' failed.", plugin_name) raise else: for resource in plugin.get_supported_resources_types(): self._plugin_map[resource] = plugin if hasattr(plugin, 'get_options_schema'): self._extended_info_schema['options_schema'][resource] \ = plugin.get_options_schema(resource) if hasattr(plugin, 'get_restore_schema'): self._extended_info_schema['restore_schema'][resource] \ = plugin.get_restore_schema(resource) if hasattr(plugin, 'get_saved_info_schema'): self._extended_info_schema['saved_info_schema'][resource] \ = plugin.get_saved_info_schema(resource) def get_checkpoint_collection(self): return self.checkpoint_collection def get_checkpoint(self, checkpoint_id, context=None): return self.get_checkpoint_collection().get(checkpoint_id, context=context) def list_checkpoints(self, project_id, provider_id, limit=None, marker=None, plan_id=None, start_date=None, end_date=None, sort_dir=None, context=None, all_tenants=False): checkpoint_collection = self.get_checkpoint_collection() return checkpoint_collection.list_ids( project_id=project_id, provider_id=provider_id, limit=limit, marker=marker, plan_id=plan_id, start_date=start_date, end_date=end_date, sort_dir=sort_dir, context=context, all_tenants=all_tenants) class ProviderRegistry(object): def __init__(self): super(ProviderRegistry, self).__init__() self.providers = {} self._load_providers() def _load_providers(self): """load provider""" config_dir = utils.find_config(CONF.provider_config_dir) for config_file in os.listdir(config_dir): if not config_file.endswith('.conf'): continue config_path = os.path.abspath(os.path.join(config_dir, config_file)) provider_config = cfg.ConfigOpts() provider_config(args=['--config-file=' + config_path]) provider_config.register_opts(provider_opts, 'provider') provider_enabled = provider_config.provider.enabled if not provider_enabled: LOG.info('Provider {0} is not enabled'.format( provider_config.provider.name) ) continue try: provider = PluggableProtectionProvider(provider_config) except Exception as e: LOG.error("Load provider: %(provider)s failed. " "Reason: %(reason)s", {'provider': provider_config.provider.name, 'reason': e}) else: LOG.info('Loaded provider: %s successfully.', provider_config.provider.name) self.providers[provider.id] = provider def list_providers(self, marker=None, limit=None, sort_keys=None, sort_dirs=None, filters=None): # TODO(jiaopengju) How to use sort_keys, sort_dirs and filters provider_ids = sorted(self.providers.keys()) provider_list = sorted( self.providers.values(), key=lambda item: item.id) if marker is not None and marker in provider_ids: provider_list = provider_list[provider_ids.index(marker) + 1:] filters = filters if filters else {} valid_providers = [] for provider in provider_list: provider_dict = dict( id=provider.id, name=provider.name, description=provider.description, extended_info_schema=provider.extended_info_schema ) for key, value in filters.items(): if key in provider_dict.keys() and \ value != provider_dict[key]: break else: valid_providers.append(provider_dict) if limit is not None and len(valid_providers) == limit: return valid_providers return valid_providers def show_provider(self, provider_id): try: return self.providers[provider_id] except KeyError: raise exception.ProviderNotFound(provider_id=provider_id)