Whamcloud - gitweb
b=191
[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  Basic plan for lmc usage:
25 # create nodes
26 ./lmc --output config.xml --node server --net server1 tcp 
27 ./lmc --merge config.xml  --node client --net client1 tcp
28 ./lmc --merge config.xml  --node client --route gw lo [hi]
29 ./lmc --merge config.xml --router --node gw1 --net gw1 tcp
30 ./lmc --merge config.xml --node gw1 --net 1 elan
31
32 ./lmc --merge config.xml --route elan 1 1 100
33 ./lmc --merge config.xml --route tcp gw1 ba1
34
35
36
37 # configure server
38 ./lmc --merge config.xml  --node server --mds mds1 /tmp/mds1 50000
39
40 # create lov
41 ./lmc --merge config.xml  --lov lov1 mds1 65536 0 0
42 ./lmc --merge config.xml  --node server --lov lov1 --ost /tmp/ost1 100000
43 ./lmc --merge config.xml  --node server --lov lov1 --ost /tmp/ost2 100000
44
45 # create client config
46 ./lmc --merge config.xml  --node client --mtpt /mnt/lustre mds1 lov1
47
48 """
49
50 import sys, os, getopt, string
51 import xml.dom.minidom
52 from xml.dom.ext import PrettyPrint
53
54
55 DEFAULT_PORT = 988 # XXX What is the right default acceptor port to use?
56
57 def usage():
58     print """usage: lmc [--node --ost | --mtpt | --lov] args
59 Commands:
60 --node node_name 
61    Node_name by itself it will create a new node. If the --router
62    option is used when creating a new node, then that node will also
63    be configured as a router. When used with other commands it
64    specifies the node to modify.
65
66 --net hostname nettype [port, recv_buf, send_buf]
67    Nettype is either tcp, toe, elan, or gm.
68    Requires --node
69
70 --route net gw lo [hi]
71    This command is used to create  routes.  NET is the
72    network type this route will be used on.  The GW is an address of
73    one of the local interfaces. LO and HI represent a range of
74    addresses that can be reached through the gateway. If HI is not
75    set, then a route to the specific host in LO is created.
76
77 --mds device [size]
78    Create a MDS using the device
79    Requires --node 
80
81 --lov lov_name [mds_name stripe_sz sub_stripe_count pattern]
82    Creates a logical volume
83    When used with other commands, it specifics the lov to modify
84
85 --ost device [size]
86    Creates an OBD/OST/OSC configuration triplet for a new device.
87    When used on "host", the device will be initialized and the OST
88    will be enabled. On client nodes, the OSC will be avaiable.
89    Requires --node
90    Optional --obduuid Specifies the UUID used for the obd. 
91    If --lov lov_name is used, this device is added to lov. 
92
93 --mtpt /mnt/point mds_name lov_name|osc_name 
94    Creates a client mount point.
95    Requires --node
96
97 Options:
98 --merge="xml file"  Add the new objects to an existing file
99 --format            Format the partitions if unformated
100                     NB: The autoformat option has been disabled until a safe
101                     method is implemented to determine if a block device has a
102                     filesystem.
103 --reformat          Reformat partitions (this should be an lconf arg,
104                     I think)
105 --obdtype="obdtype" Specifiy obdtype: valid ones are obdecho and obdfilter.
106                     This is only useful for the --ost command.
107                     The device parameters are ignored for the obdecho type.
108 """
109     sys.exit(1)
110
111 def error(*args):
112     msg = string.join(map(str,args))
113     print "Error: ", msg
114     sys.exit(1)
115     
116 def warning(*args):
117     msg = string.join(map(str,args))
118     print "Warning: ", msg
119     
120 #
121 # manage names and uuids
122 # need to initialize this by walking tree to ensure
123 # no duplicate names or uuids are created.
124 # this are just place holders for now.
125 # consider changing this to be like OBD-dev-host
126 def new_name(base):
127     ctr = 2
128     ret = base
129     while names.has_key(ret):
130         ret = "%s_%d" % (base, ctr)
131         ctr = 1 + ctr
132     names[ret] = 1
133     return ret
134
135 def new_uuid(name):
136     return "%s_UUID" % (name)
137
138 ldlm_name = 'ldlm'
139 ldlm_uuid = 'ldlm_UUID'
140 def new_lustre(dom):
141     """Create a new empty lustre document"""
142     # adding ldlm here is a bit of a hack, but one is enough.
143     str = """<lustre>
144     <ldlm name="%s" uuid="%s"/>
145     </lustre>""" % (ldlm_name, ldlm_uuid)
146     return dom.parseString(str)
147
148 names = {}
149 uuids = {}
150
151 def init_names(doc):
152     """initialize auto-name generation tables"""
153     global names, uuids
154     # get all elements that contain a name attribute
155     for n in doc.childNodes:
156         if n.nodeType == n.ELEMENT_NODE:
157             if getName(n):
158                 names[getName(n)] = 1
159                 uuids[getUUID(n)] = 1
160             init_names(n)
161
162 def get_format_flag(options):
163     if options.has_key('format'):
164         if options['format']:
165             return 'yes'
166     return 'no'
167
168 ############################################################
169 # Build config objects using DOM
170 #
171 class GenConfig:
172     doc = None
173     dom = None
174     def __init__(self, doc):
175         self.doc = doc
176
177     def ref(self, type, uuid):
178         """ generate <[type]_ref uuidref="[uuid]"/> """
179         tag = "%s_ref" % (type)
180         ref = self.doc.createElement(tag)
181         ref.setAttribute("uuidref", uuid)
182         return ref
183     
184     def newService(self, tag, name, uuid):
185         """ create a new  service elmement, which requires name and uuid attributes """
186         new = self.doc.createElement(tag)
187         new.setAttribute("name", name);
188         new.setAttribute("uuid", uuid);
189         return new
190     
191     def addText(self, node, str):
192         txt = self.doc.createTextNode(str)
193         node.appendChild(txt)
194
195     def addElement(self, node, tag, str=None):
196         """ create a new element and add it as a child to node. If str is passed,
197             a text node is created for the new element"""
198         new = self.doc.createElement(tag)
199         if str:
200             self.addText(new, str)
201         node.appendChild(new)
202         return new
203
204     def network(self, name, uuid, hostname, net, port=0, tcpbuf=0):
205         """create <network> node"""
206         network = self.newService("network", name, uuid)
207         network.setAttribute("type", net);
208         self.addElement(network, "server", hostname)
209         if port:
210             self.addElement(network, "port", "%d" %(port))
211         if tcpbuf:
212             self.addElement(network, "send_mem", "%d" %(tcpbuf))
213             self.addElement(network, "recv_mem", "%d" %(tcpbuf))
214             
215         return network
216
217     def route(self, net_type, gw, lo, hi):
218         """ create one entry for the route table """
219         ref = self.doc.createElement('route')
220         ref.setAttribute("type", net_type)
221         ref.setAttribute("gw", gw)
222         ref.setAttribute("lo", lo)
223         if hi:
224             ref.setAttribute("hi", hi)
225         return ref
226     
227     def node(self, name, uuid):
228         """ create a host """
229         node = self.newService("node", name, uuid)
230         self.addElement(node, 'profile')
231         return node
232
233     def ldlm(self, name, uuid):
234         """ create a ldlm """
235         ldlm = self.newService("ldlm", name, uuid)
236         return ldlm
237
238     def obd(self, name, uuid, fs, obdtype, devname, format, dev_size=0):
239         obd = self.newService("obd", name, uuid)
240         obd.setAttribute('type', obdtype)
241         if fs:
242             self.addElement(obd, "fstype", fs)
243         if devname:
244             dev = self.addElement(obd, "device", devname)
245             if (dev_size):
246                 dev.setAttribute("size", "%s" % (dev_size))
247             self.addElement(obd, "autoformat", format)
248         return obd
249
250     def osc(self, name, uuid, obd_uuid, net_uuid):
251         osc = self.newService("osc", name, uuid)
252         osc.appendChild(self.ref("ost", net_uuid))
253         osc.appendChild(self.ref("obd", obd_uuid))
254         return osc
255
256     def echo_client(self, name, uuid, osc_uuid):
257         ec = self.newService("echo_client", name, uuid)
258         ec.appendChild(self.ref("osc", osc_uuid))
259         return ec
260
261     def ost(self, name, uuid, obd_uuid, net_uuid):
262         ost = self.newService("ost", name, uuid)
263         ost.appendChild(self.ref("network", net_uuid))
264         ost.appendChild(self.ref("obd", obd_uuid))
265         return ost
266
267     def lov(self, name, uuid, mds_uuid, stripe_sz, stripe_count, pattern):
268         lov = self.newService("lov", name, uuid)
269         lov.appendChild(self.ref("mds", mds_uuid))
270         devs = self.addElement(lov, "devices" )
271         devs.setAttribute("stripesize", stripe_sz)
272         devs.setAttribute("stripecount", stripe_count)
273         devs.setAttribute("pattern", pattern)
274         return lov
275
276     def lovconfig(self, name, uuid, lov_uuid):
277         lovconfig = self.newService("lovconfig", name, uuid)
278         lovconfig.appendChild(self.ref("lov", lov_uuid))
279         return lovconfig
280
281     def mds(self, name, uuid, fs, devname, format, net_uuid, node_uuid,
282             failover_uuid = "", dev_size=0 ):
283         mds = self.newService("mds", name, uuid)
284         self.addElement(mds, "fstype", fs)
285         dev = self.addElement(mds, "device", devname)
286         if dev_size:
287             dev.setAttribute("size", "%s" % (dev_size))
288         self.addElement(mds, "autoformat", format)
289         mds.appendChild(self.ref("network", net_uuid))
290         mds.appendChild(self.ref("node", node_uuid))
291         if failover_uuid:
292             mds.appendChild(self.ref("failover", failover_uuid))
293         return mds
294
295     def mountpoint(self, name, uuid, mds_uuid, osc_uuid, path):
296         mtpt = self.newService("mountpoint", name, uuid)
297         mtpt.appendChild(self.ref("mds", mds_uuid))
298         mtpt.appendChild(self.ref("osc", osc_uuid))
299         self.addElement(mtpt, "path", path)
300         return mtpt
301
302 ############################################################
303 # Utilities to query a DOM tree
304 # Using this functions we can treat use config information
305 # directly as a database.
306 def getName(n):
307     return n.getAttribute('name')
308
309 def getUUID(node):
310     return node.getAttribute('uuid')
311
312
313 def findByName(lustre, name, tag = ""):
314     for n in lustre.childNodes:
315         if n.nodeType == n.ELEMENT_NODE:
316             if tag and n.nodeName != tag:
317                 continue
318             if getName(n) == name:
319                 return n
320             else:
321                 n = findByName(n, name)
322                 if n: return n
323     return None
324
325
326 def lookup(node, uuid):
327     for n in node.childNodes:
328         if n.nodeType == n.ELEMENT_NODE:
329             if getUUID(n) == uuid:
330                 return n
331             else:
332                 n = lookup(n, uuid)
333                 if n: return n
334     return None
335             
336
337 def mds2node(lustre, mds_name):
338     """ Find the node a MDS is configured on """
339     mds = findByName(lustre, mds_name, 'mds')
340     ref = mds.getElementsByTagName('node_ref')
341     if not ref:
342         error("mds2node:", "no node_ref found for", '"'+mds_name+'"')
343     node_uuid = ref[0].getAttribute('uuidref')
344     node = lookup(lustre, node_uuid)
345     if not node:
346         error('mds2node:', "no node found for :", '"'+mds_name+'"')
347     return node
348
349
350 def name2uuid(lustre, name, tag="",  fatal=1):
351     ret = findByName(lustre, name, tag)
352     if not ret:
353         if fatal:
354             error('name2uuid:', '"'+name+'"', tag, 'element not found.')
355         else:
356             return ""
357     return getUUID(ret)
358     
359
360 # XXX: assumes only one network element per node. will fix this
361 # as soon as support for routers is added
362 def get_net_uuid(lustre, node_name):
363     """ get a network uuid for a node_name """
364     node = findByName(lustre, node_name, "node")
365     if not node:
366         error ('get_net_uuid:', '"'+node_name+'"', "node element not found.")
367     net = node.getElementsByTagName('network')
368     if net:
369         return getUUID(net[0])
370     return None
371
372
373 def lov_add_osc(gen, lov, osc_uuid):
374     devs = lov.getElementsByTagName('devices')
375     if len(devs) == 1:
376         devs[0].appendChild(gen.ref("osc", osc_uuid))
377     else:
378         error("No devices element found for LOV:", lov)
379
380                             
381 def node_add_profile(gen, node, ref, uuid):
382     ret = node.getElementsByTagName('profile')
383     if not ret:
384         error('node has no profile:', node)
385     ret[0].appendChild(gen.ref(ref, uuid))
386     
387 def get_attr(dom_node, attr, default=""):
388     v = dom_node.getAttribute(attr)
389     if v:
390         return v
391     return default
392
393 ############################################################
394 # Top level commands
395 #
396 def do_add_node(gen, lustre,  options, node_name):
397     uuid = new_uuid(node_name)
398     node = gen.node(node_name, uuid)
399     node_add_profile(gen, node, 'ldlm', ldlm_uuid)
400     if options.has_key('router'):
401         node.setAttribute('router', '1')
402     lustre.appendChild(node)
403     return node
404
405     
406 def add_node(gen, lustre, options, args):
407     """ create a node with a network config """
408     if len(args) > 1:
409         usage()
410
411     node_name = options['node']
412
413     ret = findByName(lustre, node_name, "node")
414     if ret:
415         print "Node:", node_name, "exists."
416         return
417     do_add_node(gen, lustre, options, node_name)
418
419
420 def add_net(gen, lustre, options, args):
421     """ create a node with a network config """
422     if len(args) < 2:
423         usage()
424
425     node_name = options['node']
426     nid = args[0]
427     net_type = args[1]
428     port = 0
429     tcpbuf = 0
430
431     if net_type in ('tcp', 'toe'):
432         if len(args) > 2:
433             port = int(args[2])
434         else:
435             port = DEFAULT_PORT
436         if options.has_key('tcpbuf'):
437             tcpbuf = int(options['tcpbuf'])
438     elif net_type in ('elan', 'gm'):
439         port = 0
440     else:
441         print "Unknown net_type: ", net_type
442         sys.exit(2)
443
444     ret = findByName(lustre, node_name, "node")
445     if not ret:
446         node = do_add_node(gen, lustre, options, node_name)
447     else:
448         node = ret
449     net_name = new_name('NET_'+ node_name +'_'+ net_type)
450     net_uuid = new_uuid(net_name)
451     node.appendChild(gen.network(net_name, net_uuid, nid, net_type, port, tcpbuf))
452     node_add_profile(gen, node, "network", net_uuid)
453
454
455 def add_route(gen, lustre, options, args):
456     """ create a node with a network config """
457     if len(args) < 3:
458         usage()
459
460     node_name = options['node']
461     net_type= args[0]
462     gw = args[1]
463     lo = args[2]
464     hi = ''
465
466     if len(args) > 3:
467         hi = args[3]
468
469     node = findByName(lustre, node_name, "node")
470     if not node:
471         error (node_name, " not found.")
472     
473     netlist = node.getElementsByTagName('network')
474     net = netlist[0]
475     rlist = net.getElementsByTagName('route_tbl')
476     if len(rlist) > 0:
477         rtbl = rlist[0]
478     else:
479         rtbl = gen.addElement(net, 'route_tbl')
480     rtbl.appendChild(gen.route(net_type, gw, lo, hi))
481
482
483 def add_mds(gen, lustre, options, args):
484     fstype = 'extN'
485
486     if len(args) < 1:
487         usage()
488
489     if options.has_key('node'):
490         node_name = options['node']
491     else:
492         error("--mds requires a --node argument")
493
494     if options.has_key('fstype'):
495         fstype = options['fstype']
496
497     mds_name = new_name(options['mds'])
498     if mds_name != options['mds']:
499         warning("name:", options['mds'], "already used. using:", mds_name)
500     devname = args[0]
501     if len(args) > 1:
502         size = args[1]
503     else:
504         size = 0
505
506     mds_uuid = new_uuid(mds_name)
507
508     node_uuid = name2uuid(lustre, node_name, 'node')
509
510     node = findByName(lustre, node_name, "node")
511     node_add_profile(gen, node, "mds", mds_uuid)
512     net_uuid = get_net_uuid(lustre, node_name)
513     if not net_uuid:
514         error("NODE: ", node_name, "not found")
515
516     mds = gen.mds(mds_name, mds_uuid, fstype, devname, get_format_flag(options),
517                   net_uuid, node_uuid, dev_size=size)
518     lustre.appendChild(mds)
519                    
520
521 def add_ost(gen, lustre, options, args):
522     lovname = ''
523     obdtype = 'obdfilter'
524     devname = ''
525     size = 0
526     fstype = 'extN'
527     
528     if options.has_key('node'):
529         node_name = options['node']
530     else:
531         error("--ost requires a --node argument")
532
533     if options.has_key('lov'):
534         lovname = options['lov']
535
536     if options.has_key('obdtype'):
537         obdtype = options['obdtype']
538     if options.has_key('fstype'):
539         fstype = options['fstype']
540     if obdtype == 'obdecho':
541         fstype = ''
542     else:
543         if len(args) < 1:
544             usage()
545         devname = args[0]
546         if len(args) > 1:
547             size = args[1]
548         
549     obdname = new_name('OBD_'+ node_name)
550     oscname = new_name('OSC_'+ node_name)
551     ostname = new_name('OST_'+ node_name)
552     if options.has_key('obduuid'):
553         obd_uuid = options['obduuid']
554         obd = lookup(lustre, obd_uuid)
555         if obd:
556             error("Duplicate OBD UUID:", obd_uuid)
557     else:
558         obd_uuid = new_uuid(obdname)
559     ost_uuid = new_uuid(ostname)
560     osc_uuid = new_uuid(oscname)
561
562     net_uuid = get_net_uuid(lustre, node_name)
563     if not net_uuid:
564         error("NODE: ", node_name, "not found")
565     
566     obd = gen.obd(obdname, obd_uuid, fstype, obdtype, devname, get_format_flag(options), size)
567     ost = gen.ost(ostname, ost_uuid, obd_uuid, net_uuid)
568     osc = gen.osc(oscname, osc_uuid, obd_uuid, ost_uuid)
569     
570     if lovname:
571         lov = findByName(lustre, lovname, "lov")
572         if not lov:
573             error('add_ost:', '"'+lovname+'"', "lov element not found.")
574         lov_add_osc(gen, lov, osc_uuid)
575
576     node = findByName(lustre, node_name, "node")
577     node_add_profile(gen, node, 'obd', obd_uuid)
578     node_add_profile(gen, node, 'ost', ost_uuid)
579
580     lustre.appendChild(obd)
581     lustre.appendChild(osc)
582     lustre.appendChild(ost)
583
584                    
585 # this is generally only used by llecho.sh
586 def add_osc(gen, lustre, options, args):
587     """ add the osc to the profile for this node. """
588     if len(args) < 1:
589         usage()
590     osc_name = args[0]
591     if options.has_key('node'):
592         node_name = options['node']
593     else:
594         error("--osc requires a --node argument")
595     osc_uuid = name2uuid(lustre, osc_name) # either 'osc' or 'lov'
596     node = findByName(lustre, node_name, "node")
597     node_add_profile(gen, node, 'osc', osc_uuid)
598
599
600 #ditto
601 def add_echo_client(gen, lustre, options, args):
602     """ add an echo client to the profile for this node. """
603     if len(args) < 1:
604         usage()
605     osc_name = args[0]
606     if options.has_key('node'):
607         node_name = options['node']
608     else:
609         error("--echo_client requires a --node argument")
610     node = findByName(lustre, node_name, "node")
611
612     echoname = new_name('ECHO_'+ node_name)
613     echo_uuid = new_uuid(echoname)
614     node_add_profile(gen, node, 'echo_client', echo_uuid)
615     osc_uuid = name2uuid(lustre, osc_name) # either 'osc' or 'lov'
616     echo = gen.echo_client(echoname, echo_uuid, osc_uuid)
617     lustre.appendChild(echo)
618
619
620 def add_lov(gen, lustre, options, args):
621     """ create a lov """
622     if len(args) < 4:
623         usage()
624
625     name = new_name(options['lov'])
626     if name != options['lov']:
627         warning("name:", options['lov'], "already used. using:", name)
628
629     mds_name = args[0]
630     stripe_sz = args[1]
631     stripe_count = args[2]
632     pattern = args[3]
633     uuid = new_uuid(name)
634
635     ret = findByName(lustre, name, "lov")
636     if ret:
637         error("LOV: ", name, " already exists.")
638
639     mds_uuid = name2uuid(lustre, mds_name, 'mds')
640     lov = gen.lov(name, uuid, mds_uuid, stripe_sz, stripe_count, pattern)
641     lustre.appendChild(lov)
642     
643     # add an lovconfig entry to the mds profile
644     lovconfig_name = new_name('LVCFG_' + name)
645     lovconfig_uuid = new_uuid(lovconfig_name)
646     node = mds2node(lustre, mds_name)
647     node_add_profile(gen, node, "lovconfig", lovconfig_uuid)
648     lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid)
649     lustre.appendChild(lovconfig)
650
651
652
653 def add_mtpt(gen, lustre, options, args):
654     """ create mtpt on a node """
655     if len(args) < 3:
656         usage()
657
658     if options.has_key('node'):
659         node_name = options['node']
660     else:
661         error("--mtpt requires a --node argument")
662
663     path = args[0]
664     mds_name = args[1]
665     lov_name = args[2]
666
667     name = new_name('MNT_'+ node_name)
668
669     ret = findByName(lustre, name, "mountpoint")
670     if ret:
671         error("MOUNTPOINT: ", name, " already exists.")
672
673     mds_uuid = name2uuid(lustre, mds_name, tag='mds')
674     lov_uuid = name2uuid(lustre, lov_name, tag='lov', fatal=0)
675     if not lov_uuid:
676         lov_uuid = name2uuid(lustre, lov_name, tag='osc', fatal=1)
677
678     uuid = new_uuid(name)
679     mtpt = gen.mountpoint(name, uuid, mds_uuid, lov_uuid, path)
680     node = findByName(lustre, node_name, "node")
681     if not node:
682             error('node:',  node_name, "not found.")
683     node_add_profile(gen, node, "mountpoint", uuid)
684     lustre.appendChild(mtpt)
685
686
687 ############################################################
688 # Command line processing
689 #
690 def parse_cmdline(argv):
691     short_opts = "ho:i:m:"
692     long_opts = ["ost", "osc", "mtpt", "lov=", "node=", "mds=", "net",
693                  "echo_client", "tcpbuf=",
694                  "route", "router", "merge=", "format", "reformat", "output=",
695                  "obdtype=", "fstype=", "obduuid=", "in=", "help", "batch="]
696     opts = []
697     args = []
698     options = {}
699     try:
700         opts, args = getopt.getopt(argv, short_opts, long_opts)
701     except getopt.error:
702         print "invalid opt"
703         usage()
704
705     for o, a in opts:
706         # Commands to create new devices
707         if o == "--ost":
708             options['ost'] = 1
709         if o == "--osc":
710             options['osc'] = 1
711         if o == "--echo_client":
712             options['echo_client'] = 1
713         if o == "--mds":
714             options['mds'] = a
715         if o == "--net":
716             options['net'] = 1
717         if o == "--mtpt":
718             options['mtpt'] = 1
719         if o == "--node":
720             options['node'] = a
721         if o == "--route":
722             options['route'] = 1
723         if o == "--router":
724             options['router'] = 1
725         if o == "--lov":
726             options['lov'] = a
727
728         # Options for commands
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         if o == "--tcpbuf":
736             options['tcpbuf'] = a
737
738         # lmc options
739         if o in ("-h", "--help"):
740             usage()
741         if o in ("-o", "--output"):
742             options['output'] = a
743         if o in ("-m", "--merge"):
744             options['merge'] = a
745         if o == "--format":
746             options['format'] = 1
747         if o  == "--reformat":
748             options['reformat'] = 1
749         if o  == "--batch":
750             options['batch'] = a
751         if o  in ("--in" , "-i"):
752             options['in'] = a
753             
754     return options, args
755
756
757 # simple class for profiling
758 import time
759 class chrono:
760     def __init__(self):
761         self._start = 0
762     def start(self):
763         self._stop = 0
764         self._start = time.time()
765     def stop(self, msg=''):
766         self._stop = time.time()
767         if msg:
768             self.display(msg)
769     def dur(self):
770         return self._stop - self._start
771     def display(self, msg):
772         d = self.dur()
773         str = '%s: %g secs' % (msg, d)
774         print str
775
776 ############################################################
777 # Main
778 #
779 def do_command(gen, lustre, options, args):
780     if options.has_key('ost'):
781         add_ost(gen, lustre, options, args)
782     elif options.has_key('osc'):
783         add_osc(gen, lustre, options, args)
784     elif options.has_key('echo_client'):
785         add_echo_client(gen, lustre, options, args)
786     elif options.has_key('mtpt'):
787         add_mtpt(gen, lustre, options, args)
788     elif options.has_key('mds'):
789         add_mds(gen, lustre, options, args)
790     elif options.has_key('net'):
791         add_net(gen, lustre, options, args)
792     elif options.has_key('lov'):
793         add_lov(gen, lustre, options, args)
794     elif options.has_key('route'):
795         add_route(gen, lustre, options, args)
796     elif options.has_key('node'):
797         add_node(gen, lustre, options, args)
798     else:
799         print "Missing command"
800         usage()
801
802 def main():
803     options, args = parse_cmdline(sys.argv[1:])
804     outFile = '-'
805
806     if options.has_key('merge'):
807         outFile = options['merge']
808         if os.access(outFile, os.R_OK):
809             doc = xml.dom.minidom.parse(outFile)
810         else:
811             doc = new_lustre(xml.dom.minidom)
812     elif options.has_key('in'):
813         doc = xml.dom.minidom.parse(options['in'])
814     else:
815         doc = new_lustre(xml.dom.minidom)
816
817     if options.has_key('output'):
818         outFile = options['output']
819
820     lustre = doc.documentElement
821     init_names(lustre)
822     if lustre.tagName != "lustre":
823         print "Existing config not valid."
824         sys.exit(1)
825
826     gen = GenConfig(doc)
827
828     if options.has_key('batch'):
829         fp = open(options['batch'])
830         batchCommands = fp.readlines()
831         fp.close()
832         for cmd in batchCommands:
833             options, args = parse_cmdline(string.split(cmd))
834             do_command(gen, lustre, options, args)
835     else:
836         do_command(gen, lustre, options, args)
837
838     if outFile == '-':
839         PrettyPrint(doc)
840     else:
841         PrettyPrint(doc, open(outFile,"w"))
842
843 if __name__ == "__main__":
844     main()
845
846