Merge "Dell SC: Fix legacy bug, init_conn bug and REST API bug."
This commit is contained in:
commit
4f197feb0d
@ -474,29 +474,6 @@ class DellSCSanAPITestCase(test.TestCase):
|
|||||||
u'instanceName': u'Other Multipath',
|
u'instanceName': u'Other Multipath',
|
||||||
u'objectType': u'ScServerOperatingSystem'}}]
|
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',
|
MAP_PROFILE = {u'instanceId': u'64702.2941',
|
||||||
u'scName': u'Storage Center 64702',
|
u'scName': u'Storage Center 64702',
|
||||||
u'scSerialNumber': 64702,
|
u'scSerialNumber': 64702,
|
||||||
@ -520,6 +497,8 @@ class DellSCSanAPITestCase(test.TestCase):
|
|||||||
u'instanceName': u'6025-47',
|
u'instanceName': u'6025-47',
|
||||||
u'lunRequested': u'N/A'}
|
u'lunRequested': u'N/A'}
|
||||||
|
|
||||||
|
MAP_PROFILES = [MAP_PROFILE]
|
||||||
|
|
||||||
MAPPINGS = [{u'profile': {u'instanceId': u'64702.104',
|
MAPPINGS = [{u'profile': {u'instanceId': u'64702.104',
|
||||||
u'instanceName': u'92-30',
|
u'instanceName': u'92-30',
|
||||||
u'objectType': u'ScMappingProfile'},
|
u'objectType': u'ScMappingProfile'},
|
||||||
@ -1473,6 +1452,57 @@ class DellSCSanAPITestCase(test.TestCase):
|
|||||||
u'userCreated': False,
|
u'userCreated': False,
|
||||||
u'volumeCount': 0}]
|
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'
|
IQN = 'iqn.2002-03.com.compellent:5000D31000000001'
|
||||||
WWN = u'21000024FF30441C'
|
WWN = u'21000024FF30441C'
|
||||||
|
|
||||||
@ -2839,6 +2869,37 @@ class DellSCSanAPITestCase(test.TestCase):
|
|||||||
self.assertTrue(mock_get_json.called)
|
self.assertTrue(mock_get_json.called)
|
||||||
self.assertEqual([], res, 'Mapping count mismatch')
|
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,
|
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||||
'_first_result',
|
'_first_result',
|
||||||
return_value=CTRLR_PORT)
|
return_value=CTRLR_PORT)
|
||||||
@ -3075,7 +3136,11 @@ class DellSCSanAPITestCase(test.TestCase):
|
|||||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||||
'_find_mappings',
|
'_find_mappings',
|
||||||
return_value=MAPPINGS)
|
return_value=MAPPINGS)
|
||||||
|
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||||
|
'_is_virtualport_mode',
|
||||||
|
return_value=True)
|
||||||
def test_find_iscsi_properties_mappings(self,
|
def test_find_iscsi_properties_mappings(self,
|
||||||
|
mock_is_virtualport_mode,
|
||||||
mock_find_mappings,
|
mock_find_mappings,
|
||||||
mock_find_domains,
|
mock_find_domains,
|
||||||
mock_find_ctrl_port,
|
mock_find_ctrl_port,
|
||||||
@ -3084,6 +3149,7 @@ class DellSCSanAPITestCase(test.TestCase):
|
|||||||
mock_open_connection,
|
mock_open_connection,
|
||||||
mock_init):
|
mock_init):
|
||||||
res = self.scapi.find_iscsi_properties(self.VOLUME)
|
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_mappings.called)
|
||||||
self.assertTrue(mock_find_domains.called)
|
self.assertTrue(mock_find_domains.called)
|
||||||
self.assertTrue(mock_find_ctrl_port.called)
|
self.assertTrue(mock_find_ctrl_port.called)
|
||||||
@ -3112,7 +3178,11 @@ class DellSCSanAPITestCase(test.TestCase):
|
|||||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||||
'_find_mappings',
|
'_find_mappings',
|
||||||
return_value=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,
|
def test_find_iscsi_properties_by_address(self,
|
||||||
|
mock_is_virtualport_mode,
|
||||||
mock_find_mappings,
|
mock_find_mappings,
|
||||||
mock_find_domains,
|
mock_find_domains,
|
||||||
mock_find_ctrl_port,
|
mock_find_ctrl_port,
|
||||||
@ -3123,6 +3193,7 @@ class DellSCSanAPITestCase(test.TestCase):
|
|||||||
# Test case to find iSCSI mappings by IP Address & port
|
# Test case to find iSCSI mappings by IP Address & port
|
||||||
res = self.scapi.find_iscsi_properties(
|
res = self.scapi.find_iscsi_properties(
|
||||||
self.VOLUME, '192.168.0.21', 3260)
|
self.VOLUME, '192.168.0.21', 3260)
|
||||||
|
self.assertTrue(mock_is_virtualport_mode.called)
|
||||||
self.assertTrue(mock_find_mappings.called)
|
self.assertTrue(mock_find_mappings.called)
|
||||||
self.assertTrue(mock_find_domains.called)
|
self.assertTrue(mock_find_domains.called)
|
||||||
self.assertTrue(mock_find_ctrl_port.called)
|
self.assertTrue(mock_find_ctrl_port.called)
|
||||||
@ -3151,17 +3222,23 @@ class DellSCSanAPITestCase(test.TestCase):
|
|||||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||||
'_find_mappings',
|
'_find_mappings',
|
||||||
return_value=MAPPINGS)
|
return_value=MAPPINGS)
|
||||||
def test_find_iscsi_properties_by_address_not_found(self,
|
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||||
mock_find_mappings,
|
'_is_virtualport_mode',
|
||||||
mock_find_domains,
|
return_value=True)
|
||||||
mock_find_ctrl_port,
|
def test_find_iscsi_properties_by_address_not_found(
|
||||||
mock_find_active_ctrl,
|
self,
|
||||||
mock_close_connection,
|
mock_is_virtualport_mode,
|
||||||
mock_open_connection,
|
mock_find_mappings,
|
||||||
mock_init):
|
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
|
# Test case to find iSCSI mappings by IP Address & port are not found
|
||||||
res = self.scapi.find_iscsi_properties(
|
res = self.scapi.find_iscsi_properties(
|
||||||
self.VOLUME, '192.168.1.21', 3260)
|
self.VOLUME, '192.168.1.21', 3260)
|
||||||
|
self.assertTrue(mock_is_virtualport_mode.called)
|
||||||
self.assertTrue(mock_find_mappings.called)
|
self.assertTrue(mock_find_mappings.called)
|
||||||
self.assertTrue(mock_find_domains.called)
|
self.assertTrue(mock_find_domains.called)
|
||||||
self.assertTrue(mock_find_ctrl_port.called)
|
self.assertTrue(mock_find_ctrl_port.called)
|
||||||
@ -3204,7 +3281,11 @@ class DellSCSanAPITestCase(test.TestCase):
|
|||||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||||
'_find_mappings',
|
'_find_mappings',
|
||||||
return_value=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,
|
def test_find_iscsi_properties_no_domain(self,
|
||||||
|
mock_is_virtualport_mode,
|
||||||
mock_find_mappings,
|
mock_find_mappings,
|
||||||
mock_find_domains,
|
mock_find_domains,
|
||||||
mock_find_ctrl_port,
|
mock_find_ctrl_port,
|
||||||
@ -3216,6 +3297,7 @@ class DellSCSanAPITestCase(test.TestCase):
|
|||||||
self.assertRaises(exception.VolumeBackendAPIException,
|
self.assertRaises(exception.VolumeBackendAPIException,
|
||||||
self.scapi.find_iscsi_properties,
|
self.scapi.find_iscsi_properties,
|
||||||
self.VOLUME)
|
self.VOLUME)
|
||||||
|
self.assertTrue(mock_is_virtualport_mode.called)
|
||||||
self.assertTrue(mock_find_mappings.called)
|
self.assertTrue(mock_find_mappings.called)
|
||||||
self.assertTrue(mock_find_domains.called)
|
self.assertTrue(mock_find_domains.called)
|
||||||
self.assertTrue(mock_find_ctrl_port.called)
|
self.assertTrue(mock_find_ctrl_port.called)
|
||||||
@ -3227,15 +3309,15 @@ class DellSCSanAPITestCase(test.TestCase):
|
|||||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||||
'_find_controller_port',
|
'_find_controller_port',
|
||||||
return_value=None)
|
return_value=None)
|
||||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
|
||||||
'_find_domains',
|
|
||||||
return_value=ISCSI_FLT_DOMAINS)
|
|
||||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||||
'_find_mappings',
|
'_find_mappings',
|
||||||
return_value=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,
|
def test_find_iscsi_properties_no_ctrl_port(self,
|
||||||
|
mock_is_virtualport_mode,
|
||||||
mock_find_mappings,
|
mock_find_mappings,
|
||||||
mock_find_domains,
|
|
||||||
mock_find_ctrl_port,
|
mock_find_ctrl_port,
|
||||||
mock_find_active_controller,
|
mock_find_active_controller,
|
||||||
mock_close_connection,
|
mock_close_connection,
|
||||||
@ -3245,8 +3327,8 @@ class DellSCSanAPITestCase(test.TestCase):
|
|||||||
self.assertRaises(exception.VolumeBackendAPIException,
|
self.assertRaises(exception.VolumeBackendAPIException,
|
||||||
self.scapi.find_iscsi_properties,
|
self.scapi.find_iscsi_properties,
|
||||||
self.VOLUME)
|
self.VOLUME)
|
||||||
|
self.assertTrue(mock_is_virtualport_mode.called)
|
||||||
self.assertTrue(mock_find_mappings.called)
|
self.assertTrue(mock_find_mappings.called)
|
||||||
self.assertTrue(mock_find_domains.called)
|
|
||||||
self.assertTrue(mock_find_ctrl_port.called)
|
self.assertTrue(mock_find_ctrl_port.called)
|
||||||
self.assertTrue(mock_find_active_controller.called)
|
self.assertTrue(mock_find_active_controller.called)
|
||||||
|
|
||||||
@ -3262,7 +3344,11 @@ class DellSCSanAPITestCase(test.TestCase):
|
|||||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||||
'_find_mappings',
|
'_find_mappings',
|
||||||
return_value=MAPPINGS_READ_ONLY)
|
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,
|
def test_find_iscsi_properties_ro(self,
|
||||||
|
mock_is_virtualport_mode,
|
||||||
mock_find_mappings,
|
mock_find_mappings,
|
||||||
mock_find_domains,
|
mock_find_domains,
|
||||||
mock_find_ctrl_port,
|
mock_find_ctrl_port,
|
||||||
@ -3272,6 +3358,7 @@ class DellSCSanAPITestCase(test.TestCase):
|
|||||||
mock_init):
|
mock_init):
|
||||||
# Test case where Read Only mappings are found
|
# Test case where Read Only mappings are found
|
||||||
res = self.scapi.find_iscsi_properties(self.VOLUME)
|
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_mappings.called)
|
||||||
self.assertTrue(mock_find_domains.called)
|
self.assertTrue(mock_find_domains.called)
|
||||||
self.assertTrue(mock_find_ctrl_port.called)
|
self.assertTrue(mock_find_ctrl_port.called)
|
||||||
@ -3300,7 +3387,11 @@ class DellSCSanAPITestCase(test.TestCase):
|
|||||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||||
'_find_mappings',
|
'_find_mappings',
|
||||||
return_value=MAPPINGS_MULTI_PORTAL)
|
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,
|
def test_find_iscsi_properties_multi_portals(self,
|
||||||
|
mock_is_virtualport_mode,
|
||||||
mock_find_mappings,
|
mock_find_mappings,
|
||||||
mock_find_domains,
|
mock_find_domains,
|
||||||
mock_find_ctrl_port,
|
mock_find_ctrl_port,
|
||||||
@ -3314,6 +3405,7 @@ class DellSCSanAPITestCase(test.TestCase):
|
|||||||
self.assertTrue(mock_find_domains.called)
|
self.assertTrue(mock_find_domains.called)
|
||||||
self.assertTrue(mock_find_ctrl_port.called)
|
self.assertTrue(mock_find_ctrl_port.called)
|
||||||
self.assertTrue(mock_find_active_controller.called)
|
self.assertTrue(mock_find_active_controller.called)
|
||||||
|
self.assertTrue(mock_is_virtualport_mode.called)
|
||||||
expected = {'access_mode': 'rw',
|
expected = {'access_mode': 'rw',
|
||||||
'target_discovered': False,
|
'target_discovered': False,
|
||||||
'target_iqn':
|
'target_iqn':
|
||||||
@ -3332,13 +3424,275 @@ class DellSCSanAPITestCase(test.TestCase):
|
|||||||
u'192.168.0.25:3260']}
|
u'192.168.0.25:3260']}
|
||||||
self.assertEqual(expected, res, 'Wrong Target Info')
|
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,
|
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||||
'_first_result',
|
'_first_result',
|
||||||
return_value=MAP_PROFILE)
|
return_value=MAP_PROFILE)
|
||||||
@mock.patch.object(dell_storagecenter_api.HttpClient,
|
@mock.patch.object(dell_storagecenter_api.HttpClient,
|
||||||
'post',
|
'post',
|
||||||
return_value=RESPONSE_200)
|
return_value=RESPONSE_200)
|
||||||
|
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||||
|
'_find_mapping_profiles',
|
||||||
|
return_value=[])
|
||||||
def test_map_volume(self,
|
def test_map_volume(self,
|
||||||
|
mock_find_mapping_profiles,
|
||||||
mock_post,
|
mock_post,
|
||||||
mock_first_result,
|
mock_first_result,
|
||||||
mock_close_connection,
|
mock_close_connection,
|
||||||
@ -3346,6 +3700,54 @@ class DellSCSanAPITestCase(test.TestCase):
|
|||||||
mock_init):
|
mock_init):
|
||||||
res = self.scapi.map_volume(self.VOLUME,
|
res = self.scapi.map_volume(self.VOLUME,
|
||||||
self.SCSERVER)
|
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_post.called)
|
||||||
self.assertTrue(mock_first_result.called)
|
self.assertTrue(mock_first_result.called)
|
||||||
self.assertEqual(self.MAP_PROFILE, res, 'Incorrect ScMappingProfile')
|
self.assertEqual(self.MAP_PROFILE, res, 'Incorrect ScMappingProfile')
|
||||||
@ -3395,7 +3797,11 @@ class DellSCSanAPITestCase(test.TestCase):
|
|||||||
@mock.patch.object(dell_storagecenter_api.HttpClient,
|
@mock.patch.object(dell_storagecenter_api.HttpClient,
|
||||||
'post',
|
'post',
|
||||||
return_value=RESPONSE_204)
|
return_value=RESPONSE_204)
|
||||||
|
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||||
|
'_find_mapping_profiles',
|
||||||
|
return_value=[])
|
||||||
def test_map_volume_failure(self,
|
def test_map_volume_failure(self,
|
||||||
|
mock_find_mapping_profiles,
|
||||||
mock_post,
|
mock_post,
|
||||||
mock_close_connection,
|
mock_close_connection,
|
||||||
mock_open_connection,
|
mock_open_connection,
|
||||||
@ -3403,6 +3809,7 @@ class DellSCSanAPITestCase(test.TestCase):
|
|||||||
# Test case where mapping volume to server fails
|
# Test case where mapping volume to server fails
|
||||||
res = self.scapi.map_volume(self.VOLUME,
|
res = self.scapi.map_volume(self.VOLUME,
|
||||||
self.SCSERVER)
|
self.SCSERVER)
|
||||||
|
self.assertTrue(mock_find_mapping_profiles.called)
|
||||||
self.assertTrue(mock_post.called)
|
self.assertTrue(mock_post.called)
|
||||||
self.assertIsNone(res, 'None expected')
|
self.assertIsNone(res, 'None expected')
|
||||||
|
|
||||||
@ -3410,76 +3817,66 @@ class DellSCSanAPITestCase(test.TestCase):
|
|||||||
'delete',
|
'delete',
|
||||||
return_value=RESPONSE_200)
|
return_value=RESPONSE_200)
|
||||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||||
'_get_json',
|
'_find_mapping_profiles',
|
||||||
return_value=MAP_PROFILES)
|
return_value=MAP_PROFILES)
|
||||||
@mock.patch.object(dell_storagecenter_api.HttpClient,
|
|
||||||
'get',
|
|
||||||
return_value=RESPONSE_200)
|
|
||||||
def test_unmap_volume(self,
|
def test_unmap_volume(self,
|
||||||
mock_get,
|
mock_find_mapping_profiles,
|
||||||
mock_get_json,
|
|
||||||
mock_delete,
|
mock_delete,
|
||||||
mock_close_connection,
|
mock_close_connection,
|
||||||
mock_open_connection,
|
mock_open_connection,
|
||||||
mock_init):
|
mock_init):
|
||||||
res = self.scapi.unmap_volume(self.VOLUME,
|
res = self.scapi.unmap_volume(self.VOLUME,
|
||||||
self.SCSERVER)
|
self.SCSERVER)
|
||||||
self.assertTrue(mock_get.called)
|
self.assertTrue(mock_find_mapping_profiles.called)
|
||||||
self.assertTrue(mock_get_json.called)
|
|
||||||
self.assertTrue(mock_delete.called)
|
self.assertTrue(mock_delete.called)
|
||||||
self.assertTrue(res)
|
self.assertTrue(res)
|
||||||
|
|
||||||
|
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||||
|
'_find_mapping_profiles',
|
||||||
|
return_value=MAP_PROFILES)
|
||||||
@mock.patch.object(dell_storagecenter_api.HttpClient,
|
@mock.patch.object(dell_storagecenter_api.HttpClient,
|
||||||
'get',
|
'delete',
|
||||||
return_value=RESPONSE_204)
|
return_value=RESPONSE_204)
|
||||||
def test_unmap_volume_failure(self,
|
def test_unmap_volume_failure(self,
|
||||||
mock_get,
|
mock_delete,
|
||||||
|
mock_find_mapping_profiles,
|
||||||
mock_close_connection,
|
mock_close_connection,
|
||||||
mock_open_connection,
|
mock_open_connection,
|
||||||
mock_init):
|
mock_init):
|
||||||
res = self.scapi.unmap_volume(self.VOLUME,
|
res = self.scapi.unmap_volume(self.VOLUME,
|
||||||
self.SCSERVER)
|
self.SCSERVER)
|
||||||
self.assertTrue(mock_get.called)
|
self.assertTrue(mock_find_mapping_profiles.called)
|
||||||
|
self.assertTrue(mock_delete.called)
|
||||||
self.assertFalse(res)
|
self.assertFalse(res)
|
||||||
|
|
||||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||||
'_get_json',
|
'_find_mapping_profiles',
|
||||||
return_value=[])
|
return_value=[])
|
||||||
@mock.patch.object(dell_storagecenter_api.HttpClient,
|
|
||||||
'get',
|
|
||||||
return_value=RESPONSE_200)
|
|
||||||
def test_unmap_volume_no_map_profile(self,
|
def test_unmap_volume_no_map_profile(self,
|
||||||
mock_get,
|
mock_find_mapping_profiles,
|
||||||
mock_get_json,
|
|
||||||
mock_close_connection,
|
mock_close_connection,
|
||||||
mock_open_connection,
|
mock_open_connection,
|
||||||
mock_init):
|
mock_init):
|
||||||
res = self.scapi.unmap_volume(self.VOLUME,
|
res = self.scapi.unmap_volume(self.VOLUME,
|
||||||
self.SCSERVER)
|
self.SCSERVER)
|
||||||
self.assertTrue(mock_get.called)
|
self.assertTrue(mock_find_mapping_profiles.called)
|
||||||
self.assertTrue(mock_get_json.called)
|
|
||||||
self.assertTrue(res)
|
self.assertTrue(res)
|
||||||
|
|
||||||
@mock.patch.object(dell_storagecenter_api.HttpClient,
|
@mock.patch.object(dell_storagecenter_api.HttpClient,
|
||||||
'delete',
|
'delete',
|
||||||
return_value=RESPONSE_204)
|
return_value=RESPONSE_204)
|
||||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||||
'_get_json',
|
'_find_mapping_profiles',
|
||||||
return_value=MAP_PROFILES)
|
return_value=MAP_PROFILES)
|
||||||
@mock.patch.object(dell_storagecenter_api.HttpClient,
|
|
||||||
'get',
|
|
||||||
return_value=RESPONSE_200)
|
|
||||||
def test_unmap_volume_del_fail(self,
|
def test_unmap_volume_del_fail(self,
|
||||||
mock_get,
|
mock_find_mapping_profiles,
|
||||||
mock_get_json,
|
|
||||||
mock_delete,
|
mock_delete,
|
||||||
mock_close_connection,
|
mock_close_connection,
|
||||||
mock_open_connection,
|
mock_open_connection,
|
||||||
mock_init):
|
mock_init):
|
||||||
res = self.scapi.unmap_volume(self.VOLUME,
|
res = self.scapi.unmap_volume(self.VOLUME,
|
||||||
self.SCSERVER)
|
self.SCSERVER)
|
||||||
self.assertTrue(mock_get.called)
|
self.assertTrue(mock_find_mapping_profiles.called)
|
||||||
self.assertTrue(mock_get_json.called)
|
|
||||||
self.assertTrue(mock_delete.called)
|
self.assertTrue(mock_delete.called)
|
||||||
self.assertFalse(res, False)
|
self.assertFalse(res, False)
|
||||||
|
|
||||||
@ -3489,14 +3886,10 @@ class DellSCSanAPITestCase(test.TestCase):
|
|||||||
'delete',
|
'delete',
|
||||||
return_value=RESPONSE_200)
|
return_value=RESPONSE_200)
|
||||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||||
'_get_json',
|
'_find_mapping_profiles',
|
||||||
return_value=MAP_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,
|
def test_unmap_volume_no_vol_id(self,
|
||||||
mock_get,
|
mock_find_mapping_profiles,
|
||||||
mock_get_json,
|
|
||||||
mock_delete,
|
mock_delete,
|
||||||
mock_get_id,
|
mock_get_id,
|
||||||
mock_close_connection,
|
mock_close_connection,
|
||||||
@ -3506,8 +3899,7 @@ class DellSCSanAPITestCase(test.TestCase):
|
|||||||
mock_get_id.side_effect = [None, '64702.47']
|
mock_get_id.side_effect = [None, '64702.47']
|
||||||
res = self.scapi.unmap_volume(self.VOLUME,
|
res = self.scapi.unmap_volume(self.VOLUME,
|
||||||
self.SCSERVER)
|
self.SCSERVER)
|
||||||
self.assertFalse(mock_get.called)
|
self.assertFalse(mock_find_mapping_profiles.called)
|
||||||
self.assertFalse(mock_get_json.called)
|
|
||||||
self.assertFalse(mock_delete.called)
|
self.assertFalse(mock_delete.called)
|
||||||
self.assertTrue(res)
|
self.assertTrue(res)
|
||||||
|
|
||||||
@ -3517,14 +3909,10 @@ class DellSCSanAPITestCase(test.TestCase):
|
|||||||
'delete',
|
'delete',
|
||||||
return_value=RESPONSE_200)
|
return_value=RESPONSE_200)
|
||||||
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||||
'_get_json',
|
'_find_mapping_profiles',
|
||||||
return_value=MAP_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,
|
def test_unmap_volume_no_server_id(self,
|
||||||
mock_get,
|
mock_find_mapping_profiles,
|
||||||
mock_get_json,
|
|
||||||
mock_delete,
|
mock_delete,
|
||||||
mock_get_id,
|
mock_get_id,
|
||||||
mock_close_connection,
|
mock_close_connection,
|
||||||
@ -3534,11 +3922,41 @@ class DellSCSanAPITestCase(test.TestCase):
|
|||||||
mock_get_id.side_effect = ['64702.3494', None]
|
mock_get_id.side_effect = ['64702.3494', None]
|
||||||
res = self.scapi.unmap_volume(self.VOLUME,
|
res = self.scapi.unmap_volume(self.VOLUME,
|
||||||
self.SCSERVER)
|
self.SCSERVER)
|
||||||
self.assertFalse(mock_get.called)
|
self.assertFalse(mock_find_mapping_profiles.called)
|
||||||
self.assertFalse(mock_get_json.called)
|
|
||||||
self.assertFalse(mock_delete.called)
|
self.assertFalse(mock_delete.called)
|
||||||
self.assertTrue(res)
|
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,
|
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||||
'_get_json',
|
'_get_json',
|
||||||
return_value=STRG_USAGE)
|
return_value=STRG_USAGE)
|
||||||
@ -5234,6 +5652,29 @@ class DellSCSanAPIConnectionTestCase(test.TestCase):
|
|||||||
response_nc.reason = u'duplicate'
|
response_nc.reason = u'duplicate'
|
||||||
RESPONSE_204 = response_nc
|
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):
|
def setUp(self):
|
||||||
super(DellSCSanAPIConnectionTestCase, self).setUp()
|
super(DellSCSanAPIConnectionTestCase, self).setUp()
|
||||||
|
|
||||||
@ -5278,7 +5719,11 @@ class DellSCSanAPIConnectionTestCase(test.TestCase):
|
|||||||
@mock.patch.object(dell_storagecenter_api.HttpClient,
|
@mock.patch.object(dell_storagecenter_api.HttpClient,
|
||||||
'post',
|
'post',
|
||||||
return_value=RESPONSE_200)
|
return_value=RESPONSE_200)
|
||||||
|
@mock.patch.object(dell_storagecenter_api.StorageCenterApi,
|
||||||
|
'_get_json',
|
||||||
|
return_value=APIDICT)
|
||||||
def test_open_connection(self,
|
def test_open_connection(self,
|
||||||
|
mock_get_json,
|
||||||
mock_post):
|
mock_post):
|
||||||
self.scapi.open_connection()
|
self.scapi.open_connection()
|
||||||
self.assertTrue(mock_post.called)
|
self.assertTrue(mock_post.called)
|
||||||
|
@ -33,16 +33,34 @@ class PayloadFilter(object):
|
|||||||
'''PayloadFilter
|
'''PayloadFilter
|
||||||
|
|
||||||
Simple class for creating filters for interacting with the Dell
|
Simple class for creating filters for interacting with the Dell
|
||||||
Storage API.
|
Storage API DropTop2 and later.
|
||||||
|
|
||||||
Note that this defaults to "AND" filter types. This is a pretty limited
|
|
||||||
class. It only does the trivial filters required for this driver.
|
|
||||||
'''
|
'''
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, filtertype='AND'):
|
||||||
self.payload = {}
|
self.payload = {}
|
||||||
self.payload['filterType'] = 'AND'
|
self.payload['filter'] = {'filterType': filtertype,
|
||||||
self.payload['filters'] = []
|
'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'):
|
def append(self, name, val, filtertype='Equals'):
|
||||||
if val is not None:
|
if val is not None:
|
||||||
@ -167,9 +185,18 @@ class StorageCenterApi(object):
|
|||||||
'''StorageCenterApi
|
'''StorageCenterApi
|
||||||
|
|
||||||
Handles calls to Dell Enterprise Manager (EM) via the REST API interface.
|
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):
|
def __init__(self, host, port, user, password, verify):
|
||||||
'''This creates a connection to Dell Enterprise Manager.
|
'''This creates a connection to Dell Enterprise Manager.
|
||||||
@ -185,6 +212,8 @@ class StorageCenterApi(object):
|
|||||||
self.ssn = None
|
self.ssn = None
|
||||||
self.vfname = 'openstack'
|
self.vfname = 'openstack'
|
||||||
self.sfname = 'openstack'
|
self.sfname = 'openstack'
|
||||||
|
self.legacypayloadfilters = False
|
||||||
|
self.consisgroups = True
|
||||||
self.client = HttpClient(host,
|
self.client = HttpClient(host,
|
||||||
port,
|
port,
|
||||||
user,
|
user,
|
||||||
@ -286,6 +315,12 @@ class StorageCenterApi(object):
|
|||||||
blob)
|
blob)
|
||||||
return None
|
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):
|
def open_connection(self):
|
||||||
'''Authenticate against Dell Enterprise Manager.
|
'''Authenticate against Dell Enterprise Manager.
|
||||||
|
|
||||||
@ -297,13 +332,41 @@ class StorageCenterApi(object):
|
|||||||
payload['ApplicationVersion'] = self.APIVERSION
|
payload['ApplicationVersion'] = self.APIVERSION
|
||||||
r = self.client.post('ApiConnection/Login',
|
r = self.client.post('ApiConnection/Login',
|
||||||
payload)
|
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'),
|
LOG.error(_LE('Login error: %(code)d %(reason)s'),
|
||||||
{'code': r.status_code,
|
{'code': r.status_code,
|
||||||
'reason': r.reason})
|
'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):
|
def close_connection(self):
|
||||||
'''Logout of Dell Enterprise Manager.'''
|
'''Logout of Dell Enterprise Manager.'''
|
||||||
@ -427,7 +490,7 @@ class StorageCenterApi(object):
|
|||||||
:param foldername: Full path to the folder we are looking for.
|
:param foldername: Full path to the folder we are looking for.
|
||||||
:returns: Dell folder object.
|
:returns: Dell folder object.
|
||||||
'''
|
'''
|
||||||
pf = PayloadFilter()
|
pf = self._get_payload_filter()
|
||||||
pf.append('scSerialNumber', self.ssn)
|
pf.append('scSerialNumber', self.ssn)
|
||||||
basename = os.path.basename(foldername)
|
basename = os.path.basename(foldername)
|
||||||
pf.append('Name', basename)
|
pf.append('Name', basename)
|
||||||
@ -476,7 +539,7 @@ class StorageCenterApi(object):
|
|||||||
Don't wig out if this fails.
|
Don't wig out if this fails.
|
||||||
:param scvolume: Dell Volume object.
|
:param scvolume: Dell Volume object.
|
||||||
'''
|
'''
|
||||||
pf = PayloadFilter()
|
pf = self._get_payload_filter()
|
||||||
pf.append('scSerialNumber', scvolume.get('scSerialNumber'), 'Equals')
|
pf.append('scSerialNumber', scvolume.get('scSerialNumber'), 'Equals')
|
||||||
r = self.client.post('StorageCenter/ScServer/GetList', pf.payload)
|
r = self.client.post('StorageCenter/ScServer/GetList', pf.payload)
|
||||||
if r.status_code == 200:
|
if r.status_code == 200:
|
||||||
@ -521,7 +584,7 @@ class StorageCenterApi(object):
|
|||||||
# and look through for the one we want. Never many profiles, so
|
# and look through for the one we want. Never many profiles, so
|
||||||
# this doesn't cause as much overhead as it might seem.
|
# this doesn't cause as much overhead as it might seem.
|
||||||
storage_profile = storage_profile.replace(' ', '').lower()
|
storage_profile = storage_profile.replace(' ', '').lower()
|
||||||
pf = PayloadFilter()
|
pf = self._get_payload_filter()
|
||||||
pf.append('scSerialNumber', self.ssn, 'Equals')
|
pf.append('scSerialNumber', self.ssn, 'Equals')
|
||||||
r = self.client.post(
|
r = self.client.post(
|
||||||
'StorageCenter/ScStorageProfile/GetList', pf.payload)
|
'StorageCenter/ScStorageProfile/GetList', pf.payload)
|
||||||
@ -617,7 +680,7 @@ class StorageCenterApi(object):
|
|||||||
result = None
|
result = None
|
||||||
# We need a name or a device ID to find a volume.
|
# We need a name or a device ID to find a volume.
|
||||||
if name or deviceid:
|
if name or deviceid:
|
||||||
pf = PayloadFilter()
|
pf = self._get_payload_filter()
|
||||||
pf.append('scSerialNumber', self.ssn)
|
pf.append('scSerialNumber', self.ssn)
|
||||||
if name is not None:
|
if name is not None:
|
||||||
pf.append('Name', name)
|
pf.append('Name', name)
|
||||||
@ -773,7 +836,7 @@ class StorageCenterApi(object):
|
|||||||
:param osname: The name of the OS to look for.
|
:param osname: The name of the OS to look for.
|
||||||
:returns: InstanceId of the ScServerOperatingSystem object.
|
:returns: InstanceId of the ScServerOperatingSystem object.
|
||||||
'''
|
'''
|
||||||
pf = PayloadFilter()
|
pf = self._get_payload_filter()
|
||||||
pf.append('scSerialNumber', self.ssn)
|
pf.append('scSerialNumber', self.ssn)
|
||||||
r = self.client.post('StorageCenter/ScServerOperatingSystem/GetList',
|
r = self.client.post('StorageCenter/ScServerOperatingSystem/GetList',
|
||||||
pf.payload)
|
pf.payload)
|
||||||
@ -888,7 +951,7 @@ class StorageCenterApi(object):
|
|||||||
# that we found one it actually has to be attached to a
|
# that we found one it actually has to be attached to a
|
||||||
# server.
|
# server.
|
||||||
if hba is not None and hba.get('server') is not None:
|
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('scSerialNumber', self.ssn)
|
||||||
pf.append('instanceId', self._get_id(hba['server']))
|
pf.append('instanceId', self._get_id(hba['server']))
|
||||||
r = self.client.post('StorageCenter/ScServer/GetList',
|
r = self.client.post('StorageCenter/ScServer/GetList',
|
||||||
@ -916,7 +979,7 @@ class StorageCenterApi(object):
|
|||||||
'''
|
'''
|
||||||
scserverhba = None
|
scserverhba = None
|
||||||
# We search for our server by first finding our HBA
|
# We search for our server by first finding our HBA
|
||||||
pf = PayloadFilter()
|
pf = self._get_payload_filter()
|
||||||
pf.append('scSerialNumber', self.ssn)
|
pf.append('scSerialNumber', self.ssn)
|
||||||
pf.append('instanceName', instance_name)
|
pf.append('instanceName', instance_name)
|
||||||
r = self.client.post('StorageCenter/ScServerHba/GetList',
|
r = self.client.post('StorageCenter/ScServerHba/GetList',
|
||||||
@ -1006,6 +1069,28 @@ class StorageCenterApi(object):
|
|||||||
LOG.error(_LE('_find_mappings: volume is not active'))
|
LOG.error(_LE('_find_mappings: volume is not active'))
|
||||||
return mappings
|
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):
|
def _find_controller_port(self, cportid):
|
||||||
'''Finds the SC controller port object for the specified cportid.
|
'''Finds the SC controller port object for the specified cportid.
|
||||||
|
|
||||||
@ -1124,6 +1209,38 @@ class StorageCenterApi(object):
|
|||||||
iqn = controllerport.get('iscsiName')
|
iqn = controllerport.get('iscsiName')
|
||||||
return iqn
|
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):
|
def find_iscsi_properties(self, scvolume, ip=None, port=None):
|
||||||
'''Finds target information for a given Dell scvolume object mapping.
|
'''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('enter find_iscsi_properties')
|
||||||
LOG.debug('scvolume: %s', scvolume)
|
LOG.debug('scvolume: %s', scvolume)
|
||||||
active = -1
|
# Our mutable process object.
|
||||||
up = -1
|
pdata = {'active': -1,
|
||||||
access_mode = 'rw'
|
'up': -1,
|
||||||
|
'access_mode': 'rw',
|
||||||
|
'ip': ip,
|
||||||
|
'port': port}
|
||||||
|
# Our output lists.
|
||||||
portals = []
|
portals = []
|
||||||
luns = []
|
luns = []
|
||||||
iqns = []
|
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)
|
mappings = self._find_mappings(scvolume)
|
||||||
|
|
||||||
|
# We should have mappings at the time of this call but do check.
|
||||||
if len(mappings) > 0:
|
if len(mappings) > 0:
|
||||||
# In multipath (per Liberty) we will return all paths. But
|
# In multipath (per Liberty) we will return all paths. But
|
||||||
# if multipath is not set (ip and port are None) then we need
|
# if multipath is not set (ip and port are None) then we need
|
||||||
# to return a mapping from the controller on which the volume
|
# to return a mapping from the controller on which the volume
|
||||||
# is active. So find that controller.
|
# is active. So find that controller.
|
||||||
actvctrl = self._find_active_controller(scvolume)
|
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:
|
for mapping in mappings:
|
||||||
# The lun, ro mode and status are in the mapping.
|
# The lun, ro mode and status are in the mapping.
|
||||||
LOG.debug('mapping: %s', mapping)
|
LOG.debug('mapping: %s', mapping)
|
||||||
lun = mapping.get('lun')
|
lun = mapping.get('lun')
|
||||||
ro = mapping.get('readOnly', False)
|
ro = mapping.get('readOnly', False)
|
||||||
status = mapping.get('status')
|
status = mapping.get('status')
|
||||||
# Dig a bit to get our domains,IQN and controller id.
|
# Get our IQN from our mapping.
|
||||||
domains = self._get_domains(mapping)
|
|
||||||
iqn = self._get_iqn(mapping)
|
iqn = self._get_iqn(mapping)
|
||||||
ctrlid = self._get_controller_id(mapping)
|
# Check if our controller ID matches our active controller ID.
|
||||||
if domains and iqn is not None:
|
isactive = True if (self._get_controller_id(mapping) ==
|
||||||
for dom in domains:
|
actvctrl) else False
|
||||||
LOG.debug('domain: %s', dom)
|
# If we have an IQN and are in virtual port mode.
|
||||||
ipaddress = dom.get('targetIpv4Address',
|
if isvpmode and iqn:
|
||||||
dom.get('wellKnownIpAddress'))
|
domains = self._get_domains(mapping)
|
||||||
portnumber = dom.get('portNumber')
|
if domains:
|
||||||
# We save our portal.
|
for dom in domains:
|
||||||
portals.append(ipaddress + ':' +
|
LOG.debug('domain: %s', dom)
|
||||||
six.text_type(portnumber))
|
ipaddress = dom.get('targetIpv4Address',
|
||||||
iqns.append(iqn)
|
dom.get('wellKnownIpAddress'))
|
||||||
luns.append(lun)
|
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
|
# We've gone through all our mappings.
|
||||||
# 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
|
|
||||||
# Make sure we found something to return.
|
# Make sure we found something to return.
|
||||||
if len(luns) == 0:
|
if len(luns) == 0:
|
||||||
# Since we just mapped this and can't find that mapping the world
|
# 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
|
# 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
|
# on the active controller and, preferably, up. If it isn't return
|
||||||
# what we have.
|
# what we have.
|
||||||
if up != -1:
|
if pdata['up'] != -1:
|
||||||
# We found a connection that is already up. Return that.
|
# We found a connection that is already up. Return that.
|
||||||
active = up
|
pdata['active'] = pdata['up']
|
||||||
elif active == -1:
|
elif pdata['active'] == -1:
|
||||||
# This shouldn't be able to happen. Maybe a controller went
|
# This shouldn't be able to happen. Maybe a controller went
|
||||||
# down in the middle of this so just return the first one and
|
# 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.
|
# hope the ports are up by the time the connection is attempted.
|
||||||
LOG.debug('Volume is not yet active on any controller.')
|
LOG.debug('Volume is not yet active on any controller.')
|
||||||
active = 0
|
pdata['active'] = 0
|
||||||
|
|
||||||
data = {'target_discovered': False,
|
data = {'target_discovered': False,
|
||||||
'target_iqn': iqns[active],
|
'target_iqn': iqns[pdata['active']],
|
||||||
'target_iqns': iqns,
|
'target_iqns': iqns,
|
||||||
'target_portal': portals[active],
|
'target_portal': portals[pdata['active']],
|
||||||
'target_portals': portals,
|
'target_portals': portals,
|
||||||
'target_lun': luns[active],
|
'target_lun': luns[pdata['active']],
|
||||||
'target_luns': luns,
|
'target_luns': luns,
|
||||||
'access_mode': access_mode
|
'access_mode': pdata['access_mode']
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG.debug('find_iscsi_properties return: %s',
|
LOG.debug('find_iscsi_properties return: %s',
|
||||||
data)
|
data)
|
||||||
|
|
||||||
@ -1232,12 +1398,18 @@ class StorageCenterApi(object):
|
|||||||
|
|
||||||
:param scvolume: Storage Center volume object.
|
:param scvolume: Storage Center volume object.
|
||||||
:param scserver: Storage Center server opbject.
|
: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
|
# Make sure we have what we think we have
|
||||||
serverid = self._get_id(scserver)
|
serverid = self._get_id(scserver)
|
||||||
volumeid = self._get_id(scvolume)
|
volumeid = self._get_id(scvolume)
|
||||||
if serverid is not None and volumeid is not None:
|
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 = {}
|
||||||
payload['server'] = serverid
|
payload['server'] = serverid
|
||||||
advanced = {}
|
advanced = {}
|
||||||
@ -1273,35 +1445,26 @@ class StorageCenterApi(object):
|
|||||||
serverid = self._get_id(scserver)
|
serverid = self._get_id(scserver)
|
||||||
volumeid = self._get_id(scvolume)
|
volumeid = self._get_id(scvolume)
|
||||||
if serverid is not None and volumeid is not None:
|
if serverid is not None and volumeid is not None:
|
||||||
r = self.client.get('StorageCenter/ScVolume/%s/MappingProfileList'
|
profiles = self._find_mapping_profiles(scvolume)
|
||||||
% volumeid)
|
for profile in profiles:
|
||||||
if r.status_code == 200:
|
prosrv = profile.get('server')
|
||||||
profiles = self._get_json(r)
|
if prosrv is not None and self._get_id(prosrv) == serverid:
|
||||||
for profile in profiles:
|
r = self.client.delete('StorageCenter/ScMappingProfile/%s'
|
||||||
prosrv = profile.get('server')
|
% self._get_id(profile))
|
||||||
if prosrv is not None and self._get_id(prosrv) == serverid:
|
if (r.status_code != 200 or r.ok is False):
|
||||||
r = self.client.delete(
|
LOG.debug('ScMappingProfile error: '
|
||||||
'StorageCenter/ScMappingProfile/%s'
|
'%(code)d %(reason)s',
|
||||||
% self._get_id(profile))
|
{'code': r.status_code,
|
||||||
if (r.status_code != 200 or r.ok is False):
|
'reason': r.reason})
|
||||||
LOG.debug('ScMappingProfile error: '
|
LOG.error(_LE('Unable to unmap Volume %s'),
|
||||||
'%(code)d %(reason)s',
|
volumeid)
|
||||||
{'code': r.status_code,
|
# 1 failed unmap is as good as 100.
|
||||||
'reason': r.reason})
|
# Fail it and leave
|
||||||
LOG.error(_LE('Unable to unmap Volume %s'),
|
rtn = False
|
||||||
volumeid)
|
break
|
||||||
# 1 failed unmap is as good as 100.
|
LOG.debug('Volume %(vol)s unmapped from %(srv)s',
|
||||||
# Fail it and leave
|
{'vol': volumeid,
|
||||||
rtn = False
|
'srv': serverid})
|
||||||
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
|
|
||||||
return rtn
|
return rtn
|
||||||
|
|
||||||
def get_storage_usage(self):
|
def get_storage_usage(self):
|
||||||
@ -1641,7 +1804,8 @@ class StorageCenterApi(object):
|
|||||||
:return: Dell SC replay profile or None.
|
:return: Dell SC replay profile or None.
|
||||||
:raises: VolumeBackendAPIException
|
:raises: VolumeBackendAPIException
|
||||||
'''
|
'''
|
||||||
pf = PayloadFilter()
|
self.cg_except_on_no_support()
|
||||||
|
pf = self._get_payload_filter()
|
||||||
pf.append('ScSerialNumber', self.ssn)
|
pf.append('ScSerialNumber', self.ssn)
|
||||||
pf.append('Name', name)
|
pf.append('Name', name)
|
||||||
r = self.client.post('StorageCenter/ScReplayProfile/GetList',
|
r = self.client.post('StorageCenter/ScReplayProfile/GetList',
|
||||||
@ -1666,6 +1830,7 @@ class StorageCenterApi(object):
|
|||||||
the name on the Dell SC.
|
the name on the Dell SC.
|
||||||
:return: SC profile or None.
|
:return: SC profile or None.
|
||||||
'''
|
'''
|
||||||
|
self.cg_except_on_no_support()
|
||||||
profile = self.find_replay_profile(name)
|
profile = self.find_replay_profile(name)
|
||||||
if not profile:
|
if not profile:
|
||||||
payload = {}
|
payload = {}
|
||||||
@ -1688,6 +1853,7 @@ class StorageCenterApi(object):
|
|||||||
:return: Nothing.
|
:return: Nothing.
|
||||||
:raises: VolumeBackendAPIException
|
:raises: VolumeBackendAPIException
|
||||||
'''
|
'''
|
||||||
|
self.cg_except_on_no_support()
|
||||||
r = self.client.delete('StorageCenter/ScReplayProfile/%s' %
|
r = self.client.delete('StorageCenter/ScReplayProfile/%s' %
|
||||||
self._get_id(profile))
|
self._get_id(profile))
|
||||||
# 200 is a good return. Log and leave.
|
# 200 is a good return. Log and leave.
|
||||||
@ -1804,6 +1970,7 @@ class StorageCenterApi(object):
|
|||||||
removing the profile from this list of volumes.)
|
removing the profile from this list of volumes.)
|
||||||
:return: True/False on success/failure.
|
:return: True/False on success/failure.
|
||||||
'''
|
'''
|
||||||
|
self.cg_except_on_no_support()
|
||||||
ret = True
|
ret = True
|
||||||
profileid = self._get_id(profile)
|
profileid = self._get_id(profile)
|
||||||
if add_volumes:
|
if add_volumes:
|
||||||
@ -1838,6 +2005,7 @@ class StorageCenterApi(object):
|
|||||||
expiration.
|
expiration.
|
||||||
:returns: Dell SC replay object.
|
:returns: Dell SC replay object.
|
||||||
'''
|
'''
|
||||||
|
self.cg_except_on_no_support()
|
||||||
if profile:
|
if profile:
|
||||||
# We have to make sure these are snappable.
|
# We have to make sure these are snappable.
|
||||||
self._init_cg_volumes(self._get_id(profile))
|
self._init_cg_volumes(self._get_id(profile))
|
||||||
@ -1871,6 +2039,7 @@ class StorageCenterApi(object):
|
|||||||
GUID in the replay description.
|
GUID in the replay description.
|
||||||
:returns: Dell replay object or None.
|
:returns: Dell replay object or None.
|
||||||
'''
|
'''
|
||||||
|
self.cg_except_on_no_support()
|
||||||
r = self.client.get('StorageCenter/ScReplayProfile/%s/ReplayList'
|
r = self.client.get('StorageCenter/ScReplayProfile/%s/ReplayList'
|
||||||
% self._get_id(profile))
|
% self._get_id(profile))
|
||||||
replays = self._get_json(r)
|
replays = self._get_json(r)
|
||||||
@ -1906,7 +2075,7 @@ class StorageCenterApi(object):
|
|||||||
replay description.
|
replay description.
|
||||||
:returns: Boolean for success or failure.
|
:returns: Boolean for success or failure.
|
||||||
'''
|
'''
|
||||||
|
self.cg_except_on_no_support()
|
||||||
LOG.debug('Expiring consistency group replay %s', replayid)
|
LOG.debug('Expiring consistency group replay %s', replayid)
|
||||||
replay = self.find_replay(profile,
|
replay = self.find_replay(profile,
|
||||||
replayid)
|
replayid)
|
||||||
@ -1922,6 +2091,12 @@ class StorageCenterApi(object):
|
|||||||
# We either couldn't find it or expired it.
|
# We either couldn't find it or expired it.
|
||||||
return True
|
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):
|
def _size_to_gb(self, spacestring):
|
||||||
'''Splits a SC size string into GB and a remainder.
|
'''Splits a SC size string into GB and a remainder.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user