Whamcloud - gitweb
Fix some simple errors and warnings
[fs/lustre-release.git] / lustre / utils / lconf
1 #!/usr/bin/env python
2 #
3 #  Copyright (C) 2002 Cluster File Systems, Inc.
4 #   Author: Robert Read <rread@clusterfs.com>
5
6 #   This file is part of Lustre, http://www.lustre.org.
7 #
8 #   Lustre is free software; you can redistribute it and/or
9 #   modify it under the terms of version 2 of the GNU General Public
10 #   License as published by the Free Software Foundation.
11 #
12 #   Lustre is distributed in the hope that it will be useful,
13 #   but WITHOUT ANY WARRANTY; without even the implied warranty of
14 #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 #   GNU General Public License for more details.
16 #
17 #   You should have received a copy of the GNU General Public License
18 #   along with Lustre; if not, write to the Free Software
19 #   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #
21 # lconf - lustre configuration tool
22 #
23 # lconf is the main driver script for starting and stopping
24 # lustre filesystem services.
25 #
26 # Based in part on the XML obdctl modifications done by Brian Behlendorf 
27
28 import sys, getopt
29 import string, os, stat, popen2
30 import re, exceptions
31 import xml.dom.minidom
32
33 # Global parameters
34 TCP_ACCEPTOR = 'acceptor'
35 options = {}
36
37 #
38 # Maximum number of devices to search for.
39 # (the /dev/loop* nodes need to be created beforehand)
40 MAX_LOOP_DEVICES = 256
41
42
43 def usage():
44     print """usage: lconf config.xml
45
46 config.xml          Lustre configuration in xml format.
47 -v | --verbose      Print system commands as they are run
48 -d | --debug        Print system commands, but does not run them
49 --host <hostname>   Load config for <hostname>
50 --cleanup           Cleans up config. (Shutdown)
51 -h | --help         Print this help 
52 """
53     TODO = """
54 --ldap server       LDAP server with lustre config database
55 --reformat          Reformat all devices (will confirm)
56 --lustre="src dir"  Base directory of lustre sources. Used to search
57                     for modules.
58 --portals=src       Portals source 
59 --makeldiff         Translate xml source to LDIFF 
60 --iam myname        ??
61 """
62     sys.exit()
63
64 # ============================================================ 
65 # debugging and error funcs
66
67 def fixme(msg = "this feature"):
68     raise RuntimeError, msg + ' not implmemented yet.'
69
70 def panic(*args):
71     msg = string.join(map(str,args))
72     print msg
73     raise RuntimeError, msg
74
75 def log(*args):
76     msg = string.join(map(str,args))
77     print msg
78
79 def logall(msgs):
80     for s in msgs:
81         print string.strip(s)
82
83 def debug(*args):
84     msg = string.join(map(str,args))
85     if isverbose(): print msg
86
87 def isverbose():
88     return options.has_key('verbose') and  options['verbose'] == 1
89
90 def isnotouch():
91     return options.has_key('debug') and options['debug'] == 1
92
93 # ============================================================
94 # locally defined exceptions
95 class CommandError (exceptions.Exception):
96     def __init__(self, args=None):
97         self.args = args
98
99 # ============================================================
100 # handle lctl interface
101 class LCTLInterface:
102     """
103     Manage communication with lctl
104     """
105
106     def __init__(self, cmd):
107         """
108         Initialize close by finding the lctl binary.
109         """
110         syspath = string.split(os.environ['PATH'], ':')
111         syspath.insert(0, "../utils");
112         self.lctlcmd = None
113         for d in syspath:
114             lctl = os.path.join(d,cmd)
115             if os.access(lctl, os.X_OK):
116                 self.lctl = lctl
117                 break
118         if not self.lctl:
119             raise RuntimeError,  "unable to find lctl binary."
120             
121     def run(self, cmds):
122         """
123         run lctl
124         the cmds are written to stdin of lctl
125         lctl doesn't return errors when run in script mode, so
126         stderr is checked
127         should modify command line to accept multiple commands, or
128         create complex command line options
129         """
130         debug("+", self.lctl, cmds)
131         if isnotouch(): return ([], 0)
132         p = popen2.Popen3(self.lctl, 1)
133         p.tochild.write(cmds + "\n")
134         p.tochild.close()
135         out = p.fromchild.readlines()
136         ret = p.poll()
137         err = p.childerr.readlines()
138         if ret or len(err):
139             log (self.lctl, "error:", ret)
140             logall(err)
141             raise CommandError, err
142         return ret, out
143         
144         
145     # create a new device with lctl
146     def network(self, net, nid):
147         cmds =  """
148   network %s
149   mynid %s
150   quit""" % (net, nid)
151         self.run(cmds)
152
153     # create a new connection 
154     def connect(self, net, nid, port, servuuid):
155         cmds =  """
156   network %s
157   connect %s %d
158   add_uuid %s %s
159   quit""" % (net, nid, port,  servuuid, nid)
160         self.run(cmds)
161                 
162     # create a new device with lctl
163     def disconnect(self, net, nid, port, servuuid):
164         cmds =  """
165   network %s
166   disconnect %s 
167   quit""" % (net, nid)
168         self.run(cmds)
169
170     # create a new device with lctl
171     def newdev(self, attach, setup):
172         cmds = """
173   newdev
174   attach %s
175   setup %s
176   quit""" % (attach, setup)
177         self.run(cmds)
178
179     # cleanup a device
180     def cleanup(self, name, uuid):
181         cmds = """
182   device $%s
183   cleanup
184   detach
185   quit""" % (name)
186         self.run(cmds)
187
188     # create an lov
189     def lovconfig(self, uuid, mdcuuid, stripe_cnt, stripe_sz, pattern, devlist):
190         cmds = """
191   device $%s
192   probe
193   lovconfig %s %d %d %s %s
194   quit""" % (mdcuuid, uuid, stripe_cnt, stripe_sz, pattern, devlist)
195         self.run(cmds)
196
197 # ============================================================
198 # Various system-level functions
199 # (ideally moved to their own module)
200
201 # Run a command and return the output and status.
202 # stderr is sent to /dev/null, could use popen3 to
203 # save it if necessary
204 def run(*args):
205     cmd = string.join(map(str,args))
206     debug ("+", cmd)
207     if isnotouch(): return ([], 0)
208     f = os.popen(cmd + ' 2>&1')
209     out = f.readlines()
210     ret = f.close()
211     if ret:
212         ret = ret >> 8
213     else:
214         ret = 0
215     return (ret, out)
216
217
218 # is the path a block device?
219 def is_block(path):
220     s = ()
221     try:
222         s =  os.stat(path)
223     except OSError:
224         return 0
225     return stat.S_ISBLK(s[stat.ST_MODE])
226
227 # build fs according to type
228 # fixme: dangerous
229 def mkfs(fstype, dev):
230     if(fstype == 'ext3'):
231         mkfs = 'mkfs.ext2 -j -b 4096'
232     elif (fstype == 'extN'):
233         mkfs = 'mkfs.ext2 -j -b 4096'
234     else:
235         print 'unsupported fs type: ', fstype
236     if not is_block(dev):
237         force = '-F'
238     else:
239         force = ''
240     run (mkfs, force, dev)
241
242 # some systems use /dev/loopN, some /dev/loop/N
243 def loop_base():
244     import re
245     loop = '/dev/loop'
246     if not os.access(loop + str(0), os.R_OK):
247         loop = loop + '/'
248         if not os.access(loop + str(0), os.R_OK):
249             panic ("can't access loop devices")
250     return loop
251     
252 # find loop device assigned to thefile
253 def find_loop(file):
254     loop = loop_base()
255     for n in xrange(0, MAX_LOOP_DEVICES):
256         dev = loop + str(n)
257         if os.access(dev, os.R_OK):
258             (stat, out) = run('losetup', dev)
259             if (out and stat == 0):
260                 m = re.search(r'\((.*)\)', out[0])
261                 if m and file == m.group(1):
262                     return dev
263         else:
264             break
265     return ''
266
267 # create file if necessary and assign the first free loop device
268 def init_loop(file, size, fstype):
269     dev = find_loop(file)
270     if dev:
271         print 'WARNING file:', file, 'already mapped to', dev
272         return dev
273     if not os.access(file, os.R_OK | os.W_OK):
274         run("dd if=/dev/zero bs=1k count=0 seek=%d of=%s" %(size,  file))
275     loop = loop_base()
276     # find next free loop
277     for n in xrange(0, MAX_LOOP_DEVICES):
278         dev = loop + str(n)
279         if os.access(dev, os.R_OK):
280             (stat, out) = run('losetup', dev)
281             if (stat):
282                 run('losetup', dev, file)
283                 return dev
284         else:
285             print "out of loop devices"
286             return ''
287     print "out of loop devices"
288     return ''
289
290 # undo loop assignment
291 def clean_loop(file):
292     dev = find_loop(file)
293     if dev:
294         ret, out = run('losetup -d', dev)
295         if ret:
296             log('unable to clean loop device:', dev, 'for file:', file)
297             logall(out)
298
299 # initialize a block device if needed
300 def block_dev(dev, size, fstype, format):
301     if isnotouch(): return dev
302     if not is_block(dev):
303         dev = init_loop(dev, size, fstype)
304     if (format == 'yes'):
305         mkfs(fstype, dev)
306     return dev
307
308 # ============================================================
309 # Functions to prepare the various objects
310
311 def prepare_ldlm(node):
312     (name, uuid) = getNodeAttr(node)
313     print 'LDLM:', name, uuid
314     lctl.newdev(attach="ldlm %s %s" % (name, uuid),
315                 setup ="")
316     
317 def prepare_lov(node):
318     (name, uuid, mdcuuid, stripe_cnt, strip_sz, pattern, devlist, mdsname) = getLOVInfo(node)
319     print 'LOV:', name, uuid, mdcuuid, stripe_cnt, strip_sz, pattern, devlist, mdsname
320     lctl.lovconfig(uuid, mdsname, stripe_cnt, strip_sz, pattern, devlist)
321     lctl.newdev(attach="lov %s %s" % (name, uuid),
322                 setup ="%s" % (mdcuuid))
323
324 def prepare_network(node):
325     (name, uuid, type, nid, port) = getNetworkInfo(node)
326     print 'NETWORK:', name, uuid, type, nid, port
327     if type == 'tcp':
328         run(TCP_ACCEPTOR, port)
329     lctl.network(type, nid)
330
331
332 # need to check /proc/mounts and /etc/mtab before
333 # formatting anything.
334 # FIXME: check if device is already formatted.
335 def prepare_obd(obd):
336     (name, uuid, obdtype, dev, size, fstype, format) = getOBDInfo(obd)
337     print 'OBD:', name, uuid, obdtype, dev, size, fstype, format
338     dev = block_dev(dev, size, fstype, format)
339     lctl.newdev(attach="%s %s %s" % (obdtype, name, uuid),
340                 setup ="%s %s" %(dev, fstype))
341     
342
343 def prepare_ost(ost):
344     name, uuid, obd = getOSTInfo(ost)
345     print 'OST:', name, uuid, obd
346     lctl.newdev(attach="ost %s %s" % (name, uuid),
347                 setup ="$%s" % (obd))
348
349 def prepare_mds(node):
350     (name, uuid, dev, size, fstype, format) = getMDSInfo(node)
351     print 'MDS:', name, uuid, dev, size, fstype
352     # setup network for mds, too
353     dev = block_dev(dev, size, fstype, format)
354     lctl.newdev(attach="mds %s %s" % (name, uuid),
355                 setup ="%s %s" %(dev, fstype))
356
357 def prepare_osc(node):
358     (name, uuid, obduuid, ostuuid) = getOSCInfo(node)
359     print 'OSC:', name, uuid, obduuid, ostuuid
360     net = lookup(node.parentNode, ostuuid)
361     srvname, srvuuid, net, server, port = getNetworkInfo(net)
362     lctl.connect(net, server, port, ostuuid)
363     lctl.newdev(attach="osc %s %s" % (name, uuid),
364                 setup ="%s %s" %(obduuid, ostuuid))
365
366 def prepare_mdc(node):
367     (name, uuid, mdsuuid, netuuid) = getMDCInfo(node)
368     print 'MDC:', name, uuid, mdsuuid, netuuid
369     net = lookup(node.parentNode, netuuid)
370     srvname, srvuuid, net, server, port = getNetworkInfo(net)
371     lctl.connect(net, server, port, netuuid)
372     lctl.newdev(attach="mdc %s %s" % (name, uuid),
373                 setup ="%s %s" %(mdsuuid, netuuid))
374
375 def prepare_mountpoint(node):
376     name, uuid, oscuuid, mdcuuid, mtpt = getMTPTInfo(node)
377     print 'MTPT:', name, uuid, oscuuid, mdcuuid, mtpt
378     cmd = "echo mount -t lustre_lite -o ost=%s,mds=%s none %s" % \
379           (oscuuid, mdcuuid, mtpt)
380     run("mkdir", mtpt)
381     run(cmd)
382 # ============================================================
383 # Functions to cleanup the various objects
384
385 def cleanup_ldlm(node):
386     (name, uuid) = getNodeAttr(node)
387     print 'LDLM:', name, uuid
388     try:
389         lctl.cleanup(name, uuid)
390     except CommandError:
391         print "cleanup failed: ", name
392
393 def cleanup_lov(node):
394     (name, uuid, mdcuuid, stripe_cnt, strip_sz, pattern, devlist, mdsname) = getLOVInfo(node)
395     print 'LOV:', name, uuid, mdcuuid, stripe_cnt, strip_sz, pattern, devlist, mdsname
396     try:
397         lctl.cleanup(name, uuid)
398     except CommandError:
399         print "cleanup failed: ", name
400
401 def cleanup_network(node):
402     (name, uuid, type, nid, port) = getNetworkInfo(node)
403     print 'NETWORK:', name, uuid, type, nid, port
404     #lctl.network(type, nid)
405
406 # need to check /proc/mounts and /etc/mtab before
407 # formatting anything.
408 # FIXME: check if device is already formatted.
409 def cleanup_obd(obd):
410     (name, uuid, obdtype, dev, size, fstype, format) = getOBDInfo(obd)
411     print "OBD: ", name, obdtype, dev, size, fstype, format
412     try:
413         lctl.cleanup(name, uuid)
414     except CommandError:
415         print "cleanup failed: ", name
416     clean_loop(dev)
417
418 def cleanup_ost(ost):
419     name, uuid, obd = getOSTInfo(ost)
420     print "OST: ", name, uuid, obd
421     try:
422         lctl.cleanup(name, uuid)
423     except CommandError:
424         print "cleanup failed: ", name
425
426 def cleanup_mds(node):
427     (name, uuid, dev, size, fstype, format) = getMDSInfo(node)
428     print "MDS: ", name, dev, size, fstype
429     try:
430         lctl.cleanup(name, uuid)
431     except CommandError:
432         print "cleanup failed: ", name
433     clean_loop(dev)
434         
435
436 def cleanup_mdc(node):
437     (name, uuid, mdsuuid, netuuid) = getMDCInfo(node)
438     print 'MDC:', name, uuid, mdsuuid, netuuid
439     net = lookup(node.parentNode, netuuid)
440     srvname, srvuuid, net, server, port = getNetworkInfo(net)
441     try:
442         lctl.disconnect(net, server, port, netuuid)
443         lctl.cleanup(name, uuid)
444     except CommandError:
445         print "cleanup failed: ", name
446
447
448 def cleanup_osc(node):
449     (name, uuid, obduuid, ostuuid) = getOSCInfo(node)
450     print 'OSC:', name, uuid, obduuid, ostuuid
451     net = lookup(node.parentNode, ostuuid)
452     srvname, srvuuid, net, server, port = getNetworkInfo(net)
453     try:
454         lctl.disconnect(net, server, port, ostuuid)
455         lctl.cleanup(name, uuid)
456     except CommandError:
457         print "cleanup failed: ", name
458
459 def cleanup_mountpoint(node):
460     name, uuid, oscuuid, mdcuuid, mtpt = getMTPTInfo(node)
461     print 'MTPT:', name, uuid, oscuuid, mdcuuid, mtpt
462     run("umount", mtpt)
463
464 # ============================================================
465 # XML processing and query
466
467 def getDevice(obd):
468     dev = obd.getElementsByTagName('device')[0]
469     dev.normalize();
470     try:
471         size = int(dev.getAttribute('size'))
472     except ValueError:
473         size = 0
474     return dev.firstChild.data, size
475     
476
477 def getNetworkInfo(node):
478     name, uuid = getNodeAttr(node);
479     type = node.getAttribute('type')
480     nid = getText(node, 'server', "")
481     port = int(getText(node, 'port', 0))
482     return name, uuid, type, nid, port
483     
484 # extract device attributes for an obd
485 def getNodeAttr(node):
486     name = node.getAttribute('name')
487     uuid = node.getAttribute('uuid')
488     return name, uuid
489
490 def getOBDInfo(obd):
491     name, uuid = getNodeAttr(obd);
492     obdtype = obd.getAttribute('type')
493     devname, size = getDevice(obd)
494     fstype = getText(obd, 'fstype')
495     format = getText(obd, 'autoformat')
496     return (name, uuid, obdtype, devname, size, fstype, format)
497     
498 # extract LOV
499 def getLOVInfo(node):
500     name, uuid = getNodeAttr(node)
501     devs = node.getElementsByTagName('devices')[0]
502     stripe_sz = int(devs.getAttribute('stripesize'))
503     pattern = int(devs.getAttribute('pattern'))
504     mdcref =  node.getElementsByTagName('mdc_ref')[0]
505     mdcuuid = mdcref.getAttribute('uuidref')
506     mdc= lookup(node.parentNode, mdcuuid)
507     mdsref =  mdc.getElementsByTagName('mds_ref')[0]
508     mdsuuid = mdsref.getAttribute('uuidref')
509     mds= lookup(node.parentNode, mdsuuid)
510     mdsname = getName(mds)
511     devlist = ""
512     stripe_cnt = 0
513     for child in devs.childNodes:
514         if child.nodeName == 'osc_ref':
515             devlist = devlist +  child.getAttribute('uuidref') + " "
516             strip_cnt = stripe_cnt + 1
517     return (name, uuid, mdcuuid, stripe_cnt, stripe_sz, pattern, devlist, mdsname)
518     
519 # extract device attributes for an obd
520 def getMDSInfo(node):
521     name, uuid = getNodeAttr(node)
522     devname, size = getDevice(node)
523     fstype = getText(node, 'fstype')
524     format = getText(node, 'autoformat', "no")
525     return (name, uuid, devname, size, fstype, format)
526
527 # extract device attributes for an obd
528 def getMDCInfo(node):
529     name, uuid = getNodeAttr(node)
530     ref = node.getElementsByTagName('mds_ref')[0]
531     mdsuuid = ref.getAttribute('uuidref')
532     ref = node.getElementsByTagName('network_ref')[0]
533     netuuid = ref.getAttribute('uuidref')
534     return (name, uuid, mdsuuid, netuuid)
535
536     
537 # extract device attributes for an obd
538 def getOSTInfo(node):
539     name, uuid = getNodeAttr(node)
540     ref = node.getElementsByTagName('obd_ref')[0]
541     uuid = ref.getAttribute('uuidref')
542     obd = lookup(node.parentNode, uuid)
543     if obd:
544          obdname = getOBDInfo(obd)[0]
545     else:
546         obdname = "OBD NOT FOUND"
547     return (name, uuid, obdname)
548
549 # extract device attributes for an obd
550 def getOSCInfo(node):
551     name, uuid = getNodeAttr(node)
552     ref = node.getElementsByTagName('obd_ref')[0]
553     obduuid = ref.getAttribute('uuidref')
554     ref = node.getElementsByTagName('network_ref')[0]
555     ostuuid = ref.getAttribute('uuidref')
556     return (name, uuid, obduuid, ostuuid)
557
558 # extract device attributes for an obd
559 def getMTPTInfo(node):
560     name, uuid = getNodeAttr(node)
561     path = getText(node, 'path')
562     ref = node.getElementsByTagName('mdc_ref')[0]
563     mdcuuid = ref.getAttribute('uuidref')
564     ref = node.getElementsByTagName('osc_ref')[0]
565     lovuuid = ref.getAttribute('uuidref')
566     return (name, uuid, lovuuid, mdcuuid, path)
567
568     
569 # Get the text content from the first matching child
570 def getText(node, tag, default=""):
571     list = node.getElementsByTagName(tag)
572     if len(list) > 0:
573         node = list[0]
574         node.normalize()
575         return node.firstChild.data
576     else:
577         return default
578
579 # Recusively search from node for a uuid
580 def lookup(node, uuid):
581     for n in node.childNodes:
582         # this service_id check is ugly. need some other way to
583         # differentiate between definitions and references
584         if n.nodeType == n.ELEMENT_NODE:
585             if getUUID(n) == uuid:
586                 return n
587             else:
588                 n = lookup(n, uuid)
589                 if n: return n
590     return None
591
592 # Get name attribute of node
593 def getName(node):
594     return node.getAttribute('name')
595
596 def getRef(node):
597     return node.getAttribute('uuidref')
598
599 # Get name attribute of node
600 def getUUID(node):
601     return node.getAttribute('uuid')
602
603 # the tag name is the service type
604 # fixme: this should do some checks to make sure the node is a service
605 def getServiceType(node):
606     return node.nodeName
607
608 #
609 # determine what "level" a particular node is at.
610 # the order of iniitailization is based on level.  objects
611 # are assigned a level based on type:
612 #  net,devices,ldlm:1, obd, mdd:2  mds,ost:3 osc,mdc:4 mounts:5
613 def getServiceLevel(node):
614     type = getServiceType(node)
615     if type in ('network', 'device', 'ldlm'):
616         return 1
617     elif type in ('obd', 'mdd'):
618         return 2
619     elif type in ('mds','ost'):
620         return 3
621     elif type in ('mdc','osc'):
622         return 4
623     elif type in ('lov',):
624         return 5
625     elif type in ('mountpoint',):
626         return 6
627     return 0
628
629 #
630 # return list of services in a profile. list is a list of tuples
631 # [(level, node),]
632 def getServices(lustreNode, profileNode):
633     list = []
634     for n in profileNode.childNodes:
635         if n.nodeType == n.ELEMENT_NODE:
636             servNode = lookup(lustreNode, getRef(n))
637             if not servNode:
638                 panic('service not found: ' + getName(n))
639             level = getServiceLevel(servNode)
640             list.append((level, servNode))
641     list.sort()
642     return list
643
644 def getByName(lustreNode, tag, name):
645     ndList = lustreNode.getElementsByTagName(tag)
646     for nd in ndList:
647         if getName(nd) == name:
648             return nd
649     return None
650     
651
652 # ============================================================
653 # lconf type level logic
654 #
655
656 #
657 # Start a service.
658 def startService(node):
659     type = getServiceType(node)
660     debug('Starting service:', type, getName(node), getUUID(node))
661     # there must be a more dynamic way of doing this...
662     if type == 'ldlm':
663         prepare_ldlm(node)
664     elif type == 'lov':
665         prepare_lov(node)
666     elif type == 'network':
667         prepare_network(node)
668     elif type == 'obd':
669         prepare_obd(node)
670     elif type == 'ost':
671         prepare_ost(node)
672     elif type == 'mds':
673         prepare_mds(node)
674     elif type == 'osc':
675         prepare_osc(node)
676     elif type == 'mdc':
677         prepare_mdc(node)
678     elif type == 'mountpoint':
679         prepare_mountpoint(node)
680
681 #
682 # Prepare the system to run lustre using a particular profile
683 # in a the configuration. 
684 #  * load & the modules
685 #  * setup networking for the current node
686 #  * make sure partitions are in place and prepared
687 #  * initialize devices with lctl
688 # Levels is important, and needs to be enforced.
689 def startProfile(lustreNode, profileNode):
690     if not profileNode:
691         panic("profile:", profile, "not found.")
692     services = getServices(lustreNode, profileNode)
693     for s in services:
694         startService(s[1])
695
696
697 # Stop a service.
698 def stopService(node):
699     type = getServiceType(node)
700     debug('Stopping service:', type, getName(node), getUUID(node))
701     # there must be a more dynamic way of doing this...
702     if type == 'ldlm':
703         cleanup_ldlm(node)
704     elif type == 'lov':
705         cleanup_lov(node)
706     elif type == 'network':
707         cleanup_network(node)
708     elif type == 'obd':
709         cleanup_obd(node)
710     elif type == 'ost':
711         cleanup_ost(node)
712     elif type == 'mds':
713         cleanup_mds(node)
714     elif type == 'osc':
715         cleanup_osc(node)
716     elif type == 'mdc':
717         cleanup_mdc(node)
718     elif type == 'mountpoint':
719         cleanup_mountpoint(node)
720
721 # Shutdown services in reverse order than they were started
722 def cleanupProfile(lustreNode, profileNode):
723     if not profileNode:
724         panic("profile:", profile, "not found.")
725     services = getServices(lustreNode, profileNode)
726     services.reverse()
727     for s in services:
728         stopService(s[1])
729
730
731 #
732 # Load profile for 
733 def doHost(lustreNode, hosts, cleanFlag):
734     for h in hosts:
735         node = getByName(lustreNode, 'node', h)
736         if node:
737             break
738         
739     reflist = node.getElementsByTagName('profile_ref')
740     for r in reflist:
741         if cleanFlag:
742             cleanupProfile(lustreNode, lookup(lustreNode, getRef(r)))
743         else:
744             startProfile(lustreNode,  lookup(lustreNode, getRef(r)))
745
746 #
747 # Command line processing
748 #
749 def parse_cmdline(argv):
750     short_opts = "hdv"
751     long_opts = ["ldap", "reformat", "lustre=",
752                  "portals=", "makeldiff", "cleanup", "iam=",
753                  "help", "debug", "host="]
754     opts = []
755     args = []
756     global options
757     try:
758         opts, args = getopt.getopt(argv, short_opts, long_opts)
759     except getopt.GetoptError:
760         print "invalid opt"
761         usage()
762
763     for o, a in opts:
764         if o in ("-h", "--help"):
765             usage()
766         if o == "--cleanup":
767             options['cleanup'] = 1
768         if o in ("-v", "--verbose"):
769             options['verbose'] = 1
770         if o in ("-d", "--debug"):
771             options['debug'] = 1
772             options['verbose'] = 1
773         if o == "--portals":
774             options['portals'] = a
775         if o == "--lustre":
776             options['lustre'] = a
777         if o  == "--reformat":
778             options['reformat'] = 1
779         if o  == "--host":
780             options['hostname'] = [a]
781     return args
782
783 #
784 # Initialize or shutdown lustre according to a configuration file
785 #   * prepare the system for lustre
786 #   * configure devices with lctl
787 # Shutdown does steps in reverse
788 #
789 lctl = LCTLInterface('lctl')
790 def main():
791     global options
792     args = parse_cmdline(sys.argv[1:])
793     if len(args) > 0:
794         dom = xml.dom.minidom.parse(args[0])
795     else:
796         usage()
797
798     if not options.has_key('hostname'):
799         ret, host = run('hostname')
800         if ret:
801             print "unable to determine hostname"
802         else:
803             options['hostname'] = [host]
804         options['hostname'].append('localhost')
805     doHost(dom.childNodes[0], options['hostname'], options.has_key('cleanup') )
806
807 if __name__ == "__main__":
808     main()
809
810