Whamcloud - gitweb
* cleanup multiple MDC's correctly
[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
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 --startlevel <num>  Specify the level of services to start with (default 0)
68 --endlevel <num>    Specify the level of services to end with (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._start_level = 0
110         self._end_level = 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 startlevel(self, val = None):
173         if val: self._start_level = int(val)
174         return self._start_level
175
176     def endlevel(self, val = None):
177         if val: self._end_level = int(val)
178         return self._end_level
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  == 'tcp':
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 == 'tcp':
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 == 'tcp':
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     out = lctl.device_list()
649     for s in out:
650         if uuid == string.split(s)[4]:
651             return 1
652     return 0
653     
654
655 # ============================================================
656 # Classes to prepare and cleanup the various objects
657 #
658 class Module:
659     """ Base class for the rest of the modules. The default cleanup method is
660     defined here, as well as some utilitiy funcs.
661     """
662     def __init__(self, module_name, dom_node):
663         self.dom_node = dom_node
664         self.module_name = module_name
665         self.name = get_attr(dom_node, 'name')
666         self.uuid = get_attr(dom_node, 'uuid')
667         self.kmodule_list = []
668         self._server = None
669         self._connected = 0
670         
671     def info(self, *args):
672         msg = string.join(map(str,args))
673         print self.module_name + ":", self.name, self.uuid, msg
674
675
676     def lookup_server(self, srv_uuid):
677         """ Lookup a server's network information """
678         net = get_ost_net(self.dom_node.parentNode, srv_uuid)
679         if not net:
680             panic ("Unable to find a server for:", srv_uuid)
681         self._server = Network(net)
682
683     def get_server(self):
684         return self._server
685
686     def cleanup(self):
687         """ default cleanup, used for most modules """
688         self.info()
689         srv = self.get_server()
690         if srv and local_net(srv):
691             try:
692                 lctl.disconnect(srv.net_type, srv.nid, srv.port, srv.uuid)
693             except CommandError, e:
694                 log(self.module_name, "disconnect failed: ", self.name)
695                 e.dump()
696                 cleanup_error(e.rc)
697         try:
698             lctl.cleanup(self.name, self.uuid)
699         except CommandError, e:
700             log(self.module_name, "cleanup failed: ", self.name)
701             e.dump()
702             cleanup_error(e.rc)
703
704     def add_module(self, dev_dir, modname):
705         """Append a module to list of modules to load."""
706         self.kmodule_list.append((dev_dir, modname))
707
708     def mod_loaded(self, modname):
709         """Check if a module is already loaded. Look in /proc/modules for it."""
710         fp = open('/proc/modules')
711         lines = fp.readlines()
712         fp.close()
713         # please forgive my tired fingers for this one
714         ret = filter(lambda word, mod=modname: word == mod,
715                      map(lambda line: string.split(line)[0], lines))
716         return ret
717
718     def load_module(self):
719         """Load all the modules in the list in the order they appear."""
720         for dev_dir, mod in self.kmodule_list:
721             #  (rc, out) = run ('/sbin/lsmod | grep -s', mod)
722             if self.mod_loaded(mod) and not config.noexec():
723                 continue
724             log ('loading module:', mod)
725             if config.src_dir():
726                 module = find_module(config.src_dir(),dev_dir,  mod)
727                 if not module:
728                     panic('module not found:', mod)
729                 (rc, out)  = run('/sbin/insmod', module)
730                 if rc:
731                     raise CommandError('insmod', out, rc)
732             else:
733                 (rc, out) = run('/sbin/modprobe', mod)
734                 if rc:
735                     raise CommandError('modprobe', out, rc)
736             
737     def cleanup_module(self):
738         """Unload the modules in the list in reverse order."""
739         rev = self.kmodule_list
740         rev.reverse()
741         for dev_dir, mod in rev:
742             if not self.mod_loaded(mod):
743                 continue
744             # debug hack
745             if mod == 'portals' and config.dump_file():
746                 lctl.dump(config.dump_file())
747             log('unloading module:', mod)
748             if config.noexec():
749                 continue
750             (rc, out) = run('/sbin/rmmod', mod)
751             if rc:
752                 log('! unable to unload module:', mod)
753                 logall(out)
754         
755
756 class Network(Module):
757     def __init__(self,dom_node):
758         Module.__init__(self, 'NETWORK', dom_node)
759         self.net_type = get_attr(dom_node,'type')
760         self.nid = get_text(dom_node, 'server', '*')
761         self.port = get_text_int(dom_node, 'port', 0)
762         self.send_mem = get_text_int(dom_node, 'send_mem', DEFAULT_TCPBUF)
763         self.recv_mem = get_text_int(dom_node, 'recv_mem', DEFAULT_TCPBUF)
764         if '*' in self.nid:
765             self.nid = get_local_address(self.net_type, self.nid)
766             if not self.nid:
767                 panic("unable to set nid for", self.net_type, self.nid)
768             debug("nid:", self.nid)
769
770         self.add_module('portals/linux/oslib/', 'portals')
771         if node_needs_router():
772             self.add_module('portals/linux/router', 'kptlrouter')
773         if self.net_type == 'tcp':
774             self.add_module('portals/linux/socknal', 'ksocknal')
775         if self.net_type == 'toe':
776             self.add_module('portals/linux/toenal', 'ktoenal')
777         if self.net_type == 'elan':
778             self.add_module('portals/linux/rqswnal', 'kqswnal')
779         if self.net_type == 'gm':
780             self.add_module('portals/linux/gmnal', 'kgmnal')
781         self.add_module('lustre/obdclass', 'obdclass')
782         self.add_module('lustre/ptlrpc', 'ptlrpc')
783
784     def prepare(self):
785         self.info(self.net_type, self.nid, self.port)
786         if self.net_type in ('tcp', 'toe'):
787             nal_id = '' # default is socknal
788             if self.net_type == 'toe':
789                 nal_id = '-N 4'
790             ret, out = run(TCP_ACCEPTOR, '-s', self.send_mem, '-r', self.recv_mem, nal_id, self.port)
791             if ret:
792                 raise CommandError(TCP_ACCEPTOR, out, ret)
793         ret = self.dom_node.getElementsByTagName('route_tbl')
794         for a in ret:
795             for r in a.getElementsByTagName('route'):
796                 net_type = get_attr(r, 'type')
797                 gw = get_attr(r, 'gw')
798                 lo = get_attr(r, 'lo')
799                 hi = get_attr(r,'hi', '')
800                 lctl.add_route(net_type, gw, lo, hi)
801                 if net_type == 'tcp' and net_type == self.net_type and hi == '':
802                     srv = nid2server(self.dom_node.parentNode.parentNode, lo)
803                     if not srv:
804                         panic("no server for nid", lo)
805                     else:
806                         lctl.connect(srv.net_type, srv.nid, srv.port, srv.uuid, srv.send_mem, srv.recv_mem)
807
808             
809         lctl.network(self.net_type, self.nid)
810         lctl.newdev(attach = "ptlrpc RPCDEV RPCDEV_UUID")
811
812     def cleanup(self):
813         self.info(self.net_type, self.nid, self.port)
814         ret = self.dom_node.getElementsByTagName('route_tbl')
815         for a in ret:
816             for r in a.getElementsByTagName('route'):
817                 lo = get_attr(r, 'lo')
818                 hi = get_attr(r,'hi', '')
819                 if self.net_type == 'tcp' and hi == '':
820                     srv = nid2server(self.dom_node.parentNode.parentNode, lo)
821                     if not srv:
822                         panic("no server for nid", lo)
823                     else:
824                         try:
825                             lctl.disconnect(srv.net_type, srv.nid, srv.port, srv.uuid)
826                         except CommandError, e:
827                             print "disconnect failed: ", self.name
828                             e.dump()
829                             cleanup_error(e.rc)
830                 try:
831                     lctl.del_route(self.net_type, self.nid, lo, hi)
832                 except CommandError, e:
833                     print "del_route failed: ", self.name
834                     e.dump()
835                     cleanup_error(e.rc)
836               
837         try:
838             lctl.cleanup("RPCDEV", "RPCDEV_UUID")
839         except CommandError, e:
840             print "cleanup failed: ", self.name
841             e.dump()
842             cleanup_error(e.rc)
843         try:
844             lctl.disconnectAll(self.net_type)
845         except CommandError, e:
846             print "disconnectAll failed: ", self.name
847             e.dump()
848             cleanup_error(e.rc)
849         if self.net_type == 'tcp':
850             # yikes, this ugly! need to save pid in /var/something
851             run("killall acceptor")
852
853 class LDLM(Module):
854     def __init__(self,dom_node):
855         Module.__init__(self, 'LDLM', dom_node)
856         self.add_module('lustre/ldlm', 'ldlm')
857     def prepare(self):
858         self.info()
859         lctl.newdev(attach="ldlm %s %s" % (self.name, self.uuid),
860                     setup ="")
861
862 class LOV(Module):
863     def __init__(self,dom_node):
864         Module.__init__(self, 'LOV', dom_node)
865         self.mds_uuid = get_first_ref(dom_node, 'mds')
866         mds= lookup(dom_node.parentNode, self.mds_uuid)
867         self.mds_name = getName(mds)
868         devs = dom_node.getElementsByTagName('devices')
869         if len(devs) > 0:
870             dev_node = devs[0]
871             self.stripe_sz = get_attr_int(dev_node, 'stripesize', 65536)
872             self.stripe_off = get_attr_int(dev_node, 'stripeoffset', 0)
873             self.pattern = get_attr_int(dev_node, 'pattern', 0)
874             self.devlist = get_all_refs(dev_node, 'osc')
875             self.stripe_cnt = get_attr_int(dev_node, 'stripecount', len(self.devlist))
876         self.add_module('lustre/mdc', 'mdc')
877         self.add_module('lustre/lov', 'lov')
878
879     def prepare(self):
880         for osc_uuid in self.devlist:
881             osc = lookup(self.dom_node.parentNode, osc_uuid)
882             if osc:
883                 n = OSC(osc)
884                 n.prepare()
885             else:
886                 panic('osc not found:', osc_uuid)
887         mdc_uuid = prepare_mdc(self.dom_node.parentNode, self.mds_uuid)
888         self.info(self.mds_uuid, self.stripe_cnt, self.stripe_sz,
889                   self.stripe_off, self.pattern, self.devlist, self.mds_name)
890         lctl.newdev(attach="lov %s %s" % (self.name, self.uuid),
891                     setup ="%s" % (mdc_uuid))
892
893     def cleanup(self):
894         for osc_uuid in self.devlist:
895             osc = lookup(self.dom_node.parentNode, osc_uuid)
896             if osc:
897                 n = OSC(osc)
898                 n.cleanup()
899             else:
900                 panic('osc not found:', osc_uuid)
901         Module.cleanup(self)
902         cleanup_mdc(self.dom_node.parentNode, self.mds_uuid)
903
904
905     def load_module(self):
906         for osc_uuid in self.devlist:
907             osc = lookup(self.dom_node.parentNode, osc_uuid)
908             if osc:
909                 n = OSC(osc)
910                 n.load_module()
911                 break
912             else:
913                 panic('osc not found:', osc_uuid)
914         Module.load_module(self)
915
916
917     def cleanup_module(self):
918         Module.cleanup_module(self)
919         for osc_uuid in self.devlist:
920             osc = lookup(self.dom_node.parentNode, osc_uuid)
921             if osc:
922                 n = OSC(osc)
923                 n.cleanup_module()
924                 break
925             else:
926                 panic('osc not found:', osc_uuid)
927
928 class LOVConfig(Module):
929     def __init__(self,dom_node):
930         Module.__init__(self, 'LOVConfig', dom_node)
931         self.lov_uuid = get_first_ref(dom_node, 'lov')
932         l = lookup(dom_node.parentNode, self.lov_uuid)
933         self.lov = LOV(l)
934         
935     def prepare(self):
936         lov = self.lov
937         self.info(lov.mds_uuid, lov.stripe_cnt, lov.stripe_sz, lov.stripe_off,
938                   lov.pattern, lov.devlist, lov.mds_name)
939         lctl.lov_setconfig(lov.uuid, lov.mds_name, lov.stripe_cnt,
940                            lov.stripe_sz, lov.stripe_off, lov.pattern,
941                            string.join(lov.devlist))
942
943     def cleanup(self):
944         #nothing to do here
945         pass
946
947
948 class MDS(Module):
949     def __init__(self,dom_node):
950         Module.__init__(self, 'MDS', dom_node)
951         self.devname, self.size = get_device(dom_node)
952         self.fstype = get_text(dom_node, 'fstype')
953         # FIXME: if fstype not set, then determine based on kernel version
954         self.format = get_text(dom_node, 'autoformat', "no")
955         if self.fstype == 'extN':
956             self.add_module('lustre/extN', 'extN') 
957         self.add_module('lustre/mds', 'mds')
958         self.add_module('lustre/mds', 'mds_%s' % (self.fstype))
959             
960     def prepare(self):
961         self.info(self.devname, self.fstype, self.format)
962         blkdev = block_dev(self.devname, self.size, self.fstype, self.format)
963         if not is_prepared('MDT_UUID'):
964             lctl.newdev(attach="mdt %s %s" % ('MDT', 'MDT_UUID'),
965                         setup ="")
966         lctl.newdev(attach="mds %s %s" % (self.name, self.uuid),
967                     setup ="%s %s" %(blkdev, self.fstype))
968     def cleanup(self):
969         if is_prepared('MDT_UUID'):
970             try:
971                 lctl.cleanup("MDT", "MDT_UUID")
972             except CommandError, e:
973                 print "cleanup failed: ", self.name
974                 e.dump()
975                 cleanup_error(e.rc)
976         Module.cleanup(self)
977         clean_loop(self.devname)
978
979 # Very unusual case, as there is no MDC element in the XML anymore
980 # Builds itself from an MDS node
981 class MDC(Module):
982     def __init__(self,dom_node):
983         self.mds = MDS(dom_node)
984         self.dom_node = dom_node
985         self.module_name = 'MDC'
986         self.kmodule_list = []
987         self._server = None
988         self._connected = 0
989
990         host = socket.gethostname()
991         self.name = 'MDC_%s_%s' % ( host, self.mds.name )
992         self.uuid = self.name + '_UUID' 
993
994         self.lookup_server(self.mds.uuid)
995         self.add_module('lustre/mdc', 'mdc')
996
997     def prepare(self):
998         self.info(self.mds.uuid)
999         srv = self.get_server()
1000         lctl.connect(srv.net_type, srv.nid, srv.port, srv.uuid, srv.send_mem, srv.recv_mem)
1001         lctl.newdev(attach="mdc %s %s" % (self.name, self.uuid),
1002                         setup ="%s %s" %(self.mds.uuid, srv.uuid))
1003             
1004 class OBD(Module):
1005     def __init__(self, dom_node):
1006         Module.__init__(self, 'OBD', dom_node)
1007         self.obdtype = get_attr(dom_node, 'type')
1008         self.devname, self.size = get_device(dom_node)
1009         self.fstype = get_text(dom_node, 'fstype')
1010         # FIXME: if fstype not set, then determine based on kernel version
1011         self.format = get_text(dom_node, 'autoformat', 'yes')
1012         if self.fstype == 'extN':
1013             self.add_module('lustre/extN', 'extN') 
1014         self.add_module('lustre/' + self.obdtype, self.obdtype)
1015
1016     # need to check /proc/mounts and /etc/mtab before
1017     # formatting anything.
1018     # FIXME: check if device is already formatted.
1019     def prepare(self):
1020         self.info(self.obdtype, self.devname, self.size, self.fstype, self.format)
1021         if self.obdtype == 'obdecho':
1022             blkdev = ''
1023         else:
1024             blkdev = block_dev(self.devname, self.size, self.fstype, self.format)
1025         lctl.newdev(attach="%s %s %s" % (self.obdtype, self.name, self.uuid),
1026                     setup ="%s %s" %(blkdev, self.fstype))
1027     def cleanup(self):
1028         Module.cleanup(self)
1029         if not self.obdtype == 'obdecho':
1030             clean_loop(self.devname)
1031
1032 class OST(Module):
1033     def __init__(self,dom_node):
1034         Module.__init__(self, 'OST', dom_node)
1035         self.obd_uuid = get_first_ref(dom_node, 'obd')
1036         self.add_module('lustre/ost', 'ost')
1037
1038     def prepare(self):
1039         self.info(self.obd_uuid)
1040         lctl.newdev(attach="ost %s %s" % (self.name, self.uuid),
1041                     setup ="%s" % (self.obd_uuid))
1042
1043
1044 # virtual interface for  OSC and LOV
1045 class VOSC(Module):
1046     def __init__(self,dom_node):
1047         Module.__init__(self, 'VOSC', dom_node)
1048         if dom_node.nodeName == 'lov':
1049             self.osc = LOV(dom_node)
1050         else:
1051             self.osc = OSC(dom_node)
1052     def prepare(self):
1053         self.osc.prepare()
1054     def cleanup(self):
1055         self.osc.cleanup()
1056     def load_module(self):
1057         self.osc.load_module()
1058     def cleanup_module(self):
1059         self.osc.cleanup_module()
1060         
1061
1062 class OSC(Module):
1063     def __init__(self,dom_node):
1064         Module.__init__(self, 'OSC', dom_node)
1065         self.obd_uuid = get_first_ref(dom_node, 'obd')
1066         self.ost_uuid = get_first_ref(dom_node, 'ost')
1067         self.lookup_server(self.ost_uuid)
1068         self.add_module('lustre/osc', 'osc')
1069
1070     def prepare(self):
1071         self.info(self.obd_uuid, self.ost_uuid)
1072         srv = self.get_server()
1073         if local_net(srv):
1074             lctl.connect(srv.net_type, srv.nid, srv.port, srv.uuid, srv.send_mem, srv.recv_mem)
1075         else:
1076             r =  find_route(srv)
1077             if r:
1078                 lctl.add_route_host(r[0], srv.uuid, r[1], r[2])
1079             else:
1080                 panic ("no route to",  srv.nid)
1081             
1082         lctl.newdev(attach="osc %s %s" % (self.name, self.uuid),
1083                     setup ="%s %s" %(self.obd_uuid, srv.uuid))
1084
1085     def cleanup(self):
1086         srv = self.get_server()
1087         if local_net(srv):
1088             Module.cleanup(self)
1089         else:
1090             self.info(self.obd_uuid, self.ost_uuid)
1091             r =  find_route(srv)
1092             if r:
1093                 try:
1094                     lctl.del_route_host(r[0], srv.uuid, r[1], r[2])
1095                 except CommandError, e:
1096                     print "del_route failed: ", self.name
1097                     e.dump()
1098                     cleanup_error(e.rc)
1099             Module.cleanup(self)
1100             
1101
1102 class Mountpoint(Module):
1103     def __init__(self,dom_node):
1104         Module.__init__(self, 'MTPT', dom_node)
1105         self.path = get_text(dom_node, 'path')
1106         self.mds_uuid = get_first_ref(dom_node, 'mds')
1107         self.lov_uuid = get_first_ref(dom_node, 'osc')
1108         self.add_module('lustre/mdc', 'mdc')
1109         self.add_module('lustre/llite', 'llite')
1110         l = lookup(self.dom_node.parentNode, self.lov_uuid)
1111         self.osc = VOSC(l)
1112
1113     def prepare(self):
1114         self.osc.prepare()
1115         mdc_uuid = prepare_mdc(self.dom_node.parentNode, self.mds_uuid)
1116         self.info(self.path, self.mds_uuid, self.lov_uuid)
1117         cmd = "mount -t lustre_lite -o osc=%s,mdc=%s none %s" % \
1118               (self.lov_uuid, mdc_uuid, self.path)
1119         run("mkdir", self.path)
1120         ret, val = run(cmd)
1121         if ret:
1122             panic("mount failed:", self.path)
1123
1124     def cleanup(self):
1125         self.info(self.path, self.mds_uuid,self.lov_uuid)
1126         if config.force():
1127             (rc, out) = run("umount -f", self.path)
1128         else:
1129             (rc, out) = run("umount", self.path)
1130         if rc:
1131             log("umount failed, cleanup will most likely not work.")
1132         l = lookup(self.dom_node.parentNode, self.lov_uuid)
1133         self.osc.cleanup()
1134         cleanup_mdc(self.dom_node.parentNode, self.mds_uuid)
1135
1136     def load_module(self):
1137         self.osc.load_module()
1138         Module.load_module(self)
1139     def cleanup_module(self):
1140         Module.cleanup_module(self)
1141         self.osc.cleanup_module()
1142
1143
1144 # ============================================================
1145 # XML processing and query
1146 # TODO: Change query funcs to use XPath, which is muc cleaner
1147
1148 def get_device(obd):
1149     list = obd.getElementsByTagName('device')
1150     if len(list) > 0:
1151         dev = list[0]
1152         dev.normalize();
1153         size = get_attr_int(dev, 'size', 0)
1154         return dev.firstChild.data, size
1155     return '', 0
1156
1157 # Get the text content from the first matching child
1158 # If there is no content (or it is all whitespace), return
1159 # the default
1160 def get_text(dom_node, tag, default=""):
1161     list = dom_node.getElementsByTagName(tag)
1162     if len(list) > 0:
1163         dom_node = list[0]
1164         dom_node.normalize()
1165         if dom_node.firstChild:
1166             txt = string.strip(dom_node.firstChild.data)
1167             if txt:
1168                 return txt
1169     return default
1170
1171 def get_text_int(dom_node, tag, default=0):
1172     list = dom_node.getElementsByTagName(tag)
1173     n = default
1174     if len(list) > 0:
1175         dom_node = list[0]
1176         dom_node.normalize()
1177         if dom_node.firstChild:
1178             txt = string.strip(dom_node.firstChild.data)
1179             if txt:
1180                 try:
1181                     n = int(txt)
1182                 except ValueError:
1183                     panic("text value is not integer:", txt)
1184     return n
1185
1186 def get_attr(dom_node, attr, default=""):
1187     v = dom_node.getAttribute(attr)
1188     if v:
1189         return v
1190     return default
1191
1192 def get_attr_int(dom_node, attr, default=0):
1193     n = default
1194     v = dom_node.getAttribute(attr)
1195     if v:
1196         try:
1197             n = int(v)
1198         except ValueError:
1199             panic("attr value is not integer", v)
1200     return n
1201
1202 def get_first_ref(dom_node, tag):
1203     """ Get the first uuidref of the type TAG. Used one only
1204     one is expected.  Returns the uuid."""
1205     uuid = None
1206     refname = '%s_ref' % tag
1207     list = dom_node.getElementsByTagName(refname)
1208     if len(list) > 0:
1209         uuid = getRef(list[0])
1210     return uuid
1211     
1212 def get_all_refs(dom_node, tag):
1213     """ Get all the refs of type TAG.  Returns list of uuids. """
1214     uuids = []
1215     refname = '%s_ref' % tag
1216     list = dom_node.getElementsByTagName(refname)
1217     if len(list) > 0:
1218         for i in list:
1219             uuids.append(getRef(i))
1220     return uuids
1221
1222 def get_ost_net(dom_node, uuid):
1223     ost = lookup(dom_node, uuid)
1224     uuid = get_first_ref(ost, 'network')
1225     if not uuid:
1226         return None
1227     return lookup(dom_node, uuid)
1228
1229 def nid2server(dom_node, nid):
1230     netlist = dom_node.getElementsByTagName('network')
1231     for net_node in netlist:
1232         if get_text(net_node, 'server') == nid:
1233             return Network(net_node)
1234     return None
1235     
1236 def lookup(dom_node, uuid):
1237     for n in dom_node.childNodes:
1238         if n.nodeType == n.ELEMENT_NODE:
1239             if getUUID(n) == uuid:
1240                 return n
1241             else:
1242                 n = lookup(n, uuid)
1243                 if n: return n
1244     return None
1245             
1246 # Get name attribute of dom_node
1247 def getName(dom_node):
1248     return dom_node.getAttribute('name')
1249
1250 def getRef(dom_node):
1251     return dom_node.getAttribute('uuidref')
1252
1253 # Get name attribute of dom_node
1254 def getUUID(dom_node):
1255     return dom_node.getAttribute('uuid')
1256
1257 # the tag name is the service type
1258 # fixme: this should do some checks to make sure the dom_node is a service
1259 def getServiceType(dom_node):
1260     return dom_node.nodeName
1261
1262 #
1263 # determine what "level" a particular node is at.
1264 # the order of iniitailization is based on level. 
1265 def getServiceLevel(dom_node):
1266     type = getServiceType(dom_node)
1267     ret=0;
1268     if type in ('network',):
1269         ret = 10
1270     elif type in ('device', 'ldlm'):
1271         ret = 20
1272     elif type in ('obd', 'mdd'):
1273         ret = 30
1274     elif type in ('mds','ost'):
1275         ret = 40
1276     elif type in ('mdc','osc'):
1277         ret = 50
1278     elif type in ('lov', 'lovconfig'):
1279         ret = 60
1280     elif type in ('mountpoint',):
1281         ret = 70
1282
1283     if ret < config.startlevel() or ret > config.endlevel():
1284         ret = 0 
1285     return ret
1286
1287 #
1288 # return list of services in a profile. list is a list of tuples
1289 # [(level, dom_node),]
1290 def getServices(lustreNode, profileNode):
1291     list = []
1292     for n in profileNode.childNodes:
1293         if n.nodeType == n.ELEMENT_NODE:
1294             servNode = lookup(lustreNode, getRef(n))
1295             if not servNode:
1296                 print n
1297                 panic('service not found: ' + getRef(n))
1298             level = getServiceLevel(servNode)
1299             if level > 0:
1300                 list.append((level, servNode))
1301     list.sort()
1302     return list
1303
1304 def getByName(lustreNode, name, tag):
1305     ndList = lustreNode.getElementsByTagName(tag)
1306     for nd in ndList:
1307         if getName(nd) == name:
1308             return nd
1309     return None
1310     
1311
1312 ############################################################
1313 # MDC UUID hack - 
1314 # FIXME: clean this mess up!
1315 #
1316 saved_mdc = {}
1317 def prepare_mdc(dom_node, mds_uuid):
1318     global saved_mdc
1319     mds_node = lookup(dom_node, mds_uuid);
1320     if not mds_node:
1321         panic("no mds:", mds_uuid)
1322     if saved_mdc.has_key(mds_uuid):
1323         return saved_mdc[mds_uuid]
1324     mdc = MDC(mds_node)
1325     mdc.prepare()
1326     saved_mdc[mds_uuid] = mdc.uuid
1327     return mdc.uuid
1328
1329 def cleanup_mdc(dom_node, mds_uuid):
1330     global saved_mdc
1331     mds_node = lookup(dom_node, mds_uuid);
1332     if not mds_node:
1333         panic("no mds:", mds_uuid)
1334     if not saved_mdc.has_key(mds_uuid):
1335         mdc = MDC(mds_node)
1336         mdc.cleanup()
1337         saved_mdc[mds_uuid] = mdc.uuid
1338         
1339
1340 ############################################################
1341 # routing ("rooting")
1342 #
1343 routes = []
1344 local_node = []
1345 router_flag = 0
1346
1347 def init_node(dom_node):
1348     global local_node, router_flag
1349     netlist = dom_node.getElementsByTagName('network')
1350     for dom_net in netlist:
1351         type = get_attr(dom_net, 'type')
1352         gw = get_text(dom_net, 'server')
1353         local_node.append((type, gw))
1354
1355 def node_needs_router():
1356     return router_flag
1357
1358 def get_routes(type, gw, dom_net):
1359     """ Return the routes as a list of tuples of the form:
1360         [(type, gw, lo, hi),]"""
1361     res = []
1362     tbl = dom_net.getElementsByTagName('route_tbl')
1363     for t in tbl:
1364         routes = t.getElementsByTagName('route')
1365         for r in routes:
1366             lo = get_attr(r, 'lo')
1367             hi = get_attr(r, 'hi', '')
1368             res.append((type, gw, lo, hi))
1369     return res
1370     
1371
1372 def init_route_config(lustre):
1373     """ Scan the lustre config looking for routers.  Build list of
1374     routes. """
1375     global routes, router_flag
1376     routes = []
1377     list = lustre.getElementsByTagName('node')
1378     for node in list:
1379         if get_attr(node, 'router'):
1380             router_flag = 1
1381             for (local_type, local_nid) in local_node:
1382                 gw = None
1383                 netlist = node.getElementsByTagName('network')
1384                 for dom_net in netlist:
1385                     if local_type == get_attr(dom_net, 'type'):
1386                         gw = get_text(dom_net, 'server')
1387                         break
1388                 if not gw:
1389                     continue
1390                 for dom_net in netlist:
1391                     if local_type != get_attr(dom_net, 'type'):
1392                         for route in get_routes(local_type, gw, dom_net):
1393                             routes.append(route)
1394     
1395
1396 def local_net(net):
1397     global local_node
1398     for iface in local_node:
1399         if net.net_type == iface[0]:
1400             return 1
1401     return 0
1402
1403 def find_route(net):
1404     global local_node, routes
1405     frm_type = local_node[0][0]
1406     to_type = net.net_type
1407     to = net.nid
1408     debug ('looking for route to', to_type,to)
1409     for r in routes:
1410         if  r[2] == to:
1411             return r
1412     return None
1413            
1414     
1415         
1416
1417 ############################################################
1418 # lconf level logic
1419 # Start a service.
1420 def startService(dom_node, module_flag):
1421     type = getServiceType(dom_node)
1422     debug('Service:', type, getName(dom_node), getUUID(dom_node))
1423     # there must be a more dynamic way of doing this...
1424     n = None
1425     if type == 'ldlm':
1426         n = LDLM(dom_node)
1427     elif type == 'lov':
1428         n = LOV(dom_node)
1429     elif type == 'lovconfig':
1430         n = LOVConfig(dom_node)
1431     elif type == 'network':
1432         n = Network(dom_node)
1433     elif type == 'obd':
1434         n = OBD(dom_node)
1435     elif type == 'ost':
1436         n = OST(dom_node)
1437     elif type == 'mds':
1438         n = MDS(dom_node)
1439     elif type == 'osc':
1440         n = VOSC(dom_node)
1441     elif type == 'mdc':
1442         n = MDC(dom_node)
1443     elif type == 'mountpoint':
1444         n = Mountpoint(dom_node)
1445     else:
1446         panic ("unknown service type:", type)
1447
1448     if module_flag:
1449         if config.nomod():
1450             return
1451         if config.cleanup():
1452             n.cleanup_module()
1453         else:
1454             n.load_module()
1455     else:
1456         if config.nosetup():
1457             return
1458         if config.cleanup():
1459             n.cleanup()
1460         else:
1461             n.prepare()
1462
1463 #
1464 # Prepare the system to run lustre using a particular profile
1465 # in a the configuration. 
1466 #  * load & the modules
1467 #  * setup networking for the current node
1468 #  * make sure partitions are in place and prepared
1469 #  * initialize devices with lctl
1470 # Levels is important, and needs to be enforced.
1471 def startProfile(lustreNode, profileNode, module_flag):
1472     if not profileNode:
1473         panic("profile:", profile, "not found.")
1474     services = getServices(lustreNode, profileNode)
1475     if config.cleanup():
1476         services.reverse()
1477     for s in services:
1478         startService(s[1], module_flag)
1479
1480
1481 #
1482 # Load profile for 
1483 def doHost(lustreNode, hosts):
1484     global routes
1485     dom_node = None
1486     for h in hosts:
1487         dom_node = getByName(lustreNode, h, 'node')
1488         if dom_node:
1489             break
1490
1491     if not dom_node:
1492         print 'No host entry found.'
1493         return
1494
1495     if not get_attr(dom_node, 'router'):
1496         init_node(dom_node)
1497         init_route_config(lustreNode)
1498     else:
1499         global router_flag 
1500         router_flag = 1
1501
1502     # Two step process: (1) load modules, (2) setup lustre
1503     # if not cleaning, load modules first.
1504     module_flag = not config.cleanup()
1505     reflist = dom_node.getElementsByTagName('profile')
1506     for profile in reflist:
1507             startProfile(lustreNode,  profile, module_flag)
1508
1509     if not config.cleanup():
1510         sys_set_debug_path()
1511         script = config.gdb_script()
1512         run(lctl.lctl, ' modules >', script)
1513         if config.gdb():
1514             # dump /tmp/ogdb and sleep/pause here
1515             log ("The GDB module script is in", script)
1516             time.sleep(5)
1517             
1518     module_flag = not module_flag
1519     for profile in reflist:
1520             startProfile(lustreNode,  profile, module_flag)
1521
1522 ############################################################
1523 # Command line processing
1524 #
1525 def parse_cmdline(argv):
1526     short_opts = "hdnvf"
1527     long_opts = ["ldap", "reformat", "lustre=", "verbose", "gdb",
1528                  "portals=", "makeldiff", "cleanup", "noexec",
1529                  "help", "node=", "nomod", "nosetup",
1530                  "dump=", "force", "startlevel=", "endlevel="]
1531     opts = []
1532     args = []
1533     try:
1534         opts, args = getopt.getopt(argv, short_opts, long_opts)
1535     except getopt.error:
1536         print "invalid opt"
1537         usage()
1538
1539     for o, a in opts:
1540         if o in ("-h", "--help"):
1541             usage()
1542         if o in ("-d","--cleanup"):
1543             config.cleanup(1)
1544         if o in ("-v", "--verbose"):
1545             config.verbose(1)
1546         if o in ("-n", "--noexec"):
1547             config.noexec(1)
1548             config.verbose(1)
1549         if o == "--portals":
1550             config.portals = a
1551         if o == "--lustre":
1552             config.lustre = a
1553         if o == "--reformat":
1554             config.reformat(1)
1555         if o == "--node":
1556             config.node(a)
1557         if o == "--gdb":
1558             config.gdb(1)
1559         if o == "--nomod":
1560             config.nomod(1)
1561         if o == "--nosetup":
1562             config.nosetup(1)
1563         if o == "--dump":
1564             config.dump_file(a)
1565         if o in ("-f", "--force"):
1566             config.force(1)
1567         if o in ("--startlevel",):
1568                 config.startlevel(a)
1569         if o in ("--endlevel",):
1570                 config.endlevel(a)
1571
1572     return args
1573
1574 def fetch(url):
1575     import urllib
1576     data = ""
1577     try:
1578         s = urllib.urlopen(url)
1579         data = s.read()
1580     except:
1581         usage()
1582     return data
1583
1584 def setupModulePath(cmd):
1585     base = os.path.dirname(cmd)
1586     if os.access(base+"/Makefile", os.R_OK):
1587         config.src_dir(base + "/../../")
1588
1589 def sys_set_debug_path():
1590     debug("debug path: ", config.debug_path())
1591     if config.noexec():
1592         return
1593     try:
1594         fp = open('/proc/sys/portals/debug_path', 'w')
1595         fp.write(config.debug_path())
1596         fp.close()
1597     except IOError, e:
1598         print e
1599              
1600 #/proc/sys/net/core/rmem_max
1601 #/proc/sys/net/core/wmem_max
1602 def sys_set_netmem_max(path, max):
1603     debug("setting", path, "to at least", max)
1604     if config.noexec():
1605         return
1606     fp = open(path)
1607     str = fp.readline()
1608     fp.close
1609     cur = int(str)
1610     if max > cur:
1611         fp = open(path, 'w')
1612         fp.write('%d\n' %(max))
1613         fp.close()
1614     
1615     
1616 def sys_make_devices():
1617     if not os.access('/dev/portals', os.R_OK):
1618         run('mknod /dev/portals c 10 240')
1619     if not os.access('/dev/obd', os.R_OK):
1620         run('mknod /dev/obd c 10 241')
1621
1622
1623 # Add dir to the global PATH, if not already there.
1624 def add_to_path(new_dir):
1625     syspath = string.split(os.environ['PATH'], ':')
1626     if new_dir in syspath:
1627         return
1628     os.environ['PATH'] = os.environ['PATH'] + ':' + new_dir
1629     
1630
1631 DEFAULT_PATH = ('/sbin', '/usr/sbin', '/bin', '/usr/bin')
1632 # ensure basic elements are in the system path
1633 def sanitise_path():
1634     for dir in DEFAULT_PATH:
1635         add_to_path(dir)
1636
1637 # Initialize or shutdown lustre according to a configuration file
1638 #   * prepare the system for lustre
1639 #   * configure devices with lctl
1640 # Shutdown does steps in reverse
1641 #
1642 def main():
1643     global TCP_ACCEPTOR, lctl, MAXTCPBUF
1644     host = socket.gethostname()
1645
1646     sanitise_path()
1647
1648     args = parse_cmdline(sys.argv[1:])
1649     if len(args) > 0:
1650         if not os.access(args[0], os.R_OK):
1651             print 'File not found or readable:', args[0]
1652             sys.exit(1)
1653         dom = xml.dom.minidom.parse(args[0])
1654     elif config.url():
1655         xmldata = fetch(config.url())
1656         dom = xml.dom.minidom.parseString(xmldata)
1657     else:
1658         usage()
1659
1660     node_list = []
1661     if config.node():
1662         node_list.append(config.node())
1663     else:
1664         if len(host) > 0:
1665             node_list.append(host)
1666         node_list.append('localhost')
1667     debug("configuring for host: ", node_list)
1668
1669     if len(host) > 0:
1670         config._debug_path = config._debug_path + '-' + host
1671         config._gdb_script = config._gdb_script + '-' + host
1672
1673     TCP_ACCEPTOR = find_prog('acceptor')
1674     if not TCP_ACCEPTOR:
1675         if config.noexec():
1676             TCP_ACCEPTOR = 'acceptor'
1677             debug('! acceptor not found')
1678         else:
1679             panic('acceptor not found')
1680
1681     lctl = LCTLInterface('lctl')
1682
1683     setupModulePath(sys.argv[0])
1684     sys_make_devices()
1685     sys_set_netmem_max('/proc/sys/net/core/rmem_max', MAXTCPBUF)
1686     sys_set_netmem_max('/proc/sys/net/core/wmem_max', MAXTCPBUF)
1687     doHost(dom.documentElement, node_list)
1688
1689 if __name__ == "__main__":
1690     try:
1691         main()
1692     except LconfError, e:
1693         print e
1694     except CommandError, e:
1695         e.dump()
1696         sys.exit(e.rc)
1697
1698     if first_cleanup_error:
1699         sys.exit(first_cleanup_error)
1700