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