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