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