Add ability to specify backup driver via class name

This patch also deprecates backup driver initialization using module
name.

Change-Id: Id6bee9e7d0da8ead224a04f86fe79ddfb5b286cf
Related-Blueprint: generic-backup-implementation
This commit is contained in:
Ivan Kolodyazhny 2017-09-01 18:08:31 +03:00
parent 7552648b1b
commit de2ffaff36
4 changed files with 56 additions and 24 deletions

View File

@ -60,7 +60,7 @@ LOG = logging.getLogger(__name__)
backup_manager_opts = [ backup_manager_opts = [
cfg.StrOpt('backup_driver', cfg.StrOpt('backup_driver',
default='cinder.backup.drivers.swift', default='cinder.backup.drivers.swift.SwiftBackupDriver',
help='Driver to use for backups.',), help='Driver to use for backups.',),
cfg.BoolOpt('backup_service_inithost_offload', cfg.BoolOpt('backup_service_inithost_offload',
default=True, default=True,
@ -90,7 +90,6 @@ class BackupManager(manager.ThreadPoolManager):
target = messaging.Target(version=RPC_API_VERSION) target = messaging.Target(version=RPC_API_VERSION)
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.service = importutils.import_module(self.driver_name)
self.az = CONF.storage_availability_zone self.az = CONF.storage_availability_zone
self.backup_rpcapi = backup_rpcapi.BackupAPI() self.backup_rpcapi = backup_rpcapi.BackupAPI()
self.volume_rpcapi = volume_rpcapi.VolumeAPI() self.volume_rpcapi = volume_rpcapi.VolumeAPI()
@ -115,6 +114,23 @@ class BackupManager(manager.ThreadPoolManager):
return mapper[service] return mapper[service]
return service return service
def get_backup_driver(self, context):
driver = None
try:
# TODO(e0ne): remove backward compatibility in S release
service = importutils.import_module(self.driver_name)
msg = ("Backup driver initialization using module name "
"is deprecated and will be removed in a 'S' "
"release. Please, use classname for backup driver "
"reference in the config.")
versionutils.report_deprecated_feature(LOG, msg)
driver = service.get_backup_driver(context)
except ImportError:
driver_class = importutils.import_class(self.driver_name)
driver = driver_class(context=context, db=self.db)
return driver
def _update_backup_error(self, backup, err, def _update_backup_error(self, backup, err,
status=fields.BackupStatus.ERROR): status=fields.BackupStatus.ERROR):
backup.status = status backup.status = status
@ -133,7 +149,7 @@ class BackupManager(manager.ThreadPoolManager):
LOG.exception("Problem cleaning incomplete backup operations.") LOG.exception("Problem cleaning incomplete backup operations.")
def _setup_backup_driver(self, ctxt): def _setup_backup_driver(self, ctxt):
backup_service = self.service.get_backup_driver(ctxt) backup_service = self.get_backup_driver(ctxt)
backup_service.check_for_setup_error() backup_service.check_for_setup_error()
self.is_initialized = True self.is_initialized = True
raise loopingcall.LoopingCallDone() raise loopingcall.LoopingCallDone()
@ -389,7 +405,7 @@ class BackupManager(manager.ThreadPoolManager):
self._notify_about_backup_usage(context, backup, "create.end") self._notify_about_backup_usage(context, backup, "create.end")
def _run_backup(self, context, backup, volume): def _run_backup(self, context, backup, volume):
backup_service = self.service.get_backup_driver(context) backup_service = self.get_backup_driver(context)
properties = utils.brick_get_connector_properties() properties = utils.brick_get_connector_properties()
try: try:
@ -505,7 +521,7 @@ class BackupManager(manager.ThreadPoolManager):
self._notify_about_backup_usage(context, backup, "restore.end") self._notify_about_backup_usage(context, backup, "restore.end")
def _run_restore(self, context, backup, volume): def _run_restore(self, context, backup, volume):
backup_service = self.service.get_backup_driver(context) backup_service = self.get_backup_driver(context)
properties = utils.brick_get_connector_properties() properties = utils.brick_get_connector_properties()
secure_enabled = ( secure_enabled = (
@ -569,7 +585,7 @@ class BackupManager(manager.ThreadPoolManager):
raise exception.InvalidBackup(reason=err) raise exception.InvalidBackup(reason=err)
try: try:
backup_service = self.service.get_backup_driver(context) backup_service = self.get_backup_driver(context)
backup_service.delete_backup(backup) backup_service.delete_backup(backup)
except Exception as err: except Exception as err:
with excutils.save_and_reraise_exception(): with excutils.save_and_reraise_exception():
@ -653,7 +669,7 @@ class BackupManager(manager.ThreadPoolManager):
# Call driver to create backup description string # Call driver to create backup description string
try: try:
backup_service = self.service.get_backup_driver(context) backup_service = self.get_backup_driver(context)
driver_info = backup_service.export_record(backup) driver_info = backup_service.export_record(backup)
backup_url = backup.encode_record(driver_info=driver_info) backup_url = backup.encode_record(driver_info=driver_info)
backup_record['backup_url'] = backup_url backup_record['backup_url'] = backup_url
@ -709,7 +725,7 @@ class BackupManager(manager.ThreadPoolManager):
# Extract driver specific info and pass it to the driver # Extract driver specific info and pass it to the driver
driver_options = backup_options.pop('driver_info', {}) driver_options = backup_options.pop('driver_info', {})
backup_service = self.service.get_backup_driver(context) backup_service = self.get_backup_driver(context)
backup_service.import_record(backup, driver_options) backup_service.import_record(backup, driver_options)
except Exception as err: except Exception as err:
msg = six.text_type(err) msg = six.text_type(err)
@ -813,7 +829,7 @@ class BackupManager(manager.ThreadPoolManager):
if (status == fields.BackupStatus.AVAILABLE if (status == fields.BackupStatus.AVAILABLE
and backup['status'] != fields.BackupStatus.RESTORING): and backup['status'] != fields.BackupStatus.RESTORING):
# check whether we could verify the backup is ok or not # check whether we could verify the backup is ok or not
backup_service = self.service.get_backup_driver(context) backup_service = self.get_backup_driver(context)
if isinstance(backup_service, if isinstance(backup_service,
driver.BackupDriverWithVerify): driver.BackupDriverWithVerify):
backup_service.verify(backup.id) backup_service.verify(backup.id)
@ -878,7 +894,7 @@ class BackupManager(manager.ThreadPoolManager):
:param context: running context :param context: running context
""" """
backup_service = self.service.get_backup_driver(context) backup_service = self.get_backup_driver(context)
return backup_service.support_force_delete return backup_service.support_force_delete
def _attach_device(self, ctxt, backup_device, def _attach_device(self, ctxt, backup_device,

View File

@ -19,6 +19,7 @@
from oslo_config import cfg from oslo_config import cfg
from oslo_utils import importutils from oslo_utils import importutils
import six
db_driver_opt = cfg.StrOpt('db_driver', db_driver_opt = cfg.StrOpt('db_driver',
@ -38,5 +39,10 @@ class Base(object):
super(Base, self).__init__() super(Base, self).__init__()
if not db_driver: if not db_driver:
db_driver = CONF.db_driver db_driver = CONF.db_driver
self.db = importutils.import_module(db_driver) # pylint: disable=C0103
# pylint: disable=C0103
if isinstance(db_driver, six.string_types):
self.db = importutils.import_module(db_driver)
else:
self.db = db_driver
self.db.dispose_engine() self.db.dispose_engine()

View File

@ -36,7 +36,6 @@ from cinder import objects
from cinder.objects import fields from cinder.objects import fields
from cinder import test from cinder import test
from cinder.tests import fake_driver from cinder.tests import fake_driver
from cinder.tests.unit.backup import fake_service_with_verify as fake_service
from cinder.tests.unit import utils from cinder.tests.unit import utils
from cinder.volume import rpcapi as volume_rpcapi from cinder.volume import rpcapi as volume_rpcapi
@ -650,9 +649,9 @@ class BackupTestCase(BaseBackupTest):
vol_size = 1 vol_size = 1
vol_id = self._create_volume_db_entry(size=vol_size) vol_id = self._create_volume_db_entry(size=vol_size)
backup = self._create_backup_db_entry(volume_id=vol_id, backup = self._create_backup_db_entry(volume_id=vol_id,
parent_id = 'mock') parent_id='mock')
with mock.patch.object(self.backup_mgr.service, 'get_backup_driver') as \ with mock.patch.object(self.backup_mgr, 'get_backup_driver') as \
mock_get_backup_driver: mock_get_backup_driver:
mock_get_backup_driver.return_value.backup.return_value = ( mock_get_backup_driver.return_value.backup.return_value = (
{'parent_id': None}) {'parent_id': None})
@ -687,7 +686,7 @@ class BackupTestCase(BaseBackupTest):
backup = self._create_backup_db_entry(volume_id=vol_id) backup = self._create_backup_db_entry(volume_id=vol_id)
parent_backup = self._create_backup_db_entry(size=vol_size) parent_backup = self._create_backup_db_entry(size=vol_size)
with mock.patch.object(self.backup_mgr.service, 'get_backup_driver') as \ with mock.patch.object(self.backup_mgr, 'get_backup_driver') as \
mock_get_backup_driver: mock_get_backup_driver:
mock_get_backup_driver.return_value.backup.return_value = ( mock_get_backup_driver.return_value.backup.return_value = (
{'parent_id': parent_backup.id}) {'parent_id': parent_backup.id})
@ -720,7 +719,7 @@ class BackupTestCase(BaseBackupTest):
vol_id = self._create_volume_db_entry() vol_id = self._create_volume_db_entry()
backup = self._create_backup_db_entry(volume_id=vol_id) backup = self._create_backup_db_entry(volume_id=vol_id)
with mock.patch.object(self.backup_mgr.service, 'get_backup_driver') as \ with mock.patch.object(self.backup_mgr, 'get_backup_driver') as \
mock_get_backup_driver: mock_get_backup_driver:
mock_get_backup_driver.return_value.backup.side_effect = ( mock_get_backup_driver.return_value.backup.side_effect = (
FakeBackupException('fake')) FakeBackupException('fake'))
@ -759,7 +758,7 @@ class BackupTestCase(BaseBackupTest):
backup_service = lambda: None backup_service = lambda: None
backup_service.backup = mock.Mock( backup_service.backup = mock.Mock(
return_value=mock.sentinel.backup_update) return_value=mock.sentinel.backup_update)
self.backup_mgr.service.get_backup_driver = lambda x: backup_service self.backup_mgr.get_backup_driver = lambda x: backup_service
vol_id = self._create_volume_db_entry() vol_id = self._create_volume_db_entry()
backup = self._create_backup_db_entry(volume_id=vol_id) backup = self._create_backup_db_entry(volume_id=vol_id)
@ -1343,7 +1342,7 @@ class BackupTestCase(BaseBackupTest):
record where the backup driver returns an exception. record where the backup driver returns an exception.
""" """
export = self._create_exported_record_entry() export = self._create_exported_record_entry()
backup_driver = self.backup_mgr.service.get_backup_driver(self.ctxt) backup_driver = self.backup_mgr.get_backup_driver(self.ctxt)
_mock_record_import_class = ('%s.%s.%s' % _mock_record_import_class = ('%s.%s.%s' %
(backup_driver.__module__, (backup_driver.__module__,
backup_driver.__class__.__name__, backup_driver.__class__.__name__,
@ -1415,7 +1414,7 @@ class BackupTestCaseWithVerify(BaseBackupTest):
imported_record = self._create_export_record_db_entry( imported_record = self._create_export_record_db_entry(
backup_id=backup_id) backup_id=backup_id)
backup_hosts = [] backup_hosts = []
backup_driver = self.backup_mgr.service.get_backup_driver(self.ctxt) backup_driver = self.backup_mgr.get_backup_driver(self.ctxt)
_mock_backup_verify_class = ('%s.%s.%s' % _mock_backup_verify_class = ('%s.%s.%s' %
(backup_driver.__module__, (backup_driver.__module__,
backup_driver.__class__.__name__, backup_driver.__class__.__name__,
@ -1449,7 +1448,7 @@ class BackupTestCaseWithVerify(BaseBackupTest):
imported_record = self._create_export_record_db_entry( imported_record = self._create_export_record_db_entry(
backup_id=backup_id) backup_id=backup_id)
backup_hosts = [] backup_hosts = []
backup_driver = self.backup_mgr.service.get_backup_driver(self.ctxt) backup_driver = self.backup_mgr.get_backup_driver(self.ctxt)
_mock_backup_verify_class = ('%s.%s.%s' % _mock_backup_verify_class = ('%s.%s.%s' %
(backup_driver.__module__, (backup_driver.__module__,
backup_driver.__class__.__name__, backup_driver.__class__.__name__,
@ -1481,7 +1480,8 @@ class BackupTestCaseWithVerify(BaseBackupTest):
'_map_service_to_driver') as \ '_map_service_to_driver') as \
mock_map_service_to_driver: mock_map_service_to_driver:
# It should works when the service name is a string # It should works when the service name is a string
mock_map_service_to_driver.return_value = 'swift' backup_driver = 'cinder.tests.unit.backup.fake_service_with_verify'
mock_map_service_to_driver.return_value = backup_driver
self.backup_mgr.reset_status(self.ctxt, self.backup_mgr.reset_status(self.ctxt,
backup, backup,
fields.BackupStatus.AVAILABLE) fields.BackupStatus.AVAILABLE)
@ -1490,8 +1490,7 @@ class BackupTestCaseWithVerify(BaseBackupTest):
self.assertEqual(fields.BackupStatus.AVAILABLE, self.assertEqual(fields.BackupStatus.AVAILABLE,
new_backup['status']) new_backup['status'])
mock_map_service_to_driver.return_value = \ mock_map_service_to_driver.return_value = backup_driver
fake_service.get_backup_driver(self.ctxt)
self.backup_mgr.reset_status(self.ctxt, self.backup_mgr.reset_status(self.ctxt,
backup, backup,
fields.BackupStatus.ERROR) fields.BackupStatus.ERROR)
@ -1512,7 +1511,7 @@ class BackupTestCaseWithVerify(BaseBackupTest):
backup = self._create_backup_db_entry(status=fields.BackupStatus.ERROR, backup = self._create_backup_db_entry(status=fields.BackupStatus.ERROR,
volume_id=volume['id']) volume_id=volume['id'])
backup_driver = self.backup_mgr.service.get_backup_driver(self.ctxt) backup_driver = self.backup_mgr.get_backup_driver(self.ctxt)
_mock_backup_verify_class = ('%s.%s.%s' % _mock_backup_verify_class = ('%s.%s.%s' %
(backup_driver.__module__, (backup_driver.__module__,
backup_driver.__class__.__name__, backup_driver.__class__.__name__,

View File

@ -0,0 +1,11 @@
---
features:
- |
Add ability to specify backup driver via class name.
upgrade:
- |
Operators should change backup driver configuration value to use class
name to get backup service working in a 'S' release.
deprecations:
- |
Backup driver initialization using module name is deprecated.