Implement snapshots-related features for Block Device Driver

This patch adds the create_snapshot, create_volume_from_snapshot
and delete_snapshot methods to Block Device driver.

Related blueprint: block-device-driver-minimum-features-set

Change-Id: If86dca417234ea2c58fbce4e30a1626b288de3f6
This commit is contained in:
Yuriy Nesenenko 2015-12-03 19:47:16 +02:00 committed by yuriy_n
parent d1869d0b1c
commit 5cbec4cd77
2 changed files with 130 additions and 0 deletions

View File

@ -318,3 +318,100 @@ class TestBlockDeviceDriver(cinder.test.TestCase):
self.drv.extend_volume, TEST_VOLUME, 2)
lp_mocked.assert_called_once_with(TEST_VOLUME)
mock_get_size.assert_called_once_with(['/dev/loop1'])
@mock.patch('cinder.volume.utils.copy_volume')
def test_create_snapshot(self, _copy_volume):
TEST_VOLUME = obj_volume.Volume(id=1,
name_id='1234',
size=1,
display_name='vol1',
status='available',
provider_location='/dev/loop1')
TEST_SNAP = obj_snap.Snapshot(id=1,
volume_id=1,
volume_size=1024,
provider_location='/dev/loop2',
volume=TEST_VOLUME)
with mock.patch.object(self.drv, 'find_appropriate_size_device',
return_value='/dev/loop2') as fasd_mocked:
with mock.patch.object(self.drv, '_get_devices_sizes',
return_value={'/dev/loop2': 1024}) as \
gds_mocked:
with mock.patch.object(self.drv,
'_update_provider_location') as \
upl_mocked:
volutils.copy_volume('/dev/loop1', fasd_mocked, 1024,
mock.sentinel,
execute=self.drv._execute)
self.drv.create_snapshot(TEST_SNAP)
fasd_mocked.assert_called_once_with(TEST_SNAP.volume_size)
gds_mocked.assert_called_once_with(['/dev/loop2'])
upl_mocked.assert_called_once_with(
TEST_SNAP, '/dev/loop2')
def test_create_snapshot_with_not_available_volume(self):
TEST_VOLUME = obj_volume.Volume(id=1,
name_id='1234',
size=1,
display_name='vol1',
status='in use',
provider_location='/dev/loop1')
TEST_SNAP = obj_snap.Snapshot(id=1,
volume_id=1,
volume_size=1024,
provider_location='/dev/loop2',
volume=TEST_VOLUME)
self.assertRaises(cinder.exception.CinderException,
self.drv.create_snapshot, TEST_SNAP)
@mock.patch('cinder.volume.utils.copy_volume')
def test_create_volume_from_snapshot(self, _copy_volume):
TEST_SNAP = obj_snap.Snapshot(volume_id=1,
volume_size=1024,
provider_location='/dev/loop1')
TEST_VOLUME = obj_volume.Volume(id=1,
name_id='1234',
size=1,
display_name='vol1',
provider_location='/dev/loop2')
with mock.patch.object(self.drv, 'find_appropriate_size_device',
return_value='/dev/loop2') as fasd_mocked:
with mock.patch.object(self.drv, '_get_devices_sizes',
return_value={'/dev/loop2': 1024}) as \
gds_mocked:
with mock.patch.object(self.drv,
'_update_provider_location') as \
upl_mocked:
volutils.copy_volume('/dev/loop1', fasd_mocked, 1024,
mock.sentinel,
execute=self.drv._execute)
self.drv.create_volume_from_snapshot(
TEST_VOLUME, TEST_SNAP)
fasd_mocked.assert_called_once_with(
TEST_SNAP.volume_size)
gds_mocked.assert_called_once_with(['/dev/loop2'])
upl_mocked.assert_called_once_with(
TEST_VOLUME, '/dev/loop2')
@mock.patch('os.path.exists', return_value=True)
@mock.patch('cinder.volume.utils.clear_volume')
def test_delete_snapshot(self, _clear_volume, _exists):
TEST_SNAP = obj_snap.Snapshot(volume_id=1,
provider_location='/dev/loop1',
status='available')
with mock.patch.object(self.drv, 'local_path',
return_value='/dev/loop1') as lp_mocked:
with mock.patch.object(self.drv, '_get_devices_sizes',
return_value={'/dev/loop1': 1}) as \
gds_mocked:
volutils.clear_volume(gds_mocked, lp_mocked)
self.drv.delete_snapshot(TEST_SNAP)
lp_mocked.assert_called_once_with(TEST_SNAP)
gds_mocked.assert_called_once_with(['/dev/loop1'])
self.assertTrue(_exists.called)
self.assertTrue(_clear_volume.called)

View File

@ -229,6 +229,39 @@ class BlockDeviceDriver(driver.BaseVD, driver.LocalVD,
LOG.error(msg, resource=volume)
raise exception.CinderException(msg)
@utils.synchronized('block_device', external=True)
def create_snapshot(self, snapshot):
volume = snapshot.volume
if volume.status != 'available':
msg = _("Volume is not available.")
LOG.error(msg, resource=volume)
raise exception.CinderException(msg)
LOG.info(_LI('Creating volume snapshot: %s.'), snapshot.id)
device = self.find_appropriate_size_device(snapshot.volume_size)
dev_size = self._get_devices_sizes([device])
volutils.copy_volume(
self.local_path(volume), device,
dev_size[device],
self.configuration.volume_dd_blocksize,
execute=self._execute)
self._update_provider_location(snapshot, device)
def delete_snapshot(self, snapshot):
self._clear_block_device(snapshot)
@utils.synchronized('block_device', external=True)
def create_volume_from_snapshot(self, volume, snapshot):
LOG.info(_LI('Creating volume %s from snapshot.'), volume.id)
device = self.find_appropriate_size_device(snapshot.volume_size)
dev_size = self._get_devices_sizes([device])
volutils.copy_volume(
self.local_path(snapshot), device,
dev_size[device],
self.configuration.volume_dd_blocksize,
execute=self._execute)
self._update_provider_location(volume, device)
# ####### Interface methods for DataPath (Target Driver) ########
def ensure_export(self, context, volume):