Merge "Add revert to snapshot support in VxFlex OS driver"
This commit is contained in:
commit
c3c7a6328e
@ -0,0 +1,104 @@
|
|||||||
|
# Copyright (c) 2020 Dell Inc. or its subsidiaries.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
|
from cinder import context
|
||||||
|
from cinder import exception
|
||||||
|
from cinder.tests.unit import fake_constants as fake
|
||||||
|
from cinder.tests.unit import fake_snapshot
|
||||||
|
from cinder.tests.unit import fake_volume
|
||||||
|
from cinder.tests.unit.volume.drivers.dell_emc import vxflexos
|
||||||
|
|
||||||
|
|
||||||
|
class TestRevertVolume(vxflexos.TestVxFlexOSDriver):
|
||||||
|
"""Test cases for ``VxFlexOSDriver.revert_to_snapshot()``"""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
"""Setup a test case environment.
|
||||||
|
|
||||||
|
Creates a fake volume object and sets up the required API responses.
|
||||||
|
"""
|
||||||
|
|
||||||
|
super(TestRevertVolume, self).setUp()
|
||||||
|
ctx = context.RequestContext('fake', 'fake', auth_token=True)
|
||||||
|
host = 'host@backend#{}:{}'.format(
|
||||||
|
self.PROT_DOMAIN_NAME,
|
||||||
|
self.STORAGE_POOL_NAME)
|
||||||
|
self.volume = fake_volume.fake_volume_obj(
|
||||||
|
ctx, **{'provider_id': fake.PROVIDER_ID, 'host': host,
|
||||||
|
'volume_type_id': fake.VOLUME_TYPE_ID,
|
||||||
|
'size': 8})
|
||||||
|
self.snapshot = fake_snapshot.fake_snapshot_obj(
|
||||||
|
ctx, **{'volume_id': self.volume.id,
|
||||||
|
'volume_size': self.volume.size}
|
||||||
|
)
|
||||||
|
self.HTTPS_MOCK_RESPONSES = {
|
||||||
|
self.RESPONSE_MODE.Valid: {
|
||||||
|
'instances/Volume::{}/action/overwriteVolumeContent'.format(
|
||||||
|
self.volume.provider_id
|
||||||
|
): {},
|
||||||
|
},
|
||||||
|
self.RESPONSE_MODE.Invalid: {
|
||||||
|
'version': "2.6",
|
||||||
|
},
|
||||||
|
self.RESPONSE_MODE.BadStatus: {
|
||||||
|
'instances/Volume::{}/action/overwriteVolumeContent'.format(
|
||||||
|
self.volume.provider_id
|
||||||
|
): self.BAD_STATUS_RESPONSE
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
self.volume_is_replicated_mock = self.mock_object(
|
||||||
|
self.volume, 'is_replicated',
|
||||||
|
return_value=False
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_revert_to_snapshot(self):
|
||||||
|
self.driver.revert_to_snapshot(None, self.volume, self.snapshot)
|
||||||
|
|
||||||
|
def test_revert_to_snapshot_badstatus_response(self):
|
||||||
|
self.set_https_response_mode(self.RESPONSE_MODE.BadStatus)
|
||||||
|
self.assertRaises(exception.VolumeBackendAPIException,
|
||||||
|
self.driver.revert_to_snapshot,
|
||||||
|
None, self.volume, self.snapshot)
|
||||||
|
|
||||||
|
def test_revert_to_snapshot_use_generic(self):
|
||||||
|
self.set_https_response_mode(self.RESPONSE_MODE.Invalid)
|
||||||
|
self.assertRaises(NotImplementedError,
|
||||||
|
self.driver.revert_to_snapshot,
|
||||||
|
None, self.volume, self.snapshot)
|
||||||
|
|
||||||
|
def test_revert_to_snapshot_replicated_volume(self):
|
||||||
|
self.volume_is_replicated_mock.return_value = True
|
||||||
|
self.assertRaisesRegexp(
|
||||||
|
exception.InvalidVolume,
|
||||||
|
'Reverting replicated volume is not allowed.',
|
||||||
|
self.driver.revert_to_snapshot,
|
||||||
|
None, self.volume, self.snapshot
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_revert_to_snapshot_size_not_equal(self):
|
||||||
|
patched_volume = mock.MagicMock()
|
||||||
|
patched_volume.id = self.volume.id
|
||||||
|
patched_volume.size = 16
|
||||||
|
patched_volume.is_replicated.return_value = False
|
||||||
|
self.assertRaisesRegexp(
|
||||||
|
exception.InvalidVolume,
|
||||||
|
('Volume %s size is not equal to snapshot %s size.' %
|
||||||
|
(self.volume.id, self.snapshot.id)),
|
||||||
|
self.driver.revert_to_snapshot,
|
||||||
|
None, patched_volume, self.snapshot
|
||||||
|
)
|
@ -89,9 +89,10 @@ class VxFlexOSDriver(driver.VolumeDriver):
|
|||||||
3.5.0 - Add support for VxFlex OS 3.5.x
|
3.5.0 - Add support for VxFlex OS 3.5.x
|
||||||
3.5.1 - Add volume replication v2.1 support for VxFlex OS 3.5.x
|
3.5.1 - Add volume replication v2.1 support for VxFlex OS 3.5.x
|
||||||
3.5.2 - Add volume migration support
|
3.5.2 - Add volume migration support
|
||||||
|
3.5.3 - Add revert volume to snapshot support
|
||||||
"""
|
"""
|
||||||
|
|
||||||
VERSION = "3.5.2"
|
VERSION = "3.5.3"
|
||||||
# ThirdPartySystems wiki
|
# ThirdPartySystems wiki
|
||||||
CI_WIKI_NAME = "DellEMC_VxFlexOS_CI"
|
CI_WIKI_NAME = "DellEMC_VxFlexOS_CI"
|
||||||
|
|
||||||
@ -1502,6 +1503,33 @@ class VxFlexOSDriver(driver.VolumeDriver):
|
|||||||
location = new_volume.provider_location
|
location = new_volume.provider_location
|
||||||
return {"_name_id": name_id, "provider_location": location}
|
return {"_name_id": name_id, "provider_location": location}
|
||||||
|
|
||||||
|
def revert_to_snapshot(self, context, volume, snapshot):
|
||||||
|
"""Revert VxFlex OS volume to the specified snapshot."""
|
||||||
|
|
||||||
|
LOG.info("Revert volume %(vol_id)s to snapshot %(snap_id)s.",
|
||||||
|
{"vol_id": volume.id, "snap_id": snapshot.id})
|
||||||
|
|
||||||
|
client = self._get_client()
|
||||||
|
|
||||||
|
if not flex_utils.version_gte(client.query_rest_api_version(), "3.0"):
|
||||||
|
LOG.debug("VxFlex OS versions less than v3.0 do not "
|
||||||
|
"support reverting volume to snapshot. "
|
||||||
|
"Falling back to generic revert to snapshot method.")
|
||||||
|
raise NotImplementedError
|
||||||
|
elif volume.is_replicated():
|
||||||
|
msg = _("Reverting replicated volume is not allowed.")
|
||||||
|
LOG.error(msg)
|
||||||
|
raise exception.InvalidVolume(reason=msg)
|
||||||
|
elif snapshot.volume_size != volume.size:
|
||||||
|
msg = (_("Volume %(vol_id)s size is not equal to snapshot "
|
||||||
|
"%(snap_id)s size. Revert to snapshot operation is not "
|
||||||
|
"allowed.") %
|
||||||
|
{"vol_id": volume.id, "snap_id": snapshot.id})
|
||||||
|
LOG.error(msg)
|
||||||
|
raise exception.InvalidVolume(reason=msg)
|
||||||
|
|
||||||
|
client.overwrite_volume_content(volume, snapshot)
|
||||||
|
|
||||||
def _query_vxflexos_volume(self, volume, existing_ref):
|
def _query_vxflexos_volume(self, volume, existing_ref):
|
||||||
type_id = volume.get("volume_type_id")
|
type_id = volume.get("volume_type_id")
|
||||||
if "source-id" not in existing_ref:
|
if "source-id" not in existing_ref:
|
||||||
|
@ -686,3 +686,20 @@ class RestClient(object):
|
|||||||
LOG.error(msg)
|
LOG.error(msg)
|
||||||
raise exception.VolumeBackendAPIException(msg)
|
raise exception.VolumeBackendAPIException(msg)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
def overwrite_volume_content(self, volume, snapshot):
|
||||||
|
url = "/instances/Volume::%(vol_id)s/action/overwriteVolumeContent"
|
||||||
|
|
||||||
|
params = {"srcVolumeId": snapshot.provider_id}
|
||||||
|
r, response = self.execute_vxflexos_post_request(
|
||||||
|
url,
|
||||||
|
params=params,
|
||||||
|
vol_id=volume.provider_id
|
||||||
|
)
|
||||||
|
if r.status_code != http_client.OK:
|
||||||
|
msg = (_("Failed to revert volume %(vol_id)s to snapshot "
|
||||||
|
"%(snap_id)s: %(err)s.") % {"vol_id": volume.id,
|
||||||
|
"snap_id": snapshot.id,
|
||||||
|
"err": response["message"]})
|
||||||
|
LOG.error(msg)
|
||||||
|
raise exception.VolumeBackendAPIException(msg)
|
||||||
|
@ -73,6 +73,8 @@ Supported operations
|
|||||||
|
|
||||||
* Create a volume from a snapshot
|
* Create a volume from a snapshot
|
||||||
|
|
||||||
|
* Revert a volume to a snapshot
|
||||||
|
|
||||||
* Copy an image to a volume
|
* Copy an image to a volume
|
||||||
|
|
||||||
* Copy a volume to an image
|
* Copy a volume to an image
|
||||||
|
@ -774,7 +774,7 @@ driver.dell_emc_unity=complete
|
|||||||
driver.dell_emc_vmax_af=complete
|
driver.dell_emc_vmax_af=complete
|
||||||
driver.dell_emc_vmax_3=complete
|
driver.dell_emc_vmax_3=complete
|
||||||
driver.dell_emc_vnx=complete
|
driver.dell_emc_vnx=complete
|
||||||
driver.dell_emc_vxflexos=missing
|
driver.dell_emc_vxflexos=complete
|
||||||
driver.dell_emc_xtremio=missing
|
driver.dell_emc_xtremio=missing
|
||||||
driver.fujitsu_eternus=missing
|
driver.fujitsu_eternus=missing
|
||||||
driver.hpe_3par=complete
|
driver.hpe_3par=complete
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
VxFlex OS driver now supports storage-assisted revert volume to snapshot.
|
Loading…
x
Reference in New Issue
Block a user