Whamcloud - gitweb
- auto-naming is now smarter
authorrread <rread>
Tue, 6 Aug 2002 07:55:06 +0000 (07:55 +0000)
committerrread <rread>
Tue, 6 Aug 2002 07:55:06 +0000 (07:55 +0000)
- most basic features implemented, except for profile

lustre/utils/lmc

index 7e251db..d088153 100755 (executable)
 #   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 #
 
-# lmc - lustre configurtion data  manager
-#
-import sys, getopt
+"""
+lmc - lustre configurtion data  manager
+
+ Basic plan for lmc usage:
+  lmc --output config.xml --node nodename nid nettype [port=2346]
+  lmc --merge config.xml  --lov lovname stripsize stripeoffset
+  lmc --merge config.xml  --ost /dev/name nodename lovname [size=9999]
+  lmc --merge config.xml  --mtpt /mnt/lustre lovname nodename
+"""
+
+import sys, getopt, string
 import xml.dom.minidom
 from xml.dom.ext import PrettyPrint
+from xml.xpath import Evaluate
 
+DEFAULT_PORT = 888 # XXX What is the right default acceptor port to use?
 
 def usage():
-    print """usage: lmc [--ost | --mtpt | --lov] cmd args
+    print """usage: lmc [--node --ost | --mtpt | --lov] args
 Commands:
---ost "device" "host" [size]
+--node node_name hostname nettype [port]
+   Node_name is used to refer to this node during the configure process.
+   Nettype is either tcp, elan, or gm.
+
+--lov lov_name mdc_name stripe_sz stripe_off pattern
+   Creates a logical volume 
+
+--mds node_name device [size]
+
+--ost device node_name lov_name [size]
    Creates an OBD/OST/OSC configuration triplet for a new device.
    When used on "host", the device will be initialized and the OST
    will be enabled. On client nodes, the OSC will be avaiable.
+   If lov_name is used, this device is added to lov. 
 
---osc "device" "host" [lov_name]
-   Create an osc, and optionally add it to an lov.
-
---mtpt "mds" "ost/lov-name" /mnt/point
+--mtpt node_name mds_name lov_name /mnt/point
    Creates a client mount point.
 
---lov lov_name mdc_name stripe_sz stripe_off pattern
-   Produces a logical volum striped over the OSTs found in all-ost.xml.
-
 Options:
 --merge="xml file"  Add the new objects to an existing file
 --format            Format the partitions if unformated
 --reformat          Reformat partitions (this should be an lconf arg,
                     I think)
-(SCRIPT STILL UNDER DEVELOPMENT, MOST COMMANDS/OPTIONS UNIMPLEMENTED)
-"""  
+"""
+    sys.exit(1)
 
+def error(*args):
+    msg = string.join(map(str,args))
+    print msg
+    sys.exit(1)
+    
 #
 # manage names and uuids
 # need to initialize this by walking tree to ensure
 # no duplicate names or uuids are created.
 # this are just place holders for now.
 # consider changing this to be like OBD-dev-host
-name_ctr = 1
 def new_name(base):
-    global name_ctr
-    name = "%s_%d" % (base, name_ctr)
-    name_ctr += 1
-    return name
+    ctr = 2
+    ret = base
+    while names.has_key(ret):
+        ret = "%s_%d" % (base, ctr)
+        ctr = 1 + ctr
+    names[ret] = 1
+    return ret
 
 def get_uuid(name):
     return "%s_UUID" % (name)
@@ -72,6 +93,15 @@ def new_lustre(dom):
     str = """<lustre> </lustre>"""
     return dom.parseString(str)
 
+names = {}
+uuids = {}
+def init_names(lustre):
+    """initialize auto-name generation tables"""
+    global names, uuids
+    # get all elements that contain a name attribute
+    for n in Evaluate("//@name/..", lustre):
+        names[n.getAttribute("name")] = 1
+        uuids[n.getAttribute("uuid")] = 1
 
 class GenConfig:
     doc = None
@@ -106,7 +136,7 @@ class GenConfig:
         node.appendChild(new)
         return new
 
-    def network(self, name, uuid, net, hostname, port=0):
+    def network(self, name, uuid, hostname, net, port=0):
         """create <network> node"""
         network = self.newService("network", name, uuid)
         network.setAttribute("type", net);
@@ -120,7 +150,7 @@ class GenConfig:
         node = self.newService("node", name, uuid)
         return node
 
-    def obd(self, name, uuid, fs, devname, format, dev_size=0, dev_file=""):
+    def obd(self, name, uuid, fs, devname, format, dev_size=0):
         obd = self.newService("obd", name, uuid)
         obd.setAttribute('type', 'obdfilter')
         self.addElement(obd, "fstype", fs)
@@ -132,7 +162,7 @@ class GenConfig:
 
     def osc(self, name, uuid, obd_uuid, net_uuid):
         osc = self.newService("osc", name, uuid)
-        osc.appendChild(self.ref("network", net_uuid))
+        osc.appendChild(self.ref("ost", net_uuid))
         osc.appendChild(self.ref("obd", obd_uuid))
         return osc
 
@@ -142,51 +172,220 @@ class GenConfig:
         ost.appendChild(self.ref("obd", obd_uuid))
         return ost
 
+    def lov(self, name, uuid, stripe_sz, stripe_off, pattern):
+        lov = self.newService("lov", name, uuid)
+        devs = self.addElement(lov, "devices" )
+        devs.setAttribute("stripesize", stripe_sz)
+        devs.setAttribute("stripeoffset", stripe_off)
+        devs.setAttribute("pattern", pattern)
+        return lov
+
+    def mds(self, name, uuid, fs, devname, format, net_uuid, failover_uuid = "", dev_size=0 ):
+        mds = self.newService("mds", name, uuid)
+        self.addElement(mds, "fstype", fs)
+        dev = self.addElement(mds, "device", devname)
+        if dev_size:
+            dev.setAttribute("size", "%s" % (dev_size))
+        self.addElement(mds, "autoformat", format)
+        mds.appendChild(self.ref("network", net_uuid))
+        if failover_uuid:
+            mds.appendChild(self.ref("failover", failover_uuid))
+        return mds
+
+    def mdc(self, name, uuid, mds_uuid):
+        mdc = self.newService("mdc", name, uuid)
+        mdc.appendChild(self.ref("mds", mds_uuid))
+        return mdc
+
+    def mountpoint(self, name, uuid, mdc_uuid, osc_uuid, path):
+        mtpt = self.newService("mtpt", name, uuid)
+        mtpt.appendChild(self.ref("mdc", mdc_uuid))
+        mtpt.appendChild(self.ref("osc", osc_uuid))
+        self.addElement(mtpt, "path", path)
+        return mtpt
+
+def findByName(lustre, name, tag = "*"):
+    path = '//%s[@name="%s"]' % (tag, name)
+    ret = Evaluate(path, lustre)
+    if ret:
+        return ret[0]
+    return None
+    
+# XXX: assumes only one network element per node. will fix this
+# as soon as support for routers is added
+def get_net_uuid(lustre, node_name):
+    """ get a network uuid for a node_name """
+    node = findByName(lustre, node_name, "node")
+    if not node:
+        error ("node not found:", node_name)
+    net = Evaluate("./network", node)
+    if net:
+        return net[0].getAttribute("uuid")
+    return None
+
+def lov_add_osc(gen, lov, osc_uuid):
+    devs = Evaluate("devices", lov)
+    if len(devs) == 1:
+        devs[0].appendChild(gen.ref("osc", osc_uuid))
+    else:
+        error("No devices element found for LOV:", lov)
+                            
+    
 #
 # Create a new obd, osc, and ost. Add them to the DOM.
 #
-def add_OST(doc, options, args):
-    # XXX need some error checking
-    gen = GenConfig(doc)
+def add_ost(gen, lustre, options, args):
+    if len(args) < 3:
+        usage()
+
     devname = args[0]
-    host = args[1]
-    if len(args) > 2:
-        size = args[2]
+    node_name = args[1]
+    lovname = args[2]
+    if len(args) > 3:
+        size = args[3]
     else:
         size = 0
 
-    lustre = doc.getElementsByTagName("lustre")[0]
-
-    obdname = new_name("obd")
-    oscname = new_name("osc")
-    ostname = new_name("ost")
-    node_uuid = get_uuid(host)
-    net_uuid = get_uuid("net")
+    obdname = new_name(node_name+"_" + "obd")
+    oscname = new_name(node_name+"_"+"osc")
+    ostname = new_name(node_name+"_"+"ost")
     obd_uuid = get_uuid(obdname)
     ost_uuid = get_uuid(ostname)
     osc_uuid = get_uuid(oscname)
 
-    node = gen.node(host, node_uuid)
-    node.appendChild(gen.network(host, net_uuid, "tcp", host, port=2436))
+    net_uuid = get_net_uuid(lustre, node_name)
+    if not net_uuid:
+        error("NODE: ", node_name, "not found")
+    
+    lov = findByName(lustre, lovname, "lov")
+    if not lov:
+        error("LOV:", lovname, "not found.")
+
     obd = gen.obd(obdname, obd_uuid,  "extN", devname, "no", size)
     ost = gen.ost(ostname, ost_uuid, obd_uuid, net_uuid)
-    osc = gen.osc(oscname, osc_uuid, obd_uuid, net_uuid)
+    osc = gen.osc(oscname, osc_uuid, obd_uuid, ost_uuid)
     
-    lustre.appendChild(node)
+    lov_add_osc(gen, lov, osc_uuid)
     lustre.appendChild(obd)
     lustre.appendChild(osc)
     lustre.appendChild(ost)
                    
+def add_node(gen, lustre, options, args):
+    """ create a node with a network config """
+    if len(args) < 3:
+        usage()
+
+    name = args[0]
+    nid = args[1]
+    nettype = args[2]
+
+    if nettype == 'tcp':
+        if len(args) > 3:
+            port = int(args[3])
+        else:
+            port = DEFAULT_PORT
+        
+    elif nettype in ('elan', 'gm'):
+        port = 0
+    else:
+        print "Unknown nettype: ", nettype
+        sys.exit(2)
+
+    uuid = get_uuid(name)
+    node = gen.node(name, uuid)
+    net_name = name+"_net"
+    net_uuid = get_uuid(net_name)
+    node.appendChild(gen.network(net_name, net_uuid, nid, nettype, port))
+    lustre.appendChild(node)
+
+
+def add_lov(gen, lustre, options, args):
+    """ create a lov """
+    if len(args) < 4:
+        usage()
+
+    name = args[0]
+    stripe_sz = args[1]
+    stripe_off = args[2]
+    pattern = args[3]
+
+    ret = findByName(lustre, name, "lov")
+    if ret:
+        error("LOV: ", name, " already exists.")
+
+    uuid = get_uuid(name)
+    lov = gen.lov(name,uuid,stripe_sz, stripe_off, pattern)
+    lustre.appendChild(lov)
+
+def add_mtpt(gen, lustre, options, args):
+    """ create mtpt on a node """
+    if len(args) < 4:
+        usage()
+
+    node_name = args[0]
+    mdc_name = args[1]
+    lov_name = args[2]
+    path = args[3]
+
+    name = new_name(node_name + "_mtpt")
+
+    ret = findByName(lustre, name, "mountpoint")
+    if ret:
+        error("MOUNTPOINT: ", name, " already exists.")
+
+    ret = findByName(lustre, lov_name, "lov")
+    if not ret:
+        error("LOV: ", lov_name, " not found.")
+    lov_uuid = ret.getAttribute("uuid")
+
+    ret = findByName(lustre, mdc_name, "mdc")
+    if not ret:
+        error("MDC: ", mdc_name, " not found.")
+    mdc_uuid = ret.getAttribute("uuid")
+
+    uuid = get_uuid(name)
+    mtpt = gen.mountpoint(name, uuid, mdc_uuid, lov_uuid, path)
+    lustre.appendChild(mtpt)
+
+
+def add_mds(gen, lustre, options, args):
+    if len(args) < 3:
+        usage()
+
+    node_name = args[0]
+    devname = args[1]
+    if len(args) > 3:
+        size = args[3]
+    else:
+        size = 0
+
+    ret = findByName(lustre, node_name, "node")
+
+    mds_name = new_name(node_name+"_" + "mds")
+    mdc_name = new_name(node_name+"_"+"mdc")
+    mds_uuid = get_uuid(mds_name)
+    mdc_uuid = get_uuid(mdc_name)
+
+    net_uuid = get_net_uuid(lustre, node_name)
+    if not net_uuid:
+        error("NODE: ", node_name, "not found")
+
+
+    mds = gen.mds(mds_name, mds_uuid, "extN", devname, "no", net_uuid)
+    mdc = gen.mdc(mdc_name, mdc_uuid, mds_uuid)
+    lustre.appendChild(mds)
+    lustre.appendChild(mdc)
+                   
 
 #
 # Command line processing
 #
 
 def parse_cmdline(argv):
-    short_opts = "ho:"
-    long_opts = ["ost", "mtpt", "lov",
+    short_opts = "ho:i:"
+    long_opts = ["ost", "mtpt", "lov", "node", "mds",
                  "merge=", "format", "reformat", "output=",
-                 "help"]
+                 "in=", "help"]
     opts = []
     args = []
     options = {}
@@ -195,22 +394,30 @@ def parse_cmdline(argv):
     except getopt.GetoptError:
         print "invalid opt"
         usage()
-        sys.exit(2)
 
     for o, a in opts:
         if o in ("-h", "--help"):
             usage()
-            sys.exit()
         if o in ("-o", "--output"):
             options['output'] = a
         if o == "--ost":
             options['ost'] = 1
+        if o == "--mds":
+            options['mds'] = 1
+        if o == "--node":
+            options['node'] = 1
+        if o == "--lov":
+            options['lov'] = 1
+        if o == "--mtpt":
+            options['mtpt'] = 1
         if o == "--merge":
             options['merge'] = a
         if o == "--format":
             options['format'] = 1
         if o  == "--reformat":
             options['reformat'] = 1
+        if o  in ("--in" , "-i"):
+            options['in'] = a
             
     return options, args
 
@@ -221,22 +428,35 @@ def main():
     if options.has_key('merge'):
         outFile = options['merge']
         doc = xml.dom.minidom.parse(outFile)
+    elif options.has_key('in'):
+        doc = xml.dom.minidom.parse(options['in'])
     else:
         doc = new_lustre(xml.dom.minidom)
 
     if options.has_key('output'):
         outFile = options['output']
 
+    lustre = doc.documentElement
+    init_names(lustre)
+    lustre = doc.documentElement
+    if lustre.tagName != "lustre":
+        print "Existing config not valid."
+        sys.exit(1)
+
+    gen = GenConfig(doc)
     if options.has_key('ost'):
-        add_OST(doc, options, args)
+        add_ost(gen, lustre, options, args)
+    elif options.has_key('node'):
+        add_node(gen, lustre, options, args)
     elif options.has_key('mtpt'):
-        print "--mtpt not implemented"
+        add_mtpt(gen, lustre, options, args)
     elif options.has_key('lov'):
-        print "--lov not implemented"
+        add_lov(gen, lustre, options, args)
+    elif options.has_key('mds'):
+        add_mds(gen, lustre, options, args)
     else:
         print "Missing command"
         usage()
-        sys.exit(1)
 
     if outFile == '-':
         PrettyPrint(doc)