3PAR: Cinder volume revert to snapshot support

This commit implements reverting volume to a snapshot
when backend_storage is 3PAR

Change-Id: Ib89e68df8b93724e6042fa535139bd86fd232d92
This commit is contained in:
Vivek Soni 2017-09-21 01:57:29 -07:00
parent 3f4d776778
commit d317c54edb
5 changed files with 130 additions and 1 deletions

View File

@ -3034,6 +3034,70 @@ class HPE3PARBaseDriver(object):
expected +
self.standard_logout)
def test_revert_to_snapshot(self):
# setup_mock_client drive with default configuration
# and return the mock HTTP 3PAR client
volume = {'name': self.VOLUME_NAME,
'id': self.VOLUME_ID_SNAP,
'display_name': 'Foo Volume',
'size': 2,
'host': self.FAKE_CINDER_HOST,
'volume_type': None,
'volume_type_id': None}
mock_client = self.setup_driver()
mock_client.isOnlinePhysicalCopy.return_value = False
with mock.patch.object(hpecommon.HPE3PARCommon,
'_create_client') as mock_create_client:
mock_create_client.return_value = mock_client
self.driver.revert_to_snapshot(self.ctxt, volume, self.snapshot)
expected = [
mock.call.isOnlinePhysicalCopy('osv-dh-F5VGRTseuujPjbeRBVg'),
mock.call.promoteVirtualCopy('oss-L4I73ONuTci9Fd4ceij-MQ',
optional={})
]
mock_client.assert_has_calls(
self.standard_login +
expected +
self.standard_logout)
@mock.patch.object(volume_types, 'get_volume_type')
def test_revert_to_snapshot_replicated_volume(self, _mock_volume_types):
_mock_volume_types.return_value = {
'name': 'replicated',
'extra_specs': {
'replication_enabled': '<is> True',
'volume_type': self.volume_type_replicated}}
mock_client = self.setup_driver()
mock_client.isOnlinePhysicalCopy.return_value = True
mock_client.getStorageSystemInfo.return_value = mock.ANY
with mock.patch.object(hpecommon.HPE3PARCommon,
'_create_client') as mock_create_client:
mock_create_client.return_value = mock_client
self.driver.revert_to_snapshot(
self.ctxt,
self.volume_replicated,
self.snapshot)
expected = [
mock.call.stopRemoteCopy('rcg-0DM4qZEVSKON-DXN-N'),
mock.call.isOnlinePhysicalCopy('osv-0DM4qZEVSKON-DXN-NwVpw'),
mock.call.promoteVirtualCopy(
'oss-L4I73ONuTci9Fd4ceij-MQ',
optional={'online': True, 'allowRemoteCopyParent': True}),
mock.call.startRemoteCopy('rcg-0DM4qZEVSKON-DXN-N')
]
mock_client.assert_has_calls(
self.get_id_login +
self.standard_logout +
self.standard_login +
expected +
self.standard_logout)
def test_delete_snapshot(self):
# setup_mock_client drive with default configuration
# and return the mock HTTP 3PAR client

View File

@ -264,11 +264,12 @@ class HPE3PARCommon(object):
3.0.37 - Fixed image cache enabled capability. bug #1686985
3.0.38 - Fixed delete operation of replicated volume which is part
of QOS. bug #1717875
3.0.39 - Add support for revert to snapshot.
"""
VERSION = "3.0.38"
VERSION = "3.0.39"
stats = {}
@ -3068,6 +3069,49 @@ class HPE3PARCommon(object):
msg = _("Volume has a temporary snapshot.")
raise exception.VolumeIsBusy(message=msg)
def revert_to_snapshot(self, volume, snapshot):
"""Revert volume to snapshot.
:param volume: A dictionary describing the volume to revert
:param snapshot: A dictionary describing the latest snapshot
"""
volume_name = self._get_3par_vol_name(volume['id'])
snapshot_name = self._get_3par_snap_name(snapshot['id'])
rcg_name = self._get_3par_rcg_name(volume['id'])
optional = {}
replication_flag = self._volume_of_replicated_type(volume)
if replication_flag:
LOG.debug("Found replicated volume: %(volume)s.",
{'volume': volume_name})
optional['allowRemoteCopyParent'] = True
try:
self.client.stopRemoteCopy(rcg_name)
except Exception as ex:
msg = (_("There was an error stoping remote copy: %s.") %
six.text_type(ex))
LOG.error(msg)
raise exception.VolumeBackendAPIException(data=msg)
if self.client.isOnlinePhysicalCopy(volume_name):
LOG.debug("Found an online copy for %(volume)s.",
{'volume': volume_name})
optional['online'] = True
self.client.promoteVirtualCopy(snapshot_name, optional=optional)
if replication_flag:
try:
self.client.startRemoteCopy(rcg_name)
except Exception as ex:
msg = (_("There was an error starting remote copy: %s.") %
six.text_type(ex))
LOG.error(msg)
raise exception.VolumeBackendAPIException(data=msg)
LOG.info("Volume %(volume)s succesfully reverted to %(snap)s.",
{'volume': volume_name, 'snap': snapshot_name})
def find_existing_vlun(self, volume, host):
"""Finds an existing VLUN for a volume on a host.

View File

@ -675,6 +675,15 @@ class HPE3PARFCDriver(driver.ManageableVD,
finally:
self._logout(common)
@utils.trace
def revert_to_snapshot(self, context, volume, snapshot):
"""Revert volume to snapshot."""
common = self._login()
try:
common.revert_to_snapshot(volume, snapshot)
finally:
self._logout(common)
@utils.trace
def migrate_volume(self, context, volume, host):
if volume['status'] == 'in-use':

View File

@ -946,6 +946,15 @@ class HPE3PARISCSIDriver(driver.ManageableVD,
finally:
self._logout(common)
@utils.trace
def revert_to_snapshot(self, context, volume, snapshot):
"""Revert volume to snapshot."""
common = self._login()
try:
common.revert_to_snapshot(volume, snapshot)
finally:
self._logout(common)
@utils.trace
def migrate_volume(self, context, volume, host):
if volume['status'] == 'in-use':

View File

@ -0,0 +1,3 @@
---
features:
- Added revert volume to snapshot in 3par driver.