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:
parent
65e7282652
commit
f701d091be
@ -6341,6 +6341,40 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
uid_of_new_volume = self._get_vdisk_uid(new_volume['name'])
|
uid_of_new_volume = self._get_vdisk_uid(new_volume['name'])
|
||||||
self.assertEqual(uid, uid_of_new_volume)
|
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):
|
class CLIResponseTestCase(test.TestCase):
|
||||||
def test_empty(self):
|
def test_empty(self):
|
||||||
|
@ -582,12 +582,18 @@ class StorwizeSSH(object):
|
|||||||
raise exception.VolumeBackendAPIException(data=msg)
|
raise exception.VolumeBackendAPIException(data=msg)
|
||||||
return fc_map_id
|
return fc_map_id
|
||||||
|
|
||||||
def prestartfcmap(self, fc_map_id):
|
def prestartfcmap(self, fc_map_id, restore=False):
|
||||||
ssh_cmd = ['svctask', 'prestartfcmap', fc_map_id]
|
ssh_cmd = ['svctask', 'prestartfcmap']
|
||||||
|
if restore:
|
||||||
|
ssh_cmd.append('-restore')
|
||||||
|
ssh_cmd.append(fc_map_id)
|
||||||
self.run_ssh_assert_no_output(ssh_cmd)
|
self.run_ssh_assert_no_output(ssh_cmd)
|
||||||
|
|
||||||
def startfcmap(self, fc_map_id):
|
def startfcmap(self, fc_map_id, restore=False):
|
||||||
ssh_cmd = ['svctask', 'startfcmap', fc_map_id]
|
ssh_cmd = ['svctask', 'startfcmap']
|
||||||
|
if restore:
|
||||||
|
ssh_cmd.append('-restore')
|
||||||
|
ssh_cmd.append(fc_map_id)
|
||||||
self.run_ssh_assert_no_output(ssh_cmd)
|
self.run_ssh_assert_no_output(ssh_cmd)
|
||||||
|
|
||||||
def prestartfcconsistgrp(self, fc_consist_group):
|
def prestartfcconsistgrp(self, fc_consist_group):
|
||||||
@ -1461,8 +1467,8 @@ class StorwizeHelpers(object):
|
|||||||
copies['secondary'] = copy
|
copies['secondary'] = copy
|
||||||
return copies
|
return copies
|
||||||
|
|
||||||
def _prepare_fc_map(self, fc_map_id, timeout):
|
def _prepare_fc_map(self, fc_map_id, timeout, restore):
|
||||||
self.ssh.prestartfcmap(fc_map_id)
|
self.ssh.prestartfcmap(fc_map_id, restore)
|
||||||
mapping_ready = False
|
mapping_ready = False
|
||||||
max_retries = (timeout // self.WAIT_TIME) + 1
|
max_retries = (timeout // self.WAIT_TIME) + 1
|
||||||
for try_number in range(1, max_retries):
|
for try_number in range(1, max_retries):
|
||||||
@ -1474,7 +1480,7 @@ class StorwizeHelpers(object):
|
|||||||
mapping_ready = True
|
mapping_ready = True
|
||||||
break
|
break
|
||||||
elif mapping_attrs['status'] == 'stopped':
|
elif mapping_attrs['status'] == 'stopped':
|
||||||
self.ssh.prestartfcmap(fc_map_id)
|
self.ssh.prestartfcmap(fc_map_id, restore)
|
||||||
elif mapping_attrs['status'] != 'preparing':
|
elif mapping_attrs['status'] != 'preparing':
|
||||||
msg = (_('Unexecpted mapping status %(status)s for mapping '
|
msg = (_('Unexecpted mapping status %(status)s for mapping '
|
||||||
'%(id)s. Attributes: %(attr)s.')
|
'%(id)s. Attributes: %(attr)s.')
|
||||||
@ -1650,15 +1656,15 @@ class StorwizeHelpers(object):
|
|||||||
return volume_model_updates
|
return volume_model_updates
|
||||||
|
|
||||||
def run_flashcopy(self, source, target, timeout, copy_rate,
|
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."""
|
"""Create a FlashCopy mapping from the source to the target."""
|
||||||
LOG.debug('Enter: run_flashcopy: execute FlashCopy from source '
|
LOG.debug('Enter: run_flashcopy: execute FlashCopy from source '
|
||||||
'%(source)s to target %(target)s.',
|
'%(source)s to target %(target)s.',
|
||||||
{'source': source, 'target': target})
|
{'source': source, 'target': target})
|
||||||
|
|
||||||
fc_map_id = self.ssh.mkfcmap(source, target, full_copy, copy_rate)
|
fc_map_id = self.ssh.mkfcmap(source, target, full_copy, copy_rate)
|
||||||
self._prepare_fc_map(fc_map_id, timeout)
|
self._prepare_fc_map(fc_map_id, timeout, restore)
|
||||||
self.ssh.startfcmap(fc_map_id)
|
self.ssh.startfcmap(fc_map_id, restore)
|
||||||
|
|
||||||
LOG.debug('Leave: run_flashcopy: FlashCopy started from '
|
LOG.debug('Leave: run_flashcopy: FlashCopy started from '
|
||||||
'%(source)s to %(target)s.',
|
'%(source)s to %(target)s.',
|
||||||
@ -1704,10 +1710,14 @@ class StorwizeHelpers(object):
|
|||||||
return mapping_ids
|
return mapping_ids
|
||||||
|
|
||||||
def _get_flashcopy_mapping_attributes(self, fc_map_id):
|
def _get_flashcopy_mapping_attributes(self, fc_map_id):
|
||||||
resp = self.ssh.lsfcmap(fc_map_id)
|
try:
|
||||||
if not len(resp):
|
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 None
|
||||||
return resp[0]
|
|
||||||
|
|
||||||
def _get_flashcopy_consistgrp_attr(self, fc_map_id):
|
def _get_flashcopy_consistgrp_attr(self, fc_map_id):
|
||||||
resp = self.ssh.lsfcconsistgrp(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)
|
attrs = self._get_flashcopy_mapping_attributes(map_id)
|
||||||
if attrs:
|
if attrs:
|
||||||
status = attrs['status']
|
status = attrs['status']
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
|
||||||
if copy_rate == '0':
|
if copy_rate == '0':
|
||||||
if source == name:
|
if source == name:
|
||||||
@ -4603,6 +4615,30 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
|||||||
|
|
||||||
return model_update, snapshots_model
|
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):
|
def get_pool(self, volume):
|
||||||
attr = self._helpers.get_vdisk_attributes(volume['name'])
|
attr = self._helpers.get_vdisk_attributes(volume['name'])
|
||||||
|
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- Add reverting to snapshot support in Storwize Cinder driver.
|
Loading…
x
Reference in New Issue
Block a user