Whamcloud - gitweb
Add --dump option to usage output.
[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, time
30 import re, exceptions
31 import xml.dom.minidom
32
33 # Global parameters
34 TCP_ACCEPTOR = ''
35 MAXTCPBUF = 1048576
36 DEFAULT_TCPBUF = 1048576
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 --node <nodename>   Load config for <nodename>
49 -d | --cleanup      Cleans up config. (Shutdown)
50 -v | --verbose      Print system commands as they are run
51 -h | --help         Print this help 
52 --gdb               Prints message after creating gdb module script
53                     and sleeps for 5 seconds.
54 -n | --noexec       Prints the commands and steps that will be run for a
55                     config without executing them. This can used to check if a
56                     config file is doing what it should be doing. (Implies -v)
57 --nomod             Skip load/unload module step.
58 --nosetup           Skip device setup/cleanup step.
59 --reformat          Reformat all devices (without question)
60 --dump              Dump the kernel debug log before portals is unloaded
61 """
62     TODO = """
63 --ldap server       LDAP server with lustre config database
64 --makeldiff         Translate xml source to LDIFF 
65 This are perhaps not needed:
66 --lustre="src dir"  Base directory of lustre sources. Used to search
67                     for modules.
68 --portals=src       Portals source 
69 """
70     sys.exit()
71
72 # ============================================================
73 # Config parameters, encapsulated in a class
74 class Config:
75     def __init__(self):
76         # flags
77         self._noexec = 0
78         self._verbose = 0
79         self._reformat = 0
80         self._cleanup = 0
81         self._gdb = 0
82         self._nomod = 0
83         self._nosetup = 0
84         # parameters
85         self._modules = None
86         self._node = None
87         self._url = None
88         self._gdb_script = '/tmp/ogdb'
89         self._debug_path = '/tmp/lustre-log'
90         self._dump_file = None
91         self._src_dir = None
92
93     def verbose(self, flag = None):
94         if flag: self._verbose = flag
95         return self._verbose
96
97     def noexec(self, flag = None):
98         if flag: self._noexec = flag
99         return self._noexec
100
101     def reformat(self, flag = None):
102         if flag: self._reformat = flag
103         return self._reformat
104
105     def cleanup(self, flag = None):
106         if flag: self._cleanup = flag
107         return self._cleanup
108
109     def gdb(self, flag = None):
110         if flag: self._gdb = flag
111         return self._gdb
112
113     def nomod(self, flag = None):
114         if flag: self._nomod = flag
115         return self._nomod
116
117     def nosetup(self, flag = None):
118         if flag: self._nosetup = flag
119         return self._nosetup
120
121     def node(self, val = None):
122         if val: self._node = val
123         return self._node
124
125     def url(self, val = None):
126         if val: self._url = val
127         return self._url
128
129     def gdb_script(self):
130         if os.path.isdir('/r'):
131             return '/r' + self._gdb_script
132         else:
133             return self._gdb_script
134
135     def debug_path(self):
136         if os.path.isdir('/r'):
137             return '/r' + self._debug_path
138         else:
139             return self._debug_path
140
141     def src_dir(self, val = None):
142         if val: self._src_dir = val
143         return self._src_dir
144
145     def dump_file(self, val = None):
146         if val: self._dump_file = val
147         return self._dump_file
148
149 config = Config()
150
151 # ============================================================ 
152 # debugging and error funcs
153
154 def fixme(msg = "this feature"):
155     raise LconfError, msg + ' not implmemented yet.'
156
157 def panic(*args):
158     msg = string.join(map(str,args))
159     if not config.noexec():
160         raise LconfError(msg)
161     else:
162         print "! " + msg
163
164 def log(*args):
165     msg = string.join(map(str,args))
166     print msg
167
168 def logall(msgs):
169     for s in msgs:
170         print string.strip(s)
171
172 def debug(*args):
173     if config.verbose():
174         msg = string.join(map(str,args))
175         print msg
176
177 # ============================================================
178 # locally defined exceptions
179 class CommandError (exceptions.Exception):
180     def __init__(self, cmd_name, cmd_err, rc=None):
181         self.cmd_name = cmd_name
182         self.cmd_err = cmd_err
183         self.rc = rc
184
185     def dump(self):
186         import types
187         if type(self.cmd_err) == types.StringType:
188             if self.rc:
189                 print "! %s (%d): %s" % (self.cmd_name, self.rc, self.cmd_err)
190             else:
191                 print "! %s: %s" % (self.cmd_name, self.cmd_err)
192         elif type(self.cmd_err) == types.ListType:
193             if self.rc:
194                 print "! %s (error %d):" % (self.cmd_name, self.rc)
195             else:
196                 print "! %s:" % (self.cmd_name)
197             for s in self.cmd_err:
198                 print "> %s" %(string.strip(s))
199         else:
200             print self.cmd_err
201
202 class LconfError (exceptions.Exception):
203     def __init__(self, args):
204         self.args = args
205
206
207 # ============================================================
208 # handle lctl interface
209 class LCTLInterface:
210     """
211     Manage communication with lctl
212     """
213
214     def __init__(self, cmd):
215         """
216         Initialize close by finding the lctl binary.
217         """
218         self.lctl = find_prog(cmd)
219         if not self.lctl:
220             if config.noexec():
221                 debug('! lctl not found')
222                 self.lctl = 'lctl'
223             else:
224                 raise CommandError('lctl', "unable to find lctl binary.")
225             
226     def run(self, cmds):
227         """
228         run lctl
229         the cmds are written to stdin of lctl
230         lctl doesn't return errors when run in script mode, so
231         stderr is checked
232         should modify command line to accept multiple commands, or
233         create complex command line options
234         """
235         debug("+", self.lctl, cmds)
236         if config.noexec(): return (0, [])
237         p = popen2.Popen3(self.lctl, 1)
238         p.tochild.write(cmds + "\n")
239         p.tochild.close()
240         out = p.fromchild.readlines()
241         err = p.childerr.readlines()
242         ret = p.wait()
243         if ret or len(err):
244             raise CommandError(self.lctl, err, ret)
245         return ret, out
246
247             
248     def network(self, net, nid):
249         """ initialized network and add "self" """
250         # Idea: "mynid" could be used for all network types to add "self," and then
251         # this special case would be gone and the "self" hack would be hidden.
252         if net  == 'tcp':
253             cmds =  """
254   network %s
255   mynid %s
256   add_uuid self %s
257   quit""" % (net, nid, nid)
258         else:
259             cmds =  """
260   network %s
261   add_uuid self %s
262   quit""" % (net, nid)
263             
264         self.run(cmds)
265
266     # create a new connection
267     def connect(self, net, nid, port, servuuid, send_mem, recv_mem):
268         if net == 'tcp':
269             cmds =  """
270   network %s
271   add_uuid %s %s
272   send_mem %d
273   recv_mem %d
274   connect %s %d
275   quit""" % (net, servuuid, nid, send_mem, recv_mem, nid, port,  )
276         else:
277             cmds =  """
278   network %s
279   add_uuid %s %s
280   connect %s %d
281   quit""" % (net, servuuid, nid, nid, port,  )
282             
283         self.run(cmds)
284                 
285     # add a route to a range
286     def add_route(self, net, gw, lo, hi):
287         cmds =  """
288   network %s
289   add_route %s %s %s
290   quit  """ % (net, gw, lo, hi)
291         self.run(cmds)
292
293                 
294     # add a route to a range
295     def del_route(self, net, gw, lo, hi):
296         cmds =  """
297   network %s
298   del_route %s
299   quit  """ % (net, lo)
300         self.run(cmds)
301
302     # add a route to a host
303     def add_route_host(self, net, uuid, gw, tgt):
304         cmds =  """
305   network %s
306   add_uuid %s %s
307   add_route %s %s
308   quit """ % (net, uuid, tgt, gw, tgt)
309         self.run(cmds)
310
311     # add a route to a range
312     def del_route_host(self, net, uuid, gw, tgt):
313         cmds =  """
314   network %s
315   del_uuid %s
316   del_route %s
317   quit  """ % (net, uuid, tgt)
318         self.run(cmds)
319
320     # disconnect one connection
321     def disconnect(self, net, nid, port, servuuid):
322         cmds =  """
323   network %s
324   disconnect %s 
325   del_uuid %s
326   quit""" % (net, nid, servuuid)
327         self.run(cmds)
328
329     # disconnect all
330     def disconnectAll(self, net):
331         cmds =  """
332   network %s
333   del_uuid self
334   disconnect
335   quit""" % (net)
336         self.run(cmds)
337
338     # create a new device with lctl
339     def newdev(self, attach, setup = ""):
340         cmds = """
341   newdev
342   attach %s
343   setup %s
344   quit""" % (attach, setup)
345         self.run(cmds)
346
347     # cleanup a device
348     def cleanup(self, name, uuid):
349         cmds = """
350   device $%s
351   cleanup
352   detach
353   quit""" % (name)
354         self.run(cmds)
355
356     # create an lov
357     def lovconfig(self, uuid, mdsuuid, stripe_cnt, stripe_sz, stripe_off, pattern, devlist):
358         cmds = """
359   device $%s
360   probe
361   lovconfig %s %d %d %d %s %s
362   quit""" % (mdsuuid, uuid, stripe_cnt, stripe_sz, stripe_off, pattern, devlist)
363         self.run(cmds)
364
365     # cleanup a device
366     def dump(self, dump_file):
367         cmds = """
368   debug_kernel %s 1
369   quit""" % (dump_file)
370         self.run(cmds)
371
372 # ============================================================
373 # Various system-level functions
374 # (ideally moved to their own module)
375
376 # Run a command and return the output and status.
377 # stderr is sent to /dev/null, could use popen3 to
378 # save it if necessary
379 def run(*args):
380     cmd = string.join(map(str,args))
381     debug ("+", cmd)
382     if config.noexec(): return (0, [])
383     f = os.popen(cmd + ' 2>&1')
384     out = f.readlines()
385     ret = f.close()
386     if ret:
387         ret = ret >> 8
388     else:
389         ret = 0
390     return (ret, out)
391
392 # Run a command in the background.
393 def run_daemon(*args):
394     cmd = string.join(map(str,args))
395     debug ("+", cmd)
396     if config.noexec(): return 0
397     f = os.popen(cmd + ' 2>&1')
398     ret = f.close()
399     if ret:
400         ret = ret >> 8
401     else:
402         ret = 0
403     return ret
404
405 # Determine full path to use for an external command
406 # searches dirname(argv[0]) first, then PATH
407 def find_prog(cmd):
408     syspath = string.split(os.environ['PATH'], ':')
409     cmdpath = os.path.dirname(sys.argv[0])
410     syspath.insert(0, cmdpath);
411     syspath.insert(0, os.path.join(cmdpath, '../../portals/linux/utils/'))
412     for d in syspath:
413         prog = os.path.join(d,cmd)
414         if os.access(prog, os.X_OK):
415             return prog
416     return ''
417
418 # Recursively look for file starting at base dir
419 def do_find_file(base, mod):
420     fullname = os.path.join(base, mod)
421     if os.access(fullname, os.R_OK):
422         return fullname
423     for d in os.listdir(base):
424         dir = os.path.join(base,d)
425         if os.path.isdir(dir):
426             module = do_find_file(dir, mod)
427             if module:
428                 return module
429
430 def find_module(src_dir, dev_dir, modname):
431     mod = '%s.o' % (modname)
432     module = src_dir +'/'+ dev_dir +'/'+ mod
433     try: 
434        if os.access(module, os.R_OK):
435             return module
436     except OSError:
437         pass
438     return None
439
440 # is the path a block device?
441 def is_block(path):
442     s = ()
443     try:
444         s =  os.stat(path)
445     except OSError:
446         return 0
447     return stat.S_ISBLK(s[stat.ST_MODE])
448
449 # build fs according to type
450 # fixme: dangerous
451 def mkfs(fstype, dev):
452     if(fstype in ('ext3', 'extN')):
453         mkfs = 'mkfs.ext2 -j -b 4096'
454     else:
455         print 'unsupported fs type: ', fstype
456     if not is_block(dev):
457         force = '-F'
458     else:
459         force = ''
460     (ret, out) = run (mkfs, force, dev)
461     if ret:
462         panic("Unable to build fs:", dev)
463     # enable hash tree indexing on fs
464     if fstype == 'extN':
465         htree = 'echo "feature FEATURE_C5" | debugfs -w'
466         (ret, out) = run (htree, dev)
467         if ret:
468             panic("Unable to enable htree:", dev)
469
470 # some systems use /dev/loopN, some /dev/loop/N
471 def loop_base():
472     import re
473     loop = '/dev/loop'
474     if not os.access(loop + str(0), os.R_OK):
475         loop = loop + '/'
476         if not os.access(loop + str(0), os.R_OK):
477             panic ("can't access loop devices")
478     return loop
479     
480 # find loop device assigned to thefile
481 def find_loop(file):
482     loop = loop_base()
483     for n in xrange(0, MAX_LOOP_DEVICES):
484         dev = loop + str(n)
485         if os.access(dev, os.R_OK):
486             (stat, out) = run('losetup', dev)
487             if (out and stat == 0):
488                 m = re.search(r'\((.*)\)', out[0])
489                 if m and file == m.group(1):
490                     return dev
491         else:
492             break
493     return ''
494
495 # create file if necessary and assign the first free loop device
496 def init_loop(file, size, fstype):
497     dev = find_loop(file)
498     if dev:
499         print 'WARNING file:', file, 'already mapped to', dev
500         return dev
501     if config.reformat()  or not os.access(file, os.R_OK | os.W_OK):
502         run("dd if=/dev/zero bs=1k count=0 seek=%d of=%s" %(size,  file))
503     loop = loop_base()
504     # find next free loop
505     for n in xrange(0, MAX_LOOP_DEVICES):
506         dev = loop + str(n)
507         if os.access(dev, os.R_OK):
508             (stat, out) = run('losetup', dev)
509             if (stat):
510                 run('losetup', dev, file)
511                 return dev
512         else:
513             print "out of loop devices"
514             return ''
515     print "out of loop devices"
516     return ''
517
518 # undo loop assignment
519 def clean_loop(file):
520     dev = find_loop(file)
521     if dev:
522         ret, out = run('losetup -d', dev)
523         if ret:
524             log('unable to clean loop device:', dev, 'for file:', file)
525             logall(out)
526
527 # determine if dev is formatted as a <fstype> filesystem
528 def need_format(fstype, dev):
529     # FIXME don't know how to implement this    
530     return 0
531
532 # initialize a block device if needed
533 def block_dev(dev, size, fstype, format):
534     if config.noexec(): return dev
535     if not is_block(dev):
536         dev = init_loop(dev, size, fstype)
537     if config.reformat() or (need_format(fstype, dev) and format == 'yes'):
538         mkfs(fstype, dev)
539
540 #    else:
541 #        panic("device:", dev,
542 #              "not prepared, and autoformat is not set.\n",
543 #              "Rerun with --reformat option to format ALL filesystems")
544         
545     return dev
546
547 def if2addr(iface):
548     """lookup IP address for an interface"""
549     rc, out = run("/sbin/ifconfig", iface)
550     if rc or not out:
551        return None
552     addr = string.split(out[1])[1]
553     ip = string.split(addr, ':')[1]
554     return ip
555
556 def get_local_address(net_type, wildcard):
557     """Return the local address for the network type."""
558     local = ""
559     if net_type == 'tcp':
560         if  ':' in wildcard:
561             iface, star = string.split(wildcard, ':')
562             local = if2addr(iface)
563             if not local:
564                 panic ("unable to determine ip for:", wildcard)
565         else:
566             host = socket.gethostname()
567             local = socket.gethostbyname(host)
568     elif net_type == 'elan':
569         # awk '/NodeId/ { print $2 }' '/proc/elan/device0/position'
570         try:
571             fp = open('/proc/elan/device0/position', 'r')
572             lines = fp.readlines()
573             fp.close()
574             for l in lines:
575                 a = string.split(l)
576                 if a[0] == 'NodeId':
577                     local = a[1]
578                     break
579         except IOError, e:
580             log(e)
581     elif net_type == 'gm':
582         fixme("automatic local address for GM")
583     return local
584         
585         
586
587 # ============================================================
588 # Classes to prepare and cleanup the various objects
589 #
590 class Module:
591     """ Base class for the rest of the modules. The default cleanup method is
592     defined here, as well as some utilitiy funcs.
593     """
594     def __init__(self, module_name, dom_node):
595         self.dom_node = dom_node
596         self.module_name = module_name
597         self.name = get_attr(dom_node, 'name')
598         self.uuid = get_attr(dom_node, 'uuid')
599         self.kmodule_list = []
600         self._server = None
601         self._connected = 0
602         
603     def info(self, *args):
604         msg = string.join(map(str,args))
605         print self.module_name + ":", self.name, self.uuid, msg
606
607
608     def lookup_server(self, srv_uuid):
609         """ Lookup a server's network information """
610         net = get_ost_net(self.dom_node.parentNode, srv_uuid)
611         if not net:
612             panic ("Unable to find a server for:", srv_uuid)
613         self._server = Network(net)
614
615     def get_server(self):
616         return self._server
617
618     def cleanup(self):
619         """ default cleanup, used for most modules """
620         self.info()
621         srv = self.get_server()
622         if srv and local_net(srv):
623             try:
624                 lctl.disconnect(srv.net_type, srv.nid, srv.port, srv.uuid)
625             except CommandError, e:
626                 log(self.module_name, "disconnect failed: ", self.name)
627                 e.dump()
628         try:
629             lctl.cleanup(self.name, self.uuid)
630         except CommandError, e:
631             log(self.module_name, "cleanup failed: ", self.name)
632             e.dump()
633
634     def add_module(self, dev_dir, modname):
635         """Append a module to list of modules to load."""
636         self.kmodule_list.append((dev_dir, modname))
637
638     def mod_loaded(self, modname):
639         """Check if a module is already loaded. Look in /proc/modules for it."""
640         fp = open('/proc/modules')
641         lines = fp.readlines()
642         fp.close()
643         # please forgive my tired fingers for this one
644         ret = filter(lambda word, mod=modname: word == mod,
645                      map(lambda line: string.split(line)[0], lines))
646         return ret
647
648     def load_module(self):
649         """Load all the modules in the list in the order they appear."""
650         for dev_dir, mod in self.kmodule_list:
651             #  (rc, out) = run ('/sbin/lsmod | grep -s', mod)
652             if self.mod_loaded(mod) and not config.noexec():
653                 continue
654             log ('loading module:', mod)
655             if config.src_dir():
656                 module = find_module(config.src_dir(),dev_dir,  mod)
657                 if not module:
658                     panic('module not found:', mod)
659                 (rc, out)  = run('/sbin/insmod', module)
660                 if rc:
661                     raise CommandError('insmod', out, rc)
662             else:
663                 (rc, out) = run('/sbin/modprobe', mod)
664                 if rc:
665                     raise CommandError('modprobe', out, rc)
666             
667     def cleanup_module(self):
668         """Unload the modules in the list in reverse order."""
669         rev = self.kmodule_list
670         rev.reverse()
671         for dev_dir, mod in rev:
672             if not self.mod_loaded(mod):
673                 continue
674             # debug hack
675             if mod == 'portals' and config.dump_file():
676                 lctl.dump(config.dump_file())
677             log('unloading module:', mod)
678             if config.noexec():
679                 continue
680             (rc, out) = run('/sbin/rmmod', mod)
681             if rc:
682                 log('! unable to unload module:', mod)
683                 logall(out)
684         
685
686 class Network(Module):
687     def __init__(self,dom_node):
688         Module.__init__(self, 'NETWORK', dom_node)
689         self.net_type = get_attr(dom_node,'type')
690         self.nid = get_text(dom_node, 'server', '*')
691         self.port = get_text_int(dom_node, 'port', 0)
692         self.send_mem = get_text_int(dom_node, 'send_mem', DEFAULT_TCPBUF)
693         self.recv_mem = get_text_int(dom_node, 'recv_mem', DEFAULT_TCPBUF)
694         if '*' in self.nid:
695             self.nid = get_local_address(self.net_type, self.nid)
696             if not self.nid:
697                 panic("unable to set nid for", self.net_type, self.nid)
698             debug("nid:", self.nid)
699
700         self.add_module('portals/linux/oslib/', 'portals')
701         if node_needs_router():
702             self.add_module('portals/linux/router', 'kptlrouter')
703         if self.net_type == 'tcp':
704             self.add_module('portals/linux/socknal', 'ksocknal')
705         if self.net_type == 'elan':
706             self.add_module('portals/linux/rqswnal', 'kqswnal')
707         if self.net_type == 'gm':
708             self.add_module('portals/linux/gmnal', 'kgmnal')
709         self.add_module('lustre/obdclass', 'obdclass')
710         self.add_module('lustre/ptlrpc', 'ptlrpc')
711
712     def prepare(self):
713         self.info(self.net_type, self.nid, self.port)
714         if self.net_type == 'tcp':
715             ret, out = run(TCP_ACCEPTOR, '-s', self.send_mem, '-r', self.recv_mem, self.port)
716             if ret:
717                 raise CommandError(TCP_ACCEPTOR, out, ret)
718         ret = self.dom_node.getElementsByTagName('route_tbl')
719         for a in ret:
720             for r in a.getElementsByTagName('route'):
721                 net_type = get_attr(r, 'type')
722                 gw = get_attr(r, 'gw')
723                 lo = get_attr(r, 'lo')
724                 hi = get_attr(r,'hi', '')
725                 lctl.add_route(net_type, gw, lo, hi)
726                 if self.net_type == 'tcp' and hi == '':
727                     srv = nid2server(self.dom_node.parentNode.parentNode, lo)
728                     if not srv:
729                         panic("no server for nid", lo)
730                     else:
731                         lctl.connect(srv.net_type, srv.nid, srv.port, srv.uuid, srv.send_mem, srv.recv_mem)
732
733             
734         lctl.network(self.net_type, self.nid)
735         lctl.newdev(attach = "ptlrpc RPCDEV")
736
737     def cleanup(self):
738         self.info(self.net_type, self.nid, self.port)
739         ret = self.dom_node.getElementsByTagName('route_tbl')
740         for a in ret:
741             for r in a.getElementsByTagName('route'):
742                 lo = get_attr(r, 'lo')
743                 hi = get_attr(r,'hi', '')
744                 if self.net_type == 'tcp' and hi == '':
745                     srv = nid2server(self.dom_node.parentNode.parentNode, lo)
746                     if not srv:
747                         panic("no server for nid", lo)
748                     else:
749                         try:
750                             lctl.disconnect(srv.net_type, srv.nid, srv.port, srv.uuid)
751                         except CommandError, e:
752                             print "disconnect failed: ", self.name
753                             e.dump()
754                 try:
755                     lctl.del_route(self.net_type, self.nid, lo, hi)
756                 except CommandError, e:
757                     print "del_route failed: ", self.name
758                     e.dump()
759               
760         try:
761             lctl.cleanup("RPCDEV", "")
762         except CommandError, e:
763             print "cleanup failed: ", self.name
764             e.dump()
765         try:
766             lctl.disconnectAll(self.net_type)
767         except CommandError, e:
768             print "disconnectAll failed: ", self.name
769             e.dump()
770         if self.net_type == 'tcp':
771             # yikes, this ugly! need to save pid in /var/something
772             run("killall acceptor")
773
774 class LDLM(Module):
775     def __init__(self,dom_node):
776         Module.__init__(self, 'LDLM', dom_node)
777         self.add_module('lustre/ldlm', 'ldlm')
778     def prepare(self):
779         self.info()
780         lctl.newdev(attach="ldlm %s %s" % (self.name, self.uuid),
781                     setup ="")
782
783 class LOV(Module):
784     def __init__(self,dom_node):
785         Module.__init__(self, 'LOV', dom_node)
786         self.mds_uuid = get_first_ref(dom_node, 'mds')
787         mds= lookup(dom_node.parentNode, self.mds_uuid)
788         self.mds_name = getName(mds)
789         devs = dom_node.getElementsByTagName('devices')
790         if len(devs) > 0:
791             dev_node = devs[0]
792             self.stripe_sz = get_attr_int(dev_node, 'stripesize', 65536)
793             self.stripe_off = get_attr_int(dev_node, 'stripeoffset', 0)
794             self.pattern = get_attr_int(dev_node, 'pattern', 0)
795             self.devlist = get_all_refs(dev_node, 'osc')
796             self.stripe_cnt = get_attr_int(dev_node, 'stripecount', len(self.devlist))
797         self.add_module('lustre/mdc', 'mdc')
798         self.add_module('lustre/lov', 'lov')
799
800     def prepare(self):
801         for osc_uuid in self.devlist:
802             osc = lookup(self.dom_node.parentNode, osc_uuid)
803             if osc:
804                 n = OSC(osc)
805                 n.prepare()
806             else:
807                 panic('osc not found:', osc_uuid)
808         mdc_uuid = prepare_mdc(self.dom_node.parentNode, self.mds_uuid)
809         self.info(self.mds_uuid, self.stripe_cnt, self.stripe_sz,
810                   self.stripe_off, self.pattern, self.devlist, self.mds_name)
811         lctl.newdev(attach="lov %s %s" % (self.name, self.uuid),
812                     setup ="%s" % (mdc_uuid))
813
814     def cleanup(self):
815         for osc_uuid in self.devlist:
816             osc = lookup(self.dom_node.parentNode, osc_uuid)
817             if osc:
818                 n = OSC(osc)
819                 n.cleanup()
820             else:
821                 panic('osc not found:', osc_uuid)
822         Module.cleanup(self)
823         cleanup_mdc(self.dom_node.parentNode, self.mds_uuid)
824     def load_module(self):
825         for osc_uuid in self.devlist:
826             osc = lookup(self.dom_node.parentNode, osc_uuid)
827             if osc:
828                 n = OSC(osc)
829                 n.load_module()
830                 break
831             else:
832                 panic('osc not found:', osc_uuid)
833         Module.load_module(self)
834     def cleanup_module(self):
835         Module.cleanup_module(self)
836         for osc_uuid in self.devlist:
837             osc = lookup(self.dom_node.parentNode, osc_uuid)
838             if osc:
839                 n = OSC(osc)
840                 n.cleanup_module()
841                 break
842             else:
843                 panic('osc not found:', osc_uuid)
844
845 class LOVConfig(Module):
846     def __init__(self,dom_node):
847         Module.__init__(self, 'LOVConfig', dom_node)
848         self.lov_uuid = get_first_ref(dom_node, 'lov')
849         l = lookup(dom_node.parentNode, self.lov_uuid)
850         self.lov = LOV(l)
851         
852     def prepare(self):
853         lov = self.lov
854         self.info(lov.mds_uuid, lov.stripe_cnt, lov.stripe_sz, lov.stripe_off,
855                   lov.pattern, lov.devlist, lov.mds_name)
856         lctl.lovconfig(lov.uuid, lov.mds_name, lov.stripe_cnt,
857                        lov.stripe_sz, lov.stripe_off, lov.pattern,
858                        string.join(lov.devlist))
859
860     def cleanup(self):
861         #nothing to do here
862         pass
863
864
865 class MDS(Module):
866     def __init__(self,dom_node):
867         Module.__init__(self, 'MDS', dom_node)
868         self.devname, self.size = get_device(dom_node)
869         self.fstype = get_text(dom_node, 'fstype')
870         self.format = get_text(dom_node, 'autoformat', "no")
871         if self.fstype == 'extN':
872             self.add_module('lustre/extN', 'extN') 
873         self.add_module('lustre/mds', 'mds')
874         self.add_module('lustre/mds', 'mds_%s' % (self.fstype))
875             
876     def prepare(self):
877         self.info(self.devname, self.fstype, self.format)
878         blkdev = block_dev(self.devname, self.size, self.fstype, self.format)
879         lctl.newdev(attach="mds %s %s" % (self.name, self.uuid),
880                     setup ="%s %s" %(blkdev, self.fstype))
881     def cleanup(self):
882         Module.cleanup(self)
883         clean_loop(self.devname)
884
885 # Very unusual case, as there is no MDC element in the XML anymore
886 # Builds itself from an MDS node
887 class MDC(Module):
888     def __init__(self,dom_node):
889         self.mds = MDS(dom_node)
890         self.dom_node = dom_node
891         self.module_name = 'MDC'
892         self.kmodule_list = []
893         self._server = None
894         self._connected = 0
895
896         host = socket.gethostname()
897         self.name = 'MDC_'+host
898         self.uuid = self.name+'_UUID'
899
900         self.lookup_server(self.mds.uuid)
901         self.add_module('lustre/mdc', 'mdc')
902
903     def prepare(self):
904         self.info(self.mds.uuid)
905         srv = self.get_server()
906         lctl.connect(srv.net_type, srv.nid, srv.port, srv.uuid, srv.send_mem, srv.recv_mem)
907         lctl.newdev(attach="mdc %s %s" % (self.name, self.uuid),
908                         setup ="%s %s" %(self.mds.uuid, srv.uuid))
909             
910 class OBD(Module):
911     def __init__(self, dom_node):
912         Module.__init__(self, 'OBD', dom_node)
913         self.obdtype = get_attr(dom_node, 'type')
914         self.devname, self.size = get_device(dom_node)
915         self.fstype = get_text(dom_node, 'fstype')
916         self.format = get_text(dom_node, 'autoformat', 'yes')
917         if self.fstype == 'extN':
918             self.add_module('lustre/extN', 'extN') 
919         self.add_module('lustre/' + self.obdtype, self.obdtype)
920
921     # need to check /proc/mounts and /etc/mtab before
922     # formatting anything.
923     # FIXME: check if device is already formatted.
924     def prepare(self):
925         self.info(self.obdtype, self.devname, self.size, self.fstype, self.format)
926         if self.obdtype == 'obdecho':
927             blkdev = ''
928         else:
929             blkdev = block_dev(self.devname, self.size, self.fstype, self.format)
930         lctl.newdev(attach="%s %s %s" % (self.obdtype, self.name, self.uuid),
931                     setup ="%s %s" %(blkdev, self.fstype))
932     def cleanup(self):
933         Module.cleanup(self)
934         if not self.obdtype == 'obdecho':
935             clean_loop(self.devname)
936
937 class OST(Module):
938     def __init__(self,dom_node):
939         Module.__init__(self, 'OST', dom_node)
940         self.obd_uuid = get_first_ref(dom_node, 'obd')
941         self.add_module('lustre/ost', 'ost')
942
943     def prepare(self):
944         self.info(self.obd_uuid)
945         lctl.newdev(attach="ost %s %s" % (self.name, self.uuid),
946                     setup ="%s" % (self.obd_uuid))
947
948
949 # virtual interface for  OSC and LOV
950 class VOSC(Module):
951     def __init__(self,dom_node):
952         Module.__init__(self, 'VOSC', dom_node)
953         if dom_node.nodeName == 'lov':
954             self.osc = LOV(dom_node)
955         else:
956             self.osc = OSC(dom_node)
957     def prepare(self):
958         self.osc.prepare()
959     def cleanup(self):
960         self.osc.cleanup()
961     def load_module(self):
962         self.osc.load_module()
963     def cleanup_module(self):
964         self.osc.cleanup_module()
965         
966
967 class OSC(Module):
968     def __init__(self,dom_node):
969         Module.__init__(self, 'OSC', dom_node)
970         self.obd_uuid = get_first_ref(dom_node, 'obd')
971         self.ost_uuid = get_first_ref(dom_node, 'ost')
972         self.lookup_server(self.ost_uuid)
973         self.add_module('lustre/osc', 'osc')
974
975     def prepare(self):
976         self.info(self.obd_uuid, self.ost_uuid)
977         srv = self.get_server()
978         if local_net(srv):
979             lctl.connect(srv.net_type, srv.nid, srv.port, srv.uuid, srv.send_mem, srv.recv_mem)
980         else:
981             r =  find_route(srv)
982             if r:
983                 lctl.add_route_host(r[0], srv.uuid, r[1], r[2])
984             else:
985                 panic ("no route to",  srv.nid)
986             
987         lctl.newdev(attach="osc %s %s" % (self.name, self.uuid),
988                     setup ="%s %s" %(self.obd_uuid, srv.uuid))
989
990     def cleanup(self):
991         srv = self.get_server()
992         if local_net(srv):
993             Module.cleanup(self)
994         else:
995             self.info(self.obd_uuid, self.ost_uuid)
996             r =  find_route(srv)
997             if r:
998                 lctl.del_route_host(r[0], srv.uuid, r[1], r[2])
999             Module.cleanup(self)
1000             
1001
1002 class Mountpoint(Module):
1003     def __init__(self,dom_node):
1004         Module.__init__(self, 'MTPT', dom_node)
1005         self.path = get_text(dom_node, 'path')
1006         self.mds_uuid = get_first_ref(dom_node, 'mds')
1007         self.lov_uuid = get_first_ref(dom_node, 'osc')
1008         self.add_module('lustre/mdc', 'mdc')
1009         self.add_module('lustre/llite', 'llite')
1010         l = lookup(self.dom_node.parentNode, self.lov_uuid)
1011         self.osc = VOSC(l)
1012
1013     def prepare(self):
1014         self.osc.prepare()
1015         mdc_uuid = prepare_mdc(self.dom_node.parentNode, self.mds_uuid)
1016
1017         self.info(self.path, self.mds_uuid,self.lov_uuid)
1018         cmd = "mount -t lustre_lite -o osc=%s,mdc=%s none %s" % \
1019               (self.lov_uuid, mdc_uuid, self.path)
1020         run("mkdir", self.path)
1021         ret, val = run(cmd)
1022         if ret:
1023             panic("mount failed:", self.path)
1024
1025     def cleanup(self):
1026         self.info(self.path, self.mds_uuid,self.lov_uuid)
1027         (rc, out) = run("umount", self.path)
1028         if rc:
1029             log("umount failed, cleanup will most likely not work.")
1030         l = lookup(self.dom_node.parentNode, self.lov_uuid)
1031         self.osc.cleanup()
1032         cleanup_mdc(self.dom_node.parentNode, self.mds_uuid)
1033
1034     def load_module(self):
1035         self.osc.load_module()
1036         Module.load_module(self)
1037     def cleanup_module(self):
1038         Module.cleanup_module(self)
1039         self.osc.cleanup_module()
1040
1041
1042 # ============================================================
1043 # XML processing and query
1044 # TODO: Change query funcs to use XPath, which is muc cleaner
1045
1046 def get_device(obd):
1047     list = obd.getElementsByTagName('device')
1048     if len(list) > 0:
1049         dev = list[0]
1050         dev.normalize();
1051         size = get_attr_int(dev, 'size', 0)
1052         return dev.firstChild.data, size
1053     return '', 0
1054
1055 # Get the text content from the first matching child
1056 # If there is no content (or it is all whitespace), return
1057 # the default
1058 def get_text(dom_node, tag, default=""):
1059     list = dom_node.getElementsByTagName(tag)
1060     if len(list) > 0:
1061         dom_node = list[0]
1062         dom_node.normalize()
1063         if dom_node.firstChild:
1064             txt = string.strip(dom_node.firstChild.data)
1065             if txt:
1066                 return txt
1067     return default
1068
1069 def get_text_int(dom_node, tag, default=0):
1070     list = dom_node.getElementsByTagName(tag)
1071     n = default
1072     if len(list) > 0:
1073         dom_node = list[0]
1074         dom_node.normalize()
1075         if dom_node.firstChild:
1076             txt = string.strip(dom_node.firstChild.data)
1077             if txt:
1078                 try:
1079                     n = int(txt)
1080                 except ValueError:
1081                     panic("text value is not integer:", txt)
1082     return n
1083
1084 def get_attr(dom_node, attr, default=""):
1085     v = dom_node.getAttribute(attr)
1086     if v:
1087         return v
1088     return default
1089
1090 def get_attr_int(dom_node, attr, default=0):
1091     n = default
1092     v = dom_node.getAttribute(attr)
1093     if v:
1094         try:
1095             n = int(v)
1096         except ValueError:
1097             panic("attr value is not integer", v)
1098     return n
1099
1100 def get_first_ref(dom_node, tag):
1101     """ Get the first uuidref of the type TAG. Used one only
1102     one is expected.  Returns the uuid."""
1103     uuid = None
1104     refname = '%s_ref' % tag
1105     list = dom_node.getElementsByTagName(refname)
1106     if len(list) > 0:
1107         uuid = getRef(list[0])
1108     return uuid
1109     
1110 def get_all_refs(dom_node, tag):
1111     """ Get all the refs of type TAG.  Returns list of uuids. """
1112     uuids = []
1113     refname = '%s_ref' % tag
1114     list = dom_node.getElementsByTagName(refname)
1115     if len(list) > 0:
1116         for i in list:
1117             uuids.append(getRef(i))
1118     return uuids
1119
1120 def get_ost_net(dom_node, uuid):
1121     ost = lookup(dom_node, uuid)
1122     uuid = get_first_ref(ost, 'network')
1123     if not uuid:
1124         return None
1125     return lookup(dom_node, uuid)
1126
1127 def nid2server(dom_node, nid):
1128     netlist = dom_node.getElementsByTagName('network')
1129     for net_node in netlist:
1130         if get_text(net_node, 'server') == nid:
1131             return Network(net_node)
1132     return None
1133     
1134 def lookup(dom_node, uuid):
1135     for n in dom_node.childNodes:
1136         if n.nodeType == n.ELEMENT_NODE:
1137             if getUUID(n) == uuid:
1138                 return n
1139             else:
1140                 n = lookup(n, uuid)
1141                 if n: return n
1142     return None
1143             
1144 # Get name attribute of dom_node
1145 def getName(dom_node):
1146     return dom_node.getAttribute('name')
1147
1148 def getRef(dom_node):
1149     return dom_node.getAttribute('uuidref')
1150
1151 # Get name attribute of dom_node
1152 def getUUID(dom_node):
1153     return dom_node.getAttribute('uuid')
1154
1155 # the tag name is the service type
1156 # fixme: this should do some checks to make sure the dom_node is a service
1157 def getServiceType(dom_node):
1158     return dom_node.nodeName
1159
1160 #
1161 # determine what "level" a particular node is at.
1162 # the order of iniitailization is based on level. 
1163 def getServiceLevel(dom_node):
1164     type = getServiceType(dom_node)
1165     if type in ('network',):
1166         return 10
1167     elif type in ('device', 'ldlm'):
1168         return 20
1169     elif type in ('obd', 'mdd'):
1170         return 30
1171     elif type in ('mds','ost'):
1172         return 40
1173     elif type in ('mdc','osc'):
1174         return 50
1175     elif type in ('lov', 'lovconfig'):
1176         return 60
1177     elif type in ('mountpoint',):
1178         return 70
1179     return 0
1180
1181 #
1182 # return list of services in a profile. list is a list of tuples
1183 # [(level, dom_node),]
1184 def getServices(lustreNode, profileNode):
1185     list = []
1186     for n in profileNode.childNodes:
1187         if n.nodeType == n.ELEMENT_NODE:
1188             servNode = lookup(lustreNode, getRef(n))
1189             if not servNode:
1190                 print n
1191                 panic('service not found: ' + getRef(n))
1192             level = getServiceLevel(servNode)
1193             list.append((level, servNode))
1194     list.sort()
1195     return list
1196
1197 def getByName(lustreNode, name, tag):
1198     ndList = lustreNode.getElementsByTagName(tag)
1199     for nd in ndList:
1200         if getName(nd) == name:
1201             return nd
1202     return None
1203     
1204
1205 ############################################################
1206 # MDC UUID hack - 
1207 # FIXME: clean this mess up!
1208 #
1209 mdc_uuid = None
1210 def prepare_mdc(dom_node, mds_uuid):
1211     global mdc_uuid
1212     mds_node = lookup(dom_node, mds_uuid);
1213     if not mds_node:
1214         panic("no mds:", mds_uuid)
1215     if mdc_uuid:
1216         return mdc_uuid
1217     mdc = MDC(mds_node)
1218     mdc.prepare()
1219     mdc_uuid = mdc.uuid
1220     return mdc_uuid
1221
1222 mdc_cleaned = None
1223 def cleanup_mdc(dom_node, mds_uuid):
1224     global mdc_cleaned
1225     mds_node = lookup(dom_node, mds_uuid);
1226     if not mds_node:
1227         panic("no mds:", mds_uuid)
1228     if not mdc_cleaned:
1229         mdc = MDC(mds_node)
1230         mdc.cleanup()
1231         mdc_uuid = None
1232         mdc_cleaned = 'yes'
1233         
1234
1235 ############################################################
1236 # routing ("rooting")
1237 #
1238 routes = []
1239 local_node = []
1240 router_flag = 0
1241
1242 def init_node(dom_node):
1243     global local_node, router_flag
1244     netlist = dom_node.getElementsByTagName('network')
1245     for dom_net in netlist:
1246         type = get_attr(dom_net, 'type')
1247         gw = get_text(dom_net, 'server')
1248         local_node.append((type, gw))
1249
1250 def node_needs_router():
1251     return router_flag
1252
1253 def get_routes(type, gw, dom_net):
1254     """ Return the routes as a list of tuples of the form:
1255         [(type, gw, lo, hi),]"""
1256     res = []
1257     tbl = dom_net.getElementsByTagName('route_tbl')
1258     for t in tbl:
1259         routes = t.getElementsByTagName('route')
1260         for r in routes:
1261             lo = get_attr(r, 'lo')
1262             hi = get_attr(r, 'hi', '')
1263             res.append((type, gw, lo, hi))
1264     return res
1265     
1266
1267 def init_route_config(lustre):
1268     """ Scan the lustre config looking for routers.  Build list of
1269     routes. """
1270     global routes, router_flag
1271     routes = []
1272     list = lustre.getElementsByTagName('node')
1273     for node in list:
1274         if get_attr(node, 'router'):
1275             router_flag = 1
1276             for (local_type, local_nid) in local_node:
1277                 gw = None
1278                 netlist = node.getElementsByTagName('network')
1279                 for dom_net in netlist:
1280                     if local_type == get_attr(dom_net, 'type'):
1281                         gw = get_text(dom_net, 'server')
1282                         break
1283                 if not gw:
1284                     continue
1285                 for dom_net in netlist:
1286                     if local_type != get_attr(dom_net, 'type'):
1287                         for route in get_routes(local_type, gw, dom_net):
1288                             routes.append(route)
1289     
1290
1291 def local_net(net):
1292     global local_node
1293     for iface in local_node:
1294         if net.net_type == iface[0]:
1295             return 1
1296     return 0
1297
1298 def find_route(net):
1299     global local_node, routes
1300     frm_type = local_node[0][0]
1301     to_type = net.net_type
1302     to = net.nid
1303     debug ('looking for route to', to_type,to)
1304     for r in routes:
1305         if  r[2] == to:
1306             return r
1307     return None
1308            
1309     
1310         
1311
1312 ############################################################
1313 # lconf level logic
1314 # Start a service.
1315 def startService(dom_node, module_flag):
1316     type = getServiceType(dom_node)
1317     debug('Service:', type, getName(dom_node), getUUID(dom_node))
1318     # there must be a more dynamic way of doing this...
1319     n = None
1320     if type == 'ldlm':
1321         n = LDLM(dom_node)
1322     elif type == 'lov':
1323         n = LOV(dom_node)
1324     elif type == 'lovconfig':
1325         n = LOVConfig(dom_node)
1326     elif type == 'network':
1327         n = Network(dom_node)
1328     elif type == 'obd':
1329         n = OBD(dom_node)
1330     elif type == 'ost':
1331         n = OST(dom_node)
1332     elif type == 'mds':
1333         n = MDS(dom_node)
1334     elif type == 'osc':
1335         n = VOSC(dom_node)
1336     elif type == 'mdc':
1337         n = MDC(dom_node)
1338     elif type == 'mountpoint':
1339         n = Mountpoint(dom_node)
1340     else:
1341         panic ("unknown service type:", type)
1342
1343     if module_flag:
1344         if config.nomod():
1345             return
1346         if config.cleanup():
1347             n.cleanup_module()
1348         else:
1349             n.load_module()
1350     else:
1351         if config.nosetup():
1352             return
1353         if config.cleanup():
1354             n.cleanup()
1355         else:
1356             n.prepare()
1357
1358 #
1359 # Prepare the system to run lustre using a particular profile
1360 # in a the configuration. 
1361 #  * load & the modules
1362 #  * setup networking for the current node
1363 #  * make sure partitions are in place and prepared
1364 #  * initialize devices with lctl
1365 # Levels is important, and needs to be enforced.
1366 def startProfile(lustreNode, profileNode, module_flag):
1367     if not profileNode:
1368         panic("profile:", profile, "not found.")
1369     services = getServices(lustreNode, profileNode)
1370     if config.cleanup():
1371         services.reverse()
1372     for s in services:
1373         startService(s[1], module_flag)
1374
1375
1376 #
1377 # Load profile for 
1378 def doHost(lustreNode, hosts):
1379     global routes
1380     dom_node = None
1381     for h in hosts:
1382         dom_node = getByName(lustreNode, h, 'node')
1383         if dom_node:
1384             break
1385
1386     if not dom_node:
1387         print 'No host entry found.'
1388         return
1389
1390     if not get_attr(dom_node, 'router'):
1391         init_node(dom_node)
1392         init_route_config(lustreNode)
1393     else:
1394         global router_flag 
1395         router_flag = 1
1396
1397     # Two step process: (1) load modules, (2) setup lustre
1398     # if not cleaning, load modules first.
1399     module_flag = not config.cleanup()
1400     reflist = dom_node.getElementsByTagName('profile')
1401     for profile in reflist:
1402             startProfile(lustreNode,  profile, module_flag)
1403
1404     if not config.cleanup():
1405         sys_set_debug_path()
1406         script = config.gdb_script()
1407         run(lctl.lctl, ' modules >', script)
1408         if config.gdb():
1409             # dump /tmp/ogdb and sleep/pause here
1410             log ("The GDB module script is in", script)
1411             time.sleep(5)
1412             
1413     module_flag = not module_flag
1414     for profile in reflist:
1415             startProfile(lustreNode,  profile, module_flag)
1416
1417 ############################################################
1418 # Command line processing
1419 #
1420 def parse_cmdline(argv):
1421     short_opts = "hdnv"
1422     long_opts = ["ldap", "reformat", "lustre=", "verbose", "gdb",
1423                  "portals=", "makeldiff", "cleanup", "noexec",
1424                  "help", "node=", "get=", "nomod", "nosetup",
1425                  "dump="]
1426     opts = []
1427     args = []
1428     try:
1429         opts, args = getopt.getopt(argv, short_opts, long_opts)
1430     except getopt.error:
1431         print "invalid opt"
1432         usage()
1433
1434     for o, a in opts:
1435         if o in ("-h", "--help"):
1436             usage()
1437         if o in ("-d","--cleanup"):
1438             config.cleanup(1)
1439         if o in ("-v", "--verbose"):
1440             config.verbose(1)
1441         if o in ("-n", "--noexec"):
1442             config.noexec(1)
1443             config.verbose(1)
1444         if o == "--portals":
1445             config.portals =  a
1446         if o == "--lustre":
1447             config.lustre  = a
1448         if o  == "--reformat":
1449             config.reformat(1)
1450         if o  == "--node":
1451             config.node(a)
1452         if o  == "--get":
1453             config.url(a)
1454         if o  == "--gdb":
1455             config.gdb(1)
1456         if o  == "--nomod":
1457             config.nomod(1)
1458         if o  == "--nosetup":
1459             config.nosetup(1)
1460         if o  == "--dump":
1461             config.dump_file(a)
1462     return args
1463
1464 def fetch(url):
1465     import urllib
1466     data = ""
1467     try:
1468         s = urllib.urlopen(url)
1469         data = s.read()
1470     except:
1471         usage()
1472     return data
1473
1474 def setupModulePath(cmd):
1475     base = os.path.dirname(cmd)
1476     if os.access(base+"/Makefile", os.R_OK):
1477         config.src_dir(base + "/../../")
1478
1479 def sys_set_debug_path():
1480     debug("debug path: ", config.debug_path())
1481     if config.noexec():
1482         return
1483     try:
1484         fp = open('/proc/sys/portals/debug_path', 'w')
1485         fp.write(config.debug_path())
1486         fp.close()
1487     except IOError, e:
1488         print e
1489              
1490 #/proc/sys/net/core/rmem_max
1491 #/proc/sys/net/core/wmem_max
1492 def sys_set_netmem_max(path, max):
1493     debug("setting", path, "to at least", max)
1494     if config.noexec():
1495         return
1496     fp = open(path)
1497     str = fp.readline()
1498     fp.close
1499     cur = int(str)
1500     if max > cur:
1501         fp = open(path, 'w')
1502         fp.write('%d\n' %(max))
1503         fp.close()
1504     
1505     
1506 def sys_make_devices():
1507     if not os.access('/dev/portals', os.R_OK):
1508         run('mknod /dev/portals c 10 240')
1509     if not os.access('/dev/obd', os.R_OK):
1510         run('mknod /dev/obd c 10 241')
1511
1512 # Initialize or shutdown lustre according to a configuration file
1513 #   * prepare the system for lustre
1514 #   * configure devices with lctl
1515 # Shutdown does steps in reverse
1516 #
1517 def main():
1518     global TCP_ACCEPTOR, lctl, MAXTCPBUF
1519     host = socket.gethostname()
1520
1521     args = parse_cmdline(sys.argv[1:])
1522     if len(args) > 0:
1523         if not os.access(args[0], os.R_OK | os.W_OK):
1524             print 'File not found:', args[0]
1525             sys.exit(1)
1526         dom = xml.dom.minidom.parse(args[0])
1527     elif config.url():
1528         xmldata = fetch(config.url())
1529         dom = xml.dom.minidom.parseString(xmldata)
1530     else:
1531         usage()
1532
1533     node_list = []
1534     if config.node():
1535         node_list.append(config.node())
1536     else:
1537         if len(host) > 0:
1538             node_list.append(host)
1539         node_list.append('localhost')
1540     debug("configuring for host: ", node_list)
1541
1542     if len(host) > 0:
1543         config._debug_path = config._debug_path + '-' + host
1544         config._gdb_script = config._gdb_script + '-' + host
1545
1546     TCP_ACCEPTOR = find_prog('acceptor')
1547     if not TCP_ACCEPTOR:
1548         if config.noexec():
1549             TCP_ACCEPTOR = 'acceptor'
1550             debug('! acceptor not found')
1551         else:
1552             panic('acceptor not found')
1553
1554     lctl = LCTLInterface('lctl')
1555
1556     setupModulePath(sys.argv[0])
1557     sys_make_devices()
1558     sys_set_netmem_max('/proc/sys/net/core/rmem_max', MAXTCPBUF)
1559     sys_set_netmem_max('/proc/sys/net/core/wmem_max', MAXTCPBUF)
1560     doHost(dom.documentElement, node_list)
1561
1562 if __name__ == "__main__":
1563     try:
1564         main()
1565     except LconfError, e:
1566         print e
1567     except CommandError, e:
1568         e.dump()