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