Whamcloud - gitweb
Branch: HEAD
[fs/lustre-release.git] / lustre / utils / lmc
1 #!/usr/bin/env python
2 # Copyright (C) 2002 Cluster File Systems, Inc.
3 # Author: Robert Read <rread@clusterfs.com>
4
5 #   This file is part of Lustre, http://www.lustre.org.
6 #
7 #   Lustre is free software; you can redistribute it and/or
8 #   modify it under the terms of version 2 of the GNU General Public
9 #   License as published by the Free Software Foundation.
10 #
11 #   Lustre is distributed in the hope that it will be useful,
12 #   but WITHOUT ANY WARRANTY; without even the implied warranty of
13 #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 #   GNU General Public License for more details.
15 #
16 #   You should have received a copy of the GNU General Public License
17 #   along with Lustre; if not, write to the Free Software
18 #   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 #
20
21 """
22 lmc - lustre 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 lov_add(self, lov, ost, index, gen):
670         new = self.doc.createElement("lov_add")
671         new.setAttribute("lov_uuidref", lov)
672         new.setAttribute("ost_uuidref", ost)
673         new.setAttribute("index", index)
674         new.setAttribute("generation", gen)
675         return new
676
677     def lov_delete(self, lov, ost, index, gen, options):
678         if options.delete:
679             new = self.doc.createElement("lov_delete")
680         else:
681             new = self.doc.createElement("lov_deactivate")
682         new.setAttribute("lov_uuidref", lov)
683         new.setAttribute("ost_uuidref", ost)
684         new.setAttribute("index", index)
685         new.setAttribute("generation", gen)
686         return new
687
688 ############################################################
689 # Utilities to query a DOM tree
690 # Using this functions we can treat use config information
691 # directly as a database.
692 def getName(n):
693     return n.getAttribute('name')
694
695 def getUUID(node):
696     return node.getAttribute('uuid')
697
698 def findLastUpdate(lustre):
699     node = None
700     version = 0
701     for n in lustre.childNodes:
702         if n.nodeType == n.ELEMENT_NODE:
703             if n.nodeName != 'update':
704                 continue
705             tmp = int(n.getAttribute('version'))
706             if not tmp:
707                 error('malformed XML: update tag without a version attribute')
708             if tmp != version + 1:
709                 error('malformed XML: expecting update record '+str(version + 1)+', found '+str(tmp)+'.')
710             version = tmp
711             node = n
712     return node
713
714 def addUpdate(gen, lustre, node):
715     update = findLastUpdate(lustre)
716     if not update:
717         return
718     update.appendChild(node)
719
720 def findByName(lustre, name, tag = ""):
721     for n in lustre.childNodes:
722         if n.nodeType == n.ELEMENT_NODE:
723             if tag and n.nodeName != tag:
724                 continue
725             if getName(n) == name:
726                 return n
727             else:
728                 n = findByName(n, name)
729                 if n: return n
730     return None
731
732
733 def lookup(node, uuid):
734     for n in node.childNodes:
735         if n.nodeType == n.ELEMENT_NODE:
736             if getUUID(n) == uuid:
737                 return n
738             else:
739                 n = lookup(n, uuid)
740                 if n: return n
741     return None
742
743
744 def name2uuid(lustre, name, tag="",  fatal=1):
745     ret = findByName(lustre, name, tag)
746     if not ret:
747         if fatal:
748             error('name2uuid:', '"'+name+'"', tag, 'element not found.')
749         else:
750             return ""
751     return getUUID(ret)
752
753 def lookup_filesystem(lustre, fs_name):
754     for n in lustre.childNodes:
755         if n.nodeType == n.ELEMENT_NODE and n.nodeName == 'filesystem':
756             if getName(n) == fs_name:
757                 return getUUID(n)
758     return None
759
760 # XXX: assumes only one network element per node. will fix this
761 # as soon as support for routers is added
762 def get_net_uuid(lustre, node_name):
763     """ get a network uuid for a node_name """
764     node = findByName(lustre, node_name, "node")
765     if not node:
766         error ('get_net_uuid:', '"'+node_name+'"', "node element not found.")
767     net = node.getElementsByTagName('network')
768     if net:
769         return getUUID(net[0])
770     return None
771
772 def lov_mod_obd(gen, lustre, lov, tgt, osc_uuid, options):
773     tgt.setAttribute('uuidref', osc_uuid)
774     gener = int(tgt.getAttribute('generation'))
775     if not options.migrate:
776         gener = str(int(gener) + 1)
777     tgt.setAttribute('generation', str(gener))
778     tgt.setAttribute('active', '1')
779     lov_index = int(tgt.getAttribute('index'))
780     add_rec = gen.lov_add(getUUID(lov), osc_uuid, str(lov_index), str(gener))
781     addUpdate(gen, lustre, add_rec)
782     return
783
784 def lov_add_osc(gen, lustre, lov, osc_uuid, options):
785     lov_name = getName(lov)
786     lov_uuid = getUUID(lov)
787     if options.index:
788         lov_index = get_option_int(options, 'index')
789         for tgt in lov.getElementsByTagName('lov_tgt'):
790             if str(lov_index) == tgt.getAttribute('index'):
791                 uuidref = tgt.getAttribute('uuidref')
792                 if uuidref != '':
793                     raise OptionError("%s --index %d is still in use: %s" %
794                                       (lov_name, lov_index, uuidref))
795                 lov_mod_obd(gen, lustre, lov, tgt, osc_uuid, options)
796                 return
797     else:
798          lov_index = 0
799          for tgt in lov.getElementsByTagName('lov_tgt'):
800              uuidref = tgt.getAttribute('uuidref')
801              tmp = int(tgt.getAttribute('index'))
802              own_lov_uuid = tgt.getAttribute('lov_uuid')
803              if lov_uuid != own_lov_uuid:
804                 continue
805              if uuidref == '':
806                  lov_mod_obd(gen, lustre, lov, tgt, osc_uuid, options)
807                  return
808              lov_index = lov_index + 1
809
810     lov.appendChild(gen.lov_tgt(osc_uuid, lov_uuid, str(lov_index), '1'))
811     addrec = gen.lov_add(lov_uuid, osc_uuid, str(lov_index), '1')
812     addUpdate(gen, lustre, addrec)
813
814 def lov_del_osc(gen, lustre, lov, osc_uuid, options):
815     lov_name = getName(lov)
816     if options.index:
817         lov_index = get_option_int(options, 'index')
818         for tgt in lov.getElementsByTagName('lov_tgt'):
819             index = tgt.getAttribute('index')
820             if index == lov_index:
821                 uuidref = tgt.getAttribute('uuidref')
822                 if uuidref != osc_uuid:
823                     raise OptionError("%s --index %d contains %s, not %s" %
824                                       (lov_name, lov_index, osc_uuid, uuidref))
825                 if options.delete:
826                     tgt.setAttribute('uuidref', '')
827
828                 gener = tgt.getAttribute('generation')
829                 if not options.migrate:
830                     # bump the generation just in case...
831                     gener = str(int(gener) + 1)
832
833                 tgt.setAttribute('active', '0')
834                 tgt.setAttribute('generation', gener)
835                 return None
836         raise OptionError("%s --index %d not in use by %s." %
837                           (lov_name, lov_index, osc_uuid))
838
839     for tgt in lov.getElementsByTagName('lov_tgt'):
840         uuidref = tgt.getAttribute('uuidref')
841         if uuidref == osc_uuid:
842             index = tgt.getAttribute('index')
843             gener = tgt.getAttribute('generation')
844             delete_rec = gen.lov_delete(getUUID(lov), osc_uuid, index, gener,
845                                         options)
846             addUpdate(gen, lustre, delete_rec)
847
848             if options.delete:
849                 tgt.setAttribute('uuidref', '')
850             if not options.migrate:
851                 gener = str(int(gener) + 1)
852             tgt.setAttribute('active', '0')
853             tgt.setAttribute('generation', gener)
854
855 def lmv_add_obd(gen, lmv, mdc_uuid):
856     lmv.appendChild(gen.lmv_tgt(mdc_uuid))
857
858 def ref_exists(profile, uuid):
859     elist = profile.childNodes
860     for e in elist:
861         if e.nodeType == e.ELEMENT_NODE:
862             ref = e.getAttribute('uuidref')
863             if ref == uuid:
864                 return 1
865     return 0
866
867 # ensure that uuid is not already in the profile
868 # return true if uuid is added
869 def node_add_profile(gen, node, ref, uuid):
870     refname = "%s_ref" % "profile"
871     ret = node.getElementsByTagName(refname)
872     if not ret:
873         error('node has no profile ref:', node)
874     prof_uuid = ret[0].getAttribute('uuidref')
875     profile = lookup(node.parentNode, prof_uuid)
876     if not profile:
877         error("no profile found:", prof_uuid)
878     if ref_exists(profile, uuid):
879         return 0
880     profile.appendChild(gen.ref(ref, uuid))
881     return 1
882
883 def get_attr(dom_node, attr, default=""):
884     v = dom_node.getAttribute(attr)
885     if v:
886         return v
887     return default
888
889 ############################################################
890 # Top level commands
891 #
892 def set_node_options(gen, node, options):
893     if options.router:
894         node.setAttribute('router', '1')
895     if options.timeout:
896         gen.addElement(node, "timeout", get_option(options, 'timeout'))
897     if options.upcall:
898         default_upcall =  get_option(options, 'upcall')
899     else:
900         default_upcall = ''
901     if default_upcall or options.lustre_upcall:
902         if options.lustre_upcall:
903             gen.addElement(node, 'lustreUpcall', options.lustre_upcall)
904         else:
905             gen.addElement(node, 'lustreUpcall', default_upcall)
906     if default_upcall or options.portals_upcall:
907         if options.portals_upcall:
908             gen.addElement(node, 'portalsUpcall', options.portals_upcall)
909         else:
910             gen.addElement(node, 'portalsUpcall', default_upcall)
911     if options.ptldebug:
912         gen.addElement(node, "ptldebug", get_option(options, 'ptldebug'))
913     if options.subsystem:
914         gen.addElement(node, "subsystem", get_option(options, 'subsystem'))
915     return node
916
917 def do_add_node(gen, lustre,  options, node_name):
918     uuid = new_uuid(node_name)
919     prof_name = new_name("PROFILE_" + node_name)
920     prof_uuid = new_uuid(prof_name)
921     profile = gen.profile(prof_name, prof_uuid)
922     node = gen.node(node_name, uuid, prof_uuid)
923     lustre.appendChild(node)
924     lustre.appendChild(profile)
925
926     node_add_profile(gen, node, 'ldlm', ldlm_uuid)
927     set_node_options(gen, node, options)
928
929     return node
930
931 def add_node(gen, lustre, options):
932     """ create a node with a network config """
933
934     node_name = get_option(options, 'node')
935     ret = findByName(lustre, node_name, "node")
936     if ret:
937         print "Node:", node_name, "exists."
938         return
939     do_add_node(gen, lustre, options, node_name)
940
941
942 def add_net(gen, lustre, options):
943     """ create a node with a network config """
944
945     node_name = get_option(options, 'node')
946     nid = get_option(options, 'nid')
947     cluster_id = get_option(options, 'cluster_id')
948     hostaddr = get_option(options, 'hostaddr')
949     net_type = get_option(options, 'nettype')
950
951     if net_type in ('tcp','openib','ra'):
952         port = get_option_int(options, 'port')
953     elif net_type in ('elan', 'gm', 'iib', 'vib', 'lo', 'cray_kern_nal'):
954         port = 0
955     else:
956         print "Unknown net_type: ", net_type
957         sys.exit(2)
958
959     ret = findByName(lustre, node_name, "node")
960     if not ret:
961         node = do_add_node(gen, lustre, options, node_name)
962     else:
963         node = ret
964         set_node_options(gen, node, options)
965
966     net_name = new_name('NET_'+ node_name +'_'+ net_type)
967     net_uuid = new_uuid(net_name)
968     node.appendChild(gen.network(net_name, net_uuid, nid, cluster_id, net_type,
969                                  hostaddr, port))
970     node_add_profile(gen, node, "network", net_uuid)
971
972
973 def add_route(gen, lustre, options):
974     """ create a node with a network config """
975
976     node_name = get_option(options, 'node')
977     gw_net_type = get_option(options, 'nettype')
978     gw = get_option(options, 'gw')
979     gw_cluster_id = get_option(options, 'gateway_cluster_id')
980     tgt_cluster_id = get_option(options, 'target_cluster_id')
981     lo = get_option(options, 'lo')
982     hi = get_option(options, 'hi')
983     if not hi:
984         hi = lo
985
986     node = findByName(lustre, node_name, "node")
987     if not node:
988         error (node_name, " not found.")
989
990     rlist = node.getElementsByTagName('routetbl')
991     if len(rlist) > 0:
992         rtbl = rlist[0]
993     else:
994         rtbl_name = new_name("RTBL_" + node_name)
995         rtbl_uuid = new_uuid(rtbl_name)
996         rtbl = gen.routetbl(rtbl_name, rtbl_uuid)
997         node.appendChild(rtbl)
998         node_add_profile(gen, node, "routetbl", rtbl_uuid)
999     rtbl.appendChild(gen.route(gw_net_type, gw, gw_cluster_id, tgt_cluster_id,
1000                                lo, hi))
1001  
1002 def add_gks(gen, lustre, options):
1003     """ create a gks """
1004     node_name = get_option(options, 'node')
1005     gks_name = get_option(options, 'gks')
1006     if not gks_name:
1007         gks_name = new_name('GKS_'+ node_name)
1008     
1009     gkd_name = new_name("GKD_" + gks_name + "_" + node_name)
1010     gkd_uuid = new_uuid(gkd_name)
1011     
1012     gks_uuid = name2uuid(lustre, gks_name, 'gks', fatal=0)
1013
1014     if not gks_uuid:
1015         gks_uuid = new_uuid(gks_name)
1016         gks = gen.gks(gks_name, gks_uuid, gkd_uuid)
1017         lustre.appendChild(gks)
1018     else:
1019         gks = lookup(lustre, gks_uuid)
1020
1021     # add gkd profile
1022     node_uuid = name2uuid(lustre, node_name, 'node')
1023     node = findByName(lustre, node_name, "node")
1024     node_add_profile(gen, node, "gkd", gkd_uuid)
1025     net_uuid = get_net_uuid(lustre, node_name)
1026     if not net_uuid:
1027         error("NODE: ", node_name, "not found")
1028
1029     gkd = gen.gkd(gkd_name, gkd_uuid, node_uuid, gks_uuid)
1030     lustre.appendChild(gkd)
1031
1032
1033 def add_mds(gen, lustre, options):
1034     node_name = get_option(options, 'node')
1035     mds_name = get_option(options, 'mds')
1036     if not mds_name:
1037         mds_name = new_name('MDS_'+ node_name)
1038     lmv_name = get_option(options, 'lmv')
1039     mdd_name = new_name("MDD_" + mds_name +"_" + node_name)
1040     mdd_uuid = new_uuid(mdd_name)
1041
1042     lmv_uuid = ""
1043     if lmv_name:
1044         lmv = findByName(lustre, lmv_name, "lmv")
1045         if not lmv:
1046             error('add_mds:', '"' + lmv_name + '"', "lmv element not found.")
1047         lmv_uuid = name2uuid(lustre, lmv_name, fatal=0)
1048
1049     mds_uuid = name2uuid(lustre, mds_name, 'mds', fatal=0)
1050     if not mds_uuid:
1051         mds_uuid = get_option(options, 'mdsuuid')
1052         if mds_uuid:
1053             if lookup(lustre, mds_uuid):
1054                 error("Duplicate MDS UUID:", mds_uuid)
1055         else:
1056             mds_uuid = new_uuid(mds_name)
1057         mds = gen.mds(mds_name, mds_uuid, mdd_uuid, options.group)
1058         lustre.appendChild(mds)
1059         if lmv_name:
1060             lmv_add_obd(gen, lmv, mds_uuid)
1061     else:
1062         mds = lookup(lustre, mds_uuid)
1063
1064     if options.failover:
1065         mds.setAttribute('failover', "1")
1066
1067     devname = get_option(options, 'dev')
1068     backdevname = get_option(options, 'backdev')
1069     size = get_option(options, 'size')
1070     fstype = get_option(options, 'fstype')
1071     backfstype = get_option(options, 'backfstype')
1072     journal_size = get_option(options, 'journal_size')
1073     inode_size = get_option(options, 'inode_size')
1074     nspath = get_option(options, 'nspath')
1075     mkfsoptions = get_option(options, 'mkfsoptions')
1076     mountfsoptions = get_option(options, 'mountfsoptions')
1077     root_squash = get_option(options, 'root_squash')
1078     no_root_squash = get_option(options, 'no_root_squash')
1079     mds_sec = get_option(options, 'mds_mds_sec')
1080     oss_sec = get_option(options, 'mds_oss_sec')
1081     deny_sec = get_option(options, 'mds_deny_sec')
1082     fs_name = get_option(options, 'filesystem')
1083
1084     node_uuid = name2uuid(lustre, node_name, 'node')
1085
1086     node = findByName(lustre, node_name, "node")
1087     node_add_profile(gen, node, "mdsdev", mdd_uuid)
1088     net_uuid = get_net_uuid(lustre, node_name)
1089     if not net_uuid:
1090         error("NODE: ", node_name, "not found")
1091
1092     if lmv_name:
1093         mds.appendChild(gen.ref("lmv", lmv_uuid))
1094
1095     if fs_name != "":
1096         fs_uuid = name2uuid(lustre, fs_name, 'filesystem', fatal=1)
1097     else:
1098         fs_uuid = ""
1099     
1100     mdd = gen.mdsdev(mdd_name, mdd_uuid, fstype, devname,
1101                      get_format_flag(options), node_uuid, mds_uuid,
1102                      size, journal_size, inode_size, nspath, mkfsoptions, 
1103                      mountfsoptions, backfstype, backdevname,lmv_uuid, 
1104                      root_squash, no_root_squash, mds_sec, oss_sec, deny_sec, 
1105                      fs_uuid)
1106     lustre.appendChild(mdd)
1107
1108 def add_mgmt(gen, lustre, options):
1109     node_name = get_option(options, 'node')
1110     node_uuid = name2uuid(lustre, node_name, 'node')
1111     mgmt_name = get_option(options, 'mgmt')
1112     if not mgmt_name:
1113         mgmt_name = new_name('MGMT_' + node_name)
1114     mgmt_uuid = name2uuid(lustre, mgmt_name, 'mgmt', fatal=0)
1115     if not mgmt_uuid:
1116         mgmt_uuid = new_uuid(mgmt_name)
1117         mgmt = gen.mgmt(mgmt_name, mgmt_uuid, node_uuid)
1118         lustre.appendChild(mgmt)
1119     else:
1120         mgmt = lookup(lustre, mgmt_uuid)
1121
1122     node = findByName(lustre, node_name, "node")
1123     node_add_profile(gen, node, 'mgmt', mgmt_uuid)
1124
1125 def add_ost(gen, lustre, options):
1126     node_name = get_option(options, 'node')
1127     lovname = get_option(options, 'lov')
1128     osdtype = get_option(options, 'osdtype')
1129
1130     node_uuid = name2uuid(lustre, node_name, 'node')
1131
1132     if osdtype == 'obdecho':
1133         fstype = ''
1134         backfstype = ''
1135         devname = ''
1136         backdevname = ''
1137         size = 0
1138         journal_size = ''
1139         inode_size = ''
1140         mkfsoptions = ''
1141         mountfsoptions = ''
1142         deny_sec = ''
1143     else:
1144         devname = get_option(options, 'dev') # can be unset for bluearcs
1145         backdevname = get_option(options, 'backdev')
1146         size = get_option(options, 'size')
1147         fstype = get_option(options, 'fstype')
1148         backfstype = get_option(options, 'backfstype')
1149         journal_size = get_option(options, 'journal_size')
1150         inode_size = get_option(options, 'inode_size')
1151         mkfsoptions = get_option(options, 'mkfsoptions')
1152         mountfsoptions = get_option(options, 'mountfsoptions')
1153         deny_sec = get_option(options, 'ost_deny_sec')
1154
1155     fs_name = get_option(options, 'filesystem')
1156     nspath = get_option(options, 'nspath')
1157
1158     ostname = get_option(options, 'ost')
1159     if not ostname:
1160         ostname = new_name('OST_'+ node_name)
1161
1162     osdname = new_name("OSD_" + ostname + "_" + node_name)
1163     osd_uuid = new_uuid(osdname)
1164
1165     ost_uuid = name2uuid(lustre, ostname, 'ost', fatal=0)
1166     if not ost_uuid:
1167         ost_uuid = get_option(options, 'ostuuid')
1168         if ost_uuid:
1169             if lookup(lustre, ost_uuid):
1170                 error("Duplicate OST UUID:", ost_uuid)
1171         else:
1172             ost_uuid = new_uuid(ostname)
1173
1174         ost = gen.ost(ostname, ost_uuid, osd_uuid, options.group)
1175         lustre.appendChild(ost)
1176     else:
1177         ost = lookup(lustre, ost_uuid)
1178
1179     if lovname:
1180         lov = findByName(lustre, lovname, "lov")
1181         if not lov:
1182             error('add_ost:', '"'+lovname+'"', "lov element not found.")
1183         lov_add_osc(gen, lustre, lov, ost_uuid, options)
1184
1185     if options.failover:
1186         ost.setAttribute('failover', "1")
1187
1188     if fs_name != "":
1189         fs_uuid = name2uuid(lustre, fs_name, 'filesystem', fatal=1)
1190     else:
1191         fs_uuid = ""
1192         
1193     osd = gen.osd(osdname, osd_uuid, fstype, osdtype, devname,
1194                   get_format_flag(options), ost_uuid, node_uuid, size,
1195                   journal_size, inode_size, nspath, mkfsoptions, 
1196                   mountfsoptions, backfstype, backdevname, deny_sec, 
1197                   fs_uuid)
1198
1199     node = findByName(lustre, node_name, "node")
1200     node_add_profile(gen, node, 'osd', osd_uuid)
1201     lustre.appendChild(osd)
1202
1203 def del_ost(gen, lustre, options):
1204     ostname = get_option(options, 'ost')
1205     if not ostname:
1206         raise OptionError("del_ost: --ost requires a <ost name>")
1207     ost = findByName(lustre, ostname, "ost")
1208     if not ost:
1209         error('del_ost: ', 'Unable to find ', ostname)
1210     ost_uuid = name2uuid(lustre, ostname, fatal=0)
1211     if not ost_uuid:
1212         error('del_ost: ', 'Unable to find uuid for ', ostname)
1213     lovname = get_option(options, 'lov')
1214     if lovname:
1215         lov = findByName(lustre, lovname, "lov")
1216         if not lov:
1217             error('del_ost:', '"'+lovname+'"', "lov element not found.")
1218         lov_del_osc(gen, lustre, lov, ost_uuid, options)
1219         # if the user specified a speficic LOV don't delete the OST itself
1220         return
1221
1222     # remove OSD references from all LOVs
1223     for lov in lustre.getElementsByTagName('lov'):
1224         lov_del_osc(gen, lustre, lov, ost_uuid, options)
1225
1226     info = gen.info()
1227
1228     # move the OST description to the update record
1229     lustre.removeChild(ost)
1230     info.appendChild(ost)
1231
1232     active_ref = ost.getElementsByTagName('active_ref')
1233     if not active_ref:
1234         error('ost has no osd ref:', ostname)
1235
1236     # move the OSD description to the update record
1237     osd_uuid = active_ref[0].getAttribute('uuidref')
1238     osd = lookup(lustre, osd_uuid)
1239     lustre.removeChild(osd)
1240     info.appendChild(osd)
1241
1242     # make a copy of the OSS description in the update record
1243     # XXX - should check to make sure one doesn't already exist.
1244     node_ref = osd.getElementsByTagName('node_ref')
1245     if not node_ref:
1246         error('osd has no node ref:', ostname)
1247     node_uuid = node_ref[0].getAttribute('uuidref')
1248     node = lookup(lustre, node_uuid)
1249     if not node:
1250         error('unable to locate node for node ref:', node_uuid)
1251
1252     node_rec = node.cloneNode(1)
1253     info.appendChild(node_rec)
1254
1255     prof_ref = node.getElementsByTagName('profile_ref')
1256     if not prof_ref:
1257         error('node has no profile ref:', node)
1258     profile_uuid = prof_ref[0].getAttribute('uuidref')
1259
1260     # make a copy of the OSS's profile in the update record
1261     # XXX - should check to make sure one doesn't already exist.
1262     profile = lookup(lustre, profile_uuid)
1263     profile_rec = profile.cloneNode(1)
1264     info.appendChild(profile_rec)
1265
1266     # delete all references to this OSD in the OSS's current profile
1267     for osd_ref in profile.getElementsByTagName('osd_ref'):
1268         if osd_uuid == osd_ref.getAttribute('uuidref'):
1269             profile.removeChild(osd_ref)
1270
1271     # XXX - We should cleanup the node and profile elements if they
1272     #       no longer serve a purpose.
1273     addUpdate(gen, lustre, info)
1274
1275 def add_cmobd(gen, lustre, options):
1276     node_name = get_option(options, 'node')
1277     name = get_option(options, 'cmobd')
1278     uuid = new_uuid(name)
1279
1280     master_name = get_option(options, 'master_obd')
1281     cache_name = get_option(options, 'cache_obd')
1282
1283     master_uuid = name2uuid(lustre, master_name, tag='lov', fatal=0)
1284     cache_uuid = name2uuid(lustre, cache_name, tag='lov', fatal=0)
1285
1286     if not master_uuid or not cache_uuid:
1287         if not master_uuid:
1288             master_uuid = name2uuid(lustre, master_name, tag='ost', fatal=0)
1289         if not cache_uuid:
1290             cache_uuid = name2uuid(lustre, cache_name, tag='ost', 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='lmv', fatal=0)
1295         if not cache_uuid:
1296             cache_uuid = name2uuid(lustre, cache_name, tag='lmv', 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='mds', fatal=0)
1301         if not cache_uuid:
1302             cache_uuid = name2uuid(lustre, cache_name, tag='mds', fatal=0)
1303
1304     if not master_uuid: 
1305         error("cannot find master_uuid by name '" + master_name + "'")
1306     if not cache_uuid: 
1307         error("cannot find cache_uuid by name '" + cache_name + "'")
1308
1309     node = findByName(lustre, node_name, "node")
1310     node_add_profile(gen, node, "cmobd", uuid)
1311
1312     master_node = lookup(lustre, master_uuid)
1313     cache_node = lookup(lustre, cache_uuid)
1314     if not master_node:
1315         error("cannot find master node by its uuid " + master_uuid);
1316     if not cache_node:
1317         error("cannot find cache node by its uuid " + cache_uuid);
1318
1319     active = master_node.getElementsByTagName('active_ref')
1320     if active:
1321         active_uuid = active[0].getAttribute('uuidref')
1322         active_node = lookup(lustre, active_uuid)
1323         if not active_node.getElementsByTagName('obdtype'):
1324             gen.addElement(active_node, 'obdtype', 'master')
1325
1326     active = cache_node.getElementsByTagName('active_ref')
1327     if active:
1328         active_uuid = active[0].getAttribute('uuidref')
1329         active_node = lookup(lustre, active_uuid)
1330         if not active_node.getElementsByTagName('obdtype'):
1331             gen.addElement(active_node, 'obdtype', 'cache')
1332
1333     cmobd = gen.cmobd(name, uuid, master_uuid, cache_uuid)
1334     lustre.appendChild(cmobd)
1335
1336 def add_cobd(gen, lustre, options):
1337     node_name = get_option(options, 'node')
1338     name = get_option(options, 'cobd')
1339     uuid = new_uuid(name)
1340
1341     master_name = get_option(options, 'master_obd')
1342     cache_name = get_option(options, 'cache_obd')
1343
1344     # init master
1345     master_uuid = name2uuid(lustre, master_name, tag='lov', fatal=0)
1346     if not master_uuid:
1347         master_uuid = name2uuid(lustre, master_name, tag='ost', fatal=0)
1348
1349     if master_uuid:
1350         node = lookup(lustre, master_uuid)
1351         rets = node.getElementsByTagName('lov_tgt')
1352         for ret in rets:
1353             ost_uuid = ret.getAttribute('uuidref')
1354             ost_node = lookup(lustre, ost_uuid)
1355             active = ost_node.getElementsByTagName('active_ref')
1356             if active:
1357                 osd_uuid = active[0].getAttribute('uuidref')
1358                 osd_node = lookup(lustre, osd_uuid)
1359                 if not osd_node.getElementsByTagName('obdtype'):
1360                     gen.addElement(osd_node, 'obdtype', 'master')
1361
1362     # init cache
1363     cache_uuid = name2uuid(lustre, cache_name, tag='lov', fatal=0)
1364     if not cache_uuid:
1365         cache_uuid = name2uuid(lustre, cache_name, tag='ost', fatal=0)
1366
1367     if cache_uuid:
1368         node = lookup(lustre, cache_uuid)
1369         rets = node.getElementsByTagName('lov_tgt')
1370         for ret in rets:
1371             ost_uuid = ret.getAttribute('uuidref')
1372             ost_node = lookup(lustre, ost_uuid)
1373             active = ost_node.getElementsByTagName('active_ref')
1374             if active:
1375                 osd_uuid = active[0].getAttribute('uuidref')
1376                 osd_node = lookup(lustre, osd_uuid)
1377                 if not osd_node.getElementsByTagName('obdtype'):
1378                     gen.addElement(osd_node, 'obdtype', 'cache')
1379
1380     if not master_uuid or not cache_uuid:
1381         master_uuid = name2uuid(lustre, master_name, tag='lmv', fatal=0)
1382         if not master_uuid:
1383             master_uuid = name2uuid(lustre, master_name, tag='mds', fatal=0)
1384             
1385         if master_uuid:
1386             mds_node = lookup(lustre, master_uuid)
1387             ret = mds_node.getElementsByTagName('active_ref')
1388             if ret:
1389                 mdsdev_uuid = ret[0].getAttribute('uuidref')
1390                 mdsdev_node = lookup(lustre, mdsdev_uuid)
1391                 if not mdsdev_node.getElementsByTagName('obdtype'):
1392                     gen.addElement(mdsdev_node, 'obdtype', 'master')
1393
1394         cache_uuid = name2uuid(lustre, cache_name, tag='lmv', fatal=0)
1395         if not cache_uuid:
1396             cache_uuid = name2uuid(lustre, cache_name, tag='mds', fatal=0)
1397             
1398         if cache_uuid:
1399             mds_node = lookup(lustre, cache_uuid)
1400             ret = mds_node.getElementsByTagName('active_ref')
1401             if ret:
1402                 mdsdev_uuid = ret[0].getAttribute('uuidref')
1403                 mdsdev_node = lookup(lustre, mdsdev_uuid)
1404                 if not mdsdev_node.getElementsByTagName('obdtype'):
1405                     gen.addElement(mdsdev_node, 'obdtype', 'cache')
1406
1407     if not master_uuid or not cache_uuid:
1408         panic("add_cobd", "cannot find master or cache by names '" + 
1409               master_name + "' and '" + cache_name + "'")
1410         
1411     node = findByName(lustre, node_name, "node")
1412     cobd = gen.cobd(name, uuid, master_uuid, cache_uuid)
1413     lustre.appendChild(cobd)
1414
1415 def add_echo_client(gen, lustre, options):
1416     """ add an echo client to the profile for this node. """
1417     node_name = get_option(options, 'node')
1418     lov_name = get_option(options, 'ost')
1419
1420     node = findByName(lustre, node_name, 'node')
1421
1422     echoname = new_name('ECHO_'+ node_name)
1423     echo_uuid = new_uuid(echoname)
1424     node_add_profile(gen, node, 'echoclient', echo_uuid)
1425
1426     lov_uuid = name2uuid(lustre, lov_name, tag='lov', fatal=0)
1427     if not lov_uuid:
1428         lov_uuid = name2uuid(lustre, lov_name, tag='ost', fatal=1)
1429
1430     echo = gen.echo_client(echoname, echo_uuid, lov_uuid)
1431     lustre.appendChild(echo)
1432
1433 def add_lov(gen, lustre, options):
1434     """ create a lov """
1435
1436     lov_orig = get_option(options, 'lov')
1437     name = new_name(lov_orig)
1438     if name != lov_orig:
1439         warning("name:", lov_orig, "already used. using:", name)
1440
1441     lmv_name = get_option(options, 'lmv')
1442     mds_name = get_option(options, 'mds')
1443     aware = get_option(options, 'aware')
1444     
1445     if not mds_name and not lmv_name:
1446         error("LOV: either MDS or LMV must be specified.");
1447     if mds_name and lmv_name:
1448         error("LOV: either MDS or LMV must be specified.");
1449     
1450     stripe_sz = get_option_int(options, 'stripe_sz')
1451     stripe_cnt = get_option_int(options, 'stripe_cnt')
1452     pattern = get_option_int(options, 'stripe_pattern')
1453     uuid = new_uuid(name)
1454
1455     ret = findByName(lustre, name, "lov")
1456     if ret:
1457         error("LOV: ", name, " already exists.")
1458
1459     if lmv_name:
1460         mds_uuid = name2uuid(lustre, lmv_name, 'lmv')
1461     else:
1462         mds_uuid = name2uuid(lustre, mds_name, 'mds')
1463
1464     lov = gen.lov(name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern)
1465     lustre.appendChild(lov)
1466
1467     # add an lovconfig entry to the active mdsdev profile
1468     lovconfig_name = new_name('LVCFG_' + name)
1469     lovconfig_uuid = new_uuid(lovconfig_name)
1470
1471     if mds_name:
1472         md_tgt = findByName(lustre, mds_name, "mds")
1473         if not md_tgt:
1474             error("can't find MDS '" + mds_name + "'")
1475     else:
1476         md_tgt = findByName(lustre, lmv_name, "lmv")
1477         if not md_tgt:
1478             error("can't find LMV '" + lmv_name + "'")
1479     
1480     md_tgt.appendChild(gen.ref("lovconfig", lovconfig_uuid))
1481     md_tgt.appendChild(gen.ref("client", uuid))
1482     
1483     # adding lovconfig and client to aware MD targets
1484     if aware:
1485         md_names = string.split(aware, ',');
1486         for md_name in md_names:
1487         
1488             md_tgt = findByName(lustre, md_name, "mds")
1489             if not md_tgt:
1490                 md_tgt = findByName(lustre, md_name, "lmv")
1491
1492             if not md_tgt:
1493                 error("can't find '" + mds_name + "'")
1494             
1495             md_tgt.appendChild(gen.ref("lovconfig", lovconfig_uuid))
1496             md_tgt.appendChild(gen.ref("client", uuid))
1497         
1498     lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid)
1499     lustre.appendChild(lovconfig)
1500
1501 def add_default_lov(gen, lustre, mds_name, lov_name):
1502     """ create a default lov """
1503
1504     stripe_sz = DEFAULT_STRIPE_SZ
1505     stripe_cnt = DEFAULT_STRIPE_CNT
1506     pattern = DEFAULT_STRIPE_PATTERN
1507     uuid = new_uuid(lov_name)
1508
1509     ret = findByName(lustre, lov_name, "lov")
1510     if ret:
1511         error("LOV: ", lov_name, " already exists.")
1512
1513     mds_uuid = name2uuid(lustre, mds_name, 'mds')
1514     lov = gen.lov(lov_name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern)
1515     lustre.appendChild(lov)
1516
1517     # add an lovconfig entry to the active mdsdev profile
1518     lovconfig_name = new_name('LVCFG_' + lov_name)
1519     lovconfig_uuid = new_uuid(lovconfig_name)
1520     mds = findByName(lustre, mds_name)
1521     mds.appendChild(gen.ref("lovconfig", lovconfig_uuid))
1522     lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid)
1523     lustre.appendChild(lovconfig)
1524
1525 def add_lmv(gen, lustre, options):
1526     """ create a lmv """
1527
1528     lmv_orig = get_option(options, 'lmv')
1529     name = new_name(lmv_orig)
1530     if name != lmv_orig:
1531         warning("name:", lmv_orig, "already used. using:", name)
1532
1533     uuid = new_uuid(name)
1534     ret = findByName(lustre, name, "lmv")
1535     if ret:
1536         error("LMV: ", name, " already exists.")
1537
1538     lmv = gen.lmv(name, uuid)
1539     lustre.appendChild(lmv)
1540    
1541 def new_filesystem(gen, lustre, fs_name, mds_uuid, obd_uuid, 
1542                    mgmt_uuid, gks_uuid):
1543     fs_uuid = new_uuid(fs_name)
1544     fs = gen.filesystem(fs_name, fs_uuid, mds_uuid, obd_uuid, 
1545                         mgmt_uuid, gks_uuid)
1546     lustre.appendChild(fs)
1547     return fs_uuid
1548
1549 def get_fs_uuid(gen, lustre, fs_name, mds_name, obd_name, 
1550                 mgmt_name, gks_name):
1551     mds_uuid = name2uuid(lustre, mds_name, tag='mds', fatal=0)
1552     if not mds_uuid:
1553         mds_uuid = name2uuid(lustre, mds_name, tag='lmv', fatal=0)
1554     if not mds_uuid:
1555         mds_uuid = name2uuid(lustre, mds_name, tag='cobd', fatal=0)
1556     if not mds_uuid:
1557         error("mds '" + mds_name + "' is not found")
1558
1559     obd_uuid = name2uuid(lustre, obd_name, tag='ost', fatal=0)
1560     if not obd_uuid:
1561         obd_uuid = name2uuid(lustre, obd_name, tag='lov', fatal=0)
1562     if not obd_uuid:
1563         obd_uuid = name2uuid(lustre, obd_name, tag='cobd', fatal=0)
1564     if not obd_uuid:
1565         error("ost '" + obd_name + "' is not found")
1566         
1567     if mgmt_name:
1568         mgmt_uuid = name2uuid(lustre, mgmt_name, tag='mgmt', fatal=1)
1569     else:
1570         mgmt_uuid = ''
1571
1572     if gks_name:
1573         gks_uuid = name2uuid(lustre, gks_name, tag='gks', fatal=1)
1574     else: 
1575         gks_uuid = ''
1576         
1577     fs_uuid = lookup_filesystem(lustre, fs_name)
1578     if fs_uuid:
1579         fs = lookup(lustre, fs_uuid)
1580         if not ref_exists(fs, mds_uuid):
1581             fs.appendChild(gen.ref("mds", mds_uuid))
1582         if not ref_exists(fs, obd_uuid):
1583             fs.appendChild(gen.ref("obd", obd_uuid))
1584         if gks_uuid and not ref_exists(fs, gks_uuid):
1585             fs.appendChild(gen.ref("gks", gks_uuid))
1586     else:
1587         fs_uuid = new_filesystem(gen, lustre, fs_name, 
1588                                  mds_uuid, obd_uuid, 
1589                                  mgmt_uuid, gks_uuid)
1590     return fs_uuid
1591
1592 def add_filesystem(gen, lustre, options):
1593     """ create filesytem """
1594     fs_orig = get_option(options, 'filesystem')
1595     name = new_name(fs_orig)
1596     if name != fs_orig:
1597         warning("name:", fs_orig, "already used. using:", name)
1598
1599     uuid = new_uuid(name)
1600     ret = findByName(lustre, name, "filesystem")
1601     if ret:
1602         error("FS: ", name, " already exists.")
1603
1604     gks_name = get_option(options, 'gks')
1605     if gks_name:
1606         gks_uuid = name2uuid(lustre, gks_name, tag='gks', fatal=1)
1607     else: 
1608         gks_uuid = ''
1609     fs = gen.filesystem(name, uuid, "", "", "", gks_uuid)
1610     lustre.appendChild(fs)
1611     
1612 def add_mtpt(gen, lustre, options):
1613     """ create mtpt on a node """
1614     node_name = get_option(options, 'node')
1615
1616     path = get_option(options, 'path')
1617     clientoptions = get_option(options, "clientoptions")
1618     mds_sec = get_option(options, "mds_sec")
1619     oss_sec = get_option(options, "oss_sec")
1620     fs_name = get_option(options, 'filesystem')
1621
1622     lov_name = get_option(options, 'lov')
1623     ost_name = get_option(options, 'ost')
1624     mds_name = get_option(options, 'mds')
1625     gks_name = get_option(options, 'gks')
1626     if mds_name == '':
1627         mds_name = get_option(options, 'lmv')
1628         if mds_name == '':
1629             error("--add mtpt requires either --mds or --lmv.")
1630     if lov_name == '':
1631         if ost_name == '':
1632             error("--add mtpt requires --lov lov_name or --ost ost_name")
1633         else:
1634             warning("use default value for lov, due no --lov lov_name provided")
1635             lov_name = new_name("lov_default")
1636             add_default_lov(gen, lustre, mds_name, lov_name)
1637             ost_uuid = name2uuid(lustre, ost_name, 'ost', fatal=0)
1638             if not ost_uuid:
1639                 error('add_mtpt:', '"'+ost_name+'"', "ost element not found.")
1640             lov = findByName(lustre, lov_name, "lov")
1641             lov_add_osc(gen, lustre, lov, ost_uuid, options)
1642
1643     if fs_name == '':
1644         fs_name = new_name("FS_fsname")
1645         mgmt_name = get_option(options, 'mgmt')
1646     else:
1647         mgmt_name = ""
1648         
1649     fs_uuid = get_fs_uuid(gen, lustre, fs_name, 
1650                           mds_name, lov_name, mgmt_name, gks_name)
1651
1652     name = new_name('MNT_'+ node_name)
1653
1654     ret = findByName(lustre, name, "mountpoint")
1655     if ret:
1656         # this can't happen, because new_name creates unique names
1657         error("MOUNTPOINT: ", name, " already exists.")
1658
1659     uuid = new_uuid(name)
1660     mtpt = gen.mountpoint(name, uuid, fs_uuid, path, 
1661                           clientoptions, mds_sec, oss_sec)
1662     node = findByName(lustre, node_name, "node")
1663     if not node:
1664         error('node:',  node_name, "not found.")
1665     node_add_profile(gen, node, "mountpoint", uuid)
1666     lustre.appendChild(mtpt)
1667
1668 def commit_version(gen, lustre):
1669     update = findLastUpdate(lustre)
1670     if update:
1671         version = int(update.getAttribute("version")) + 1
1672     else:
1673         version = 1
1674
1675     new = gen.update(str(version))
1676     lustre.appendChild(new)
1677     
1678
1679 ############################################################
1680 # Command line processing
1681 #
1682 class OptionError (exceptions.Exception):
1683     def __init__(self, args):
1684         self.args = args
1685
1686 def get_option(options, tag):
1687     """Look for tag in options hash and return the value if set. If not
1688     set, then if return default it is set, otherwise exception."""
1689     if options.__getattr__(tag) != None:
1690         return options.__getattr__(tag)
1691     else:
1692         raise OptionError("--add %s requires --%s <value>" % (options.add, tag))
1693
1694 def get_option_int(options, tag):
1695     """Return an integer option.  Raise exception if the value is not an int"""
1696     val = get_option(options, tag)
1697     try:
1698         n = int(val)
1699     except ValueError:
1700         raise OptionError("--%s <num> (value must be integer)" % (tag))
1701     return n
1702
1703 # simple class for profiling
1704 import time
1705 class chrono:
1706     def __init__(self):
1707         self._start = 0
1708     def start(self):
1709         self._stop = 0
1710         self._start = time.time()
1711     def stop(self, msg=''):
1712         self._stop = time.time()
1713         if msg:
1714             self.display(msg)
1715     def dur(self):
1716         return self._stop - self._start
1717     def display(self, msg):
1718         d = self.dur()
1719         str = '%s: %g secs' % (msg, d)
1720         print str
1721
1722 #################################################################
1723 # function cmdlinesplit used to split cmd line from batch file
1724 #
1725 def cmdlinesplit(cmdline):
1726
1727     double_quote  = re.compile(r'"(([^"\\]|\\.)*)"')
1728     single_quote  = re.compile(r"'(.*?)'")
1729     escaped = re.compile(r'\\(.)')
1730     esc_quote = re.compile(r'\\([\\"])')
1731     outside = re.compile(r"""([^\s\\'"]+)""") #" fucking emacs.
1732
1733     arg_list = []
1734     i = 0; arg = None
1735     while i < len(cmdline):
1736         c = cmdline[i]
1737         if c == '"':
1738             match = double_quote.match(cmdline, i)
1739             if not match:
1740                 print "Unmatched double quote:", cmdline
1741                 sys.exit(1)
1742             i = match.end()
1743             if arg is None: arg = esc_quote.sub(r'\1', match.group(1))
1744             else:           arg = arg + esc_quote.sub(r'\1', match.group(1))
1745
1746         elif c == "'":
1747             match = single_quote.match(cmdline, i)
1748             if not match:
1749                 print "Unmatched single quote:", cmdline
1750                 sys.exit(1)
1751             i = match.end()
1752             if arg is None: arg = match.group(1)
1753             else:           arg = arg + match.group(1)
1754
1755         elif c == "\\":
1756             match = escaped.match(cmdline, i)
1757             if not match:
1758                 print "Unmatched backslash", cmdline
1759                 sys.exit(1)
1760             i = match.end()
1761             if arg is None: arg = match.group(1)
1762             else:           arg = arg + match.group(1)
1763
1764         elif c in string.whitespace:
1765             if arg != None:
1766                 arg_list.append(str(arg))
1767             arg = None
1768             while i < len(cmdline) and cmdline[i] in string.whitespace:
1769                 i = i + 1
1770         else:
1771             match = outside.match(cmdline, i)
1772             assert match
1773             i = match.end()
1774             if arg is None: arg = match.group()
1775             else:           arg = arg + match.group()
1776
1777     if arg != None: arg_list.append(str(arg))
1778
1779     return arg_list
1780
1781 ############################################################
1782 # Main
1783 #
1784
1785 def add(devtype, gen, lustre, options):
1786     if devtype == 'net':
1787         add_net(gen, lustre, options)
1788     elif devtype == 'mtpt':
1789         add_mtpt(gen, lustre, options)
1790     elif devtype == 'mds':
1791         add_mds(gen, lustre, options)
1792     elif devtype == 'ost':
1793         add_ost(gen, lustre, options)
1794     elif devtype == 'lov':
1795         add_lov(gen, lustre, options)
1796     elif devtype == 'route':
1797         add_route(gen, lustre, options)
1798     elif devtype == 'node':
1799         add_node(gen, lustre, options)
1800     elif devtype == 'echo_client':
1801         add_echo_client(gen, lustre, options)
1802     elif devtype == 'cobd':
1803         add_cobd(gen, lustre, options)
1804     elif devtype == 'cmobd':
1805         add_cmobd(gen, lustre, options)
1806     elif devtype == 'mgmt':
1807         add_mgmt(gen, lustre, options)
1808     elif devtype == 'lmv':
1809         add_lmv(gen, lustre, options)
1810     elif devtype == 'filesystem':
1811         add_filesystem(gen, lustre, options)
1812     elif devtype == 'gks':
1813         add_gks(gen, lustre, options)
1814     else:
1815         error("unknown device type:", devtype)
1816
1817 def delete(devtype, gen, lustre, options):
1818     if devtype == 'ost':
1819         del_ost(gen, lustre, options)
1820     elif options.delete:
1821         error("delete not supported for device type:", devtype)
1822     elif options.deactivate:
1823         error("deactivate not supported for device type:", devtype)
1824     else:
1825         error("in delete(), but neither .delete nor .deactivate are set.  Tell CFS.")
1826
1827 def commit(gen, lustre):
1828     commit_version(gen, lustre)
1829
1830 def do_command(gen, lustre, options, args):
1831     if options.add:
1832         add(options.add, gen, lustre, options)
1833     elif options.delete:
1834         delete(options.delete, gen, lustre, options)
1835     elif options.deactivate:
1836         delete(options.deactivate, gen, lustre, options)
1837     elif options.commit:
1838         commit(gen, lustre)
1839     else:
1840         error("Missing command")
1841
1842 def main():
1843     cl = Lustre.Options("lmc", "", lmc_options)
1844     try:
1845         options, args = cl.parse(sys.argv[1:])
1846     except Lustre.OptionError, e:
1847         panic("lmc", e)
1848
1849     if len(args) > 0:
1850         panic(string.join(sys.argv), "Unexpected extra arguments on command line: " + string.join(args))
1851
1852     if options.reference:
1853         reference()
1854         sys.exit(0)
1855
1856     outFile = '-'
1857
1858     if options.merge:
1859         outFile = options.merge
1860         if os.access(outFile, os.R_OK):
1861             doc = xml.dom.minidom.parse(outFile)
1862         else:
1863             doc = new_lustre(xml.dom.minidom)
1864     elif options.input:
1865         doc = xml.dom.minidom.parse(options.input)
1866     else:
1867         doc = new_lustre(xml.dom.minidom)
1868
1869     if options.output:
1870         outFile = options.output
1871
1872     lustre = doc.documentElement
1873     init_names(lustre)
1874     if lustre.tagName != "lustre":
1875         print "Existing config not valid."
1876         sys.exit(1)
1877
1878     gen = GenConfig(doc)
1879
1880     if options.batch:
1881         fp = open(options.batch)
1882         batchCommands = fp.readlines()
1883         fp.close()
1884         for cmd in batchCommands:
1885             try:
1886                 options, args = cl.parse(cmdlinesplit(cmd))
1887                 if options.merge or options.input or options.output:
1888                     print "The batchfile should not contain --merge, --input or --output."
1889                     sys.exit(1)
1890                 do_command(gen, lustre, options, args)
1891             except OptionError, e:
1892                 panic(cmd, e)
1893             except Lustre.OptionError, e:
1894                 panic(cmd, e)
1895     else:
1896         try:
1897             do_command(gen, lustre, options, args)
1898         except OptionError, e:
1899             panic(string.join(sys.argv),e)
1900         except Lustre.OptionError, e:
1901             panic("lmc", e)
1902
1903     if outFile == '-':
1904         printDoc(doc)
1905     else:
1906         printDoc(doc, open(outFile,"w"))
1907
1908 if __name__ == "__main__":
1909     main()