Whamcloud - gitweb
- debug info to investigate a source of small writes
[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 configuration data manager
23
24   See Lustre book (http://www.lustre.org/docs/lustre.pdf) for documentation on lmc.
25
26 """
27
28 import sys, os, getopt, string, exceptions, re
29 import xml.dom.minidom
30
31 def printDoc(doc, stream=sys.stdout):
32     try:
33         from xml.dom.ext import PrettyPrint
34         PrettyPrint(doc, stream)
35     except ImportError:
36         stream.write(doc.toxml())
37         stream.write("\n")
38
39
40 PYMOD_DIR = "/usr/lib/lustre/python"
41
42 def development_mode():
43     base = os.path.dirname(sys.argv[0])
44     if os.access(base+"/Makefile.am", os.R_OK):
45         return 1
46     return 0
47
48 if not development_mode():
49     sys.path.append(PYMOD_DIR)
50
51 import Lustre
52
53 DEFAULT_PORT = 988
54 DEFAULT_STRIPE_SZ = 1048576
55 DEFAULT_STRIPE_CNT = 1
56 DEFAULT_STRIPE_PATTERN = 0
57 UUID_MAX_LENGTH = 31
58
59 def reference():
60     print """usage: lmc --add object [object parameters]
61
62 Object creation command summary:
63
64 --add node
65   --node node_name
66   --timeout num
67   --upcall path
68   --lustre_upcall path
69   --portals_upcall path
70   --ptldebug debug_level
71   --subsystem subsystem_name
72
73 --add net
74   --node node_name
75   --nid nid
76   --cluster_id 
77   --nettype tcp|elan|gm|openib|iib|vib|ra
78   --hostaddr ip[/netmask]
79   --port port
80   --tcpbuf size
81   --irq_affinity 0|1
82   --router
83
84 --add filesystem
85   --filesystem fs_name
86   --gks gks_name
87
88 --add mds
89   --node node_name
90   --mds mds_name
91   --failover
92   --dev path
93   --backdev path
94   --fstype ldiskfs|ext3
95   --backfstype ldiskfs|ext3|tmpfs
96   --size size
97   --nspath
98   --journal_size size
99   --inode_size size
100   --mdsuuid uuid
101   --lmv lmv_name
102   --mkfsoptions options
103   --mountfsoptions options
104   --root_squash uid:gid
105   --no_root_squash ptl_nid 
106   --mds_mds_sec flavor
107   --mds_oss_sec flavor
108   --mds_deny_sec flavor[,flavor[...]]
109   --filesystem filesystem name
110
111 --add lov
112   --lov lov_name
113   --mds mds_name
114   --lmv lmv_name
115   --aware one or few mds/lmv names separated by comma
116   --stripe_sz num
117   --stripe_cnt num
118   --stripe_pattern num
119
120 --add ost
121   --node node_name
122   --ost ost_name 
123   --failover
124   --lov lov_name 
125   --index index
126   --dev path
127   --backdev path
128   --size size
129   --fstype ldiskfs|ext3
130   --backfstype ldiskfs|ext3|tmpfs
131   --journal_size size
132   --inode_size size
133   --osdtype obdecho|obdfilter
134   --ostuuid uuid
135   --mkfsoptions options
136   --mountfsoptions options
137   --nspath
138   --ost_deny_sec flavor[,flavor[...]]
139   --filesystem filesystem name
140  
141 --delete ost
142   --ost ost_name
143   --migrate
144   
145 --deactivate ost
146   --node node_name
147   --ost ost_name
148
149 --add mtpt  - Mountpoint
150   --node node_name
151   --path /mnt/point
152   --mds mds_name
153   --lmv lmv_name
154   --ost ost_name OR --lov lov_name
155   --clientoptions options
156   --mds_sec flavor
157   --oss_sec flavor
158
159 --add route
160   --node nodename
161   --router
162   --gw nid
163   --gateway_cluster_id nid
164   --target_cluster_id nid
165   --lo nid
166   --hi nid
167
168 --add echo_client
169   --node nodename
170
171 --add mgmt  - Management/monitoring service
172   --node node_name
173   --mgmt mgmt_service_name
174
175 --add lmv
176   --lmv lmv_name
177
178 --add cobd
179   --node node_name
180   --master_obd obd_name
181   --cache_obd obd_name
182
183 --add cmobd
184   --node node_name
185   --master_obd obd_name
186   --cache_obd obd_name
187
188 --add gks
189   --gks gks_name  
190
191 --commit - Close a configuration version, and start a new one
192 """
193
194 PARAM = Lustre.Options.PARAM
195 PARAMLIST = Lustre.Options.PARAMLIST
196 lmc_options = [
197     # lmc input/output options
198     ('reference', "Print short reference for commands."),
199     ('verbose,v', "Print system commands as they are run."),
200     ('merge,m', "Append to the specified config file.", PARAM),
201     ('output,o', "Write XML configuration into given output file. Overwrite existing content.", PARAM),
202     ('input,i', "", PARAM),
203     ('batch', "Used to execute lmc commands in batch mode.", PARAM),
204
205     # commands
206     ('add', "", PARAM),
207     ('delete', "", PARAM),
208     ('deactivate', "", PARAM),
209     ('commit', "Commit all config changes and start a new version"),
210
211     # node options
212     ('node', "Add a new node in the cluster configuration.", PARAM),
213     ('timeout', "Set timeout to initiate recovery.", PARAM),
214     ('upcall', "Set both lustre and portals upcall scripts.", PARAM),
215     ('lustre_upcall', "Set location of lustre upcall script.", PARAM),
216     ('portals_upcall', "Set location of portals upcall script.", PARAM),
217     ('ptldebug', "Set the portals debug level",  PARAM),
218     ('subsystem', "Specify which Lustre subsystems have debug output recorded in the log",  PARAM),
219
220     # network 
221     ('nettype', "Specify the network type. This can be tcp/elan/gm/openib/iib/vib/ra.", PARAM),
222     ('nid', "Give the network ID, e.g ElanID/IP Address as used by portals.", PARAM),
223     ('port', "Optional argument to specify the TCP port number.", PARAM, DEFAULT_PORT),
224     ('hostaddr', "Optional argument to specify the host address.", PARAMLIST),
225     ('cluster_id', "Specify the cluster ID", PARAM, "0"),
226
227     # routes
228     ('route', "Add a new route for the cluster.", PARAM),
229     ('router', "Optional flag to mark a node as router."),
230     ('gw', "Specify the nid of the gateway for a route.", PARAM),
231     ('gateway_cluster_id', "", PARAM, "0"),
232     ('target_cluster_id', "", PARAM, "0"),
233     ('lo', "For a range route, this is the low value nid.", PARAM),
234     ('hi', "For a range route, this is a hi value nid.", PARAM,""),
235
236     # servers: mds and ost
237     ('mds', "Specify MDS name.", PARAM,""),
238     ('ost', "Specify the OST name.", PARAM,""),
239     ('osdtype', "This could obdfilter or obdecho.", PARAM, "obdfilter"),
240     ('failover', "Enable failover support on OSTs or MDS?"),
241     ('group', "", PARAM),
242     ('dev', "Path of the device on local system.", PARAM,""),
243     ('backdev', "Path of the device for backing storage on local system.", PARAM,""),
244     ('size', "Specify the size of the device if needed.", PARAM,"0"),
245     ('journal_size', "Specify new journal size for underlying file system.", PARAM,"0"),
246     ('inode_size', "Specify new inode size for underlying file system.", PARAM,"0"),
247     ('fstype', "Optional argument to specify the filesystem type.", PARAM, "ext3"),
248     ('backfstype', "Optional argument to specify the backing filesystem type.", PARAM, "ext3"),
249     ('mkfsoptions', "Optional argument to mkfs.", PARAM, ""),
250     ('mountfsoptions', "Optional argument to mount fs.", PARAM, ""),
251     ('ostuuid', "Optional argument to specify OST UUID", PARAM,""),
252     ('mdsuuid', "Optional argument to specify MDS UUID", PARAM,""),
253     ('root_squash', "MDS squash root to appointed uid.", PARAM, ""),
254     ('no_root_squash', "Don't squash root for appointed nid.", PARAM, ""),
255     ('nspath', "Local mount point of server namespace.", PARAM,""),
256     ('mds_mds_sec', "Specify the secure flavor for connection from this mds to other mds.", PARAM, ""),
257     ('mds_oss_sec', "Specify the secure flavor for connection from this mds to ost.", PARAM, ""),
258     ('mds_deny_sec', "Specify the secure flavor which is denied from remote to this mds.", PARAM, ""),
259     ('ost_deny_sec', "Specify the secure flavor which is denied from remote to this ost.", PARAM, ""),
260     ('filesystem', "Specify the filesystem name device belong to.", PARAM, ""),
261     ('format', ""),
262     ('migrate', "used for offline migrate of an ost in conjunctio with add/delete"),
263
264     # clients: mountpoint and echo
265     ('echo_client', "", PARAM),
266     ('path', "Specify the mountpoint for Lustre.", PARAM),
267     ('filesystem', "Lustre filesystem name", PARAM,""),
268     ('clientoptions', "Specify the options for Lustre, such as async.", PARAM, ""),
269     ('mds_sec', "Specify the secure flavor for connection from this client to mds.", PARAM, ""),
270     ('oss_sec', "Specify the secure flavor for connection from this client to ost.", PARAM, ""),
271
272     # lov
273     ('lov', "Specify LOV name.", PARAM,""),
274     ('mds/lmv', "Specify MDS/LMV name using this LOV.", PARAM,""),
275     ('aware', "Specify MDS/LMV aware of this LOV.", PARAM,""),
276     ('index', "Specify index for OBD in LOV target table.", PARAM),
277     ('stripe_sz', "Specify the stripe size in bytes.", PARAM),
278     ('stripe_cnt', "Specify the number of OSTs each file should be striped on.", PARAM, 0),
279     ('stripe_pattern', "Specify the stripe pattern. RAID 0 is the only one currently supported.", PARAM, 0),
280
281     # cobd
282     ('master_obd', "Specify the real device for the cache obd system.", PARAM),
283     ('cache_obd', "Specify the cache device for the cache obd system.", PARAM),
284     ('cobd', "Specify COBD name", PARAM),
285
286     # cmobd
287     ('master_obd', "Specify the master device for the cmobd system.", PARAM),
288     ('cache_obd',  "Specify the cache device for the cmobd obd system.", PARAM),
289     ('cmobd',      "Specify COBD name", PARAM),
290
291     ('mgmt', "Specify management/monitoring service name.", PARAM, ""),
292
293     # lmv
294     ('lmv', "Specify LMV name.", PARAM,""),
295     
296     #gks name
297     ('gks', "Specify gks name.", PARAM,""),
298
299     ]
300
301 def error(*args):
302     msg = string.join(map(str,args))
303     raise OptionError("Error: " +  msg)
304
305 def panic(cmd, msg):
306     print "! " + cmd
307     print msg
308     sys.exit(1)
309
310
311 def warning(*args):
312     msg = string.join(map(str,args))
313     print "Warning: ", msg
314
315 #
316 # manage names and uuids
317 # need to initialize this by walking tree to ensure
318 # no duplicate names or uuids are created.
319 # this are just place holders for now.
320 # consider changing this to be like OBD-dev-host
321 def new_name(base):
322     ctr = 2
323     ret = base
324     while names.has_key(ret):
325         ret = "%s_%d" % (base, ctr)
326         ctr = 1 + ctr
327     names[ret] = 1
328     return ret
329
330 def new_uuid(name):
331     ctr = 2
332     ret = "%s_UUID" % (name)
333     if len(ret) > UUID_MAX_LENGTH:
334         ret = ret[-UUID_MAX_LENGTH:]
335     while uuids.has_key(ret):
336         ret = "%s_UUID_%d" % (name, ctr)
337         ctr = 1 + ctr
338         if len(ret) > UUID_MAX_LENGTH:
339             ret = ret[-UUID_MAX_LENGTH:]
340     uuids[ret] = 1
341     return ret
342
343
344 ldlm_name = 'ldlm'
345 ldlm_uuid = 'ldlm_UUID'
346
347 def new_lustre(dom):
348     """Create a new empty lustre document"""
349     # adding ldlm here is a bit of a hack, but one is enough.
350     str = """<lustre version="%s">
351     <ldlm name="%s" uuid="%s"/>
352     </lustre>""" % (Lustre.CONFIG_VERSION, ldlm_name, ldlm_uuid)
353     return dom.parseString(str)
354
355 names = {}
356 uuids = {}
357
358 def init_names(doc):
359     """initialize auto-name generation tables"""
360     global names, uuids
361     # get all elements that contain a name attribute
362     for n in doc.childNodes:
363         if n.nodeType == n.ELEMENT_NODE:
364             if getName(n):
365                 names[getName(n)] = 1
366                 uuids[getUUID(n)] = 1
367             init_names(n)
368
369 def get_format_flag(options):
370     if options.format:
371         return 'yes'
372     return 'no'
373
374 ############################################################
375 # Build config objects using DOM
376 #
377 class GenConfig:
378     doc = None
379     dom = None
380     def __init__(self, doc):
381         self.doc = doc
382
383     def ref(self, type, uuid):
384         """ generate <[type]_ref uuidref="[uuid]"/> """
385         tag = "%s_ref" % (type)
386         ref = self.doc.createElement(tag)
387         ref.setAttribute("uuidref", uuid)
388         return ref
389         
390     def dev(self, devname):
391         """ generate <dev devpath="[devname]"/> """
392         tgt = self.doc.createElement('dev')
393         tgt.setAttribute("dev", devname)
394         return tgt
395
396     def newService(self, tag, name, uuid):
397         """ create a new  service elmement, which requires name and uuid attributes """
398         new = self.doc.createElement(tag)
399         new.setAttribute("uuid", uuid);
400         new.setAttribute("name", name);
401         return new
402
403     def addText(self, node, str):
404         txt = self.doc.createTextNode(str)
405         node.appendChild(txt)
406
407     def addElement(self, node, tag, str=None):
408         """ create a new element and add it as a child to node. If str is passed,
409             a text node is created for the new element"""
410         new = self.doc.createElement(tag)
411         if str:
412             self.addText(new, str)
413         node.appendChild(new)
414         return new
415
416     def network(self, name, uuid, nid, cluster_id, net, hostaddr="",
417                 port=0):
418         """create <network> node"""
419         network = self.newService("network", name, uuid)
420         network.setAttribute("nettype", net);
421         self.addElement(network, "nid", nid)
422         self.addElement(network, "clusterid", cluster_id)
423         for host in  hostaddr:
424             self.addElement(network, "hostaddr", host)
425         if port:
426             self.addElement(network, "port", "%d" %(port))
427         
428         return network
429
430     def routetbl(self, name, uuid):
431         """create <routetbl> node"""
432         rtbl = self.newService("routetbl", name, uuid)
433         return rtbl
434
435     def route(self, gw_net_type, gw, gw_cluster_id, tgt_cluster_id, lo, hi):
436         """ create one entry for the route table """
437         ref = self.doc.createElement('route')
438         ref.setAttribute("type", gw_net_type)
439         ref.setAttribute("gw", gw)
440         ref.setAttribute("gwclusterid", gw_cluster_id)
441         ref.setAttribute("tgtclusterid", tgt_cluster_id)
442         ref.setAttribute("lo", lo)
443         if hi:
444             ref.setAttribute("hi", hi)
445         return ref
446
447     def profile(self, name, uuid):
448         """ create a host """
449         profile = self.newService("profile", name, uuid)
450         return profile
451
452     def node(self, name, uuid, prof_uuid):
453         """ create a host """
454         node = self.newService("node", name, uuid)
455         node.appendChild(self.ref("profile", prof_uuid))
456         return node
457
458     def ldlm(self, name, uuid):
459         """ create a ldlm """
460         ldlm = self.newService("ldlm", name, uuid)
461         return ldlm
462
463     def osd(self, name, uuid, fstype, osdtype, devname, format, ost_uuid,
464             node_uuid, dev_size=0, journal_size=0, inode_size=0, nspath="", 
465             mkfsoptions="", mountfsoptions="", backfstype="", backdevname="",
466             deny_sec="", fs_uuid=""):
467         osd = self.newService("osd", name, uuid)
468         osd.setAttribute('osdtype', osdtype)
469         osd.appendChild(self.ref("target", ost_uuid))
470         osd.appendChild(self.ref("node", node_uuid))
471
472         if devname:
473             osd.appendChild(self.dev(devname)) 
474         if fstype:
475             self.addElement(osd, "fstype", fstype)
476         if backfstype:
477             self.addElement(osd, "backfstype", backfstype)
478         if backdevname:
479             self.addElement(osd, "backdevpath", backdevname)
480         if devname:
481             dev = self.addElement(osd, "devpath", devname)
482             self.addElement(osd, "autoformat", format)
483             if dev_size:
484                 self.addElement(osd, "devsize", "%s" % (dev_size))
485             if journal_size:
486                 self.addElement(osd, "journalsize", "%s" % (journal_size))
487             if inode_size:
488                 self.addElement(osd, "inodesize", "%s" % (inode_size))
489             if mkfsoptions:
490                 self.addElement(osd, "mkfsoptions", mkfsoptions)
491             if mountfsoptions:
492                 self.addElement(osd, "mountfsoptions", mountfsoptions)
493             if deny_sec:
494                 self.addElement(osd, "deny_sec", deny_sec)
495             if fs_uuid:
496                 osd.appendChild(self.ref("filesystem", fs_uuid))
497         if nspath:
498             self.addElement(osd, "nspath", nspath)
499         return osd
500
501     def cobd(self, name, uuid, master_uuid, cache_uuid):
502         cobd = self.newService("cobd", name, uuid)
503         cobd.appendChild(self.ref("masterobd",master_uuid))
504         cobd.appendChild(self.ref("cacheobd",cache_uuid))
505         return cobd
506
507     def cmobd(self, name, uuid, master_uuid, cache_uuid):
508         cmobd = self.newService("cmobd", name, uuid)
509         cmobd.appendChild(self.ref("masterobd",master_uuid))
510         cmobd.appendChild(self.ref("cacheobd",cache_uuid))
511         return cmobd
512
513     def ost(self, name, uuid, osd_uuid, group=""):
514         ost = self.newService("ost", name, uuid)
515         ost.appendChild(self.ref("active", osd_uuid))
516         if group:
517             self.addElement(ost, "group", group)
518         return ost
519
520     def oss(self, name, uuid):
521         oss = self.newService("oss", name, uuid)
522         return oss
523
524     def lov(self, name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern):
525         lov = self.newService("lov", name, uuid)
526         lov.appendChild(self.ref("mds", mds_uuid))
527         lov.setAttribute("stripesize", str(stripe_sz))
528         lov.setAttribute("stripecount", str(stripe_cnt))
529         lov.setAttribute("stripepattern", str(pattern))
530         return lov
531
532     def lov_tgt(self, obd_uuid, lov_uuid, index, generation):
533         tgt = self.doc.createElement('lov_tgt')
534         tgt.setAttribute("uuidref", obd_uuid)
535         tgt.setAttribute("lov_uuid", lov_uuid)
536         tgt.setAttribute("index", index)
537         tgt.setAttribute("generation", generation)
538         tgt.setAttribute("active", '1')
539         return tgt
540
541     def lovconfig(self, name, uuid, lov_uuid):
542         lovconfig = self.newService("lovconfig", name, uuid)
543         lovconfig.appendChild(self.ref("lov", lov_uuid))
544         return lovconfig
545
546     def lmv_tgt(self, mdt_uuid):
547         tgt = self.doc.createElement('lmv_tgt')
548         tgt.setAttribute("uuidref", mdt_uuid)
549         return tgt
550
551     def lmv(self, name, uuid):
552         lmv = self.newService("lmv", name, uuid)
553         return lmv
554
555     def gks(self, name, uuid, gkd_uuid):
556         gks = self.newService("gks", name, uuid)
557         gks.appendChild(self.ref("active", gkd_uuid))
558         return gks 
559
560     def gkd(self, name, uuid, node_uuid, gks_uuid):
561         gkd = self.newService("gkd", name, uuid)
562         gkd.appendChild(self.ref("node", node_uuid))
563         gkd.appendChild(self.ref("target", gks_uuid))
564         return gkd
565     
566     def mds(self, name, uuid, mdd_uuid, group="", lmv=""):
567         mds = self.newService("mds", name, uuid)
568         mds.appendChild(self.ref("active", mdd_uuid))
569         if group:
570             self.addElement(mds, "group", group)
571         return mds
572
573     def mdsdev(self, name, uuid, fstype, devname, format, node_uuid,
574                mds_uuid, dev_size=0, journal_size=0, inode_size=256,
575                nspath="", mkfsoptions="", mountfsoptions="", backfstype="", 
576                backdevname="",lmv_uuid="", root_squash="", no_root_squash="",
577                mds_sec="", oss_sec="", deny_sec="", fs_uuid=""):
578         mdd = self.newService("mdsdev", name, uuid)
579         self.addElement(mdd, "fstype", fstype)
580         if backfstype:
581             self.addElement(mdd, "backfstype", backfstype)
582         dev = self.addElement(mdd, "devpath", devname)
583         if backdevname:
584             self.addElement(mdd, "backdevpath", backdevname)
585         self.addElement(mdd, "autoformat", format)
586         if dev_size:
587             self.addElement(mdd, "devsize", "%s" % (dev_size))
588         if journal_size:
589             self.addElement(mdd, "journalsize", "%s" % (journal_size))
590         if inode_size:
591             self.addElement(mdd, "inodesize", "%s" % (inode_size))
592         if nspath:
593             self.addElement(mdd, "nspath", nspath)
594         if mkfsoptions:
595             self.addElement(mdd, "mkfsoptions", mkfsoptions)
596         if mountfsoptions:
597             self.addElement(mdd, "mountfsoptions", mountfsoptions)
598         if root_squash:
599             self.addElement(mdd, "root_squash", root_squash)
600         if no_root_squash:
601             self.addElement(mdd, "no_root_squash", no_root_squash)
602         if mds_sec:
603             self.addElement(mdd, "mds_sec", mds_sec)
604         if oss_sec:
605             self.addElement(mdd, "oss_sec", oss_sec)
606         if deny_sec:
607             self.addElement(mdd, "deny_sec", deny_sec)
608         if fs_uuid:
609             mdd.appendChild(self.ref("filesystem", fs_uuid))
610         mdd.appendChild(self.ref("node", node_uuid))
611         mdd.appendChild(self.ref("target", mds_uuid))
612         
613         dev = self.dev(devname)
614         if dev != None:
615             mdd.appendChild(dev)
616
617         if lmv_uuid:
618             mdd.appendChild(self.ref("lmv", lmv_uuid))
619
620         return mdd
621
622     def mgmt(self, mgmt_name, mgmt_uuid, node_uuid):
623         mgmt = self.newService("mgmt", mgmt_name, mgmt_uuid)
624         mgmt.appendChild(self.ref("node", node_uuid))
625         # Placeholder until mgmt-service failover.
626         mgmt.appendChild(self.ref("active", mgmt_uuid))
627         return mgmt
628
629     def mountpoint(self, name, uuid, fs_uuid, path, clientoptions,
630                    mds_sec, oss_sec):
631         mtpt = self.newService("mountpoint", name, uuid)
632         mtpt.appendChild(self.ref("filesystem", fs_uuid))
633         self.addElement(mtpt, "path", path)
634         if clientoptions:
635             self.addElement(mtpt, "clientoptions", clientoptions)
636         if mds_sec:
637             self.addElement(mtpt, "mds_sec", mds_sec)
638         if oss_sec:
639             self.addElement(mtpt, "oss_sec", oss_sec)
640         return mtpt
641
642     def filesystem(self, name, uuid, mds_uuid, obd_uuid, mgmt_uuid, gks_uuid):
643         fs = self.newService("filesystem", name, uuid)
644         
645         if mds_uuid:
646             fs.appendChild(self.ref("mds", mds_uuid))
647         if obd_uuid:
648             fs.appendChild(self.ref("obd", obd_uuid))
649         if gks_uuid:
650             fs.appendChild(self.ref("gks", gks_uuid))
651         if mgmt_uuid:
652             fs.appendChild(self.ref("mgmt", mgmt_uuid))
653         return fs
654
655     def echo_client(self, name, uuid, osc_uuid):
656         ec = self.newService("echoclient", name, uuid)
657         ec.appendChild(self.ref("obd", osc_uuid))
658         return ec
659
660     def update(self, version):
661         new = self.doc.createElement("update")
662         new.setAttribute("version", version)
663         return new
664
665     def info(self):
666         new = self.doc.createElement("info")
667         return new
668
669     def lmv_add(self, lmv, mdt):
670         new = self.doc.createElement("lmv_add")
671         new.setAttribute("lmv_uuidref", lmv)
672         new.setAttribute("mdt_uuidref", mdt)
673         return new
674
675     def lov_add(self, lov, ost, index, gen):
676         new = self.doc.createElement("lov_add")
677         new.setAttribute("lov_uuidref", lov)
678         new.setAttribute("ost_uuidref", ost)
679         new.setAttribute("index", index)
680         new.setAttribute("generation", gen)
681         return new
682
683     def lov_delete(self, lov, ost, index, gen, options):
684         if options.delete:
685             new = self.doc.createElement("lov_delete")
686         else:
687             new = self.doc.createElement("lov_deactivate")
688         new.setAttribute("lov_uuidref", lov)
689         new.setAttribute("ost_uuidref", ost)
690         new.setAttribute("index", index)
691         new.setAttribute("generation", gen)
692         return new
693
694 ############################################################
695 # Utilities to query a DOM tree
696 # Using this functions we can treat use config information
697 # directly as a database.
698 def getName(n):
699     return n.getAttribute('name')
700
701 def getUUID(node):
702     return node.getAttribute('uuid')
703
704 def findLastUpdate(lustre):
705     node = None
706     version = 0
707     for n in lustre.childNodes:
708         if n.nodeType == n.ELEMENT_NODE:
709             if n.nodeName != 'update':
710                 continue
711             tmp = int(n.getAttribute('version'))
712             if not tmp:
713                 error('malformed XML: update tag without a version attribute')
714             if tmp != version + 1:
715                 error('malformed XML: expecting update record '+str(version + 1)+', found '+str(tmp)+'.')
716             version = tmp
717             node = n
718     return node
719
720 def addUpdate(gen, lustre, node):
721     update = findLastUpdate(lustre)
722     if not update:
723         return
724     update.appendChild(node)
725
726 def findByName(lustre, name, tag = ""):
727     for n in lustre.childNodes:
728         if n.nodeType == n.ELEMENT_NODE:
729             if tag and n.nodeName != tag:
730                 continue
731             if getName(n) == name:
732                 return n
733             else:
734                 n = findByName(n, name)
735                 if n: return n
736     return None
737
738
739 def lookup(node, uuid):
740     for n in node.childNodes:
741         if n.nodeType == n.ELEMENT_NODE:
742             if getUUID(n) == uuid:
743                 return n
744             else:
745                 n = lookup(n, uuid)
746                 if n: return n
747     return None
748
749
750 def name2uuid(lustre, name, tag="",  fatal=1):
751     ret = findByName(lustre, name, tag)
752     if not ret:
753         if fatal:
754             error('name2uuid:', '"'+name+'"', tag, 'element not found.')
755         else:
756             return ""
757     return getUUID(ret)
758
759 def lookup_filesystem(lustre, fs_name):
760     for n in lustre.childNodes:
761         if n.nodeType == n.ELEMENT_NODE and n.nodeName == 'filesystem':
762             if getName(n) == fs_name:
763                 return getUUID(n)
764     return None
765
766 # XXX: assumes only one network element per node. will fix this
767 # as soon as support for routers is added
768 def get_net_uuid(lustre, node_name):
769     """ get a network uuid for a node_name """
770     node = findByName(lustre, node_name, "node")
771     if not node:
772         error ('get_net_uuid:', '"'+node_name+'"', "node element not found.")
773     net = node.getElementsByTagName('network')
774     if net:
775         return getUUID(net[0])
776     return None
777
778 def lov_mod_obd(gen, lustre, lov, tgt, osc_uuid, options):
779     tgt.setAttribute('uuidref', osc_uuid)
780     gener = int(tgt.getAttribute('generation'))
781     if not options.migrate:
782         gener = str(int(gener) + 1)
783     tgt.setAttribute('generation', str(gener))
784     tgt.setAttribute('active', '1')
785     lov_index = int(tgt.getAttribute('index'))
786     add_rec = gen.lov_add(getUUID(lov), osc_uuid, str(lov_index), str(gener))
787     addUpdate(gen, lustre, add_rec)
788     return
789
790 def lov_add_osc(gen, lustre, lov, osc_uuid, options):
791     lov_name = getName(lov)
792     lov_uuid = getUUID(lov)
793     if options.index:
794         lov_index = get_option_int(options, 'index')
795         for tgt in lov.getElementsByTagName('lov_tgt'):
796             if str(lov_index) == tgt.getAttribute('index'):
797                 uuidref = tgt.getAttribute('uuidref')
798                 if uuidref != '':
799                     raise OptionError("%s --index %d is still in use: %s" %
800                                       (lov_name, lov_index, uuidref))
801                 lov_mod_obd(gen, lustre, lov, tgt, osc_uuid, options)
802                 return
803     else:
804          lov_index = 0
805          for tgt in lov.getElementsByTagName('lov_tgt'):
806              uuidref = tgt.getAttribute('uuidref')
807              tmp = int(tgt.getAttribute('index'))
808              own_lov_uuid = tgt.getAttribute('lov_uuid')
809              if lov_uuid != own_lov_uuid:
810                 continue
811              if uuidref == '':
812                  lov_mod_obd(gen, lustre, lov, tgt, osc_uuid, options)
813                  return
814              lov_index = lov_index + 1
815
816     lov.appendChild(gen.lov_tgt(osc_uuid, lov_uuid, str(lov_index), '1'))
817     addrec = gen.lov_add(lov_uuid, osc_uuid, str(lov_index), '1')
818     addUpdate(gen, lustre, addrec)
819
820 def lov_del_osc(gen, lustre, lov, osc_uuid, options):
821     lov_name = getName(lov)
822     if options.index:
823         lov_index = get_option_int(options, 'index')
824         for tgt in lov.getElementsByTagName('lov_tgt'):
825             index = tgt.getAttribute('index')
826             if index == lov_index:
827                 uuidref = tgt.getAttribute('uuidref')
828                 if uuidref != osc_uuid:
829                     raise OptionError("%s --index %d contains %s, not %s" %
830                                       (lov_name, lov_index, osc_uuid, uuidref))
831                 if options.delete:
832                     tgt.setAttribute('uuidref', '')
833
834                 gener = tgt.getAttribute('generation')
835                 if not options.migrate:
836                     # bump the generation just in case...
837                     gener = str(int(gener) + 1)
838
839                 tgt.setAttribute('active', '0')
840                 tgt.setAttribute('generation', gener)
841                 return None
842         raise OptionError("%s --index %d not in use by %s." %
843                           (lov_name, lov_index, osc_uuid))
844
845     for tgt in lov.getElementsByTagName('lov_tgt'):
846         uuidref = tgt.getAttribute('uuidref')
847         if uuidref == osc_uuid:
848             index = tgt.getAttribute('index')
849             gener = tgt.getAttribute('generation')
850             delete_rec = gen.lov_delete(getUUID(lov), osc_uuid, index, gener,
851                                         options)
852             addUpdate(gen, lustre, delete_rec)
853
854             if options.delete:
855                 tgt.setAttribute('uuidref', '')
856             if not options.migrate:
857                 gener = str(int(gener) + 1)
858             tgt.setAttribute('active', '0')
859             tgt.setAttribute('generation', gener)
860
861 def lmv_add_mdc(gen, lustre, lmv, mdc_uuid):
862     lmv.appendChild(gen.lmv_tgt(mdc_uuid))
863     addrec = gen.lmv_add(getUUID(lmv), mdc_uuid)
864     addUpdate(gen, lustre, addrec)
865                             
866 def ref_exists(profile, uuid):
867     elist = profile.childNodes
868     for e in elist:
869         if e.nodeType == e.ELEMENT_NODE:
870             ref = e.getAttribute('uuidref')
871             if ref == uuid:
872                 return 1
873     return 0
874
875 # ensure that uuid is not already in the profile
876 # return true if uuid is added
877 def node_add_profile(gen, node, ref, uuid):
878     refname = "%s_ref" % "profile"
879     ret = node.getElementsByTagName(refname)
880     if not ret:
881         error('node has no profile ref:', node)
882     prof_uuid = ret[0].getAttribute('uuidref')
883     profile = lookup(node.parentNode, prof_uuid)
884     if not profile:
885         error("no profile found:", prof_uuid)
886     if ref_exists(profile, uuid):
887         return 0
888     profile.appendChild(gen.ref(ref, uuid))
889     return 1
890
891 def get_attr(dom_node, attr, default=""):
892     v = dom_node.getAttribute(attr)
893     if v:
894         return v
895     return default
896
897 ############################################################
898 # Top level commands
899 #
900 def set_node_options(gen, node, options):
901     if options.router:
902         node.setAttribute('router', '1')
903     if options.timeout:
904         gen.addElement(node, "timeout", get_option(options, 'timeout'))
905     if options.upcall:
906         default_upcall =  get_option(options, 'upcall')
907     else:
908         default_upcall = ''
909     if default_upcall or options.lustre_upcall:
910         if options.lustre_upcall:
911             gen.addElement(node, 'lustreUpcall', options.lustre_upcall)
912         else:
913             gen.addElement(node, 'lustreUpcall', default_upcall)
914     if default_upcall or options.portals_upcall:
915         if options.portals_upcall:
916             gen.addElement(node, 'portalsUpcall', options.portals_upcall)
917         else:
918             gen.addElement(node, 'portalsUpcall', default_upcall)
919     if options.ptldebug:
920         gen.addElement(node, "ptldebug", get_option(options, 'ptldebug'))
921     if options.subsystem:
922         gen.addElement(node, "subsystem", get_option(options, 'subsystem'))
923     return node
924
925 def do_add_node(gen, lustre,  options, node_name):
926     uuid = new_uuid(node_name)
927     prof_name = new_name("PROFILE_" + node_name)
928     prof_uuid = new_uuid(prof_name)
929     profile = gen.profile(prof_name, prof_uuid)
930     node = gen.node(node_name, uuid, prof_uuid)
931     lustre.appendChild(node)
932     lustre.appendChild(profile)
933
934     node_add_profile(gen, node, 'ldlm', ldlm_uuid)
935     set_node_options(gen, node, options)
936
937     return node
938
939 def add_node(gen, lustre, options):
940     """ create a node with a network config """
941
942     node_name = get_option(options, 'node')
943     ret = findByName(lustre, node_name, "node")
944     if ret:
945         print "Node:", node_name, "exists."
946         return
947     do_add_node(gen, lustre, options, node_name)
948
949
950 def add_net(gen, lustre, options):
951     """ create a node with a network config """
952
953     node_name = get_option(options, 'node')
954     nid = get_option(options, 'nid')
955     cluster_id = get_option(options, 'cluster_id')
956     hostaddr = get_option(options, 'hostaddr')
957     net_type = get_option(options, 'nettype')
958
959     if net_type in ('tcp','openib','ra'):
960         port = get_option_int(options, 'port')
961     elif net_type in ('elan', 'gm', 'iib', 'vib', 'lo', 'cray_kern_nal'):
962         port = 0
963     else:
964         print "Unknown net_type: ", net_type
965         sys.exit(2)
966
967     ret = findByName(lustre, node_name, "node")
968     if not ret:
969         node = do_add_node(gen, lustre, options, node_name)
970     else:
971         node = ret
972         set_node_options(gen, node, options)
973
974     net_name = new_name('NET_'+ node_name +'_'+ net_type)
975     net_uuid = new_uuid(net_name)
976     node.appendChild(gen.network(net_name, net_uuid, nid, cluster_id, net_type,
977                                  hostaddr, port))
978     node_add_profile(gen, node, "network", net_uuid)
979
980
981 def add_route(gen, lustre, options):
982     """ create a node with a network config """
983
984     node_name = get_option(options, 'node')
985     gw_net_type = get_option(options, 'nettype')
986     gw = get_option(options, 'gw')
987     gw_cluster_id = get_option(options, 'gateway_cluster_id')
988     tgt_cluster_id = get_option(options, 'target_cluster_id')
989     lo = get_option(options, 'lo')
990     hi = get_option(options, 'hi')
991     if not hi:
992         hi = lo
993
994     node = findByName(lustre, node_name, "node")
995     if not node:
996         error (node_name, " not found.")
997
998     rlist = node.getElementsByTagName('routetbl')
999     if len(rlist) > 0:
1000         rtbl = rlist[0]
1001     else:
1002         rtbl_name = new_name("RTBL_" + node_name)
1003         rtbl_uuid = new_uuid(rtbl_name)
1004         rtbl = gen.routetbl(rtbl_name, rtbl_uuid)
1005         node.appendChild(rtbl)
1006         node_add_profile(gen, node, "routetbl", rtbl_uuid)
1007     rtbl.appendChild(gen.route(gw_net_type, gw, gw_cluster_id, tgt_cluster_id,
1008                                lo, hi))
1009  
1010 def add_gks(gen, lustre, options):
1011     """ create a gks """
1012     node_name = get_option(options, 'node')
1013     gks_name = get_option(options, 'gks')
1014     if not gks_name:
1015         gks_name = new_name('GKS_'+ node_name)
1016     
1017     gkd_name = new_name("GKD_" + gks_name + "_" + node_name)
1018     gkd_uuid = new_uuid(gkd_name)
1019     
1020     gks_uuid = name2uuid(lustre, gks_name, 'gks', fatal=0)
1021
1022     if not gks_uuid:
1023         gks_uuid = new_uuid(gks_name)
1024         gks = gen.gks(gks_name, gks_uuid, gkd_uuid)
1025         lustre.appendChild(gks)
1026     else:
1027         gks = lookup(lustre, gks_uuid)
1028
1029     # add gkd profile
1030     node_uuid = name2uuid(lustre, node_name, 'node')
1031     node = findByName(lustre, node_name, "node")
1032     node_add_profile(gen, node, "gkd", gkd_uuid)
1033     net_uuid = get_net_uuid(lustre, node_name)
1034     if not net_uuid:
1035         error("NODE: ", node_name, "not found")
1036
1037     gkd = gen.gkd(gkd_name, gkd_uuid, node_uuid, gks_uuid)
1038     lustre.appendChild(gkd)
1039
1040
1041 def add_mds(gen, lustre, options):
1042     node_name = get_option(options, 'node')
1043     mds_name = get_option(options, 'mds')
1044     if not mds_name:
1045         mds_name = new_name('MDS_'+ node_name)
1046     lmv_name = get_option(options, 'lmv')
1047     mdd_name = new_name("MDD_" + mds_name +"_" + node_name)
1048     mdd_uuid = new_uuid(mdd_name)
1049
1050     mds_uuid = name2uuid(lustre, mds_name, 'mds', fatal=0)
1051     if not mds_uuid:
1052         mds_uuid = get_option(options, 'mdsuuid')
1053         if mds_uuid:
1054             if lookup(lustre, mds_uuid):
1055                 error("Duplicate MDS UUID:", mds_uuid)
1056         else:
1057             mds_uuid = new_uuid(mds_name)
1058         mds = gen.mds(mds_name, mds_uuid, mdd_uuid, options.group)
1059         lustre.appendChild(mds)
1060     else:
1061         mds = lookup(lustre, mds_uuid)
1062
1063     lmv_uuid = ""
1064     if lmv_name:
1065         lmv = findByName(lustre, lmv_name, "lmv")
1066         if not lmv:
1067             error('add_mds:', '"' + lmv_name + '"', "lmv element not found.")
1068         lmv_add_mdc(gen, lustre, lmv, mds_uuid)
1069         lmv_uuid = name2uuid(lustre, lmv_name, fatal=0)
1070         if lmv_uuid:
1071             mds.appendChild(gen.ref("lmv", lmv_uuid))
1072     
1073     if options.failover:
1074         mds.setAttribute('failover', "1")
1075
1076     devname = get_option(options, 'dev')
1077     backdevname = get_option(options, 'backdev')
1078     size = get_option(options, 'size')
1079     fstype = get_option(options, 'fstype')
1080     backfstype = get_option(options, 'backfstype')
1081     journal_size = get_option(options, 'journal_size')
1082     inode_size = get_option(options, 'inode_size')
1083     nspath = get_option(options, 'nspath')
1084     mkfsoptions = get_option(options, 'mkfsoptions')
1085     mountfsoptions = get_option(options, 'mountfsoptions')
1086     root_squash = get_option(options, 'root_squash')
1087     no_root_squash = get_option(options, 'no_root_squash')
1088     mds_sec = get_option(options, 'mds_mds_sec')
1089     oss_sec = get_option(options, 'mds_oss_sec')
1090     deny_sec = get_option(options, 'mds_deny_sec')
1091     fs_name = get_option(options, 'filesystem')
1092
1093     node_uuid = name2uuid(lustre, node_name, 'node')
1094
1095     node = findByName(lustre, node_name, "node")
1096     node_add_profile(gen, node, "mdsdev", mdd_uuid)
1097     net_uuid = get_net_uuid(lustre, node_name)
1098     if not net_uuid:
1099         error("NODE: ", node_name, "not found")
1100
1101     if fs_name != "":
1102         fs_uuid = name2uuid(lustre, fs_name, 'filesystem', fatal=1)
1103     else:
1104         fs_uuid = ""
1105     
1106     mdd = gen.mdsdev(mdd_name, mdd_uuid, fstype, devname,
1107                      get_format_flag(options), node_uuid, mds_uuid,
1108                      size, journal_size, inode_size, nspath, mkfsoptions, 
1109                      mountfsoptions, backfstype, backdevname,lmv_uuid, 
1110                      root_squash, no_root_squash, mds_sec, oss_sec, deny_sec, 
1111                      fs_uuid)
1112     lustre.appendChild(mdd)
1113
1114 def add_mgmt(gen, lustre, options):
1115     node_name = get_option(options, 'node')
1116     node_uuid = name2uuid(lustre, node_name, 'node')
1117     mgmt_name = get_option(options, 'mgmt')
1118     if not mgmt_name:
1119         mgmt_name = new_name('MGMT_' + node_name)
1120     mgmt_uuid = name2uuid(lustre, mgmt_name, 'mgmt', fatal=0)
1121     if not mgmt_uuid:
1122         mgmt_uuid = new_uuid(mgmt_name)
1123         mgmt = gen.mgmt(mgmt_name, mgmt_uuid, node_uuid)
1124         lustre.appendChild(mgmt)
1125     else:
1126         mgmt = lookup(lustre, mgmt_uuid)
1127
1128     node = findByName(lustre, node_name, "node")
1129     node_add_profile(gen, node, 'mgmt', mgmt_uuid)
1130
1131 def add_ost(gen, lustre, options):
1132     node_name = get_option(options, 'node')
1133     lovname = get_option(options, 'lov')
1134     osdtype = get_option(options, 'osdtype')
1135
1136     node_uuid = name2uuid(lustre, node_name, 'node')
1137
1138     if osdtype == 'obdecho':
1139         fstype = ''
1140         backfstype = ''
1141         devname = ''
1142         backdevname = ''
1143         size = 0
1144         journal_size = ''
1145         inode_size = ''
1146         mkfsoptions = ''
1147         mountfsoptions = ''
1148         deny_sec = ''
1149     else:
1150         devname = get_option(options, 'dev') # can be unset for bluearcs
1151         backdevname = get_option(options, 'backdev')
1152         size = get_option(options, 'size')
1153         fstype = get_option(options, 'fstype')
1154         backfstype = get_option(options, 'backfstype')
1155         journal_size = get_option(options, 'journal_size')
1156         inode_size = get_option(options, 'inode_size')
1157         mkfsoptions = get_option(options, 'mkfsoptions')
1158         mountfsoptions = get_option(options, 'mountfsoptions')
1159         deny_sec = get_option(options, 'ost_deny_sec')
1160
1161     fs_name = get_option(options, 'filesystem')
1162     nspath = get_option(options, 'nspath')
1163
1164     ostname = get_option(options, 'ost')
1165     if not ostname:
1166         ostname = new_name('OST_'+ node_name)
1167
1168     osdname = new_name("OSD_" + ostname + "_" + node_name)
1169     osd_uuid = new_uuid(osdname)
1170
1171     ost_uuid = name2uuid(lustre, ostname, 'ost', fatal=0)
1172     if not ost_uuid:
1173         ost_uuid = get_option(options, 'ostuuid')
1174         if ost_uuid:
1175             if lookup(lustre, ost_uuid):
1176                 error("Duplicate OST UUID:", ost_uuid)
1177         else:
1178             ost_uuid = new_uuid(ostname)
1179
1180         ost = gen.ost(ostname, ost_uuid, osd_uuid, options.group)
1181         lustre.appendChild(ost)
1182     else:
1183         ost = lookup(lustre, ost_uuid)
1184
1185     if lovname:
1186         lov = findByName(lustre, lovname, "lov")
1187         if not lov:
1188             error('add_ost:', '"'+lovname+'"', "lov element not found.")
1189         lov_add_osc(gen, lustre, lov, ost_uuid, options)
1190
1191     if options.failover:
1192         ost.setAttribute('failover', "1")
1193
1194     if fs_name != "":
1195         fs_uuid = name2uuid(lustre, fs_name, 'filesystem', fatal=1)
1196     else:
1197         fs_uuid = ""
1198         
1199     osd = gen.osd(osdname, osd_uuid, fstype, osdtype, devname,
1200                   get_format_flag(options), ost_uuid, node_uuid, size,
1201                   journal_size, inode_size, nspath, mkfsoptions, 
1202                   mountfsoptions, backfstype, backdevname, deny_sec, 
1203                   fs_uuid)
1204
1205     node = findByName(lustre, node_name, "node")
1206     node_add_profile(gen, node, 'osd', osd_uuid)
1207     lustre.appendChild(osd)
1208
1209 def del_ost(gen, lustre, options):
1210     ostname = get_option(options, 'ost')
1211     if not ostname:
1212         raise OptionError("del_ost: --ost requires a <ost name>")
1213     ost = findByName(lustre, ostname, "ost")
1214     if not ost:
1215         error('del_ost: ', 'Unable to find ', ostname)
1216     ost_uuid = name2uuid(lustre, ostname, fatal=0)
1217     if not ost_uuid:
1218         error('del_ost: ', 'Unable to find uuid for ', ostname)
1219     lovname = get_option(options, 'lov')
1220     if lovname:
1221         lov = findByName(lustre, lovname, "lov")
1222         if not lov:
1223             error('del_ost:', '"'+lovname+'"', "lov element not found.")
1224         lov_del_osc(gen, lustre, lov, ost_uuid, options)
1225         # if the user specified a speficic LOV don't delete the OST itself
1226         return
1227
1228     # remove OSD references from all LOVs
1229     for lov in lustre.getElementsByTagName('lov'):
1230         lov_del_osc(gen, lustre, lov, ost_uuid, options)
1231
1232     info = gen.info()
1233
1234     # move the OST description to the update record
1235     lustre.removeChild(ost)
1236     info.appendChild(ost)
1237
1238     active_ref = ost.getElementsByTagName('active_ref')
1239     if not active_ref:
1240         error('ost has no osd ref:', ostname)
1241
1242     # move the OSD description to the update record
1243     osd_uuid = active_ref[0].getAttribute('uuidref')
1244     osd = lookup(lustre, osd_uuid)
1245     lustre.removeChild(osd)
1246     info.appendChild(osd)
1247
1248     # make a copy of the OSS description in the update record
1249     # XXX - should check to make sure one doesn't already exist.
1250     node_ref = osd.getElementsByTagName('node_ref')
1251     if not node_ref:
1252         error('osd has no node ref:', ostname)
1253     node_uuid = node_ref[0].getAttribute('uuidref')
1254     node = lookup(lustre, node_uuid)
1255     if not node:
1256         error('unable to locate node for node ref:', node_uuid)
1257
1258     node_rec = node.cloneNode(1)
1259     info.appendChild(node_rec)
1260
1261     prof_ref = node.getElementsByTagName('profile_ref')
1262     if not prof_ref:
1263         error('node has no profile ref:', node)
1264     profile_uuid = prof_ref[0].getAttribute('uuidref')
1265
1266     # make a copy of the OSS's profile in the update record
1267     # XXX - should check to make sure one doesn't already exist.
1268     profile = lookup(lustre, profile_uuid)
1269     profile_rec = profile.cloneNode(1)
1270     info.appendChild(profile_rec)
1271
1272     # delete all references to this OSD in the OSS's current profile
1273     for osd_ref in profile.getElementsByTagName('osd_ref'):
1274         if osd_uuid == osd_ref.getAttribute('uuidref'):
1275             profile.removeChild(osd_ref)
1276
1277     # XXX - We should cleanup the node and profile elements if they
1278     #       no longer serve a purpose.
1279     addUpdate(gen, lustre, info)
1280
1281 def add_cmobd(gen, lustre, options):
1282     node_name = get_option(options, 'node')
1283     name = get_option(options, 'cmobd')
1284     uuid = new_uuid(name)
1285
1286     master_name = get_option(options, 'master_obd')
1287     cache_name = get_option(options, 'cache_obd')
1288
1289     master_uuid = name2uuid(lustre, master_name, tag='lov', fatal=0)
1290     cache_uuid = name2uuid(lustre, cache_name, tag='lov', fatal=0)
1291
1292     if not master_uuid or not cache_uuid:
1293         if not master_uuid:
1294             master_uuid = name2uuid(lustre, master_name, tag='ost', fatal=0)
1295         if not cache_uuid:
1296             cache_uuid = name2uuid(lustre, cache_name, tag='ost', fatal=0)
1297
1298     if not master_uuid or not cache_uuid:
1299         if not master_uuid:
1300             master_uuid = name2uuid(lustre, master_name, tag='lmv', fatal=0)
1301         if not cache_uuid:
1302             cache_uuid = name2uuid(lustre, cache_name, tag='lmv', fatal=0)
1303
1304     if not master_uuid or not cache_uuid:
1305         if not master_uuid:
1306             master_uuid = name2uuid(lustre, master_name, tag='mds', fatal=0)
1307         if not cache_uuid:
1308             cache_uuid = name2uuid(lustre, cache_name, tag='mds', fatal=0)
1309
1310     if not master_uuid: 
1311         error("cannot find master_uuid by name '" + master_name + "'")
1312     if not cache_uuid: 
1313         error("cannot find cache_uuid by name '" + cache_name + "'")
1314
1315     node = findByName(lustre, node_name, "node")
1316     node_add_profile(gen, node, "cmobd", uuid)
1317
1318     master_node = lookup(lustre, master_uuid)
1319     cache_node = lookup(lustre, cache_uuid)
1320     if not master_node:
1321         error("cannot find master node by its uuid " + master_uuid);
1322     if not cache_node:
1323         error("cannot find cache node by its uuid " + cache_uuid);
1324
1325     active = master_node.getElementsByTagName('active_ref')
1326     if active:
1327         active_uuid = active[0].getAttribute('uuidref')
1328         active_node = lookup(lustre, active_uuid)
1329         if not active_node.getElementsByTagName('obdtype'):
1330             gen.addElement(active_node, 'obdtype', 'master')
1331
1332     active = cache_node.getElementsByTagName('active_ref')
1333     if active:
1334         active_uuid = active[0].getAttribute('uuidref')
1335         active_node = lookup(lustre, active_uuid)
1336         if not active_node.getElementsByTagName('obdtype'):
1337             gen.addElement(active_node, 'obdtype', 'cache')
1338
1339     cmobd = gen.cmobd(name, uuid, master_uuid, cache_uuid)
1340     lustre.appendChild(cmobd)
1341
1342 def add_cobd(gen, lustre, options):
1343     node_name = get_option(options, 'node')
1344     name = get_option(options, 'cobd')
1345     uuid = new_uuid(name)
1346
1347     master_name = get_option(options, 'master_obd')
1348     cache_name = get_option(options, 'cache_obd')
1349
1350     # init master
1351     master_uuid = name2uuid(lustre, master_name, tag='lov', fatal=0)
1352     if not master_uuid:
1353         master_uuid = name2uuid(lustre, master_name, tag='ost', fatal=0)
1354
1355     if master_uuid:
1356         node = lookup(lustre, master_uuid)
1357         rets = node.getElementsByTagName('lov_tgt')
1358         for ret in rets:
1359             ost_uuid = ret.getAttribute('uuidref')
1360             ost_node = lookup(lustre, ost_uuid)
1361             active = ost_node.getElementsByTagName('active_ref')
1362             if active:
1363                 osd_uuid = active[0].getAttribute('uuidref')
1364                 osd_node = lookup(lustre, osd_uuid)
1365                 if not osd_node.getElementsByTagName('obdtype'):
1366                     gen.addElement(osd_node, 'obdtype', 'master')
1367
1368     # init cache
1369     cache_uuid = name2uuid(lustre, cache_name, tag='lov', fatal=0)
1370     if not cache_uuid:
1371         cache_uuid = name2uuid(lustre, cache_name, tag='ost', fatal=0)
1372
1373     if cache_uuid:
1374         node = lookup(lustre, cache_uuid)
1375         rets = node.getElementsByTagName('lov_tgt')
1376         for ret in rets:
1377             ost_uuid = ret.getAttribute('uuidref')
1378             ost_node = lookup(lustre, ost_uuid)
1379             active = ost_node.getElementsByTagName('active_ref')
1380             if active:
1381                 osd_uuid = active[0].getAttribute('uuidref')
1382                 osd_node = lookup(lustre, osd_uuid)
1383                 if not osd_node.getElementsByTagName('obdtype'):
1384                     gen.addElement(osd_node, 'obdtype', 'cache')
1385
1386     if not master_uuid or not cache_uuid:
1387         master_uuid = name2uuid(lustre, master_name, tag='lmv', fatal=0)
1388         if not master_uuid:
1389             master_uuid = name2uuid(lustre, master_name, tag='mds', fatal=0)
1390             
1391         if master_uuid:
1392             mds_node = lookup(lustre, master_uuid)
1393             ret = mds_node.getElementsByTagName('active_ref')
1394             if ret:
1395                 mdsdev_uuid = ret[0].getAttribute('uuidref')
1396                 mdsdev_node = lookup(lustre, mdsdev_uuid)
1397                 if not mdsdev_node.getElementsByTagName('obdtype'):
1398                     gen.addElement(mdsdev_node, 'obdtype', 'master')
1399
1400         cache_uuid = name2uuid(lustre, cache_name, tag='lmv', fatal=0)
1401         if not cache_uuid:
1402             cache_uuid = name2uuid(lustre, cache_name, tag='mds', fatal=0)
1403             
1404         if cache_uuid:
1405             mds_node = lookup(lustre, cache_uuid)
1406             ret = mds_node.getElementsByTagName('active_ref')
1407             if ret:
1408                 mdsdev_uuid = ret[0].getAttribute('uuidref')
1409                 mdsdev_node = lookup(lustre, mdsdev_uuid)
1410                 if not mdsdev_node.getElementsByTagName('obdtype'):
1411                     gen.addElement(mdsdev_node, 'obdtype', 'cache')
1412
1413     if not master_uuid or not cache_uuid:
1414         panic("add_cobd", "cannot find master or cache by names '" + 
1415               master_name + "' and '" + cache_name + "'")
1416         
1417     node = findByName(lustre, node_name, "node")
1418     cobd = gen.cobd(name, uuid, master_uuid, cache_uuid)
1419     lustre.appendChild(cobd)
1420
1421 def add_echo_client(gen, lustre, options):
1422     """ add an echo client to the profile for this node. """
1423     node_name = get_option(options, 'node')
1424     lov_name = get_option(options, 'ost')
1425
1426     node = findByName(lustre, node_name, 'node')
1427
1428     echoname = new_name('ECHO_'+ node_name)
1429     echo_uuid = new_uuid(echoname)
1430     node_add_profile(gen, node, 'echoclient', echo_uuid)
1431
1432     lov_uuid = name2uuid(lustre, lov_name, tag='lov', fatal=0)
1433     if not lov_uuid:
1434         lov_uuid = name2uuid(lustre, lov_name, tag='ost', fatal=1)
1435
1436     echo = gen.echo_client(echoname, echo_uuid, lov_uuid)
1437     lustre.appendChild(echo)
1438
1439 def add_lov(gen, lustre, options):
1440     """ create a lov """
1441
1442     lov_orig = get_option(options, 'lov')
1443     name = new_name(lov_orig)
1444     if name != lov_orig:
1445         warning("name:", lov_orig, "already used. using:", name)
1446
1447     lmv_name = get_option(options, 'lmv')
1448     mds_name = get_option(options, 'mds')
1449     aware = get_option(options, 'aware')
1450     
1451     if not mds_name and not lmv_name:
1452         error("LOV: either MDS or LMV must be specified.");
1453     if mds_name and lmv_name:
1454         error("LOV: either MDS or LMV must be specified.");
1455     
1456     stripe_sz = get_option_int(options, 'stripe_sz')
1457     stripe_cnt = get_option_int(options, 'stripe_cnt')
1458     pattern = get_option_int(options, 'stripe_pattern')
1459     uuid = new_uuid(name)
1460
1461     ret = findByName(lustre, name, "lov")
1462     if ret:
1463         error("LOV: ", name, " already exists.")
1464
1465     if lmv_name:
1466         mds_uuid = name2uuid(lustre, lmv_name, 'lmv')
1467     else:
1468         mds_uuid = name2uuid(lustre, mds_name, 'mds')
1469
1470     lov = gen.lov(name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern)
1471     lustre.appendChild(lov)
1472
1473     # add an lovconfig entry to the active mdsdev profile
1474     lovconfig_name = new_name('LVCFG_' + name)
1475     lovconfig_uuid = new_uuid(lovconfig_name)
1476
1477     if mds_name:
1478         md_tgt = findByName(lustre, mds_name, "mds")
1479         if not md_tgt:
1480             error("can't find MDS '" + mds_name + "'")
1481     else:
1482         md_tgt = findByName(lustre, lmv_name, "lmv")
1483         if not md_tgt:
1484             error("can't find LMV '" + lmv_name + "'")
1485     
1486     md_tgt.appendChild(gen.ref("lovconfig", lovconfig_uuid))
1487     md_tgt.appendChild(gen.ref("client", uuid))
1488     
1489     # adding lovconfig and client to aware MD targets
1490     if aware:
1491         md_names = string.split(aware, ',');
1492         for md_name in md_names:
1493         
1494             md_tgt = findByName(lustre, md_name, "mds")
1495             if not md_tgt:
1496                 md_tgt = findByName(lustre, md_name, "lmv")
1497
1498             if not md_tgt:
1499                 error("can't find '" + mds_name + "'")
1500             
1501             md_tgt.appendChild(gen.ref("lovconfig", lovconfig_uuid))
1502             md_tgt.appendChild(gen.ref("client", uuid))
1503         
1504     lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid)
1505     lustre.appendChild(lovconfig)
1506
1507 def add_default_lov(gen, lustre, mds_name, lov_name):
1508     """ create a default lov """
1509
1510     stripe_sz = DEFAULT_STRIPE_SZ
1511     stripe_cnt = DEFAULT_STRIPE_CNT
1512     pattern = DEFAULT_STRIPE_PATTERN
1513     uuid = new_uuid(lov_name)
1514
1515     ret = findByName(lustre, lov_name, "lov")
1516     if ret:
1517         error("LOV: ", lov_name, " already exists.")
1518
1519     mds_uuid = name2uuid(lustre, mds_name, 'mds')
1520     lov = gen.lov(lov_name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern)
1521     lustre.appendChild(lov)
1522
1523     # add an lovconfig entry to the active mdsdev profile
1524     lovconfig_name = new_name('LVCFG_' + lov_name)
1525     lovconfig_uuid = new_uuid(lovconfig_name)
1526     mds = findByName(lustre, mds_name)
1527     mds.appendChild(gen.ref("lovconfig", lovconfig_uuid))
1528     lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid)
1529     lustre.appendChild(lovconfig)
1530
1531 def add_lmv(gen, lustre, options):
1532     """ create a lmv """
1533
1534     lmv_orig = get_option(options, 'lmv')
1535     name = new_name(lmv_orig)
1536     if name != lmv_orig:
1537         warning("name:", lmv_orig, "already used. using:", name)
1538
1539     uuid = new_uuid(name)
1540     ret = findByName(lustre, name, "lmv")
1541     if ret:
1542         error("LMV: ", name, " already exists.")
1543
1544     lmv = gen.lmv(name, uuid)
1545     lustre.appendChild(lmv)
1546    
1547 def new_filesystem(gen, lustre, fs_name, mds_uuid, obd_uuid, 
1548                    mgmt_uuid, gks_uuid):
1549     fs_uuid = new_uuid(fs_name)
1550     fs = gen.filesystem(fs_name, fs_uuid, mds_uuid, obd_uuid, 
1551                         mgmt_uuid, gks_uuid)
1552     lustre.appendChild(fs)
1553     return fs_uuid
1554
1555 def get_fs_uuid(gen, lustre, fs_name, mds_name, obd_name, 
1556                 mgmt_name, gks_name):
1557     mds_uuid = name2uuid(lustre, mds_name, tag='mds', fatal=0)
1558     if not mds_uuid:
1559         mds_uuid = name2uuid(lustre, mds_name, tag='lmv', fatal=0)
1560     if not mds_uuid:
1561         mds_uuid = name2uuid(lustre, mds_name, tag='cobd', fatal=0)
1562     if not mds_uuid:
1563         error("mds '" + mds_name + "' is not found")
1564
1565     obd_uuid = name2uuid(lustre, obd_name, tag='ost', fatal=0)
1566     if not obd_uuid:
1567         obd_uuid = name2uuid(lustre, obd_name, tag='lov', fatal=0)
1568     if not obd_uuid:
1569         obd_uuid = name2uuid(lustre, obd_name, tag='cobd', fatal=0)
1570     if not obd_uuid:
1571         error("ost '" + obd_name + "' is not found")
1572         
1573     if mgmt_name:
1574         mgmt_uuid = name2uuid(lustre, mgmt_name, tag='mgmt', fatal=1)
1575     else:
1576         mgmt_uuid = ''
1577
1578     if gks_name:
1579         gks_uuid = name2uuid(lustre, gks_name, tag='gks', fatal=1)
1580     else: 
1581         gks_uuid = ''
1582         
1583     fs_uuid = lookup_filesystem(lustre, fs_name)
1584     if fs_uuid:
1585         fs = lookup(lustre, fs_uuid)
1586         if not ref_exists(fs, mds_uuid):
1587             fs.appendChild(gen.ref("mds", mds_uuid))
1588         if not ref_exists(fs, obd_uuid):
1589             fs.appendChild(gen.ref("obd", obd_uuid))
1590         if gks_uuid and not ref_exists(fs, gks_uuid):
1591             fs.appendChild(gen.ref("gks", gks_uuid))
1592     else:
1593         fs_uuid = new_filesystem(gen, lustre, fs_name, 
1594                                  mds_uuid, obd_uuid, 
1595                                  mgmt_uuid, gks_uuid)
1596     return fs_uuid
1597
1598 def add_filesystem(gen, lustre, options):
1599     """ create filesytem """
1600     fs_orig = get_option(options, 'filesystem')
1601     name = new_name(fs_orig)
1602     if name != fs_orig:
1603         warning("name:", fs_orig, "already used. using:", name)
1604
1605     uuid = new_uuid(name)
1606     ret = findByName(lustre, name, "filesystem")
1607     if ret:
1608         error("FS: ", name, " already exists.")
1609
1610     gks_name = get_option(options, 'gks')
1611     if gks_name:
1612         gks_uuid = name2uuid(lustre, gks_name, tag='gks', fatal=1)
1613     else: 
1614         gks_uuid = ''
1615     fs = gen.filesystem(name, uuid, "", "", "", gks_uuid)
1616     lustre.appendChild(fs)
1617     
1618 def add_mtpt(gen, lustre, options):
1619     """ create mtpt on a node """
1620     node_name = get_option(options, 'node')
1621
1622     path = get_option(options, 'path')
1623     clientoptions = get_option(options, "clientoptions")
1624     mds_sec = get_option(options, "mds_sec")
1625     oss_sec = get_option(options, "oss_sec")
1626     fs_name = get_option(options, 'filesystem')
1627
1628     lov_name = get_option(options, 'lov')
1629     ost_name = get_option(options, 'ost')
1630     mds_name = get_option(options, 'mds')
1631     gks_name = get_option(options, 'gks')
1632     if mds_name == '':
1633         mds_name = get_option(options, 'lmv')
1634         if mds_name == '':
1635             error("--add mtpt requires either --mds or --lmv.")
1636     if lov_name == '':
1637         if ost_name == '':
1638             error("--add mtpt requires --lov lov_name or --ost ost_name")
1639         else:
1640             warning("use default value for lov, due no --lov lov_name provided")
1641             lov_name = new_name("lov_default")
1642             add_default_lov(gen, lustre, mds_name, lov_name)
1643             ost_uuid = name2uuid(lustre, ost_name, 'ost', fatal=0)
1644             if not ost_uuid:
1645                 error('add_mtpt:', '"'+ost_name+'"', "ost element not found.")
1646             lov = findByName(lustre, lov_name, "lov")
1647             lov_add_osc(gen, lustre, lov, ost_uuid, options)
1648
1649     if fs_name == '':
1650         fs_name = new_name("FS_fsname")
1651         mgmt_name = get_option(options, 'mgmt')
1652     else:
1653         mgmt_name = ""
1654         
1655     fs_uuid = get_fs_uuid(gen, lustre, fs_name, 
1656                           mds_name, lov_name, mgmt_name, gks_name)
1657
1658     name = new_name('MNT_'+ node_name)
1659
1660     ret = findByName(lustre, name, "mountpoint")
1661     if ret:
1662         # this can't happen, because new_name creates unique names
1663         error("MOUNTPOINT: ", name, " already exists.")
1664
1665     uuid = new_uuid(name)
1666     mtpt = gen.mountpoint(name, uuid, fs_uuid, path, 
1667                           clientoptions, mds_sec, oss_sec)
1668     node = findByName(lustre, node_name, "node")
1669     if not node:
1670         error('node:',  node_name, "not found.")
1671     node_add_profile(gen, node, "mountpoint", uuid)
1672     lustre.appendChild(mtpt)
1673
1674 def commit_version(gen, lustre):
1675     update = findLastUpdate(lustre)
1676     if update:
1677         version = int(update.getAttribute("version")) + 1
1678     else:
1679         version = 1
1680
1681     new = gen.update(str(version))
1682     lustre.appendChild(new)
1683     
1684
1685 ############################################################
1686 # Command line processing
1687 #
1688 class OptionError (exceptions.Exception):
1689     def __init__(self, args):
1690         self.args = args
1691
1692 def get_option(options, tag):
1693     """Look for tag in options hash and return the value if set. If not
1694     set, then if return default it is set, otherwise exception."""
1695     if options.__getattr__(tag) != None:
1696         return options.__getattr__(tag)
1697     else:
1698         raise OptionError("--add %s requires --%s <value>" % (options.add, tag))
1699
1700 def get_option_int(options, tag):
1701     """Return an integer option.  Raise exception if the value is not an int"""
1702     val = get_option(options, tag)
1703     try:
1704         n = int(val)
1705     except ValueError:
1706         raise OptionError("--%s <num> (value must be integer)" % (tag))
1707     return n
1708
1709 # simple class for profiling
1710 import time
1711 class chrono:
1712     def __init__(self):
1713         self._start = 0
1714     def start(self):
1715         self._stop = 0
1716         self._start = time.time()
1717     def stop(self, msg=''):
1718         self._stop = time.time()
1719         if msg:
1720             self.display(msg)
1721     def dur(self):
1722         return self._stop - self._start
1723     def display(self, msg):
1724         d = self.dur()
1725         str = '%s: %g secs' % (msg, d)
1726         print str
1727
1728 #################################################################
1729 # function cmdlinesplit used to split cmd line from batch file
1730 #
1731 def cmdlinesplit(cmdline):
1732
1733     double_quote  = re.compile(r'"(([^"\\]|\\.)*)"')
1734     single_quote  = re.compile(r"'(.*?)'")
1735     escaped = re.compile(r'\\(.)')
1736     esc_quote = re.compile(r'\\([\\"])')
1737     outside = re.compile(r"""([^\s\\'"]+)""") #" fucking emacs.
1738
1739     arg_list = []
1740     i = 0; arg = None
1741     while i < len(cmdline):
1742         c = cmdline[i]
1743         if c == '"':
1744             match = double_quote.match(cmdline, i)
1745             if not match:
1746                 print "Unmatched double quote:", cmdline
1747                 sys.exit(1)
1748             i = match.end()
1749             if arg is None: arg = esc_quote.sub(r'\1', match.group(1))
1750             else:           arg = arg + esc_quote.sub(r'\1', match.group(1))
1751
1752         elif c == "'":
1753             match = single_quote.match(cmdline, i)
1754             if not match:
1755                 print "Unmatched single quote:", cmdline
1756                 sys.exit(1)
1757             i = match.end()
1758             if arg is None: arg = match.group(1)
1759             else:           arg = arg + match.group(1)
1760
1761         elif c == "\\":
1762             match = escaped.match(cmdline, i)
1763             if not match:
1764                 print "Unmatched backslash", cmdline
1765                 sys.exit(1)
1766             i = match.end()
1767             if arg is None: arg = match.group(1)
1768             else:           arg = arg + match.group(1)
1769
1770         elif c in string.whitespace:
1771             if arg != None:
1772                 arg_list.append(str(arg))
1773             arg = None
1774             while i < len(cmdline) and cmdline[i] in string.whitespace:
1775                 i = i + 1
1776         else:
1777             match = outside.match(cmdline, i)
1778             assert match
1779             i = match.end()
1780             if arg is None: arg = match.group()
1781             else:           arg = arg + match.group()
1782
1783     if arg != None: arg_list.append(str(arg))
1784
1785     return arg_list
1786
1787 ############################################################
1788 # Main
1789 #
1790
1791 def add(devtype, gen, lustre, options):
1792     if devtype == 'net':
1793         add_net(gen, lustre, options)
1794     elif devtype == 'mtpt':
1795         add_mtpt(gen, lustre, options)
1796     elif devtype == 'mds':
1797         add_mds(gen, lustre, options)
1798     elif devtype == 'ost':
1799         add_ost(gen, lustre, options)
1800     elif devtype == 'lov':
1801         add_lov(gen, lustre, options)
1802     elif devtype == 'route':
1803         add_route(gen, lustre, options)
1804     elif devtype == 'node':
1805         add_node(gen, lustre, options)
1806     elif devtype == 'echo_client':
1807         add_echo_client(gen, lustre, options)
1808     elif devtype == 'cobd':
1809         add_cobd(gen, lustre, options)
1810     elif devtype == 'cmobd':
1811         add_cmobd(gen, lustre, options)
1812     elif devtype == 'mgmt':
1813         add_mgmt(gen, lustre, options)
1814     elif devtype == 'lmv':
1815         add_lmv(gen, lustre, options)
1816     elif devtype == 'filesystem':
1817         add_filesystem(gen, lustre, options)
1818     elif devtype == 'gks':
1819         add_gks(gen, lustre, options)
1820     else:
1821         error("unknown device type:", devtype)
1822
1823 def delete(devtype, gen, lustre, options):
1824     if devtype == 'ost':
1825         del_ost(gen, lustre, options)
1826     elif options.delete:
1827         error("delete not supported for device type:", devtype)
1828     elif options.deactivate:
1829         error("deactivate not supported for device type:", devtype)
1830     else:
1831         error("in delete(), but neither .delete nor .deactivate are set.  Tell CFS.")
1832
1833 def commit(gen, lustre):
1834     commit_version(gen, lustre)
1835
1836 def do_command(gen, lustre, options, args):
1837     if options.add:
1838         add(options.add, gen, lustre, options)
1839     elif options.delete:
1840         delete(options.delete, gen, lustre, options)
1841     elif options.deactivate:
1842         delete(options.deactivate, gen, lustre, options)
1843     elif options.commit:
1844         commit(gen, lustre)
1845     else:
1846         error("Missing command")
1847
1848 def main():
1849     cl = Lustre.Options("lmc", "", lmc_options)
1850     try:
1851         options, args = cl.parse(sys.argv[1:])
1852     except Lustre.OptionError, e:
1853         panic("lmc", e)
1854
1855     if len(args) > 0:
1856         panic(string.join(sys.argv), "Unexpected extra arguments on command line: " + string.join(args))
1857
1858     if options.reference:
1859         reference()
1860         sys.exit(0)
1861
1862     outFile = '-'
1863
1864     if options.merge:
1865         outFile = options.merge
1866         if os.access(outFile, os.R_OK):
1867             doc = xml.dom.minidom.parse(outFile)
1868         else:
1869             doc = new_lustre(xml.dom.minidom)
1870     elif options.input:
1871         doc = xml.dom.minidom.parse(options.input)
1872     else:
1873         doc = new_lustre(xml.dom.minidom)
1874
1875     if options.output:
1876         outFile = options.output
1877
1878     lustre = doc.documentElement
1879     init_names(lustre)
1880     if lustre.tagName != "lustre":
1881         print "Existing config not valid."
1882         sys.exit(1)
1883
1884     gen = GenConfig(doc)
1885
1886     if options.batch:
1887         fp = open(options.batch)
1888         batchCommands = fp.readlines()
1889         fp.close()
1890         for cmd in batchCommands:
1891             try:
1892                 options, args = cl.parse(cmdlinesplit(cmd))
1893                 if options.merge or options.input or options.output:
1894                     print "The batchfile should not contain --merge, --input or --output."
1895                     sys.exit(1)
1896                 do_command(gen, lustre, options, args)
1897             except OptionError, e:
1898                 panic(cmd, e)
1899             except Lustre.OptionError, e:
1900                 panic(cmd, e)
1901     else:
1902         try:
1903             do_command(gen, lustre, options, args)
1904         except OptionError, e:
1905             panic(string.join(sys.argv),e)
1906         except Lustre.OptionError, e:
1907             panic("lmc", e)
1908
1909     if outFile == '-':
1910         printDoc(doc)
1911     else:
1912         printDoc(doc, open(outFile,"w"))
1913
1914 if __name__ == "__main__":
1915     main()