From 87cf9cb41ed99a7ac3cb77edf93acb5efa61dd46 Mon Sep 17 00:00:00 2001 From: zengyingzhe Date: Mon, 19 Jun 2017 19:19:26 +0800 Subject: [PATCH] Fix bugs while integrated with Huawei Dorado array This patch fixes two bugs while driver integrated with Huawei Dorado array: 1. the KeyError exception while querying storage pool infos, because some attributes don't exist for Dorado array. 2. attaching volume failed if the volume is a Huawei hypermetro volume, at this instance, driver logic will miss querying some infos from Dorado array, which leads KeyError exception at the afterwards processing logic. Change-Id: I0d5017de8417adc92bf6e3d3988a78cd761e75dc Closes-Bug: #1698991 (cherry picked from commit bcf885c63e3cf9e9a884815414037af725de9705) --- .../drivers/huawei/test_huawei_drivers.py | 32 +++++++++++++------ cinder/volume/drivers/huawei/huawei_driver.py | 11 ++++--- cinder/volume/drivers/huawei/hypermetro.py | 5 ++- cinder/volume/drivers/huawei/rest_client.py | 13 ++++---- 4 files changed, 37 insertions(+), 24 deletions(-) diff --git a/cinder/tests/unit/volume/drivers/huawei/test_huawei_drivers.py b/cinder/tests/unit/volume/drivers/huawei/test_huawei_drivers.py index 7ca9bdc19..84629a4d3 100644 --- a/cinder/tests/unit/volume/drivers/huawei/test_huawei_drivers.py +++ b/cinder/tests/unit/volume/drivers/huawei/test_huawei_drivers.py @@ -2849,7 +2849,14 @@ class HuaweiISCSIDriverTestCase(HuaweiTestBase): "USAGETYPE": constants.BLOCK_STORAGE_POOL_TYPE, "TIER0CAPACITY": "0", "TIER1CAPACITY": "0", - "TIER2CAPACITY": "48"}] + "TIER2CAPACITY": "48"}, + {"NAME": "test004", + "ID": "0", + "USERFREECAPACITY": "36", + "DATASPACE": "35", + "USERTOTALCAPACITY": "48", + "USAGETYPE": constants.BLOCK_STORAGE_POOL_TYPE, + "TIER0CAPACITY": "40"}] pool_name = 'test001' test_info = {'CAPACITY': '36', 'ID': '0', 'TOTALCAPACITY': '48', 'TIER0CAPACITY': '48', 'TIER1CAPACITY': '0', @@ -2874,6 +2881,13 @@ class HuaweiISCSIDriverTestCase(HuaweiTestBase): pool_info = self.driver.client.get_pool_info(pool_name, pools) self.assertEqual(test_info, pool_info) + pool_name = 'test004' + test_info = {'CAPACITY': '35', 'ID': '0', 'TOTALCAPACITY': '48', + 'TIER0CAPACITY': '40', 'TIER1CAPACITY': '0', + 'TIER2CAPACITY': '0'} + pool_info = self.driver.client.get_pool_info(pool_name, pools) + self.assertEqual(test_info, pool_info) + def test_get_smartx_specs_opts(self): smartx_opts = smartx.SmartX().get_smartx_specs_opts(smarttier_opts) @@ -3301,15 +3315,6 @@ class HuaweiISCSIDriverTestCase(HuaweiTestBase): lun_PARENTID = mock_create_lun.call_args[0][0]['PARENTID'] self.assertEqual(FAKE_FIND_POOL_RESPONSE['ID'], lun_PARENTID) - @mock.patch.object(huawei_driver.huawei_utils, 'get_volume_metadata', - return_value={'hypermetro_id': '3400a30d844d0007', - 'remote_lun_id': '1'}) - def test_hypermetro_none_map_info_fail(self, mock_metadata): - self.assertRaises(exception.VolumeBackendAPIException, - self.driver.metro.connect_volume_fc, - self.volume, - FakeConnector) - @ddt.data(FAKE_POOLS_UNSUPPORT_REPORT, FAKE_POOLS_SUPPORT_REPORT) @mock.patch.object(rest_client.RestClient, 'check_lun_exist', return_value=True) @@ -4329,9 +4334,14 @@ class HuaweiFCDriverTestCase(HuaweiTestBase): mock_fc_init.assert_called_with(volume, FakeConnector) def test_initialize_connection_success(self): + do_mapping_mocker = self.mock_object( + self.driver.client, 'do_mapping', + wraps=self.driver.client.do_mapping) iscsi_properties = self.driver.initialize_connection(self.volume, FakeConnector) self.assertEqual(1, iscsi_properties['data']['target_lun']) + do_mapping_mocker.assert_called_once_with( + '11', '0', '1', None, '11', False) def test_initialize_connection_fail_no_online_wwns_in_host(self): self.mock_object(rest_client.RestClient, 'get_online_free_wwns', @@ -4955,6 +4965,8 @@ class HuaweiFCDriverTestCase(HuaweiTestBase): fc_properties = self.driver.metro.connect_volume_fc(self.volume, FakeConnector) self.assertEqual(1, fc_properties['data']['target_lun']) + mock_map.assert_called_once_with('1', '0', '1', + hypermetro_lun=True) @mock.patch.object(huawei_driver.huawei_utils, 'get_volume_metadata', return_value={'hypermetro_id': '3400a30d844d0007', diff --git a/cinder/volume/drivers/huawei/huawei_driver.py b/cinder/volume/drivers/huawei/huawei_driver.py index a606966d8..d8960ba38 100644 --- a/cinder/volume/drivers/huawei/huawei_driver.py +++ b/cinder/volume/drivers/huawei/huawei_driver.py @@ -2170,9 +2170,14 @@ class HuaweiFCDriver(HuaweiBaseDriver, driver.FibreChannelDriver): # Add host into hostgroup. hostgroup_id = self.client.add_host_to_hostgroup(host_id) + + metadata = huawei_utils.get_volume_metadata(volume) + LOG.info(_LI("initialize_connection, metadata is: %s."), metadata) + hypermetro_lun = 'hypermetro_id' in metadata + map_info = self.client.do_mapping(lun_id, hostgroup_id, host_id, portg_id, - lun_type) + lun_type, hypermetro_lun) host_lun_id = self.client.get_host_lun_id(host_id, lun_id, lun_type) @@ -2186,9 +2191,7 @@ class HuaweiFCDriver(HuaweiBaseDriver, driver.FibreChannelDriver): 'map_info': map_info}, } # Deal with hypermetro connection. - metadata = huawei_utils.get_volume_metadata(volume) - LOG.info(_LI("initialize_connection, metadata is: %s."), metadata) - if 'hypermetro_id' in metadata: + if hypermetro_lun: loc_tgt_wwn = fc_info['data']['target_wwn'] local_ini_tgt_map = fc_info['data']['initiator_target_map'] hyperm = hypermetro.HuaweiHyperMetro(self.client, diff --git a/cinder/volume/drivers/huawei/hypermetro.py b/cinder/volume/drivers/huawei/hypermetro.py index 535dd938b..6b32ab926 100644 --- a/cinder/volume/drivers/huawei/hypermetro.py +++ b/cinder/volume/drivers/huawei/hypermetro.py @@ -156,9 +156,8 @@ class HuaweiHyperMetro(object): # Add host into hostgroup. hostgroup_id = self.rmt_client.add_host_to_hostgroup(host_id) - map_info = self.rmt_client.do_mapping(lun_id, - hostgroup_id, - host_id) + map_info = self.rmt_client.do_mapping(lun_id, hostgroup_id, host_id, + hypermetro_lun=True) if not map_info: msg = _('Map info is None due to array version ' 'not supporting hypermetro.') diff --git a/cinder/volume/drivers/huawei/rest_client.py b/cinder/volume/drivers/huawei/rest_client.py index 77c3bade5..b57ec630d 100644 --- a/cinder/volume/drivers/huawei/rest_client.py +++ b/cinder/volume/drivers/huawei/rest_client.py @@ -257,10 +257,10 @@ class RestClient(object): info['ID'] = pool['ID'] info['CAPACITY'] = pool.get('DATASPACE', pool['USERFREECAPACITY']) - info['TOTALCAPACITY'] = pool['USERTOTALCAPACITY'] - info['TIER0CAPACITY'] = pool['TIER0CAPACITY'] - info['TIER1CAPACITY'] = pool['TIER1CAPACITY'] - info['TIER2CAPACITY'] = pool['TIER2CAPACITY'] + info['TOTALCAPACITY'] = pool.get('USERTOTALCAPACITY', '0') + info['TIER0CAPACITY'] = pool.get('TIER0CAPACITY', '0') + info['TIER1CAPACITY'] = pool.get('TIER1CAPACITY', '0') + info['TIER2CAPACITY'] = pool.get('TIER2CAPACITY', '0') return info @@ -432,7 +432,7 @@ class RestClient(object): return False def do_mapping(self, lun_id, hostgroup_id, host_id, portgroup_id=None, - lun_type=constants.LUN_TYPE): + lun_type=constants.LUN_TYPE, hypermetro_lun=False): """Add hostgroup and lungroup to mapping view.""" lungroup_name = constants.LUNGROUP_PREFIX + host_id mapping_view_name = constants.MAPPING_VIEW_PREFIX + host_id @@ -475,8 +475,7 @@ class RestClient(object): self._associate_portgroup_to_view(view_id, portgroup_id) - version = self.find_array_version() - if version >= constants.ARRAY_VERSION: + if hypermetro_lun: aval_luns = self.find_view_by_id(view_id) map_info["lun_id"] = lun_id map_info["view_id"] = view_id