From 3c362510172b11e90424a0e83337f840a26f321d Mon Sep 17 00:00:00 2001 From: Liucheng Jiang Date: Mon, 6 Jun 2016 09:02:32 +0800 Subject: [PATCH] Huawei: Support iSCSI configuration in replication feature In most case, users need much more features to attach volume to VM, such as iSCSI multipath, CHAP, etc. In Huawei cinder driver replication feature, we need to fit the case when using iSCSI driver. We add a new key word into replication_device, called iscsi_info. The detail as follows: replication_device = backend_id:huawei-replica-1, storage_pool:pool_1, san_address:san_url_1;san_url_2, iscsi_default_target_ip:192.168.1.100, san_user:admin,san_password:passwd, iscsi_info: {Name:xxx;CHAPinfo:user#password;ALUA:1; TargetIP:0.0.0.0;TargetPortGroup:xxx}; {Name:xxx;CHAPinfo:user#password;ALUA:1; TargetIP:0.0.0.0;TargetPortGroup:xxx} All key words in iscsi_info are case insensitive. The meaning of them are the same with that in huawei_config.xml, which always used in master array. Change-Id: I4a0cce1858c3a8539a62e7dae6e1092d4e86707f Closes-Bug: #1588736 --- cinder/tests/unit/test_huawei_drivers.py | 33 ++++++++++++- cinder/volume/drivers/huawei/huawei_conf.py | 47 ++++++++++++++++++- cinder/volume/drivers/huawei/huawei_driver.py | 7 +-- ...ation-in-replication-7ec53737b95ffa54.yaml | 3 ++ 4 files changed, 84 insertions(+), 6 deletions(-) create mode 100644 releasenotes/notes/huawei-support-iscsi-configuration-in-replication-7ec53737b95ffa54.yaml diff --git a/cinder/tests/unit/test_huawei_drivers.py b/cinder/tests/unit/test_huawei_drivers.py index 28f823518be..5288939ebda 100644 --- a/cinder/tests/unit/test_huawei_drivers.py +++ b/cinder/tests/unit/test_huawei_drivers.py @@ -1886,12 +1886,20 @@ class FakeHuaweiConf(huawei_conf.HuaweiConf): 'TargetPortGroup': 'portgroup-test', } setattr(self.conf, 'iscsi_info', [iscsi_info]) + rmt_iscsi_info = ('{ Name: iqn.1993-08.debian:01:ec2bff7acxxx;\n' + 'TargetIP:1.1.1.1;CHAPinfo:mm-user#mm-user@storage;' + 'ALUA:1; TargetPortGroup:portgroup-test};\t\n ' + '{ Name: iqn.1993-08.debian:01:ec2bff7acyyy;\n' + 'TargetIP:2.2.2.2;CHAPinfo:nn-user#nn-user@storage;' + 'ALUA:0; TargetPortGroup:portgroup-test1}\t\n') + targets = [{'backend_id': REPLICA_BACKEND_ID, 'storage_pool': 'OpenStack_Pool', 'san_address': 'https://192.0.2.69:8088/deviceManager/rest/', 'san_user': 'admin', - 'san_password': 'Admin@storage1'}] + 'san_password': 'Admin@storage1', + 'iscsi_info': rmt_iscsi_info}] setattr(self.conf, 'replication_device', targets) setattr(self.conf, 'safe_get', self.safe_get) @@ -2032,6 +2040,27 @@ class HuaweiISCSIDriverTestCase(test.TestCase): self.portgroup_id = 11 self.driver.client.login() + def test_parse_rmt_iscsi_info(self): + rmt_devs = self.driver.huawei_conf.get_replication_devices() + iscsi_info = rmt_devs[0]['iscsi_info'] + expected_iscsi_info = [{'Name': 'iqn.1993-08.debian:01:ec2bff7acxxx', + 'TargetIP': '1.1.1.1', + 'CHAPinfo': 'mm-user;mm-user@storage', + 'ALUA': '1', + 'TargetPortGroup': 'portgroup-test'}, + {'Name': 'iqn.1993-08.debian:01:ec2bff7acyyy', + 'TargetIP': '2.2.2.2', + 'CHAPinfo': 'nn-user;nn-user@storage', + 'ALUA': '0', + 'TargetPortGroup': 'portgroup-test1'}] + self.assertEqual(expected_iscsi_info, iscsi_info) + + def test_parse_rmt_iscsi_info_without_iscsi_configuration(self): + self.configuration.replication_device[0]['iscsi_info'] = '' + rmt_devs = self.driver.huawei_conf.get_replication_devices() + iscsi_info = rmt_devs[0]['iscsi_info'] + self.assertEqual([], iscsi_info) + def test_login_success(self): device_id = self.driver.client.login() self.assertEqual('210235G7J20000000000', device_id) @@ -2136,7 +2165,7 @@ class HuaweiISCSIDriverTestCase(test.TestCase): def test_get_volume_status(self): data = self.driver.get_volume_stats() - self.assertEqual('2.0.5', data['driver_version']) + self.assertEqual('2.0.6', data['driver_version']) @mock.patch.object(rest_client.RestClient, 'get_lun_info', return_value={"CAPACITY": 6291456}) diff --git a/cinder/volume/drivers/huawei/huawei_conf.py b/cinder/volume/drivers/huawei/huawei_conf.py index 6a7a9b7670a..462276bbe13 100644 --- a/cinder/volume/drivers/huawei/huawei_conf.py +++ b/cinder/volume/drivers/huawei/huawei_conf.py @@ -252,6 +252,50 @@ class HuaweiConf(object): setattr(self.conf, 'iscsi_info', iscsi_info) + def _parse_rmt_iscsi_info(self, iscsi_info): + if not (iscsi_info and iscsi_info.strip()): + return [] + + # Consider iscsi_info value: + # ' {Name:xxx ;;TargetPortGroup: xxx};\n' + # '{Name:\t\rxxx;CHAPinfo: mm-usr#mm-pwd} ' + + # Step 1, ignore whitespace characters, convert to: + # '{Name:xxx;;TargetPortGroup:xxx};{Name:xxx;CHAPinfo:mm-usr#mm-pwd}' + iscsi_info = ''.join(iscsi_info.split()) + + # Step 2, make initiators configure list, convert to: + # ['Name:xxx;;TargetPortGroup:xxx', 'Name:xxx;CHAPinfo:mm-usr#mm-pwd'] + initiator_infos = iscsi_info[1:-1].split('};{') + + # Step 3, get initiator configure pairs, convert to: + # [['Name:xxx', '', 'TargetPortGroup:xxx'], + # ['Name:xxx', 'CHAPinfo:mm-usr#mm-pwd']] + initiator_infos = map(lambda x: x.split(';'), initiator_infos) + + # Step 4, remove invalid configure pairs, convert to: + # [['Name:xxx', 'TargetPortGroup:xxx'], + # ['Name:xxx', 'CHAPinfo:mm-usr#mm-pwd']] + initiator_infos = map(lambda x: filter(lambda y: y, x), + initiator_infos) + + # Step 5, make initiators configure dict, convert to: + # [{'TargetPortGroup': 'xxx', 'Name': 'xxx'}, + # {'Name': 'xxx', 'CHAPinfo': 'mm-usr#mm-pwd'}] + get_opts = lambda x: x.split(':', 1) + initiator_infos = map(lambda x: dict(map(get_opts, x)), + initiator_infos) + # Convert generator to list for py3 compatibility. + initiator_infos = list(initiator_infos) + + # Step 6, replace CHAPinfo 'user#pwd' to 'user;pwd' + key = 'CHAPinfo' + for info in initiator_infos: + if key in info: + info[key] = info[key].replace('#', ';', 1) + + return initiator_infos + def get_replication_devices(self): devs = self.conf.safe_get('replication_device') if not devs: @@ -265,7 +309,8 @@ class HuaweiConf(object): dev_config['san_user'] = dev['san_user'] dev_config['san_password'] = dev['san_password'] dev_config['storage_pool'] = dev['storage_pool'].split(';') - dev_config['iscsi_info'] = [] + dev_config['iscsi_info'] = self._parse_rmt_iscsi_info( + dev.get('iscsi_info')) dev_config['iscsi_default_target_ip'] = ( dev['iscsi_default_target_ip'].split(';') if 'iscsi_default_target_ip' in dev diff --git a/cinder/volume/drivers/huawei/huawei_driver.py b/cinder/volume/drivers/huawei/huawei_driver.py index 704ec67a41f..6b8bab6ff54 100644 --- a/cinder/volume/drivers/huawei/huawei_driver.py +++ b/cinder/volume/drivers/huawei/huawei_driver.py @@ -1607,9 +1607,10 @@ class HuaweiISCSIDriver(HuaweiBaseDriver, driver.ISCSIDriver): 2.0.2 - Refactor HuaweiISCSIDriver 2.0.3 - Manage/unmanage snapshot support 2.0.5 - Replication V2 support + 2.0.6 - Support iSCSI configuration in Replication """ - VERSION = "2.0.5" + VERSION = "2.0.6" def __init__(self, *args, **kwargs): super(HuaweiISCSIDriver, self).__init__(*args, **kwargs) @@ -1667,7 +1668,7 @@ class HuaweiISCSIDriver(HuaweiBaseDriver, driver.ISCSIDriver): LOG.info(_LI("initialize_connection, host lun id is: %s."), hostlun_id) - chapinfo = self.client.find_chap_info(self.configuration.iscsi_info, + chapinfo = self.client.find_chap_info(self.client.iscsi_info, initiator_name) # Return iSCSI properties. @@ -1716,7 +1717,7 @@ class HuaweiISCSIDriver(HuaweiBaseDriver, driver.ISCSIDriver): portgroup_id = None view_id = None left_lunnum = -1 - for ini in self.configuration.iscsi_info: + for ini in self.client.iscsi_info: if ini['Name'] == initiator_name: for key in ini: if key == 'TargetPortGroup': diff --git a/releasenotes/notes/huawei-support-iscsi-configuration-in-replication-7ec53737b95ffa54.yaml b/releasenotes/notes/huawei-support-iscsi-configuration-in-replication-7ec53737b95ffa54.yaml new file mode 100644 index 00000000000..3b79696f65e --- /dev/null +++ b/releasenotes/notes/huawei-support-iscsi-configuration-in-replication-7ec53737b95ffa54.yaml @@ -0,0 +1,3 @@ +--- +upgrade: + - Support iSCSI configuration in replication in Huawei driver.