Whamcloud - gitweb
b=1719
[fs/lustre-release.git] / lustre / utils / lmc
index bb6377f..8e2baf0 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
-
-
+lmc - lustre configuration data manager
 
-# 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 (http://www.lustre.org/docs/lustre.pdf) for documentation on lmc.
 
 """
 
-import sys, os, getopt, string
+import sys, os, getopt, string, exceptions, random
 import xml.dom.minidom
 from xml.dom.ext import PrettyPrint
 
-
-DEFAULT_PORT = 988 # XXX What is the right default acceptor port to use?
-
-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, 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.
+PYMOD_DIR = "/usr/lib/lustre/python"
+
+def development_mode():
+    base = os.path.dirname(sys.argv[0])
+    if os.access(base+"/Makefile.am", os.R_OK):
+        return 1
+    return 0
+
+if not development_mode():
+    sys.path.append(PYMOD_DIR)
+
+import Lustre
+
+DEFAULT_PORT = 988 
+
+def reference():
+    print """usage: lmc --add object [object parameters]
+
+Object creation command summary:
+
+--add node
+  --node node_name
+  --timeout num
+  --upcall path
+  --lustre_upcall path
+  --portals_upcall path
+  --ptldebug debug_level
+  --subsystem subsystem_name
+
+--add net
+  --node node_name
+  --nid nid
+  --cluster_id 
+  --nettype tcp|elan|gm|scimac
+  --hostaddr addr
+  --port port
+  --tcpbuf size
+  --irq_affinity 0|1
+  --router
+
+--add mds
+  --node node_name
+  --mds mds_name
+  --dev path
+  --fstype extN|ext3
+  --size size
+  --nspath
+  --journal_size size
+
+--add lov
+  --lov lov_name
+  --mds mds_name
+  --stripe_sz num
+  --stripe_cnt num
+  --stripe_pattern num
+
+--add ost
+  --node node_name
+  --ost ost_name 
+  --lov lov_name 
+  --dev path
+  --size size
+  --fstype extN|ext3
+  --journal_size size
+  --obdtype obdecho|obdfilter
+  --ostuuid uuid
+--add mtpt  - Mountpoint
+  --node node_name
+  --path /mnt/point
+  --mds mds_name
+  --ost ost_name OR --lov lov_name
+
+--add route
+  --node nodename
+  --gw nid
+  --tgt nid
+  --lo nid
+  --hi nid
+
+--add echo_client
+  --node nodename
+
+--add mgmt  - Management/monitoring service
+  --node node_name
+  --mgmt mgmt_service_name
 """
-    sys.exit(1)
+
+PARAM = Lustre.Options.PARAM
+lmc_options = [
+    # lmc input/output options
+    ('reference', "Print short reference for commands."), 
+    ('verbose,v', "Print system commands as they are run."),
+    ('merge,m', "Append to the specified config file.", PARAM),
+    ('output,o', "Write XML configuration into given output file. Overwrite existing content.", PARAM),
+    ('input,i', "", PARAM),
+    ('batch', "Used to execute lmc commands in batch mode.", PARAM),
+
+    # commands
+    ('add', "", PARAM),
+    
+    # node options
+    ('node', "Add a new node in the cluster configuration.", PARAM),
+    ('timeout', "Set timeout to initiate recovery.", PARAM),
+    ('upcall', "Set both lustre and portals upcall scripts.", PARAM),
+    ('lustre_upcall', "Set location of lustre upcall script.", PARAM),
+    ('portals_upcall', "Set location of portals upcall script.", PARAM),
+    ('ptldebug', "Set the portals debug level",  PARAM),
+    ('subsystem', "Specify which Lustre subsystems have debug output recorded in the log",  PARAM),
+
+    # network 
+    ('nettype', "Specify the network type. This can be tcp/elan/gm/scimac.", PARAM),
+    ('nid', "Give the network ID, e.g ElanID/IP Address as used by portals.", PARAM),
+    ('tcpbuf', "Optional argument to specify the TCP buffer size.", PARAM, "0"),
+    ('port', "Optional argument to specify the TCP port number.", PARAM, DEFAULT_PORT),
+    ('irq_affinity', "Optional argument.", PARAM, 0),
+    ('hostaddr', "", PARAM,""),
+    ('cluster_id', "Specify the cluster ID", PARAM, "0"),
+
+    # routes
+    ('route', "Add a new route for the cluster.", PARAM),
+    ('router', "Optional flag to mark a node as router."),
+    ('gw', "Specify the nid of the gateway for a route.", PARAM),
+    ('gateway_cluster_id', "", PARAM, "0"),
+    ('target_cluster_id', "", PARAM, "0"),
+    ('lo', "For a range route, this is the low value nid.", PARAM),
+    ('hi', "For a range route, this is a hi value nid.", PARAM,""),
+
+    # servers: mds and ost
+    ('mds', "Specify MDS name.", PARAM),
+    ('ost', "Specify the OST name.", PARAM,""),
+    ('osdtype', "This could obdfilter or obdecho.", PARAM, "obdfilter"),
+    ('failover', "Enable failover support on OSTs or MDS?"),
+    ('group', "", PARAM),
+    ('dev', "Path of the device on local system.", PARAM,""),
+    ('size', "Specify the size of the device if needed.", PARAM,"0"),
+    ('journal_size', "Specify new journal size for underlying ext3 file system.", PARAM,"0"),
+    ('fstype', "Optional argument to specify the filesystem type.", PARAM, "ext3"),
+    ('mkfsoptions', "Optional argument to mkfs.", PARAM, ""),
+    ('ostuuid', "", PARAM,""),
+    ('nspath', "Local mount point of server namespace.", PARAM,""),
+    ('format', ""),
+
+    # clients: mountpoint and echo
+    ('echo_client', "", PARAM),
+    ('path', "Specify the mountpoint for Lustre.", PARAM),
+    ('filesystem', "Lustre filesystem name", PARAM,""),
+
+    # lov
+    ('lov', "Specify LOV name.", PARAM,""),
+    ('stripe_sz', "Specify the stripe size in bytes.", PARAM),
+    ('stripe_cnt', "Specify the number of OSTs each file should be striped on.", PARAM, 0),
+    ('stripe_pattern', "Specify the stripe pattern. RAID 0 is the only one currently supported.", PARAM, 0),
+
+    # cobd
+    ('real_obd', "", PARAM),
+    ('cache_obd', "", PARAM),
+
+    ('mgmt', "Specify management/monitoring service name.", PARAM, ""),
+    ]
 
 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))
@@ -133,16 +220,21 @@ def new_name(base):
     return ret
 
 def new_uuid(name):
-    return "%s_UUID" % (name)
+    ret_uuid = '%05x_%.19s_%05x%05x' % (int(random.random() * 1048576),
+                                        name,
+                                        int(random.random() * 1048576),
+                                        int(random.random() * 1048576))
+    return ret_uuid[:36]
 
 ldlm_name = 'ldlm'
 ldlm_uuid = 'ldlm_UUID'
+
 def new_lustre(dom):
     """Create a new empty lustre document"""
     # adding ldlm here is a bit of a hack, but one is enough.
-    str = """<lustre>
+    str = """<lustre version="%s">
     <ldlm name="%s" uuid="%s"/>
-    </lustre>""" % (ldlm_name, ldlm_uuid)
+    </lustre>""" % (Lustre.CONFIG_VERSION, ldlm_name, ldlm_uuid)
     return dom.parseString(str)
 
 names = {}
@@ -160,9 +252,8 @@ def init_names(doc):
             init_names(n)
 
 def get_format_flag(options):
-    if options.has_key('format'):
-        if options['format']:
-            return 'yes'
+    if options.format:
+        return 'yes'
     return 'no'
 
 ############################################################
@@ -184,8 +275,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):
@@ -201,33 +292,51 @@ class GenConfig:
         node.appendChild(new)
         return new
 
-    def network(self, name, uuid, hostname, net, port=0, tcpbuf=0):
+    def network(self, name, uuid, nid, cluster_id, net, hostaddr="",
+                port=0, tcpbuf=0, irq_aff=0):
         """create <network> node"""
         network = self.newService("network", name, uuid)
-        network.setAttribute("type", net);
-        self.addElement(network, "server", hostname)
+        network.setAttribute("nettype", net);
+        self.addElement(network, "nid", nid)
+        self.addElement(network, "clusterid", cluster_id)
+        if hostaddr:
+            self.addElement(network, "hostaddr", hostaddr)
         if port:
             self.addElement(network, "port", "%d" %(port))
         if tcpbuf:
-            self.addElement(network, "send_mem", "%d" %(tcpbuf))
-            self.addElement(network, "recv_mem", "%d" %(tcpbuf))
+            self.addElement(network, "sendmem", "%d" %(tcpbuf))
+            self.addElement(network, "recvmem", "%d" %(tcpbuf))
+        if irq_aff:
+            self.addElement(network, "irqaffinity", "%d" %(irq_aff))
             
         return network
 
-    def route(self, net_type, gw, lo, hi):
+    def routetbl(self, name, uuid):
+        """create <routetbl> node"""
+        rtbl = self.newService("routetbl", name, uuid)
+        return rtbl
+        
+    def route(self, gw_net_type, gw, gw_cluster_id, tgt_cluster_id, lo, hi):
         """ create one entry for the route table """
         ref = self.doc.createElement('route')
-        ref.setAttribute("type", net_type)
+        ref.setAttribute("type", gw_net_type)
         ref.setAttribute("gw", gw)
+        ref.setAttribute("gwclusterid", gw_cluster_id)
+        ref.setAttribute("tgtclusterid", tgt_cluster_id)
         ref.setAttribute("lo", lo)
         if hi:
             ref.setAttribute("hi", hi)
         return ref
     
-    def node(self, name, uuid):
+    def profile(self, name, uuid):
+        """ create a host """
+        profile = self.newService("profile", name, uuid)
+        return profile
+
+    def node(self, name, uuid, prof_uuid):
         """ create a host """
         node = self.newService("node", name, uuid)
-        self.addElement(node, 'profile')
+        node.appendChild(self.ref("profile", prof_uuid))
         return node
 
     def ldlm(self, name, uuid):
@@ -235,37 +344,48 @@ class GenConfig:
         ldlm = self.newService("ldlm", name, uuid)
         return ldlm
 
-    def obd(self, name, uuid, fs, obdtype, devname, format, dev_size=0):
-        obd = self.newService("obd", name, uuid)
-        obd.setAttribute('type', obdtype)
+    def osd(self, name, uuid, fs, osdtype, devname, format, ost_uuid,
+            node_uuid, dev_size=0, journal_size=0, nspath=""):
+        osd = self.newService("osd", name, uuid)
+        osd.setAttribute('osdtype', osdtype)
+        osd.appendChild(self.ref("target", ost_uuid))
+        osd.appendChild(self.ref("node", node_uuid))
         if fs:
-            self.addElement(obd, "fstype", fs)
+            self.addElement(osd, "fstype", fs)
         if devname:
-            dev = self.addElement(obd, "device", devname)
-            if (dev_size):
-                dev.setAttribute("size", "%s" % (dev_size))
-            self.addElement(obd, "autoformat", format)
-        return obd
-
-    def osc(self, name, uuid, obd_uuid, net_uuid):
-        osc = self.newService("osc", name, uuid)
-        osc.appendChild(self.ref("ost", net_uuid))
-        osc.appendChild(self.ref("obd", obd_uuid))
-        return osc
-
-    def ost(self, name, uuid, obd_uuid, net_uuid):
+            dev = self.addElement(osd, "devpath", devname)
+            self.addElement(osd, "autoformat", format)
+            if dev_size:
+                self.addElement(osd, "devsize", "%s" % (dev_size))
+            if journal_size:
+                self.addElement(osd, "journalsize", "%s" % (journal_size))
+        if nspath:
+            self.addElement(osd, "nspath", nspath)
+        return osd
+
+    def cobd(self, name, uuid, real_uuid, cache_uuid):
+        cobd = self.newService("cobd", name, uuid)
+        cobd.appendChild(self.ref("realobd",real_uuid))
+        cobd.appendChild(self.ref("cacheobd",cache_uuid))
+        return cobd
+
+    def ost(self, name, uuid, osd_uuid, group=""):
         ost = self.newService("ost", name, uuid)
-        ost.appendChild(self.ref("network", net_uuid))
-        ost.appendChild(self.ref("obd", obd_uuid))
+        ost.appendChild(self.ref("active", osd_uuid))
+        if group:
+            self.addElement(ost, "group", group)
         return ost
 
-    def lov(self, name, uuid, mds_uuid, stripe_sz, stripe_count, pattern):
+    def oss(self, name, uuid):
+        oss = self.newService("oss", name, uuid)
+        return oss
+
+    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("pattern", pattern)
+        lov.setAttribute("stripesize", str(stripe_sz))
+        lov.setAttribute("stripecount", str(stripe_cnt))
+        lov.setAttribute("stripepattern", str(pattern))
         return lov
 
     def lovconfig(self, name, uuid, lov_uuid):
@@ -273,27 +393,57 @@ class GenConfig:
         lovconfig.appendChild(self.ref("lov", lov_uuid))
         return lovconfig
 
-    def mds(self, name, uuid, fs, devname, format, net_uuid, node_uuid,
-            failover_uuid = "", dev_size=0 ):
+    def mds(self, name, uuid, mdd_uuid, group=""):
         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))
-        mds.appendChild(self.ref("node", node_uuid))
-        if failover_uuid:
-            mds.appendChild(self.ref("failover", failover_uuid))
+        mds.appendChild(self.ref("active",mdd_uuid))
+        if group:
+            self.addElement(mds, "group", group)
         return mds
 
-    def mountpoint(self, name, uuid, mds_uuid, osc_uuid, path):
+    def mdsdev(self, name, uuid, fs, devname, format, node_uuid,
+            mds_uuid, dev_size=0, journal_size=0, nspath="", mkfsoptions=""):
+        mdd = self.newService("mdsdev", name, uuid)
+        self.addElement(mdd, "fstype", fs)
+        dev = self.addElement(mdd, "devpath", devname)
+        self.addElement(mdd, "autoformat", format)
+        if dev_size:
+                self.addElement(mdd, "devsize", "%s" % (dev_size))
+        if journal_size:
+            self.addElement(mdd, "journalsize", "%s" % (journal_size))
+        if nspath:
+            self.addElement(mdd, "nspath", nspath)
+        if mkfsoptions:
+            self.addElement(mdd, "mkfsoptions", mkfsoptions)
+        mdd.appendChild(self.ref("node", node_uuid))
+        mdd.appendChild(self.ref("target", mds_uuid))
+        return mdd
+
+    def mgmt(self, mgmt_name, mgmt_uuid, node_uuid):
+        mgmt = self.newService("mgmt", mgmt_name, mgmt_uuid)
+        mgmt.appendChild(self.ref("node", node_uuid))
+        # Placeholder until mgmt-service failover.
+        mgmt.appendChild(self.ref("active", mgmt_uuid))
+        return mgmt
+
+    def mountpoint(self, name, uuid, fs_uuid, path):
         mtpt = self.newService("mountpoint", name, uuid)
-        mtpt.appendChild(self.ref("mds", mds_uuid))
-        mtpt.appendChild(self.ref("osc", osc_uuid))
+        mtpt.appendChild(self.ref("filesystem", fs_uuid))
         self.addElement(mtpt, "path", path)
         return mtpt
 
+    def filesystem(self, name, uuid, mds_uuid, obd_uuid, mgmt_uuid):
+        fs = self.newService("filesystem", name, uuid)
+        fs.appendChild(self.ref("mds", mds_uuid))
+        fs.appendChild(self.ref("obd", obd_uuid))
+        if mgmt_uuid:
+            fs.appendChild(self.ref("mgmt", mgmt_uuid))
+        return fs
+        
+    def echo_client(self, name, uuid, osc_uuid):
+        ec = self.newService("echoclient", name, uuid)
+        ec.appendChild(self.ref("obd", osc_uuid))
+        return ec
+
 ############################################################
 # Utilities to query a DOM tree
 # Using this functions we can treat use config information
@@ -327,19 +477,6 @@ def lookup(node, uuid):
                 n = lookup(n, uuid)
                 if n: return n
     return None
-            
-
-def mds2node(lustre, mds_name):
-    """ Find the node a MDS is configured on """
-    mds = findByName(lustre, mds_name, 'mds')
-    ref = mds.getElementsByTagName('node_ref')
-    if not ref:
-        error("mds2node:", "no node_ref found for", '"'+mds_name+'"')
-    node_uuid = ref[0].getAttribute('uuidref')
-    node = lookup(lustre, node_uuid)
-    if not node:
-        error('mds2node:', "no node found for :", '"'+mds_name+'"')
-    return node
 
 
 def name2uuid(lustre, name, tag="",  fatal=1):
@@ -351,6 +488,12 @@ def name2uuid(lustre, name, tag="",  fatal=1):
             return ""
     return getUUID(ret)
     
+def lookup_filesystem(lustre, mds_uuid, ost_uuid):
+    for n in lustre.childNodes:
+        if n.nodeType == n.ELEMENT_NODE and n.nodeName == 'filesystem':
+            if ref_exists(n, mds_uuid) and ref_exists(n, ost_uuid):
+                return getUUID(n)
+    return None
 
 # XXX: assumes only one network element per node. will fix this
 # as soon as support for routers is added
@@ -365,19 +508,33 @@ def get_net_uuid(lustre, node_name):
     return None
 
 
-def lov_add_osc(gen, lov, osc_uuid):
-    devs = lov.getElementsByTagName('devices')
-    if len(devs) == 1:
-        devs[0].appendChild(gen.ref("osc", osc_uuid))
-    else:
-        error("No devices element found for LOV:", lov)
-
+def lov_add_obd(gen, lov, osc_uuid):
+    lov.appendChild(gen.ref("obd", osc_uuid))
                             
+def ref_exists(profile, uuid):
+    elist = profile.childNodes
+    for e in elist:
+        if e.nodeType == e.ELEMENT_NODE:
+            ref = e.getAttribute('uuidref')
+            if ref == uuid:
+                return 1
+    return 0
+        
+# ensure that uuid is not already in the profile
+# return true if uuid is added
 def node_add_profile(gen, node, ref, uuid):
-    ret = node.getElementsByTagName('profile')
+    refname = "%s_ref" % "profile"
+    ret = node.getElementsByTagName(refname)
     if not ret:
-        error('node has no profile:', node)
-    ret[0].appendChild(gen.ref(ref, uuid))
+        error('node has no profile ref:', node)
+    prof_uuid = ret[0].getAttribute('uuidref')
+    profile = lookup(node.parentNode, prof_uuid)
+    if not profile:
+        error("no profile found:", prof_uuid)
+    if ref_exists(profile, uuid):
+        return 0
+    profile.appendChild(gen.ref(ref, uuid))
+    return 1
     
 def get_attr(dom_node, attr, default=""):
     v = dom_node.getAttribute(attr)
@@ -388,23 +545,49 @@ def get_attr(dom_node, attr, default=""):
 ############################################################
 # Top level commands
 #
+def set_node_options(gen, node, options):
+    if options.router:
+        node.setAttribute('router', '1')
+    if options.timeout:
+        gen.addElement(node, "timeout", get_option(options, 'timeout'))
+    if options.upcall:
+        default_upcall =  get_option(options, 'upcall')
+    else:
+        default_upcall = ''
+    if default_upcall or options.lustre_upcall:
+        if options.lustre_upcall:
+            gen.addElement(node, 'lustreUpcall', options.lustre_upcall)
+        else: 
+            gen.addElement(node, 'lustreUpcall', default_upcall)
+    if default_upcall or options.portals_upcall:
+        if options.portals_upcall:
+            gen.addElement(node, 'portalsUpcall', options.portals_upcall)
+        else:
+            gen.addElement(node, 'portalsUpcall', default_upcall)
+    if options.ptldebug:
+        gen.addElement(node, "ptldebug", get_option(options, 'ptldebug'))
+    if options.subsystem:
+        gen.addElement(node, "subsystem", get_option(options, 'subsystem'))
+    return node
+
 def do_add_node(gen, lustre,  options, node_name):
     uuid = new_uuid(node_name)
-    node = gen.node(node_name, uuid)
-    node_add_profile(gen, node, 'ldlm', ldlm_uuid)
-    if options.has_key('router'):
-        node.setAttribute('router', '1')
+    prof_name = new_name("PROFILE_" + node_name)
+    prof_uuid = new_uuid(prof_name)
+    profile = gen.profile(prof_name, prof_uuid)
+    node = gen.node(node_name, uuid, prof_uuid)
     lustre.appendChild(node)
+    lustre.appendChild(profile)
+
+    node_add_profile(gen, node, 'ldlm', ldlm_uuid)
+    set_node_options(gen, node, options)
     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:
         print "Node:", node_name, "exists."
@@ -412,26 +595,23 @@ 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 == 'tcp':
-        if len(args) > 2:
-            port = int(args[2])
-        else:
-            port = DEFAULT_PORT
-        if options.has_key('tcpbuf'):
-            tcpbuf = int(options['tcpbuf'])
-    elif net_type in ('elan', 'gm'):
+
+    node_name = get_option(options, 'node')
+    nid = get_option(options, 'nid')
+    cluster_id = get_option(options, 'cluster_id')
+    hostaddr = get_option(options, 'hostaddr')
+    net_type = get_option(options, 'nettype')
+
+    if net_type in ('tcp',):
+        port = get_option_int(options, 'port')
+        tcpbuf = get_option_int(options, 'tcpbuf')
+        irq_aff = get_option_int(options, 'irq_affinity')
+    elif net_type in ('elan', 'gm', 'scimac'):
         port = 0
+        tcpbuf = 0
+        irq_aff = 0
     else:
         print "Unknown net_type: ", net_type
         sys.exit(2)
@@ -441,164 +621,214 @@ def add_net(gen, lustre, options, args):
         node = do_add_node(gen, lustre, options, node_name)
     else:
         node = ret
+        set_node_options(gen, node, options)
+
     net_name = new_name('NET_'+ node_name +'_'+ net_type)
     net_uuid = new_uuid(net_name)
-    node.appendChild(gen.network(net_name, net_uuid, nid, net_type, port, tcpbuf))
+    node.appendChild(gen.network(net_name, net_uuid, nid, cluster_id, net_type,
+                                 hostaddr, port, tcpbuf, irq_aff))
     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')
+    gw_net_type = get_option(options, 'nettype')
+    gw = get_option(options, 'gw')
+    gw_cluster_id = get_option(options, 'gateway_cluster_id')
+    tgt_cluster_id = get_option(options, 'target_cluster_id')
+    lo = get_option(options, 'lo')
+    hi = get_option(options, 'hi')
+    if not hi:
+        hi = lo
 
     node = findByName(lustre, node_name, "node")
     if not node:
         error (node_name, " not found.")
     
-    netlist = node.getElementsByTagName('network')
-    net = netlist[0]
-    rlist = net.getElementsByTagName('route_tbl')
+    rlist = node.getElementsByTagName('routetbl')
     if len(rlist) > 0:
         rtbl = rlist[0]
     else:
-        rtbl = gen.addElement(net, 'route_tbl')
-    rtbl.appendChild(gen.route(net_type, gw, lo, hi))
-
-
-def add_mds(gen, lustre, options, args):
-    if len(args) < 1:
-        usage()
-
-    if options.has_key('node'):
-        node_name = options['node']
-    else:
-        error("--mds requires a --node argument")
-
-    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]
+        rtbl_name = new_name("RTBL_" + node_name)
+        rtbl_uuid = new_uuid(rtbl_name)
+        rtbl = gen.routetbl(rtbl_name, rtbl_uuid)
+        node.appendChild(rtbl)
+        node_add_profile(gen, node, "routetbl", rtbl_uuid)
+    rtbl.appendChild(gen.route(gw_net_type, gw, gw_cluster_id, tgt_cluster_id,
+                               lo, hi))
+
+
+def add_mds(gen, lustre, options):
+    node_name = get_option(options, 'node')
+    mds_name = get_option(options, 'mds')
+    mdd_name = new_name("MDD_" + mds_name +"_" + node_name)
+    mdd_uuid = new_uuid(mdd_name)
+
+    mds_uuid = name2uuid(lustre, mds_name, fatal=0)
+    if not mds_uuid:
+        mds_uuid = new_uuid(mds_name)
+        mds = gen.mds(mds_name, mds_uuid, mdd_uuid, options.group)
+        lustre.appendChild(mds)
     else:
-        size = 0
+        mds = lookup(lustre, mds_uuid)
+    if options.failover:
+        mds.setAttribute('failover', "1")
 
-    mds_uuid = new_uuid(mds_name)
+    devname = get_option(options, 'dev')
+    size = get_option(options, 'size')
+    fstype = get_option(options, 'fstype')
+    journal_size = get_option(options, 'journal_size')
+    nspath = get_option(options, 'nspath')
+    mkfsoptions = get_option(options, 'mkfsoptions')
 
     node_uuid = name2uuid(lustre, node_name, 'node')
 
     node = findByName(lustre, node_name, "node")
-    node_add_profile(gen, node, "mds", mds_uuid)
+    node_add_profile(gen, node, "mdsdev", mdd_uuid)
     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, get_format_flag(options),
-                  net_uuid, node_uuid, dev_size=size)
-    lustre.appendChild(mds)
+    mdd = gen.mdsdev(mdd_name, mdd_uuid, fstype, devname,
+                     get_format_flag(options), node_uuid, mds_uuid,
+                     size, journal_size, nspath, mkfsoptions)
+    lustre.appendChild(mdd)
                    
 
-def add_ost(gen, lustre, options, args):
-    lovname = ''
-    obdtype = 'obdfilter'
-    devname = ''
-    size = 0
-    fstype = 'extN'
-    
-    if options.has_key('node'):
-        node_name = options['node']
+def add_mgmt(gen, lustre, options):
+    node_name = get_option(options, 'node')
+    node_uuid = name2uuid(lustre, node_name)
+    mgmt_name = get_option(options, 'mgmt')
+    if not mgmt_name:
+        mgmt_name = new_name('MGMT_' + node_name)
+    mgmt_uuid = name2uuid(lustre, mgmt_name, fatal=0)
+    if not mgmt_uuid:
+        mgmt_uuid = new_uuid(mgmt_name)
+        mgmt = gen.mgmt(mgmt_name, mgmt_uuid, node_uuid)
+        lustre.appendChild(mgmt)
     else:
-        error("--ost requires a --node argument")
+        mgmt = lookup(lustre, mgmt_uuid)
+
+    node = findByName(lustre, node_name, "node")
+    node_add_profile(gen, node, 'mgmt', mgmt_uuid)
+
+def add_ost(gen, lustre, options):
+    node_name = get_option(options, 'node')
+    lovname = get_option(options, 'lov')
+    osdtype = get_option(options, 'osdtype')
 
-    if options.has_key('lov'):
-        lovname = options['lov']
+    node_uuid = name2uuid(lustre, node_name)
 
-    if options.has_key('obdtype'):
-        obdtype = options['obdtype']
-    if obdtype == 'obdecho':
+    if osdtype == 'obdecho':
+        fstype = ''
+        devname = ''
+        size = 0
         fstype = ''
+        journal_size = ''
     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')
+        fstype = get_option(options, 'fstype')
+        journal_size = get_option(options, 'journal_size')
         
-    obdname = new_name('OBD_'+ node_name)
-    oscname = new_name('OSC_'+ node_name)
-    ostname = new_name('OST_'+ node_name)
-    if options.has_key('obduuid'):
-        obd_uuid = options['obduuid']
-        obd = lookup(lustre, obd_uuid)
-        if obd:
-            error("Duplicate OBD UUID:", obd_uuid)
+    nspath = get_option(options, 'nspath')
+
+    ostname = get_option(options, 'ost')
+    if not ostname:
+        ostname = new_name('OST_'+ node_name)
+
+    osdname = new_name("OSD_" + ostname + "_" + node_name)
+    osd_uuid = new_uuid(osdname)
+
+    ost_uuid = name2uuid(lustre, ostname, fatal=0)
+    if not ost_uuid:
+        ost_uuid = get_option(options, 'ostuuid')
+        if ost_uuid:
+            if lookup(lustre, ost_uuid):
+                error("Duplicate OST UUID:", ost_uuid)
+        else:
+            ost_uuid = new_uuid(ostname)
+
+        ost = gen.ost(ostname, ost_uuid, osd_uuid, options.group)
+        lustre.appendChild(ost)
+        if lovname:
+            lov = findByName(lustre, lovname, "lov")
+            if not lov:
+                error('add_ost:', '"'+lovname+'"', "lov element not found.")
+            lov_add_obd(gen, lov, ost_uuid)
     else:
-        obd_uuid = new_uuid(obdname)
-    ost_uuid = new_uuid(ostname)
-    osc_uuid = new_uuid(oscname)
+        ost = lookup(lustre, ost_uuid)
 
-    net_uuid = get_net_uuid(lustre, node_name)
-    if not net_uuid:
-        error("NODE: ", node_name, "not found")
+    if options.failover:
+        ost.setAttribute('failover', "1")
     
-    obd = gen.obd(obdname, obd_uuid, fstype, obdtype, devname, get_format_flag(options), size)
-    ost = gen.ost(ostname, ost_uuid, obd_uuid, net_uuid)
-    osc = gen.osc(oscname, osc_uuid, obd_uuid, ost_uuid)
-    
-    if lovname:
-        lov = findByName(lustre, lovname, "lov")
-        if not lov:
-            error('add_ost:', '"'+lovname+'"', "lov element not found.")
-        lov_add_osc(gen, lov, osc_uuid)
+
+    osd = gen.osd(osdname, osd_uuid, fstype, osdtype, devname,
+                  get_format_flag(options), ost_uuid, node_uuid, size,
+                  journal_size, nspath)
 
     node = findByName(lustre, node_name, "node")
-    node_add_profile(gen, node, 'obd', obd_uuid)
-    node_add_profile(gen, node, 'ost', ost_uuid)
 
-    lustre.appendChild(obd)
-    lustre.appendChild(osc)
-    lustre.appendChild(ost)
+##     if node_add_profile(gen, node, 'oss', oss_uuid):
+##         ossname = 'OSS'
+##         oss_uuid = new_uuid(ossname)
+##         oss = gen.oss(ossname, oss_uuid)
+##         lustre.appendChild(oss)
+
+    node_add_profile(gen, node, 'osd', osd_uuid)
+    lustre.appendChild(osd)
 
                    
-# 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')
+    
+    real_uuid = name2uuid(lustre, real_name, tag='obd')
+    cache_uuid = name2uuid(lustre, cache_name, tag='obd')
+
     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)
+
+
+def add_echo_client(gen, lustre, options):
+    """ add an echo client to the profile for this node. """
+    node_name = get_option(options, 'node')
+    lov_name = get_option(options, 'ost')
 
+    node = findByName(lustre, node_name, 'node')
 
-def add_lov(gen, lustre, options, args):
+    echoname = new_name('ECHO_'+ node_name)
+    echo_uuid = new_uuid(echoname)
+    node_add_profile(gen, node, 'echoclient', echo_uuid)
+
+    lov_uuid = name2uuid(lustre, lov_name, tag='lov', fatal=0)
+    if not lov_uuid:
+        lov_uuid = name2uuid(lustre, lov_name, tag='ost', fatal=1)
+
+    echo = gen.echo_client(echoname, echo_uuid, lov_uuid)
+    lustre.appendChild(echo)
+
+
+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_int(options, 'stripe_sz')
+    stripe_cnt = get_option_int(options, 'stripe_cnt')
+    pattern = get_option_int(options, 'stripe_pattern')
     uuid = new_uuid(name)
 
     ret = findByName(lustre, name, "lov")
@@ -606,117 +836,96 @@ 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
+    # add an lovconfig entry to the active mdsdev profile
     lovconfig_name = new_name('LVCFG_' + name)
     lovconfig_uuid = new_uuid(lovconfig_name)
-    node = mds2node(lustre, mds_name)
-    node_add_profile(gen, node, "lovconfig", lovconfig_uuid)
+    mds = findByName(lustre, mds_name)
+    mds.appendChild(gen.ref("lovconfig", lovconfig_uuid))
     lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid)
     lustre.appendChild(lovconfig)
 
+def new_filesystem(gen, lustre, mds_uuid, obd_uuid, mgmt_uuid):
+    fs_name = new_name("FS_fsname")
+    fs_uuid = new_uuid(fs_name)
+    mds = lookup(lustre, mds_uuid)
+    mds.appendChild(gen.ref("filesystem", fs_uuid))
+    fs = gen.filesystem(fs_name, fs_uuid, mds_uuid, obd_uuid, mgmt_uuid)
+    lustre.appendChild(fs)
+    return fs_uuid
 
-
-def add_mtpt(gen, lustre, options, args):
+def get_fs_uuid(gen, lustre, mds_name, obd_name, mgmt_name):
+    mds_uuid = name2uuid(lustre, mds_name, tag='mds')
+    obd_uuid = name2uuid(lustre, obd_name, tag='lov', fatal=0)
+    if not obd_uuid:
+        obd_uuid = name2uuid(lustre, obd_name, tag='ost', fatal=1)
+    if mgmt_name:
+        mgmt_uuid = name2uuid(lustre, mgmt_name, tag='mgmt', fatal=1)
+    else:
+        mgmt_uuid = ''
+    fs_uuid = lookup_filesystem(lustre, mds_uuid, obd_uuid)
+    if not fs_uuid:
+        fs_uuid = new_filesystem(gen, lustre, mds_uuid, obd_uuid, mgmt_uuid)
+    return fs_uuid
+    
+def add_mtpt(gen, lustre, options):
     """ create mtpt on a node """
-    if len(args) < 3:
-        usage()
-
-    if options.has_key('node'):
-        node_name = options['node']
+    node_name = get_option(options, 'node')
+
+    path = get_option(options, 'path')
+    fs_name = get_option(options, 'filesystem')
+    if fs_name == '':
+        mds_name = get_option(options, 'mds')
+        lov_name = get_option(options, 'lov')
+        if lov_name == '':
+            lov_name = get_option(options, 'ost')
+            if lov_name == '':
+                error("--add mtpt requires either --filesystem or --mds with an  --lov lov_name or --ost ost_name")
+        mgmt_name = get_option(options, 'mgmt')
+        fs_uuid = get_fs_uuid(gen, lustre, mds_name, lov_name, mgmt_name)
     else:
-        error("--mtpt requires a --node argument")
-
-    path = args[0]
-    mds_name = args[1]
-    lov_name = args[2]
+        fs_uuid = name2uuid(lustre, fs_name, tag='filesystem')
 
     name = new_name('MNT_'+ node_name)
 
     ret = findByName(lustre, name, "mountpoint")
     if ret:
+        # this can't happen, because new_name creates unique names
         error("MOUNTPOINT: ", name, " already exists.")
 
-    mds_uuid = name2uuid(lustre, mds_name, tag='mds')
-    lov_uuid = name2uuid(lustre, lov_name, tag='lov', fatal=0)
-    if not lov_uuid:
-        lov_uuid = name2uuid(lustre, lov_name, tag='osc', fatal=1)
-
     uuid = new_uuid(name)
-    mtpt = gen.mountpoint(name, uuid, mds_uuid, lov_uuid, path)
+    mtpt = gen.mountpoint(name, uuid, fs_uuid, path)
     node = findByName(lustre, node_name, "node")
     if not node:
-            error('node:',  node_name, "not found.")
+        error('node:',  node_name, "not found.")
     node_add_profile(gen, node, "mountpoint", uuid)
     lustre.appendChild(mtpt)
 
-
 ############################################################
 # Command line processing
 #
-def parse_cmdline(argv):
-    short_opts = "ho:i:m:"
-    long_opts = ["ost", "osc", "mtpt", "lov=", "node=", "mds=", "net", "tcpbuf=",
-                 "route", "router", "merge=", "format", "reformat", "output=",
-                 "obdtype=", "obduuid=", "in=", "help", "batch="]
-    opts = []
-    args = []
-    options = {}
-    try:
-        opts, args = getopt.getopt(argv, short_opts, long_opts)
-    except getopt.error:
-        print "invalid opt"
-        usage()
-
-    for o, a in opts:
-        # Commands to create new devices
-        if o == "--ost":
-            options['ost'] = 1
-        if o == "--osc":
-            options['osc'] = 1
-        if o == "--mds":
-            options['mds'] = a
-        if o == "--net":
-            options['net'] = 1
-        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
-        if o == "--obdtype":
-            options['obdtype'] = a
-        if o == "--obduuid":
-            options['obduuid'] = a
-        if o == "--tcpbuf":
-            options['tcpbuf'] = a
-
-        # lmc options
-        if o in ("-h", "--help"):
-            usage()
-        if o in ("-o", "--output"):
-            options['output'] = a
-        if o in ("-m", "--merge"):
-            options['merge'] = a
-        if o == "--format":
-            options['format'] = 1
-        if o  == "--reformat":
-            options['reformat'] = 1
-        if o  == "--batch":
-            options['batch'] = a
-        if o  in ("--in" , "-i"):
-            options['in'] = a
-            
-    return options, args
+class OptionError (exceptions.Exception):
+    def __init__(self, args):
+        self.args = args
+
+def get_option(options, tag):
+    """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.__getattr__(tag) != None:
+        return options.__getattr__(tag)
+    else:
+        raise OptionError("--add %s requires --%s <value>" % (options.add, tag))
 
+def get_option_int(options, tag):
+    """Return an integer option.  Raise exception if the value is not an int"""
+    val = get_option(options, tag)
+    try:
+        n = int(val)
+    except ValueError:
+        raise OptionError("--%s <num> (value must be integer)" % (tag))        
+    return n
 
 # simple class for profiling
 import time
@@ -740,44 +949,66 @@ class chrono:
 ############################################################
 # Main
 #
+
+def add(devtype, gen, lustre, options):
+    if devtype == 'net':
+        add_net(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 == 'cobd':
+        add_cobd(gen, lustre, options)
+    elif devtype == 'mgmt':
+        add_mgmt(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('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.add:
+        add(options.add, gen, lustre, options)
     else:
-        print "Missing command"
-        usage()
+        error("Missing command")
 
 def main():
-    options, args = parse_cmdline(sys.argv[1:])
+    cl = Lustre.Options("lmc", "", lmc_options)
+    try:
+        options, args = cl.parse(sys.argv[1:])
+    except Lustre.OptionError, e:
+        panic("lmc", e)
+
+    if len(args) > 0:
+        panic(string.join(sys.argv), "Unexpected extra arguments on command line: " + string.join(args))
+
+    if options.reference:
+        reference()
+        sys.exit(0)
+
     outFile = '-'
 
-    if options.has_key('merge'):
-        outFile = options['merge']
+    if options.merge:
+        outFile = options.merge
         if os.access(outFile, os.R_OK):
             doc = xml.dom.minidom.parse(outFile)
         else:
             doc = new_lustre(xml.dom.minidom)
-    elif options.has_key('in'):
-        doc = xml.dom.minidom.parse(options['in'])
+    elif options.input:
+        doc = xml.dom.minidom.parse(options.input)
     else:
         doc = new_lustre(xml.dom.minidom)
 
-    if options.has_key('output'):
-        outFile = options['output']
+    if options.output:
+        outFile = options.output
 
     lustre = doc.documentElement
     init_names(lustre)
@@ -787,15 +1018,34 @@ def main():
 
     gen = GenConfig(doc)
 
-    if options.has_key('batch'):
-        fp = open(options['batch'])
+    # the PRNG is normally seeded with time(), which is not so good for starting    # time-synchronized clusters
+    input = open('/dev/urandom', 'r')
+    if not input:
+        print 'Unable to open /dev/urandom!'
+        sys.exit(1)
+    seed = input.read(32)
+    input.close()
+    random.seed(seed)
+
+    if options.batch:
+        fp = open(options.batch)
         batchCommands = fp.readlines()
         fp.close()
         for cmd in batchCommands:
-            options, args = parse_cmdline(string.split(cmd))
-            do_command(gen, lustre, options, args)
+            try:
+                options, args = cl.parse(string.split(cmd))
+                do_command(gen, lustre, options, args)
+            except OptionError, e:
+                panic(cmd, e)
+            except Lustre.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)
+        except Lustre.OptionError, e:
+            panic("lmc", e)
 
     if outFile == '-':
         PrettyPrint(doc)
@@ -804,5 +1054,3 @@ def main():
 
 if __name__ == "__main__":
     main()
-
-