VMAX driver - Create a CG from a source CG

Currently, we can only create a consistency group from a
cg snapshot. This updates the api to accommodate creating
a cg from another cg

Change-Id: I6fd01739b62fd399cf9a397431c10a2a7f7ec0f2
Implements: blueprint vmax-clone-cg
This commit is contained in:
Helen Walsh 2016-09-26 17:21:16 +01:00
parent f2431b5d24
commit 24ec725bb2
3 changed files with 63 additions and 24 deletions

View File

@ -3937,6 +3937,34 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
self.assertEqual([{'status': 'available', 'id': '2'}],
volumes_model_update)
@mock.patch.object(
emc_vmax_utils.EMCVMAXUtils,
'find_group_sync_rg_by_target',
return_value="")
@mock.patch.object(
emc_vmax_common.EMCVMAXCommon,
'_find_consistency_group',
return_value=(None, EMCVMAXCommonData.test_CG))
@mock.patch.object(
emc_vmax_common.EMCVMAXCommon,
'_get_pool_and_storage_system',
return_value=(None, EMCVMAXCommonData.storage_system))
@mock.patch.object(
volume_types,
'get_volume_type_extra_specs',
return_value={'volume_backend_name': 'ISCSINoFAST'})
def test_create_consistencygroup_from_source_cg(
self, _mock_volume_type, _mock_storage, _mock_cg, _mock_rg):
volumes = [self.data.test_source_volume]
model_update, volumes_model_update = (
self.driver.create_consistencygroup_from_src(
self.data.test_ctxt, self.data.test_CG, volumes,
source_cg=self.data.test_CG, source_vols=volumes))
self.assertEqual({'status': fields.ConsistencyGroupStatus.AVAILABLE},
model_update)
self.assertEqual([{'status': 'available', 'id': '2'}],
volumes_model_update)
@mock.patch.object(
emc_vmax_common.EMCVMAXCommon,
'_update_pool_stats',

View File

@ -4377,26 +4377,31 @@ class EMCVMAXCommon(object):
volumes_model_update is a list of dictionaries of volume
update
"""
if source_cg or source_vols:
LOG.debug("The VMAX driver does not support creating a "
"consistency group from a consistency group in "
"this version.")
raise NotImplementedError()
if cgsnapshot:
sourceCgName = self.utils.truncate_string(cgsnapshot['id'],
TRUNCATE_8)
source_vols_or_snapshots = snapshots
source_id = cgsnapshot['consistencygroup_id']
elif source_cg:
sourceCgName = self.utils.truncate_string(source_cg['id'],
TRUNCATE_8)
source_vols_or_snapshots = source_vols
source_id = source_cg['id']
else:
exceptionMessage = (_("Must supply either CG snaphot or "
"a source CG."))
raise exception.VolumeBackendAPIException(
data=exceptionMessage)
LOG.debug("Enter EMCVMAXCommon::create_consistencygroup_from_src. "
"Group to be created: %(cgId)s, "
"Source snapshot: %(cgSnapshot)s.",
"Source : %(SourceCGId)s.",
{'cgId': group['id'],
'cgSnapshot': cgsnapshot['consistencygroup_id']})
'SourceCGId': source_id})
self.create_consistencygroup(context, group)
targetCgName = self.utils.truncate_string(group['id'], TRUNCATE_8)
if not snapshots:
exceptionMessage = (_("No source snapshots provided to create "
"consistency group %s.") % targetCgName)
raise exception.VolumeBackendAPIException(
data=exceptionMessage)
modelUpdate = {'status': fields.ConsistencyGroupStatus.AVAILABLE}
try:
@ -4413,9 +4418,14 @@ class EMCVMAXCommon(object):
LOG.debug("Create CG %(targetCg)s from snapshot.",
{'targetCg': targetCgInstanceName})
for volume, snapshot in zip(volumes, snapshots):
volumeSizeInbits = int(self.utils.convert_gb_to_bits(
snapshot['volume_size']))
for volume, source_vol_or_snapshot in zip(
volumes, source_vols_or_snapshots):
if 'size' in source_vol_or_snapshot:
volumeSizeInbits = int(self.utils.convert_gb_to_bits(
source_vol_or_snapshot['size']))
else:
volumeSizeInbits = int(self.utils.convert_gb_to_bits(
source_vol_or_snapshot['volume_size']))
targetVolumeName = 'targetVol'
volume = {'size': int(self.utils.convert_bits_to_gbs(
volumeSizeInbits))}
@ -4432,9 +4442,9 @@ class EMCVMAXCommon(object):
targetVolumeInstance = self.utils.find_volume_instance(
self.conn, volumeDict, targetVolumeName)
LOG.debug("Create target volume for member snapshot. "
"Source snapshot: %(snapshot)s, "
"Source : %(snapshot)s, "
"Target volume: %(targetVol)s.",
{'snapshot': snapshot['id'],
{'snapshot': source_vol_or_snapshot['id'],
'targetVol': targetVolumeInstance.path})
self.provision.add_volume_to_cg(self.conn,
@ -4444,13 +4454,12 @@ class EMCVMAXCommon(object):
targetCgName,
targetVolumeName,
extraSpecs)
sourceCgInstanceName = self._find_consistency_group(
replicationService, str(cgsnapshot['id']))
replicationService, sourceCgName)
if sourceCgInstanceName is None:
exceptionMessage = (_("Cannot find source CG instance. "
"consistencygroup_id: %s.") %
cgsnapshot['consistencygroup_id'])
source_id)
raise exception.VolumeBackendAPIException(
data=exceptionMessage)
relationName = self.utils.truncate_string(group['id'], TRUNCATE_5)
@ -4479,11 +4488,10 @@ class EMCVMAXCommon(object):
self.conn, replicationService,
rgSyncInstanceName, extraSpecs)
except Exception:
cgSnapshotId = cgsnapshot['consistencygroup_id']
exceptionMessage = (_("Failed to create CG %(cgName)s "
"from snapshot %(cgSnapshot)s.")
"from source %(cgSnapshot)s.")
% {'cgName': targetCgName,
'cgSnapshot': cgSnapshotId})
'cgSnapshot': source_id})
LOG.exception(exceptionMessage)
raise exception.VolumeBackendAPIException(data=exceptionMessage)
volumes_model_update = self.utils.get_volume_model_updates(

View File

@ -0,0 +1,3 @@
---
features:
VMAX Driver - Create a CG from a source CG