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):
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"
if mdev is not None:
info = {"device": mdev,
"id": mdev_id,
+ "name": mdev_name,
"devices": devices}
return info
return None
# License for the specific language governing permissions and limitations
# under the License.
+import os
import os.path
import string
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']
('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"
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'])
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'])
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'])
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'])