Whamcloud - gitweb
9f4893c37950266a563e4161a6c96b9ba0ff77d1
[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   --node node_name
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     ('group', "", PARAM),
243     ('dev', "Path of the device on local system.", PARAM,""),
244     ('backdev', "Path of the device for backing storage on local system.", PARAM,""),
245     ('size', "Specify the size of the device if needed.", PARAM,"0"),
246     ('journal_size', "Specify new journal size for underlying file system.", PARAM,"0"),
247     ('inode_size', "Specify new inode size for underlying file system.", PARAM,"0"),
248     ('fstype', "Optional argument to specify the filesystem type.", PARAM, "ext3"),
249     ('backfstype', "Optional argument to specify the backing filesystem type.", PARAM, "ext3"),
250     ('mkfsoptions', "Optional argument to mkfs.", PARAM, ""),
251     ('mountfsoptions', "Optional argument to mount fs.", PARAM, ""),
252     ('ostuuid', "Optional argument to specify OST UUID", PARAM,""),
253     ('mdsuuid', "Optional argument to specify MDS UUID", PARAM,""),
254     ('root_squash', "MDS squash root to appointed uid.", PARAM, ""),
255     ('no_root_squash', "Don't squash root for appointed nid.", PARAM, ""),
256     ('nspath', "Local mount point of server namespace.", PARAM,""),
257     ('mds_mds_sec', "Specify the secure flavor for connection from this mds to other mds.", PARAM, ""),
258     ('mds_oss_sec', "Specify the secure flavor for connection from this mds to ost.", PARAM, ""),
259     ('mds_deny_sec', "Specify the secure flavor which is denied from remote to this mds.", PARAM, ""),
260     ('ost_deny_sec', "Specify the secure flavor which is denied from remote to this ost.", PARAM, ""),
261     ('filesystem', "Specify the filesystem name device belong to.", PARAM, ""),
262     ('format', ""),
263     ('migrate', "used for offline migrate of an ost in conjunctio with add/delete"),
264
265     # clients: mountpoint and echo
266     ('echo_client', "", PARAM),
267     ('path', "Specify the mountpoint for Lustre.", PARAM),
268     ('filesystem', "Lustre filesystem name", PARAM,""),
269     ('clientoptions', "Specify the options for Lustre, such as async.", PARAM, ""),
270     ('mds_sec', "Specify the secure flavor for connection from this client to mds.", PARAM, ""),
271     ('oss_sec', "Specify the secure flavor for connection from this client to ost.", PARAM, ""),
272
273     # lov
274     ('lov', "Specify LOV name.", PARAM,""),
275     ('mds/lmv', "Specify MDS/LMV name using this LOV.", PARAM,""),
276     ('aware', "Specify MDS/LMV aware of this LOV.", PARAM,""),
277     ('index', "Specify index for OBD in LOV target table.", PARAM),
278     ('stripe_sz', "Specify the stripe size in bytes.", PARAM),
279     ('stripe_cnt', "Specify the number of OSTs each file should be striped on.", PARAM, 0),
280     ('stripe_pattern', "Specify the stripe pattern. RAID 0 is the only one currently supported.", PARAM, 0),
281
282     # cobd
283     ('master_obd', "Specify the real device for the cache obd system.", PARAM),
284     ('cache_obd', "Specify the cache device for the cache obd system.", PARAM),
285     ('cobd', "Specify COBD name", PARAM),
286
287     # cmobd
288     ('master_obd', "Specify the master device for the cmobd system.", PARAM),
289     ('cache_obd',  "Specify the cache device for the cmobd obd system.", PARAM),
290     ('cmobd',      "Specify COBD name", PARAM),
291
292     ('mgmt', "Specify management/monitoring service name.", PARAM, ""),
293
294     # lmv
295     ('lmv', "Specify LMV name.", PARAM,""),
296     
297     #gks name
298     ('gks', "Specify gks name.", PARAM,""),
299
300     ]
301
302 def error(*args):
303     msg = string.join(map(str,args))
304     raise OptionError("Error: " +  msg)
305
306 def panic(cmd, msg):
307     print "! " + cmd
308     print msg
309     sys.exit(1)
310
311
312 def warning(*args):
313     msg = string.join(map(str,args))
314     print "Warning: ", msg
315
316 #
317 # manage names and uuids
318 # need to initialize this by walking tree to ensure
319 # no duplicate names or uuids are created.
320 # this are just place holders for now.
321 # consider changing this to be like OBD-dev-host
322 def new_name(base):
323     ctr = 2
324     ret = base
325     while names.has_key(ret):
326         ret = "%s_%d" % (base, ctr)
327         ctr = 1 + ctr
328     names[ret] = 1
329     return ret
330
331 def new_uuid(name):
332     ctr = 2
333     ret = "%s_UUID" % (name)
334     if len(ret) > UUID_MAX_LENGTH:
335         ret = ret[-UUID_MAX_LENGTH:]
336     while uuids.has_key(ret):
337         ret = "%s_UUID_%d" % (name, ctr)
338         ctr = 1 + ctr
339         if len(ret) > UUID_MAX_LENGTH:
340             ret = ret[-UUID_MAX_LENGTH:]
341     uuids[ret] = 1
342     return ret
343
344
345 ldlm_name = 'ldlm'
346 ldlm_uuid = 'ldlm_UUID'
347
348 def new_lustre(dom):
349     """Create a new empty lustre document"""
350     # adding ldlm here is a bit of a hack, but one is enough.
351     str = """<lustre version="%s">
352     <ldlm name="%s" uuid="%s"/>
353     </lustre>""" % (Lustre.CONFIG_VERSION, ldlm_name, ldlm_uuid)
354     return dom.parseString(str)
355
356 names = {}
357 uuids = {}
358
359 def init_names(doc):
360     """initialize auto-name generation tables"""
361     global names, uuids
362     # get all elements that contain a name attribute
363     for n in doc.childNodes:
364         if n.nodeType == n.ELEMENT_NODE:
365             if getName(n):
366                 names[getName(n)] = 1
367                 uuids[getUUID(n)] = 1
368             init_names(n)
369
370 def get_format_flag(options):
371     if options.format:
372         return 'yes'
373     return 'no'
374
375 ############################################################
376 # Build config objects using DOM
377 #
378 class GenConfig:
379     doc = None
380     dom = None
381     def __init__(self, doc):
382         self.doc = doc
383
384     def ref(self, type, uuid):
385         """ generate <[type]_ref uuidref="[uuid]"/> """
386         tag = "%s_ref" % (type)
387         ref = self.doc.createElement(tag)
388         ref.setAttribute("uuidref", uuid)
389         return ref
390         
391     def dev(self, devname):
392         """ generate <dev devpath="[devname]"/> """
393         tgt = self.doc.createElement('dev')
394         tgt.setAttribute("dev", devname)
395         return tgt
396
397     def newService(self, tag, name, uuid):
398         """ create a new  service elmement, which requires name and uuid attributes """
399         new = self.doc.createElement(tag)
400         new.setAttribute("uuid", uuid);
401         new.setAttribute("name", name);
402         return new
403
404     def addText(self, node, str):
405         txt = self.doc.createTextNode(str)
406         node.appendChild(txt)
407
408     def addElement(self, node, tag, str=None):
409         """ create a new element and add it as a child to node. If str is passed,
410             a text node is created for the new element"""
411         new = self.doc.createElement(tag)
412         if str:
413             self.addText(new, str)
414         node.appendChild(new)
415         return new
416
417     def network(self, name, uuid, nid, cluster_id, net, hostaddr="",
418                 port=0):
419         """create <network> node"""
420         network = self.newService("network", name, uuid)
421         network.setAttribute("nettype", net);
422         self.addElement(network, "nid", nid)
423         self.addElement(network, "clusterid", cluster_id)
424         for host in  hostaddr:
425             self.addElement(network, "hostaddr", host)
426         if port:
427             self.addElement(network, "port", "%d" %(port))
428         
429         return network
430
431     def routetbl(self, name, uuid):
432         """create <routetbl> node"""
433         rtbl = self.newService("routetbl", name, uuid)
434         return rtbl
435
436     def route(self, gw_net_type, gw, gw_cluster_id, tgt_cluster_id, lo, hi):
437         """ create one entry for the route table """
438         ref = self.doc.createElement('route')
439         ref.setAttribute("type", gw_net_type)
440         ref.setAttribute("gw", gw)
441         ref.setAttribute("gwclusterid", gw_cluster_id)
442         ref.setAttribute("tgtclusterid", tgt_cluster_id)
443         ref.setAttribute("lo", lo)
444         if hi:
445             ref.setAttribute("hi", hi)
446         return ref
447
448     def profile(self, name, uuid):
449         """ create a host """
450         profile = self.newService("profile", name, uuid)
451         return profile
452
453     def node(self, name, uuid, prof_uuid):
454         """ create a host """
455         node = self.newService("node", name, uuid)
456         node.appendChild(self.ref("profile", prof_uuid))
457         return node
458
459     def ldlm(self, name, uuid):
460         """ create a ldlm """
461         ldlm = self.newService("ldlm", name, uuid)
462         return ldlm
463
464     def osd(self, name, uuid, fstype, osdtype, devname, format, ost_uuid,
465             node_uuid, dev_size=0, journal_size=0, inode_size=0, nspath="", 
466             mkfsoptions="", mountfsoptions="", backfstype="", backdevname="",
467             deny_sec="", fs_uuid=""):
468         osd = self.newService("osd", name, uuid)
469         osd.setAttribute('osdtype', osdtype)
470         osd.appendChild(self.ref("target", ost_uuid))
471         osd.appendChild(self.ref("node", node_uuid))
472         osd.appendChild(self.dev(devname)) 
473
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 add(self, lov, ost, index, gen):
666         new = self.doc.createElement("add")
667         new.setAttribute("lov_uuidref", lov)
668         new.setAttribute("ost_uuidref", ost)
669         new.setAttribute("index", index)
670         new.setAttribute("generation", gen)
671         return new
672
673     def delete(self, lov, ost, index, gen, options):
674         if options.delete:
675             new = self.doc.createElement("delete")
676         else:
677             new = self.doc.createElement("deactivate")
678         new.setAttribute("lov_uuidref", lov)
679         new.setAttribute("ost_uuidref", ost)
680         new.setAttribute("index", index)
681         new.setAttribute("generation", gen)
682         return new
683
684 ############################################################
685 # Utilities to query a DOM tree
686 # Using this functions we can treat use config information
687 # directly as a database.
688 def getName(n):
689     return n.getAttribute('name')
690
691 def getUUID(node):
692     return node.getAttribute('uuid')
693
694 def findLastUpdate(lustre):
695     node = None
696     version = 0
697     for n in lustre.childNodes:
698         if n.nodeType == n.ELEMENT_NODE:
699             if n.nodeName != 'update':
700                 continue
701             tmp = int(n.getAttribute('version'))
702             if not tmp:
703                 error('malformed XML: update tag without a version attribute')
704             if tmp != version + 1:
705                 error('malformed XML: expecting update record '+str(version + 1)+', found '+str(tmp)+'.')
706             version = tmp
707             node = n
708     return node
709
710 def addUpdate(gen, lustre, node):
711     update = findLastUpdate(lustre)
712     if not update:
713         return
714     #add_record = update.getElementsByTagName('add')
715     #if not add_record:
716     #    add_record = gen.add()
717     #    update.appendChild(add_record)
718     #else:
719     #    add_record = add_record[0]
720     #add_record.appendChild(node)
721     update.appendChild(node)
722
723 def delUpdate(gen, lustre, node):
724     update = findLastUpdate(lustre)
725     if not update:
726         return
727     update.appendChild(node)
728
729 def findByName(lustre, name, tag = ""):
730     for n in lustre.childNodes:
731         if n.nodeType == n.ELEMENT_NODE:
732             if tag and n.nodeName != tag:
733                 continue
734             if getName(n) == name:
735                 return n
736             else:
737                 n = findByName(n, name)
738                 if n: return n
739     return None
740
741
742 def lookup(node, uuid):
743     for n in node.childNodes:
744         if n.nodeType == n.ELEMENT_NODE:
745             if getUUID(n) == uuid:
746                 return n
747             else:
748                 n = lookup(n, uuid)
749                 if n: return n
750     return None
751
752
753 def name2uuid(lustre, name, tag="",  fatal=1):
754     ret = findByName(lustre, name, tag)
755     if not ret:
756         if fatal:
757             error('name2uuid:', '"'+name+'"', tag, 'element not found.')
758         else:
759             return ""
760     return getUUID(ret)
761
762 def lookup_filesystem(lustre, fs_name):
763     for n in lustre.childNodes:
764         if n.nodeType == n.ELEMENT_NODE and n.nodeName == 'filesystem':
765             if getName(n) == fs_name:
766                 return getUUID(n)
767     return None
768
769 # XXX: assumes only one network element per node. will fix this
770 # as soon as support for routers is added
771 def get_net_uuid(lustre, node_name):
772     """ get a network uuid for a node_name """
773     node = findByName(lustre, node_name, "node")
774     if not node:
775         error ('get_net_uuid:', '"'+node_name+'"', "node element not found.")
776     net = node.getElementsByTagName('network')
777     if net:
778         return getUUID(net[0])
779     return None
780
781 def lov_mod_obd(gen, lustre, lov, tgt, osc_uuid, options):
782     tgt.setAttribute('uuidref', osc_uuid)
783     if options.migrate:
784         gener = int(tgt.getAttribute('generation'))
785     else:
786         gener = int(tgt.getAttribute('generation')) + 1
787     tgt.setAttribute('generation', str(gener))
788     tgt.setAttribute('active', '1')
789     lov_index = int(tgt.getAttribute('index'))
790     addUpdate(gen, lustre, gen.add(getUUID(lov), osc_uuid, str(lov_index),
791               str(gener)))
792     return
793
794 def lov_add_obd(gen, lustre, lov, osc_uuid, options):
795     lov_name = getName(lov)
796     lov_uuid = getUUID(lov)
797     if options.index:
798         lov_index = get_option_int(options, 'index')
799         for tgt in lustre.getElementsByTagName('lov_tgt'):
800             if str(lov_index) == tgt.getAttribute('index'):
801                 uuidref = tgt.getAttribute('uuidref')
802                 if uuidref != '':
803                     raise OptionError("%s --index %d is still in use: %s" %
804                                       (lov_name, lov_index, uuidref))
805                 lov_mod_obd(gen, lustre, lov, tgt, osc_uuid, options)
806                 return
807     else:
808          lov_index = 0
809          for tgt in lustre.getElementsByTagName('lov_tgt'):
810              uuidref = tgt.getAttribute('uuidref')
811              tmp = int(tgt.getAttribute('index'))
812              own_lov_uuid = tgt.getAttribute('lov_uuid')
813              if lov_uuid != own_lov_uuid:
814                 continue
815              if uuidref == '':
816                  lov_mod_obd(gen, lustre, lov, tgt, osc_uuid, options)
817                  return
818              lov_index = lov_index + 1
819
820     lov.appendChild(gen.lov_tgt(osc_uuid, lov_uuid, str(lov_index), '1'))
821     addUpdate(gen, lustre, gen.add(getUUID(lov), lov_uuid, str(lov_index), '1'))
822
823 def lov_del_obd(gen, lustre, lov, osc_uuid, options):
824     lov_name = getName(lov)
825     if options.index:
826         lov_index = get_option_int(options, 'index')
827         for tgt in lustre.getElementsByTagName('lov_tgt'):
828             index = tgt.getAttribute('index')
829             if index == lov_index:
830                 uuidref = tgt.getAttribute('uuidref')
831                 if uuidref != osc_uuid:
832                     raise OptionError("%s --index %d contains %s, not %s" %
833                                       (lov_name, lov_index, osc_uuid, uuidref))
834                 if options.delete:
835                     tgt.setAttribute('uuidref', '')
836
837                 # bump the generation just in case...
838                 if options.migrate:
839                     gen = int(tgt.getAttribute('generation'))
840                 else:
841                     gen = int(tgt.getAttribute('generation')) + 1
842
843                 tgt.setAttribute('active', '0')
844                 tgt.setAttribute('generation', str(gen))
845                 return
846         raise OptionError("%s --index %d not in use by %s." %
847                           (lov_name, lov_index, osc_uuid))
848
849     for tgt in lustre.getElementsByTagName('lov_tgt'):
850         uuidref = tgt.getAttribute('uuidref')
851         if uuidref == osc_uuid:
852             genera = int(tgt.getAttribute('generation'))
853             delete_rec = gen.delete(getUUID(lov),
854                                     osc_uuid,tgt.getAttribute('index'),
855                                     str(genera), options)
856             delUpdate(gen, lustre, delete_rec)
857
858             if options.delete:
859                 tgt.setAttribute('uuidref', '')
860             if not options.migrate:
861                 genera = genera + 1
862             tgt.setAttribute('active', '0')
863             tgt.setAttribute('generation', str(genera))
864
865 def lmv_add_obd(gen, lmv, mdc_uuid):
866     lmv.appendChild(gen.lmv_tgt(mdc_uuid))
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 = findByName(lustre, lmv_name, "lmv")
1055         if not lmv:
1056             error('add_mds:', '"' + lmv_name + '"', "lmv element not found.")
1057         lmv_uuid = name2uuid(lustre, lmv_name, fatal=0)
1058
1059     mds_uuid = name2uuid(lustre, mds_name, 'mds', fatal=0)
1060     if not mds_uuid:
1061         mds_uuid = get_option(options, 'mdsuuid')
1062         if mds_uuid:
1063             if lookup(lustre, mds_uuid):
1064                 error("Duplicate MDS UUID:", mds_uuid)
1065         else:
1066             mds_uuid = new_uuid(mds_name)
1067         mds = gen.mds(mds_name, mds_uuid, mdd_uuid, options.group)
1068         lustre.appendChild(mds)
1069         if lmv_name:
1070             lmv_add_obd(gen, lmv, mds_uuid)
1071     else:
1072         mds = lookup(lustre, mds_uuid)
1073
1074     if options.failover:
1075         mds.setAttribute('failover', "1")
1076
1077     devname = get_option(options, 'dev')
1078     backdevname = get_option(options, 'backdev')
1079     size = get_option(options, 'size')
1080     fstype = get_option(options, 'fstype')
1081     backfstype = get_option(options, 'backfstype')
1082     journal_size = get_option(options, 'journal_size')
1083     inode_size = get_option(options, 'inode_size')
1084     nspath = get_option(options, 'nspath')
1085     mkfsoptions = get_option(options, 'mkfsoptions')
1086     mountfsoptions = get_option(options, 'mountfsoptions')
1087     root_squash = get_option(options, 'root_squash')
1088     no_root_squash = get_option(options, 'no_root_squash')
1089     mds_sec = get_option(options, 'mds_mds_sec')
1090     oss_sec = get_option(options, 'mds_oss_sec')
1091     deny_sec = get_option(options, 'mds_deny_sec')
1092     fs_name = get_option(options, 'filesystem')
1093
1094     node_uuid = name2uuid(lustre, node_name, 'node')
1095
1096     node = findByName(lustre, node_name, "node")
1097     node_add_profile(gen, node, "mdsdev", mdd_uuid)
1098     net_uuid = get_net_uuid(lustre, node_name)
1099     if not net_uuid:
1100         error("NODE: ", node_name, "not found")
1101
1102     if lmv_name:
1103         mds.appendChild(gen.ref("lmv", lmv_uuid))
1104
1105     if fs_name != "":
1106         fs_uuid = name2uuid(lustre, fs_name, 'filesystem', fatal=1)
1107     else:
1108         fs_uuid = ""
1109     
1110     mdd = gen.mdsdev(mdd_name, mdd_uuid, fstype, devname,
1111                      get_format_flag(options), node_uuid, mds_uuid,
1112                      size, journal_size, inode_size, nspath, mkfsoptions, 
1113                      mountfsoptions, backfstype, backdevname,lmv_uuid, 
1114                      root_squash, no_root_squash, mds_sec, oss_sec, deny_sec, 
1115                      fs_uuid)
1116     lustre.appendChild(mdd)
1117
1118 def add_mgmt(gen, lustre, options):
1119     node_name = get_option(options, 'node')
1120     node_uuid = name2uuid(lustre, node_name, 'node')
1121     mgmt_name = get_option(options, 'mgmt')
1122     if not mgmt_name:
1123         mgmt_name = new_name('MGMT_' + node_name)
1124     mgmt_uuid = name2uuid(lustre, mgmt_name, 'mgmt', fatal=0)
1125     if not mgmt_uuid:
1126         mgmt_uuid = new_uuid(mgmt_name)
1127         mgmt = gen.mgmt(mgmt_name, mgmt_uuid, node_uuid)
1128         lustre.appendChild(mgmt)
1129     else:
1130         mgmt = lookup(lustre, mgmt_uuid)
1131
1132     node = findByName(lustre, node_name, "node")
1133     node_add_profile(gen, node, 'mgmt', mgmt_uuid)
1134
1135 def add_ost(gen, lustre, options):
1136     node_name = get_option(options, 'node')
1137     lovname = get_option(options, 'lov')
1138     osdtype = get_option(options, 'osdtype')
1139
1140     node_uuid = name2uuid(lustre, node_name, 'node')
1141
1142     if osdtype == 'obdecho':
1143         fstype = ''
1144         backfstype = ''
1145         devname = ''
1146         backdevname = ''
1147         size = 0
1148         journal_size = ''
1149         inode_size = ''
1150         mkfsoptions = ''
1151         mountfsoptions = ''
1152         deny_sec = ''
1153     else:
1154         devname = get_option(options, 'dev') # can be unset for bluearcs
1155         backdevname = get_option(options, 'backdev')
1156         size = get_option(options, 'size')
1157         fstype = get_option(options, 'fstype')
1158         backfstype = get_option(options, 'backfstype')
1159         journal_size = get_option(options, 'journal_size')
1160         inode_size = get_option(options, 'inode_size')
1161         mkfsoptions = get_option(options, 'mkfsoptions')
1162         mountfsoptions = get_option(options, 'mountfsoptions')
1163         deny_sec = get_option(options, 'ost_deny_sec')
1164
1165     fs_name = get_option(options, 'filesystem')
1166     nspath = get_option(options, 'nspath')
1167
1168     ostname = get_option(options, 'ost')
1169     if not ostname:
1170         ostname = new_name('OST_'+ node_name)
1171
1172     osdname = new_name("OSD_" + ostname + "_" + node_name)
1173     osd_uuid = new_uuid(osdname)
1174
1175     ost_uuid = name2uuid(lustre, ostname, 'ost', fatal=0)
1176     if not ost_uuid:
1177         ost_uuid = get_option(options, 'ostuuid')
1178         if ost_uuid:
1179             if lookup(lustre, ost_uuid):
1180                 error("Duplicate OST UUID:", ost_uuid)
1181         else:
1182             ost_uuid = new_uuid(ostname)
1183
1184         ost = gen.ost(ostname, ost_uuid, osd_uuid, options.group)
1185         lustre.appendChild(ost)
1186     else:
1187         ost = lookup(lustre, ost_uuid)
1188
1189     if lovname:
1190         lov = findByName(lustre, lovname, "lov")
1191         if not lov:
1192             error('add_ost:', '"'+lovname+'"', "lov element not found.")
1193         lov_add_obd(gen, lustre, lov, ost_uuid, options)
1194
1195     if options.failover:
1196         ost.setAttribute('failover', "1")
1197
1198     if fs_name != "":
1199         fs_uuid = name2uuid(lustre, fs_name, 'filesystem', fatal=1)
1200     else:
1201         fs_uuid = ""
1202         
1203     osd = gen.osd(osdname, osd_uuid, fstype, osdtype, devname,
1204                   get_format_flag(options), ost_uuid, node_uuid, size,
1205                   journal_size, inode_size, nspath, mkfsoptions, 
1206                   mountfsoptions, backfstype, backdevname, deny_sec, 
1207                   fs_uuid)
1208
1209     node = findByName(lustre, node_name, "node")
1210     node_add_profile(gen, node, 'osd', osd_uuid)
1211     lustre.appendChild(osd)
1212
1213 def del_ost(gen, lustre, options):
1214     ostname = get_option(options, 'ost')
1215     if not ostname:
1216         raise OptionError("del_ost: --ost requires a <ost name>")
1217     ost = findByName(lustre, ostname, "ost")
1218     if not ost:
1219         error('del_ost: ', 'Unable to find ', ostname)
1220     ost_uuid = name2uuid(lustre, ostname, fatal=0)
1221     if not ost_uuid:
1222         error('del_ost: ', 'Unable to find uuid for ', ostname)
1223     lovname = get_option(options, 'lov')
1224     if lovname:
1225         lov = findByName(lustre, lovname, "lov")
1226         if not lov:
1227             error('del_ost:', '"'+lovname+'"', "lov element not found.")
1228         lov_del_obd(gen, lustre, lov, ost_uuid, options)
1229         # if the user specified a speficic LOV don't delete the OST itself
1230         return
1231
1232     # remove OSD references from all LOVs
1233     for n in lustre.getElementsByTagName('lov'):
1234         lov_del_obd(gen, lustre, n, ost_uuid, options)
1235     if not options.migrate:
1236         return
1237     # delete the OSDs
1238     for osd in lustre.getElementsByTagName('osd'):
1239         if ref_exists(osd, ost_uuid):
1240             osd_uuid = osd.getAttribute('uuid')
1241             # delete all profile references to this OSD
1242             for profile in lustre.getElementsByTagName('profile'):
1243                 for osd_ref in profile.getElementsByTagName('osd_ref'):
1244                     if osd_uuid == osd_ref.getAttribute('uuidref'):
1245                         profile.removeChild(osd_ref)
1246             lustre.removeChild(osd)
1247
1248     # delete the OST
1249     lustre.removeChild(ost)
1250
1251 def add_cmobd(gen, lustre, options):
1252     node_name = get_option(options, 'node')
1253     name = get_option(options, 'cmobd')
1254     uuid = new_uuid(name)
1255
1256     master_name = get_option(options, 'master_obd')
1257     cache_name = get_option(options, 'cache_obd')
1258
1259     master_uuid = name2uuid(lustre, master_name, tag='lov', fatal=0)
1260     cache_uuid = name2uuid(lustre, cache_name, tag='lov', fatal=0)
1261
1262     if not master_uuid or not cache_uuid:
1263         if not master_uuid:
1264             master_uuid = name2uuid(lustre, master_name, tag='ost', fatal=0)
1265         if not cache_uuid:
1266             cache_uuid = name2uuid(lustre, cache_name, tag='ost', fatal=0)
1267
1268     if not master_uuid or not cache_uuid:
1269         if not master_uuid:
1270             master_uuid = name2uuid(lustre, master_name, tag='lmv', fatal=0)
1271         if not cache_uuid:
1272             cache_uuid = name2uuid(lustre, cache_name, tag='lmv', fatal=0)
1273
1274     if not master_uuid or not cache_uuid:
1275         if not master_uuid:
1276             master_uuid = name2uuid(lustre, master_name, tag='mds', fatal=0)
1277         if not cache_uuid:
1278             cache_uuid = name2uuid(lustre, cache_name, tag='mds', fatal=0)
1279
1280     if not master_uuid: 
1281         error("cannot find master_uuid by name '" + master_name + "'")
1282     if not cache_uuid: 
1283         error("cannot find cache_uuid by name '" + cache_name + "'")
1284
1285     node = findByName(lustre, node_name, "node")
1286     node_add_profile(gen, node, "cmobd", uuid)
1287
1288     master_node = lookup(lustre, master_uuid)
1289     cache_node = lookup(lustre, cache_uuid)
1290     if not master_node:
1291         error("cannot find master node by its uuid " + master_uuid);
1292     if not cache_node:
1293         error("cannot find cache node by its uuid " + cache_uuid);
1294
1295     active = master_node.getElementsByTagName('active_ref')
1296     if active:
1297         active_uuid = active[0].getAttribute('uuidref')
1298         active_node = lookup(lustre, active_uuid)
1299         if not active_node.getElementsByTagName('obdtype'):
1300             gen.addElement(active_node, 'obdtype', 'master')
1301
1302     active = cache_node.getElementsByTagName('active_ref')
1303     if active:
1304         active_uuid = active[0].getAttribute('uuidref')
1305         active_node = lookup(lustre, active_uuid)
1306         if not active_node.getElementsByTagName('obdtype'):
1307             gen.addElement(active_node, 'obdtype', 'cache')
1308
1309     cmobd = gen.cmobd(name, uuid, master_uuid, cache_uuid)
1310     lustre.appendChild(cmobd)
1311
1312 def add_cobd(gen, lustre, options):
1313     node_name = get_option(options, 'node')
1314     name = get_option(options, 'cobd')
1315     uuid = new_uuid(name)
1316
1317     master_name = get_option(options, 'master_obd')
1318     cache_name = get_option(options, 'cache_obd')
1319
1320     # init master
1321     master_uuid = name2uuid(lustre, master_name, tag='lov', fatal=0)
1322     if not master_uuid:
1323         master_uuid = name2uuid(lustre, master_name, tag='ost', fatal=0)
1324
1325     if master_uuid:
1326         node = lookup(lustre, master_uuid)
1327         rets = node.getElementsByTagName('lov_tgt')
1328         for ret in rets:
1329             ost_uuid = ret.getAttribute('uuidref')
1330             ost_node = lookup(lustre, ost_uuid)
1331             active = ost_node.getElementsByTagName('active_ref')
1332             if active:
1333                 osd_uuid = active[0].getAttribute('uuidref')
1334                 osd_node = lookup(lustre, osd_uuid)
1335                 if not osd_node.getElementsByTagName('obdtype'):
1336                     gen.addElement(osd_node, 'obdtype', 'master')
1337
1338     # init cache
1339     cache_uuid = name2uuid(lustre, cache_name, tag='lov', fatal=0)
1340     if not cache_uuid:
1341         cache_uuid = name2uuid(lustre, cache_name, tag='ost', fatal=0)
1342
1343     if cache_uuid:
1344         node = lookup(lustre, cache_uuid)
1345         rets = node.getElementsByTagName('lov_tgt')
1346         for ret in rets:
1347             ost_uuid = ret.getAttribute('uuidref')
1348             ost_node = lookup(lustre, ost_uuid)
1349             active = ost_node.getElementsByTagName('active_ref')
1350             if active:
1351                 osd_uuid = active[0].getAttribute('uuidref')
1352                 osd_node = lookup(lustre, osd_uuid)
1353                 if not osd_node.getElementsByTagName('obdtype'):
1354                     gen.addElement(osd_node, 'obdtype', 'cache')
1355
1356     if not master_uuid or not cache_uuid:
1357         master_uuid = name2uuid(lustre, master_name, tag='lmv', fatal=0)
1358         if not master_uuid:
1359             master_uuid = name2uuid(lustre, master_name, tag='mds', fatal=0)
1360             
1361         if master_uuid:
1362             mds_node = lookup(lustre, master_uuid)
1363             ret = mds_node.getElementsByTagName('active_ref')
1364             if ret:
1365                 mdsdev_uuid = ret[0].getAttribute('uuidref')
1366                 mdsdev_node = lookup(lustre, mdsdev_uuid)
1367                 if not mdsdev_node.getElementsByTagName('obdtype'):
1368                     gen.addElement(mdsdev_node, 'obdtype', 'master')
1369
1370         cache_uuid = name2uuid(lustre, cache_name, tag='lmv', fatal=0)
1371         if not cache_uuid:
1372             cache_uuid = name2uuid(lustre, cache_name, tag='mds', fatal=0)
1373             
1374         if cache_uuid:
1375             mds_node = lookup(lustre, cache_uuid)
1376             ret = mds_node.getElementsByTagName('active_ref')
1377             if ret:
1378                 mdsdev_uuid = ret[0].getAttribute('uuidref')
1379                 mdsdev_node = lookup(lustre, mdsdev_uuid)
1380                 if not mdsdev_node.getElementsByTagName('obdtype'):
1381                     gen.addElement(mdsdev_node, 'obdtype', 'cache')
1382
1383     if not master_uuid or not cache_uuid:
1384         panic("add_cobd", "cannot find master or cache by names '" + 
1385               master_name + "' and '" + cache_name + "'")
1386         
1387     node = findByName(lustre, node_name, "node")
1388     cobd = gen.cobd(name, uuid, master_uuid, cache_uuid)
1389     lustre.appendChild(cobd)
1390
1391 def add_echo_client(gen, lustre, options):
1392     """ add an echo client to the profile for this node. """
1393     node_name = get_option(options, 'node')
1394     lov_name = get_option(options, 'ost')
1395
1396     node = findByName(lustre, node_name, 'node')
1397
1398     echoname = new_name('ECHO_'+ node_name)
1399     echo_uuid = new_uuid(echoname)
1400     node_add_profile(gen, node, 'echoclient', echo_uuid)
1401
1402     lov_uuid = name2uuid(lustre, lov_name, tag='lov', fatal=0)
1403     if not lov_uuid:
1404         lov_uuid = name2uuid(lustre, lov_name, tag='ost', fatal=1)
1405
1406     echo = gen.echo_client(echoname, echo_uuid, lov_uuid)
1407     lustre.appendChild(echo)
1408
1409 def add_lov(gen, lustre, options):
1410     """ create a lov """
1411
1412     lov_orig = get_option(options, 'lov')
1413     name = new_name(lov_orig)
1414     if name != lov_orig:
1415         warning("name:", lov_orig, "already used. using:", name)
1416
1417     lmv_name = get_option(options, 'lmv')
1418     mds_name = get_option(options, 'mds')
1419     aware = get_option(options, 'aware')
1420     
1421     if not mds_name and not lmv_name:
1422         error("LOV: either MDS or LMV must be specified.");
1423     if mds_name and lmv_name:
1424         error("LOV: either MDS or LMV must be specified.");
1425     
1426     stripe_sz = get_option_int(options, 'stripe_sz')
1427     stripe_cnt = get_option_int(options, 'stripe_cnt')
1428     pattern = get_option_int(options, 'stripe_pattern')
1429     uuid = new_uuid(name)
1430
1431     ret = findByName(lustre, name, "lov")
1432     if ret:
1433         error("LOV: ", name, " already exists.")
1434
1435     if lmv_name:
1436         mds_uuid = name2uuid(lustre, lmv_name, 'lmv')
1437     else:
1438         mds_uuid = name2uuid(lustre, mds_name, 'mds')
1439
1440     lov = gen.lov(name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern)
1441     lustre.appendChild(lov)
1442
1443     # add an lovconfig entry to the active mdsdev profile
1444     lovconfig_name = new_name('LVCFG_' + name)
1445     lovconfig_uuid = new_uuid(lovconfig_name)
1446
1447     if mds_name:
1448         md_tgt = findByName(lustre, mds_name, "mds")
1449         if not md_tgt:
1450             error("can't find MDS '" + mds_name + "'")
1451     else:
1452         md_tgt = findByName(lustre, lmv_name, "lmv")
1453         if not md_tgt:
1454             error("can't find LMV '" + lmv_name + "'")
1455     
1456     md_tgt.appendChild(gen.ref("lovconfig", lovconfig_uuid))
1457     md_tgt.appendChild(gen.ref("client", uuid))
1458     
1459     # adding lovconfig and client to aware MD targets
1460     if aware:
1461         md_names = string.split(aware, ',');
1462         for md_name in md_names:
1463         
1464             md_tgt = findByName(lustre, md_name, "mds")
1465             if not md_tgt:
1466                 md_tgt = findByName(lustre, md_name, "lmv")
1467
1468             if not md_tgt:
1469                 error("can't find '" + mds_name + "'")
1470             
1471             md_tgt.appendChild(gen.ref("lovconfig", lovconfig_uuid))
1472             md_tgt.appendChild(gen.ref("client", uuid))
1473         
1474     lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid)
1475     lustre.appendChild(lovconfig)
1476
1477 def add_default_lov(gen, lustre, mds_name, lov_name):
1478     """ create a default lov """
1479
1480     stripe_sz = DEFAULT_STRIPE_SZ
1481     stripe_cnt = DEFAULT_STRIPE_CNT
1482     pattern = DEFAULT_STRIPE_PATTERN
1483     uuid = new_uuid(lov_name)
1484
1485     ret = findByName(lustre, lov_name, "lov")
1486     if ret:
1487         error("LOV: ", lov_name, " already exists.")
1488
1489     mds_uuid = name2uuid(lustre, mds_name, 'mds')
1490     lov = gen.lov(lov_name, uuid, mds_uuid, stripe_sz, stripe_cnt, pattern)
1491     lustre.appendChild(lov)
1492
1493     # add an lovconfig entry to the active mdsdev profile
1494     lovconfig_name = new_name('LVCFG_' + lov_name)
1495     lovconfig_uuid = new_uuid(lovconfig_name)
1496     mds = findByName(lustre, mds_name)
1497     mds.appendChild(gen.ref("lovconfig", lovconfig_uuid))
1498     lovconfig = gen.lovconfig(lovconfig_name, lovconfig_uuid, uuid)
1499     lustre.appendChild(lovconfig)
1500
1501 def add_lmv(gen, lustre, options):
1502     """ create a lmv """
1503
1504     lmv_orig = get_option(options, 'lmv')
1505     name = new_name(lmv_orig)
1506     if name != lmv_orig:
1507         warning("name:", lmv_orig, "already used. using:", name)
1508
1509     uuid = new_uuid(name)
1510     ret = findByName(lustre, name, "lmv")
1511     if ret:
1512         error("LMV: ", name, " already exists.")
1513
1514     lmv = gen.lmv(name, uuid)
1515     lustre.appendChild(lmv)
1516    
1517 def new_filesystem(gen, lustre, fs_name, mds_uuid, obd_uuid, 
1518                    mgmt_uuid, gks_uuid):
1519     fs_uuid = new_uuid(fs_name)
1520     fs = gen.filesystem(fs_name, fs_uuid, mds_uuid, obd_uuid, 
1521                         mgmt_uuid, gks_uuid)
1522     lustre.appendChild(fs)
1523     return fs_uuid
1524
1525 def get_fs_uuid(gen, lustre, fs_name, mds_name, obd_name, 
1526                 mgmt_name, gks_name):
1527     mds_uuid = name2uuid(lustre, mds_name, tag='mds', fatal=0)
1528     if not mds_uuid:
1529         mds_uuid = name2uuid(lustre, mds_name, tag='lmv', fatal=0)
1530     if not mds_uuid:
1531         mds_uuid = name2uuid(lustre, mds_name, tag='cobd', fatal=0)
1532     if not mds_uuid:
1533         error("mds '" + mds_name + "' is not found")
1534
1535     obd_uuid = name2uuid(lustre, obd_name, tag='ost', fatal=0)
1536     if not obd_uuid:
1537         obd_uuid = name2uuid(lustre, obd_name, tag='lov', fatal=0)
1538     if not obd_uuid:
1539         obd_uuid = name2uuid(lustre, obd_name, tag='cobd', fatal=0)
1540     if not obd_uuid:
1541         error("ost '" + obd_name + "' is not found")
1542         
1543     if mgmt_name:
1544         mgmt_uuid = name2uuid(lustre, mgmt_name, tag='mgmt', fatal=1)
1545     else:
1546         mgmt_uuid = ''
1547
1548     if gks_name:
1549         gks_uuid = name2uuid(lustre, gks_name, tag='gks', fatal=1)
1550     else: 
1551         gks_uuid = ''
1552         
1553     fs_uuid = lookup_filesystem(lustre, fs_name)
1554     if fs_uuid:
1555         fs = lookup(lustre, fs_uuid)
1556         if not ref_exists(fs, mds_uuid):
1557             fs.appendChild(gen.ref("mds", mds_uuid))
1558         if not ref_exists(fs, obd_uuid):
1559             fs.appendChild(gen.ref("obd", obd_uuid))
1560         if gks_uuid and not ref_exists(fs, gks_uuid):
1561             fs.appendChild(gen.ref("gks", gks_uuid))
1562     else:
1563         fs_uuid = new_filesystem(gen, lustre, fs_name, 
1564                                  mds_uuid, obd_uuid, 
1565                                  mgmt_uuid, gks_uuid)
1566     return fs_uuid
1567
1568 def add_filesystem(gen, lustre, options):
1569     """ create filesytem """
1570     fs_orig = get_option(options, 'filesystem')
1571     name = new_name(fs_orig)
1572     if name != fs_orig:
1573         warning("name:", fs_orig, "already used. using:", name)
1574
1575     uuid = new_uuid(name)
1576     ret = findByName(lustre, name, "filesystem")
1577     if ret:
1578         error("FS: ", name, " already exists.")
1579
1580     gks_name = get_option(options, 'gks')
1581     if gks_name:
1582         gks_uuid = name2uuid(lustre, gks_name, tag='gks', fatal=1)
1583     else: 
1584         gks_uuid = ''
1585     fs = gen.filesystem(name, uuid, "", "", "", gks_uuid)
1586     lustre.appendChild(fs)
1587     
1588 def add_mtpt(gen, lustre, options):
1589     """ create mtpt on a node """
1590     node_name = get_option(options, 'node')
1591
1592     path = get_option(options, 'path')
1593     clientoptions = get_option(options, "clientoptions")
1594     mds_sec = get_option(options, "mds_sec")
1595     oss_sec = get_option(options, "oss_sec")
1596     fs_name = get_option(options, 'filesystem')
1597
1598     lov_name = get_option(options, 'lov')
1599     ost_name = get_option(options, 'ost')
1600     mds_name = get_option(options, 'mds')
1601     gks_name = get_option(options, 'gks')
1602     if mds_name == '':
1603         mds_name = get_option(options, 'lmv')
1604         if mds_name == '':
1605             error("--add mtpt requires either --mds or --lmv.")
1606     if lov_name == '':
1607         if ost_name == '':
1608             error("--add mtpt requires --lov lov_name or --ost ost_name")
1609         else:
1610             warning("use default value for lov, due no --lov lov_name provided")
1611             lov_name = new_name("lov_default")
1612             add_default_lov(gen, lustre, mds_name, lov_name)
1613             ost_uuid = name2uuid(lustre, ost_name, 'ost', fatal=0)
1614             if not ost_uuid:
1615                 error('add_mtpt:', '"'+ost_name+'"', "ost element not found.")
1616             lov = findByName(lustre, lov_name, "lov")
1617             lov_add_obd(gen, lustre, lov, ost_uuid, options)
1618
1619     if fs_name == '':
1620         fs_name = new_name("FS_fsname")
1621         mgmt_name = get_option(options, 'mgmt')
1622     else:
1623         mgmt_name = ""
1624         
1625     fs_uuid = get_fs_uuid(gen, lustre, fs_name, 
1626                           mds_name, lov_name, mgmt_name, gks_name)
1627
1628     name = new_name('MNT_'+ node_name)
1629
1630     ret = findByName(lustre, name, "mountpoint")
1631     if ret:
1632         # this can't happen, because new_name creates unique names
1633         error("MOUNTPOINT: ", name, " already exists.")
1634
1635     uuid = new_uuid(name)
1636     mtpt = gen.mountpoint(name, uuid, fs_uuid, path, 
1637                           clientoptions, mds_sec, oss_sec)
1638     node = findByName(lustre, node_name, "node")
1639     if not node:
1640         error('node:',  node_name, "not found.")
1641     node_add_profile(gen, node, "mountpoint", uuid)
1642     lustre.appendChild(mtpt)
1643
1644 def commit_version(gen, lustre):
1645     update = findLastUpdate(lustre)
1646     if update:
1647         version = int(update.getAttribute("version")) + 1
1648     else:
1649         version = 1
1650
1651     new = gen.update(str(version))
1652     lustre.appendChild(new)
1653     
1654
1655 ############################################################
1656 # Command line processing
1657 #
1658 class OptionError (exceptions.Exception):
1659     def __init__(self, args):
1660         self.args = args
1661
1662 def get_option(options, tag):
1663     """Look for tag in options hash and return the value if set. If not
1664     set, then if return default it is set, otherwise exception."""
1665     if options.__getattr__(tag) != None:
1666         return options.__getattr__(tag)
1667     else:
1668         raise OptionError("--add %s requires --%s <value>" % (options.add, tag))
1669
1670 def get_option_int(options, tag):
1671     """Return an integer option.  Raise exception if the value is not an int"""
1672     val = get_option(options, tag)
1673     try:
1674         n = int(val)
1675     except ValueError:
1676         raise OptionError("--%s <num> (value must be integer)" % (tag))
1677     return n
1678
1679 # simple class for profiling
1680 import time
1681 class chrono:
1682     def __init__(self):
1683         self._start = 0
1684     def start(self):
1685         self._stop = 0
1686         self._start = time.time()
1687     def stop(self, msg=''):
1688         self._stop = time.time()
1689         if msg:
1690             self.display(msg)
1691     def dur(self):
1692         return self._stop - self._start
1693     def display(self, msg):
1694         d = self.dur()
1695         str = '%s: %g secs' % (msg, d)
1696         print str
1697
1698 #################################################################
1699 # function cmdlinesplit used to split cmd line from batch file
1700 #
1701 def cmdlinesplit(cmdline):
1702
1703     double_quote  = re.compile(r'"(([^"\\]|\\.)*)"')
1704     single_quote  = re.compile(r"'(.*?)'")
1705     escaped = re.compile(r'\\(.)')
1706     esc_quote = re.compile(r'\\([\\"])')
1707     outside = re.compile(r"""([^\s\\'"]+)""") #" fucking emacs.
1708
1709     arg_list = []
1710     i = 0; arg = None
1711     while i < len(cmdline):
1712         c = cmdline[i]
1713         if c == '"':
1714             match = double_quote.match(cmdline, i)
1715             if not match:
1716                 print "Unmatched double quote:", cmdline
1717                 sys.exit(1)
1718             i = match.end()
1719             if arg is None: arg = esc_quote.sub(r'\1', match.group(1))
1720             else:           arg = arg + esc_quote.sub(r'\1', match.group(1))
1721
1722         elif c == "'":
1723             match = single_quote.match(cmdline, i)
1724             if not match:
1725                 print "Unmatched single quote:", cmdline
1726                 sys.exit(1)
1727             i = match.end()
1728             if arg is None: arg = match.group(1)
1729             else:           arg = arg + match.group(1)
1730
1731         elif c == "\\":
1732             match = escaped.match(cmdline, i)
1733             if not match:
1734                 print "Unmatched backslash", cmdline
1735                 sys.exit(1)
1736             i = match.end()
1737             if arg is None: arg = match.group(1)
1738             else:           arg = arg + match.group(1)
1739
1740         elif c in string.whitespace:
1741             if arg != None:
1742                 arg_list.append(str(arg))
1743             arg = None
1744             while i < len(cmdline) and cmdline[i] in string.whitespace:
1745                 i = i + 1
1746         else:
1747             match = outside.match(cmdline, i)
1748             assert match
1749             i = match.end()
1750             if arg is None: arg = match.group()
1751             else:           arg = arg + match.group()
1752
1753     if arg != None: arg_list.append(str(arg))
1754
1755     return arg_list
1756
1757 ############################################################
1758 # Main
1759 #
1760
1761 def add(devtype, gen, lustre, options):
1762     if devtype == 'net':
1763         add_net(gen, lustre, options)
1764     elif devtype == 'mtpt':
1765         add_mtpt(gen, lustre, options)
1766     elif devtype == 'mds':
1767         add_mds(gen, lustre, options)
1768     elif devtype == 'ost':
1769         add_ost(gen, lustre, options)
1770     elif devtype == 'lov':
1771         add_lov(gen, lustre, options)
1772     elif devtype == 'route':
1773         add_route(gen, lustre, options)
1774     elif devtype == 'node':
1775         add_node(gen, lustre, options)
1776     elif devtype == 'echo_client':
1777         add_echo_client(gen, lustre, options)
1778     elif devtype == 'cobd':
1779         add_cobd(gen, lustre, options)
1780     elif devtype == 'cmobd':
1781         add_cmobd(gen, lustre, options)
1782     elif devtype == 'mgmt':
1783         add_mgmt(gen, lustre, options)
1784     elif devtype == 'lmv':
1785         add_lmv(gen, lustre, options)
1786     elif devtype == 'filesystem':
1787         add_filesystem(gen, lustre, options)
1788     elif devtype == 'gks':
1789         add_gks(gen, lustre, options)
1790     else:
1791         error("unknown device type:", devtype)
1792
1793 def delete(devtype, gen, lustre, options):
1794     if devtype == 'ost':
1795         del_ost(gen, lustre, options)
1796     elif options.delete:
1797         error("delete not supported for device type:", devtype)
1798     elif options.deactivate:
1799         error("deactivate not supported for device type:", devtype)
1800     else:
1801         error("in delete(), but neither .delete nor .deactivate are set.  Tell CFS.")
1802
1803 def commit(gen, lustre):
1804     commit_version(gen, lustre)
1805
1806 def do_command(gen, lustre, options, args):
1807     if options.add:
1808         add(options.add, gen, lustre, options)
1809     elif options.delete:
1810         delete(options.delete, gen, lustre, options)
1811     elif options.deactivate:
1812         delete(options.deactivate, gen, lustre, options)
1813     elif options.commit:
1814         commit(gen, lustre)
1815     else:
1816         error("Missing command")
1817
1818 def main():
1819     cl = Lustre.Options("lmc", "", lmc_options)
1820     try:
1821         options, args = cl.parse(sys.argv[1:])
1822     except Lustre.OptionError, e:
1823         panic("lmc", e)
1824
1825     if len(args) > 0:
1826         panic(string.join(sys.argv), "Unexpected extra arguments on command line: " + string.join(args))
1827
1828     if options.reference:
1829         reference()
1830         sys.exit(0)
1831
1832     outFile = '-'
1833
1834     if options.merge:
1835         outFile = options.merge
1836         if os.access(outFile, os.R_OK):
1837             doc = xml.dom.minidom.parse(outFile)
1838         else:
1839             doc = new_lustre(xml.dom.minidom)
1840     elif options.input:
1841         doc = xml.dom.minidom.parse(options.input)
1842     else:
1843         doc = new_lustre(xml.dom.minidom)
1844
1845     if options.output:
1846         outFile = options.output
1847
1848     lustre = doc.documentElement
1849     init_names(lustre)
1850     if lustre.tagName != "lustre":
1851         print "Existing config not valid."
1852         sys.exit(1)
1853
1854     gen = GenConfig(doc)
1855
1856     if options.batch:
1857         fp = open(options.batch)
1858         batchCommands = fp.readlines()
1859         fp.close()
1860         for cmd in batchCommands:
1861             try:
1862                 options, args = cl.parse(cmdlinesplit(cmd))
1863                 if options.merge or options.input or options.output:
1864                     print "The batchfile should not contain --merge, --input or --output."
1865                     sys.exit(1)
1866                 do_command(gen, lustre, options, args)
1867             except OptionError, e:
1868                 panic(cmd, e)
1869             except Lustre.OptionError, e:
1870                 panic(cmd, e)
1871     else:
1872         try:
1873             do_command(gen, lustre, options, args)
1874         except OptionError, e:
1875             panic(string.join(sys.argv),e)
1876         except Lustre.OptionError, e:
1877             panic("lmc", e)
1878
1879     if outFile == '-':
1880         printDoc(doc)
1881     else:
1882         printDoc(doc, open(outFile,"w"))
1883
1884 if __name__ == "__main__":
1885     main()