diff --git a/cinder/tests/unit/volume/drivers/ibm/test_storwize_svc.py b/cinder/tests/unit/volume/drivers/ibm/test_storwize_svc.py index 3fe143f3719..265599129a9 100644 --- a/cinder/tests/unit/volume/drivers/ibm/test_storwize_svc.py +++ b/cinder/tests/unit/volume/drivers/ibm/test_storwize_svc.py @@ -88,7 +88,9 @@ class StorwizeSVCManagementSimulator(object): self._other_pools = {'openstack2': {}, 'openstack3': {}} self._next_cmd_error = { 'lsportip': '', + 'lsip': '', 'lsfabric': '', + 'lsfcportsetmember': '', 'lsiscsiauth': '', 'lsnodecanister': '', 'mkvdisk': '', @@ -747,45 +749,45 @@ port_speed!N/A ports = [None] * 17 ports[0] = ['id', 'WWPN', 'WWNN', 'port_id', 'owning_node_id', 'current_node_id', 'nportid', 'host_io_permitted', - 'virtualized'] + 'virtualized', 'fc_io_port_id'] ports[1] = ['0', '5005076801106CFE', '5005076801106CFE', '1', '1', - '1', '042200', 'no', 'no'] + '1', '042200', 'no', 'no', ''] ports[2] = ['0', '5005076801996CFE', '5005076801106CFE', '1', '1', - '1', '042200', 'yes', 'yes'] + '1', '042200', 'yes', 'yes', ''] ports[3] = ['0', '5005076801206CFE', '5005076801106CFE', '2', '1', - '1', '042200', 'no', 'no'] + '1', '042200', 'no', 'no', ''] ports[4] = ['0', '5005076801A96CFE', '5005076801106CFE', '2', '1', - '1', '042200', 'yes', 'yes'] + '1', '042200', 'yes', 'yes', ''] ports[5] = ['0', '5005076801306CFE', '5005076801106CFE', '3', '1', - '', '042200', 'no', 'no'] + '', '042200', 'no', 'no', ''] ports[6] = ['0', '5005076801B96CFE', '5005076801106CFE', '3', '1', - '', '042200', 'yes', 'yes'] + '', '042200', 'yes', 'yes', ''] ports[7] = ['0', '5005076801406CFE', '5005076801106CFE', '4', '1', - '', '042200', 'no', 'no'] + '', '042200', 'no', 'no', ''] ports[8] = ['0', '5005076801C96CFE', '5005076801106CFE', '4', '1', - '', '042200', 'yes', 'yes'] + '', '042200', 'yes', 'yes', ''] ports[9] = ['0', '5005076801101806', '5005076801101806', '1', '2', - '2', '042200', 'no', 'no'] + '2', '042200', 'no', 'no', ''] ports[10] = ['0', '5005076801991806', '5005076801101806', '1', '2', - '2', '042200', 'yes', 'yes'] + '2', '042200', 'yes', 'yes', ''] ports[11] = ['0', '5005076801201806', '5005076801101806', '2', '2', - '2', '042200', 'no', 'no'] + '2', '042200', 'no', 'no', ''] ports[12] = ['0', '5005076801A91806', '5005076801101806', '2', '2', - '2', '042200', 'yes', 'yes'] + '2', '042200', 'yes', 'yes', ''] ports[13] = ['0', '5005076801301806', '5005076801101806', '3', '2', - '', '042200', 'no', 'no'] + '', '042200', 'no', 'no', ''] ports[14] = ['0', '5005076801B91806', '5005076801101806', '3', '2', - '', '042200', 'yes', 'yes'] + '', '042200', 'yes', 'yes', ''] ports[15] = ['0', '5005076801401806', '5005076801101806', '4', '2', - '', '042200', 'no', 'no'] + '', '042200', 'no', 'no', ''] ports[16] = ['0', '5005076801C91806', '5005076801101806', '4', '2', - '', '042200', 'yes', 'yes'] + '', '042200', 'yes', 'yes', ''] if 'filtervalue' in kwargs: rows = [] rows.append(['id', 'WWPN', 'WWNN', 'port_id', 'owning_node_id', 'current_node_id', 'nportid', 'host_io_permitted', - 'virtualized']) + 'virtualized', 'fc_io_port_id']) if ':' in kwargs['filtervalue']: filter1 = kwargs['filtervalue'].split(':')[0] @@ -805,6 +807,73 @@ port_speed!N/A rows = ports return self._print_info_cmd(rows=rows, **kwargs) + # Print mostly made-up stuff in the correct syntax + def _cmd_lsfcportsetmember(self, **kwargs): + rows = [None] * 7 + rows[0] = ['id', 'fc_io_port_id', 'portset_id', 'portset_name', + 'owner_id', 'owner_name'] + rows[1] = ['0', '5', '6', 'portset6', '', ''] + rows[2] = ['1', '5', '64', 'portset64', '', ''] + rows[3] = ['2', '6', '6', 'portset6', '', ''] + rows[4] = ['3', '6', '64', 'portset64', '', ''] + rows[5] = ['4', '7', '64', 'portset64', '', ''] + rows[6] = ['5', '8', '64', 'portset64', '', ''] + + if self._next_cmd_error['lsfcportsetmember'] == 'header_mismatch': + rows[0].pop(2) + self._next_cmd_error['lsfcportsetmember'] = '' + if self._next_cmd_error['lsfcportsetmember'] == 'remove_field': + for row in rows: + row.pop(1) + self._next_cmd_error['lsfcportsetmember'] = '' + + return self._print_info_cmd(rows=rows, **kwargs) + + # Print mostly made-up stuff in the correct syntax + def _cmd_lsip(self, **kwargs): + ports = [None] * 9 + ports[0] = ['id', 'node_id', 'node_name', 'port_id', 'portset_id', + 'portset_name', 'IP_address', 'prefix', 'vlan', 'gateway', + 'owner_id', 'owner_name'] + ports[1] = ['0', '1', 'node1', '5', '0', 'portset0', '1.234.50.11', + '24', '1001', '', '', ''] + ports[2] = ['1', '1', 'node1', '6', '4', 'portset4', '1.234.51.11', + '24', '1002', '', '', ''] + ports[3] = ['2', '1', 'node1', '7', '5', 'portset5', '1.234.52.11', + '24', '1003', '', '', ''] + ports[4] = ['3', '1', 'node1', '8', '6', 'portset6', '1.234.53.11', + '24', '1004', '', '', ''] + ports[5] = ['4', '2', 'node2', '5', '0', 'portset0', '1.234.54.11', + '24', '1005', '', '', ''] + ports[6] = ['5', '2', 'node2', '6', '4', 'portset4', '1.234.55.11', + '24', '1006', '', '', ''] + ports[7] = ['6', '2', 'node2', '7', '5', 'portset5', '1.234.56.11', + '24', '1007', '', '', ''] + ports[8] = ['7', '2', 'node2', '8', '6', 'portset6', '1.234.57.11', + '24', '1008', '', '', ''] + + if 'filtervalue' in kwargs: + rows = [] + rows.append(['id', 'node_id', 'node_name', 'port_id', 'portset_id', + 'portset_name', 'IP_address', 'prefix', 'vlan', + 'gateway', 'owner_id', 'owner_name']) + + value = kwargs['filtervalue'].split('=')[1] + for v in ports: + if six.text_type(v[5]) == value: + rows.append(v) + else: + rows = ports + + if self._next_cmd_error['lsip'] == 'header_mismatch': + rows[0].pop(2) + self._next_cmd_error['lsip'] = '' + if self._next_cmd_error['lsip'] == 'remove_field': + for row in rows: + row.pop(1) + self._next_cmd_error['lsip'] = '' + return self._print_info_cmd(rows=rows, **kwargs) + # Print mostly made-up stuff in the correct syntax def _cmd_lsportip(self, **kwargs): if self._next_cmd_error['lsportip'] == 'ip_no_config': @@ -1247,6 +1316,10 @@ port_speed!N/A host_info['site_name'] = kwargs['site'].strip('\'\"') else: host_info['site_name'] = '' + if 'portset' in kwargs: + host_info['portset_name'] = kwargs['portset'].strip('\'\"') + else: + host_info['portset_name'] = '' out, err = self._add_port_to_host(host_info, **kwargs) if not len(err): self._hosts_list[host_name] = host_info @@ -4826,6 +4899,26 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase): self.sim.error_injection('lsportip', 'remove_field') self.assertRaises(exception.VolumeBackendAPIException, self.driver.do_setup, None) + self.sim.error_injection('lsfcportsetmember', 'invalid_input') + self.driver.do_setup(None) + + with mock.patch.object(storwize_svc_common.StorwizeHelpers, + 'get_system_info') as get_system_info: + fake_system_info = {'code_level': (8, 5, 0, 0), + 'topology': 'standard', + 'system_name': 'storwize-svc-sim', + 'system_id': '0123456789ABCDEF'} + get_system_info.return_value = fake_system_info + + if self.USESIM: + self.sim.error_injection('lsip', 'invalid_portset') + self.driver.do_setup(None) + self.sim.error_injection('lsip', 'header_mismatch') + self.assertRaises(exception.VolumeBackendAPIException, + self.driver.do_setup, None) + self.sim.error_injection('lsip', 'remove_field') + self.assertRaises(exception.VolumeBackendAPIException, + self.driver.do_setup, None) # Check with bad parameters self._set_flag('san_ip', '') @@ -4873,6 +4966,37 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase): # Finally, check with good parameters self.driver.do_setup(None) + @mock.patch.object(storwize_svc_common.StorwizeSSH, + 'mkhost') + def test_storwize_create_host_with_portset(self, mkhost): + self.driver.do_setup(self.ctxt) + connector = {'host': 'storwize-svc-host', + 'initiator': 'iqn.1993-08.org.debian:01:eac5ccc1aaa', + 'ip': '127.0.0.1'} + # Using portset other than default portset0 + portset = "portset1" + self.driver._helpers.create_host(connector, iscsi=True, + portset=portset) + host_name = self.driver._helpers.get_host_from_connector( + connector, iscsi=True) + self.assertIsNotNone(host_name) + + @mock.patch.object(storwize_svc_common.StorwizeSSH, + 'mkhost') + def test_storwize_create_host_with_portset_from_config(self, mkhost): + self.driver.do_setup(self.ctxt) + connector = {'host': 'storwize-svc-host', + 'initiator': 'iqn.1993-08.org.debian:01:eac5ccc1aaa', + 'ip': '127.0.0.1'} + # Using portset other than default portset0 + self._set_flag('storwize_portset', "portset1") + self.driver._helpers.create_host( + connector, iscsi=True, + portset=self.driver.configuration.storwize_portset) + host_name = self.driver._helpers.get_host_from_connector( + connector, iscsi=True) + self.assertIsNotNone(host_name) + @mock.patch.object(ssh_utils, 'SSHPool') @mock.patch.object(processutils, 'ssh_execute') def test_run_ssh_set_up_with_san_ip(self, mock_ssh_execute, mock_ssh_pool): @@ -5288,6 +5412,7 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase): 'mirror_pool': None, 'volume_topology': None, 'peer_pool': None, + 'storwize_portset': None, 'storwize_svc_src_child_pool': None, 'storwize_svc_target_child_pool': None, 'cycle_period_seconds': 300 diff --git a/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_common.py b/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_common.py index ae741ce1a02..dd090454cfb 100644 --- a/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_common.py +++ b/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_common.py @@ -133,6 +133,10 @@ storwize_svc_opts = [ default=None, help='Specifies the name of the pool in which mirrored copy ' 'is stored. Example: "pool2"'), + cfg.StrOpt('storwize_portset', + default=None, + help='Specifies the name of the portset in which ' + 'host to be created.'), cfg.StrOpt('storwize_svc_src_child_pool', default=None, help='Specifies the name of the source child pool in which ' @@ -272,11 +276,13 @@ class StorwizeSSH(object): port.append(port_name) return port - def mkhost(self, host_name, port_type, port_name, site=None): + def mkhost(self, host_name, port_type, port_name, site=None, portset=None): port = self._create_port_arg(port_type, port_name) ssh_cmd = ['svctask', 'mkhost', '-force'] + port if site: ssh_cmd += ['-site', '"%s"' % site] + if portset: + ssh_cmd += ['-portset', '"%s"' % portset] ssh_cmd += ['-name', '"%s"' % host_name] return self.run_ssh_check_created(ssh_cmd) @@ -318,6 +324,12 @@ class StorwizeSSH(object): ssh_cmd = ['svcinfo', 'lsiscsiauth', '-delim', '!'] return self.run_ssh_info(ssh_cmd, with_header=True) + def lsip(self, portset=None): + ssh_cmd = ['svcinfo', 'lsip', '-delim', '!'] + if portset: + ssh_cmd += ['-filtervalue', 'portset_name=%s' % portset] + return self.run_ssh_info(ssh_cmd, with_header=True) + def lsfabric(self, wwpn=None, host=None): ssh_cmd = ['svcinfo', 'lsfabric', '-delim', '!'] if wwpn: @@ -765,6 +777,10 @@ class StorwizeSSH(object): ssh_cmd += ['-filtervalue', 'current_node_id=%s' % current_node_id] return self.run_ssh_info(ssh_cmd, with_header=True) + def lsfcportsetmember(self): + ssh_cmd = ['svcinfo', 'lsfcportsetmember', '-delim', '!'] + return self.run_ssh_info(ssh_cmd, with_header=True) + def migratevdisk(self, vdisk, dest_pool, copy_id='0'): ssh_cmd = ['svctask', 'migratevdisk', '-mdiskgrp', dest_pool, '-copy', copy_id, '-vdisk', vdisk] @@ -1070,6 +1086,7 @@ class StorwizeHelpers(object): node['WWPN'] = [] node['ipv4'] = [] node['ipv6'] = [] + node['IP_address'] = [] node['enabled_protocols'] = [] nodes[node['id']] = node node['site_id'] = (node_data['site_id'] @@ -1080,21 +1097,37 @@ class StorwizeHelpers(object): self.handle_keyerror('lsnode', node_data) return nodes - def add_iscsi_ip_addrs(self, storage_nodes): + def add_iscsi_ip_addrs(self, storage_nodes, code_level, portset=None): """Add iSCSI IP addresses to system node information.""" - resp = self.ssh.lsportip() - for ip_data in resp: - try: - state = ip_data['state'] - if ip_data['node_id'] in storage_nodes and ( - state == 'configured' or state == 'online'): - node = storage_nodes[ip_data['node_id']] - if len(ip_data['IP_address']): - node['ipv4'].append(ip_data['IP_address']) - if len(ip_data['IP_address_6']): - node['ipv6'].append(ip_data['IP_address_6']) - except KeyError: - self.handle_keyerror('lsportip', ip_data) + if code_level >= (8, 4, 2, 0): + portset_name = portset if portset else 'portset0' + lsip_resp = self.ssh.lsip(portset=portset_name) + for node_data in storage_nodes: + ip_addresses = [] + try: + for ip_data in lsip_resp: + if ip_data['node_id'] in node_data: + if (ip_data['IP_address']): + ip_addresses.append(ip_data['IP_address']) + except KeyError: + self.handle_keyerror('lsip', ip_data) + if ip_addresses: + storage_nodes[ip_data['node_id']]['IP_address'] = ( + ip_addresses) + else: + lsportip_resp = self.ssh.lsportip() + for ip_data in lsportip_resp: + try: + state = ip_data['state'] + if ip_data['node_id'] in storage_nodes and ( + state == 'configured' or state == 'online'): + node = storage_nodes[ip_data['node_id']] + if len(ip_data['IP_address']): + node['ipv4'].append(ip_data['IP_address']) + if len(ip_data['IP_address_6']): + node['ipv6'].append(ip_data['IP_address_6']) + except KeyError: + self.handle_keyerror('lsportip', ip_data) def add_fc_wwpns(self, storage_nodes, code_level): """Add FC WWPNs to system node information.""" @@ -1110,20 +1143,36 @@ class StorwizeHelpers(object): port_info['status'] == 'active'): wwpns.add(port_info['WWPN']) else: - npiv_wwpns = self.get_npiv_wwpns(node_id=node['id']) + npiv_wwpns = self.get_npiv_wwpns(code_level, + node_id=node['id']) wwpns.update(npiv_wwpns) node['WWPN'] = list(wwpns) LOG.info('WWPN on node %(node)s: %(wwpn)s.', {'node': node['id'], 'wwpn': node['WWPN']}) - def get_npiv_wwpns(self, node_id=None, host_io=None): + def get_npiv_wwpns(self, code_level, node_id=None, host_io=None, + portset=None): wwpns = set() # In the response of lstargetportfc, the host_io_permitted # indicates whether the port can be used for host I/O - resp = self.ssh.lstargetportfc(current_node_id=node_id, - host_io_permitted=host_io) - for port_info in resp: - wwpns.add(port_info['WWPN']) + targetportfc_resp = self.ssh.lstargetportfc(current_node_id=node_id, + host_io_permitted=host_io) + if code_level >= (8, 4, 2, 0): + portset_name = portset if portset else 'portset64' + port_ids = set() + fcportsetmember_resp = self.ssh.lsfcportsetmember() + for portset_member in fcportsetmember_resp: + if portset_member['portset_name'] == portset_name: + port_ids.add(portset_member['fc_io_port_id']) + + for port_info in targetportfc_resp: + for port_id in port_ids: + if port_id == port_info['fc_io_port_id']: + wwpns.add(port_info['WWPN']) + break + else: + for port_info in targetportfc_resp: + wwpns.add(port_info['WWPN']) return list(wwpns) def add_chap_secret_to_host(self, host_name): @@ -1288,7 +1337,7 @@ class StorwizeHelpers(object): LOG.debug('Leave: get_host_from_connector: host %s.', host_name) return host_name - def create_host(self, connector, iscsi=False, site=None): + def create_host(self, connector, iscsi=False, site=None, portset=None): """Create a new host on the storage system. We create a host name and associate it with the given connection @@ -1343,7 +1392,7 @@ class StorwizeHelpers(object): # Create a host with one port port = ports.pop(0) # Host site_id is necessary for hyperswap volume. - self.ssh.mkhost(host_name, port[0], port[1], site) + self.ssh.mkhost(host_name, port[0], port[1], site, portset) # Add any additional ports to the host for port in ports: @@ -1514,6 +1563,7 @@ class StorwizeHelpers(object): 'mirror_pool': config.storwize_svc_mirror_pool, 'volume_topology': None, 'peer_pool': config.storwize_peer_pool, + 'storwize_portset': config.storwize_portset, 'storwize_svc_src_child_pool': config.storwize_svc_src_child_pool, 'storwize_svc_target_child_pool': @@ -3279,14 +3329,15 @@ class StorwizeSVCCommonDriver(san.SanDriver, state['storage_nodes'] = helper.get_node_info() # Add the iSCSI IP addresses and WWPNs to the storage node info - helper.add_iscsi_ip_addrs(state['storage_nodes']) + helper.add_iscsi_ip_addrs(state['storage_nodes'], state['code_level']) helper.add_fc_wwpns(state['storage_nodes'], state['code_level']) # For each node, check what connection modes it supports. Delete any # nodes that do not support any types (may be partially configured). to_delete = [] for k, node in state['storage_nodes'].items(): - if ((len(node['ipv4']) or len(node['ipv6'])) + if ((len(node['ipv4']) or len(node['ipv6']) or + len(node['IP_address'])) and len(node['iscsi_name'])): node['enabled_protocols'].append('iSCSI') state['enabled_protocols'].add('iSCSI') diff --git a/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_fc.py b/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_fc.py index 1dd1c04a3d5..170340c26ec 100644 --- a/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_fc.py +++ b/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_fc.py @@ -96,9 +96,10 @@ class StorwizeSVCFCDriver(storwize_common.StorwizeSVCCommonDriver): 2.2.3 - Add replication group support 2.2.4 - Add backup snapshots support 2.2.5 - Add hyperswap support + 2.2.6 - Add support for host attachment using portsets """ - VERSION = "2.2.5" + VERSION = "2.2.6" # ThirdPartySystems wiki page CI_WIKI_NAME = "IBM_STORAGE_CI" @@ -190,7 +191,10 @@ class StorwizeSVCFCDriver(storwize_common.StorwizeSVCCommonDriver): # this connector info. host_name = None try: - host_name = backend_helper.create_host(connector, site=host_site) + opts = self._get_vdisk_params(volume.volume_type_id) + host_name = ( + backend_helper.create_host(connector, site=host_site, + portset=opts['storwize_portset'])) except exception.VolumeBackendAPIException as excp: if "CMMVC6035E" in excp.msg: msg = (_('Host already exists for connector ' @@ -266,8 +270,10 @@ class StorwizeSVCFCDriver(storwize_common.StorwizeSVCCommonDriver): conn_wwpns.extend(node['WWPN']) else: npiv_wwpns = backend_helper.get_npiv_wwpns( + node_state['code_level'], node_id=node['id'], - host_io="yes") + host_io="yes", + portset=opts['storwize_portset']) conn_wwpns.extend(npiv_wwpns) properties['target_wwn'] = conn_wwpns @@ -423,8 +429,10 @@ class StorwizeSVCFCDriver(storwize_common.StorwizeSVCCommonDriver): if node_state['code_level'] < (7, 7, 0, 0): conn_wwpns.extend(node['WWPN']) else: - npivwwpns = backend_helper.get_npiv_wwpns(node_id=node['id'], - host_io="yes") + npivwwpns = ( + backend_helper.get_npiv_wwpns(node_state['code_level'], + node_id=node['id'], + host_io="yes")) conn_wwpns.extend(npivwwpns) i_t_map = self._make_initiator_target_map(connector['wwpns'], diff --git a/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_iscsi.py b/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_iscsi.py index beaabe175b9..9e4d9211f60 100644 --- a/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_iscsi.py +++ b/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_iscsi.py @@ -94,9 +94,10 @@ class StorwizeSVCISCSIDriver(storwize_common.StorwizeSVCCommonDriver): 2.2.2 - Add replication group support 2.2.3 - Add backup snapshots support 2.2.4 - Add hyperswap support + 2.2.5 - Add support for host attachment using portsets """ - VERSION = "2.2.4" + VERSION = "2.2.5" # ThirdPartySystems wiki page CI_WIKI_NAME = "IBM_STORAGE_CI" @@ -183,8 +184,11 @@ class StorwizeSVCISCSIDriver(storwize_common.StorwizeSVCCommonDriver): # this connector info. host_name = None try: - host_name = backend_helper.create_host(connector, iscsi=True, - site=host_site) + opts = self._get_vdisk_params(volume.volume_type_id) + host_name = ( + backend_helper.create_host(connector, iscsi=True, + site=host_site, + portset=opts['storwize_portset'])) except exception.VolumeBackendAPIException as excp: if "CMMVC6578E" in excp.msg: msg = (_('Host already exists for connector ' @@ -213,13 +217,15 @@ class StorwizeSVCISCSIDriver(storwize_common.StorwizeSVCCommonDriver): try: properties = self._get_single_iscsi_data(volume, connector, - lun_id, chap_secret) + lun_id, chap_secret, + opts['storwize_portset']) multipath = connector.get('multipath', False) if multipath: - properties = self._get_multi_iscsi_data(volume, connector, - lun_id, properties, - backend_helper, - node_state) + properties = ( + self._get_multi_iscsi_data(volume, connector, + lun_id, properties, + backend_helper, node_state, + opts['storwize_portset'])) except Exception as ex: with excutils.save_and_reraise_exception(): LOG.error('initialize_connection: Failed to export volume ' @@ -240,7 +246,8 @@ class StorwizeSVCISCSIDriver(storwize_common.StorwizeSVCCommonDriver): return {'driver_volume_type': 'iscsi', 'data': properties, } - def _get_single_iscsi_data(self, volume, connector, lun_id, chap_secret): + def _get_single_iscsi_data(self, volume, connector, lun_id, + chap_secret, portset): LOG.debug('enter: _get_single_iscsi_data: volume %(vol)s with ' 'connector %(conn)s lun_id %(lun_id)s', {'vol': volume.id, 'conn': connector, @@ -277,6 +284,11 @@ class StorwizeSVCISCSIDriver(storwize_common.StorwizeSVCCommonDriver): # Get preferred node and other nodes in I/O group preferred_node_entry = None io_group_nodes = [] + if node_state['code_level'] >= (8, 4, 2, 0): + backend_helper.add_iscsi_ip_addrs(node_state['storage_nodes'], + node_state['code_level'], + portset=portset) + for node in node_state['storage_nodes'].values(): if self.protocol not in node['enabled_protocols']: continue @@ -305,10 +317,14 @@ class StorwizeSVCISCSIDriver(storwize_common.StorwizeSVCCommonDriver): 'target_lun': lun_id, 'volume_id': volume.id} - if preferred_node_entry['ipv4']: - ipaddr = preferred_node_entry['ipv4'][0] + if node_state['code_level'] >= (8, 4, 2, 0): + if preferred_node_entry['IP_address']: + ipaddr = preferred_node_entry['IP_address'][0] else: - ipaddr = preferred_node_entry['ipv6'][0] + if preferred_node_entry['ipv4']: + ipaddr = preferred_node_entry['ipv4'][0] + else: + ipaddr = preferred_node_entry['ipv6'][0] properties['target_portal'] = '%s:%s' % (ipaddr, '3260') properties['target_iqn'] = preferred_node_entry['iscsi_name'] if chap_secret: @@ -327,14 +343,18 @@ class StorwizeSVCISCSIDriver(storwize_common.StorwizeSVCCommonDriver): return properties def _get_multi_iscsi_data(self, volume, connector, lun_id, properties, - backend_helper, node_state): + backend_helper, node_state, portset): LOG.debug('enter: _get_multi_iscsi_data: volume %(vol)s with ' 'connector %(conn)s lun_id %(lun_id)s', {'vol': volume.id, 'conn': connector, 'lun_id': lun_id}) try: - resp = backend_helper.ssh.lsportip() + if node_state['code_level'] >= (8, 4, 2, 0): + portset_name = portset if portset else 'portset0' + resp = backend_helper.ssh.lsip(portset=portset_name) + else: + resp = backend_helper.ssh.lsportip() except Exception as ex: msg = (_('_get_multi_iscsi_data: Failed to ' 'get port ip because of exception: ' @@ -351,11 +371,14 @@ class StorwizeSVCISCSIDriver(storwize_common.StorwizeSVCCommonDriver): continue link_state = ip_data.get('link_state', None) valid_port = '' - if ((ip_data['state'] == 'configured' and - link_state == 'active') or - ip_data['state'] == 'online'): - valid_port = (ip_data['IP_address'] or - ip_data['IP_address_6']) + if node_state['code_level'] >= (8, 4, 2, 0): + valid_port = ip_data['IP_address'] + else: + if ((ip_data['state'] == 'configured' and + link_state == 'active') or + ip_data['state'] == 'online'): + valid_port = (ip_data['IP_address'] or + ip_data['IP_address_6']) if valid_port: properties['target_portals'].append( '%s:%s' % (valid_port, '3260')) diff --git a/releasenotes/notes/ibm-svf-manage-host-attachment-using-portsets-0003c54b185f0eb2.yaml b/releasenotes/notes/ibm-svf-manage-host-attachment-using-portsets-0003c54b185f0eb2.yaml new file mode 100644 index 00000000000..bbfa2d6666e --- /dev/null +++ b/releasenotes/notes/ibm-svf-manage-host-attachment-using-portsets-0003c54b185f0eb2.yaml @@ -0,0 +1,5 @@ +--- +features: + - | + IBM Spectrum Virtualize Family driver: Added support to manage host + attachment using portsets for code level >= 8.4.2.0