]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Fix multipath device discovery when UFN is enabled.
authorLee Yarwood <lyarwood@redhat.com>
Thu, 2 Apr 2015 14:46:38 +0000 (15:46 +0100)
committerLee Yarwood <lyarwood@redhat.com>
Thu, 2 Apr 2015 15:39:57 +0000 (16:39 +0100)
This currently returns an invalid path of `/dev/mapper/${WWID}`
when UFN is enabled leading to failures later on when we attempt to
use the device.

The output of `multipath -l ${path}` or `multipath -l ${wwid}`
should always list the correct device identifier to use with this
path as the first word on the first line.

Closes-Bug: 1401799
Change-Id: Ib371b699fadcbbbb666e08eb0124c442e94a55e8

cinder/brick/initiator/linuxscsi.py
cinder/tests/brick/test_brick_linuxscsi.py

index aa1272c083ac960926fcbd78c3ed7d46ea37dcb5..f702df7d8ff5a627e903de5c57770336a7b23d38 100644 (file)
@@ -30,6 +30,7 @@ from cinder.openstack.common import loopingcall
 LOG = logging.getLogger(__name__)
 
 MULTIPATH_ERROR_REGEX = re.compile("\w{3} \d+ \d\d:\d\d:\d\d \|.*$")
+MULTIPATH_WWID_REGEX = re.compile("\((?P<wwid>.+)\)")
 
 
 class LinuxSCSI(executor.Executor):
@@ -182,21 +183,26 @@ class LinuxSCSI(executor.Executor):
             lines = [line for line in lines
                      if not re.match(MULTIPATH_ERROR_REGEX, line)]
             if lines:
-                line = lines[0]
-                info = line.split(" ")
-                # device line output is different depending
-                # on /etc/multipath.conf settings.
-                if info[1][:2] == "dm":
-                    mdev = "/dev/%s" % info[1]
-                    mdev_id = info[0]
-                elif info[2][:2] == "dm":
-                    mdev = "/dev/%s" % info[2]
-                    mdev_id = info[1].replace('(', '')
-                    mdev_id = mdev_id.replace(')', '')
-
-                if mdev is None:
-                    LOG.warn(_LW("Couldn't find multipath device %(line)s")
-                             % {'line': line})
+
+                # Use the device name, be it the WWID, mpathN or custom alias
+                # of a device to build the device path. This should be the
+                # first item on the first line of output from `multipath -l
+                # ${path}` or `multipath -l ${wwid}`..
+                mdev_name = lines[0].split(" ")[0]
+                mdev = '/dev/mapper/%s' % mdev_name
+
+                # Find the WWID for the LUN if we are using mpathN or aliases.
+                wwid_search = MULTIPATH_WWID_REGEX.search(lines[0])
+                if wwid_search is not None:
+                    mdev_id = wwid_search.group('wwid')
+                else:
+                    mdev_id = mdev_name
+
+                # Confirm that the device is present.
+                try:
+                    os.stat(mdev)
+                except OSError:
+                    LOG.warn(_LW("Couldn't find multipath device %s"), mdev)
                     return None
 
                 LOG.debug("Found multipath device = %(mdev)s"
@@ -220,6 +226,7 @@ class LinuxSCSI(executor.Executor):
         if mdev is not None:
             info = {"device": mdev,
                     "id": mdev_id,
+                    "name": mdev_name,
                     "devices": devices}
             return info
         return None
index cac64b2e84cdf6d2cd6d95734a166a3e1c4e70dc..0b3e35baccb7b95c745fc39e722ccfd6144ba898 100644 (file)
@@ -12,6 +12,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import os
 import os.path
 import string
 
@@ -30,11 +31,15 @@ class LinuxSCSITestCase(test.TestCase):
         self.cmds = []
         self.stubs.Set(os.path, 'realpath', lambda x: '/dev/sdc')
         self.linuxscsi = linuxscsi.LinuxSCSI(None, execute=self.fake_execute)
+        self.fake_stat_result = os.stat(__file__)
 
     def fake_execute(self, *cmd, **kwargs):
         self.cmds.append(string.join(cmd))
         return "", None
 
+    def fake_stat(self, path):
+        return self.fake_stat_result
+
     def test_echo_scsi_command(self):
         self.linuxscsi.echo_scsi_command("/some/path", "1")
         expected_commands = ['tee -a /some/path']
@@ -110,7 +115,7 @@ class LinuxSCSITestCase(test.TestCase):
             ('multipath -f 350002ac20398383d'), ]
         self.assertEqual(expected_commands, self.cmds)
 
-    def test_find_multipath_device_3par(self):
+    def test_find_multipath_device_3par_ufn(self):
         def fake_execute(*cmd, **kwargs):
             out = ("mpath6 (350002ac20398383d) dm-3 3PARdata,VV\n"
                    "size=2.0G features='0' hwhandler='0' wp=rw\n"
@@ -121,10 +126,15 @@ class LinuxSCSITestCase(test.TestCase):
             return out, None
 
         self.stubs.Set(self.linuxscsi, '_execute', fake_execute)
+        self.stubs.SmartSet(os, 'stat', self.fake_stat)
 
         info = self.linuxscsi.find_multipath_device('/dev/sde')
         LOG.error("info = %s" % info)
-        self.assertEqual("/dev/dm-3", info["device"])
+
+        self.assertEqual("350002ac20398383d", info['id'])
+        self.assertEqual("mpath6", info['name'])
+        self.assertEqual("/dev/mapper/mpath6", info['device'])
+
         self.assertEqual("/dev/sde", info['devices'][0]['device'])
         self.assertEqual("0", info['devices'][0]['host'])
         self.assertEqual("0", info['devices'][0]['id'])
@@ -152,10 +162,16 @@ class LinuxSCSITestCase(test.TestCase):
             return out, None
 
         self.stubs.Set(self.linuxscsi, '_execute', fake_execute)
+        self.stubs.SmartSet(os, 'stat', self.fake_stat)
 
         info = self.linuxscsi.find_multipath_device('/dev/sde')
         LOG.error("info = %s" % info)
-        self.assertEqual("/dev/dm-2", info["device"])
+
+        self.assertEqual("36005076da00638089c000000000004d5", info["id"])
+        self.assertEqual("36005076da00638089c000000000004d5", info["name"])
+        self.assertEqual("/dev/mapper/36005076da00638089c000000000004d5",
+                         info["device"])
+
         self.assertEqual("/dev/sde", info['devices'][0]['device'])
         self.assertEqual("6", info['devices'][0]['host'])
         self.assertEqual("0", info['devices'][0]['channel'])
@@ -180,10 +196,16 @@ class LinuxSCSITestCase(test.TestCase):
             return out, None
 
         self.stubs.Set(self.linuxscsi, '_execute', fake_execute)
+        self.stubs.SmartSet(os, 'stat', self.fake_stat)
 
         info = self.linuxscsi.find_multipath_device('/dev/sdd')
         LOG.error("info = %s" % info)
-        self.assertEqual("/dev/dm-2", info["device"])
+
+        self.assertEqual("36005076303ffc48e0000000000000101", info["id"])
+        self.assertEqual("36005076303ffc48e0000000000000101", info["name"])
+        self.assertEqual("/dev/mapper/36005076303ffc48e0000000000000101",
+                         info["device"])
+
         self.assertEqual("/dev/sdd", info['devices'][0]['device'])
         self.assertEqual("6", info['devices'][0]['host'])
         self.assertEqual("0", info['devices'][0]['channel'])
@@ -209,10 +231,16 @@ class LinuxSCSITestCase(test.TestCase):
             return out, None
 
         self.stubs.Set(self.linuxscsi, '_execute', fake_execute)
+        self.stubs.SmartSet(os, 'stat', self.fake_stat)
 
         info = self.linuxscsi.find_multipath_device('/dev/sdd')
         LOG.error("info = %s" % info)
-        self.assertEqual("/dev/dm-2", info["device"])
+
+        self.assertEqual("36005076303ffc48e0000000000000101", info["id"])
+        self.assertEqual("36005076303ffc48e0000000000000101", info["name"])
+        self.assertEqual("/dev/mapper/36005076303ffc48e0000000000000101",
+                         info["device"])
+
         self.assertEqual("/dev/sdd", info['devices'][0]['device'])
         self.assertEqual("6", info['devices'][0]['host'])
         self.assertEqual("0", info['devices'][0]['channel'])