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),
118 "openibnal" : (1 << 22),
123 first_cleanup_error = 0
124 def cleanup_error(rc):
125 global first_cleanup_error
126 if not first_cleanup_error:
127 first_cleanup_error = rc
129 # ============================================================
130 # debugging and error funcs
132 def fixme(msg = "this feature"):
133 raise Lustre.LconfError, msg + ' not implemented yet.'
136 msg = string.join(map(str,args))
137 if not config.noexec:
138 raise Lustre.LconfError(msg)
143 msg = string.join(map(str,args))
148 print string.strip(s)
152 msg = string.join(map(str,args))
155 # ack, python's builtin int() does not support '0x123' syntax.
156 # eval can do it, although what a hack!
160 return eval(s, {}, {})
163 except SyntaxError, e:
164 raise ValueError("not a number")
166 raise ValueError("not a number")
168 # ============================================================
169 # locally defined exceptions
170 class CommandError (exceptions.Exception):
171 def __init__(self, cmd_name, cmd_err, rc=None):
172 self.cmd_name = cmd_name
173 self.cmd_err = cmd_err
178 if type(self.cmd_err) == types.StringType:
180 print "! %s (%d): %s" % (self.cmd_name, self.rc, self.cmd_err)
182 print "! %s: %s" % (self.cmd_name, self.cmd_err)
183 elif type(self.cmd_err) == types.ListType:
185 print "! %s (error %d):" % (self.cmd_name, self.rc)
187 print "! %s:" % (self.cmd_name)
188 for s in self.cmd_err:
189 print "> %s" %(string.strip(s))
194 # ============================================================
195 # handle daemons, like the acceptor
197 """ Manage starting and stopping a daemon. Assumes daemon manages
198 it's own pid file. """
200 def __init__(self, cmd):
206 log(self.command, "already running.")
208 self.path = find_prog(self.command)
210 panic(self.command, "not found.")
211 ret, out = runcmd(self.path +' '+ self.command_line())
213 raise CommandError(self.path, out, ret)
217 pid = self.read_pidfile()
219 log ("killing process", pid)
221 #time.sleep(1) # let daemon die
223 log("unable to kill", self.command, e)
225 log("unable to kill", self.command)
228 pid = self.read_pidfile()
238 def read_pidfile(self):
240 fp = open(self.pidfile(), 'r')
247 def clean_pidfile(self):
248 """ Remove a stale pidfile """
249 log("removing stale pidfile:", self.pidfile())
251 os.unlink(self.pidfile())
253 log(self.pidfile(), e)
255 class AcceptorHandler(DaemonHandler):
256 def __init__(self, port, net_type):
257 DaemonHandler.__init__(self, "acceptor")
262 return "/var/run/%s-%d.pid" % (self.command, self.port)
264 def command_line(self):
265 return string.join(map(str,(self.flags, self.port)))
269 # start the acceptors
271 if config.lctl_dump or config.record:
273 for port in acceptors.keys():
274 daemon = acceptors[port]
275 if not daemon.running():
278 def run_one_acceptor(port):
279 if config.lctl_dump or config.record:
281 if acceptors.has_key(port):
282 daemon = acceptors[port]
283 if not daemon.running():
286 panic("run_one_acceptor: No acceptor defined for port:", port)
288 def stop_acceptor(port):
289 if acceptors.has_key(port):
290 daemon = acceptors[port]
295 # ============================================================
296 # handle lctl interface
299 Manage communication with lctl
302 def __init__(self, cmd):
304 Initialize close by finding the lctl binary.
306 self.lctl = find_prog(cmd)
308 self.record_device = ''
311 debug('! lctl not found')
314 raise CommandError('lctl', "unable to find lctl binary.")
316 def use_save_file(self, file):
317 self.save_file = file
319 def record(self, dev_name, logname):
320 log("Recording log", logname, "on", dev_name)
321 self.record_device = dev_name
322 self.record_log = logname
324 def end_record(self):
325 log("End recording log", self.record_log, "on", self.record_device)
326 self.record_device = None
327 self.record_log = None
329 def set_nonblock(self, fd):
330 fl = fcntl.fcntl(fd, F_GETFL)
331 fcntl.fcntl(fd, F_SETFL, fl | os.O_NDELAY)
336 the cmds are written to stdin of lctl
337 lctl doesn't return errors when run in script mode, so
339 should modify command line to accept multiple commands, or
340 create complex command line options
344 cmds = '\n dump ' + self.save_file + '\n' + cmds
345 elif self.record_device:
349 %s""" % (self.record_device, self.record_log, cmds)
351 debug("+", cmd_line, cmds)
352 if config.noexec: return (0, [])
354 child = popen2.Popen3(cmd_line, 1) # Capture stdout and stderr from command
355 child.tochild.write(cmds + "\n")
356 child.tochild.close()
357 # print "LCTL:", cmds
359 # From "Python Cookbook" from O'Reilly
360 outfile = child.fromchild
361 outfd = outfile.fileno()
362 self.set_nonblock(outfd)
363 errfile = child.childerr
364 errfd = errfile.fileno()
365 self.set_nonblock(errfd)
367 outdata = errdata = ''
370 ready = select.select([outfd,errfd],[],[]) # Wait for input
371 if outfd in ready[0]:
372 outchunk = outfile.read()
373 if outchunk == '': outeof = 1
374 outdata = outdata + outchunk
375 if errfd in ready[0]:
376 errchunk = errfile.read()
377 if errchunk == '': erreof = 1
378 errdata = errdata + errchunk
379 if outeof and erreof: break
380 # end of "borrowed" code
383 if os.WIFEXITED(ret):
384 rc = os.WEXITSTATUS(ret)
387 if rc or len(errdata):
388 raise CommandError(self.lctl, errdata, rc)
391 def runcmd(self, *args):
393 run lctl using the command line
395 cmd = string.join(map(str,args))
396 debug("+", self.lctl, cmd)
397 rc, out = run(self.lctl, cmd)
399 raise CommandError(self.lctl, out, rc)
403 def clear_log(self, dev, log):
404 """ clear an existing log """
409 quit """ % (dev, log)
412 def network(self, net, nid):
417 quit """ % (net, nid)
420 def root_squash(self, name, uid, nid):
424 quit""" % (name, uid, nid)
427 # create a new connection
428 def add_uuid(self, net_type, uuid, nid):
429 cmds = "\n add_uuid %s %s %s" %(uuid, nid, net_type)
432 def add_peer(self, net_type, nid, hostaddr, port):
433 if net_type in ('tcp',) and not config.lctl_dump:
438 nid, hostaddr, port )
440 elif net_type in ('openib',) and not config.lctl_dump:
448 def connect(self, srv):
449 self.add_uuid(srv.net_type, srv.nid_uuid, srv.nid)
450 if srv.net_type in ('tcp','openib',) and not config.lctl_dump:
451 self.add_peer(srv.net_type, srv.nid, srv.hostaddr, srv.port)
454 def recover(self, dev_name, new_conn):
457 recover %s""" %(dev_name, new_conn)
460 # add a route to a range
461 def add_route(self, net, gw, lo, hi):
469 except CommandError, e:
473 def del_route(self, net, gw, lo, hi):
478 quit """ % (net, gw, lo, hi)
481 # add a route to a host
482 def add_route_host(self, net, uuid, gw, tgt):
483 self.add_uuid(net, uuid, tgt)
491 except CommandError, e:
495 # add a route to a range
496 def del_route_host(self, net, uuid, gw, tgt):
502 quit """ % (net, gw, tgt)
505 def del_peer(self, net_type, nid, hostaddr):
506 if net_type in ('tcp',) and not config.lctl_dump:
510 del_peer %s %s single_share
514 elif net_type in ('openib',) and not config.lctl_dump:
518 del_peer %s single_share
523 # disconnect one connection
524 def disconnect(self, srv):
525 self.del_uuid(srv.nid_uuid)
526 if srv.net_type in ('tcp','openib',) and not config.lctl_dump:
527 self.del_peer(srv.net_type, srv.nid, srv.hostaddr)
529 def del_uuid(self, uuid):
537 def disconnectAll(self, net):
545 def attach(self, type, name, uuid):
548 quit""" % (type, name, uuid)
551 def setup(self, name, setup = ""):
555 quit""" % (name, setup)
558 def add_conn(self, name, conn_uuid):
562 quit""" % (name, conn_uuid)
566 # create a new device with lctl
567 def newdev(self, type, name, uuid, setup = ""):
568 self.attach(type, name, uuid);
570 self.setup(name, setup)
571 except CommandError, e:
572 self.cleanup(name, uuid, 0)
577 def cleanup(self, name, uuid, force, failover = 0):
578 if failover: force = 1
584 quit""" % (name, ('', 'force')[force],
585 ('', 'failover')[failover])
589 def lov_setup(self, name, uuid, desc_uuid, stripe_cnt,
590 stripe_sz, stripe_off, pattern, devlist = None):
593 lov_setup %s %d %d %d %s %s
594 quit""" % (name, uuid, desc_uuid, stripe_cnt, stripe_sz, stripe_off,
598 # add an OBD to a LOV
599 def lov_add_obd(self, name, uuid, obd_uuid, index, gen):
601 lov_modify_tgts add %s %s %s %s
602 quit""" % (name, obd_uuid, index, gen)
606 def lmv_setup(self, name, uuid, desc_uuid, devlist):
610 quit""" % (name, uuid, desc_uuid, devlist)
613 # delete an OBD from a LOV
614 def lov_del_obd(self, name, uuid, obd_uuid, index, gen):
616 lov_modify_tgts del %s %s %s %s
617 quit""" % (name, obd_uuid, index, gen)
621 def deactivate(self, name):
629 def dump(self, dump_file):
632 quit""" % (dump_file)
635 # get list of devices
636 def device_list(self):
637 devices = '/proc/fs/lustre/devices'
639 if os.access(devices, os.R_OK):
641 fp = open(devices, 'r')
649 def lustre_version(self):
650 rc, out = self.runcmd('version')
654 def mount_option(self, profile, osc, mdc):
656 mount_option %s %s %s
657 quit""" % (profile, osc, mdc)
660 # delete mount options
661 def del_mount_option(self, profile):
667 def set_timeout(self, timeout):
673 def set_lustre_upcall(self, upcall):
678 # ============================================================
679 # Various system-level functions
680 # (ideally moved to their own module)
682 # Run a command and return the output and status.
683 # stderr is sent to /dev/null, could use popen3 to
684 # save it if necessary
687 if config.noexec: return (0, [])
688 f = os.popen(cmd + ' 2>&1')
698 cmd = string.join(map(str,args))
701 # Run a command in the background.
702 def run_daemon(*args):
703 cmd = string.join(map(str,args))
705 if config.noexec: return 0
706 f = os.popen(cmd + ' 2>&1')
714 # Determine full path to use for an external command
715 # searches dirname(argv[0]) first, then PATH
717 syspath = string.split(os.environ['PATH'], ':')
718 cmdpath = os.path.dirname(sys.argv[0])
719 syspath.insert(0, cmdpath);
721 syspath.insert(0, os.path.join(config.portals, 'utils/'))
723 prog = os.path.join(d,cmd)
724 if os.access(prog, os.X_OK):
728 # Recursively look for file starting at base dir
729 def do_find_file(base, mod):
730 fullname = os.path.join(base, mod)
731 if os.access(fullname, os.R_OK):
733 for d in os.listdir(base):
734 dir = os.path.join(base,d)
735 if os.path.isdir(dir):
736 module = do_find_file(dir, mod)
740 def find_module(src_dir, dev_dir, modname):
741 modbase = src_dir +'/'+ dev_dir +'/'+ modname
742 for modext in '.ko', '.o':
743 module = modbase + modext
745 if os.access(module, os.R_OK):
751 # is the path a block device?
758 return stat.S_ISBLK(s[stat.ST_MODE])
760 # find the journal device from mkfs options
766 while i < len(x) - 1:
767 if x[i] == '-J' and x[i+1].startswith('device='):
775 # build fs according to type
777 def mkfs(dev, devsize, fstype, jsize, isize, mkfsoptions, isblock=1):
783 panic("size of filesystem on '%s' must be larger than 8MB, but is set to %s"%
785 # devsize is in 1k, and fs block count is in 4k
786 block_cnt = devsize/4
788 if fstype in ('ext3', 'extN', 'ldiskfs'):
789 # ext3 journal size is in megabytes
790 # but don't set jsize if mkfsoptions indicates a separate journal device
791 if jsize == 0 and jdev(mkfsoptions) == '':
793 if not is_block(dev):
794 ret, out = runcmd("ls -l %s" %dev)
795 devsize = int(string.split(out[0])[4]) / 1024
797 # sfdisk works for symlink, hardlink, and realdev
798 ret, out = runcmd("sfdisk -s %s" %dev)
800 devsize = int(out[0])
802 # sfdisk -s will fail for too large block device,
803 # then, read the size of partition from /proc/partitions
805 # get the realpath of the device
806 # it may be the real device, such as /dev/hda7
807 # or the hardlink created via mknod for a device
808 if 'realpath' in dir(os.path):
809 real_dev = os.path.realpath(dev)
813 while os.path.islink(real_dev) and (link_count < 20):
814 link_count = link_count + 1
815 dev_link = os.readlink(real_dev)
816 if os.path.isabs(dev_link):
819 real_dev = os.path.join(os.path.dirname(real_dev), dev_link)
821 panic("Entountered too many symbolic links resolving block device:", dev)
823 # get the major and minor number of the realpath via ls
824 # it seems python(os.stat) does not return
825 # the st_rdev member of the stat structure
826 ret, out = runcmd("ls -l %s" %real_dev)
827 major = string.split(string.split(out[0])[4], ",")[0]
828 minor = string.split(out[0])[5]
830 # get the devsize from /proc/partitions with the major and minor number
831 ret, out = runcmd("cat /proc/partitions")
834 if string.split(line)[0] == major and string.split(line)[1] == minor:
835 devsize = int(string.split(line)[2])
838 if devsize > 1024 * 1024:
839 jsize = ((devsize / 102400) * 4)
842 if jsize: jopt = "-J size=%d" %(jsize,)
843 if isize: iopt = "-I %d" %(isize,)
844 mkfs = 'mkfs.ext2 -j -b 4096 '
845 if not isblock or config.force:
847 if jdev(mkfsoptions) != '':
848 jmkfs = 'mkfs.ext2 -b 4096 -O journal_dev '
850 jmkfs = jmkfs + '-F '
851 jmkfs = jmkfs + jdev(mkfsoptions)
852 (ret, out) = run (jmkfs)
854 panic("Unable format journal device:", jdev(mkfsoptions), string.join(out))
856 elif fstype == 'reiserfs':
857 # reiserfs journal size is in blocks
858 if jsize: jopt = "--journal_size %d" %(jsize,)
859 mkfs = 'mkreiserfs -ff'
861 panic('unsupported fs type: ', fstype)
863 if config.mkfsoptions != None:
864 mkfs = mkfs + ' ' + config.mkfsoptions
865 if mkfsoptions != None:
866 mkfs = mkfs + ' ' + mkfsoptions
867 (ret, out) = run (mkfs, jopt, iopt, dev, block_cnt)
869 panic("Unable to build fs:", dev, string.join(out))
870 # enable hash tree indexing on fsswe
871 if fstype in ('ext3', 'extN', 'ldiskfs'):
872 htree = 'echo "feature FEATURE_C5" | debugfs -w'
873 (ret, out) = run (htree, dev)
875 panic("Unable to enable htree:", dev)
877 # some systems use /dev/loopN, some /dev/loop/N
881 if not os.access(loop + str(0), os.R_OK):
883 if not os.access(loop + str(0), os.R_OK):
884 panic ("can't access loop devices")
887 # find loop device assigned to the file
888 def find_assigned_loop(file):
890 for n in xrange(0, MAX_LOOP_DEVICES):
892 if os.access(dev, os.R_OK):
893 (stat, out) = run('losetup', dev)
894 if out and stat == 0:
895 m = re.search(r'\((.*)\)', out[0])
896 if m and file == m.group(1):
902 # create file if necessary and assign the first free loop device
903 def init_loop(file, size, fstype, journal_size, inode_size,
904 mkfsoptions, reformat, autoformat, backfstype, backfile):
907 realfstype = backfstype
908 if is_block(backfile):
909 if reformat or (need_format(realfstype, backfile) and autoformat == 'yes'):
910 mkfs(realfile, size, realfstype, journal_size, inode_size, mkfsoptions, isblock=0)
916 dev = find_assigned_loop(realfile)
918 print 'WARNING file:', realfile, 'already mapped to', dev
921 if reformat or not os.access(realfile, os.R_OK | os.W_OK):
923 panic("size of loopback file '%s' must be larger than 8MB, but is set to %s" % (realfile, size))
924 (ret, out) = run("dd if=/dev/zero bs=1k count=0 seek=%d of=%s" %(size, realfile))
926 panic("Unable to create backing store:", realfile)
928 mkfs(realfile, size, realfstype, journal_size, inode_size,
929 mkfsoptions, isblock=0)
932 # find next free loop
933 for n in xrange(0, MAX_LOOP_DEVICES):
935 if os.access(dev, os.R_OK):
936 (stat, out) = run('losetup', dev)
938 run('losetup', dev, realfile)
941 print "out of loop devices"
943 print "out of loop devices"
946 # undo loop assignment
947 def clean_loop(file):
948 dev = find_assigned_loop(file)
950 ret, out = run('losetup -d', dev)
952 log('unable to clean loop device:', dev, 'for file:', file)
955 # determine if dev is formatted as a <fstype> filesystem
956 def need_format(fstype, dev):
957 # FIXME don't know how to implement this
960 # initialize a block device if needed
961 def block_dev(dev, size, fstype, reformat, autoformat, journal_size,
962 inode_size, mkfsoptions, backfstype, backdev):
966 if fstype == 'smfs' or not is_block(dev):
967 dev = init_loop(dev, size, fstype, journal_size, inode_size,
968 mkfsoptions, reformat, autoformat, backfstype, backdev)
969 elif reformat or (need_format(fstype, dev) and autoformat == 'yes'):
970 mkfs(dev, size, fstype, journal_size, inode_size, mkfsoptions,
973 # panic("device:", dev,
974 # "not prepared, and autoformat is not set.\n",
975 # "Rerun with --reformat option to format ALL filesystems")
980 """lookup IP address for an interface"""
981 rc, out = run("/sbin/ifconfig", iface)
984 addr = string.split(out[1])[1]
985 ip = string.split(addr, ':')[1]
988 def def_mount_options(fstype, target):
989 """returns deafult mount options for passed fstype and target (mds, ost)"""
990 if fstype == 'ext3' or fstype == 'ldiskfs':
991 mountfsoptions = "errors=remount-ro"
992 if target == 'ost' and sys_get_branch() == '2.4':
993 mountfsoptions = "%s,asyncdel" % (mountfsoptions)
994 return mountfsoptions
997 def sys_get_elan_position_file():
998 procfiles = ["/proc/elan/device0/position",
999 "/proc/qsnet/elan4/device0/position",
1000 "/proc/qsnet/elan3/device0/position"]
1002 if os.access(p, os.R_OK):
1006 def sys_get_local_nid(net_type, wildcard, cluster_id):
1007 """Return the local nid."""
1009 if sys_get_elan_position_file():
1010 local = sys_get_local_address('elan', '*', cluster_id)
1012 local = sys_get_local_address(net_type, wildcard, cluster_id)
1015 def sys_get_local_address(net_type, wildcard, cluster_id):
1016 """Return the local address for the network type."""
1018 if net_type in ('tcp','openib',):
1020 iface, star = string.split(wildcard, ':')
1021 local = if2addr(iface)
1023 panic ("unable to determine ip for:", wildcard)
1025 host = socket.gethostname()
1026 local = socket.gethostbyname(host)
1027 elif net_type == 'elan':
1028 # awk '/NodeId/ { print $2 }' 'sys_get_elan_position_file()'
1029 f = sys_get_elan_position_file()
1031 panic ("unable to determine local Elan ID")
1034 lines = fp.readlines()
1038 if a[0] == 'NodeId':
1042 nid = my_int(cluster_id) + my_int(elan_id)
1043 local = "%d" % (nid)
1044 except ValueError, e:
1048 elif net_type == 'gm':
1049 fixme("automatic local address for GM")
1053 def sys_get_branch():
1054 """Returns kernel release"""
1056 fp = open('/proc/sys/kernel/osrelease')
1057 lines = fp.readlines()
1061 version = string.split(l)
1062 a = string.split(version[0], '.')
1063 return a[0] + '.' + a[1]
1069 def mod_loaded(modname):
1070 """Check if a module is already loaded. Look in /proc/modules for it."""
1072 fp = open('/proc/modules')
1073 lines = fp.readlines()
1075 # please forgive my tired fingers for this one
1076 ret = filter(lambda word, mod=modname: word == mod,
1077 map(lambda line: string.split(line)[0], lines))
1079 except Exception, e:
1082 # XXX: instead of device_list, ask for $name and see what we get
1083 def is_prepared(name):
1084 """Return true if a device exists for the name"""
1085 if config.lctl_dump:
1087 if (config.noexec or config.record) and config.cleanup:
1090 # expect this format:
1091 # 1 UP ldlm ldlm ldlm_UUID 2
1092 out = lctl.device_list()
1094 if name == string.split(s)[3]:
1096 except CommandError, e:
1100 def is_network_prepared():
1101 """If the any device exists, then assume that all networking
1102 has been configured"""
1103 out = lctl.device_list()
1106 def fs_is_mounted(path):
1107 """Return true if path is a mounted lustre filesystem"""
1109 fp = open('/proc/mounts')
1110 lines = fp.readlines()
1114 if a[1] == path and a[2] == 'lustre_lite':
1122 """Manage kernel modules"""
1123 def __init__(self, lustre_dir, portals_dir):
1124 self.lustre_dir = lustre_dir
1125 self.portals_dir = portals_dir
1126 self.kmodule_list = []
1128 def add_portals_module(self, dev_dir, modname):
1129 """Append a module to list of modules to load."""
1130 self.kmodule_list.append((self.portals_dir, dev_dir, modname))
1132 def add_lustre_module(self, dev_dir, modname):
1133 """Append a module to list of modules to load."""
1134 self.kmodule_list.append((self.lustre_dir, dev_dir, modname))
1136 def load_module(self):
1137 """Load all the modules in the list in the order they appear."""
1138 for src_dir, dev_dir, mod in self.kmodule_list:
1139 if mod_loaded(mod) and not config.noexec:
1141 log ('loading module:', mod, 'srcdir', src_dir, 'devdir', dev_dir)
1143 module = find_module(src_dir, dev_dir, mod)
1145 panic('module not found:', mod)
1146 (rc, out) = run('/sbin/insmod', module)
1148 raise CommandError('insmod', out, rc)
1150 (rc, out) = run('/sbin/modprobe', mod)
1152 raise CommandError('modprobe', out, rc)
1154 def cleanup_module(self):
1155 """Unload the modules in the list in reverse order."""
1156 rev = self.kmodule_list
1158 for src_dir, dev_dir, mod in rev:
1159 if not mod_loaded(mod) and not config.noexec:
1162 if mod == 'portals' and config.dump:
1163 lctl.dump(config.dump)
1164 log('unloading module:', mod)
1165 (rc, out) = run('/sbin/rmmod', mod)
1167 log('! unable to unload module:', mod)
1170 # ============================================================
1171 # Classes to prepare and cleanup the various objects
1174 """ Base class for the rest of the modules. The default cleanup method is
1175 defined here, as well as some utilitiy funcs.
1177 def __init__(self, module_name, db):
1179 self.module_name = module_name
1180 self.name = self.db.getName()
1181 self.uuid = self.db.getUUID()
1184 self.kmod = kmod(config.lustre, config.portals)
1186 def info(self, *args):
1187 msg = string.join(map(str,args))
1188 print self.module_name + ":", self.name, self.uuid, msg
1191 """ default cleanup, used for most modules """
1194 lctl.cleanup(self.name, self.uuid, config.force)
1195 except CommandError, e:
1196 log(self.module_name, "cleanup failed: ", self.name)
1200 def add_portals_module(self, dev_dir, modname):
1201 """Append a module to list of modules to load."""
1202 self.kmod.add_portals_module(dev_dir, modname)
1204 def add_lustre_module(self, dev_dir, modname):
1205 """Append a module to list of modules to load."""
1206 self.kmod.add_lustre_module(dev_dir, modname)
1208 def load_module(self):
1209 """Load all the modules in the list in the order they appear."""
1210 self.kmod.load_module()
1212 def cleanup_module(self):
1213 """Unload the modules in the list in reverse order."""
1214 if self.safe_to_clean():
1215 self.kmod.cleanup_module()
1217 def safe_to_clean(self):
1220 def safe_to_clean_modules(self):
1221 return self.safe_to_clean()
1223 class Network(Module):
1224 def __init__(self,db):
1225 Module.__init__(self, 'NETWORK', db)
1226 self.net_type = self.db.get_val('nettype')
1227 self.nid = self.db.get_val('nid', '*')
1228 self.cluster_id = self.db.get_val('clusterid', "0")
1229 self.port = self.db.get_val_int('port', 0)
1232 self.nid = sys_get_local_nid(self.net_type, self.nid, self.cluster_id)
1234 panic("unable to set nid for", self.net_type, self.nid, cluster_id)
1235 self.generic_nid = 1
1236 debug("nid:", self.nid)
1238 self.generic_nid = 0
1240 self.nid_uuid = self.nid_to_uuid(self.nid)
1242 self.hostaddr = self.db.get_val('hostaddr', self.nid)
1243 if '*' in self.hostaddr:
1244 self.hostaddr = sys_get_local_address(self.net_type, self.hostaddr, self.cluster_id)
1245 if not self.hostaddr:
1246 panic("unable to set hostaddr for", self.net_type, self.hostaddr, self.cluster_id)
1247 debug("hostaddr:", self.hostaddr)
1249 self.add_portals_module("libcfs", 'libcfs')
1250 self.add_portals_module("portals", 'portals')
1251 if node_needs_router():
1252 self.add_portals_module("router", 'kptlrouter')
1253 if self.net_type == 'tcp':
1254 self.add_portals_module("knals/socknal", 'ksocknal')
1255 if self.net_type == 'elan':
1256 self.add_portals_module("knals/qswnal", 'kqswnal')
1257 if self.net_type == 'gm':
1258 self.add_portals_module("knals/gmnal", 'kgmnal')
1259 if self.net_type == 'openib':
1260 self.add_portals_module("knals/openibnal", 'kopenibnal')
1262 def nid_to_uuid(self, nid):
1263 return "NID_%s_UUID" %(nid,)
1266 if not config.record and is_network_prepared():
1268 self.info(self.net_type, self.nid, self.port)
1269 if not (config.record and self.generic_nid):
1270 lctl.network(self.net_type, self.nid)
1271 if self.net_type == 'tcp':
1273 if self.net_type == 'elan':
1275 if self.port and node_is_router():
1276 run_one_acceptor(self.port)
1277 self.connect_peer_gateways()
1279 def connect_peer_gateways(self):
1280 for router in self.db.lookup_class('node'):
1281 if router.get_val_int('router', 0):
1282 for netuuid in router.get_networks():
1283 net = self.db.lookup(netuuid)
1285 if (gw.cluster_id == self.cluster_id and
1286 gw.net_type == self.net_type):
1287 if gw.nid != self.nid:
1290 def disconnect_peer_gateways(self):
1291 for router in self.db.lookup_class('node'):
1292 if router.get_val_int('router', 0):
1293 for netuuid in router.get_networks():
1294 net = self.db.lookup(netuuid)
1296 if (gw.cluster_id == self.cluster_id and
1297 gw.net_type == self.net_type):
1298 if gw.nid != self.nid:
1301 except CommandError, e:
1302 print "disconnect failed: ", self.name
1306 def safe_to_clean(self):
1307 return not is_network_prepared()
1310 self.info(self.net_type, self.nid, self.port)
1312 stop_acceptor(self.port)
1313 if node_is_router():
1314 self.disconnect_peer_gateways()
1316 def correct_level(self, level, op=None):
1319 class RouteTable(Module):
1320 def __init__(self,db):
1321 Module.__init__(self, 'ROUTES', db)
1323 def server_for_route(self, net_type, gw, gw_cluster_id, tgt_cluster_id,
1325 # only setup connections for tcp and openib NALs
1328 if not net_type in ('tcp','openib'):
1331 # connect to target if route is to single node and this node is the gw
1332 if lo == hi and local_interface(net_type, gw_cluster_id, gw):
1333 if not local_cluster(net_type, tgt_cluster_id):
1334 panic("target", lo, " not on the local cluster")
1335 srvdb = self.db.nid2server(lo, net_type, gw_cluster_id)
1336 # connect to gateway if this node is not the gw
1337 elif (local_cluster(net_type, gw_cluster_id)
1338 and not local_interface(net_type, gw_cluster_id, gw)):
1339 srvdb = self.db.nid2server(gw, net_type, gw_cluster_id)
1344 panic("no server for nid", lo)
1347 return Network(srvdb)
1350 if not config.record and is_network_prepared():
1353 for net_type, gw, gw_cluster_id, tgt_cluster_id, lo, hi in self.db.get_route_tbl():
1354 lctl.add_route(net_type, gw, lo, hi)
1355 srv = self.server_for_route(net_type, gw, gw_cluster_id, tgt_cluster_id, lo, hi)
1359 def safe_to_clean(self):
1360 return not is_network_prepared()
1363 if is_network_prepared():
1364 # the network is still being used, don't clean it up
1366 for net_type, gw, gw_cluster_id, tgt_cluster_id, lo, hi in self.db.get_route_tbl():
1367 srv = self.server_for_route(net_type, gw, gw_cluster_id, tgt_cluster_id, lo, hi)
1370 lctl.disconnect(srv)
1371 except CommandError, e:
1372 print "disconnect failed: ", self.name
1377 lctl.del_route(net_type, gw, lo, hi)
1378 except CommandError, e:
1379 print "del_route failed: ", self.name
1383 # This is only needed to load the modules; the LDLM device
1384 # is now created automatically.
1386 def __init__(self,db):
1387 Module.__init__(self, 'LDLM', db)
1388 self.add_lustre_module('lvfs', 'lvfs')
1389 self.add_lustre_module('obdclass', 'obdclass')
1390 self.add_lustre_module('ptlrpc', 'ptlrpc')
1398 def correct_level(self, level, op=None):
1403 def __init__(self, db, uuid, fs_name, name_override = None, config_only = None):
1404 Module.__init__(self, 'LOV', db)
1405 if name_override != None:
1406 self.name = "lov_%s" % name_override
1407 self.add_lustre_module('lov', 'lov')
1408 self.mds_uuid = self.db.get_first_ref('mds')
1409 self.stripe_sz = self.db.get_val_int('stripesize', 1048576)
1410 self.stripe_off = self.db.get_val_int('stripeoffset', 0)
1411 self.pattern = self.db.get_val_int('stripepattern', 0)
1412 self.devlist = self.db.get_lov_tgts('lov_tgt')
1413 self.stripe_cnt = self.db.get_val_int('stripecount', len(self.devlist))
1416 self.desc_uuid = self.uuid
1417 self.uuid = generate_client_uuid(self.name)
1418 self.fs_name = fs_name
1420 self.config_only = 1
1422 self.config_only = None
1423 mds = self.db.lookup(self.mds_uuid)
1424 self.mds_name = mds.getName()
1425 for (obd_uuid, index, gen, active) in self.devlist:
1428 self.obdlist.append(obd_uuid)
1429 obd = self.db.lookup(obd_uuid)
1430 osc = get_osc(obd, self.uuid, fs_name)
1432 self.osclist.append((osc, index, gen, active))
1434 panic('osc not found:', obd_uuid)
1440 if not config.record and is_prepared(self.name):
1442 self.info(self.mds_uuid, self.stripe_cnt, self.stripe_sz,
1443 self.stripe_off, self.pattern, self.devlist,
1445 lctl.lov_setup(self.name, self.uuid, self.desc_uuid, self.stripe_cnt,
1446 self.stripe_sz, self.stripe_off, self.pattern,
1447 string.join(self.obdlist))
1448 for (osc, index, gen, active) in self.osclist:
1449 target_uuid = osc.target_uuid
1451 # Only ignore connect failures with --force, which
1452 # isn't implemented here yet.
1454 osc.prepare(ignore_connect_failure=0)
1455 except CommandError, e:
1456 print "Error preparing OSC %s\n" % osc.uuid
1458 lctl.lov_add_obd(self.name, self.uuid, target_uuid, index, gen)
1461 for (osc, index, gen, active) in self.osclist:
1462 target_uuid = osc.target_uuid
1464 if is_prepared(self.name):
1465 Module.cleanup(self)
1466 if self.config_only:
1467 panic("Can't clean up config_only LOV ", self.name)
1469 def load_module(self):
1470 if self.config_only:
1471 panic("Can't load modules for config_only LOV ", self.name)
1472 for (osc, index, gen, active) in self.osclist:
1475 Module.load_module(self)
1477 def cleanup_module(self):
1478 if self.config_only:
1479 panic("Can't cleanup modules for config_only LOV ", self.name)
1480 Module.cleanup_module(self)
1481 for (osc, index, gen, active) in self.osclist:
1483 osc.cleanup_module()
1486 def correct_level(self, level, op=None):
1490 def __init__(self, db, uuid, fs_name, name_override = None):
1491 Module.__init__(self, 'LMV', db)
1492 if name_override != None:
1493 self.name = "lmv_%s" % name_override
1494 self.add_lustre_module('lmv', 'lmv')
1495 self.devlist = self.db.get_refs('mds')
1497 self.desc_uuid = self.uuid
1499 self.fs_name = fs_name
1500 for mds_uuid in self.devlist:
1501 mds = self.db.lookup(mds_uuid)
1503 panic("MDS not found!")
1504 mdc = MDC(mds, self.uuid, fs_name)
1506 self.mdclist.append(mdc)
1508 panic('mdc not found:', mds_uuid)
1511 if is_prepared(self.name):
1513 for mdc in self.mdclist:
1515 # Only ignore connect failures with --force, which
1516 # isn't implemented here yet.
1517 mdc.prepare(ignore_connect_failure=0)
1518 except CommandError, e:
1519 print "Error preparing LMV %s\n" % mdc.uuid
1521 lctl.lmv_setup(self.name, self.uuid, self.desc_uuid,
1522 string.join(self.devlist))
1525 for mdc in self.mdclist:
1527 if is_prepared(self.name):
1528 Module.cleanup(self)
1530 def load_module(self):
1531 for mdc in self.mdclist:
1534 Module.load_module(self)
1536 def cleanup_module(self):
1537 Module.cleanup_module(self)
1538 for mdc in self.mdclist:
1539 mdc.cleanup_module()
1542 def correct_level(self, level, op=None):
1545 class MDSDEV(Module):
1546 def __init__(self,db):
1547 Module.__init__(self, 'MDSDEV', db)
1548 self.devpath = self.db.get_val('devpath','')
1549 self.backdevpath = self.db.get_val('backdevpath','')
1550 self.size = self.db.get_val_int('devsize', 0)
1551 self.journal_size = self.db.get_val_int('journalsize', 0)
1552 self.fstype = self.db.get_val('fstype', '')
1553 self.backfstype = self.db.get_val('backfstype', '')
1554 self.nspath = self.db.get_val('nspath', '')
1555 self.mkfsoptions = self.db.get_val('mkfsoptions', '')
1556 self.mountfsoptions = self.db.get_val('mountfsoptions', '')
1557 self.root_squash = self.db.get_val('root_squash', '')
1558 self.no_root_squash = self.db.get_val('no_root_squash', '')
1559 self.cachetype = self.db.get_val('cachetype', '')
1560 # overwrite the orignal MDSDEV name and uuid with the MDS name and uuid
1561 target_uuid = self.db.get_first_ref('target')
1562 mds = self.db.lookup(target_uuid)
1563 self.name = mds.getName()
1564 self.filesystem_uuids = mds.get_refs('filesystem')
1567 self.master_mds = ""
1568 if not self.filesystem_uuids:
1569 self.lmv_uuid = self.db.get_first_ref('lmv')
1570 if not self.lmv_uuid:
1571 panic("ALERT: can't find lvm uuid")
1573 self.lmv = self.db.lookup(self.lmv_uuid)
1575 self.filesystem_uuids = self.lmv.get_refs('filesystem')
1576 self.master_mds = self.lmv_uuid
1577 # FIXME: if fstype not set, then determine based on kernel version
1578 self.format = self.db.get_val('autoformat', "no")
1579 if mds.get_val('failover', 0):
1580 self.failover_mds = 'f'
1582 self.failover_mds = 'n'
1583 active_uuid = get_active_target(mds)
1585 panic("No target device found:", target_uuid)
1586 if active_uuid == self.uuid:
1590 if self.active and config.group and config.group != mds.get_val('group'):
1593 self.inode_size = self.db.get_val_int('inodesize', 0)
1594 if self.inode_size == 0:
1595 # find the LOV for this MDS
1596 lovconfig_uuid = mds.get_first_ref('lovconfig')
1597 if not lovconfig_uuid:
1598 if not self.lmv_uuid:
1599 panic("No LOV found for lovconfig ", lovconfig.name)
1602 panic("No LMV initialized and not lovconfig_uuid found")
1604 lovconfig_uuid = self.lmv.get_first_ref('lovconfig')
1605 lovconfig = self.lmv.lookup(lovconfig_uuid)
1606 lov_uuid = lovconfig.get_first_ref('lov')
1608 panic("No LOV found for lovconfig ", lovconfig.name)
1610 lovconfig = mds.lookup(lovconfig_uuid)
1611 lov_uuid = lovconfig.get_first_ref('lov')
1613 panic("No LOV found for lovconfig ", lovconfig.name)
1616 lovconfig_uuid = self.lmv.get_first_ref('lovconfig')
1617 lovconfig = self.lmv.lookup(lovconfig_uuid)
1618 lov_uuid = lovconfig.get_first_ref('lov')
1620 lov = LOV(self.db.lookup(lov_uuid), lov_uuid, 'FS_name', config_only = 1)
1622 # default stripe count controls default inode_size
1623 if (lov.stripe_cnt > 0):
1624 stripe_count = lov.stripe_cnt
1626 stripe_count = len(lov.devlist)
1628 if stripe_count > 77:
1629 self.inode_size = 4096
1630 elif stripe_count > 35:
1631 self.inode_size = 2048
1632 elif stripe_count > 13:
1633 self.inode_size = 1024
1634 elif stripe_count > 3:
1635 self.inode_size = 512
1637 self.inode_size = 256
1639 self.target_dev_uuid = self.uuid
1640 self.uuid = target_uuid
1643 client_uuid = generate_client_uuid(self.name)
1644 client_uuid = self.name + "_lmv_" + "UUID"
1645 self.master = LMV(self.db.lookup(self.lmv_uuid), client_uuid, self.name, self.name)
1646 self.master_mds = self.master.name
1649 self.add_lustre_module('mdc', 'mdc')
1650 self.add_lustre_module('osc', 'osc')
1651 self.add_lustre_module('lov', 'lov')
1652 self.add_lustre_module('lmv', 'lmv')
1653 self.add_lustre_module('ost', 'ost')
1654 self.add_lustre_module('mds', 'mds')
1656 if self.fstype == 'smfs':
1657 self.add_lustre_module('smfs', 'smfs')
1659 if self.fstype == 'ldiskfs':
1660 self.add_lustre_module('ldiskfs', 'ldiskfs')
1663 self.add_lustre_module('lvfs', 'fsfilt_%s' % (self.fstype))
1665 # if fstype is smfs, then we should also take care about backing
1667 if self.fstype == 'smfs':
1668 self.add_lustre_module('lvfs', 'fsfilt_%s' % (self.backfstype))
1670 for options in string.split(self.mountfsoptions, ','):
1671 if options == 'snap':
1672 if not self.fstype == 'smfs':
1673 panic("mountoptions with snap, but fstype is not smfs\n")
1674 self.add_lustre_module('lvfs', 'fsfilt_snap_%s' % (self.fstype))
1675 self.add_lustre_module('lvfs', 'fsfilt_snap_%s' % (self.backfstype))
1676 def load_module(self):
1678 Module.load_module(self)
1681 if not config.record and is_prepared(self.name):
1684 debug(self.uuid, "not active")
1687 # run write_conf automatically, if --reformat used
1689 self.info(self.devpath, self.fstype, self.size, self.format)
1693 self.master.prepare()
1694 # never reformat here
1695 blkdev = block_dev(self.devpath, self.size, self.fstype, 0,
1696 self.format, self.journal_size, self.inode_size,
1697 self.mkfsoptions, self.backfstype, self.backdevpath)
1699 if not is_prepared('MDT'):
1700 lctl.newdev("mdt", 'MDT', 'MDT_UUID', setup ="")
1702 mountfsoptions = def_mount_options(self.fstype, 'mds')
1704 if config.mountfsoptions:
1706 mountfsoptions = mountfsoptions + ',' + config.mountfsoptions
1708 mountfsoptions = config.mountfsoptions
1709 if self.mountfsoptions:
1710 mountfsoptions = mountfsoptions + ',' + self.mountfsoptions
1712 if self.mountfsoptions:
1714 mountfsoptions = mountfsoptions + ',' + self.mountfsoptions
1716 mountfsoptions = self.mountfsoptions
1718 if self.fstype == 'smfs':
1719 realdev = self.fstype
1722 mountfsoptions = "%s,type=%s,dev=%s" % (mountfsoptions,
1726 mountfsoptions = "type=%s,dev=%s" % (self.backfstype,
1731 print 'MDS mount options: ' + mountfsoptions
1733 if not self.master_mds:
1734 self.master_mds = 'dumb'
1735 if not self.cachetype:
1736 self.cachetype = 'dumb'
1737 lctl.newdev("mds", self.name, self.uuid,
1738 setup ="%s %s %s %s %s %s" %(realdev, self.fstype,
1739 self.name, mountfsoptions,
1740 self.master_mds, self.cachetype))
1742 if development_mode():
1743 procentry = "/proc/fs/lustre/mds/grp_hash_upcall"
1744 upcall = os.path.abspath(os.path.dirname(sys.argv[0]) + "/l_getgroups")
1745 if not (os.access(procentry, os.R_OK) and os.access(upcall, os.R_OK)):
1746 print "MDS Warning: failed to set group-hash upcall"
1748 run("echo ", upcall, " > ", procentry)
1750 except CommandError, e:
1752 panic("MDS is missing the config log. Need to run " +
1753 "lconf --write_conf.")
1757 if config.root_squash == None:
1758 config.root_squash = self.root_squash
1759 if config.no_root_squash == None:
1760 config.no_root_squash = self.no_root_squash
1761 if config.root_squash:
1762 if config.no_root_squash:
1763 nsnid = config.no_root_squash
1766 lctl.root_squash(self.name, config.root_squash, nsnid)
1768 def write_conf(self):
1770 if not is_prepared(self.name):
1771 self.info(self.devpath, self.fstype, self.format)
1773 blkdev = block_dev(self.devpath, self.size, self.fstype,
1774 config.reformat, self.format, self.journal_size,
1775 self.inode_size, self.mkfsoptions,
1776 self.backfstype, self.backdevpath)
1778 # Even for writing logs we mount mds with supplied mount options
1779 # because it will not mount smfs (if used) otherwise.
1781 mountfsoptions = def_mount_options(self.fstype, 'mds')
1783 if config.mountfsoptions:
1785 mountfsoptions = mountfsoptions + ',' + config.mountfsoptions
1787 mountfsoptions = config.mountfsoptions
1788 if self.mountfsoptions:
1789 mountfsoptions = mountfsoptions + ',' + self.mountfsoptions
1791 if self.mountfsoptions:
1793 mountfsoptions = mountfsoptions + ',' + self.mountfsoptions
1795 mountfsoptions = self.mountfsoptions
1797 if self.fstype == 'smfs':
1798 realdev = self.fstype
1801 mountfsoptions = "%s,type=%s,dev=%s" % (mountfsoptions,
1805 mountfsoptions = "type=%s,dev=%s" % (self.backfstype,
1810 print 'MDS mount options: ' + mountfsoptions
1812 # As mount options are passed by 4th param to config tool, we need
1813 # to pass something in 3rd param. But we do not want this 3rd param
1814 # be counted as a profile name for reading log on MDS setup, thus,
1815 # we pass there some predefined sign like 'dumb', which will be
1816 # checked in MDS code and skipped. Probably there is more nice way
1817 # like pass empty string and check it in config tool and pass null
1819 lctl.newdev("mds", self.name, self.uuid,
1820 setup ="%s %s %s %s" %(realdev, self.fstype,
1821 'dumb', mountfsoptions))
1824 # record logs for the MDS lov
1825 for uuid in self.filesystem_uuids:
1826 log("recording clients for filesystem:", uuid)
1827 fs = self.db.lookup(uuid)
1829 # this is ugly, should be organized nice later.
1830 target_uuid = self.db.get_first_ref('target')
1831 mds = self.db.lookup(target_uuid)
1833 lovconfig_uuid = mds.get_first_ref('lovconfig')
1835 lovconfig = mds.lookup(lovconfig_uuid)
1836 obd_uuid = lovconfig.get_first_ref('lov')
1838 obd_uuid = fs.get_first_ref('obd')
1840 client_uuid = generate_client_uuid(self.name)
1841 client = VOSC(self.db.lookup(obd_uuid), client_uuid, self.name,
1844 lctl.clear_log(self.name, self.name)
1845 lctl.record(self.name, self.name)
1847 lctl.mount_option(self.name, client.get_name(), "")
1849 process_updates(self.db, self.name, self.name, client)
1852 lctl.clear_log(self.name, self.name + '-clean')
1853 lctl.record(self.name, self.name + '-clean')
1855 lctl.del_mount_option(self.name)
1857 process_updates(self.db, self.name, self.name + '-clean', client)
1861 # record logs for each client
1867 config_options = "--ldapurl " + config.ldapurl + " --config " + config.config
1869 config_options = CONFIG_FILE
1871 for node_db in self.db.lookup_class('node'):
1872 client_name = node_db.getName()
1873 for prof_uuid in node_db.get_refs('profile'):
1874 prof_db = node_db.lookup(prof_uuid)
1875 # refactor this into a funtion to test "clientness"
1877 for ref_class, ref_uuid in prof_db.get_all_refs():
1878 if ref_class in ('mountpoint','echoclient'):
1879 debug("recording", client_name)
1880 old_noexec = config.noexec
1882 ret, out = run (sys.argv[0], noexec_opt,
1883 " -v --record --nomod",
1884 "--record_log", client_name,
1885 "--record_device", self.name,
1886 "--node", client_name,
1889 for s in out: log("record> ", string.strip(s))
1890 ret, out = run (sys.argv[0], noexec_opt,
1891 "--cleanup -v --record --nomod",
1892 "--record_log", client_name + "-clean",
1893 "--record_device", self.name,
1894 "--node", client_name,
1897 for s in out: log("record> ", string.strip(s))
1898 config.noexec = old_noexec
1901 lctl.cleanup(self.name, self.uuid, 0, 0)
1902 except CommandError, e:
1903 log(self.module_name, "cleanup failed: ", self.name)
1906 Module.cleanup(self)
1908 if self.fstype == 'smfs':
1909 clean_loop(self.backdevpath)
1911 clean_loop(self.devpath)
1913 def msd_remaining(self):
1914 out = lctl.device_list()
1916 if string.split(s)[2] in ('mds',):
1919 def safe_to_clean(self):
1922 def safe_to_clean_modules(self):
1923 return not self.msd_remaining()
1927 debug(self.uuid, "not active")
1930 if is_prepared(self.name):
1932 lctl.cleanup(self.name, self.uuid, config.force,
1934 except CommandError, e:
1935 log(self.module_name, "cleanup failed: ", self.name)
1938 Module.cleanup(self)
1941 self.master.cleanup()
1942 if not self.msd_remaining() and is_prepared('MDT'):
1944 lctl.cleanup("MDT", "MDT_UUID", config.force,
1946 except CommandError, e:
1947 print "cleanup failed: ", self.name
1951 if self.fstype == 'smfs':
1952 clean_loop(self.backdevpath)
1954 clean_loop(self.devpath)
1956 def correct_level(self, level, op=None):
1957 #if self.master_mds:
1962 def __init__(self, db):
1963 Module.__init__(self, 'OSD', db)
1964 self.osdtype = self.db.get_val('osdtype')
1965 self.devpath = self.db.get_val('devpath', '')
1966 self.backdevpath = self.db.get_val('backdevpath', '')
1967 self.size = self.db.get_val_int('devsize', 0)
1968 self.journal_size = self.db.get_val_int('journalsize', 0)
1969 self.inode_size = self.db.get_val_int('inodesize', 0)
1970 self.mkfsoptions = self.db.get_val('mkfsoptions', '')
1971 self.mountfsoptions = self.db.get_val('mountfsoptions', '')
1972 self.fstype = self.db.get_val('fstype', '')
1973 self.backfstype = self.db.get_val('backfstype', '')
1974 self.nspath = self.db.get_val('nspath', '')
1975 target_uuid = self.db.get_first_ref('target')
1976 ost = self.db.lookup(target_uuid)
1977 self.name = ost.getName()
1978 self.format = self.db.get_val('autoformat', 'yes')
1979 if ost.get_val('failover', 0):
1980 self.failover_ost = 'f'
1982 self.failover_ost = 'n'
1984 active_uuid = get_active_target(ost)
1986 panic("No target device found:", target_uuid)
1987 if active_uuid == self.uuid:
1991 if self.active and config.group and config.group != ost.get_val('group'):
1994 self.target_dev_uuid = self.uuid
1995 self.uuid = target_uuid
1997 self.add_lustre_module('ost', 'ost')
1998 if self.fstype == 'smfs':
1999 self.add_lustre_module('smfs', 'smfs')
2000 # FIXME: should we default to ext3 here?
2001 if self.fstype == 'ldiskfs':
2002 self.add_lustre_module('ldiskfs', 'ldiskfs')
2004 self.add_lustre_module('lvfs' , 'fsfilt_%s' % (self.fstype))
2005 if self.fstype == 'smfs':
2006 self.add_lustre_module('lvfs' , 'fsfilt_%s' % (self.backfstype))
2008 for options in self.mountfsoptions:
2009 if options == 'snap':
2010 if not self.fstype == 'smfs':
2011 panic("mountoptions with snap, but fstype is not smfs\n")
2012 self.add_lustre_module('lvfs', 'fsfilt_snap_%s' % (self.fstype))
2013 self.add_lustre_module('lvfs', 'fsfilt_snap_%s' % (self.backfstype))
2015 self.add_lustre_module(self.osdtype, self.osdtype)
2017 def load_module(self):
2019 Module.load_module(self)
2021 # need to check /proc/mounts and /etc/mtab before
2022 # formatting anything.
2023 # FIXME: check if device is already formatted.
2025 if is_prepared(self.name):
2028 debug(self.uuid, "not active")
2030 self.info(self.osdtype, self.devpath, self.size, self.fstype,
2031 self.format, self.journal_size, self.inode_size)
2033 if self.osdtype == 'obdecho':
2036 blkdev = block_dev(self.devpath, self.size, self.fstype,
2037 config.reformat, self.format, self.journal_size,
2038 self.inode_size, self.mkfsoptions, self.backfstype,
2041 mountfsoptions = def_mount_options(self.fstype, 'ost')
2043 if config.mountfsoptions:
2045 mountfsoptions = mountfsoptions + ',' + config.mountfsoptions
2047 mountfsoptions = config.mountfsoptions
2048 if self.mountfsoptions:
2049 mountfsoptions = mountfsoptions + ',' + self.mountfsoptions
2051 if self.mountfsoptions:
2053 mountfsoptions = mountfsoptions + ',' + self.mountfsoptions
2055 mountfsoptions = self.mountfsoptions
2057 if self.fstype == 'smfs':
2058 realdev = self.fstype
2061 mountfsoptions = "%s,type=%s,dev=%s" % (mountfsoptions,
2065 mountfsoptions = "type=%s,dev=%s" % (self.backfstype,
2070 print 'OSD mount options: ' + mountfsoptions
2072 lctl.newdev(self.osdtype, self.name, self.uuid,
2073 setup ="%s %s %s %s" %(realdev, self.fstype,
2076 if not is_prepared('OSS'):
2077 lctl.newdev("ost", 'OSS', 'OSS_UUID', setup ="")
2079 def osd_remaining(self):
2080 out = lctl.device_list()
2082 if string.split(s)[2] in ('obdfilter', 'obdecho'):
2085 def safe_to_clean(self):
2088 def safe_to_clean_modules(self):
2089 return not self.osd_remaining()
2093 debug(self.uuid, "not active")
2095 if is_prepared(self.name):
2098 lctl.cleanup(self.name, self.uuid, config.force,
2100 except CommandError, e:
2101 log(self.module_name, "cleanup failed: ", self.name)
2104 if not self.osd_remaining() and is_prepared('OSS'):
2106 lctl.cleanup("OSS", "OSS_UUID", config.force,
2108 except CommandError, e:
2109 print "cleanup failed: ", self.name
2112 if not self.osdtype == 'obdecho':
2113 if self.fstype == 'smfs':
2114 clean_loop(self.backdevpath)
2116 clean_loop(self.devpath)
2118 def correct_level(self, level, op=None):
2121 # Generic client module, used by OSC and MDC
2122 class Client(Module):
2123 def __init__(self, tgtdb, uuid, module, fs_name, self_name=None,
2125 self.target_name = tgtdb.getName()
2126 self.target_uuid = tgtdb.getUUID()
2129 self.backup_targets = []
2131 self.tgt_dev_uuid = get_active_target(tgtdb)
2132 if not self.tgt_dev_uuid:
2133 panic("No target device found for target(1):", self.target_name)
2135 self.kmod = kmod(config.lustre, config.portals)
2139 self.module = module
2140 self.module_name = string.upper(module)
2142 self.name = '%s_%s_%s_%s' % (self.module_name, socket.gethostname(),
2143 self.target_name, fs_name)
2145 self.name = self_name
2147 self.lookup_server(self.tgt_dev_uuid)
2149 self.lookup_backup_targets()
2150 self.fs_name = fs_name
2153 self.add_lustre_module(module_dir, module)
2155 def lookup_server(self, srv_uuid):
2156 """ Lookup a server's network information """
2157 self._server_nets = get_ost_net(self.db, srv_uuid)
2158 if len(self._server_nets) == 0:
2159 panic ("Unable to find a server for:", srv_uuid)
2162 def get_servers(self):
2163 return self._server_nets
2164 def lookup_backup_targets(self):
2165 """ Lookup alternative network information """
2166 prof_list = toplustreDB.get_refs('profile')
2167 for prof_uuid in prof_list:
2168 prof_db = toplustreDB.lookup(prof_uuid)
2170 panic("profile:", prof_uuid, "not found.")
2171 for ref_class, ref_uuid in prof_db.get_all_refs():
2172 if ref_class in ('osd', 'mdsdev'):
2173 devdb = toplustreDB.lookup(ref_uuid)
2174 uuid = devdb.get_first_ref('target')
2175 if self.target_uuid == uuid and self.tgt_dev_uuid != ref_uuid:
2176 self.backup_targets.append(ref_uuid)
2178 def prepare(self, ignore_connect_failure = 0):
2179 self.info(self.target_uuid)
2180 if not config.record and is_prepared(self.name):
2183 srv = choose_local_server(self.get_servers())
2187 routes = find_route(self.get_servers())
2188 if len(routes) == 0:
2189 panic ("no route to", self.target_uuid)
2190 for (srv, r) in routes:
2191 lctl.add_route_host(r[0], srv.nid_uuid, r[1], r[3])
2192 except CommandError, e:
2193 if not ignore_connect_failure:
2196 if self.permits_inactive() and (self.target_uuid in config.inactive or self.active == 0):
2197 debug("%s inactive" % self.target_uuid)
2198 inactive_p = "inactive"
2200 debug("%s active" % self.target_uuid)
2202 lctl.newdev(self.module, self.name, self.uuid,
2203 setup ="%s %s %s" % (self.target_uuid, srv.nid_uuid,
2205 for tgt_dev_uuid in self.backup_targets:
2206 this_nets = get_ost_net(toplustreDB, tgt_dev_uuid)
2207 if len(this_nets) == 0:
2208 panic ("Unable to find a server for:", tgt_dev_uuid)
2209 srv = choose_local_server(this_nets)
2213 routes = find_route(this_nets);
2214 if len(routes) == 0:
2215 panic("no route to", tgt_dev_uuid)
2216 for (srv, r) in routes:
2217 lctl.add_route_host(r[0]. srv.nid_uuid, r[1], r[3])
2219 lctl.add_conn(self.name, srv.nid_uuid);
2222 if is_prepared(self.name):
2223 Module.cleanup(self)
2225 srv = choose_local_server(self.get_servers())
2227 lctl.disconnect(srv)
2229 for (srv, r) in find_route(self.get_servers()):
2230 lctl.del_route_host(r[0], srv.nid_uuid, r[1], r[3])
2231 except CommandError, e:
2232 log(self.module_name, "cleanup failed: ", self.name)
2236 for tgt_dev_uuid in self.backup_targets:
2237 this_net = get_ost_net(toplustreDB, tgt_dev_uuid)
2238 srv = choose_local_server(this_net)
2240 lctl.disconnect(srv)
2242 for (srv, r) in find_route(this_net):
2243 lctl.del_route_host(r[0]. srv.nid_uuid, r[1], r[3])
2246 def correct_level(self, level, op=None):
2249 def deactivate(self):
2251 lctl.deactivate(self.name)
2252 except CommandError, e:
2253 log(self.module_name, "deactivate failed: ", self.name)
2258 def __init__(self, db, uuid, fs_name):
2259 Client.__init__(self, db, uuid, 'mdc', fs_name)
2261 def permits_inactive(self):
2265 def __init__(self, db, uuid, fs_name):
2266 Client.__init__(self, db, uuid, 'osc', fs_name)
2268 def permits_inactive(self):
2272 def __init__(self, db, uuid, fs_name, name_override = None, config_only = None):
2273 Module.__init__(self, 'VLOV', db)
2274 if name_override != None:
2275 self.name = "lov_%s" % name_override
2276 self.add_lustre_module('lov', 'lov')
2277 self.stripe_sz = 65536
2281 self.desc_uuid = self.uuid
2282 self.uuid = generate_client_uuid(self.name)
2283 self.fs_name = fs_name
2284 self.osc = get_osc(db, self.uuid, fs_name)
2286 panic('osc not found:', self.uuid)
2288 self.config_only = 1
2290 self.config_only = None
2296 if not config.record and is_prepared(self.name):
2298 lctl.lov_setup(self.name, self.uuid, self.desc_uuid, self.stripe_cnt,
2299 self.stripe_sz, self.stripe_off, self.pattern)
2300 target_uuid = self.osc.target_uuid
2303 self.osc.prepare(ignore_connect_failure=0)
2304 except CommandError, e:
2305 print "Error preparing OSC %s\n" % osc.uuid
2307 lctl.lov_add_obd(self.name, self.uuid, target_uuid, 0, 1)
2310 target_uuid = self.osc.target_uuid
2312 if is_prepared(self.name):
2313 Module.cleanup(self)
2314 if self.config_only:
2315 panic("Can't clean up config_only LOV ", self.name)
2317 def load_module(self):
2318 if self.config_only:
2319 panic("Can't load modules for config_only LOV ", self.name)
2320 self.osc.load_module()
2321 Module.load_module(self)
2323 def cleanup_module(self):
2324 if self.config_only:
2325 panic("Can't cleanup modules for config_only LOV ", self.name)
2326 Module.cleanup_module(self)
2327 self.osc.cleanup_module()
2329 def correct_level(self, level, op=None):
2332 class CMOBD(Module):
2333 def __init__(self,db):
2334 Module.__init__(self, 'CMOBD', db)
2335 self.name = self.db.getName();
2336 self.uuid = generate_client_uuid(self.name)
2337 self.master_uuid = self.db.get_first_ref('masterobd')
2338 self.cache_uuid = self.db.get_first_ref('cacheobd')
2339 self.add_lustre_module('cmobd', 'cmobd')
2340 master_obd = self.db.lookup(self.master_uuid)
2342 panic('master obd not found:', self.master_uuid)
2343 cache_obd = self.db.lookup(self.cache_uuid)
2345 panic('cache obd not found:', self.cache_uuid)
2347 if master_obd.get_class() == 'ost':
2348 self.client_uuid = generate_client_uuid(self.name)
2349 self.master= VLOV(master_obd, self.client_uuid, self.name,
2350 "%s_master" % (self.name))
2351 self.master_uuid = self.master.get_uuid()
2353 self.master = get_mdc(db, self.name, self.master_uuid)
2354 # need to check /proc/mounts and /etc/mtab before
2355 # formatting anything.
2356 # FIXME: check if device is already formatted.
2358 self.master.prepare()
2359 if not config.record and is_prepared(self.name):
2361 self.info(self.master_uuid, self.cache_uuid)
2362 lctl.newdev("cmobd", self.name, self.uuid,
2363 setup ="%s %s" %(self.master_uuid,
2367 if is_prepared(self.name):
2368 Module.cleanup(self)
2369 self.master.cleanup()
2371 def load_module(self):
2372 self.master.load_module()
2373 Module.load_module(self)
2375 def cleanup_module(self):
2376 Module.cleanup_module(self)
2377 self.master.cleanup_module()
2379 def correct_level(self, level, op=None):
2383 def __init__(self, db, uuid, name, type, name_override = None):
2384 Module.__init__(self, 'COBD', db)
2385 self.name = self.db.getName();
2386 self.uuid = generate_client_uuid(self.name)
2387 self.real_uuid = self.db.get_first_ref('realobd')
2388 self.cache_uuid = self.db.get_first_ref('cacheobd')
2389 self.add_lustre_module('cobd', 'cobd')
2390 real_obd = self.db.lookup(self.real_uuid)
2392 panic('real obd not found:', self.real_uuid)
2393 cache_obd = self.db.lookup(self.cache_uuid)
2395 panic('cache obd not found:', self.cache_uuid)
2397 self.real = LOV(real_obd, self.real_uuid, name,
2398 "%s_real" % (self.name));
2399 self.cache = LOV(cache_obd, self.cache_uuid, name,
2400 "%s_cache" % (self.name));
2402 self.real = get_mdc(db, name, self.real_uuid)
2403 self.cache = get_mdc(db, name, self.cache_uuid)
2404 # need to check /proc/mounts and /etc/mtab before
2405 # formatting anything.
2406 # FIXME: check if device is already formatted.
2411 def get_real_name(self):
2412 return self.real.name
2413 def get_cache_name(self):
2414 return self.cache.name
2417 self.cache.prepare()
2418 if not config.record and is_prepared(self.name):
2420 self.info(self.real_uuid, self.cache_uuid)
2421 lctl.newdev("cobd", self.name, self.uuid,
2422 setup ="%s %s" %(self.real.name,
2426 if is_prepared(self.name):
2427 Module.cleanup(self)
2429 self.cache.cleanup()
2431 def load_module(self):
2432 self.real.load_module()
2433 Module.load_module(self)
2435 def cleanup_module(self):
2436 Module.cleanup_module(self)
2437 self.real.cleanup_module()
2439 # virtual interface for OSC and LOV
2441 def __init__(self, db, client_uuid, name, name_override = None):
2442 Module.__init__(self, 'VOSC', db)
2443 if db.get_class() == 'lov':
2444 self.osc = LOV(db, client_uuid, name, name_override)
2446 elif db.get_class() == 'cobd':
2447 self.osc = COBD(db, client_uuid, name, 'obd')
2450 self.osc = OSC(db, client_uuid, name)
2453 return self.osc.get_uuid()
2455 return self.osc.get_name()
2460 def load_module(self):
2461 self.osc.load_module()
2462 def cleanup_module(self):
2463 self.osc.cleanup_module()
2464 def correct_level(self, level, op=None):
2465 return self.osc.correct_level(level, op)
2467 # virtual interface for MDC and LMV
2469 def __init__(self, db, client_uuid, name, name_override = None):
2470 Module.__init__(self, 'VMDC', db)
2471 if db.get_class() == 'lmv':
2472 self.mdc = LMV(db, client_uuid, name)
2473 elif db.get_class() == 'cobd':
2474 self.mdc = COBD(db, client_uuid, name, 'mds')
2476 self.mdc = MDC(db, client_uuid, name)
2478 return self.mdc.uuid
2480 return self.mdc.name
2485 def load_module(self):
2486 self.mdc.load_module()
2487 def cleanup_module(self):
2488 self.mdc.cleanup_module()
2489 def correct_level(self, level, op=None):
2490 return self.mdc.correct_level(level, op)
2492 class ECHO_CLIENT(Module):
2493 def __init__(self,db):
2494 Module.__init__(self, 'ECHO_CLIENT', db)
2495 self.add_lustre_module('obdecho', 'obdecho')
2496 self.obd_uuid = self.db.get_first_ref('obd')
2497 obd = self.db.lookup(self.obd_uuid)
2498 self.uuid = generate_client_uuid(self.name)
2499 self.osc = VOSC(obd, self.uuid, self.name)
2502 if not config.record and is_prepared(self.name):
2505 self.osc.prepare() # XXX This is so cheating. -p
2506 self.info(self.obd_uuid)
2508 lctl.newdev("echo_client", self.name, self.uuid,
2509 setup = self.osc.get_name())
2512 if is_prepared(self.name):
2513 Module.cleanup(self)
2516 def load_module(self):
2517 self.osc.load_module()
2518 Module.load_module(self)
2520 def cleanup_module(self):
2521 Module.cleanup_module(self)
2522 self.osc.cleanup_module()
2524 def correct_level(self, level, op=None):
2527 def generate_client_uuid(name):
2528 client_uuid = '%05x_%.19s_%05x%05x' % (int(random.random() * 1048576),
2530 int(random.random() * 1048576),
2531 int(random.random() * 1048576))
2532 return client_uuid[:36]
2534 def my_rstrip(s, chars):
2535 """my_rstrip(s, chars) -> strips any instances of the characters
2536 found in chars from the right side of string s"""
2537 # XXX required because python versions pre 2.2.3 don't allow
2538 #string.rstrip() to take alternate char lists
2542 ns = string.rstrip(s, '/')
2543 except TypeError, e:
2544 for i in range(len(s) - 1, 0, -1):
2552 class Mountpoint(Module):
2553 def __init__(self,db):
2554 Module.__init__(self, 'MTPT', db)
2555 self.path = self.db.get_val('path')
2556 self.clientoptions = self.db.get_val('clientoptions', '')
2557 self.fs_uuid = self.db.get_first_ref('filesystem')
2558 fs = self.db.lookup(self.fs_uuid)
2559 self.mds_uuid = fs.get_first_ref('lmv')
2560 if not self.mds_uuid:
2561 self.mds_uuid = fs.get_first_ref('mds')
2562 self.obd_uuid = fs.get_first_ref('obd')
2563 client_uuid = generate_client_uuid(self.name)
2565 ost = self.db.lookup(self.obd_uuid)
2567 panic("no ost: ", self.obd_uuid)
2569 mds = self.db.lookup(self.mds_uuid)
2571 panic("no mds: ", self.mds_uuid)
2573 self.add_lustre_module('mdc', 'mdc')
2574 self.add_lustre_module('lmv', 'lmv')
2575 self.add_lustre_module('llite', 'llite')
2577 self.vosc = VOSC(ost, client_uuid, self.name)
2578 self.vmdc = VMDC(mds, client_uuid, self.name)
2581 if not config.record and fs_is_mounted(self.path):
2582 log(self.path, "already mounted.")
2587 vmdc_name = self.vmdc.get_name()
2589 self.info(self.path, self.mds_uuid, self.obd_uuid)
2590 if config.record or config.lctl_dump:
2591 lctl.mount_option(local_node_name, self.vosc.get_name(), vmdc_name)
2594 if config.clientoptions:
2595 if self.clientoptions:
2596 self.clientoptions = self.clientoptions + ',' + \
2597 config.clientoptions
2599 self.clientoptions = config.clientoptions
2600 if self.clientoptions:
2601 self.clientoptions = ',' + self.clientoptions
2602 # Linux kernel will deal with async and not pass it to ll_fill_super,
2603 # so replace it with Lustre async
2604 self.clientoptions = string.replace(self.clientoptions, "async",
2607 cmd = "mount -t lustre_lite -o osc=%s,mdc=%s%s %s %s" % \
2608 (self.vosc.get_name(), vmdc_name, self.clientoptions,
2609 config.config, self.path)
2610 run("mkdir", self.path)
2615 panic("mount failed:", self.path, ":", string.join(val))
2618 self.info(self.path, self.mds_uuid,self.obd_uuid)
2620 if config.record or config.lctl_dump:
2621 lctl.del_mount_option(local_node_name)
2623 if fs_is_mounted(self.path):
2625 (rc, out) = run("umount", "-f", self.path)
2627 (rc, out) = run("umount", self.path)
2629 raise CommandError('umount', out, rc)
2631 if fs_is_mounted(self.path):
2632 panic("fs is still mounted:", self.path)
2637 def load_module(self):
2638 self.vosc.load_module()
2639 Module.load_module(self)
2641 def cleanup_module(self):
2642 Module.cleanup_module(self)
2643 self.vosc.cleanup_module()
2645 def correct_level(self, level, op=None):
2648 # ============================================================
2649 # misc query functions
2651 def get_ost_net(self, osd_uuid):
2655 osd = self.lookup(osd_uuid)
2656 node_uuid = osd.get_first_ref('node')
2657 node = self.lookup(node_uuid)
2659 panic("unable to find node for osd_uuid:", osd_uuid,
2660 " node_ref:", node_uuid_)
2661 for net_uuid in node.get_networks():
2662 db = node.lookup(net_uuid)
2663 srv_list.append(Network(db))
2667 # the order of iniitailization is based on level.
2668 def getServiceLevel(self):
2669 type = self.get_class()
2671 if type in ('network',):
2673 elif type in ('routetbl',):
2675 elif type in ('ldlm',):
2677 elif type in ('osd', 'cobd'):
2679 elif type in ('mdsdev',):
2681 elif type in ('lmv',):
2683 elif type in ('cmobd',):
2685 elif type in ('mountpoint', 'echoclient'):
2688 panic("Unknown type: ", type)
2690 if ret < config.minlevel or ret > config.maxlevel:
2695 # return list of services in a profile. list is a list of tuples
2696 # [(level, db_object),]
2697 def getServices(self):
2699 for ref_class, ref_uuid in self.get_all_refs():
2700 servdb = self.lookup(ref_uuid)
2702 level = getServiceLevel(servdb)
2704 list.append((level, servdb))
2706 panic('service not found: ' + ref_uuid)
2712 ############################################################
2714 # FIXME: clean this mess up!
2716 # OSC is no longer in the xml, so we have to fake it.
2717 # this is getting ugly and begging for another refactoring
2718 def get_osc(ost_db, uuid, fs_name):
2719 osc = OSC(ost_db, uuid, fs_name)
2722 def get_mdc(db, fs_name, mds_uuid):
2723 mds_db = db.lookup(mds_uuid);
2725 error("no mds:", mds_uuid)
2726 mdc = MDC(mds_db, mds_uuid, fs_name)
2729 ############################################################
2730 # routing ("rooting")
2731 # list of (nettype, cluster_id, nid)
2734 def find_local_clusters(node_db):
2735 global local_clusters
2736 for netuuid in node_db.get_networks():
2737 net = node_db.lookup(netuuid)
2739 debug("add_local", netuuid)
2740 local_clusters.append((srv.net_type, srv.cluster_id, srv.nid))
2742 if acceptors.has_key(srv.port):
2743 panic("duplicate port:", srv.port)
2744 acceptors[srv.port] = AcceptorHandler(srv.port, srv.net_type)
2746 # This node is a gateway.
2748 def node_is_router():
2751 # If there are any routers found in the config, then this will be true
2752 # and all nodes will load kptlrouter.
2754 def node_needs_router():
2755 return needs_router or is_router
2757 # list of (nettype, gw, tgt_cluster_id, lo, hi)
2758 # Currently, these local routes are only added to kptlrouter route
2759 # table if they are needed to connect to a specific server. This
2760 # should be changed so all available routes are loaded, and the
2761 # ptlrouter can make all the decisions.
2764 def find_local_routes(lustre):
2765 """ Scan the lustre config looking for routers . Build list of
2767 global local_routes, needs_router
2769 list = lustre.lookup_class('node')
2771 if router.get_val_int('router', 0):
2773 for (local_type, local_cluster_id, local_nid) in local_clusters:
2775 for netuuid in router.get_networks():
2776 db = router.lookup(netuuid)
2777 if (local_type == db.get_val('nettype') and
2778 local_cluster_id == db.get_val('clusterid')):
2779 gw = db.get_val('nid')
2782 debug("find_local_routes: gw is", gw)
2783 for route in router.get_local_routes(local_type, gw):
2784 local_routes.append(route)
2785 debug("find_local_routes:", local_routes)
2788 def choose_local_server(srv_list):
2789 for srv in srv_list:
2790 if local_cluster(srv.net_type, srv.cluster_id):
2793 def local_cluster(net_type, cluster_id):
2794 for cluster in local_clusters:
2795 if net_type == cluster[0] and cluster_id == cluster[1]:
2799 def local_interface(net_type, cluster_id, nid):
2800 for cluster in local_clusters:
2801 if (net_type == cluster[0] and cluster_id == cluster[1]
2802 and nid == cluster[2]):
2806 def find_route(srv_list):
2808 frm_type = local_clusters[0][0]
2809 for srv in srv_list:
2810 debug("find_route: srv:", srv.nid, "type: ", srv.net_type)
2811 to_type = srv.net_type
2813 cluster_id = srv.cluster_id
2814 debug ('looking for route to', to_type, to)
2815 for r in local_routes:
2816 debug("find_route: ", r)
2817 if (r[3] <= to and to <= r[4]) and cluster_id == r[2]:
2818 result.append((srv, r))
2821 def get_active_target(db):
2822 target_uuid = db.getUUID()
2823 target_name = db.getName()
2824 node_name = get_select(target_name)
2826 tgt_dev_uuid = db.get_node_tgt_dev(node_name, target_uuid)
2828 tgt_dev_uuid = db.get_first_ref('active')
2831 def get_server_by_nid_uuid(db, nid_uuid):
2832 for n in db.lookup_class("network"):
2834 if net.nid_uuid == nid_uuid:
2838 ############################################################
2842 type = db.get_class()
2843 debug('Service:', type, db.getName(), db.getUUID())
2848 n = LOV(db, "YOU_SHOULD_NEVER_SEE_THIS_UUID")
2849 elif type == 'network':
2851 elif type == 'routetbl':
2855 elif type == 'cobd':
2856 n = COBD(db, "YOU_SHOULD_NEVER_SEE_THIS_UUID")
2857 elif type == 'cmobd':
2859 elif type == 'mdsdev':
2861 elif type == 'mountpoint':
2863 elif type == 'echoclient':
2868 panic ("unknown service type:", type)
2872 # Prepare the system to run lustre using a particular profile
2873 # in a the configuration.
2874 # * load & the modules
2875 # * setup networking for the current node
2876 # * make sure partitions are in place and prepared
2877 # * initialize devices with lctl
2878 # Levels is important, and needs to be enforced.
2879 def for_each_profile(db, prof_list, operation):
2880 for prof_uuid in prof_list:
2881 prof_db = db.lookup(prof_uuid)
2883 panic("profile:", prof_uuid, "not found.")
2884 services = getServices(prof_db)
2887 def magic_get_osc(db, rec, lov):
2889 lov_uuid = lov.get_uuid()
2890 lov_name = lov.osc.fs_name
2892 lov_uuid = rec.getAttribute('lov_uuidref')
2893 # FIXME: better way to find the mountpoint?
2894 filesystems = db.root_node.getElementsByTagName('filesystem')
2896 for fs in filesystems:
2897 ref = fs.getElementsByTagName('obd_ref')
2898 if ref[0].getAttribute('uuidref') == lov_uuid:
2899 fsuuid = fs.getAttribute('uuid')
2903 panic("malformed xml: lov uuid '" + lov_uuid + "' referenced in 'add' record is not used by any filesystems.")
2905 mtpts = db.root_node.getElementsByTagName('mountpoint')
2908 ref = fs.getElementsByTagName('filesystem_ref')
2909 if ref[0].getAttribute('uuidref') == fsuuid:
2910 lov_name = fs.getAttribute('name')
2914 panic("malformed xml: 'add' record references lov uuid '" + lov_uuid + "', which references filesystem uuid '" + fsuuid + "', which does not reference a mountpoint.")
2916 print "lov_uuid: " + lov_uuid + "; lov_name: " + lov_name
2918 ost_uuid = rec.getAttribute('ost_uuidref')
2919 obd = db.lookup(ost_uuid)
2922 panic("malformed xml: 'add' record references ost uuid '" + ost_uuid + "' which cannot be found.")
2924 osc = get_osc(obd, lov_uuid, lov_name)
2926 panic('osc not found:', obd_uuid)
2929 # write logs for update records. sadly, logs of all types -- and updates in
2930 # particular -- are something of an afterthought. lconf needs rewritten with
2931 # these as core concepts. so this is a pretty big hack.
2932 def process_update_record(db, update, lov):
2933 for rec in update.childNodes:
2934 if rec.nodeType != rec.ELEMENT_NODE:
2937 log("found "+rec.nodeName+" record in update version " +
2938 str(update.getAttribute('version')))
2940 lov_uuid = rec.getAttribute('lov_uuidref')
2941 ost_uuid = rec.getAttribute('ost_uuidref')
2942 index = rec.getAttribute('index')
2943 gen = rec.getAttribute('generation')
2945 if not lov_uuid or not ost_uuid or not index or not gen:
2946 panic("malformed xml: 'update' record requires lov_uuid, ost_uuid, index, and generation.")
2949 tmplov = db.lookup(lov_uuid)
2951 panic("malformed xml: 'delete' record contains lov UUID '" + lov_uuid + "', which cannot be located.")
2952 lov_name = tmplov.getName()
2954 lov_name = lov.osc.name
2956 # ------------------------------------------------------------- add
2957 if rec.nodeName == 'add':
2959 lctl.lov_del_obd(lov_name, lov_uuid, ost_uuid, index, gen)
2962 osc = magic_get_osc(db, rec, lov)
2965 # Only ignore connect failures with --force, which
2966 # isn't implemented here yet.
2967 osc.prepare(ignore_connect_failure=0)
2968 except CommandError, e:
2969 print "Error preparing OSC %s\n" % osc.uuid
2972 lctl.lov_add_obd(lov_name, lov_uuid, ost_uuid, index, gen)
2974 # ------------------------------------------------------ deactivate
2975 elif rec.nodeName == 'deactivate':
2979 osc = magic_get_osc(db, rec, lov)
2983 except CommandError, e:
2984 print "Error deactivating OSC %s\n" % osc.uuid
2987 # ---------------------------------------------------------- delete
2988 elif rec.nodeName == 'delete':
2992 osc = magic_get_osc(db, rec, lov)
2998 except CommandError, e:
2999 print "Error cleaning up OSC %s\n" % osc.uuid
3002 lctl.lov_del_obd(lov_name, lov_uuid, ost_uuid, index, gen)
3004 def process_updates(db, log_device, log_name, lov = None):
3005 updates = db.root_node.getElementsByTagName('update')
3007 if not u.childNodes:
3008 log("ignoring empty update record (version " +
3009 str(u.getAttribute('version')) + ")")
3012 version = u.getAttribute('version')
3013 real_name = "%s-%s" % (log_name, version)
3014 lctl.clear_log(log_device, real_name)
3015 lctl.record(log_device, real_name)
3017 process_update_record(db, u, lov)
3021 def doWriteconf(services):
3025 if s[1].get_class() == 'mdsdev':
3026 n = newService(s[1])
3029 def doSetup(services):
3034 n = newService(s[1])
3036 slist.append((n.level, n))
3039 nl = n[1].correct_level(n[0])
3040 nlist.append((nl, n[1]))
3045 def doModules(services):
3049 n = newService(s[1])
3052 def doCleanup(services):
3057 n = newService(s[1])
3059 slist.append((n.level, n))
3062 nl = n[1].correct_level(n[0])
3063 nlist.append((nl, n[1]))
3067 if n[1].safe_to_clean():
3070 def doUnloadModules(services):
3075 n = newService(s[1])
3076 if n.safe_to_clean_modules():
3081 def doHost(lustreDB, hosts):
3082 global is_router, local_node_name
3085 node_db = lustreDB.lookup_name(h, 'node')
3089 panic('No host entry found.')
3091 local_node_name = node_db.get_val('name', 0)
3092 is_router = node_db.get_val_int('router', 0)
3093 lustre_upcall = node_db.get_val('lustreUpcall', '')
3094 portals_upcall = node_db.get_val('portalsUpcall', '')
3095 timeout = node_db.get_val_int('timeout', 0)
3096 ptldebug = node_db.get_val('ptldebug', '')
3097 subsystem = node_db.get_val('subsystem', '')
3099 find_local_clusters(node_db)
3101 find_local_routes(lustreDB)
3103 # Two step process: (1) load modules, (2) setup lustre
3104 # if not cleaning, load modules first.
3105 prof_list = node_db.get_refs('profile')
3107 if config.write_conf:
3108 for_each_profile(node_db, prof_list, doModules)
3110 for_each_profile(node_db, prof_list, doWriteconf)
3111 for_each_profile(node_db, prof_list, doUnloadModules)
3114 elif config.recover:
3115 if not (config.tgt_uuid and config.client_uuid and config.conn_uuid):
3116 raise Lustre.LconfError( "--recovery requires --tgt_uuid <UUID> " +
3117 "--client_uuid <UUID> --conn_uuid <UUID>")
3118 doRecovery(lustreDB, lctl, config.tgt_uuid, config.client_uuid,
3120 elif config.cleanup:
3122 # the command line can override this value
3124 # ugly hack, only need to run lctl commands for --dump
3125 if config.lctl_dump or config.record:
3126 for_each_profile(node_db, prof_list, doCleanup)
3129 sys_set_timeout(timeout)
3130 sys_set_ptldebug(ptldebug)
3131 sys_set_subsystem(subsystem)
3132 sys_set_lustre_upcall(lustre_upcall)
3133 sys_set_portals_upcall(portals_upcall)
3135 for_each_profile(node_db, prof_list, doCleanup)
3136 for_each_profile(node_db, prof_list, doUnloadModules)
3140 # ugly hack, only need to run lctl commands for --dump
3141 if config.lctl_dump or config.record:
3142 sys_set_timeout(timeout)
3143 sys_set_lustre_upcall(lustre_upcall)
3144 for_each_profile(node_db, prof_list, doSetup)
3148 sys_set_netmem_max('/proc/sys/net/core/rmem_max', MAXTCPBUF)
3149 sys_set_netmem_max('/proc/sys/net/core/wmem_max', MAXTCPBUF)
3151 for_each_profile(node_db, prof_list, doModules)
3153 sys_set_debug_path()
3154 sys_set_ptldebug(ptldebug)
3155 sys_set_subsystem(subsystem)
3156 script = config.gdb_script
3157 run(lctl.lctl, ' modules >', script)
3159 log ("The GDB module script is in", script)
3160 # pause, so user has time to break and
3163 sys_set_timeout(timeout)
3164 sys_set_lustre_upcall(lustre_upcall)
3165 sys_set_portals_upcall(portals_upcall)
3167 for_each_profile(node_db, prof_list, doSetup)
3170 def doRecovery(lustreDB, lctl, tgt_uuid, client_uuid, nid_uuid):
3171 tgt = lustreDB.lookup(tgt_uuid)
3173 raise Lustre.LconfError("doRecovery: "+ tgt_uuid +" not found.")
3174 new_uuid = get_active_target(tgt)
3176 raise Lustre.LconfError("doRecovery: no active target found for: " +
3178 net = choose_local_server(get_ost_net(lustreDB, new_uuid))
3180 raise Lustre.LconfError("Unable to find a connection to:" + new_uuid)
3182 log("Reconnecting", tgt_uuid, " to ", net.nid_uuid);
3184 oldnet = get_server_by_nid_uuid(lustreDB, nid_uuid)
3187 lctl.disconnect(oldnet)
3188 except CommandError, e:
3189 log("recover: disconnect", nid_uuid, "failed: ")
3194 except CommandError, e:
3195 log("recover: connect failed")
3198 lctl.recover(client_uuid, net.nid_uuid)
3201 def setupModulePath(cmd, portals_dir = PORTALS_DIR):
3202 base = os.path.dirname(cmd)
3203 if development_mode():
3204 if not config.lustre:
3205 debug('using objdir module paths')
3206 config.lustre = (os.path.join(base, ".."))
3207 # normalize the portals dir, using command line arg if set
3209 portals_dir = config.portals
3210 dir = os.path.join(config.lustre, portals_dir)
3211 config.portals = dir
3212 debug('config.portals', config.portals)
3213 elif config.lustre and config.portals:
3215 # if --lustre and --portals, normalize portals
3216 # can ignore POTRALS_DIR here, since it is probly useless here
3217 config.portals = os.path.join(config.lustre, config.portals)
3218 debug('config.portals B', config.portals)
3220 def sysctl(path, val):
3221 debug("+ sysctl", path, val)
3225 fp = open(os.path.join('/proc/sys', path), 'w')
3232 def sys_set_debug_path():
3233 sysctl('portals/debug_path', config.debug_path)
3235 def sys_set_lustre_upcall(upcall):
3236 # the command overrides the value in the node config
3237 if config.lustre_upcall:
3238 upcall = config.lustre_upcall
3240 upcall = config.upcall
3242 lctl.set_lustre_upcall(upcall)
3244 def sys_set_portals_upcall(upcall):
3245 # the command overrides the value in the node config
3246 if config.portals_upcall:
3247 upcall = config.portals_upcall
3249 upcall = config.upcall
3251 sysctl('portals/upcall', upcall)
3253 def sys_set_timeout(timeout):
3254 # the command overrides the value in the node config
3255 if config.timeout and config.timeout > 0:
3256 timeout = config.timeout
3257 if timeout != None and timeout > 0:
3258 lctl.set_timeout(timeout)
3260 def sys_tweak_socknal ():
3261 # reserve at least 8MB, or we run out of RAM in skb_alloc under read
3262 if sys_get_branch() == '2.6':
3263 fp = open('/proc/meminfo')
3264 lines = fp.readlines()
3269 if a[0] == 'MemTotal:':
3271 debug("memtotal" + memtotal)
3272 if int(memtotal) < 262144:
3273 minfree = int(memtotal) / 16
3276 debug("+ minfree ", minfree)
3277 sysctl("vm/min_free_kbytes", minfree)
3278 if config.single_socket:
3279 sysctl("socknal/typed", 0)
3281 def sys_optimize_elan ():
3282 procfiles = ["/proc/elan/config/eventint_punt_loops",
3283 "/proc/qsnet/elan3/config/eventint_punt_loops",
3284 "/proc/qsnet/elan4/config/elan4_mainint_punt_loops"]
3286 if os.access(p, os.W_OK):
3287 run ("echo 1 > " + p)
3289 def sys_set_ptldebug(ptldebug):
3291 ptldebug = config.ptldebug
3294 val = eval(ptldebug, ptldebug_names)
3295 val = "0x%x" % (val)
3296 sysctl('portals/debug', val)
3297 except NameError, e:
3300 def sys_set_subsystem(subsystem):
3301 if config.subsystem:
3302 subsystem = config.subsystem
3305 val = eval(subsystem, subsystem_names)
3306 val = "0x%x" % (val)
3307 sysctl('portals/subsystem_debug', val)
3308 except NameError, e:
3311 def sys_set_netmem_max(path, max):
3312 debug("setting", path, "to at least", max)
3320 fp = open(path, 'w')
3321 fp.write('%d\n' %(max))
3325 def sys_make_devices():
3326 if not os.access('/dev/portals', os.R_OK):
3327 run('mknod /dev/portals c 10 240')
3328 if not os.access('/dev/obd', os.R_OK):
3329 run('mknod /dev/obd c 10 241')
3332 # Add dir to the global PATH, if not already there.
3333 def add_to_path(new_dir):
3334 syspath = string.split(os.environ['PATH'], ':')
3335 if new_dir in syspath:
3337 os.environ['PATH'] = os.environ['PATH'] + ':' + new_dir
3339 def default_debug_path():
3340 path = '/tmp/lustre-log'
3341 if os.path.isdir('/r'):
3346 def default_gdb_script():
3347 script = '/tmp/ogdb'
3348 if os.path.isdir('/r'):
3349 return '/r' + script
3354 DEFAULT_PATH = ('/sbin', '/usr/sbin', '/bin', '/usr/bin')
3355 # ensure basic elements are in the system path
3356 def sanitise_path():
3357 for dir in DEFAULT_PATH:
3360 # global hack for the --select handling
3362 def init_select(args):
3363 # args = [service=nodeA,service2=nodeB service3=nodeC]
3366 list = string.split(arg, ',')
3368 srv, node = string.split(entry, '=')
3369 tgt_select[srv] = node
3371 def get_select(srv):
3372 if tgt_select.has_key(srv):
3373 return tgt_select[srv]
3377 FLAG = Lustre.Options.FLAG
3378 PARAM = Lustre.Options.PARAM
3379 INTPARAM = Lustre.Options.INTPARAM
3380 PARAMLIST = Lustre.Options.PARAMLIST
3382 ('verbose,v', "Print system commands as they are run"),
3383 ('ldapurl',"LDAP server URL, eg. ldap://localhost", PARAM),
3384 ('config', "Cluster config name used for LDAP query", PARAM),
3385 ('select', "service=nodeA,service2=nodeB ", PARAMLIST),
3386 ('node', "Load config for <nodename>", PARAM),
3387 ('cleanup,d', "Cleans up config. (Shutdown)"),
3388 ('force,f', "Forced unmounting and/or obd detach during cleanup",
3390 ('single_socket', "socknal option: only use one socket instead of bundle",
3392 ('failover',"""Used to shut down without saving state.
3393 This will allow this node to "give up" a service to a
3394 another node for failover purposes. This will not
3395 be a clean shutdown.""",
3397 ('gdb', """Prints message after creating gdb module script
3398 and sleeps for 5 seconds."""),
3399 ('noexec,n', """Prints the commands and steps that will be run for a
3400 config without executing them. This can used to check if a
3401 config file is doing what it should be doing"""),
3402 ('nomod', "Skip load/unload module step."),
3403 ('nosetup', "Skip device setup/cleanup step."),
3404 ('reformat', "Reformat all devices (without question)"),
3405 ('mkfsoptions', "Additional options for the mk*fs command line", PARAM),
3406 ('mountfsoptions', "Additional options for mount fs command line", PARAM),
3407 ('clientoptions', "Additional options for Lustre", PARAM),
3408 ('dump', "Dump the kernel debug log to file before portals is unloaded",
3410 ('write_conf', "Save all the client config information on mds."),
3411 ('record', "Write config information on mds."),
3412 ('record_log', "Name of config record log.", PARAM),
3413 ('record_device', "MDS device name that will record the config commands",
3415 ('root_squash', "MDS squash root to appointed uid",
3417 ('no_root_squash', "Don't squash root for appointed nid",
3419 ('minlevel', "Minimum level of services to configure/cleanup",
3421 ('maxlevel', """Maximum level of services to configure/cleanup
3422 Levels are aproximatly like:
3427 70 - mountpoint, echo_client, osc, mdc, lov""",
3429 ('lustre', """Base directory of lustre sources. This parameter will
3430 cause lconf to load modules from a source tree.""", PARAM),
3431 ('portals', """Portals source directory. If this is a relative path,
3432 then it is assumed to be relative to lustre. """, PARAM),
3433 ('timeout', "Set recovery timeout", INTPARAM),
3434 ('upcall', "Set both portals and lustre upcall script", PARAM),
3435 ('lustre_upcall', "Set lustre upcall script", PARAM),
3436 ('portals_upcall', "Set portals upcall script", PARAM),
3437 ('lctl_dump', "Save lctl ioctls to the dumpfile argument", PARAM),
3438 ('ptldebug', "Set the portals debug level", PARAM),
3439 ('subsystem', "Set the portals debug subsystem", PARAM),
3440 ('gdb_script', "Fullname of gdb debug script", PARAM, default_gdb_script()),
3441 ('debug_path', "Path to save debug dumps", PARAM, default_debug_path()),
3442 # Client recovery options
3443 ('recover', "Recover a device"),
3444 ('group', "The group of devices to configure or cleanup", PARAM),
3445 ('tgt_uuid', "The failed target (required for recovery)", PARAM),
3446 ('client_uuid', "The failed client (required for recovery)", PARAM),
3447 ('conn_uuid', "The failed connection (required for recovery)", PARAM),
3449 ('inactive', """The name of an inactive service, to be ignored during
3450 mounting (currently OST-only). Can be repeated.""",
3455 global lctl, config, toplustreDB, CONFIG_FILE
3457 # in the upcall this is set to SIG_IGN
3458 signal.signal(signal.SIGCHLD, signal.SIG_DFL)
3460 cl = Lustre.Options("lconf", "config.xml", lconf_options)
3462 config, args = cl.parse(sys.argv[1:])
3463 except Lustre.OptionError, e:
3467 setupModulePath(sys.argv[0])
3469 host = socket.gethostname()
3471 # the PRNG is normally seeded with time(), which is not so good for starting
3472 # time-synchronized clusters
3473 input = open('/dev/urandom', 'r')
3475 print 'Unable to open /dev/urandom!'
3477 seed = input.read(32)
3483 init_select(config.select)
3486 # allow config to be fetched via HTTP, but only with python2
3487 if sys.version[0] != '1' and args[0].startswith('http://'):
3490 config_file = urllib2.urlopen(args[0])
3491 except (urllib2.URLError, socket.error), err:
3492 if hasattr(err, 'args'):
3494 print "Could not access '%s': %s" %(args[0], err)
3496 elif not os.access(args[0], os.R_OK):
3497 print 'File not found or readable:', args[0]
3501 config_file = open(args[0], 'r')
3503 dom = xml.dom.minidom.parse(config_file)
3505 panic("%s does not appear to be a config file." % (args[0]))
3506 sys.exit(1) # make sure to die here, even in debug mode.
3508 CONFIG_FILE = args[0]
3509 lustreDB = Lustre.LustreDB_XML(dom.documentElement, dom.documentElement)
3510 if not config.config:
3511 config.config = os.path.basename(args[0])# use full path?
3512 if config.config[-4:] == '.xml':
3513 config.config = config.config[:-4]
3514 elif config.ldapurl:
3515 if not config.config:
3516 panic("--ldapurl requires --config name")
3517 dn = "config=%s,fs=lustre" % (config.config)
3518 lustreDB = Lustre.LustreDB_LDAP('', {}, base=dn, url = config.ldapurl)
3519 elif config.ptldebug or config.subsystem:
3520 sys_set_ptldebug(None)
3521 sys_set_subsystem(None)
3524 print 'Missing config file or ldap URL.'
3525 print 'see lconf --help for command summary'
3528 toplustreDB = lustreDB
3530 ver = lustreDB.get_version()
3532 panic("No version found in config data, please recreate.")
3533 if ver != Lustre.CONFIG_VERSION:
3534 panic("Config version", ver, "does not match lconf version",
3535 Lustre.CONFIG_VERSION)
3539 node_list.append(config.node)
3542 node_list.append(host)
3543 node_list.append('localhost')
3545 debug("configuring for host: ", node_list)
3548 config.debug_path = config.debug_path + '-' + host
3549 config.gdb_script = config.gdb_script + '-' + host
3551 lctl = LCTLInterface('lctl')
3553 if config.lctl_dump:
3554 lctl.use_save_file(config.lctl_dump)
3557 if not (config.record_device and config.record_log):
3558 panic("When recording, both --record_log and --record_device must be specified.")
3559 lctl.clear_log(config.record_device, config.record_log)
3560 lctl.record(config.record_device, config.record_log)
3562 doHost(lustreDB, node_list)
3564 if not config.record:
3569 process_updates(lustreDB, config.record_device, config.record_log)
3571 if __name__ == "__main__":
3574 except Lustre.LconfError, e:
3576 # traceback.print_exc(file=sys.stdout)
3578 except CommandError, e:
3582 if first_cleanup_error:
3583 sys.exit(first_cleanup_error)