Whamcloud - gitweb
Also comment out obdctl_SOURCES, otherwise it will fail to configure.
[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         if n.nodeType == n.ELEMENT_NODE:
608             if getUUID(n) == uuid:
609                 return n
610             else:
611                 n = lookup(n, uuid)
612                 if n: return n
613     return None
614
615 # Get name attribute of node
616 def getName(node):
617     return node.getAttribute('name')
618
619 def getRef(node):
620     return node.getAttribute('uuidref')
621
622 # Get name attribute of node
623 def getUUID(node):
624     return node.getAttribute('uuid')
625
626 # the tag name is the service type
627 # fixme: this should do some checks to make sure the node is a service
628 def getServiceType(node):
629     return node.nodeName
630
631 #
632 # determine what "level" a particular node is at.
633 # the order of iniitailization is based on level.  objects
634 # are assigned a level based on type:
635 #  net,devices,ldlm:1, obd, mdd:2  mds,ost:3 osc,mdc:4 mounts:5
636 def getServiceLevel(node):
637     type = getServiceType(node)
638     if type in ('network',):
639         return 1
640     if type in ('device', 'ldlm'):
641         return 2
642     elif type in ('obd', 'mdd'):
643         return 3
644     elif type in ('mds','ost'):
645         return 4
646     elif type in ('mdc','osc'):
647         return 5
648     elif type in ('lov',):
649         return 6
650     elif type in ('mountpoint',):
651         return 7
652     return 0
653
654 #
655 # return list of services in a profile. list is a list of tuples
656 # [(level, node),]
657 def getServices(lustreNode, profileNode):
658     list = []
659     for n in profileNode.childNodes:
660         if n.nodeType == n.ELEMENT_NODE:
661             servNode = lookup(lustreNode, getRef(n))
662             if not servNode:
663                 print n
664                 panic('service not found: ' + getRef(n))
665             level = getServiceLevel(servNode)
666             list.append((level, servNode))
667     list.sort()
668     return list
669
670 def getByName(lustreNode, tag, name):
671     ndList = lustreNode.getElementsByTagName(tag)
672     for nd in ndList:
673         if getName(nd) == name:
674             return nd
675     return None
676     
677
678 # ============================================================
679 # lconf type level logic
680 #
681
682 #
683 # Start a service.
684 def startService(node):
685     type = getServiceType(node)
686     debug('Starting service:', type, getName(node), getUUID(node))
687     # there must be a more dynamic way of doing this...
688     if type == 'ldlm':
689         prepare_ldlm(node)
690     elif type == 'lov':
691         prepare_lov(node)
692     elif type == 'network':
693         prepare_network(node)
694     elif type == 'obd':
695         prepare_obd(node)
696     elif type == 'ost':
697         prepare_ost(node)
698     elif type == 'mds':
699         prepare_mds(node)
700     elif type == 'osc':
701         prepare_osc(node)
702     elif type == 'mdc':
703         prepare_mdc(node)
704     elif type == 'mountpoint':
705         prepare_mountpoint(node)
706
707 #
708 # Prepare the system to run lustre using a particular profile
709 # in a the configuration. 
710 #  * load & the modules
711 #  * setup networking for the current node
712 #  * make sure partitions are in place and prepared
713 #  * initialize devices with lctl
714 # Levels is important, and needs to be enforced.
715 def startProfile(lustreNode, profileNode):
716     if not profileNode:
717         panic("profile:", profile, "not found.")
718     services = getServices(lustreNode, profileNode)
719     for s in services:
720         startService(s[1])
721
722
723 # Stop a service.
724 def stopService(node):
725     type = getServiceType(node)
726     debug('Stopping service:', type, getName(node), getUUID(node))
727     # there must be a more dynamic way of doing this...
728     if type == 'ldlm':
729         cleanup_ldlm(node)
730     elif type == 'lov':
731         cleanup_lov(node)
732     elif type == 'network':
733         cleanup_network(node)
734     elif type == 'obd':
735         cleanup_obd(node)
736     elif type == 'ost':
737         cleanup_ost(node)
738     elif type == 'mds':
739         cleanup_mds(node)
740     elif type == 'osc':
741         cleanup_osc(node)
742     elif type == 'mdc':
743         cleanup_mdc(node)
744     elif type == 'mountpoint':
745         cleanup_mountpoint(node)
746
747 # Shutdown services in reverse order than they were started
748 def cleanupProfile(lustreNode, profileNode):
749     if not profileNode:
750         panic("profile:", profile, "not found.")
751     services = getServices(lustreNode, profileNode)
752     services.reverse()
753     for s in services:
754         stopService(s[1])
755
756
757 #
758 # Load profile for 
759 def doHost(lustreNode, hosts, cleanFlag):
760     node = None
761     for h in hosts:
762         node = getByName(lustreNode, 'node', h)
763         if node:
764             break
765
766     if not node:
767         print 'No host entry found.'
768         return
769
770     reflist = node.getElementsByTagName('profile_ref')
771     for r in reflist:
772         if cleanFlag:
773             cleanupProfile(lustreNode, lookup(lustreNode, getRef(r)))
774         else:
775             startProfile(lustreNode,  lookup(lustreNode, getRef(r)))
776
777 #
778 # Command line processing
779 #
780 def parse_cmdline(argv):
781     short_opts = "hdv"
782     long_opts = ["ldap", "reformat", "lustre=", "verbose",
783                  "portals=", "makeldiff", "cleanup", "iam=",
784                  "help", "debug", "host=", "get="]
785     opts = []
786     args = []
787     global options
788     try:
789         opts, args = getopt.getopt(argv, short_opts, long_opts)
790     except getopt.GetoptError:
791         print "invalid opt"
792         usage()
793
794     for o, a in opts:
795         if o in ("-h", "--help"):
796             usage()
797         if o == "--cleanup":
798             options['cleanup'] = 1
799         if o in ("-v", "--verbose"):
800             options['verbose'] = 1
801         if o in ("-d", "--debug"):
802             options['debug'] = 1
803             options['verbose'] = 1
804         if o == "--portals":
805             options['portals'] = a
806         if o == "--lustre":
807             options['lustre'] = a
808         if o  == "--reformat":
809             options['reformat'] = 1
810         if o  == "--host":
811             options['hostname'] = [a]
812         if o  == "--get":
813             options['url'] = a
814     return args
815
816 def fetch(url):
817     import urllib
818     data = ""
819     try:
820         s = urllib.urlopen(url)
821         data = s.read()
822     except:
823         usage()
824     return data
825
826 # Initialize or shutdown lustre according to a configuration file
827 #   * prepare the system for lustre
828 #   * configure devices with lctl
829 # Shutdown does steps in reverse
830 #
831 lctl = LCTLInterface('lctl')
832 def main():
833     global options
834     args = parse_cmdline(sys.argv[1:])
835     if len(args) > 0:
836         dom = xml.dom.minidom.parse(args[0])
837     elif options.has_key('url'):
838         xmldata = fetch(options['url'])
839         dom = xml.dom.minidom.parseString(xmldata)
840     else:
841         usage()
842
843     if not options.has_key('hostname'):
844         options['hostname'] = []
845         ret, host = run('hostname')
846         if ret:
847             print "unable to determine hostname"
848         elif len(host) > 0:
849             options['hostname'].append(string.strip(host[0]))
850         options['hostname'].append('localhost')
851     print "configuring for host: ", options['hostname']
852     doHost(dom.childNodes[0], options['hostname'], options.has_key('cleanup') )
853
854 if __name__ == "__main__":
855     main()
856
857