Nimble: Add support for revert to snapshot
blueprint nimble-add-revert-to-snapshot-support Change-Id: I63f4ae165486451b8c3da2e5d7a40a4c2a96ad4a
This commit is contained in:
parent
53124744e4
commit
56ee0971b3
@ -154,6 +154,13 @@ FAKE_IGROUP_LIST_RESPONSE_FC = [
|
|||||||
{'wwpn': '10:00:00:00:00:00:00:01'}],
|
{'wwpn': '10:00:00:00:00:00:00:01'}],
|
||||||
'name': 'test-igrp2'}]
|
'name': 'test-igrp2'}]
|
||||||
|
|
||||||
|
FAKE_GET_VOL_INFO_REVERT = {'name': 'testvolume',
|
||||||
|
'id': fake.VOLUME_ID,
|
||||||
|
'clone': False,
|
||||||
|
'target_name': 'iqn.test',
|
||||||
|
'online': True,
|
||||||
|
'agent_type': 'openstack',
|
||||||
|
'last_snap': {'snap_id': fake.SNAPSHOT_ID}}
|
||||||
|
|
||||||
FAKE_CREATE_VOLUME_NEGATIVE_RESPONSE = exception.VolumeBackendAPIException(
|
FAKE_CREATE_VOLUME_NEGATIVE_RESPONSE = exception.VolumeBackendAPIException(
|
||||||
"Volume testvolume not found")
|
"Volume testvolume not found")
|
||||||
@ -173,6 +180,9 @@ FAKE_CREATE_VOLUME_NEGATIVE_DEDUPE = exception.VolumeBackendAPIException(
|
|||||||
FAKE_CREATE_VOLUME_NEGATIVE_QOS = exception.VolumeBackendAPIException(
|
FAKE_CREATE_VOLUME_NEGATIVE_QOS = exception.VolumeBackendAPIException(
|
||||||
"Please set valid IOPS limitin the range [256, 4294967294]")
|
"Please set valid IOPS limitin the range [256, 4294967294]")
|
||||||
|
|
||||||
|
FAKE_VOLUME_RESTORE_NEGATIVE_RESPONSE = exception.VolumeBackendAPIException(
|
||||||
|
"No recent Snapshot found")
|
||||||
|
|
||||||
FAKE_POSITIVE_GROUP_INFO_RESPONSE = {
|
FAKE_POSITIVE_GROUP_INFO_RESPONSE = {
|
||||||
'version_current': '3.0.0.0',
|
'version_current': '3.0.0.0',
|
||||||
'group_target_enabled': False,
|
'group_target_enabled': False,
|
||||||
@ -1189,6 +1199,55 @@ class NimbleDriverSnapshotTestCase(NimbleDriverBaseTestCase):
|
|||||||
'limit': 100}})]
|
'limit': 100}})]
|
||||||
self.mock_client_service.assert_has_calls(expected_calls)
|
self.mock_client_service.assert_has_calls(expected_calls)
|
||||||
|
|
||||||
|
@mock.patch(NIMBLE_URLLIB2)
|
||||||
|
@mock.patch(NIMBLE_CLIENT)
|
||||||
|
@NimbleDriverBaseTestCase.client_mock_decorator(create_configuration(
|
||||||
|
'nimble', 'nimble_pass', '10.18.108.55', 'default', '*'))
|
||||||
|
def test_revert_to_snapshot(self):
|
||||||
|
self.mock_client_service.online_vol.return_value = (
|
||||||
|
FAKE_GENERIC_POSITIVE_RESPONSE)
|
||||||
|
self.mock_client_service.volume_restore.return_value = (
|
||||||
|
FAKE_GENERIC_POSITIVE_RESPONSE)
|
||||||
|
self.mock_client_service.get_vol_info.return_value = (
|
||||||
|
FAKE_GET_VOL_INFO_REVERT)
|
||||||
|
self.mock_client_service.get_netconfig.return_value = (
|
||||||
|
FAKE_POSITIVE_NETCONFIG_RESPONSE)
|
||||||
|
ctx = context.get_admin_context()
|
||||||
|
self.driver.revert_to_snapshot(ctx,
|
||||||
|
{'id': fake.VOLUME_ID,
|
||||||
|
'size': 1,
|
||||||
|
'name': 'testvolume'},
|
||||||
|
{'id': fake.SNAPSHOT_ID,
|
||||||
|
'volume_id': fake.VOLUME_ID})
|
||||||
|
expected_calls = [mock.call.online_vol('testvolume', False),
|
||||||
|
mock.call.volume_restore('testvolume',
|
||||||
|
{'data': {'id': fake.VOLUME_ID,
|
||||||
|
'base_snap_id': fake.SNAPSHOT_ID}}),
|
||||||
|
mock.call.online_vol('testvolume', True)]
|
||||||
|
self.mock_client_service.assert_has_calls(expected_calls)
|
||||||
|
|
||||||
|
@mock.patch(NIMBLE_URLLIB2)
|
||||||
|
@mock.patch(NIMBLE_CLIENT)
|
||||||
|
@NimbleDriverBaseTestCase.client_mock_decorator(create_configuration(
|
||||||
|
'nimble', 'nimble_pass', '10.18.108.55', 'default', '*'))
|
||||||
|
def test_revert_to_snapshot_negative(self):
|
||||||
|
self.mock_client_service.online_vol.return_value = (
|
||||||
|
FAKE_GENERIC_POSITIVE_RESPONSE)
|
||||||
|
self.mock_client_service.volume_restore.side_effect = (
|
||||||
|
FAKE_VOLUME_RESTORE_NEGATIVE_RESPONSE)
|
||||||
|
self.mock_client_service.get_vol_info.return_value = (
|
||||||
|
FAKE_GET_VOL_INFO_REVERT)
|
||||||
|
self.mock_client_service.get_netconfig.return_value = (
|
||||||
|
FAKE_POSITIVE_NETCONFIG_RESPONSE)
|
||||||
|
ctx = context.get_admin_context()
|
||||||
|
self.assertRaises(exception.VolumeBackendAPIException,
|
||||||
|
self.driver.revert_to_snapshot, ctx,
|
||||||
|
{'id': fake.VOLUME_ID,
|
||||||
|
'size': 1,
|
||||||
|
'name': 'testvolume'},
|
||||||
|
{'id': fake.SNAPSHOT_ID,
|
||||||
|
'volume_id': fake.VOLUME_ID})
|
||||||
|
|
||||||
|
|
||||||
class NimbleDriverConnectionTestCase(NimbleDriverBaseTestCase):
|
class NimbleDriverConnectionTestCase(NimbleDriverBaseTestCase):
|
||||||
|
|
||||||
|
@ -737,6 +737,28 @@ class NimbleBaseVolumeDriver(san.SanDriver):
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def revert_to_snapshot(self, context, volume, snapshot):
|
||||||
|
vol_info = self.APIExecutor.get_vol_info(volume['name'])
|
||||||
|
snap_id = vol_info['last_snap']['snap_id']
|
||||||
|
volume_id = vol_info['id']
|
||||||
|
LOG.debug("Reverting volume %(vol)s with snapshot id %(snap_id)s",
|
||||||
|
{'vol': volume['name'], 'snap_id': snap_id})
|
||||||
|
data = {'data': {"base_snap_id": snap_id, "id": volume_id}}
|
||||||
|
try:
|
||||||
|
self.APIExecutor.online_vol(volume['name'], False)
|
||||||
|
self.APIExecutor.volume_restore(volume['name'], data)
|
||||||
|
LOG.info("Volume %(vol)s is successfully restored with "
|
||||||
|
"snap_id %(snap_id)s",
|
||||||
|
{'vol': volume['name'], 'snap_id': snap_id})
|
||||||
|
self.APIExecutor.online_vol(volume['name'], True)
|
||||||
|
except NimbleAPIException as ex:
|
||||||
|
raise NimbleAPIException(_("Unable to restore %(vol)s to "
|
||||||
|
"%(snap_id)s: %(err)s") %
|
||||||
|
{'vol': volume['name'],
|
||||||
|
'snap_id': snap_id,
|
||||||
|
'err': ex.message})
|
||||||
|
return self._get_model_info(volume['name'])
|
||||||
|
|
||||||
|
|
||||||
@interface.volumedriver
|
@interface.volumedriver
|
||||||
class NimbleISCSIDriver(NimbleBaseVolumeDriver, san.SanISCSIDriver):
|
class NimbleISCSIDriver(NimbleBaseVolumeDriver, san.SanISCSIDriver):
|
||||||
@ -1846,6 +1868,11 @@ class NimbleRestAPIExecutor(object):
|
|||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
def volume_restore(self, volume_name, data):
|
||||||
|
volume_id = self.get_volume_id_by_name(volume_name)
|
||||||
|
api = 'volumes/%s/actions/restore' % volume_id
|
||||||
|
self.post(api, data)
|
||||||
|
|
||||||
@_connection_checker
|
@_connection_checker
|
||||||
def get(self, api):
|
def get(self, api):
|
||||||
return self.get_query(api, None)
|
return self.get_query(api, None)
|
||||||
|
@ -38,7 +38,7 @@ Supported operations
|
|||||||
* Retype a volume
|
* Retype a volume
|
||||||
* Create a Thinly Provisioned Volume
|
* Create a Thinly Provisioned Volume
|
||||||
* Attach a volume to multiple servers simultaneously (multiattach)
|
* Attach a volume to multiple servers simultaneously (multiattach)
|
||||||
|
* Volume Revert to Snapshot
|
||||||
|
|
||||||
Nimble Storage driver configuration
|
Nimble Storage driver configuration
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
@ -832,7 +832,7 @@ driver.netapp_ontap=missing
|
|||||||
driver.netapp_solidfire=complete
|
driver.netapp_solidfire=complete
|
||||||
driver.nexenta=missing
|
driver.nexenta=missing
|
||||||
driver.nfs=missing
|
driver.nfs=missing
|
||||||
driver.nimble=missing
|
driver.nimble=complete
|
||||||
driver.prophetstor=missing
|
driver.prophetstor=missing
|
||||||
driver.pure=complete
|
driver.pure=complete
|
||||||
driver.qnap=missing
|
driver.qnap=missing
|
||||||
|
4
releasenotes/notes/1899512-7a872a2c19e53536.yaml
Normal file
4
releasenotes/notes/1899512-7a872a2c19e53536.yaml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Added revert to snapshot feature in Nimble driver.
|
Loading…
x
Reference in New Issue
Block a user