Whamcloud - gitweb
- allow lconf to continue to run in debug mode even if acceptor and lctl
[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, socket
30 import re, exceptions
31 import xml.dom.minidom
32
33 # Global parameters
34 TCP_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 --get <url>         URL to fetch a config file
48 -v | --verbose      Print system commands as they are run
49 -d | --debug        Print system commands, but does not run them
50 --host <hostname>   Load config for <hostname>
51 --cleanup           Cleans up config. (Shutdown)
52 -h | --help         Print this help 
53 """
54     TODO = """
55 --ldap server       LDAP server with lustre config database
56 --reformat          Reformat all devices (will confirm)
57 --lustre="src dir"  Base directory of lustre sources. Used to search
58                     for modules.
59 --portals=src       Portals source 
60 --makeldiff         Translate xml source to LDIFF 
61 --iam myname        ??
62 """
63     sys.exit()
64
65 # ============================================================ 
66 # debugging and error funcs
67
68 def fixme(msg = "this feature"):
69     raise RuntimeError, msg + ' not implmemented yet.'
70
71 def panic(*args):
72     msg = string.join(map(str,args))
73     print msg
74     raise RuntimeError, msg
75
76 def log(*args):
77     msg = string.join(map(str,args))
78     print msg
79
80 def logall(msgs):
81     for s in msgs:
82         print string.strip(s)
83
84 def debug(*args):
85     msg = string.join(map(str,args))
86     if isverbose(): print msg
87
88 def isverbose():
89     return options.has_key('verbose') and  options['verbose'] == 1
90
91 def isnotouch():
92     return options.has_key('debug') and options['debug'] == 1
93
94 # ============================================================
95 # locally defined exceptions
96 class CommandError (exceptions.Exception):
97     def __init__(self, args=None):
98         self.args = args
99
100 # ============================================================
101 # handle lctl interface
102 class LCTLInterface:
103     """
104     Manage communication with lctl
105     """
106
107     def __init__(self, cmd):
108         """
109         Initialize close by finding the lctl binary.
110         """
111         self.lctl = find_prog(cmd)
112         if not self.lctl:
113             if isnotouch():
114                 debug('! lctl not found')
115                 self.lctl = 'lctl'
116             else:
117                 raise CommandError,  "unable to find lctl binary."
118             
119     def run(self, cmds):
120         """
121         run lctl
122         the cmds are written to stdin of lctl
123         lctl doesn't return errors when run in script mode, so
124         stderr is checked
125         should modify command line to accept multiple commands, or
126         create complex command line options
127         """
128         debug("+", self.lctl, cmds)
129         if isnotouch(): return ([], 0)
130         p = popen2.Popen3(self.lctl, 1)
131         p.tochild.write(cmds + "\n")
132         p.tochild.close()
133         out = p.fromchild.readlines()
134         ret = p.poll()
135         for l in out:
136             debug('lctl:',string.strip(l))
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     def network(self, net, nid):
145         """ initialized network and add "self" """
146         # Idea: "mynid" could be used for all network types to add "self," and then
147         # this special case would be gone and the "self" hack would be hidden.
148         if net  == 'tcp':
149             cmds =  """
150   network %s
151   mynid %s
152   add_uuid self %s
153   quit""" % (net, nid, nid)
154         else:
155             cmds =  """
156   network %s
157   add_uuid self %s
158   quit""" % (net, nid)
159             
160         self.run(cmds)
161
162     # create a new connection 
163     def connect(self, net, nid, port, servuuid, send_buf, read_buf):
164         # XXX: buf size params not used yet
165         cmds =  """
166   network %s
167   connect %s %d
168   add_uuid %s %s
169   quit""" % (net, nid, port,  servuuid, nid)
170         self.run(cmds)
171                 
172     # create a new connection 
173     def add_route(self, net, to, via):
174         cmds =  """
175         """ 
176         #self.run(cmds)
177
178     # create a new device with lctl
179     def disconnect(self, net, nid, port, servuuid):
180         cmds =  """
181   network %s
182   disconnect %s 
183   quit""" % (net, nid)
184         self.run(cmds)
185
186     # create a new device with lctl
187     def newdev(self, attach, setup = ""):
188         cmds = """
189   newdev
190   attach %s
191   setup %s
192   quit""" % (attach, setup)
193         self.run(cmds)
194
195     # cleanup a device
196     def cleanup(self, name, uuid):
197         cmds = """
198   device $%s
199   cleanup
200   detach
201   quit""" % (name)
202         self.run(cmds)
203
204     # create an lov
205     def lovconfig(self, uuid, mdsuuid, stripe_cnt, stripe_sz, stripe_off, pattern, devlist):
206         cmds = """
207   device $%s
208   probe
209   lovconfig %s %d %d %d %s %s
210   quit""" % (mdsuuid, uuid, stripe_cnt, stripe_sz, stripe_off, pattern, devlist)
211         self.run(cmds)
212
213 # ============================================================
214 # Various system-level functions
215 # (ideally moved to their own module)
216
217 # Run a command and return the output and status.
218 # stderr is sent to /dev/null, could use popen3 to
219 # save it if necessary
220 def run(*args):
221     cmd = string.join(map(str,args))
222     debug ("+", cmd)
223     if isnotouch(): return (0, [])
224     f = os.popen(cmd + ' 2>&1')
225     out = f.readlines()
226     ret = f.close()
227     if ret:
228         ret = ret >> 8
229     else:
230         ret = 0
231     return (ret, out)
232
233 # Run a command in the background.
234 def run_daemon(*args):
235     cmd = string.join(map(str,args))
236     debug ("+", cmd)
237     if isnotouch(): return 0
238     f = os.popen(cmd + ' 2>&1')
239     ret = f.close()
240     if ret:
241         ret = ret >> 8
242     else:
243         ret = 0
244     return ret
245
246
247 # Determine full path to use for an external command
248 # searches dirname(argv[0]) first, then PATH
249 def find_prog(cmd):
250     syspath = string.split(os.environ['PATH'], ':')
251     cmdpath = os.path.dirname(sys.argv[0])
252     syspath.insert(0, cmdpath);
253     syspath.insert(0, os.path.join(cmdpath, '../../portals/linux/utils/'))
254     for d in syspath:
255         prog = os.path.join(d,cmd)
256         if os.access(prog, os.X_OK):
257             return prog
258     return ''
259
260
261 # is the path a block device?
262 def is_block(path):
263     s = ()
264     try:
265         s =  os.stat(path)
266     except OSError:
267         return 0
268     return stat.S_ISBLK(s[stat.ST_MODE])
269
270 # build fs according to type
271 # fixme: dangerous
272 def mkfs(fstype, dev):
273     if(fstype in ('ext3', 'extN')):
274         mkfs = 'mkfs.ext2 -j -b 4096'
275     else:
276         print 'unsupported fs type: ', fstype
277     if not is_block(dev):
278         force = '-F'
279     else:
280         force = ''
281     (ret, out) = run (mkfs, force, dev)
282     if ret:
283         panic("Unable to build fs:", dev)
284     # enable hash tree indexing on fs
285     if fstype == 'extN':
286         htree = 'echo "feature FEATURE_C5" | debugfs -w'
287         (ret, out) = run (htree, dev)
288         if ret:
289             panic("Unable to enable htree:", dev)
290
291 # some systems use /dev/loopN, some /dev/loop/N
292 def loop_base():
293     import re
294     loop = '/dev/loop'
295     if not os.access(loop + str(0), os.R_OK):
296         loop = loop + '/'
297         if not os.access(loop + str(0), os.R_OK):
298             panic ("can't access loop devices")
299     return loop
300     
301 # find loop device assigned to thefile
302 def find_loop(file):
303     loop = loop_base()
304     for n in xrange(0, MAX_LOOP_DEVICES):
305         dev = loop + str(n)
306         if os.access(dev, os.R_OK):
307             (stat, out) = run('losetup', dev)
308             if (out and stat == 0):
309                 m = re.search(r'\((.*)\)', out[0])
310                 if m and file == m.group(1):
311                     return dev
312         else:
313             break
314     return ''
315
316 # create file if necessary and assign the first free loop device
317 def init_loop(file, size, fstype):
318     dev = find_loop(file)
319     if dev:
320         print 'WARNING file:', file, 'already mapped to', dev
321         return dev
322     if not os.access(file, os.R_OK | os.W_OK):
323         run("dd if=/dev/zero bs=1k count=0 seek=%d of=%s" %(size,  file))
324     loop = loop_base()
325     # find next free loop
326     for n in xrange(0, MAX_LOOP_DEVICES):
327         dev = loop + str(n)
328         if os.access(dev, os.R_OK):
329             (stat, out) = run('losetup', dev)
330             if (stat):
331                 run('losetup', dev, file)
332                 return dev
333         else:
334             print "out of loop devices"
335             return ''
336     print "out of loop devices"
337     return ''
338
339 # undo loop assignment
340 def clean_loop(file):
341     dev = find_loop(file)
342     if dev:
343         ret, out = run('losetup -d', dev)
344         if ret:
345             log('unable to clean loop device:', dev, 'for file:', file)
346             logall(out)
347
348 # initialize a block device if needed
349 def block_dev(dev, size, fstype, format):
350     if isnotouch(): return dev
351     if not is_block(dev):
352         dev = init_loop(dev, size, fstype)
353     if (format == 'yes'):
354         mkfs(fstype, dev)
355     return dev
356
357 # ============================================================
358 # Classes to prepare and cleanup the various objects
359 #
360 class Module:
361     """ Base class for the rest of the modules. The default cleanup method is
362     defined here, as well as some utilitiy funcs.
363     """
364     def __init__(self, tag_name, node):
365         self.dom_node = node
366         self.tag_name = tag_name
367         self.name = node.getAttribute('name')
368         self.uuid = node.getAttribute('uuid')
369
370     def info(self, *args):
371         msg = string.join(map(str,args))
372         print self.tag_name + ":", self.name, self.uuid, msg
373
374     def cleanup(self):
375         """ default cleanup, used for most modules """
376         self.info()
377         try:
378             lctl.cleanup(self.name, self.uuid)
379         except CommandError:
380             print "cleanup failed: ", self.name
381
382 class Network(Module):
383     def __init__(self,node):
384         Module.__init__(self, 'NETWORK', node)
385         self.net_type = node.getAttribute('type')
386         self.nid = getText(node, 'server', "")
387         self.port = int(getText(node, 'port', 0))
388         self.send_buf = int(getText(node, 'send_buf', 0))
389         self.read_buf = int(getText(node, 'read_buf', 0))
390
391     def prepare(self):
392         self.info(self.net_type, self.nid, self.port)
393         if self.net_type == 'tcp':
394             ret = run_daemon(TCP_ACCEPTOR, self.port)
395             if ret:
396                 print "error:", ret
397                 raise CommandError, "cannot run acceptor"
398         lctl.network(self.net_type, self.nid)
399         lctl.newdev(attach = "ptlrpc RPCDEV")
400
401     def cleanup(self):
402         self.info(self.net_type, self.nid, self.port)
403         try:
404             lctl.cleanup("RPCDEV", "")
405         except CommandError:
406             print "cleanup failed: ", self.name
407         if self.net_type == 'tcp':
408             # yikes, this ugly! need to save pid in /var/something
409             run("killall acceptor")
410
411 class LDLM(Module):
412     def __init__(self,node):
413         Module.__init__(self, 'LDLM', node)
414     def prepare(self):
415         self.info()
416         lctl.newdev(attach="ldlm %s %s" % (self.name, self.uuid),
417                     setup ="")
418
419 class LOV(Module):
420     def __init__(self,node):
421         Module.__init__(self, 'LOV', node)
422         devs = node.getElementsByTagName('devices')[0]
423         self.stripe_sz = int(devs.getAttribute('stripesize'))
424         self.stripe_off = int(devs.getAttribute('stripeoffset'))
425         self.pattern = int(devs.getAttribute('pattern'))
426         mdsref =  node.getElementsByTagName('mds_ref')[0]
427         self.mdsuuid = mdsref.getAttribute('uuidref')
428         mds= lookup(node.parentNode, self.mdsuuid)
429         self.mdsname = getName(mds)
430         devlist = ""
431         stripe_cnt = 0
432         for child in devs.childNodes:
433             if child.nodeName == 'osc_ref':
434                 devlist = devlist +  child.getAttribute('uuidref') + " "
435                 stripe_cnt = stripe_cnt + 1
436         self.devlist = devlist
437         self.stripe_cnt = stripe_cnt
438
439     def prepare(self):
440         self.info(self.mdsuuid, self.stripe_cnt, self.stripe_sz, self.stripe_off, self.pattern,
441         self.devlist, self.mdsname)
442         lctl.lovconfig(self.uuid, self.mdsname, self.stripe_cnt,
443                        self.stripe_sz, self.stripe_off, self.pattern,
444                        self.devlist)
445
446     def cleanup(self):
447         pass
448
449 class MDS(Module):
450     def __init__(self,node):
451         Module.__init__(self, 'MDS', node)
452         self.devname, self.size = getDevice(node)
453         self.fstype = getText(node, 'fstype')
454         self.format = getText(node, 'autoformat', "no")
455
456     def prepare(self):
457         self.info(self.devname, self.fstype, self.format)
458         blkdev = block_dev(self.devname, self.size, self.fstype, self.format)
459         lctl.newdev(attach="mds %s %s" % (self.name, self.uuid),
460                     setup ="%s %s" %(blkdev, self.fstype))
461     def cleanup(self):
462         Module.cleanup(self)
463         clean_loop(self.devname)
464
465 class MDC(Module):
466     def __init__(self,node):
467         Module.__init__(self, 'MDC', node)
468         ref = node.getElementsByTagName('mds_ref')[0]
469         self.mds_uuid = ref.getAttribute('uuidref')
470
471     def prepare(self):
472         self.info(self.mds_uuid)
473         mds = lookup(self.dom_node.parentNode, self.mds_uuid)
474         if mds == None:
475             panic(self.mdsuuid, "not found.")
476         net = get_ost_net(self.dom_node.parentNode, self.mds_uuid)
477         srv = Network(net)
478         lctl.connect(srv.net_type, srv.nid, srv.port, srv.uuid, srv.send_buf, srv.read_buf)
479         lctl.newdev(attach="mdc %s %s" % (self.name, self.uuid),
480                         setup ="%s %s" %(self.mds_uuid, srv.uuid))
481             
482     def cleanup(self):
483         self.info(self.mds_uuid)
484         net = get_ost_net(self.dom_node.parentNode, self.mds_uuid)
485         srv = Network(net)
486         try:
487             lctl.disconnect(srv.net_type, srv.nid, srv.port, srv.uuid)
488             lctl.cleanup(self.name, self.uuid)
489         except CommandError:
490             print "cleanup failed: ", self.name
491
492 class OBD(Module):
493     def __init__(self, node):
494         Module.__init__(self, 'OBD', node)
495         self.obdtype = node.getAttribute('type')
496         self.devname, self.size = getDevice(node)
497         self.fstype = getText(node, 'fstype')
498         self.format = getText(node, 'autoformat', 'yes')
499
500     # need to check /proc/mounts and /etc/mtab before
501     # formatting anything.
502     # FIXME: check if device is already formatted.
503     def prepare(self):
504         self.info(self.obdtype, self.devname, self.size, self.fstype, self.format)
505         blkdev = block_dev(self.devname, self.size, self.fstype, self.format)
506         lctl.newdev(attach="%s %s %s" % (self.obdtype, self.name, self.uuid),
507                     setup ="%s %s" %(blkdev, self.fstype))
508     def cleanup(self):
509         Module.cleanup(self)
510         clean_loop(self.devname)
511
512 class OST(Module):
513     def __init__(self,node):
514         Module.__init__(self, 'OST', node)
515         ref = node.getElementsByTagName('obd_ref')[0]
516         self.obd_uuid = ref.getAttribute('uuidref')
517
518     def prepare(self):
519         self.info(self.obd_uuid)
520         lctl.newdev(attach="ost %s %s" % (self.name, self.uuid),
521                     setup ="%s" % (self.obd_uuid))
522
523 class OSC(Module):
524     def __init__(self,node):
525         Module.__init__(self, 'OSC', node)
526         ref = node.getElementsByTagName('obd_ref')[0]
527         self.obd_uuid = ref.getAttribute('uuidref')
528         ref = node.getElementsByTagName('ost_ref')[0]
529         self.ost_uuid = ref.getAttribute('uuidref')
530
531     def prepare(self):
532         self.info(self.obd_uuid, self.ost_uuid)
533         net = get_ost_net(self.dom_node.parentNode, self.ost_uuid)
534         srv = Network(net)
535         lctl.connect(srv.net_type, srv.nid, srv.port, srv.uuid, srv.send_buf, srv.read_buf)
536         lctl.newdev(attach="osc %s %s" % (self.name, self.uuid),
537                     setup ="%s %s" %(self.obd_uuid, srv.uuid))
538
539     def cleanup(self):
540         self.info(self.obd_uuid, self.ost_uuid)
541         net_uuid = get_ost_net(self.dom_node.parentNode, self.ost_uuid)
542         srv = Network(net)
543         try:
544             lctl.disconnect(srv.net_type, srv.nid, srv.port, srv.uuid)
545             lctl.cleanup(self.name, self.uuid)
546         except CommandError:
547             print "cleanup failed: ", self.name
548
549 class Mountpoint(Module):
550     def __init__(self,node):
551         Module.__init__(self, 'MTPT', node)
552         self.path = getText(node, 'path')
553         ref = node.getElementsByTagName('mdc_ref')[0]
554         self.mdc_uuid = ref.getAttribute('uuidref')
555         ref = node.getElementsByTagName('osc_ref')[0]
556         self.lov_uuid = ref.getAttribute('uuidref')
557
558     def prepare(self):
559         l = lookup(self.dom_node.parentNode, self.lov_uuid)
560         if l.nodeName == 'lov':
561             dev = LOV(l)
562             for osc_uuid in string.split(dev.devlist):
563                 osc = lookup(self.dom_node.parentNode, osc_uuid)
564                 if osc:
565                     n = OSC(osc)
566                     n.prepare()
567                 else:
568                     panic('osc not found:', osc_uuid)
569         else:
570             dev = OSC(l)
571             dev.prepare()
572             
573         self.info(self.path, self.mdc_uuid,self.lov_uuid)
574         lctl.newdev(attach="lov %s %s" % (dev.name, dev.uuid),
575                     setup ="%s" % (self.mdc_uuid))
576         cmd = "mount -t lustre_lite -o osc=%s,mdc=%s none %s" % \
577               (self.lov_uuid, self.mdc_uuid, self.path)
578         run("mkdir", self.path)
579         ret, val = run(cmd)
580         if ret:
581             panic("mount failed:", self.path)
582     def cleanup(self):
583         self.info(self.path, self.mdc_uuid,self.lov_uuid)
584         run("umount", self.path)
585
586 # ============================================================
587 # XML processing and query
588 # TODO: Change query funcs to use XPath, which is muc cleaner
589
590 def getDevice(obd):
591     dev = obd.getElementsByTagName('device')[0]
592     dev.normalize();
593     try:
594         size = int(dev.getAttribute('size'))
595     except ValueError:
596         size = 0
597     return dev.firstChild.data, size
598
599 # Get the text content from the first matching child
600 def getText(node, tag, default=""):
601     list = node.getElementsByTagName(tag)
602     if len(list) > 0:
603         node = list[0]
604         node.normalize()
605         return node.firstChild.data
606     else:
607         return default
608
609 def get_ost_net(node, uuid):
610     ost = lookup(node, uuid)
611     list = ost.getElementsByTagName('network_ref')
612     if list:
613         uuid = list[0].getAttribute('uuidref')
614     else:
615         return None
616     return lookup(node, uuid)
617     
618 def lookup(node, uuid):
619     for n in node.childNodes:
620         if n.nodeType == n.ELEMENT_NODE:
621             if getUUID(n) == uuid:
622                 return n
623             else:
624                 n = lookup(n, uuid)
625                 if n: return n
626     return None
627             
628 # Get name attribute of node
629 def getName(node):
630     return node.getAttribute('name')
631
632 def getRef(node):
633     return node.getAttribute('uuidref')
634
635 # Get name attribute of node
636 def getUUID(node):
637     return node.getAttribute('uuid')
638
639 # the tag name is the service type
640 # fixme: this should do some checks to make sure the node is a service
641 def getServiceType(node):
642     return node.nodeName
643
644 #
645 # determine what "level" a particular node is at.
646 # the order of iniitailization is based on level.  objects
647 # are assigned a level based on type:
648 #  net,devices,ldlm:1, obd, mdd:2  mds,ost:3 osc,mdc:4 mounts:5
649 def getServiceLevel(node):
650     type = getServiceType(node)
651     if type in ('network',):
652         return 1
653     if type in ('device', 'ldlm'):
654         return 2
655     elif type in ('obd', 'mdd'):
656         return 3
657     elif type in ('mds','ost'):
658         return 4
659     elif type in ('mdc','osc'):
660         return 5
661     elif type in ('lov',):
662         return 6
663     elif type in ('mountpoint',):
664         return 7
665     return 0
666
667 #
668 # return list of services in a profile. list is a list of tuples
669 # [(level, node),]
670 def getServices(lustreNode, profileNode):
671     list = []
672     for n in profileNode.childNodes:
673         if n.nodeType == n.ELEMENT_NODE:
674             servNode = lookup(lustreNode, getRef(n))
675             if not servNode:
676                 print n
677                 panic('service not found: ' + getRef(n))
678             level = getServiceLevel(servNode)
679             list.append((level, servNode))
680     list.sort()
681     return list
682
683 def getByName(lustreNode, tag, name):
684     ndList = lustreNode.getElementsByTagName(tag)
685     for nd in ndList:
686         if getName(nd) == name:
687             return nd
688     return None
689     
690
691 # ============================================================
692 # lconf level logic
693 # Start a service.
694 def startService(node, cleanFlag):
695     type = getServiceType(node)
696     debug('Starting service:', type, getName(node), getUUID(node))
697     # there must be a more dynamic way of doing this...
698     n = None
699     if type == 'ldlm':
700         n = LDLM(node)
701     elif type == 'lov':
702         n = LOV(node)
703     elif type == 'network':
704         n = Network(node)
705     elif type == 'obd':
706         n = OBD(node)
707     elif type == 'ost':
708         n = OST(node)
709     elif type == 'mds':
710         n = MDS(node)
711     elif type == 'osc':
712         n = OSC(node)
713     elif type == 'mdc':
714         n = MDC(node)
715     elif type == 'mountpoint':
716         n = Mountpoint(node)
717     else:
718         panic ("unknown service type:", type)
719
720     if cleanFlag:
721         n.cleanup()
722     else:
723         n.prepare()
724
725 #
726 # Prepare the system to run lustre using a particular profile
727 # in a the configuration. 
728 #  * load & the modules
729 #  * setup networking for the current node
730 #  * make sure partitions are in place and prepared
731 #  * initialize devices with lctl
732 # Levels is important, and needs to be enforced.
733 def startProfile(lustreNode, profileNode, cleanFlag):
734     if not profileNode:
735         panic("profile:", profile, "not found.")
736     services = getServices(lustreNode, profileNode)
737     if cleanFlag:
738         services.reverse()
739     for s in services:
740         startService(s[1], cleanFlag)
741
742 #
743 # Load profile for 
744 def doHost(lustreNode, hosts, cleanFlag):
745     node = None
746     for h in hosts:
747         node = getByName(lustreNode, 'node', h)
748         if node:
749             break
750
751     if not node:
752         print 'No host entry found.'
753         return
754
755     reflist = node.getElementsByTagName('profile')
756     for profile in reflist:
757             startProfile(lustreNode,  profile, cleanFlag)
758
759 # Command line processing
760 #
761 def parse_cmdline(argv):
762     short_opts = "hdv"
763     long_opts = ["ldap", "reformat", "lustre=", "verbose",
764                  "portals=", "makeldiff", "cleanup", "iam=",
765                  "help", "debug", "host=", "get="]
766     opts = []
767     args = []
768     global options
769     try:
770         opts, args = getopt.getopt(argv, short_opts, long_opts)
771     except getopt.GetoptError:
772         print "invalid opt"
773         usage()
774
775     for o, a in opts:
776         if o in ("-h", "--help"):
777             usage()
778         if o == "--cleanup":
779             options['cleanup'] = 1
780         if o in ("-v", "--verbose"):
781             options['verbose'] = 1
782         if o in ("-d", "--debug"):
783             options['debug'] = 1
784             options['verbose'] = 1
785         if o == "--portals":
786             options['portals'] = a
787         if o == "--lustre":
788             options['lustre'] = a
789         if o  == "--reformat":
790             options['reformat'] = 1
791         if o  == "--host":
792             options['hostname'] = [a]
793         if o  == "--get":
794             options['url'] = a
795     return args
796
797 def fetch(url):
798     import urllib
799     data = ""
800     try:
801         s = urllib.urlopen(url)
802         data = s.read()
803     except:
804         usage()
805     return data
806
807 # Initialize or shutdown lustre according to a configuration file
808 #   * prepare the system for lustre
809 #   * configure devices with lctl
810 # Shutdown does steps in reverse
811 #
812 def main():
813     global options, TCP_ACCEPTOR, lctl
814     args = parse_cmdline(sys.argv[1:])
815     if len(args) > 0:
816         if not os.access(args[0], os.R_OK | os.W_OK):
817             print 'File not found:', args[0]
818             sys.exit(1)
819         dom = xml.dom.minidom.parse(args[0])
820     elif options.has_key('url'):
821         xmldata = fetch(options['url'])
822         dom = xml.dom.minidom.parseString(xmldata)
823     else:
824         usage()
825
826     if not options.has_key('hostname'):
827         options['hostname'] = []
828         host = socket.gethostname()
829         if len(host) > 0:
830             options['hostname'].append(host)
831         options['hostname'].append('localhost')
832     print "configuring for host: ", options['hostname']
833
834     TCP_ACCEPTOR = find_prog('acceptor')
835     if not TCP_ACCEPTOR:
836         if isnotouch():
837             TCP_ACCEPTOR = 'acceptor'
838             debug('! acceptor not found')
839         else:
840             panic('acceptor not found')
841
842     lctl = LCTLInterface('lctl')
843
844     doHost(dom.documentElement, options['hostname'], options.has_key('cleanup') )
845
846 if __name__ == "__main__":
847     try:
848         main()
849     except RuntimeError:
850         pass
851     except CommandError:
852         print '<insert exception data here>'
853         pass
854
855