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