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.
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.
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.
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.
21 # lconf - lustre configuration tool
23 # lconf is the main driver script for starting and stopping
24 # lustre filesystem services.
26 # Based in part on the XML obdctl modifications done by Brian Behlendorf
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
33 if sys.version[0] == '1':
34 from FCNTL import F_GETFL, F_SETFL
36 from fcntl import F_GETFL, F_SETFL
38 PYMOD_DIR = "/usr/lib/lustre/python"
40 def development_mode():
41 base = os.path.dirname(sys.argv[0])
42 if os.access(base+"/Makefile", os.R_OK):
46 if development_mode():
47 sys.path.append('../utils')
49 sys.path.append(PYMOD_DIR)
55 DEFAULT_TCPBUF = 8388608
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'
63 # Needed to call lconf --record
66 # Please keep these in sync with the values in portals/kp30.h
78 "warning" : (1 << 10),
82 "portals" : (1 << 14),
84 "dlmtrace" : (1 << 16),
88 "rpctrace" : (1 << 20),
89 "vfstrace" : (1 << 21),
96 "undefined" : (1 << 0),
106 "portals" : (1 << 10),
107 "socknal" : (1 << 11),
108 "qswnal" : (1 << 12),
109 "pinger" : (1 << 13),
110 "filter" : (1 << 14),
116 "ptlrouter" : (1 << 20),
127 first_cleanup_error = 0
128 def cleanup_error(rc):
129 global first_cleanup_error
130 if not first_cleanup_error:
131 first_cleanup_error = rc
133 # ============================================================
134 # debugging and error funcs
136 def fixme(msg = "this feature"):
137 raise Lustre.LconfError, msg + ' not implemented yet.'
140 msg = string.join(map(str,args))
141 if not config.noexec:
142 raise Lustre.LconfError(msg)
147 msg = string.join(map(str,args))
152 print string.strip(s)
156 msg = string.join(map(str,args))
159 # ack, python's builtin int() does not support '0x123' syntax.
160 # eval can do it, although what a hack!
164 return eval(s, {}, {})
167 except SyntaxError, e:
168 raise ValueError("not a number")
170 raise ValueError("not a number")
172 # ============================================================
173 # locally defined exceptions
174 class CommandError (exceptions.Exception):
175 def __init__(self, cmd_name, cmd_err, rc=None):
176 self.cmd_name = cmd_name
177 self.cmd_err = cmd_err
182 if type(self.cmd_err) == types.StringType:
184 print "! %s (%d): %s" % (self.cmd_name, self.rc, self.cmd_err)
186 print "! %s: %s" % (self.cmd_name, self.cmd_err)
187 elif type(self.cmd_err) == types.ListType:
189 print "! %s (error %d):" % (self.cmd_name, self.rc)
191 print "! %s:" % (self.cmd_name)
192 for s in self.cmd_err:
193 print "> %s" %(string.strip(s))
198 # ============================================================
199 # handle daemons, like the acceptor
201 """ Manage starting and stopping a daemon. Assumes daemon manages
202 it's own pid file. """
204 def __init__(self, cmd):
210 log(self.command, "already running.")
212 self.path = find_prog(self.command)
214 panic(self.command, "not found.")
215 ret, out = runcmd(self.path +' '+ self.command_line())
217 raise CommandError(self.path, out, ret)
221 pid = self.read_pidfile()
224 log ("killing process", pid)
227 log("was unable to find pid of " + self.command)
228 #time.sleep(1) # let daemon die
230 log("unable to kill", self.command, e)
232 log("unable to kill", self.command)
235 pid = self.read_pidfile()
241 log("was unable to find pid of " + self.command)
248 def read_pidfile(self):
250 fp = open(self.pidfile(), 'r')
260 def clean_pidfile(self):
261 """ Remove a stale pidfile """
262 log("removing stale pidfile:", self.pidfile())
264 os.unlink(self.pidfile())
266 log(self.pidfile(), e)
268 class AcceptorHandler(DaemonHandler):
269 def __init__(self, port, net_type):
270 DaemonHandler.__init__(self, "acceptor")
275 return "/var/run/%s-%d.pid" % (self.command, self.port)
277 def command_line(self):
278 return string.join(map(str,(self.flags, self.port)))
282 # start the acceptors
284 if config.lctl_dump or config.record:
286 for port in acceptors.keys():
287 daemon = acceptors[port]
288 if not daemon.running():
291 def run_one_acceptor(port):
292 if config.lctl_dump or config.record:
294 if acceptors.has_key(port):
295 daemon = acceptors[port]
296 if not daemon.running():
299 panic("run_one_acceptor: No acceptor defined for port:", port)
301 def stop_acceptor(port):
302 if acceptors.has_key(port):
303 daemon = acceptors[port]
308 # ============================================================
309 # handle lctl interface
312 Manage communication with lctl
315 def __init__(self, cmd):
317 Initialize close by finding the lctl binary.
319 self.lctl = find_prog(cmd)
321 self.record_device = ''
324 debug('! lctl not found')
327 raise CommandError('lctl', "unable to find lctl binary.")
329 def use_save_file(self, file):
330 self.save_file = file
332 def record(self, dev_name, logname):
333 log("Recording log", logname, "on", dev_name)
334 self.record_device = dev_name
335 self.record_log = logname
337 def end_record(self):
338 log("End recording log", self.record_log, "on", self.record_device)
339 self.record_device = None
340 self.record_log = None
342 def set_nonblock(self, fd):
343 fl = fcntl.fcntl(fd, F_GETFL)
344 fcntl.fcntl(fd, F_SETFL, fl | os.O_NDELAY)
349 the cmds are written to stdin of lctl
350 lctl doesn't return errors when run in script mode, so
352 should modify command line to accept multiple commands, or
353 create complex command line options
357 cmds = '\n dump ' + self.save_file + '\n' + cmds
358 elif self.record_device:
362 %s""" % (self.record_device, self.record_log, cmds)
364 debug("+", cmd_line, cmds)
365 if config.noexec: return (0, [])
367 child = popen2.Popen3(cmd_line, 1) # Capture stdout and stderr from command
368 child.tochild.write(cmds + "\n")
369 child.tochild.close()
370 # print "LCTL:", cmds
372 # From "Python Cookbook" from O'Reilly
373 outfile = child.fromchild
374 outfd = outfile.fileno()
375 self.set_nonblock(outfd)
376 errfile = child.childerr
377 errfd = errfile.fileno()
378 self.set_nonblock(errfd)
380 outdata = errdata = ''
383 ready = select.select([outfd,errfd],[],[]) # Wait for input
384 if outfd in ready[0]:
385 outchunk = outfile.read()
386 if outchunk == '': outeof = 1
387 outdata = outdata + outchunk
388 if errfd in ready[0]:
389 errchunk = errfile.read()
390 if errchunk == '': erreof = 1
391 errdata = errdata + errchunk
392 if outeof and erreof: break
393 # end of "borrowed" code
396 if os.WIFEXITED(ret):
397 rc = os.WEXITSTATUS(ret)
400 if rc or len(errdata):
401 raise CommandError(self.lctl, errdata, rc)
404 def runcmd(self, *args):
406 run lctl using the command line
408 cmd = string.join(map(str,args))
409 debug("+", self.lctl, cmd)
410 rc, out = run(self.lctl, cmd)
412 raise CommandError(self.lctl, out, rc)
415 def clear_log(self, dev, log):
416 """ clear an existing log """
421 quit """ % (dev, log)
424 def root_squash(self, name, uid, nid):
428 quit""" % (name, uid, nid)
431 def network(self, net, nid):
436 quit """ % (net, nid)
440 def add_interface(self, net, ip, netmask = ""):
441 """ add an interface """
445 quit """ % (net, ip, netmask)
448 # delete an interface
449 def del_interface(self, net, ip):
450 """ delete an interface """
457 # create a new connection
458 def add_uuid(self, net_type, uuid, nid):
459 cmds = "\n add_uuid %s %s %s" %(uuid, nid, net_type)
462 def add_peer(self, net_type, nid, hostaddr, port):
463 if net_type in ('tcp',) and not config.lctl_dump:
468 nid, hostaddr, port )
470 elif net_type in ('openib','iib',) and not config.lctl_dump:
478 def connect(self, srv):
479 self.add_uuid(srv.net_type, srv.nid_uuid, srv.nid)
480 if srv.net_type in ('tcp','openib','iib',) and not config.lctl_dump:
482 hostaddr = string.split(srv.hostaddr[0], '/')[0]
483 self.add_peer(srv.net_type, srv.nid, hostaddr, srv.port)
486 def recover(self, dev_name, new_conn):
489 recover %s""" %(dev_name, new_conn)
492 # add a route to a range
493 def add_route(self, net, gw, lo, hi):
501 except CommandError, e:
505 def del_route(self, net, gw, lo, hi):
510 quit """ % (net, gw, lo, hi)
513 # add a route to a host
514 def add_route_host(self, net, uuid, gw, tgt):
515 self.add_uuid(net, uuid, tgt)
523 except CommandError, e:
527 # add a route to a range
528 def del_route_host(self, net, uuid, gw, tgt):
534 quit """ % (net, gw, tgt)
538 def del_peer(self, net_type, nid, hostaddr):
539 if net_type in ('tcp',) and not config.lctl_dump:
543 del_peer %s %s single_share
547 elif net_type in ('openib','iib',) and not config.lctl_dump:
551 del_peer %s single_share
556 # disconnect one connection
557 def disconnect(self, srv):
558 self.del_uuid(srv.nid_uuid)
559 if srv.net_type in ('tcp','openib','iib',) and not config.lctl_dump:
561 hostaddr = string.split(srv.hostaddr[0], '/')[0]
562 self.del_peer(srv.net_type, srv.nid, hostaddr)
564 def del_uuid(self, uuid):
572 def disconnectAll(self, net):
580 def attach(self, type, name, uuid):
583 quit""" % (type, name, uuid)
586 def setup(self, name, setup = ""):
590 quit""" % (name, setup)
593 def add_conn(self, name, conn_uuid):
597 quit""" % (name, conn_uuid)
601 # create a new device with lctl
602 def newdev(self, type, name, uuid, setup = ""):
603 self.attach(type, name, uuid);
605 self.setup(name, setup)
606 except CommandError, e:
607 self.cleanup(name, uuid, 0)
612 def cleanup(self, name, uuid, force, failover = 0):
613 if failover: force = 1
619 quit""" % (name, ('', 'force')[force],
620 ('', 'failover')[failover])
624 def lov_setup(self, name, uuid, desc_uuid, stripe_cnt,
625 stripe_sz, stripe_off, pattern, devlist = None):
628 lov_setup %s %d %d %d %s %s
629 quit""" % (name, uuid, desc_uuid, stripe_cnt, stripe_sz, stripe_off,
633 # add an OBD to a LOV
634 def lov_add_obd(self, name, uuid, obd_uuid, index, gen):
636 lov_modify_tgts add %s %s %s %s
637 quit""" % (name, obd_uuid, index, gen)
641 def lmv_setup(self, name, uuid, desc_uuid, devlist):
645 quit""" % (name, uuid, desc_uuid, devlist)
648 # delete an OBD from a LOV
649 def lov_del_obd(self, name, uuid, obd_uuid, index, gen):
651 lov_modify_tgts del %s %s %s %s
652 quit""" % (name, obd_uuid, index, gen)
656 def deactivate(self, name):
664 def dump(self, dump_file):
667 quit""" % (dump_file)
670 # get list of devices
671 def device_list(self):
672 devices = '/proc/fs/lustre/devices'
674 if os.access(devices, os.R_OK):
676 fp = open(devices, 'r')
684 def lustre_version(self):
685 rc, out = self.runcmd('version')
689 def mount_option(self, profile, osc, mdc):
691 mount_option %s %s %s
692 quit""" % (profile, osc, mdc)
695 # delete mount options
696 def del_mount_option(self, profile):
702 def set_timeout(self, timeout):
708 def set_lustre_upcall(self, upcall):
713 # ============================================================
714 # Various system-level functions
715 # (ideally moved to their own module)
717 # Run a command and return the output and status.
718 # stderr is sent to /dev/null, could use popen3 to
719 # save it if necessary
722 if config.noexec: return (0, [])
723 f = os.popen(cmd + ' 2>&1')
733 cmd = string.join(map(str,args))
736 # Run a command in the background.
737 def run_daemon(*args):
738 cmd = string.join(map(str,args))
740 if config.noexec: return 0
741 f = os.popen(cmd + ' 2>&1')
749 # Determine full path to use for an external command
750 # searches dirname(argv[0]) first, then PATH
752 syspath = string.split(os.environ['PATH'], ':')
753 cmdpath = os.path.dirname(sys.argv[0])
754 syspath.insert(0, cmdpath);
756 syspath.insert(0, os.path.join(config.portals, 'utils/'))
758 prog = os.path.join(d,cmd)
759 if os.access(prog, os.X_OK):
763 # Recursively look for file starting at base dir
764 def do_find_file(base, mod):
765 fullname = os.path.join(base, mod)
766 if os.access(fullname, os.R_OK):
768 for d in os.listdir(base):
769 dir = os.path.join(base,d)
770 if os.path.isdir(dir):
771 module = do_find_file(dir, mod)
775 # is the path a block device?
782 return stat.S_ISBLK(s[stat.ST_MODE])
784 # find the journal device from mkfs options
790 while i < len(x) - 1:
791 if x[i] == '-J' and x[i+1].startswith('device='):
797 # build fs according to type
799 def mkfs(dev, devsize, fstype, jsize, isize, mkfsoptions, isblock=1):
805 panic("size of filesystem on '%s' must be larger than 8MB, but is set to %s"%
807 # devsize is in 1k, and fs block count is in 4k
808 block_cnt = devsize/4
810 if fstype in ('ext3', 'extN', 'ldiskfs'):
811 # ext3 journal size is in megabytes
812 # but don't set jsize if mkfsoptions indicates a separate journal device
813 if jsize == 0 and jdev(mkfsoptions) == '':
815 if not is_block(dev):
816 ret, out = runcmd("ls -l %s" %dev)
817 devsize = int(string.split(out[0])[4]) / 1024
819 # sfdisk works for symlink, hardlink, and realdev
820 ret, out = runcmd("sfdisk -s %s" %dev)
822 devsize = int(out[0])
824 # sfdisk -s will fail for too large block device,
825 # then, read the size of partition from /proc/partitions
827 # get the realpath of the device
828 # it may be the real device, such as /dev/hda7
829 # or the hardlink created via mknod for a device
830 if 'realpath' in dir(os.path):
831 real_dev = os.path.realpath(dev)
835 while os.path.islink(real_dev) and (link_count < 20):
836 link_count = link_count + 1
837 dev_link = os.readlink(real_dev)
838 if os.path.isabs(dev_link):
841 real_dev = os.path.join(os.path.dirname(real_dev), dev_link)
843 panic("Entountered too many symbolic links resolving block device:", dev)
845 # get the major and minor number of the realpath via ls
846 # it seems python(os.stat) does not return
847 # the st_rdev member of the stat structure
848 ret, out = runcmd("ls -l %s" %real_dev)
849 major = string.split(string.split(out[0])[4], ",")[0]
850 minor = string.split(out[0])[5]
852 # get the devsize from /proc/partitions with the major and minor number
853 ret, out = runcmd("cat /proc/partitions")
856 if string.split(line)[0] == major and string.split(line)[1] == minor:
857 devsize = int(string.split(line)[2])
860 if devsize > 1024 * 1024:
861 jsize = ((devsize / 102400) * 4)
864 if jsize: jopt = "-J size=%d" %(jsize,)
865 if isize: iopt = "-I %d" %(isize,)
866 mkfs = 'mkfs.ext2 -j -b 4096 '
867 if not isblock or config.force:
869 if jdev(mkfsoptions) != '':
870 jmkfs = 'mkfs.ext2 -b 4096 -O journal_dev '
872 jmkfs = jmkfs + '-F '
873 jmkfs = jmkfs + jdev(mkfsoptions)
874 (ret, out) = run (jmkfs)
876 panic("Unable format journal device:", jdev(mkfsoptions), string.join(out))
877 elif fstype == 'reiserfs':
878 # reiserfs journal size is in blocks
879 if jsize: jopt = "--journal_size %d" %(jsize,)
880 mkfs = 'mkreiserfs -ff'
882 panic('unsupported fs type: ', fstype)
884 if config.mkfsoptions != None:
885 mkfs = mkfs + ' ' + config.mkfsoptions
886 if mkfsoptions != None:
887 mkfs = mkfs + ' ' + mkfsoptions
888 (ret, out) = run (mkfs, jopt, iopt, dev, block_cnt)
890 panic("Unable to build fs:", dev, string.join(out))
891 # enable hash tree indexing on fsswe
892 if fstype in ('ext3', 'extN', 'ldiskfs'):
893 htree = 'echo "feature FEATURE_C5" | debugfs -w'
894 (ret, out) = run (htree, dev)
896 panic("Unable to enable htree:", dev)
898 # some systems use /dev/loopN, some /dev/loop/N
902 if not os.access(loop + str(0), os.R_OK):
904 if not os.access(loop + str(0), os.R_OK):
905 panic ("can't access loop devices")
908 # find loop device assigned to the file
909 def find_assigned_loop(file):
911 for n in xrange(0, MAX_LOOP_DEVICES):
913 if os.access(dev, os.R_OK):
914 (stat, out) = run('losetup', dev)
915 if out and stat == 0:
916 m = re.search(r'\((.*)\)', out[0])
917 if m and file == m.group(1):
923 # create file if necessary and assign the first free loop device
924 def init_loop(file, size, fstype, journal_size, inode_size,
925 mkfsoptions, reformat, autoformat, backfstype, backfile):
928 realfstype = backfstype
929 if is_block(backfile):
930 if reformat or (need_format(realfstype, backfile) and autoformat == 'yes'):
931 mkfs(realfile, size, realfstype, journal_size, inode_size, mkfsoptions, isblock=0)
937 dev = find_assigned_loop(realfile)
939 print 'WARNING: file ', realfile, 'already mapped to', dev
942 if reformat or not os.access(realfile, os.R_OK | os.W_OK):
944 panic("size of loopback file '%s' must be larger than 8MB, but is set to %s" % (realfile, size))
945 (ret, out) = run("dd if=/dev/zero bs=1k count=0 seek=%d of=%s" %(size, realfile))
947 panic("Unable to create backing store:", realfile)
949 mkfs(realfile, size, realfstype, journal_size, inode_size,
950 mkfsoptions, isblock=0)
953 # find next free loop
954 for n in xrange(0, MAX_LOOP_DEVICES):
956 if os.access(dev, os.R_OK):
957 (stat, out) = run('losetup', dev)
959 print "attach " + realfile + " <-> " + dev
960 run('losetup', dev, realfile)
963 print "out of loop devices"
965 print "out of loop devices"
968 # undo loop assignment
969 def clean_loop(dev, fstype, backfstype, backdev):
974 if not is_block(realfile):
975 dev = find_assigned_loop(realfile)
977 print "detach " + dev + " <-> " + realfile
978 ret, out = run('losetup -d', dev)
980 log('unable to clean loop device:', dev, 'for file:', realfile)
983 # finilizes passed device
984 def clean_dev(dev, fstype, backfstype, backdev):
985 if fstype == 'smfs' or not is_block(dev):
986 clean_loop(dev, fstype, backfstype, backdev)
988 # determine if dev is formatted as a <fstype> filesystem
989 def need_format(fstype, dev):
990 # FIXME don't know how to implement this
993 # initialize a block device if needed
994 def block_dev(dev, size, fstype, reformat, autoformat, journal_size,
995 inode_size, mkfsoptions, backfstype, backdev):
999 if fstype == 'smfs' or not is_block(dev):
1000 dev = init_loop(dev, size, fstype, journal_size, inode_size,
1001 mkfsoptions, reformat, autoformat, backfstype, backdev)
1002 elif reformat or (need_format(fstype, dev) and autoformat == 'yes'):
1003 mkfs(dev, size, fstype, journal_size, inode_size, mkfsoptions,
1006 # panic("device:", dev,
1007 # "not prepared, and autoformat is not set.\n",
1008 # "Rerun with --reformat option to format ALL filesystems")
1013 """lookup IP address for an interface"""
1014 rc, out = run("/sbin/ifconfig", iface)
1017 addr = string.split(out[1])[1]
1018 ip = string.split(addr, ':')[1]
1021 def def_mount_options(fstype, target):
1022 """returns deafult mount options for passed fstype and target (mds, ost)"""
1023 if fstype == 'ext3' or fstype == 'ldiskfs':
1024 mountfsoptions = "errors=remount-ro"
1025 if target == 'ost' and sys_get_branch() == '2.4':
1026 mountfsoptions = "%s,asyncdel" % (mountfsoptions)
1027 return mountfsoptions
1030 def sys_get_elan_position_file():
1031 procfiles = ["/proc/elan/device0/position",
1032 "/proc/qsnet/elan4/device0/position",
1033 "/proc/qsnet/elan3/device0/position"]
1035 if os.access(p, os.R_OK):
1039 def sys_get_local_nid(net_type, wildcard, cluster_id):
1040 """Return the local nid."""
1042 if sys_get_elan_position_file():
1043 local = sys_get_local_address('elan', '*', cluster_id)
1045 local = sys_get_local_address(net_type, wildcard, cluster_id)
1048 def sys_get_local_address(net_type, wildcard, cluster_id):
1049 """Return the local address for the network type."""
1051 if net_type in ('tcp','openib','iib',):
1053 iface, star = string.split(wildcard, ':')
1054 local = if2addr(iface)
1056 panic ("unable to determine ip for:", wildcard)
1058 host = socket.gethostname()
1059 local = socket.gethostbyname(host)
1060 elif net_type == 'elan':
1061 # awk '/NodeId/ { print $2 }' 'sys_get_elan_position_file()'
1062 f = sys_get_elan_position_file()
1064 panic ("unable to determine local Elan ID")
1067 lines = fp.readlines()
1071 if a[0] == 'NodeId':
1075 nid = my_int(cluster_id) + my_int(elan_id)
1076 local = "%d" % (nid)
1077 except ValueError, e:
1081 elif net_type == 'lo':
1082 fixme("automatic local address for loopback")
1083 elif net_type == 'gm':
1084 fixme("automatic local address for GM")
1088 def sys_get_branch():
1089 """Returns kernel release"""
1091 fp = open('/proc/sys/kernel/osrelease')
1092 lines = fp.readlines()
1096 version = string.split(l)
1097 a = string.split(version[0], '.')
1098 return a[0] + '.' + a[1]
1103 # XXX: instead of device_list, ask for $name and see what we get
1104 def is_prepared(name):
1105 """Return true if a device exists for the name"""
1106 if config.lctl_dump:
1108 if (config.noexec or config.record) and config.cleanup:
1111 # expect this format:
1112 # 1 UP ldlm ldlm ldlm_UUID 2
1113 out = lctl.device_list()
1115 if name == string.split(s)[3]:
1117 except CommandError, e:
1121 def net_is_prepared():
1122 """If the any device exists, then assume that all networking
1123 has been configured"""
1124 out = lctl.device_list()
1127 def fs_is_mounted(path):
1128 """Return true if path is a mounted lustre filesystem"""
1130 fp = open('/proc/mounts')
1131 lines = fp.readlines()
1135 if a[1] == path and a[2] == 'lustre_lite':
1141 def kmod_find(src_dir, dev_dir, modname):
1142 modbase = src_dir +'/'+ dev_dir +'/'+ modname
1143 for modext in '.ko', '.o':
1144 module = modbase + modext
1146 if os.access(module, os.R_OK):
1152 def kmod_info(modname):
1153 """Returns reference count for passed module name."""
1155 fp = open('/proc/modules')
1156 lines = fp.readlines()
1159 # please forgive my tired fingers for this one
1160 ret = filter(lambda word, mod = modname: word[0] == mod,
1161 map(lambda line: string.split(line), lines))
1165 except Exception, e:
1169 """Presents kernel module"""
1170 def __init__(self, src_dir, dev_dir, name):
1171 self.src_dir = src_dir
1172 self.dev_dir = dev_dir
1177 log ('loading module:', self.name, 'srcdir',
1178 self.src_dir, 'devdir', self.dev_dir)
1180 module = kmod_find(self.src_dir, self.dev_dir,
1183 panic('module not found:', self.name)
1184 (rc, out) = run('/sbin/insmod', module)
1186 raise CommandError('insmod', out, rc)
1188 (rc, out) = run('/sbin/modprobe', self.name)
1190 raise CommandError('modprobe', out, rc)
1194 log('unloading module:', self.name)
1195 (rc, out) = run('/sbin/rmmod', self.name)
1197 log('unable to unload module:', self.name +
1198 "(" + self.refcount() + ")")
1202 """Returns module info if any."""
1203 return kmod_info(self.name)
1206 """Returns 1 if module is loaded. Otherwise 0 is returned."""
1213 """Returns module refcount."""
1220 """Returns 1 if module is used, otherwise 0 is returned."""
1226 if users and users != '(unused)' and users != '-':
1234 """Returns 1 if module is busy, otherwise 0 is returned."""
1235 if self.loaded() and (self.used() or self.refcount() != '0'):
1241 """Manage kernel modules"""
1242 def __init__(self, lustre_dir, portals_dir):
1243 self.lustre_dir = lustre_dir
1244 self.portals_dir = portals_dir
1245 self.kmodule_list = []
1247 def find_module(self, modname):
1248 """Find module by module name"""
1249 for mod in self.kmodule_list:
1250 if mod.name == modname:
1254 def add_portals_module(self, dev_dir, modname):
1255 """Append a module to list of modules to load."""
1257 mod = self.find_module(modname)
1259 mod = kmod(self.portals_dir, dev_dir, modname)
1260 self.kmodule_list.append(mod)
1262 def add_lustre_module(self, dev_dir, modname):
1263 """Append a module to list of modules to load."""
1265 mod = self.find_module(modname)
1267 mod = kmod(self.lustre_dir, dev_dir, modname)
1268 self.kmodule_list.append(mod)
1270 def load_modules(self):
1271 """Load all the modules in the list in the order they appear."""
1272 for mod in self.kmodule_list:
1273 if mod.loaded() and not config.noexec:
1277 def cleanup_modules(self):
1278 """Unload the modules in the list in reverse order."""
1279 rev = self.kmodule_list
1282 if (not mod.loaded() or mod.busy()) and not config.noexec:
1285 if mod.name == 'portals' and config.dump:
1286 lctl.dump(config.dump)
1289 # ============================================================
1290 # Classes to prepare and cleanup the various objects
1293 """ Base class for the rest of the modules. The default cleanup method is
1294 defined here, as well as some utilitiy funcs.
1296 def __init__(self, module_name, db):
1298 self.module_name = module_name
1299 self.name = self.db.getName()
1300 self.uuid = self.db.getUUID()
1304 def info(self, *args):
1305 msg = string.join(map(str,args))
1306 print self.module_name + ":", self.name, self.uuid, msg
1309 """ default cleanup, used for most modules """
1312 lctl.cleanup(self.name, self.uuid, config.force)
1313 except CommandError, e:
1314 log(self.module_name, "cleanup failed: ", self.name)
1318 def add_module(self, manager):
1319 """Adds all needed modules in the order they appear."""
1322 def safe_to_clean(self):
1325 def safe_to_clean_modules(self):
1326 return self.safe_to_clean()
1328 class Network(Module):
1329 def __init__(self,db):
1330 Module.__init__(self, 'NETWORK', db)
1331 self.net_type = self.db.get_val('nettype')
1332 self.nid = self.db.get_val('nid', '*')
1333 self.cluster_id = self.db.get_val('clusterid', "0")
1334 self.port = self.db.get_val_int('port', 0)
1337 self.nid = sys_get_local_nid(self.net_type, self.nid, self.cluster_id)
1339 panic("unable to set nid for", self.net_type, self.nid, cluster_id)
1340 self.generic_nid = 1
1341 debug("nid:", self.nid)
1343 self.generic_nid = 0
1345 self.nid_uuid = self.nid_to_uuid(self.nid)
1346 self.hostaddr = self.db.get_hostaddr()
1347 if len(self.hostaddr) == 0:
1348 self.hostaddr.append(self.nid)
1349 if '*' in self.hostaddr[0]:
1350 self.hostaddr[0] = sys_get_local_address(self.net_type, self.hostaddr[0], self.cluster_id)
1351 if not self.hostaddr[0]:
1352 panic("unable to set hostaddr for", self.net_type, self.hostaddr[0], self.cluster_id)
1353 debug("hostaddr:", self.hostaddr[0])
1355 def add_module(self, manager):
1356 manager.add_portals_module("libcfs", 'libcfs')
1357 manager.add_portals_module("portals", 'portals')
1358 if node_needs_router():
1359 manager.add_portals_module("router", 'kptlrouter')
1360 if self.net_type == 'tcp':
1361 manager.add_portals_module("knals/socknal", 'ksocknal')
1362 if self.net_type == 'elan':
1363 manager.add_portals_module("knals/qswnal", 'kqswnal')
1364 if self.net_type == 'gm':
1365 manager.add_portals_module("knals/gmnal", 'kgmnal')
1366 if self.net_type == 'openib':
1367 manager.add_portals_module("knals/openibnal", 'kopenibnal')
1368 if self.net_type == 'iib':
1369 manager.add_portals_module("knals/iibnal", 'kiibnal')
1370 if self.net_type == 'lo':
1371 manager.add_portals_module("knals/lonal", 'klonal')
1373 def nid_to_uuid(self, nid):
1374 return "NID_%s_UUID" %(nid,)
1377 if not config.record and net_is_prepared():
1379 self.info(self.net_type, self.nid, self.port)
1380 if not (config.record and self.generic_nid):
1381 lctl.network(self.net_type, self.nid)
1382 if self.net_type == 'tcp':
1384 for hostaddr in self.db.get_hostaddr():
1385 ip = string.split(hostaddr, '/')[0]
1386 if len(string.split(hostaddr, '/')) == 2:
1387 netmask = string.split(hostaddr, '/')[1]
1390 lctl.add_interface(self.net_type, ip, netmask)
1391 if self.net_type == 'elan':
1393 if self.port and node_is_router():
1394 run_one_acceptor(self.port)
1395 self.connect_peer_gateways()
1397 def connect_peer_gateways(self):
1398 for router in self.db.lookup_class('node'):
1399 if router.get_val_int('router', 0):
1400 for netuuid in router.get_networks():
1401 net = self.db.lookup(netuuid)
1403 if (gw.cluster_id == self.cluster_id and
1404 gw.net_type == self.net_type):
1405 if gw.nid != self.nid:
1408 def disconnect_peer_gateways(self):
1409 for router in self.db.lookup_class('node'):
1410 if router.get_val_int('router', 0):
1411 for netuuid in router.get_networks():
1412 net = self.db.lookup(netuuid)
1414 if (gw.cluster_id == self.cluster_id and
1415 gw.net_type == self.net_type):
1416 if gw.nid != self.nid:
1419 except CommandError, e:
1420 print "disconnect failed: ", self.name
1424 def safe_to_clean(self):
1425 return not net_is_prepared()
1428 self.info(self.net_type, self.nid, self.port)
1430 stop_acceptor(self.port)
1431 if node_is_router():
1432 self.disconnect_peer_gateways()
1433 if self.net_type == 'tcp':
1434 for hostaddr in self.db.get_hostaddr():
1435 ip = string.split(hostaddr, '/')[0]
1436 lctl.del_interface(self.net_type, ip)
1438 def correct_level(self, level, op=None):
1441 class RouteTable(Module):
1442 def __init__(self,db):
1443 Module.__init__(self, 'ROUTES', db)
1445 def server_for_route(self, net_type, gw, gw_cluster_id, tgt_cluster_id,
1447 # only setup connections for tcp, openib, and iib NALs
1449 if not net_type in ('tcp','openib','iib',):
1452 # connect to target if route is to single node and this node is the gw
1453 if lo == hi and local_interface(net_type, gw_cluster_id, gw):
1454 if not local_cluster(net_type, tgt_cluster_id):
1455 panic("target", lo, " not on the local cluster")
1456 srvdb = self.db.nid2server(lo, net_type, gw_cluster_id)
1457 # connect to gateway if this node is not the gw
1458 elif (local_cluster(net_type, gw_cluster_id)
1459 and not local_interface(net_type, gw_cluster_id, gw)):
1460 srvdb = self.db.nid2server(gw, net_type, gw_cluster_id)
1465 panic("no server for nid", lo)
1468 return Network(srvdb)
1471 if not config.record and net_is_prepared():
1474 for net_type, gw, gw_cluster_id, tgt_cluster_id, lo, hi in self.db.get_route_tbl():
1475 lctl.add_route(net_type, gw, lo, hi)
1476 srv = self.server_for_route(net_type, gw, gw_cluster_id, tgt_cluster_id, lo, hi)
1480 def safe_to_clean(self):
1481 return not net_is_prepared()
1484 if net_is_prepared():
1485 # the network is still being used, don't clean it up
1487 for net_type, gw, gw_cluster_id, tgt_cluster_id, lo, hi in self.db.get_route_tbl():
1488 srv = self.server_for_route(net_type, gw, gw_cluster_id, tgt_cluster_id, lo, hi)
1491 lctl.disconnect(srv)
1492 except CommandError, e:
1493 print "disconnect failed: ", self.name
1498 lctl.del_route(net_type, gw, lo, hi)
1499 except CommandError, e:
1500 print "del_route failed: ", self.name
1504 class Management(Module):
1505 def __init__(self, db):
1506 Module.__init__(self, 'MGMT', db)
1508 def add_module(self, manager):
1509 manager.add_lustre_module('lvfs', 'lvfs')
1510 manager.add_lustre_module('obdclass', 'obdclass')
1511 manager.add_lustre_module('ptlrpc', 'ptlrpc')
1512 manager.add_lustre_module('mgmt', 'mgmt_svc')
1515 if not config.record and is_prepared(self.name):
1518 lctl.newdev("mgmt", self.name, self.uuid)
1520 def safe_to_clean(self):
1524 if is_prepared(self.name):
1525 Module.cleanup(self)
1527 def correct_level(self, level, op=None):
1530 # This is only needed to load the modules; the LDLM device
1531 # is now created automatically.
1533 def __init__(self,db):
1534 Module.__init__(self, 'LDLM', db)
1536 def add_module(self, manager):
1537 manager.add_lustre_module('lvfs', 'lvfs')
1538 manager.add_lustre_module('obdclass', 'obdclass')
1539 manager.add_lustre_module('ptlrpc', 'ptlrpc')
1547 def correct_level(self, level, op=None):
1551 def __init__(self, db, uuid, fs_name, name_override = None, config_only = None):
1552 Module.__init__(self, 'LOV', db)
1553 if name_override != None:
1554 self.name = "lov_%s" % name_override
1555 self.mds_uuid = self.db.get_first_ref('mds')
1556 self.stripe_sz = self.db.get_val_int('stripesize', 1048576)
1557 self.stripe_off = self.db.get_val_int('stripeoffset', 0)
1558 self.pattern = self.db.get_val_int('stripepattern', 0)
1559 self.devlist = self.db.get_lov_tgts('lov_tgt')
1560 self.stripe_cnt = self.db.get_val_int('stripecount', len(self.devlist))
1563 self.desc_uuid = self.uuid
1564 self.uuid = generate_client_uuid(self.name)
1565 self.fs_name = fs_name
1567 self.config_only = 1
1569 self.config_only = None
1570 mds = self.db.lookup(self.mds_uuid)
1571 self.mds_name = mds.getName()
1572 for (obd_uuid, index, gen, active) in self.devlist:
1575 self.obdlist.append(obd_uuid)
1576 obd = self.db.lookup(obd_uuid)
1577 osc = get_osc(obd, self.uuid, fs_name)
1579 self.osclist.append((osc, index, gen, active))
1581 panic('osc not found:', obd_uuid)
1587 if not config.record and is_prepared(self.name):
1589 self.info(self.mds_uuid, self.stripe_cnt, self.stripe_sz,
1590 self.stripe_off, self.pattern, self.devlist,
1592 lctl.lov_setup(self.name, self.uuid, self.desc_uuid, self.stripe_cnt,
1593 self.stripe_sz, self.stripe_off, self.pattern,
1594 string.join(self.obdlist))
1595 for (osc, index, gen, active) in self.osclist:
1596 target_uuid = osc.target_uuid
1598 # Only ignore connect failures with --force, which
1599 # isn't implemented here yet.
1601 osc.prepare(ignore_connect_failure=0)
1602 except CommandError, e:
1603 print "Error preparing OSC %s\n" % osc.uuid
1605 lctl.lov_add_obd(self.name, self.uuid, target_uuid, index, gen)
1608 for (osc, index, gen, active) in self.osclist:
1609 target_uuid = osc.target_uuid
1611 if is_prepared(self.name):
1612 Module.cleanup(self)
1613 if self.config_only:
1614 panic("Can't clean up config_only LOV ", self.name)
1616 def add_module(self, manager):
1617 if self.config_only:
1618 panic("Can't load modules for config_only LOV ", self.name)
1619 for (osc, index, gen, active) in self.osclist:
1620 osc.add_module(manager)
1622 manager.add_lustre_module('lov', 'lov')
1624 def correct_level(self, level, op=None):
1628 def __init__(self, db, uuid, fs_name, name_override = None):
1629 Module.__init__(self, 'LMV', db)
1630 if name_override != None:
1631 self.name = "lmv_%s" % name_override
1632 self.devlist = self.db.get_refs('mds')
1634 self.desc_uuid = self.uuid
1636 self.fs_name = fs_name
1637 for mds_uuid in self.devlist:
1638 mds = self.db.lookup(mds_uuid)
1640 panic("MDS not found!")
1641 mdc = MDC(mds, self.uuid, fs_name)
1643 self.mdclist.append(mdc)
1645 panic('mdc not found:', mds_uuid)
1648 if is_prepared(self.name):
1650 for mdc in self.mdclist:
1652 # Only ignore connect failures with --force, which
1653 # isn't implemented here yet.
1654 mdc.prepare(ignore_connect_failure=0)
1655 except CommandError, e:
1656 print "Error preparing LMV %s\n" % mdc.uuid
1658 lctl.lmv_setup(self.name, self.uuid, self.desc_uuid,
1659 string.join(self.devlist))
1662 for mdc in self.mdclist:
1664 if is_prepared(self.name):
1665 Module.cleanup(self)
1667 def add_module(self, manager):
1668 for mdc in self.mdclist:
1669 mdc.add_module(manager)
1671 manager.add_lustre_module('lmv', 'lmv')
1673 def correct_level(self, level, op=None):
1676 class MDSDEV(Module):
1677 def __init__(self,db):
1678 Module.__init__(self, 'MDSDEV', db)
1679 self.devpath = self.db.get_val('devpath','')
1680 self.backdevpath = self.db.get_val('backdevpath','')
1681 self.size = self.db.get_val_int('devsize', 0)
1682 self.journal_size = self.db.get_val_int('journalsize', 0)
1683 self.fstype = self.db.get_val('fstype', '')
1684 self.backfstype = self.db.get_val('backfstype', '')
1685 self.nspath = self.db.get_val('nspath', '')
1686 self.mkfsoptions = self.db.get_val('mkfsoptions', '')
1687 self.mountfsoptions = self.db.get_val('mountfsoptions', '')
1688 self.obdtype = self.db.get_val('obdtype', '')
1689 self.root_squash = self.db.get_val('root_squash', '')
1690 self.no_root_squash = self.db.get_val('no_root_squash', '')
1691 # overwrite the orignal MDSDEV name and uuid with the MDS name and uuid
1692 target_uuid = self.db.get_first_ref('target')
1693 self.mds = self.db.lookup(target_uuid)
1694 self.name = self.mds.getName()
1695 self.client_uuids = self.mds.get_refs('client')
1701 self.master_uuid = ""
1704 # it is possible to have MDS with no clients. It is master MDS
1705 # in configuration with CMOBD.
1706 self.lmv_uuid = self.db.get_first_ref('lmv')
1708 self.lmv = self.db.lookup(self.lmv_uuid)
1710 self.client_uuids = self.lmv.get_refs('client')
1711 self.master_uuid = self.lmv_uuid
1713 # FIXME: if fstype not set, then determine based on kernel version
1714 self.format = self.db.get_val('autoformat', "no")
1715 if self.mds.get_val('failover', 0):
1716 self.failover_mds = 'f'
1718 self.failover_mds = 'n'
1719 active_uuid = get_active_target(self.mds)
1721 panic("No target device found:", target_uuid)
1722 if active_uuid == self.uuid:
1726 if self.active and config.group and config.group != self.mds.get_val('group'):
1729 # default inode inode for case when neither LOV either
1730 # LMV is accessible.
1731 self.inode_size = 256
1733 inode_size = self.db.get_val_int('inodesize', 0)
1734 if not inode_size == 0:
1735 self.inode_size = inode_size
1737 # find the LOV for this MDS
1738 lovconfig_uuid = self.mds.get_first_ref('lovconfig')
1739 if lovconfig_uuid or self.lmv:
1741 lovconfig_uuid = self.lmv.get_first_ref('lovconfig')
1742 lovconfig = self.lmv.lookup(lovconfig_uuid)
1743 lov_uuid = lovconfig.get_first_ref('lov')
1745 panic(self.mds.getName() + ": No LOV found for lovconfig ",
1748 lovconfig = self.mds.lookup(lovconfig_uuid)
1749 lov_uuid = lovconfig.get_first_ref('lov')
1751 panic(self.mds.getName() + ": No LOV found for lovconfig ",
1755 lovconfig_uuid = self.lmv.get_first_ref('lovconfig')
1756 lovconfig = self.lmv.lookup(lovconfig_uuid)
1757 lov_uuid = lovconfig.get_first_ref('lov')
1759 lov = LOV(self.db.lookup(lov_uuid), lov_uuid, 'FS_name',
1762 # default stripe count controls default inode_size
1763 stripe_count = lov.stripe_cnt
1764 if stripe_count > 77:
1765 self.inode_size = 4096
1766 elif stripe_count > 35:
1767 self.inode_size = 2048
1768 elif stripe_count > 13:
1769 self.inode_size = 1024
1770 elif stripe_count > 3:
1771 self.inode_size = 512
1773 self.inode_size = 256
1775 self.target_dev_uuid = self.uuid
1776 self.uuid = target_uuid
1779 if self.master_uuid:
1780 client_uuid = self.name + "_lmv_" + "UUID"
1781 self.master = LMV(self.db.lookup(self.lmv_uuid), client_uuid,
1782 self.name, self.name)
1783 self.master_uuid = self.master.name
1785 def add_module(self, manager):
1787 manager.add_lustre_module('mdc', 'mdc')
1788 manager.add_lustre_module('osc', 'osc')
1789 manager.add_lustre_module('ost', 'ost')
1790 manager.add_lustre_module('lov', 'lov')
1791 manager.add_lustre_module('mds', 'mds')
1793 if self.fstype == 'smfs':
1794 manager.add_lustre_module('smfs', 'smfs')
1796 if self.fstype == 'ldiskfs':
1797 manager.add_lustre_module('ldiskfs', 'ldiskfs')
1800 manager.add_lustre_module('lvfs', 'fsfilt_%s' % (self.fstype))
1802 # if fstype is smfs, then we should also take care about backing
1804 if self.fstype == 'smfs':
1805 manager.add_lustre_module('lvfs', 'fsfilt_%s' % (self.backfstype))
1807 for option in string.split(self.mountfsoptions, ','):
1808 if option == 'snap':
1809 if not self.fstype == 'smfs':
1810 panic("mountoptions has 'snap', but fstype is not smfs.")
1811 manager.add_lustre_module('lvfs', 'fsfilt_snap_%s' % (self.fstype))
1812 manager.add_lustre_module('lvfs', 'fsfilt_snap_%s' % (self.backfstype))
1815 if self.master_uuid:
1816 self.master.add_module(manager)
1819 if not config.record and is_prepared(self.name):
1822 debug(self.uuid, "not active")
1825 # run write_conf automatically, if --reformat used
1827 self.info(self.devpath, self.fstype, self.size, self.format)
1831 if self.master_uuid:
1832 self.master.prepare()
1834 # never reformat here
1835 blkdev = block_dev(self.devpath, self.size, self.fstype, 0,
1836 self.format, self.journal_size, self.inode_size,
1837 self.mkfsoptions, self.backfstype, self.backdevpath)
1839 if not is_prepared('MDT'):
1840 lctl.newdev("mdt", 'MDT', 'MDT_UUID', setup ="")
1842 mountfsoptions = def_mount_options(self.fstype, 'mds')
1844 if config.mountfsoptions:
1846 mountfsoptions = mountfsoptions + ',' + config.mountfsoptions
1848 mountfsoptions = config.mountfsoptions
1849 if self.mountfsoptions:
1850 mountfsoptions = mountfsoptions + ',' + self.mountfsoptions
1852 if self.mountfsoptions:
1854 mountfsoptions = mountfsoptions + ',' + self.mountfsoptions
1856 mountfsoptions = self.mountfsoptions
1858 if self.fstype == 'smfs':
1859 realdev = self.fstype
1862 mountfsoptions = "%s,type=%s,dev=%s" % (mountfsoptions,
1866 mountfsoptions = "type=%s,dev=%s" % (self.backfstype,
1871 print 'MDS mount options: ' + mountfsoptions
1873 if not self.master_uuid:
1874 self.master_uuid = 'dumb'
1876 if not self.obdtype:
1877 self.obdtype = 'dumb'
1879 if not self.client_uuids:
1880 lctl.newdev("mds", self.name, self.uuid,
1881 setup ="%s %s %s %s %s %s" %(realdev, self.fstype,
1882 'dumb', mountfsoptions,
1883 self.master_uuid, self.obdtype))
1885 lctl.newdev("mds", self.name, self.uuid,
1886 setup ="%s %s %s %s %s %s" %(realdev, self.fstype,
1887 self.name, mountfsoptions,
1888 self.master_uuid, self.obdtype))
1890 if development_mode():
1891 procentry = "/proc/fs/lustre/mds/grp_hash_upcall"
1892 upcall = os.path.abspath(os.path.dirname(sys.argv[0]) + "/l_getgroups")
1893 if not (os.access(procentry, os.R_OK) and os.access(upcall, os.R_OK)):
1894 print "MDS Warning: failed to set group-hash upcall"
1896 run("echo ", upcall, " > ", procentry)
1898 except CommandError, e:
1900 panic("MDS is missing the config log. Need to run " +
1901 "lconf --write_conf.")
1905 if config.root_squash == None:
1906 config.root_squash = self.root_squash
1907 if config.no_root_squash == None:
1908 config.no_root_squash = self.no_root_squash
1909 if config.root_squash:
1910 if config.no_root_squash:
1911 nsnid = config.no_root_squash
1914 lctl.root_squash(self.name, config.root_squash, nsnid)
1916 def write_conf(self):
1917 if not self.client_uuids:
1921 if not is_prepared(self.name):
1922 self.info(self.devpath, self.fstype, self.format)
1924 blkdev = block_dev(self.devpath, self.size, self.fstype,
1925 config.reformat, self.format, self.journal_size,
1926 self.inode_size, self.mkfsoptions,
1927 self.backfstype, self.backdevpath)
1929 # Even for writing logs we mount mds with supplied mount options
1930 # because it will not mount smfs (if used) otherwise.
1932 mountfsoptions = def_mount_options(self.fstype, 'mds')
1934 if config.mountfsoptions:
1936 mountfsoptions = mountfsoptions + ',' + config.mountfsoptions
1938 mountfsoptions = config.mountfsoptions
1939 if self.mountfsoptions:
1940 mountfsoptions = mountfsoptions + ',' + self.mountfsoptions
1942 if self.mountfsoptions:
1944 mountfsoptions = mountfsoptions + ',' + self.mountfsoptions
1946 mountfsoptions = self.mountfsoptions
1948 if self.fstype == 'smfs':
1949 realdev = self.fstype
1952 mountfsoptions = "%s,type=%s,dev=%s" % (mountfsoptions,
1956 mountfsoptions = "type=%s,dev=%s" % (self.backfstype,
1961 print 'MDS mount options: ' + mountfsoptions
1963 if not self.obdtype:
1964 self.obdtype = 'dumb'
1966 # As mount options are passed by 4th param to config tool, we need
1967 # to pass something in 3rd param. But we do not want this 3rd param
1968 # be counted as a profile name for reading log on MDS setup, thus,
1969 # we pass there some predefined sign like 'dumb', which will be
1970 # checked in MDS code and skipped. Probably there is more nice way
1971 # like pass empty string and check it in config tool and pass null
1973 lctl.newdev("mds", self.name, self.uuid,
1974 setup ="%s %s %s %s %s %s" %(realdev, self.fstype,
1975 'dumb', mountfsoptions,
1976 'dumb', self.obdtype))
1979 # record logs for all MDS clients
1980 for obd_uuid in self.client_uuids:
1981 log("recording client:", obd_uuid)
1983 client_uuid = generate_client_uuid(self.name)
1984 client = VOSC(self.db.lookup(obd_uuid), client_uuid,
1985 self.name, self.name)
1987 lctl.clear_log(self.name, self.name)
1988 lctl.record(self.name, self.name)
1990 lctl.mount_option(self.name, client.get_name(), "")
1992 process_updates(self.db, self.name, self.name, client)
1995 lctl.clear_log(self.name, self.name + '-clean')
1996 lctl.record(self.name, self.name + '-clean')
1998 lctl.del_mount_option(self.name)
2000 process_updates(self.db, self.name, self.name + '-clean', client)
2004 # record logs for each client
2010 config_options = "--ldapurl " + config.ldapurl + " --config " + config.config
2012 config_options = CONFIG_FILE
2014 for node_db in self.db.lookup_class('node'):
2015 client_name = node_db.getName()
2016 for prof_uuid in node_db.get_refs('profile'):
2017 prof_db = node_db.lookup(prof_uuid)
2018 # refactor this into a funtion to test "clientness"
2020 for ref_class, ref_uuid in prof_db.get_all_refs():
2021 if ref_class in ('mountpoint','echoclient'):
2022 debug("recording", client_name)
2023 old_noexec = config.noexec
2025 ret, out = run (sys.argv[0], noexec_opt,
2026 " -v --record --nomod",
2027 "--record_log", client_name,
2028 "--record_device", self.name,
2029 "--node", client_name,
2032 for s in out: log("record> ", string.strip(s))
2033 ret, out = run (sys.argv[0], noexec_opt,
2034 "--cleanup -v --record --nomod",
2035 "--record_log", client_name + "-clean",
2036 "--record_device", self.name,
2037 "--node", client_name,
2040 for s in out: log("record> ", string.strip(s))
2041 config.noexec = old_noexec
2044 lctl.cleanup(self.name, self.uuid, 0, 0)
2045 except CommandError, e:
2046 log(self.module_name, "cleanup failed: ", self.name)
2049 Module.cleanup(self)
2051 clean_dev(self.devpath, self.fstype, self.backfstype,
2054 def msd_remaining(self):
2055 out = lctl.device_list()
2057 if string.split(s)[2] in ('mds',):
2060 def safe_to_clean(self):
2063 def safe_to_clean_modules(self):
2064 return not self.msd_remaining()
2068 debug(self.uuid, "not active")
2071 if is_prepared(self.name):
2073 lctl.cleanup(self.name, self.uuid, config.force,
2075 except CommandError, e:
2076 log(self.module_name, "cleanup failed: ", self.name)
2079 Module.cleanup(self)
2081 if self.master_uuid:
2082 self.master.cleanup()
2083 if not self.msd_remaining() and is_prepared('MDT'):
2085 lctl.cleanup("MDT", "MDT_UUID", config.force,
2087 except CommandError, e:
2088 print "cleanup failed: ", self.name
2092 clean_dev(self.devpath, self.fstype, self.backfstype,
2095 def correct_level(self, level, op=None):
2096 #if self.master_uuid:
2101 def __init__(self, db):
2102 Module.__init__(self, 'OSD', db)
2103 self.osdtype = self.db.get_val('osdtype')
2104 self.devpath = self.db.get_val('devpath', '')
2105 self.backdevpath = self.db.get_val('backdevpath', '')
2106 self.size = self.db.get_val_int('devsize', 0)
2107 self.journal_size = self.db.get_val_int('journalsize', 0)
2108 self.inode_size = self.db.get_val_int('inodesize', 0)
2109 self.mkfsoptions = self.db.get_val('mkfsoptions', '')
2110 self.mountfsoptions = self.db.get_val('mountfsoptions', '')
2111 self.fstype = self.db.get_val('fstype', '')
2112 self.backfstype = self.db.get_val('backfstype', '')
2113 self.nspath = self.db.get_val('nspath', '')
2114 target_uuid = self.db.get_first_ref('target')
2115 ost = self.db.lookup(target_uuid)
2116 self.name = ost.getName()
2117 self.format = self.db.get_val('autoformat', 'yes')
2118 if ost.get_val('failover', 0):
2119 self.failover_ost = 'f'
2121 self.failover_ost = 'n'
2123 active_uuid = get_active_target(ost)
2125 panic("No target device found:", target_uuid)
2126 if active_uuid == self.uuid:
2130 if self.active and config.group and config.group != ost.get_val('group'):
2133 self.target_dev_uuid = self.uuid
2134 self.uuid = target_uuid
2136 def add_module(self, manager):
2138 manager.add_lustre_module('ost', 'ost')
2140 if self.fstype == 'smfs':
2141 manager.add_lustre_module('smfs', 'smfs')
2143 if self.fstype == 'ldiskfs':
2144 manager.add_lustre_module('ldiskfs', 'ldiskfs')
2146 manager.add_lustre_module('lvfs' , 'fsfilt_%s' % (self.fstype))
2147 if self.fstype == 'smfs':
2148 manager.add_lustre_module('lvfs' , 'fsfilt_%s' % (self.backfstype))
2150 for option in self.mountfsoptions:
2151 if option == 'snap':
2152 if not self.fstype == 'smfs':
2153 panic("mountoptions with snap, but fstype is not smfs\n")
2154 manager.add_lustre_module('lvfs', 'fsfilt_snap_%s' % (self.fstype))
2155 manager.add_lustre_module('lvfs', 'fsfilt_snap_%s' % (self.backfstype))
2157 manager.add_lustre_module(self.osdtype, self.osdtype)
2159 # need to check /proc/mounts and /etc/mtab before
2160 # formatting anything.
2161 # FIXME: check if device is already formatted.
2163 if is_prepared(self.name):
2166 debug(self.uuid, "not active")
2168 self.info(self.osdtype, self.devpath, self.size, self.fstype,
2169 self.format, self.journal_size, self.inode_size)
2171 if self.osdtype == 'obdecho':
2174 blkdev = block_dev(self.devpath, self.size, self.fstype,
2175 config.reformat, self.format, self.journal_size,
2176 self.inode_size, self.mkfsoptions, self.backfstype,
2179 mountfsoptions = def_mount_options(self.fstype, 'ost')
2181 if config.mountfsoptions:
2183 mountfsoptions = mountfsoptions + ',' + config.mountfsoptions
2185 mountfsoptions = config.mountfsoptions
2186 if self.mountfsoptions:
2187 mountfsoptions = mountfsoptions + ',' + self.mountfsoptions
2189 if self.mountfsoptions:
2191 mountfsoptions = mountfsoptions + ',' + self.mountfsoptions
2193 mountfsoptions = self.mountfsoptions
2195 if self.fstype == 'smfs':
2196 realdev = self.fstype
2199 mountfsoptions = "%s,type=%s,dev=%s" % (mountfsoptions,
2203 mountfsoptions = "type=%s,dev=%s" % (self.backfstype,
2208 print 'OSD mount options: ' + mountfsoptions
2210 lctl.newdev(self.osdtype, self.name, self.uuid,
2211 setup ="%s %s %s %s" %(realdev, self.fstype,
2214 if not is_prepared('OSS'):
2215 lctl.newdev("ost", 'OSS', 'OSS_UUID', setup ="")
2217 def osd_remaining(self):
2218 out = lctl.device_list()
2220 if string.split(s)[2] in ('obdfilter', 'obdecho'):
2223 def safe_to_clean(self):
2226 def safe_to_clean_modules(self):
2227 return not self.osd_remaining()
2231 debug(self.uuid, "not active")
2233 if is_prepared(self.name):
2236 lctl.cleanup(self.name, self.uuid, config.force,
2238 except CommandError, e:
2239 log(self.module_name, "cleanup failed: ", self.name)
2242 if not self.osd_remaining() and is_prepared('OSS'):
2244 lctl.cleanup("OSS", "OSS_UUID", config.force,
2246 except CommandError, e:
2247 print "cleanup failed: ", self.name
2250 if not self.osdtype == 'obdecho':
2251 clean_dev(self.devpath, self.fstype, self.backfstype,
2254 def correct_level(self, level, op=None):
2257 def mgmt_uuid_for_fs(mtpt_name):
2260 mtpt_db = toplustreDB.lookup_name(mtpt_name)
2261 fs_uuid = mtpt_db.get_first_ref('filesystem')
2262 fs = toplustreDB.lookup(fs_uuid)
2265 return fs.get_first_ref('mgmt')
2267 # Generic client module, used by OSC and MDC
2268 class Client(Module):
2269 def __init__(self, tgtdb, uuid, module, fs_name, self_name=None,
2271 self.target_name = tgtdb.getName()
2272 self.target_uuid = tgtdb.getUUID()
2273 self.module_dir = module_dir
2274 self.module = module
2278 self.tgt_dev_uuid = get_active_target(tgtdb)
2279 if not self.tgt_dev_uuid:
2280 panic("No target device found for target(1):", self.target_name)
2285 self.module = module
2286 self.module_name = string.upper(module)
2288 self.name = '%s_%s_%s_%s' % (self.module_name, socket.gethostname(),
2289 self.target_name, fs_name)
2291 self.name = self_name
2293 self.lookup_server(self.tgt_dev_uuid)
2294 mgmt_uuid = mgmt_uuid_for_fs(fs_name)
2296 self.mgmt_name = mgmtcli_name_for_uuid(mgmt_uuid)
2299 self.fs_name = fs_name
2300 if not self.module_dir:
2301 self.module_dir = module
2303 def add_module(self, manager):
2304 manager.add_lustre_module(self.module_dir, self.module)
2306 def lookup_server(self, srv_uuid):
2307 """ Lookup a server's network information """
2308 self._server_nets = get_ost_net(self.db, srv_uuid)
2309 if len(self._server_nets) == 0:
2310 panic ("Unable to find a server for:", srv_uuid)
2315 def get_servers(self):
2316 return self._server_nets
2318 def prepare(self, ignore_connect_failure = 0):
2319 self.info(self.target_uuid)
2320 if not config.record and is_prepared(self.name):
2323 srv = choose_local_server(self.get_servers())
2327 routes = find_route(self.get_servers())
2328 if len(routes) == 0:
2329 panic ("no route to", self.target_uuid)
2330 for (srv, r) in routes:
2331 lctl.add_route_host(r[0], srv.nid_uuid, r[1], r[3])
2332 except CommandError, e:
2333 if not ignore_connect_failure:
2336 if self.permits_inactive() and (self.target_uuid in config.inactive or self.active == 0):
2337 debug("%s inactive" % self.target_uuid)
2338 inactive_p = "inactive"
2340 debug("%s active" % self.target_uuid)
2342 lctl.newdev(self.module, self.name, self.uuid,
2343 setup ="%s %s %s %s" % (self.target_uuid, srv.nid_uuid,
2344 inactive_p, self.mgmt_name))
2347 if is_prepared(self.name):
2348 Module.cleanup(self)
2350 srv = choose_local_server(self.get_servers())
2352 lctl.disconnect(srv)
2354 for (srv, r) in find_route(self.get_servers()):
2355 lctl.del_route_host(r[0], srv.nid_uuid, r[1], r[3])
2356 except CommandError, e:
2357 log(self.module_name, "cleanup failed: ", self.name)
2361 def correct_level(self, level, op=None):
2364 def deactivate(self):
2366 lctl.deactivate(self.name)
2367 except CommandError, e:
2368 log(self.module_name, "deactivate failed: ", self.name)
2373 def __init__(self, db, uuid, fs_name):
2374 Client.__init__(self, db, uuid, 'mdc', fs_name)
2376 def permits_inactive(self):
2380 def __init__(self, db, uuid, fs_name):
2381 Client.__init__(self, db, uuid, 'osc', fs_name)
2383 def permits_inactive(self):
2386 def mgmtcli_name_for_uuid(uuid):
2387 return 'MGMTCLI_%s' % uuid
2389 class ManagementClient(Client):
2390 def __init__(self, db, uuid):
2391 Client.__init__(self, db, uuid, 'mgmt_cli', '',
2392 self_name = mgmtcli_name_for_uuid(db.getUUID()),
2393 module_dir = 'mgmt')
2395 class CMOBD(Module):
2396 def __init__(self, db):
2397 Module.__init__(self, 'CMOBD', db)
2398 self.name = self.db.getName();
2399 self.uuid = generate_client_uuid(self.name)
2400 self.master_uuid = self.db.get_first_ref('masterobd')
2401 self.cache_uuid = self.db.get_first_ref('cacheobd')
2403 master_obd = self.db.lookup(self.master_uuid)
2405 panic('master obd not found:', self.master_uuid)
2407 cache_obd = self.db.lookup(self.cache_uuid)
2409 panic('cache obd not found:', self.cache_uuid)
2411 master_class = master_obd.get_class()
2412 cache_class = cache_obd.get_class()
2414 if master_class == 'ost' or master_class == 'lov':
2415 self.master = LOV(master_obd, self.master_uuid, self.name,
2416 "%s_master" % (self.name));
2417 self.cache = LOV(cache_obd, self.cache_uuid, self.name,
2418 "%s_cache" % (self.name));
2419 if master_class == 'mds':
2420 self.master = get_mdc(db, self.name, self.master_uuid)
2421 if cache_class == 'mds':
2422 self.cache = get_mdc(db, self.name, self.cache_uuid)
2424 if master_class == 'lmv':
2425 self.master = LMV(master_obd, self.master_uuid, self.name,
2426 "%s_master" % (self.name));
2427 if cache_class == 'lmv':
2428 self.cache = LMV(cache_obd, self.cache_uuid, self.name,
2429 "%s_cache" % (self.name));
2431 # need to check /proc/mounts and /etc/mtab before
2432 # formatting anything.
2433 # FIXME: check if device is already formatted.
2435 self.master.prepare()
2436 if not config.record and is_prepared(self.name):
2438 self.info(self.master_uuid, self.cache_uuid)
2439 lctl.newdev("cmobd", self.name, self.uuid,
2440 setup ="%s %s" %(self.master_uuid,
2447 def get_master_name(self):
2448 return self.master.name
2449 def get_cache_name(self):
2450 return self.cache.name
2453 if is_prepared(self.name):
2454 Module.cleanup(self)
2455 self.master.cleanup()
2457 def add_module(self, manager):
2458 manager.add_lustre_module('cmobd', 'cmobd')
2459 self.master.add_module(manager)
2461 def correct_level(self, level, op=None):
2465 def __init__(self, db, uuid, name):
2466 Module.__init__(self, 'COBD', db)
2467 self.name = self.db.getName();
2468 self.uuid = generate_client_uuid(self.name)
2469 self.master_uuid = self.db.get_first_ref('masterobd')
2470 self.cache_uuid = self.db.get_first_ref('cacheobd')
2472 master_obd = self.db.lookup(self.master_uuid)
2474 panic('master obd not found:', self.master_uuid)
2476 cache_obd = self.db.lookup(self.cache_uuid)
2478 panic('cache obd not found:', self.cache_uuid)
2480 master_class = master_obd.get_class()
2481 cache_class = cache_obd.get_class()
2483 if master_class == 'ost' or master_class == 'lov':
2484 self.master = LOV(master_obd, self.master_uuid, name,
2485 "%s_master" % (self.name));
2486 self.cache = LOV(cache_obd, self.cache_uuid, name,
2487 "%s_cache" % (self.name));
2488 if master_class == 'mds':
2489 self.master = get_mdc(db, name, self.master_uuid)
2490 if cache_class == 'mds':
2491 self.cache = get_mdc(db, name, self.cache_uuid)
2493 if master_class == 'lmv':
2494 self.master = LMV(master_obd, self.master_uuid, self.name,
2495 "%s_master" % (self.name));
2496 if cache_class == 'lmv':
2497 self.cache = LMV(cache_obd, self.cache_uuid, self.name,
2498 "%s_cache" % (self.name));
2500 # need to check /proc/mounts and /etc/mtab before
2501 # formatting anything.
2502 # FIXME: check if device is already formatted.
2509 def get_master_name(self):
2510 return self.master.name
2512 def get_cache_name(self):
2513 return self.cache.name
2516 self.master.prepare()
2517 self.cache.prepare()
2518 if not config.record and is_prepared(self.name):
2520 self.info(self.master_uuid, self.cache_uuid)
2521 lctl.newdev("cobd", self.name, self.uuid,
2522 setup ="%s %s" %(self.master.name,
2526 if is_prepared(self.name):
2527 Module.cleanup(self)
2528 self.master.cleanup()
2529 self.cache.cleanup()
2531 def add_module(self, manager):
2532 manager.add_lustre_module('cobd', 'cobd')
2533 self.master.add_module(manager)
2535 # virtual interface for OSC and LOV
2537 def __init__(self, db, client_uuid, name, name_override = None):
2538 Module.__init__(self, 'VOSC', db)
2539 if db.get_class() == 'lov':
2540 self.osc = LOV(db, client_uuid, name, name_override)
2542 elif db.get_class() == 'cobd':
2543 self.osc = COBD(db, client_uuid, name)
2546 self.osc = OSC(db, client_uuid, name)
2550 return self.osc.get_uuid()
2553 return self.osc.get_name()
2561 def add_module(self, manager):
2562 self.osc.add_module(manager)
2564 def correct_level(self, level, op=None):
2565 return self.osc.correct_level(level, op)
2567 # virtual interface for MDC and LMV
2569 def __init__(self, db, client_uuid, name, name_override = None):
2570 Module.__init__(self, 'VMDC', db)
2571 if db.get_class() == 'lmv':
2572 self.mdc = LMV(db, client_uuid, name)
2573 elif db.get_class() == 'cobd':
2574 self.mdc = COBD(db, client_uuid, name)
2576 self.mdc = MDC(db, client_uuid, name)
2579 return self.mdc.uuid
2582 return self.mdc.name
2590 def add_module(self, manager):
2591 self.mdc.add_module(manager)
2593 def correct_level(self, level, op=None):
2594 return self.mdc.correct_level(level, op)
2596 class ECHO_CLIENT(Module):
2597 def __init__(self,db):
2598 Module.__init__(self, 'ECHO_CLIENT', db)
2599 self.obd_uuid = self.db.get_first_ref('obd')
2600 obd = self.db.lookup(self.obd_uuid)
2601 self.uuid = generate_client_uuid(self.name)
2602 self.osc = VOSC(obd, self.uuid, self.name)
2605 if not config.record and is_prepared(self.name):
2608 self.osc.prepare() # XXX This is so cheating. -p
2609 self.info(self.obd_uuid)
2611 lctl.newdev("echo_client", self.name, self.uuid,
2612 setup = self.osc.get_name())
2615 if is_prepared(self.name):
2616 Module.cleanup(self)
2619 def add_module(self, manager):
2620 self.osc.add_module(manager)
2621 manager.add_lustre_module('obdecho', 'obdecho')
2623 def correct_level(self, level, op=None):
2626 def generate_client_uuid(name):
2627 client_uuid = '%05x_%.19s_%05x%05x' % (int(random.random() * 1048576),
2629 int(random.random() * 1048576),
2630 int(random.random() * 1048576))
2631 return client_uuid[:36]
2633 class Mountpoint(Module):
2634 def __init__(self,db):
2635 Module.__init__(self, 'MTPT', db)
2636 self.path = self.db.get_val('path')
2637 self.clientoptions = self.db.get_val('clientoptions', '')
2638 self.fs_uuid = self.db.get_first_ref('filesystem')
2639 fs = self.db.lookup(self.fs_uuid)
2640 self.mds_uuid = fs.get_first_ref('lmv')
2641 if not self.mds_uuid:
2642 self.mds_uuid = fs.get_first_ref('mds')
2643 self.obd_uuid = fs.get_first_ref('obd')
2644 self.mgmt_uuid = fs.get_first_ref('mgmt')
2645 client_uuid = generate_client_uuid(self.name)
2647 ost = self.db.lookup(self.obd_uuid)
2649 panic("no ost: ", self.obd_uuid)
2651 mds = self.db.lookup(self.mds_uuid)
2653 panic("no mds: ", self.mds_uuid)
2655 self.vosc = VOSC(ost, client_uuid, self.name)
2656 self.vmdc = VMDC(mds, client_uuid, self.name)
2659 self.mgmtcli = ManagementClient(db.lookup(self.mgmt_uuid),
2665 if not config.record and fs_is_mounted(self.path):
2666 log(self.path, "already mounted.")
2670 self.mgmtcli.prepare()
2673 vmdc_name = self.vmdc.get_name()
2675 self.info(self.path, self.mds_uuid, self.obd_uuid)
2676 if config.record or config.lctl_dump:
2677 lctl.mount_option(local_node_name, self.vosc.get_name(), vmdc_name)
2680 if config.clientoptions:
2681 if self.clientoptions:
2682 self.clientoptions = self.clientoptions + ',' + \
2683 config.clientoptions
2685 self.clientoptions = config.clientoptions
2686 if self.clientoptions:
2687 self.clientoptions = ',' + self.clientoptions
2688 # Linux kernel will deal with async and not pass it to ll_fill_super,
2689 # so replace it with Lustre async
2690 self.clientoptions = string.replace(self.clientoptions, "async",
2693 cmd = "mount -t lustre_lite -o osc=%s,mdc=%s%s %s %s" % \
2694 (self.vosc.get_name(), vmdc_name, self.clientoptions,
2695 config.config, self.path)
2696 run("mkdir", self.path)
2701 panic("mount failed:", self.path, ":", string.join(val))
2704 self.info(self.path, self.mds_uuid,self.obd_uuid)
2706 if config.record or config.lctl_dump:
2707 lctl.del_mount_option(local_node_name)
2709 if fs_is_mounted(self.path):
2711 (rc, out) = run("umount", "-f", self.path)
2713 (rc, out) = run("umount", self.path)
2715 raise CommandError('umount', out, rc)
2717 if fs_is_mounted(self.path):
2718 panic("fs is still mounted:", self.path)
2723 self.mgmtcli.cleanup()
2725 def add_module(self, manager):
2726 manager.add_lustre_module('mdc', 'mdc')
2729 self.mgmtcli.add_module(manager)
2731 self.vosc.add_module(manager)
2732 self.vmdc.add_module(manager)
2734 manager.add_lustre_module('llite', 'llite')
2736 def correct_level(self, level, op=None):
2739 # ============================================================
2740 # misc query functions
2742 def get_ost_net(self, osd_uuid):
2746 osd = self.lookup(osd_uuid)
2747 node_uuid = osd.get_first_ref('node')
2748 node = self.lookup(node_uuid)
2750 panic("unable to find node for osd_uuid:", osd_uuid,
2751 " node_ref:", node_uuid_)
2752 for net_uuid in node.get_networks():
2753 db = node.lookup(net_uuid)
2754 srv_list.append(Network(db))
2758 # the order of iniitailization is based on level.
2759 def getServiceLevel(self):
2760 type = self.get_class()
2762 if type in ('network',):
2764 elif type in ('routetbl',):
2766 elif type in ('ldlm',):
2768 elif type in ('osd', 'cobd'):
2770 elif type in ('mdsdev',):
2772 elif type in ('lmv',):
2774 elif type in ('cmobd',):
2776 elif type in ('mountpoint', 'echoclient'):
2779 panic("Unknown type: ", type)
2781 if ret < config.minlevel or ret > config.maxlevel:
2786 # return list of services in a profile. list is a list of tuples
2787 # [(level, db_object),]
2788 def getServices(self):
2790 for ref_class, ref_uuid in self.get_all_refs():
2791 servdb = self.lookup(ref_uuid)
2793 level = getServiceLevel(servdb)
2795 list.append((level, servdb))
2797 panic('service not found: ' + ref_uuid)
2803 ############################################################
2805 # FIXME: clean this mess up!
2807 # OSC is no longer in the xml, so we have to fake it.
2808 # this is getting ugly and begging for another refactoring
2809 def get_osc(ost_db, uuid, fs_name):
2810 osc = OSC(ost_db, uuid, fs_name)
2813 def get_mdc(db, fs_name, mds_uuid):
2814 mds_db = db.lookup(mds_uuid);
2816 error("no mds:", mds_uuid)
2817 mdc = MDC(mds_db, mds_uuid, fs_name)
2820 ############################################################
2821 # routing ("rooting")
2823 # list of (nettype, cluster_id, nid)
2826 def find_local_clusters(node_db):
2827 global local_clusters
2828 for netuuid in node_db.get_networks():
2829 net = node_db.lookup(netuuid)
2831 debug("add_local", netuuid)
2832 local_clusters.append((srv.net_type, srv.cluster_id, srv.nid))
2834 if acceptors.has_key(srv.port):
2835 panic("duplicate port:", srv.port)
2836 acceptors[srv.port] = AcceptorHandler(srv.port, srv.net_type)
2838 # This node is a gateway.
2840 def node_is_router():
2843 # If there are any routers found in the config, then this will be true
2844 # and all nodes will load kptlrouter.
2846 def node_needs_router():
2847 return needs_router or is_router
2849 # list of (nettype, gw, tgt_cluster_id, lo, hi)
2850 # Currently, these local routes are only added to kptlrouter route
2851 # table if they are needed to connect to a specific server. This
2852 # should be changed so all available routes are loaded, and the
2853 # ptlrouter can make all the decisions.
2856 def find_local_routes(lustre):
2857 """ Scan the lustre config looking for routers . Build list of
2859 global local_routes, needs_router
2861 list = lustre.lookup_class('node')
2863 if router.get_val_int('router', 0):
2865 for (local_type, local_cluster_id, local_nid) in local_clusters:
2867 for netuuid in router.get_networks():
2868 db = router.lookup(netuuid)
2869 if (local_type == db.get_val('nettype') and
2870 local_cluster_id == db.get_val('clusterid')):
2871 gw = db.get_val('nid')
2874 debug("find_local_routes: gw is", gw)
2875 for route in router.get_local_routes(local_type, gw):
2876 local_routes.append(route)
2877 debug("find_local_routes:", local_routes)
2880 def choose_local_server(srv_list):
2881 for srv in srv_list:
2882 if local_cluster(srv.net_type, srv.cluster_id):
2885 def local_cluster(net_type, cluster_id):
2886 for cluster in local_clusters:
2887 if net_type == cluster[0] and cluster_id == cluster[1]:
2891 def local_interface(net_type, cluster_id, nid):
2892 for cluster in local_clusters:
2893 if (net_type == cluster[0] and cluster_id == cluster[1]
2894 and nid == cluster[2]):
2898 def find_route(srv_list):
2900 frm_type = local_clusters[0][0]
2901 for srv in srv_list:
2902 debug("find_route: srv:", srv.nid, "type: ", srv.net_type)
2903 to_type = srv.net_type
2905 cluster_id = srv.cluster_id
2906 debug ('looking for route to', to_type, to)
2907 for r in local_routes:
2908 debug("find_route: ", r)
2909 if (r[3] <= to and to <= r[4]) and cluster_id == r[2]:
2910 result.append((srv, r))
2913 def get_active_target(db):
2914 target_uuid = db.getUUID()
2915 target_name = db.getName()
2916 node_name = get_select(target_name)
2918 tgt_dev_uuid = db.get_node_tgt_dev(node_name, target_uuid)
2920 tgt_dev_uuid = db.get_first_ref('active')
2923 def get_server_by_nid_uuid(db, nid_uuid):
2924 for n in db.lookup_class("network"):
2926 if net.nid_uuid == nid_uuid:
2930 ############################################################
2934 type = db.get_class()
2935 debug('Service:', type, db.getName(), db.getUUID())
2940 n = LOV(db, "YOU_SHOULD_NEVER_SEE_THIS_UUID")
2941 elif type == 'network':
2943 elif type == 'routetbl':
2947 elif type == 'cobd':
2948 n = COBD(db, "YOU_SHOULD_NEVER_SEE_THIS_UUID")
2949 elif type == 'cmobd':
2951 elif type == 'mdsdev':
2953 elif type == 'mountpoint':
2955 elif type == 'echoclient':
2960 panic ("unknown service type:", type)
2964 # Prepare the system to run lustre using a particular profile
2965 # in a the configuration.
2966 # * load & the modules
2967 # * setup networking for the current node
2968 # * make sure partitions are in place and prepared
2969 # * initialize devices with lctl
2970 # Levels is important, and needs to be enforced.
2971 def for_each_profile(db, prof_list, operation):
2972 for prof_uuid in prof_list:
2973 prof_db = db.lookup(prof_uuid)
2975 panic("profile:", prof_uuid, "not found.")
2976 services = getServices(prof_db)
2979 def magic_get_osc(db, rec, lov):
2981 lov_uuid = lov.get_uuid()
2982 lov_name = lov.osc.fs_name
2984 lov_uuid = rec.getAttribute('lov_uuidref')
2985 # FIXME: better way to find the mountpoint?
2986 filesystems = db.root_node.getElementsByTagName('filesystem')
2988 for fs in filesystems:
2989 ref = fs.getElementsByTagName('obd_ref')
2990 if ref[0].getAttribute('uuidref') == lov_uuid:
2991 fsuuid = fs.getAttribute('uuid')
2995 panic("malformed xml: lov uuid '" + lov_uuid + "' referenced in 'add' record is not used by any filesystems.")
2997 mtpts = db.root_node.getElementsByTagName('mountpoint')
3000 ref = fs.getElementsByTagName('filesystem_ref')
3001 if ref[0].getAttribute('uuidref') == fsuuid:
3002 lov_name = fs.getAttribute('name')
3006 panic("malformed xml: 'add' record references lov uuid '" + lov_uuid + "', which references filesystem uuid '" + fsuuid + "', which does not reference a mountpoint.")
3008 print "lov_uuid: " + lov_uuid + "; lov_name: " + lov_name
3010 ost_uuid = rec.getAttribute('ost_uuidref')
3011 obd = db.lookup(ost_uuid)
3014 panic("malformed xml: 'add' record references ost uuid '" + ost_uuid + "' which cannot be found.")
3016 osc = get_osc(obd, lov_uuid, lov_name)
3018 panic('osc not found:', obd_uuid)
3021 # write logs for update records. sadly, logs of all types -- and updates in
3022 # particular -- are something of an afterthought. lconf needs rewritten with
3023 # these as core concepts. so this is a pretty big hack.
3024 def process_update_record(db, update, lov):
3025 for rec in update.childNodes:
3026 if rec.nodeType != rec.ELEMENT_NODE:
3029 log("found "+rec.nodeName+" record in update version " +
3030 str(update.getAttribute('version')))
3032 lov_uuid = rec.getAttribute('lov_uuidref')
3033 ost_uuid = rec.getAttribute('ost_uuidref')
3034 index = rec.getAttribute('index')
3035 gen = rec.getAttribute('generation')
3037 if not lov_uuid or not ost_uuid or not index or not gen:
3038 panic("malformed xml: 'update' record requires lov_uuid, ost_uuid, index, and generation.")
3041 tmplov = db.lookup(lov_uuid)
3043 panic("malformed xml: 'delete' record contains lov UUID '" + lov_uuid + "', which cannot be located.")
3044 lov_name = tmplov.getName()
3046 lov_name = lov.osc.name
3048 # ------------------------------------------------------------- add
3049 if rec.nodeName == 'add':
3051 lctl.lov_del_obd(lov_name, lov_uuid, ost_uuid, index, gen)
3054 osc = magic_get_osc(db, rec, lov)
3057 # Only ignore connect failures with --force, which
3058 # isn't implemented here yet.
3059 osc.prepare(ignore_connect_failure=0)
3060 except CommandError, e:
3061 print "Error preparing OSC %s\n" % osc.uuid
3064 lctl.lov_add_obd(lov_name, lov_uuid, ost_uuid, index, gen)
3066 # ------------------------------------------------------ deactivate
3067 elif rec.nodeName == 'deactivate':
3071 osc = magic_get_osc(db, rec, lov)
3075 except CommandError, e:
3076 print "Error deactivating OSC %s\n" % osc.uuid
3079 # ---------------------------------------------------------- delete
3080 elif rec.nodeName == 'delete':
3084 osc = magic_get_osc(db, rec, lov)
3090 except CommandError, e:
3091 print "Error cleaning up OSC %s\n" % osc.uuid
3094 lctl.lov_del_obd(lov_name, lov_uuid, ost_uuid, index, gen)
3096 def process_updates(db, log_device, log_name, lov = None):
3097 updates = db.root_node.getElementsByTagName('update')
3099 if not u.childNodes:
3100 log("ignoring empty update record (version " +
3101 str(u.getAttribute('version')) + ")")
3104 version = u.getAttribute('version')
3105 real_name = "%s-%s" % (log_name, version)
3106 lctl.clear_log(log_device, real_name)
3107 lctl.record(log_device, real_name)
3109 process_update_record(db, u, lov)
3113 def doWriteconf(services):
3117 if s[1].get_class() == 'mdsdev':
3118 n = newService(s[1])
3121 def doSetup(services):
3126 n = newService(s[1])
3128 slist.append((n.level, n))
3131 nl = n[1].correct_level(n[0])
3132 nlist.append((nl, n[1]))
3137 def doLoadModules(services):
3141 # adding all needed modules from all services
3143 n = newService(s[1])
3144 n.add_module(mod_manager)
3146 # loading all registered modules
3147 mod_manager.load_modules()
3149 def doUnloadModules(services):
3153 # adding all needed modules from all services
3155 n = newService(s[1])
3156 if n.safe_to_clean_modules():
3157 n.add_module(mod_manager)
3159 # unloading all registered modules
3160 mod_manager.cleanup_modules()
3162 def doCleanup(services):
3168 n = newService(s[1])
3170 slist.append((n.level, n))
3173 nl = n[1].correct_level(n[0])
3174 nlist.append((nl, n[1]))
3179 if n[1].safe_to_clean():
3184 def doHost(lustreDB, hosts):
3185 global is_router, local_node_name
3188 node_db = lustreDB.lookup_name(h, 'node')
3192 panic('No host entry found.')
3194 local_node_name = node_db.get_val('name', 0)
3195 is_router = node_db.get_val_int('router', 0)
3196 lustre_upcall = node_db.get_val('lustreUpcall', '')
3197 portals_upcall = node_db.get_val('portalsUpcall', '')
3198 timeout = node_db.get_val_int('timeout', 0)
3199 ptldebug = node_db.get_val('ptldebug', '')
3200 subsystem = node_db.get_val('subsystem', '')
3202 find_local_clusters(node_db)
3204 find_local_routes(lustreDB)
3206 # Two step process: (1) load modules, (2) setup lustre
3207 # if not cleaning, load modules first.
3208 prof_list = node_db.get_refs('profile')
3210 if config.write_conf:
3211 for_each_profile(node_db, prof_list, doLoadModules)
3213 for_each_profile(node_db, prof_list, doWriteconf)
3214 for_each_profile(node_db, prof_list, doUnloadModules)
3217 elif config.recover:
3218 if not (config.tgt_uuid and config.client_uuid and config.conn_uuid):
3219 raise Lustre.LconfError( "--recovery requires --tgt_uuid <UUID> " +
3220 "--client_uuid <UUID> --conn_uuid <UUID>")
3221 doRecovery(lustreDB, lctl, config.tgt_uuid, config.client_uuid,
3223 elif config.cleanup:
3225 # the command line can override this value
3227 # ugly hack, only need to run lctl commands for --dump
3228 if config.lctl_dump or config.record:
3229 for_each_profile(node_db, prof_list, doCleanup)
3232 sys_set_timeout(timeout)
3233 sys_set_ptldebug(ptldebug)
3234 sys_set_subsystem(subsystem)
3235 sys_set_lustre_upcall(lustre_upcall)
3236 sys_set_portals_upcall(portals_upcall)
3238 for_each_profile(node_db, prof_list, doCleanup)
3239 for_each_profile(node_db, prof_list, doUnloadModules)
3243 # ugly hack, only need to run lctl commands for --dump
3244 if config.lctl_dump or config.record:
3245 sys_set_timeout(timeout)
3246 sys_set_lustre_upcall(lustre_upcall)
3247 for_each_profile(node_db, prof_list, doSetup)
3251 sys_set_netmem_max('/proc/sys/net/core/rmem_max', MAXTCPBUF)
3252 sys_set_netmem_max('/proc/sys/net/core/wmem_max', MAXTCPBUF)
3254 for_each_profile(node_db, prof_list, doLoadModules)
3256 sys_set_debug_path()
3257 sys_set_ptldebug(ptldebug)
3258 sys_set_subsystem(subsystem)
3259 script = config.gdb_script
3260 run(lctl.lctl, ' modules >', script)
3262 log ("The GDB module script is in", script)
3263 # pause, so user has time to break and
3266 sys_set_timeout(timeout)
3267 sys_set_lustre_upcall(lustre_upcall)
3268 sys_set_portals_upcall(portals_upcall)
3270 for_each_profile(node_db, prof_list, doSetup)
3273 def doRecovery(lustreDB, lctl, tgt_uuid, client_uuid, nid_uuid):
3274 tgt = lustreDB.lookup(tgt_uuid)
3276 raise Lustre.LconfError("doRecovery: "+ tgt_uuid +" not found.")
3277 new_uuid = get_active_target(tgt)
3279 raise Lustre.LconfError("doRecovery: no active target found for: " +
3281 net = choose_local_server(get_ost_net(lustreDB, new_uuid))
3283 raise Lustre.LconfError("Unable to find a connection to:" + new_uuid)
3285 log("Reconnecting", tgt_uuid, " to ", net.nid_uuid);
3287 oldnet = get_server_by_nid_uuid(lustreDB, nid_uuid)
3290 lctl.disconnect(oldnet)
3291 except CommandError, e:
3292 log("recover: disconnect", nid_uuid, "failed: ")
3297 except CommandError, e:
3298 log("recover: connect failed")
3301 lctl.recover(client_uuid, net.nid_uuid)
3304 def setupModulePath(cmd, portals_dir = PORTALS_DIR):
3305 base = os.path.dirname(cmd)
3306 if development_mode():
3307 if not config.lustre:
3308 debug('using objdir module paths')
3309 config.lustre = (os.path.join(base, ".."))
3310 # normalize the portals dir, using command line arg if set
3312 portals_dir = config.portals
3313 dir = os.path.join(config.lustre, portals_dir)
3314 config.portals = dir
3315 debug('config.portals', config.portals)
3316 elif config.lustre and config.portals:
3318 # if --lustre and --portals, normalize portals
3319 # can ignore POTRALS_DIR here, since it is probly useless here
3320 config.portals = os.path.join(config.lustre, config.portals)
3321 debug('config.portals B', config.portals)
3323 def sysctl(path, val):
3324 debug("+ sysctl", path, val)
3328 fp = open(os.path.join('/proc/sys', path), 'w')
3335 def sys_set_debug_path():
3336 sysctl('portals/debug_path', config.debug_path)
3338 def sys_set_lustre_upcall(upcall):
3339 # the command overrides the value in the node config
3340 if config.lustre_upcall:
3341 upcall = config.lustre_upcall
3343 upcall = config.upcall
3345 lctl.set_lustre_upcall(upcall)
3347 def sys_set_portals_upcall(upcall):
3348 # the command overrides the value in the node config
3349 if config.portals_upcall:
3350 upcall = config.portals_upcall
3352 upcall = config.upcall
3354 sysctl('portals/upcall', upcall)
3356 def sys_set_timeout(timeout):
3357 # the command overrides the value in the node config
3358 if config.timeout and config.timeout > 0:
3359 timeout = config.timeout
3360 if timeout != None and timeout > 0:
3361 lctl.set_timeout(timeout)
3363 def sys_tweak_socknal ():
3364 # reserve at least 8MB, or we run out of RAM in skb_alloc under read
3365 if sys_get_branch() == '2.6':
3366 fp = open('/proc/meminfo')
3367 lines = fp.readlines()
3372 if a[0] == 'MemTotal:':
3374 debug("memtotal" + memtotal)
3375 if int(memtotal) < 262144:
3376 minfree = int(memtotal) / 16
3379 debug("+ minfree ", minfree)
3380 sysctl("vm/min_free_kbytes", minfree)
3381 if config.single_socket:
3382 sysctl("socknal/typed", 0)
3384 def sys_optimize_elan ():
3385 procfiles = ["/proc/elan/config/eventint_punt_loops",
3386 "/proc/qsnet/elan3/config/eventint_punt_loops",
3387 "/proc/qsnet/elan4/config/elan4_mainint_punt_loops"]
3389 if os.access(p, os.W_OK):
3390 run ("echo 1 > " + p)
3392 def sys_set_ptldebug(ptldebug):
3394 ptldebug = config.ptldebug
3397 val = eval(ptldebug, ptldebug_names)
3398 val = "0x%x" % (val)
3399 sysctl('portals/debug', val)
3400 except NameError, e:
3403 def sys_set_subsystem(subsystem):
3404 if config.subsystem:
3405 subsystem = config.subsystem
3408 val = eval(subsystem, subsystem_names)
3409 val = "0x%x" % (val)
3410 sysctl('portals/subsystem_debug', val)
3411 except NameError, e:
3414 def sys_set_netmem_max(path, max):
3415 debug("setting", path, "to at least", max)
3423 fp = open(path, 'w')
3424 fp.write('%d\n' %(max))
3428 def sys_make_devices():
3429 if not os.access('/dev/portals', os.R_OK):
3430 run('mknod /dev/portals c 10 240')
3431 if not os.access('/dev/obd', os.R_OK):
3432 run('mknod /dev/obd c 10 241')
3435 # Add dir to the global PATH, if not already there.
3436 def add_to_path(new_dir):
3437 syspath = string.split(os.environ['PATH'], ':')
3438 if new_dir in syspath:
3440 os.environ['PATH'] = os.environ['PATH'] + ':' + new_dir
3442 def default_debug_path():
3443 path = '/tmp/lustre-log'
3444 if os.path.isdir('/r'):
3449 def default_gdb_script():
3450 script = '/tmp/ogdb'
3451 if os.path.isdir('/r'):
3452 return '/r' + script
3457 DEFAULT_PATH = ('/sbin', '/usr/sbin', '/bin', '/usr/bin')
3458 # ensure basic elements are in the system path
3459 def sanitise_path():
3460 for dir in DEFAULT_PATH:
3463 # global hack for the --select handling
3465 def init_select(args):
3466 # args = [service=nodeA,service2=nodeB service3=nodeC]
3469 list = string.split(arg, ',')
3471 srv, node = string.split(entry, '=')
3472 tgt_select[srv] = node
3474 def get_select(srv):
3475 if tgt_select.has_key(srv):
3476 return tgt_select[srv]
3480 FLAG = Lustre.Options.FLAG
3481 PARAM = Lustre.Options.PARAM
3482 INTPARAM = Lustre.Options.INTPARAM
3483 PARAMLIST = Lustre.Options.PARAMLIST
3485 ('verbose,v', "Print system commands as they are run"),
3486 ('ldapurl',"LDAP server URL, eg. ldap://localhost", PARAM),
3487 ('config', "Cluster config name used for LDAP query", PARAM),
3488 ('select', "service=nodeA,service2=nodeB ", PARAMLIST),
3489 ('node', "Load config for <nodename>", PARAM),
3490 ('cleanup,d', "Cleans up config. (Shutdown)"),
3491 ('force,f', "Forced unmounting and/or obd detach during cleanup",
3493 ('single_socket', "socknal option: only use one socket instead of bundle",
3495 ('failover',"""Used to shut down without saving state.
3496 This will allow this node to "give up" a service to a
3497 another node for failover purposes. This will not
3498 be a clean shutdown.""",
3500 ('gdb', """Prints message after creating gdb module script
3501 and sleeps for 5 seconds."""),
3502 ('noexec,n', """Prints the commands and steps that will be run for a
3503 config without executing them. This can used to check if a
3504 config file is doing what it should be doing"""),
3505 ('nomod', "Skip load/unload module step."),
3506 ('nosetup', "Skip device setup/cleanup step."),
3507 ('reformat', "Reformat all devices (without question)"),
3508 ('mkfsoptions', "Additional options for the mk*fs command line", PARAM),
3509 ('mountfsoptions', "Additional options for mount fs command line", PARAM),
3510 ('clientoptions', "Additional options for Lustre", PARAM),
3511 ('dump', "Dump the kernel debug log to file before portals is unloaded",
3513 ('write_conf', "Save all the client config information on mds."),
3514 ('record', "Write config information on mds."),
3515 ('record_log', "Name of config record log.", PARAM),
3516 ('record_device', "MDS device name that will record the config commands",
3518 ('root_squash', "MDS squash root to appointed uid",
3520 ('no_root_squash', "Don't squash root for appointed nid",
3522 ('minlevel', "Minimum level of services to configure/cleanup",
3524 ('maxlevel', """Maximum level of services to configure/cleanup
3525 Levels are aproximatly like:
3530 70 - mountpoint, echo_client, osc, mdc, lov""",
3532 ('lustre', """Base directory of lustre sources. This parameter will
3533 cause lconf to load modules from a source tree.""", PARAM),
3534 ('portals', """Portals source directory. If this is a relative path,
3535 then it is assumed to be relative to lustre. """, PARAM),
3536 ('timeout', "Set recovery timeout", INTPARAM),
3537 ('upcall', "Set both portals and lustre upcall script", PARAM),
3538 ('lustre_upcall', "Set lustre upcall script", PARAM),
3539 ('portals_upcall', "Set portals upcall script", PARAM),
3540 ('lctl_dump', "Save lctl ioctls to the dumpfile argument", PARAM),
3541 ('ptldebug', "Set the portals debug level", PARAM),
3542 ('subsystem', "Set the portals debug subsystem", PARAM),
3543 ('gdb_script', "Fullname of gdb debug script", PARAM, default_gdb_script()),
3544 ('debug_path', "Path to save debug dumps", PARAM, default_debug_path()),
3545 # Client recovery options
3546 ('recover', "Recover a device"),
3547 ('group', "The group of devices to configure or cleanup", PARAM),
3548 ('tgt_uuid', "The failed target (required for recovery)", PARAM),
3549 ('client_uuid', "The failed client (required for recovery)", PARAM),
3550 ('conn_uuid', "The failed connection (required for recovery)", PARAM),
3552 ('inactive', """The name of an inactive service, to be ignored during
3553 mounting (currently OST-only). Can be repeated.""",
3558 global lctl, config, toplustreDB, CONFIG_FILE, mod_manager
3560 # in the upcall this is set to SIG_IGN
3561 signal.signal(signal.SIGCHLD, signal.SIG_DFL)
3563 cl = Lustre.Options("lconf", "config.xml", lconf_options)
3565 config, args = cl.parse(sys.argv[1:])
3566 except Lustre.OptionError, e:
3570 setupModulePath(sys.argv[0])
3572 host = socket.gethostname()
3574 # the PRNG is normally seeded with time(), which is not so good for starting
3575 # time-synchronized clusters
3576 input = open('/dev/urandom', 'r')
3578 print 'Unable to open /dev/urandom!'
3580 seed = input.read(32)
3586 init_select(config.select)
3589 # allow config to be fetched via HTTP, but only with python2
3590 if sys.version[0] != '1' and args[0].startswith('http://'):
3593 config_file = urllib2.urlopen(args[0])
3594 except (urllib2.URLError, socket.error), err:
3595 if hasattr(err, 'args'):
3597 print "Could not access '%s': %s" %(args[0], err)
3599 elif not os.access(args[0], os.R_OK):
3600 print 'File not found or readable:', args[0]
3604 config_file = open(args[0], 'r')
3606 dom = xml.dom.minidom.parse(config_file)
3608 panic("%s does not appear to be a config file." % (args[0]))
3609 sys.exit(1) # make sure to die here, even in debug mode.
3611 CONFIG_FILE = args[0]
3612 lustreDB = Lustre.LustreDB_XML(dom.documentElement, dom.documentElement)
3613 if not config.config:
3614 config.config = os.path.basename(args[0])# use full path?
3615 if config.config[-4:] == '.xml':
3616 config.config = config.config[:-4]
3617 elif config.ldapurl:
3618 if not config.config:
3619 panic("--ldapurl requires --config name")
3620 dn = "config=%s,fs=lustre" % (config.config)
3621 lustreDB = Lustre.LustreDB_LDAP('', {}, base=dn, url = config.ldapurl)
3622 elif config.ptldebug or config.subsystem:
3623 sys_set_ptldebug(None)
3624 sys_set_subsystem(None)
3627 print 'Missing config file or ldap URL.'
3628 print 'see lconf --help for command summary'
3631 toplustreDB = lustreDB
3633 ver = lustreDB.get_version()
3635 panic("No version found in config data, please recreate.")
3636 if ver != Lustre.CONFIG_VERSION:
3637 panic("Config version", ver, "does not match lconf version",
3638 Lustre.CONFIG_VERSION)
3642 node_list.append(config.node)
3645 node_list.append(host)
3646 node_list.append('localhost')
3648 debug("configuring for host: ", node_list)
3651 config.debug_path = config.debug_path + '-' + host
3652 config.gdb_script = config.gdb_script + '-' + host
3654 lctl = LCTLInterface('lctl')
3656 if config.lctl_dump:
3657 lctl.use_save_file(config.lctl_dump)
3660 if not (config.record_device and config.record_log):
3661 panic("When recording, both --record_log and --record_device must be specified.")
3662 lctl.clear_log(config.record_device, config.record_log)
3663 lctl.record(config.record_device, config.record_log)
3665 # init module manager
3666 mod_manager = kmod_manager(config.lustre, config.portals)
3668 doHost(lustreDB, node_list)
3670 if not config.record:
3675 process_updates(lustreDB, config.record_device, config.record_log)
3677 if __name__ == "__main__":
3680 except Lustre.LconfError, e:
3682 # traceback.print_exc(file=sys.stdout)
3684 except CommandError, e:
3688 if first_cleanup_error:
3689 sys.exit(first_cleanup_error)