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 766645a7799..861036a3486 100644 --- a/cinder/tests/unit/volume/drivers/huawei/test_huawei_drivers.py +++ b/cinder/tests/unit/volume/drivers/huawei/test_huawei_drivers.py @@ -21,7 +21,6 @@ import mock import re import requests import tempfile -import unittest from xml.dom import minidom from xml.etree import ElementTree @@ -53,15 +52,25 @@ admin_contex = context.get_admin_context() vol_attrs = ('id', 'lun_type', 'provider_location', 'metadata') Volume = collections.namedtuple('Volume', vol_attrs) -PROVIDER_LOCATION = '11' +PROVIDER_LOCATION = ('{"huawei_lun_id": "11", ' + '"huawei_lun_wwn": "6643e8c1004c5f6723e9f454003"}') +PROVIDER_LOCATION_WITH_HYPERMETRO = ( + '{"huawei_lun_id": "11", ' + '"huawei_lun_wwn": "6643e8c1004c5f6723e9f454003", ' + '"hypermetro_id": "11", ' + '"remote_lun_id": "1"}') +SNAP_PROVIDER_LOCATION = '{"huawei_snapshot_id": "11"}' + HOST = 'ubuntu001@backend001#OpenStack_Pool' ID = '21ec7341-9256-497b-97d9-ef48edcf0635' ENCODE_NAME = huawei_utils.encode_name(ID) -ADMIN_METADATA = {'huawei_lun_wwn': '6643e8c1004c5f6723e9f454003'} +METADATA = {} TEST_PAIR_ID = "3400a30d844d0004" -REPLICA_DRIVER_DATA = '{"pair_id": "%s", "rmt_lun_id": "1"}' % TEST_PAIR_ID VOL_METADATA = [{'key': 'hypermetro_id', 'value': '11'}, {'key': 'remote_lun_id', 'value': '1'}] +ADMIN_METADATA = [{'key': 'huawei_lun_wwn', 'value': 'FAKE_WWN'}] +REPLICA_DRIVER_DATA = ('{"pair_id": "%s", "rmt_lun_id": "1", ' + '"rmt_lun_wwn": "FAKE_RMT_LUN_WWN"}') % TEST_PAIR_ID hypermetro_devices = """{ "remote_device": { @@ -502,7 +511,7 @@ FAKE_SNAPSHOT_LIST_INFO_RESPONSE = { "description": "0" }, "data": [{ - "ID": 11, + "ID": "11", "NAME": ENCODE_NAME }, ] } @@ -515,7 +524,7 @@ FAKE_CREATE_SNAPSHOT_INFO_RESPONSE = """ "code": 0 }, "data": { - "ID": 11, + "ID": "11", "NAME": "YheUoRwbSX2BxN7" } } @@ -529,7 +538,7 @@ FAKE_GET_SNAPSHOT_INFO_RESPONSE = """ "description": "0" }, "data": { - "ID": 11, + "ID": "11", "NAME": "YheUoRwbSX2BxN7" } } @@ -2231,21 +2240,22 @@ class HuaweiTestBase(test.TestCase): self.volume = fake_volume.fake_volume_obj( admin_contex, host=HOST, provider_location=PROVIDER_LOCATION, - admin_metadata=ADMIN_METADATA, id=ID) + metadata=METADATA, id=ID) self.snapshot = fake_snapshot.fake_snapshot_obj( - admin_contex, provider_location=PROVIDER_LOCATION, id=ID) + admin_contex, provider_location=SNAP_PROVIDER_LOCATION, id=ID) self.snapshot.volume = self.volume self.replica_volume = fake_volume.fake_volume_obj( admin_contex, host=HOST, provider_location=PROVIDER_LOCATION, - admin_metadata=ADMIN_METADATA, replication_status='disabled', + metadata=METADATA, replication_status='disabled', replication_driver_data=REPLICA_DRIVER_DATA, id=ID) self.hyper_volume = fake_volume.fake_volume_obj( - admin_contex, host=HOST, provider_location=PROVIDER_LOCATION, - volume_metadata=VOL_METADATA, id=ID) + admin_contex, host=HOST, + provider_location=PROVIDER_LOCATION_WITH_HYPERMETRO, + id=ID) self.original_volume = fake_volume.fake_volume_obj(admin_contex, id=ID) @@ -2271,12 +2281,14 @@ class HuaweiTestBase(test.TestCase): @mock.patch.object(rest_client, 'RestClient') def test_create_snapshot_success(self, mock_client): lun_info = self.driver.create_snapshot(self.snapshot) - self.assertEqual(11, lun_info['provider_location']) + self.assertDictEqual({"huawei_snapshot_id": "11"}, + json.loads(lun_info['provider_location'])) self.snapshot.volume_id = ID self.snapshot.volume = self.volume lun_info = self.driver.create_snapshot(self.snapshot) - self.assertEqual(11, lun_info['provider_location']) + self.assertDictEqual({"huawei_snapshot_id": "11"}, + json.loads(lun_info['provider_location'])) @ddt.data('1', '', '0') def test_copy_volume(self, input_speed): @@ -2328,6 +2340,75 @@ class HuaweiTestBase(test.TestCase): 'POST' ) + @ddt.data( + { + 'volume': fake_volume.fake_volume_obj( + admin_contex, + provider_location=PROVIDER_LOCATION), + 'expect': {'huawei_lun_id': '11', + 'huawei_lun_wwn': '6643e8c1004c5f6723e9f454003'} + }, + { + 'volume': fake_volume.fake_volume_obj( + admin_contex, + provider_location=None), + 'expect': {} + }, + { + 'volume': fake_volume.fake_volume_obj( + admin_contex, + provider_location=''), + 'expect': {} + }, + { + 'volume': fake_volume.fake_volume_obj( + admin_contex, + provider_location='11', + volume_admin_metadata=ADMIN_METADATA, + volume_metadata=VOL_METADATA + ), + 'expect': {'huawei_lun_id': '11', + 'huawei_lun_wwn': 'FAKE_WWN', + 'hypermetro_id': '11', + 'remote_lun_id': '1'} + } + ) + @ddt.unpack + def test_get_lun_metadata(self, volume, expect): + metadata = huawei_utils.get_lun_metadata(volume) + self.assertEqual(expect, metadata) + + @ddt.data( + { + 'snapshot': fake_snapshot.fake_snapshot_obj( + admin_contex, + provider_location=SNAP_PROVIDER_LOCATION), + 'expect': {'huawei_snapshot_id': '11'} + }, + { + 'snapshot': fake_snapshot.fake_snapshot_obj( + admin_contex, + provider_location=None), + 'expect': {} + }, + { + 'snapshot': fake_snapshot.fake_snapshot_obj( + admin_contex, + provider_location=''), + 'expect': {} + }, + { + 'snapshot': fake_snapshot.fake_snapshot_obj( + admin_contex, + provider_location='11'), + 'expect': {'huawei_snapshot_id': '11'} + } + ) + @ddt.unpack + def test_get_snapshot_metadata(self, snapshot, expect): + metadata = huawei_utils.get_snapshot_metadata(snapshot) + self.assertEqual(expect, metadata) + @ddt.ddt class HuaweiISCSIDriverTestCase(HuaweiTestBase): @@ -2411,12 +2492,18 @@ class HuaweiISCSIDriverTestCase(HuaweiTestBase): self.volume.host = 'ubuntu001@backend001#OpenStack_Pool' lun_info = self.driver.create_volume(self.volume) - self.assertEqual('1', lun_info['provider_location']) + expect_value = {"huawei_lun_id": "1", + "huawei_lun_wwn": "6643e8c1004c5f6723e9f454003"} + self.assertDictEqual(expect_value, + json.loads(lun_info['provider_location'])) # No pool info in the volume. self.volume.host = 'ubuntu001@backend001' lun_info = self.driver.create_volume(self.volume) - self.assertEqual('1', lun_info['provider_location']) + expect_value = {"huawei_lun_id": "1", + "huawei_lun_wwn": "6643e8c1004c5f6723e9f454003"} + self.assertDictEqual(expect_value, + json.loads(lun_info['provider_location'])) @ddt.data(FAKE_POOLS_UNSUPPORT_REPORT, FAKE_POOLS_SUPPORT_REPORT) def test_delete_replication_fail(self, pool_data): @@ -2609,7 +2696,6 @@ class HuaweiISCSIDriverTestCase(HuaweiTestBase): def test_delete_snapshot_success(self): self.driver.delete_snapshot(self.snapshot) - @unittest.skip("Skip until bug #1578986 is fixed") def test_create_volume_from_snapsuccess(self): self.mock_object( huawei_driver.HuaweiBaseDriver, @@ -2617,13 +2703,17 @@ class HuaweiISCSIDriverTestCase(HuaweiTestBase): return_value={'extra_specs': sync_replica_specs}) self.mock_object(replication.ReplicaCommonDriver, 'sync') model_update = self.driver.create_volume_from_snapshot(self.volume, - self.volume) - self.assertEqual('1', model_update['provider_location']) + self.snapshot) + expect_value = {"huawei_lun_id": "1", + "huawei_lun_wwn": "6643e8c1004c5f6723e9f454003"} + self.assertDictEqual(expect_value, + json.loads(model_update['provider_location'])) driver_data = {'pair_id': TEST_PAIR_ID, - 'rmt_lun_id': '1'} - driver_data = replication.to_string(driver_data) - self.assertEqual(driver_data, model_update['replication_driver_data']) + 'rmt_lun_id': '1', + 'rmt_lun_wwn': '6643e8c1004c5f6723e9f454003'} + self.assertDictEqual( + driver_data, json.loads(model_update['replication_driver_data'])) self.assertEqual('available', model_update['replication_status']) @mock.patch.object(huawei_driver.HuaweiISCSIDriver, @@ -2810,19 +2900,19 @@ class HuaweiISCSIDriverTestCase(HuaweiTestBase): self.driver.extend_volume, self.volume, 3) - def test_get_admin_metadata(self): + def test_get_volume_metadata(self): metadata = [{'key': 'huawei_lun_wwn', 'value': '1'}] tmp_volume = fake_volume.fake_volume_obj( - admin_contex, volume_admin_metadata=metadata) + admin_contex, volume_metadata=metadata) expected_value = {'huawei_lun_wwn': '1'} - admin_metadata = huawei_utils.get_admin_metadata(tmp_volume) - self.assertEqual(expected_value, admin_metadata) + metadata = huawei_utils.get_volume_metadata(tmp_volume) + self.assertEqual(expected_value, metadata) - metadata = {'huawei_lun_wwn': '1'} + expected_value = {'huawei_lun_wwn': '1'} tmp_volume = fake_volume.fake_volume_obj(admin_contex) - tmp_volume.admin_metadata = metadata - admin_metadata = huawei_utils.get_admin_metadata(tmp_volume) - self.assertEqual(expected_value, admin_metadata) + tmp_volume.metadata = expected_value + metadata = huawei_utils.get_volume_metadata(tmp_volume) + self.assertEqual(expected_value, metadata) def test_login_fail(self): self.driver.client.test_fail = True @@ -2972,7 +3062,10 @@ class HuaweiISCSIDriverTestCase(HuaweiTestBase): def test_create_smartqos(self, mock_qos_value, pool_data): self.driver.support_func = pool_data lun_info = self.driver.create_volume(self.volume) - self.assertEqual('1', lun_info['provider_location']) + expect_value = {"huawei_lun_id": "1", + "huawei_lun_wwn": "6643e8c1004c5f6723e9f454003"} + self.assertDictEqual(expect_value, + json.loads(lun_info['provider_location'])) @ddt.data('front-end', 'back-end') @mock.patch.object(huawei_driver.HuaweiBaseDriver, '_get_volume_params', @@ -2996,7 +3089,10 @@ class HuaweiISCSIDriverTestCase(HuaweiTestBase): 'consumer': mock_consumer}) self.driver.support_func = FAKE_POOLS_SUPPORT_REPORT lun_info = self.driver.create_volume(self.volume) - self.assertEqual('1', lun_info['provider_location']) + expect_value = {"huawei_lun_id": "1", + "huawei_lun_wwn": "6643e8c1004c5f6723e9f454003"} + self.assertDictEqual(expect_value, + json.loads(lun_info['provider_location'])) @ddt.data([{'specs': {'maxBandWidth': '100', 'IOType': '3'}}, FAKE_POOLS_UNSUPPORT_REPORT], @@ -3062,7 +3158,10 @@ class HuaweiISCSIDriverTestCase(HuaweiTestBase): mock_array_version): self.driver.support_func = FAKE_POOLS_SUPPORT_REPORT lun_info = self.driver.create_volume(self.volume) - self.assertEqual('1', lun_info['provider_location']) + expect_value = {"huawei_lun_id": "1", + "huawei_lun_wwn": "6643e8c1004c5f6723e9f454003"} + self.assertDictEqual(expect_value, + json.loads(lun_info['provider_location'])) @mock.patch.object(smartx.SmartQos, 'get_qos_by_volume_type', return_value={'MINIOPS': '100', @@ -3077,7 +3176,10 @@ class HuaweiISCSIDriverTestCase(HuaweiTestBase): mock_array_version): self.driver.support_func = FAKE_POOLS_SUPPORT_REPORT lun_info = self.driver.create_volume(self.volume) - self.assertEqual('1', lun_info['provider_location']) + expect_value = {"huawei_lun_id": "1", + "huawei_lun_wwn": "6643e8c1004c5f6723e9f454003"} + self.assertDictEqual(expect_value, + json.loads(lun_info['provider_location'])) @mock.patch.object(smartx.SmartQos, 'get_qos_by_volume_type', return_value={'MINIOPS': '100', @@ -3165,7 +3267,10 @@ class HuaweiISCSIDriverTestCase(HuaweiTestBase): 'partitionname': 'partition-test'}) def test_create_smartx(self, mock_volume_types, mock_add_lun_to_partition): lun_info = self.driver.create_volume(self.volume) - self.assertEqual('1', lun_info['provider_location']) + expect_value = {"huawei_lun_id": "1", + "huawei_lun_wwn": "6643e8c1004c5f6723e9f454003"} + self.assertDictEqual(expect_value, + json.loads(lun_info['provider_location'])) @ddt.data([{'smarttier': 'true', 'smartcache': 'true', 'smartpartition': 'true', @@ -3308,10 +3413,13 @@ class HuaweiISCSIDriverTestCase(HuaweiTestBase): mock_pool_info, mock_all_pool_info, mock_login_return): - metadata = {"hypermetro_id": '11', - "remote_lun_id": '1'} + location = {"huawei_lun_id": "1", + "hypermetro_id": "11", + "remote_lun_id": "1", + "huawei_lun_wwn": "6643e8c1004c5f6723e9f454003"} lun_info = self.driver.create_volume(self.hyper_volume) - self.assertEqual(metadata, lun_info['metadata']) + self.assertDictEqual(location, + json.loads(lun_info['provider_location'])) @ddt.data(FAKE_POOLS_UNSUPPORT_REPORT, FAKE_POOLS_SUPPORT_REPORT) @mock.patch.object(huawei_driver.HuaweiBaseDriver, '_get_volume_params', @@ -3552,12 +3660,10 @@ class HuaweiISCSIDriverTestCase(HuaweiTestBase): external_ref = {'source-name': 'LUN1'} model_update = self.driver.manage_existing(self.volume, external_ref) - expected_val = { - 'admin_metadata': { - 'huawei_lun_wwn': '6643e8c1004c5f6723e9f454003' - }, - 'provider_location': 'ID1'} - self.assertEqual(expected_val, model_update) + location = {"huawei_lun_wwn": "6643e8c1004c5f6723e9f454003", + "huawei_lun_id": "ID1"} + self.assertDictEqual(location, + json.loads(model_update['provider_location'])) @ddt.data([[{'PRILUNID': 'ID1'}], []], [[{'PRILUNID': 'ID2'}], ['ID1', 'ID2']]) @@ -3653,12 +3759,10 @@ class HuaweiISCSIDriverTestCase(HuaweiTestBase): self.driver.support_func = pool_data model_update = self.driver.manage_existing(self.volume, external_ref) - expected_val = { - 'admin_metadata': { - 'huawei_lun_wwn': '6643e8c1004c5f6723e9f454003' - }, - 'provider_location': 'ID1'} - self.assertEqual(expected_val, model_update) + expected = {"huawei_lun_wwn": "6643e8c1004c5f6723e9f454003", + "huawei_lun_id": "ID1"} + self.assertDictEqual(expected, + json.loads(model_update['provider_location'])) def test_unmanage(self): self.driver.unmanage(self.volume) @@ -3708,12 +3812,14 @@ class HuaweiISCSIDriverTestCase(HuaweiTestBase): external_ref = {'source-name': 'test1'} model_update = self.driver.manage_existing_snapshot(self.snapshot, external_ref) - self.assertEqual({'provider_location': 'ID1'}, model_update) + expect_value = {'provider_location': '{"huawei_snapshot_id": "ID1"}'} + self.assertEqual(expect_value, model_update) external_ref = {'source-id': 'ID1'} model_update = self.driver.manage_existing_snapshot(self.snapshot, external_ref) - self.assertEqual({'provider_location': 'ID1'}, model_update) + expect_value = {'provider_location': '{"huawei_snapshot_id": "ID1"}'} + self.assertEqual(expect_value, model_update) @mock.patch.object(rest_client.RestClient, 'get_snapshot_info', return_value={'ID': 'ID1', @@ -3769,9 +3875,10 @@ class HuaweiISCSIDriverTestCase(HuaweiTestBase): model_update = self.driver.create_volume(self.replica_volume) driver_data = {'pair_id': TEST_PAIR_ID, - 'rmt_lun_id': '1'} - driver_data = replication.to_string(driver_data) - self.assertEqual(driver_data, model_update['replication_driver_data']) + 'rmt_lun_id': '1', + 'rmt_lun_wwn': '6643e8c1004c5f6723e9f454003'} + self.assertDictEqual( + driver_data, json.loads(model_update['replication_driver_data'])) self.assertEqual('available', model_update['replication_status']) @ddt.data( @@ -3888,7 +3995,6 @@ class HuaweiISCSIDriverTestCase(HuaweiTestBase): return_value=False) self.driver.delete_volume(self.replica_volume) - @unittest.skip("Skip until bug #1578986 is fixed") def test_wait_volume_online(self): replica = FakeReplicaPairManager(self.driver.client, self.driver.replica_client, @@ -3907,7 +4013,6 @@ class HuaweiISCSIDriverTestCase(HuaweiTestBase): self.driver.client, lun_info) - @unittest.skip("Skip until bug #1578986 is fixed") def test_wait_second_access(self): pair_id = '1' access_ro = constants.REPLICA_SECOND_RO @@ -3924,7 +4029,6 @@ class HuaweiISCSIDriverTestCase(HuaweiTestBase): self.assertRaises(exception.VolumeBackendAPIException, common_driver.wait_second_access, pair_id, access_rw) - @unittest.skip("Skip until bug #1578986 is fixed") def test_wait_replica_ready(self): normal_status = { 'RUNNINGSTATUS': constants.REPLICA_RUNNING_STATUS_NORMAL, @@ -4052,12 +4156,19 @@ class HuaweiISCSIDriverTestCase(HuaweiTestBase): v_id = volumes_update[0]['volume_id'] v_update = volumes_update[0]['updates'] self.assertEqual(self.replica_volume.id, v_id) - self.assertEqual('1', v_update['provider_location']) + + expect_location = {"huawei_lun_wwn": "FAKE_RMT_LUN_WWN", + "huawei_lun_id": "1"} + self.assertDictEqual( + expect_location, json.loads(v_update['provider_location'])) self.assertEqual('failed-over', v_update['replication_status']) + + metadata = huawei_utils.get_lun_metadata(self.replica_volume) new_drv_data = {'pair_id': TEST_PAIR_ID, - 'rmt_lun_id': self.replica_volume.provider_location} - new_drv_data = replication.to_string(new_drv_data) - self.assertEqual(new_drv_data, v_update['replication_driver_data']) + 'rmt_lun_id': metadata['huawei_lun_id'], + 'rmt_lun_wwn': metadata['huawei_lun_wwn']} + self.assertDictEqual( + new_drv_data, json.loads(v_update['replication_driver_data'])) @ddt.data({}, {'pair_id': TEST_PAIR_ID}) def test_failover_replica_volumes_invalid_drv_data(self, mock_drv_data): @@ -4110,12 +4221,19 @@ class HuaweiISCSIDriverTestCase(HuaweiTestBase): v_id = volumes_update[0]['volume_id'] v_update = volumes_update[0]['updates'] self.assertEqual(self.replica_volume.id, v_id) - self.assertEqual('1', v_update['provider_location']) + + expect_location = {"huawei_lun_wwn": "FAKE_RMT_LUN_WWN", + "huawei_lun_id": "1"} + self.assertDictEqual( + expect_location, json.loads(v_update['provider_location'])) self.assertEqual('available', v_update['replication_status']) + + metadata = huawei_utils.get_lun_metadata(self.replica_volume) new_drv_data = {'pair_id': TEST_PAIR_ID, - 'rmt_lun_id': self.replica_volume.provider_location} - new_drv_data = replication.to_string(new_drv_data) - self.assertEqual(new_drv_data, v_update['replication_driver_data']) + 'rmt_lun_id': metadata['huawei_lun_id'], + 'rmt_lun_wwn': metadata['huawei_lun_wwn']} + self.assertDictEqual( + new_drv_data, json.loads(v_update['replication_driver_data'])) @ddt.data({}, {'pair_id': TEST_PAIR_ID}) def test_failback_replica_volumes_invalid_drv_data(self, mock_drv_data): @@ -4145,7 +4263,6 @@ class HuaweiISCSIDriverTestCase(HuaweiTestBase): self.assertEqual(self.replica_volume.id, v_id) self.assertEqual('error', v_update['replication_status']) - @unittest.skip("Skip until bug #1578986 is fixed") @mock.patch('oslo_service.loopingcall.FixedIntervalLoopingCall', new=utils.ZeroIntervalLoopingCall) @mock.patch.object(replication.PairOp, 'is_primary', @@ -4201,7 +4318,6 @@ class HuaweiISCSIDriverTestCase(HuaweiTestBase): common_driver.protect_second(replica_id) common_driver.unprotect_second(replica_id) - @unittest.skip("Skip until bug #1578986 is fixed") def test_replication_driver_sync(self): replica_id = TEST_PAIR_ID op = replication.PairOp(self.driver.client) @@ -4312,11 +4428,12 @@ class HuaweiISCSIDriverTestCase(HuaweiTestBase): model, snapshots = ( self.driver.create_group_snapshot(ctxt, self.group_snapshot, test_snapshots)) - snapshots_model_update = [{'id': '21ec7341-9256-497b-97d9' - '-ef48edcf0635', - 'status': 'available', - 'provider_location': 11}] - self.assertEqual(snapshots_model_update, snapshots) + + self.assertEqual('21ec7341-9256-497b-97d9-ef48edcf0635', + snapshots[0]['id']) + self.assertEqual('available', snapshots[0]['status']) + self.assertDictEqual({'huawei_snapshot_id': '11'}, + json.loads(snapshots[0]['provider_location'])) self.assertEqual(fields.GroupSnapshotStatus.AVAILABLE, model['status']) @cg_or_cg_snapshot @@ -4380,7 +4497,10 @@ class HuaweiFCDriverTestCase(HuaweiTestBase): def test_create_volume_success(self): lun_info = self.driver.create_volume(self.volume) - self.assertEqual('1', lun_info['provider_location']) + expect_value = {"huawei_lun_id": "1", + "huawei_lun_wwn": "6643e8c1004c5f6723e9f454003"} + self.assertDictEqual(expect_value, + json.loads(lun_info['provider_location'])) @ddt.data(FAKE_POOLS_UNSUPPORT_REPORT, FAKE_POOLS_SUPPORT_REPORT) def test_delete_volume_success(self, pool_data): @@ -4390,11 +4510,13 @@ class HuaweiFCDriverTestCase(HuaweiTestBase): def test_delete_snapshot_success(self): self.driver.delete_snapshot(self.snapshot) - @unittest.skip("Skip until bug #1578986 is fixed") def test_create_volume_from_snapsuccess(self): lun_info = self.driver.create_volume_from_snapshot(self.volume, - self.volume) - self.assertEqual('1', lun_info['provider_location']) + self.snapshot) + expect_value = {"huawei_lun_id": "1", + "huawei_lun_wwn": "6643e8c1004c5f6723e9f454003"} + self.assertDictEqual(expect_value, + json.loads(lun_info['provider_location'])) @mock.patch.object(huawei_driver.HuaweiFCDriver, 'initialize_connection', @@ -4606,7 +4728,6 @@ class HuaweiFCDriverTestCase(HuaweiTestBase): '12') self.assertFalse(result) - @unittest.skip("Skip until bug #1578986 is fixed") @ddt.data(FAKE_POOLS_UNSUPPORT_REPORT, FAKE_POOLS_SUPPORT_REPORT) @mock.patch.object(rest_client, 'RestClient') def test_migrate_volume_success(self, mock_add_lun_to_partition, @@ -4688,13 +4809,15 @@ class HuaweiFCDriverTestCase(HuaweiTestBase): self.assertFalse(is_valid) # storage_protocol is not match current protocol and volume status is # 'in-use'. + location = ('{"huawei_lun_wwn": "6643e8c1004c5f6723e9f454003", ' + '"huawei_lun_id": "11"}') volume_in_use = {'name': 'volume-21ec7341-9256-497b-97d9-ef48edcf0635', 'size': 2, 'volume_name': 'vol1', 'id': ID, 'volume_id': '21ec7341-9256-497b-97d9-ef48edcf0635', 'volume_attachment': 'in-use', - 'provider_location': '11'} + 'provider_location': location} invalid_host2 = {'host': 'ubuntu001@backend002#OpenStack_Pool', 'capabilities': {'location_info': '210235G7J20000000001', @@ -4743,7 +4866,6 @@ class HuaweiFCDriverTestCase(HuaweiTestBase): test_new_type, None, test_host) self.assertTrue(retype) - @unittest.skip("Skip until bug #1578986 is fixed") @ddt.data(FAKE_POOLS_UNSUPPORT_REPORT, FAKE_POOLS_SUPPORT_REPORT) @mock.patch.object(rest_client, 'RestClient') @mock.patch.object( @@ -4934,7 +5056,10 @@ class HuaweiFCDriverTestCase(HuaweiTestBase): def test_multi_resturls_success(self): self.driver.client.test_multi_url_flag = True lun_info = self.driver.create_volume(self.volume) - self.assertEqual('1', lun_info['provider_location']) + expect_value = {"huawei_lun_id": "1", + "huawei_lun_wwn": "6643e8c1004c5f6723e9f454003"} + self.assertDictEqual(expect_value, + json.loads(lun_info['provider_location'])) def test_get_id_from_result(self): result = {} @@ -4998,10 +5123,13 @@ class HuaweiFCDriverTestCase(HuaweiTestBase): mock_volume_ready, mock_logout): - metadata = {"hypermetro_id": '11', - "remote_lun_id": '1'} + location = {"huawei_lun_id": "1", + "hypermetro_id": "11", + "remote_lun_id": "1", + "huawei_lun_wwn": "6643e8c1004c5f6723e9f454003"} lun_info = self.driver.create_volume(self.hyper_volume) - self.assertEqual(metadata, lun_info['metadata']) + self.assertDictEqual(location, + json.loads(lun_info['provider_location'])) @ddt.data(FAKE_POOLS_UNSUPPORT_REPORT, FAKE_POOLS_SUPPORT_REPORT) @mock.patch.object(huawei_driver.HuaweiBaseDriver, '_get_volume_params', @@ -5030,7 +5158,7 @@ class HuaweiFCDriverTestCase(HuaweiTestBase): self.assertRaises(exception.VolumeBackendAPIException, self.driver.metro.create_hypermetro, "11", {}) - @mock.patch.object(huawei_driver.huawei_utils, 'get_volume_metadata', + @mock.patch.object(huawei_driver.huawei_utils, 'get_lun_metadata', return_value={'hypermetro_id': '3400a30d844d0007', 'remote_lun_id': '1'}) @mock.patch.object(rest_client.RestClient, 'do_mapping', @@ -5044,13 +5172,13 @@ class HuaweiFCDriverTestCase(HuaweiTestBase): mock_map.assert_called_once_with('1', '0', '1', hypermetro_lun=True) - @mock.patch.object(huawei_driver.huawei_utils, 'get_volume_metadata', + @mock.patch.object(huawei_driver.huawei_utils, 'get_lun_metadata', return_value={'hypermetro_id': '3400a30d844d0007', 'remote_lun_id': '1'}) def test_terminate_hypermetro_connection_success(self, mock_metradata): self.driver.metro.disconnect_volume_fc(self.volume, FakeConnector) - @mock.patch.object(huawei_driver.huawei_utils, 'get_volume_metadata', + @mock.patch.object(huawei_driver.huawei_utils, 'get_lun_metadata', return_value={'hypermetro_id': '3400a30d844d0007', 'remote_lun_id': None}) @mock.patch.object(rest_client.RestClient, 'get_lun_id_by_name', @@ -5058,15 +5186,14 @@ class HuaweiFCDriverTestCase(HuaweiTestBase): def test_hypermetroid_none_fail(self, mock_metadata, moke_metro_name): self.assertRaises(exception.VolumeBackendAPIException, self.driver.metro.connect_volume_fc, - self.volume, + self.hyper_volume, FakeConnector) - @unittest.skip("Skip until bug #1578986 is fixed") def test_wait_volume_ready_success(self): flag = self.driver.metro._wait_volume_ready("11") self.assertIsNone(flag) - @mock.patch.object(huawei_driver.huawei_utils, 'get_volume_metadata', + @mock.patch.object(huawei_driver.huawei_utils, 'get_lun_metadata', return_value={'hypermetro_id': '3400a30d844d0007', 'remote_lun_id': '1'}) @mock.patch.object(rest_client.RestClient, 'get_online_free_wwns', @@ -5078,7 +5205,7 @@ class HuaweiFCDriverTestCase(HuaweiTestBase): mock_host_initiators): self.assertRaises(exception.VolumeBackendAPIException, self.driver.metro.connect_volume_fc, - self.volume, + self.hyper_volume, FakeConnector) def test_create_snapshot_fail_hypermetro(self): @@ -5198,7 +5325,7 @@ class HuaweiFCDriverTestCase(HuaweiTestBase): @mock.patch.object(huawei_driver.HuaweiBaseDriver, '_get_group_type', return_value=[{"hypermetro": "true"}]) - @mock.patch.object(huawei_driver.huawei_utils, 'get_volume_metadata', + @mock.patch.object(huawei_driver.huawei_utils, 'get_lun_metadata', return_value={'hypermetro_id': '3400a30d844d0007', 'remote_lun_id': '59'}) @cg_or_cg_snapshot diff --git a/cinder/volume/drivers/huawei/huawei_driver.py b/cinder/volume/drivers/huawei/huawei_driver.py index 09eb63d1e40..3657e90d046 100644 --- a/cinder/volume/drivers/huawei/huawei_driver.py +++ b/cinder/volume/drivers/huawei/huawei_driver.py @@ -344,17 +344,13 @@ class HuaweiBaseDriver(driver.VolumeDriver): {'volume': volume.id, 'params': params}) return params - def _create_volume(self, volume, lun_params): + def _create_volume(self, lun_params): # Create LUN on the array. - model_update = {} lun_info = self.client.create_lun(lun_params) - model_update['provider_location'] = lun_info['ID'] + metadata = {'huawei_lun_id': lun_info['ID'], + 'huawei_lun_wwn': lun_info['WWN']} + model_update = {'metadata': metadata} - admin_metadata = huawei_utils.get_admin_metadata(volume) - admin_metadata.update({'huawei_lun_wwn': lun_info['WWN']}) - model_update['admin_metadata'] = admin_metadata - metadata = huawei_utils.get_volume_metadata(volume) - model_update['metadata'] = metadata return lun_info, model_update def _create_base_type_volume(self, opts, volume, volume_type): @@ -363,7 +359,7 @@ class HuaweiBaseDriver(driver.VolumeDriver): Base type is the service type which doesn't conflict with the other. """ lun_params = self._get_lun_params(volume, opts) - lun_info, model_update = self._create_volume(volume, lun_params) + lun_info, model_update = self._create_volume(lun_params) lun_id = lun_info['ID'] try: @@ -438,10 +434,15 @@ class HuaweiBaseDriver(driver.VolumeDriver): model_update = self._add_extend_type_to_volume(opts, lun_params, lun_info, model_update) + + model_update['provider_location'] = huawei_utils.to_string( + **model_update.pop('metadata')) + return model_update def _delete_volume(self, volume): - lun_id = volume.provider_location + metadata = huawei_utils.get_lun_metadata(volume) + lun_id = metadata.get('huawei_lun_id') if not lun_id: return @@ -470,7 +471,7 @@ class HuaweiBaseDriver(driver.VolumeDriver): smart_qos = smartx.SmartQos(self.client) smart_qos.remove(qos_id, lun_id) - metadata = huawei_utils.get_volume_metadata(volume) + metadata = huawei_utils.get_lun_metadata(volume) if 'hypermetro_id' in metadata: metro = hypermetro.HuaweiHyperMetro(self.client, self.rmt_client, @@ -658,7 +659,9 @@ class HuaweiBaseDriver(driver.VolumeDriver): pool_info = self.client.get_pool_info(pool_name, pools) src_volume_name = huawei_utils.encode_name(volume.id) dst_volume_name = six.text_type(hash(src_volume_name)) - src_id = volume.provider_location + + metadata = huawei_utils.get_lun_metadata(volume) + src_id = metadata['huawei_lun_id'] opts = None qos = None @@ -678,9 +681,12 @@ class HuaweiBaseDriver(driver.VolumeDriver): lun_info = self.client.get_lun_info(src_id) - policy = lun_info['DATATRANSFERPOLICY'] if opts['policy']: policy = opts['policy'] + else: + policy = lun_info.get('DATATRANSFERPOLICY', + self.configuration.lun_policy) + lun_params = { 'NAME': dst_volume_name, 'PARENTID': pool_info['ID'], @@ -691,8 +697,12 @@ class HuaweiBaseDriver(driver.VolumeDriver): 'PREFETCHPOLICY': lun_info['PREFETCHPOLICY'], 'PREFETCHVALUE': lun_info['PREFETCHVALUE'], 'DATATRANSFERPOLICY': policy, - 'READCACHEPOLICY': lun_info['READCACHEPOLICY'], - 'WRITECACHEPOLICY': lun_info['WRITECACHEPOLICY'], + 'READCACHEPOLICY': lun_info.get( + 'READCACHEPOLICY', + self.configuration.lun_read_cache_policy), + 'WRITECACHEPOLICY': lun_info.get( + 'WRITECACHEPOLICY', + self.configuration.lun_write_cache_policy), 'OWNINGCONTROLLER': lun_info['OWNINGCONTROLLER'], } for item in lun_params.keys(): @@ -734,7 +744,8 @@ class HuaweiBaseDriver(driver.VolumeDriver): raise exception.VolumeBackendAPIException(data=err_msg) snapshotname = huawei_utils.encode_name(snapshot.id) - snapshot_id = snapshot.provider_location + metadata = huawei_utils.get_snapshot_metadata(snapshot) + snapshot_id = metadata.get('huawei_snapshot_id') if snapshot_id is None: snapshot_id = self.client.get_snapshot_id_by_name(snapshotname) if snapshot_id is None: @@ -748,7 +759,7 @@ class HuaweiBaseDriver(driver.VolumeDriver): lun_params, lun_info, model_update = ( self._create_base_type_volume(opts, volume, volume_type)) - tgt_lun_id = model_update['provider_location'] + tgt_lun_id = lun_info['ID'] luncopy_name = huawei_utils.encode_name(volume.id) LOG.info( 'create_volume_from_snapshot: src_lun_id: %(src_lun_id)s, ' @@ -778,6 +789,9 @@ class HuaweiBaseDriver(driver.VolumeDriver): # now, not hypermetro. model_update = self._add_extend_type_to_volume(opts, lun_params, lun_info, model_update) + model_update['provider_location'] = huawei_utils.to_string( + **model_update.pop('metadata')) + return model_update def create_cloned_volume(self, volume, src_vref): @@ -817,7 +831,8 @@ class HuaweiBaseDriver(driver.VolumeDriver): If not exists, raise or log warning. """ # Firstly, try to find LUN ID by volume.provider_location. - lun_id = volume.provider_location + metadata = huawei_utils.get_lun_metadata(volume) + lun_id = metadata.get('huawei_lun_id') # If LUN ID not recorded, find LUN ID by LUN NAME. if not lun_id: volume_name = huawei_utils.encode_name(volume.id) @@ -831,8 +846,7 @@ class HuaweiBaseDriver(driver.VolumeDriver): raise exception.VolumeBackendAPIException(data=msg) return - metadata = huawei_utils.get_admin_metadata(volume) - lun_wwn = metadata.get('huawei_lun_wwn') if metadata else None + lun_wwn = metadata.get('huawei_lun_wwn') if not lun_wwn: LOG.debug("No LUN WWN recorded for volume %s.", volume.id) @@ -908,7 +922,8 @@ class HuaweiBaseDriver(driver.VolumeDriver): snapshot_id = snapshot_info['ID'] self.client.activate_snapshot(snapshot_id) - return {'provider_location': snapshot_info['ID'], + location = huawei_utils.to_string(huawei_snapshot_id=snapshot_id) + return {'provider_location': location, 'lun_info': snapshot_info} def delete_snapshot(self, snapshot): @@ -921,7 +936,8 @@ class HuaweiBaseDriver(driver.VolumeDriver): {'snapshot': snapshotname, 'volume': volume_name},) - snapshot_id = snapshot.provider_location + metadata = huawei_utils.get_snapshot_metadata(snapshot) + snapshot_id = metadata.get('huawei_snapshot_id') if snapshot_id is None: snapshot_id = self.client.get_snapshot_id_by_name(snapshotname) @@ -1196,7 +1212,8 @@ class HuaweiBaseDriver(driver.VolumeDriver): 'replication_type': None, } - lun_id = volume.provider_location + metadata = huawei_utils.get_lun_metadata(volume) + lun_id = metadata['huawei_lun_id'] old_opts = self.get_lun_specs(lun_id) new_specs = new_type['extra_specs'] @@ -1476,12 +1493,10 @@ class HuaweiBaseDriver(driver.VolumeDriver): {'old_name': lun_info.get('NAME'), 'new_name': new_name}) self.client.rename_lun(lun_id, new_name, description) - metadata = huawei_utils.get_admin_metadata(volume) - metadata.update({'huawei_lun_wwn': lun_info['WWN']}) - model_update = {} - model_update.update({'admin_metadata': metadata}) - model_update.update({'provider_location': lun_id}) + location = huawei_utils.to_string(huawei_lun_id=lun_id, + huawei_lun_wwn=lun_info['WWN']) + model_update = {'provider_location': location} if new_opts and new_opts.get('replication_enabled'): LOG.debug("Manage volume need to create replication.") @@ -1565,9 +1580,9 @@ class HuaweiBaseDriver(driver.VolumeDriver): def manage_existing_snapshot(self, snapshot, existing_ref): snapshot_info = self._get_snapshot_info_by_ref(existing_ref) snapshot_id = snapshot_info.get('ID') - volume = snapshot.volume - lun_id = volume.provider_location - if lun_id != snapshot_info.get('PARENTID'): + parent_metadata = huawei_utils.get_lun_metadata(snapshot.volume) + parent_lun_id = parent_metadata.get('huawei_lun_id') + if parent_lun_id != snapshot_info.get('PARENTID'): msg = (_("Can't import snapshot %s to Cinder. " "Snapshot doesn't belong to volume."), snapshot_id) raise exception.ManageExistingInvalidReference( @@ -1587,7 +1602,8 @@ class HuaweiBaseDriver(driver.VolumeDriver): {'old_name': snapshot_info.get('NAME'), 'new_name': snapshot_name}) - return {'provider_location': snapshot_id} + location = huawei_utils.to_string(huawei_snapshot_id=snapshot_id) + return {'provider_location': location} def manage_existing_snapshot_get_size(self, snapshot, existing_ref): """Get the size of the existing snapshot.""" @@ -1702,9 +1718,11 @@ class HuaweiBaseDriver(driver.VolumeDriver): info = self.client.create_snapshot(lun_id, snapshot_name, snapshot_description) + location = huawei_utils.to_string( + huawei_snapshot_id=info['ID']) snap_model_update = {'id': snapshot.id, 'status': fields.SnapshotStatus.AVAILABLE, - 'provider_location': info['ID']} + 'provider_location': location} snapshots_model_update.append(snap_model_update) added_snapshots_info.append(info) except Exception: @@ -1874,7 +1892,8 @@ class HuaweiBaseDriver(driver.VolumeDriver): def get_lun_id_and_type(self, volume): if hasattr(volume, 'lun_type'): - lun_id = volume.provider_location + metadata = huawei_utils.get_snapshot_metadata(volume) + lun_id = metadata['huawei_snapshot_id'] lun_type = constants.SNAPSHOT_TYPE else: lun_id = self._check_volume_exist_on_array( @@ -2197,7 +2216,7 @@ 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) + metadata = huawei_utils.get_lun_metadata(volume) LOG.info("initialize_connection, metadata is: %s.", metadata) hypermetro_lun = 'hypermetro_id' in metadata @@ -2356,7 +2375,7 @@ class HuaweiFCDriver(HuaweiBaseDriver, driver.FibreChannelDriver): self.client.delete_mapping_view(view_id) # Deal with hypermetro connection. - metadata = huawei_utils.get_volume_metadata(volume) + metadata = huawei_utils.get_lun_metadata(volume) LOG.info("Detach Volume, metadata is: %s.", metadata) if 'hypermetro_id' in metadata: diff --git a/cinder/volume/drivers/huawei/huawei_utils.py b/cinder/volume/drivers/huawei/huawei_utils.py index 012f1e7be13..c9f673054dd 100644 --- a/cinder/volume/drivers/huawei/huawei_utils.py +++ b/cinder/volume/drivers/huawei/huawei_utils.py @@ -13,6 +13,7 @@ # License for the specific language governing permissions and limitations # under the License. +import json import six import time @@ -124,3 +125,37 @@ def check_whether_operate_consistency_group(func): raise NotImplementedError(msg) return func(self, context, group, *args, **kwargs) return wrapper + + +def to_string(**kwargs): + return json.dumps(kwargs) if kwargs else '' + + +def get_lun_metadata(volume): + if not volume.provider_location: + return {} + + info = json.loads(volume.provider_location) + if isinstance(info, dict): + return info + + # To keep compatible with old driver version + admin_metadata = get_admin_metadata(volume) + metadata = get_volume_metadata(volume) + return {'huawei_lun_id': six.text_type(info), + 'huawei_lun_wwn': admin_metadata.get('huawei_lun_wwn'), + 'hypermetro_id': metadata.get('hypermetro_id'), + 'remote_lun_id': metadata.get('remote_lun_id') + } + + +def get_snapshot_metadata(snapshot): + if not snapshot.provider_location: + return {} + + info = json.loads(snapshot.provider_location) + if isinstance(info, dict): + return info + + # To keep compatible with old driver version + return {'huawei_snapshot_id': six.text_type(info)} diff --git a/cinder/volume/drivers/huawei/hypermetro.py b/cinder/volume/drivers/huawei/hypermetro.py index 9c7e36e8980..ff74858456a 100644 --- a/cinder/volume/drivers/huawei/hypermetro.py +++ b/cinder/volume/drivers/huawei/hypermetro.py @@ -75,7 +75,7 @@ class HuaweiHyperMetro(object): def delete_hypermetro(self, volume): """Delete hypermetro.""" - metadata = huawei_utils.get_volume_metadata(volume) + metadata = huawei_utils.get_lun_metadata(volume) metro_id = metadata['hypermetro_id'] remote_lun_id = metadata['remote_lun_id'] @@ -112,7 +112,7 @@ class HuaweiHyperMetro(object): {'wwpns': wwns, 'volume': volume_name}) - metadata = huawei_utils.get_volume_metadata(volume) + metadata = huawei_utils.get_lun_metadata(volume) lun_id = metadata['remote_lun_id'] if lun_id is None: @@ -185,7 +185,7 @@ class HuaweiHyperMetro(object): """Delete map between a volume and a host for FC.""" wwns = connector['wwpns'] volume_name = huawei_utils.encode_name(volume.id) - metadata = huawei_utils.get_volume_metadata(volume) + metadata = huawei_utils.get_lun_metadata(volume) lun_id = metadata['remote_lun_id'] host_name = connector['host'] left_lunnum = -1 @@ -331,7 +331,7 @@ class HuaweiHyperMetro(object): raise exception.VolumeBackendAPIException(data=msg) def check_metro_need_to_stop(self, volume): - metadata = huawei_utils.get_volume_metadata(volume) + metadata = huawei_utils.get_lun_metadata(volume) metro_id = metadata['hypermetro_id'] metro_existed = self.client.check_hypermetro_exist(metro_id) diff --git a/cinder/volume/drivers/huawei/replication.py b/cinder/volume/drivers/huawei/replication.py index 87d9e3c0a46..3a1b58e40cf 100644 --- a/cinder/volume/drivers/huawei/replication.py +++ b/cinder/volume/drivers/huawei/replication.py @@ -505,7 +505,8 @@ class ReplicaPairManager(object): model_update = {} driver_data = {'pair_id': pair_id, - 'rmt_lun_id': rmt_lun_id} + 'rmt_lun_id': rmt_lun_id, + 'rmt_lun_wwn': rmt_lun_info['WWN']} model_update['replication_driver_data'] = to_string(driver_data) model_update['replication_status'] = 'available' LOG.debug('Create replication, return info: %s.', model_update) @@ -582,16 +583,18 @@ class ReplicaPairManager(object): # Switch replication pair role, and start synchronize. self.rmt_driver.enable(pair_id) - lun_info = self.rmt_client.get_lun_info(rmt_lun_id) - admin_metadata = huawei_utils.get_admin_metadata(v) - admin_metadata.update({'huawei_lun_wwn': lun_info['WWN']}) - new_drv_data = {'pair_id': pair_id, - 'rmt_lun_id': v.provider_location} - new_drv_data = to_string(new_drv_data) - v_update['updates'] = {'provider_location': rmt_lun_id, + local_metadata = huawei_utils.get_lun_metadata(v) + new_drv_data = to_string( + {'pair_id': pair_id, + 'rmt_lun_id': local_metadata.get('huawei_lun_id'), + 'rmt_lun_wwn': local_metadata.get('huawei_lun_wwn')}) + location = huawei_utils.to_string( + huawei_lun_id=rmt_lun_id, + huawei_lun_wwn=drv_data.get('rmt_lun_wwn')) + + v_update['updates'] = {'provider_location': location, 'replication_status': 'available', - 'replication_driver_data': new_drv_data, - 'admin_metadata': admin_metadata} + 'replication_driver_data': new_drv_data} volumes_update.append(v_update) return volumes_update @@ -622,17 +625,18 @@ class ReplicaPairManager(object): self.rmt_driver.failover(pair_id) - lun_info = self.rmt_client.get_lun_info(rmt_lun_id) - admin_metadata = huawei_utils.get_admin_metadata(v) - admin_metadata.update({'huawei_lun_wwn': lun_info['WWN']}) + local_metadata = huawei_utils.get_lun_metadata(v) + new_drv_data = to_string( + {'pair_id': pair_id, + 'rmt_lun_id': local_metadata.get('huawei_lun_id'), + 'rmt_lun_wwn': local_metadata.get('huawei_lun_wwn')}) + location = huawei_utils.to_string( + huawei_lun_id=rmt_lun_id, + huawei_lun_wwn=drv_data.get('rmt_lun_wwn')) - new_drv_data = {'pair_id': pair_id, - 'rmt_lun_id': v.provider_location} - new_drv_data = to_string(new_drv_data) - v_update['updates'] = {'provider_location': rmt_lun_id, + v_update['updates'] = {'provider_location': location, 'replication_status': 'failed-over', - 'replication_driver_data': new_drv_data, - 'admin_metadata': admin_metadata} + 'replication_driver_data': new_drv_data} volumes_update.append(v_update) return volumes_update diff --git a/cinder/volume/drivers/huawei/rest_client.py b/cinder/volume/drivers/huawei/rest_client.py index feb95a3caad..0843baa93af 100644 --- a/cinder/volume/drivers/huawei/rest_client.py +++ b/cinder/volume/drivers/huawei/rest_client.py @@ -26,6 +26,7 @@ from cinder import exception from cinder.i18n import _ from cinder import utils from cinder.volume.drivers.huawei import constants +from cinder.volume.drivers.huawei import huawei_utils LOG = logging.getLogger(__name__) @@ -324,8 +325,10 @@ class RestClient(object): return result['data'] def get_lun_id(self, volume, volume_name): - lun_id = (volume.provider_location or + metadata = huawei_utils.get_lun_metadata(volume) + lun_id = (metadata.get('huawei_lun_id') or self.get_lun_id_by_name(volume_name)) + if not lun_id: msg = (_("Can't find lun info on the array. " "volume: %(id)s, lun name: %(name)s.") %