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