Merge "Dell SC: Fix legacy bug, init_conn bug and REST API bug."

This commit is contained in:
Jenkins 2015-07-25 04:40:31 +00:00 committed by Gerrit Code Review
commit 4f197feb0d
2 changed files with 794 additions and 174 deletions

View File

@ -474,29 +474,6 @@ class DellSCSanAPITestCase(test.TestCase):
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,
@ -520,6 +497,8 @@ class DellSCSanAPITestCase(test.TestCase):
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'},
@ -1473,6 +1452,57 @@ class DellSCSanAPITestCase(test.TestCase):
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'
@ -2839,6 +2869,37 @@ class DellSCSanAPITestCase(test.TestCase):
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)
@ -3075,7 +3136,11 @@ class DellSCSanAPITestCase(test.TestCase):
@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,
@ -3084,6 +3149,7 @@ class DellSCSanAPITestCase(test.TestCase):
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)
@ -3112,7 +3178,11 @@ class DellSCSanAPITestCase(test.TestCase):
@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,
@ -3123,6 +3193,7 @@ class DellSCSanAPITestCase(test.TestCase):
# 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)
@ -3151,17 +3222,23 @@ class DellSCSanAPITestCase(test.TestCase):
@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)
@ -3204,7 +3281,11 @@ class DellSCSanAPITestCase(test.TestCase):
@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,
@ -3216,6 +3297,7 @@ class DellSCSanAPITestCase(test.TestCase):
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)
@ -3227,15 +3309,15 @@ class DellSCSanAPITestCase(test.TestCase):
@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,
@ -3245,8 +3327,8 @@ class DellSCSanAPITestCase(test.TestCase):
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)
@ -3262,7 +3344,11 @@ class DellSCSanAPITestCase(test.TestCase):
@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,
@ -3272,6 +3358,7 @@ class DellSCSanAPITestCase(test.TestCase):
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)
@ -3300,7 +3387,11 @@ class DellSCSanAPITestCase(test.TestCase):
@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,
@ -3314,6 +3405,7 @@ class DellSCSanAPITestCase(test.TestCase):
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':
@ -3332,13 +3424,275 @@ class DellSCSanAPITestCase(test.TestCase):
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,
@ -3346,6 +3700,54 @@ class DellSCSanAPITestCase(test.TestCase):
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')
@ -3395,7 +3797,11 @@ class DellSCSanAPITestCase(test.TestCase):
@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,
@ -3403,6 +3809,7 @@ class DellSCSanAPITestCase(test.TestCase):
# 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')
@ -3410,76 +3817,66 @@ class DellSCSanAPITestCase(test.TestCase):
'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)
@ -3489,14 +3886,10 @@ class DellSCSanAPITestCase(test.TestCase):
'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,
@ -3506,8 +3899,7 @@ class DellSCSanAPITestCase(test.TestCase):
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)
@ -3517,14 +3909,10 @@ class DellSCSanAPITestCase(test.TestCase):
'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,
@ -3534,11 +3922,41 @@ class DellSCSanAPITestCase(test.TestCase):
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)
@ -5234,6 +5652,29 @@ class DellSCSanAPIConnectionTestCase(test.TestCase):
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()
@ -5278,7 +5719,11 @@ class DellSCSanAPIConnectionTestCase(test.TestCase):
@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)

View File

@ -33,16 +33,34 @@ class PayloadFilter(object):
'''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:
@ -167,9 +185,18 @@ class StorageCenterApi(object):
'''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.
@ -185,6 +212,8 @@ class StorageCenterApi(object):
self.ssn = None
self.vfname = 'openstack'
self.sfname = 'openstack'
self.legacypayloadfilters = False
self.consisgroups = True
self.client = HttpClient(host,
port,
user,
@ -286,6 +315,12 @@ class StorageCenterApi(object):
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.
@ -297,13 +332,41 @@ class StorageCenterApi(object):
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.'''
@ -427,7 +490,7 @@ class StorageCenterApi(object):
: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)
@ -476,7 +539,7 @@ class StorageCenterApi(object):
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:
@ -521,7 +584,7 @@ class StorageCenterApi(object):
# 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)
@ -617,7 +680,7 @@ class StorageCenterApi(object):
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)
@ -773,7 +836,7 @@ class StorageCenterApi(object):
: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)
@ -888,7 +951,7 @@ class StorageCenterApi(object):
# 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',
@ -916,7 +979,7 @@ class StorageCenterApi(object):
'''
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',
@ -1006,6 +1069,28 @@ class StorageCenterApi(object):
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.
@ -1124,6 +1209,38 @@ class StorageCenterApi(object):
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.
@ -1137,58 +1254,108 @@ class StorageCenterApi(object):
'''
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)
# 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 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
# 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
@ -1199,26 +1366,25 @@ class StorageCenterApi(object):
# 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)
@ -1232,12 +1398,18 @@ class StorageCenterApi(object):
: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 = {}
@ -1273,35 +1445,26 @@ class StorageCenterApi(object):
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):
@ -1641,7 +1804,8 @@ class StorageCenterApi(object):
: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',
@ -1666,6 +1830,7 @@ class StorageCenterApi(object):
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 = {}
@ -1688,6 +1853,7 @@ class StorageCenterApi(object):
: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.
@ -1804,6 +1970,7 @@ class StorageCenterApi(object):
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:
@ -1838,6 +2005,7 @@ class StorageCenterApi(object):
expiration.
:returns: Dell SC replay object.
'''
self.cg_except_on_no_support()
if profile:
# We have to make sure these are snappable.
self._init_cg_volumes(self._get_id(profile))
@ -1871,6 +2039,7 @@ class StorageCenterApi(object):
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)
@ -1906,7 +2075,7 @@ class StorageCenterApi(object):
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)
@ -1922,6 +2091,12 @@ class StorageCenterApi(object):
# 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.