Merge "[SVF]:Fix multiple lshost calls during attach."

This commit is contained in:
Zuul 2021-09-09 06:20:18 +00:00 committed by Gerrit Code Review
commit f3d12a1385
5 changed files with 152 additions and 49 deletions

View File

@ -178,6 +178,9 @@ class StorwizeSVCManagementSimulator(object):
'CMMVC8783E': ('', 'CMMVC8783E The volume copy was not deleted '
'because the volume is part of a consistency '
'group.'),
'CMMVC6578E': ('', 'CMMVC6578E The command has failed because '
'the iSCSI name is already assigned or is '
'not valid.'),
}
self._fc_transitions = {'begin': {'make': 'idle_or_copied'},
'idle_or_copied': {'prepare': 'preparing',
@ -1209,7 +1212,10 @@ port_speed!N/A
continue
for port in v[added_key]:
if port == added_val:
return self._errors['CMMVC6581E']
error = 'CMMVC6035E'
if 'iscsiname' in kwargs:
error = 'CMMVC6578E'
return self._errors[error]
return ('', '')
# Make a host
@ -3264,7 +3270,10 @@ class StorwizeSVCISCSIDriverTestCase(test.TestCase):
snapshot,
connector)
def test_storwize_initialize_iscsi_connection_with_host_site(self):
@mock.patch.object(storwize_svc_common.StorwizeHelpers,
'initialize_host_info')
def test_storwize_initialize_iscsi_connection_with_host_site(self,
init_host):
connector = {'host': 'storwize-svc-host',
'wwnns': ['20000090fa17311e', '20000090fa17311f'],
'wwpns': ['ff00000000000000', 'ff00000000000001'],
@ -3279,6 +3288,8 @@ class StorwizeSVCISCSIDriverTestCase(test.TestCase):
volume_iSCSI_2 = self._create_volume()
volume_iSCSI_2['volume_type_id'] = vol_type_iSCSI['id']
self.iscsi_driver.initialize_connection(volume_iSCSI, connector)
init_host.assert_called()
self.assertEqual(1, init_host.call_count)
host_name = self.iscsi_driver._helpers.get_host_from_connector(
connector, iscsi=True)
host_info = self.iscsi_driver._helpers.ssh.lshost(host=host_name)
@ -3337,7 +3348,10 @@ class StorwizeSVCISCSIDriverTestCase(test.TestCase):
volume_iSCSI, connector)
term_conn.assert_called_once_with(volume_iSCSI, connector)
def test_storwize_terminate_iscsi_connection_multi_attach(self):
@mock.patch.object(storwize_svc_common.StorwizeHelpers,
'initialize_host_info')
def test_storwize_terminate_iscsi_connection_multi_attach(self,
init_host_info):
# create an iSCSI volume
volume_iSCSI = self._create_volume()
extra_spec = {'capabilities:storage_protocol': '<in> iSCSI'}
@ -3355,6 +3369,7 @@ class StorwizeSVCISCSIDriverTestCase(test.TestCase):
# map and unmap the volume to two hosts normal case
self.iscsi_driver.initialize_connection(volume_iSCSI, connector)
init_host_info.assert_called()
self.iscsi_driver.initialize_connection(volume_iSCSI, connector2)
for conn in [connector, connector2]:
host = self.iscsi_driver._helpers.get_host_from_connector(
@ -3382,6 +3397,7 @@ class StorwizeSVCISCSIDriverTestCase(test.TestCase):
rmmap.side_effect = Exception('boom')
self.iscsi_driver.terminate_connection(volume_iSCSI,
connector2)
init_host_info.assert_called()
host_name = self.iscsi_driver._helpers.get_host_from_connector(
connector2, iscsi=True)
self.assertIsNone(host_name)
@ -4401,12 +4417,6 @@ class StorwizeSVCFcDriverTestCase(test.TestCase):
# Check bad output from lsfabric for the 2nd volume
if protocol == 'FC' and self.USESIM:
for error in ['remove_field', 'header_mismatch']:
self.sim.error_injection('lsfabric', error)
self.assertRaises(exception.VolumeBackendAPIException,
self.fc_driver.initialize_connection,
volume2, self._connector)
with mock.patch.object(storwize_svc_common.StorwizeHelpers,
'get_conn_fc_wwpns') as conn_fc_wwpns:
conn_fc_wwpns.return_value = []
@ -9823,17 +9833,17 @@ class StorwizeHelpersTestCase(test.TestCase):
access=access)
startrcrelationship.assert_called_once_with(opts['RC_name'], None)
@mock.patch.object(storwize_svc_common.StorwizeSSH, 'lsfabric')
@mock.patch.object(storwize_svc_common.StorwizeHelpers,
'get_host_from_host_info')
@mock.patch.object(storwize_svc_common.StorwizeSSH, 'lshost')
@mock.patch.object(storwize_svc_common.StorwizeSSH, 'lsvdiskhostmap')
def test_get_host_from_connector_with_vol(self,
lsvdishosmap,
lshost,
lsfabric):
get_host_from_host_info):
vol = 'testvol'
connector = {"wwpns": ["10000090fa3870d7", "C050760825191B00"]}
lsfabric.return_value = [{"remote_wwpn": "10000090fa3870d7",
"name": "test_host"}]
get_host_from_host_info.return_value = "test_host", []
raw = "id!name!host_id!host_name!vdisk_UID\n2594!testvol!315!"\
"test_host!60050768028110A4700000000001168E"
ssh_cmd = ['svcinfo', 'lsvdiskhostmap', '-delim', '!', '"%s"' % vol]
@ -9844,23 +9854,23 @@ class StorwizeHelpersTestCase(test.TestCase):
host = self.storwize_svc_common.get_host_from_connector(connector,
vol)
self.assertEqual(host, "test_host")
lsfabric.assert_called_with(wwpn='10000090fa3870d7')
self.assertEqual(1, lsfabric.call_count)
get_host_from_host_info.assert_called_with(connector, False)
self.assertEqual(1, get_host_from_host_info.call_count)
lsvdishosmap.assert_called_with(vol)
self.assertEqual(1, lsvdishosmap.call_count)
lshost.assert_not_called()
@mock.patch.object(storwize_svc_common.StorwizeSSH, 'lsfabric')
@mock.patch.object(storwize_svc_common.StorwizeHelpers,
'get_host_from_host_info')
@mock.patch.object(storwize_svc_common.StorwizeSSH, 'lshost')
@mock.patch.object(storwize_svc_common.StorwizeSSH, 'lsvdiskhostmap')
def test_get_host_from_connector_wo_vol(self,
lsvdishosmap,
lshost,
lsfabric):
get_host_from_host_info):
vol = 'testvol'
connector = {"wwpns": ["10000090fa3870d7", "C050760825191B00"]}
lsfabric.return_value = [{"remote_wwpn": "10000090fa3870d7",
"name": "test_host"}]
get_host_from_host_info.return_value = "test_host", []
raw = "id!name!host_id!host_name!vdisk_UID\n2594!testvol!315!"\
"test_host!60050768028110A4700000000001168E"
ssh_cmd = ['svcinfo', 'lsvdiskhostmap', '-delim', '!', '"%s"' % vol]
@ -9870,8 +9880,8 @@ class StorwizeHelpersTestCase(test.TestCase):
True)
host = self.storwize_svc_common.get_host_from_connector(connector)
self.assertEqual(host, "test_host")
lsfabric.assert_called_with(wwpn='10000090fa3870d7')
self.assertEqual(1, lsfabric.call_count)
get_host_from_host_info.assert_called_with(connector, False)
self.assertEqual(1, get_host_from_host_info.call_count)
lsvdishosmap.assert_not_called()
self.assertEqual(0, lsvdishosmap.call_count)
lshost.assert_not_called()
@ -12896,11 +12906,14 @@ class StorwizeSVCReplicationTestCase(test.TestCase):
self.driver._sync_with_aux_grp(self.ctxt, rccg_name)
startrccg.assert_called_with(rccg_name, 'aux')
@mock.patch.object(storwize_svc_common.StorwizeHelpers,
'initialize_host_info')
@mock.patch.object(storwize_svc_common.StorwizeHelpers,
'get_host_from_connector')
@mock.patch.object(storwize_svc_common.StorwizeHelpers,
'check_vol_mapped_to_host')
def test_get_map_info_from_connector(self, is_mapped, get_host_from_conn):
def test_get_map_info_from_connector(self, is_mapped, get_host_from_conn,
initialize_host_info):
self.driver.configuration.set_override('replication_device',
[self.rep_target])
self.driver.do_setup(self.ctxt)
@ -12927,6 +12940,8 @@ class StorwizeSVCReplicationTestCase(test.TestCase):
backend_helper)
self.assertEqual(self.driver._master_state,
node_state)
initialize_host_info.assert_called()
self.assertEqual(1, initialize_host_info.call_count)
connector = {'host': 'storwize-svc-host',
'wwnns': ['20000090fa17311e', '20000090fa17311f'],

View File

@ -796,6 +796,7 @@ class StorwizeHelpers(object):
self.check_fcmapping_interval = 3
self.code_level = None
self.stats = {}
self.Host_connector_info = {"FC": {}, "ISCSI": {}}
@staticmethod
def handle_keyerror(cmd, out):
@ -1131,28 +1132,48 @@ class StorwizeHelpers(object):
wwpns.add(wwpn)
return list(wwpns)
def initialize_host_info(self):
"""Get the host,wwpn,iscsi and store in Host_connector_info."""
if (not self.Host_connector_info['FC'] and
not self.Host_connector_info['ISCSI']):
hosts_info = self.ssh.lshost()
host_list = list(hosts_info.select('name'))
for eachhost in host_list:
resp = self.ssh.lshost(host=eachhost)
if list(resp.select("WWPN")) != [None]:
for wwpn in resp.select('WWPN'):
if wwpn not in self.Host_connector_info['FC'].keys():
self.Host_connector_info['FC'][wwpn] = eachhost
elif list(resp.select('iscsi_name')) != [None]:
for iscsi_name in resp.select('iscsi_name'):
if (iscsi_name not in
self.Host_connector_info['ISCSI'].keys()):
self.Host_connector_info['ISCSI'][iscsi_name] = (
eachhost)
def get_host_from_host_info(self, connector, iscsi=False):
host_name = None
new_wwpn = []
if iscsi and 'initiator' in connector:
if connector['initiator'] in self.Host_connector_info['ISCSI']:
iqn = connector['initiator']
host_name = self.Host_connector_info['ISCSI'][iqn]
elif 'wwpns' in connector:
for wwpn in connector['wwpns']:
if wwpn.upper() in self.Host_connector_info['FC']:
host_name = self.Host_connector_info['FC'][wwpn.upper()]
else:
new_wwpn.append(['wwpn', '%s' % wwpn])
return host_name, new_wwpn
def get_host_from_connector(self, connector, volume_name=None,
iscsi=False):
"""Return the Storwize host described by the connector."""
LOG.debug('Enter: get_host_from_connector: %s.', connector)
# If we have FC information, we have a faster lookup option
host_name = None
if 'wwpns' in connector and not iscsi:
for wwpn in connector['wwpns']:
resp = self.ssh.lsfabric(wwpn=wwpn)
for wwpn_info in resp:
try:
if (wwpn_info['remote_wwpn'] and
wwpn_info['name'] and
wwpn_info['remote_wwpn'].lower() ==
wwpn.lower()):
host_name = wwpn_info['name']
break
except KeyError:
self.handle_keyerror('lsfabric', wwpn_info)
if host_name:
break
host_name, new_wwpn = self.get_host_from_host_info(connector, iscsi)
if host_name and volume_name:
hosts_map_info = self.ssh.lsvdiskhostmap(volume_name)
@ -1168,6 +1189,11 @@ class StorwizeHelpers(object):
host_name = None
if host_name:
for port in new_wwpn:
LOG.debug('update wwpn %(wwpn)s to host %(host)s.',
{'wwpn': port, 'host': host_name})
self.ssh.addhostport(host_name, port[0], port[1])
LOG.debug('Leave: get_host_from_connector: host %s.', host_name)
return host_name
@ -1298,6 +1324,13 @@ class StorwizeHelpers(object):
for port in ports:
self.ssh.addhostport(host_name, port[0], port[1])
if iscsi and 'initiator' in connector:
iqn = connector['initiator']
self.Host_connector_info['ISCSI'][iqn] = host_name
elif 'wwpns' in connector:
for wwpn in connector['wwpns']:
self.Host_connector_info['FC'][wwpn.upper()] = host_name
LOG.debug('Leave: create_host: host %(host)s - %(host_name)s.',
{'host': connector['host'], 'host_name': host_name})
return host_name
@ -1308,6 +1341,23 @@ class StorwizeHelpers(object):
def delete_host(self, host_name):
self.ssh.rmhost(host_name)
if host_name in self.Host_connector_info['ISCSI'].values():
host_iqn = None
for iqn, host in self.Host_connector_info['ISCSI'].items():
if host == host_name:
host_iqn = iqn
break
if host_iqn:
self.Host_connector_info['ISCSI'].pop(host_iqn)
elif host_name in self.Host_connector_info['FC'].values():
host_wwpn = []
for wwpn, host in self.Host_connector_info['FC'].items():
if host == host_name:
host_wwpn.append(wwpn)
for wwpn in host_wwpn:
self.Host_connector_info['FC'].pop(wwpn)
def _get_unused_lun_id(self, host_name):
luns_used = []
result_lun = '-1'
@ -4863,6 +4913,8 @@ class StorwizeSVCCommonDriver(san.SanDriver,
vol_name, backend_helper, node_state = self._get_vol_sys_info(
volume)
backend_helper.initialize_host_info()
info = {}
if 'host' in connector:
# get host according to FC protocol

View File

@ -172,6 +172,8 @@ class StorwizeSVCFCDriver(storwize_common.StorwizeSVCCommonDriver):
volume)
host_site = None
backend_helper.initialize_host_info()
is_hyper_volume = self.is_volume_hyperswap(volume)
if is_hyper_volume:
host_site = self._get_volume_host_site_from_conf(volume,
@ -183,12 +185,24 @@ class StorwizeSVCFCDriver(storwize_common.StorwizeSVCCommonDriver):
LOG.error(msg)
raise exception.VolumeDriverException(message=msg)
# Check if a host object is defined for this host name
host_name = backend_helper.get_host_from_connector(connector)
if host_name is None:
# Host does not exist - add a new host to Storwize/SVC
# Try creating the host, if host creation is successfull continue
# with intialization flow, else search for host object defined for
# this connector info.
host_name = None
try:
host_name = backend_helper.create_host(connector, site=host_site)
elif is_hyper_volume:
except exception.VolumeBackendAPIException as excp:
if "CMMVC6035E" in excp.msg:
msg = (_('Host already exists for connector '
'%(conn)s'), {'conn': connector})
LOG.info(msg)
host_name = backend_helper.get_host_from_connector(connector)
else:
msg = (_('Error creating host %(ex)s'), {'ex': excp.msg})
LOG.error(msg)
raise exception.VolumeDriverException(message=msg)
if is_hyper_volume:
self._update_host_site_for_hyperswap_volume(host_name, host_site)
volume_attributes = backend_helper.get_vdisk_attributes(volume_name)

View File

@ -166,6 +166,8 @@ class StorwizeSVCISCSIDriver(storwize_common.StorwizeSVCCommonDriver):
volume_name, backend_helper, node_state = self._get_vol_sys_info(
volume)
backend_helper.initialize_host_info()
host_site = self._get_volume_host_site_from_conf(volume,
connector,
iscsi=True)
@ -176,14 +178,26 @@ class StorwizeSVCISCSIDriver(storwize_common.StorwizeSVCCommonDriver):
LOG.error(msg)
raise exception.VolumeDriverException(message=msg)
# Check if a host object is defined for this host name
host_name = backend_helper.get_host_from_connector(connector,
iscsi=True)
if host_name is None:
# Host does not exist - add a new host to Storwize/SVC
# Try creating the host, if host creation is successfull continue
# with intialization flow, else search for host object defined for
# this connector info.
host_name = None
try:
host_name = backend_helper.create_host(connector, iscsi=True,
site=host_site)
elif is_hyper_volume:
except exception.VolumeBackendAPIException as excp:
if "CMMVC6578E" in excp.msg:
msg = (_('Host already exists for connector '
'%(conn)s'), {'conn': connector})
LOG.info(msg)
host_name = backend_helper.get_host_from_connector(connector,
iscsi=True)
else:
msg = (_('Error creating host %(ex)s'), {'ex': excp.msg})
LOG.error(msg)
raise exception.VolumeDriverException(message=msg)
if is_hyper_volume:
self._update_host_site_for_hyperswap_volume(host_name, host_site)
chap_secret = backend_helper.get_chap_secret_for_host(host_name)

View File

@ -0,0 +1,8 @@
---
fixes:
- |
IBM Spectrum Virtualize Family driver `Bug #1913363
<https://bugs.launchpad.net/cinder/+bug/1913363>`_: Fixed
issue in get_host_from_connector by caching the host
information during attach or detach operations and using
host details from cached information.