From: Avishay Traeger Date: Thu, 7 Mar 2013 17:18:54 +0000 (+0200) Subject: Do not use prefix to lookup host in Storwize/SVC. X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=e342ff4b509a4184bfa984b467e9cd79b53ed9af;p=openstack-build%2Fcinder-build.git Do not use prefix to lookup host in Storwize/SVC. Currently, the Storwize/SVC driver creates a host name prefix for host objects on the back-end, and uses that to look up hosts. However, if a host was already created with a different name (for example, manually by an admin), the host creation operation will fail, as a host with that connection information already exists. Instead, we look up a host based on available connection information. Fixes bug: 1149072 Change-Id: I336dbea85bfaf928a550a15d177e2b9b0ffd38bf --- diff --git a/cinder/tests/test_storwize_svc.py b/cinder/tests/test_storwize_svc.py index 96062e1c1..1d142d06f 100644 --- a/cinder/tests/test_storwize_svc.py +++ b/cinder/tests/test_storwize_svc.py @@ -213,6 +213,7 @@ class StorwizeSVCManagementSimulator: 'unit', 'easytier', 'warning', + 'wwpn', ] # Handle the special case of lsnode which is a two-word command @@ -474,14 +475,16 @@ class StorwizeSVCManagementSimulator: def _cmd_lsfabric(self, **kwargs): host_name = kwargs['host'] if 'host' in kwargs else None + target_wwpn = kwargs['wwpn'] if 'wwpn' in kwargs else None host_infos = [] for hk, hv in self._hosts_list.iteritems(): if not host_name or hv['host_name'] == host_name: for mk, mv in self._mappings_list.iteritems(): if mv['host'] == hv['host_name']: - host_infos.append(hv) - break + if not target_wwpn or target_wwpn in hv['wwpns']: + host_infos.append(hv) + break if not len(host_infos): return ('', '') diff --git a/cinder/volume/drivers/storwize_svc.py b/cinder/volume/drivers/storwize_svc.py index 8c43c0310..9dc542175 100644 --- a/cinder/volume/drivers/storwize_svc.py +++ b/cinder/volume/drivers/storwize_svc.py @@ -420,6 +420,57 @@ class StorwizeSVCDriver(san.SanISCSIDriver): host_name = str(host_name) return host_name[:55] + def _find_host_from_wwpn(self, connector): + for wwpn in connector['wwpns']: + ssh_cmd = 'lsfabric -wwpn %s -delim !' % wwpn + out, err = self._run_ssh(ssh_cmd) + host_lines = out.strip().split('\n') + + if len(host_lines) == 0: + # This WWPN is not in use + continue + + header = host_lines.pop(0).split('!') + self._assert_ssh_return('remote_wwpn' in header and + 'name' in header, + '_find_host_from_wwpn', + ssh_cmd, out, err) + rmt_wwpn_idx = header.index('remote_wwpn') + name_idx = header.index('name') + + wwpns = map(lambda x: x.split('!')[rmt_wwpn_idx], host_lines) + + if wwpn in wwpns: + # All the wwpns will be the mapping for the same + # host from this WWPN-based query. Just pick + # the name from first line. + hostname = host_lines[0].split('!')[name_idx] + return hostname + + # Didn't find a host + return None + + def _find_host_exhaustive(self, connector, hosts): + for host in hosts: + ssh_cmd = 'lshost -delim ! %s' % host + out, err = self._run_ssh(ssh_cmd) + self._assert_ssh_return(len(out.strip()), + '_find_host_exhaustive', + ssh_cmd, out, err) + for attr_line in out.split('\n'): + # If '!' not found, return the string and two empty strings + attr_name, foo, attr_val = attr_line.partition('!') + if (attr_name == 'iscsi_name' and + 'initiator' in connector and + attr_val == connector['initiator']): + return host + elif (attr_name == 'WWPN' and + 'wwpns' in connector and + attr_val.lower() in + map(str.lower, map(str, connector['wwpns']))): + return host + return None + def _get_host_from_connector(self, connector): """List the hosts defined in the storage. @@ -438,46 +489,24 @@ class StorwizeSVCDriver(san.SanISCSIDriver): if not len(out.strip()): return None - host_lines = out.strip().split('\n') - self._assert_ssh_return(len(host_lines), '_get_host_from_connector', - ssh_cmd, out, err) - header = host_lines.pop(0).split('!') - self._assert_ssh_return('name' in header, '_get_host_from_connector', - ssh_cmd, out, err) - name_index = header.index('name') - - hosts = map(lambda x: x.split('!')[name_index], host_lines) + # If we have FC information, we have a faster lookup option hostname = None + if 'wwpns' in connector: + hostname = self._find_host_from_wwpn(connector) - # For each host with the prefix, check connection details to verify - for host in hosts: - if not host.startswith(prefix): - continue - ssh_cmd = 'lshost -delim ! %s' % host - out, err = self._run_ssh(ssh_cmd) - self._assert_ssh_return(len(out.strip()), + # If we don't have a hostname yet, try the long way + if not hostname: + host_lines = out.strip().split('\n') + self._assert_ssh_return(len(host_lines), '_get_host_from_connector', ssh_cmd, out, err) - for attr_line in out.split('\n'): - # If '!' not found, return the string and two empty strings - attr_name, foo, attr_val = attr_line.partition('!') - found = False - if ('initiator' in connector and - attr_name == 'iscsi_name' and - attr_val == connector['initiator']): - found = True - elif ('wwpns' in connector and - attr_name == 'WWPN' and - attr_val.lower() in - map(str.lower, map(str, connector['wwpns']))): - found = True - - if found: - hostname = host - break - - if hostname is not None: - break + header = host_lines.pop(0).split('!') + self._assert_ssh_return('name' in header, + '_get_host_from_connector', + ssh_cmd, out, err) + name_index = header.index('name') + hosts = map(lambda x: x.split('!')[name_index], host_lines) + hostname = self._find_host_exhaustive(connector, hosts) LOG.debug(_('leave: _get_host_from_connector: host %s') % hostname)