From b6b60c8cd91d47f6b8146cecf6ea807aced60a9d Mon Sep 17 00:00:00 2001 From: raghavendrat Date: Mon, 27 Nov 2023 13:49:01 +0000 Subject: [PATCH] HPE 3par - Add ipv6 support This patch adds ipv6 support to the iscsi driver. Closes-Bug: #2045411 Change-Id: I8a65c2c3f3017e041f6b3be629ce54c27566cf6b --- .../unit/volume/drivers/hpe/test_hpe3par.py | 108 +++++++++++++++++- cinder/volume/drivers/hpe/hpe_3par_iscsi.py | 50 ++++++-- ...par-add-ipv6-support-a9f453a66c51e6d3.yaml | 4 + 3 files changed, 148 insertions(+), 14 deletions(-) create mode 100644 releasenotes/notes/hpe-3par-add-ipv6-support-a9f453a66c51e6d3.yaml diff --git a/cinder/tests/unit/volume/drivers/hpe/test_hpe3par.py b/cinder/tests/unit/volume/drivers/hpe/test_hpe3par.py index 1d5cff514c9..ef507270f30 100644 --- a/cinder/tests/unit/volume/drivers/hpe/test_hpe3par.py +++ b/cinder/tests/unit/volume/drivers/hpe/test_hpe3par.py @@ -163,6 +163,14 @@ class HPE3PARBaseDriver(test.TestCase): '21810002ac00383d'), 'linkState': 4} + FAKE_ISCSI_PORT_V6 = {'portPos': {'node': 8, 'slot': 1, 'cardPort': 2}, + 'protocol': 2, + 'mode': 2, + 'IPAddr': '2001:db8:abcd:12:ffff:ffff:ffff:ff02', + 'iSCSIName': ('iqn.2000-05.com.3pardata:' + '21810002ac00383e'), + 'linkState': 4} + volume_snapshot = {'name': VOLUME_NAME, 'id': VOLUME_ID, 'display_name': 'Foo Volume', @@ -463,7 +471,7 @@ class HPE3PARBaseDriver(test.TestCase): 'CHAP_INITIATOR': 1, 'CHAP_TARGET': 2, 'getPorts.return_value': { - 'members': FAKE_FC_PORTS + [FAKE_ISCSI_PORT] + 'members': FAKE_FC_PORTS + [FAKE_ISCSI_PORT] + [FAKE_ISCSI_PORT_V6] } } @@ -8781,6 +8789,15 @@ class TestHPE3PARISCSIDriver(HPE3PARBaseDriver): 'target_luns': [TARGET_LUN], 'target_portals': ['1.1.1.2:1234']}} + multipath_properties_v6 = { + 'driver_volume_type': 'iscsi', + 'data': + {'encrypted': False, + 'target_discovered': True, + 'target_iqns': [TARGET_IQN], + 'target_luns': [TARGET_LUN], + 'target_portals': ['[2001:db8:abcd:12:ffff:ffff:ffff:ff02]:3260']}} + def setup_driver(self, config=None, mock_conf=None, wsapi_version=None): self.ctxt = context.get_admin_context() @@ -9266,6 +9283,75 @@ class TestHPE3PARISCSIDriver(HPE3PARBaseDriver): self.assertDictEqual(self.multipath_properties, result) + def test_initialize_connection_v6(self): + # setup_mock_client drive with default configuration + # and return the mock HTTP 3PAR client + conf = self.setup_configuration() + conf.hpe3par_iscsi_ips = ["2001:db8:abcd:12:ffff:ffff:ffff:ff02"] + mock_client = self.setup_driver(config=conf) + mock_client.getVolume.return_value = {'userCPG': HPE3PAR_CPG} + mock_client.getCPG.return_value = {} + mock_client.getHost.side_effect = [ + hpeexceptions.HTTPNotFound('fake'), + {'name': self.FAKE_HOST}] + mock_client.queryHost.return_value = { + 'members': [{ + 'name': self.FAKE_HOST + }] + } + + mock_client.getHostVLUNs.side_effect = [ + hpeexceptions.HTTPNotFound('fake'), + [{'active': True, + 'volumeName': self.VOLUME_3PAR_NAME, + 'lun': self.TARGET_LUN, 'type': 0, + 'portPos': {'node': 8, 'slot': 1, 'cardPort': 2}}]] + + location = ("%(volume_name)s,%(lun_id)s,%(host)s,%(nsp)s" % + {'volume_name': self.VOLUME_3PAR_NAME, + 'lun_id': self.TARGET_LUN, + 'host': self.FAKE_HOST, + 'nsp': 'something'}) + mock_client.createVLUN.return_value = location + + mock_client.getiSCSIPorts.return_value = [{ + 'IPAddr': '2001:db8:abcd:12:ffff:ffff:ffff:ff02', + 'iSCSIName': self.TARGET_IQN, + }] + + with mock.patch.object(hpecommon.HPE3PARCommon, + '_create_client') as mock_create_client: + mock_create_client.return_value = mock_client + volume = copy.deepcopy(self.volume) + volume.replication_status = 'disabled' + result = self.driver.initialize_connection( + volume, + self.connector_multipath_enabled) + + expected = [ + mock.call.getVolume(self.VOLUME_3PAR_NAME), + mock.call.getCPG(HPE3PAR_CPG), + mock.call.getHost(self.FAKE_HOST), + mock.call.queryHost(iqns=['iqn.1993-08.org.debian:01:222']), + mock.call.getHost(self.FAKE_HOST), + mock.call.getiSCSIPorts( + state=self.mock_client_conf['PORT_STATE_READY']), + mock.call.getHostVLUNs(self.FAKE_HOST), + mock.call.createVLUN( + self.VOLUME_3PAR_NAME, + auto=True, + hostname=self.FAKE_HOST, + portPos=self.FAKE_ISCSI_PORT_V6['portPos'], + lun=None), + mock.call.getHostVLUNs(self.FAKE_HOST)] + + mock_client.assert_has_calls( + self.standard_login + + expected + + self.standard_logout) + + self.assertDictEqual(self.multipath_properties_v6, result) + def test_terminate_connection_for_clear_chap_creds_not_found(self): # setup_mock_client drive with default configuration # and return the mock HTTP 3PAR client @@ -10764,11 +10850,16 @@ class TestHPE3PARISCSIDriver(HPE3PARBaseDriver): mock_client.assert_has_calls(expected) self.assertDictEqual(expected_model, model) - def test_initialize_iscsi_ports_with_iscsi_ip_and_port(self): + # (i) ip_addr is default i.e v4 + # (ii) ip_addr is v6 + @ddt.data({'ip_addr': '10.10.220.252:1234'}, + {'ip_addr': '[2001:db8:abcd:12:ffff:ffff:ffff:ff02]:5678'}) + @ddt.unpack + def test_initialize_iscsi_ports_with_iscsi_ip_and_port(self, ip_addr): # setup_mock_client drive with default configuration # and return the mock HTTP 3PAR client conf = self.setup_configuration() - conf.hpe3par_iscsi_ips = ["10.10.220.252:1234"] + conf.hpe3par_iscsi_ips = [ip_addr] mock_client = self.setup_driver(config=conf) mock_client.getPorts.return_value = PORTS_RET @@ -11168,7 +11259,16 @@ PORTS_RET = ({'members': 'iSCSIName': 'iqn.2000-05.com.3pardata:21810002ac00383d', 'mode': 2, 'HWAddr': '2C27D75375D6', - 'type': 8}]}) + 'type': 8}, + {'portPos': {'node': 1, 'slot': 8, 'cardPort': 3}, + 'protocol': 2, + 'IPAddr': '2001:db8:abcd:12:ffff:ffff:ffff:ff02', # v6 address + 'linkState': 4, + 'device': [], + 'iSCSIName': 'iqn.2000-05.com.3pardata:21810002ac00383d', + 'mode': 2, + 'HWAddr': '2C27D75375D8', + 'type': 3}]}) PORTS_VLAN_RET = ({'members': [{'portPos': {'node': 1, 'slot': 8, 'cardPort': 2}, diff --git a/cinder/volume/drivers/hpe/hpe_3par_iscsi.py b/cinder/volume/drivers/hpe/hpe_3par_iscsi.py index 7d38d52b786..15cafd14b1a 100644 --- a/cinder/volume/drivers/hpe/hpe_3par_iscsi.py +++ b/cinder/volume/drivers/hpe/hpe_3par_iscsi.py @@ -130,10 +130,11 @@ class HPE3PARISCSIDriver(hpebasedriver.HPE3PARDriverBase): 4.0.5 - Added Primera array check. bug #1849525 4.0.6 - Allow iSCSI support for Primera 4.2 onwards 4.0.7 - Use vlan iscsi ips. Bug #2015034 + 4.0.8 - Add ipv6 support. Bug #2045411 """ - VERSION = "4.0.7" + VERSION = "4.0.8" # The name of the CI wiki page. CI_WIKI_NAME = "HPE_Storage_CI" @@ -189,11 +190,25 @@ class HPE3PARISCSIDriver(hpebasedriver.HPE3PARDriverBase): if len(backend_conf['hpe3par_iscsi_ips']) > 0: # add port values to ip_addr, if necessary for ip_addr in backend_conf['hpe3par_iscsi_ips']: - ip = ip_addr.split(':') - if len(ip) == 1: - temp_iscsi_ip[ip_addr] = {'ip_port': DEFAULT_ISCSI_PORT} - elif len(ip) == 2: - temp_iscsi_ip[ip[0]] = {'ip_port': ip[1]} + if "." in ip_addr: + # v4 + ip = ip_addr.split(':') + if len(ip) == 1: + temp_iscsi_ip[ip_addr] = ( + {'ip_port': DEFAULT_ISCSI_PORT}) + elif len(ip) == 2: + temp_iscsi_ip[ip[0]] = {'ip_port': ip[1]} + elif ":" in ip_addr: + # v6 + if "]" in ip_addr: + ip = ip_addr.split(']:') + ip_addr_v6 = ip[0] + ip_addr_v6 = ip_addr_v6.strip('[') + port_v6 = ip[1] + temp_iscsi_ip[ip_addr_v6] = {'ip_port': port_v6} + else: + temp_iscsi_ip[ip_addr] = ( + {'ip_port': DEFAULT_ISCSI_PORT}) else: LOG.warning("Invalid IP address format '%s'", ip_addr) @@ -280,8 +295,15 @@ class HPE3PARISCSIDriver(hpebasedriver.HPE3PARDriverBase): if lun_id is None: lun_id = vlun['lun'] - iscsi_ip_port = "%s:%s" % ( - iscsi_ip, iscsi_ips[iscsi_ip]['ip_port']) + if ":" in iscsi_ip: + # v6 + iscsi_ip_port = "[%s]:%s" % ( + iscsi_ip, iscsi_ips[iscsi_ip]['ip_port']) + else: + # v4 + iscsi_ip_port = "%s:%s" % ( + iscsi_ip, iscsi_ips[iscsi_ip]['ip_port']) + LOG.debug("iscsi_ip_port: %(var)s", {'var': iscsi_ip_port}) target_portals.append(iscsi_ip_port) target_iqns.append(port['iSCSIName']) target_luns.append(vlun['lun']) @@ -490,9 +512,17 @@ class HPE3PARISCSIDriver(hpebasedriver.HPE3PARDriverBase): iscsi_ip_port = iscsi_ips[iscsi_ip]['ip_port'] iscsi_target_iqn = iscsi_ips[iscsi_ip]['iqn'] + if ":" in iscsi_ip: + # v6 + target_portal = "[%s]:%s" % ( + iscsi_ip, iscsi_ip_port) + else: + # v4 + target_portal = "%s:%s" % ( + iscsi_ip, iscsi_ip_port) + LOG.debug("target_portal: %(var)s", {'var': target_portal}) info = {'driver_volume_type': 'iscsi', - 'data': {'target_portal': "%s:%s" % - (iscsi_ip, iscsi_ip_port), + 'data': {'target_portal': target_portal, 'target_iqn': iscsi_target_iqn, 'target_lun': vlun['lun'], 'target_discovered': True diff --git a/releasenotes/notes/hpe-3par-add-ipv6-support-a9f453a66c51e6d3.yaml b/releasenotes/notes/hpe-3par-add-ipv6-support-a9f453a66c51e6d3.yaml new file mode 100644 index 00000000000..b050248f5fe --- /dev/null +++ b/releasenotes/notes/hpe-3par-add-ipv6-support-a9f453a66c51e6d3.yaml @@ -0,0 +1,4 @@ +fixes: + - | + HPE 3PAR driver `Bug #2045411 `_: + Added support for ipv6 address in the 3PAR iSCSI driver.