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