Storwize: revert to snapshot support

Adding support for reverting volume to a snapshot
in Storwize/SVC driver.

Change-Id: I0e83162641279ffe242d18dfd3062ce37b3a959b
Implements: blueprint storwize-revert-snapshot
This commit is contained in:
Xiaoqin Li 2017-11-09 02:13:57 -08:00
parent 65e7282652
commit f701d091be
3 changed files with 86 additions and 13 deletions

View File

@ -6341,6 +6341,40 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
uid_of_new_volume = self._get_vdisk_uid(new_volume['name'])
self.assertEqual(uid, uid_of_new_volume)
@mock.patch.object(storwize_svc_common.StorwizeSSH,
'mkfcmap')
@mock.patch.object(storwize_svc_common.StorwizeHelpers,
'_prepare_fc_map')
@mock.patch.object(storwize_svc_common.StorwizeSSH,
'startfcmap')
def test_revert_to_snapshot(self, startfcmap, prepare_fc_map, mkfcmap):
mkfcmap.side_effect = ['1']
vol1 = self._generate_vol_info()
snap1 = self._generate_snap_info(vol1.id)
vol1.size = '11'
self.assertRaises(exception.InvalidInput,
self.driver.revert_to_snapshot, self.ctxt,
vol1, snap1)
vol2 = self._generate_vol_info()
snap2 = self._generate_snap_info(vol2.id)
with mock.patch.object(storwize_svc_common.StorwizeSVCCommonDriver,
'_get_volume_replicated_type') as vol_rep_type:
vol_rep_type.side_effect = [True, False]
self.assertRaises(exception.InvalidInput,
self.driver.revert_to_snapshot, self.ctxt,
vol2, snap2)
self.driver.revert_to_snapshot(self.ctxt, vol2, snap2)
mkfcmap.assert_called_once_with(
snap2.name, vol2.name, True,
self.driver.configuration.storwize_svc_flashcopy_rate)
prepare_fc_map.assert_called_once_with(
'1', self.driver.configuration.storwize_svc_flashcopy_timeout,
True,)
startfcmap.assert_called_once_with('1', True)
class CLIResponseTestCase(test.TestCase):
def test_empty(self):

View File

@ -582,12 +582,18 @@ class StorwizeSSH(object):
raise exception.VolumeBackendAPIException(data=msg)
return fc_map_id
def prestartfcmap(self, fc_map_id):
ssh_cmd = ['svctask', 'prestartfcmap', fc_map_id]
def prestartfcmap(self, fc_map_id, restore=False):
ssh_cmd = ['svctask', 'prestartfcmap']
if restore:
ssh_cmd.append('-restore')
ssh_cmd.append(fc_map_id)
self.run_ssh_assert_no_output(ssh_cmd)
def startfcmap(self, fc_map_id):
ssh_cmd = ['svctask', 'startfcmap', fc_map_id]
def startfcmap(self, fc_map_id, restore=False):
ssh_cmd = ['svctask', 'startfcmap']
if restore:
ssh_cmd.append('-restore')
ssh_cmd.append(fc_map_id)
self.run_ssh_assert_no_output(ssh_cmd)
def prestartfcconsistgrp(self, fc_consist_group):
@ -1461,8 +1467,8 @@ class StorwizeHelpers(object):
copies['secondary'] = copy
return copies
def _prepare_fc_map(self, fc_map_id, timeout):
self.ssh.prestartfcmap(fc_map_id)
def _prepare_fc_map(self, fc_map_id, timeout, restore):
self.ssh.prestartfcmap(fc_map_id, restore)
mapping_ready = False
max_retries = (timeout // self.WAIT_TIME) + 1
for try_number in range(1, max_retries):
@ -1474,7 +1480,7 @@ class StorwizeHelpers(object):
mapping_ready = True
break
elif mapping_attrs['status'] == 'stopped':
self.ssh.prestartfcmap(fc_map_id)
self.ssh.prestartfcmap(fc_map_id, restore)
elif mapping_attrs['status'] != 'preparing':
msg = (_('Unexecpted mapping status %(status)s for mapping '
'%(id)s. Attributes: %(attr)s.')
@ -1650,15 +1656,15 @@ class StorwizeHelpers(object):
return volume_model_updates
def run_flashcopy(self, source, target, timeout, copy_rate,
full_copy=True):
full_copy=True, restore=False):
"""Create a FlashCopy mapping from the source to the target."""
LOG.debug('Enter: run_flashcopy: execute FlashCopy from source '
'%(source)s to target %(target)s.',
{'source': source, 'target': target})
fc_map_id = self.ssh.mkfcmap(source, target, full_copy, copy_rate)
self._prepare_fc_map(fc_map_id, timeout)
self.ssh.startfcmap(fc_map_id)
self._prepare_fc_map(fc_map_id, timeout, restore)
self.ssh.startfcmap(fc_map_id, restore)
LOG.debug('Leave: run_flashcopy: FlashCopy started from '
'%(source)s to %(target)s.',
@ -1704,10 +1710,14 @@ class StorwizeHelpers(object):
return mapping_ids
def _get_flashcopy_mapping_attributes(self, fc_map_id):
resp = self.ssh.lsfcmap(fc_map_id)
if not len(resp):
try:
resp = self.ssh.lsfcmap(fc_map_id)
return resp[0] if len(resp) else None
except exception.VolumeBackendAPIException as ex:
LOG.warning("Failed to get fcmap %(fcmap)s info. "
"Exception: %(ex)s.", {'fcmap': fc_map_id,
'ex': ex})
return None
return resp[0]
def _get_flashcopy_consistgrp_attr(self, fc_map_id):
resp = self.ssh.lsfcconsistgrp(fc_map_id)
@ -1736,6 +1746,8 @@ class StorwizeHelpers(object):
attrs = self._get_flashcopy_mapping_attributes(map_id)
if attrs:
status = attrs['status']
else:
continue
if copy_rate == '0':
if source == name:
@ -4603,6 +4615,30 @@ class StorwizeSVCCommonDriver(san.SanDriver,
return model_update, snapshots_model
@cinder_utils.trace
def revert_to_snapshot(self, context, volume, snapshot):
"""Revert volume to snapshot."""
if snapshot.volume_size != volume.size:
raise exception.InvalidInput(
reason=_('Reverting volume is not supported if the volume '
'size is not equal to the snapshot size.'))
rep_type = self._get_volume_replicated_type(context, volume)
if rep_type:
raise exception.InvalidInput(
reason=_('Reverting replication volume is not supported.'))
try:
self._helpers.run_flashcopy(
snapshot.name, volume.name,
self.configuration.storwize_svc_flashcopy_timeout,
self.configuration.storwize_svc_flashcopy_rate, True, True)
except Exception as err:
msg = (_("Reverting volume %(vol)s to snapshot %(snap)s failed "
"due to: %(err)s.")
% {"vol": volume.name, "snap": snapshot.name, "err": err})
LOG.error(msg)
raise exception.VolumeBackendAPIException(data=msg)
def get_pool(self, volume):
attr = self._helpers.get_vdisk_attributes(volume['name'])

View File

@ -0,0 +1,3 @@
---
features:
- Add reverting to snapshot support in Storwize Cinder driver.