Merge "[SVf] Manage host attachment using portsets"
This commit is contained in:
commit
2cdabb6a97
cinder
tests/unit/volume/drivers/ibm
volume/drivers/ibm/storwize_svc
releasenotes/notes
@ -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':
|
||||
@ -3292,14 +3342,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'))
|
||||
|
5
releasenotes/notes/ibm-svf-manage-host-attachment-using-portsets-0003c54b185f0eb2.yaml
Normal file
5
releasenotes/notes/ibm-svf-manage-host-attachment-using-portsets-0003c54b185f0eb2.yaml
Normal file
@ -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…
x
Reference in New Issue
Block a user