EMCCollections=None, InitiatorMaskingGroup=None,
DeviceMaskingGroup=None, TargetMaskingGroup=None,
ProtocolController=None, StorageID=None, IDType=None,
- WaitForCopyState=None):
+ WaitForCopyState=None, Collections=None):
rc = 0
myjob = SE_ConcreteJob()
self.driver.utils._is_sync_complete = mock.Mock(
return_value=True)
rc = self.driver.utils.wait_for_sync(conn, mysync)
- self.assertIsNone(rc)
+ self.assertIsNotNone(rc)
self.driver.utils._is_sync_complete.assert_called_once_with(
conn, mysync)
self.assertTrue(self.driver.utils._is_sync_complete.return_value)
loopingcall_orig = loopingcall.FixedIntervalLoopingCall
loopingcall.FixedIntervalLoopingCall = mock.Mock()
rc = self.driver.utils.wait_for_sync(conn, mysync)
- self.assertIsNone(rc)
+ self.assertIsNotNone(rc)
loopingcall.FixedIntervalLoopingCall.assert_called_once_with(
mock.ANY)
loopingcall.FixedIntervalLoopingCall.reset_mock()
self.driver.utils._is_sync_complete = mock.Mock(
return_value=True)
rc = self.driver.utils.wait_for_sync(conn, mysync, extraSpecs)
- self.assertIsNone(rc)
+ self.assertIsNotNone(rc)
self.driver.utils._is_sync_complete.assert_called_once_with(
conn, mysync)
self.assertTrue(self.driver.utils._is_sync_complete.return_value)
loopingcall_orig = loopingcall.FixedIntervalLoopingCall
loopingcall.FixedIntervalLoopingCall = mock.Mock()
rc = self.driver.utils.wait_for_sync(conn, mysync)
- self.assertIsNone(rc)
+ self.assertIsNotNone(rc)
loopingcall.FixedIntervalLoopingCall.assert_called_once_with(
mock.ANY)
loopingcall.FixedIntervalLoopingCall.reset_mock()
class EMCVMAXUtilsTest(test.TestCase):
def setUp(self):
-
self.data = EMCVMAXCommonData()
+
super(EMCVMAXUtilsTest, self).setUp()
configuration = mock.Mock()
exception.VolumeBackendAPIException,
self.driver.utils.get_protocol_controller,
conn, hardwareid)
+
+ def test_set_target_element_supplier_in_rsd(self):
+ conn = FakeEcomConnection()
+ extraSpecs = self.data.extra_specs
+ repServiceInstanceName = (
+ self.driver.utils.find_replication_service(
+ conn, self.data.storage_system))
+ rsdInstance = self.driver.utils.set_target_element_supplier_in_rsd(
+ conn, repServiceInstanceName,
+ emc_vmax_common.SNAPVX_REPLICATION_TYPE,
+ emc_vmax_common.CREATE_NEW_TARGET, extraSpecs)
+ self.assertIsNotNone(rsdInstance)
+
+ def test_set_copy_methodology_in_rsd(self):
+ conn = FakeEcomConnection()
+ extraSpecs = self.data.extra_specs
+ repServiceInstanceName = (
+ self.driver.utils.find_replication_service(
+ conn, self.data.storage_system))
+ rsdInstance = self.driver.utils.set_copy_methodology_in_rsd(
+ conn, repServiceInstanceName,
+ emc_vmax_provision.SYNC_CLONE_LOCAL,
+ emc_vmax_provision.COPY_ON_WRITE, extraSpecs)
+ self.assertIsNotNone(rsdInstance)
+
+
+class EMCVMAXCommonTest(test.TestCase):
+ def setUp(self):
+ self.data = EMCVMAXCommonData()
+
+ super(EMCVMAXCommonTest, self).setUp()
+
+ configuration = mock.Mock()
+ configuration.safe_get.return_value = 'CommonTests'
+ configuration.config_group = 'CommonTests'
+ emc_vmax_common.EMCVMAXCommon._gather_info = mock.Mock()
+ driver = emc_vmax_iscsi.EMCVMAXISCSIDriver(configuration=configuration)
+ driver.db = FakeDB()
+ self.driver = driver
+ self.driver.utils = emc_vmax_utils.EMCVMAXUtils(object)
+
+ @mock.patch.object(
+ emc_vmax_common.EMCVMAXCommon,
+ '_get_pool_and_storage_system',
+ return_value=(None, EMCVMAXCommonData.storage_system))
+ def test_create_duplicate_volume(self, mock_pool):
+ common = self.driver.common
+ common.conn = FakeEcomConnection()
+ volumeInstanceName = (
+ common.conn.EnumerateInstanceNames("EMC_StorageVolume")[0])
+ sourceInstance = common.conn.GetInstance(volumeInstanceName)
+ cloneName = "SS-V3-Vol"
+ extraSpecs = {'volume_backend_name': 'V3_BE',
+ 'isV3': True,
+ 'storagetype:pool': 'SRP_1',
+ 'storagetype:workload': 'DSS',
+ 'storagetype:slo': 'Bronze'}
+ targetInstance = common.conn.GetInstance(volumeInstanceName)
+ common.utils.find_volume_instance = mock.Mock(
+ return_value=targetInstance)
+ duplicateVolumeInstance = self.driver.common._create_duplicate_volume(
+ sourceInstance, cloneName, extraSpecs)
+ self.assertIsNotNone(duplicateVolumeInstance)
+
+ def test_cleanup_target(self):
+ common = self.driver.common
+ common.conn = FakeEcomConnection()
+ volumeInstanceName = (
+ common.conn.EnumerateInstanceNames("EMC_StorageVolume")[0])
+ extraSpecs = {'volume_backend_name': 'V3_BE',
+ 'isV3': True,
+ 'storagetype:pool': 'SRP_1',
+ 'storagetype:workload': 'DSS',
+ 'storagetype:slo': 'Bronze'}
+ targetInstance = common.conn.GetInstance(volumeInstanceName)
+ repServiceInstanceName = (
+ self.driver.utils.find_replication_service(
+ common.conn, self.data.storage_system))
+ common.utils.find_sync_sv_by_target = mock.Mock(
+ return_value=(None, None))
+
+ self.driver.common._cleanup_target(
+ repServiceInstanceName, targetInstance, extraSpecs)
ISV3 = 'isV3'
TRUNCATE_5 = 5
TRUNCATE_8 = 8
+SNAPVX = 7
+DISSOLVE_SNAPVX = 9
+CREATE_NEW_TARGET = 2
+SNAPVX_REPLICATION_TYPE = 6
emc_opts = [
cfg.StrOpt('cinder_emc_config_file',
if not extraSpecs[ISV3]:
snapshotInstance = self._find_lun(snapshot)
+ if snapshotInstance is None:
+ LOG.error(_LE(
+ "Snapshot %(snapshotname)s not found on the array. "
+ "No volume to delete."),
+ {'snapshotname': snapshotname})
+ return (-1, snapshotname)
storageSystem = snapshotInstance['SystemName']
# Wait for it to fully sync in case there is an ongoing
:param extraSpecs: extra specifications
:returns: sgInstanceName
"""
- storageGroupName = self.utils.get_v3_storage_group_name(
- poolName, slo, workload)
- controllerConfigService = (
- self.utils.find_controller_configuration_service(
- self.conn, storageSystemName))
- sgInstanceName = self.utils.find_storage_masking_group(
- self.conn, controllerConfigService, storageGroupName)
+ storageGroupName, controllerConfigService, sgInstanceName = (
+ self.utils.get_v3_default_sg_instance_name(
+ self.conn, poolName, slo, workload, storageSystemName))
if sgInstanceName is None:
sgInstanceName = self.provisionv3.create_storage_group_v3(
self.conn, controllerConfigService, storageGroupName,
:returns: dict -- cloneDict
"""
cloneName = cloneVolume['name']
- # Default syncType 8: clone.
- syncType = self.utils.get_num(8, '16')
- # Default operation 8: Detach for clone.
- operation = self.utils.get_num(8, '16')
-
- numOfBlocks = sourceInstance['NumberOfBlocks']
- blockSize = sourceInstance['BlockSize']
- volumeSizeInbits = numOfBlocks * blockSize
-
- volume = {'size':
- int(self.utils.convert_bits_to_gbs(volumeSizeInbits))}
- _rc, volumeDict, _storageSystemName = (
- self._create_v3_volume(
- volume, cloneName, volumeSizeInbits, extraSpecs))
- targetInstance = self.utils.find_volume_instance(
- self.conn, volumeDict, cloneName)
- LOG.debug("Create replica target volume "
- "source volume: %(sourceVol)s, "
- "target volume: %(targetVol)s.",
- {'sourceVol': sourceInstance.path,
- 'targetVol': targetInstance.path})
+ # SyncType 7: snap, VG3R default snapshot is snapVx.
+ syncType = self.utils.get_num(SNAPVX, '16')
+ # Operation 9: Dissolve for snapVx.
+ operation = self.utils.get_num(DISSOLVE_SNAPVX, '16')
+ rsdInstance = None
+ targetInstance = None
if isSnapshot:
- # SyncType 7: snap, VG3R default snapshot is snapVx.
- syncType = self.utils.get_num(7, '16')
- # Operation 9: Dissolve for snapVx.
- operation = self.utils.get_num(9, '16')
+ rsdInstance = self.utils.set_target_element_supplier_in_rsd(
+ self.conn, repServiceInstanceName, SNAPVX_REPLICATION_TYPE,
+ CREATE_NEW_TARGET, extraSpecs)
+ else:
+ targetInstance = self._create_duplicate_volume(
+ sourceInstance, cloneName, extraSpecs)
try:
_rc, job = (
self.provisionv3.create_element_replica(
self.conn, repServiceInstanceName, cloneName, syncType,
- sourceInstance, extraSpecs, targetInstance))
+ sourceInstance, extraSpecs, targetInstance, rsdInstance))
except Exception:
LOG.warning(_LW(
"Clone failed on V3. Cleaning up the target volume. "
"Clone name: %(cloneName)s "),
{'cloneName': cloneName})
# Check if the copy session exists.
- storageSystem = targetInstance['SystemName']
- syncInstanceName = self.utils.find_sync_sv_by_target(
- self.conn, storageSystem, targetInstance, False)
- if syncInstanceName is not None:
- # Break the clone relationship.
- rc, job = self.provisionv3.break_replication_relationship(
- self.conn, repServiceInstanceName, syncInstanceName,
- operation, extraSpecs, True)
- storageConfigService = (
- self.utils.find_storage_configuration_service(
- self.conn, storageSystem))
- deviceId = targetInstance['DeviceID']
- volumeName = targetInstance['Name']
- rc = self._delete_from_pool_v3(
- storageConfigService, targetInstance, volumeName,
- deviceId, extraSpecs)
- # Re-throw the exception.
- raise
+ if targetInstance:
+ self._cleanup_target(
+ repServiceInstanceName, targetInstance, extraSpecs)
+ # Re-throw the exception.
+ raise
cloneDict = self.provisionv3.get_volume_dict_from_job(
self.conn, job['Job'])
+ targetVolumeInstance = (
+ self.provisionv3.get_volume_from_job(self.conn, job['Job']))
+ LOG.info(_LI("The target instance device id is: %(deviceid)s."),
+ {'deviceid': targetVolumeInstance['DeviceID']})
cloneVolume['provider_location'] = six.text_type(cloneDict)
self._find_storage_sync_sv_sv(cloneVolume, sourceVolume,
extraSpecs, True))
- # Detach/dissolve the clone/snap relationship.
- # 8 - Detach operation.
- # 9 - Dissolve operation.
- if isSnapshot:
- # Operation 9: dissolve for snapVx.
- operation = self.utils.get_num(9, '16')
- else:
- # Operation 8: detach for clone.
- operation = self.utils.get_num(8, '16')
-
rc, job = self.provisionv3.break_replication_relationship(
self.conn, repServiceInstanceName, syncInstanceName,
operation, extraSpecs)
return rc, cloneDict
+ def _cleanup_target(
+ self, repServiceInstanceName, targetInstance, extraSpecs):
+ """cleanup target after exception
+
+ :param repServiceInstanceName: the replication service
+ :param targetInstance: the target instance
+ :param extraSpecs: extra specifications
+ """
+ storageSystem = targetInstance['SystemName']
+ syncInstanceName = self.utils.find_sync_sv_by_target(
+ self.conn, storageSystem, targetInstance, False)
+ if syncInstanceName is not None:
+ # Break the clone relationship.
+ self.provisionv3.break_replication_relationship(
+ self.conn, repServiceInstanceName, syncInstanceName,
+ DISSOLVE_SNAPVX, extraSpecs, True)
+ storageConfigService = (
+ self.utils.find_storage_configuration_service(
+ self.conn, storageSystem))
+ deviceId = targetInstance['DeviceID']
+ volumeName = targetInstance['Name']
+ self._delete_from_pool_v3(
+ storageConfigService, targetInstance, volumeName,
+ deviceId, extraSpecs)
+
def _delete_cg_and_members(
self, storageSystem, cgName, modelUpdate, volumes, extraSpecs):
"""Helper function to delete a consistencygroup and its member volumes.
volumeName, new_size_in_bits, extraSpecs)
return rc, volumeDict
+
+ def _create_duplicate_volume(
+ self, sourceInstance, cloneName, extraSpecs):
+ """Create a volume in the same dimensions of the source volume.
+
+ :param sourceInstance: the source volume instance
+ :param cloneName: the user supplied snap name
+ :param extraSpecs: additional info
+ :returns: targetInstance
+ """
+ numOfBlocks = sourceInstance['NumberOfBlocks']
+ blockSize = sourceInstance['BlockSize']
+ volumeSizeInbits = numOfBlocks * blockSize
+
+ volume = {'size':
+ int(self.utils.convert_bits_to_gbs(volumeSizeInbits))}
+ _rc, volumeDict, _storageSystemName = (
+ self._create_v3_volume(
+ volume, cloneName, volumeSizeInbits, extraSpecs))
+ targetInstance = self.utils.find_volume_instance(
+ self.conn, volumeDict, cloneName)
+ LOG.debug("Create replica target volume "
+ "Source Volume: %(sourceVol)s, "
+ "Target Volume: %(targetVol)s.",
+ {'sourceVol': sourceInstance.path,
+ 'targetVol': targetInstance.path})
+ return targetInstance
- Changing PercentSynced to CopyState (bug #1517103)
- Getting iscsi ip from port in existing masking view
- Replacement of EMCGetTargetEndpoints api (bug #1512791)
+ - VMAX3 snapvx improvements (bug #1522821)
"""
VERSION = "2.3.0"
- Changing PercentSynced to CopyState (bug #1517103)
- Getting iscsi ip from port in existing masking view
- Replacement of EMCGetTargetEndpoints api (bug #1512791)
+ - VMAX3 snapvx improvements (bug #1522821)
"""
VERSION = "2.3.0"
EMC_ROOT = 'root/emc'
THINPROVISIONINGCOMPOSITE = 32768
THINPROVISIONING = 5
+SYNC_CLONE_LOCAL = 10
+COPY_ON_WRITE = 6
+TF_CLONE = 8
class EMCVMAXProvision(object):
"""
if copyOnWrite:
startTime = time.time()
- repServiceCapabilityInstanceNames = conn.AssociatorNames(
- repServiceInstanceName,
- ResultClass='CIM_ReplicationServiceCapabilities',
- AssocClass='CIM_ElementCapabilities')
- repServiceCapabilityInstanceName = (
- repServiceCapabilityInstanceNames[0])
-
# ReplicationType 10 - Synchronous Clone Local.
- rc, rsd = conn.InvokeMethod(
- 'GetDefaultReplicationSettingData',
- repServiceCapabilityInstanceName,
- ReplicationType=self.utils.get_num(10, '16'))
-
- if rc != 0:
- rc, errordesc = self.utils.wait_for_job_complete(conn, rsd,
- extraSpecs)
- if rc != 0:
- exceptionMessage = (_(
- "Error creating cloned volume using "
- "Volume: %(cloneName)s, Source Volume: "
- "%(sourceName)s. Return code: %(rc)lu. "
- "Error: %(error)s.")
- % {'cloneName': cloneName,
- 'sourceName': sourceName,
- 'rc': rc,
- 'error': errordesc})
- LOG.error(exceptionMessage)
- raise exception.VolumeBackendAPIException(
- data=exceptionMessage)
-
- LOG.debug("InvokeMethod GetDefaultReplicationSettingData "
- "took: %(delta)s H:MM:SS.",
- {'delta': self.utils.get_time_delta(startTime,
- time.time())})
-
# Set DesiredCopyMethodology to Copy-On-Write (6).
- rsdInstance = rsd['DefaultInstance']
- rsdInstance['DesiredCopyMethodology'] = self.utils.get_num(6, '16')
-
- startTime = time.time()
+ rsdInstance = self.utils.set_copy_methodology_in_rsd(
+ conn, repServiceInstanceName, SYNC_CLONE_LOCAL,
+ COPY_ON_WRITE, extraSpecs)
# SyncType 8 - Clone.
# ReplicationSettingData.DesiredCopyMethodology Copy-On-Write (6).
rc, job = conn.InvokeMethod(
'CreateElementReplica', repServiceInstanceName,
- ElementName=cloneName, SyncType=self.utils.get_num(8, '16'),
+ ElementName=cloneName,
+ SyncType=self.utils.get_num(TF_CLONE, '16'),
ReplicationSettingData=rsdInstance,
SourceElement=sourceInstance.path)
else:
rc, job = conn.InvokeMethod(
'CreateElementReplica', repServiceInstanceName,
ElementName=cloneName,
- SyncType=self.utils.get_num(8, '16'),
+ SyncType=self.utils.get_num(TF_CLONE, '16'),
SourceElement=sourceInstance.path)
else:
rc, job = conn.InvokeMethod(
'CreateElementReplica', repServiceInstanceName,
ElementName=cloneName,
- SyncType=self.utils.get_num(8, '16'),
+ SyncType=self.utils.get_num(TF_CLONE, '16'),
SourceElement=sourceInstance.path,
TargetElement=targetInstance.path)
THINPROVISIONINGCOMPOSITE = 32768
THINPROVISIONING = 5
INFO_SRC_V3 = 3
+ACTIVATESNAPVX = 4
+DEACTIVATESNAPVX = 19
+SNAPSYNCTYPE = 7
class EMCVMAXProvisionV3(object):
associators = conn.Associators(
jobInstance,
ResultClass='EMC_StorageVolume')
- volpath = associators[0].path
+ if len(associators) > 0:
+ return self.create_volume_dict(associators[0].path)
+ else:
+ exceptionMessage = (_(
+ "Unable to get storage volume from job."))
+ LOG.error(exceptionMessage)
+ raise exception.VolumeBackendAPIException(data=exceptionMessage)
+
+ def get_volume_from_job(self, conn, jobInstance):
+ """Given the jobInstance determine the volume Instance.
+
+ :param conn: the ecom connection
+ :param jobInstance: the instance of a job
+ :returns: dict -- volumeDict - an instance of a volume
+ """
+ associators = conn.Associators(
+ jobInstance,
+ ResultClass='EMC_StorageVolume')
+ if len(associators) > 0:
+ return associators[0]
+ else:
+ exceptionMessage = (_(
+ "Unable to get storage volume from job."))
+ LOG.error(exceptionMessage)
+ raise exception.VolumeBackendAPIException(data=exceptionMessage)
+
+ def create_volume_dict(self, volumeInstanceName):
+ """Create volume dictionary
+
+ :param volumeInstanceName: the instance of a job
+ :returns: dict -- volumeDict - an instance of a volume
+ """
+ volpath = volumeInstanceName
volumeDict = {}
volumeDict['classname'] = volpath.classname
keys = {}
def create_element_replica(
self, conn, repServiceInstanceName,
cloneName, syncType, sourceInstance, extraSpecs,
- targetInstance=None):
+ targetInstance=None, rsdInstance=None):
"""Make SMI-S call to create replica for source element.
:param conn: the connection to the ecom server
:param syncType: 7=snapshot, 8=clone
:param sourceInstance: source volume instance
:param extraSpecs: additional info
- :param targetInstance: target volume instance. Defaults to None
+ :param targetInstance: Target volume instance. Default None
+ :param rsdInstance: replication settingdata instance. Default None
:returns: int -- rc - return code
:returns: job - job object of the replica creation operation
:raises: VolumeBackendAPIException
"""
startTime = time.time()
-
- if targetInstance is None:
- LOG.debug("Create targetless replica: %(clone)s "
- "syncType: %(syncType)s Source: %(source)s.",
- {'clone': cloneName,
- 'syncType': syncType,
- 'source': sourceInstance.path})
- rc, job = conn.InvokeMethod(
- 'CreateElementReplica', repServiceInstanceName,
- ElementName=cloneName, SyncType=syncType,
- SourceElement=sourceInstance.path)
- else:
- LOG.debug(
- "Create replica: %(clone)s syncType: %(syncType)s "
- "Source: %(source)s target: %(target)s.",
- {'clone': cloneName,
- 'syncType': syncType,
- 'source': sourceInstance.path,
- 'target': targetInstance.path})
+ LOG.debug("Create replica: %(clone)s "
+ "syncType: %(syncType)s Source: %(source)s.",
+ {'clone': cloneName,
+ 'syncType': syncType,
+ 'source': sourceInstance.path})
+ storageSystemName = sourceInstance['SystemName']
+ __, __, sgInstanceName = (
+ self.utils.get_v3_default_sg_instance_name(
+ conn, extraSpecs[self.utils.POOL],
+ extraSpecs[self.utils.SLO],
+ extraSpecs[self.utils.WORKLOAD], storageSystemName))
+ if targetInstance is None and rsdInstance is None:
rc, job = conn.InvokeMethod(
'CreateElementReplica', repServiceInstanceName,
- ElementName=cloneName, SyncType=syncType,
+ ElementName=cloneName,
+ SyncType=self.utils.get_num(syncType, '16'),
SourceElement=sourceInstance.path,
- TargetElement=targetInstance.path)
+ Collections=[sgInstanceName])
+ else:
+ rc, job = self._create_element_replica_extra_params(
+ conn, repServiceInstanceName, cloneName, syncType,
+ sourceInstance, targetInstance, rsdInstance,
+ sgInstanceName)
if rc != 0:
rc, errordesc = self.utils.wait_for_job_complete(conn, job,
time.time())})
return rc, job
+ def _create_element_replica_extra_params(
+ self, conn, repServiceInstanceName, cloneName, syncType,
+ sourceInstance, targetInstance, rsdInstance, sgInstanceName):
+ """CreateElementReplica using extra parameters.
+
+ :param conn: the connection to the ecom server
+ :param repServiceInstanceName: replication service
+ :param cloneName: clone volume name
+ :param syncType: 7=snapshot, 8=clone
+ :param sourceInstance: source volume instance
+ :param targetInstance: Target volume instance. Default None
+ :param rsdInstance: replication settingdata instance. Default None
+ :param sgInstanceName: pool instance name
+ :returns: int -- rc - return code
+ :returns: job - job object of the replica creation operation
+ """
+ syncType = self.utils.get_num(syncType, '16')
+ if targetInstance and rsdInstance:
+ rc, job = conn.InvokeMethod(
+ 'CreateElementReplica', repServiceInstanceName,
+ ElementName=cloneName,
+ SyncType=syncType,
+ SourceElement=sourceInstance.path,
+ TargetElement=targetInstance.path,
+ ReplicationSettingData=rsdInstance)
+ elif targetInstance:
+ rc, job = conn.InvokeMethod(
+ 'CreateElementReplica', repServiceInstanceName,
+ ElementName=cloneName,
+ SyncType=syncType,
+ SourceElement=sourceInstance.path,
+ TargetElement=targetInstance.path)
+ elif rsdInstance:
+ rc, job = conn.InvokeMethod(
+ 'CreateElementReplica', repServiceInstanceName,
+ ElementName=cloneName,
+ SyncType=syncType,
+ SourceElement=sourceInstance.path,
+ ReplicationSettingData=rsdInstance,
+ Collections=[sgInstanceName])
+
+ return rc, job
+
def break_replication_relationship(
self, conn, repServiceInstanceName, syncInstanceName,
operation, extraSpecs, force=False):
:returns: job object of the replica creation operation
"""
# Operation 4: activate the snapVx.
- operation = self.utils.get_num(4, '16')
+ operation = ACTIVATESNAPVX
LOG.debug("Activate snap: %(sv)s operation: %(operation)s.",
{'sv': syncInstanceName, 'operation': operation})
:returns: job object of the replica creation operation
"""
# Operation 4: activate the snapVx.
- operation = self.utils.get_num(19, '16')
+ operation = DEACTIVATESNAPVX
LOG.debug("Return snap resource back to pool: "
"%(sv)s operation: %(operation)s.",
rc, job = conn.InvokeMethod(
'ModifyReplicaSynchronization', repServiceInstanceName,
- Operation=operation,
+ Operation=self.utils.get_num(operation, '16'),
Synchronization=syncInstanceName,
Force=force)
'relationName': relationName,
'srcGroup': srcGroupInstanceName,
'tgtGroup': tgtGroupInstanceName})
- # 7 for snap.
- syncType = 7
rc, job = conn.InvokeMethod(
'CreateGroupReplica',
replicationService,
RelationshipName=relationName,
SourceGroup=srcGroupInstanceName,
TargetGroup=tgtGroupInstanceName,
- SyncType=self.utils.get_num(syncType, '16'))
+ SyncType=self.utils.get_num(SNAPSYNCTYPE, '16'))
if rc != 0:
rc, errordesc = self.utils.wait_for_job_complete(conn, job,
:raises: VolumeBackendAPIException
"""
retries = kwargs['retries']
- maxJobRetries = self._get_max_job_retries(extraSpecs)
- wait_for_sync_called = kwargs['wait_for_sync_called']
- if self._is_sync_complete(conn, syncName):
- raise loopingcall.LoopingCallDone()
- if retries > maxJobRetries:
- LOG.error(_LE("_wait_for_sync failed after %(retries)d "
- "tries."),
- {'retries': retries})
- raise loopingcall.LoopingCallDone()
try:
kwargs['retries'] = retries + 1
- if not wait_for_sync_called:
+ if not kwargs['wait_for_sync_called']:
if self._is_sync_complete(conn, syncName):
kwargs['wait_for_sync_called'] = True
except Exception:
LOG.exception(exceptionMessage)
raise exception.VolumeBackendAPIException(exceptionMessage)
+ if kwargs['retries'] > maxJobRetries:
+ LOG.error(_LE("_wait_for_sync failed after %(retries)d "
+ "tries."),
+ {'retries': retries})
+ raise loopingcall.LoopingCallDone(retvalue=maxJobRetries)
+ if kwargs['wait_for_sync_called']:
+ raise loopingcall.LoopingCallDone()
+
+ maxJobRetries = self._get_max_job_retries(extraSpecs)
kwargs = {'retries': 0,
'wait_for_sync_called': False}
intervalInSecs = self._get_interval_in_secs(extraSpecs)
timer = loopingcall.FixedIntervalLoopingCall(_wait_for_sync)
- timer.start(interval=intervalInSecs).wait()
+ rc = timer.start(interval=intervalInSecs).wait()
+ return rc
def _is_sync_complete(self, conn, syncName):
"""Check if the job is finished.
LOG.error(exceptionMessage)
raise exception.VolumeBackendAPIException(data=exceptionMessage)
return protocolControllerInstanceName
+
+ def get_replication_setting_data(self, conn, repServiceInstanceName,
+ replication_type, extraSpecs):
+ """Get the replication setting data
+
+ :param conn: connection the ecom server
+ :param repServiceInstanceName: the storage group instance name
+ :param replication_type: the replication type
+ :param copy_methodology: the copy methodology
+ :returns: instance rsdInstance
+ """
+ repServiceCapabilityInstanceNames = conn.AssociatorNames(
+ repServiceInstanceName,
+ ResultClass='CIM_ReplicationServiceCapabilities',
+ AssocClass='CIM_ElementCapabilities')
+ repServiceCapabilityInstanceName = (
+ repServiceCapabilityInstanceNames[0])
+
+ rc, rsd = conn.InvokeMethod(
+ 'GetDefaultReplicationSettingData',
+ repServiceCapabilityInstanceName,
+ ReplicationType=self.get_num(replication_type, '16'))
+
+ if rc != 0:
+ rc, errordesc = self.wait_for_job_complete(conn, rsd,
+ extraSpecs)
+ if rc != 0:
+ exceptionMessage = (_(
+ "Error getting ReplicationSettingData. "
+ "Return code: %(rc)lu. "
+ "Error: %(error)s.")
+ % {'rc': rc,
+ 'error': errordesc})
+ LOG.error(exceptionMessage)
+ raise exception.VolumeBackendAPIException(
+ data=exceptionMessage)
+ return rsd
+
+ def set_copy_methodology_in_rsd(self, conn, repServiceInstanceName,
+ replication_type, copy_methodology,
+ extraSpecs):
+ """Get the replication setting data
+
+ :param conn: connection the ecom server
+ :param repServiceInstanceName: the storage group instance name
+ :param replication_type: the replication type
+ :param copy_methodology: the copy methodology
+ :returns: instance rsdInstance
+ """
+ rsd = self.get_replication_setting_data(
+ conn, repServiceInstanceName, replication_type, extraSpecs)
+ rsdInstance = rsd['DefaultInstance']
+ rsdInstance['DesiredCopyMethodology'] = (
+ self.get_num(copy_methodology, '16'))
+ return rsdInstance
+
+ def set_target_element_supplier_in_rsd(
+ self, conn, repServiceInstanceName, replication_type,
+ target_type, extraSpecs):
+ """Get the replication setting data
+
+ :param conn: connection the ecom server
+ :param repServiceInstanceName: the storage group instance name
+ :param replication_type: the replication type
+ :param target_type: Use existing, Create new, Use and create
+ :returns: instance rsdInstance
+ """
+ rsd = self.get_replication_setting_data(
+ conn, repServiceInstanceName, replication_type, extraSpecs)
+ rsdInstance = rsd['DefaultInstance']
+ rsdInstance['TargetElementSupplier'] = (
+ self.get_num(target_type, '16'))
+
+ return rsdInstance
+
+ def get_v3_default_sg_instance_name(
+ self, conn, poolName, slo, workload, storageSystemName):
+ """Get the V3 default instance name
+
+ :param conn: the connection to the ecom server
+ :param poolName: the pool name
+ :param slo: the SLO
+ :param workload: the workload
+ :param storageSystemName: the storage system name
+ :returns: the storage group instance name
+ """
+ storageGroupName = self.get_v3_storage_group_name(
+ poolName, slo, workload)
+ controllerConfigService = (
+ self.find_controller_configuration_service(
+ conn, storageSystemName))
+ sgInstanceName = self.find_storage_masking_group(
+ conn, controllerConfigService, storageGroupName)
+ return storageGroupName, controllerConfigService, sgInstanceName