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:
parent
3f4d776778
commit
d317c54edb
@ -3034,6 +3034,70 @@ class HPE3PARBaseDriver(object):
|
|||||||
expected +
|
expected +
|
||||||
self.standard_logout)
|
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):
|
def test_delete_snapshot(self):
|
||||||
# setup_mock_client drive with default configuration
|
# setup_mock_client drive with default configuration
|
||||||
# and return the mock HTTP 3PAR client
|
# and return the mock HTTP 3PAR client
|
||||||
|
@ -264,11 +264,12 @@ class HPE3PARCommon(object):
|
|||||||
3.0.37 - Fixed image cache enabled capability. bug #1686985
|
3.0.37 - Fixed image cache enabled capability. bug #1686985
|
||||||
3.0.38 - Fixed delete operation of replicated volume which is part
|
3.0.38 - Fixed delete operation of replicated volume which is part
|
||||||
of QOS. bug #1717875
|
of QOS. bug #1717875
|
||||||
|
3.0.39 - Add support for revert to snapshot.
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
VERSION = "3.0.38"
|
VERSION = "3.0.39"
|
||||||
|
|
||||||
stats = {}
|
stats = {}
|
||||||
|
|
||||||
@ -3068,6 +3069,49 @@ class HPE3PARCommon(object):
|
|||||||
msg = _("Volume has a temporary snapshot.")
|
msg = _("Volume has a temporary snapshot.")
|
||||||
raise exception.VolumeIsBusy(message=msg)
|
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):
|
def find_existing_vlun(self, volume, host):
|
||||||
"""Finds an existing VLUN for a volume on a host.
|
"""Finds an existing VLUN for a volume on a host.
|
||||||
|
|
||||||
|
@ -675,6 +675,15 @@ class HPE3PARFCDriver(driver.ManageableVD,
|
|||||||
finally:
|
finally:
|
||||||
self._logout(common)
|
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
|
@utils.trace
|
||||||
def migrate_volume(self, context, volume, host):
|
def migrate_volume(self, context, volume, host):
|
||||||
if volume['status'] == 'in-use':
|
if volume['status'] == 'in-use':
|
||||||
|
@ -946,6 +946,15 @@ class HPE3PARISCSIDriver(driver.ManageableVD,
|
|||||||
finally:
|
finally:
|
||||||
self._logout(common)
|
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
|
@utils.trace
|
||||||
def migrate_volume(self, context, volume, host):
|
def migrate_volume(self, context, volume, host):
|
||||||
if volume['status'] == 'in-use':
|
if volume['status'] == 'in-use':
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- Added revert volume to snapshot in 3par driver.
|
Loading…
Reference in New Issue
Block a user