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