replic_service['CreationClassName'] = \
self.data.replication_service_creationclass
replic_services.append(replic_service)
+ replic_service2 = {}
+ replic_service2['SystemName'] = self.data.storage_system_v3
+ replic_service2['CreationClassName'] = (
+ self.data.replication_service_creationclass)
+ replic_services.append(replic_service2)
return replic_services
def _enum_pools(self):
self.driver.delete_cgsnapshot(
self.data.test_ctxt, self.data.test_CG_snapshot)
+ @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_update_CG_add_volume_no_fast_success(
+ self, _mock_volume_type, _mock_storage_system):
+ add_volumes = []
+ add_volumes.append(self.data.test_source_volume)
+ remove_volumes = None
+ self.driver.update_consistencygroup(
+ self.data.test_ctxt, self.data.test_CG,
+ add_volumes, remove_volumes)
+ # Multiple volumes
+ add_volumes.append(self.data.test_source_volume)
+ self.driver.update_consistencygroup(
+ self.data.test_ctxt, self.data.test_CG,
+ add_volumes, remove_volumes)
+ # Can't find CG
+ self.driver.common._find_consistency_group = mock.Mock(
+ return_value=None)
+ self.assertRaises(exception.ConsistencyGroupNotFound,
+ self.driver.update_consistencygroup,
+ self.data.test_ctxt, self.data.test_CG,
+ add_volumes, remove_volumes)
+
+ @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_update_CG_remove_volume_no_fast_success(
+ self, _mock_volume_type, _mock_storage_system):
+ remove_volumes = []
+ remove_volumes.append(self.data.test_source_volume)
+ add_volumes = None
+ self.driver.update_consistencygroup(
+ self.data.test_ctxt, self.data.test_CG,
+ add_volumes, remove_volumes)
+ # Multiple volumes
+ remove_volumes.append(self.data.test_source_volume)
+ self.driver.update_consistencygroup(
+ self.data.test_ctxt, self.data.test_CG,
+ add_volumes, remove_volumes)
+
# Bug https://bugs.launchpad.net/cinder/+bug/1442376
@mock.patch.object(
emc_vmax_common.EMCVMAXCommon,
self.driver.delete_cgsnapshot(
self.data.test_ctxt, self.data.test_CG_snapshot)
+ @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': 'ISCSIFAST'})
+ def test_update_CG_add_volume_fast_success(
+ self, _mock_volume_type, _mock_storage_system):
+ add_volumes = []
+ add_volumes.append(self.data.test_source_volume)
+ remove_volumes = None
+ self.driver.update_consistencygroup(
+ self.data.test_ctxt, self.data.test_CG,
+ add_volumes, remove_volumes)
+ # Multiple volumes
+ add_volumes.append(self.data.test_source_volume)
+ self.driver.update_consistencygroup(
+ self.data.test_ctxt, self.data.test_CG,
+ add_volumes, remove_volumes)
+
+ @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': 'ISCSIFAST'})
+ def test_update_CG_remove_volume_fast_success(
+ self, _mock_volume_type, _mock_storage_system):
+ remove_volumes = []
+ remove_volumes.append(self.data.test_source_volume)
+ add_volumes = None
+ self.driver.update_consistencygroup(
+ self.data.test_ctxt, self.data.test_CG,
+ add_volumes, remove_volumes)
+ # Multiple volumes
+ remove_volumes.append(self.data.test_source_volume)
+ self.driver.update_consistencygroup(
+ self.data.test_ctxt, self.data.test_CG,
+ add_volumes, remove_volumes)
+
def _cleanup(self):
bExists = os.path.exists(self.config_file_path)
if bExists:
self.driver.delete_cgsnapshot(
self.data.test_ctxt, self.data.test_CG_snapshot)
+ @mock.patch.object(
+ emc_vmax_common.EMCVMAXCommon,
+ '_get_pool_and_storage_system',
+ return_value=(None, EMCVMAXCommonData.storage_system_v3))
+ @mock.patch.object(
+ volume_types,
+ 'get_volume_type_extra_specs',
+ return_value={'volume_backend_name': 'V3_BE'})
+ def test_update_CG_add_volume_v3_success(
+ self, _mock_volume_type, _mock_storage_system):
+ add_volumes = []
+ add_volumes.append(self.data.test_source_volume)
+ remove_volumes = None
+ self.driver.update_consistencygroup(
+ self.data.test_ctxt, self.data.test_CG,
+ add_volumes, remove_volumes)
+ # Multiple volumes
+ add_volumes.append(self.data.test_source_volume)
+ self.driver.update_consistencygroup(
+ self.data.test_ctxt, self.data.test_CG,
+ add_volumes, remove_volumes)
+ # Can't find CG
+ self.driver.common._find_consistency_group = mock.Mock(
+ return_value=None)
+ self.assertRaises(exception.ConsistencyGroupNotFound,
+ self.driver.update_consistencygroup,
+ self.data.test_ctxt, self.data.test_CG,
+ add_volumes, remove_volumes)
+
+ @mock.patch.object(
+ emc_vmax_common.EMCVMAXCommon,
+ '_get_pool_and_storage_system',
+ return_value=(None, EMCVMAXCommonData.storage_system_v3))
+ @mock.patch.object(
+ volume_types,
+ 'get_volume_type_extra_specs',
+ return_value={'volume_backend_name': 'V3_BE'})
+ def test_update_CG_remove_volume_v3_success(
+ self, _mock_volume_type, _mock_storage_system):
+ remove_volumes = []
+ remove_volumes.append(self.data.test_source_volume)
+ add_volumes = None
+ self.driver.update_consistencygroup(
+ self.data.test_ctxt, self.data.test_CG,
+ add_volumes, remove_volumes)
+ # Multiple volumes
+ remove_volumes.append(self.data.test_source_volume)
+ self.driver.update_consistencygroup(
+ self.data.test_ctxt, self.data.test_CG,
+ add_volumes, remove_volumes)
+
@mock.patch.object(
emc_vmax_common.EMCVMAXCommon,
'_is_same_host',
from oslo_config import cfg
from oslo_log import log as logging
from oslo_utils import units
-
import six
from cinder import exception
volumeInstance = self.utils.rename_volume(self.conn,
volumeInstance,
volumeId)
+
+ def update_consistencygroup(self, group, add_volumes,
+ remove_volumes):
+ """Updates LUNs in consistency group.
+
+ :param group: storage configuration service instance
+ :param add_volumes: the volumes uuids you want to add to the CG
+ :param remove_volumes: the volumes uuids you want to remove from
+ the CG
+ """
+ LOG.info(_LI("Update Consistency Group: %(group)s. "
+ "This adds and/or removes volumes from a CG."),
+ {'group': group['id']})
+
+ modelUpdate = {'status': 'available'}
+ volumeTypeId = group['volume_type_id'].replace(",", "")
+
+ cg_name = self.utils.truncate_string(group['id'], 8)
+
+ extraSpecs = self._initial_setup(None, volumeTypeId)
+
+ _poolInstanceName, storageSystem = (
+ self._get_pool_and_storage_system(extraSpecs))
+ add_vols = [vol for vol in add_volumes] if add_volumes else []
+ add_instance_names = self._get_volume_instance_names(add_vols)
+ remove_vols = [vol for vol in remove_volumes] if remove_volumes else []
+ remove_instance_names = self._get_volume_instance_names(remove_vols)
+ self.conn = self._get_ecom_connection()
+
+ try:
+ replicationService = self.utils.find_replication_service(
+ self.conn, storageSystem)
+ cgInstanceName = (
+ self._find_consistency_group(replicationService, cg_name))
+ if cgInstanceName is None:
+ raise exception.ConsistencyGroupNotFound(
+ consistencygroup_id=cg_name)
+ # Add volume(s) to a consistency group
+ if add_instance_names:
+ self.provision.add_volume_to_cg(
+ self.conn, replicationService, cgInstanceName,
+ add_instance_names, cg_name, None,
+ extraSpecs)
+ # Remove volume(s) from a consistency group
+ if remove_instance_names:
+ self.provision.remove_volume_from_cg(
+ self.conn, replicationService, cgInstanceName,
+ remove_instance_names, cg_name, None,
+ extraSpecs)
+ except exception.ConsistencyGroupNotFound:
+ raise
+ except Exception as ex:
+ LOG.error(_LE("Exception: %(ex)s"), {'ex': ex})
+ exceptionMessage = (_("Failed to update consistency group:"
+ " %(cgName)s.")
+ % {'cgName': cg_name})
+ LOG.error(exceptionMessage)
+ raise exception.VolumeBackendAPIException(data=exceptionMessage)
+
+ return modelUpdate, None, None
+
+ def _get_volume_instance_names(self, volumes):
+ """Get volume instance names from volume.
+
+ :param volumes: volume objects
+ :returns: volume instance names
+ """
+ volumeInstanceNames = []
+ for volume in volumes:
+ volumeInstance = self._find_lun(volume)
+ if volumeInstance is None:
+ LOG.error(_LE("Volume %(name)s not found on the array."),
+ {'name': volume['name']})
+ else:
+ volumeInstanceNames.append(volumeInstance.path)
+ return volumeInstanceNames
"""
startTime = time.time()
+ if isinstance(volumeInstanceName, list):
+ theElements = volumeInstanceName
+ volumeName = 'Bulk Add'
+ else:
+ theElements = [volumeInstanceName]
+
rc, job = conn.InvokeMethod(
'AddMembers',
replicationService,
- Members=[volumeInstanceName],
+ Members=theElements,
ReplicationGroup=cgInstanceName)
if rc != 0:
extraSpecs)
if rc != 0:
exceptionMessage = (_(
- "Failed to add volume %(volumeName)s: "
- "to consistency group %(cgName)s "
- "Return code: %(rc)lu. Error: %(error)s.")
+ "Failed to add volume %(volumeName)s "
+ "to consistency group %(cgName)s. "
+ "Return code: %(rc)lu. Error: %(error)s.")
% {'volumeName': volumeName,
'cgName': cgName,
'rc': rc,
"""
startTime = time.time()
+ if isinstance(volumeInstanceName, list):
+ theElements = volumeInstanceName
+ volumeName = 'Bulk Remove'
+ else:
+ theElements = [volumeInstanceName]
+
rc, job = conn.InvokeMethod(
'RemoveMembers',
replicationService,
- Members=[volumeInstanceName],
- ReplicationGroup=cgInstanceName,
- RemoveElements=True)
+ Members=theElements,
+ ReplicationGroup=cgInstanceName)
if rc != 0:
rc, errordesc = self.utils.wait_for_job_complete(conn, job,
extraSpecs)
if rc != 0:
exceptionMessage = (_(
- "Failed to remove volume %(volumeName)s: "
- "to consistency group %(cgName)s "
- "Return code: %(rc)lu. Error: %(error)s.")
+ "Failed to remove volume %(volumeName)s "
+ "from consistency group %(cgName)s. "
+ "Return code: %(rc)lu. Error: %(error)s.")
% {'volumeName': volumeName,
'cgName': cgName,
'rc': rc,