summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2015-04-08 15:08:25 +0000
committerGerrit Code Review <review@openstack.org>2015-04-08 15:08:25 +0000
commitb3c2b0cc6d4748f08ae2814f634411f9dde1e06d (patch)
tree8410726783eed02a8cb10e893fce1474b2478e4e
parent420931abd5204627840f4117f305a9aec8848f7d (diff)
parente82b39baa4ef382415d54dc85b99fc2554ac56a7 (diff)
downloadnova-b3c2b0cc6d4748f08ae2814f634411f9dde1e06d.tar.gz
Merge "Fix multipath device discovery when UFN is enabled."
-rw-r--r--nova/storage/linuxscsi.py40
-rw-r--r--nova/tests/unit/test_linuxscsi.py57
2 files changed, 75 insertions, 22 deletions
diff --git a/nova/storage/linuxscsi.py b/nova/storage/linuxscsi.py
index ed30462ec0..285dda96f6 100644
--- a/nova/storage/linuxscsi.py
+++ b/nova/storage/linuxscsi.py
@@ -21,8 +21,13 @@ from nova.i18n import _LW
from nova.openstack.common import loopingcall
from nova import utils
+import os
+import re
+
LOG = logging.getLogger(__name__)
+MULTIPATH_WWID_REGEX = re.compile("\((?P<wwid>.+)\)")
+
def echo_scsi_command(path, content):
"""Used to echo strings to scsi subsystem."""
@@ -106,23 +111,29 @@ def find_multipath_device(device):
lines = out.strip()
lines = lines.split("\n")
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_id = info[0]
- mdev = '/dev/mapper/%s' % mdev_id
- elif info[2][:2] == "dm":
- mdev_id = info[1].replace('(', '')
- mdev_id = mdev_id.replace(')', '')
- mdev = '/dev/mapper/%s' % mdev_id
-
- if mdev is None:
- LOG.warning(_LW("Couldn't find multipath device %s"), 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 /dev/${path}`.
+ 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.warning(_LW("Couldn't find multipath device %s"), mdev)
return None
LOG.debug("Found multipath device = %s", mdev)
+
device_lines = lines[3:]
for dev_line in device_lines:
if dev_line.find("policy") != -1:
@@ -147,6 +158,7 @@ def find_multipath_device(device):
if mdev is not None:
info = {"device": mdev,
"id": mdev_id,
+ "name": mdev_name,
"devices": devices}
return info
return None
diff --git a/nova/tests/unit/test_linuxscsi.py b/nova/tests/unit/test_linuxscsi.py
index 45d6212a80..279b3c9a6a 100644
--- a/nova/tests/unit/test_linuxscsi.py
+++ b/nova/tests/unit/test_linuxscsi.py
@@ -20,6 +20,8 @@ from nova.storage import linuxscsi
from nova import test
from nova import utils
+import os
+
LOG = logging.getLogger(__name__)
CONF = cfg.CONF
@@ -29,16 +31,21 @@ class StorageLinuxSCSITestCase(test.NoDBTestCase):
def setUp(self):
super(StorageLinuxSCSITestCase, self).setUp()
self.executes = []
+ self.fake_stat_result = os.stat(__file__)
def fake_execute(*cmd, **kwargs):
self.executes.append(cmd)
return None, None
+ def fake_stat(path):
+ return self.fake_stat_result
+
self.stubs.Set(utils, 'execute', fake_execute)
+ self.stubs.Set(os, 'stat', fake_stat)
def test_find_multipath_device_3par(self):
def fake_execute(*cmd, **kwargs):
- out = ("mpath6 (350002ac20398383d) dm-3 3PARdata,VV\n"
+ out = ("350002ac20398383d dm-3 3PARdata,VV\n"
"size=2.0G features='0' hwhandler='0' wp=rw\n"
"`-+- policy='round-robin 0' prio=-1 status=active\n"
" |- 0:0:0:1 sde 8:64 active undef running\n"
@@ -46,12 +53,34 @@ class StorageLinuxSCSITestCase(test.NoDBTestCase):
)
return out, None
- def fake_execute2(*cmd, **kwargs):
- out = ("350002ac20398383d dm-3 3PARdata,VV\n"
+ self.stubs.Set(utils, 'execute', fake_execute)
+
+ info = linuxscsi.find_multipath_device('/dev/sde')
+ LOG.error("info = %s" % info)
+
+ self.assertEqual("350002ac20398383d", info["name"])
+ self.assertEqual("350002ac20398383d", info["id"])
+ self.assertEqual("/dev/mapper/350002ac20398383d", info["device"])
+
+ self.assertEqual("/dev/sde", info['devices'][0]['device'])
+ self.assertEqual("0", info['devices'][0]['host'])
+ self.assertEqual("0", info['devices'][0]['id'])
+ self.assertEqual("0", info['devices'][0]['channel'])
+ self.assertEqual("1", info['devices'][0]['lun'])
+
+ self.assertEqual("/dev/sdf", info['devices'][1]['device'])
+ self.assertEqual("2", info['devices'][1]['host'])
+ self.assertEqual("0", info['devices'][1]['id'])
+ self.assertEqual("0", info['devices'][1]['channel'])
+ self.assertEqual("1", info['devices'][1]['lun'])
+
+ 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"
"`-+- policy='round-robin 0' prio=-1 status=active\n"
- " |- 0:0:0:1 sde 8:64 active undef running\n"
- " `- 2:0:0:1 sdf 8:80 active undef running\n"
+ " |- 0:0:0:1 sde 8:64 active undef running\n"
+ " `- 2:0:0:1 sdf 8:80 active undef running\n"
)
return out, None
@@ -59,7 +88,11 @@ class StorageLinuxSCSITestCase(test.NoDBTestCase):
info = linuxscsi.find_multipath_device('/dev/sde')
LOG.error("info = %s" % info)
- self.assertEqual("/dev/mapper/350002ac20398383d", info["device"])
+
+ self.assertEqual("mpath6", info["name"])
+ self.assertEqual("350002ac20398383d", info["id"])
+ 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'])
@@ -90,8 +123,12 @@ class StorageLinuxSCSITestCase(test.NoDBTestCase):
info = linuxscsi.find_multipath_device('/dev/sde')
LOG.error("info = %s" % info)
+
+ self.assertEqual("36005076da00638089c000000000004d5", info["name"])
+ self.assertEqual("36005076da00638089c000000000004d5", info["id"])
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'])
@@ -110,8 +147,8 @@ class StorageLinuxSCSITestCase(test.NoDBTestCase):
"size=1.0G features='1 queue_if_no_path' hwhandler='0'"
" wp=rw\n"
"`-+- policy='round-robin 0' prio=-1 status=active\n"
- " |- 6:0:2:0 sdd 8:64 active undef running\n"
- " `- 6:1:0:3 sdc 8:32 active undef running\n"
+ " |- 6:0:2:0 sdd 8:64 active undef running\n"
+ " `- 6:1:0:3 sdc 8:32 active undef running\n"
)
return out, None
@@ -119,8 +156,12 @@ class StorageLinuxSCSITestCase(test.NoDBTestCase):
info = linuxscsi.find_multipath_device('/dev/sdd')
LOG.error("info = %s" % info)
+
+ self.assertEqual("36005076303ffc48e0000000000000101", info["name"])
+ self.assertEqual("36005076303ffc48e0000000000000101", info["id"])
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'])