Whamcloud - gitweb
Merge of b_md to HEAD:
[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 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 mountpoint(self, name, uuid, mds_uuid, osc_uuid, path):
291         mtpt = self.newService("mountpoint", name, uuid)
292         mtpt.appendChild(self.ref("mds", mds_uuid))
293         mtpt.appendChild(self.ref("osc", osc_uuid))
294         self.addElement(mtpt, "path", path)
295         return mtpt
296
297     def echo_client(self, name, uuid, osc_uuid):
298         ec = self.newService("echo_client", name, uuid)
299         ec.appendChild(self.ref("osc", osc_uuid))
300         return ec
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     lov_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
616     lov_uuid = name2uuid(lustre, lov_name, tag='lov', fatal=0)
617     if not lov_uuid:
618         lov_uuid = name2uuid(lustre, lov_name, tag='osc', fatal=1)
619
620     echo = gen.echo_client(echoname, echo_uuid, lov_uuid)
621     lustre.appendChild(echo)
622
623
624 def add_lov(gen, lustre, options, args):
625     """ create a lov """
626     if len(args) < 4:
627         usage()
628
629     name = new_name(options['lov'])
630     if name != options['lov']:
631         warning("name:", options['lov'], "already used. using:", name)
632
633     mds_name = args[0]
634     stripe_sz = args[1]
635     stripe_count = args[2]
636     pattern = args[3]
637     uuid = new_uuid(name)
638
639     ret = findByName(lustre, name, "lov")
640     if ret:
641         error("LOV: ", name, " already exists.")
642
643     mds_uuid = name2uuid(lustre, mds_name, 'mds')
644     lov = gen.lov(name, uuid, mds_uuid, stripe_sz, stripe_count, pattern)
645     lustre.appendChild(lov)
646     
647     # add an lovconfig entry to the mds profile
648     lovconfig_name = new_name('LVCFG_' + name)
649     lovconfig_uuid = new_uuid(lovconfig_name)
650     node = mds2node(lustre, mds_name)
651     node_add_profile(gen, node, "lovconfig", lovconfig_uuid)
652     lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid)
653     lustre.appendChild(lovconfig)
654
655
656
657 def add_mtpt(gen, lustre, options, args):
658     """ create mtpt on a node """
659     if len(args) < 3:
660         usage()
661
662     if options.has_key('node'):
663         node_name = options['node']
664     else:
665         error("--mtpt requires a --node argument")
666
667     path = args[0]
668     mds_name = args[1]
669     lov_name = args[2]
670
671     name = new_name('MNT_'+ node_name)
672
673     ret = findByName(lustre, name, "mountpoint")
674     if ret:
675         error("MOUNTPOINT: ", name, " already exists.")
676
677     mds_uuid = name2uuid(lustre, mds_name, tag='mds')
678     lov_uuid = name2uuid(lustre, lov_name, tag='lov', fatal=0)
679     if not lov_uuid:
680         lov_uuid = name2uuid(lustre, lov_name, tag='osc', fatal=1)
681
682     uuid = new_uuid(name)
683     mtpt = gen.mountpoint(name, uuid, mds_uuid, lov_uuid, path)
684     node = findByName(lustre, node_name, "node")
685     if not node:
686             error('node:',  node_name, "not found.")
687     node_add_profile(gen, node, "mountpoint", uuid)
688     lustre.appendChild(mtpt)
689
690
691 ############################################################
692 # Command line processing
693 #
694 def parse_cmdline(argv):
695     short_opts = "ho:i:m:"
696     long_opts = ["ost", "osc", "mtpt", "lov=", "node=", "mds=", "net",
697                  "echo_client", "tcpbuf=",
698                  "route", "router", "merge=", "format", "reformat", "output=",
699                  "obdtype=", "fstype=", "obduuid=", "in=", "help", "batch="]
700     opts = []
701     args = []
702     options = {}
703     try:
704         opts, args = getopt.getopt(argv, short_opts, long_opts)
705     except getopt.error:
706         print "invalid opt"
707         usage()
708
709     for o, a in opts:
710         # Commands to create new devices
711         if o == "--ost":
712             options['ost'] = 1
713         if o == "--osc":
714             options['osc'] = 1
715         if o == "--echo_client":
716             options['echo_client'] = 1
717         if o == "--mds":
718             options['mds'] = a
719         if o == "--net":
720             options['net'] = 1
721         if o == "--mtpt":
722             options['mtpt'] = 1
723         if o == "--node":
724             options['node'] = a
725         if o == "--route":
726             options['route'] = 1
727         if o == "--router":
728             options['router'] = 1
729         if o == "--lov":
730             options['lov'] = a
731
732         # Options for commands
733         if o == "--obdtype":
734             options['obdtype'] = a
735         if o == "--fstype":
736             options['fstype'] = a
737         if o == "--obduuid":
738             options['obduuid'] = a
739         if o == "--tcpbuf":
740             options['tcpbuf'] = a
741
742         # lmc options
743         if o in ("-h", "--help"):
744             usage()
745         if o in ("-o", "--output"):
746             options['output'] = a
747         if o in ("-m", "--merge"):
748             options['merge'] = a
749         if o == "--format":
750             options['format'] = 1
751         if o  == "--reformat":
752             options['reformat'] = 1
753         if o  == "--batch":
754             options['batch'] = a
755         if o  in ("--in" , "-i"):
756             options['in'] = a
757             
758     return options, args
759
760
761 # simple class for profiling
762 import time
763 class chrono:
764     def __init__(self):
765         self._start = 0
766     def start(self):
767         self._stop = 0
768         self._start = time.time()
769     def stop(self, msg=''):
770         self._stop = time.time()
771         if msg:
772             self.display(msg)
773     def dur(self):
774         return self._stop - self._start
775     def display(self, msg):
776         d = self.dur()
777         str = '%s: %g secs' % (msg, d)
778         print str
779
780 ############################################################
781 # Main
782 #
783 def do_command(gen, lustre, options, args):
784     if options.has_key('ost'):
785         add_ost(gen, lustre, options, args)
786     elif options.has_key('osc'):
787         add_osc(gen, lustre, options, args)
788     elif options.has_key('echo_client'):
789         add_echo_client(gen, lustre, options, args)
790     elif options.has_key('mtpt'):
791         add_mtpt(gen, lustre, options, args)
792     elif options.has_key('mds'):
793         add_mds(gen, lustre, options, args)
794     elif options.has_key('net'):
795         add_net(gen, lustre, options, args)
796     elif options.has_key('lov'):
797         add_lov(gen, lustre, options, args)
798     elif options.has_key('route'):
799         add_route(gen, lustre, options, args)
800     elif options.has_key('node'):
801         add_node(gen, lustre, options, args)
802     else:
803         print "Missing command"
804         usage()
805
806 def main():
807     options, args = parse_cmdline(sys.argv[1:])
808     outFile = '-'
809
810     if options.has_key('merge'):
811         outFile = options['merge']
812         if os.access(outFile, os.R_OK):
813             doc = xml.dom.minidom.parse(outFile)
814         else:
815             doc = new_lustre(xml.dom.minidom)
816     elif options.has_key('in'):
817         doc = xml.dom.minidom.parse(options['in'])
818     else:
819         doc = new_lustre(xml.dom.minidom)
820
821     if options.has_key('output'):
822         outFile = options['output']
823
824     lustre = doc.documentElement
825     init_names(lustre)
826     if lustre.tagName != "lustre":
827         print "Existing config not valid."
828         sys.exit(1)
829
830     gen = GenConfig(doc)
831
832     if options.has_key('batch'):
833         fp = open(options['batch'])
834         batchCommands = fp.readlines()
835         fp.close()
836         for cmd in batchCommands:
837             options, args = parse_cmdline(string.split(cmd))
838             do_command(gen, lustre, options, args)
839     else:
840         do_command(gen, lustre, options, args)
841
842     if outFile == '-':
843         PrettyPrint(doc)
844     else:
845         PrettyPrint(doc, open(outFile,"w"))
846
847 if __name__ == "__main__":
848     main()
849
850