]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Do not use prefix to lookup host in Storwize/SVC.
authorAvishay Traeger <avishay@il.ibm.com>
Thu, 7 Mar 2013 17:18:54 +0000 (19:18 +0200)
committerAvishay Traeger <avishay@il.ibm.com>
Mon, 11 Mar 2013 09:09:41 +0000 (11:09 +0200)
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

cinder/tests/test_storwize_svc.py
cinder/volume/drivers/storwize_svc.py

index 96062e1c1875f7c8e1187b1d64ae1c6ffcd9c347..1d142d06f143c0c77d6e18786a161b4249802c9b 100644 (file)
@@ -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 ('', '')
index 8c43c0310c814bf28b5a55bf70b090f20d1ddb37..9dc5421754a0808b84edc43a2c0a925c0a7c8ffa 100644 (file)
@@ -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)