Whamcloud - gitweb
Fix OST AMD - mark new OST active when it is added.
[fs/lustre-release.git] / lustre / utils / lmc
index 76757a7..335572a 100755 (executable)
 #
 
 """
 #
 
 """
-lmc - lustre configurtion data  manager
+lmc - lustre configuration data manager
 
 
-  See lustre book for documentation for lmc.
+  See Lustre book (http://www.lustre.org/docs/lustre.pdf) for documentation on lmc.
 
 """
 
 
 """
 
-import sys, os, getopt, string, exceptions
+import sys, os, getopt, string, exceptions, re
 import xml.dom.minidom
 import xml.dom.minidom
-from xml.dom.ext import PrettyPrint
 
 
-DEFAULT_PORT = 988 
+def printDoc(doc, stream=sys.stdout):
+    try:
+        from xml.dom.ext import PrettyPrint
+        PrettyPrint(doc, stream)
+    except ImportError:
+        stream.write(doc.toxml())
+        stream.write("\n")
+
+
+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)
 
 
-def usage():
+import Lustre
+
+DEFAULT_PORT = 988
+DEFAULT_STRIPE_SZ = 1048576
+DEFAULT_STRIPE_CNT = 1
+DEFAULT_STRIPE_PATTERN = 0
+UUID_MAX_LENGTH = 31
+
+def reference():
     print """usage: lmc --add object [object parameters]
 
 Object creation command summary:
     print """usage: lmc --add object [object parameters]
 
 Object creation command summary:
@@ -39,25 +64,38 @@ Object creation command summary:
 --add node
   --node node_name
   --timeout num
 --add node
   --node node_name
   --timeout num
-  --recovery_upcall path
+  --upcall path
+  --lustre_upcall path
+  --portals_upcall path
+  --ptldebug debug_level
+  --subsystem subsystem_name
 
 --add net
   --node node_name
   --nid nid
 
 --add net
   --node node_name
   --nid nid
-  --nettype tcp|elan|toe|gm
+  --cluster_id
+  --nettype tcp|elan|gm
   --hostaddr addr
   --port port
   --tcpbuf size
   --irq_affinity 0|1
   --hostaddr addr
   --port port
   --tcpbuf size
   --irq_affinity 0|1
-  --nid_exchange 0|1
   --router
 
 --add mds
   --node node_name
   --mds mds_name
   --router
 
 --add mds
   --node node_name
   --mds mds_name
+  --failover
   --dev path
   --dev path
-  --fstype extN|ext3
+  --backdev path
+  --fstype ldiskfs|ext3
+  --backfstype ldiskfs|ext3|tmpfs
   --size size
   --size size
+  --nspath
+  --journal_size size
+  --inode_size size
+  --lmv lmv_name
+  --mkfsoptions options
+  --mountfsoptions options
 
 --add lov
   --lov lov_name
 
 --add lov
   --lov lov_name
@@ -65,23 +103,168 @@ Object creation command summary:
   --stripe_sz num
   --stripe_cnt num
   --stripe_pattern num
   --stripe_sz num
   --stripe_cnt num
   --stripe_pattern num
+  --lmv lmv_name
 
 
--add ost
+--add ost
   --node node_name
   --ost ost_name 
   --node node_name
   --ost ost_name 
+  --failover
   --lov lov_name 
   --lov lov_name 
+  --index index
   --dev path
   --dev path
+  --backdev path
   --size size
   --size size
-  --fstype extN|ext3
+  --fstype ldiskfs|ext3
+  --backfstype ldiskfs|ext3|tmpfs
+  --journal_size size
+  --inode_size size
+  --osdtype obdecho|obdfilter
   --ostuuid uuid
   --ostuuid uuid
-  
+  --mkfsoptions options
+  --mountfsoptions options
+  --nspath
+--delete ost
+  --node node_name
+  --ost ost_name
+  --migrate
+--deactivate ost
+  --node node_name
+  --ost ost_name
+
 --add mtpt  - Mountpoint
   --node node_name
   --path /mnt/point
   --mds mds_name
 --add mtpt  - Mountpoint
   --node node_name
   --path /mnt/point
   --mds mds_name
+  --lmv lmv_name
   --ost ost_name OR --lov lov_name
   --ost ost_name OR --lov lov_name
+  --clientoptions options
+
+--add route
+  --node nodename
+  --router
+  --gw nid
+  --gateway_cluster_id nid
+  --target_cluster_id nid
+  --lo nid
+  --hi nid
+
+--add echo_client
+  --node nodename
+
+--add mgmt  - Management/monitoring service
+  --node node_name
+  --mgmt mgmt_service_name
+
+--add lmv
+  --lmv lmv_name
+
+--add cobd
+  --node node_name
+  --real_obd obd_name
+  --cache_obd obd_name
+
+--add cmobd
+  --node node_name
+  --master_dev obd_name
+  --cache_dev  obd_name
+
+--commit - Close a configuration version, and start a new one
 """
 """
-    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),
+    ('delete', "", PARAM),
+    ('deactivate', "", PARAM),
+    ('commit', "Commit all config changes and start a new version"),
+
+    # 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.", 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,""),
+    ('backdev', "Path of the device for backing storage on local system.", PARAM,""),
+    ('size', "Specify the size of the device if needed.", PARAM,"0"),
+    ('journal_size', "Specify new journal size for underlying file system.", PARAM,"0"),
+    ('inode_size', "Specify new inode size for underlying file system.", PARAM,"0"),
+    ('fstype', "Optional argument to specify the filesystem type.", PARAM, "ext3"),
+    ('backfstype', "Optional argument to specify the backing filesystem type.", PARAM, "ext3"),
+    ('mkfsoptions', "Optional argument to mkfs.", PARAM, ""),
+    ('mountfsoptions', "Optional argument to mount fs.", PARAM, ""),
+    ('ostuuid', "", PARAM,""),
+    ('nspath', "Local mount point of server namespace.", PARAM,""),
+    ('format', ""),
+    ('migrate', "used for offline migrate of an ost in conjunctio with add/delete"),
+
+    # clients: mountpoint and echo
+    ('echo_client', "", PARAM),
+    ('path', "Specify the mountpoint for Lustre.", PARAM),
+    ('filesystem', "Lustre filesystem name", PARAM,""),
+    ('clientoptions', "Specify the options for Lustre, such as async.", PARAM, ""),
+
+    # lov
+    ('lov', "Specify LOV name.", PARAM,""),
+    ('index', "Specify index for OBD in LOV target table.", 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', "Specify the real device for the cache obd system.", PARAM),
+    ('cache_obd', "Specify the cache device for the cache obd system.", PARAM),
+    ('cobd', "Specify COBD name", PARAM),
+
+    # cmobd
+    ('master_dev', "Specify the master device for the cmobd system.", PARAM),
+    ('cache_dev',  "Specify the cache device for the cmobd obd system.", PARAM),
+    ('cmobd',      "Specify COBD name", PARAM),
+
+
+    ('mgmt', "Specify management/monitoring service name.", PARAM, ""),
+
+    # lmv
+    ('lmv', "Specify LMV name.", PARAM,""),
+    ]
 
 def error(*args):
     msg = string.join(map(str,args))
 
 def error(*args):
     msg = string.join(map(str,args))
@@ -92,11 +275,11 @@ def panic(cmd, msg):
     print msg
     sys.exit(1)
 
     print msg
     sys.exit(1)
 
-    
+
 def warning(*args):
     msg = string.join(map(str,args))
     print "Warning: ", msg
 def warning(*args):
     msg = string.join(map(str,args))
     print "Warning: ", msg
-    
+
 #
 # manage names and uuids
 # need to initialize this by walking tree to ensure
 #
 # manage names and uuids
 # need to initialize this by walking tree to ensure
@@ -113,22 +296,28 @@ def new_name(base):
     return ret
 
 def new_uuid(name):
     return ret
 
 def new_uuid(name):
-    return "%s_UUID" % (name)
+    ctr = 2
+    ret = "%s_UUID" % (name)
+    if len(ret) > UUID_MAX_LENGTH:
+        ret = ret[-UUID_MAX_LENGTH:]
+    while uuids.has_key(ret):
+        ret = "%s_UUID_%d" % (name, ctr)
+        ctr = 1 + ctr
+        if len(ret) > UUID_MAX_LENGTH:
+            ret = ret[-UUID_MAX_LENGTH:]
+    uuids[ret] = 1
+    return ret
+
 
 ldlm_name = 'ldlm'
 ldlm_uuid = 'ldlm_UUID'
 
 
 ldlm_name = 'ldlm'
 ldlm_uuid = 'ldlm_UUID'
 
-ptlrpc_name = 'RPCDEV'
-ptlrpc_uuid = 'RPCDEV_UUID'
-
 def new_lustre(dom):
     """Create a new empty lustre document"""
     # adding ldlm here is a bit of a hack, but one is enough.
 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"/>
     <ldlm name="%s" uuid="%s"/>
-    <ptlrpc name="%s" uuid="%s"/>
-    </lustre>""" % (ldlm_name, ldlm_uuid,
-                    ptlrpc_name, ptlrpc_uuid)
+    </lustre>""" % (Lustre.CONFIG_VERSION, ldlm_name, ldlm_uuid)
     return dom.parseString(str)
 
 names = {}
     return dom.parseString(str)
 
 names = {}
@@ -146,9 +335,8 @@ def init_names(doc):
             init_names(n)
 
 def get_format_flag(options):
             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'
 
 ############################################################
     return 'no'
 
 ############################################################
@@ -166,14 +354,20 @@ class GenConfig:
         ref = self.doc.createElement(tag)
         ref.setAttribute("uuidref", uuid)
         return ref
         ref = self.doc.createElement(tag)
         ref.setAttribute("uuidref", uuid)
         return ref
-    
+       
+    def dev(self, devname):
+        """ generate <dev devpath="[devname]"/> """
+       tgt = self.doc.createElement('dev')
+        tgt.setAttribute("dev", devname)
+       return tgt
+
     def newService(self, tag, name, uuid):
         """ create a new  service elmement, which requires name and uuid attributes """
         new = self.doc.createElement(tag)
         new.setAttribute("uuid", uuid);
         new.setAttribute("name", name);
         return new
     def newService(self, tag, name, uuid):
         """ create a new  service elmement, which requires name and uuid attributes """
         new = self.doc.createElement(tag)
         new.setAttribute("uuid", uuid);
         new.setAttribute("name", name);
         return new
-    
+
     def addText(self, node, str):
         txt = self.doc.createTextNode(str)
         node.appendChild(txt)
     def addText(self, node, str):
         txt = self.doc.createTextNode(str)
         node.appendChild(txt)
@@ -187,11 +381,13 @@ class GenConfig:
         node.appendChild(new)
         return new
 
         node.appendChild(new)
         return new
 
-    def network(self, name, uuid, nid, net, hostaddr="", port=0, tcpbuf=0, irq_aff=0, nid_xchg=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("nettype", net);
         self.addElement(network, "nid", nid)
         """create <network> node"""
         network = self.newService("network", name, uuid)
         network.setAttribute("nettype", net);
         self.addElement(network, "nid", nid)
+        self.addElement(network, "clusterid", cluster_id)
         if hostaddr:
             self.addElement(network, "hostaddr", hostaddr)
         if port:
         if hostaddr:
             self.addElement(network, "hostaddr", hostaddr)
         if port:
@@ -201,26 +397,26 @@ class GenConfig:
             self.addElement(network, "recvmem", "%d" %(tcpbuf))
         if irq_aff:
             self.addElement(network, "irqaffinity", "%d" %(irq_aff))
             self.addElement(network, "recvmem", "%d" %(tcpbuf))
         if irq_aff:
             self.addElement(network, "irqaffinity", "%d" %(irq_aff))
-        if nid_xchg:
-            self.addElement(network, "nidexchange", "%d" %(nid_xchg))
-            
+
         return network
 
     def routetbl(self, name, uuid):
         """create <routetbl> node"""
         rtbl = self.newService("routetbl", name, uuid)
         return rtbl
         return network
 
     def routetbl(self, name, uuid):
         """create <routetbl> node"""
         rtbl = self.newService("routetbl", name, uuid)
         return rtbl
-        
-    def route(self, net_type, gw, lo, hi):
+
+    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')
         """ 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("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
         ref.setAttribute("lo", lo)
         if hi:
             ref.setAttribute("hi", hi)
         return ref
-    
+
     def profile(self, name, uuid):
         """ create a host """
         profile = self.newService("profile", name, uuid)
     def profile(self, name, uuid):
         """ create a host """
         profile = self.newService("profile", name, uuid)
@@ -237,18 +433,36 @@ class GenConfig:
         ldlm = self.newService("ldlm", name, uuid)
         return ldlm
 
         ldlm = self.newService("ldlm", name, uuid)
         return ldlm
 
-    def osd(self, name, uuid, fs, osdtype, devname, format, ost_uuid, node_uuid, dev_size=0):
+    def osd(self, name, uuid, fstype, osdtype, devname, format, ost_uuid,
+            node_uuid, dev_size=0, journal_size=0, inode_size=0, nspath="", 
+            mkfsoptions="", mountfsoptions="", backfstype="", backdevname=""):
         osd = self.newService("osd", name, uuid)
         osd.setAttribute('osdtype', osdtype)
         osd.appendChild(self.ref("target", ost_uuid))
         osd.appendChild(self.ref("node", node_uuid))
         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(osd, "fstype", fs)
+       osd.appendChild(self.dev(devname)) 
+
+       if fstype:
+            self.addElement(osd, "fstype", fstype)
+        if backfstype:
+            self.addElement(osd, "backfstype", backfstype)
+        if backdevname:
+            self.addElement(osd, "backdevpath", backdevname)
         if devname:
             dev = self.addElement(osd, "devpath", devname)
             self.addElement(osd, "autoformat", format)
             if dev_size:
                 self.addElement(osd, "devsize", "%s" % (dev_size))
         if devname:
             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 inode_size:
+                self.addElement(osd, "inodesize", "%s" % (inode_size))
+            if mkfsoptions:
+                self.addElement(osd, "mkfsoptions", mkfsoptions)
+            if mountfsoptions:
+                self.addElement(osd, "mountfsoptions", mountfsoptions)
+        if nspath:
+            self.addElement(osd, "nspath", nspath)
         return osd
 
     def cobd(self, name, uuid, real_uuid, cache_uuid):
         return osd
 
     def cobd(self, name, uuid, real_uuid, cache_uuid):
@@ -257,9 +471,17 @@ class GenConfig:
         cobd.appendChild(self.ref("cacheobd",cache_uuid))
         return cobd
 
         cobd.appendChild(self.ref("cacheobd",cache_uuid))
         return cobd
 
-    def ost(self, name, uuid, osd_uuid):
+    def cmobd(self, name, uuid, real_uuid, cache_uuid):
+        cmobd = self.newService("cmobd", name, uuid)
+        cmobd.appendChild(self.ref("masterobd",real_uuid))
+        cmobd.appendChild(self.ref("cacheobd",cache_uuid))
+        return cmobd
+
+    def ost(self, name, uuid, osd_uuid, group=""):
         ost = self.newService("ost", name, uuid)
         ost.appendChild(self.ref("active", osd_uuid))
         ost = self.newService("ost", name, uuid)
         ost.appendChild(self.ref("active", osd_uuid))
+        if group:
+            self.addElement(ost, "group", group)
         return ost
 
     def oss(self, name, uuid):
         return ost
 
     def oss(self, name, uuid):
@@ -274,40 +496,117 @@ class GenConfig:
         lov.setAttribute("stripepattern", str(pattern))
         return lov
 
         lov.setAttribute("stripepattern", str(pattern))
         return lov
 
+    def lov_tgt(self, obd_uuid, index, generation):
+        tgt = self.doc.createElement('lov_tgt')
+        tgt.setAttribute("uuidref", obd_uuid)
+        tgt.setAttribute("index", index)
+        tgt.setAttribute("generation", generation)
+        tgt.setAttribute("active", '1')
+        return tgt
+
     def lovconfig(self, name, uuid, lov_uuid):
         lovconfig = self.newService("lovconfig", name, uuid)
         lovconfig.appendChild(self.ref("lov", lov_uuid))
         return lovconfig
 
     def lovconfig(self, name, uuid, lov_uuid):
         lovconfig = self.newService("lovconfig", name, uuid)
         lovconfig.appendChild(self.ref("lov", lov_uuid))
         return lovconfig
 
-    def mds(self, name, uuid, mdd_uuid):
+    def lmv(self, name, uuid):
+        lmv = self.newService("lmv", name, uuid)
+        return lmv
+
+    def mds(self, name, uuid, mdd_uuid, group="", lmv=""):
         mds = self.newService("mds", name, uuid)
         mds.appendChild(self.ref("active",mdd_uuid))
         mds = self.newService("mds", name, uuid)
         mds.appendChild(self.ref("active",mdd_uuid))
+        if group:
+            self.addElement(mds, "group", group)
         return mds
 
         return mds
 
-    def mdsdev(self, name, uuid, fs, devname, format, node_uuid,
-            mds_uuid, dev_size=0 ):
+    def mdsdev(self, name, uuid, fstype, devname, format, node_uuid,
+               mds_uuid, dev_size=0, journal_size=0, inode_size=256,
+               nspath="", mkfsoptions="", mountfsoptions="", backfstype="", 
+               backdevname="", lmv_uuid=""):
         mdd = self.newService("mdsdev", name, uuid)
         mdd = self.newService("mdsdev", name, uuid)
-        self.addElement(mdd, "fstype", fs)
+        self.addElement(mdd, "fstype", fstype)
+        if backfstype:
+                self.addElement(mdd, "backfstype", backfstype)
         dev = self.addElement(mdd, "devpath", devname)
         dev = self.addElement(mdd, "devpath", devname)
+        if backdevname:
+            self.addElement(mdd, "backdevpath", backdevname)
         self.addElement(mdd, "autoformat", format)
         if dev_size:
                 self.addElement(mdd, "devsize", "%s" % (dev_size))
         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 inode_size:
+            self.addElement(mdd, "inodesize", "%s" % (inode_size))
+        if nspath:
+            self.addElement(mdd, "nspath", nspath)
+        if mkfsoptions:
+            self.addElement(mdd, "mkfsoptions", mkfsoptions)
+        if mountfsoptions:
+            self.addElement(mdd, "mountfsoptions", mountfsoptions)
+
         mdd.appendChild(self.ref("node", node_uuid))
         mdd.appendChild(self.ref("target", mds_uuid))
         mdd.appendChild(self.ref("node", node_uuid))
         mdd.appendChild(self.ref("target", mds_uuid))
+       mdd.appendChild(self.dev(devname)) 
+       
+       if lmv_uuid:
+            mdd.appendChild(self.ref("lmv", lmv_uuid))
+           self.addElement(mdd, "lmv", lmv_uuid)
+
         return mdd
 
         return mdd
 
-    def mountpoint(self, name, uuid, mds_uuid, osc_uuid, path):
+    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, clientoptions):
         mtpt = self.newService("mountpoint", name, uuid)
         mtpt = self.newService("mountpoint", name, uuid)
-        mtpt.appendChild(self.ref("mds", mds_uuid))
-        mtpt.appendChild(self.ref("obd", osc_uuid))
+        mtpt.appendChild(self.ref("filesystem", fs_uuid))
         self.addElement(mtpt, "path", path)
         self.addElement(mtpt, "path", path)
+        if clientoptions:
+            self.addElement(mtpt, "clientoptions", clientoptions)
         return mtpt
 
         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
 
     def echo_client(self, name, uuid, osc_uuid):
         ec = self.newService("echoclient", name, uuid)
         ec.appendChild(self.ref("obd", osc_uuid))
         return ec
 
+    def update(self, version):
+        new = self.doc.createElement("update")
+        new.setAttribute("version", version)
+        return new
+
+    def add(self, lov, ost, index, gen):
+        new = self.doc.createElement("add")
+        new.setAttribute("lov_uuidref", lov)
+        new.setAttribute("ost_uuidref", ost)
+        new.setAttribute("index", index)
+        new.setAttribute("generation", gen)
+        return new
+
+    def delete(self, lov, ost, index, gen, options):
+        if options.delete:
+            new = self.doc.createElement("delete")
+        else:
+            new = self.doc.createElement("deactivate")
+        new.setAttribute("lov_uuidref", lov)
+        new.setAttribute("ost_uuidref", ost)
+        new.setAttribute("index", index)
+        new.setAttribute("generation", gen)
+        return new
+
 ############################################################
 # Utilities to query a DOM tree
 # Using this functions we can treat use config information
 ############################################################
 # Utilities to query a DOM tree
 # Using this functions we can treat use config information
@@ -318,6 +617,40 @@ def getName(n):
 def getUUID(node):
     return node.getAttribute('uuid')
 
 def getUUID(node):
     return node.getAttribute('uuid')
 
+def findLastUpdate(lustre):
+    node = None
+    version = 0
+    for n in lustre.childNodes:
+        if n.nodeType == n.ELEMENT_NODE:
+            if n.nodeName != 'update':
+                continue
+            tmp = int(n.getAttribute('version'))
+            if not tmp:
+                error('malformed XML: update tag without a version attribute')
+            if tmp != version + 1:
+                error('malformed XML: expecting update record '+str(version + 1)+', found '+str(tmp)+'.')
+            version = tmp
+            node = n
+    return node
+
+def addUpdate(gen, lustre, node):
+    update = findLastUpdate(lustre)
+    if not update:
+        return
+    #add_record = update.getElementsByTagName('add')
+    #if not add_record:
+    #    add_record = gen.add()
+    #    update.appendChild(add_record)
+    #else:
+    #    add_record = add_record[0]
+    #add_record.appendChild(node)
+    update.appendChild(node)
+
+def delUpdate(gen, lustre, node):
+    update = findLastUpdate(lustre)
+    if not update:
+        return
+    update.appendChild(node)
 
 def findByName(lustre, name, tag = ""):
     for n in lustre.childNodes:
 
 def findByName(lustre, name, tag = ""):
     for n in lustre.childNodes:
@@ -351,7 +684,13 @@ def name2uuid(lustre, name, tag="",  fatal=1):
         else:
             return ""
     return getUUID(ret)
         else:
             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
 
 # XXX: assumes only one network element per node. will fix this
 # as soon as support for routers is added
@@ -365,9 +704,91 @@ def get_net_uuid(lustre, node_name):
         return getUUID(net[0])
     return None
 
         return getUUID(net[0])
     return None
 
-
-def lov_add_obd(gen, lov, osc_uuid):
-    lov.appendChild(gen.ref("obd", osc_uuid))
+def lov_mod_obd(gen, lustre, lov, tgt, osc_uuid, options):
+    tgt.setAttribute('uuidref', osc_uuid)
+    if options.migrate:
+        gener = int(tgt.getAttribute('generation'))
+    else:
+        gener = int(tgt.getAttribute('generation')) + 1
+    tgt.setAttribute('generation', str(gener))
+    tgt.setAttribute('active', '1')
+    lov_index = int(tgt.getAttribute('index'))
+    addUpdate(gen, lustre, gen.add(getUUID(lov), osc_uuid, str(lov_index),
+              str(gener)))
+    return
+
+def lov_add_obd(gen, lustre, lov, osc_uuid, options):
+    lov_name = getName(lov)
+    if options.index:
+        lov_index = get_option_int(options, 'index')
+        for tgt in lustre.getElementsByTagName('lov_tgt'):
+            if str(lov_index) == tgt.getAttribute('index'):
+                uuidref = tgt.getAttribute('uuidref')
+                if uuidref != '':
+                    raise OptionError("%s --index %d is still in use: %s" %
+                                      (lov_name, lov_index, uuidref))
+                lov_mod_obd(gen, lustre, lov, tgt, osc_uuid, options)
+                return
+    else:
+         lov_index = 0
+         for tgt in lustre.getElementsByTagName('lov_tgt'):
+             uuidref = tgt.getAttribute('uuidref')
+             tmp = int(tgt.getAttribute('index'))
+             if tmp != lov_index:
+                 error('malformed xml: LOV targets are not ordered; found index '+str(tmp)+', expected '+str(lov_index)+'.')
+             uuidref = tgt.getAttribute('uuidref')
+             if uuidref == '':
+                 lov_mod_obd(gen, lustre, lov, tgt, osc_uuid, options)
+                 return
+             lov_index = lov_index + 1
+
+    lov.appendChild(gen.lov_tgt(osc_uuid, str(lov_index), '1'))
+    addUpdate(gen, lustre, gen.add(getUUID(lov), osc_uuid, str(lov_index), '1'))
+
+def lov_del_obd(gen, lustre, lov, osc_uuid, options):
+    lov_name = getName(lov)
+    if options.index:
+        lov_index = get_option_int(options, 'index')
+        for tgt in lustre.getElementsByTagName('lov_tgt'):
+            index = tgt.getAttribute('index')
+            if index == lov_index:
+                uuidref = tgt.getAttribute('uuidref')
+                if uuidref != osc_uuid:
+                    raise OptionError("%s --index %d contains %s, not %s" %
+                                      (lov_name, lov_index, osc_uuid, uuidref))
+                if options.delete:
+                    tgt.setAttribute('uuidref', '')
+
+                # bump the generation just in case...
+                if options.migrate:
+                    gen = int(tgt.getAttribute('generation'))
+                else:
+                    gen = int(tgt.getAttribute('generation')) + 1
+
+                tgt.setAttribute('active', '0')
+                tgt.setAttribute('generation', str(gen))
+                return
+        raise OptionError("%s --index %d not in use by %s." %
+                          (lov_name, lov_index, osc_uuid))
+
+    for tgt in lustre.getElementsByTagName('lov_tgt'):
+        uuidref = tgt.getAttribute('uuidref')
+        if uuidref == osc_uuid:
+            genera = int(tgt.getAttribute('generation'))
+            delete_rec = gen.delete(getUUID(lov),
+                                    osc_uuid,tgt.getAttribute('index'),
+                                    str(genera), options)
+            delUpdate(gen, lustre, delete_rec)
+
+            if options.delete:
+                tgt.setAttribute('uuidref', '')
+            if not options.migrate:
+                genera = genera + 1
+            tgt.setAttribute('active', '0')
+            tgt.setAttribute('generation', str(genera))
+
+def lmv_add_obd(gen, lmv, mdc_uuid):
+    lmv.appendChild(gen.ref("mds", mdc_uuid))
                             
 def ref_exists(profile, uuid):
     elist = profile.childNodes
                             
 def ref_exists(profile, uuid):
     elist = profile.childNodes
@@ -377,7 +798,7 @@ def ref_exists(profile, uuid):
             if ref == uuid:
                 return 1
     return 0
             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):
 # ensure that uuid is not already in the profile
 # return true if uuid is added
 def node_add_profile(gen, node, ref, uuid):
@@ -393,7 +814,41 @@ def node_add_profile(gen, node, ref, uuid):
         return 0
     profile.appendChild(gen.ref(ref, uuid))
     return 1
         return 0
     profile.appendChild(gen.ref(ref, uuid))
     return 1
-    
+
+# ensure that uuid is not already in the profile
+# return true if uuid is added
+def node_found_target_by_dev(gen, lustre, node, devname):
+    refname = "%s_ref" % "profile"
+    ret = node.getElementsByTagName(refname)
+    if not ret:
+        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)
+   
+    osd_list = lustre.getElementsByTagName('osd')
+
+    for osd in osd_list:
+       obd_dev = osd.getElementsByTagName('dev') 
+       if obd_dev and obd_dev[0].getAttribute('dev') == devname:
+           for ost in lustre.getElementsByTagName('ost'):
+               active_ret = ost.getElementsByTagName('active_ref')
+               if active_ret[0].getAttribute('uuidref') == osd.getAttribute('uuid'):
+                       return ost.getAttribute('uuid')
+    mdsdev_list = lustre.getElementsByTagName('mdsdev')
+
+    for mdsdev in mdsdev_list:
+       obd_dev = mdsdev.getElementsByTagName('dev') 
+       if obd_dev and obd_dev[0].getAttribute('dev') == devname:
+           for mds in lustre.getElementsByTagName('mds'):
+               active_ret = mds.getElementsByTagName('active_ref')
+               if active_ret[0].getAttribute('uuidref') == mdsdev.getAttribute('uuid'):
+                       return mds.getAttribute('uuid')
+   
+    return "" 
+
 def get_attr(dom_node, attr, default=""):
     v = dom_node.getAttribute(attr)
     if v:
 def get_attr(dom_node, attr, default=""):
     v = dom_node.getAttribute(attr)
     if v:
@@ -403,6 +858,31 @@ def get_attr(dom_node, attr, default=""):
 ############################################################
 # Top level commands
 #
 ############################################################
 # 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)
     prof_name = new_name("PROFILE_" + node_name)
 def do_add_node(gen, lustre,  options, node_name):
     uuid = new_uuid(node_name)
     prof_name = new_name("PROFILE_" + node_name)
@@ -413,16 +893,11 @@ def do_add_node(gen, lustre,  options, node_name):
     lustre.appendChild(profile)
 
     node_add_profile(gen, node, 'ldlm', ldlm_uuid)
     lustre.appendChild(profile)
 
     node_add_profile(gen, node, 'ldlm', ldlm_uuid)
-    node_add_profile(gen, node, 'ptlrpc', ptlrpc_uuid)
-    if has_option(options, 'router'):
-        node.setAttribute('router', '1')
-    if has_option(options, 'timeout'):
-        node.setAttribute('timeout', get_option(options, 'timeout'))
-    if has_option(options, 'recovery_upcall'):
-        node.setAttribute('recovery_upcall', get_option(options, 'recovery_upcall'))
+    set_node_options(gen, node, options)
+
     return node
 
     return node
 
-    
+
 def add_node(gen, lustre, options):
     """ create a node with a network config """
 
 def add_node(gen, lustre, options):
     """ create a node with a network config """
 
@@ -439,19 +914,18 @@ def add_net(gen, lustre, options):
 
     node_name = get_option(options, 'node')
     nid = get_option(options, 'nid')
 
     node_name = get_option(options, 'node')
     nid = get_option(options, 'nid')
-    hostaddr = get_option(options, 'hostaddr', '')
+    cluster_id = get_option(options, 'cluster_id')
+    hostaddr = get_option(options, 'hostaddr')
     net_type = get_option(options, 'nettype')
 
     net_type = get_option(options, 'nettype')
 
-    if net_type in ('tcp', 'toe'):
-        port = get_option_int(options, 'port', DEFAULT_PORT)
-        tcpbuf = get_option_int(options, 'tcpbuf', 0)
-        irq_aff = get_option_int(options, 'irq_affinity', 0)
-        nid_xchg = get_option_int(options, 'nid_exchange', 0)
+    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'):
         port = 0
         tcpbuf = 0
         irq_aff = 0
     elif net_type in ('elan', 'gm'):
         port = 0
         tcpbuf = 0
         irq_aff = 0
-        nid_xchg = 0
     else:
         print "Unknown net_type: ", net_type
         sys.exit(2)
     else:
         print "Unknown net_type: ", net_type
         sys.exit(2)
@@ -461,9 +935,12 @@ def add_net(gen, lustre, options):
         node = do_add_node(gen, lustre, options, node_name)
     else:
         node = ret
         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)
     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, hostaddr, port, tcpbuf, irq_aff, nid_xchg))
+    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)
 
 
     node_add_profile(gen, node, "network", net_uuid)
 
 
@@ -471,15 +948,19 @@ def add_route(gen, lustre, options):
     """ create a node with a network config """
 
     node_name = get_option(options, 'node')
     """ create a node with a network config """
 
     node_name = get_option(options, 'node')
-    net_type = get_option(options, 'nettype')
+    gw_net_type = get_option(options, 'nettype')
     gw = get_option(options, 'gw')
     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')
     lo = get_option(options, 'lo')
-    hi = get_option(options, 'hi', '')
+    hi = get_option(options, 'hi')
+    if not hi:
+        hi = lo
 
     node = findByName(lustre, node_name, "node")
     if not node:
         error (node_name, " not found.")
 
     node = findByName(lustre, node_name, "node")
     if not node:
         error (node_name, " not found.")
-    
+
     rlist = node.getElementsByTagName('routetbl')
     if len(rlist) > 0:
         rtbl = rlist[0]
     rlist = node.getElementsByTagName('routetbl')
     if len(rlist) > 0:
         rtbl = rlist[0]
@@ -489,24 +970,47 @@ def add_route(gen, lustre, options):
         rtbl = gen.routetbl(rtbl_name, rtbl_uuid)
         node.appendChild(rtbl)
         node_add_profile(gen, node, "routetbl", rtbl_uuid)
         rtbl = gen.routetbl(rtbl_name, rtbl_uuid)
         node.appendChild(rtbl)
         node_add_profile(gen, node, "routetbl", rtbl_uuid)
-    rtbl.appendChild(gen.route(net_type, gw, lo, hi))
+    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')
 
 
 def add_mds(gen, lustre, options):
     node_name = get_option(options, 'node')
     mds_name = get_option(options, 'mds')
+    lmv_name = get_option(options, 'lmv')
     mdd_name = new_name("MDD_" + mds_name +"_" + node_name)
     mdd_uuid = new_uuid(mdd_name)
 
     mdd_name = new_name("MDD_" + mds_name +"_" + node_name)
     mdd_uuid = new_uuid(mdd_name)
 
-    mds_uuid = name2uuid(lustre, mds_name, fatal=0)
+    lmv_uuid = ""
+    if lmv_name:
+        lmv = findByName(lustre, lmv_name, "lmv")
+        if not lmv:
+            error('add_mds:', '"' + lmv_name + '"', "lmv element not found.")
+        lmv_uuid = name2uuid(lustre, lmv_name, fatal=0)
+
+    mds_uuid = name2uuid(lustre, mds_name, 'mds', fatal=0)
     if not mds_uuid:
         mds_uuid = new_uuid(mds_name)
     if not mds_uuid:
         mds_uuid = new_uuid(mds_name)
-        mds = gen.mds(mds_name, mds_uuid, mdd_uuid)
+        mds = gen.mds(mds_name, mds_uuid, mdd_uuid, options.group)
         lustre.appendChild(mds)
         lustre.appendChild(mds)
-        
+        if lmv_name:
+            lmv_add_obd(gen, lmv, mds_uuid)
+    else:
+        mds = lookup(lustre, mds_uuid)
+
+    if options.failover:
+        mds.setAttribute('failover', "1")
+
     devname = get_option(options, 'dev')
     devname = get_option(options, 'dev')
-    size = get_option(options, 'size', 0)
-    fstype = get_option(options, 'fstype', 'extN')
+    backdevname = get_option(options, 'backdev')
+    size = get_option(options, 'size')
+    fstype = get_option(options, 'fstype')
+    backfstype = get_option(options, 'backfstype')
+    journal_size = get_option(options, 'journal_size')
+    inode_size = get_option(options, 'inode_size')
+    nspath = get_option(options, 'nspath')
+    mkfsoptions = get_option(options, 'mkfsoptions')
+    mountfsoptions = get_option(options, 'mountfsoptions')
 
     node_uuid = name2uuid(lustre, node_name, 'node')
 
 
     node_uuid = name2uuid(lustre, node_name, 'node')
 
@@ -516,54 +1020,98 @@ def add_mds(gen, lustre, options):
     if not net_uuid:
         error("NODE: ", node_name, "not found")
 
     if not net_uuid:
         error("NODE: ", node_name, "not found")
 
-    mdd = gen.mdsdev(mdd_name, mdd_uuid, fstype, devname, get_format_flag(options),
-                  node_uuid, mds_uuid, dev_size=size)
+    if lmv_name:
+        mds.appendChild(gen.ref("lmv", lmv_uuid))
+
+    mdd = gen.mdsdev(mdd_name, mdd_uuid, fstype, devname,
+                     get_format_flag(options), node_uuid, mds_uuid,
+                     size, journal_size, inode_size, nspath, mkfsoptions, 
+                     mountfsoptions, backfstype, backdevname, lmv_uuid)
     lustre.appendChild(mdd)
     lustre.appendChild(mdd)
-                   
+
+
+def add_mgmt(gen, lustre, options):
+    node_name = get_option(options, 'node')
+    node_uuid = name2uuid(lustre, node_name, 'node')
+    mgmt_name = get_option(options, 'mgmt')
+    if not mgmt_name:
+        mgmt_name = new_name('MGMT_' + node_name)
+    mgmt_uuid = name2uuid(lustre, mgmt_name, 'mgmt', 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:
+        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')
 
 def add_ost(gen, lustre, options):
     node_name = get_option(options, 'node')
-    lovname = get_option(options, 'lov', '')
-    osdtype = get_option(options, 'osdtype', 'obdfilter', deprecated_tag="obdtype")
+    lovname = get_option(options, 'lov')
+    osdtype = get_option(options, 'osdtype')
 
 
-    node_uuid = name2uuid(lustre, node_name)
+    node_uuid = name2uuid(lustre, node_name, 'node')
 
     if osdtype == 'obdecho':
         fstype = ''
 
     if osdtype == 'obdecho':
         fstype = ''
+        backfstype = ''
         devname = ''
         devname = ''
+        backdevname = ''
         size = 0
         size = 0
-        fstype = ''
+        journal_size = ''
+        inode_size = ''
+        mkfsoptions = ''
+        mountfsoptions = ''
     else:
     else:
-        devname = get_option(options, 'dev', '') # can be unset for bluearcs
-        size = get_option(options, 'size', 0)
-        fstype = get_option(options, 'fstype', 'extN')
-        
-    ostname = get_option(options, 'ost', '', deprecated_tag='obd')
+        devname = get_option(options, 'dev') # can be unset for bluearcs
+        backdevname = get_option(options, 'backdev')
+        size = get_option(options, 'size')
+        fstype = get_option(options, 'fstype')
+        backfstype = get_option(options, 'backfstype')
+        journal_size = get_option(options, 'journal_size')
+        inode_size = get_option(options, 'inode_size')
+        mkfsoptions = get_option(options, 'mkfsoptions')
+        mountfsoptions = get_option(options, 'mountfsoptions')
+
+    nspath = get_option(options, 'nspath')
+
+    ostname = get_option(options, 'ost')
     if not ostname:
         ostname = new_name('OST_'+ node_name)
 
     if not ostname:
         ostname = new_name('OST_'+ node_name)
 
-    osdname = new_name("OSD_" + ostname)
+    osdname = new_name("OSD_" + ostname + "_" + node_name)
     osd_uuid = new_uuid(osdname)
 
     osd_uuid = new_uuid(osdname)
 
-    ost_uuid = name2uuid(lustre, ostname, fatal=0)
+    ost_uuid = name2uuid(lustre, ostname, 'ost', fatal=0)
     if not ost_uuid:
     if not ost_uuid:
-        ost_uuid = get_option(options, 'ostuuid', '', deprecated_tag = 'obduuid')
+        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)
 
         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)
+        ost = gen.ost(ostname, ost_uuid, osd_uuid, options.group)
         lustre.appendChild(ost)
         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:
+        ost = lookup(lustre, ost_uuid)
+
+    if lovname:
+        lov = findByName(lustre, lovname, "lov")
+        if not lov:
+            error('add_ost:', '"'+lovname+'"', "lov element not found.")
+        lov_add_obd(gen, lustre, lov, ost_uuid, options)
+
+    if options.failover:
+        ost.setAttribute('failover', "1")
 
 
-    osd = gen.osd(osdname, osd_uuid, fstype, osdtype, devname, get_format_flag(options), ost_uuid,
-                  node_uuid, size)
+
+    osd = gen.osd(osdname, osd_uuid, fstype, osdtype, devname,
+                  get_format_flag(options), ost_uuid, node_uuid, size,
+                  journal_size, inode_size, nspath, mkfsoptions, 
+                  mountfsoptions, backfstype, backdevname)
 
     node = findByName(lustre, node_name, "node")
 
 
     node = findByName(lustre, node_name, "node")
 
@@ -576,20 +1124,117 @@ def add_ost(gen, lustre, options):
     node_add_profile(gen, node, 'osd', osd_uuid)
     lustre.appendChild(osd)
 
     node_add_profile(gen, node, 'osd', osd_uuid)
     lustre.appendChild(osd)
 
-                   
+def del_ost(gen, lustre, options):
+    ostname = get_option(options, 'ost')
+    if not ostname:
+        raise OptionError("del_ost: --ost requires a <ost name>")
+    ost = findByName(lustre, ostname, "ost")
+    if not ost:
+        error('del_ost: ', 'Unable to find ', ostname)
+    ost_uuid = name2uuid(lustre, ostname, fatal=0)
+    if not ost_uuid:
+        error('del_ost: ', 'Unable to find uuid for ', ostname)
+    lovname = get_option(options, 'lov')
+    if lovname:
+        lov = findByName(lustre, lovname, "lov")
+        if not lov:
+            error('del_ost:', '"'+lovname+'"', "lov element not found.")
+        lov_del_obd(gen, lustre, lov, ost_uuid, options)
+        # if the user specified a speficic LOV don't delete the OST itself
+        return
+
+    # remove OSD references from all LOVs
+    for n in lustre.getElementsByTagName('lov'):
+        lov_del_obd(gen, lustre, n, ost_uuid, options)
+    if not options.migrate:
+        return
+    # delete the OSDs
+    for osd in lustre.getElementsByTagName('osd'):
+        if ref_exists(osd, ost_uuid):
+            osd_uuid = osd.getAttribute('uuid')
+            # delete all profile references to this OSD
+            for profile in lustre.getElementsByTagName('profile'):
+                for osd_ref in profile.getElementsByTagName('osd_ref'):
+                    if osd_uuid == osd_ref.getAttribute('uuidref'):
+                        profile.removeChild(osd_ref)
+            lustre.removeChild(osd)
+
+    # delete the OST
+    lustre.removeChild(ost)
+
+def add_cmobd(gen, lustre, options):
+    node_name = get_option(options, 'node')
+    name = get_option(options, 'cmobd')
+    uuid = new_uuid(name)
+
+    real_name = get_option(options, 'master_dev')
+    cache_name = get_option(options, 'cache_dev')
+
+    node = findByName(lustre, node_name, "node")
+    node_add_profile(gen, node, "cmobd", uuid)
+    real_uuid = node_found_target_by_dev(gen, lustre, node, real_name)     
+    cache_uuid = node_found_target_by_dev(gen, lustre, node, cache_name)
+    if not real_uuid: 
+       panic("add_cmobd", "can not find real_uuid")
+    if not cache_uuid: 
+       panic("add_cmobd", "can not find cache_uuid")
+    cmobd = gen.cmobd(name, uuid, real_uuid, cache_uuid)
+    lustre.appendChild(cmobd)
+
 def add_cobd(gen, lustre, options):
     node_name = get_option(options, 'node')
 def add_cobd(gen, lustre, options):
     node_name = get_option(options, 'node')
-    name = new_name('COBD_' + node_name)
+    name = get_option(options, 'cobd')
     uuid = new_uuid(name)
 
     real_name = get_option(options, 'real_obd')
     cache_name = get_option(options, 'cache_obd')
     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')
+
+    real_uuid = name2uuid(lustre, real_name, tag='lov', fatal=0)
+    cache_uuid = name2uuid(lustre, cache_name, tag='lov', fatal=0)
+
+    if real_uuid:
+        node = lookup(lustre, real_uuid)
+        rets = node.getElementsByTagName('lov_tgt')
+        for ret in rets:
+            ost_uuid = ret.getAttribute('uuidref')
+            ost_node = lookup(lustre, ost_uuid)
+            ret = ost_node.getElementsByTagName('active_ref')
+            if ret:
+                osd_uuid = ret[0].getAttribute('uuidref')
+                osd_node = lookup(lustre, osd_uuid)
+                gen.addElement(osd_node, 'cachetype', 'master')
+
+    if cache_uuid:
+        node = lookup(lustre, cache_uuid)
+        rets = node.getElementsByTagName('lov_tgt')
+        for ret in rets:
+            ost_uuid = ret.getAttribute('uuidref')
+            ost_node = lookup(lustre, ost_uuid)
+            ret = ost_node.getElementsByTagName('active_ref')
+            if ret:
+                osd_uuid = ret[0].getAttribute('uuidref')
+                osd_node = lookup(lustre, osd_uuid)
+                gen.addElement(osd_node, 'cachetype', 'cache')
+
+    if not real_uuid or not cache_uuid:
+        real_uuid = name2uuid(lustre,real_name, tag='mds')
+        cache_uuid = name2uuid(lustre,cache_name, tag='mds')
+        if real_uuid:
+            mds_node = lookup(lustre, real_uuid)
+            ret = mds_node.getElementsByTagName('active_ref')
+            if ret:
+                mdsdev_uuid = ret[0].getAttribute('uuidref')
+                mdsdev_node = lookup(lustre, mdsdev_uuid)
+                gen.addElement(mdsdev_node, 'cachetype', 'master')
+        if cache_uuid:
+            mds_node = lookup(lustre, cache_uuid)
+            ret = mds_node.getElementsByTagName('active_ref')
+            if ret:
+                mdsdev_uuid = ret[0].getAttribute('uuidref')
+                mdsdev_node = lookup(lustre, mdsdev_uuid)
+                gen.addElement(mdsdev_node, 'cachetype', 'cache')
 
     node = findByName(lustre, node_name, "node")
 
     node = findByName(lustre, node_name, "node")
-    node_add_profile(gen, node, "cobd", uuid)
     cobd = gen.cobd(name, uuid, real_uuid, cache_uuid)
     lustre.appendChild(cobd)
 
     cobd = gen.cobd(name, uuid, real_uuid, cache_uuid)
     lustre.appendChild(cobd)
 
@@ -616,76 +1261,184 @@ def add_echo_client(gen, lustre, options):
 def add_lov(gen, lustre, options):
     """ create a lov """
 
 def add_lov(gen, lustre, options):
     """ create a lov """
 
+    lmv_name = get_option(options, 'lmv')
     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 = get_option(options, 'mds')
     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 = get_option(options, 'mds')
+    if not mds_name:
+       if not lmv_name:
+           error("LOV: MDS or LMV must be specified.");
+
     stripe_sz = get_option_int(options, 'stripe_sz')
     stripe_sz = get_option_int(options, 'stripe_sz')
-    stripe_cnt = get_option_int(options, 'stripe_cnt', 0)
-    pattern = get_option_int(options, 'stripe_pattern', 0)
+    stripe_cnt = get_option_int(options, 'stripe_cnt')
+    pattern = get_option_int(options, 'stripe_pattern')
     uuid = new_uuid(name)
 
     ret = findByName(lustre, name, "lov")
     if ret:
         error("LOV: ", name, " already exists.")
 
     uuid = new_uuid(name)
 
     ret = findByName(lustre, name, "lov")
     if ret:
         error("LOV: ", name, " already exists.")
 
-    mds_uuid = name2uuid(lustre, mds_name, 'mds')
+    if not mds_name:
+        mds_uuid = name2uuid(lustre, lmv_name, 'lmv')
+    else:
+        mds_uuid = name2uuid(lustre, mds_name, 'mds')
+
     lov = gen.lov(name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern)
     lustre.appendChild(lov)
     lov = gen.lov(name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern)
     lustre.appendChild(lov)
-    
+
     # add an lovconfig entry to the active mdsdev profile
     lovconfig_name = new_name('LVCFG_' + name)
     lovconfig_uuid = new_uuid(lovconfig_name)
     # add an lovconfig entry to the active mdsdev profile
     lovconfig_name = new_name('LVCFG_' + name)
     lovconfig_uuid = new_uuid(lovconfig_name)
+    if mds_name:
+        mds = findByName(lustre, mds_name, "mds")
+        mds.appendChild(gen.ref("lovconfig", lovconfig_uuid))
+    if lmv_name:
+        lmv = findByName(lustre, lmv_name, "lmv")
+        lmv.appendChild(gen.ref("lovconfig", lovconfig_uuid))
+    lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid)
+    lustre.appendChild(lovconfig)
+
+def add_default_lov(gen, lustre, mds_name, lov_name):
+    """ create a default lov """
+
+    stripe_sz = DEFAULT_STRIPE_SZ
+    stripe_cnt = DEFAULT_STRIPE_CNT
+    pattern = DEFAULT_STRIPE_PATTERN
+    uuid = new_uuid(lov_name)
+
+    ret = findByName(lustre, lov_name, "lov")
+    if ret:
+        error("LOV: ", lov_name, " already exists.")
+
+    mds_uuid = name2uuid(lustre, mds_name, 'mds')
+    lov = gen.lov(lov_name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern)
+    lustre.appendChild(lov)
+
+    # add an lovconfig entry to the active mdsdev profile
+    lovconfig_name = new_name('LVCFG_' + lov_name)
+    lovconfig_uuid = new_uuid(lovconfig_name)
     mds = findByName(lustre, mds_name)
     mds.appendChild(gen.ref("lovconfig", lovconfig_uuid))
     lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid)
     lustre.appendChild(lovconfig)
 
     mds = findByName(lustre, mds_name)
     mds.appendChild(gen.ref("lovconfig", lovconfig_uuid))
     lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid)
     lustre.appendChild(lovconfig)
 
+def add_lmv(gen, lustre, options):
+    """ create a lmv """
+
+    lmv_orig = get_option(options, 'lmv')
+    name = new_name(lmv_orig)
+    if name != lmv_orig:
+        warning("name:", lmv_orig, "already used. using:", name)
+
+    uuid = new_uuid(name)
+    ret = findByName(lustre, name, "lmv")
+    if ret:
+        error("LMV: ", name, " already exists.")
+
+    lmv = gen.lmv(name, uuid)
+    lustre.appendChild(lmv)
+
+def new_filesystem(gen, lustre, mds_uuid, obd_uuid, mgmt_uuid):
+    fs_name = new_name("FS_fsname")
+    fs_uuid = new_uuid(fs_name)
+    cobd = lookup(lustre, mds_uuid)
+    #SHOULD appendChild filesystem to real mds not cobd
+    ret = cobd.getElementsByTagName("cacheobd_ref")
+    if ret:
+        cacheobd_uuid = ret[0].getAttribute('uuidref') 
+        cacheobd = lookup(lustre, cacheobd_uuid)
+        cacheobd.appendChild(gen.ref("filesystem", fs_uuid))
+        ret = cobd.getElementsByTagName("realobd_ref")
+        if ret:
+            realobd_uuid = ret[0].getAttribute('uuidref')
+            realobd = lookup(lustre, realobd_uuid)
+            realobd.appendChild(gen.ref("filesystem", fs_uuid))
+    else:
+        cobd.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 get_fs_uuid(gen, lustre, mds_name, obd_name, mgmt_name):
+    mds_uuid = name2uuid(lustre, mds_name, tag='mds', fatal=0)
+    if not mds_uuid:
+        mds_uuid = name2uuid(lustre, mds_name, tag='lmv', fatal=0)
+    if not mds_uuid:
+        mds_uuid = name2uuid(lustre, mds_name, tag='cobd', fatal=1) 
+    obd_uuid = name2uuid(lustre, obd_name, tag='lov', fatal=0)
+    if obd_uuid == '':
+       obd_uuid = name2uuid(lustre, obd_name, tag='cobd')
+    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 """
     node_name = get_option(options, 'node')
 
     path = get_option(options, 'path')
 
 def add_mtpt(gen, lustre, options):
     """ create mtpt on a node """
     node_name = get_option(options, 'node')
 
     path = get_option(options, 'path')
+    clientoptions = get_option(options, "clientoptions")
+    fs_name = get_option(options, 'filesystem')
+
+    lov_name = get_option(options, 'lov')
+    ost_name = get_option(options, 'ost')
     mds_name = get_option(options, 'mds')
     mds_name = get_option(options, 'mds')
-    lov_name = get_option(options, 'lov', '')
+    if mds_name == '':
+        mds_name = get_option(options, 'lmv')
+        if mds_name == '':
+            error("--add mtpt requires either --mds or --lmv.")
     if lov_name == '':
     if lov_name == '':
-        lov_name = get_option(options, 'ost', '', deprecated_tag='obd')
-        if lov_name == '':
-            error("--add mtpt requires either --lov lov_name or --ost ost_name")
+        if ost_name == '':
+            error("--add mtpt requires --lov lov_name or --ost ost_name")
+        else:
+            warning("use default value for lov, due no --lov lov_name provided")
+            lov_name = new_name("lov_default")
+            add_default_lov(gen, lustre, mds_name, lov_name)
+            ost_uuid = name2uuid(lustre, ost_name, 'ost', fatal=0)
+            if not ost_uuid:
+                error('add_mtpt:', '"'+ost_name+'"', "ost element not found.")
+            lov = findByName(lustre, lov_name, "lov")
+            lov_add_obd(gen, lustre, lov, ost_uuid, options)
+
+    if fs_name == '':
+        mgmt_name = get_option(options, 'mgmt')
+        fs_uuid = get_fs_uuid(gen, lustre, mds_name, lov_name, mgmt_name)
+    else:
+        fs_uuid = name2uuid(lustre, fs_name, tag='filesystem')
 
     name = new_name('MNT_'+ node_name)
 
     ret = findByName(lustre, name, "mountpoint")
     if ret:
 
     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.")
 
         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='ost', fatal=1)
-
     uuid = new_uuid(name)
     uuid = new_uuid(name)
-    mtpt = gen.mountpoint(name, uuid, mds_uuid, lov_uuid, path)
+    mtpt = gen.mountpoint(name, uuid, fs_uuid, path, clientoptions)
     node = findByName(lustre, node_name, "node")
     if not node:
         error('node:',  node_name, "not found.")
     node_add_profile(gen, node, "mountpoint", uuid)
     lustre.appendChild(mtpt)
 
     node = findByName(lustre, node_name, "node")
     if not node:
         error('node:',  node_name, "not found.")
     node_add_profile(gen, node, "mountpoint", uuid)
     lustre.appendChild(mtpt)
 
-# obsolete, leaving behind for reference 
-def add_oscref(gen, lustre, options):
-    """ create mtpt on a node """
-    node_name = get_option(options, 'node')
-    osc_name = get_option(options, 'osc')
+def commit_version(gen, lustre):
+    update = findLastUpdate(lustre)
+    if update:
+        version = int(update.getAttribute("version")) + 1
+    else:
+        version = 1
 
 
-    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)
+    new = gen.update(str(version))
+    lustre.appendChild(new)
+    
 
 ############################################################
 # Command line processing
 
 ############################################################
 # Command line processing
@@ -694,161 +1447,23 @@ class OptionError (exceptions.Exception):
     def __init__(self, args):
         self.args = args
 
     def __init__(self, args):
         self.args = args
 
-def has_option(options, tag):
-    """Look for tag in options hash and return the true if set"""
-    if options.has_key(tag):
-        return 1
-    return 0
-
-def get_option(options, tag, default = None, deprecated_tag=None):
+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."""
     """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 deprecated_tag and options.has_key(deprecated_tag):
-            warning('--'+deprecated_tag, " is deprecated, please use:", '--'+tag)
-            return options[deprecated_tag]
-    elif default != None:
-        return default
+    if options.__getattr__(tag) != None:
+        return options.__getattr__(tag)
     else:
     else:
-        raise OptionError("--add %s requires --%s <value>" % (options['add'], tag))
-        # this exception should print an error like '--add blah requires --<tag> value'
+        raise OptionError("--add %s requires --%s <value>" % (options.add, tag))
 
 
-def get_option_int(options, tag, default = None):
+def get_option_int(options, tag):
     """Return an integer option.  Raise exception if the value is not an int"""
     """Return an integer option.  Raise exception if the value is not an int"""
-    val = get_option(options, tag, default)
+    val = get_option(options, tag)
     try:
         n = int(val)
     except ValueError:
     try:
         n = int(val)
     except ValueError:
-        raise OptionError("--%s <num> (value must be integer)" % (tag))        
+        raise OptionError("--%s <num> (value must be integer)" % (tag))
     return n
 
     return n
 
-def parse_cmdline(argv):
-    short_opts = "ho:i:m:"
-    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=", "ost=", "obdtype=", "osdtype=", "obduuid=", "in=",
-                 "ostuuid=", "path=", "help", "batch=", "lov=", "gw=", "lo=", "hi=",
-                 "osc=", "real_obd=", "cache_obd=", "fstype=",
-                 "timeout=", "recovery_upcall=", "nid_exchange=", "irq_affinity=",
-                 "hostaddr=",]
-    opts = []
-    args = []
-    options = {}
-    try:
-        opts, args = getopt.getopt(argv, short_opts, long_opts)
-    except getopt.error, e:
-        panic(string.join(sys.argv), e)
-
-    for o, a in opts:
-        # Commands to create new devices
-        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
-        if o == "--ost":
-            options['ost'] = a
-
-        # node options
-        if o == "--timeout":
-            options['timeout'] = a
-        if o == "--recovery_upcall":
-            options['recovery_upcall'] = a
-        if o == "--router":
-            options['router'] = 1
-        
-        # network options
-        if o == "--nid":
-            options['nid'] = a
-        if o == "--hostaddr":
-            options['hostaddr'] = a
-        if o == "--nettype":
-            options['nettype'] = a
-        if o == "--net":
-            options[''] = a
-        if o == "--tcpbuf":
-            options['tcpbuf'] = a
-        if o == "--port":
-            options['port'] = a
-        if o == "--mtpt":
-            options['mtpt'] = 1
-        if o == "--route":
-            options['route'] = 1
-        if o == "--nid_exchange":
-            options['nid_exchange'] = a
-        if o == "--irq_affinity":
-            options['irq_affinity'] = a
-
-        # 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 == "--osdtype":
-            options['osdtype'] = a
-        if o == "--fstype":
-            options['fstype'] = a
-        if o == "--obduuid":
-            options['obduuid'] = a
-        if o == "--ostuuid":
-            options['ostuuid'] = 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"):
-            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":
-            warning("the lmc --reformat option is not supported. Use lconf --reformat")
-            options['reformat'] = 1
-        if o  == "--batch":
-            options['batch'] = a
-        if o  in ("--in" , "-i"):
-            options['in'] = a
-            
-    return options, args
-
-
 # simple class for profiling
 import time
 class chrono:
 # simple class for profiling
 import time
 class chrono:
@@ -868,7 +1483,64 @@ class chrono:
         str = '%s: %g secs' % (msg, d)
         print str
 
         str = '%s: %g secs' % (msg, d)
         print str
 
+#################################################################
+# function cmdlinesplit used to split cmd line from batch file
+#
+def cmdlinesplit(cmdline):
+
+    double_quote  = re.compile(r'"(([^"\\]|\\.)*)"')
+    single_quote  = re.compile(r"'(.*?)'")
+    escaped = re.compile(r'\\(.)')
+    esc_quote = re.compile(r'\\([\\"])')
+    outside = re.compile(r"""([^\s\\'"]+)""") #" fucking emacs.
+
+    arg_list = []
+    i = 0; arg = None
+    while i < len(cmdline):
+        c = cmdline[i]
+        if c == '"':
+            match = double_quote.match(cmdline, i)
+            if not match:
+                print "Unmatched double quote:", cmdline
+                sys.exit(1)
+            i = match.end()
+            if arg is None: arg = esc_quote.sub(r'\1', match.group(1))
+            else:           arg = arg + esc_quote.sub(r'\1', match.group(1))
+
+        elif c == "'":
+            match = single_quote.match(cmdline, i)
+            if not match:
+                print "Unmatched single quote:", cmdline
+                sys.exit(1)
+            i = match.end()
+            if arg is None: arg = match.group(1)
+            else:           arg = arg + match.group(1)
+
+        elif c == "\\":
+            match = escaped.match(cmdline, i)
+            if not match:
+                print "Unmatched backslash", cmdline
+                sys.exit(1)
+            i = match.end()
+            if arg is None: arg = match.group(1)
+            else:           arg = arg + match.group(1)
+
+        elif c in string.whitespace:
+            if arg != None:
+                arg_list.append(str(arg))
+            arg = None
+            while i < len(cmdline) and cmdline[i] in string.whitespace:
+                i = i + 1
+        else:
+            match = outside.match(cmdline, i)
+            assert match
+            i = match.end()
+            if arg is None: arg = match.group()
+            else:           arg = arg + match.group()
+
+    if arg != None: arg_list.append(str(arg))
 
 
+    return arg_list
 
 ############################################################
 # Main
 
 ############################################################
 # Main
@@ -877,8 +1549,6 @@ class chrono:
 def add(devtype, gen, lustre, options):
     if devtype == 'net':
         add_net(gen, lustre, options)
 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':
     elif devtype == 'mtpt':
         add_mtpt(gen, lustre, options)
     elif devtype == 'mds':
@@ -895,32 +1565,69 @@ def add(devtype, gen, lustre, options):
         add_echo_client(gen, lustre, options)
     elif devtype == 'cobd':
         add_cobd(gen, lustre, options)
         add_echo_client(gen, lustre, options)
     elif devtype == 'cobd':
         add_cobd(gen, lustre, options)
+    elif devtype == 'cmobd':
+        add_cmobd(gen, lustre, options)
+    elif devtype == 'mgmt':
+        add_mgmt(gen, lustre, options)
+    elif devtype == 'lmv':
+        add_lmv(gen, lustre, options)
     else:
         error("unknown device type:", devtype)
     else:
         error("unknown device type:", devtype)
-    
+
+def delete(devtype, gen, lustre, options):
+    if devtype == 'ost':
+        del_ost(gen, lustre, options)
+    elif options.delete:
+        error("delete not supported for device type:", devtype)
+    elif options.deactivate:
+        error("deactivate not supported for device type:", devtype)
+    else:
+        error("in delete(), but neither .delete nor .deactivate are set.  Tell CFS.")
+
+def commit(gen, lustre):
+    commit_version(gen, lustre)
+
 def do_command(gen, lustre, options, args):
 def do_command(gen, lustre, options, args):
-    if options.has_key('add'):
-        add(options['add'], gen, lustre, options)
+    if options.add:
+        add(options.add, gen, lustre, options)
+    elif options.delete:
+        delete(options.delete, gen, lustre, options)
+    elif options.deactivate:
+        delete(options.deactivate, gen, lustre, options)
+    elif options.commit:
+        commit(gen, lustre)
     else:
         error("Missing command")
 
 def main():
     else:
         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 = '-'
 
     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)
         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)
 
     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)
 
     lustre = doc.documentElement
     init_names(lustre)
@@ -930,26 +1637,33 @@ def main():
 
     gen = GenConfig(doc)
 
 
     gen = GenConfig(doc)
 
-    if options.has_key('batch'):
-        fp = open(options['batch'])
+    if options.batch:
+        fp = open(options.batch)
         batchCommands = fp.readlines()
         fp.close()
         for cmd in batchCommands:
         batchCommands = fp.readlines()
         fp.close()
         for cmd in batchCommands:
-            options, args = parse_cmdline(string.split(cmd))
             try:
             try:
+                options, args = cl.parse(cmdlinesplit(cmd))
+                if options.merge or options.input or options.output:
+                        print "The batchfile should not contain --merge, --input or --output."
+                        sys.exit(1)
                 do_command(gen, lustre, options, args)
             except OptionError, e:
                 panic(cmd, e)
                 do_command(gen, lustre, options, args)
             except OptionError, e:
                 panic(cmd, e)
+            except Lustre.OptionError, e:
+                panic(cmd, e)
     else:
         try:
             do_command(gen, lustre, options, args)
         except OptionError, e:
             panic(string.join(sys.argv),e)
     else:
         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 == '-':
 
     if outFile == '-':
-        PrettyPrint(doc)
+        printDoc(doc)
     else:
     else:
-        PrettyPrint(doc, open(outFile,"w"))
+        printDoc(doc, open(outFile,"w"))
 
 if __name__ == "__main__":
     main()
 
 if __name__ == "__main__":
     main()