Whamcloud - gitweb
Fix OST AMD - mark new OST active when it is added.
[fs/lustre-release.git] / lustre / utils / lmc
index 8ab7278..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
-from xml.dom.ext import PrettyPrint
+
+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"
 
@@ -42,7 +50,11 @@ if not development_mode():
 
 import Lustre
 
-DEFAULT_PORT = 988 
+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]
@@ -55,25 +67,35 @@ Object creation command summary:
   --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|toe|gm|scimac
+  --cluster_id
+  --nettype tcp|elan|gm
   --hostaddr addr
   --port port
   --tcpbuf size
   --irq_affinity 0|1
-  --nid_exchange 0|1
   --router
 
 --add mds
   --node node_name
   --mds mds_name
+  --failover
   --dev path
-  --fstype extN|ext3
+  --backdev path
+  --fstype ldiskfs|ext3
+  --backfstype ldiskfs|ext3|tmpfs
   --size size
+  --nspath
+  --journal_size size
+  --inode_size size
+  --lmv lmv_name
+  --mkfsoptions options
+  --mountfsoptions options
 
 --add lov
   --lov lov_name
@@ -81,89 +103,167 @@ Object creation command summary:
   --stripe_sz num
   --stripe_cnt num
   --stripe_pattern num
+  --lmv lmv_name
 
--add ost
+--add ost
   --node node_name
   --ost ost_name 
+  --failover
   --lov lov_name 
+  --index index
   --dev path
+  --backdev path
   --size size
-  --fstype extN|ext3
+  --fstype ldiskfs|ext3
+  --backfstype ldiskfs|ext3|tmpfs
+  --journal_size size
+  --inode_size size
+  --osdtype obdecho|obdfilter
   --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
+  --lmv lmv_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
 """
 
 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', "", PARAM),
-    ('output,o', "", PARAM),
+    ('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', "", 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', "", PARAM),
-    ('timeout', "", PARAM),
+    ('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),
-
-    # network 
-    ('nettype', "", PARAM),
-    ('nid', "", PARAM),
-    ('tcpbuf', "", PARAM, 0),
-    ('port', "", PARAM, DEFAULT_PORT),
-    ('nid_exchange', "", PARAM, 0),
-    ('irq_affinity', "", PARAM, 0),
-    ('hostaddr', "", PARAM, ""),
-    ('cluster_id', "", PARAM, "0"),
+    ('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', "", PARAM),
-    ('router', ""),
-    ('gw', "", PARAM),
-    ('gw_cluster_id', "", PARAM, "0"),
+    ('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', "", PARAM),
-    ('hi', "", PARAM, ""),
+    ('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', "", PARAM),
-    ('ost', "", PARAM, ""),
-    ('osdtype', "", PARAM, "obdfilter"),
-    ('failover', ""),
+    ('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', "", PARAM, ""),
-    ('size', "", PARAM, 0),
-    ('journal_size', "", PARAM, 0),
-    ('fstype', "", PARAM, "ext3"),
-    ('ostuuid', "", 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', "", PARAM),
-    ('filesystem', "Lustre filesystem name", 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', "", PARAM, ''),
-    ('stripe_sz', "", PARAM),
-    ('stripe_cnt', "", PARAM, 0),
-    ('stripe_pattern', "", PARAM, 0),
+    ('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', "", PARAM),
-    ('cache_obd', "", PARAM),
+    
+    ('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):
@@ -175,11 +275,11 @@ def panic(cmd, msg):
     print msg
     sys.exit(1)
 
-    
+
 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
@@ -196,7 +296,18 @@ def new_name(base):
     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'
@@ -243,14 +354,20 @@ class GenConfig:
         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 addText(self, node, str):
         txt = self.doc.createTextNode(str)
         node.appendChild(txt)
@@ -265,7 +382,7 @@ class GenConfig:
         return new
 
     def network(self, name, uuid, nid, cluster_id, net, hostaddr="",
-                port=0, tcpbuf=0, irq_aff=0, nid_xchg=0):
+                port=0, tcpbuf=0, irq_aff=0):
         """create <network> node"""
         network = self.newService("network", name, uuid)
         network.setAttribute("nettype", net);
@@ -280,16 +397,14 @@ class GenConfig:
             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
-        
+
     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')
@@ -301,7 +416,7 @@ class GenConfig:
         if hi:
             ref.setAttribute("hi", hi)
         return ref
-    
+
     def profile(self, name, uuid):
         """ create a host """
         profile = self.newService("profile", name, uuid)
@@ -318,14 +433,21 @@ class GenConfig:
         ldlm = self.newService("ldlm", name, uuid)
         return ldlm
 
-    def osd(self, name, uuid, fs, osdtype, devname, format, ost_uuid,
-            node_uuid, dev_size=0, journal_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))
-        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)
@@ -333,6 +455,14 @@ class GenConfig:
                 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):
@@ -341,6 +471,12 @@ class GenConfig:
         cobd.appendChild(self.ref("cacheobd",cache_uuid))
         return cobd
 
+    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))
@@ -360,49 +496,117 @@ class GenConfig:
         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 mds(self, name, uuid, mdd_uuid, group=""):
+    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))
         if group:
             self.addElement(mds, "group", group)
         return mds
 
-    def mdsdev(self, name, uuid, fs, devname, format, node_uuid,
-            mds_uuid, dev_size=0, journal_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)
-        self.addElement(mdd, "fstype", fs)
+        self.addElement(mdd, "fstype", fstype)
+        if backfstype:
+                self.addElement(mdd, "backfstype", backfstype)
         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))
         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.dev(devname)) 
+       
+       if lmv_uuid:
+            mdd.appendChild(self.ref("lmv", lmv_uuid))
+           self.addElement(mdd, "lmv", lmv_uuid)
+
         return mdd
 
-    def mountpoint(self, name, uuid, fs_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.appendChild(self.ref("filesystem", fs_uuid))
         self.addElement(mtpt, "path", path)
+        if clientoptions:
+            self.addElement(mtpt, "clientoptions", clientoptions)
         return mtpt
 
-    def filesystem(self, name, uuid, mds_uuid, obd_uuid):
+    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 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
@@ -413,6 +617,40 @@ def getName(n):
 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:
@@ -446,7 +684,7 @@ def name2uuid(lustre, name, tag="",  fatal=1):
         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':
@@ -466,9 +704,91 @@ def get_net_uuid(lustre, node_name):
         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
@@ -478,7 +798,7 @@ def ref_exists(profile, uuid):
             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):
@@ -494,7 +814,41 @@ def node_add_profile(gen, node, ref, uuid):
         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:
@@ -516,13 +870,17 @@ def set_node_options(gen, node, options):
     if default_upcall or options.lustre_upcall:
         if options.lustre_upcall:
             gen.addElement(node, 'lustreUpcall', options.lustre_upcall)
-        else: 
+        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):
@@ -536,9 +894,10 @@ def do_add_node(gen, lustre,  options, node_name):
 
     node_add_profile(gen, node, 'ldlm', ldlm_uuid)
     set_node_options(gen, node, options)
+
     return node
 
-    
+
 def add_node(gen, lustre, options):
     """ create a node with a network config """
 
@@ -559,16 +918,14 @@ def add_net(gen, lustre, options):
     hostaddr = get_option(options, 'hostaddr')
     net_type = get_option(options, 'nettype')
 
-    if net_type in ('tcp', 'toe'):
+    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')
-        nid_xchg = get_option_int(options, 'nid_exchange')
-    elif net_type in ('elan', 'gm', 'scimac'):
+    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)
@@ -583,7 +940,7 @@ def add_net(gen, lustre, 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, cluster_id, net_type,
-                                 hostaddr, port, tcpbuf, irq_aff, nid_xchg))
+                                 hostaddr, port, tcpbuf, irq_aff))
     node_add_profile(gen, node, "network", net_uuid)
 
 
@@ -593,7 +950,7 @@ def add_route(gen, lustre, options):
     node_name = get_option(options, 'node')
     gw_net_type = get_option(options, 'nettype')
     gw = get_option(options, 'gw')
-    gw_cluster_id = get_option(options, 'gw_cluster_id')
+    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')
@@ -603,7 +960,7 @@ def add_route(gen, lustre, options):
     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]
@@ -620,23 +977,40 @@ def add_route(gen, lustre, options):
 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)
 
-    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)
         mds = gen.mds(mds_name, mds_uuid, mdd_uuid, options.group)
         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')
+    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')
 
@@ -646,31 +1020,63 @@ def add_mds(gen, lustre, options):
     if not net_uuid:
         error("NODE: ", node_name, "not found")
 
+    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,
-                     dev_size=size, journal_size=journal_size)
+                     size, journal_size, inode_size, nspath, mkfsoptions, 
+                     mountfsoptions, backfstype, backdevname, lmv_uuid)
     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')
     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 = ''
+        backfstype = ''
         devname = ''
+        backdevname = ''
         size = 0
-        fstype = ''
         journal_size = ''
+        inode_size = ''
+        mkfsoptions = ''
+        mountfsoptions = ''
     else:
         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)
@@ -678,7 +1084,7 @@ def add_ost(gen, lustre, options):
     osdname = new_name("OSD_" + ostname + "_" + node_name)
     osd_uuid = new_uuid(osdname)
 
-    ost_uuid = name2uuid(lustre, ostname, fatal=0)
+    ost_uuid = name2uuid(lustre, ostname, 'ost', fatal=0)
     if not ost_uuid:
         ost_uuid = get_option(options, 'ostuuid')
         if ost_uuid:
@@ -689,21 +1095,23 @@ def add_ost(gen, lustre, options):
 
         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:
         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,
-                  journal_size)
+                  journal_size, inode_size, nspath, mkfsoptions, 
+                  mountfsoptions, backfstype, backdevname)
 
     node = findByName(lustre, node_name, "node")
 
@@ -716,20 +1124,117 @@ def add_ost(gen, lustre, options):
     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')
-    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')
-    
-    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_add_profile(gen, node, "cobd", uuid)
     cobd = gen.cobd(name, uuid, real_uuid, cache_uuid)
     lustre.appendChild(cobd)
 
@@ -756,12 +1261,17 @@ def add_echo_client(gen, lustre, options):
 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')
+    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_cnt = get_option_int(options, 'stripe_cnt')
     pattern = get_option_int(options, 'stripe_pattern')
@@ -771,51 +1281,136 @@ def add_lov(gen, lustre, options):
     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)
-    
+
     # 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)
 
-def new_filesystem(gen, lustre, mds_uuid, obd_uuid):
+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)
-    mds = lookup(lustre, mds_uuid)
-    mds.appendChild(gen.ref("filesystem", fs_uuid))
-    fs = gen.filesystem(fs_name, fs_uuid, mds_uuid, obd_uuid)
+    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):
-    mds_uuid = name2uuid(lustre, mds_name, tag='mds')
+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 not obd_uuid:
-        obd_uuid = name2uuid(lustre, obd_name, tag='ost', fatal=1)
+    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)
+        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')
+    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')
+    if mds_name == '':
+        mds_name = get_option(options, 'lmv')
+        if mds_name == '':
+            error("--add mtpt requires either --mds or --lmv.")
+    if lov_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 == '':
-        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")
-        fs_uuid = get_fs_uuid(gen, lustre, mds_name, lov_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')
 
@@ -827,13 +1422,24 @@ def add_mtpt(gen, lustre, options):
         error("MOUNTPOINT: ", name, " already exists.")
 
     uuid = new_uuid(name)
-    mtpt = gen.mountpoint(name, uuid, fs_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)
 
+def commit_version(gen, lustre):
+    update = findLastUpdate(lustre)
+    if update:
+        version = int(update.getAttribute("version")) + 1
+    else:
+        version = 1
+
+    new = gen.update(str(version))
+    lustre.appendChild(new)
+    
+
 ############################################################
 # Command line processing
 #
@@ -855,7 +1461,7 @@ def get_option_int(options, tag):
     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
 
 # simple class for profiling
@@ -877,6 +1483,65 @@ class chrono:
         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
 #
@@ -900,12 +1565,37 @@ def add(devtype, 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)
-    
+
+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):
     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")
 
@@ -953,7 +1643,10 @@ def main():
         fp.close()
         for cmd in batchCommands:
             try:
-                options, args = cl.parse(string.split(cmd))
+                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)
@@ -968,9 +1661,9 @@ def main():
             panic("lmc", e)
 
     if outFile == '-':
-        PrettyPrint(doc)
+        printDoc(doc)
     else:
-        PrettyPrint(doc, open(outFile,"w"))
+        printDoc(doc, open(outFile,"w"))
 
 if __name__ == "__main__":
     main()