Whamcloud - gitweb
Merge b_md to HEAD for 0.5.19 release.
[fs/lustre-release.git] / lustre / utils / lmc
1 #!/usr/bin/env python
2 # Copyright (C) 2002 Cluster File Systems, Inc.
3 # Author: Robert Read <rread@clusterfs.com>
4
5 #   This file is part of Lustre, http://www.lustre.org.
6 #
7 #   Lustre is free software; you can redistribute it and/or
8 #   modify it under the terms of version 2 of the GNU General Public
9 #   License as published by the Free Software Foundation.
10 #
11 #   Lustre is distributed in the hope that it will be useful,
12 #   but WITHOUT ANY WARRANTY; without even the implied warranty of
13 #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 #   GNU General Public License for more details.
15 #
16 #   You should have received a copy of the GNU General Public License
17 #   along with Lustre; if not, write to the Free Software
18 #   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 #
20
21 """
22 lmc - lustre configurtion data  manager
23
24   See lustre book for documentation for lmc.
25
26 """
27
28 import sys, os, getopt, string, exceptions
29 import xml.dom.minidom
30 from xml.dom.ext import PrettyPrint
31
32 DEFAULT_PORT = 988 
33
34 def usage():
35     print """usage: lmc --add object [object parameters]
36
37 Object creation command summary:
38
39 --add node
40   --node node_name
41   --timeout num
42   --recovery_upcall path
43
44 --add net
45   --node node_name
46   --nid addr
47   --nettype tcp|elan|toe|gm
48   --port port
49   --tcpbuf size
50   --router
51
52 --add mds
53   --node node_name
54   --mds mds_name
55   --dev path
56   --fstype extN|ext3
57   --size size
58
59 --add lov
60   --lov lov_name
61   --mds mds_name
62   --stripe_sz num
63   --stripe_cnt num
64   --stripe_pattern num
65
66 -add ost
67   --node node_name
68   --obd obd_name 
69   --lov lov_name 
70   --dev path
71   --size size
72   --fstype extN|ext3
73   --obduuid uuid
74   
75 --add mtpt  - Mountpoint
76   --node node_name
77   --path /mnt/point
78   --mds mds_name
79   --obd obd_name OR --lov lovname
80 """
81     sys.exit(1)
82
83 def error(*args):
84     msg = string.join(map(str,args))
85     raise OptionError("Error: " +  msg)
86
87 def panic(cmd, msg):
88     print "! " + cmd
89     print msg
90     sys.exit(1)
91
92     
93 def warning(*args):
94     msg = string.join(map(str,args))
95     print "Warning: ", msg
96     
97 #
98 # manage names and uuids
99 # need to initialize this by walking tree to ensure
100 # no duplicate names or uuids are created.
101 # this are just place holders for now.
102 # consider changing this to be like OBD-dev-host
103 def new_name(base):
104     ctr = 2
105     ret = base
106     while names.has_key(ret):
107         ret = "%s_%d" % (base, ctr)
108         ctr = 1 + ctr
109     names[ret] = 1
110     return ret
111
112 def new_uuid(name):
113     return "%s_UUID" % (name)
114
115 ldlm_name = 'ldlm'
116 ldlm_uuid = 'ldlm_UUID'
117 def new_lustre(dom):
118     """Create a new empty lustre document"""
119     # adding ldlm here is a bit of a hack, but one is enough.
120     str = """<lustre>
121     <ldlm name="%s" uuid="%s"/>
122     </lustre>""" % (ldlm_name, ldlm_uuid)
123     return dom.parseString(str)
124
125 names = {}
126 uuids = {}
127
128 def init_names(doc):
129     """initialize auto-name generation tables"""
130     global names, uuids
131     # get all elements that contain a name attribute
132     for n in doc.childNodes:
133         if n.nodeType == n.ELEMENT_NODE:
134             if getName(n):
135                 names[getName(n)] = 1
136                 uuids[getUUID(n)] = 1
137             init_names(n)
138
139 def get_format_flag(options):
140     if options.has_key('format'):
141         if options['format']:
142             return 'yes'
143     return 'no'
144
145 ############################################################
146 # Build config objects using DOM
147 #
148 class GenConfig:
149     doc = None
150     dom = None
151     def __init__(self, doc):
152         self.doc = doc
153
154     def ref(self, type, uuid):
155         """ generate <[type]_ref uuidref="[uuid]"/> """
156         tag = "%s_ref" % (type)
157         ref = self.doc.createElement(tag)
158         ref.setAttribute("uuidref", uuid)
159         return ref
160     
161     def newService(self, tag, name, uuid):
162         """ create a new  service elmement, which requires name and uuid attributes """
163         new = self.doc.createElement(tag)
164         new.setAttribute("uuid", uuid);
165         new.setAttribute("name", name);
166         return new
167     
168     def addText(self, node, str):
169         txt = self.doc.createTextNode(str)
170         node.appendChild(txt)
171
172     def addElement(self, node, tag, str=None):
173         """ create a new element and add it as a child to node. If str is passed,
174             a text node is created for the new element"""
175         new = self.doc.createElement(tag)
176         if str:
177             self.addText(new, str)
178         node.appendChild(new)
179         return new
180
181     def network(self, name, uuid, hostname, net, port=0, tcpbuf=0):
182         """create <network> node"""
183         network = self.newService("network", name, uuid)
184         network.setAttribute("nettype", net);
185         self.addElement(network, "nid", hostname)
186         if port:
187             self.addElement(network, "port", "%d" %(port))
188         if tcpbuf:
189             self.addElement(network, "sendmem", "%d" %(tcpbuf))
190             self.addElement(network, "recvmem", "%d" %(tcpbuf))
191             
192         return network
193
194     def route(self, net_type, gw, lo, hi):
195         """ create one entry for the route table """
196         ref = self.doc.createElement('route')
197         ref.setAttribute("type", net_type)
198         ref.setAttribute("gw", gw)
199         ref.setAttribute("lo", lo)
200         if hi:
201             ref.setAttribute("hi", hi)
202         return ref
203     
204     def profile(self, name, uuid):
205         """ create a host """
206         profile = self.newService("profile", name, uuid)
207         return profile
208
209     def node(self, name, uuid, prof_uuid):
210         """ create a host """
211         node = self.newService("node", name, uuid)
212         node.appendChild(self.ref("profile", prof_uuid))
213         return node
214
215     def ldlm(self, name, uuid):
216         """ create a ldlm """
217         ldlm = self.newService("ldlm", name, uuid)
218         return ldlm
219
220     def obd(self, name, uuid, fs, obdtype, devname, format, ost_uuid, dev_size=0):
221         obd = self.newService("obd", name, uuid)
222         obd.setAttribute('obdtype', obdtype)
223         obd.appendChild(self.ref("active", ost_uuid))
224         if fs:
225             self.addElement(obd, "fstype", fs)
226         if devname:
227             dev = self.addElement(obd, "devpath", devname)
228             self.addElement(obd, "autoformat", format)
229             if dev_size:
230                 self.addElement(obd, "devsize", "%s" % (dev_size))
231         return obd
232
233     def cobd(self, name, uuid, real_uuid, cache_uuid):
234         cobd = self.newService("cobd", name, uuid)
235         cobd.appendChild(self.ref("realobd",real_uuid))
236         cobd.appendChild(self.ref("cacheobd",cache_uuid))
237         return cobd
238
239     def ost(self, name, uuid, obd_uuid, net_uuid):
240         ost = self.newService("ost", name, uuid)
241         ost.appendChild(self.ref("network", net_uuid))
242         ost.appendChild(self.ref("obd", obd_uuid))
243         return ost
244
245     def lov(self, name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern):
246         lov = self.newService("lov", name, uuid)
247         lov.appendChild(self.ref("mds", mds_uuid))
248         lov.setAttribute("stripesize", stripe_sz)
249         lov.setAttribute("stripecount", stripe_cnt)
250         lov.setAttribute("stripepattern", pattern)
251         return lov
252
253     def lovconfig(self, name, uuid, lov_uuid):
254         lovconfig = self.newService("lovconfig", name, uuid)
255         lovconfig.appendChild(self.ref("lov", lov_uuid))
256         return lovconfig
257
258     def mds(self, name, uuid, mdd_uuid):
259         mds = self.newService("mds", name, uuid)
260         mds.appendChild(self.ref("active",mdd_uuid))
261         return mds
262
263     def mdsdev(self, name, uuid, fs, devname, format, net_uuid, node_uuid,
264             mds_uuid, dev_size=0 ):
265         mdd = self.newService("mdsdev", name, uuid)
266         self.addElement(mdd, "fstype", fs)
267         dev = self.addElement(mdd, "devpath", devname)
268         self.addElement(mdd, "autoformat", format)
269         if dev_size:
270                 self.addElement(mdd, "devsize", "%s" % (dev_size))
271         mdd.appendChild(self.ref("network", net_uuid))
272         mdd.appendChild(self.ref("mds", mds_uuid))
273         return mdd
274
275     def mountpoint(self, name, uuid, mds_uuid, osc_uuid, path):
276         mtpt = self.newService("mountpoint", name, uuid)
277         mtpt.appendChild(self.ref("mds", mds_uuid))
278         mtpt.appendChild(self.ref("obd", osc_uuid))
279         self.addElement(mtpt, "path", path)
280         return mtpt
281
282     def echo_client(self, name, uuid, osc_uuid):
283         ec = self.newService("echoclient", name, uuid)
284         ec.appendChild(self.ref("obd", osc_uuid))
285         return ec
286
287 ############################################################
288 # Utilities to query a DOM tree
289 # Using this functions we can treat use config information
290 # directly as a database.
291 def getName(n):
292     return n.getAttribute('name')
293
294 def getUUID(node):
295     return node.getAttribute('uuid')
296
297
298 def findByName(lustre, name, tag = ""):
299     for n in lustre.childNodes:
300         if n.nodeType == n.ELEMENT_NODE:
301             if tag and n.nodeName != tag:
302                 continue
303             if getName(n) == name:
304                 return n
305             else:
306                 n = findByName(n, name)
307                 if n: return n
308     return None
309
310
311 def lookup(node, uuid):
312     for n in node.childNodes:
313         if n.nodeType == n.ELEMENT_NODE:
314             if getUUID(n) == uuid:
315                 return n
316             else:
317                 n = lookup(n, uuid)
318                 if n: return n
319     return None
320
321
322 def name2uuid(lustre, name, tag="",  fatal=1):
323     ret = findByName(lustre, name, tag)
324     if not ret:
325         if fatal:
326             error('name2uuid:', '"'+name+'"', tag, 'element not found.')
327         else:
328             return ""
329     return getUUID(ret)
330     
331
332 # XXX: assumes only one network element per node. will fix this
333 # as soon as support for routers is added
334 def get_net_uuid(lustre, node_name):
335     """ get a network uuid for a node_name """
336     node = findByName(lustre, node_name, "node")
337     if not node:
338         error ('get_net_uuid:', '"'+node_name+'"', "node element not found.")
339     net = node.getElementsByTagName('network')
340     if net:
341         return getUUID(net[0])
342     return None
343
344
345 def lov_add_obd(gen, lov, osc_uuid):
346     lov.appendChild(gen.ref("obd", osc_uuid))
347                             
348 def node_add_profile(gen, node, ref, uuid):
349     refname = "%s_ref" % "profile"
350     ret = node.getElementsByTagName(refname)
351     if not ret:
352         error('node has no profile ref:', node)
353     prof_uuid = ret[0].getAttribute('uuidref')
354     profile = lookup(node.parentNode, prof_uuid)
355     profile.appendChild(gen.ref(ref, uuid))
356     
357 def get_attr(dom_node, attr, default=""):
358     v = dom_node.getAttribute(attr)
359     if v:
360         return v
361     return default
362
363 ############################################################
364 # Top level commands
365 #
366 def do_add_node(gen, lustre,  options, node_name):
367     uuid = new_uuid(node_name)
368     prof_name = new_name("PROFILE_" + node_name)
369     prof_uuid = new_uuid(prof_name)
370     profile = gen.profile(prof_name, prof_uuid)
371     node = gen.node(node_name, uuid, prof_uuid)
372     lustre.appendChild(node)
373     lustre.appendChild(profile)
374
375     node_add_profile(gen, node, 'ldlm', ldlm_uuid)
376     if has_option(options, 'router'):
377         node.setAttribute('router', '1')
378     if has_option(options, 'timeout'):
379         node.setAttribute('timeout', get_option(options, 'timeout'))
380     if has_option(options, 'recovery_upcall'):
381         node.setAttribute('recovery_upcall', get_option(options, 'recovery_upcall'))
382     return node
383
384     
385 def add_node(gen, lustre, options):
386     """ create a node with a network config """
387
388     node_name = get_option(options, 'node')
389     ret = findByName(lustre, node_name, "node")
390     if ret:
391         print "Node:", node_name, "exists."
392         return
393     do_add_node(gen, lustre, options, node_name)
394
395
396 def add_net(gen, lustre, options):
397     """ create a node with a network config """
398
399     node_name = get_option(options, 'node')
400     nid = get_option(options, 'nid')
401     net_type = get_option(options, 'nettype')
402
403     if net_type == 'tcp':
404         port = get_option_int(options, 'port', DEFAULT_PORT)
405         tcpbuf = get_option_int(options, 'tcpbuf', 0)
406     elif net_type in ('elan', 'gm'):
407         port = 0
408         tcpbuf = 0
409     else:
410         print "Unknown net_type: ", net_type
411         sys.exit(2)
412
413     ret = findByName(lustre, node_name, "node")
414     if not ret:
415         node = do_add_node(gen, lustre, options, node_name)
416     else:
417         node = ret
418     net_name = new_name('NET_'+ node_name +'_'+ net_type)
419     net_uuid = new_uuid(net_name)
420     node.appendChild(gen.network(net_name, net_uuid, nid, net_type, port, tcpbuf))
421     node_add_profile(gen, node, "network", net_uuid)
422
423
424 def add_route(gen, lustre, options):
425     """ create a node with a network config """
426
427     node_name = get_option(options, 'node')
428     net_type = get_option(options, 'nettype')
429     gw = get_option(options, 'gw')
430     lo = get_option(options, 'lo')
431     hi = get_option(options, 'hi', '')
432
433     node = findByName(lustre, node_name, "node")
434     if not node:
435         error (node_name, " not found.")
436     
437     netlist = node.getElementsByTagName('network')
438     net = netlist[0]
439     rlist = net.getElementsByTagName('routetbl')
440     if len(rlist) > 0:
441         rtbl = rlist[0]
442     else:
443         rtbl = gen.addElement(net, 'routetbl')
444     rtbl.appendChild(gen.route(net_type, gw, lo, hi))
445
446
447 def add_mds(gen, lustre, options):
448     node_name = get_option(options, 'node')
449     mds_name = get_option(options, 'mds')
450     mdd_name = new_name("MDD_" + mds_name +"_" + node_name)
451     mdd_uuid = new_uuid(mdd_name)
452
453     mds_uuid = name2uuid(lustre, mds_name, fatal=0)
454     if not mds_uuid:
455         mds_uuid = new_uuid(mds_name)
456         mds = gen.mds(mds_name, mds_uuid, mdd_uuid)
457         lustre.appendChild(mds)
458         
459     devname = get_option(options, 'dev')
460     size = get_option(options, 'size', 0)
461     fstype = get_option(options, 'fstype', 'extN')
462
463     node_uuid = name2uuid(lustre, node_name, 'node')
464
465     node = findByName(lustre, node_name, "node")
466     node_add_profile(gen, node, "mdsdev", mdd_uuid)
467     net_uuid = get_net_uuid(lustre, node_name)
468     if not net_uuid:
469         error("NODE: ", node_name, "not found")
470
471     mdd = gen.mdsdev(mdd_name, mdd_uuid, fstype, devname, get_format_flag(options),
472                   net_uuid, node_uuid, mds_uuid, dev_size=size)
473     lustre.appendChild(mdd)
474                    
475
476 def add_ost(gen, lustre, options):
477     node_name = get_option(options, 'node')
478     lovname = get_option(options, 'lov', '')
479     obdtype = get_option(options, 'obdtype', 'obdfilter')
480
481     if obdtype == 'obdecho':
482         fstype = ''
483         devname = ''
484         size = 0
485         fstype = ''
486     else:
487         devname = get_option(options, 'dev', '') # can be unset for bluearcs
488         size = get_option(options, 'size', 0)
489         fstype = get_option(options, 'fstype', 'extN')
490         
491     obdname = get_option(options, 'obd', 'OBD_'+ node_name)
492     obdname = new_name(obdname)
493     ostname = new_name('OST_'+ obdname)
494     if options.has_key('obduuid'):
495         obd_uuid = options['obduuid']
496         obd = lookup(lustre, obd_uuid)
497         if obd:
498             error("Duplicate OBD UUID:", obd_uuid)
499     else:
500         obd_uuid = new_uuid(obdname)
501     ost_uuid = new_uuid(ostname)
502
503     net_uuid = get_net_uuid(lustre, node_name)
504     if not net_uuid:
505         error("NODE: ", node_name, "not found")
506     
507     obd = gen.obd(obdname, obd_uuid, fstype, obdtype, devname, get_format_flag(options), ost_uuid,
508                   size)
509     ost = gen.ost(ostname, ost_uuid, obd_uuid, net_uuid)
510     
511     if lovname:
512         lov = findByName(lustre, lovname, "lov")
513         if not lov:
514             error('add_ost:', '"'+lovname+'"', "lov element not found.")
515         lov_add_obd(gen, lov, obd_uuid)
516
517     node = findByName(lustre, node_name, "node")
518     node_add_profile(gen, node, 'obd', obd_uuid)
519     node_add_profile(gen, node, 'ost', ost_uuid)
520
521     lustre.appendChild(obd)
522     lustre.appendChild(ost)
523
524                    
525 def add_cobd(gen, lustre, options):
526     node_name = get_option(options, 'node')
527     name = new_name('COBD_' + node_name)
528     uuid = new_uuid(name)
529
530     real_name = get_option(options, 'real_obd')
531     cache_name = get_option(options, 'cache_obd')
532     
533     real_uuid = name2uuid(lustre, real_name, tag='obd')
534     cache_uuid = name2uuid(lustre, cache_name, tag='obd')
535
536     node = findByName(lustre, node_name, "node")
537     node_add_profile(gen, node, "cobd", uuid)
538     cobd = gen.cobd(name, uuid, real_uuid, cache_uuid)
539     lustre.appendChild(cobd)
540
541
542 def add_echo_client(gen, lustre, options):
543     """ add an echo client to the profile for this node. """
544     node_name = get_option(options, 'node')
545     lov_name = get_option(options, 'obd')
546
547     node = findByName(lustre, node_name, 'node')
548
549     echoname = new_name('ECHO_'+ node_name)
550     echo_uuid = new_uuid(echoname)
551     node_add_profile(gen, node, 'echoclient', echo_uuid)
552
553     lov_uuid = name2uuid(lustre, lov_name, tag='lov', fatal=0)
554     if not lov_uuid:
555         lov_uuid = name2uuid(lustre, lov_name, tag='obd', fatal=1)
556
557     echo = gen.echo_client(echoname, echo_uuid, lov_uuid)
558     lustre.appendChild(echo)
559
560
561 def add_lov(gen, lustre, options):
562     """ create a lov """
563
564     lov_orig = get_option(options, 'lov')
565     name = new_name(lov_orig)
566     if name != lov_orig:
567         warning("name:", lov_orig, "already used. using:", name)
568
569     mds_name = get_option(options, 'mds')
570     stripe_sz = get_option(options, 'stripe_sz')
571     stripe_cnt = get_option(options, 'stripe_cnt', 0)
572     pattern = get_option(options, 'stripe_pattern', 0)
573     uuid = new_uuid(name)
574
575     ret = findByName(lustre, name, "lov")
576     if ret:
577         error("LOV: ", name, " already exists.")
578
579     mds_uuid = name2uuid(lustre, mds_name, 'mds')
580     lov = gen.lov(name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern)
581     lustre.appendChild(lov)
582     
583     # add an lovconfig entry to the active mdsdev profile
584     lovconfig_name = new_name('LVCFG_' + name)
585     lovconfig_uuid = new_uuid(lovconfig_name)
586     mds = findByName(lustre, mds_name)
587     mds.appendChild(gen.ref("lovconfig", lovconfig_uuid))
588     lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid)
589     lustre.appendChild(lovconfig)
590
591
592 def add_mtpt(gen, lustre, options):
593     """ create mtpt on a node """
594     node_name = get_option(options, 'node')
595
596     path = get_option(options, 'path')
597     mds_name = get_option(options, 'mds')
598     lov_name = get_option(options, 'lov', '')
599     if lov_name == '':
600         lov_name = get_option(options, 'obd', '')
601         if lov_name == '':
602             error("--add mtpt requires either --lov lov_name or --obd obd_name")
603
604     name = new_name('MNT_'+ node_name)
605
606     ret = findByName(lustre, name, "mountpoint")
607     if ret:
608         error("MOUNTPOINT: ", name, " already exists.")
609
610     mds_uuid = name2uuid(lustre, mds_name, tag='mds')
611     lov_uuid = name2uuid(lustre, lov_name, tag='lov', fatal=0)
612     if not lov_uuid:
613         lov_uuid = name2uuid(lustre, lov_name, tag='obd', fatal=1)
614
615     uuid = new_uuid(name)
616     mtpt = gen.mountpoint(name, uuid, mds_uuid, lov_uuid, path)
617     node = findByName(lustre, node_name, "node")
618     if not node:
619             error('node:',  node_name, "not found.")
620     node_add_profile(gen, node, "mountpoint", uuid)
621     lustre.appendChild(mtpt)
622
623 def add_oscref(gen, lustre, options):
624     """ create mtpt on a node """
625     node_name = get_option(options, 'node')
626     osc_name = get_option(options, 'osc')
627
628     osc_uuid = name2uuid(lustre, osc_name, tag='osc')
629     node = findByName(lustre, node_name, "node")
630     if not node:
631             error('node:', node_name, "not found")
632     node_add_profile(gen, node, "osc",osc_uuid)
633
634 ############################################################
635 # Command line processing
636 #
637 class OptionError (exceptions.Exception):
638     def __init__(self, args):
639         self.args = args
640
641 def has_option(options, tag):
642     """Look for tag in options hash and return the true if set"""
643     if options.has_key(tag):
644         return 1
645     return 0
646
647 def get_option(options, tag, default = None):
648     """Look for tag in options hash and return the value if set. If not
649     set, then if return default it is set, otherwise exception."""
650     if options.has_key(tag):
651         return options[tag]
652     elif default != None:
653         return default
654     else:
655         raise OptionError("--add %s requires --%s value" % (options['add'], tag))
656         # this exception should print an error like '--add blah requires --<tag> value'
657
658 def get_option_int(options, tag, default = None):
659     """Return an integer option.  Raise exception if the value is not an int"""
660     val = get_option(options, tag, default)
661     return int(val)
662
663 def parse_cmdline(argv):
664     short_opts = "ho:i:m:"
665     long_opts = ["add=", "node=", "nettype=", "nid=", "tcpbuf=", "port=",
666                  "echo_client=", "stripe_sz=", "stripe_cnt=", "stripe_pattern=",
667                  "mds=", "route", "router", "merge=", "format", "reformat", "output=",
668                  "dev=", "size=", "obd=", "obdtype=", "obduuid=", "in=",
669                  "path=", "help", "batch=", "lov=", "gw=", "lo=", "hi=",
670                  "oscref", "osc=", "real_obd=", "cache_obd=", "fstype=",
671                  "timeout=", "recovery_upcall="]
672     opts = []
673     args = []
674     options = {}
675     try:
676         opts, args = getopt.getopt(argv, short_opts, long_opts)
677     except getopt.error, e:
678         panic(string.join(sys.argv), e)
679
680     for o, a in opts:
681         # Commands to create new devices
682         if o == "--add":
683             options['add'] = a
684
685         if o == "--node":
686             options['node'] = a
687
688         # devices names
689         if o == "--lov":
690             options['lov'] = a
691         if o == "--mds":
692             options['mds'] = a
693         if o == "--obd":
694             options['obd'] = a
695
696         # node options
697         if o == "--timeout":
698             options['timeout'] = a
699         if o == "--recovery_upcall":
700             options['recovery_upcall'] = a
701         if o == "--router":
702             options['router'] = 1
703         
704         # network options
705         if o == "--nid":
706             options['nid'] = a
707         if o == "--nettype":
708             options['nettype'] = a
709         if o == "--net":
710             options[''] = a
711         if o == "--tcpbuf":
712             options['tcpbuf'] = a
713         if o == "--port":
714             options['port'] = a
715         if o == "--mtpt":
716             options['mtpt'] = 1
717         if o == "--route":
718             options['route'] = 1
719
720         # ost options
721         if o == "--dev":
722             options['dev'] = a
723         if o == "--size":
724             options['size'] = a
725         if o == "--path":
726             options['path'] = a
727         if o == "--osc":
728             options['osc'] = a
729         if o == "--obdtype":
730             options['obdtype'] = a
731         if o == "--fstype":
732             options['fstype'] = a
733         if o == "--obduuid":
734             options['obduuid'] = a
735
736         # lov options
737         if o == "--stripe_sz":
738             options['stripe_sz'] = a
739         if o == "--stripe_cnt":
740             options['stripe_cnt'] = a
741         if o == "--stripe_pattern":
742             options['stripe_pattern'] = a
743         if o == "--gw":
744             options['gw'] = a
745         if o == "--lo":
746             options['lo'] = a
747         if o == "--hi":
748             options['hi'] = a
749
750         # cobd
751         if o == "--cache_obd":
752             options['cache_obd'] = a
753         if o == "--real_obd":
754             options['real_obd'] = a
755
756         # lmc options
757         if o in ("-h", "--help"):
758             usage()
759         if o in ("-o", "--output"):
760             options['output'] = a
761         if o in ("-m", "--merge"):
762             options['merge'] = a
763         if o == "--format":
764             options['format'] = 1
765         if o  == "--reformat":
766             options['reformat'] = 1
767         if o  == "--batch":
768             options['batch'] = a
769         if o  in ("--in" , "-i"):
770             options['in'] = a
771             
772     return options, args
773
774
775 # simple class for profiling
776 import time
777 class chrono:
778     def __init__(self):
779         self._start = 0
780     def start(self):
781         self._stop = 0
782         self._start = time.time()
783     def stop(self, msg=''):
784         self._stop = time.time()
785         if msg:
786             self.display(msg)
787     def dur(self):
788         return self._stop - self._start
789     def display(self, msg):
790         d = self.dur()
791         str = '%s: %g secs' % (msg, d)
792         print str
793
794
795
796 ############################################################
797 # Main
798 #
799
800 def add(devtype, gen, lustre, options):
801     if devtype == 'net':
802         add_net(gen, lustre, options)
803     elif devtype =='osc':
804         add_osc(gen, lustre, options)
805     elif devtype == 'mtpt':
806         add_mtpt(gen, lustre, options)
807     elif devtype == 'mds':
808         add_mds(gen, lustre, options)
809     elif devtype == 'ost':
810         add_ost(gen, lustre, options)
811     elif devtype == 'lov':
812         add_lov(gen, lustre, options)
813     elif devtype == 'route':
814         add_route(gen, lustre, options)
815     elif devtype == 'node':
816         add_node(gen, lustre, options)
817     elif devtype == 'echo_client':
818         add_echo_client(gen, lustre, options)
819     elif devtype == 'oscref':
820         add_oscref(gen, lustre, options)
821     elif devtype == 'cobd':
822         add_cobd(gen, lustre, options)
823     else:
824         error("unknown device type:", devtype)
825     
826 def do_command(gen, lustre, options, args):
827     if options.has_key('add'):
828         add(options['add'], gen, lustre, options)
829     else:
830         error("Missing command")
831
832 def main():
833     options, args = parse_cmdline(sys.argv[1:])
834     outFile = '-'
835
836     if options.has_key('merge'):
837         outFile = options['merge']
838         if os.access(outFile, os.R_OK):
839             doc = xml.dom.minidom.parse(outFile)
840         else:
841             doc = new_lustre(xml.dom.minidom)
842     elif options.has_key('in'):
843         doc = xml.dom.minidom.parse(options['in'])
844     else:
845         doc = new_lustre(xml.dom.minidom)
846
847     if options.has_key('output'):
848         outFile = options['output']
849
850     lustre = doc.documentElement
851     init_names(lustre)
852     if lustre.tagName != "lustre":
853         print "Existing config not valid."
854         sys.exit(1)
855
856     gen = GenConfig(doc)
857
858     if options.has_key('batch'):
859         fp = open(options['batch'])
860         batchCommands = fp.readlines()
861         fp.close()
862         for cmd in batchCommands:
863             options, args = parse_cmdline(string.split(cmd))
864             try:
865                 do_command(gen, lustre, options, args)
866             except OptionError, e:
867                 panic(cmd, e)
868     else:
869         try:
870             do_command(gen, lustre, options, args)
871         except OptionError, e:
872             panic(string.join(sys.argv),e)
873
874     if outFile == '-':
875         PrettyPrint(doc)
876     else:
877         PrettyPrint(doc, open(outFile,"w"))
878
879 if __name__ == "__main__":
880     main()