232 lines
8.6 KiB
Python
Executable File
232 lines
8.6 KiB
Python
Executable File
# 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):
|
|
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)
|
|
|
|
|
|
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)
|