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