Whamcloud - gitweb
a5c93fd4e7be6047c641c9a1681e9b14b0cb9eaf
[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, pattern, devlist):
191         cmds = """
192   device $%s
193   probe
194   lovconfig %s %d %d %s %s
195   quit""" % (mdcuuid, uuid, stripe_cnt, stripe_sz, 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, pattern, devlist, mdsname) = getLOVInfo(node)
333     print 'LOV:', name, uuid, mdcuuid, stripe_cnt, strip_sz, pattern, devlist, mdsname
334     lctl.lovconfig(uuid, mdsname, stripe_cnt, strip_sz, 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     lctl.connect(net, server, port, netuuid)
390     lctl.newdev(attach="mdc %s %s" % (name, uuid),
391                 setup ="%s %s" %(mdsuuid, netuuid))
392
393 def prepare_mountpoint(node):
394     name, uuid, oscuuid, mdcuuid, mtpt = getMTPTInfo(node)
395     print 'MTPT:', name, uuid, oscuuid, mdcuuid, mtpt
396     cmd = "mount -t lustre_lite -o ost=%s,mds=%s none %s" % \
397           (oscuuid, mdcuuid, mtpt)
398     run("mkdir", mtpt)
399     run(cmd)
400 # ============================================================
401 # Functions to cleanup the various objects
402
403 def cleanup_ldlm(node):
404     (name, uuid) = getNodeAttr(node)
405     print 'LDLM:', name, uuid
406     try:
407         lctl.cleanup(name, uuid)
408     except CommandError:
409         print "cleanup failed: ", name
410
411 def cleanup_lov(node):
412     (name, uuid, mdcuuid, stripe_cnt, strip_sz, pattern, devlist, mdsname) = getLOVInfo(node)
413     print 'LOV:', name, uuid, mdcuuid, stripe_cnt, strip_sz, pattern, devlist, mdsname
414     try:
415         lctl.cleanup(name, uuid)
416     except CommandError:
417         print "cleanup failed: ", name
418
419 def cleanup_network(node):
420     (name, uuid, type, nid, port) = getNetworkInfo(node)
421     print 'NETWORK:', name, uuid, type, nid, port
422     try:
423         lctl.cleanup("RPCDEV", "")
424     except CommandError:
425         print "cleanup failed: ", name
426     # yikes, this ugly! need to save pid in /var/something
427     run("killall acceptor")
428
429
430 # need to check /proc/mounts and /etc/mtab before
431 # formatting anything.
432 # FIXME: check if device is already formatted.
433 def cleanup_obd(obd):
434     (name, uuid, obdtype, dev, size, fstype, format) = getOBDInfo(obd)
435     print "OBD: ", name, obdtype, dev, size, fstype, format
436     try:
437         lctl.cleanup(name, uuid)
438     except CommandError:
439         print "cleanup failed: ", name
440     clean_loop(dev)
441
442 def cleanup_ost(ost):
443     name, uuid, obd = getOSTInfo(ost)
444     print "OST: ", name, uuid, obd
445     try:
446         lctl.cleanup(name, uuid)
447     except CommandError:
448         print "cleanup failed: ", name
449
450 def cleanup_mds(node):
451     (name, uuid, dev, size, fstype, format) = getMDSInfo(node)
452     print "MDS: ", name, dev, size, fstype
453     try:
454         lctl.cleanup(name, uuid)
455     except CommandError:
456         print "cleanup failed: ", name
457     clean_loop(dev)
458         
459
460 def cleanup_mdc(node):
461     (name, uuid, mdsuuid, netuuid) = getMDCInfo(node)
462     print 'MDC:', name, uuid, mdsuuid, netuuid
463     net = lookup(node.parentNode, netuuid)
464     srvname, srvuuid, net, server, port = getNetworkInfo(net)
465     try:
466         lctl.disconnect(net, server, port, netuuid)
467         lctl.cleanup(name, uuid)
468     except CommandError:
469         print "cleanup failed: ", name
470
471
472 def cleanup_osc(node):
473     (name, uuid, obduuid, ostuuid) = getOSCInfo(node)
474     print 'OSC:', name, uuid, obduuid, ostuuid
475     net = lookup(node.parentNode, ostuuid)
476     srvname, srvuuid, net, server, port = getNetworkInfo(net)
477     try:
478         lctl.disconnect(net, server, port, ostuuid)
479         lctl.cleanup(name, uuid)
480     except CommandError:
481         print "cleanup failed: ", name
482
483 def cleanup_mountpoint(node):
484     name, uuid, oscuuid, mdcuuid, mtpt = getMTPTInfo(node)
485     print 'MTPT:', name, uuid, oscuuid, mdcuuid, mtpt
486     run("umount", mtpt)
487
488 # ============================================================
489 # XML processing and query
490
491 def getDevice(obd):
492     dev = obd.getElementsByTagName('device')[0]
493     dev.normalize();
494     try:
495         size = int(dev.getAttribute('size'))
496     except ValueError:
497         size = 0
498     return dev.firstChild.data, size
499     
500
501 def getNetworkInfo(node):
502     name, uuid = getNodeAttr(node);
503     type = node.getAttribute('type')
504     nid = getText(node, 'server', "")
505     port = int(getText(node, 'port', 0))
506     return name, uuid, type, nid, port
507     
508 # extract device attributes for an obd
509 def getNodeAttr(node):
510     name = node.getAttribute('name')
511     uuid = node.getAttribute('uuid')
512     return name, uuid
513
514 def getOBDInfo(obd):
515     name, uuid = getNodeAttr(obd);
516     obdtype = obd.getAttribute('type')
517     devname, size = getDevice(obd)
518     fstype = getText(obd, 'fstype')
519     format = getText(obd, 'autoformat')
520     return (name, uuid, obdtype, devname, size, fstype, format)
521     
522 # extract LOV
523 def getLOVInfo(node):
524     name, uuid = getNodeAttr(node)
525     devs = node.getElementsByTagName('devices')[0]
526     stripe_sz = int(devs.getAttribute('stripesize'))
527     pattern = int(devs.getAttribute('pattern'))
528     mdcref =  node.getElementsByTagName('mdc_ref')[0]
529     mdcuuid = mdcref.getAttribute('uuidref')
530     mdc= lookup(node.parentNode, mdcuuid)
531     mdsref =  mdc.getElementsByTagName('mds_ref')[0]
532     mdsuuid = mdsref.getAttribute('uuidref')
533     mds= lookup(node.parentNode, mdsuuid)
534     mdsname = getName(mds)
535     devlist = ""
536     stripe_cnt = 0
537     for child in devs.childNodes:
538         if child.nodeName == 'osc_ref':
539             devlist = devlist +  child.getAttribute('uuidref') + " "
540             strip_cnt = stripe_cnt + 1
541     return (name, uuid, mdcuuid, stripe_cnt, stripe_sz, pattern, devlist, mdsname)
542     
543 # extract device attributes for an obd
544 def getMDSInfo(node):
545     name, uuid = getNodeAttr(node)
546     devname, size = getDevice(node)
547     fstype = getText(node, 'fstype')
548     format = getText(node, 'autoformat', "no")
549     return (name, uuid, devname, size, fstype, format)
550
551 # extract device attributes for an obd
552 def getMDCInfo(node):
553     name, uuid = getNodeAttr(node)
554     ref = node.getElementsByTagName('mds_ref')[0]
555     mdsuuid = ref.getAttribute('uuidref')
556     ref = node.getElementsByTagName('network_ref')[0]
557     netuuid = ref.getAttribute('uuidref')
558     return (name, uuid, mdsuuid, netuuid)
559
560     
561 # extract device attributes for an obd
562 def getOSTInfo(node):
563     name, uuid = getNodeAttr(node)
564     ref = node.getElementsByTagName('obd_ref')[0]
565     uuid = ref.getAttribute('uuidref')
566     obd = lookup(node.parentNode, uuid)
567     if obd:
568          obdname = getOBDInfo(obd)[0]
569     else:
570         obdname = "OBD NOT FOUND"
571     return (name, uuid, obdname)
572
573 # extract device attributes for an obd
574 def getOSCInfo(node):
575     name, uuid = getNodeAttr(node)
576     ref = node.getElementsByTagName('obd_ref')[0]
577     obduuid = ref.getAttribute('uuidref')
578     ref = node.getElementsByTagName('network_ref')[0]
579     ostuuid = ref.getAttribute('uuidref')
580     return (name, uuid, obduuid, ostuuid)
581
582 # extract device attributes for an obd
583 def getMTPTInfo(node):
584     name, uuid = getNodeAttr(node)
585     path = getText(node, 'path')
586     ref = node.getElementsByTagName('mdc_ref')[0]
587     mdcuuid = ref.getAttribute('uuidref')
588     ref = node.getElementsByTagName('osc_ref')[0]
589     lovuuid = ref.getAttribute('uuidref')
590     return (name, uuid, lovuuid, mdcuuid, path)
591
592     
593 # Get the text content from the first matching child
594 def getText(node, tag, default=""):
595     list = node.getElementsByTagName(tag)
596     if len(list) > 0:
597         node = list[0]
598         node.normalize()
599         return node.firstChild.data
600     else:
601         return default
602
603 # Recusively search from node for a uuid
604 def lookup(node, uuid):
605     for n in node.childNodes:
606         # this service_id check is ugly. need some other way to
607         # differentiate between definitions and references
608         if n.nodeType == n.ELEMENT_NODE:
609             if getUUID(n) == uuid:
610                 return n
611             else:
612                 n = lookup(n, uuid)
613                 if n: return n
614     return None
615
616 # Get name attribute of node
617 def getName(node):
618     return node.getAttribute('name')
619
620 def getRef(node):
621     return node.getAttribute('uuidref')
622
623 # Get name attribute of node
624 def getUUID(node):
625     return node.getAttribute('uuid')
626
627 # the tag name is the service type
628 # fixme: this should do some checks to make sure the node is a service
629 def getServiceType(node):
630     return node.nodeName
631
632 #
633 # determine what "level" a particular node is at.
634 # the order of iniitailization is based on level.  objects
635 # are assigned a level based on type:
636 #  net,devices,ldlm:1, obd, mdd:2  mds,ost:3 osc,mdc:4 mounts:5
637 def getServiceLevel(node):
638     type = getServiceType(node)
639     if type in ('network',):
640         return 1
641     if type in ('device', 'ldlm'):
642         return 2
643     elif type in ('obd', 'mdd'):
644         return 3
645     elif type in ('mds','ost'):
646         return 4
647     elif type in ('mdc','osc'):
648         return 5
649     elif type in ('lov',):
650         return 6
651     elif type in ('mountpoint',):
652         return 7
653     return 0
654
655 #
656 # return list of services in a profile. list is a list of tuples
657 # [(level, node),]
658 def getServices(lustreNode, profileNode):
659     list = []
660     for n in profileNode.childNodes:
661         if n.nodeType == n.ELEMENT_NODE:
662             servNode = lookup(lustreNode, getRef(n))
663             if not servNode:
664                 print n
665                 panic('service not found: ' + getRef(n))
666             level = getServiceLevel(servNode)
667             list.append((level, servNode))
668     list.sort()
669     return list
670
671 def getByName(lustreNode, tag, name):
672     ndList = lustreNode.getElementsByTagName(tag)
673     for nd in ndList:
674         if getName(nd) == name:
675             return nd
676     return None
677     
678
679 # ============================================================
680 # lconf type level logic
681 #
682
683 #
684 # Start a service.
685 def startService(node):
686     type = getServiceType(node)
687     debug('Starting service:', type, getName(node), getUUID(node))
688     # there must be a more dynamic way of doing this...
689     if type == 'ldlm':
690         prepare_ldlm(node)
691     elif type == 'lov':
692         prepare_lov(node)
693     elif type == 'network':
694         prepare_network(node)
695     elif type == 'obd':
696         prepare_obd(node)
697     elif type == 'ost':
698         prepare_ost(node)
699     elif type == 'mds':
700         prepare_mds(node)
701     elif type == 'osc':
702         prepare_osc(node)
703     elif type == 'mdc':
704         prepare_mdc(node)
705     elif type == 'mountpoint':
706         prepare_mountpoint(node)
707
708 #
709 # Prepare the system to run lustre using a particular profile
710 # in a the configuration. 
711 #  * load & the modules
712 #  * setup networking for the current node
713 #  * make sure partitions are in place and prepared
714 #  * initialize devices with lctl
715 # Levels is important, and needs to be enforced.
716 def startProfile(lustreNode, profileNode):
717     if not profileNode:
718         panic("profile:", profile, "not found.")
719     services = getServices(lustreNode, profileNode)
720     for s in services:
721         startService(s[1])
722
723
724 # Stop a service.
725 def stopService(node):
726     type = getServiceType(node)
727     debug('Stopping service:', type, getName(node), getUUID(node))
728     # there must be a more dynamic way of doing this...
729     if type == 'ldlm':
730         cleanup_ldlm(node)
731     elif type == 'lov':
732         cleanup_lov(node)
733     elif type == 'network':
734         cleanup_network(node)
735     elif type == 'obd':
736         cleanup_obd(node)
737     elif type == 'ost':
738         cleanup_ost(node)
739     elif type == 'mds':
740         cleanup_mds(node)
741     elif type == 'osc':
742         cleanup_osc(node)
743     elif type == 'mdc':
744         cleanup_mdc(node)
745     elif type == 'mountpoint':
746         cleanup_mountpoint(node)
747
748 # Shutdown services in reverse order than they were started
749 def cleanupProfile(lustreNode, profileNode):
750     if not profileNode:
751         panic("profile:", profile, "not found.")
752     services = getServices(lustreNode, profileNode)
753     services.reverse()
754     for s in services:
755         stopService(s[1])
756
757
758 #
759 # Load profile for 
760 def doHost(lustreNode, hosts, cleanFlag):
761     for h in hosts:
762         node = getByName(lustreNode, 'node', h)
763         if node:
764             break
765         
766     reflist = node.getElementsByTagName('profile_ref')
767     for r in reflist:
768         if cleanFlag:
769             cleanupProfile(lustreNode, lookup(lustreNode, getRef(r)))
770         else:
771             startProfile(lustreNode,  lookup(lustreNode, getRef(r)))
772
773 #
774 # Command line processing
775 #
776 def parse_cmdline(argv):
777     short_opts = "hdv"
778     long_opts = ["ldap", "reformat", "lustre=", "verbose",
779                  "portals=", "makeldiff", "cleanup", "iam=",
780                  "help", "debug", "host=", "get="]
781     opts = []
782     args = []
783     global options
784     try:
785         opts, args = getopt.getopt(argv, short_opts, long_opts)
786     except getopt.GetoptError:
787         print "invalid opt"
788         usage()
789
790     for o, a in opts:
791         if o in ("-h", "--help"):
792             usage()
793         if o == "--cleanup":
794             options['cleanup'] = 1
795         if o in ("-v", "--verbose"):
796             options['verbose'] = 1
797         if o in ("-d", "--debug"):
798             options['debug'] = 1
799             options['verbose'] = 1
800         if o == "--portals":
801             options['portals'] = a
802         if o == "--lustre":
803             options['lustre'] = a
804         if o  == "--reformat":
805             options['reformat'] = 1
806         if o  == "--host":
807             options['hostname'] = [a]
808         if o  == "--get":
809             options['url'] = a
810     return args
811
812 def fetch(url):
813     import urllib
814     data = ""
815     try:
816         s = urllib.urlopen(url)
817         data = s.read()
818     except:
819         usage()
820     return data
821
822 # Initialize or shutdown lustre according to a configuration file
823 #   * prepare the system for lustre
824 #   * configure devices with lctl
825 # Shutdown does steps in reverse
826 #
827 lctl = LCTLInterface('lctl')
828 def main():
829     global options
830     args = parse_cmdline(sys.argv[1:])
831     if len(args) > 0:
832         dom = xml.dom.minidom.parse(args[0])
833     elif options.has_key('url'):
834         xmldata = fetch(options['url'])
835         dom = xml.dom.minidom.parseString(xmldata)
836     else:
837         usage()
838
839     if not options.has_key('hostname'):
840         ret, host = run('hostname')
841         if ret:
842             print "unable to determine hostname"
843         else:
844             options['hostname'] = [string.strip(host[0])] 
845         options['hostname'].append('localhost')
846     print "configuring for host: ", options['hostname']
847     doHost(dom.childNodes[0], options['hostname'], options.has_key('cleanup') )
848
849 if __name__ == "__main__":
850     main()
851
852