def InvokeMethod(self, MethodName, Service, ElementName=None, InPool=None,
ElementType=None, Size=None,
- SyncType=None, SourceElement=None,
+ SyncType=None, SourceElement=None, TargetElement=None,
Operation=None, Synchronization=None,
TheElements=None, TheElement=None,
LUNames=None, InitiatorPortIDs=None, DeviceAccesses=None,
fakeinstance = instance.fake_getpolicyinstance()
return fakeinstance
+ def _getinstance_syncsvsv(self, objectpath):
+ svInstance = {}
+ svInstance['SyncedElement'] = 'SyncedElement'
+ svInstance['SystemElement'] = 'SystemElement'
+ svInstance['PercentSynced'] = 100
+ return svInstance
+
def _default_getinstance(self, objectpath):
return objectpath
FakeDB,
'volume_get',
return_value=EMCVMAXCommonData.test_source_volume)
+ @mock.patch.object(
+ EMCVMAXUtils,
+ 'get_volume_meta_head',
+ return_value=[EMCVMAXCommonData.test_volume])
+ @mock.patch.object(
+ EMCVMAXUtils,
+ 'get_meta_members_capacity_in_bit',
+ return_value=[1234567, 7654321])
@mock.patch.object(
EMCVMAXCommon,
- '_find_storage_sync_sv_sv',
- return_value=(None, None))
- def test_create_snapshot_no_fast_success(
- self, mock_volume_type,
- mock_volume, mock_sync_sv):
+ '_get_pool_and_storage_system',
+ return_value=(None, EMCVMAXCommonData.storage_system))
+ def test_create_snapshot_different_sizes_meta_no_fast_success(
+ self, mock_volume_type, mock_volume,
+ mock_meta, mock_size, mock_pool):
self.data.test_volume['volume_name'] = "vmax-1234567"
+ common = self.driver.common
+ volumeDict = {'classname': u'Symm_StorageVolume',
+ 'keybindings': EMCVMAXCommonData.keybindings}
+ common.provision.create_volume_from_pool = (
+ mock.Mock(return_value=(volumeDict, 0L)))
+ common.provision.get_volume_dict_from_job = (
+ mock.Mock(return_value=volumeDict))
self.driver.create_snapshot(self.data.test_volume)
def test_create_snapshot_no_fast_failed(self):
volume_types,
'get_volume_type_extra_specs',
return_value={'volume_backend_name': 'ISCSINoFAST'})
- @mock.patch.object(
- FakeDB,
- 'volume_get',
- return_value=EMCVMAXCommonData.test_source_volume)
@mock.patch.object(
EMCVMAXCommon,
'_find_storage_sync_sv_sv',
return_value=(None, None))
- def test_create_volume_from_snapshot_no_fast_success(
- self, mock_volume_type,
- mock_volume, mock_sync_sv):
+ @mock.patch.object(
+ EMCVMAXUtils,
+ 'get_volume_meta_head',
+ return_value=[EMCVMAXCommonData.test_volume])
+ @mock.patch.object(
+ EMCVMAXUtils,
+ 'get_meta_members_capacity_in_bit',
+ return_value=[1234567])
+ def test_create_volume_from_same_size_meta_snapshot(
+ self, mock_volume_type, mock_sync_sv, mock_meta, mock_size):
self.data.test_volume['volume_name'] = "vmax-1234567"
self.driver.create_volume_from_snapshot(
- self.data.test_volume, EMCVMAXCommonData.test_source_volume)
+ self.data.test_volume, self.data.test_volume)
def test_create_volume_from_snapshot_no_fast_failed(self):
self.data.test_volume['volume_name'] = "vmax-1234567"
EMCVMAXCommon,
'_find_storage_sync_sv_sv',
return_value=(None, None))
- def test_create_clone_no_fast_success(self, mock_volume_type,
- mock_volume, mock_sync_sv):
+ @mock.patch.object(
+ EMCVMAXUtils,
+ 'get_volume_meta_head',
+ return_value=None)
+ def test_create_clone_simple_volume_no_fast_success(
+ self, mock_volume_type, mock_volume, mock_sync_sv,
+ mock_simple_volume):
self.data.test_volume['volume_name'] = "vmax-1234567"
self.driver.create_cloned_volume(self.data.test_volume,
EMCVMAXCommonData.test_source_volume)
@mock.patch.object(
volume_types,
'get_volume_type_extra_specs',
- return_value={'volume_backend_name': 'ISCSIFAST',
- 'FASTPOLICY': 'FC_GOLD1'})
- @mock.patch.object(
- EMCVMAXUtils,
- 'find_storage_masking_group',
- return_value=EMCVMAXCommonData.storagegroupname)
+ return_value={'volume_backend_name': 'ISCSIFAST'})
@mock.patch.object(
FakeDB,
'volume_get',
return_value=EMCVMAXCommonData.test_source_volume)
@mock.patch.object(
- EMCVMAXCommon,
- '_find_storage_sync_sv_sv',
- return_value=(None, None))
+ EMCVMAXFast,
+ 'get_pool_associated_to_policy',
+ return_value=1)
@mock.patch.object(
EMCVMAXUtils,
- 'find_storage_configuration_service',
- return_value=1)
+ 'get_volume_meta_head',
+ return_value=[EMCVMAXCommonData.test_volume])
@mock.patch.object(
EMCVMAXUtils,
- 'find_controller_configuration_service',
- return_value=1)
+ 'get_meta_members_capacity_in_bit',
+ return_value=[1234567, 7654321])
@mock.patch.object(
EMCVMAXCommon,
- '_get_or_create_default_storage_group',
- return_value=1)
- def test_create_snapshot_fast_success(
- self, mock_volume_type, mock_storage_group, mock_volume,
- mock_sync_sv, mock_storage_config_service, mock_controller_service,
- mock_default_sg):
+ '_get_pool_and_storage_system',
+ return_value=(None, EMCVMAXCommonData.storage_system))
+ def test_create_snapshot_different_sizes_meta_fast_success(
+ self, mock_volume_type, mock_volume, mock_meta,
+ mock_size, mock_pool, mock_policy):
self.data.test_volume['volume_name'] = "vmax-1234567"
+ common = self.driver.common
+
+ volumeDict = {'classname': u'Symm_StorageVolume',
+ 'keybindings': EMCVMAXCommonData.keybindings}
+ common.provision.create_volume_from_pool = (
+ mock.Mock(return_value=(volumeDict, 0L)))
+ common.provision.get_volume_dict_from_job = (
+ mock.Mock(return_value=volumeDict))
+ common.fast.is_volume_in_default_SG = (
+ mock.Mock(return_value=True))
self.driver.create_snapshot(self.data.test_volume)
def test_create_snapshot_fast_failed(self):
@mock.patch.object(
volume_types,
'get_volume_type_extra_specs',
- return_value={'volume_backend_name': 'ISCSIFAST',
- 'FASTPOLICY': 'FC_GOLD1'})
- @mock.patch.object(
- EMCVMAXUtils,
- 'find_storage_masking_group',
- return_value=EMCVMAXCommonData.storagegroupname)
- @mock.patch.object(
- FakeDB,
- 'volume_get',
- return_value=EMCVMAXCommonData.test_source_volume)
+ return_value={'volume_backend_name': 'ISCSIFAST'})
@mock.patch.object(
EMCVMAXCommon,
'_find_storage_sync_sv_sv',
return_value=(None, None))
@mock.patch.object(
EMCVMAXUtils,
- 'find_storage_configuration_service',
- return_value=1)
+ 'get_volume_meta_head',
+ return_value=[EMCVMAXCommonData.test_volume])
@mock.patch.object(
EMCVMAXUtils,
- 'find_controller_configuration_service',
- return_value=1)
- @mock.patch.object(
- EMCVMAXCommon,
- '_get_or_create_default_storage_group',
- return_value=1)
- def test_create_volume_from_snapshot_fast_success(
- self, mock_volume_type, mock_storage_group, mock_volume,
- mock_sync_sv, mock_storage_config_service, mock_controller_service,
- mock_default_sg):
+ 'get_meta_members_capacity_in_bit',
+ return_value=[1234567])
+ def test_create_volume_from_same_size_meta_snapshot(
+ self, mock_volume_type, mock_sync_sv, mock_meta, mock_size):
self.data.test_volume['volume_name'] = "vmax-1234567"
+ self.driver.common.utils.find_storage_configuration_service = (
+ mock.Mock(return_value=EMCVMAXCommonData.storage_system))
+ self.driver.common._get_or_create_default_storage_group = (
+ mock.Mock(return_value=EMCVMAXCommonData.default_storage_group))
+ self.driver.common.fast.is_volume_in_default_SG = (
+ mock.Mock(return_value=True))
self.driver.create_volume_from_snapshot(
- self.data.test_volume, EMCVMAXCommonData.test_source_volume)
+ self.data.test_volume, self.data.test_volume)
@mock.patch.object(
volume_types,
EMCVMAXCommon,
'_find_storage_sync_sv_sv',
return_value=(None, None))
+ @mock.patch.object(
+ EMCVMAXUtils,
+ 'get_volume_meta_head',
+ return_value=None)
def test_create_volume_from_snapshot_fast_failed(
- self, mock_volume_type,
- mock_rep_service, mock_sync_sv):
+ self, mock_type, mock_rep_service, mock_sync_sv, mock_meta):
+
self.data.test_volume['volume_name'] = "vmax-1234567"
self.assertRaises(exception.VolumeBackendAPIException,
self.driver.create_volume_from_snapshot,
@mock.patch.object(
volume_types,
'get_volume_type_extra_specs',
- return_value={'volume_backend_name': 'ISCSIFAST',
- 'FASTPOLICY': 'FC_GOLD1'})
- @mock.patch.object(
- EMCVMAXUtils,
- 'find_storage_masking_group',
- return_value=EMCVMAXCommonData.storagegroupname)
+ return_value={'volume_backend_name': 'ISCSIFAST'})
@mock.patch.object(
FakeDB,
'volume_get',
return_value=(None, None))
@mock.patch.object(
EMCVMAXUtils,
- 'find_storage_configuration_service',
- return_value=1)
- @mock.patch.object(
- EMCVMAXUtils,
- 'find_controller_configuration_service',
- return_value=1)
- @mock.patch.object(
- EMCVMAXCommon,
- '_get_or_create_default_storage_group',
- return_value=1)
- def test_create_clone_fast_success(self, mock_volume_type,
- mock_storage_group, mock_volume,
- mock_sync_sv,
- mock_storage_config_service,
- mock_controller_service,
- mock_default_sg):
+ 'get_volume_meta_head',
+ return_value=None)
+ def test_create_clone_simple_volume_fast_success(
+ self, mock_volume_type, mock_volume, mock_sync_sv,
+ mock_simple_volume):
self.data.test_volume['volume_name'] = "vmax-1234567"
+ self.driver.common.utils.find_storage_configuration_service = (
+ mock.Mock(return_value=EMCVMAXCommonData.storage_system))
+ self.driver.common._get_or_create_default_storage_group = (
+ mock.Mock(return_value=EMCVMAXCommonData.default_storage_group))
+ self.driver.common.fast.is_volume_in_default_SG = (
+ mock.Mock(return_value=True))
self.driver.create_cloned_volume(self.data.test_volume,
EMCVMAXCommonData.test_source_volume)
@mock.patch.object(
volume_types,
'get_volume_type_extra_specs',
- return_value={'volume_backend_name': 'ISCSIFAST',
- 'FASTPOLICY': 'FC_GOLD1'})
+ return_value={'volume_backend_name': 'ISCSIFAST'})
+ @mock.patch.object(
+ FakeDB,
+ 'volume_get',
+ return_value=EMCVMAXCommonData.test_source_volume)
+ @mock.patch.object(
+ EMCVMAXFast,
+ 'get_pool_associated_to_policy',
+ return_value=1)
+ @mock.patch.object(
+ EMCVMAXUtils,
+ 'get_volume_meta_head',
+ return_value=[EMCVMAXCommonData.test_volume])
+ @mock.patch.object(
+ EMCVMAXUtils,
+ 'get_meta_members_capacity_in_bit',
+ return_value=[1234567, 7654321])
@mock.patch.object(
EMCVMAXCommon,
- '_find_storage_sync_sv_sv',
- return_value=(None, None))
- def test_create_clone_fast_failed(self, mock_volume_type,
- mock_sync_sv):
+ '_get_pool_and_storage_system',
+ return_value=(None, EMCVMAXCommonData.storage_system))
+ def test_create_clone_fast_failed(
+ self, mock_volume_type, mock_vol, mock_policy, mock_meta,
+ mock_size, mock_pool):
self.data.test_volume['volume_name'] = "vmax-1234567"
+ self.driver.common._modify_and_get_composite_volume_instance = (
+ mock.Mock(return_value=(1L, None)))
self.assertRaises(exception.VolumeBackendAPIException,
self.driver.create_cloned_volume,
self.data.test_volume,
self.data.test_volume,
newSize)
- @mock.patch.object(
- volume_types,
- 'get_volume_type_extra_specs',
- return_value={'volume_backend_name': 'FCNoFAST'})
- @mock.patch.object(
- FakeDB,
- 'volume_get',
- return_value=EMCVMAXCommonData.test_source_volume)
- @mock.patch.object(
- EMCVMAXCommon,
- '_find_storage_sync_sv_sv',
- return_value=(None, None))
- def test_create_snapshot_no_fast_success(
- self, mock_volume_type,
- mock_volume, mock_sync_sv):
- self.data.test_volume['volume_name'] = "vmax-1234567"
- self.driver.create_snapshot(self.data.test_volume)
-
- def test_create_snapshot_no_fast_failed(self):
- self.data.test_volume['volume_name'] = "vmax-1234567"
- self.assertRaises(exception.VolumeBackendAPIException,
- self.driver.create_snapshot,
- self.data.test_volume)
-
- @mock.patch.object(
- volume_types,
- 'get_volume_type_extra_specs',
- return_value={'volume_backend_name': 'FCNoFAST'})
- @mock.patch.object(
- FakeDB,
- 'volume_get',
- return_value=EMCVMAXCommonData.test_source_volume)
- @mock.patch.object(
- EMCVMAXCommon,
- '_find_storage_sync_sv_sv',
- return_value=(None, None))
- def test_create_volume_from_snapshot_no_fast_success(
- self, mock_volume_type,
- mock_volume, mock_sync_sv):
- self.data.test_volume['volume_name'] = "vmax-1234567"
- self.driver.create_volume_from_snapshot(
- self.data.test_volume, EMCVMAXCommonData.test_source_volume)
-
- def test_create_volume_from_snapshot_no_fast_failed(self):
- self.data.test_volume['volume_name'] = "vmax-1234567"
- self.assertRaises(exception.VolumeBackendAPIException,
- self.driver.create_volume_from_snapshot,
- self.data.test_volume,
- EMCVMAXCommonData.test_source_volume)
-
- @mock.patch.object(
- volume_types,
- 'get_volume_type_extra_specs',
- return_value={'volume_backend_name': 'FCNoFAST'})
- @mock.patch.object(
- FakeDB,
- 'volume_get',
- return_value=EMCVMAXCommonData.test_source_volume)
- @mock.patch.object(
- EMCVMAXCommon,
- '_find_storage_sync_sv_sv',
- return_value=(None, None))
- def test_create_clone_no_fast_success(self, mock_volume_type,
- mock_volume, mock_sync_sv):
- self.data.test_volume['volume_name'] = "vmax-1234567"
- self.driver.create_cloned_volume(self.data.test_volume,
- EMCVMAXCommonData.test_source_volume)
-
- def test_create_clone_no_fast_failed(self):
- self.data.test_volume['volume_name'] = "vmax-1234567"
- self.assertRaises(exception.VolumeBackendAPIException,
- self.driver.create_cloned_volume,
- self.data.test_volume,
- EMCVMAXCommonData.test_source_volume)
-
@mock.patch.object(
volume_types,
'get_volume_type_extra_specs',
@mock.patch.object(
volume_types,
'get_volume_type_extra_specs',
- return_value={'volume_backend_name': 'FCFAST',
- 'FASTPOLICY': 'FC_GOLD1'})
- @mock.patch.object(
- EMCVMAXUtils,
- 'find_storage_masking_group',
- return_value=EMCVMAXCommonData.storagegroupname)
+ return_value={'volume_backend_name': 'FCFAST'})
@mock.patch.object(
FakeDB,
'volume_get',
return_value=EMCVMAXCommonData.test_source_volume)
@mock.patch.object(
- EMCVMAXCommon,
- '_find_storage_sync_sv_sv',
- return_value=(None, None))
+ EMCVMAXFast,
+ 'get_pool_associated_to_policy',
+ return_value=1)
@mock.patch.object(
EMCVMAXUtils,
- 'find_storage_configuration_service',
- return_value=1)
+ 'get_volume_meta_head',
+ return_value=[EMCVMAXCommonData.test_volume])
@mock.patch.object(
EMCVMAXUtils,
- 'find_controller_configuration_service',
- return_value=1)
+ 'get_meta_members_capacity_in_bit',
+ return_value=[1234567, 7654321])
@mock.patch.object(
EMCVMAXCommon,
- '_get_or_create_default_storage_group',
- return_value=1)
- def test_create_snapshot_fast_success(self, mock_volume_type,
- mock_storage_group, mock_volume,
- mock_sync_sv,
- mock_storage_config_service,
- mock_controller_config_service,
- mock_default_sg):
+ '_get_pool_and_storage_system',
+ return_value=(None, EMCVMAXCommonData.storage_system))
+ def test_create_snapshot_different_sizes_meta_fast_success(
+ self, mock_volume_type, mock_volume, mock_meta,
+ mock_size, mock_pool, mock_policy):
self.data.test_volume['volume_name'] = "vmax-1234567"
+ common = self.driver.common
+
+ volumeDict = {'classname': u'Symm_StorageVolume',
+ 'keybindings': EMCVMAXCommonData.keybindings}
+ common.provision.create_volume_from_pool = (
+ mock.Mock(return_value=(volumeDict, 0L)))
+ common.provision.get_volume_dict_from_job = (
+ mock.Mock(return_value=volumeDict))
+ common.fast.is_volume_in_default_SG = (
+ mock.Mock(return_value=True))
self.driver.create_snapshot(self.data.test_volume)
def test_create_snapshot_fast_failed(self):
@mock.patch.object(
volume_types,
'get_volume_type_extra_specs',
- return_value={'volume_backend_name': 'FCFAST',
- 'FASTPOLICY': 'FC_GOLD1'})
- @mock.patch.object(
- EMCVMAXUtils,
- 'find_storage_masking_group',
- return_value=EMCVMAXCommonData.storagegroupname)
+ return_value={'volume_backend_name': 'FCFAST'})
@mock.patch.object(
FakeDB,
'volume_get',
return_value=(None, None))
@mock.patch.object(
EMCVMAXUtils,
- 'find_storage_configuration_service',
- return_value=1)
- @mock.patch.object(
- EMCVMAXUtils,
- 'find_controller_configuration_service',
- return_value=1)
- @mock.patch.object(
- EMCVMAXCommon,
- '_get_or_create_default_storage_group',
- return_value=1)
- def test_create_volume_from_snapshot_fast_success(
- self, mock_volume_type, mock_storage_group, mock_volume,
- mock_sync_sv, mock_storage_config_service,
- mock_controller_config_service, mock_default_sg):
- self.data.test_volume['volume_name'] = "vmax-1234567"
- self.driver.create_volume_from_snapshot(
- self.data.test_volume, EMCVMAXCommonData.test_source_volume)
-
- @mock.patch.object(
- volume_types,
- 'get_volume_type_extra_specs',
- return_value={'storagetype: pool': 'gold',
- 'volume_backend_name': 'FCFAST'})
- @mock.patch.object(
- EMCVMAXUtils,
- 'find_replication_service',
+ 'get_volume_meta_head',
return_value=None)
- @mock.patch.object(
- EMCVMAXCommon,
- '_find_storage_sync_sv_sv',
- return_value=(None, None))
- def test_create_volume_from_snapshot_fast_failed(self, mock_volume_type,
- mock_rep_service,
- mock_sync_sv):
+ def test_create_clone_simple_volume_fast_success(
+ self, mock_volume_type,
+ mock_volume, mock_sync_sv, mock_meta):
self.data.test_volume['volume_name'] = "vmax-1234567"
- self.assertRaises(exception.VolumeBackendAPIException,
- self.driver.create_volume_from_snapshot,
- self.data.test_volume,
- EMCVMAXCommonData.test_source_volume)
+ self.driver.common.utils.find_storage_configuration_service = (
+ mock.Mock(return_value=EMCVMAXCommonData.storage_system))
+ self.driver.common._get_or_create_default_storage_group = (
+ mock.Mock(return_value=EMCVMAXCommonData.default_storage_group))
+ self.driver.common.fast.is_volume_in_default_SG = (
+ mock.Mock(return_value=True))
+ self.driver.create_cloned_volume(
+ self.data.test_volume,
+ EMCVMAXCommonData.test_source_volume)
@mock.patch.object(
volume_types,
'get_volume_type_extra_specs',
- return_value={'volume_backend_name': 'FCFAST',
- 'FASTPOLICY': 'FC_GOLD1'})
- @mock.patch.object(
- EMCVMAXUtils,
- 'find_storage_masking_group',
- return_value=EMCVMAXCommonData.storagegroupname)
+ return_value={'volume_backend_name': 'FCFAST'})
@mock.patch.object(
FakeDB,
'volume_get',
return_value=EMCVMAXCommonData.test_source_volume)
@mock.patch.object(
- EMCVMAXCommon,
- '_find_storage_sync_sv_sv',
- return_value=(None, None))
- @mock.patch.object(
- EMCVMAXUtils,
- 'find_storage_configuration_service',
+ EMCVMAXFast,
+ 'get_pool_associated_to_policy',
return_value=1)
@mock.patch.object(
EMCVMAXUtils,
- 'find_controller_configuration_service',
- return_value=1)
- @mock.patch.object(
- EMCVMAXCommon,
- '_get_or_create_default_storage_group',
- return_value=1)
- def test_create_clone_fast_success(self, mock_volume_type,
- mock_storage_group, mock_volume,
- mock_sync_sv,
- mock_storage_config_service,
- mock_controller_config_service,
- mock_default_sg):
- self.data.test_volume['volume_name'] = "vmax-1234567"
- self.driver.create_cloned_volume(self.data.test_volume,
- EMCVMAXCommonData.test_source_volume)
-
- @mock.patch.object(
- volume_types,
- 'get_volume_type_extra_specs',
- return_value={'volume_backend_name': 'FCFAST'})
+ 'get_volume_meta_head',
+ return_value=[EMCVMAXCommonData.test_volume])
@mock.patch.object(
EMCVMAXUtils,
- 'find_replication_service',
- return_value=None)
+ 'get_meta_members_capacity_in_bit',
+ return_value=[1234567, 7654321])
@mock.patch.object(
EMCVMAXCommon,
- '_find_storage_sync_sv_sv',
- return_value=(None, None))
- def test_create_clone_fast_failed(self, mock_volume_type,
- mock_rep_service, mock_sync_sv):
+ '_get_pool_and_storage_system',
+ return_value=(None, EMCVMAXCommonData.storage_system))
+ def test_create_clone_fast_failed(
+ self, mock_volume_type, mock_vol,
+ mock_policy, mock_meta, mock_size, mock_pool):
self.data.test_volume['volume_name'] = "vmax-1234567"
+ self.driver.common._modify_and_get_composite_volume_instance = (
+ mock.Mock(return_value=(1L, None)))
self.assertRaises(exception.VolumeBackendAPIException,
self.driver.create_cloned_volume,
self.data.test_volume,
volumeName = volume['name']
extraSpecs = self._initial_setup(volume)
- memberCount, errorDesc = self.utils.determine_member_count(
- volume['size'], extraSpecs[MEMBERCOUNT], extraSpecs[COMPOSITETYPE])
- if errorDesc is not None:
- exceptionMessage = (_("The striped meta count of %(memberCount)s "
- "is too small for volume: %(volumeName)s. "
- "with size %(volumeSize)s ")
- % {'memberCount': memberCount,
- 'volumeName': volumeName,
- 'volumeSize': volume['size']})
- LOG.error(exceptionMessage)
- raise exception.VolumeBackendAPIException(data=exceptionMessage)
-
self.conn = self._get_ecom_connection()
- poolInstanceName, storageSystemName = (
- self._get_pool_and_storage_system(extraSpecs))
-
- LOG.debug("Create Volume: %(volume)s Pool: %(pool)s "
- "Storage System: %(storageSystem)s "
- "Size: %(size)lu "
- % {'volume': volumeName,
- 'pool': poolInstanceName,
- 'storageSystem': storageSystemName,
- 'size': volumeSize})
-
- elementCompositionService = (
- self.utils.find_element_composition_service(self.conn,
- storageSystemName))
-
- storageConfigService = self.utils.find_storage_configuration_service(
- self.conn, storageSystemName)
-
- # If FAST is intended to be used we must first check that the pool
- # is associated with the correct storage tier
- if extraSpecs[FASTPOLICY] is not None:
- foundPoolInstanceName = self.fast.get_pool_associated_to_policy(
- self.conn, extraSpecs[FASTPOLICY], extraSpecs[ARRAY],
- storageConfigService, poolInstanceName)
- if foundPoolInstanceName is None:
- exceptionMessage = (_("Pool: %(poolName)s. "
- "is not associated to storage tier for "
- "fast policy %(fastPolicy)s.")
- % {'poolName': extraSpecs[POOL],
- 'fastPolicy': extraSpecs[FASTPOLICY]})
- LOG.error(exceptionMessage)
- raise exception.VolumeBackendAPIException(
- data=exceptionMessage)
-
- compositeType = self.utils.get_composite_type(
- extraSpecs[COMPOSITETYPE])
-
- volumeDict, rc = self.provision.create_composite_volume(
- self.conn, elementCompositionService, volumeSize, volumeName,
- poolInstanceName, compositeType, memberCount)
-
- # Now that we have already checked that the pool is associated with
- # the correct storage tier and the volume was successfully created
- # add the volume to the default storage group created for
- # volumes in pools associated with this fast policy
- if extraSpecs[FASTPOLICY]:
- LOG.info(_LI("Adding volume: %(volumeName)s to "
- "default storage group "
- "for FAST policy: %(fastPolicyName)s "),
- {'volumeName': volumeName,
- 'fastPolicyName': extraSpecs[FASTPOLICY]})
- defaultStorageGroupInstanceName = (
- self._get_or_create_default_storage_group(
- self.conn, storageSystemName, volumeDict,
- volumeName, extraSpecs[FASTPOLICY]))
- if not defaultStorageGroupInstanceName:
- exceptionMessage = (_(
- "Unable to create or get default storage group for "
- "FAST policy: %(fastPolicyName)s. ")
- % {'fastPolicyName': extraSpecs[FASTPOLICY]})
- LOG.error(exceptionMessage)
- raise exception.VolumeBackendAPIException(
- data=exceptionMessage)
-
- self._add_volume_to_default_storage_group_on_create(
- volumeDict, volumeName, storageConfigService,
- storageSystemName, extraSpecs[FASTPOLICY])
+ rc, volumeDict, storageSystemName = self._create_composite_volume(
+ volume, extraSpecs, volumeName, volumeSize)
LOG.info(_LI("Leaving create_volume: %(volumeName)s "
"Return code: %(rc)lu "
# Device is already mapped so we will leave the state as is
deviceNumber = deviceInfoDict['hostlunid']
LOG.info(_LI("Volume %(volume)s is already mapped. "
- "The device number is %(deviceNumber)s ")
+ "The device number is %(deviceNumber)s ")
% {'volume': volumeName,
'deviceNumber': deviceNumber})
else:
conn, controllerConfigurationService, volumeInstance,
volumeName, targetFastPolicyName))
if assocDefaultStorageGroupName is None:
- errorMsg = (_(
+ errorMsg = (_LE(
"Failed to add %(volumeName)s "
"to default storage group for fast policy "
"%(fastPolicyName)s ")
"and fast policy"))
if targetArraySerialNumber not in sourceArraySerialNumber:
- errorMessage = (_(
+ errorMessage = (_LE(
"The source array : %(sourceArraySerialNumber)s does not "
"match the target array: %(targetArraySerialNumber)s"
"skipping storage-assisted migration")
assocPoolInstance = self.conn.GetInstance(
assocPoolInstanceName)
if assocPoolInstance['ElementName'] == targetPoolName:
- errorMessage = (_("No action required. Volume : %(volumeName)s is "
- "already part of pool : %(pool)s")
+ errorMessage = (_LE("No action required. Volume : %(volumeName)s "
+ "is already part of pool : %(pool)s")
% {'volumeName': volumeName,
'pool': targetPoolName})
LOG.error(errorMessage)
LOG.info(_LI("Volume status is: %s"), volumeStatus)
if (host['capabilities']['storage_protocol'] != self.protocol and
(volumeStatus != 'available' and volumeStatus != 'retyping')):
- errorMessage = (_(
+ errorMessage = (_LE(
"Only available volumes can be migrated between "
"different protocols"))
LOG.error(errorMessage)
cloneName = cloneVolume['name']
LOG.info(_LI("Create a Clone from Volume: Clone "
- "Volume: %(cloneName)s "
+ "Volume: %(cloneName)s "
"Source Volume: %(sourceName)s")
% {'cloneName': cloneName,
'sourceName': sourceName})
sourceInstance = self._find_lun(sourceVolume)
storageSystem = sourceInstance['SystemName']
-
- LOG.debug("Create Cloned Volume: Volume: %(cloneName)s "
- "Source Volume: %(sourceName)s Source Instance: "
- "%(sourceInstance)s Storage System: %(storageSystem)s."
- % {'cloneName': cloneName,
- 'sourceName': sourceName,
- 'sourceInstance': sourceInstance.path,
- 'storageSystem': storageSystem})
-
repServiceInstanceName = self.utils.find_replication_service(
self.conn, storageSystem)
'elementname': cloneName,
'sourceelement': sourceInstance.path})
+ return self._examine_source_and_create_clone(
+ repServiceInstanceName, cloneVolume, sourceVolume,
+ sourceInstance, extraSpecs)
+
+ def _examine_source_and_create_clone(self, repServiceInstanceName,
+ cloneVolume, sourceVolume,
+ sourceInstance, extraSpecs):
+ """Create a clone (v2).
+
+ :param repServiceInstanceName: the replication service
+ :param cloneVolume: the clone volume object
+ :param sourceVolume: the source volume object
+ :param sourceInstance: the device ID of the volume
+ :param fastPolicyName: the FAST policy name(if it exists)
+ :returns: rc
+ """
+ # check if the source volume contains any meta devices
+ metaHeadInstanceName = self.utils.get_volume_meta_head(
+ self.conn, sourceInstance.path)
+
+ if metaHeadInstanceName is None: # simple volume
+ return self._create_replica_and_delete_clone_relationship(
+ repServiceInstanceName, cloneVolume, sourceVolume,
+ sourceInstance, None, extraSpecs)
+ else: # composite volume with meta device members
+ # check if the meta members' capacity
+ metaMemberInstanceNames = (
+ self.utils.get_meta_members_of_composite_volume(
+ self.conn, metaHeadInstanceName))
+ volumeCapacities = self.utils.get_meta_members_capacity_in_bit(
+ self.conn, metaMemberInstanceNames)
+ LOG.debug("Volume capacities: %(metasizes)s "
+ % {'metasizes': volumeCapacities})
+ if len(set(volumeCapacities)) == 1:
+ LOG.debug("Meta volume all of the same size")
+ return self._create_replica_and_delete_clone_relationship(
+ repServiceInstanceName, cloneVolume, sourceVolume,
+ sourceInstance, None, extraSpecs)
+
+ LOG.debug("Meta volumes are of different sizes: "
+ "%d different sizes." % len(set(volumeCapacities)))
+
+ baseTargetVolumeInstance = None
+ for volumeSizeInbits in volumeCapacities:
+ if baseTargetVolumeInstance is None: # Create base volume
+ baseVolumeName = "TargetBaseVol"
+ volume = {'size': int(self.utils.convert_bits_to_gbs(
+ volumeSizeInbits))}
+ rc, baseVolumeDict, storageSystemName = (
+ self._create_composite_volume(
+ volume, extraSpecs,
+ baseVolumeName, volumeSizeInbits))
+ baseTargetVolumeInstance = self.utils.find_volume_instance(
+ self.conn, baseVolumeDict, baseVolumeName)
+ LOG.info(_LI("Base target volume %(targetVol)s created. "
+ "Capacity in bits: %(capInBits)lu ")
+ % {'capInBits': volumeSizeInbits,
+ 'targetVol': baseTargetVolumeInstance.path})
+ else: # create append volume
+ targetVolumeName = "MetaVol"
+ volume = {'size': int(self.utils.convert_bits_to_gbs(
+ volumeSizeInbits))}
+ storageConfigService = (
+ self.utils.find_storage_configuration_service(
+ self.conn, storageSystemName))
+ unboundVolumeInstance = (
+ self._create_and_get_unbound_volume(
+ self.conn, storageConfigService,
+ baseTargetVolumeInstance.path, volumeSizeInbits))
+ if unboundVolumeInstance is None:
+ exceptionMessage = (_(
+ "Error Creating unbound volume."))
+ LOG.error(exceptionMessage)
+ raise exception.VolumeBackendAPIException(
+ data=exceptionMessage)
+
+ # append the new unbound volume to the
+ # base target composite volume
+ baseTargetVolumeInstance = self.utils.find_volume_instance(
+ self.conn, baseVolumeDict, baseVolumeName)
+ elementCompositionService = (
+ self.utils.find_element_composition_service(
+ self.conn, storageSystemName))
+ compositeType = self.utils.get_composite_type(
+ extraSpecs[COMPOSITETYPE])
+ rc, modifiedVolumeDict = (
+ self._modify_and_get_composite_volume_instance(
+ self.conn, elementCompositionService,
+ baseTargetVolumeInstance,
+ unboundVolumeInstance.path,
+ targetVolumeName, compositeType))
+ if modifiedVolumeDict is None:
+ exceptionMessage = (_(
+ "Error appending volume %(volumename)s to "
+ "target base volume")
+ % {'volumename': targetVolumeName})
+ LOG.error(exceptionMessage)
+ raise exception.VolumeBackendAPIException(
+ data=exceptionMessage)
+
+ LOG.debug("Create replica for meta members of different sizes.")
+ return self._create_replica_and_delete_clone_relationship(
+ repServiceInstanceName, cloneVolume, sourceVolume,
+ sourceInstance, baseTargetVolumeInstance, extraSpecs)
+
+ def _create_replica_and_delete_clone_relationship(
+ self, repServiceInstanceName, cloneVolume, sourceVolume,
+ sourceInstance, targetInstance, extraSpecs):
+ """Helper function to create a clone and delete the relationship.
+
+ This function creates clone of the source volume and then
+ delete the clone replatinship once the copy completes.
+
+ :param repServiceInstanceName: replication service instance name
+ :param cloneVolume: target volume of the clone operation
+ :param sourceVolume: source volume of the clone operation
+ :param sourceInstance: instance of ECOM StorageVolume object
+ :param targetInstance: instance of ECOM StorageVolume object
+ :param extraSpecs: extraSpecs info
+ :returns: rc the return code, cloneDict the cloned volume dictionary
+ """
+ sourceName = sourceVolume['name']
+ cloneName = cloneVolume['name']
# Create a Clone from source volume
rc, job = self.provision.create_element_replica(
self.conn, repServiceInstanceName, cloneName, sourceName,
- sourceInstance)
+ sourceInstance, targetInstance)
cloneDict = self.provision.get_volume_dict_from_job(
self.conn, job['Job'])
raise exception.VolumeBackendAPIException(
data=exceptionMessage)
- self._add_volume_to_default_storage_group_on_create(
- cloneDict, cloneName, storageConfigService, storageSystemName,
- extraSpecs[FASTPOLICY])
+ # check if the clone/snapshot volume already part of the default sg
+ cloneInstance = self.utils.find_volume_instance(
+ self.conn, cloneDict, cloneName)
+ inDefaultSG = self.fast.is_volume_in_default_SG(
+ self.conn, cloneInstance.path)
+ if inDefaultSG is False:
+ self._add_volume_to_default_storage_group_on_create(
+ cloneDict, cloneName, storageConfigService,
+ storageSystemName, extraSpecs[FASTPOLICY])
LOG.debug("Leaving _create_cloned_volume: Volume: "
"%(cloneName)s Source Volume: %(sourceName)s "
self.conn, controllerConfigurationService,
volumeInstance, volumeName, fastPolicyName))
if assocDefaultStorageGroupName is None:
- errorMsg = (_(
+ errorMsg = (_LE(
"Failed to Roll back to re-add volume %(volumeName)s "
"to default storage group for fast policy "
"%(fastPolicyName)s: Please contact your sysadmin to "
self.conn, maskingViewInstanceName)
def get_masking_view_by_volume(self, volume):
- """Given volume, retrieve the masking view instance name
+ """Given volume, retrieve the masking view instance name.
:param volume: the volume
:param mvInstanceName: masking view instance name
self.conn, volumeInstance)
def get_masking_views_by_port_group(self, portGroupInstanceName):
- """Given port group, retrieve the masking view instance name
+ """Given port group, retrieve the masking view instance name.
:param : the volume
:param mvInstanceName: masking view instance name
% {'pg': portGroupInstanceName})
return self.masking.get_masking_views_by_port_group(
self.conn, portGroupInstanceName)
+
+ def _create_composite_volume(
+ self, volume, extraSpecs, volumeName, volumeSize):
+ """Create a composite volume.
+
+ :param volume: the volume object
+ :param extraSpecs:
+ :param volumeName:
+ :param volumeSize:
+ :returns:
+ """
+ memberCount, errorDesc = self.utils.determine_member_count(
+ volume['size'], extraSpecs[MEMBERCOUNT], extraSpecs[COMPOSITETYPE])
+ if errorDesc is not None:
+ exceptionMessage = (_("The striped meta count of %(memberCount)s "
+ "is too small for volume: %(volumeName)s. "
+ "with size %(volumeSize)s ")
+ % {'memberCount': memberCount,
+ 'volumeName': volumeName,
+ 'volumeSize': volume['size']})
+ LOG.error(exceptionMessage)
+ raise exception.VolumeBackendAPIException(data=exceptionMessage)
+
+ poolInstanceName, storageSystemName = (
+ self._get_pool_and_storage_system(extraSpecs))
+
+ LOG.debug("Create Volume: %(volume)s Pool: %(pool)s "
+ "Storage System: %(storageSystem)s "
+ "Size: %(size)lu "
+ % {'volume': volumeName,
+ 'pool': poolInstanceName,
+ 'storageSystem': storageSystemName,
+ 'size': volumeSize})
+
+ elementCompositionService = (
+ self.utils.find_element_composition_service(self.conn,
+ storageSystemName))
+
+ storageConfigService = self.utils.find_storage_configuration_service(
+ self.conn, storageSystemName)
+
+ # If FAST is intended to be used we must first check that the pool
+ # is associated with the correct storage tier
+ if extraSpecs[FASTPOLICY] is not None:
+ foundPoolInstanceName = self.fast.get_pool_associated_to_policy(
+ self.conn, extraSpecs[FASTPOLICY], extraSpecs[ARRAY],
+ storageConfigService, poolInstanceName)
+ if foundPoolInstanceName is None:
+ exceptionMessage = (_("Pool: %(poolName)s. "
+ "is not associated to storage tier for "
+ "fast policy %(fastPolicy)s.")
+ % {'poolName': extraSpecs[POOL],
+ 'fastPolicy': extraSpecs[FASTPOLICY]})
+ LOG.error(exceptionMessage)
+ raise exception.VolumeBackendAPIException(
+ data=exceptionMessage)
+
+ compositeType = self.utils.get_composite_type(
+ extraSpecs[COMPOSITETYPE])
+
+ volumeDict, rc = self.provision.create_composite_volume(
+ self.conn, elementCompositionService, volumeSize, volumeName,
+ poolInstanceName, compositeType, memberCount)
+
+ # Now that we have already checked that the pool is associated with
+ # the correct storage tier and the volume was successfully created
+ # add the volume to the default storage group created for
+ # volumes in pools associated with this fast policy
+ if extraSpecs[FASTPOLICY]:
+ LOG.info(_LI("Adding volume: %(volumeName)s to default storage "
+ "group for FAST policy: %(fastPolicyName)s ")
+ % {'volumeName': volumeName,
+ 'fastPolicyName': extraSpecs[FASTPOLICY]})
+ defaultStorageGroupInstanceName = (
+ self._get_or_create_default_storage_group(
+ self.conn, storageSystemName, volumeDict,
+ volumeName, extraSpecs[FASTPOLICY]))
+ if not defaultStorageGroupInstanceName:
+ exceptionMessage = (_(
+ "Unable to create or get default storage group for "
+ "FAST policy: %(fastPolicyName)s. ")
+ % {'fastPolicyName': extraSpecs[FASTPOLICY]})
+ LOG.error(exceptionMessage)
+ raise exception.VolumeBackendAPIException(
+ data=exceptionMessage)
+
+ self._add_volume_to_default_storage_group_on_create(
+ volumeDict, volumeName, storageConfigService,
+ storageSystemName, extraSpecs[FASTPOLICY])
+ return rc, volumeDict, storageSystemName
foundDefaultStorageGroupInstanceName = (
assocStorageGroupInstanceName)
else:
- exceptionMessage = (_(
+ errorMessage = (_LW(
"Volume: %(volumeName)s Does not belong "
"to storage storage group %(defaultSgGroupName)s. ")
% {'volumeName': volumeName,
'defaultSgGroupName': defaultSgGroupName})
- LOG.warn(exceptionMessage)
+ LOG.warn(errorMessage)
return foundDefaultStorageGroupInstanceName
def add_volume_to_default_storage_group_for_fast_policy(
if len(storageTierInstanceNames) == 0:
storageTierInstanceNames = None
LOG.warn(_LW("Unable to get storage tiers "
- "from tier policy rule "))
+ "from tier policy rule."))
return storageTierInstanceNames
tierPolicyRuleInstanceName = self._get_service_level_tier_policy(
conn, tierPolicyServiceInstanceName, fastPolicyName)
if tierPolicyRuleInstanceName is None:
- errorMessage = (_(
+ errorMessage = (_LE(
"Cannot find the fast policy %(fastPolicyName)s")
% {'fastPolicyName': fastPolicyName})
storageGroupName, fastPolicyName)
except Exception as ex:
LOG.error(_LE("Exception: %s") % six.text_type(ex))
- errorMessage = (_(
+ errorMessage = (_LE(
"Failed to add storage group %(storageGroupInstanceName)s "
" to tier policy rule %(tierPolicyRuleInstanceName)s")
% {'storageGroupInstanceName': storageGroupInstanceName,
rc, errordesc = self.utils.wait_for_job_complete(conn, job)
if rc != 0L:
LOG.error(_LE("Error disassociating storage group from "
- "policy: %s") % errordesc)
+ "policy: %s") % errordesc)
else:
LOG.debug("Disassociated storage group from policy %s")
else:
fastPolicyName = tierPolicyInstanceName['PolicyRuleName']
return fastPolicyName
+
+ def is_volume_in_default_SG(self, conn, volumeInstanceName):
+ """Check if the volume is already part of the default storage group.
+
+ :param volumeInstanceName: the volume instance
+ :returns: True if the volume is already in default storage group
+ False otherwise
+ """
+ sgInstanceNames = conn.AssociatorNames(
+ volumeInstanceName,
+ ResultClass='CIM_DeviceMaskingGroup')
+ if len(sgInstanceNames) == 0:
+ LOG.debug("volume %(vol)s is not in default sg."
+ % {'vol': volumeInstanceName})
+ return False
+ else:
+ for sgInstance in sgInstanceNames:
+ if DEFAULT_SG_PREFIX in sgInstance['InstanceID']:
+ LOG.debug("volume %(vol)s already in default sg."
+ % {'vol': volumeInstanceName})
+ return True
+ return False
def create_element_replica(
self, conn, repServiceInstanceName, cloneName,
- sourceName, sourceInstance):
+ sourceName, sourceInstance, targetInstance):
"""Make SMI-S call to create replica for source element.
:param conn: the connection to the ecom server
:param cloneName: replica name
:param sourceName: source volume name
:param sourceInstance: source volume instance
+ :param targetInstance: target volume instance
:returns: rc - return code
:returns: job - job object of the replica creation operation
"""
- rc, job = conn.InvokeMethod(
- 'CreateElementReplica', repServiceInstanceName,
- ElementName=cloneName,
- SyncType=self.utils.get_num(8, '16'),
- SourceElement=sourceInstance.path)
+ if targetInstance is None:
+ rc, job = conn.InvokeMethod(
+ 'CreateElementReplica', repServiceInstanceName,
+ ElementName=cloneName,
+ SyncType=self.utils.get_num(8, '16'),
+ SourceElement=sourceInstance.path)
+ else:
+ rc, job = conn.InvokeMethod(
+ 'CreateElementReplica', repServiceInstanceName,
+ ElementName=cloneName,
+ SyncType=self.utils.get_num(8, '16'),
+ SourceElement=sourceInstance.path,
+ TargetElement=targetInstance.path)
if rc != 0L:
rc, errordesc = self.utils.wait_for_job_complete(conn, job)
"""
def _wait_for_sync():
- """Called at an interval until the synchronization is finished"""
+ """Called at an interval until the synchronization is finished."""
if self._is_sync_complete(conn, syncName):
raise loopingcall.LoopingCallDone()
if self.retries > JOB_RETRIES:
- LOG.error(_LE("_wait_for_sync failed after %(retries)d tries")
+ LOG.error(_LE("_wait_for_sync failed after %(retries)d tries.")
% {'retries': self.retries})
raise loopingcall.LoopingCallDone()
try:
break
return foundIpAddress
+
+ def get_volume_meta_head(self, conn, volumeInstanceName):
+ """Get the head of a meta volume.
+
+ :param volumeInstanceName: the composite volume instance name
+ :returns: the instance name of the meta volume head
+ """
+ metaHeadInstanceName = None
+ metaHeads = conn.AssociatorNames(
+ volumeInstanceName,
+ ResultClass='EMC_Meta')
+
+ if len(metaHeads) > 0:
+ metaHeadInstanceName = metaHeads[0]
+ if metaHeadInstanceName is None:
+ LOG.info(_LI("Volume %(volume)s does not have meta device "
+ "members."),
+ {'volume': volumeInstanceName})
+
+ return metaHeadInstanceName
+
+ def get_meta_members_of_composite_volume(
+ self, conn, metaHeadInstanceName):
+ """Get the member volumes of a composite volume.
+
+ :param metaHeadInstanceName: head of the composite volume
+ :returns: an array containing instance names of member volumes
+ """
+ metaMembers = conn.AssociatorNames(
+ metaHeadInstanceName,
+ AssocClass='CIM_BasedOn',
+ ResultClass='EMC_PartialAllocOfConcreteExtent')
+ LOG.debug("metaMembers: %(members)s " % {'members': metaMembers})
+ return metaMembers
+
+ def get_meta_members_capacity_in_bit(self, conn, volumeInstanceNames):
+ """Get the capacity in bits of all meta device member volumes.
+
+ :param volumeInstanceNames: array contains meta device member volumes
+ :returns: array contains capacities of each member device in bits
+ """
+ capacitiesInBit = []
+ for volumeInstanceName in volumeInstanceNames:
+ volumeInstance = conn.GetInstance(volumeInstanceName)
+ numOfBlocks = volumeInstance['ConsumableBlocks']
+ blockSize = volumeInstance['BlockSize']
+ volumeSizeInbits = numOfBlocks * blockSize
+ capacitiesInBit.append(volumeSizeInbits)
+ return capacitiesInBit