From: Tom Swanson Date: Thu, 2 Apr 2015 22:55:44 +0000 (-0500) Subject: Dell SC driver has insufficient iscsi logging X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=d0be2551e7ce944270db6023515b1852f495fb58;p=openstack-build%2Fcinder-build.git Dell SC driver has insufficient iscsi logging In the case where a volume was mapped but the server could not locate the volume not enough information was being logged to sort out the failure. Added logging to Dell SC ISCSI driver. Now returns much more connection information on trying to map a volume. Also tries to return iscsi properties associated with the controller on which the volume in question is active. Updated tests. Minor comment change. Change-Id: I76bf501152802c5421be316703615fdc27a49072 Closes-Bug: 1439852 --- diff --git a/cinder/tests/test_dellsc.py b/cinder/tests/test_dellsc.py index 9115d53f2..19c60bb43 100644 --- a/cinder/tests/test_dellsc.py +++ b/cinder/tests/test_dellsc.py @@ -180,7 +180,7 @@ class DellSCSanISCSIDriverTestCase(test.TestCase): ISCSI_PROPERTIES = {'access_mode': 'rw', 'target_discovered': False, 'target_iqns': - [u'iqn.2002-03.com.compellent:5000d31000fcbe43'], + [u'iqn.2002-03.com.compellent:5000d31000fcbe43'], 'target_luns': [1], 'target_portals': [u'192.168.0.21:3260']} @@ -343,7 +343,7 @@ class DellSCSanISCSIDriverTestCase(test.TestCase): return_value=MAPPINGS[0]) @mock.patch.object(dell_storagecenter_api.StorageCenterApi, 'find_iscsi_properties', - return_value=ISCSI_PROPERTIES) + return_value=(0, ISCSI_PROPERTIES)) def test_initialize_connection(self, mock_find_iscsi_props, mock_map_volume, @@ -388,7 +388,7 @@ class DellSCSanISCSIDriverTestCase(test.TestCase): return_value=MAPPINGS[0]) @mock.patch.object(dell_storagecenter_api.StorageCenterApi, 'find_iscsi_properties', - return_value=ISCSI_PROPERTIES) + return_value=(0, ISCSI_PROPERTIES)) def test_initialize_connection_multi_path(self, mock_find_iscsi_props, mock_map_volume, @@ -432,7 +432,7 @@ class DellSCSanISCSIDriverTestCase(test.TestCase): return_value=MAPPINGS) @mock.patch.object(dell_storagecenter_api.StorageCenterApi, 'find_iscsi_properties', - return_value=ISCSI_PROPERTIES_EMPTY) + return_value=(0, ISCSI_PROPERTIES_EMPTY)) def test_initialize_connection_no_iqn(self, mock_find_iscsi_properties, mock_map_volume, @@ -466,7 +466,7 @@ class DellSCSanISCSIDriverTestCase(test.TestCase): return_value=MAPPINGS) @mock.patch.object(dell_storagecenter_api.StorageCenterApi, 'find_iscsi_properties', - return_value=ISCSI_PROPERTIES_EMPTY) + return_value=(0, ISCSI_PROPERTIES_EMPTY)) def test_initialize_connection_no_server(self, mock_find_iscsi_properties, mock_map_volume, @@ -498,7 +498,7 @@ class DellSCSanISCSIDriverTestCase(test.TestCase): return_value=MAPPINGS) @mock.patch.object(dell_storagecenter_api.StorageCenterApi, 'find_iscsi_properties', - return_value=ISCSI_PROPERTIES_EMPTY) + return_value=(0, ISCSI_PROPERTIES_EMPTY)) def test_initialize_connection_vol_not_found(self, mock_find_iscsi_properties, mock_map_volume, @@ -532,7 +532,7 @@ class DellSCSanISCSIDriverTestCase(test.TestCase): return_value=None) @mock.patch.object(dell_storagecenter_api.StorageCenterApi, 'find_iscsi_properties', - return_value=ISCSI_PROPERTIES) + return_value=(0, ISCSI_PROPERTIES)) def test_initialize_connection_map_vol_fail(self, mock_find_iscsi_props, mock_map_volume, diff --git a/cinder/tests/test_dellscapi.py b/cinder/tests/test_dellscapi.py index 4bb964e6b..85f38ebeb 100644 --- a/cinder/tests/test_dellscapi.py +++ b/cinder/tests/test_dellscapi.py @@ -110,6 +110,51 @@ class DellSCSanAPITestCase(test.TestCase): u'mapped': False, u'cmmSource': False} + VOLUME_CONFIG = \ + {u'instanceId': u'64702.3494', + u'scSerialNumber': 64702, + u'maximumSiblingCount': 100, + u'writeCacheStatus': u'Up', + u'objectType': u'ScVolumeConfiguration', + u'currentSiblingConfiguredSize': u'2.147483648E9 Bytes', + u'compressionPaused': False, + u'enforceConsumptionLimit': False, + u'volumeSpaceConsumptionLimit': u'2.147483648E9 Bytes', + u'readCacheEnabled': True, + u'writeCacheEnabled': True, + u'instanceName': u'volume-ff9589d3-2d41-48d5-9ef5-2713a875e85b', + u'dateModified': u'04/03/2015 12:01:08 AM', + u'modifyUser': u'Admin', + u'replayExpirationPaused': False, + u'currentSiblingCount': 1, + u'replayCreationPaused': False, + u'replayProfileList': [{u'instanceId': u'64702.2', + u'instanceName': u'Daily', + u'objectType': u'ScReplayProfile'}], + u'dateCreated': u'04/04/2014 03:54:26 AM', + u'volume': {u'instanceId': u'64702.3494', + u'instanceName': + u'volume-37883deb-85cd-426a-9a98-62eaad8671ea', + u'objectType': u'ScVolume'}, + u'controller': {u'instanceId': u'64702.64703', + u'instanceName': u'SN 64703', + u'objectType': u'ScController'}, + u'coalesceIntoActive': False, + u'createUser': u'Admin', + u'importToLowestTier': False, + u'readCacheStatus': u'Up', + u'maximumSiblingConfiguredSpace': u'5.49755813888E14 Bytes', + u'storageProfile': {u'instanceId': u'64702.1', + u'instanceName': u'Recommended', + u'objectType': u'ScStorageProfile'}, + u'scName': u'Storage Center 64702', + u'notes': u'', + u'diskFolder': {u'instanceId': u'64702.3', + u'instanceName': u'Assigned', + u'objectType': u'ScDiskFolder'}, + u'openVmsUniqueDiskId': 48, + u'compressionEnabled': False} + INACTIVE_VOLUME = \ {u'instanceId': u'64702.3494', u'scSerialNumber': 64702, @@ -623,6 +668,110 @@ class DellSCSanAPITestCase(test.TestCase): u'transport': u'FibreChannel', u'objectType': u'ScMapping'}] + FC_MAPPINGS_LUN_MISMATCH = \ + [{u'profile': {u'instanceId': u'64702.2941', + u'instanceName': u'6025-47', + u'objectType': u'ScMappingProfile'}, + u'status': u'Up', + u'statusMessage': u'', + u'instanceId': u'64702.7639.64702', + 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'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'readOnly': False, + u'lun': 1, + u'serverHba': {u'instanceId': u'64702.3282218607', + u'instanceName': u'21000024FF30441C', + u'objectType': u'ScServerHba'}, + u'path': {u'instanceId': u'64702.64702.64703.27.73', + u'instanceName': + u'21000024FF30441C-5000D31000FCBE36', + u'objectType': u'ScServerHbaPath'}, + u'controllerPort': + {u'instanceId': u'64702.5764839588723736118.50', + u'instanceName': u'5000D31000FCBE36', + u'objectType': u'ScControllerPort'}, + u'instanceName': u'64702-7639', + u'transport': u'FibreChannel', + u'objectType': u'ScMapping'}, + {u'profile': {u'instanceId': u'64702.2941', + u'instanceName': u'6025-47', + u'objectType': u'ScMappingProfile'}, + u'status': u'Up', + u'statusMessage': u'', + u'instanceId': u'64702.7640.64702', + 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'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'readOnly': False, + u'lun': 1, + u'serverHba': {u'instanceId': u'64702.3282218606', + u'instanceName': u'21000024FF30441D', + u'objectType': u'ScServerHba'}, + u'path': + {u'instanceId': u'64702.64702.64703.27.78', + u'instanceName': u'21000024FF30441D-5000D31000FCBE36', + u'objectType': u'ScServerHbaPath'}, + u'controllerPort': + {u'instanceId': u'64702.5764839588723736118.50', + u'instanceName': u'5000D31000FCBE36', + u'objectType': u'ScControllerPort'}, + u'instanceName': u'64702-7640', + u'transport': u'FibreChannel', + u'objectType': u'ScMapping'}, + {u'profile': {u'instanceId': u'64702.2941', + u'instanceName': u'6025-47', + u'objectType': u'ScMappingProfile'}, + u'status': u'Up', + u'statusMessage': u'', + u'instanceId': u'64702.7638.64702', + 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'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'readOnly': False, + u'lun': 2, + u'serverHba': {u'instanceId': u'64702.3282218606', + u'instanceName': u'21000024FF30441D', + u'objectType': u'ScServerHba'}, + u'path': + {u'instanceId': u'64702.64702.64703.28.76', + u'instanceName': u'21000024FF30441D-5000D31000FCBE3E', + u'objectType': u'ScServerHbaPath'}, + u'controllerPort': {u'instanceId': + u'64702.5764839588723736126.60', + u'instanceName': u'5000D31000FCBE3E', + u'objectType': u'ScControllerPort'}, + u'instanceName': u'64702-7638', + u'transport': u'FibreChannel', + u'objectType': u'ScMapping'}] + RPLAY = {u'scSerialNumber': 64702, u'globalIndex': u'64702-46-250', u'description': u'Cinder Clone Replay', @@ -1070,6 +1219,40 @@ class DellSCSanAPITestCase(test.TestCase): u'statusMessage': u'', u'objectType': u'ScControllerPort'} + FC_CTRLR_PORT_WWN_ERROR = \ + {u'preferredParent': + {u'instanceId': u'64702.5764839588723736093.57', + u'instanceName': u'5000D31000FCBE1D', + u'objectType': u'ScControllerPort'}, + u'status': u'Up', + u'iscsiIpAddress': u'0.0.0.0', + u'Wwn': u'5000D31000FCBE36', + u'name': u'5000D31000FCBE36', + u'parent': + {u'instanceId': u'64702.5764839588723736093.57', + u'instanceName': u'5000D31000FCBE1D', + u'objectType': u'ScControllerPort'}, + u'iscsiGateway': u'0.0.0.0', + u'instanceId': u'64702.5764839588723736118.50', + u'scName': u'Storage Center 64702', + u'scSerialNumber': 64702, + u'transportType': u'FibreChannel', + u'virtual': True, + u'controller': {u'instanceId': u'64702.64703', + u'instanceName': u'SN 64703', + u'objectType': u'ScController'}, + u'iscsiName': u'', + u'purpose': u'FrontEnd', + u'iscsiSubnetMask': u'0.0.0.0', + u'faultDomain': + {u'instanceId': u'64702.1.0', + u'instanceName': u'Domain 0', + u'objectType': u'ScControllerPortFaultDomain'}, + u'instanceName': u'5000D31000FCBE36', + u'childStatus': u'Up', + u'statusMessage': u'', + u'objectType': u'ScControllerPort'} + STRG_USAGE = {u'systemSpace': u'7.38197504E8 Bytes', u'freeSpace': u'1.297659461632E13 Bytes', u'oversubscribedSpace': u'0.0 Bytes', @@ -1094,6 +1277,10 @@ class DellSCSanAPITestCase(test.TestCase): WWNS = [u'21000024FF30441C', u'21000024FF30441D'] + # Used to test finding no match in find_wwns + WWNS_NO_MATCH = [u'21000024FF30451C', + u'21000024FF30451D'] + FLDR_PATH = 'StorageCenter/ScVolumeFolder/' # Create a Response object that indicates OK @@ -2464,6 +2651,125 @@ class DellSCSanAPITestCase(test.TestCase): self.assertEqual([], wwns, 'WWNs is not empty') self.assertEqual({}, itmap, 'WWN mapping not empty') + @mock.patch.object(dell_storagecenter_api.StorageCenterApi, + '_find_controller_port', + return_value=FC_CTRLR_PORT_WWN_ERROR) + @mock.patch.object(dell_storagecenter_api.StorageCenterApi, + '_find_mappings', + return_value=FC_MAPPINGS) + @mock.patch.object(dell_storagecenter_api.StorageCenterApi, + '_find_fc_initiators', + return_value=WWNS) + def test_find_wwns_wwn_error(self, + mock_find_fc_initiators, + mock_find_mappings, + mock_find_controller_port, + mock_close_connection, + mock_open_connection, + mock_init): + # Test case where ScControllerPort object has WWn instead of wwn for a + # property + lun, wwns, itmap = self.scapi.find_wwns(self.VOLUME, + self.SCSERVER) + self.assertTrue(mock_find_fc_initiators.called) + self.assertTrue(mock_find_mappings.called) + self.assertTrue(mock_find_controller_port.called) + + self.assertEqual(None, lun, 'Incorrect LUN') + self.assertEqual([], wwns, 'WWNs is not empty') + self.assertEqual({}, itmap, 'WWN mapping not empty') + + @mock.patch.object(dell_storagecenter_api.StorageCenterApi, + '_find_controller_port', + return_value=FC_CTRLR_PORT) + @mock.patch.object(dell_storagecenter_api.StorageCenterApi, + '_find_mappings', + return_value=FC_MAPPINGS) + @mock.patch.object(dell_storagecenter_api.StorageCenterApi, + '_find_fc_initiators', + return_value=WWNS_NO_MATCH) + # Test case where HBA name is not found in list of initiators + def test_find_wwns_hbaname_not_found(self, + mock_find_fc_initiators, + mock_find_mappings, + mock_find_controller_port, + mock_close_connection, + mock_open_connection, + mock_init): + lun, wwns, itmap = self.scapi.find_wwns(self.VOLUME, + self.SCSERVER) + self.assertTrue(mock_find_fc_initiators.called) + self.assertTrue(mock_find_mappings.called) + self.assertTrue(mock_find_controller_port.called) + + self.assertEqual(None, lun, 'Incorrect LUN') + self.assertEqual([], wwns, 'WWNs is not empty') + self.assertEqual({}, itmap, 'WWN mapping not empty') + + @mock.patch.object(dell_storagecenter_api.StorageCenterApi, + '_find_controller_port', + return_value=FC_CTRLR_PORT) + @mock.patch.object(dell_storagecenter_api.StorageCenterApi, + '_find_mappings', + return_value=FC_MAPPINGS_LUN_MISMATCH) + @mock.patch.object(dell_storagecenter_api.StorageCenterApi, + '_find_fc_initiators', + return_value=WWNS) + # Test case where FC mappings contain a LUN mismatch + def test_find_wwns_lun_mismatch(self, + mock_find_fc_initiators, + mock_find_mappings, + mock_find_controller_port, + mock_close_connection, + mock_open_connection, + mock_init): + lun, wwns, itmap = self.scapi.find_wwns(self.VOLUME, + self.SCSERVER) + self.assertTrue(mock_find_fc_initiators.called) + self.assertTrue(mock_find_mappings.called) + self.assertTrue(mock_find_controller_port.called) + # The _find_controller_port is Mocked, so all mapping pairs + # will have the same WWN for the ScControllerPort + itmapCompare = {u'21000024FF30441C': [u'5000D31000FCBE36'], + u'21000024FF30441D': + [u'5000D31000FCBE36', u'5000D31000FCBE36']} + self.assertEqual(1, lun, 'Incorrect LUN') + self.assertIsNotNone(wwns, 'WWNs is None') + self.assertEqual(itmapCompare, itmap, 'WWN mapping incorrect') + + @mock.patch.object(dell_storagecenter_api.StorageCenterApi, + '_first_result', + return_value=VOLUME_CONFIG) + @mock.patch.object(dell_storagecenter_api.HttpClient, + 'get', + return_value=RESPONSE_200) + def test_find_active_controller(self, + mock_get, + mock_first_result, + mock_close_connection, + mock_open_connection, + mock_init): + res = self.scapi._find_active_controller(self.VOLUME) + self.assertTrue(mock_get.called) + self.assertTrue(mock_first_result.called) + self.assertEqual('64702.64703', res, 'Unexpected Active Controller') + + @mock.patch.object(dell_storagecenter_api.HttpClient, + 'get', + return_value=RESPONSE_204) + def test_find_active_controller_failure(self, + mock_get, + mock_close_connection, + mock_open_connection, + mock_init): + # Test case of where get of ScVolume MappingList fails + res = self.scapi._find_active_controller(self.VOLUME) + self.assertTrue(mock_get.called) + self.assertEqual(None, res, 'Expected None') + + @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) @@ -2477,6 +2783,7 @@ class DellSCSanAPITestCase(test.TestCase): mock_find_mappings, mock_find_domain, mock_find_ctrl_port, + mock_find_active_controller, mock_close_connection, mock_open_connection, mock_init): @@ -2484,14 +2791,19 @@ class DellSCSanAPITestCase(test.TestCase): self.assertTrue(mock_find_mappings.called) self.assertTrue(mock_find_domain.called) self.assertTrue(mock_find_ctrl_port.called) - expected = {'access_mode': 'rw', - 'target_discovered': False, - 'target_iqns': + self.assertTrue(mock_find_active_controller.called) + expected = (0, + {'access_mode': 'rw', + 'target_discovered': False, + 'target_iqns': [u'iqn.2002-03.com.compellent:5000d31000fcbe43'], - 'target_luns': [1], - 'target_portals': [u'192.168.0.21:3260']} + 'target_luns': [1], + '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) @@ -2505,6 +2817,7 @@ class DellSCSanAPITestCase(test.TestCase): mock_find_mappings, mock_find_domain, mock_find_ctrl_port, + mock_find_active_controller, mock_close_connection, mock_open_connection, mock_init): @@ -2514,14 +2827,19 @@ class DellSCSanAPITestCase(test.TestCase): self.assertTrue(mock_find_mappings.called) self.assertTrue(mock_find_domain.called) self.assertTrue(mock_find_ctrl_port.called) - expected = {'access_mode': 'rw', - 'target_discovered': False, - 'target_iqns': + self.assertTrue(mock_find_active_controller.called) + expected = (0, + {'access_mode': 'rw', + 'target_discovered': False, + 'target_iqns': [u'iqn.2002-03.com.compellent:5000d31000fcbe43'], - 'target_luns': [1], - 'target_portals': [u'192.168.0.21:3260']} + 'target_luns': [1], + '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) @@ -2535,6 +2853,7 @@ class DellSCSanAPITestCase(test.TestCase): mock_find_mappings, mock_find_domain, mock_find_ctrl_port, + mock_find_active_ctrl, mock_close_connection, mock_open_connection, mock_init): @@ -2544,31 +2863,42 @@ class DellSCSanAPITestCase(test.TestCase): self.assertTrue(mock_find_mappings.called) self.assertTrue(mock_find_domain.called) self.assertTrue(mock_find_ctrl_port.called) - expected = {'access_mode': 'rw', - 'target_discovered': False, - 'target_iqns': [], - 'target_luns': [], - 'target_portals': []} + self.assertTrue(mock_find_active_ctrl.called) + expected = (0, + {'access_mode': 'rw', + 'target_discovered': False, + 'target_iqns': [], + 'target_luns': [], + 'target_portals': []}) 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_mappings', return_value=[]) def test_find_iscsi_properties_no_mapping(self, mock_find_mappings, + mock_find_active_controller, mock_close_connection, mock_open_connection, mock_init): # Test case where there are no ScMapping(s) res = self.scapi.find_iscsi_properties(self.VOLUME) self.assertTrue(mock_find_mappings.called) - expected = {'access_mode': 'rw', - 'target_discovered': False, - 'target_iqns': [], - 'target_luns': [], - 'target_portals': []} + self.assertTrue(mock_find_active_controller.called) + expected = (0, + {'access_mode': 'rw', + 'target_discovered': False, + 'target_iqns': [], + 'target_luns': [], + 'target_portals': []}) self.assertEqual(expected, res, 'Expected empty 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) @@ -2582,6 +2912,7 @@ class DellSCSanAPITestCase(test.TestCase): mock_find_mappings, mock_find_domain, mock_find_ctrl_port, + mock_find_active_controller, mock_close_connection, mock_open_connection, mock_init): @@ -2590,13 +2921,18 @@ class DellSCSanAPITestCase(test.TestCase): self.assertTrue(mock_find_mappings.called) self.assertTrue(mock_find_domain.called) self.assertFalse(mock_find_ctrl_port.called) - expected = {'access_mode': 'rw', - 'target_discovered': False, - 'target_iqns': [], - 'target_luns': [], - 'target_portals': []} + self.assertTrue(mock_find_active_controller.called) + expected = (0, + {'access_mode': 'rw', + 'target_discovered': False, + 'target_iqns': [], + 'target_luns': [], + 'target_portals': []}) self.assertEqual(expected, res, 'Expected empty 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=None) @@ -2610,6 +2946,7 @@ class DellSCSanAPITestCase(test.TestCase): mock_find_mappings, mock_find_domain, mock_find_ctrl_port, + mock_find_active_controller, mock_close_connection, mock_open_connection, mock_init): @@ -2618,13 +2955,18 @@ class DellSCSanAPITestCase(test.TestCase): self.assertTrue(mock_find_mappings.called) self.assertTrue(mock_find_domain.called) self.assertTrue(mock_find_ctrl_port.called) - expected = {'access_mode': 'rw', - 'target_discovered': False, - 'target_iqns': [], - 'target_luns': [], - 'target_portals': []} + self.assertTrue(mock_find_active_controller.called) + expected = (0, + {'access_mode': 'rw', + 'target_discovered': False, + 'target_iqns': [], + 'target_luns': [], + 'target_portals': []}) self.assertEqual(expected, res, 'Expected empty 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) @@ -2638,6 +2980,7 @@ class DellSCSanAPITestCase(test.TestCase): mock_find_mappings, mock_find_domain, mock_find_ctrl_port, + mock_find_active_controller, mock_close_connection, mock_open_connection, mock_init): @@ -2646,14 +2989,19 @@ class DellSCSanAPITestCase(test.TestCase): self.assertTrue(mock_find_mappings.called) self.assertTrue(mock_find_domain.called) self.assertTrue(mock_find_ctrl_port.called) - expected = {'access_mode': 'ro', - 'target_discovered': False, - 'target_iqns': + self.assertTrue(mock_find_active_controller.called) + expected = (0, + {'access_mode': 'ro', + 'target_discovered': False, + 'target_iqns': [u'iqn.2002-03.com.compellent:5000d31000fcbe43'], - 'target_luns': [1], - 'target_portals': [u'192.168.0.21:3260']} + 'target_luns': [1], + '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) @@ -2667,6 +3015,7 @@ class DellSCSanAPITestCase(test.TestCase): mock_find_mappings, mock_find_domain, mock_find_ctrl_port, + mock_find_active_controller, mock_close_connection, mock_open_connection, mock_init): @@ -2675,13 +3024,15 @@ class DellSCSanAPITestCase(test.TestCase): self.assertTrue(mock_find_mappings.called) self.assertTrue(mock_find_domain.called) self.assertTrue(mock_find_ctrl_port.called) - expected = {'access_mode': 'rw', - 'target_discovered': False, - 'target_iqns': + self.assertTrue(mock_find_active_controller.called) + expected = (0, + {'access_mode': 'rw', + 'target_discovered': False, + 'target_iqns': [u'iqn.2002-03.com.compellent:5000d31000fcbe43'], - 'target_luns': [1], - 'target_portals': - [u'192.168.0.21:3260', u'192.168.0.25:3260']} + 'target_luns': [1], + 'target_portals': + [u'192.168.0.21:3260', u'192.168.0.25:3260']}) self.assertEqual(expected, res, 'Wrong Target Info') @mock.patch.object(dell_storagecenter_api.StorageCenterApi, diff --git a/cinder/volume/drivers/dell/dell_storagecenter_api.py b/cinder/volume/drivers/dell/dell_storagecenter_api.py index 31f6428f4..3f1d39625 100644 --- a/cinder/volume/drivers/dell/dell_storagecenter_api.py +++ b/cinder/volume/drivers/dell/dell_storagecenter_api.py @@ -358,6 +358,10 @@ class StorageCenterApi(object): scservers = self._get_json(r) # Sort through the servers looking for one with connectivity. for scserver in scservers: + # TODO(tom_swanson): Add check for server type. + # This needs to be either a physical or virtual server. + # Outside of tempest tests this should not matter as we only + # "init" a volume to allow snapshotting of an empty volume. if scserver.get('status', '').lower() != 'down': # Map to actually create the volume self.map_volume(scvolume, @@ -795,23 +799,42 @@ class StorageCenterApi(object): # pretend we succeeded. return lun, wwns, itmap + def _find_active_controller(self, scvolume): + LOG.debug('find_active_controller') + activecontroller = None + r = self.client.get('StorageCenter/ScVolume/%s/VolumeConfiguration' + % self._get_id(scvolume)) + if r.status_code == 200: + volumeconfiguration = self._first_result(r) + controller = volumeconfiguration.get('controller') + activecontroller = self._get_id(controller) + LOG.debug('activecontroller %s', activecontroller) + return activecontroller + def find_iscsi_properties(self, scvolume, ip=None, port=None): + LOG.debug('enter find_iscsi_properties') + LOG.debug('scvolume: %s', scvolume) + activeindex = -1 luns = [] iqns = [] portals = [] access_mode = 'rw' mappings = self._find_mappings(scvolume) + activecontroller = self._find_active_controller(scvolume) if len(mappings) > 0: for mapping in mappings: + LOG.debug('mapping: %s', mapping) # find the controller port for this mapping cport = mapping.get('controllerPort') cportid = self._get_id(cport) domains = self._find_domains(cportid) if domains: controllerport = self._find_controller_port(cportid) + LOG.debug('controllerport: %s', controllerport) if controllerport is not None: appendproperties = False for d in domains: + LOG.debug('domain: %s', d) ipaddress = d.get('targetIpv4Address', d.get('wellKnownIpAddress')) portnumber = d.get('portNumber') @@ -825,6 +848,9 @@ class StorageCenterApi(object): if portals.count(portal) == 0: appendproperties = True portals.append(portal) + else: + LOG.debug('Domain %s has two portals.', + self._get_id(d)) # We do not report lun and iqn info unless it is for # the configured port OR the user has not enabled # multipath. (In which case ip and port sent in @@ -832,17 +858,27 @@ class StorageCenterApi(object): if appendproperties is True: iqns.append(controllerport.get('iscsiName')) luns.append(mapping.get('lun')) + if activeindex == -1: + controller = controllerport.get('controller') + controllerid = self._get_id(controller) + if controllerid == activecontroller: + activeindex = len(iqns) - 1 if mapping['readOnly'] is True: access_mode = 'ro' + if activeindex == -1: + LOG.debug('Volume is not yet active on any controller.') + activeindex = 0 + data = {'target_discovered': False, 'target_iqns': iqns, 'target_portals': portals, 'target_luns': luns, 'access_mode': access_mode } + LOG.debug('find_iscsi_properties return: %s', data) - return data + return activeindex, data def map_volume(self, scvolume, scserver): '''map_volume diff --git a/cinder/volume/drivers/dell/dell_storagecenter_common.py b/cinder/volume/drivers/dell/dell_storagecenter_common.py index f72333a6d..47511ab7b 100644 --- a/cinder/volume/drivers/dell/dell_storagecenter_common.py +++ b/cinder/volume/drivers/dell/dell_storagecenter_common.py @@ -330,8 +330,8 @@ class DellCommonDriver(san.SanDriver): data['driver_version'] = self.VERSION data['storage_protocol'] = 'iSCSI' data['reserved_percentage'] = 0 - # in theory if storageusage is None then we should have - # blown up getting it. If not just report inifinite. + # In theory if storageusage is None then we should have + # blown up getting it. If not just report unavailable. if storageusage is not None: totalcapacity = storageusage.get('availableSpace') totalcapacitygb = self._bytes_to_gb(totalcapacity) diff --git a/cinder/volume/drivers/dell/dell_storagecenter_iscsi.py b/cinder/volume/drivers/dell/dell_storagecenter_iscsi.py index 40eb7614c..45cf5cb0d 100644 --- a/cinder/volume/drivers/dell/dell_storagecenter_iscsi.py +++ b/cinder/volume/drivers/dell/dell_storagecenter_iscsi.py @@ -80,7 +80,7 @@ class DellStorageCenterISCSIDriver(san.SanISCSIDriver, if multipath: # Just return our properties with all the mappings - iscsiproperties = ( + idx, iscsiproperties = ( api.find_iscsi_properties(scvolume, None, None)) @@ -90,7 +90,7 @@ class DellStorageCenterISCSIDriver(san.SanISCSIDriver, # Only return the iqn for the user specified port. ip = self.configuration.iscsi_ip_address port = self.configuration.iscsi_port - iscsiproperties = ( + idx, iscsiproperties = ( api.find_iscsi_properties(scvolume, ip, port)) @@ -101,11 +101,11 @@ class DellStorageCenterISCSIDriver(san.SanISCSIDriver, # one listed we can assume that we found what # we are looking for. Otherwise error. if len(portals) > 0: - properties['target_portal'] = portals[0] + properties['target_portal'] = portals[idx] properties['target_iqn'] = ( - iscsiproperties['target_iqns'][0]) + iscsiproperties['target_iqns'][idx]) properties['target_lun'] = ( - iscsiproperties['target_luns'][0]) + iscsiproperties['target_luns'][idx]) properties['access_mode'] = ( iscsiproperties['access_mode']) LOG.debug(properties)