u'instanceName': u'Other Multipath',
u'objectType': u'ScServerOperatingSystem'}}]
- MAP_PROFILES = [{u'instanceId': u'64702.2941',
- u'scName': u'Storage Center 64702',
- u'scSerialNumber': 64702,
- u'controller': {u'instanceId': u'64702.64703',
- u'instanceName': u'SN 64703',
- u'objectType': u'ScController'},
- u'lunUsed': [1],
- u'server': {u'instanceId': u'64702.47',
- u'instanceName': u'Server_21000024ff30441d',
- u'objectType': u'ScPhysicalServer'},
- u'volume':
- {u'instanceId': u'64702.6025',
- u'instanceName': u'Server_21000024ff30441d Test Vol',
- u'objectType': u'ScVolume'},
- u'connectivity': u'Up',
- u'readOnly': False,
- u'objectType': u'ScMappingProfile',
- u'hostCache': False,
- u'mappedVia': u'Server',
- u'mapCount': 3,
- u'instanceName': u'6025-47',
- u'lunRequested': u'N/A'}]
-
MAP_PROFILE = {u'instanceId': u'64702.2941',
u'scName': u'Storage Center 64702',
u'scSerialNumber': 64702,
u'instanceName': u'6025-47',
u'lunRequested': u'N/A'}
+ MAP_PROFILES = [MAP_PROFILE]
+
MAPPINGS = [{u'profile': {u'instanceId': u'64702.104',
u'instanceName': u'92-30',
u'objectType': u'ScMappingProfile'},
u'userCreated': False,
u'volumeCount': 0}]
+ ISCSI_CONFIG = {
+ u'initialReadyToTransfer': True,
+ u'scSerialNumber': 64065,
+ u'macAddress': u'00c0dd-1da173',
+ u'instanceId': u'64065.5764839588723573038.6',
+ u'vlanTagging': False,
+ u'mapCount': 8,
+ u'cardModel': u'Qle4062',
+ u'portNumber': 3260,
+ u'firstBurstSize': 256,
+ u'deviceName': u'PCIDEV09',
+ u'subnetMask': u'255.255.255.0',
+ u'speed': u'1 Gbps',
+ u'maximumVlanCount': 0,
+ u'gatewayIpAddress': u'192.168.0.1',
+ u'slot': 4,
+ u'sfpData': u'',
+ u'dataDigest': False,
+ u'chapEnabled': False,
+ u'firmwareVersion': u'03.00.01.77',
+ u'preferredControllerIndex': 64066,
+ u'defaultTimeToRetain': 20,
+ u'objectType': u'ScControllerPortIscsiConfiguration',
+ u'instanceName': u'5000d31000FCBE43',
+ u'scName': u'sc64065',
+ u'revision': u'0',
+ u'controllerPortIndex': 5764839588723573038,
+ u'maxBurstSize': 512,
+ u'targetCount': 20,
+ u'description': u'QLogic QLE4062 iSCSI Adapter Rev 0 Copper',
+ u'vlanSupported': True,
+ u'chapName': u'iqn.2002-03.com.compellent:5000d31000fcbe43',
+ u'windowSize': 128,
+ u'vlanId': 0,
+ u'defaultTimeToWait': 2,
+ u'headerDigest': False,
+ u'slotPort': 2,
+ u'immediateDataWrite': False,
+ u'storageCenterTargetCount': 20,
+ u'vlanCount': 0,
+ u'scsiCommandTimeout': 60,
+ u'slotType': u'PCI4',
+ u'ipAddress': u'192.168.0.21',
+ u'vlanUserPriority': 0,
+ u'bothCount': 0,
+ u'initiatorCount': 33,
+ u'keepAliveTimeout': 30,
+ u'homeControllerIndex': 64066,
+ u'chapSecret': u'',
+ u'maximumTransmissionUnit': 1500}
+
IQN = 'iqn.2002-03.com.compellent:5000D31000000001'
WWN = u'21000024FF30441C'
self.assertTrue(mock_get_json.called)
self.assertEqual([], res, 'Mapping count mismatch')
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_get_json',
+ return_value=MAP_PROFILES)
+ @mock.patch.object(dell_storagecenter_api.HttpClient,
+ 'get',
+ return_value=RESPONSE_200)
+ def test_find_mapping_profiles(self,
+ mock_get,
+ mock_get_json,
+ mock_close_connection,
+ mock_open_connection,
+ mock_init):
+ # Test case where ScVolume has no mappings
+ res = self.scapi._find_mapping_profiles(self.VOLUME)
+ self.assertTrue(mock_get.called)
+ self.assertTrue(mock_get_json.called)
+ self.assertEqual(self.MAP_PROFILES, res)
+
+ @mock.patch.object(dell_storagecenter_api.HttpClient,
+ 'get',
+ return_value=RESPONSE_400)
+ def test_find_mapping_profiles_error(self,
+ mock_get,
+ mock_close_connection,
+ mock_open_connection,
+ mock_init):
+ # Test case where ScVolume has no mappings
+ res = self.scapi._find_mapping_profiles(self.VOLUME)
+ self.assertTrue(mock_get.called)
+ self.assertEqual([], res)
+
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_first_result',
return_value=CTRLR_PORT)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_mappings',
return_value=MAPPINGS)
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_is_virtualport_mode',
+ return_value=True)
def test_find_iscsi_properties_mappings(self,
+ mock_is_virtualport_mode,
mock_find_mappings,
mock_find_domains,
mock_find_ctrl_port,
mock_open_connection,
mock_init):
res = self.scapi.find_iscsi_properties(self.VOLUME)
+ self.assertTrue(mock_is_virtualport_mode.called)
self.assertTrue(mock_find_mappings.called)
self.assertTrue(mock_find_domains.called)
self.assertTrue(mock_find_ctrl_port.called)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_mappings',
return_value=MAPPINGS)
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_is_virtualport_mode',
+ return_value=True)
def test_find_iscsi_properties_by_address(self,
+ mock_is_virtualport_mode,
mock_find_mappings,
mock_find_domains,
mock_find_ctrl_port,
# Test case to find iSCSI mappings by IP Address & port
res = self.scapi.find_iscsi_properties(
self.VOLUME, '192.168.0.21', 3260)
+ self.assertTrue(mock_is_virtualport_mode.called)
self.assertTrue(mock_find_mappings.called)
self.assertTrue(mock_find_domains.called)
self.assertTrue(mock_find_ctrl_port.called)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_mappings',
return_value=MAPPINGS)
- def test_find_iscsi_properties_by_address_not_found(self,
- mock_find_mappings,
- mock_find_domains,
- mock_find_ctrl_port,
- mock_find_active_ctrl,
- mock_close_connection,
- mock_open_connection,
- mock_init):
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_is_virtualport_mode',
+ return_value=True)
+ def test_find_iscsi_properties_by_address_not_found(
+ self,
+ mock_is_virtualport_mode,
+ mock_find_mappings,
+ mock_find_domains,
+ mock_find_ctrl_port,
+ mock_find_active_ctrl,
+ mock_close_connection,
+ mock_open_connection,
+ mock_init):
# Test case to find iSCSI mappings by IP Address & port are not found
res = self.scapi.find_iscsi_properties(
self.VOLUME, '192.168.1.21', 3260)
+ self.assertTrue(mock_is_virtualport_mode.called)
self.assertTrue(mock_find_mappings.called)
self.assertTrue(mock_find_domains.called)
self.assertTrue(mock_find_ctrl_port.called)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_mappings',
return_value=MAPPINGS)
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_is_virtualport_mode',
+ return_value=True)
def test_find_iscsi_properties_no_domain(self,
+ mock_is_virtualport_mode,
mock_find_mappings,
mock_find_domains,
mock_find_ctrl_port,
self.assertRaises(exception.VolumeBackendAPIException,
self.scapi.find_iscsi_properties,
self.VOLUME)
+ self.assertTrue(mock_is_virtualport_mode.called)
self.assertTrue(mock_find_mappings.called)
self.assertTrue(mock_find_domains.called)
self.assertTrue(mock_find_ctrl_port.called)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_controller_port',
return_value=None)
- @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
- '_find_domains',
- return_value=ISCSI_FLT_DOMAINS)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_mappings',
return_value=MAPPINGS)
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_is_virtualport_mode',
+ return_value=True)
def test_find_iscsi_properties_no_ctrl_port(self,
+ mock_is_virtualport_mode,
mock_find_mappings,
- mock_find_domains,
mock_find_ctrl_port,
mock_find_active_controller,
mock_close_connection,
self.assertRaises(exception.VolumeBackendAPIException,
self.scapi.find_iscsi_properties,
self.VOLUME)
+ self.assertTrue(mock_is_virtualport_mode.called)
self.assertTrue(mock_find_mappings.called)
- self.assertTrue(mock_find_domains.called)
self.assertTrue(mock_find_ctrl_port.called)
self.assertTrue(mock_find_active_controller.called)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_mappings',
return_value=MAPPINGS_READ_ONLY)
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_is_virtualport_mode',
+ return_value=True)
def test_find_iscsi_properties_ro(self,
+ mock_is_virtualport_mode,
mock_find_mappings,
mock_find_domains,
mock_find_ctrl_port,
mock_init):
# Test case where Read Only mappings are found
res = self.scapi.find_iscsi_properties(self.VOLUME)
+ self.assertTrue(mock_is_virtualport_mode.called)
self.assertTrue(mock_find_mappings.called)
self.assertTrue(mock_find_domains.called)
self.assertTrue(mock_find_ctrl_port.called)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_find_mappings',
return_value=MAPPINGS_MULTI_PORTAL)
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_is_virtualport_mode',
+ return_value=True)
def test_find_iscsi_properties_multi_portals(self,
+ mock_is_virtualport_mode,
mock_find_mappings,
mock_find_domains,
mock_find_ctrl_port,
self.assertTrue(mock_find_domains.called)
self.assertTrue(mock_find_ctrl_port.called)
self.assertTrue(mock_find_active_controller.called)
+ self.assertTrue(mock_is_virtualport_mode.called)
expected = {'access_mode': 'rw',
'target_discovered': False,
'target_iqn':
u'192.168.0.25:3260']}
self.assertEqual(expected, res, 'Wrong Target Info')
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_find_active_controller',
+ return_value='64702.5764839588723736131.91')
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_find_controller_port',
+ return_value=ISCSI_CTRLR_PORT)
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_find_mappings',
+ return_value=MAPPINGS)
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_is_virtualport_mode',
+ return_value=False)
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_find_controller_port_iscsi_config',
+ return_value=ISCSI_CONFIG)
+ def test_find_iscsi_properties_mappings_legacy(
+ self,
+ mock_find_controller_port_iscsi_config,
+ mock_is_virtualport_mode,
+ mock_find_mappings,
+ mock_find_ctrl_port,
+ mock_find_active_controller,
+ mock_close_connection,
+ mock_open_connection,
+ mock_init):
+ res = self.scapi.find_iscsi_properties(self.VOLUME)
+ self.assertTrue(mock_is_virtualport_mode.called)
+ self.assertTrue(mock_find_mappings.called)
+ self.assertTrue(mock_find_ctrl_port.called)
+ self.assertTrue(mock_find_controller_port_iscsi_config.called)
+ self.assertTrue(mock_find_active_controller.called)
+ expected = {'access_mode': 'rw',
+ 'target_discovered': False,
+ 'target_iqn':
+ u'iqn.2002-03.com.compellent:5000d31000fcbe43',
+ 'target_iqns':
+ [u'iqn.2002-03.com.compellent:5000d31000fcbe43'],
+ 'target_lun': 1,
+ 'target_luns': [1],
+ 'target_portal': u'192.168.0.21:3260',
+ 'target_portals': [u'192.168.0.21:3260']}
+ self.assertEqual(expected, res, 'Wrong Target Info')
+
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_find_active_controller',
+ return_value='64702.5764839588723736131.91')
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_find_controller_port',
+ return_value=ISCSI_CTRLR_PORT)
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_find_mappings',
+ return_value=MAPPINGS)
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_is_virtualport_mode',
+ return_value=False)
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_find_controller_port_iscsi_config',
+ return_value=None)
+ def test_find_iscsi_properties_mappings_legacy_no_iscsi_config(
+ self,
+ mock_find_controller_port_iscsi_config,
+ mock_is_virtualport_mode,
+ mock_find_mappings,
+ mock_find_ctrl_port,
+ mock_find_active_controller,
+ mock_close_connection,
+ mock_open_connection,
+ mock_init):
+ self.assertRaises(exception.VolumeBackendAPIException,
+ self.scapi.find_iscsi_properties,
+ self.VOLUME)
+ self.assertTrue(mock_is_virtualport_mode.called)
+ self.assertTrue(mock_find_mappings.called)
+ self.assertTrue(mock_find_ctrl_port.called)
+ self.assertTrue(mock_find_controller_port_iscsi_config.called)
+ self.assertTrue(mock_find_active_controller.called)
+
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_find_active_controller',
+ return_value='64702.64702')
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_find_controller_port',
+ return_value=ISCSI_CTRLR_PORT)
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_find_mappings',
+ return_value=MAPPINGS)
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_is_virtualport_mode',
+ return_value=False)
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_find_controller_port_iscsi_config',
+ return_value=ISCSI_CONFIG)
+ def test_find_iscsi_properties_by_address_legacy(
+ self,
+ mock_find_controller_port_iscsi_config,
+ mock_is_virtualport_mode,
+ mock_find_mappings,
+ mock_find_ctrl_port,
+ mock_find_active_controller,
+ mock_close_connection,
+ mock_open_connection,
+ mock_init):
+ # Test case to find iSCSI mappings by IP Address & port
+ res = self.scapi.find_iscsi_properties(
+ self.VOLUME, '192.168.0.21', 3260)
+ self.assertTrue(mock_is_virtualport_mode.called)
+ self.assertTrue(mock_find_mappings.called)
+ self.assertTrue(mock_find_ctrl_port.called)
+ self.assertTrue(mock_find_active_controller.called)
+ self.assertTrue(mock_find_controller_port_iscsi_config.called)
+ expected = {'access_mode': 'rw',
+ 'target_discovered': False,
+ 'target_iqn':
+ u'iqn.2002-03.com.compellent:5000d31000fcbe43',
+ 'target_iqns':
+ [u'iqn.2002-03.com.compellent:5000d31000fcbe43'],
+ 'target_lun': 1,
+ 'target_luns': [1],
+ 'target_portal': u'192.168.0.21:3260',
+ 'target_portals': [u'192.168.0.21:3260']}
+ self.assertEqual(expected, res, 'Wrong Target Info')
+
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_find_active_controller',
+ return_value='64702.64702')
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_find_controller_port',
+ return_value=ISCSI_CTRLR_PORT)
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_find_mappings',
+ return_value=MAPPINGS)
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_is_virtualport_mode',
+ return_value=False)
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_find_controller_port_iscsi_config',
+ return_value=ISCSI_CONFIG)
+ def test_find_iscsi_properties_by_address_not_found_legacy(
+ self,
+ mock_find_controller_port_iscsi_config,
+ mock_is_virtualport_mode,
+ mock_find_mappings,
+ mock_find_ctrl_port,
+ mock_find_active_ctrl,
+ mock_close_connection,
+ mock_open_connection,
+ mock_init):
+ # Test case to find iSCSI mappings by IP Address & port are not found
+ res = self.scapi.find_iscsi_properties(
+ self.VOLUME, '192.168.1.21', 3260)
+ self.assertTrue(mock_is_virtualport_mode.called)
+ self.assertTrue(mock_find_mappings.called)
+ self.assertTrue(mock_find_ctrl_port.called)
+ self.assertTrue(mock_find_active_ctrl.called)
+ self.assertTrue(mock_find_controller_port_iscsi_config.called)
+ expected = {'access_mode': 'rw',
+ 'target_discovered': False,
+ 'target_iqn':
+ u'iqn.2002-03.com.compellent:5000d31000fcbe43',
+ 'target_iqns':
+ [u'iqn.2002-03.com.compellent:5000d31000fcbe43'],
+ 'target_lun': 1,
+ 'target_luns': [1],
+ 'target_portal': u'192.168.0.21:3260',
+ 'target_portals': [u'192.168.0.21:3260']}
+ self.assertEqual(expected, res, 'Wrong Target Info')
+
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_find_active_controller',
+ return_value='64702.64702')
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_find_controller_port',
+ return_value=ISCSI_CTRLR_PORT)
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_find_mappings',
+ return_value=MAPPINGS_READ_ONLY)
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_is_virtualport_mode',
+ return_value=False)
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_find_controller_port_iscsi_config',
+ return_value=ISCSI_CONFIG)
+ def test_find_iscsi_properties_ro_legacy(self,
+ mock_find_iscsi_config,
+ mock_is_virtualport_mode,
+ mock_find_mappings,
+ mock_find_ctrl_port,
+ mock_find_active_controller,
+ mock_close_connection,
+ mock_open_connection,
+ mock_init):
+ # Test case where Read Only mappings are found
+ res = self.scapi.find_iscsi_properties(self.VOLUME)
+ self.assertTrue(mock_is_virtualport_mode.called)
+ self.assertTrue(mock_find_mappings.called)
+ self.assertTrue(mock_find_ctrl_port.called)
+ self.assertTrue(mock_find_active_controller.called)
+ self.assertTrue(mock_find_iscsi_config.called)
+ expected = {'access_mode': 'ro',
+ 'target_discovered': False,
+ 'target_iqn':
+ u'iqn.2002-03.com.compellent:5000d31000fcbe43',
+ 'target_iqns':
+ [u'iqn.2002-03.com.compellent:5000d31000fcbe43'],
+ 'target_lun': 1,
+ 'target_luns': [1],
+ 'target_portal': u'192.168.0.21:3260',
+ 'target_portals': [u'192.168.0.21:3260']}
+ self.assertEqual(expected, res, 'Wrong Target Info')
+
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_find_active_controller',
+ return_value='64702.64702')
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_find_controller_port',
+ return_value=ISCSI_CTRLR_PORT)
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_find_mappings',
+ return_value=MAPPINGS_MULTI_PORTAL)
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_is_virtualport_mode',
+ return_value=False)
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_find_controller_port_iscsi_config',
+ return_value=ISCSI_CONFIG)
+ def test_find_iscsi_properties_multi_portals_legacy(
+ self,
+ mock_find_controller_port_iscsi_config,
+ mock_is_virtualport_mode,
+ mock_find_mappings,
+ mock_find_ctrl_port,
+ mock_find_active_controller,
+ mock_close_connection,
+ mock_open_connection,
+ mock_init):
+ # Test case where there are multiple portals
+ res = self.scapi.find_iscsi_properties(self.VOLUME)
+ self.assertTrue(mock_find_mappings.called)
+ self.assertTrue(mock_find_ctrl_port.called)
+ self.assertTrue(mock_find_active_controller.called)
+ self.assertTrue(mock_is_virtualport_mode.called)
+ self.assertTrue(mock_find_controller_port_iscsi_config.called)
+ # Since we're feeding the same info back multiple times the information
+ # will be duped.
+ expected = {'access_mode': 'rw',
+ 'target_discovered': False,
+ 'target_iqn':
+ u'iqn.2002-03.com.compellent:5000d31000fcbe43',
+ 'target_iqns':
+ [u'iqn.2002-03.com.compellent:5000d31000fcbe43',
+ u'iqn.2002-03.com.compellent:5000d31000fcbe43'],
+ 'target_lun': 1,
+ 'target_luns': [1, 1],
+ 'target_portal': u'192.168.0.21:3260',
+ 'target_portals': [u'192.168.0.21:3260',
+ u'192.168.0.21:3260']}
+ self.assertEqual(expected, res, 'Wrong Target Info')
+
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_first_result',
return_value=MAP_PROFILE)
@mock.patch.object(dell_storagecenter_api.HttpClient,
'post',
return_value=RESPONSE_200)
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_find_mapping_profiles',
+ return_value=[])
def test_map_volume(self,
+ mock_find_mapping_profiles,
mock_post,
mock_first_result,
mock_close_connection,
mock_init):
res = self.scapi.map_volume(self.VOLUME,
self.SCSERVER)
+ self.assertTrue(mock_find_mapping_profiles.called)
+ self.assertTrue(mock_post.called)
+ self.assertTrue(mock_first_result.called)
+ self.assertEqual(self.MAP_PROFILE, res, 'Incorrect ScMappingProfile')
+
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_first_result',
+ return_value=MAP_PROFILE)
+ @mock.patch.object(dell_storagecenter_api.HttpClient,
+ 'post',
+ return_value=RESPONSE_200)
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_find_mapping_profiles',
+ return_value=MAP_PROFILES)
+ def test_map_volume_existing_mapping(self,
+ mock_find_mappings,
+ mock_post,
+ mock_first_result,
+ mock_close_connection,
+ mock_open_connection,
+ mock_init):
+ res = self.scapi.map_volume(self.VOLUME,
+ self.SCSERVER)
+ self.assertTrue(mock_find_mappings.called)
+ self.assertFalse(mock_post.called)
+ self.assertFalse(mock_first_result.called)
+ self.assertEqual(self.MAP_PROFILE, res, 'Incorrect ScMappingProfile')
+
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_first_result',
+ return_value=MAP_PROFILE)
+ @mock.patch.object(dell_storagecenter_api.HttpClient,
+ 'post',
+ return_value=RESPONSE_200)
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_find_mapping_profiles',
+ return_value=[])
+ def test_map_volume_existing_mapping_not_us(self,
+ mock_find_mappings,
+ mock_post,
+ mock_first_result,
+ mock_close_connection,
+ mock_open_connection,
+ mock_init):
+ server = {'instanceId': 64702.48}
+ res = self.scapi.map_volume(self.VOLUME,
+ server)
+ self.assertTrue(mock_find_mappings.called)
self.assertTrue(mock_post.called)
self.assertTrue(mock_first_result.called)
self.assertEqual(self.MAP_PROFILE, res, 'Incorrect ScMappingProfile')
@mock.patch.object(dell_storagecenter_api.HttpClient,
'post',
return_value=RESPONSE_204)
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_find_mapping_profiles',
+ return_value=[])
def test_map_volume_failure(self,
+ mock_find_mapping_profiles,
mock_post,
mock_close_connection,
mock_open_connection,
# Test case where mapping volume to server fails
res = self.scapi.map_volume(self.VOLUME,
self.SCSERVER)
+ self.assertTrue(mock_find_mapping_profiles.called)
self.assertTrue(mock_post.called)
self.assertIsNone(res, 'None expected')
'delete',
return_value=RESPONSE_200)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
- '_get_json',
+ '_find_mapping_profiles',
return_value=MAP_PROFILES)
- @mock.patch.object(dell_storagecenter_api.HttpClient,
- 'get',
- return_value=RESPONSE_200)
def test_unmap_volume(self,
- mock_get,
- mock_get_json,
+ mock_find_mapping_profiles,
mock_delete,
mock_close_connection,
mock_open_connection,
mock_init):
res = self.scapi.unmap_volume(self.VOLUME,
self.SCSERVER)
- self.assertTrue(mock_get.called)
- self.assertTrue(mock_get_json.called)
+ self.assertTrue(mock_find_mapping_profiles.called)
self.assertTrue(mock_delete.called)
self.assertTrue(res)
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_find_mapping_profiles',
+ return_value=MAP_PROFILES)
@mock.patch.object(dell_storagecenter_api.HttpClient,
- 'get',
+ 'delete',
return_value=RESPONSE_204)
def test_unmap_volume_failure(self,
- mock_get,
+ mock_delete,
+ mock_find_mapping_profiles,
mock_close_connection,
mock_open_connection,
mock_init):
res = self.scapi.unmap_volume(self.VOLUME,
self.SCSERVER)
- self.assertTrue(mock_get.called)
+ self.assertTrue(mock_find_mapping_profiles.called)
+ self.assertTrue(mock_delete.called)
self.assertFalse(res)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
- '_get_json',
+ '_find_mapping_profiles',
return_value=[])
- @mock.patch.object(dell_storagecenter_api.HttpClient,
- 'get',
- return_value=RESPONSE_200)
def test_unmap_volume_no_map_profile(self,
- mock_get,
- mock_get_json,
+ mock_find_mapping_profiles,
mock_close_connection,
mock_open_connection,
mock_init):
res = self.scapi.unmap_volume(self.VOLUME,
self.SCSERVER)
- self.assertTrue(mock_get.called)
- self.assertTrue(mock_get_json.called)
+ self.assertTrue(mock_find_mapping_profiles.called)
self.assertTrue(res)
@mock.patch.object(dell_storagecenter_api.HttpClient,
'delete',
return_value=RESPONSE_204)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
- '_get_json',
+ '_find_mapping_profiles',
return_value=MAP_PROFILES)
- @mock.patch.object(dell_storagecenter_api.HttpClient,
- 'get',
- return_value=RESPONSE_200)
def test_unmap_volume_del_fail(self,
- mock_get,
- mock_get_json,
+ mock_find_mapping_profiles,
mock_delete,
mock_close_connection,
mock_open_connection,
mock_init):
res = self.scapi.unmap_volume(self.VOLUME,
self.SCSERVER)
- self.assertTrue(mock_get.called)
- self.assertTrue(mock_get_json.called)
+ self.assertTrue(mock_find_mapping_profiles.called)
self.assertTrue(mock_delete.called)
self.assertFalse(res, False)
'delete',
return_value=RESPONSE_200)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
- '_get_json',
+ '_find_mapping_profiles',
return_value=MAP_PROFILES)
- @mock.patch.object(dell_storagecenter_api.HttpClient,
- 'get',
- return_value=RESPONSE_200)
def test_unmap_volume_no_vol_id(self,
- mock_get,
- mock_get_json,
+ mock_find_mapping_profiles,
mock_delete,
mock_get_id,
mock_close_connection,
mock_get_id.side_effect = [None, '64702.47']
res = self.scapi.unmap_volume(self.VOLUME,
self.SCSERVER)
- self.assertFalse(mock_get.called)
- self.assertFalse(mock_get_json.called)
+ self.assertFalse(mock_find_mapping_profiles.called)
self.assertFalse(mock_delete.called)
self.assertTrue(res)
'delete',
return_value=RESPONSE_200)
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
- '_get_json',
+ '_find_mapping_profiles',
return_value=MAP_PROFILES)
- @mock.patch.object(dell_storagecenter_api.HttpClient,
- 'get',
- return_value=RESPONSE_200)
def test_unmap_volume_no_server_id(self,
- mock_get,
- mock_get_json,
+ mock_find_mapping_profiles,
mock_delete,
mock_get_id,
mock_close_connection,
mock_get_id.side_effect = ['64702.3494', None]
res = self.scapi.unmap_volume(self.VOLUME,
self.SCSERVER)
- self.assertFalse(mock_get.called)
- self.assertFalse(mock_get_json.called)
+ self.assertFalse(mock_find_mapping_profiles.called)
self.assertFalse(mock_delete.called)
self.assertTrue(res)
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_get_json',
+ return_value=[{'a': 1}, {'a': 2}])
+ @mock.patch.object(dell_storagecenter_api.HttpClient,
+ 'get',
+ return_value=RESPONSE_200)
+ def test_find_controller_port_iscsi_config(self,
+ mock_get,
+ mock_get_json,
+ mock_close_connection,
+ mock_open_connection,
+ mock_init):
+ # Not much to test here. Just make sure we call our stuff and
+ # that we return the first item returned to us.
+ res = self.scapi._find_controller_port_iscsi_config('guid')
+ self.assertTrue(mock_get.called)
+ self.assertTrue(mock_get_json.called)
+ self.assertEqual({'a': 1}, res)
+
+ @mock.patch.object(dell_storagecenter_api.HttpClient,
+ 'get',
+ return_value=RESPONSE_400)
+ def test_find_controller_port_iscsi_config_err(self,
+ mock_get,
+ mock_close_connection,
+ mock_open_connection,
+ mock_init):
+ res = self.scapi._find_controller_port_iscsi_config('guid')
+ self.assertTrue(mock_get.called)
+ self.assertEqual(None, res)
+
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
'_get_json',
return_value=STRG_USAGE)
response_nc.reason = u'duplicate'
RESPONSE_204 = response_nc
+ APIDICT = {u'instanceId': u'0',
+ u'hostName': u'192.168.0.200',
+ u'userId': 434226,
+ u'connectionKey': u'',
+ u'minApiVersion': u'0.1',
+ u'webServicesPort': 3033,
+ u'locale': u'en_US',
+ u'objectType': u'ApiConnection',
+ u'secureString': u'',
+ u'applicationVersion': u'2.0.1',
+ u'source': u'REST',
+ u'commandLine': False,
+ u'application': u'Cinder REST Driver',
+ u'sessionKey': 1436460614863,
+ u'provider': u'EnterpriseManager',
+ u'instanceName': u'ApiConnection',
+ u'connected': True,
+ u'userName': u'Admin',
+ u'useHttps': False,
+ u'providerVersion': u'15.3.1.186',
+ u'apiVersion': u'2.2',
+ u'apiBuild': 199}
+
def setUp(self):
super(DellSCSanAPIConnectionTestCase, self).setUp()
@mock.patch.object(dell_storagecenter_api.HttpClient,
'post',
return_value=RESPONSE_200)
+ @mock.patch.object(dell_storagecenter_api.StorageCenterApi,
+ '_get_json',
+ return_value=APIDICT)
def test_open_connection(self,
+ mock_get_json,
mock_post):
self.scapi.open_connection()
self.assertTrue(mock_post.called)
'''PayloadFilter
Simple class for creating filters for interacting with the Dell
- Storage API.
-
- Note that this defaults to "AND" filter types. This is a pretty limited
- class. It only does the trivial filters required for this driver.
+ Storage API DropTop2 and later.
'''
- def __init__(self):
+ def __init__(self, filtertype='AND'):
self.payload = {}
- self.payload['filterType'] = 'AND'
- self.payload['filters'] = []
+ self.payload['filter'] = {'filterType': filtertype,
+ 'filters': []}
+
+ def append(self, name, val, filtertype='Equals'):
+ if val is not None:
+ apifilter = {}
+ apifilter['attributeName'] = name
+ apifilter['attributeValue'] = val
+ apifilter['filterType'] = filtertype
+ self.payload['filter']['filters'].append(apifilter)
+
+
+class LegacyPayloadFilter(object):
+
+ '''LegacyPayloadFilter
+
+ Simple class for creating filters for interacting with the Dell
+ Storage API pre DropTop2.
+ '''
+
+ def __init__(self, filter_type='AND'):
+ self.payload = {'filterType': filter_type,
+ 'filters': []}
def append(self, name, val, filtertype='Equals'):
if val is not None:
'''StorageCenterApi
Handles calls to Dell Enterprise Manager (EM) via the REST API interface.
- '''
- APIVERSION = '2.0.1'
+ Version history:
+ 1.0.0 - Initial driver
+ 1.1.0 - Added extra spec support for Storage Profile selection
+ 1.2.0 - Added consistency group support.
+ 2.0.0 - Switched to inheriting functional objects rather than volume
+ driver.
+ 2.1.0 - Added support for ManageableVD.
+ 2.2.0 - Added API 2.2 support.
+ 2.3.0 - Added Legacy Port Mode Support
+ '''
+ APIVERSION = '2.3.0'
def __init__(self, host, port, user, password, verify):
'''This creates a connection to Dell Enterprise Manager.
self.ssn = None
self.vfname = 'openstack'
self.sfname = 'openstack'
+ self.legacypayloadfilters = False
+ self.consisgroups = True
self.client = HttpClient(host,
port,
user,
blob)
return None
+ def _get_payload_filter(self, filterType='AND'):
+ # 2.1 or earlier and we are talking LegacyPayloadFilters.
+ if self.legacypayloadfilters:
+ return LegacyPayloadFilter(filterType)
+ return PayloadFilter(filterType)
+
def open_connection(self):
'''Authenticate against Dell Enterprise Manager.
payload['ApplicationVersion'] = self.APIVERSION
r = self.client.post('ApiConnection/Login',
payload)
- # TODO(Swanson): If we get a 400 back we should also print the text.
- if r.status_code != 200:
+
+ if r.status_code == 200:
+ # We should be logged in. Try to grab the api version out of the
+ # response.
+ try:
+ apidict = self._get_json(r)
+ version = apidict['apiVersion']
+ splitver = version.split('.')
+ if splitver[0] == '2':
+ if splitver[1] == '0':
+ self.consisgroups = False
+ self.legacypayloadfilters = True
+
+ elif splitver[1] == '1':
+ self.legacypayloadfilters = True
+ return
+
+ except Exception:
+ # Good return but not the login response we were expecting.
+ # Log it and error out.
+ LOG.error(_LE('Unrecognized Login Response: %s'), r)
+ else:
+ # Call error.
LOG.error(_LE('Login error: %(code)d %(reason)s'),
{'code': r.status_code,
'reason': r.reason})
- raise exception.VolumeBackendAPIException(
- _('Failed to connect to Enterprise Manager'))
+
+ # Bad request.
+ # TODO(Swanson): Should add this to all returns.
+ if r.status_code == 400:
+ LOG.debug('Bad Request. Return text: %s', r.text)
+
+ # If we fell to this point then raise an exception.
+ raise exception.VolumeBackendAPIException(
+ _('Failed to connect to Enterprise Manager'))
def close_connection(self):
'''Logout of Dell Enterprise Manager.'''
:param foldername: Full path to the folder we are looking for.
:returns: Dell folder object.
'''
- pf = PayloadFilter()
+ pf = self._get_payload_filter()
pf.append('scSerialNumber', self.ssn)
basename = os.path.basename(foldername)
pf.append('Name', basename)
Don't wig out if this fails.
:param scvolume: Dell Volume object.
'''
- pf = PayloadFilter()
+ pf = self._get_payload_filter()
pf.append('scSerialNumber', scvolume.get('scSerialNumber'), 'Equals')
r = self.client.post('StorageCenter/ScServer/GetList', pf.payload)
if r.status_code == 200:
# and look through for the one we want. Never many profiles, so
# this doesn't cause as much overhead as it might seem.
storage_profile = storage_profile.replace(' ', '').lower()
- pf = PayloadFilter()
+ pf = self._get_payload_filter()
pf.append('scSerialNumber', self.ssn, 'Equals')
r = self.client.post(
'StorageCenter/ScStorageProfile/GetList', pf.payload)
result = None
# We need a name or a device ID to find a volume.
if name or deviceid:
- pf = PayloadFilter()
+ pf = self._get_payload_filter()
pf.append('scSerialNumber', self.ssn)
if name is not None:
pf.append('Name', name)
:param osname: The name of the OS to look for.
:returns: InstanceId of the ScServerOperatingSystem object.
'''
- pf = PayloadFilter()
+ pf = self._get_payload_filter()
pf.append('scSerialNumber', self.ssn)
r = self.client.post('StorageCenter/ScServerOperatingSystem/GetList',
pf.payload)
# that we found one it actually has to be attached to a
# server.
if hba is not None and hba.get('server') is not None:
- pf = PayloadFilter()
+ pf = self._get_payload_filter()
pf.append('scSerialNumber', self.ssn)
pf.append('instanceId', self._get_id(hba['server']))
r = self.client.post('StorageCenter/ScServer/GetList',
'''
scserverhba = None
# We search for our server by first finding our HBA
- pf = PayloadFilter()
+ pf = self._get_payload_filter()
pf.append('scSerialNumber', self.ssn)
pf.append('instanceName', instance_name)
r = self.client.post('StorageCenter/ScServerHba/GetList',
LOG.error(_LE('_find_mappings: volume is not active'))
return mappings
+ def _find_mapping_profiles(self, scvolume):
+ '''Find the Dell volume object mapping profiles.
+
+ :param scvolume: Dell volume object.
+ :returns: A list of Dell mapping profile objects.
+ '''
+ mapping_profiles = []
+ if scvolume.get('active', False):
+ r = self.client.get('StorageCenter/ScVolume/%s/MappingProfileList'
+ % self._get_id(scvolume))
+ if r.status_code == 200:
+ mapping_profiles = self._get_json(r)
+ else:
+ LOG.debug('MappingProfileList error: %(code)d %(reason)s',
+ {'code': r.status_code,
+ 'reason': r.reason})
+ LOG.error(_LE('Unable to find volume mapping profiles: %s'),
+ scvolume.get('name'))
+ else:
+ LOG.error(_LE('_find_mappings: volume is not active'))
+ return mapping_profiles
+
def _find_controller_port(self, cportid):
'''Finds the SC controller port object for the specified cportid.
iqn = controllerport.get('iscsiName')
return iqn
+ def _is_virtualport_mode(self):
+ isvpmode = False
+ r = self.client.get('StorageCenter/ScConfiguration/%s' % self.ssn)
+ if r.status_code == 200:
+ scconfig = self._get_json(r)
+ if scconfig:
+ isvpmode = True if (scconfig['iscsiTransportMode'] ==
+ 'VirtualPort') else False
+ return isvpmode
+
+ def _find_controller_port_iscsi_config(self, cportid):
+ '''Finds the SC controller port object for the specified cportid.
+
+ :param cportid: The instanceID of the Dell backend controller port.
+ :returns: The controller port object.
+ '''
+ controllerport = None
+ r = self.client.get('StorageCenter/'
+ 'ScControllerPortIscsiConfiguration/%s'
+ % cportid)
+ if r.status_code == 200:
+ controllerport = self._first_result(r)
+ else:
+ LOG.debug('ScControllerPortIscsiConfiguration error: '
+ '%(code)d %(reason)s',
+ {'code': r.status_code,
+ 'reason': r.reason})
+ LOG.error(_LE('Unable to find controller '
+ 'port iscsi configuration: %s'),
+ cportid)
+ return controllerport
+
def find_iscsi_properties(self, scvolume, ip=None, port=None):
'''Finds target information for a given Dell scvolume object mapping.
'''
LOG.debug('enter find_iscsi_properties')
LOG.debug('scvolume: %s', scvolume)
- active = -1
- up = -1
- access_mode = 'rw'
+ # Our mutable process object.
+ pdata = {'active': -1,
+ 'up': -1,
+ 'access_mode': 'rw',
+ 'ip': ip,
+ 'port': port}
+ # Our output lists.
portals = []
luns = []
iqns = []
+
+ # Process just looks for the best port to return.
+ def process(lun, iqn, address, port, readonly, status, active):
+ '''Process this mapping information.
+
+ :param lun: SCSI Lun.
+ :param iqn: iSCSI IQN address.
+ :param address: IP address.
+ :param port: IP Port number
+ :param readonly: Boolean indicating mapping is readonly.
+ :param status: String indicating mapping status. (Up is what we
+ are looking for.)
+ :param active: Boolean indicating whether this is on the active
+ controller or not.
+ :return: Nothing
+ '''
+ portals.append(address + ':' +
+ six.text_type(port))
+ iqns.append(iqn)
+ luns.append(lun)
+
+ # We've all the information. We need to find
+ # the best single portal to return. So check
+ # this one if it is on the right IP, port and
+ # if the access and status are correct.
+ if ((pdata['ip'] is None or pdata['ip'] == address) and
+ (pdata['port'] is None or pdata['port'] == port)):
+
+ # We need to point to the best link.
+ # So state active and status up is preferred
+ # but we don't actually need the state to be
+ # up at this point.
+ if pdata['up'] == -1:
+ pdata['access_mode'] = 'rw' if readonly is False else 'ro'
+ if active:
+ pdata['active'] = len(iqns) - 1
+ if status == 'Up':
+ pdata['up'] = pdata['active']
+
+ # Start by getting our mappings.
mappings = self._find_mappings(scvolume)
+
+ # We should have mappings at the time of this call but do check.
if len(mappings) > 0:
# In multipath (per Liberty) we will return all paths. But
# if multipath is not set (ip and port are None) then we need
# to return a mapping from the controller on which the volume
# is active. So find that controller.
actvctrl = self._find_active_controller(scvolume)
+ # Two different methods are used to find our luns and portals
+ # depending on whether we are in virtual or legacy port mode.
+ isvpmode = self._is_virtualport_mode()
+ # Trundle through our mappings.
for mapping in mappings:
# The lun, ro mode and status are in the mapping.
LOG.debug('mapping: %s', mapping)
lun = mapping.get('lun')
ro = mapping.get('readOnly', False)
status = mapping.get('status')
- # Dig a bit to get our domains,IQN and controller id.
- domains = self._get_domains(mapping)
+ # Get our IQN from our mapping.
iqn = self._get_iqn(mapping)
- ctrlid = self._get_controller_id(mapping)
- if domains and iqn is not None:
- for dom in domains:
- LOG.debug('domain: %s', dom)
- ipaddress = dom.get('targetIpv4Address',
- dom.get('wellKnownIpAddress'))
- portnumber = dom.get('portNumber')
- # We save our portal.
- portals.append(ipaddress + ':' +
- six.text_type(portnumber))
- iqns.append(iqn)
- luns.append(lun)
-
- # We've all the information. We need to find
- # the best single portal to return. So check
- # this one if it is on the right IP, port and
- # if the access and status are correct.
- if ((ip is None or ip == ipaddress) and
- (port is None or port == portnumber)):
-
- # We need to point to the best link.
- # So state active and status up is preferred
- # but we don't actually need the state to be
- # up at this point.
- if up == -1:
- access_mode = 'rw' if ro is False else 'ro'
- if actvctrl == ctrlid:
- active = len(iqns) - 1
- if status == 'Up':
- up = active
+ # Check if our controller ID matches our active controller ID.
+ isactive = True if (self._get_controller_id(mapping) ==
+ actvctrl) else False
+ # If we have an IQN and are in virtual port mode.
+ if isvpmode and iqn:
+ domains = self._get_domains(mapping)
+ if domains:
+ for dom in domains:
+ LOG.debug('domain: %s', dom)
+ ipaddress = dom.get('targetIpv4Address',
+ dom.get('wellKnownIpAddress'))
+ portnumber = dom.get('portNumber')
+ # We have all our information. Process this portal.
+ process(lun, iqn, ipaddress, portnumber,
+ ro, status, isactive)
+ # Else we are in legacy mode.
+ elif iqn:
+ # Need to get individual ports
+ cportid = self._get_id(mapping.get('controllerPort'))
+ # Legacy mode stuff is in the ISCSI configuration object.
+ cpconfig = self._find_controller_port_iscsi_config(cportid)
+ # This should really never fail. Things happen so if it
+ # does just keep moving. Return what we can.
+ if cpconfig:
+ ipaddress = cpconfig.get('ipAddress')
+ portnumber = cpconfig.get('portNumber')
+ # We have all our information. Process this portal.
+ process(lun, iqn, ipaddress, portnumber,
+ ro, status, isactive)
+
+ # We've gone through all our mappings.
# Make sure we found something to return.
if len(luns) == 0:
# Since we just mapped this and can't find that mapping the world
# Make sure we point to the best portal we can. This means it is
# on the active controller and, preferably, up. If it isn't return
# what we have.
- if up != -1:
+ if pdata['up'] != -1:
# We found a connection that is already up. Return that.
- active = up
- elif active == -1:
+ pdata['active'] = pdata['up']
+ elif pdata['active'] == -1:
# This shouldn't be able to happen. Maybe a controller went
# down in the middle of this so just return the first one and
# hope the ports are up by the time the connection is attempted.
LOG.debug('Volume is not yet active on any controller.')
- active = 0
+ pdata['active'] = 0
data = {'target_discovered': False,
- 'target_iqn': iqns[active],
+ 'target_iqn': iqns[pdata['active']],
'target_iqns': iqns,
- 'target_portal': portals[active],
+ 'target_portal': portals[pdata['active']],
'target_portals': portals,
- 'target_lun': luns[active],
+ 'target_lun': luns[pdata['active']],
'target_luns': luns,
- 'access_mode': access_mode
+ 'access_mode': pdata['access_mode']
}
-
LOG.debug('find_iscsi_properties return: %s',
data)
:param scvolume: Storage Center volume object.
:param scserver: Storage Center server opbject.
- :returns: scmapping or None
+ :returns: SC mapping profile or None
'''
# Make sure we have what we think we have
serverid = self._get_id(scserver)
volumeid = self._get_id(scvolume)
if serverid is not None and volumeid is not None:
+ # If we have a mapping to our server return it here.
+ mprofiles = self._find_mapping_profiles(scvolume)
+ for mprofile in mprofiles:
+ if self._get_id(mprofile.get('server')) == serverid:
+ return mprofile
+ # No? Then map it up.
payload = {}
payload['server'] = serverid
advanced = {}
serverid = self._get_id(scserver)
volumeid = self._get_id(scvolume)
if serverid is not None and volumeid is not None:
- r = self.client.get('StorageCenter/ScVolume/%s/MappingProfileList'
- % volumeid)
- if r.status_code == 200:
- profiles = self._get_json(r)
- for profile in profiles:
- prosrv = profile.get('server')
- if prosrv is not None and self._get_id(prosrv) == serverid:
- r = self.client.delete(
- 'StorageCenter/ScMappingProfile/%s'
- % self._get_id(profile))
- if (r.status_code != 200 or r.ok is False):
- LOG.debug('ScMappingProfile error: '
- '%(code)d %(reason)s',
- {'code': r.status_code,
- 'reason': r.reason})
- LOG.error(_LE('Unable to unmap Volume %s'),
- volumeid)
- # 1 failed unmap is as good as 100.
- # Fail it and leave
- rtn = False
- break
- LOG.debug('Volume %(vol)s unmapped from %(srv)s',
- {'vol': volumeid,
- 'srv': serverid})
- else:
- LOG.debug('MappingProfileList error: %(code)d %(reason)s',
- {'code': r.status_code,
- 'reason': r.reason})
- rtn = False
+ profiles = self._find_mapping_profiles(scvolume)
+ for profile in profiles:
+ prosrv = profile.get('server')
+ if prosrv is not None and self._get_id(prosrv) == serverid:
+ r = self.client.delete('StorageCenter/ScMappingProfile/%s'
+ % self._get_id(profile))
+ if (r.status_code != 200 or r.ok is False):
+ LOG.debug('ScMappingProfile error: '
+ '%(code)d %(reason)s',
+ {'code': r.status_code,
+ 'reason': r.reason})
+ LOG.error(_LE('Unable to unmap Volume %s'),
+ volumeid)
+ # 1 failed unmap is as good as 100.
+ # Fail it and leave
+ rtn = False
+ break
+ LOG.debug('Volume %(vol)s unmapped from %(srv)s',
+ {'vol': volumeid,
+ 'srv': serverid})
return rtn
def get_storage_usage(self):
:return: Dell SC replay profile or None.
:raises: VolumeBackendAPIException
'''
- pf = PayloadFilter()
+ self.cg_except_on_no_support()
+ pf = self._get_payload_filter()
pf.append('ScSerialNumber', self.ssn)
pf.append('Name', name)
r = self.client.post('StorageCenter/ScReplayProfile/GetList',
the name on the Dell SC.
:return: SC profile or None.
'''
+ self.cg_except_on_no_support()
profile = self.find_replay_profile(name)
if not profile:
payload = {}
:return: Nothing.
:raises: VolumeBackendAPIException
'''
+ self.cg_except_on_no_support()
r = self.client.delete('StorageCenter/ScReplayProfile/%s' %
self._get_id(profile))
# 200 is a good return. Log and leave.
removing the profile from this list of volumes.)
:return: True/False on success/failure.
'''
+ self.cg_except_on_no_support()
ret = True
profileid = self._get_id(profile)
if add_volumes:
expiration.
:returns: Dell SC replay object.
'''
+ self.cg_except_on_no_support()
if profile:
payload = {}
payload['description'] = replayid
GUID in the replay description.
:returns: Dell replay object or None.
'''
+ self.cg_except_on_no_support()
r = self.client.get('StorageCenter/ScReplayProfile/%s/ReplayList'
% self._get_id(profile))
replays = self._get_json(r)
replay description.
:returns: Boolean for success or failure.
'''
-
+ self.cg_except_on_no_support()
LOG.debug('Expiring consistency group replay %s', replayid)
replay = self.find_replay(profile,
replayid)
# We either couldn't find it or expired it.
return True
+ def cg_except_on_no_support(self):
+ if not self.consisgroups:
+ msg = _('Dell API 2.1 or later required'
+ ' for Consistency Group support')
+ raise NotImplementedError(msg)
+
def _size_to_gb(self, spacestring):
'''Splits a SC size string into GB and a remainder.