Whamcloud - gitweb
* New LMC Interface
[fs/lustre-release.git] / lustre / utils / lmc
index 3d7c7bf..b4f92ea 100755 (executable)
 
 """
 lmc - lustre configurtion data  manager
- Basic plan for lmc usage:
-# create nodes
-./lmc --output config.xml --node server --net server1 tcp 
-./lmc --merge config.xml  --node client --net client1 tcp
-./lmc --merge config.xml  --node client --route gw lo [hi]
-./lmc --merge config.xml --router --node gw1 --net gw1 tcp
-./lmc --merge config.xml --node gw1 --net 1 elan
 
-./lmc --merge config.xml --route elan 1 1 100
-./lmc --merge config.xml --route tcp gw1 ba1
-
-
-
-# configure server
-./lmc --merge config.xml  --node server --mds mds1 /tmp/mds1 50000
-
-# create lov
-./lmc --merge config.xml  --lov lov1 mds1 65536 0 0
-./lmc --merge config.xml  --node server --lov lov1 --ost /tmp/ost1 100000
-./lmc --merge config.xml  --node server --lov lov1 --ost /tmp/ost2 100000
-
-# create client config
-./lmc --merge config.xml  --node client --mtpt /mnt/lustre mds1 lov1
+  See lustre book for documentation for lmc.
 
 """
 
-import sys, os, getopt, string
+import sys, os, getopt, string, exceptions
 import xml.dom.minidom
 from xml.dom.ext import PrettyPrint
 
-
-DEFAULT_PORT = 988 # XXX What is the right default acceptor port to use?
+DEFAULT_PORT = 988 
 
 def usage():
-    print """usage: lmc [--node --ost | --mtpt | --lov] args
-Commands:
---node node_name 
-   Node_name by itself it will create a new node. If the --router
-   option is used when creating a new node, then that node will also
-   be configured as a router. When used with other commands it
-   specifies the node to modify.
-
---net hostname nettype [port, recv_buf, send_buf]
-   Nettype is either tcp, toe, elan, or gm.
-   Requires --node
-
---route net gw lo [hi]
-   This command is used to create  routes.  NET is the
-   network type this route will be used on.  The GW is an address of
-   one of the local interfaces. LO and HI represent a range of
-   addresses that can be reached through the gateway. If HI is not
-   set, then a route to the specific host in LO is created.
-
---mds device [size]
-   Create a MDS using the device
-   Requires --node 
-
---lov lov_name [mds_name stripe_sz sub_stripe_count pattern]
-   Creates a logical volume
-   When used with other commands, it specifics the lov to modify
-
---ost device [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.
-   Requires --node
-   Optional --obduuid Specifies the UUID used for the obd. 
-   If --lov lov_name is used, this device is added to lov. 
-
---mtpt /mnt/point mds_name lov_name|osc_name 
-   Creates a client mount point.
-   Requires --node
-
-Options:
---merge="xml file"  Add the new objects to an existing file
---format            Format the partitions if unformated
-                    NB: The autoformat option has been disabled until a safe
-                    method is implemented to determine if a block device has a
-                    filesystem.
---reformat          Reformat partitions (this should be an lconf arg,
-                    I think)
---obdtype="obdtype" Specifiy obdtype: valid ones are obdecho and obdfilter.
-                    This is only useful for the --ost command.
-                    The device parameters are ignored for the obdecho type.
-"""
+    print """usage: lmc --add object [object parameters]"""
     sys.exit(1)
 
 def error(*args):
     msg = string.join(map(str,args))
-    print "Error: ", msg
+    raise OptionError("Error: " +  msg)
+
+def panic(cmd, msg):
+    print "! " + cmd
+    print msg
     sys.exit(1)
+
     
 def warning(*args):
     msg = string.join(map(str,args))
@@ -184,8 +116,8 @@ class GenConfig:
     def newService(self, tag, name, uuid):
         """ create a new  service elmement, which requires name and uuid attributes """
         new = self.doc.createElement(tag)
-        new.setAttribute("name", name);
         new.setAttribute("uuid", uuid);
+        new.setAttribute("name", name);
         return new
     
     def addText(self, node, str):
@@ -247,6 +179,12 @@ class GenConfig:
             self.addElement(obd, "autoformat", format)
         return obd
 
+    def cobd(self, name, uuid, real_uuid, cache_uuid):
+        cobd = self.newService("cobd", name, uuid)
+        cobd.appendChild(self.ref("real_obd",real_uuid))
+        cobd.appendChild(self.ref("cache_obd",cache_uuid))
+        return cobd
+
     def osc(self, name, uuid, obd_uuid, net_uuid):
         osc = self.newService("osc", name, uuid)
         osc.appendChild(self.ref("ost", net_uuid))
@@ -259,12 +197,12 @@ class GenConfig:
         ost.appendChild(self.ref("obd", obd_uuid))
         return ost
 
-    def lov(self, name, uuid, mds_uuid, stripe_sz, stripe_count, pattern):
+    def lov(self, name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern):
         lov = self.newService("lov", name, uuid)
         lov.appendChild(self.ref("mds", mds_uuid))
         devs = self.addElement(lov, "devices" )
         devs.setAttribute("stripesize", stripe_sz)
-        devs.setAttribute("stripecount", stripe_count)
+        devs.setAttribute("stripecount", stripe_cnt)
         devs.setAttribute("pattern", pattern)
         return lov
 
@@ -403,12 +341,10 @@ def do_add_node(gen, lustre,  options, node_name):
     return node
 
     
-def add_node(gen, lustre, options, args):
+def add_node(gen, lustre, options):
     """ create a node with a network config """
-    if len(args) > 1:
-        usage()
 
-    node_name = options['node']
+    node_name = get_option(options, 'node')
 
     ret = findByName(lustre, node_name, "node")
     if ret:
@@ -417,26 +353,19 @@ def add_node(gen, lustre, options, args):
     do_add_node(gen, lustre, options, node_name)
 
 
-def add_net(gen, lustre, options, args):
+def add_net(gen, lustre, options):
     """ create a node with a network config """
-    if len(args) < 2:
-        usage()
-
-    node_name = options['node']
-    nid = args[0]
-    net_type = args[1]
-    port = 0
-    tcpbuf = 0
-
-    if net_type in ('tcp', 'toe'):
-        if len(args) > 2:
-            port = int(args[2])
-        else:
-            port = DEFAULT_PORT
-        if options.has_key('tcpbuf'):
-            tcpbuf = int(options['tcpbuf'])
+
+    node_name = get_option(options, 'node')
+    nid = get_option(options, 'nid')
+    net_type = get_option(options, 'nettype')
+
+    if net_type == 'tcp':
+        port = get_option_int(options, 'port', DEFAULT_PORT)
+        tcpbuf = get_option_int(options, 'tcpbuf', 0)
     elif net_type in ('elan', 'gm'):
         port = 0
+        tcpbuf = 0
     else:
         print "Unknown net_type: ", net_type
         sys.exit(2)
@@ -452,19 +381,14 @@ def add_net(gen, lustre, options, args):
     node_add_profile(gen, node, "network", net_uuid)
 
 
-def add_route(gen, lustre, options, args):
+def add_route(gen, lustre, options):
     """ create a node with a network config """
-    if len(args) < 3:
-        usage()
-
-    node_name = options['node']
-    net_type= args[0]
-    gw = args[1]
-    lo = args[2]
-    hi = ''
 
-    if len(args) > 3:
-        hi = args[3]
+    node_name = get_option(options, 'node')
+    net_type = get_option(options, 'nettype')
+    gw = get_option(options, 'gw')
+    lo = get_option(options, 'lo')
+    hi = get_option(options, 'hi', '')
 
     node = findByName(lustre, node_name, "node")
     if not node:
@@ -480,28 +404,15 @@ def add_route(gen, lustre, options, args):
     rtbl.appendChild(gen.route(net_type, gw, lo, hi))
 
 
-def add_mds(gen, lustre, options, args):
-    fstype = 'extN'
-
-    if len(args) < 1:
-        usage()
-
-    if options.has_key('node'):
-        node_name = options['node']
-    else:
-        error("--mds requires a --node argument")
-
-    if options.has_key('fstype'):
-        fstype = options['fstype']
-
-    mds_name = new_name(options['mds'])
-    if mds_name != options['mds']:
-        warning("name:", options['mds'], "already used. using:", mds_name)
-    devname = args[0]
-    if len(args) > 1:
-        size = args[1]
-    else:
-        size = 0
+def add_mds(gen, lustre, options):
+    node_name = get_option(options, 'node')
+    mds_orig = get_option(options, 'mds')
+    mds_name = new_name(mds_orig)
+    if mds_name != mds_orig:
+        warning("name:", mds_orig, "already used. using:", mds_name)
+    devname = get_option(options, 'dev')
+    size = get_option(options, 'size', 0)
+    fstype = get_option(options, 'fstype', 'extN')
 
     mds_uuid = new_uuid(mds_name)
 
@@ -518,37 +429,25 @@ def add_mds(gen, lustre, options, args):
     lustre.appendChild(mds)
                    
 
-def add_ost(gen, lustre, options, args):
-    lovname = ''
-    obdtype = 'obdfilter'
-    devname = ''
-    size = 0
-    fstype = 'extN'
-    
-    if options.has_key('node'):
-        node_name = options['node']
-    else:
-        error("--ost requires a --node argument")
+def add_ost(gen, lustre, options):
+    node_name = get_option(options, 'node')
+    lovname = get_option(options, 'lov', '')
+    obdtype = get_option(options, 'obdtype', 'obdfilter')
 
-    if options.has_key('lov'):
-        lovname = options['lov']
-
-    if options.has_key('obdtype'):
-        obdtype = options['obdtype']
-    if options.has_key('fstype'):
-        fstype = options['fstype']
     if obdtype == 'obdecho':
         fstype = ''
+        devname = ''
+        size = 0
+        fstype = ''
     else:
-        if len(args) < 1:
-            usage()
-        devname = args[0]
-        if len(args) > 1:
-            size = args[1]
+        devname = get_option(options, 'dev', '') # can be unset for bluearcs
+        size = get_option(options, 'size', 0)
+        fstype = get_option(options, 'fstype', 'extN')
         
-    obdname = new_name('OBD_'+ node_name)
-    oscname = new_name('OSC_'+ node_name)
-    ostname = new_name('OST_'+ node_name)
+    obdname = get_option(options, 'obd', 'OBD_'+ node_name)
+    obdname = new_name(obdname)
+    oscname = new_name('OSC_'+ obdname)
+    ostname = new_name('OST_'+ obdname)
     if options.has_key('obduuid'):
         obd_uuid = options['obduuid']
         obd = lookup(lustre, obd_uuid)
@@ -582,32 +481,32 @@ def add_ost(gen, lustre, options, args):
     lustre.appendChild(ost)
 
                    
-# this is generally only used by llecho.sh
-def add_osc(gen, lustre, options, args):
-    """ add the osc to the profile for this node. """
-    if len(args) < 1:
-        usage()
-    osc_name = args[0]
-    if options.has_key('node'):
-        node_name = options['node']
-    else:
-        error("--osc requires a --node argument")
-    osc_uuid = name2uuid(lustre, osc_name) # either 'osc' or 'lov'
+def add_cobd(gen, lustre, options):
+    node_name = get_option(options, 'node')
+    name = new_name('COBD_' + node_name)
+    uuid = new_uuid(name)
+
+    real_name = get_option(options, 'real_obd')
+    cache_name = get_option(options, 'cache_obd')
+    # temp hack until merged with b_recover and OSC is removed
+    real_name = 'OSC_' + real_name
+    cache_name = 'OSC_' + cache_name
+    
+    real_uuid = name2uuid(lustre, real_name, tag='osc')
+    cache_uuid = name2uuid(lustre, cache_name, tag='osc')
+
     node = findByName(lustre, node_name, "node")
-    node_add_profile(gen, node, 'osc', osc_uuid)
+    node_add_profile(gen, node, "cobd", uuid)
+    cobd = gen.cobd(name, uuid, real_uuid, cache_uuid)
+    lustre.appendChild(cobd)
 
 
-#ditto
-def add_echo_client(gen, lustre, options, args):
+def add_echo_client(gen, lustre, options):
     """ add an echo client to the profile for this node. """
-    if len(args) < 1:
-        usage()
-    lov_name = args[0]
-    if options.has_key('node'):
-        node_name = options['node']
-    else:
-        error("--echo_client requires a --node argument")
-    node = findByName(lustre, node_name, "node")
+    node_name = get_option(options, 'node')
+    lov_name = get_option(options, 'obd')
+
+    node = findByName(lustre, node_name, 'node')
 
     echoname = new_name('ECHO_'+ node_name)
     echo_uuid = new_uuid(echoname)
@@ -615,25 +514,26 @@ def add_echo_client(gen, lustre, options, args):
 
     lov_uuid = name2uuid(lustre, lov_name, tag='lov', fatal=0)
     if not lov_uuid:
+        # remove this hack when the osc uuids are removed
+        lov_name = 'OSC_' + lov_name
         lov_uuid = name2uuid(lustre, lov_name, tag='osc', fatal=1)
 
     echo = gen.echo_client(echoname, echo_uuid, lov_uuid)
     lustre.appendChild(echo)
 
 
-def add_lov(gen, lustre, options, args):
+def add_lov(gen, lustre, options):
     """ create a lov """
-    if len(args) < 4:
-        usage()
 
-    name = new_name(options['lov'])
-    if name != options['lov']:
-        warning("name:", options['lov'], "already used. using:", name)
+    lov_orig = get_option(options, 'lov')
+    name = new_name(lov_orig)
+    if name != lov_orig:
+        warning("name:", lov_orig, "already used. using:", name)
 
-    mds_name = args[0]
-    stripe_sz = args[1]
-    stripe_count = args[2]
-    pattern = args[3]
+    mds_name = get_option(options, 'mds')
+    stripe_sz = get_option(options, 'stripe_sz')
+    stripe_cnt = get_option(options, 'stripe_cnt', 0)
+    pattern = get_option(options, 'stripe_pattern', 0)
     uuid = new_uuid(name)
 
     ret = findByName(lustre, name, "lov")
@@ -641,7 +541,7 @@ def add_lov(gen, lustre, options, args):
         error("LOV: ", name, " already exists.")
 
     mds_uuid = name2uuid(lustre, mds_name, 'mds')
-    lov = gen.lov(name, uuid, mds_uuid, stripe_sz, stripe_count, pattern)
+    lov = gen.lov(name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern)
     lustre.appendChild(lov)
     
     # add an lovconfig entry to the mds profile
@@ -653,20 +553,17 @@ def add_lov(gen, lustre, options, args):
     lustre.appendChild(lovconfig)
 
 
-
-def add_mtpt(gen, lustre, options, args):
+def add_mtpt(gen, lustre, options):
     """ create mtpt on a node """
-    if len(args) < 3:
-        usage()
+    node_name = get_option(options, 'node')
 
-    if options.has_key('node'):
-        node_name = options['node']
-    else:
-        error("--mtpt requires a --node argument")
-
-    path = args[0]
-    mds_name = args[1]
-    lov_name = args[2]
+    path = get_option(options, 'path')
+    mds_name = get_option(options, 'mds')
+    lov_name = get_option(options, 'lov', '')
+    if lov_name == '':
+        lov_name = get_option(options, 'obd', '')
+        if lov_name == '':
+            error("--add mtpt requires either --lov lov_name or --obd obd_name")
 
     name = new_name('MNT_'+ node_name)
 
@@ -677,6 +574,8 @@ def add_mtpt(gen, lustre, options, args):
     mds_uuid = name2uuid(lustre, mds_name, tag='mds')
     lov_uuid = name2uuid(lustre, lov_name, tag='lov', fatal=0)
     if not lov_uuid:
+        # remove this hack when OSC is removed
+        lov_name = 'OSC_' + lov_name
         lov_uuid = name2uuid(lustre, lov_name, tag='osc', fatal=1)
 
     uuid = new_uuid(name)
@@ -687,57 +586,125 @@ def add_mtpt(gen, lustre, options, args):
     node_add_profile(gen, node, "mountpoint", uuid)
     lustre.appendChild(mtpt)
 
+def add_oscref(gen, lustre, options):
+    """ create mtpt on a node """
+    node_name = get_option(options, 'node')
+    osc_name = get_option(options, 'osc')
+
+    osc_uuid = name2uuid(lustre, osc_name, tag='osc')
+    node = findByName(lustre, node_name, "node")
+    if not node:
+           error('node:', node_name, "not found")
+    node_add_profile(gen, node, "osc",osc_uuid)
 
 ############################################################
 # Command line processing
 #
+class OptionError (exceptions.Exception):
+    def __init__(self, args):
+        self.args = args
+
+def get_option(options, tag, default = None):
+    """Look for tag in options hash and return the value if set. If not
+    set, then if return default it is set, otherwise exception."""
+    if options.has_key(tag):
+        return options[tag]
+    elif default != None:
+        return default
+    else:
+        raise OptionError("--add %s requires --%s value" % (options['add'], tag))
+        # this exception should print an error like '--add blah requires --<tag> value'
+
+def get_option_int(options, tag, default = None):
+    """Return an integer option.  Raise exception if the value is not an int"""
+    val = get_option(options, tag, default)
+    return int(val)
+
 def parse_cmdline(argv):
     short_opts = "ho:i:m:"
-    long_opts = ["ost", "osc", "mtpt", "lov=", "node=", "mds=", "net",
-                 "echo_client", "tcpbuf=",
-                 "route", "router", "merge=", "format", "reformat", "output=",
-                 "obdtype=", "fstype=", "obduuid=", "in=", "help", "batch="]
+    long_opts = ["add=", "node=", "nettype=", "nid=", "tcpbuf=", "port=",
+                 "echo_client=", "stripe_sz=", "stripe_cnt=", "stripe_pattern=",
+                 "mds=", "route", "router", "merge=", "format", "reformat", "output=",
+                 "dev=", "size=", "obd=", "obdtype=", "obduuid=", "in=",
+                 "path=", "help", "batch=", "lov=", "gw=", "lo=", "hi=",
+                 "oscref", "osc=", "real_obd=", "cache_obd=", "fstype="]
     opts = []
     args = []
     options = {}
     try:
         opts, args = getopt.getopt(argv, short_opts, long_opts)
-    except getopt.error:
-        print "invalid opt"
-        usage()
+    except getopt.error, e:
+        panic(string.join(sys.argv), e)
 
     for o, a in opts:
         # Commands to create new devices
-        if o == "--ost":
-            options['ost'] = 1
-        if o == "--osc":
-            options['osc'] = 1
-        if o == "--echo_client":
-            options['echo_client'] = 1
+        if o == "--add":
+            options['add'] = a
+
+        if o == "--node":
+            options['node'] = a
+
+        # devices names
+        if o == "--lov":
+            options['lov'] = a
         if o == "--mds":
             options['mds'] = a
+        if o == "--obd":
+            options['obd'] = a
+
+        # network options
+        if o == "--nid":
+            options['nid'] = a
+        if o == "--nettype":
+            options['nettype'] = a
         if o == "--net":
-            options['net'] = 1
+            options[''] = a
+        if o == "--tcpbuf":
+            options['tcpbuf'] = a
+        if o == "--port":
+            options['port'] = a
         if o == "--mtpt":
             options['mtpt'] = 1
-        if o == "--node":
-            options['node'] = a
         if o == "--route":
             options['route'] = 1
         if o == "--router":
             options['router'] = 1
-        if o == "--lov":
-            options['lov'] = a
 
-        # Options for commands
+        # ost options
+        if o == "--dev":
+            options['dev'] = a
+        if o == "--size":
+            options['size'] = a
+        if o == "--path":
+            options['path'] = a
+        if o == "--osc":
+            options['osc'] = a
         if o == "--obdtype":
             options['obdtype'] = a
         if o == "--fstype":
             options['fstype'] = a
         if o == "--obduuid":
             options['obduuid'] = a
-        if o == "--tcpbuf":
-            options['tcpbuf'] = a
+
+        # lov options
+        if o == "--stripe_sz":
+            options['stripe_sz'] = a
+        if o == "--stripe_cnt":
+            options['stripe_cnt'] = a
+        if o == "--stripe_pattern":
+            options['stripe_pattern'] = a
+        if o == "--gw":
+            options['gw'] = a
+        if o == "--lo":
+            options['lo'] = a
+        if o == "--hi":
+            options['hi'] = a
+
+        # cobd
+        if o == "--cache_obd":
+            options['cache_obd'] = a
+        if o == "--real_obd":
+            options['real_obd'] = a
 
         # lmc options
         if o in ("-h", "--help"):
@@ -777,31 +744,43 @@ class chrono:
         str = '%s: %g secs' % (msg, d)
         print str
 
+
+
 ############################################################
 # Main
 #
+
+def add(devtype, gen, lustre, options):
+    if devtype == 'net':
+        add_net(gen, lustre, options)
+    elif devtype =='osc':
+        add_osc(gen, lustre, options)
+    elif devtype == 'mtpt':
+        add_mtpt(gen, lustre, options)
+    elif devtype == 'mds':
+        add_mds(gen, lustre, options)
+    elif devtype == 'ost':
+        add_ost(gen, lustre, options)
+    elif devtype == 'lov':
+        add_lov(gen, lustre, options)
+    elif devtype == 'route':
+        add_route(gen, lustre, options)
+    elif devtype == 'node':
+        add_node(gen, lustre, options)
+    elif devtype == 'echo_client':
+        add_echo_client(gen, lustre, options)
+    elif devtype == 'oscref':
+        add_oscref(gen, lustre, options)
+    elif devtype == 'cobd':
+        add_cobd(gen, lustre, options)
+    else:
+        error("unknown device type:", devtype)
+    
 def do_command(gen, lustre, options, args):
-    if options.has_key('ost'):
-        add_ost(gen, lustre, options, args)
-    elif options.has_key('osc'):
-        add_osc(gen, lustre, options, args)
-    elif options.has_key('echo_client'):
-        add_echo_client(gen, lustre, options, args)
-    elif options.has_key('mtpt'):
-        add_mtpt(gen, lustre, options, args)
-    elif options.has_key('mds'):
-        add_mds(gen, lustre, options, args)
-    elif options.has_key('net'):
-        add_net(gen, lustre, options, args)
-    elif options.has_key('lov'):
-        add_lov(gen, lustre, options, args)
-    elif options.has_key('route'):
-        add_route(gen, lustre, options, args)
-    elif options.has_key('node'):
-        add_node(gen, lustre, options, args)
+    if options.has_key('add'):
+        add(options['add'], gen, lustre, options)
     else:
-        print "Missing command"
-        usage()
+        error("Missing command")
 
 def main():
     options, args = parse_cmdline(sys.argv[1:])
@@ -835,9 +814,15 @@ def main():
         fp.close()
         for cmd in batchCommands:
             options, args = parse_cmdline(string.split(cmd))
-            do_command(gen, lustre, options, args)
+            try:
+                do_command(gen, lustre, options, args)
+            except OptionError, e:
+                panic(cmd, e)
     else:
-        do_command(gen, lustre, options, args)
+        try:
+            do_command(gen, lustre, options, args)
+        except OptionError, e:
+            panic(string.join(sys.argv),e)
 
     if outFile == '-':
         PrettyPrint(doc)