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