Whamcloud - gitweb
land b_hd_sec onto HEAD:
[fs/lustre-release.git] / lustre / utils / lconf
1 #!/usr/bin/env python
2 #
3 #  Copyright (C) 2002-2003 Cluster File Systems, Inc.
4 #   Authors: Robert Read <rread@clusterfs.com>
5 #            Mike Shaver <shaver@clusterfs.com>
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, types
29 import string, os, stat, popen2, socket, time, random, fcntl, select
30 import re, exceptions, signal, traceback
31 import xml.dom.minidom
32
33 if sys.version[0] == '1':
34     from FCNTL import F_GETFL, F_SETFL
35 else:
36     from fcntl import F_GETFL, F_SETFL
37
38 PYMOD_DIR = "/usr/lib/lustre/python"
39
40 def development_mode():
41     base = os.path.dirname(sys.argv[0])
42     if os.access(base+"/Makefile", os.R_OK):
43         return 1
44     return 0
45
46 if development_mode():
47     sys.path.append('../utils')
48 else:
49     sys.path.append(PYMOD_DIR)
50
51 import Lustre
52
53 # Global parameters
54 MAXTCPBUF = 16777216
55 DEFAULT_TCPBUF = 8388608
56 DEFAULT_PORT = 988
57 #
58 # Maximum number of devices to search for.
59 # (the /dev/loop* nodes need to be created beforehand)
60 MAX_LOOP_DEVICES = 256
61 PORTALS_DIR = '../portals'
62
63 # Needed to call lconf --record
64 CONFIG_FILE = "" 
65
66 # Please keep these in sync with the values in portals/kp30.h
67 ptldebug_names = { 
68     "trace" :     (1 << 0),
69     "inode" :     (1 << 1),
70     "super" :     (1 << 2),
71     "ext2" :      (1 << 3),
72     "malloc" :    (1 << 4),
73     "cache" :     (1 << 5),
74     "info" :      (1 << 6),
75     "ioctl" :     (1 << 7),
76     "blocks" :    (1 << 8),
77     "net" :       (1 << 9),
78     "warning" :   (1 << 10),
79     "buffs" :     (1 << 11),
80     "other" :     (1 << 12),
81     "dentry" :    (1 << 13),
82     "portals" :   (1 << 14),
83     "page" :      (1 << 15),
84     "dlmtrace" :  (1 << 16),
85     "error" :     (1 << 17),
86     "emerg" :     (1 << 18),
87     "ha" :        (1 << 19),
88     "rpctrace" :  (1 << 20),
89     "vfstrace" :  (1 << 21),
90     "reada" :     (1 << 22),
91     "mmap" :      (1 << 23),
92     "config" :    (1 << 24),
93     "console" :   (1 << 25),
94     "quota" :     (1 << 26),
95     "sec" :       (1 << 27),
96 }
97
98 subsystem_names = {
99     "undefined" :    (1 << 0),
100     "mdc" :          (1 << 1),
101     "mds" :          (1 << 2),
102     "osc" :          (1 << 3),
103     "ost" :          (1 << 4),
104     "class" :        (1 << 5),
105     "log" :          (1 << 6),
106     "llite" :        (1 << 7),
107     "rpc" :          (1 << 8),
108     "mgmt" :         (1 << 9),
109     "portals" :      (1 << 10),
110     "nal" :          (1 << 11),
111     "pinger" :       (1 << 12),
112     "filter" :       (1 << 13),
113     "ptlbd" :        (1 << 14),
114     "echo" :         (1 << 15),
115     "ldlm" :         (1 << 16),
116     "lov" :          (1 << 17),
117     "ptlrouter" :    (1 << 18),
118     "cobd" :         (1 << 19),
119     "sm" :           (1 << 20),
120     "asobd" :        (1 << 21),
121     "confobd" :      (1 << 22),
122     "lmv" :          (1 << 23),
123     "cmobd" :        (1 << 24),
124     "sec" :          (1 << 25),
125     }
126
127
128 first_cleanup_error = 0
129 def cleanup_error(rc):
130     global first_cleanup_error
131     if not first_cleanup_error:
132         first_cleanup_error = rc
133
134 # ============================================================ 
135 # debugging and error funcs
136
137 def fixme(msg = "this feature"):
138     raise Lustre.LconfError, msg + ' not implemented yet.'
139
140 def panic(*args):
141     msg = string.join(map(str,args))
142     if not config.noexec:
143         raise Lustre.LconfError(msg)
144     else:
145         print "! " + msg
146
147 def log(*args):
148     msg = string.join(map(str,args))
149     print msg
150
151 def logall(msgs):
152     for s in msgs:
153         print string.strip(s)
154
155 def debug(*args):
156     if config.verbose:
157         msg = string.join(map(str,args))
158         print msg
159
160 # ack, python's builtin int() does not support '0x123' syntax.
161 # eval can do it, although what a hack!
162 def my_int(s):
163     try:
164         if s[0:2] == '0x':
165             return eval(s, {}, {})
166         else:
167             return int(s)
168     except SyntaxError, e:
169         raise ValueError("not a number")
170     except NameError, e:
171         raise ValueError("not a number")
172
173 # ============================================================
174 # locally defined exceptions
175 class CommandError (exceptions.Exception):
176     def __init__(self, cmd_name, cmd_err, rc=None):
177         self.cmd_name = cmd_name
178         self.cmd_err = cmd_err
179         self.rc = rc
180
181     def dump(self):
182         import types
183         if type(self.cmd_err) == types.StringType:
184             if self.rc:
185                 print "! %s (%d): %s" % (self.cmd_name, self.rc, self.cmd_err)
186             else:
187                 print "! %s: %s" % (self.cmd_name, self.cmd_err)
188         elif type(self.cmd_err) == types.ListType:
189             if self.rc:
190                 print "! %s (error %d):" % (self.cmd_name, self.rc)
191             else:
192                 print "! %s:" % (self.cmd_name)
193             for s in self.cmd_err:
194                 print "> %s" %(string.strip(s))
195         else:
196             print self.cmd_err
197
198
199 # ============================================================
200 # handle daemons, like the acceptor
201 class DaemonHandler:
202     """ Manage starting and stopping a daemon. Assumes daemon manages
203     it's own pid file. """
204
205     def __init__(self, cmd):
206         self.command = cmd
207         self.path =""
208
209     def start(self):
210         if self.running():
211             log(self.command, "already running.")
212         if not self.path:
213             self.path = find_prog(self.command)
214             if not self.path:
215                 panic(self.command, "not found.")
216         ret, out = runcmd(self.path +' '+ self.command_line())
217         if ret:
218             raise CommandError(self.path, out, ret)
219
220     def stop(self):
221         if self.running():
222             pid = self.read_pidfile()
223             try:
224                 if pid != 1:
225                     log ("killing process", pid)
226                     os.kill(pid, 15)
227                 else:
228                     log("was unable to find pid of " + self.command)
229                 #time.sleep(1) # let daemon die
230             except OSError, e:
231                 log("unable to kill", self.command, e)
232             if self.running():
233                 log("unable to kill", self.command)
234
235     def running(self):
236         pid = self.read_pidfile()
237         if pid:
238             try:
239                 if pid != 1:
240                     os.kill(pid, 0)
241                 else:
242                     log("was unable to find pid of " + self.command)
243             except OSError:
244                 self.clean_pidfile()
245             else:
246                 return 1
247         return 0
248
249     def read_pidfile(self):
250         try:
251             fp = open(self.pidfile(), 'r')
252             val = fp.read()
253             if val == '':
254                 val = '1'
255             pid = int(val)
256             fp.close()
257             return pid
258         except IOError:
259             return 0
260         
261     def clean_pidfile(self):
262         """ Remove a stale pidfile """
263         log("removing stale pidfile:", self.pidfile())
264         try:
265             os.unlink(self.pidfile())
266         except OSError, e:
267             log(self.pidfile(), e)
268             
269 class AcceptorHandler(DaemonHandler):
270     def __init__(self, port, net_type):
271         DaemonHandler.__init__(self, "acceptor")
272         self.port = port
273         self.flags = ''
274
275     def pidfile(self):
276         return "/var/run/%s-%d.pid" % (self.command, self.port)
277
278     def command_line(self):
279         return string.join(map(str,(self.flags, self.port)))
280     
281 acceptors = {}
282
283 # start the acceptors
284 def run_acceptors():
285     if config.lctl_dump or config.record:
286         return
287     for port in acceptors.keys():
288         daemon = acceptors[port]
289         if not daemon.running():
290             daemon.start()
291
292 def run_one_acceptor(port):
293     if config.lctl_dump or config.record:
294         return
295     if acceptors.has_key(port):
296         daemon = acceptors[port]
297         if not daemon.running():
298             daemon.start()
299     else:
300          panic("run_one_acceptor: No acceptor defined for port:", port)   
301         
302 def stop_acceptor(port):
303     if acceptors.has_key(port):
304         daemon = acceptors[port]
305         if daemon.running():
306             daemon.stop()
307         
308
309 # ============================================================
310 # handle lctl interface
311 class LCTLInterface:
312     """
313     Manage communication with lctl
314     """
315
316     def __init__(self, cmd):
317         """
318         Initialize close by finding the lctl binary.
319         """
320         self.lctl = find_prog(cmd)
321         self.save_file = ''
322         self.record_device = ''
323         if not self.lctl:
324             if config.noexec:
325                 debug('! lctl not found')
326                 self.lctl = 'lctl'
327             else:
328                 raise CommandError('lctl', "unable to find lctl binary.")
329
330     def use_save_file(self, file):
331         self.save_file = file
332         
333     def record(self, dev_name, logname):
334         log("Recording log", logname, "on", dev_name)
335         self.record_device = dev_name
336         self.record_log = logname
337
338     def end_record(self):
339         log("End recording log", self.record_log, "on", self.record_device)
340         self.record_device = None
341         self.record_log = None
342
343     def set_nonblock(self, fd):
344         fl = fcntl.fcntl(fd, F_GETFL)
345         fcntl.fcntl(fd, F_SETFL, fl | os.O_NDELAY)
346
347     def run(self, cmds):
348         """
349         run lctl
350         the cmds are written to stdin of lctl
351         lctl doesn't return errors when run in script mode, so
352         stderr is checked
353         should modify command line to accept multiple commands, or
354         create complex command line options
355         """
356         cmd_line = self.lctl
357         if self.save_file:
358             cmds = '\n  dump ' + self.save_file + '\n' + cmds
359         elif self.record_device:
360             cmds = """
361     device $%s
362     record %s
363     %s""" % (self.record_device, self.record_log, cmds)
364             
365         debug("+", cmd_line, cmds)
366         if config.noexec: return (0, [])
367
368         child = popen2.Popen3(cmd_line, 1) # Capture stdout and stderr from command
369         child.tochild.write(cmds + "\n")
370         child.tochild.close()
371 #       print "LCTL:", cmds
372
373         # From "Python Cookbook" from O'Reilly
374         outfile = child.fromchild
375         outfd = outfile.fileno()
376         self.set_nonblock(outfd)
377         errfile = child.childerr
378         errfd = errfile.fileno()
379         self.set_nonblock(errfd)
380
381         outdata = errdata = ''
382         outeof = erreof = 0
383         while 1:
384             ready = select.select([outfd,errfd],[],[]) # Wait for input
385             if outfd in ready[0]:
386                 outchunk = outfile.read()
387                 if outchunk == '': outeof = 1
388                 outdata = outdata + outchunk
389             if errfd in ready[0]:
390                 errchunk = errfile.read()
391                 if errchunk == '': erreof = 1
392                 errdata = errdata + errchunk
393             if outeof and erreof: break
394         # end of "borrowed" code
395
396         ret = child.wait()
397         if os.WIFEXITED(ret):
398             rc = os.WEXITSTATUS(ret)
399         else:
400             rc = 0
401         if rc or len(errdata):
402             raise CommandError(self.lctl, errdata, rc)
403         return rc, outdata
404
405     def runcmd(self, *args):
406         """
407         run lctl using the command line
408         """
409         cmd = string.join(map(str,args))
410         debug("+", self.lctl, cmd)
411         rc, out = run(self.lctl, cmd)
412         if rc:
413             raise CommandError(self.lctl, out, rc)
414         return rc, out
415
416     def clear_log(self, dev, log):
417         """ clear an existing log """
418         cmds =  """
419   device $%s
420   probe
421   clear_log %s
422   quit """ % (dev, log)
423         self.run(cmds)
424
425     def root_squash(self, name, uid, nid):
426         cmds = """
427   device $%s
428   root_squash %s %s
429   quit""" % (name, uid, nid)
430         self.run(cmds)
431
432     def network(self, net, nid):
433         """ set mynid """
434         cmds =  """
435   network %s
436   mynid %s
437   quit """ % (net, nid)
438         self.run(cmds)
439
440     # add an interface
441     def add_interface(self, net, ip, netmask = ""):
442         """ add an interface """
443         cmds = """
444   network %s
445   add_interface %s %s
446   quit """ % (net, ip, netmask)
447         self.run(cmds)
448
449     # delete an interface
450     def del_interface(self, net, ip):
451         """ delete an interface """
452         cmds = """
453   network %s
454   del_interface %s
455   quit """ % (net, ip)
456         self.run(cmds)
457
458     # create a new connection
459     def add_uuid(self, net_type, uuid, nid):
460         cmds = "\n  add_uuid %s %s %s" %(uuid, nid, net_type)
461         self.run(cmds)
462
463     def add_peer(self, net_type, nid, hostaddr, port):
464         if net_type  in ('tcp','openib','ra') and not config.lctl_dump:
465             cmds =  """
466   network %s
467   add_peer %s %s %d
468   quit""" % (net_type,
469              nid, hostaddr, port )
470             self.run(cmds)
471         elif net_type in ('iib',) and not config.lctl_dump:
472             cmds =  """
473   network %s
474   add_peer %s
475   quit""" % (net_type,
476              nid )
477             self.run(cmds)
478         elif net_type in ('vib',) and not config.lctl_dump:
479             cmds =  """
480   network %s
481   add_peer %s %s
482   quit""" % (net_type,
483              nid, hostaddr )
484             self.run(cmds)
485     
486     def connect(self, srv):
487         self.add_uuid(srv.net_type, srv.nid_uuid, srv.nid)
488         if srv.net_type  in ('tcp','openib','iib','vib','ra') and not config.lctl_dump:
489             if srv.hostaddr[0]:
490                 hostaddr = string.split(srv.hostaddr[0], '/')[0]
491             self.add_peer(srv.net_type, srv.nid, hostaddr, srv.port)
492
493     # Recover a device
494     def recover(self, dev_name, new_conn):
495         cmds = """
496     device $%s
497     recover %s""" %(dev_name, new_conn)
498         self.run(cmds)
499                 
500     # add a route to a range
501     def add_route(self, net, gw, lo, hi):
502         cmds =  """
503   network %s
504   add_route %s %s %s
505   quit  """ % (net,
506                gw, lo, hi)
507         try:
508             self.run(cmds)
509         except CommandError, e:
510             log ("ignore: ")
511             e.dump()
512                 
513     def del_route(self, net, gw, lo, hi):
514         cmds =  """
515   ignore_errors
516   network %s
517   del_route %s %s %s
518   quit  """ % (net, gw, lo, hi)
519         self.run(cmds)
520
521     # add a route to a host
522     def add_route_host(self, net, uuid, gw, tgt):
523         self.add_uuid(net, uuid, tgt)
524         cmds =  """
525   network %s
526   add_route %s %s
527   quit """ % (net,
528               gw, tgt)
529         try:
530             self.run(cmds)
531         except CommandError, e:
532             log ("ignore: ")
533             e.dump()
534
535     # add a route to a range
536     def del_route_host(self, net, uuid, gw, tgt):
537         self.del_uuid(uuid)
538         cmds =  """
539   ignore_errors
540   network %s
541   del_route %s %s
542   quit  """ % (net, gw, tgt)
543         self.run(cmds)
544
545
546     def del_peer(self, net_type, nid, hostaddr):
547         if net_type  in ('tcp',) and not config.lctl_dump:
548                 cmds =  """
549   ignore_errors
550   network %s
551   del_peer %s %s single_share
552   quit""" % (net_type,
553              nid, hostaddr)
554                 self.run(cmds)
555         elif net_type  in ('openib','iib','vib','ra') and not config.lctl_dump:
556                 cmds =  """
557   ignore_errors
558   network %s
559   del_peer %s single_share
560   quit""" % (net_type,
561              nid)
562                 self.run(cmds)
563         
564     # disconnect one connection
565     def disconnect(self, srv):
566         self.del_uuid(srv.nid_uuid)
567         if srv.net_type  in ('tcp','openib','iib','vib','ra') and not config.lctl_dump:
568             if srv.hostaddr[0]:
569                 hostaddr = string.split(srv.hostaddr[0], '/')[0]
570             self.del_peer(srv.net_type, srv.nid, hostaddr)
571
572     def del_uuid(self, uuid):
573         cmds =  """
574   ignore_errors
575   del_uuid %s
576   quit""" % (uuid,)
577         self.run(cmds)
578
579     # disconnect all
580     def disconnectAll(self, net):
581         cmds =  """
582   ignore_errors
583   network %s
584   disconnect
585   quit""" % (net)
586         self.run(cmds)
587
588     def attach(self, type, name, uuid):
589         cmds = """
590   attach %s %s %s
591   quit""" % (type, name, uuid)
592         self.run(cmds)
593         
594     def detach(self, name):
595         cmds = """
596   cfg_device %s
597   detach
598   quit""" % (name)
599         self.run(cmds)
600         
601     def set_security(self, name, key, value):
602         cmds = """
603   cfg_device %s
604   set_security %s %s
605   quit""" % (name, key, value)
606         self.run(cmds)
607
608     def setup(self, name, setup = ""):
609         cmds = """
610   cfg_device %s
611   setup %s
612   quit""" % (name, setup)
613         self.run(cmds)
614         
615     def add_conn(self, name, conn_uuid):
616         cmds = """
617   cfg_device %s
618   add_conn %s
619   quit""" % (name, conn_uuid)
620         self.run(cmds)
621
622     def start(self, name, conf_name):
623         cmds = """
624   device $%s
625   start %s
626   quit""" % (name, conf_name)
627         self.run(cmds)
628
629     # create a new device with lctl
630     def newdev(self, type, name, uuid, setup = ""):
631         self.attach(type, name, uuid);
632         try:
633             self.setup(name, setup)
634         except CommandError, e:
635             self.cleanup(name, uuid, 0)
636             raise e
637         
638     # cleanup a device
639     def cleanup(self, name, uuid, force, failover = 0):
640         if failover: force = 1
641         cmds = """
642   ignore_errors
643   cfg_device $%s
644   cleanup %s %s
645   detach
646   quit""" % (name, ('', 'force')[force],
647              ('', 'failover')[failover])
648         self.run(cmds)
649
650     # create an lov
651     def lov_setup(self, name, uuid, desc_uuid, stripe_cnt,
652                   stripe_sz, stripe_off, pattern, devlist = None):
653         cmds = """
654   attach lov %s %s
655   lov_setup %s %d %d %d %s %s
656   quit""" % (name, uuid, desc_uuid, stripe_cnt, stripe_sz, stripe_off,
657              pattern, devlist)
658         self.run(cmds)
659
660     # add an OBD to a LOV
661     def lov_add_obd(self, name, uuid, obd_uuid, index, gen):
662         cmds = """
663   lov_modify_tgts add %s %s %s %s
664   quit""" % (name, obd_uuid, index, gen)
665         self.run(cmds)
666
667     # create an lmv
668     def lmv_setup(self, name, uuid, desc_uuid, devlist):
669         cmds = """
670   attach lmv %s %s
671   lmv_setup %s %s
672   quit""" % (name, uuid, desc_uuid, devlist)
673         self.run(cmds)
674
675     # delete an OBD from a LOV
676     def lov_del_obd(self, name, uuid, obd_uuid, index, gen):
677         cmds = """
678   lov_modify_tgts del %s %s %s %s
679   quit""" % (name, obd_uuid, index, gen)
680         self.run(cmds)
681
682     # deactivate an OBD
683     def deactivate(self, name):
684         cmds = """
685   device $%s
686   deactivate
687   quit""" % (name)
688         self.run(cmds)
689
690     # dump the log file
691     def dump(self, dump_file):
692         cmds = """
693   debug_kernel %s 1
694   quit""" % (dump_file)
695         self.run(cmds)
696
697     # get list of devices
698     def device_list(self):
699         devices = '/proc/fs/lustre/devices'
700         ret = []
701         if os.access(devices, os.R_OK):
702             try:
703                 fp = open(devices, 'r')
704                 ret =  fp.readlines()
705                 fp.close()
706             except IOError, e:
707                 log(e)
708         return ret
709
710     # get lustre version
711     def lustre_version(self):
712         rc, out = self.runcmd('version')
713         return out
714
715     # dump mount options
716     def mount_option(self, profile, osc, mdc):
717         cmds = """
718   mount_option %s %s %s
719   quit""" % (profile, osc, mdc)
720         self.run(cmds)
721
722     # delete mount options
723     def del_mount_option(self, profile):
724         cmds = """
725   del_mount_option %s
726   quit""" % (profile,)
727         self.run(cmds)
728
729     def set_timeout(self, timeout):
730         cmds = """
731   set_timeout %s
732   quit""" % (timeout,)
733         self.run(cmds)
734
735     def set_lustre_upcall(self, upcall):
736         cmds = """
737   set_lustre_upcall %s
738   quit""" % (upcall,)
739         self.run(cmds)
740 # ============================================================
741 # Various system-level functions
742 # (ideally moved to their own module)
743
744 # Run a command and return the output and status.
745 # stderr is sent to /dev/null, could use popen3 to
746 # save it if necessary
747 def runcmd(cmd):
748     debug ("+", cmd)
749     if config.noexec: return (0, [])
750     f = os.popen(cmd + ' 2>&1')
751     out = f.readlines()
752     ret = f.close()
753     if ret:
754         ret = ret >> 8
755     else:
756         ret = 0
757     return (ret, out)
758
759 def run(*args):
760     cmd = string.join(map(str,args))
761     return runcmd(cmd)
762
763 # Run a command in the background.
764 def run_daemon(*args):
765     cmd = string.join(map(str,args))
766     debug ("+", cmd)
767     if config.noexec: return 0
768     f = os.popen(cmd + ' 2>&1')
769     ret = f.close()
770     if ret:
771         ret = ret >> 8
772     else:
773         ret = 0
774     return ret
775
776 # Determine full path to use for an external command
777 # searches dirname(argv[0]) first, then PATH
778 def find_prog(cmd):
779     syspath = string.split(os.environ['PATH'], ':')
780     cmdpath = os.path.dirname(sys.argv[0])
781     syspath.insert(0, cmdpath);
782     if config.portals:
783         syspath.insert(0, os.path.join(config.portals, 'utils/'))
784     for d in syspath:
785         prog = os.path.join(d,cmd)
786         if os.access(prog, os.X_OK):
787             return prog
788     return ''
789
790 # Recursively look for file starting at base dir
791 def do_find_file(base, mod):
792     fullname = os.path.join(base, mod)
793     if os.access(fullname, os.R_OK):
794         return fullname
795     for d in os.listdir(base):
796         dir = os.path.join(base,d)
797         if os.path.isdir(dir):
798             module = do_find_file(dir, mod)
799             if module:
800                 return module
801
802 # is the path a block device?
803 def is_block(path):
804     s = ()
805     try:
806         s =  os.stat(path)
807     except OSError:
808         return 0
809     return stat.S_ISBLK(s[stat.ST_MODE])
810
811 # find the journal device from mkfs options
812 def jdev(opts):
813     if opts == None:
814         return ''
815     x=string.split(opts)
816     i=0
817     while i < len(x) - 1:
818         if x[i] == '-J' and x[i+1].startswith('device='):
819             str=x[i+1]
820             return str[7:]
821         i=i+1
822     return ''
823
824 # build fs according to type
825 # fixme: dangerous
826 def mkfs(dev, devsize, fstype, jsize, isize, mkfsoptions, isblock=1):
827     block_cnt = ''
828     jopt = ''
829     iopt = ''
830     if devsize:
831         if devsize < 8000:
832             panic("size of filesystem on '%s' must be larger than 8MB, but is set to %s"%
833                   (dev, devsize))
834         # devsize is in 1k, and fs block count is in 4k
835         block_cnt = devsize/4
836
837     if fstype in ('ext3', 'extN', 'ldiskfs'):
838         # ext3 journal size is in megabytes
839         # but don't set jsize if mkfsoptions indicates a separate journal device
840         if jsize == 0 and jdev(mkfsoptions) == '':
841             if devsize == 0:
842                 if not is_block(dev):
843                     ret, out = runcmd("ls -l %s" %dev)
844                     devsize = int(string.split(out[0])[4]) / 1024
845                 else:
846                     # sfdisk works for symlink, hardlink, and realdev
847                     ret, out = runcmd("sfdisk -s %s" %dev)
848                     if not ret:
849                         devsize = int(out[0])
850                     else:
851                         # sfdisk -s will fail for too large block device,
852                         # then, read the size of partition from /proc/partitions
853
854                         # get the realpath of the device
855                         # it may be the real device, such as /dev/hda7
856                         # or the hardlink created via mknod for a device
857                         if 'realpath' in dir(os.path):
858                             real_dev = os.path.realpath(dev)
859                         else:
860                             real_dev = dev
861                             link_count = 0
862                             while os.path.islink(real_dev) and (link_count < 20):
863                                 link_count = link_count + 1
864                                 dev_link = os.readlink(real_dev)
865                                 if os.path.isabs(dev_link):
866                                     real_dev = dev_link
867                                 else:
868                                     real_dev = os.path.join(os.path.dirname(real_dev), dev_link)
869                                 if link_count > 19:
870                                     panic("Entountered too many symbolic links resolving block device:", dev)
871
872                         # get the major and minor number of the realpath via ls
873                         # it seems python(os.stat) does not return 
874                         # the st_rdev member of the stat structure
875                         ret, out = runcmd("ls -l %s" %real_dev)
876                         major = string.split(string.split(out[0])[4], ",")[0]
877                         minor = string.split(out[0])[5]
878
879                         # get the devsize from /proc/partitions with the major and minor number
880                         ret, out = runcmd("cat /proc/partitions")
881                         for line in out:
882                             if len(line) > 1:
883                                 if string.split(line)[0] == major and string.split(line)[1] == minor:
884                                     devsize = int(string.split(line)[2])
885                                     break
886
887             if devsize > 1024 * 1024:
888                 jsize = ((devsize / 102400) * 4)
889             if jsize > 400:
890                 jsize = 400        
891         if jsize:  jopt = "-J size=%d" %(jsize,)
892         if isize:  iopt = "-I %d" %(isize,)
893         mkfs = 'mkfs.ext2 -j -b 4096 '
894         if not isblock or config.force:
895             mkfs = mkfs + ' -F '
896         if jdev(mkfsoptions) != '':
897             jmkfs = 'mkfs.ext2 -b 4096 -O journal_dev '
898             if config.force:
899                 jmkfs = jmkfs + '-F '
900             jmkfs = jmkfs + jdev(mkfsoptions)                
901             (ret, out) = run (jmkfs)
902             if ret:
903                 panic("Unable format journal device:", jdev(mkfsoptions), string.join(out))
904     elif fstype == 'reiserfs':
905         # reiserfs journal size is in blocks
906         if jsize:  jopt = "--journal_size %d" %(jsize,)
907         mkfs = 'mkreiserfs -ff'
908     else:
909         panic('unsupported fs type: ', fstype)
910
911     if config.mkfsoptions != None:
912         mkfs = mkfs + ' ' + config.mkfsoptions
913     if mkfsoptions != None:
914         mkfs = mkfs + ' ' + mkfsoptions
915     (ret, out) = run (mkfs, jopt, iopt, dev, block_cnt)
916     if ret:
917         panic("Unable to build fs:", dev, string.join(out))
918     # enable hash tree indexing on fsswe
919     if fstype in ('ext3', 'extN', 'ldiskfs'):
920         htree = 'echo "feature FEATURE_C5" | debugfs -w'
921         (ret, out) = run (htree, dev)
922         if ret:
923             panic("Unable to enable htree:", dev)
924
925 # some systems use /dev/loopN, some /dev/loop/N
926 def loop_base():
927     import re
928     loop = '/dev/loop'
929     if not os.access(loop + str(0), os.R_OK):
930         loop = loop + '/'
931         if not os.access(loop + str(0), os.R_OK):
932             panic ("can't access loop devices")
933     return loop
934     
935 # find loop device assigned to the file
936 def find_assigned_loop(file):
937     loop = loop_base()
938     for n in xrange(0, MAX_LOOP_DEVICES):
939         dev = loop + str(n)
940         if os.access(dev, os.R_OK):
941             (stat, out) = run('losetup', dev)
942             if out and stat == 0:
943                 m = re.search(r'\((.*)\)', out[0])
944                 if m and file == m.group(1):
945                     return dev
946     return ''
947
948 # find free loop device
949 def find_free_loop(file):
950     loop = loop_base()
951     
952     # find next free loop
953     for n in xrange(0, MAX_LOOP_DEVICES):
954         dev = loop + str(n)
955         if os.access(dev, os.R_OK):
956             (stat, out) = run('losetup', dev)
957             if stat:
958                 return dev
959     return ''
960
961 # create file if necessary and assign the first free loop device
962 def init_loop(file, size, fstype, journal_size, inode_size, 
963               mkfsoptions, reformat, autoformat, backfstype, backfile):
964     if fstype == 'smfs':
965         realfile = backfile
966         realfstype = backfstype
967         if is_block(backfile):
968             if reformat or (need_format(realfstype, backfile) and autoformat == 'yes'):
969                 mkfs(realfile, size, realfstype, journal_size, inode_size, mkfsoptions, isblock=0)
970             return realfile
971     else:
972         realfile = file
973         realfstype = fstype
974             
975     dev = find_assigned_loop(realfile)
976     if dev:
977         print 'WARNING: file', realfile, 'already mapped to', dev
978         return dev
979             
980     if reformat or not os.access(realfile, os.R_OK | os.W_OK):
981         (ret, out) = run("dd if=/dev/zero bs=1k count=0 seek=%d of=%s" %(size, realfile))
982         if ret:
983             panic("Unable to create backing store:", realfile)
984         mkfs(realfile, size, realfstype, journal_size, inode_size, 
985              mkfsoptions, isblock=0)
986
987     dev = find_free_loop(realfile)
988     if dev:
989         print "attach " + realfile + " <-> " + dev                  
990         run('losetup', dev, realfile)
991         return dev
992
993     print "out of loop devices"
994     return ''
995
996 # undo loop assignment
997 def clean_loop(dev, fstype, backfstype, backdev):
998     if fstype == 'smfs':
999         realfile = backdev
1000     else:
1001         realfile = dev
1002     if not is_block(realfile):
1003         dev = find_assigned_loop(realfile)
1004         if dev:
1005             print "detach " + dev + " <-> " + realfile
1006             ret, out = run('losetup -d', dev)
1007             if ret:
1008                 log('unable to clean loop device', dev, 'for file', realfile)
1009                 logall(out)
1010
1011 # finilizes passed device
1012 def clean_dev(dev, fstype, backfstype, backdev):
1013     if fstype == 'smfs' or not is_block(dev):
1014         clean_loop(dev, fstype, backfstype, backdev)
1015         
1016 # determine if dev is formatted as a <fstype> filesystem
1017 def need_format(fstype, dev):
1018     # FIXME don't know how to implement this    
1019     return 0
1020
1021 # initialize a block device if needed
1022 def block_dev(dev, size, fstype, reformat, autoformat, journal_size,
1023               inode_size, mkfsoptions, backfstype, backdev):
1024     if config.noexec: 
1025         return dev
1026         
1027     if fstype == 'smfs' or not is_block(dev):
1028         dev = init_loop(dev, size, fstype, journal_size, inode_size,
1029                         mkfsoptions, reformat, autoformat, backfstype, backdev)
1030     elif reformat or (need_format(fstype, dev) and autoformat == 'yes'):
1031         mkfs(dev, size, fstype, journal_size, inode_size, mkfsoptions,
1032              isblock=0)
1033 #    else:
1034 #        panic("device:", dev,
1035 #              "not prepared, and autoformat is not set.\n",
1036 #              "Rerun with --reformat option to format ALL filesystems")
1037         
1038     return dev
1039
1040 def if2addr(iface):
1041     """lookup IP address for an interface"""
1042     rc, out = run("/sbin/ifconfig", iface)
1043     if rc or not out:
1044        return None
1045     addr = string.split(out[1])[1]
1046     ip = string.split(addr, ':')[1]
1047     return ip
1048
1049 def def_mount_options(fstype, target):
1050     """returns deafult mount options for passed fstype and target (mds, ost)"""
1051     if fstype == 'ext3' or fstype == 'ldiskfs':
1052         mountfsoptions = "errors=remount-ro"
1053         if target == 'ost' and sys_get_branch() == '2.4':
1054             mountfsoptions = "%s,asyncdel" % (mountfsoptions)
1055         return mountfsoptions
1056     return ""
1057         
1058 def sys_get_elan_position_file():
1059     procfiles = ["/proc/elan/device0/position",
1060                  "/proc/qsnet/elan4/device0/position",
1061                  "/proc/qsnet/elan3/device0/position"]
1062     for p in procfiles:
1063         if os.access(p, os.R_OK):
1064             return p
1065     return ""
1066
1067 def sys_get_local_nid(net_type, wildcard, cluster_id):
1068     """Return the local nid."""
1069     local = ""
1070     if sys_get_elan_position_file():
1071         local = sys_get_local_address('elan', '*', cluster_id)
1072     else:
1073         local = sys_get_local_address(net_type, wildcard, cluster_id)
1074     return local
1075         
1076 def sys_get_local_address(net_type, wildcard, cluster_id):
1077     """Return the local address for the network type."""
1078     local = ""
1079     if net_type in ('tcp','openib','iib','vib','ra'):
1080         if  ':' in wildcard:
1081             iface, star = string.split(wildcard, ':')
1082             local = if2addr(iface)
1083             if not local:
1084                 panic ("unable to determine ip for:", wildcard)
1085         else:
1086             host = socket.gethostname()
1087             local = socket.gethostbyname(host)
1088     elif net_type == 'elan':
1089         # awk '/NodeId/ { print $2 }' 'sys_get_elan_position_file()'
1090         f = sys_get_elan_position_file()
1091         if not f:
1092             panic ("unable to determine local Elan ID")
1093         try:
1094             fp = open(f, 'r')
1095             lines = fp.readlines()
1096             fp.close()
1097             for l in lines:
1098                 a = string.split(l)
1099                 if a[0] == 'NodeId':
1100                     elan_id = a[1]
1101                     break
1102             try:
1103                 nid = my_int(cluster_id) + my_int(elan_id) 
1104                 local = "%d" % (nid)
1105             except ValueError, e:
1106                 local = elan_id
1107         except IOError, e:
1108             log(e)
1109     elif net_type == 'lo':
1110         fixme("automatic local address for loopback")
1111     elif net_type == 'gm':
1112         fixme("automatic local address for GM")
1113
1114     return local
1115
1116 def sys_get_branch():
1117     """Returns kernel release"""
1118     try:
1119         fp = open('/proc/sys/kernel/osrelease')
1120         lines = fp.readlines()
1121         fp.close()
1122         
1123         for l in lines:
1124             version = string.split(l)
1125             a = string.split(version[0], '.')
1126             return a[0] + '.' + a[1]
1127     except IOError, e:
1128         log(e)
1129     return ""
1130
1131 # XXX: instead of device_list, ask for $name and see what we get
1132 def is_prepared(name):
1133     """Return true if a device exists for the name"""
1134     if config.lctl_dump:
1135         return 0
1136     if (config.noexec or config.record) and config.cleanup:
1137         return 1
1138     try:
1139         # expect this format:
1140         # 1 UP ldlm ldlm ldlm_UUID 2
1141         out = lctl.device_list()
1142         for s in out:
1143             if name == string.split(s)[3]:
1144                 return 1
1145     except CommandError, e:
1146         e.dump()
1147     return 0
1148
1149 def net_is_prepared():
1150     """If the any device exists, then assume that all networking
1151        has been configured"""
1152     out = lctl.device_list()
1153     return len(out) > 0
1154
1155 def fs_is_mounted(path):
1156     """Return true if path is a mounted lustre filesystem"""
1157     try:
1158         fp = open('/proc/mounts')
1159         lines = fp.readlines()
1160         fp.close()
1161         for l in lines:
1162             a = string.split(l)
1163             if a[1] == path and a[2] == 'lustre_lite':
1164                 return 1
1165     except IOError, e:
1166         log(e)
1167     return 0
1168
1169 def kmod_find(src_dir, dev_dir, modname):
1170     modbase = src_dir +'/'+ dev_dir +'/'+ modname
1171     for modext in '.ko', '.o':
1172         module = modbase + modext
1173         try:
1174             if os.access(module, os.R_OK):
1175                 return module
1176         except OSError:
1177                pass
1178     return None
1179
1180 def kmod_info(modname):
1181     """Returns reference count for passed module name."""
1182     try:
1183         fp = open('/proc/modules')
1184         lines = fp.readlines()
1185         fp.close()
1186         
1187         # please forgive my tired fingers for this one
1188         ret = filter(lambda word, mod = modname: word[0] == mod,
1189                      map(lambda line: string.split(line), lines))
1190         if not ret:
1191             return ''
1192         return ret[0]
1193     except Exception, e:
1194         return 0
1195
1196 class kmod:
1197     """Presents kernel module"""
1198     def __init__(self, src_dir, dev_dir, name):
1199         self.src_dir = src_dir
1200         self.dev_dir = dev_dir
1201         self.name = name
1202
1203     # FIXME we ignore the failure of loading gss module, because we might
1204     # don't need it at all.
1205     def load(self):
1206         """Load module"""
1207         log ('loading module:', self.name, 'srcdir',
1208              self.src_dir, 'devdir', self.dev_dir)
1209         if self.src_dir:
1210             module = kmod_find(self.src_dir, self.dev_dir,
1211                                self.name)
1212             if not module and self.name != 'ptlrpcs_gss':
1213                 panic('module not found:', self.name)
1214             (rc, out)  = run('/sbin/insmod', module)
1215             if rc:
1216                 if self.name == 'ptlrpcs_gss':
1217                     print "Warning: not support gss security!"
1218                 else:
1219                     raise CommandError('insmod', out, rc)
1220         else:
1221             (rc, out) = run('/sbin/modprobe', self.name)
1222             if rc:
1223                 if self.name == 'ptlrpcs_gss':
1224                     print "Warning: not support gss security!"
1225                 else:
1226                     raise CommandError('modprobe', out, rc)
1227
1228     def cleanup(self):
1229         """Unload module"""
1230         log('unloading module:', self.name)
1231         (rc, out) = run('/sbin/rmmod', self.name)
1232         if rc:
1233             log('unable to unload module:', self.name +
1234                 "(" + self.refcount() + ")")
1235             logall(out)
1236
1237     def info(self):
1238         """Returns module info if any."""
1239         return kmod_info(self.name)
1240
1241     def loaded(self):
1242         """Returns 1 if module is loaded. Otherwise 0 is returned."""
1243         if self.info():
1244             return 1
1245         else:
1246             return 0
1247
1248     def refcount(self):
1249         """Returns module refcount."""
1250         info = self.info()
1251         if not info:
1252             return ''
1253         return info[2]
1254
1255     def used(self):
1256         """Returns 1 if module is used, otherwise 0 is returned."""
1257         info = self.info()
1258         if not info:
1259             return 0
1260         if len(info) > 3:
1261             users = info[3]
1262             if users and users != '(unused)' and users != '-':
1263                 return 1
1264             else:
1265                 return 0
1266         else:
1267             return 0
1268
1269     def busy(self):
1270         """Returns 1 if module is busy, otherwise 0 is returned."""
1271         if self.loaded() and (self.used() or self.refcount() != '0'):
1272             return 1
1273         else:
1274             return 0
1275
1276 class kmod_manager:
1277     """Manage kernel modules"""
1278     def __init__(self, lustre_dir, portals_dir):
1279         self.lustre_dir = lustre_dir
1280         self.portals_dir = portals_dir
1281         self.kmodule_list = []
1282
1283     def find_module(self, modname):
1284         """Find module by module name"""
1285         for mod in self.kmodule_list:
1286             if mod.name == modname:
1287                 return mod
1288         return ''
1289         
1290     def add_portals_module(self, dev_dir, modname):
1291         """Append a module to list of modules to load."""
1292
1293         mod = self.find_module(modname)
1294         if not mod:
1295             mod = kmod(self.portals_dir, dev_dir, modname)
1296             self.kmodule_list.append(mod)
1297
1298     def add_lustre_module(self, dev_dir, modname):
1299         """Append a module to list of modules to load."""
1300
1301         mod = self.find_module(modname)
1302         if not mod:
1303             mod = kmod(self.lustre_dir, dev_dir, modname)
1304             self.kmodule_list.append(mod)
1305         
1306     def load_modules(self):
1307         """Load all the modules in the list in the order they appear."""
1308         for mod in self.kmodule_list:
1309             if mod.loaded() and not config.noexec:
1310                 continue
1311             mod.load()
1312
1313     def cleanup_modules(self):
1314         """Unload the modules in the list in reverse order."""
1315         rev = self.kmodule_list
1316         rev.reverse()
1317         for mod in rev:
1318             if (not mod.loaded() or mod.busy()) and not config.noexec:
1319                 continue
1320             # debug hack
1321             if mod.name == 'portals' and config.dump:
1322                 lctl.dump(config.dump)
1323             mod.cleanup()
1324             
1325 # ============================================================
1326 # Classes to prepare and cleanup the various objects
1327 #
1328 class Module:
1329     """ Base class for the rest of the modules. The default cleanup method is
1330     defined here, as well as some utilitiy funcs.
1331     """
1332     def __init__(self, module_name, db):
1333         self.db = db
1334         self.module_name = module_name
1335         self.name = self.db.getName()
1336         self.uuid = self.db.getUUID()
1337         self._server = None
1338         self._connected = 0
1339
1340     def info(self, *args):
1341         msg = string.join(map(str,args))
1342         print self.module_name + ":", self.name, self.uuid, msg
1343
1344     def cleanup(self):
1345         """ default cleanup, used for most modules """
1346         self.info()
1347         try:
1348             lctl.cleanup(self.name, self.uuid, config.force)
1349         except CommandError, e:
1350             log(self.module_name, "cleanup failed: ", self.name)
1351             e.dump()
1352             cleanup_error(e.rc)
1353
1354     def add_module(self, manager):
1355         """Adds all needed modules in the order they appear."""
1356         return
1357
1358     def safe_to_clean(self):
1359         return 1
1360
1361     def safe_to_clean_modules(self):
1362         return self.safe_to_clean()
1363         
1364 class Network(Module):
1365     def __init__(self,db):
1366         Module.__init__(self, 'NETWORK', db)
1367         self.net_type = self.db.get_val('nettype')
1368         self.nid = self.db.get_val('nid', '*')
1369         self.cluster_id = self.db.get_val('clusterid', "0")
1370         self.port = self.db.get_val_int('port', 0)
1371
1372         if '*' in self.nid:
1373             self.nid = sys_get_local_nid(self.net_type, self.nid, self.cluster_id)
1374             if not self.nid:
1375                 panic("unable to set nid for", self.net_type, self.nid, cluster_id)
1376             self.generic_nid = 1
1377             debug("nid:", self.nid)
1378         else:
1379             self.generic_nid = 0
1380
1381         self.nid_uuid = self.nid_to_uuid(self.nid)
1382         self.hostaddr = self.db.get_hostaddr()
1383         if len(self.hostaddr) == 0:
1384             self.hostaddr.append(self.nid)
1385         if '*' in self.hostaddr[0]:
1386             self.hostaddr[0] = sys_get_local_address(self.net_type, self.hostaddr[0], self.cluster_id)
1387             if not self.hostaddr[0]:
1388                 panic("unable to set hostaddr for", self.net_type, self.hostaddr[0], self.cluster_id)
1389             debug("hostaddr:", self.hostaddr[0])
1390
1391     def add_module(self, manager):
1392         manager.add_portals_module("libcfs", 'libcfs')
1393         manager.add_portals_module("portals", 'portals')
1394         
1395         if node_needs_router():
1396             manager.add_portals_module("router", 'kptlrouter')
1397         if self.net_type == 'tcp':
1398             manager.add_portals_module("knals/socknal", 'ksocknal')
1399         if self.net_type == 'elan':
1400             manager.add_portals_module("knals/qswnal", 'kqswnal')
1401         if self.net_type == 'gm':
1402             manager.add_portals_module("knals/gmnal", 'kgmnal')
1403         if self.net_type == 'openib':
1404             manager.add_portals_module("knals/openibnal", 'kopenibnal')
1405         if self.net_type == 'iib':
1406             manager.add_portals_module("knals/iibnal", 'kiibnal')
1407         if self.net_type == 'vib':
1408             self.add_portals_module("knals/vibnal", 'kvibnal')
1409         if self.net_type == 'lo':
1410             manager.add_portals_module("knals/lonal", 'klonal')
1411         if self.net_type == 'ra':
1412             manager.add_portals_module("knals/ranal", 'kranal')
1413
1414     def nid_to_uuid(self, nid):
1415         return "NID_%s_UUID" %(nid,)
1416
1417     def prepare(self):
1418         if not config.record and net_is_prepared():
1419             return
1420         self.info(self.net_type, self.nid, self.port)
1421         if not (config.record and self.generic_nid):
1422             lctl.network(self.net_type, self.nid)
1423         if self.net_type == 'tcp':
1424             sys_tweak_socknal()
1425             for hostaddr in self.db.get_hostaddr():
1426                 ip = string.split(hostaddr, '/')[0]
1427                 if len(string.split(hostaddr, '/')) == 2:
1428                     netmask = string.split(hostaddr, '/')[1]
1429                 else:
1430                     netmask = ""
1431                 lctl.add_interface(self.net_type, ip, netmask)
1432         if self.net_type == 'elan':
1433             sys_optimize_elan()
1434         if self.port and  node_is_router():
1435             run_one_acceptor(self.port)
1436             self.connect_peer_gateways()
1437
1438     def connect_peer_gateways(self):
1439         for router in self.db.lookup_class('node'):
1440             if router.get_val_int('router', 0):
1441                 for netuuid in router.get_networks():
1442                     net = self.db.lookup(netuuid)
1443                     gw = Network(net)
1444                     if (gw.cluster_id == self.cluster_id and
1445                         gw.net_type == self.net_type):
1446                         if gw.nid != self.nid:
1447                             lctl.connect(gw)
1448
1449     def disconnect_peer_gateways(self):
1450         for router in self.db.lookup_class('node'):
1451             if router.get_val_int('router', 0):
1452                 for netuuid in router.get_networks():
1453                     net = self.db.lookup(netuuid)
1454                     gw = Network(net)
1455                     if (gw.cluster_id == self.cluster_id and
1456                         gw.net_type == self.net_type):
1457                         if gw.nid != self.nid:
1458                             try:
1459                                 lctl.disconnect(gw)
1460                             except CommandError, e:
1461                                 print "disconnect failed: ", self.name
1462                                 e.dump()
1463                                 cleanup_error(e.rc)
1464
1465     def safe_to_clean(self):
1466         return not net_is_prepared()
1467
1468     def cleanup(self):
1469         self.info(self.net_type, self.nid, self.port)
1470         if self.port:
1471             stop_acceptor(self.port)
1472         if  node_is_router():
1473             self.disconnect_peer_gateways()
1474         if self.net_type == 'tcp':
1475             for hostaddr in self.db.get_hostaddr():
1476                 ip = string.split(hostaddr, '/')[0]
1477                 lctl.del_interface(self.net_type, ip)
1478
1479     def correct_level(self, level, op=None):
1480         return level
1481
1482 class RouteTable(Module):
1483     def __init__(self,db):
1484         Module.__init__(self, 'ROUTES', db)
1485
1486     def server_for_route(self, net_type, gw, gw_cluster_id, tgt_cluster_id,
1487                          lo, hi):
1488         # only setup connections for tcp, openib, and iib NALs
1489         srvdb = None
1490         if not net_type in ('tcp','openib','iib','vib','ra'):
1491             return None
1492
1493         # connect to target if route is to single node and this node is the gw
1494         if lo == hi and local_interface(net_type, gw_cluster_id, gw):
1495             if not local_cluster(net_type, tgt_cluster_id):
1496                 panic("target", lo, " not on the local cluster")
1497             srvdb = self.db.nid2server(lo, net_type, gw_cluster_id)
1498         # connect to gateway if this node is not the gw
1499         elif (local_cluster(net_type, gw_cluster_id)
1500               and not local_interface(net_type, gw_cluster_id, gw)):
1501             srvdb = self.db.nid2server(gw, net_type, gw_cluster_id)
1502         else:
1503             return None
1504
1505         if not srvdb:
1506             panic("no server for nid", lo)
1507             return None
1508
1509         return Network(srvdb)
1510         
1511     def prepare(self):
1512         if not config.record and net_is_prepared():
1513             return
1514         self.info()
1515         for net_type, gw, gw_cluster_id, tgt_cluster_id, lo, hi in self.db.get_route_tbl():
1516             lctl.add_route(net_type, gw, lo, hi)
1517             srv = self.server_for_route(net_type, gw, gw_cluster_id, tgt_cluster_id, lo, hi)
1518             if srv:
1519                 lctl.connect(srv)
1520
1521     def safe_to_clean(self):
1522         return not net_is_prepared()
1523
1524     def cleanup(self):
1525         if net_is_prepared():
1526             # the network is still being used, don't clean it up
1527             return
1528         for net_type, gw, gw_cluster_id, tgt_cluster_id, lo, hi in self.db.get_route_tbl():
1529             srv = self.server_for_route(net_type, gw, gw_cluster_id, tgt_cluster_id, lo, hi)
1530             if srv:
1531                 try:
1532                     lctl.disconnect(srv)
1533                 except CommandError, e:
1534                     print "disconnect failed: ", self.name
1535                     e.dump()
1536                     cleanup_error(e.rc)
1537
1538             try:
1539                 lctl.del_route(net_type, gw, lo, hi)
1540             except CommandError, e:
1541                 print "del_route failed: ", self.name
1542                 e.dump()
1543                 cleanup_error(e.rc)
1544
1545 class Management(Module):
1546     def __init__(self, db):
1547         Module.__init__(self, 'MGMT', db)
1548
1549     def add_module(self, manager):
1550         manager.add_lustre_module('lvfs', 'lvfs')
1551         manager.add_lustre_module('obdclass', 'obdclass')
1552         manager.add_lustre_module('ptlrpc', 'ptlrpc')
1553         manager.add_lustre_module('mgmt', 'mgmt_svc')
1554
1555     def prepare(self):
1556         if not config.record and is_prepared(self.name):
1557             return
1558         self.info()
1559         lctl.newdev("mgmt", self.name, self.uuid)
1560
1561     def safe_to_clean(self):
1562         return 1
1563
1564     def cleanup(self):
1565         if is_prepared(self.name):
1566             Module.cleanup(self)
1567
1568     def correct_level(self, level, op=None):
1569         return level
1570
1571 # This is only needed to load the modules; the LDLM device
1572 # is now created automatically.
1573 class LDLM(Module):
1574     def __init__(self,db):
1575         Module.__init__(self, 'LDLM', db)
1576
1577     def add_module(self, manager):
1578         manager.add_lustre_module('lvfs', 'lvfs')
1579         manager.add_lustre_module('obdclass', 'obdclass')
1580         manager.add_lustre_module('sec', 'ptlrpcs')
1581         manager.add_lustre_module('ptlrpc', 'ptlrpc')
1582         manager.add_lustre_module('sec/gss', 'ptlrpcs_gss')
1583
1584     def prepare(self):
1585         return
1586
1587     def cleanup(self):
1588         return
1589
1590     def correct_level(self, level, op=None):
1591         return level
1592
1593 class LOV(Module):
1594     def __init__(self, db, uuid, fs_name, name_override = None, config_only = None):
1595         Module.__init__(self, 'LOV', db)
1596         if name_override != None:
1597             self.name = "lov_%s" % name_override
1598         self.mds_uuid = self.db.get_first_ref('mds')
1599         self.stripe_sz = self.db.get_val_int('stripesize', 1048576)
1600         self.stripe_off = self.db.get_val_int('stripeoffset', 0)
1601         self.pattern = self.db.get_val_int('stripepattern', 0)
1602         self.devlist = self.db.get_lov_tgts('lov_tgt')
1603         self.stripe_cnt = self.db.get_val_int('stripecount', len(self.devlist))
1604         self.osclist = []
1605         self.obdlist = []
1606         self.desc_uuid = self.uuid
1607         self.uuid = generate_client_uuid(self.name)
1608         self.fs_name = fs_name
1609         if config_only:
1610             self.config_only = 1
1611             return
1612         self.config_only = None
1613         mds = self.db.lookup(self.mds_uuid)
1614         self.mds_name = mds.getName()
1615         for (obd_uuid, index, gen, active) in self.devlist:
1616             if obd_uuid == '':
1617                 continue
1618             self.obdlist.append(obd_uuid)
1619             obd = self.db.lookup(obd_uuid)
1620             osc = get_osc(obd, self.uuid, fs_name)
1621             if osc:
1622                 self.osclist.append((osc, index, gen, active))
1623             else:
1624                 panic('osc not found:', obd_uuid)
1625     def get_uuid(self):
1626         return self.uuid
1627     def get_name(self):
1628         return self.name
1629     def prepare(self):
1630         if not config.record and is_prepared(self.name):
1631             return
1632         self.info(self.mds_uuid, self.stripe_cnt, self.stripe_sz,
1633                   self.stripe_off, self.pattern, self.devlist,
1634                   self.mds_name)
1635         lctl.lov_setup(self.name, self.uuid, self.desc_uuid,  self.stripe_cnt,
1636                        self.stripe_sz, self.stripe_off, self.pattern,
1637                        string.join(self.obdlist))
1638         for (osc, index, gen, active) in self.osclist:
1639             target_uuid = osc.target_uuid
1640             try:
1641                 # Only ignore connect failures with --force, which
1642                 # isn't implemented here yet.
1643                 osc.active = active
1644                 osc.prepare(ignore_connect_failure=0)
1645             except CommandError, e:
1646                 print "Error preparing OSC %s\n" % osc.uuid
1647                 raise e
1648             lctl.lov_add_obd(self.name, self.uuid, target_uuid, index, gen)
1649
1650     def cleanup(self):
1651         for (osc, index, gen, active) in self.osclist:
1652             target_uuid = osc.target_uuid
1653             osc.cleanup()
1654         if is_prepared(self.name):
1655             Module.cleanup(self)
1656         if self.config_only:
1657             panic("Can't clean up config_only LOV ", self.name)
1658
1659     def add_module(self, manager):
1660         if self.config_only:
1661             panic("Can't load modules for config_only LOV ", self.name)
1662         for (osc, index, gen, active) in self.osclist:
1663             osc.add_module(manager)
1664             break
1665         manager.add_lustre_module('lov', 'lov')
1666
1667     def correct_level(self, level, op=None):
1668         return level
1669
1670 class LMV(Module):
1671     def __init__(self, db, uuid, fs_name, name_override = None):
1672         Module.__init__(self, 'LMV', db)
1673         if name_override != None:
1674             self.name = "lmv_%s" % name_override
1675             
1676         self.devlist = self.db.get_lmv_tgts('lmv_tgt')
1677         if self.devlist == None:
1678             self.devlist = self.db.get_refs('mds')
1679             
1680         self.mdclist = []
1681         self.desc_uuid = self.uuid
1682         self.uuid = uuid
1683         self.fs_name = fs_name
1684         for mds_uuid in self.devlist:
1685             mds = self.db.lookup(mds_uuid)
1686             if not mds:
1687                 panic("MDS not found!")
1688             mdc = MDC(mds, self.uuid, fs_name)
1689             if mdc:
1690                  self.mdclist.append(mdc)
1691             else:
1692                  panic('mdc not found:', mds_uuid)
1693
1694     def prepare(self):
1695         if is_prepared(self.name):
1696             return
1697             
1698         self.info();
1699         for mdc in self.mdclist:
1700             try:
1701                 # Only ignore connect failures with --force, which
1702                 # isn't implemented here yet.
1703                 mdc.prepare(ignore_connect_failure=0)
1704             except CommandError, e:
1705                 print "Error preparing LMV %s\n" % mdc.uuid
1706                 raise e
1707         
1708         lctl.lmv_setup(self.name, self.uuid, self.desc_uuid,
1709                        string.join(self.devlist))
1710
1711     def cleanup(self):
1712         for mdc in self.mdclist:
1713             mdc.cleanup()
1714         if is_prepared(self.name):
1715             Module.cleanup(self)
1716
1717     def add_module(self, manager):
1718         for mdc in self.mdclist:
1719             mdc.add_module(manager)
1720             break
1721         manager.add_lustre_module('lmv', 'lmv')
1722
1723     def correct_level(self, level, op=None):
1724         return level
1725
1726 class CONFDEV(Module):
1727     def __init__(self, db, name, target_uuid, uuid):
1728         Module.__init__(self, 'CONFDEV', db)
1729         self.devpath = self.db.get_val('devpath','')
1730         self.backdevpath = self.db.get_val('devpath','')
1731         self.size = self.db.get_val_int('devsize', 0)
1732         self.journal_size = self.db.get_val_int('journalsize', 0)
1733         self.fstype = self.db.get_val('fstype', '')
1734         self.backfstype = self.db.get_val('backfstype', '')
1735         self.mkfsoptions = self.db.get_val('mkfsoptions', '')
1736         self.mountfsoptions = self.db.get_val('mountfsoptions', '')
1737         self.target = self.db.lookup(target_uuid)
1738         self.name = "conf_%s" % self.target.getName()
1739         self.client_uuids = self.target.get_refs('client')
1740         self.obdtype = self.db.get_val('obdtype', '')
1741         
1742         if self.obdtype == None:
1743             self.obdtype = 'dumb'
1744         
1745         self.conf_name = name
1746         self.conf_uuid = uuid
1747         self.realdev = self.devpath
1748         
1749         self.lmv = None
1750         self.master = None
1751         
1752         lmv_uuid = self.db.get_first_ref('lmv')
1753         if lmv_uuid != None:
1754             self.lmv = self.db.lookup(lmv_uuid)
1755             if self.lmv != None:
1756                 self.client_uuids = self.lmv.get_refs('client')
1757
1758         if self.target.get_class() == 'mds':
1759             if self.target.get_val('failover', 0):
1760                 self.failover_mds = 'f'
1761             else:
1762                 self.failover_mds = 'n'
1763             self.format = self.db.get_val('autoformat', "no")
1764         else:
1765             self.format = self.db.get_val('autoformat', "yes")
1766             self.osdtype = self.db.get_val('osdtype')
1767             ost = self.db.lookup(target_uuid)
1768             if ost.get_val('failover', 0):
1769                 self.failover_ost = 'f'
1770             else:
1771                 self.failover_ost = 'n'
1772
1773         self.inode_size = self.get_inode_size()
1774
1775         if self.lmv != None:
1776             client_uuid = self.name + "_lmv_UUID"
1777             self.master = LMV(self.lmv, client_uuid, 
1778                               self.conf_name, self.conf_name)
1779
1780     def get_inode_size(self):
1781         inode_size = self.db.get_val_int('inodesize', 0)
1782         if inode_size == 0 and self.target.get_class() == 'mds':
1783         
1784             # default inode size for case when neither LOV either 
1785             # LMV is accessible.
1786             self.inode_size = 256
1787             
1788             # find the LOV for this MDS
1789             lovconfig_uuid = self.target.get_first_ref('lovconfig')
1790             if lovconfig_uuid or self.lmv != None:
1791                 if self.lmv != None:
1792                     lovconfig_uuid = self.lmv.get_first_ref('lovconfig')
1793                     lovconfig = self.lmv.lookup(lovconfig_uuid)
1794                     lov_uuid = lovconfig.get_first_ref('lov')
1795                     if lov_uuid == None:
1796                         panic(self.target.getName() + ": No LOV found for lovconfig ", 
1797                               lovconfig.name)
1798                 else:
1799                     lovconfig = self.target.lookup(lovconfig_uuid)
1800                     lov_uuid = lovconfig.get_first_ref('lov')
1801                     if lov_uuid == None:
1802                        panic(self.target.getName() + ": No LOV found for lovconfig ", 
1803                              lovconfig.name)
1804                     if self.lmv != None:
1805                         lovconfig_uuid = self.lmv.get_first_ref('lovconfig')
1806                         lovconfig = self.lmv.lookup(lovconfig_uuid)
1807                         lov_uuid = lovconfig.get_first_ref('lov')
1808
1809                 lov = LOV(self.db.lookup(lov_uuid), lov_uuid, self.name, 
1810                           config_only = 1)
1811
1812                 # default stripe count controls default inode_size
1813                 if lov.stripe_cnt > 0:
1814                     stripe_count = lov.stripe_cnt
1815                 else:
1816                     stripe_count = len(lov.devlist)
1817                 if stripe_count > 77:
1818                     inode_size = 4096
1819                 elif stripe_count > 35:
1820                     inode_size = 2048
1821                 elif stripe_count > 13:
1822                     inode_size = 1024
1823                 elif stripe_count > 3:
1824                     inode_size = 512
1825                 else:
1826                     inode_size = 256
1827                     
1828         return inode_size
1829             
1830     def get_mount_options(self, blkdev):
1831         options = def_mount_options(self.fstype, 
1832                                     self.target.get_class())
1833             
1834         if config.mountfsoptions:
1835             if options:
1836                 options = "%s,%s" %(options, config.mountfsoptions)
1837             else:
1838                 options = config.mountfsoptions
1839             if self.mountfsoptions:
1840                 options = "%s,%s" %(options, self.mountfsoptions)
1841         else:
1842             if self.mountfsoptions:
1843                 if options:
1844                     options = "%s,%s" %(options, self.mountfsoptions)
1845                 else:
1846                     options = self.mountfsoptions
1847             
1848         if self.fstype == 'smfs':
1849             if options:
1850                 options = "%s,type=%s,dev=%s" %(options, self.backfstype, 
1851                                                 blkdev)
1852             else:
1853                 options = "type=%s,dev=%s" %(self.backfstype, 
1854                                              blkdev)
1855         
1856         if self.target.get_class() == 'mds':
1857             if options:
1858                 options = "%s,acl,user_xattr,iopen_nopriv" %(options)
1859             else:
1860                 options = "iopen_nopriv"
1861             
1862         return options
1863
1864     def prepare(self):
1865         if is_prepared(self.name):
1866             return
1867         
1868         blkdev = block_dev(self.devpath, self.size, self.fstype,
1869                            config.reformat, self.format, self.journal_size,
1870                            self.inode_size, self.mkfsoptions, self.backfstype,
1871                            self.backdevpath)
1872
1873         if self.fstype == 'smfs':
1874             realdev = blkdev
1875         else:
1876             realdev = blkdev
1877                 
1878         mountfsoptions = self.get_mount_options(blkdev)
1879
1880         self.info(self.target.get_class(), realdev, mountfsoptions, 
1881                   self.fstype, self.size, self.format)
1882
1883         lctl.newdev("confobd", self.name, self.uuid, 
1884                     setup ="%s %s %s" %(realdev, self.fstype, 
1885                                         mountfsoptions))
1886
1887         self.mountfsoptions = mountfsoptions
1888         self.realdev = realdev
1889
1890     def add_module(self, manager):
1891         manager.add_lustre_module('obdclass', 'confobd')
1892
1893     def write_conf(self):
1894         if self.target.get_class() == 'ost':
1895             config.record = 1
1896             lctl.clear_log(self.name, self.target.getName() + '-conf')
1897             lctl.record(self.name, self.target.getName() + '-conf')
1898             lctl.newdev(self.osdtype, self.conf_name, self.conf_uuid,
1899                         setup ="%s %s %s %s" %(self.realdev, self.fstype,
1900                                                self.failover_ost,
1901                                                self.mountfsoptions))
1902             lctl.end_record()
1903             lctl.clear_log(self.name, 'OSS-conf')
1904             lctl.record(self.name, 'OSS-conf')
1905             lctl.newdev("ost", 'OSS', 'OSS_UUID', setup ="")
1906             lctl.end_record()
1907             config.record = 0
1908             return
1909
1910         if self.target.get_class() == 'mds':
1911             if self.master != None:
1912                 master_name = self.master.name
1913             else:
1914                 master_name = 'dumb'
1915
1916             config.record = 1
1917             lctl.clear_log(self.name, self.target.getName() + '-conf')
1918             lctl.record(self.name, self.target.getName() + '-conf')
1919             lctl.newdev("mds", self.conf_name, self.conf_uuid,
1920                         setup ="%s %s %s %s %s %s" %(self.realdev, self.fstype,
1921                                                      self.conf_name, self.mountfsoptions,
1922                                                      master_name, self.obdtype))
1923             lctl.end_record()
1924             config.record = 0
1925
1926         if not self.client_uuids:
1927             return 0
1928
1929         for uuid in self.client_uuids:
1930             log("recording client:", uuid)
1931             client_uuid = generate_client_uuid(self.name)
1932             client = VOSC(self.db.lookup(uuid), client_uuid, 
1933                           self.target.getName(), self.name)
1934             config.record = 1
1935             lctl.clear_log(self.name, self.target.getName())
1936             lctl.record(self.name, self.target.getName())
1937             client.prepare()
1938             lctl.mount_option(self.target.getName(), client.get_name(), "")
1939             lctl.end_record()
1940
1941             config.cleanup = 1
1942             lctl.clear_log(self.name, self.target.getName() + '-clean')
1943             lctl.record(self.name, self.target.getName() + '-clean')
1944             client.cleanup()
1945             lctl.del_mount_option(self.target.getName())
1946             lctl.end_record()
1947             config.cleanup = 0
1948             config.record = 0
1949
1950         if config.record:
1951             return
1952
1953         # record logs for each client
1954         if config.ldapurl:
1955             config_options = "--ldapurl " + config.ldapurl + " --config " + config.config
1956         else:
1957             config_options = CONFIG_FILE
1958
1959         for node_db in self.db.lookup_class('node'):
1960             client_name = node_db.getName()
1961             for prof_uuid in node_db.get_refs('profile'):
1962                 prof_db = node_db.lookup(prof_uuid)
1963                 # refactor this into a funtion to test "clientness"
1964                 # of a node.
1965                 for ref_class, ref_uuid in prof_db.get_all_refs():
1966                     if ref_class in ('mountpoint','echoclient'):
1967                         debug("recording", client_name)
1968                         old_noexec = config.noexec
1969                         config.noexec = 0
1970                         noexec_opt = ('', '-n')
1971                         ret, out = run (sys.argv[0],
1972                                         noexec_opt[old_noexec == 1],
1973                                         " -v --record --nomod",
1974                                         "--record_log", client_name,
1975                                         "--record_device", self.name,
1976                                         "--node", client_name,
1977                                         config_options)
1978                         if config.verbose:
1979                             for s in out: log("record> ", string.strip(s))
1980                         ret, out = run (sys.argv[0],
1981                                         noexec_opt[old_noexec == 1],
1982                                         "--cleanup -v --record --nomod",
1983                                         "--record_log", client_name + "-clean",
1984                                         "--record_device", self.name,
1985                                         "--node", client_name,
1986                                         config_options)
1987                         if config.verbose:
1988                             for s in out: log("record> ", string.strip(s))
1989                         config.noexec = old_noexec
1990
1991     def start(self):
1992          try:
1993             lctl.start(self.name, self.conf_name)
1994          except CommandError, e:
1995             raise e
1996          if self.target.get_class() == 'ost':
1997              if not is_prepared('OSS'):
1998                  try:
1999                      lctl.start(self.name, 'OSS')
2000                  except CommandError, e:
2001                      raise e
2002
2003     def cleanup(self):
2004         if is_prepared(self.name):
2005             try:
2006                 lctl.cleanup(self.name, self.uuid, 0, 0)
2007                 clean_dev(self.devpath, self.fstype, 
2008                           self.backfstype, self.backdevpath)
2009             except CommandError, e:
2010                 log(self.module_name, "cleanup failed: ", self.name)
2011                 e.dump()
2012                 cleanup_error(e.rc)
2013                 Module.cleanup(self)
2014
2015 class MDSDEV(Module):
2016     def __init__(self,db):
2017         Module.__init__(self, 'MDSDEV', db)
2018         self.devpath = self.db.get_val('devpath','')
2019         self.backdevpath = self.db.get_val('devpath','')
2020         self.size = self.db.get_val_int('devsize', 0)
2021         self.journal_size = self.db.get_val_int('journalsize', 0)
2022         self.fstype = self.db.get_val('fstype', '')
2023         self.backfstype = self.db.get_val('backfstype', '')
2024         self.nspath = self.db.get_val('nspath', '')
2025         self.mkfsoptions = self.db.get_val('mkfsoptions', '')
2026         self.mountfsoptions = self.db.get_val('mountfsoptions', '')
2027         self.obdtype = self.db.get_val('obdtype', '')
2028         self.root_squash = self.db.get_val('root_squash', '')
2029         self.no_root_squash = self.db.get_val('no_root_squash', '')
2030
2031         target_uuid = self.db.get_first_ref('target')
2032         self.target = self.db.lookup(target_uuid)
2033         self.name = self.target.getName()
2034         self.master = None
2035         self.lmv = None
2036         
2037         lmv_uuid = self.db.get_first_ref('lmv')
2038         if lmv_uuid != None:
2039             self.lmv = self.db.lookup(lmv_uuid)
2040
2041         active_uuid = get_active_target(self.target)
2042         if not active_uuid:
2043             panic("No target device found:", target_uuid)
2044         if active_uuid == self.uuid:
2045             self.active = 1
2046             group = self.target.get_val('group')
2047             if config.group and config.group != group:
2048                 self.active = 0
2049         else:
2050             self.active = 0
2051
2052         self.uuid = target_uuid
2053
2054         # setup LMV
2055         if self.lmv != None:
2056             client_uuid = self.name + "_lmv_UUID"
2057             self.master = LMV(self.lmv, client_uuid, 
2058                               self.name, self.name)
2059                               
2060         self.confobd = CONFDEV(self.db, self.name, 
2061                                target_uuid, self.uuid)
2062
2063     def add_module(self, manager):
2064         if self.active:
2065             manager.add_lustre_module('mdc', 'mdc')
2066             manager.add_lustre_module('osc', 'osc')
2067             manager.add_lustre_module('ost', 'ost')
2068             manager.add_lustre_module('lov', 'lov')
2069             manager.add_lustre_module('mds', 'mds')
2070
2071             if self.fstype == 'smfs' or self.fstype == 'ldiskfs':
2072                 manager.add_lustre_module(self.fstype, self.fstype)
2073                 
2074             if self.fstype:
2075                 manager.add_lustre_module('lvfs', 'fsfilt_%s' % (self.fstype))
2076             
2077             # if fstype is smfs, then we should also take care about backing 
2078             # store fs.
2079             if self.fstype == 'smfs':
2080                 manager.add_lustre_module(self.backfstype, self.backfstype)
2081                 manager.add_lustre_module('lvfs', 'fsfilt_%s' % (self.backfstype))
2082
2083             for option in string.split(self.mountfsoptions, ','):
2084                 if option == 'snap':
2085                     if not self.fstype == 'smfs':
2086                         panic("mountoptions has 'snap', but fstype is not smfs.")
2087                     manager.add_lustre_module('lvfs', 'fsfilt_snap_%s' % (self.fstype))
2088                     manager.add_lustre_module('lvfs', 'fsfilt_snap_%s' % (self.backfstype))
2089
2090         # add LMV modules
2091         if self.master != None:
2092             self.master.add_module(manager)
2093  
2094         # add CONFOBD modules
2095         if self.confobd != None:
2096             self.confobd.add_module(manager)
2097             
2098     def write_conf(self):
2099         if is_prepared(self.name):
2100             return
2101         if not self.active:
2102             debug(self.uuid, "not active")
2103             return
2104         run_acceptors()
2105         self.confobd.prepare()
2106         self.confobd.write_conf()
2107         self.confobd.cleanup()
2108
2109     def prepare(self):
2110         if is_prepared(self.name):
2111             return
2112         if not self.active:
2113             debug(self.uuid, "not active")
2114             return
2115         run_acceptors()
2116
2117         self.confobd.prepare()
2118         if config.reformat:
2119             self.confobd.write_conf()
2120
2121         # prepare LMV
2122         if self.master != None:
2123              self.master.prepare()
2124
2125         lctl.attach("mds", self.name, self.uuid)
2126         if config.mds_mds_sec:
2127             lctl.set_security(self.name, "mds_mds_sec", config.mds_mds_sec)
2128         if config.mds_ost_sec:
2129             lctl.set_security(self.name, "mds_ost_sec", config.mds_ost_sec)
2130         lctl.detach(self.name)
2131
2132         if not config.record:
2133             self.confobd.start()
2134         
2135         if not is_prepared('MDT'):
2136             lctl.newdev("mdt", 'MDT', 'MDT_UUID', setup ="")
2137
2138         if development_mode():
2139             procentry = "/proc/fs/lustre/mds/lsd_upcall"
2140             upcall = os.path.abspath(os.path.dirname(sys.argv[0]) + "/lsd_upcall")
2141             if not (os.access(procentry, os.R_OK) and os.access(upcall, os.R_OK)):
2142                 print "MDS Warning: failed to set lsd cache upcall"
2143             else:
2144                 run("echo ", upcall, " > ", procentry)
2145
2146         if config.root_squash == None:
2147             config.root_squash = self.root_squash
2148         if config.no_root_squash == None:
2149             config.no_root_squash = self.no_root_squash
2150         if config.root_squash:
2151             if config.no_root_squash:
2152                 nsnid = config.no_root_squash
2153             else:
2154                 nsnid = "0"
2155             lctl.root_squash(self.name, config.root_squash, nsnid)
2156
2157     def msd_remaining(self):
2158         out = lctl.device_list()
2159         for s in out:
2160             if string.split(s)[2] in ('mds',):
2161                 return 1
2162
2163     def safe_to_clean(self):
2164         return self.active
2165
2166     def safe_to_clean_modules(self):
2167         return not self.msd_remaining()
2168         
2169     def cleanup(self):
2170         if not self.active:
2171             debug(self.uuid, "not active")
2172             return
2173         self.info()
2174         if is_prepared(self.name):
2175             try:
2176                 lctl.cleanup(self.name, self.uuid, config.force,
2177                              config.failover)
2178             except CommandError, e:
2179                 log(self.module_name, "cleanup failed: ", self.name)
2180                 e.dump()
2181                 cleanup_error(e.rc)
2182                 Module.cleanup(self)
2183             # cleanup LMV
2184             if self.master != None:
2185                 self.master.cleanup()
2186         if not self.msd_remaining() and is_prepared('MDT'):
2187             try:
2188                 lctl.cleanup("MDT", "MDT_UUID", config.force,
2189                              config.failover)
2190             except CommandError, e:
2191                 print "cleanup failed: ", self.name
2192                 e.dump()
2193                 cleanup_error(e.rc)
2194         
2195         if self.confobd:
2196             self.confobd.cleanup()
2197
2198     def correct_level(self, level, op=None):
2199         #if self.master != None:
2200         #   level = level + 2
2201         return level
2202         
2203 class OSD(Module):
2204     def __init__(self, db):
2205         Module.__init__(self, 'OSD', db)
2206         self.osdtype = self.db.get_val('osdtype')
2207         self.devpath = self.db.get_val('devpath', '')
2208         self.backdevpath = self.db.get_val('devpath', '')
2209         self.size = self.db.get_val_int('devsize', 0)
2210         self.journal_size = self.db.get_val_int('journalsize', 0)
2211         self.inode_size = self.db.get_val_int('inodesize', 0)
2212         self.mkfsoptions = self.db.get_val('mkfsoptions', '')
2213         self.mountfsoptions = self.db.get_val('mountfsoptions', '')
2214         self.fstype = self.db.get_val('fstype', '')
2215         self.backfstype = self.db.get_val('backfstype', '')
2216         self.nspath = self.db.get_val('nspath', '')
2217         target_uuid = self.db.get_first_ref('target')
2218         ost = self.db.lookup(target_uuid)
2219         self.name = ost.getName()
2220         self.format = self.db.get_val('autoformat', 'yes')
2221         if ost.get_val('failover', 0):
2222             self.failover_ost = 'f'
2223         else:
2224             self.failover_ost = 'n'
2225
2226         active_uuid = get_active_target(ost)
2227         if not active_uuid:
2228             panic("No target device found:", target_uuid)
2229         if active_uuid == self.uuid:
2230             self.active = 1
2231             group = ost.get_val('group')
2232             if config.group and config.group != group:
2233                 self.active = 0
2234         else:
2235             self.active = 0
2236
2237         self.uuid = target_uuid
2238         self.confobd = CONFDEV(self.db, self.name, 
2239                                target_uuid, self.uuid)
2240     
2241     def add_module(self, manager):
2242         if not self.active:
2243             return
2244         manager.add_lustre_module('ost', 'ost')
2245             
2246         if self.fstype == 'smfs' or self.fstype == 'ldiskfs':
2247             manager.add_lustre_module(self.fstype, self.fstype)
2248                 
2249         if self.fstype:
2250             manager.add_lustre_module('lvfs' , 'fsfilt_%s' % (self.fstype))
2251
2252         if self.fstype == 'smfs':
2253             manager.add_lustre_module(self.backfstype, self.backfstype)
2254             manager.add_lustre_module('lvfs' , 'fsfilt_%s' % (self.backfstype))
2255
2256         for option in self.mountfsoptions:
2257             if option == 'snap':
2258                 if not self.fstype == 'smfs':
2259                     panic("mountoptions with snap, but fstype is not smfs\n")
2260                 manager.add_lustre_module('lvfs', 'fsfilt_snap_%s' % (self.fstype))
2261                 manager.add_lustre_module('lvfs', 'fsfilt_snap_%s' % (self.backfstype))
2262
2263         manager.add_lustre_module(self.osdtype, self.osdtype)
2264         
2265         # add CONFOBD modules
2266         if self.confobd != None:
2267             self.confobd.add_module(manager)
2268
2269     def prepare(self):
2270         if is_prepared(self.name):
2271             return
2272         if not self.active:
2273             debug(self.uuid, "not active")
2274             return
2275
2276         run_acceptors()
2277         if self.osdtype == 'obdecho':
2278             self.info(self.osdtype)
2279             lctl.newdev("obdecho", self.name, self.uuid)
2280             if not is_prepared('OSS'):
2281                 lctl.newdev("ost", 'OSS', 'OSS_UUID', setup="")
2282         else:
2283             self.confobd.prepare()
2284             if config.reformat:
2285                 self.confobd.write_conf()
2286             if not config.record:
2287                 self.confobd.start()        
2288
2289     def write_conf(self):
2290         if is_prepared(self.name):
2291             return
2292         if not self.active:
2293             debug(self.uuid, "not active")
2294             return
2295                                                                                                                
2296         run_acceptors()
2297         if self.osdtype != 'obdecho':
2298             self.confobd.prepare()
2299             self.confobd.write_conf()
2300             if not config.write_conf:
2301                 self.confobd.start()
2302             self.confobd.cleanup()
2303
2304     def osd_remaining(self):
2305         out = lctl.device_list()
2306         for s in out:
2307             if string.split(s)[2] in ('obdfilter', 'obdecho'):
2308                 return 1
2309
2310     def safe_to_clean(self):
2311         return self.active
2312
2313     def safe_to_clean_modules(self):
2314         return not self.osd_remaining()
2315
2316     def cleanup(self):
2317         if not self.active:
2318             debug(self.uuid, "not active")
2319             return
2320             
2321         if is_prepared(self.name):
2322             self.info()
2323             try:
2324                 lctl.cleanup(self.name, self.uuid, config.force,
2325                              config.failover)
2326             except CommandError, e:
2327                 log(self.module_name, "cleanup failed: ", self.name)
2328                 e.dump()
2329                 cleanup_error(e.rc)
2330         if not self.osd_remaining() and is_prepared('OSS'):
2331             try:
2332                 lctl.cleanup("OSS", "OSS_UUID", config.force,
2333                              config.failover)
2334             except CommandError, e:
2335                 print "cleanup failed: ", self.name
2336                 e.dump()
2337                 cleanup_error(e.rc)
2338
2339         if self.osdtype != 'obdecho':
2340             if self.confobd:
2341                 self.confobd.cleanup()
2342
2343     def correct_level(self, level, op=None):
2344         return level
2345
2346 # Generic client module, used by OSC and MDC
2347 class Client(Module):
2348     def __init__(self, tgtdb, uuid, module, fs_name, 
2349                  self_name=None, module_dir=None):
2350         self.target_name = tgtdb.getName()
2351         self.target_uuid = tgtdb.getUUID()
2352         self.module_dir = module_dir
2353         self.backup_targets = []
2354         self.module = module
2355         self.db = tgtdb
2356
2357         self.tgt_dev_uuid = get_active_target(tgtdb)
2358         if not self.tgt_dev_uuid:
2359             panic("No target device found for target(1):", self.target_name)
2360
2361         self._server = None
2362         self._connected = 0
2363
2364         self.module = module
2365         self.module_name = string.upper(module)
2366         if not self_name:
2367             self.name = '%s_%s_%s_%s' % (self.module_name, socket.gethostname(),
2368                                          self.target_name, fs_name)
2369         else:
2370             self.name = self_name
2371         self.uuid = uuid
2372         self.lookup_server(self.tgt_dev_uuid)
2373         self.lookup_backup_targets()
2374         self.fs_name = fs_name
2375         if not self.module_dir:
2376             self.module_dir = module
2377
2378     def add_module(self, manager):
2379         manager.add_lustre_module(self.module_dir, self.module)
2380
2381     def lookup_server(self, srv_uuid):
2382         """ Lookup a server's network information """
2383         self._server_nets = get_ost_net(self.db, srv_uuid)
2384         if len(self._server_nets) == 0:
2385             panic ("Unable to find a server for:", srv_uuid)
2386             
2387     def get_name(self):
2388         return self.name
2389
2390     def get_servers(self):
2391         return self._server_nets
2392
2393     def lookup_backup_targets(self):
2394         """ Lookup alternative network information """
2395         prof_list = toplustreDB.get_refs('profile')
2396         for prof_uuid in prof_list:
2397             prof_db = toplustreDB.lookup(prof_uuid)
2398             if not prof_db:
2399                 panic("profile:", prof_uuid, "not found.")
2400             for ref_class, ref_uuid in prof_db.get_all_refs():
2401                 if ref_class in ('osd', 'mdsdev'):
2402                     devdb = toplustreDB.lookup(ref_uuid)
2403                     uuid = devdb.get_first_ref('target')
2404                     if self.target_uuid == uuid and self.tgt_dev_uuid != ref_uuid:
2405                         self.backup_targets.append(ref_uuid)
2406
2407     def prepare(self, ignore_connect_failure = 0):
2408         self.info(self.target_uuid)
2409         if not config.record and is_prepared(self.name):
2410             self.cleanup()
2411         try:
2412             srv = choose_local_server(self.get_servers())
2413             if srv:
2414                 lctl.connect(srv)
2415             else:
2416                 routes = find_route(self.get_servers())
2417                 if len(routes) == 0:
2418                     panic ("no route to",  self.target_uuid)
2419                 for (srv, r) in routes:
2420                     lctl.add_route_host(r[0], srv.nid_uuid, r[1], r[3])
2421         except CommandError, e:
2422             if not ignore_connect_failure:
2423                 raise e
2424
2425         if srv:
2426             if self.target_uuid in config.inactive and self.permits_inactive():
2427                 debug("%s inactive" % self.target_uuid)
2428                 inactive_p = "inactive"
2429             else:
2430                 debug("%s active" % self.target_uuid)
2431                 inactive_p = ""
2432             lctl.newdev(self.module, self.name, self.uuid,
2433                         setup ="%s %s %s" % (self.target_uuid, srv.nid_uuid,
2434                                                 inactive_p))
2435         for tgt_dev_uuid in self.backup_targets:
2436             this_nets = get_ost_net(toplustreDB, tgt_dev_uuid)
2437             if len(this_nets) == 0:
2438                 panic ("Unable to find a server for:", tgt_dev_uuid)
2439             srv = choose_local_server(this_nets)
2440             if srv:
2441                 lctl.connect(srv)
2442             else:
2443                 routes = find_route(this_nets);
2444                 if len(routes) == 0:
2445                     panic("no route to", tgt_dev_uuid)
2446                 for (srv, r) in routes:
2447                     lctl.add_route_host(r[0]. srv.nid_uuid, r[1], r[3])
2448             if srv:
2449                 lctl.add_conn(self.name, srv.nid_uuid);
2450
2451     def cleanup(self):
2452         if is_prepared(self.name):
2453             Module.cleanup(self)
2454             try:
2455                 srv = choose_local_server(self.get_servers())
2456                 if srv:
2457                     lctl.disconnect(srv)
2458                 else:
2459                     for (srv, r) in find_route(self.get_servers()):
2460                         lctl.del_route_host(r[0], srv.nid_uuid, r[1], r[3])
2461             except CommandError, e:
2462                 log(self.module_name, "cleanup failed: ", self.name)
2463                 e.dump()
2464                 cleanup_error(e.rc)
2465
2466             for tgt_dev_uuid in self.backup_targets:
2467                 this_net = get_ost_net(toplustreDB, tgt_dev_uuid)
2468                 srv = choose_local_server(this_net)
2469                 if srv:
2470                     lctl.disconnect(srv)
2471                 else:
2472                     for (srv, r) in find_route(this_net):
2473                         lctl.del_route_host(r[0]. srv.nid_uuid, r[1], r[3])
2474
2475     def correct_level(self, level, op=None):
2476         return level
2477
2478     def deactivate(self):
2479         try:
2480             lctl.deactivate(self.name)
2481         except CommandError, e:
2482             log(self.module_name, "deactivate failed: ", self.name)
2483             e.dump()
2484             cleanup_error(e.rc)
2485
2486 class MDC(Client):
2487     def __init__(self, db, uuid, fs_name):
2488          Client.__init__(self, db, uuid, 'mdc', fs_name)
2489
2490     def permits_inactive(self):
2491         return 0
2492
2493 class OSC(Client):
2494     def __init__(self, db, uuid, fs_name):
2495          Client.__init__(self, db, uuid, 'osc', fs_name)
2496
2497     def permits_inactive(self):
2498         return 1
2499
2500 class CMOBD(Module):
2501     def __init__(self, db):
2502         Module.__init__(self, 'CMOBD', db)
2503         self.name = self.db.getName(); 
2504         self.uuid = generate_client_uuid(self.name)
2505         self.master_uuid = self.db.get_first_ref('masterobd')
2506         self.cache_uuid = self.db.get_first_ref('cacheobd')
2507
2508         master_obd = self.db.lookup(self.master_uuid)
2509         if not master_obd:
2510             panic('master obd not found:', self.master_uuid)
2511
2512         cache_obd = self.db.lookup(self.cache_uuid)
2513         if not cache_obd:
2514             panic('cache obd not found:', self.cache_uuid)
2515             
2516         self.master = None
2517         self.cache = None
2518             
2519         master_class = master_obd.get_class()
2520         cache_class = cache_obd.get_class()
2521
2522         if master_class == 'ost' or master_class == 'lov':
2523             client_uuid = "%s_lov_master_UUID" % (self.name)
2524             self.master = LOV(master_obd, client_uuid, self.name);
2525         elif master_class == 'mds':
2526             self.master = get_mdc(db, self.name, self.master_uuid) 
2527         elif master_class == 'lmv':
2528             client_uuid = "%s_lmv_master_UUID" % (self.name)
2529             self.master = LMV(master_obd, client_uuid, self.name);
2530         else:
2531             panic("unknown master obd class '%s'" %(master_class))
2532             
2533         if cache_class == 'ost' or cache_class == 'lov':
2534             client_uuid = "%s_lov_cache_UUID" % (self.name)
2535             self.cache = LOV(cache_obd, client_uuid, self.name);
2536         elif cache_class == 'mds':
2537             self.cache = get_mdc(db, self.name, self.cache_uuid)
2538         elif cache_class == 'lmv':
2539             client_uuid = "%s_lmv_cache_UUID" % (self.name)
2540             self.cache = LMV(cache_obd, client_uuid, self.name);
2541         else:
2542             panic("unknown cache obd class '%s'" %(cache_class))
2543
2544     def prepare(self):
2545         self.master.prepare()
2546         if not config.record and is_prepared(self.name):
2547             return
2548         self.info(self.master_uuid, self.cache_uuid)
2549         lctl.newdev("cmobd", self.name, self.uuid,
2550                     setup ="%s %s" %(self.master.uuid,
2551                                      self.cache.uuid))
2552
2553     def get_uuid(self):
2554         return self.uuid
2555         
2556     def get_name(self):
2557         return self.name
2558         
2559     def get_master_name(self):
2560         return self.master.name
2561             
2562     def get_cache_name(self):
2563         return self.cache.name
2564
2565     def cleanup(self):
2566         if is_prepared(self.name):
2567             Module.cleanup(self)
2568         if self.master:
2569             self.master.cleanup()
2570
2571     def add_module(self, manager):
2572         manager.add_lustre_module('cmobd', 'cmobd')
2573         self.master.add_module(manager)
2574
2575     def correct_level(self, level, op=None):
2576         return level
2577
2578 class COBD(Module):
2579     def __init__(self, db, uuid, name):
2580         Module.__init__(self, 'COBD', db)
2581         self.name = self.db.getName(); 
2582         self.uuid = generate_client_uuid(self.name)
2583         self.master_uuid = self.db.get_first_ref('masterobd')
2584         self.cache_uuid = self.db.get_first_ref('cacheobd')
2585
2586         master_obd = self.db.lookup(self.master_uuid)
2587         if not master_obd:
2588             panic('master obd not found:', self.master_uuid)
2589
2590         cache_obd = self.db.lookup(self.cache_uuid)
2591         if not cache_obd:
2592             panic('cache obd not found:', self.cache_uuid)
2593             
2594         self.master = None
2595         self.cache = None
2596
2597         master_class = master_obd.get_class()
2598         cache_class = cache_obd.get_class()
2599
2600         if master_class == 'ost' or master_class == 'lov':
2601             client_uuid = "%s_lov_master_UUID" % (self.name)
2602             self.master = LOV(master_obd, client_uuid, name);
2603         elif master_class == 'mds':
2604             self.master = get_mdc(db, name, self.master_uuid) 
2605         elif master_class == 'lmv':
2606             client_uuid = "%s_lmv_master_UUID" % (self.name)
2607             self.master = LMV(master_obd, client_uuid, self.name);
2608         else:
2609             panic("unknown master obd class '%s'" %(master_class))
2610             
2611         if cache_class == 'ost' or cache_class == 'lov':
2612             client_uuid = "%s_lov_cache_UUID" % (self.name)
2613             self.cache = LOV(cache_obd, client_uuid, name);
2614         elif cache_class == 'mds':
2615             self.cache = get_mdc(db, name, self.cache_uuid)
2616         elif cache_class == 'lmv':
2617             client_uuid = "%s_lmv_cache_UUID" % (self.name)
2618             self.cache = LMV(cache_obd, client_uuid, self.name);
2619         else:
2620             panic("unknown cache obd class '%s'" %(cache_class))
2621             
2622     def get_uuid(self):
2623         return self.uuid
2624
2625     def get_name(self):
2626         return self.name
2627
2628     def get_master_name(self):
2629         return self.master.name
2630
2631     def get_cache_name(self):
2632         return self.cache.name
2633
2634     def prepare(self):
2635         self.master.prepare()
2636         self.cache.prepare()
2637         if not config.record and is_prepared(self.name):
2638             return
2639         self.info(self.master_uuid, self.cache_uuid)
2640         lctl.newdev("cobd", self.name, self.uuid,
2641                     setup ="%s %s" %(self.master.name,
2642                                      self.cache.name))
2643
2644     def cleanup(self):
2645         if is_prepared(self.name):
2646             Module.cleanup(self)
2647         self.master.cleanup()
2648         self.cache.cleanup()
2649
2650     def add_module(self, manager):
2651         manager.add_lustre_module('cobd', 'cobd')
2652         self.master.add_module(manager)
2653
2654 # virtual interface for  OSC and LOV
2655 class VOSC(Module):
2656     def __init__(self, db, client_uuid, name, name_override = None):
2657         Module.__init__(self, 'VOSC', db)
2658         if db.get_class() == 'lov':
2659             self.osc = LOV(db, client_uuid, name, name_override)
2660             self.type = 'lov'
2661         elif db.get_class() == 'cobd':
2662             self.osc = COBD(db, client_uuid, name)
2663             self.type = 'cobd'
2664         else:
2665             self.osc = OSC(db, client_uuid, name)
2666             self.type = 'osc'
2667             
2668     def get_uuid(self):
2669         return self.osc.get_uuid()
2670
2671     def get_name(self):
2672         return self.osc.get_name()
2673
2674     def prepare(self):
2675         self.osc.prepare()
2676         
2677     def cleanup(self):
2678         self.osc.cleanup()
2679         
2680     def add_module(self, manager):
2681         self.osc.add_module(manager)
2682         
2683     def correct_level(self, level, op=None):
2684         return self.osc.correct_level(level, op)
2685
2686 # virtual interface for MDC and LMV
2687 class VMDC(Module):
2688     def __init__(self, db, client_uuid, name, name_override = None):
2689         Module.__init__(self, 'VMDC', db)
2690         if db.get_class() == 'lmv':
2691             self.mdc = LMV(db, client_uuid, name, name_override)
2692         elif db.get_class() == 'cobd':
2693             self.mdc = COBD(db, client_uuid, name)
2694         else:
2695             self.mdc = MDC(db, client_uuid, name)
2696             
2697     def get_uuid(self):
2698         return self.mdc.uuid
2699
2700     def get_name(self):
2701         return self.mdc.name
2702
2703     def prepare(self):
2704         self.mdc.prepare()
2705         
2706     def cleanup(self):
2707         self.mdc.cleanup()
2708         
2709     def add_module(self, manager):
2710         self.mdc.add_module(manager)
2711         
2712     def correct_level(self, level, op=None):
2713         return self.mdc.correct_level(level, op)
2714
2715 class ECHO_CLIENT(Module):
2716     def __init__(self,db):
2717         Module.__init__(self, 'ECHO_CLIENT', db)
2718         self.obd_uuid = self.db.get_first_ref('obd')
2719         obd = self.db.lookup(self.obd_uuid)
2720         self.uuid = generate_client_uuid(self.name)
2721         self.osc = VOSC(obd, self.uuid, self.name)
2722
2723     def prepare(self):
2724         if not config.record and is_prepared(self.name):
2725             return
2726         run_acceptors()
2727         self.osc.prepare() # XXX This is so cheating. -p
2728         self.info(self.obd_uuid)
2729
2730         lctl.newdev("echo_client", self.name, self.uuid,
2731                     setup = self.osc.get_name())
2732
2733     def cleanup(self):
2734         if is_prepared(self.name):
2735             Module.cleanup(self)
2736         self.osc.cleanup()
2737
2738     def add_module(self, manager):
2739         self.osc.add_module(manager)
2740         manager.add_lustre_module('obdecho', 'obdecho')
2741
2742     def correct_level(self, level, op=None):
2743         return level
2744
2745 def generate_client_uuid(name):
2746         client_uuid = '%05x_%.19s_%05x%05x' % (int(random.random() * 1048576),
2747                                                name,
2748                                                int(random.random() * 1048576),
2749                                                int(random.random() * 1048576))
2750         return client_uuid[:36]
2751
2752 class Mountpoint(Module):
2753     def __init__(self,db):
2754         Module.__init__(self, 'MTPT', db)
2755         self.path = self.db.get_val('path')
2756         self.clientoptions = self.db.get_val('clientoptions', '')
2757         self.fs_uuid = self.db.get_first_ref('filesystem')
2758         fs = self.db.lookup(self.fs_uuid)
2759         self.mds_uuid = fs.get_first_ref('lmv')
2760         if not self.mds_uuid:
2761             self.mds_uuid = fs.get_first_ref('mds')
2762         self.obd_uuid = fs.get_first_ref('obd')
2763         client_uuid = generate_client_uuid(self.name)
2764
2765         ost = self.db.lookup(self.obd_uuid)
2766         if not ost:
2767             panic("no ost: ", self.obd_uuid)
2768             
2769         mds = self.db.lookup(self.mds_uuid)
2770         if not mds:
2771             panic("no mds: ", self.mds_uuid)
2772        
2773         self.vosc = VOSC(ost, client_uuid, self.name, self.name)
2774         self.vmdc = VMDC(mds, client_uuid, self.name, self.name)
2775         
2776     def prepare(self):
2777         if not config.record and fs_is_mounted(self.path):
2778             log(self.path, "already mounted.")
2779             return
2780         run_acceptors()
2781
2782         self.vosc.prepare()
2783         self.vmdc.prepare()
2784
2785         self.info(self.path, self.mds_uuid, self.obd_uuid)
2786         if config.record or config.lctl_dump:
2787             lctl.mount_option(local_node_name, self.vosc.get_name(), 
2788                               self.vmdc.get_name())
2789             return
2790
2791         if config.clientoptions:
2792             if self.clientoptions:
2793                 self.clientoptions = self.clientoptions + ',' + config.clientoptions
2794             else:
2795                 self.clientoptions = config.clientoptions
2796         if self.clientoptions:
2797             self.clientoptions = ',' + self.clientoptions
2798             # Linux kernel will deal with async and not pass it to ll_fill_super,
2799             # so replace it with Lustre async
2800             self.clientoptions = string.replace(self.clientoptions, "async", "lasync")
2801
2802         if not config.sec:
2803             config.sec = "null"
2804         cmd = "mount -t lustre_lite -o osc=%s,mdc=%s,sec=%s%s %s %s" % \
2805               (self.vosc.get_name(), self.vmdc.get_name(), config.sec, 
2806                self.clientoptions, config.config, self.path)
2807         run("mkdir", self.path)
2808         ret, val = run(cmd)
2809         if ret:
2810             self.vmdc.cleanup()            
2811             self.vosc.cleanup()
2812             panic("mount failed:", self.path, ":", string.join(val))
2813
2814     def cleanup(self):
2815         self.info(self.path, self.mds_uuid,self.obd_uuid)
2816
2817         if config.record or config.lctl_dump:
2818             lctl.del_mount_option(local_node_name)
2819         else:
2820             if fs_is_mounted(self.path):
2821                 if config.force:
2822                     (rc, out) = run("umount", "-f", self.path)
2823                 else:
2824                     (rc, out) = run("umount", self.path)
2825                 if rc:
2826                     raise CommandError('umount', out, rc)
2827
2828             if fs_is_mounted(self.path):
2829                 panic("fs is still mounted:", self.path)
2830
2831         self.vmdc.cleanup()
2832         self.vosc.cleanup()
2833
2834     def add_module(self, manager):
2835         self.vosc.add_module(manager)
2836         self.vmdc.add_module(manager)
2837         manager.add_lustre_module('llite', 'llite')
2838
2839     def correct_level(self, level, op=None):
2840         return level
2841
2842 # ============================================================
2843 # misc query functions
2844
2845 def get_ost_net(self, osd_uuid):
2846     srv_list = []
2847     if not osd_uuid:
2848         return srv_list
2849     osd = self.lookup(osd_uuid)
2850     node_uuid = osd.get_first_ref('node')
2851     node = self.lookup(node_uuid)
2852     if not node:
2853         panic("unable to find node for osd_uuid:", osd_uuid,
2854               " node_ref:", node_uuid_)
2855     for net_uuid in node.get_networks():
2856         db = node.lookup(net_uuid)
2857         srv_list.append(Network(db))
2858     return srv_list
2859
2860 # the order of iniitailization is based on level. 
2861 def getServiceLevel(self):
2862     type = self.get_class()
2863     ret=0;
2864     if type in ('network',):
2865         ret = 5
2866     elif type in ('routetbl',):
2867         ret = 6
2868     elif type in ('ldlm',):
2869         ret = 20
2870     elif type in ('osd', 'cobd'):
2871         ret = 30
2872     elif type in ('mdsdev',):
2873         ret = 40
2874     elif type in ('lmv',):
2875         ret = 45
2876     elif type in ('cmobd',):
2877         ret = 50
2878     elif type in ('mountpoint', 'echoclient'):
2879         ret = 70
2880     else:
2881         panic("Unknown type: ", type)
2882
2883     if ret < config.minlevel or ret > config.maxlevel:
2884         ret = 0
2885     return ret
2886
2887 #
2888 # return list of services in a profile. list is a list of tuples
2889 # [(level, db_object),]
2890 def getServices(self):
2891     list = []
2892     for ref_class, ref_uuid in self.get_all_refs():
2893             servdb = self.lookup(ref_uuid)
2894             if  servdb:
2895                 level = getServiceLevel(servdb)
2896                 if level > 0:
2897                     list.append((level, servdb))
2898             else:
2899                 panic('service not found: ' + ref_uuid)
2900
2901     list.sort()
2902     return list
2903
2904
2905 ############################################################
2906 # MDC UUID hack -
2907 # FIXME: clean this mess up!
2908 #
2909 # OSC is no longer in the xml, so we have to fake it.
2910 # this is getting ugly and begging for another refactoring
2911 def get_osc(ost_db, uuid, fs_name):
2912     osc = OSC(ost_db, uuid, fs_name)
2913     return osc
2914
2915 def get_mdc(db, fs_name, mds_uuid):
2916     mds_db = db.lookup(mds_uuid);
2917     if not mds_db:
2918         error("no mds:", mds_uuid)
2919     mdc = MDC(mds_db, mds_uuid, fs_name)
2920     return mdc
2921
2922 ############################################################
2923 # routing ("rooting")
2924
2925 # list of (nettype, cluster_id, nid)
2926 local_clusters = []
2927
2928 def find_local_clusters(node_db):
2929     global local_clusters
2930     for netuuid in node_db.get_networks():
2931         net = node_db.lookup(netuuid)
2932         srv = Network(net)
2933         debug("add_local", netuuid)
2934         local_clusters.append((srv.net_type, srv.cluster_id, srv.nid))
2935         if srv.port > 0:
2936             if not acceptors.has_key(srv.port):
2937                 acceptors[srv.port] = AcceptorHandler(srv.port, srv.net_type)
2938
2939 # This node is a gateway.
2940 is_router = 0
2941 def node_is_router():
2942     return is_router
2943
2944 # If there are any routers found in the config, then this will be true
2945 # and all nodes will load kptlrouter.
2946 needs_router = 0
2947 def node_needs_router():
2948     return needs_router or is_router
2949
2950 # list of (nettype, gw, tgt_cluster_id, lo, hi)
2951 # Currently, these local routes are only added to kptlrouter route
2952 # table if they are needed to connect to a specific server.  This
2953 # should be changed so all available routes are loaded, and the
2954 # ptlrouter can make all the decisions.
2955 local_routes = []
2956
2957 def find_local_routes(lustre):
2958     """ Scan the lustre config looking for routers .  Build list of
2959     routes. """
2960     global local_routes, needs_router
2961     local_routes = []
2962     list = lustre.lookup_class('node')
2963     for router in list:
2964         if router.get_val_int('router', 0):
2965             needs_router = 1
2966             for (local_type, local_cluster_id, local_nid) in local_clusters:
2967                 gw = None
2968                 for netuuid in router.get_networks():
2969                     db = router.lookup(netuuid)
2970                     if (local_type == db.get_val('nettype') and
2971                        local_cluster_id == db.get_val('clusterid')):
2972                         gw = db.get_val('nid')
2973                         break
2974                 if gw:
2975                     debug("find_local_routes: gw is", gw)
2976                     for route in router.get_local_routes(local_type, gw):
2977                         local_routes.append(route)
2978     debug("find_local_routes:", local_routes)
2979
2980
2981 def choose_local_server(srv_list):
2982     for srv in srv_list:
2983         if local_cluster(srv.net_type, srv.cluster_id):
2984             return srv
2985
2986 def local_cluster(net_type, cluster_id):
2987     for cluster in local_clusters:
2988         if net_type == cluster[0] and cluster_id == cluster[1]:
2989             return 1
2990     return 0
2991
2992 def local_interface(net_type, cluster_id, nid):
2993     for cluster in local_clusters:
2994         if (net_type == cluster[0] and cluster_id == cluster[1]
2995             and nid == cluster[2]):
2996             return 1
2997     return 0
2998
2999 def find_route(srv_list):
3000     result = []
3001     frm_type = local_clusters[0][0]
3002     for srv in srv_list:
3003         debug("find_route: srv:", srv.nid, "type: ", srv.net_type)
3004         to_type = srv.net_type
3005         to = srv.nid
3006         cluster_id = srv.cluster_id
3007         debug ('looking for route to', to_type, to)
3008         for r in local_routes:
3009             debug("find_route: ", r)
3010             if  (r[3] <= to and to <= r[4]) and cluster_id == r[2]:
3011                 result.append((srv, r))
3012     return result
3013            
3014 def get_active_target(db):
3015     target_uuid = db.getUUID()
3016     target_name = db.getName()
3017     node_name = get_select(target_name)
3018     if node_name:
3019         tgt_dev_uuid = db.get_node_tgt_dev(node_name, target_uuid)
3020     else:
3021         tgt_dev_uuid = db.get_first_ref('active')
3022     return tgt_dev_uuid
3023
3024 def get_server_by_nid_uuid(db,  nid_uuid):
3025     for n in db.lookup_class("network"):
3026         net = Network(n)
3027         if net.nid_uuid == nid_uuid:
3028             return net
3029         
3030
3031 ############################################################
3032 # lconf level logic
3033 # Start a service.
3034 def newService(db):
3035     type = db.get_class()
3036     debug('Service:', type, db.getName(), db.getUUID())
3037     n = None
3038     if type == 'ldlm':
3039         n = LDLM(db)
3040     elif type == 'lov':
3041         n = LOV(db, "YOU_SHOULD_NEVER_SEE_THIS_UUID")
3042     elif type == 'network':
3043         n = Network(db)
3044     elif type == 'routetbl':
3045         n = RouteTable(db)
3046     elif type == 'osd':
3047         n = OSD(db)
3048     elif type == 'cobd':
3049         n = COBD(db, "YOU_SHOULD_NEVER_SEE_THIS_UUID")
3050     elif type == 'cmobd':
3051         n = CMOBD(db)
3052     elif type == 'mdsdev':
3053         n = MDSDEV(db)
3054     elif type == 'mountpoint':
3055         n = Mountpoint(db)
3056     elif type == 'echoclient':
3057         n = ECHO_CLIENT(db)
3058     elif type == 'lmv':
3059         n = LMV(db)
3060     else:
3061         panic ("unknown service type:", type)
3062     return n
3063
3064 #
3065 # Prepare the system to run lustre using a particular profile
3066 # in a the configuration. 
3067 #  * load & the modules
3068 #  * setup networking for the current node
3069 #  * make sure partitions are in place and prepared
3070 #  * initialize devices with lctl
3071 # Levels is important, and needs to be enforced.
3072 def for_each_profile(db, prof_list, operation):
3073     for prof_uuid in prof_list:
3074         prof_db = db.lookup(prof_uuid)
3075         if not prof_db:
3076             panic("profile:", prof_uuid, "not found.")
3077         services = getServices(prof_db)
3078         operation(services)
3079
3080 def magic_get_osc(db, rec, lov):
3081     if lov:
3082         lov_uuid = lov.get_uuid()
3083         lov_name = lov.osc.fs_name
3084     else:
3085         lov_uuid = rec.getAttribute('lov_uuidref')
3086         # FIXME: better way to find the mountpoint?
3087         filesystems = db.root_node.getElementsByTagName('filesystem')
3088         fsuuid = None
3089         for fs in filesystems:
3090             ref = fs.getElementsByTagName('obd_ref')
3091             if ref[0].getAttribute('uuidref') == lov_uuid:
3092                 fsuuid = fs.getAttribute('uuid')
3093                 break
3094
3095         if not fsuuid:
3096             panic("malformed xml: lov uuid '" + lov_uuid + "' referenced in 'add' record is not used by any filesystems.")
3097
3098         mtpts = db.root_node.getElementsByTagName('mountpoint')
3099         lov_name = None
3100         for fs in mtpts:
3101             ref = fs.getElementsByTagName('filesystem_ref')
3102             if ref[0].getAttribute('uuidref') == fsuuid:
3103                 lov_name = fs.getAttribute('name')
3104                 break
3105
3106         if not lov_name:
3107             panic("malformed xml: 'add' record references lov uuid '" + lov_uuid + "', which references filesystem uuid '" + fsuuid + "', which does not reference a mountpoint.")
3108
3109     print "lov_uuid: " + lov_uuid + "; lov_name: " + lov_name
3110
3111     ost_uuid = rec.getAttribute('ost_uuidref')
3112     obd = db.lookup(ost_uuid)
3113
3114     if not obd:
3115         panic("malformed xml: 'add' record references ost uuid '" + ost_uuid + "' which cannot be found.")
3116
3117     osc = get_osc(obd, lov_uuid, lov_name)
3118     if not osc:
3119         panic('osc not found:', obd_uuid)
3120     return osc
3121
3122 # write logs for update records.  sadly, logs of all types -- and updates in
3123 # particular -- are something of an afterthought.  lconf needs rewritten with
3124 # these as core concepts.  so this is a pretty big hack.
3125 def process_update_record(db, update, lov):
3126     for rec in update.childNodes:
3127         if rec.nodeType != rec.ELEMENT_NODE:
3128             continue
3129
3130         log("found "+rec.nodeName+" record in update version " +
3131             str(update.getAttribute('version')))
3132
3133         lov_uuid = rec.getAttribute('lov_uuidref')
3134         ost_uuid = rec.getAttribute('ost_uuidref')
3135         index = rec.getAttribute('index')
3136         gen = rec.getAttribute('generation')
3137
3138         if not lov_uuid or not ost_uuid or not index or not gen:
3139             panic("malformed xml: 'update' record requires lov_uuid, ost_uuid, index, and generation.")
3140
3141         if not lov:
3142             tmplov = db.lookup(lov_uuid)
3143             if not tmplov:
3144                 panic("malformed xml: 'delete' record contains lov UUID '" + lov_uuid + "', which cannot be located.")
3145             lov_name = tmplov.getName()
3146         else:
3147             lov_name = lov.osc.name
3148
3149         # ------------------------------------------------------------- add
3150         if rec.nodeName == 'add':
3151             if config.cleanup:
3152                 lctl.lov_del_obd(lov_name, lov_uuid, ost_uuid, index, gen)
3153                 continue
3154
3155             osc = magic_get_osc(db, rec, lov)
3156
3157             try:
3158                 # Only ignore connect failures with --force, which
3159                 # isn't implemented here yet.
3160                 osc.prepare(ignore_connect_failure=0)
3161             except CommandError, e:
3162                 print "Error preparing OSC %s\n" % osc.uuid
3163                 raise e
3164
3165             lctl.lov_add_obd(lov_name, lov_uuid, ost_uuid, index, gen)
3166
3167         # ------------------------------------------------------ deactivate
3168         elif rec.nodeName == 'deactivate':
3169             if config.cleanup:
3170                 continue
3171
3172             osc = magic_get_osc(db, rec, lov)
3173
3174             try:
3175                 osc.deactivate()
3176             except CommandError, e:
3177                 print "Error deactivating OSC %s\n" % osc.uuid
3178                 raise e
3179
3180         # ---------------------------------------------------------- delete
3181         elif rec.nodeName == 'delete':
3182             if config.cleanup:
3183                 continue
3184
3185             osc = magic_get_osc(db, rec, lov)
3186
3187             try:
3188                 config.cleanup = 1
3189                 osc.cleanup()
3190                 config.cleanup = 0
3191             except CommandError, e:
3192                 print "Error cleaning up OSC %s\n" % osc.uuid
3193                 raise e
3194
3195             lctl.lov_del_obd(lov_name, lov_uuid, ost_uuid, index, gen)
3196
3197 def process_updates(db, log_device, log_name, lov = None):
3198     updates = db.root_node.getElementsByTagName('update')
3199     for u in updates:
3200         if not u.childNodes:
3201             log("ignoring empty update record (version " +
3202                 str(u.getAttribute('version')) + ")")
3203             continue
3204
3205         version = u.getAttribute('version')
3206         real_name = "%s-%s" % (log_name, version)
3207         lctl.clear_log(log_device, real_name)
3208         lctl.record(log_device, real_name)
3209
3210         process_update_record(db, u, lov)
3211
3212         lctl.end_record()
3213
3214 def doWriteconf(services):
3215     #if config.nosetup:
3216     #    return
3217     for s in services:
3218         if s[1].get_class() == 'mdsdev' or s[1].get_class() == 'osd':
3219             n = newService(s[1])
3220             n.write_conf()
3221             n.cleanup()
3222
3223 def doSetup(services):
3224     if config.nosetup:
3225         return
3226     slist = []
3227     for s in services:
3228         n = newService(s[1])
3229         n.level = s[0]
3230         slist.append((n.level, n))
3231     nlist = []
3232     for n in slist:
3233         nl = n[1].correct_level(n[0])
3234         nlist.append((nl, n[1]))
3235     nlist.sort()
3236     for n in nlist:
3237         n[1].prepare()
3238
3239 def doLoadModules(services):
3240     if config.nomod:
3241         return
3242         
3243     # adding all needed modules from all services
3244     for s in services:
3245         n = newService(s[1])
3246         n.add_module(mod_manager)
3247     
3248     # loading all registered modules
3249     mod_manager.load_modules()
3250
3251 def doUnloadModules(services):
3252     if config.nomod:
3253         return
3254         
3255     # adding all needed modules from all services
3256     for s in services:
3257         n = newService(s[1])
3258         if n.safe_to_clean_modules():
3259             n.add_module(mod_manager)
3260     
3261     # unloading all registered modules
3262     mod_manager.cleanup_modules()
3263
3264 def doCleanup(services):
3265     if config.nosetup:
3266         return
3267     slist = []
3268
3269     for s in services:
3270         n = newService(s[1])
3271         n.level = s[0]
3272         slist.append((n.level, n))
3273     nlist = []
3274     for n in slist:
3275         nl = n[1].correct_level(n[0])
3276         nlist.append((nl, n[1]))
3277     nlist.sort()
3278     nlist.reverse()
3279
3280     for n in nlist:
3281         if n[1].safe_to_clean():
3282             n[1].cleanup()
3283
3284 #
3285 # Load profile for 
3286 def doHost(lustreDB, hosts):
3287     global is_router, local_node_name
3288     node_db = None
3289     for h in hosts:
3290         node_db = lustreDB.lookup_name(h, 'node')
3291         if node_db:
3292             break
3293     if not node_db:
3294         panic('No host entry found.')
3295
3296     local_node_name = node_db.get_val('name', 0)
3297     is_router = node_db.get_val_int('router', 0)
3298     lustre_upcall = node_db.get_val('lustreUpcall', '')
3299     portals_upcall = node_db.get_val('portalsUpcall', '')
3300     timeout = node_db.get_val_int('timeout', 0)
3301     ptldebug = node_db.get_val('ptldebug', '')
3302     subsystem = node_db.get_val('subsystem', '')
3303     
3304     find_local_clusters(node_db)
3305     if not is_router:
3306         find_local_routes(lustreDB)
3307
3308     # Two step process: (1) load modules, (2) setup lustre
3309     # if not cleaning, load modules first.
3310     prof_list = node_db.get_refs('profile')
3311
3312     if config.write_conf:
3313         for_each_profile(node_db, prof_list, doLoadModules)
3314         sys_make_devices()
3315         for_each_profile(node_db, prof_list, doWriteconf)
3316         for_each_profile(node_db, prof_list, doUnloadModules)
3317         lustreDB.close()
3318
3319     elif config.recover:
3320         if not (config.tgt_uuid and config.client_uuid and config.conn_uuid):
3321             raise Lustre.LconfError( "--recovery requires --tgt_uuid <UUID> " +
3322                                      "--client_uuid <UUID> --conn_uuid <UUID>")
3323         doRecovery(lustreDB, lctl, config.tgt_uuid, config.client_uuid,
3324                    config.conn_uuid)
3325     elif config.cleanup:
3326         if config.force:
3327             # the command line can override this value
3328             timeout = 5
3329         # ugly hack, only need to run lctl commands for --dump
3330         if config.lctl_dump or config.record:
3331             for_each_profile(node_db, prof_list, doCleanup)
3332             return
3333
3334         sys_set_timeout(timeout)
3335         sys_set_ptldebug(ptldebug)
3336         sys_set_subsystem(subsystem)
3337         sys_set_lustre_upcall(lustre_upcall)
3338         sys_set_portals_upcall(portals_upcall)
3339
3340         for_each_profile(node_db, prof_list, doCleanup)
3341         for_each_profile(node_db, prof_list, doUnloadModules)
3342         lustreDB.close()
3343
3344     else:
3345         # ugly hack, only need to run lctl commands for --dump
3346         if config.lctl_dump or config.record:
3347             sys_set_timeout(timeout)
3348             sys_set_lustre_upcall(lustre_upcall)
3349             for_each_profile(node_db, prof_list, doSetup)
3350             return
3351
3352         sys_make_devices()
3353         sys_set_netmem_max('/proc/sys/net/core/rmem_max', MAXTCPBUF)
3354         sys_set_netmem_max('/proc/sys/net/core/wmem_max', MAXTCPBUF)
3355
3356         for_each_profile(node_db, prof_list, doLoadModules)
3357
3358         sys_set_debug_path()
3359         sys_set_ptldebug(ptldebug)
3360         sys_set_subsystem(subsystem)
3361         script = config.gdb_script
3362         run(lctl.lctl, ' modules >', script)
3363         if config.gdb:
3364             log ("The GDB module script is in", script)
3365             # pause, so user has time to break and
3366             # load the script
3367             time.sleep(5)
3368         sys_set_timeout(timeout)
3369         sys_set_lustre_upcall(lustre_upcall)
3370         sys_set_portals_upcall(portals_upcall)
3371
3372         for_each_profile(node_db, prof_list, doSetup)
3373         lustreDB.close()
3374
3375 def doRecovery(lustreDB, lctl, tgt_uuid, client_uuid, nid_uuid):
3376     tgt = lustreDB.lookup(tgt_uuid)
3377     if not tgt:
3378         raise Lustre.LconfError("doRecovery: "+ tgt_uuid +" not found.")
3379     new_uuid = get_active_target(tgt)
3380     if not new_uuid:
3381         raise Lustre.LconfError("doRecovery: no active target found for: " +
3382                                 tgt_uuid)
3383     net = choose_local_server(get_ost_net(lustreDB, new_uuid))
3384     if not net:
3385         raise Lustre.LconfError("Unable to find a connection to:" + new_uuid)
3386
3387     log("Reconnecting", tgt_uuid, " to ",  net.nid_uuid);
3388     try:
3389         oldnet = get_server_by_nid_uuid(lustreDB, nid_uuid)
3390         lustreDB.close()
3391         if oldnet:
3392             lctl.disconnect(oldnet)
3393     except CommandError, e:
3394         log("recover: disconnect", nid_uuid, "failed: ")
3395         e.dump()
3396
3397     try:
3398         lctl.connect(net)
3399     except CommandError, e:
3400         log("recover: connect failed")
3401         e.dump()
3402
3403     lctl.recover(client_uuid, net.nid_uuid)
3404
3405
3406 def setupModulePath(cmd, portals_dir = PORTALS_DIR):
3407     base = os.path.dirname(cmd)
3408     if development_mode():
3409         if not config.lustre:
3410             debug('using objdir module paths')            
3411             config.lustre = (os.path.join(base, ".."))
3412         # normalize the portals dir, using command line arg if set
3413         if config.portals:
3414             portals_dir = config.portals
3415         dir = os.path.join(config.lustre, portals_dir)
3416         config.portals = dir
3417         debug('config.portals', config.portals)
3418     elif config.lustre and config.portals:
3419         # production mode
3420         # if --lustre and --portals, normalize portals 
3421         # can ignore POTRALS_DIR here, since it is probly useless here
3422         config.portals = os.path.join(config.lustre, config.portals)
3423         debug('config.portals B', config.portals)
3424
3425 def sysctl(path, val):
3426     debug("+ sysctl", path, val)
3427     if config.noexec:
3428         return
3429     try:
3430         fp = open(os.path.join('/proc/sys', path), 'w')
3431         fp.write(str(val))
3432         fp.close()
3433     except IOError, e:
3434         panic(str(e))
3435
3436
3437 def sys_set_debug_path():
3438     sysctl('portals/debug_path', config.debug_path)
3439
3440 def sys_set_lustre_upcall(upcall):
3441     # the command overrides the value in the node config
3442     if config.lustre_upcall:
3443         upcall = config.lustre_upcall
3444     elif config.upcall:
3445         upcall = config.upcall
3446     if upcall:
3447         lctl.set_lustre_upcall(upcall)
3448
3449 def sys_set_portals_upcall(upcall):
3450     # the command overrides the value in the node config
3451     if config.portals_upcall:
3452         upcall = config.portals_upcall
3453     elif config.upcall:
3454         upcall = config.upcall
3455     if upcall:
3456         sysctl('portals/upcall', upcall)
3457
3458 def sys_set_timeout(timeout):
3459     # the command overrides the value in the node config
3460     if config.timeout and config.timeout > 0:
3461         timeout = config.timeout
3462     if timeout != None and timeout > 0:
3463         lctl.set_timeout(timeout)
3464
3465 def sys_tweak_socknal ():
3466     # reserve at least 8MB, or we run out of RAM in skb_alloc under read
3467     if sys_get_branch() == '2.6':
3468         fp = open('/proc/meminfo')
3469         lines = fp.readlines()
3470         fp.close()
3471         memtotal = 131072
3472         for l in lines:
3473             a = string.split(l)
3474             if a[0] == 'MemTotal:':
3475                 memtotal = a[1]
3476                 debug("memtotal" + memtotal)
3477         if int(memtotal) < 262144:
3478             minfree = int(memtotal) / 16
3479         else:
3480             minfree = 32768
3481         debug("+ minfree ", minfree)
3482         sysctl("vm/min_free_kbytes", minfree)
3483     if config.single_socket:
3484         sysctl("socknal/typed", 0)
3485
3486 def sys_optimize_elan ():
3487     procfiles = ["/proc/elan/config/eventint_punt_loops",
3488                  "/proc/qsnet/elan3/config/eventint_punt_loops",
3489                  "/proc/qsnet/elan4/config/elan4_mainint_punt_loops"]
3490     for p in procfiles:
3491         if os.access(p, os.W_OK):
3492             run ("echo 1 > " + p)
3493
3494 def sys_set_ptldebug(ptldebug):
3495     if config.ptldebug:
3496         ptldebug = config.ptldebug
3497     if ptldebug:
3498         try:
3499             val = eval(ptldebug, ptldebug_names)
3500             val = "0x%x" % (id(val) & 0xffffffffL)
3501             sysctl('portals/debug', val)
3502         except NameError, e:
3503             panic(str(e))
3504
3505 def sys_set_subsystem(subsystem):
3506     if config.subsystem:
3507         subsystem = config.subsystem
3508     if subsystem:
3509         try:
3510             val = eval(subsystem, subsystem_names)
3511             val = "0x%x" % (id(val) & 0xffffffffL)
3512             sysctl('portals/subsystem_debug', val)
3513         except NameError, e:
3514             panic(str(e))
3515
3516 def sys_set_netmem_max(path, max):
3517     debug("setting", path, "to at least", max)
3518     if config.noexec:
3519         return
3520     fp = open(path)
3521     str = fp.readline()
3522     fp.close()
3523     cur = int(str)
3524     if max > cur:
3525         fp = open(path, 'w')
3526         fp.write('%d\n' %(max))
3527         fp.close()
3528     
3529 def sys_make_devices():
3530     if not os.access('/dev/portals', os.R_OK):
3531         run('mknod /dev/portals c 10 240')
3532     if not os.access('/dev/obd', os.R_OK):
3533         run('mknod /dev/obd c 10 241')
3534
3535 # Add dir to the global PATH, if not already there.
3536 def add_to_path(new_dir):
3537     syspath = string.split(os.environ['PATH'], ':')
3538     if new_dir in syspath:
3539         return
3540     os.environ['PATH'] = os.environ['PATH'] + ':' + new_dir
3541     
3542 def default_debug_path():
3543     path = '/tmp/lustre-log'
3544     if os.path.isdir('/r'):
3545         return '/r' + path
3546     else:
3547         return path
3548
3549 def default_gdb_script():
3550     script = '/tmp/ogdb'
3551     if os.path.isdir('/r'):
3552         return '/r' + script
3553     else:
3554         return script
3555
3556 DEFAULT_PATH = ('/sbin', '/usr/sbin', '/bin', '/usr/bin')
3557 # ensure basic elements are in the system path
3558 def sanitise_path():
3559     for dir in DEFAULT_PATH:
3560         add_to_path(dir)
3561
3562 # global hack for the --select handling
3563 tgt_select = {}
3564 def init_select(args):
3565     # args = [service=nodeA,service2=nodeB service3=nodeC]
3566     global tgt_select
3567     for arg in args:
3568         list = string.split(arg, ',')
3569         for entry in list:
3570             srv, node = string.split(entry, '=')
3571             tgt_select[srv] = node
3572
3573 def get_select(srv):
3574     if tgt_select.has_key(srv):
3575         return tgt_select[srv]
3576     return None
3577
3578
3579 FLAG = Lustre.Options.FLAG
3580 PARAM = Lustre.Options.PARAM
3581 INTPARAM = Lustre.Options.INTPARAM
3582 PARAMLIST = Lustre.Options.PARAMLIST
3583 lconf_options = [
3584     ('verbose,v', "Print system commands as they are run"),
3585     ('ldapurl',"LDAP server URL, eg. ldap://localhost", PARAM),
3586     ('config', "Cluster config name used for LDAP query", PARAM),
3587     ('select', "service=nodeA,service2=nodeB ", PARAMLIST),
3588     ('node',   "Load config for <nodename>", PARAM),
3589     ('sec',    "security flavor <null|krb5i|krb5p> of client", PARAM),
3590     ('mds_mds_sec', "security flavor <null|krb5i|krb5p> of inter mds's", PARAM),
3591     ('mds_ost_sec', "security flavor <null|krb5i|krb5p> of mds's-ost's", PARAM),
3592     ('cleanup,d', "Cleans up config. (Shutdown)"),
3593     ('force,f', "Forced unmounting and/or obd detach during cleanup",
3594                FLAG, 0),
3595     ('single_socket', "socknal option: only use one socket instead of bundle",
3596                FLAG, 0),
3597     ('failover',"""Used to shut down without saving state.
3598                    This will allow this node to "give up" a service to a
3599                    another node for failover purposes. This will not
3600                    be a clean shutdown.""",
3601                FLAG, 0),
3602     ('gdb', """Prints message after creating gdb module script
3603                     and sleeps for 5 seconds."""),
3604     ('noexec,n', """Prints the commands and steps that will be run for a
3605                     config without executing them. This can used to check if a
3606                     config file is doing what it should be doing"""),
3607     ('nomod', "Skip load/unload module step."),
3608     ('nosetup', "Skip device setup/cleanup step."),
3609     ('reformat', "Reformat all devices (without question)"),
3610     ('mkfsoptions', "Additional options for the mk*fs command line", PARAM),
3611     ('mountfsoptions', "Additional options for mount fs command line", PARAM),
3612     ('clientoptions', "Additional options for Lustre", PARAM),
3613     ('dump',  "Dump the kernel debug log to file before portals is unloaded",
3614                PARAM),
3615     ('write_conf', "Save all the client config information on mds."),
3616     ('record', "Write config information on mds."),
3617     ('record_log', "Name of config record log.", PARAM),
3618     ('record_device', "MDS device name that will record the config commands",
3619               PARAM),
3620     ('root_squash', "MDS squash root to appointed uid",
3621               PARAM),
3622     ('no_root_squash', "Don't squash root for appointed nid",
3623               PARAM),
3624     ('minlevel', "Minimum level of services to configure/cleanup",
3625                  INTPARAM, 0),
3626     ('maxlevel', """Maximum level of services to configure/cleanup 
3627                     Levels are aproximatly like:
3628                             10 - netwrk
3629                             20 - device, ldlm
3630                             30 - osd, mdd
3631                             40 - mds, ost
3632                             70 - mountpoint, echo_client, osc, mdc, lov""",
3633                INTPARAM, 100),
3634     ('lustre', """Base directory of lustre sources. This parameter will
3635                   cause lconf to load modules from a source tree.""", PARAM),
3636     ('portals', """Portals source directory.  If this is a relative path,
3637                    then it is assumed to be relative to lustre. """, PARAM),
3638     ('timeout', "Set recovery timeout", INTPARAM),
3639     ('upcall',  "Set both portals and lustre upcall script", PARAM),
3640     ('lustre_upcall', "Set lustre upcall script", PARAM),
3641     ('portals_upcall', "Set portals upcall script", PARAM),
3642     ('lctl_dump', "Save lctl ioctls to the dumpfile argument", PARAM),
3643     ('ptldebug', "Set the portals debug level",  PARAM),
3644     ('subsystem', "Set the portals debug subsystem",  PARAM),
3645     ('gdb_script', "Fullname of gdb debug script", PARAM, default_gdb_script()),
3646     ('debug_path', "Path to save debug dumps", PARAM, default_debug_path()),
3647 # Client recovery options
3648     ('recover', "Recover a device"),
3649     ('group', "The group of devices to configure or cleanup", PARAM),
3650     ('tgt_uuid', "The failed target (required for recovery)", PARAM),
3651     ('client_uuid', "The failed client (required for recovery)", PARAM),
3652     ('conn_uuid', "The failed connection (required for recovery)", PARAM),
3653
3654     ('inactive', """The name of an inactive service, to be ignored during
3655                     mounting (currently OST-only). Can be repeated.""",
3656                 PARAMLIST),
3657     ]      
3658
3659 def main():
3660     global lctl, config, toplustreDB, CONFIG_FILE, mod_manager
3661
3662     # in the upcall this is set to SIG_IGN
3663     signal.signal(signal.SIGCHLD, signal.SIG_DFL)
3664     
3665     cl = Lustre.Options("lconf", "config.xml", lconf_options)
3666     try:
3667         config, args = cl.parse(sys.argv[1:])
3668     except Lustre.OptionError, e:
3669         print e
3670         sys.exit(1)
3671
3672     setupModulePath(sys.argv[0])
3673
3674     host = socket.gethostname()
3675
3676     # the PRNG is normally seeded with time(), which is not so good for starting
3677     # time-synchronized clusters
3678     input = open('/dev/urandom', 'r')
3679     if not input:
3680         print 'Unable to open /dev/urandom!'
3681         sys.exit(1)
3682     seed = input.read(32)
3683     input.close()
3684     random.seed(seed)
3685
3686     sanitise_path()
3687     
3688     init_select(config.select)
3689
3690     if len(args) > 0:
3691         # allow config to be fetched via HTTP, but only with python2
3692         if sys.version[0] != '1' and args[0].startswith('http://'):
3693             import urllib2
3694             try:
3695                 config_file = urllib2.urlopen(args[0])
3696             except (urllib2.URLError, socket.error), err:
3697                 if hasattr(err, 'args'):
3698                     err = err.args[1]
3699                 print "Could not access '%s': %s" %(args[0], err)
3700                 sys.exit(1)
3701         elif not os.access(args[0], os.R_OK):
3702             print 'File not found or readable:', args[0]
3703             sys.exit(1)
3704         else:
3705             # regular file
3706             config_file = open(args[0], 'r')
3707         try:
3708             dom = xml.dom.minidom.parse(config_file)
3709         except Exception:
3710             panic("%s does not appear to be a config file." % (args[0]))
3711             sys.exit(1) # make sure to die here, even in debug mode.
3712         config_file.close()
3713         CONFIG_FILE = args[0]
3714         lustreDB = Lustre.LustreDB_XML(dom.documentElement, dom.documentElement)
3715         if not config.config:
3716             config.config = os.path.basename(args[0])# use full path?
3717             if config.config[-4:] == '.xml':
3718                 config.config = config.config[:-4]
3719     elif config.ldapurl:
3720         if not config.config:
3721             panic("--ldapurl requires --config name")
3722         dn = "config=%s,fs=lustre" % (config.config)
3723         lustreDB = Lustre.LustreDB_LDAP('', {}, base=dn, url = config.ldapurl)
3724     elif config.ptldebug or config.subsystem:
3725         sys_set_ptldebug(None)
3726         sys_set_subsystem(None)
3727         sys.exit(0)
3728     else:
3729         print 'Missing config file or ldap URL.'
3730         print 'see lconf --help for command summary'
3731         sys.exit(1)
3732
3733     toplustreDB = lustreDB
3734
3735     ver = lustreDB.get_version()
3736     if not ver:
3737         panic("No version found in config data, please recreate.")
3738     if ver != Lustre.CONFIG_VERSION:
3739         panic("Config version", ver, "does not match lconf version",
3740               Lustre.CONFIG_VERSION)
3741
3742     node_list = []
3743     if config.node:
3744         node_list.append(config.node)
3745     else:
3746         if len(host) > 0:
3747             node_list.append(host)
3748         node_list.append('localhost')
3749
3750     debug("configuring for host: ", node_list)
3751
3752     if len(host) > 0:
3753         config.debug_path = config.debug_path + '-' + host
3754         config.gdb_script = config.gdb_script + '-' + host
3755
3756     lctl = LCTLInterface('lctl')
3757
3758     if config.lctl_dump:
3759         lctl.use_save_file(config.lctl_dump)
3760
3761     if config.record:
3762         if not (config.record_device and config.record_log):
3763             panic("When recording, both --record_log and --record_device must be specified.")
3764         lctl.clear_log(config.record_device, config.record_log)
3765         lctl.record(config.record_device, config.record_log)
3766
3767     # init module manager
3768     mod_manager = kmod_manager(config.lustre, config.portals)
3769
3770     doHost(lustreDB, node_list)
3771
3772     if not config.record:
3773         return
3774
3775     lctl.end_record()
3776
3777     process_updates(lustreDB, config.record_device, config.record_log)
3778
3779 if __name__ == "__main__":
3780     try:
3781         main()
3782     except Lustre.LconfError, e:
3783         print e
3784 #        traceback.print_exc(file=sys.stdout)
3785         sys.exit(1)
3786     except CommandError, e:
3787         e.dump()
3788         sys.exit(e.rc)
3789
3790     if first_cleanup_error:
3791         sys.exit(first_cleanup_error)