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