]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Scality SOFS: implement volume backup and restore
authorJordanP <jordan.pittier@scality.com>
Tue, 18 Nov 2014 13:34:39 +0000 (14:34 +0100)
committerJordanP <jordan.pittier@scality.com>
Fri, 21 Nov 2014 17:23:46 +0000 (18:23 +0100)
Add support in Scality SOFS driver for volume backup interface
to backup or restore a volume using backup service
specified in cinder.conf.

Change-Id: I6b4b132c7aec9d0e9e558fd30036cf95d80698d1

cinder/tests/test_scality.py
cinder/volume/drivers/scality.py

index b001856214009eeedbb27a1fff8f0066a86d1df3..b9d1529b903bc2338699c94e2fd9a9060a17a40f 100644 (file)
@@ -27,6 +27,8 @@ from oslo.utils import units
 from cinder import context
 from cinder import exception
 from cinder.image import image_utils
+from cinder.openstack.common import fileutils
+from cinder.openstack.common import imageutils
 from cinder import test
 from cinder import utils
 from cinder.volume import configuration as conf
@@ -286,3 +288,59 @@ class ScalityDriverTestCase(test.TestCase):
         self.mox.ReplayAll()
 
         self._driver.extend_volume(self.TEST_VOLUME, self.TEST_NEWSIZE)
+
+    def test_backup_volume(self):
+        self.mox.StubOutWithMock(self._driver, 'db')
+        self.mox.StubOutWithMock(self._driver.db, 'volume_get')
+
+        volume = {'id': '2', 'name': self.TEST_VOLNAME}
+        self._driver.db.volume_get(context, volume['id']).AndReturn(volume)
+
+        info = imageutils.QemuImgInfo()
+        info.file_format = 'raw'
+        self.mox.StubOutWithMock(image_utils, 'qemu_img_info')
+        image_utils.qemu_img_info(self.TEST_VOLPATH).AndReturn(info)
+
+        self.mox.StubOutWithMock(utils, 'temporary_chown')
+        mock_tempchown = self.mox.CreateMockAnything()
+        utils.temporary_chown(self.TEST_VOLPATH).AndReturn(mock_tempchown)
+        mock_tempchown.__enter__()
+        mock_tempchown.__exit__(None, None, None)
+
+        self.mox.StubOutWithMock(fileutils, 'file_open')
+        mock_fileopen = self.mox.CreateMockAnything()
+        fileutils.file_open(self.TEST_VOLPATH).AndReturn(mock_fileopen)
+        mock_fileopen.__enter__()
+        mock_fileopen.__exit__(None, None, None)
+
+        backup = {'volume_id': volume['id']}
+        mock_servicebackup = self.mox.CreateMockAnything()
+        mock_servicebackup.backup(backup, mox_lib.IgnoreArg())
+
+        self.mox.ReplayAll()
+        self._driver.backup_volume(context, backup, mock_servicebackup)
+        self.mox.VerifyAll()
+
+    def test_restore_backup(self):
+        volume = {'id': '2', 'name': self.TEST_VOLNAME}
+
+        self.mox.StubOutWithMock(utils, 'temporary_chown')
+        mock_tempchown = self.mox.CreateMockAnything()
+        utils.temporary_chown(self.TEST_VOLPATH).AndReturn(mock_tempchown)
+        mock_tempchown.__enter__()
+        mock_tempchown.__exit__(None, None, None)
+
+        self.mox.StubOutWithMock(fileutils, 'file_open')
+        mock_fileopen = self.mox.CreateMockAnything()
+        fileutils.file_open(self.TEST_VOLPATH, 'wb').AndReturn(mock_fileopen)
+        mock_fileopen.__enter__()
+        mock_fileopen.__exit__(None, None, None)
+
+        backup = {'id': 123, 'volume_id': volume['id']}
+        mock_servicebackup = self.mox.CreateMockAnything()
+        mock_servicebackup.restore(backup, volume['id'], mox_lib.IgnoreArg())
+
+        self.mox.ReplayAll()
+        self._driver.restore_backup(context, backup, volume,
+                                    mock_servicebackup)
+        self.mox.VerifyAll()
index 282ac3a1b71e41b39f2137a8ec9d23165cf4940e..583fa3f4ad92a5ce23fb03b6cb313dd16d2ef340 100644 (file)
@@ -26,9 +26,11 @@ from oslo.utils import units
 import six.moves.urllib.parse as urlparse
 
 from cinder import exception
-from cinder.i18n import _
+from cinder.i18n import _, _LI
 from cinder.image import image_utils
+from cinder.openstack.common import fileutils
 from cinder.openstack.common import log as logging
+from cinder import utils
 from cinder.volume import driver
 
 
@@ -283,8 +285,30 @@ class ScalityDriver(driver.VolumeDriver):
 
     def backup_volume(self, context, backup, backup_service):
         """Create a new backup from an existing volume."""
-        raise NotImplementedError()
+        volume = self.db.volume_get(context, backup['volume_id'])
+        volume_local_path = self.local_path(volume)
+        LOG.info(_LI('Begin backup of volume %s.') % volume['name'])
+
+        qemu_img_info = image_utils.qemu_img_info(volume_local_path)
+        if qemu_img_info.file_format != 'raw':
+            msg = _('Backup is only supported for raw-formatted '
+                    'SOFS volumes.')
+            raise exception.InvalidVolume(msg)
+
+        if qemu_img_info.backing_file is not None:
+            msg = _('Backup is only supported for SOFS volumes '
+                    'without backing file.')
+            raise exception.InvalidVolume(msg)
+
+        with utils.temporary_chown(volume_local_path):
+            with fileutils.file_open(volume_local_path) as volume_file:
+                backup_service.backup(backup, volume_file)
 
     def restore_backup(self, context, backup, volume, backup_service):
         """Restore an existing backup to a new or existing volume."""
-        raise NotImplementedError()
+        LOG.info(_LI('Restoring backup %(backup)s to volume %(volume)s.') %
+                 {'backup': backup['id'], 'volume': volume['name']})
+        volume_local_path = self.local_path(volume)
+        with utils.temporary_chown(volume_local_path):
+            with fileutils.file_open(volume_local_path, 'wb') as volume_file:
+                backup_service.restore(backup, volume['id'], volume_file)