[SVf] Manage host attachment using portsets
[Spectrum Virtualize family] Providing support to IBM Storwize cinder driver to use portsets to manage host attachment, backend storage connectivity and IP replication traffic. Portsets are groupings of logical addresses that are associated with specific traffic types. Portsets are created on the storage. Hosts are then created using the portset info given by the admin. Implements: blueprint ibm-svf-portset Change-Id: I38c9889bff2d18d3dadd49f28b8436a77b131a22
This commit is contained in:
parent
ac0779ad18
commit
88fd602edd
@ -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
|
||||
|
@ -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')
|
||||
|
@ -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'],
|
||||
|
@ -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'))
|
||||
|
@ -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
|
Loading…
Reference in New Issue
Block a user