--- /dev/null
+# Copyright (C) 2013 Deutsche Telekom AG
+# 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.
+#
+"""Base class for all backup drivers."""
+
+from cinder.db import base
+
+
+class BackupDriver(base.Base):
+
+ def backup(self, backup, volume_file):
+ """Starts a backup of a specified volume"""
+ raise NotImplementedError()
+
+ def restore(self, backup, volume_id, volume_file):
+ """Restores a saved backup"""
+ raise NotImplementedError()
+
+ def delete(self, backup):
+ """Deletes a saved backup"""
+ raise NotImplementedError()
"""Ceph Backup Service Implementation"""
-from cinder.db import base
+import os
+import time
+
+import eventlet
+from oslo.config import cfg
+
+from cinder.backup.driver import BackupDriver
from cinder import exception
from cinder.openstack.common import log as logging
from cinder import units
import cinder.volume.drivers.rbd as rbddriver
-import eventlet
-import os
-from oslo.config import cfg
-import time
try:
import rados
CONF.register_opts(service_opts)
-class CephBackupService(base.Base):
+class CephBackupDriver(BackupDriver):
"""Backup up Cinder volumes to Ceph Object Store"""
def __init__(self, context, db_driver=None):
- super(CephBackupService, self).__init__(db_driver)
+ super(CephBackupDriver, self).__init__(db_driver)
self.rbd = rbd
self.rados = rados
self.context = context
LOG.debug(_("delete '%s' finished") % (backup_id))
-def get_backup_service(context):
- return CephBackupService(context)
+def get_backup_driver(context):
+ return CephBackupDriver(context)
import eventlet
from oslo.config import cfg
-from cinder.db import base
+from cinder.backup.driver import BackupDriver
from cinder import exception
from cinder.openstack.common import log as logging
from cinder.openstack.common import timeutils
CONF.register_opts(swiftbackup_service_opts)
-class SwiftBackupService(base.Base):
+class SwiftBackupDriver(BackupDriver):
"""Provides backup, restore and delete of backup objects within Swift."""
- SERVICE_VERSION = '1.0.0'
- SERVICE_VERSION_MAPPING = {'1.0.0': '_restore_v1'}
+ DRIVER_VERSION = '1.0.0'
+ DRIVER_VERSION_MAPPING = {'1.0.0': '_restore_v1'}
def _get_compressor(self, algorithm):
try:
preauthtoken=self.context.auth_token,
starting_backoff=self.swift_backoff)
- super(SwiftBackupService, self).__init__(db_driver)
+ super(SwiftBackupDriver, self).__init__(db_driver)
def _check_container_exists(self, container):
LOG.debug(_('_check_container_exists: container: %s') % container)
' metadata filename: %(filename)s') %
{'container': container, 'filename': filename})
metadata = {}
- metadata['version'] = self.SERVICE_VERSION
+ metadata['version'] = self.DRIVER_VERSION
metadata['backup_id'] = backup['id']
metadata['volume_id'] = volume_id
metadata['backup_name'] = backup['display_name']
metadata_version = metadata['version']
LOG.debug(_('Restoring swift backup version %s'), metadata_version)
try:
- restore_func = getattr(self, self.SERVICE_VERSION_MAPPING.get(
+ restore_func = getattr(self, self.DRIVER_VERSION_MAPPING.get(
metadata_version))
except TypeError:
err = (_('No support to restore swift backup version %s')
LOG.debug(_('delete %s finished') % backup['id'])
-def get_backup_service(context):
- return SwiftBackupService(context)
+def get_backup_driver(context):
+ return SwiftBackupDriver(context)
LOG = logging.getLogger(__name__)
backup_manager_opts = [
- cfg.StrOpt('backup_service',
- default='cinder.backup.services.swift',
- help='Service to use for backups.'),
+ cfg.StrOpt('backup_driver',
+ default='cinder.backup.drivers.swift',
+ help='Driver to use for backups.',
+ deprecated_name='backup_service'),
]
+# This map doesn't need to be extended in the future since it's only
+# for old backup services
+mapper = {'cinder.backup.services.swift': 'cinder.backup.drivers.swift',
+ 'cinder.backup.services.ceph': 'cinder.backup.drivers.ceph'}
+
CONF = cfg.CONF
CONF.register_opts(backup_manager_opts)
RPC_API_VERSION = '1.0'
def __init__(self, service_name=None, *args, **kwargs):
- self.service = importutils.import_module(CONF.backup_service)
+ self.service = importutils.import_module(self.driver_name)
self.az = CONF.storage_availability_zone
self.volume_manager = importutils.import_object(
CONF.volume_manager)
*args, **kwargs)
self.driver.db = self.db
+ @property
+ def driver_name(self):
+ """This function maps old backup services to backup drivers."""
+
+ return self._map_service_to_driver(CONF.backup_driver)
+
+ def _map_service_to_driver(self, service):
+ """Maps services to drivers."""
+
+ if service in mapper:
+ return mapper[service]
+ return service
+
def init_host(self):
"""Do any initialization that needs to be run if this is a
standalone service.
{'backup_id': backup_id, 'volume_id': volume_id})
self.db.backup_update(context, backup_id, {'host': self.host,
'service':
- CONF.backup_service})
+ self.driver_name})
expected_status = 'backing-up'
actual_status = volume['status']
raise exception.InvalidBackup(reason=err)
try:
- backup_service = self.service.get_backup_service(context)
+ backup_service = self.service.get_backup_driver(context)
self.driver.backup_volume(context, backup, backup_service)
except Exception as err:
with excutils.save_and_reraise_exception():
volume['id'], volume['size'],
backup['id'], backup['size'])
- backup_service = backup['service']
- configured_service = CONF.backup_service
+ backup_service = self._map_service_to_driver(backup['service'])
+ configured_service = self.driver_name
if backup_service != configured_service:
err = _('restore_backup aborted, the backup service currently'
' configured [%(configured_service)s] is not the'
raise exception.InvalidBackup(reason=err)
try:
- backup_service = self.service.get_backup_service(context)
+ backup_service = self.service.get_backup_driver(context)
self.driver.restore_backup(context, backup, volume,
backup_service)
except Exception as err:
'fail_reason': err})
raise exception.InvalidBackup(reason=err)
- backup_service = backup['service']
+ backup_service = self._map_service_to_driver(backup['service'])
if backup_service is not None:
- configured_service = CONF.backup_service
+ configured_service = self.driver_name
if backup_service != configured_service:
err = _('delete_backup aborted, the backup service currently'
' configured [%(configured_service)s] is not the'
raise exception.InvalidBackup(reason=err)
try:
- backup_service = self.service.get_backup_service(context)
+ backup_service = self.service.get_backup_driver(context)
backup_service.delete(backup)
except Exception as err:
with excutils.save_and_reraise_exception():
# License for the specific language governing permissions and limitations
# under the License.
+from cinder.backup.driver import BackupDriver
from cinder.db import base
from cinder.openstack.common import log as logging
LOG = logging.getLogger(__name__)
-class FakeBackupService(base.Base):
+class FakeBackupService(BackupDriver):
def __init__(self, context, db_driver=None):
super(FakeBackupService, self).__init__(db_driver)
raise IOError('fake')
-def get_backup_service(context):
+def get_backup_driver(context):
return FakeBackupService(context)
CONF.import_opt('policy_file', 'cinder.policy')
CONF.import_opt('volume_driver', 'cinder.volume.manager')
CONF.import_opt('xiv_proxy', 'cinder.volume.drivers.xiv')
-CONF.import_opt('backup_service', 'cinder.backup.manager')
+CONF.import_opt('backup_driver', 'cinder.backup.manager')
def_vol_type = 'fake_vol_type'
conf.set_default('sqlite_synchronous', False)
conf.set_default('policy_file', 'cinder/tests/policy.json')
conf.set_default('xiv_proxy', 'cinder.tests.test_xiv.XIVFakeProxyDriver')
- conf.set_default('backup_service', 'cinder.tests.backup.fake_service')
+ conf.set_default('backup_driver', 'cinder.tests.backup.fake_service')
flags.DECLARE('policy_file', 'cinder.policy')
flags.DECLARE('volume_driver', 'cinder.volume.manager')
flags.DECLARE('xiv_proxy', 'cinder.volume.drivers.xiv')
-flags.DECLARE('backup_service', 'cinder.backup.manager')
+flags.DECLARE('backup_driver', 'cinder.backup.manager')
def_vol_type = 'fake_vol_type'
conf.set_default('sqlite_synchronous', False)
conf.set_default('policy_file', 'cinder/tests/policy.json')
conf.set_default('xiv_proxy', 'cinder.tests.test_xiv.XIVFakeProxyDriver')
- conf.set_default('backup_service', 'cinder.tests.backup.fake_service')
+ conf.set_default('backup_driver', 'cinder.tests.backup.fake_service')
backup['container'] = container
backup['status'] = status
backup['fail_reason'] = ''
- backup['service'] = CONF.backup_service
+ backup['service'] = CONF.backup_driver
backup['size'] = size
backup['object_count'] = object_count
return db.backup_create(self.ctxt, backup)['id']
ctxt_read_deleted = context.get_admin_context('yes')
backups = db.backup_get_all_by_host(ctxt_read_deleted, 'testhost')
self.assertEqual(len(backups), 2)
+
+ def test_backup_manager_driver_name(self):
+ """"Test mapping between backup services and backup drivers."""
+
+ old_setting = CONF.backup_driver
+ setattr(cfg.CONF, 'backup_driver', "cinder.backup.services.swift")
+ backup_mgr = \
+ importutils.import_object(CONF.backup_manager)
+ self.assertEqual('cinder.backup.drivers.swift',
+ backup_mgr.driver_name)
+ setattr(cfg.CONF, 'backup_driver', old_setting)
import tempfile
import uuid
-from cinder.backup.services.ceph import CephBackupService
+from cinder.backup.drivers.ceph import CephBackupDriver
from cinder.tests.backup.fake_rados import mock_rados
from cinder.tests.backup.fake_rados import mock_rbd
-from cinder.backup.services import ceph
+from cinder.backup.drivers import ceph
from cinder import context
from cinder import db
from cinder import exception
self.volume_file.seek(0)
def test_get_rbd_support(self):
- service = CephBackupService(self.ctxt)
+ service = CephBackupDriver(self.ctxt)
self.assertFalse(hasattr(service.rbd, 'RBD_FEATURE_LAYERING'))
self.assertFalse(hasattr(service.rbd, 'RBD_FEATURE_STRIPINGV2'))
self.assertEquals(features, 1 | 2)
def test_tranfer_data_from_rbd(self):
- service = CephBackupService(self.ctxt)
+ service = CephBackupDriver(self.ctxt)
with tempfile.NamedTemporaryFile() as test_file:
self.volume_file.seek(0)
self.assertEquals(checksum.digest(), self.checksum.digest())
def test_tranfer_data_to_rbd(self):
- service = CephBackupService(self.ctxt)
+ service = CephBackupDriver(self.ctxt)
with tempfile.NamedTemporaryFile() as test_file:
checksum = hashlib.sha256()
self.assertEquals(checksum.digest(), self.checksum.digest())
def test_backup_volume_from_file(self):
- service = CephBackupService(self.ctxt)
+ service = CephBackupDriver(self.ctxt)
with tempfile.NamedTemporaryFile() as test_file:
checksum = hashlib.sha256()
super(BackupCephTestCase, self).tearDown()
def test_backup_error1(self):
- service = CephBackupService(self.ctxt)
+ service = CephBackupDriver(self.ctxt)
backup = db.backup_get(self.ctxt, self.backup_id)
self._create_volume_db_entry(self.vol_id, 0)
self.assertRaises(exception.InvalidParameterValue, service.backup,
backup, self.volume_file)
def test_backup_error2(self):
- service = CephBackupService(self.ctxt)
+ service = CephBackupDriver(self.ctxt)
backup = db.backup_get(self.ctxt, self.backup_id)
self._create_volume_db_entry(self.vol_id, 1)
self.assertRaises(exception.BackupVolumeInvalidType, service.backup,
backup, None)
def test_backup_good(self):
- service = CephBackupService(self.ctxt)
+ service = CephBackupDriver(self.ctxt)
backup = db.backup_get(self.ctxt, self.backup_id)
self._create_volume_db_entry(self.vol_id, 1)
self.assertEquals(checksum.digest(), self.checksum.digest())
def test_restore(self):
- service = CephBackupService(self.ctxt)
+ service = CephBackupDriver(self.ctxt)
self._create_volume_db_entry(self.vol_id, 1)
backup = db.backup_get(self.ctxt, self.backup_id)
self.assertEquals(checksum.digest(), self.checksum.digest())
def test_delete(self):
- service = CephBackupService(self.ctxt)
+ service = CephBackupDriver(self.ctxt)
self._create_volume_db_entry(self.vol_id, 1)
backup = db.backup_get(self.ctxt, self.backup_id)
from swiftclient import client as swift
-from cinder.backup.services.swift import SwiftBackupService
+from cinder.backup.drivers.swift import SwiftBackupDriver
from cinder import context
from cinder import db
from cinder import exception
def test_backup_uncompressed(self):
self._create_backup_db_entry()
self.flags(backup_compression_algorithm='none')
- service = SwiftBackupService(self.ctxt)
+ service = SwiftBackupDriver(self.ctxt)
self.volume_file.seek(0)
backup = db.backup_get(self.ctxt, 123)
service.backup(backup, self.volume_file)
def test_backup_bz2(self):
self._create_backup_db_entry()
self.flags(backup_compression_algorithm='bz2')
- service = SwiftBackupService(self.ctxt)
+ service = SwiftBackupDriver(self.ctxt)
self.volume_file.seek(0)
backup = db.backup_get(self.ctxt, 123)
service.backup(backup, self.volume_file)
def test_backup_zlib(self):
self._create_backup_db_entry()
self.flags(backup_compression_algorithm='zlib')
- service = SwiftBackupService(self.ctxt)
+ service = SwiftBackupDriver(self.ctxt)
self.volume_file.seek(0)
backup = db.backup_get(self.ctxt, 123)
service.backup(backup, self.volume_file)
def test_backup_default_container(self):
self._create_backup_db_entry(container=None)
- service = SwiftBackupService(self.ctxt)
+ service = SwiftBackupDriver(self.ctxt)
self.volume_file.seek(0)
backup = db.backup_get(self.ctxt, 123)
service.backup(backup, self.volume_file)
def test_backup_custom_container(self):
container_name = 'fake99'
self._create_backup_db_entry(container=container_name)
- service = SwiftBackupService(self.ctxt)
+ service = SwiftBackupDriver(self.ctxt)
self.volume_file.seek(0)
backup = db.backup_get(self.ctxt, 123)
service.backup(backup, self.volume_file)
def test_create_backup_container_check_wraps_socket_error(self):
container_name = 'socket_error_on_head'
self._create_backup_db_entry(container=container_name)
- service = SwiftBackupService(self.ctxt)
+ service = SwiftBackupDriver(self.ctxt)
self.volume_file.seek(0)
backup = db.backup_get(self.ctxt, 123)
self.assertRaises(exception.SwiftConnectionFailed,
def test_create_backup_put_object_wraps_socket_error(self):
container_name = 'socket_error_on_put'
self._create_backup_db_entry(container=container_name)
- service = SwiftBackupService(self.ctxt)
+ service = SwiftBackupDriver(self.ctxt)
self.volume_file.seek(0)
backup = db.backup_get(self.ctxt, 123)
self.assertRaises(exception.SwiftConnectionFailed,
def test_restore(self):
self._create_backup_db_entry()
- service = SwiftBackupService(self.ctxt)
+ service = SwiftBackupDriver(self.ctxt)
with tempfile.NamedTemporaryFile() as volume_file:
backup = db.backup_get(self.ctxt, 123)
def test_restore_wraps_socket_error(self):
container_name = 'socket_error_on_get'
self._create_backup_db_entry(container=container_name)
- service = SwiftBackupService(self.ctxt)
+ service = SwiftBackupDriver(self.ctxt)
with tempfile.NamedTemporaryFile() as volume_file:
backup = db.backup_get(self.ctxt, 123)
def test_restore_unsupported_version(self):
container_name = 'unsupported_version'
self._create_backup_db_entry(container=container_name)
- service = SwiftBackupService(self.ctxt)
+ service = SwiftBackupDriver(self.ctxt)
with tempfile.NamedTemporaryFile() as volume_file:
backup = db.backup_get(self.ctxt, 123)
def test_delete(self):
self._create_backup_db_entry()
- service = SwiftBackupService(self.ctxt)
+ service = SwiftBackupDriver(self.ctxt)
backup = db.backup_get(self.ctxt, 123)
service.delete(backup)
def test_delete_wraps_socket_error(self):
container_name = 'socket_error_on_delete'
self._create_backup_db_entry(container=container_name)
- service = SwiftBackupService(self.ctxt)
+ service = SwiftBackupDriver(self.ctxt)
backup = db.backup_get(self.ctxt, 123)
self.assertRaises(exception.SwiftConnectionFailed,
service.delete,
backup)
def test_get_compressor(self):
- service = SwiftBackupService(self.ctxt)
+ service = SwiftBackupDriver(self.ctxt)
compressor = service._get_compressor('None')
self.assertEquals(compressor, None)
compressor = service._get_compressor('zlib')
self.assertRaises(ValueError, service._get_compressor, 'fake')
def test_check_container_exists(self):
- service = SwiftBackupService(self.ctxt)
+ service = SwiftBackupDriver(self.ctxt)
exists = service._check_container_exists('fake_container')
self.assertEquals(exists, True)
exists = service._check_container_exists('missing_container')
#
# Service to use for backups. (string value)
-#backup_service=cinder.backup.services.swift
+#backup_driver=cinder.backup.drivers.swift
#
-# Options defined in cinder.backup.services.swift
+# Options defined in cinder.backup.drivers.swift
#
# The URL of the Swift endpoint (string value)