Merge "3PAR: Adding volume checks to manage snapshot API"
This commit is contained in:
commit
12fd290098
@ -3460,14 +3460,17 @@ class HPE3PARBaseDriver(object):
|
|||||||
|
|
||||||
new_comment = Comment({
|
new_comment = Comment({
|
||||||
"display_name": "snap",
|
"display_name": "snap",
|
||||||
"volume_name": "volume-007dbfce-7579-40bc-8f90-a20b3902283e",
|
"volume_name": self.VOLUME_NAME,
|
||||||
"volume_id": "007dbfce-7579-40bc-8f90-a20b3902283e",
|
"volume_id": self.VOLUME_ID,
|
||||||
"description": "",
|
"description": "",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
volume = {'id': self.VOLUME_ID}
|
||||||
|
|
||||||
snapshot = {
|
snapshot = {
|
||||||
'display_name': None,
|
'display_name': None,
|
||||||
'id': '007dbfce-7579-40bc-8f90-a20b3902283e',
|
'id': self.SNAPSHOT_ID,
|
||||||
'volume_id': self.VOLUME_ID,
|
'volume': volume,
|
||||||
}
|
}
|
||||||
|
|
||||||
mock_client.getVolume.return_value = {
|
mock_client.getVolume.return_value = {
|
||||||
@ -3493,7 +3496,6 @@ class HPE3PARBaseDriver(object):
|
|||||||
{'newName': oss_matcher,
|
{'newName': oss_matcher,
|
||||||
'comment': new_comment}),
|
'comment': new_comment}),
|
||||||
]
|
]
|
||||||
|
|
||||||
mock_client.assert_has_calls(
|
mock_client.assert_has_calls(
|
||||||
self.standard_login +
|
self.standard_login +
|
||||||
expected +
|
expected +
|
||||||
@ -3503,10 +3505,12 @@ class HPE3PARBaseDriver(object):
|
|||||||
def test_manage_existing_snapshot_invalid_parent(self):
|
def test_manage_existing_snapshot_invalid_parent(self):
|
||||||
mock_client = self.setup_driver()
|
mock_client = self.setup_driver()
|
||||||
|
|
||||||
|
volume = {'id': self.VOLUME_ID}
|
||||||
|
|
||||||
snapshot = {
|
snapshot = {
|
||||||
'display_name': None,
|
'display_name': None,
|
||||||
'id': '007dbfce-7579-40bc-8f90-a20b3902283e',
|
'id': '007dbfce-7579-40bc-8f90-a20b3902283e',
|
||||||
'volume_id': self.VOLUME_ID,
|
'volume': volume,
|
||||||
}
|
}
|
||||||
|
|
||||||
mock_client.getVolume.return_value = {
|
mock_client.getVolume.return_value = {
|
||||||
@ -3536,6 +3540,38 @@ class HPE3PARBaseDriver(object):
|
|||||||
expected +
|
expected +
|
||||||
self.standard_logout)
|
self.standard_logout)
|
||||||
|
|
||||||
|
def test_manage_existing_snapshot_failed_over_volume(self):
|
||||||
|
mock_client = self.setup_driver()
|
||||||
|
|
||||||
|
volume = {
|
||||||
|
'id': self.VOLUME_ID,
|
||||||
|
'replication_status': 'failed-over',
|
||||||
|
}
|
||||||
|
|
||||||
|
snapshot = {
|
||||||
|
'display_name': None,
|
||||||
|
'id': '007dbfce-7579-40bc-8f90-a20b3902283e',
|
||||||
|
'volume': volume,
|
||||||
|
}
|
||||||
|
|
||||||
|
mock_client.getVolume.return_value = {
|
||||||
|
"comment": "{'display_name': 'snap'}",
|
||||||
|
'copyOf': self.VOLUME_NAME_3PAR,
|
||||||
|
}
|
||||||
|
|
||||||
|
with mock.patch.object(hpecommon.HPE3PARCommon,
|
||||||
|
'_create_client') as mock_create_client:
|
||||||
|
mock_create_client.return_value = mock_client
|
||||||
|
common = self.driver._login()
|
||||||
|
|
||||||
|
ums_matcher = common._get_3par_ums_name(snapshot['id'])
|
||||||
|
existing_ref = {'source-name': ums_matcher}
|
||||||
|
|
||||||
|
self.assertRaises(exception.InvalidInput,
|
||||||
|
self.driver.manage_existing_snapshot,
|
||||||
|
snapshot=snapshot,
|
||||||
|
existing_ref=existing_ref)
|
||||||
|
|
||||||
def test_manage_existing_get_size(self):
|
def test_manage_existing_get_size(self):
|
||||||
mock_client = self.setup_driver()
|
mock_client = self.setup_driver()
|
||||||
mock_client.getVolume.return_value = {'sizeMiB': 2048}
|
mock_client.getVolume.return_value = {'sizeMiB': 2048}
|
||||||
@ -3731,6 +3767,22 @@ class HPE3PARBaseDriver(object):
|
|||||||
expected +
|
expected +
|
||||||
self.standard_logout)
|
self.standard_logout)
|
||||||
|
|
||||||
|
def test_unmanage_snapshot_failed_over_volume(self):
|
||||||
|
mock_client = self.setup_driver()
|
||||||
|
|
||||||
|
volume = {'replication_status': 'failed-over', }
|
||||||
|
snapshot = {'id': self.SNAPSHOT_ID,
|
||||||
|
'display_name': 'fake_snap',
|
||||||
|
'volume': volume, }
|
||||||
|
|
||||||
|
with mock.patch.object(hpecommon.HPE3PARCommon,
|
||||||
|
'_create_client') as mock_create_client:
|
||||||
|
mock_create_client.return_value = mock_client
|
||||||
|
|
||||||
|
self.assertRaises(exception.SnapshotIsBusy,
|
||||||
|
self.driver.unmanage_snapshot,
|
||||||
|
snapshot=snapshot)
|
||||||
|
|
||||||
def test__safe_hostname(self):
|
def test__safe_hostname(self):
|
||||||
long_hostname = "abc123abc123abc123abc123abc123abc123"
|
long_hostname = "abc123abc123abc123abc123abc123abc123"
|
||||||
fixed_hostname = "abc123abc123abc123abc123abc123a"
|
fixed_hostname = "abc123abc123abc123abc123abc123a"
|
||||||
|
@ -223,10 +223,11 @@ class HPE3PARCommon(object):
|
|||||||
3.0.7 - Enable standard capabilities based on 3PAR licenses
|
3.0.7 - Enable standard capabilities based on 3PAR licenses
|
||||||
3.0.8 - Optimize array ID retrieval
|
3.0.8 - Optimize array ID retrieval
|
||||||
3.0.9 - Bump minimum API version for volume replication
|
3.0.9 - Bump minimum API version for volume replication
|
||||||
|
3.0.10 - Added additional volumes checks to the manage snapshot API
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
VERSION = "3.0.9"
|
VERSION = "3.0.10"
|
||||||
|
|
||||||
stats = {}
|
stats = {}
|
||||||
|
|
||||||
@ -793,6 +794,15 @@ class HPE3PARCommon(object):
|
|||||||
existing_ref is a dictionary of the form:
|
existing_ref is a dictionary of the form:
|
||||||
{'source-name': <name of the snapshot>}
|
{'source-name': <name of the snapshot>}
|
||||||
"""
|
"""
|
||||||
|
# Potential parent volume for the snapshot
|
||||||
|
volume = snapshot['volume']
|
||||||
|
|
||||||
|
# Do not allow for managing of snapshots for 'failed-over' volumes.
|
||||||
|
if volume.get('replication_status') == 'failed-over':
|
||||||
|
err = (_("Managing of snapshots to failed-over volumes is "
|
||||||
|
"not allowed."))
|
||||||
|
raise exception.InvalidInput(reason=err)
|
||||||
|
|
||||||
target_snap_name = self._get_existing_volume_ref_name(existing_ref,
|
target_snap_name = self._get_existing_volume_ref_name(existing_ref,
|
||||||
is_snapshot=True)
|
is_snapshot=True)
|
||||||
|
|
||||||
@ -806,7 +816,7 @@ class HPE3PARCommon(object):
|
|||||||
raise exception.InvalidInput(reason=err)
|
raise exception.InvalidInput(reason=err)
|
||||||
|
|
||||||
# Make sure the snapshot is being associated with the correct volume.
|
# Make sure the snapshot is being associated with the correct volume.
|
||||||
parent_vol_name = self._get_3par_vol_name(snapshot['volume_id'])
|
parent_vol_name = self._get_3par_vol_name(volume['id'])
|
||||||
if parent_vol_name != snap['copyOf']:
|
if parent_vol_name != snap['copyOf']:
|
||||||
err = (_("The provided snapshot '%s' is not a snapshot of "
|
err = (_("The provided snapshot '%s' is not a snapshot of "
|
||||||
"the provided volume.") % target_snap_name)
|
"the provided volume.") % target_snap_name)
|
||||||
@ -830,8 +840,8 @@ class HPE3PARCommon(object):
|
|||||||
|
|
||||||
# Generate the new snapshot information based on the new ID.
|
# Generate the new snapshot information based on the new ID.
|
||||||
new_snap_name = self._get_3par_snap_name(snapshot['id'])
|
new_snap_name = self._get_3par_snap_name(snapshot['id'])
|
||||||
new_comment['volume_id'] = snapshot['id']
|
new_comment['volume_id'] = volume['id']
|
||||||
new_comment['volume_name'] = 'volume-' + snapshot['id']
|
new_comment['volume_name'] = 'volume-' + volume['id']
|
||||||
if snapshot.get('display_description', None):
|
if snapshot.get('display_description', None):
|
||||||
new_comment['description'] = snapshot['display_description']
|
new_comment['description'] = snapshot['display_description']
|
||||||
else:
|
else:
|
||||||
@ -923,6 +933,18 @@ class HPE3PARCommon(object):
|
|||||||
|
|
||||||
def unmanage_snapshot(self, snapshot):
|
def unmanage_snapshot(self, snapshot):
|
||||||
"""Removes the specified snapshot from Cinder management."""
|
"""Removes the specified snapshot from Cinder management."""
|
||||||
|
# Parent volume for the snapshot
|
||||||
|
volume = snapshot['volume']
|
||||||
|
|
||||||
|
# Do not allow unmanaging of snapshots from 'failed-over' volumes.
|
||||||
|
if volume.get('replication_status') == 'failed-over':
|
||||||
|
err = (_("Unmanaging of snapshots from failed-over volumes is "
|
||||||
|
"not allowed."))
|
||||||
|
LOG.error(err)
|
||||||
|
# TODO(leeantho) Change this exception to Invalid when the volume
|
||||||
|
# manager supports handling that.
|
||||||
|
raise exception.SnapshotIsBusy(snapshot_name=snapshot['id'])
|
||||||
|
|
||||||
# Rename the snapshots's name to ums-* format so that it can be
|
# Rename the snapshots's name to ums-* format so that it can be
|
||||||
# easily found later.
|
# easily found later.
|
||||||
snap_name = self._get_3par_snap_name(snapshot['id'])
|
snap_name = self._get_3par_snap_name(snapshot['id'])
|
||||||
|
Loading…
x
Reference in New Issue
Block a user