karbor/karbor/services/protection/provider.py

223 lines
8.2 KiB
Python

# 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):
return self.get_checkpoint_collection().get(checkpoint_id)
def list_checkpoints(self, project_id, provider_id, limit=None,
marker=None, plan_id=None, start_date=None,
end_date=None, sort_dir=None):
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)
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:]
valid_providers = []
for provider in provider_list:
valid_providers.append(
dict(id=provider.id,
name=provider.name,
description=provider.description,
extended_info_schema=provider.extended_info_schema
))
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)