Whamcloud - gitweb
Modified the this to generate mdc configuration.
[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, 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("network", net_uuid))
253         osc.appendChild(self.ref("obd", obd_uuid))
254         return osc
255
256     def ost(self, name, uuid, obd_uuid, net_uuid):
257         ost = self.newService("ost", name, uuid)
258         ost.appendChild(self.ref("network", net_uuid))
259         ost.appendChild(self.ref("obd", obd_uuid))
260         return ost
261
262     def lov(self, name, uuid, mds_uuid, stripe_sz, stripe_count, pattern):
263         lov = self.newService("lov", name, uuid)
264         lov.appendChild(self.ref("mds", mds_uuid))
265         devs = self.addElement(lov, "devices" )
266         devs.setAttribute("stripesize", stripe_sz)
267         devs.setAttribute("stripecount", stripe_count)
268         devs.setAttribute("pattern", pattern)
269         return lov
270
271     def lovconfig(self, name, uuid, lov_uuid):
272         lovconfig = self.newService("lovconfig", name, uuid)
273         lovconfig.appendChild(self.ref("lov", lov_uuid))
274         return lovconfig
275
276     def mds(self, name, uuid, fs, devname, format, net_uuid, node_uuid,
277             failover_uuid = "", dev_size=0 ):
278         mds = self.newService("mds", name, uuid)
279         self.addElement(mds, "fstype", fs)
280         dev = self.addElement(mds, "device", devname)
281         if dev_size:
282             dev.setAttribute("size", "%s" % (dev_size))
283         self.addElement(mds, "autoformat", format)
284         mds.appendChild(self.ref("network", net_uuid))
285         mds.appendChild(self.ref("node", node_uuid))
286         if failover_uuid:
287             mds.appendChild(self.ref("failover", failover_uuid))
288         return mds
289
290     def mdc(self, name, uuid, mds_uuid, net_uuid):
291         mdc = self.newService("mdc",name,uuid)
292         mdc.appendChild(self.ref("mds",mds_uuid))
293         mdc.appendChild(self.ref("network",net_uuid))
294         return mdc
295  
296     def mountpoint(self, name, uuid, mdc_uuid, osc_uuid, path):
297         mtpt = self.newService("mountpoint", name, uuid)
298         mtpt.appendChild(self.ref("mdc", mdc_uuid))
299         mtpt.appendChild(self.ref("osc", osc_uuid))
300         self.addElement(mtpt, "path", path)
301         return mtpt
302
303 ############################################################
304 # Utilities to query a DOM tree
305 # Using this functions we can treat use config information
306 # directly as a database.
307 def getName(n):
308     return n.getAttribute('name')
309
310 def getUUID(node):
311     return node.getAttribute('uuid')
312
313
314 def findByName(lustre, name, tag = ""):
315     for n in lustre.childNodes:
316         if n.nodeType == n.ELEMENT_NODE:
317             if tag and n.nodeName != tag:
318                 continue
319             if getName(n) == name:
320                 return n
321             else:
322                 n = findByName(n, name)
323                 if n: return n
324     return None
325
326
327 def lookup(node, uuid):
328     for n in node.childNodes:
329         if n.nodeType == n.ELEMENT_NODE:
330             if getUUID(n) == uuid:
331                 return n
332             else:
333                 n = lookup(n, uuid)
334                 if n: return n
335     return None
336             
337
338 def mds2node(lustre, mds_name):
339     """ Find the node a MDS is configured on """
340     mds = findByName(lustre, mds_name, 'mds')
341     ref = mds.getElementsByTagName('node_ref')
342     if not ref:
343         error("mds2node:", "no node_ref found for", '"'+mds_name+'"')
344     node_uuid = ref[0].getAttribute('uuidref')
345     node = lookup(lustre, node_uuid)
346     if not node:
347         error('mds2node:', "no node found for :", '"'+mds_name+'"')
348     return node
349
350
351 def name2uuid(lustre, name, tag="",  fatal=1):
352     ret = findByName(lustre, name, tag)
353     if not ret:
354         if fatal:
355             error('name2uuid:', '"'+name+'"', tag, 'element not found.')
356         else:
357             return ""
358     return getUUID(ret)
359     
360
361 # XXX: assumes only one network element per node. will fix this
362 # as soon as support for routers is added
363 def get_net_uuid(lustre, node_name):
364     """ get a network uuid for a node_name """
365     node = findByName(lustre, node_name, "node")
366     if not node:
367         error ('get_net_uuid:', '"'+node_name+'"', "node element not found.")
368     net = node.getElementsByTagName('network')
369     if net:
370         return getUUID(net[0])
371     return None
372
373
374 def lov_add_osc(gen, lov, osc_uuid):
375     devs = lov.getElementsByTagName('devices')
376     if len(devs) == 1:
377         devs[0].appendChild(gen.ref("osc", osc_uuid))
378     else:
379         error("No devices element found for LOV:", lov)
380
381                             
382 def node_add_profile(gen, node, ref, uuid):
383     ret = node.getElementsByTagName('profile')
384     if not ret:
385         error('node has no profile:', node)
386     ret[0].appendChild(gen.ref(ref, uuid))
387     
388 def get_attr(dom_node, attr, default=""):
389     v = dom_node.getAttribute(attr)
390     if v:
391         return v
392     return default
393
394 ############################################################
395 # Top level commands
396 #
397 def do_add_node(gen, lustre,  options, node_name):
398     uuid = new_uuid(node_name)
399     node = gen.node(node_name, uuid)
400     node_add_profile(gen, node, 'ldlm', ldlm_uuid)
401     if options.has_key('router'):
402         node.setAttribute('router', '1')
403     lustre.appendChild(node)
404     return node
405
406     
407 def add_node(gen, lustre, options, args):
408     """ create a node with a network config """
409     if len(args) > 1:
410         usage()
411
412     node_name = options['node']
413
414     ret = findByName(lustre, node_name, "node")
415     if ret:
416         print "Node:", node_name, "exists."
417         return
418     do_add_node(gen, lustre, options, node_name)
419
420
421 def add_net(gen, lustre, options, args):
422     """ create a node with a network config """
423     if len(args) < 2:
424         usage()
425
426     node_name = options['node']
427     nid = args[0]
428     net_type = args[1]
429     port = 0
430     tcpbuf = 0
431
432     if net_type == 'tcp':
433         if len(args) > 2:
434             port = int(args[2])
435         else:
436             port = DEFAULT_PORT
437         if options.has_key('tcpbuf'):
438             tcpbuf = int(options['tcpbuf'])
439     elif net_type in ('elan', 'gm'):
440         port = 0
441     else:
442         print "Unknown net_type: ", net_type
443         sys.exit(2)
444
445     ret = findByName(lustre, node_name, "node")
446     if not ret:
447         node = do_add_node(gen, lustre, options, node_name)
448     else:
449         node = ret
450     net_name = new_name('NET_'+ node_name +'_'+ net_type)
451     net_uuid = new_uuid(net_name)
452     node.appendChild(gen.network(net_name, net_uuid, nid, net_type, port, tcpbuf))
453     node_add_profile(gen, node, "network", net_uuid)
454
455
456 def add_route(gen, lustre, options, args):
457     """ create a node with a network config """
458     if len(args) < 3:
459         usage()
460
461     node_name = options['node']
462     net_type= args[0]
463     gw = args[1]
464     lo = args[2]
465     hi = ''
466
467     if len(args) > 3:
468         hi = args[3]
469
470     node = findByName(lustre, node_name, "node")
471     if not node:
472         error (node_name, " not found.")
473     
474     netlist = node.getElementsByTagName('network')
475     net = netlist[0]
476     rlist = net.getElementsByTagName('route_tbl')
477     if len(rlist) > 0:
478         rtbl = rlist[0]
479     else:
480         rtbl = gen.addElement(net, 'route_tbl')
481     rtbl.appendChild(gen.route(net_type, gw, lo, hi))
482
483
484 def add_mds(gen, lustre, options, args):
485     if len(args) < 1:
486         usage()
487
488     if options.has_key('node'):
489         node_name = options['node']
490     else:
491         error("--mds requires a --node argument")
492
493     mds_name = new_name(options['mds'])
494     if mds_name != options['mds']:
495         warning("name:", options['mds'], "already used. using:", mds_name)
496     devname = args[0]
497     if len(args) > 1:
498         size = args[1]
499     else:
500         size = 0
501
502     mds_uuid = new_uuid(mds_name)
503
504     node_uuid = name2uuid(lustre, node_name, 'node')
505
506     node = findByName(lustre, node_name, "node")
507     node_add_profile(gen, node, "mds", mds_uuid)
508     net_uuid = get_net_uuid(lustre, node_name)
509     if not net_uuid:
510         error("NODE: ", node_name, "not found")
511
512
513     mds = gen.mds(mds_name, mds_uuid, "extN", devname, get_format_flag(options),
514                   net_uuid, node_uuid, dev_size=size)
515     lustre.appendChild(mds)
516                    
517
518 def add_ost(gen, lustre, options, args):
519     lovname = ''
520     obdtype = 'obdfilter'
521     devname = ''
522     size = 0
523     fstype = 'extN'
524     
525     if options.has_key('node'):
526         node_name = options['node']
527     else:
528         error("--ost requires a --node argument")
529
530     if options.has_key('lov'):
531         lovname = options['lov']
532
533     if options.has_key('obdtype'):
534         obdtype = options['obdtype']
535
536     if obdtype == 'obdecho':
537         fstype = ''
538     else:
539         if len(args) < 1:
540             usage()
541         devname = args[0]
542         if len(args) > 1:
543             size = args[1]
544         
545     obdname = new_name('OBD_'+ node_name)
546     oscname = new_name('OSC_'+ node_name)
547     ostname = new_name('OST_'+ node_name)
548     if options.has_key('obduuid'):
549         obd_uuid = options['obduuid']
550         obd = lookup(lustre, obd_uuid)
551         if obd:
552             error("Duplicate OBD UUID:", obd_uuid)
553     else:
554         obd_uuid = new_uuid(obdname)
555     ost_uuid = new_uuid(ostname)
556     osc_uuid = new_uuid(oscname)
557
558     net_uuid = get_net_uuid(lustre, node_name)
559     if not net_uuid:
560         error("NODE: ", node_name, "not found")
561     
562     obd = gen.obd(obdname, obd_uuid, fstype, obdtype, devname, get_format_flag(options), size)
563     ost = gen.ost(ostname, ost_uuid, obd_uuid, net_uuid)
564     osc = gen.osc(oscname, osc_uuid, obd_uuid, net_uuid)
565     
566     if lovname:
567         lov = findByName(lustre, lovname, "lov")
568         if not lov:
569             error('add_ost:', '"'+lovname+'"', "lov element not found.")
570         lov_add_osc(gen, lov, osc_uuid)
571
572     node = findByName(lustre, node_name, "node")
573     node_add_profile(gen, node, 'obd', obd_uuid)
574     node_add_profile(gen, node, 'ost', ost_uuid)
575
576     lustre.appendChild(obd)
577     lustre.appendChild(osc)
578     lustre.appendChild(ost)
579
580                    
581 # this is generally only used by llecho.sh
582 def add_osc(gen, lustre, options, args):
583     """ add the osc to the profile for this node. """
584     if len(args) < 1:
585         usage()
586     osc_name = args[0]
587     if options.has_key('node'):
588         node_name = options['node']
589     else:
590         error("--osc requires a --node argument")
591     osc_uuid = name2uuid(lustre, osc_name) # either 'osc' or 'lov'
592     node = findByName(lustre, node_name, "node")
593     node_add_profile(gen, node, 'osc', osc_uuid)
594
595
596 def add_lov(gen, lustre, options, args):
597     """ create a lov """
598     if len(args) < 4:
599         usage()
600
601     name = new_name(options['lov'])
602     if name != options['lov']:
603         warning("name:", options['lov'], "already used. using:", name)
604
605     mds_name = args[0]
606     stripe_sz = args[1]
607     stripe_count = args[2]
608     pattern = args[3]
609     uuid = new_uuid(name)
610
611     ret = findByName(lustre, name, "lov")
612     if ret:
613         error("LOV: ", name, " already exists.")
614
615     mds_uuid = name2uuid(lustre, mds_name, 'mds')
616     lov = gen.lov(name, uuid, mds_uuid, stripe_sz, stripe_count, pattern)
617     lustre.appendChild(lov)
618     
619     # add an lovconfig entry to the mds profile
620     lovconfig_name = new_name('LVCFG_' + name)
621     lovconfig_uuid = new_uuid(lovconfig_name)
622     node = mds2node(lustre, mds_name)
623     node_add_profile(gen, node, "lovconfig", lovconfig_uuid)
624     lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid)
625     lustre.appendChild(lovconfig)
626
627
628
629 def add_mtpt(gen, lustre, options, args):
630     """ create mtpt on a node """
631     if len(args) < 3:
632         usage()
633
634     if options.has_key('node'):
635         node_name = options['node']
636     else:
637         error("--mtpt requires a --node argument")
638
639     path = args[0]
640     mds_name = args[1]
641     lov_name = args[2]
642
643     name = new_name('MNT_'+ node_name)
644
645     ret = findByName(lustre, name, "mountpoint")
646     if ret:
647         error("MOUNTPOINT: ", name, " already exists.")
648
649     mds_uuid = name2uuid(lustre, mds_name, tag='mds')
650     lov_uuid = name2uuid(lustre, lov_name, tag='lov', fatal=0)
651     if not lov_uuid:
652         lov_uuid = name2uuid(lustre, lov_name, tag='osc', fatal=1)
653
654     uuid = new_uuid(name)
655     mdc_name = new_name('MDC_'+mds_name)
656     mdc_uuid = new_uuid(mdc_name)
657     lovnode = lookup(lustre,lov_uuid)
658
659
660     mdsnode = lookup(lustre,mds_uuid) 
661     ref = mdsnode.getElementsByTagName('network_ref')
662     net_uuid = ref[0].getAttribute('uuidref')
663
664     mdc = gen.mdc(mdc_name,mdc_uuid,mds_uuid,net_uuid)
665     lustre.appendChild(mdc)
666
667      
668     lovnode.appendChild(gen.ref("mdc",mdc_uuid))
669
670  
671     mtpt = gen.mountpoint(name, uuid, mdc_uuid, lov_uuid, path)
672
673     node = findByName(lustre, node_name, "node")
674     if not node:
675             error('node:',  node_name, "not found.")
676     node_add_profile(gen, node, "mountpoint", uuid)
677     lustre.appendChild(mtpt)
678
679
680 ############################################################
681 # Command line processing
682 #
683 def parse_cmdline(argv):
684     short_opts = "ho:i:m:"
685     long_opts = ["ost", "osc", "mtpt", "lov=", "node=", "mds=", "net", "tcpbuf=",
686                  "route", "router", "merge=", "format", "reformat", "output=",
687                  "obdtype=", "obduuid=", "in=", "help", "batch="]
688     opts = []
689     args = []
690     options = {}
691     try:
692         opts, args = getopt.getopt(argv, short_opts, long_opts)
693     except getopt.error:
694         print "invalid opt"
695         usage()
696
697     for o, a in opts:
698         # Commands to create new devices
699         if o == "--ost":
700             options['ost'] = 1
701         if o == "--osc":
702             options['osc'] = 1
703         if o == "--mds":
704             options['mds'] = a
705         if o == "--net":
706             options['net'] = 1
707         if o == "--mtpt":
708             options['mtpt'] = 1
709         if o == "--node":
710             options['node'] = a
711         if o == "--route":
712             options['route'] = 1
713         if o == "--router":
714             options['router'] = 1
715         if o == "--lov":
716             options['lov'] = a
717
718         # Options for commands
719         if o == "--obdtype":
720             options['obdtype'] = a
721         if o == "--obduuid":
722             options['obduuid'] = a
723         if o == "--tcpbuf":
724             options['tcpbuf'] = a
725
726         # lmc options
727         if o in ("-h", "--help"):
728             usage()
729         if o in ("-o", "--output"):
730             options['output'] = a
731         if o in ("-m", "--merge"):
732             options['merge'] = a
733         if o == "--format":
734             options['format'] = 1
735         if o  == "--reformat":
736             options['reformat'] = 1
737         if o  == "--batch":
738             options['batch'] = a
739         if o  in ("--in" , "-i"):
740             options['in'] = a
741             
742     return options, args
743
744
745 # simple class for profiling
746 import time
747 class chrono:
748     def __init__(self):
749         self._start = 0
750     def start(self):
751         self._stop = 0
752         self._start = time.time()
753     def stop(self, msg=''):
754         self._stop = time.time()
755         if msg:
756             self.display(msg)
757     def dur(self):
758         return self._stop - self._start
759     def display(self, msg):
760         d = self.dur()
761         str = '%s: %g secs' % (msg, d)
762         print str
763
764 ############################################################
765 # Main
766 #
767 def do_command(gen, lustre, options, args):
768     if options.has_key('ost'):
769         add_ost(gen, lustre, options, args)
770     elif options.has_key('osc'):
771         add_osc(gen, lustre, options, args)
772     elif options.has_key('mtpt'):
773         add_mtpt(gen, lustre, options, args)
774     elif options.has_key('mds'):
775         add_mds(gen, lustre, options, args)
776     elif options.has_key('net'):
777         add_net(gen, lustre, options, args)
778     elif options.has_key('lov'):
779         add_lov(gen, lustre, options, args)
780     elif options.has_key('route'):
781         add_route(gen, lustre, options, args)
782     elif options.has_key('node'):
783         add_node(gen, lustre, options, args)
784     else:
785         print "Missing command"
786         usage()
787
788 def main():
789     options, args = parse_cmdline(sys.argv[1:])
790     outFile = '-'
791
792     if options.has_key('merge'):
793         outFile = options['merge']
794         if os.access(outFile, os.R_OK):
795             doc = xml.dom.minidom.parse(outFile)
796         else:
797             doc = new_lustre(xml.dom.minidom)
798     elif options.has_key('in'):
799         doc = xml.dom.minidom.parse(options['in'])
800     else:
801         doc = new_lustre(xml.dom.minidom)
802
803     if options.has_key('output'):
804         outFile = options['output']
805
806     lustre = doc.documentElement
807     init_names(lustre)
808     if lustre.tagName != "lustre":
809         print "Existing config not valid."
810         sys.exit(1)
811
812     gen = GenConfig(doc)
813
814     if options.has_key('batch'):
815         fp = open(options['batch'])
816         batchCommands = fp.readlines()
817         fp.close()
818         for cmd in batchCommands:
819             options, args = parse_cmdline(string.split(cmd))
820             do_command(gen, lustre, options, args)
821     else:
822         do_command(gen, lustre, options, args)
823
824     if outFile == '-':
825         PrettyPrint(doc)
826     else:
827         PrettyPrint(doc, open(outFile,"w"))
828
829 if __name__ == "__main__":
830     main()
831
832