Personal tools
You are here: Home Documentation files mpath2multipath
Document Actions

mpath2multipath

Automatically give names to mpaths.

Click here to get the file

Size 6.8 kB - File type text/python-source

File contents

#!/usr/bin/python

"""mpath2multipath [wwwn=Alias]* [DefaultAlias]
  This program generates an output to be passed to the multipath configuration file.
  Every storagesystem gets an Alias in the following order.
  If an alias is found for the wwwn of the storagesystem it is taken.
  If there is no alias found for the wwwn the DefaultAlias is used.
  If no default alias is given the wwwn is the alias.
"""

__version__="$Revision: 1.2 $"

# $Id: mpath2multipath.py,v 1.2 2008/03/19 13:49:59 marc Exp $

import re
import popen2
import sys
import os.path
import commands

class DiskDescriptor(object):
    def getDescriptor(self, **kwds):
        return 0
    
class _DefaultDiskDescriptor(DiskDescriptor):
    def getDescriptor(self, **kwds):
        return int(kwds["lun"])
DefaultDiskDescriptor=_DefaultDiskDescriptor()

class _XPDiskDescriptor(DiskDescriptor):
    SCSI_INFO_CMD="scsi_info"
    DESC_DIGITS=-5
    DESC_KEY="LUN"
    def getDescriptor(self, **kwds):
        if kwds.has_key("digits"):
            self.DESC_DIGITS=-kwds["digits"]
        __cmd="%s %s" %(self.SCSI_INFO_CMD,kwds["device"])
        (_rc, output)=commands.getstatusoutput(__cmd)
        if _rc >> 8 != 0:
            raise OSError(_rc >> 8, output)
        _pairs=output.split(":")
        _descriptors=dict()
#        print _pairs
        for _pair in _pairs:
            if _pair.find("=")<1:
                pass
#            print _pair
            (_key, _value)=_pair.split("=")
            _descriptors[_key]=_value[1:-1]
        # last 4 digits
        return int(_descriptors[self.DESC_KEY][self.DESC_DIGITS:], 16)
XPDiskDescriptor=_XPDiskDescriptor()
        

def getWWWN(scsi_hostid, scsi_busid, scsi_id):
#    print "%s, %s, %s" %(scsi_hostid, scsi_busid, scsi_id)
    filename="/sys/class/fc_transport/target%s:%s:%s/node_name" %(scsi_hostid, scsi_busid, scsi_id)
    if not os.path.exists(filename):
        return ""
    nodenamef=open(filename, "r")
    nodename=nodenamef.readlines()[0]
    nodename=nodename[2:-1]
    nodenamef.close()
    return nodename

def printMultipathConf(scsi_devs, padding=3):
    _wwwns=scsi_devs.keys()
    _wwwns.sort()
    for wwwn in _wwwns:
        _luns=scsi_devs[wwwn].keys()
        _luns.sort(lambda x, y: int(x)-int(y))
        for lun in _luns:
            format="""multipath {
   wwid %s
   alias %s_%0"""+str(padding)+"""u
}"""
            print format %(scsi_devs[wwwn][lun], wwwn, lun)

def main():
    from optparse import OptionParser
    parser = OptionParser(description=__doc__, version=__version__)
    parser.add_option("-X", "--xp",             dest="xp",      default=False,     action="store_true",   help="Behave as all attached devices are HP XPs.")
    parser.add_option("-F", "--full",           dest="full",    default=False,     action="store_true",   help="Reformat all multipath devices independent on name.")
    parser.add_option("-W", "--xpwwwn",         dest="xpwwwn",                     action="append", type="string", help="Define the wwns to be handled as HP XP. Implies --xp.")
    parser.add_option(""  , "--infile",         dest="infile",  default="",        action="store",  type="string", help="Instead of executing multipath use this file as input")
    parser.add_option("-P", "--padding",        dest="padding", default=3,         action="store",  type="int",    help="Padding for the lower part of the description. Defaults to 3 digits.")
    parser.add_option("",   "--devname",        dest="devname", default="mpath\d+",action="store",  type="string", help="Device regular expression to match. Defaults to mpath")
    (options, args) = parser.parse_args()
    
    DEFAULT_KEY="__DEFAULT__"
    scsi_devs=dict()

    mappings=dict()
    for arg in args:
        if arg.find("=")>0:
           (key, value)=arg.split("=")
        else:
           value=arg
           key=DEFAULT_KEY
        mappings[key]=value
        if arg=='-h' or arg=='--help':
           usage(sys.argv[0])
           sys.exit(0)
    
    descriptors=dict()
    if options.full:
        options.devname="\S+"
    if options.xp and not options.xpwwwn:
        descriptors[DEFAULT_KEY]=XPDiskDescriptor
    elif options.xpwwwn:
        for _xpwwwn in options.xpwwwn:
            descriptors[_xpwwwn]=XPDiskDescriptor
    else:
        descriptors[DEFAULT_KEY]=DefaultDiskDescriptor

    if options.infile:
        _lines=open(options.infile)
    else:
        __cmd="multipath -l"
        child=popen2.Popen3(__cmd, False)
        _lines=child.fromchild.readlines()
#    __rc=child.wait()
#    if __rc==0:
    id=None
    for line in _lines:
        regexp=re.match("^(?P<device>%s)\s+\((?P<uid>[0-9a-fA-F]+)\)" %options.devname, line)
        if regexp:
            id=regexp.group("uid")
            device=regexp.group("device")
#            print id
#            print device
        if not regexp:
            regexp=re.match("^(?P<device>\S+)\s+\((?P<uid>[0-9a-fA-F]+)\)", line)
            if regexp:
                id=None
        regexp=re.match("^.+([0-9]+):([0-9]+):([0-9]+):([0-9]+)", line)
        if id and regexp:
#            print id, regexp
            (scsi_hostid, scsi_busid, scsi_id, scsi_lun)=regexp.groups()
            wwwn=getWWWN(scsi_hostid, scsi_busid, scsi_id)
#            print wwwn
            if mappings.has_key(wwwn):
                key=mappings[wwwn]
            elif mappings.has_key(DEFAULT_KEY):
                key=mappings[DEFAULT_KEY]
            else:
                key=wwwn
            if descriptors.has_key(wwwn):
                descriptor=descriptors[wwwn]
            elif descriptors.has_key(DEFAULT_KEY):
                descriptor=descriptors[DEFAULT_KEY]
            else:
                descriptor=DefaultDiskDescriptor
            if not scsi_devs.has_key(key):
                    scsi_devs[key]=dict()
            disk_descriptor=descriptor.getDescriptor(wwwn=wwwn, lun=scsi_lun, id=scsi_id, uid=id, device=os.path.join("/dev/mapper", device), digits=options.padding)
            scsi_devs[key][disk_descriptor]=id

    printMultipathConf(scsi_devs, options.padding)

if __name__ == "__main__":
    main()

#/^mpath.*/ {
#  match($2, /\((.*)\)/, _id)
#  mpath=$1; id=_id[1];
#  scsi_hostid=[]
#  scsi_busid=[]
#  scsi_id=[]
#  scsi_lun=[]
#}
#/[0-9]+:[0-9]+:[0-9]+:[0-9]+/ {
#  match($2, /([0-9]+):([0-9]+):([0-9]+):([0-9]+)/, scsi_addr);
#  scsi_hostid=(scsi_hostid<scsi_addr[1])?scsi_addr[1]:scsi_hostid
#  scsi_busid=(scsi_busid<scsi_addr[2])?scsi_addr[2]:scsi_busid
#  scsi_id=(scsi_id<scsi_addr[3])?scsi_addr[3]:scsi_id
#  scsi_lun=(scsi_lun<scsi_addr[4])?scsi_addr[4]:scsi_lun
#}
#$0=="" && scsi_hostid >=0 && scsi_busid >= 0 && scsi_id >= 0 && scsi_lun >= 0 {
#  print "multipath {"
#  print "  wwid "id
#  print "  alias "storagename"_"scsi_lun
#  print "}"
################
# $Log: mpath2multipath.py,v $
# Revision 1.2  2008/03/19 13:49:59  marc
# - added xp compatibility mode
# - more configurable
#
# Revision 1.1  2007/09/17 11:38:04  marc
# - new release 0.1-9
#

Powered by Plone CMS, the Open Source Content Management System

This site conforms to the following standards: