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),
121 "confobd" : (1 << 25),
128 first_cleanup_error = 0
129 def cleanup_error(rc):
130 global first_cleanup_error
131 if not first_cleanup_error:
132 first_cleanup_error = rc
134 # ============================================================
135 # debugging and error funcs
137 def fixme(msg = "this feature"):
138 raise Lustre.LconfError, msg + ' not implemented yet.'
141 msg = string.join(map(str,args))
142 if not config.noexec:
143 raise Lustre.LconfError(msg)
148 msg = string.join(map(str,args))
153 print string.strip(s)
157 msg = string.join(map(str,args))
160 # ack, python's builtin int() does not support '0x123' syntax.
161 # eval can do it, although what a hack!
165 return eval(s, {}, {})
168 except SyntaxError, e:
169 raise ValueError("not a number")
171 raise ValueError("not a number")
173 # ============================================================
174 # locally defined exceptions
175 class CommandError (exceptions.Exception):
176 def __init__(self, cmd_name, cmd_err, rc=None):
177 self.cmd_name = cmd_name
178 self.cmd_err = cmd_err
183 if type(self.cmd_err) == types.StringType:
185 print "! %s (%d): %s" % (self.cmd_name, self.rc, self.cmd_err)
187 print "! %s: %s" % (self.cmd_name, self.cmd_err)
188 elif type(self.cmd_err) == types.ListType:
190 print "! %s (error %d):" % (self.cmd_name, self.rc)
192 print "! %s:" % (self.cmd_name)
193 for s in self.cmd_err:
194 print "> %s" %(string.strip(s))
199 # ============================================================
200 # handle daemons, like the acceptor
202 """ Manage starting and stopping a daemon. Assumes daemon manages
203 it's own pid file. """
205 def __init__(self, cmd):
211 log(self.command, "already running.")
213 self.path = find_prog(self.command)
215 panic(self.command, "not found.")
216 ret, out = runcmd(self.path +' '+ self.command_line())
218 raise CommandError(self.path, out, ret)
222 pid = self.read_pidfile()
225 log ("killing process", pid)
228 log("was unable to find pid of " + self.command)
229 #time.sleep(1) # let daemon die
231 log("unable to kill", self.command, e)
233 log("unable to kill", self.command)
236 pid = self.read_pidfile()
242 log("was unable to find pid of " + self.command)
249 def read_pidfile(self):
251 fp = open(self.pidfile(), 'r')
261 def clean_pidfile(self):
262 """ Remove a stale pidfile """
263 log("removing stale pidfile:", self.pidfile())
265 os.unlink(self.pidfile())
267 log(self.pidfile(), e)
269 class AcceptorHandler(DaemonHandler):
270 def __init__(self, port, net_type):
271 DaemonHandler.__init__(self, "acceptor")
276 return "/var/run/%s-%d.pid" % (self.command, self.port)
278 def command_line(self):
279 return string.join(map(str,(self.flags, self.port)))
283 # start the acceptors
285 if config.lctl_dump or config.record:
287 for port in acceptors.keys():
288 daemon = acceptors[port]
289 if not daemon.running():
292 def run_one_acceptor(port):
293 if config.lctl_dump or config.record:
295 if acceptors.has_key(port):
296 daemon = acceptors[port]
297 if not daemon.running():
300 panic("run_one_acceptor: No acceptor defined for port:", port)
302 def stop_acceptor(port):
303 if acceptors.has_key(port):
304 daemon = acceptors[port]
309 # ============================================================
310 # handle lctl interface
313 Manage communication with lctl
316 def __init__(self, cmd):
318 Initialize close by finding the lctl binary.
320 self.lctl = find_prog(cmd)
322 self.record_device = ''
325 debug('! lctl not found')
328 raise CommandError('lctl', "unable to find lctl binary.")
330 def use_save_file(self, file):
331 self.save_file = file
333 def record(self, dev_name, logname):
334 log("Recording log", logname, "on", dev_name)
335 self.record_device = dev_name
336 self.record_log = logname
338 def end_record(self):
339 log("End recording log", self.record_log, "on", self.record_device)
340 self.record_device = None
341 self.record_log = None
343 def set_nonblock(self, fd):
344 fl = fcntl.fcntl(fd, F_GETFL)
345 fcntl.fcntl(fd, F_SETFL, fl | os.O_NDELAY)
350 the cmds are written to stdin of lctl
351 lctl doesn't return errors when run in script mode, so
353 should modify command line to accept multiple commands, or
354 create complex command line options
358 cmds = '\n dump ' + self.save_file + '\n' + cmds
359 elif self.record_device:
363 %s""" % (self.record_device, self.record_log, cmds)
365 debug("+", cmd_line, cmds)
366 if config.noexec: return (0, [])
368 child = popen2.Popen3(cmd_line, 1) # Capture stdout and stderr from command
369 child.tochild.write(cmds + "\n")
370 child.tochild.close()
371 # print "LCTL:", cmds
373 # From "Python Cookbook" from O'Reilly
374 outfile = child.fromchild
375 outfd = outfile.fileno()
376 self.set_nonblock(outfd)
377 errfile = child.childerr
378 errfd = errfile.fileno()
379 self.set_nonblock(errfd)
381 outdata = errdata = ''
384 ready = select.select([outfd,errfd],[],[]) # Wait for input
385 if outfd in ready[0]:
386 outchunk = outfile.read()
387 if outchunk == '': outeof = 1
388 outdata = outdata + outchunk
389 if errfd in ready[0]:
390 errchunk = errfile.read()
391 if errchunk == '': erreof = 1
392 errdata = errdata + errchunk
393 if outeof and erreof: break
394 # end of "borrowed" code
397 if os.WIFEXITED(ret):
398 rc = os.WEXITSTATUS(ret)
401 if rc or len(errdata):
402 raise CommandError(self.lctl, errdata, rc)
405 def runcmd(self, *args):
407 run lctl using the command line
409 cmd = string.join(map(str,args))
410 debug("+", self.lctl, cmd)
411 rc, out = run(self.lctl, cmd)
413 raise CommandError(self.lctl, out, rc)
416 def clear_log(self, dev, log):
417 """ clear an existing log """
422 quit """ % (dev, log)
425 def root_squash(self, name, uid, nid):
429 quit""" % (name, uid, nid)
432 def network(self, net, nid):
437 quit """ % (net, nid)
441 def add_interface(self, net, ip, netmask = ""):
442 """ add an interface """
446 quit """ % (net, ip, netmask)
449 # delete an interface
450 def del_interface(self, net, ip):
451 """ delete an interface """
458 # create a new connection
459 def add_uuid(self, net_type, uuid, nid):
460 cmds = "\n add_uuid %s %s %s" %(uuid, nid, net_type)
463 def add_peer(self, net_type, nid, hostaddr, port):
464 if net_type in ('tcp',) and not config.lctl_dump:
469 nid, hostaddr, port )
471 elif net_type in ('openib','iib',) and not config.lctl_dump:
479 def connect(self, srv):
480 self.add_uuid(srv.net_type, srv.nid_uuid, srv.nid)
481 if srv.net_type in ('tcp','openib','iib',) and not config.lctl_dump:
483 hostaddr = string.split(srv.hostaddr[0], '/')[0]
484 self.add_peer(srv.net_type, srv.nid, hostaddr, srv.port)
487 def recover(self, dev_name, new_conn):
490 recover %s""" %(dev_name, new_conn)
493 # add a route to a range
494 def add_route(self, net, gw, lo, hi):
502 except CommandError, e:
506 def del_route(self, net, gw, lo, hi):
511 quit """ % (net, gw, lo, hi)
514 # add a route to a host
515 def add_route_host(self, net, uuid, gw, tgt):
516 self.add_uuid(net, uuid, tgt)
524 except CommandError, e:
528 # add a route to a range
529 def del_route_host(self, net, uuid, gw, tgt):
535 quit """ % (net, gw, tgt)
539 def del_peer(self, net_type, nid, hostaddr):
540 if net_type in ('tcp',) and not config.lctl_dump:
544 del_peer %s %s single_share
548 elif net_type in ('openib','iib',) and not config.lctl_dump:
552 del_peer %s single_share
557 # disconnect one connection
558 def disconnect(self, srv):
559 self.del_uuid(srv.nid_uuid)
560 if srv.net_type in ('tcp','openib','iib',) and not config.lctl_dump:
562 hostaddr = string.split(srv.hostaddr[0], '/')[0]
563 self.del_peer(srv.net_type, srv.nid, hostaddr)
565 def del_uuid(self, uuid):
573 def disconnectAll(self, net):
581 def attach(self, type, name, uuid):
584 quit""" % (type, name, uuid)
587 def setup(self, name, setup = ""):
591 quit""" % (name, setup)
594 def add_conn(self, name, conn_uuid):
598 quit""" % (name, conn_uuid)
602 # create a new device with lctl
603 def newdev(self, type, name, uuid, setup = ""):
604 self.attach(type, name, uuid);
606 self.setup(name, setup)
607 except CommandError, e:
608 self.cleanup(name, uuid, 0)
613 def cleanup(self, name, uuid, force, failover = 0):
614 if failover: force = 1
620 quit""" % (name, ('', 'force')[force],
621 ('', 'failover')[failover])
625 def lov_setup(self, name, uuid, desc_uuid, stripe_cnt,
626 stripe_sz, stripe_off, pattern, devlist = None):
629 lov_setup %s %d %d %d %s %s
630 quit""" % (name, uuid, desc_uuid, stripe_cnt, stripe_sz, stripe_off,
634 # add an OBD to a LOV
635 def lov_add_obd(self, name, uuid, obd_uuid, index, gen):
637 lov_modify_tgts add %s %s %s %s
638 quit""" % (name, obd_uuid, index, gen)
642 def lmv_setup(self, name, uuid, desc_uuid, devlist):
646 quit""" % (name, uuid, desc_uuid, devlist)
649 # delete an OBD from a LOV
650 def lov_del_obd(self, name, uuid, obd_uuid, index, gen):
652 lov_modify_tgts del %s %s %s %s
653 quit""" % (name, obd_uuid, index, gen)
657 def deactivate(self, name):
665 def dump(self, dump_file):
668 quit""" % (dump_file)
671 # get list of devices
672 def device_list(self):
673 devices = '/proc/fs/lustre/devices'
675 if os.access(devices, os.R_OK):
677 fp = open(devices, 'r')
685 def lustre_version(self):
686 rc, out = self.runcmd('version')
690 def mount_option(self, profile, osc, mdc):
692 mount_option %s %s %s
693 quit""" % (profile, osc, mdc)
696 # delete mount options
697 def del_mount_option(self, profile):
703 def set_timeout(self, timeout):
709 def set_lustre_upcall(self, upcall):
714 # ============================================================
715 # Various system-level functions
716 # (ideally moved to their own module)
718 # Run a command and return the output and status.
719 # stderr is sent to /dev/null, could use popen3 to
720 # save it if necessary
723 if config.noexec: return (0, [])
724 f = os.popen(cmd + ' 2>&1')
734 cmd = string.join(map(str,args))
737 # Run a command in the background.
738 def run_daemon(*args):
739 cmd = string.join(map(str,args))
741 if config.noexec: return 0
742 f = os.popen(cmd + ' 2>&1')
750 # Determine full path to use for an external command
751 # searches dirname(argv[0]) first, then PATH
753 syspath = string.split(os.environ['PATH'], ':')
754 cmdpath = os.path.dirname(sys.argv[0])
755 syspath.insert(0, cmdpath);
757 syspath.insert(0, os.path.join(config.portals, 'utils/'))
759 prog = os.path.join(d,cmd)
760 if os.access(prog, os.X_OK):
764 # Recursively look for file starting at base dir
765 def do_find_file(base, mod):
766 fullname = os.path.join(base, mod)
767 if os.access(fullname, os.R_OK):
769 for d in os.listdir(base):
770 dir = os.path.join(base,d)
771 if os.path.isdir(dir):
772 module = do_find_file(dir, mod)
776 # is the path a block device?
783 return stat.S_ISBLK(s[stat.ST_MODE])
785 # find the journal device from mkfs options
791 while i < len(x) - 1:
792 if x[i] == '-J' and x[i+1].startswith('device='):
798 # build fs according to type
800 def mkfs(dev, devsize, fstype, jsize, isize, mkfsoptions, isblock=1):
806 panic("size of filesystem on '%s' must be larger than 8MB, but is set to %s"%
808 # devsize is in 1k, and fs block count is in 4k
809 block_cnt = devsize/4
811 if fstype in ('ext3', 'extN', 'ldiskfs'):
812 # ext3 journal size is in megabytes
813 # but don't set jsize if mkfsoptions indicates a separate journal device
814 if jsize == 0 and jdev(mkfsoptions) == '':
816 if not is_block(dev):
817 ret, out = runcmd("ls -l %s" %dev)
818 devsize = int(string.split(out[0])[4]) / 1024
820 # sfdisk works for symlink, hardlink, and realdev
821 ret, out = runcmd("sfdisk -s %s" %dev)
823 devsize = int(out[0])
825 # sfdisk -s will fail for too large block device,
826 # then, read the size of partition from /proc/partitions
828 # get the realpath of the device
829 # it may be the real device, such as /dev/hda7
830 # or the hardlink created via mknod for a device
831 if 'realpath' in dir(os.path):
832 real_dev = os.path.realpath(dev)
836 while os.path.islink(real_dev) and (link_count < 20):
837 link_count = link_count + 1
838 dev_link = os.readlink(real_dev)
839 if os.path.isabs(dev_link):
842 real_dev = os.path.join(os.path.dirname(real_dev), dev_link)
844 panic("Entountered too many symbolic links resolving block device:", dev)
846 # get the major and minor number of the realpath via ls
847 # it seems python(os.stat) does not return
848 # the st_rdev member of the stat structure
849 ret, out = runcmd("ls -l %s" %real_dev)
850 major = string.split(string.split(out[0])[4], ",")[0]
851 minor = string.split(out[0])[5]
853 # get the devsize from /proc/partitions with the major and minor number
854 ret, out = runcmd("cat /proc/partitions")
857 if string.split(line)[0] == major and string.split(line)[1] == minor:
858 devsize = int(string.split(line)[2])
861 if devsize > 1024 * 1024:
862 jsize = ((devsize / 102400) * 4)
865 if jsize: jopt = "-J size=%d" %(jsize,)
866 if isize: iopt = "-I %d" %(isize,)
867 mkfs = 'mkfs.ext2 -j -b 4096 '
868 if not isblock or config.force:
870 if jdev(mkfsoptions) != '':
871 jmkfs = 'mkfs.ext2 -b 4096 -O journal_dev '
873 jmkfs = jmkfs + '-F '
874 jmkfs = jmkfs + jdev(mkfsoptions)
875 (ret, out) = run (jmkfs)
877 panic("Unable format journal device:", jdev(mkfsoptions), string.join(out))
878 elif fstype == 'reiserfs':
879 # reiserfs journal size is in blocks
880 if jsize: jopt = "--journal_size %d" %(jsize,)
881 mkfs = 'mkreiserfs -ff'
883 panic('unsupported fs type: ', fstype)
885 if config.mkfsoptions != None:
886 mkfs = mkfs + ' ' + config.mkfsoptions
887 if mkfsoptions != None:
888 mkfs = mkfs + ' ' + mkfsoptions
889 (ret, out) = run (mkfs, jopt, iopt, dev, block_cnt)
891 panic("Unable to build fs:", dev, string.join(out))
892 # enable hash tree indexing on fsswe
893 if fstype in ('ext3', 'extN', 'ldiskfs'):
894 htree = 'echo "feature FEATURE_C5" | debugfs -w'
895 (ret, out) = run (htree, dev)
897 panic("Unable to enable htree:", dev)
899 # some systems use /dev/loopN, some /dev/loop/N
903 if not os.access(loop + str(0), os.R_OK):
905 if not os.access(loop + str(0), os.R_OK):
906 panic ("can't access loop devices")
909 # find loop device assigned to the file
910 def find_assigned_loop(file):
912 for n in xrange(0, MAX_LOOP_DEVICES):
914 if os.access(dev, os.R_OK):
915 (stat, out) = run('losetup', dev)
916 if out and stat == 0:
917 m = re.search(r'\((.*)\)', out[0])
918 if m and file == m.group(1):
924 # create file if necessary and assign the first free loop device
925 def init_loop(file, size, fstype, journal_size, inode_size,
926 mkfsoptions, reformat, autoformat, backfstype, backfile):
929 realfstype = backfstype
930 if is_block(backfile):
931 if reformat or (need_format(realfstype, backfile) and autoformat == 'yes'):
932 mkfs(realfile, size, realfstype, journal_size, inode_size, mkfsoptions, isblock=0)
938 dev = find_assigned_loop(realfile)
940 print 'WARNING: file ', realfile, 'already mapped to', dev
943 if reformat or not os.access(realfile, os.R_OK | os.W_OK):
945 panic("size of loopback file '%s' must be larger than 8MB, but is set to %s" % (realfile, size))
946 (ret, out) = run("dd if=/dev/zero bs=1k count=0 seek=%d of=%s" %(size, realfile))
948 panic("Unable to create backing store:", realfile)
950 mkfs(realfile, size, realfstype, journal_size, inode_size,
951 mkfsoptions, isblock=0)
954 # find next free loop
955 for n in xrange(0, MAX_LOOP_DEVICES):
957 if os.access(dev, os.R_OK):
958 (stat, out) = run('losetup', dev)
960 print "attach " + realfile + " <-> " + dev
961 run('losetup', dev, realfile)
964 print "out of loop devices"
966 print "out of loop devices"
969 # undo loop assignment
970 def clean_loop(dev, fstype, backfstype, backdev):
975 if not is_block(realfile):
976 dev = find_assigned_loop(realfile)
978 print "detach " + dev + " <-> " + realfile
979 ret, out = run('losetup -d', dev)
981 log('unable to clean loop device:', dev, 'for file:', realfile)
984 # finilizes passed device
985 def clean_dev(dev, fstype, backfstype, backdev):
986 if fstype == 'smfs' or not is_block(dev):
987 clean_loop(dev, fstype, backfstype, backdev)
989 # determine if dev is formatted as a <fstype> filesystem
990 def need_format(fstype, dev):
991 # FIXME don't know how to implement this
994 # initialize a block device if needed
995 def block_dev(dev, size, fstype, reformat, autoformat, journal_size,
996 inode_size, mkfsoptions, backfstype, backdev):
1000 if fstype == 'smfs' or not is_block(dev):
1001 dev = init_loop(dev, size, fstype, journal_size, inode_size,
1002 mkfsoptions, reformat, autoformat, backfstype, backdev)
1003 elif reformat or (need_format(fstype, dev) and autoformat == 'yes'):
1004 mkfs(dev, size, fstype, journal_size, inode_size, mkfsoptions,
1007 # panic("device:", dev,
1008 # "not prepared, and autoformat is not set.\n",
1009 # "Rerun with --reformat option to format ALL filesystems")
1014 """lookup IP address for an interface"""
1015 rc, out = run("/sbin/ifconfig", iface)
1018 addr = string.split(out[1])[1]
1019 ip = string.split(addr, ':')[1]
1022 def def_mount_options(fstype, target):
1023 """returns deafult mount options for passed fstype and target (mds, ost)"""
1024 if fstype == 'ext3' or fstype == 'ldiskfs':
1025 mountfsoptions = "errors=remount-ro"
1026 if target == 'ost' and sys_get_branch() == '2.4':
1027 mountfsoptions = "%s,asyncdel" % (mountfsoptions)
1028 return mountfsoptions
1031 def sys_get_elan_position_file():
1032 procfiles = ["/proc/elan/device0/position",
1033 "/proc/qsnet/elan4/device0/position",
1034 "/proc/qsnet/elan3/device0/position"]
1036 if os.access(p, os.R_OK):
1040 def sys_get_local_nid(net_type, wildcard, cluster_id):
1041 """Return the local nid."""
1043 if sys_get_elan_position_file():
1044 local = sys_get_local_address('elan', '*', cluster_id)
1046 local = sys_get_local_address(net_type, wildcard, cluster_id)
1049 def sys_get_local_address(net_type, wildcard, cluster_id):
1050 """Return the local address for the network type."""
1052 if net_type in ('tcp','openib','iib',):
1054 iface, star = string.split(wildcard, ':')
1055 local = if2addr(iface)
1057 panic ("unable to determine ip for:", wildcard)
1059 host = socket.gethostname()
1060 local = socket.gethostbyname(host)
1061 elif net_type == 'elan':
1062 # awk '/NodeId/ { print $2 }' 'sys_get_elan_position_file()'
1063 f = sys_get_elan_position_file()
1065 panic ("unable to determine local Elan ID")
1068 lines = fp.readlines()
1072 if a[0] == 'NodeId':
1076 nid = my_int(cluster_id) + my_int(elan_id)
1077 local = "%d" % (nid)
1078 except ValueError, e:
1082 elif net_type == 'lo':
1083 fixme("automatic local address for loopback")
1084 elif net_type == 'gm':
1085 fixme("automatic local address for GM")
1089 def sys_get_branch():
1090 """Returns kernel release"""
1092 fp = open('/proc/sys/kernel/osrelease')
1093 lines = fp.readlines()
1097 version = string.split(l)
1098 a = string.split(version[0], '.')
1099 return a[0] + '.' + a[1]
1104 # XXX: instead of device_list, ask for $name and see what we get
1105 def is_prepared(name):
1106 """Return true if a device exists for the name"""
1107 if config.lctl_dump:
1109 if (config.noexec or config.record) and config.cleanup:
1112 # expect this format:
1113 # 1 UP ldlm ldlm ldlm_UUID 2
1114 out = lctl.device_list()
1116 if name == string.split(s)[3]:
1118 except CommandError, e:
1122 def net_is_prepared():
1123 """If the any device exists, then assume that all networking
1124 has been configured"""
1125 out = lctl.device_list()
1128 def fs_is_mounted(path):
1129 """Return true if path is a mounted lustre filesystem"""
1131 fp = open('/proc/mounts')
1132 lines = fp.readlines()
1136 if a[1] == path and a[2] == 'lustre_lite':
1142 def kmod_find(src_dir, dev_dir, modname):
1143 modbase = src_dir +'/'+ dev_dir +'/'+ modname
1144 for modext in '.ko', '.o':
1145 module = modbase + modext
1147 if os.access(module, os.R_OK):
1153 def kmod_info(modname):
1154 """Returns reference count for passed module name."""
1156 fp = open('/proc/modules')
1157 lines = fp.readlines()
1160 # please forgive my tired fingers for this one
1161 ret = filter(lambda word, mod = modname: word[0] == mod,
1162 map(lambda line: string.split(line), lines))
1166 except Exception, e:
1170 """Presents kernel module"""
1171 def __init__(self, src_dir, dev_dir, name):
1172 self.src_dir = src_dir
1173 self.dev_dir = dev_dir
1178 log ('loading module:', self.name, 'srcdir',
1179 self.src_dir, 'devdir', self.dev_dir)
1181 module = kmod_find(self.src_dir, self.dev_dir,
1184 panic('module not found:', self.name)
1185 (rc, out) = run('/sbin/insmod', module)
1187 raise CommandError('insmod', out, rc)
1189 (rc, out) = run('/sbin/modprobe', self.name)
1191 raise CommandError('modprobe', out, rc)
1195 log('unloading module:', self.name)
1196 (rc, out) = run('/sbin/rmmod', self.name)
1198 log('unable to unload module:', self.name +
1199 "(" + self.refcount() + ")")
1203 """Returns module info if any."""
1204 return kmod_info(self.name)
1207 """Returns 1 if module is loaded. Otherwise 0 is returned."""
1214 """Returns module refcount."""
1221 """Returns 1 if module is used, otherwise 0 is returned."""
1227 if users and users != '(unused)' and users != '-':
1235 """Returns 1 if module is busy, otherwise 0 is returned."""
1236 if self.loaded() and (self.used() or self.refcount() != '0'):
1242 """Manage kernel modules"""
1243 def __init__(self, lustre_dir, portals_dir):
1244 self.lustre_dir = lustre_dir
1245 self.portals_dir = portals_dir
1246 self.kmodule_list = []
1248 def find_module(self, modname):
1249 """Find module by module name"""
1250 for mod in self.kmodule_list:
1251 if mod.name == modname:
1255 def add_portals_module(self, dev_dir, modname):
1256 """Append a module to list of modules to load."""
1258 mod = self.find_module(modname)
1260 mod = kmod(self.portals_dir, dev_dir, modname)
1261 self.kmodule_list.append(mod)
1263 def add_lustre_module(self, dev_dir, modname):
1264 """Append a module to list of modules to load."""
1266 mod = self.find_module(modname)
1268 mod = kmod(self.lustre_dir, dev_dir, modname)
1269 self.kmodule_list.append(mod)
1271 def load_modules(self):
1272 """Load all the modules in the list in the order they appear."""
1273 for mod in self.kmodule_list:
1274 if mod.loaded() and not config.noexec:
1278 def cleanup_modules(self):
1279 """Unload the modules in the list in reverse order."""
1280 rev = self.kmodule_list
1283 if (not mod.loaded() or mod.busy()) and not config.noexec:
1286 if mod.name == 'portals' and config.dump:
1287 lctl.dump(config.dump)
1290 # ============================================================
1291 # Classes to prepare and cleanup the various objects
1294 """ Base class for the rest of the modules. The default cleanup method is
1295 defined here, as well as some utilitiy funcs.
1297 def __init__(self, module_name, db):
1299 self.module_name = module_name
1300 self.name = self.db.getName()
1301 self.uuid = self.db.getUUID()
1305 def info(self, *args):
1306 msg = string.join(map(str,args))
1307 print self.module_name + ":", self.name, self.uuid, msg
1310 """ default cleanup, used for most modules """
1313 lctl.cleanup(self.name, self.uuid, config.force)
1314 except CommandError, e:
1315 log(self.module_name, "cleanup failed: ", self.name)
1319 def add_module(self, manager):
1320 """Adds all needed modules in the order they appear."""
1323 def safe_to_clean(self):
1326 def safe_to_clean_modules(self):
1327 return self.safe_to_clean()
1329 class Network(Module):
1330 def __init__(self,db):
1331 Module.__init__(self, 'NETWORK', db)
1332 self.net_type = self.db.get_val('nettype')
1333 self.nid = self.db.get_val('nid', '*')
1334 self.cluster_id = self.db.get_val('clusterid', "0")
1335 self.port = self.db.get_val_int('port', 0)
1338 self.nid = sys_get_local_nid(self.net_type, self.nid, self.cluster_id)
1340 panic("unable to set nid for", self.net_type, self.nid, cluster_id)
1341 self.generic_nid = 1
1342 debug("nid:", self.nid)
1344 self.generic_nid = 0
1346 self.nid_uuid = self.nid_to_uuid(self.nid)
1347 self.hostaddr = self.db.get_hostaddr()
1348 if len(self.hostaddr) == 0:
1349 self.hostaddr.append(self.nid)
1350 if '*' in self.hostaddr[0]:
1351 self.hostaddr[0] = sys_get_local_address(self.net_type, self.hostaddr[0], self.cluster_id)
1352 if not self.hostaddr[0]:
1353 panic("unable to set hostaddr for", self.net_type, self.hostaddr[0], self.cluster_id)
1354 debug("hostaddr:", self.hostaddr[0])
1356 def add_module(self, manager):
1357 manager.add_portals_module("libcfs", 'libcfs')
1358 manager.add_portals_module("portals", 'portals')
1359 if node_needs_router():
1360 manager.add_portals_module("router", 'kptlrouter')
1361 if self.net_type == 'tcp':
1362 manager.add_portals_module("knals/socknal", 'ksocknal')
1363 if self.net_type == 'elan':
1364 manager.add_portals_module("knals/qswnal", 'kqswnal')
1365 if self.net_type == 'gm':
1366 manager.add_portals_module("knals/gmnal", 'kgmnal')
1367 if self.net_type == 'openib':
1368 manager.add_portals_module("knals/openibnal", 'kopenibnal')
1369 if self.net_type == 'iib':
1370 manager.add_portals_module("knals/iibnal", 'kiibnal')
1371 if self.net_type == 'lo':
1372 manager.add_portals_module("knals/lonal", 'klonal')
1374 def nid_to_uuid(self, nid):
1375 return "NID_%s_UUID" %(nid,)
1378 if not config.record and net_is_prepared():
1380 self.info(self.net_type, self.nid, self.port)
1381 if not (config.record and self.generic_nid):
1382 lctl.network(self.net_type, self.nid)
1383 if self.net_type == 'tcp':
1385 for hostaddr in self.db.get_hostaddr():
1386 ip = string.split(hostaddr, '/')[0]
1387 if len(string.split(hostaddr, '/')) == 2:
1388 netmask = string.split(hostaddr, '/')[1]
1391 lctl.add_interface(self.net_type, ip, netmask)
1392 if self.net_type == 'elan':
1394 if self.port and node_is_router():
1395 run_one_acceptor(self.port)
1396 self.connect_peer_gateways()
1398 def connect_peer_gateways(self):
1399 for router in self.db.lookup_class('node'):
1400 if router.get_val_int('router', 0):
1401 for netuuid in router.get_networks():
1402 net = self.db.lookup(netuuid)
1404 if (gw.cluster_id == self.cluster_id and
1405 gw.net_type == self.net_type):
1406 if gw.nid != self.nid:
1409 def disconnect_peer_gateways(self):
1410 for router in self.db.lookup_class('node'):
1411 if router.get_val_int('router', 0):
1412 for netuuid in router.get_networks():
1413 net = self.db.lookup(netuuid)
1415 if (gw.cluster_id == self.cluster_id and
1416 gw.net_type == self.net_type):
1417 if gw.nid != self.nid:
1420 except CommandError, e:
1421 print "disconnect failed: ", self.name
1425 def safe_to_clean(self):
1426 return not net_is_prepared()
1429 self.info(self.net_type, self.nid, self.port)
1431 stop_acceptor(self.port)
1432 if node_is_router():
1433 self.disconnect_peer_gateways()
1434 if self.net_type == 'tcp':
1435 for hostaddr in self.db.get_hostaddr():
1436 ip = string.split(hostaddr, '/')[0]
1437 lctl.del_interface(self.net_type, ip)
1439 def correct_level(self, level, op=None):
1442 class RouteTable(Module):
1443 def __init__(self,db):
1444 Module.__init__(self, 'ROUTES', db)
1446 def server_for_route(self, net_type, gw, gw_cluster_id, tgt_cluster_id,
1448 # only setup connections for tcp, openib, and iib NALs
1450 if not net_type in ('tcp','openib','iib',):
1453 # connect to target if route is to single node and this node is the gw
1454 if lo == hi and local_interface(net_type, gw_cluster_id, gw):
1455 if not local_cluster(net_type, tgt_cluster_id):
1456 panic("target", lo, " not on the local cluster")
1457 srvdb = self.db.nid2server(lo, net_type, gw_cluster_id)
1458 # connect to gateway if this node is not the gw
1459 elif (local_cluster(net_type, gw_cluster_id)
1460 and not local_interface(net_type, gw_cluster_id, gw)):
1461 srvdb = self.db.nid2server(gw, net_type, gw_cluster_id)
1466 panic("no server for nid", lo)
1469 return Network(srvdb)
1472 if not config.record and net_is_prepared():
1475 for net_type, gw, gw_cluster_id, tgt_cluster_id, lo, hi in self.db.get_route_tbl():
1476 lctl.add_route(net_type, gw, lo, hi)
1477 srv = self.server_for_route(net_type, gw, gw_cluster_id, tgt_cluster_id, lo, hi)
1481 def safe_to_clean(self):
1482 return not net_is_prepared()
1485 if net_is_prepared():
1486 # the network is still being used, don't clean it up
1488 for net_type, gw, gw_cluster_id, tgt_cluster_id, lo, hi in self.db.get_route_tbl():
1489 srv = self.server_for_route(net_type, gw, gw_cluster_id, tgt_cluster_id, lo, hi)
1492 lctl.disconnect(srv)
1493 except CommandError, e:
1494 print "disconnect failed: ", self.name
1499 lctl.del_route(net_type, gw, lo, hi)
1500 except CommandError, e:
1501 print "del_route failed: ", self.name
1505 class Management(Module):
1506 def __init__(self, db):
1507 Module.__init__(self, 'MGMT', db)
1509 def add_module(self, manager):
1510 manager.add_lustre_module('lvfs', 'lvfs')
1511 manager.add_lustre_module('obdclass', 'obdclass')
1512 manager.add_lustre_module('ptlrpc', 'ptlrpc')
1513 manager.add_lustre_module('mgmt', 'mgmt_svc')
1516 if not config.record and is_prepared(self.name):
1519 lctl.newdev("mgmt", self.name, self.uuid)
1521 def safe_to_clean(self):
1525 if is_prepared(self.name):
1526 Module.cleanup(self)
1528 def correct_level(self, level, op=None):
1531 # This is only needed to load the modules; the LDLM device
1532 # is now created automatically.
1534 def __init__(self,db):
1535 Module.__init__(self, 'LDLM', db)
1537 def add_module(self, manager):
1538 manager.add_lustre_module('lvfs', 'lvfs')
1539 manager.add_lustre_module('obdclass', 'obdclass')
1540 manager.add_lustre_module('ptlrpc', 'ptlrpc')
1548 def correct_level(self, level, op=None):
1552 def __init__(self, db, uuid, fs_name, name_override = None, config_only = None):
1553 Module.__init__(self, 'LOV', db)
1554 if name_override != None:
1555 self.name = "lov_%s" % name_override
1556 self.mds_uuid = self.db.get_first_ref('mds')
1557 self.stripe_sz = self.db.get_val_int('stripesize', 1048576)
1558 self.stripe_off = self.db.get_val_int('stripeoffset', 0)
1559 self.pattern = self.db.get_val_int('stripepattern', 0)
1560 self.devlist = self.db.get_lov_tgts('lov_tgt')
1561 self.stripe_cnt = self.db.get_val_int('stripecount', len(self.devlist))
1564 self.desc_uuid = self.uuid
1565 self.uuid = generate_client_uuid(self.name)
1566 self.fs_name = fs_name
1568 self.config_only = 1
1570 self.config_only = None
1571 mds = self.db.lookup(self.mds_uuid)
1572 self.mds_name = mds.getName()
1573 for (obd_uuid, index, gen, active) in self.devlist:
1576 self.obdlist.append(obd_uuid)
1577 obd = self.db.lookup(obd_uuid)
1578 osc = get_osc(obd, self.uuid, fs_name)
1580 self.osclist.append((osc, index, gen, active))
1582 panic('osc not found:', obd_uuid)
1588 if not config.record and is_prepared(self.name):
1590 self.info(self.mds_uuid, self.stripe_cnt, self.stripe_sz,
1591 self.stripe_off, self.pattern, self.devlist,
1593 lctl.lov_setup(self.name, self.uuid, self.desc_uuid, self.stripe_cnt,
1594 self.stripe_sz, self.stripe_off, self.pattern,
1595 string.join(self.obdlist))
1596 for (osc, index, gen, active) in self.osclist:
1597 target_uuid = osc.target_uuid
1599 # Only ignore connect failures with --force, which
1600 # isn't implemented here yet.
1602 osc.prepare(ignore_connect_failure=0)
1603 except CommandError, e:
1604 print "Error preparing OSC %s\n" % osc.uuid
1606 lctl.lov_add_obd(self.name, self.uuid, target_uuid, index, gen)
1609 for (osc, index, gen, active) in self.osclist:
1610 target_uuid = osc.target_uuid
1612 if is_prepared(self.name):
1613 Module.cleanup(self)
1614 if self.config_only:
1615 panic("Can't clean up config_only LOV ", self.name)
1617 def add_module(self, manager):
1618 if self.config_only:
1619 panic("Can't load modules for config_only LOV ", self.name)
1620 for (osc, index, gen, active) in self.osclist:
1621 osc.add_module(manager)
1623 manager.add_lustre_module('lov', 'lov')
1625 def correct_level(self, level, op=None):
1629 def __init__(self, db, uuid, fs_name, name_override = None):
1630 Module.__init__(self, 'LMV', db)
1631 if name_override != None:
1632 self.name = "lmv_%s" % name_override
1634 self.devlist = self.db.get_lmv_tgts('lmv_tgt')
1635 if self.devlist == None:
1636 self.devlist = self.db.get_refs('mds')
1639 self.desc_uuid = self.uuid
1641 self.fs_name = fs_name
1642 for mds_uuid in self.devlist:
1643 mds = self.db.lookup(mds_uuid)
1645 panic("MDS not found!")
1646 mdc = MDC(mds, self.uuid, fs_name)
1648 self.mdclist.append(mdc)
1650 panic('mdc not found:', mds_uuid)
1653 if is_prepared(self.name):
1657 for mdc in self.mdclist:
1659 # Only ignore connect failures with --force, which
1660 # isn't implemented here yet.
1661 mdc.prepare(ignore_connect_failure=0)
1662 except CommandError, e:
1663 print "Error preparing LMV %s\n" % mdc.uuid
1666 lctl.lmv_setup(self.name, self.uuid, self.desc_uuid,
1667 string.join(self.devlist))
1670 for mdc in self.mdclist:
1672 if is_prepared(self.name):
1673 Module.cleanup(self)
1675 def add_module(self, manager):
1676 for mdc in self.mdclist:
1677 mdc.add_module(manager)
1679 manager.add_lustre_module('lmv', 'lmv')
1681 def correct_level(self, level, op=None):
1684 class MDSDEV(Module):
1685 def __init__(self,db):
1686 Module.__init__(self, 'MDSDEV', db)
1687 self.devpath = self.db.get_val('devpath','')
1688 self.backdevpath = self.db.get_val('backdevpath','')
1689 self.size = self.db.get_val_int('devsize', 0)
1690 self.journal_size = self.db.get_val_int('journalsize', 0)
1691 self.fstype = self.db.get_val('fstype', '')
1692 self.backfstype = self.db.get_val('backfstype', '')
1693 self.nspath = self.db.get_val('nspath', '')
1694 self.mkfsoptions = self.db.get_val('mkfsoptions', '')
1695 self.mountfsoptions = self.db.get_val('mountfsoptions', '')
1696 self.obdtype = self.db.get_val('obdtype', '')
1697 self.root_squash = self.db.get_val('root_squash', '')
1698 self.no_root_squash = self.db.get_val('no_root_squash', '')
1699 # overwrite the orignal MDSDEV name and uuid with the MDS name and uuid
1700 target_uuid = self.db.get_first_ref('target')
1701 self.mds = self.db.lookup(target_uuid)
1702 self.name = self.mds.getName()
1703 self.client_uuids = self.mds.get_refs('client')
1708 lmv_uuid = self.db.get_first_ref('lmv')
1709 if lmv_uuid != None:
1710 self.lmv = self.db.lookup(lmv_uuid)
1711 if self.lmv != None:
1712 self.client_uuids = self.lmv.get_refs('client')
1714 # FIXME: if fstype not set, then determine based on kernel version
1715 self.format = self.db.get_val('autoformat', "no")
1716 if self.mds.get_val('failover', 0):
1717 self.failover_mds = 'f'
1719 self.failover_mds = 'n'
1720 active_uuid = get_active_target(self.mds)
1722 panic("No target device found:", target_uuid)
1723 if active_uuid == self.uuid:
1727 if self.active and config.group and config.group != self.mds.get_val('group'):
1730 # default inode inode for case when neither LOV either
1731 # LMV is accessible.
1732 self.inode_size = 256
1734 inode_size = self.db.get_val_int('inodesize', 0)
1735 if not inode_size == 0:
1736 self.inode_size = inode_size
1738 # find the LOV for this MDS
1739 lovconfig_uuid = self.mds.get_first_ref('lovconfig')
1740 if lovconfig_uuid or self.lmv != None:
1741 if self.lmv != None:
1742 lovconfig_uuid = self.lmv.get_first_ref('lovconfig')
1743 lovconfig = self.lmv.lookup(lovconfig_uuid)
1744 lov_uuid = lovconfig.get_first_ref('lov')
1745 if lov_uuid == None:
1746 panic(self.mds.getName() + ": No LOV found for lovconfig ",
1749 lovconfig = self.mds.lookup(lovconfig_uuid)
1750 lov_uuid = lovconfig.get_first_ref('lov')
1751 if lov_uuid == None:
1752 panic(self.mds.getName() + ": No LOV found for lovconfig ",
1755 if self.lmv != None:
1756 lovconfig_uuid = self.lmv.get_first_ref('lovconfig')
1757 lovconfig = self.lmv.lookup(lovconfig_uuid)
1758 lov_uuid = lovconfig.get_first_ref('lov')
1760 lov = LOV(self.db.lookup(lov_uuid), lov_uuid, self.name,
1763 # default stripe count controls default inode_size
1764 stripe_count = lov.stripe_cnt
1765 if stripe_count > 77:
1766 self.inode_size = 4096
1767 elif stripe_count > 35:
1768 self.inode_size = 2048
1769 elif stripe_count > 13:
1770 self.inode_size = 1024
1771 elif stripe_count > 3:
1772 self.inode_size = 512
1774 self.inode_size = 256
1776 self.target_dev_uuid = self.uuid
1777 self.uuid = target_uuid
1780 if self.lmv != None:
1781 client_uuid = self.name + "_lmv_UUID"
1782 self.master = LMV(self.lmv, client_uuid,
1783 self.name, self.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' or self.fstype == 'ldiskfs':
1794 manager.add_lustre_module(self.fstype, self.fstype)
1797 manager.add_lustre_module('lvfs', 'fsfilt_%s' % (self.fstype))
1799 # if fstype is smfs, then we should also take care about backing
1801 if self.fstype == 'smfs':
1802 manager.add_lustre_module(self.backfstype, self.backfstype)
1803 manager.add_lustre_module('lvfs', 'fsfilt_%s' % (self.backfstype))
1805 for option in string.split(self.mountfsoptions, ','):
1806 if option == 'snap':
1807 if not self.fstype == 'smfs':
1808 panic("mountoptions has 'snap', but fstype is not smfs.")
1809 manager.add_lustre_module('lvfs', 'fsfilt_snap_%s' % (self.fstype))
1810 manager.add_lustre_module('lvfs', 'fsfilt_snap_%s' % (self.backfstype))
1813 if self.master != None:
1814 self.master.add_module(manager)
1816 def get_mount_options(self, blkdev):
1817 options = def_mount_options(self.fstype, 'mds')
1819 if config.mountfsoptions:
1821 options = "%s,%s" %(options, config.mountfsoptions)
1823 options = config.mountfsoptions
1824 if self.mountfsoptions:
1825 options = "%s,%s" %(options, self.mountfsoptions)
1827 if self.mountfsoptions:
1829 options = "%s,%s" %(options, self.mountfsoptions)
1831 options = self.mountfsoptions
1833 if self.fstype == 'smfs':
1835 options = "%s,type=%s,dev=%s" %(options,
1836 self.backfstype, blkdev)
1838 options = "type=%s,dev=%s" %(self.backfstype, blkdev)
1842 if not config.record and is_prepared(self.name):
1845 debug(self.uuid, "not active")
1848 # run write_conf automatically, if --reformat used
1853 if self.master != None:
1854 self.master.prepare()
1856 # never reformat here
1857 blkdev = block_dev(self.devpath, self.size, self.fstype, 0,
1858 self.format, self.journal_size, self.inode_size,
1859 self.mkfsoptions, self.backfstype, self.backdevpath)
1861 if not is_prepared('MDT'):
1862 lctl.newdev("mdt", 'MDT', 'MDT_UUID', setup ="")
1864 if self.fstype == 'smfs':
1865 realdev = self.fstype
1869 if self.obdtype == None:
1870 self.obdtype = 'dumb'
1872 if self.master == None:
1873 master_name = 'dumb'
1875 master_name = self.master.name
1877 if self.client_uuids == None:
1878 profile_name = 'dumb'
1880 profile_name = self.name
1882 mountfsoptions = self.get_mount_options(blkdev)
1884 self.info("mds", realdev, mountfsoptions, self.fstype, self.size,
1885 self.format, master_name, profile_name, self.obdtype)
1887 lctl.newdev("mds", self.name, self.uuid,
1888 setup = "%s %s %s %s %s %s" %(realdev,
1889 self.fstype, profile_name, mountfsoptions,
1890 master_name, self.obdtype))
1892 if development_mode():
1893 procentry = "/proc/fs/lustre/mds/grp_hash_upcall"
1894 upcall = os.path.abspath(os.path.dirname(sys.argv[0]) + "/l_getgroups")
1895 if not (os.access(procentry, os.R_OK) and os.access(upcall, os.R_OK)):
1896 print "MDS Warning: failed to set group-hash upcall"
1898 run("echo ", upcall, " > ", procentry)
1900 except CommandError, e:
1902 panic("MDS is missing the config log. Need to run " +
1903 "lconf --write_conf.")
1907 if config.root_squash == None:
1908 config.root_squash = self.root_squash
1909 if config.no_root_squash == None:
1910 config.no_root_squash = self.no_root_squash
1911 if config.root_squash:
1912 if config.no_root_squash:
1913 nsnid = config.no_root_squash
1916 lctl.root_squash(self.name, config.root_squash, nsnid)
1918 def write_conf(self):
1919 if not self.client_uuids:
1923 if not is_prepared(self.name):
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 if self.fstype == 'smfs':
1930 realdev = self.fstype
1934 # Even for writing logs we mount mds with supplied mount options
1935 # because it will not mount smfs (if used) otherwise.
1936 mountfsoptions = self.get_mount_options(blkdev)
1938 if self.obdtype == None:
1939 self.obdtype = 'dumb'
1941 self.info("mds", realdev, mountfsoptions, self.fstype, self.size,
1942 self.format, "dumb", "dumb", self.obdtype)
1944 lctl.newdev("mds", self.name, self.uuid,
1945 setup ="%s %s %s %s %s %s" %(realdev, self.fstype,
1946 'dumb', mountfsoptions,
1947 'dumb', self.obdtype))
1950 # record logs for all MDS clients
1951 for obd_uuid in self.client_uuids:
1952 log("recording client:", obd_uuid)
1954 client_uuid = generate_client_uuid(self.name)
1955 client = VOSC(self.db.lookup(obd_uuid), client_uuid,
1956 self.name, self.name)
1958 lctl.clear_log(self.name, self.name)
1959 lctl.record(self.name, self.name)
1961 lctl.mount_option(self.name, client.get_name(), "")
1963 process_updates(self.db, self.name, self.name, client)
1966 lctl.clear_log(self.name, self.name + '-clean')
1967 lctl.record(self.name, self.name + '-clean')
1969 lctl.del_mount_option(self.name)
1971 process_updates(self.db, self.name, self.name + '-clean', client)
1975 # record logs for each client
1981 config_options = "--ldapurl " + config.ldapurl + " --config " + config.config
1983 config_options = CONFIG_FILE
1985 for node_db in self.db.lookup_class('node'):
1986 client_name = node_db.getName()
1987 for prof_uuid in node_db.get_refs('profile'):
1988 prof_db = node_db.lookup(prof_uuid)
1989 # refactor this into a funtion to test "clientness"
1991 for ref_class, ref_uuid in prof_db.get_all_refs():
1992 if ref_class in ('mountpoint','echoclient'):
1993 debug("recording", client_name)
1994 old_noexec = config.noexec
1996 ret, out = run (sys.argv[0], noexec_opt,
1997 " -v --record --nomod",
1998 "--record_log", client_name,
1999 "--record_device", self.name,
2000 "--node", client_name,
2003 for s in out: log("record> ", string.strip(s))
2004 ret, out = run (sys.argv[0], noexec_opt,
2005 "--cleanup -v --record --nomod",
2006 "--record_log", client_name + "-clean",
2007 "--record_device", self.name,
2008 "--node", client_name,
2011 for s in out: log("record> ", string.strip(s))
2012 config.noexec = old_noexec
2015 lctl.cleanup(self.name, self.uuid, 0, 0)
2016 except CommandError, e:
2017 log(self.module_name, "cleanup failed: ", self.name)
2020 Module.cleanup(self)
2022 clean_dev(self.devpath, self.fstype, self.backfstype,
2025 def msd_remaining(self):
2026 out = lctl.device_list()
2028 if string.split(s)[2] in ('mds',):
2031 def safe_to_clean(self):
2034 def safe_to_clean_modules(self):
2035 return not self.msd_remaining()
2039 debug(self.uuid, "not active")
2042 if is_prepared(self.name):
2044 lctl.cleanup(self.name, self.uuid, config.force,
2046 except CommandError, e:
2047 log(self.module_name, "cleanup failed: ", self.name)
2050 Module.cleanup(self)
2052 if self.master != None:
2053 self.master.cleanup()
2054 if not self.msd_remaining() and is_prepared('MDT'):
2056 lctl.cleanup("MDT", "MDT_UUID", config.force,
2058 except CommandError, e:
2059 print "cleanup failed: ", self.name
2063 clean_dev(self.devpath, self.fstype, self.backfstype,
2066 def correct_level(self, level, op=None):
2067 #if self.master != None:
2072 def __init__(self, db):
2073 Module.__init__(self, 'OSD', db)
2074 self.osdtype = self.db.get_val('osdtype')
2075 self.devpath = self.db.get_val('devpath', '')
2076 self.backdevpath = self.db.get_val('backdevpath', '')
2077 self.size = self.db.get_val_int('devsize', 0)
2078 self.journal_size = self.db.get_val_int('journalsize', 0)
2079 self.inode_size = self.db.get_val_int('inodesize', 0)
2080 self.mkfsoptions = self.db.get_val('mkfsoptions', '')
2081 self.mountfsoptions = self.db.get_val('mountfsoptions', '')
2082 self.fstype = self.db.get_val('fstype', '')
2083 self.backfstype = self.db.get_val('backfstype', '')
2084 self.nspath = self.db.get_val('nspath', '')
2085 target_uuid = self.db.get_first_ref('target')
2086 ost = self.db.lookup(target_uuid)
2087 self.name = ost.getName()
2088 self.format = self.db.get_val('autoformat', 'yes')
2089 if ost.get_val('failover', 0):
2090 self.failover_ost = 'f'
2092 self.failover_ost = 'n'
2094 active_uuid = get_active_target(ost)
2096 panic("No target device found:", target_uuid)
2097 if active_uuid == self.uuid:
2101 if self.active and config.group and config.group != ost.get_val('group'):
2104 self.target_dev_uuid = self.uuid
2105 self.uuid = target_uuid
2107 def add_module(self, manager):
2109 manager.add_lustre_module('ost', 'ost')
2111 if self.fstype == 'smfs' or self.fstype == 'ldiskfs':
2112 manager.add_lustre_module(self.fstype, self.fstype)
2115 manager.add_lustre_module('lvfs' , 'fsfilt_%s' % (self.fstype))
2117 if self.fstype == 'smfs':
2118 manager.add_lustre_module(self.backfstype, self.backfstype)
2119 manager.add_lustre_module('lvfs' , 'fsfilt_%s' % (self.backfstype))
2121 for option in self.mountfsoptions:
2122 if option == 'snap':
2123 if not self.fstype == 'smfs':
2124 panic("mountoptions with snap, but fstype is not smfs\n")
2125 manager.add_lustre_module('lvfs', 'fsfilt_snap_%s' % (self.fstype))
2126 manager.add_lustre_module('lvfs', 'fsfilt_snap_%s' % (self.backfstype))
2128 manager.add_lustre_module(self.osdtype, self.osdtype)
2130 def get_mount_options(self, blkdev):
2131 options = def_mount_options(self.fstype, 'ost')
2133 if config.mountfsoptions:
2135 options = "%s,%s" %(options, config.mountfsoptions)
2137 options = config.mountfsoptions
2138 if self.mountfsoptions:
2139 options = "%s,%s" %(options, self.mountfsoptions)
2141 if self.mountfsoptions:
2143 options = "%s,%s" %(options, self.mountfsoptions)
2145 options = self.mountfsoptions
2147 if self.fstype == 'smfs':
2149 options = "%s,type=%s,dev=%s" %(options,
2150 self.backfstype, blkdev)
2152 options = "type=%s,dev=%s" %(self.backfstype,
2156 # need to check /proc/mounts and /etc/mtab before
2157 # formatting anything.
2158 # FIXME: check if device is already formatted.
2160 if is_prepared(self.name):
2163 debug(self.uuid, "not active")
2166 if self.osdtype == 'obdecho':
2169 blkdev = block_dev(self.devpath, self.size, self.fstype,
2170 config.reformat, self.format, self.journal_size,
2171 self.inode_size, self.mkfsoptions, self.backfstype,
2174 if self.fstype == 'smfs':
2175 realdev = self.fstype
2179 mountfsoptions = self.get_mount_options(blkdev)
2181 self.info(self.osdtype, realdev, mountfsoptions, self.fstype,
2182 self.size, self.format, self.journal_size, self.inode_size)
2184 lctl.newdev(self.osdtype, self.name, self.uuid,
2185 setup ="%s %s %s %s" %(realdev, self.fstype,
2188 if not is_prepared('OSS'):
2189 lctl.newdev("ost", 'OSS', 'OSS_UUID', setup ="")
2191 def osd_remaining(self):
2192 out = lctl.device_list()
2194 if string.split(s)[2] in ('obdfilter', 'obdecho'):
2197 def safe_to_clean(self):
2200 def safe_to_clean_modules(self):
2201 return not self.osd_remaining()
2205 debug(self.uuid, "not active")
2207 if is_prepared(self.name):
2210 lctl.cleanup(self.name, self.uuid, config.force,
2212 except CommandError, e:
2213 log(self.module_name, "cleanup failed: ", self.name)
2216 if not self.osd_remaining() and is_prepared('OSS'):
2218 lctl.cleanup("OSS", "OSS_UUID", config.force,
2220 except CommandError, e:
2221 print "cleanup failed: ", self.name
2224 if not self.osdtype == 'obdecho':
2225 clean_dev(self.devpath, self.fstype, self.backfstype,
2228 def correct_level(self, level, op=None):
2231 def mgmt_uuid_for_fs(mtpt_name):
2234 mtpt_db = toplustreDB.lookup_name(mtpt_name)
2235 fs_uuid = mtpt_db.get_first_ref('filesystem')
2236 fs = toplustreDB.lookup(fs_uuid)
2239 return fs.get_first_ref('mgmt')
2241 # Generic client module, used by OSC and MDC
2242 class Client(Module):
2243 def __init__(self, tgtdb, uuid, module, fs_name, self_name=None,
2245 self.target_name = tgtdb.getName()
2246 self.target_uuid = tgtdb.getUUID()
2247 self.module_dir = module_dir
2248 self.module = module
2252 self.tgt_dev_uuid = get_active_target(tgtdb)
2253 if not self.tgt_dev_uuid:
2254 panic("No target device found for target(1):", self.target_name)
2259 self.module = module
2260 self.module_name = string.upper(module)
2262 self.name = '%s_%s_%s_%s' % (self.module_name, socket.gethostname(),
2263 self.target_name, fs_name)
2265 self.name = self_name
2267 self.lookup_server(self.tgt_dev_uuid)
2268 mgmt_uuid = mgmt_uuid_for_fs(fs_name)
2270 self.mgmt_name = mgmtcli_name_for_uuid(mgmt_uuid)
2273 self.fs_name = fs_name
2274 if not self.module_dir:
2275 self.module_dir = module
2277 def add_module(self, manager):
2278 manager.add_lustre_module(self.module_dir, self.module)
2280 def lookup_server(self, srv_uuid):
2281 """ Lookup a server's network information """
2282 self._server_nets = get_ost_net(self.db, srv_uuid)
2283 if len(self._server_nets) == 0:
2284 panic ("Unable to find a server for:", srv_uuid)
2289 def get_servers(self):
2290 return self._server_nets
2292 def prepare(self, ignore_connect_failure = 0):
2293 self.info(self.target_uuid)
2294 if not config.record and is_prepared(self.name):
2297 srv = choose_local_server(self.get_servers())
2301 routes = find_route(self.get_servers())
2302 if len(routes) == 0:
2303 panic ("no route to", self.target_uuid)
2304 for (srv, r) in routes:
2305 lctl.add_route_host(r[0], srv.nid_uuid, r[1], r[3])
2306 except CommandError, e:
2307 if not ignore_connect_failure:
2310 if self.permits_inactive() and (self.target_uuid in config.inactive or self.active == 0):
2311 debug("%s inactive" % self.target_uuid)
2312 inactive_p = "inactive"
2314 debug("%s active" % self.target_uuid)
2316 lctl.newdev(self.module, self.name, self.uuid,
2317 setup ="%s %s %s %s" % (self.target_uuid, srv.nid_uuid,
2318 inactive_p, self.mgmt_name))
2321 if is_prepared(self.name):
2322 Module.cleanup(self)
2324 srv = choose_local_server(self.get_servers())
2326 lctl.disconnect(srv)
2328 for (srv, r) in find_route(self.get_servers()):
2329 lctl.del_route_host(r[0], srv.nid_uuid, r[1], r[3])
2330 except CommandError, e:
2331 log(self.module_name, "cleanup failed: ", self.name)
2335 def correct_level(self, level, op=None):
2338 def deactivate(self):
2340 lctl.deactivate(self.name)
2341 except CommandError, e:
2342 log(self.module_name, "deactivate failed: ", self.name)
2347 def __init__(self, db, uuid, fs_name):
2348 Client.__init__(self, db, uuid, 'mdc', fs_name)
2350 def permits_inactive(self):
2354 def __init__(self, db, uuid, fs_name):
2355 Client.__init__(self, db, uuid, 'osc', fs_name)
2357 def permits_inactive(self):
2360 def mgmtcli_name_for_uuid(uuid):
2361 return 'MGMTCLI_%s' % uuid
2363 class ManagementClient(Client):
2364 def __init__(self, db, uuid):
2365 Client.__init__(self, db, uuid, 'mgmt_cli', '',
2366 self_name = mgmtcli_name_for_uuid(db.getUUID()),
2367 module_dir = 'mgmt')
2369 class CMOBD(Module):
2370 def __init__(self, db):
2371 Module.__init__(self, 'CMOBD', db)
2372 self.name = self.db.getName();
2373 self.uuid = generate_client_uuid(self.name)
2374 self.master_uuid = self.db.get_first_ref('masterobd')
2375 self.cache_uuid = self.db.get_first_ref('cacheobd')
2377 master_obd = self.db.lookup(self.master_uuid)
2379 panic('master obd not found:', self.master_uuid)
2381 cache_obd = self.db.lookup(self.cache_uuid)
2383 panic('cache obd not found:', self.cache_uuid)
2388 master_class = master_obd.get_class()
2389 cache_class = cache_obd.get_class()
2391 if master_class == 'ost' or master_class == 'lov':
2392 client_uuid = "%s_lov_master_UUID" % (self.name)
2393 self.master = LOV(master_obd, client_uuid, self.name);
2394 elif master_class == 'mds':
2395 self.master = get_mdc(db, self.name, self.master_uuid)
2396 elif master_class == 'lmv':
2397 client_uuid = "%s_lmv_master_UUID" % (self.name)
2398 self.master = LMV(master_obd, client_uuid, self.name);
2400 panic("unknown master obd class '%s'" %(master_class))
2402 if cache_class == 'ost' or cache_class == 'lov':
2403 client_uuid = "%s_lov_cache_UUID" % (self.name)
2404 self.cache = LOV(cache_obd, client_uuid, self.name);
2405 elif cache_class == 'mds':
2406 self.cache = get_mdc(db, self.name, self.cache_uuid)
2407 elif cache_class == 'lmv':
2408 client_uuid = "%s_lmv_cache_UUID" % (self.name)
2409 self.cache = LMV(cache_obd, client_uuid, self.name);
2411 panic("unknown cache obd class '%s'" %(cache_class))
2414 self.master.prepare()
2415 if not config.record and is_prepared(self.name):
2417 self.info(self.master_uuid, self.cache_uuid)
2418 lctl.newdev("cmobd", self.name, self.uuid,
2419 setup ="%s %s" %(self.master.uuid,
2428 def get_master_name(self):
2429 return self.master.name
2431 def get_cache_name(self):
2432 return self.cache.name
2435 if is_prepared(self.name):
2436 Module.cleanup(self)
2438 self.master.cleanup()
2440 def add_module(self, manager):
2441 manager.add_lustre_module('cmobd', 'cmobd')
2442 self.master.add_module(manager)
2444 def correct_level(self, level, op=None):
2448 def __init__(self, db, uuid, name):
2449 Module.__init__(self, 'COBD', db)
2450 self.name = self.db.getName();
2451 self.uuid = generate_client_uuid(self.name)
2452 self.master_uuid = self.db.get_first_ref('masterobd')
2453 self.cache_uuid = self.db.get_first_ref('cacheobd')
2455 master_obd = self.db.lookup(self.master_uuid)
2457 panic('master obd not found:', self.master_uuid)
2459 cache_obd = self.db.lookup(self.cache_uuid)
2461 panic('cache obd not found:', self.cache_uuid)
2466 master_class = master_obd.get_class()
2467 cache_class = cache_obd.get_class()
2469 if master_class == 'ost' or master_class == 'lov':
2470 client_uuid = "%s_lov_master_UUID" % (self.name)
2471 self.master = LOV(master_obd, client_uuid, name);
2472 elif master_class == 'mds':
2473 self.master = get_mdc(db, name, self.master_uuid)
2474 elif master_class == 'lmv':
2475 client_uuid = "%s_lmv_master_UUID" % (self.name)
2476 self.master = LMV(master_obd, client_uuid, self.name);
2478 panic("unknown master obd class '%s'" %(master_class))
2480 if cache_class == 'ost' or cache_class == 'lov':
2481 client_uuid = "%s_lov_cache_UUID" % (self.name)
2482 self.cache = LOV(cache_obd, client_uuid, name);
2483 elif cache_class == 'mds':
2484 self.cache = get_mdc(db, name, self.cache_uuid)
2485 elif cache_class == 'lmv':
2486 client_uuid = "%s_lmv_cache_UUID" % (self.name)
2487 self.cache = LMV(cache_obd, client_uuid, self.name);
2489 panic("unknown cache obd class '%s'" %(cache_class))
2497 def get_master_name(self):
2498 return self.master.name
2500 def get_cache_name(self):
2501 return self.cache.name
2504 self.master.prepare()
2505 self.cache.prepare()
2506 if not config.record and is_prepared(self.name):
2508 self.info(self.master_uuid, self.cache_uuid)
2509 lctl.newdev("cobd", self.name, self.uuid,
2510 setup ="%s %s" %(self.master.name,
2514 if is_prepared(self.name):
2515 Module.cleanup(self)
2516 self.master.cleanup()
2517 self.cache.cleanup()
2519 def add_module(self, manager):
2520 manager.add_lustre_module('cobd', 'cobd')
2521 self.master.add_module(manager)
2523 # virtual interface for OSC and LOV
2525 def __init__(self, db, client_uuid, name, name_override = None):
2526 Module.__init__(self, 'VOSC', db)
2527 if db.get_class() == 'lov':
2528 self.osc = LOV(db, client_uuid, name, name_override)
2530 elif db.get_class() == 'cobd':
2531 self.osc = COBD(db, client_uuid, name)
2534 self.osc = OSC(db, client_uuid, name)
2538 return self.osc.get_uuid()
2541 return self.osc.get_name()
2549 def add_module(self, manager):
2550 self.osc.add_module(manager)
2552 def correct_level(self, level, op=None):
2553 return self.osc.correct_level(level, op)
2555 # virtual interface for MDC and LMV
2557 def __init__(self, db, client_uuid, name, name_override = None):
2558 Module.__init__(self, 'VMDC', db)
2559 if db.get_class() == 'lmv':
2560 self.mdc = LMV(db, client_uuid, name, name_override)
2561 elif db.get_class() == 'cobd':
2562 self.mdc = COBD(db, client_uuid, name)
2564 self.mdc = MDC(db, client_uuid, name)
2567 return self.mdc.uuid
2570 return self.mdc.name
2578 def add_module(self, manager):
2579 self.mdc.add_module(manager)
2581 def correct_level(self, level, op=None):
2582 return self.mdc.correct_level(level, op)
2584 class ECHO_CLIENT(Module):
2585 def __init__(self,db):
2586 Module.__init__(self, 'ECHO_CLIENT', db)
2587 self.obd_uuid = self.db.get_first_ref('obd')
2588 obd = self.db.lookup(self.obd_uuid)
2589 self.uuid = generate_client_uuid(self.name)
2590 self.osc = VOSC(obd, self.uuid, self.name)
2593 if not config.record and is_prepared(self.name):
2596 self.osc.prepare() # XXX This is so cheating. -p
2597 self.info(self.obd_uuid)
2599 lctl.newdev("echo_client", self.name, self.uuid,
2600 setup = self.osc.get_name())
2603 if is_prepared(self.name):
2604 Module.cleanup(self)
2607 def add_module(self, manager):
2608 self.osc.add_module(manager)
2609 manager.add_lustre_module('obdecho', 'obdecho')
2611 def correct_level(self, level, op=None):
2614 def generate_client_uuid(name):
2615 client_uuid = '%05x_%.19s_%05x%05x' % (int(random.random() * 1048576),
2617 int(random.random() * 1048576),
2618 int(random.random() * 1048576))
2619 return client_uuid[:36]
2621 class Mountpoint(Module):
2622 def __init__(self,db):
2623 Module.__init__(self, 'MTPT', db)
2624 self.path = self.db.get_val('path')
2625 self.clientoptions = self.db.get_val('clientoptions', '')
2626 self.fs_uuid = self.db.get_first_ref('filesystem')
2627 fs = self.db.lookup(self.fs_uuid)
2628 self.mds_uuid = fs.get_first_ref('lmv')
2629 if not self.mds_uuid:
2630 self.mds_uuid = fs.get_first_ref('mds')
2631 self.obd_uuid = fs.get_first_ref('obd')
2632 self.mgmt_uuid = fs.get_first_ref('mgmt')
2633 client_uuid = generate_client_uuid(self.name)
2635 ost = self.db.lookup(self.obd_uuid)
2637 panic("no ost: ", self.obd_uuid)
2639 mds = self.db.lookup(self.mds_uuid)
2641 panic("no mds: ", self.mds_uuid)
2643 self.vosc = VOSC(ost, client_uuid, self.name, self.name)
2644 self.vmdc = VMDC(mds, client_uuid, self.name, self.name)
2647 self.mgmtcli = ManagementClient(db.lookup(self.mgmt_uuid),
2653 if not config.record and fs_is_mounted(self.path):
2654 log(self.path, "already mounted.")
2658 self.mgmtcli.prepare()
2661 vmdc_name = self.vmdc.get_name()
2663 self.info(self.path, self.mds_uuid, self.obd_uuid)
2664 if config.record or config.lctl_dump:
2665 lctl.mount_option(local_node_name, self.vosc.get_name(), vmdc_name)
2668 if config.clientoptions:
2669 if self.clientoptions:
2670 self.clientoptions = self.clientoptions + ',' + \
2671 config.clientoptions
2673 self.clientoptions = config.clientoptions
2674 if self.clientoptions:
2675 self.clientoptions = ',' + self.clientoptions
2676 # Linux kernel will deal with async and not pass it to ll_fill_super,
2677 # so replace it with Lustre async
2678 self.clientoptions = string.replace(self.clientoptions, "async",
2681 cmd = "mount -t lustre_lite -o osc=%s,mdc=%s%s %s %s" % \
2682 (self.vosc.get_name(), vmdc_name, self.clientoptions,
2683 config.config, self.path)
2684 run("mkdir", self.path)
2689 panic("mount failed:", self.path, ":", string.join(val))
2692 self.info(self.path, self.mds_uuid,self.obd_uuid)
2694 if config.record or config.lctl_dump:
2695 lctl.del_mount_option(local_node_name)
2697 if fs_is_mounted(self.path):
2699 (rc, out) = run("umount", "-f", self.path)
2701 (rc, out) = run("umount", self.path)
2703 raise CommandError('umount', out, rc)
2705 if fs_is_mounted(self.path):
2706 panic("fs is still mounted:", self.path)
2711 self.mgmtcli.cleanup()
2713 def add_module(self, manager):
2714 manager.add_lustre_module('mdc', 'mdc')
2717 self.mgmtcli.add_module(manager)
2719 self.vosc.add_module(manager)
2720 self.vmdc.add_module(manager)
2722 manager.add_lustre_module('llite', 'llite')
2724 def correct_level(self, level, op=None):
2727 # ============================================================
2728 # misc query functions
2730 def get_ost_net(self, osd_uuid):
2734 osd = self.lookup(osd_uuid)
2735 node_uuid = osd.get_first_ref('node')
2736 node = self.lookup(node_uuid)
2738 panic("unable to find node for osd_uuid:", osd_uuid,
2739 " node_ref:", node_uuid_)
2740 for net_uuid in node.get_networks():
2741 db = node.lookup(net_uuid)
2742 srv_list.append(Network(db))
2746 # the order of iniitailization is based on level.
2747 def getServiceLevel(self):
2748 type = self.get_class()
2750 if type in ('network',):
2752 elif type in ('routetbl',):
2754 elif type in ('ldlm',):
2756 elif type in ('osd', 'cobd'):
2758 elif type in ('mdsdev',):
2760 elif type in ('lmv',):
2762 elif type in ('cmobd',):
2764 elif type in ('mountpoint', 'echoclient'):
2767 panic("Unknown type: ", type)
2769 if ret < config.minlevel or ret > config.maxlevel:
2774 # return list of services in a profile. list is a list of tuples
2775 # [(level, db_object),]
2776 def getServices(self):
2778 for ref_class, ref_uuid in self.get_all_refs():
2779 servdb = self.lookup(ref_uuid)
2781 level = getServiceLevel(servdb)
2783 list.append((level, servdb))
2785 panic('service not found: ' + ref_uuid)
2791 ############################################################
2793 # FIXME: clean this mess up!
2795 # OSC is no longer in the xml, so we have to fake it.
2796 # this is getting ugly and begging for another refactoring
2797 def get_osc(ost_db, uuid, fs_name):
2798 osc = OSC(ost_db, uuid, fs_name)
2801 def get_mdc(db, fs_name, mds_uuid):
2802 mds_db = db.lookup(mds_uuid);
2804 error("no mds:", mds_uuid)
2805 mdc = MDC(mds_db, mds_uuid, fs_name)
2808 ############################################################
2809 # routing ("rooting")
2811 # list of (nettype, cluster_id, nid)
2814 def find_local_clusters(node_db):
2815 global local_clusters
2816 for netuuid in node_db.get_networks():
2817 net = node_db.lookup(netuuid)
2819 debug("add_local", netuuid)
2820 local_clusters.append((srv.net_type, srv.cluster_id, srv.nid))
2822 if acceptors.has_key(srv.port):
2823 panic("duplicate port:", srv.port)
2824 acceptors[srv.port] = AcceptorHandler(srv.port, srv.net_type)
2826 # This node is a gateway.
2828 def node_is_router():
2831 # If there are any routers found in the config, then this will be true
2832 # and all nodes will load kptlrouter.
2834 def node_needs_router():
2835 return needs_router or is_router
2837 # list of (nettype, gw, tgt_cluster_id, lo, hi)
2838 # Currently, these local routes are only added to kptlrouter route
2839 # table if they are needed to connect to a specific server. This
2840 # should be changed so all available routes are loaded, and the
2841 # ptlrouter can make all the decisions.
2844 def find_local_routes(lustre):
2845 """ Scan the lustre config looking for routers . Build list of
2847 global local_routes, needs_router
2849 list = lustre.lookup_class('node')
2851 if router.get_val_int('router', 0):
2853 for (local_type, local_cluster_id, local_nid) in local_clusters:
2855 for netuuid in router.get_networks():
2856 db = router.lookup(netuuid)
2857 if (local_type == db.get_val('nettype') and
2858 local_cluster_id == db.get_val('clusterid')):
2859 gw = db.get_val('nid')
2862 debug("find_local_routes: gw is", gw)
2863 for route in router.get_local_routes(local_type, gw):
2864 local_routes.append(route)
2865 debug("find_local_routes:", local_routes)
2868 def choose_local_server(srv_list):
2869 for srv in srv_list:
2870 if local_cluster(srv.net_type, srv.cluster_id):
2873 def local_cluster(net_type, cluster_id):
2874 for cluster in local_clusters:
2875 if net_type == cluster[0] and cluster_id == cluster[1]:
2879 def local_interface(net_type, cluster_id, nid):
2880 for cluster in local_clusters:
2881 if (net_type == cluster[0] and cluster_id == cluster[1]
2882 and nid == cluster[2]):
2886 def find_route(srv_list):
2888 frm_type = local_clusters[0][0]
2889 for srv in srv_list:
2890 debug("find_route: srv:", srv.nid, "type: ", srv.net_type)
2891 to_type = srv.net_type
2893 cluster_id = srv.cluster_id
2894 debug ('looking for route to', to_type, to)
2895 for r in local_routes:
2896 debug("find_route: ", r)
2897 if (r[3] <= to and to <= r[4]) and cluster_id == r[2]:
2898 result.append((srv, r))
2901 def get_active_target(db):
2902 target_uuid = db.getUUID()
2903 target_name = db.getName()
2904 node_name = get_select(target_name)
2906 tgt_dev_uuid = db.get_node_tgt_dev(node_name, target_uuid)
2908 tgt_dev_uuid = db.get_first_ref('active')
2911 def get_server_by_nid_uuid(db, nid_uuid):
2912 for n in db.lookup_class("network"):
2914 if net.nid_uuid == nid_uuid:
2918 ############################################################
2922 type = db.get_class()
2923 debug('Service:', type, db.getName(), db.getUUID())
2928 n = LOV(db, "YOU_SHOULD_NEVER_SEE_THIS_UUID")
2929 elif type == 'network':
2931 elif type == 'routetbl':
2935 elif type == 'cobd':
2936 n = COBD(db, "YOU_SHOULD_NEVER_SEE_THIS_UUID")
2937 elif type == 'cmobd':
2939 elif type == 'mdsdev':
2941 elif type == 'mountpoint':
2943 elif type == 'echoclient':
2948 panic ("unknown service type:", type)
2952 # Prepare the system to run lustre using a particular profile
2953 # in a the configuration.
2954 # * load & the modules
2955 # * setup networking for the current node
2956 # * make sure partitions are in place and prepared
2957 # * initialize devices with lctl
2958 # Levels is important, and needs to be enforced.
2959 def for_each_profile(db, prof_list, operation):
2960 for prof_uuid in prof_list:
2961 prof_db = db.lookup(prof_uuid)
2963 panic("profile:", prof_uuid, "not found.")
2964 services = getServices(prof_db)
2967 def magic_get_osc(db, rec, lov):
2969 lov_uuid = lov.get_uuid()
2970 lov_name = lov.osc.fs_name
2972 lov_uuid = rec.getAttribute('lov_uuidref')
2973 # FIXME: better way to find the mountpoint?
2974 filesystems = db.root_node.getElementsByTagName('filesystem')
2976 for fs in filesystems:
2977 ref = fs.getElementsByTagName('obd_ref')
2978 if ref[0].getAttribute('uuidref') == lov_uuid:
2979 fsuuid = fs.getAttribute('uuid')
2983 panic("malformed xml: lov uuid '" + lov_uuid + "' referenced in 'add' record is not used by any filesystems.")
2985 mtpts = db.root_node.getElementsByTagName('mountpoint')
2988 ref = fs.getElementsByTagName('filesystem_ref')
2989 if ref[0].getAttribute('uuidref') == fsuuid:
2990 lov_name = fs.getAttribute('name')
2994 panic("malformed xml: 'add' record references lov uuid '" + lov_uuid + "', which references filesystem uuid '" + fsuuid + "', which does not reference a mountpoint.")
2996 print "lov_uuid: " + lov_uuid + "; lov_name: " + lov_name
2998 ost_uuid = rec.getAttribute('ost_uuidref')
2999 obd = db.lookup(ost_uuid)
3002 panic("malformed xml: 'add' record references ost uuid '" + ost_uuid + "' which cannot be found.")
3004 osc = get_osc(obd, lov_uuid, lov_name)
3006 panic('osc not found:', obd_uuid)
3009 # write logs for update records. sadly, logs of all types -- and updates in
3010 # particular -- are something of an afterthought. lconf needs rewritten with
3011 # these as core concepts. so this is a pretty big hack.
3012 def process_update_record(db, update, lov):
3013 for rec in update.childNodes:
3014 if rec.nodeType != rec.ELEMENT_NODE:
3017 log("found "+rec.nodeName+" record in update version " +
3018 str(update.getAttribute('version')))
3020 lov_uuid = rec.getAttribute('lov_uuidref')
3021 ost_uuid = rec.getAttribute('ost_uuidref')
3022 index = rec.getAttribute('index')
3023 gen = rec.getAttribute('generation')
3025 if not lov_uuid or not ost_uuid or not index or not gen:
3026 panic("malformed xml: 'update' record requires lov_uuid, ost_uuid, index, and generation.")
3029 tmplov = db.lookup(lov_uuid)
3031 panic("malformed xml: 'delete' record contains lov UUID '" + lov_uuid + "', which cannot be located.")
3032 lov_name = tmplov.getName()
3034 lov_name = lov.osc.name
3036 # ------------------------------------------------------------- add
3037 if rec.nodeName == 'add':
3039 lctl.lov_del_obd(lov_name, lov_uuid, ost_uuid, index, gen)
3042 osc = magic_get_osc(db, rec, lov)
3045 # Only ignore connect failures with --force, which
3046 # isn't implemented here yet.
3047 osc.prepare(ignore_connect_failure=0)
3048 except CommandError, e:
3049 print "Error preparing OSC %s\n" % osc.uuid
3052 lctl.lov_add_obd(lov_name, lov_uuid, ost_uuid, index, gen)
3054 # ------------------------------------------------------ deactivate
3055 elif rec.nodeName == 'deactivate':
3059 osc = magic_get_osc(db, rec, lov)
3063 except CommandError, e:
3064 print "Error deactivating OSC %s\n" % osc.uuid
3067 # ---------------------------------------------------------- delete
3068 elif rec.nodeName == 'delete':
3072 osc = magic_get_osc(db, rec, lov)
3078 except CommandError, e:
3079 print "Error cleaning up OSC %s\n" % osc.uuid
3082 lctl.lov_del_obd(lov_name, lov_uuid, ost_uuid, index, gen)
3084 def process_updates(db, log_device, log_name, lov = None):
3085 updates = db.root_node.getElementsByTagName('update')
3087 if not u.childNodes:
3088 log("ignoring empty update record (version " +
3089 str(u.getAttribute('version')) + ")")
3092 version = u.getAttribute('version')
3093 real_name = "%s-%s" % (log_name, version)
3094 lctl.clear_log(log_device, real_name)
3095 lctl.record(log_device, real_name)
3097 process_update_record(db, u, lov)
3101 def doWriteconf(services):
3105 if s[1].get_class() == 'mdsdev':
3106 n = newService(s[1])
3109 def doSetup(services):
3114 n = newService(s[1])
3116 slist.append((n.level, n))
3119 nl = n[1].correct_level(n[0])
3120 nlist.append((nl, n[1]))
3125 def doLoadModules(services):
3129 # adding all needed modules from all services
3131 n = newService(s[1])
3132 n.add_module(mod_manager)
3134 # loading all registered modules
3135 mod_manager.load_modules()
3137 def doUnloadModules(services):
3141 # adding all needed modules from all services
3143 n = newService(s[1])
3144 if n.safe_to_clean_modules():
3145 n.add_module(mod_manager)
3147 # unloading all registered modules
3148 mod_manager.cleanup_modules()
3150 def doCleanup(services):
3156 n = newService(s[1])
3158 slist.append((n.level, n))
3161 nl = n[1].correct_level(n[0])
3162 nlist.append((nl, n[1]))
3167 if n[1].safe_to_clean():
3172 def doHost(lustreDB, hosts):
3173 global is_router, local_node_name
3176 node_db = lustreDB.lookup_name(h, 'node')
3180 panic('No host entry found.')
3182 local_node_name = node_db.get_val('name', 0)
3183 is_router = node_db.get_val_int('router', 0)
3184 lustre_upcall = node_db.get_val('lustreUpcall', '')
3185 portals_upcall = node_db.get_val('portalsUpcall', '')
3186 timeout = node_db.get_val_int('timeout', 0)
3187 ptldebug = node_db.get_val('ptldebug', '')
3188 subsystem = node_db.get_val('subsystem', '')
3190 find_local_clusters(node_db)
3192 find_local_routes(lustreDB)
3194 # Two step process: (1) load modules, (2) setup lustre
3195 # if not cleaning, load modules first.
3196 prof_list = node_db.get_refs('profile')
3198 if config.write_conf:
3199 for_each_profile(node_db, prof_list, doLoadModules)
3201 for_each_profile(node_db, prof_list, doWriteconf)
3202 for_each_profile(node_db, prof_list, doUnloadModules)
3205 elif config.recover:
3206 if not (config.tgt_uuid and config.client_uuid and config.conn_uuid):
3207 raise Lustre.LconfError( "--recovery requires --tgt_uuid <UUID> " +
3208 "--client_uuid <UUID> --conn_uuid <UUID>")
3209 doRecovery(lustreDB, lctl, config.tgt_uuid, config.client_uuid,
3211 elif config.cleanup:
3213 # the command line can override this value
3215 # ugly hack, only need to run lctl commands for --dump
3216 if config.lctl_dump or config.record:
3217 for_each_profile(node_db, prof_list, doCleanup)
3220 sys_set_timeout(timeout)
3221 sys_set_ptldebug(ptldebug)
3222 sys_set_subsystem(subsystem)
3223 sys_set_lustre_upcall(lustre_upcall)
3224 sys_set_portals_upcall(portals_upcall)
3226 for_each_profile(node_db, prof_list, doCleanup)
3227 for_each_profile(node_db, prof_list, doUnloadModules)
3231 # ugly hack, only need to run lctl commands for --dump
3232 if config.lctl_dump or config.record:
3233 sys_set_timeout(timeout)
3234 sys_set_lustre_upcall(lustre_upcall)
3235 for_each_profile(node_db, prof_list, doSetup)
3239 sys_set_netmem_max('/proc/sys/net/core/rmem_max', MAXTCPBUF)
3240 sys_set_netmem_max('/proc/sys/net/core/wmem_max', MAXTCPBUF)
3242 for_each_profile(node_db, prof_list, doLoadModules)
3244 sys_set_debug_path()
3245 sys_set_ptldebug(ptldebug)
3246 sys_set_subsystem(subsystem)
3247 script = config.gdb_script
3248 run(lctl.lctl, ' modules >', script)
3250 log ("The GDB module script is in", script)
3251 # pause, so user has time to break and
3254 sys_set_timeout(timeout)
3255 sys_set_lustre_upcall(lustre_upcall)
3256 sys_set_portals_upcall(portals_upcall)
3258 for_each_profile(node_db, prof_list, doSetup)
3261 def doRecovery(lustreDB, lctl, tgt_uuid, client_uuid, nid_uuid):
3262 tgt = lustreDB.lookup(tgt_uuid)
3264 raise Lustre.LconfError("doRecovery: "+ tgt_uuid +" not found.")
3265 new_uuid = get_active_target(tgt)
3267 raise Lustre.LconfError("doRecovery: no active target found for: " +
3269 net = choose_local_server(get_ost_net(lustreDB, new_uuid))
3271 raise Lustre.LconfError("Unable to find a connection to:" + new_uuid)
3273 log("Reconnecting", tgt_uuid, " to ", net.nid_uuid);
3275 oldnet = get_server_by_nid_uuid(lustreDB, nid_uuid)
3278 lctl.disconnect(oldnet)
3279 except CommandError, e:
3280 log("recover: disconnect", nid_uuid, "failed: ")
3285 except CommandError, e:
3286 log("recover: connect failed")
3289 lctl.recover(client_uuid, net.nid_uuid)
3292 def setupModulePath(cmd, portals_dir = PORTALS_DIR):
3293 base = os.path.dirname(cmd)
3294 if development_mode():
3295 if not config.lustre:
3296 debug('using objdir module paths')
3297 config.lustre = (os.path.join(base, ".."))
3298 # normalize the portals dir, using command line arg if set
3300 portals_dir = config.portals
3301 dir = os.path.join(config.lustre, portals_dir)
3302 config.portals = dir
3303 debug('config.portals', config.portals)
3304 elif config.lustre and config.portals:
3306 # if --lustre and --portals, normalize portals
3307 # can ignore POTRALS_DIR here, since it is probly useless here
3308 config.portals = os.path.join(config.lustre, config.portals)
3309 debug('config.portals B', config.portals)
3311 def sysctl(path, val):
3312 debug("+ sysctl", path, val)
3316 fp = open(os.path.join('/proc/sys', path), 'w')
3323 def sys_set_debug_path():
3324 sysctl('portals/debug_path', config.debug_path)
3326 def sys_set_lustre_upcall(upcall):
3327 # the command overrides the value in the node config
3328 if config.lustre_upcall:
3329 upcall = config.lustre_upcall
3331 upcall = config.upcall
3333 lctl.set_lustre_upcall(upcall)
3335 def sys_set_portals_upcall(upcall):
3336 # the command overrides the value in the node config
3337 if config.portals_upcall:
3338 upcall = config.portals_upcall
3340 upcall = config.upcall
3342 sysctl('portals/upcall', upcall)
3344 def sys_set_timeout(timeout):
3345 # the command overrides the value in the node config
3346 if config.timeout and config.timeout > 0:
3347 timeout = config.timeout
3348 if timeout != None and timeout > 0:
3349 lctl.set_timeout(timeout)
3351 def sys_tweak_socknal ():
3352 # reserve at least 8MB, or we run out of RAM in skb_alloc under read
3353 if sys_get_branch() == '2.6':
3354 fp = open('/proc/meminfo')
3355 lines = fp.readlines()
3360 if a[0] == 'MemTotal:':
3362 debug("memtotal" + memtotal)
3363 if int(memtotal) < 262144:
3364 minfree = int(memtotal) / 16
3367 debug("+ minfree ", minfree)
3368 sysctl("vm/min_free_kbytes", minfree)
3369 if config.single_socket:
3370 sysctl("socknal/typed", 0)
3372 def sys_optimize_elan ():
3373 procfiles = ["/proc/elan/config/eventint_punt_loops",
3374 "/proc/qsnet/elan3/config/eventint_punt_loops",
3375 "/proc/qsnet/elan4/config/elan4_mainint_punt_loops"]
3377 if os.access(p, os.W_OK):
3378 run ("echo 1 > " + p)
3380 def sys_set_ptldebug(ptldebug):
3382 ptldebug = config.ptldebug
3385 val = eval(ptldebug, ptldebug_names)
3386 val = "0x%x" % (val)
3387 sysctl('portals/debug', val)
3388 except NameError, e:
3391 def sys_set_subsystem(subsystem):
3392 if config.subsystem:
3393 subsystem = config.subsystem
3396 val = eval(subsystem, subsystem_names)
3397 val = "0x%x" % (val)
3398 sysctl('portals/subsystem_debug', val)
3399 except NameError, e:
3402 def sys_set_netmem_max(path, max):
3403 debug("setting", path, "to at least", max)
3411 fp = open(path, 'w')
3412 fp.write('%d\n' %(max))
3416 def sys_make_devices():
3417 if not os.access('/dev/portals', os.R_OK):
3418 run('mknod /dev/portals c 10 240')
3419 if not os.access('/dev/obd', os.R_OK):
3420 run('mknod /dev/obd c 10 241')
3423 # Add dir to the global PATH, if not already there.
3424 def add_to_path(new_dir):
3425 syspath = string.split(os.environ['PATH'], ':')
3426 if new_dir in syspath:
3428 os.environ['PATH'] = os.environ['PATH'] + ':' + new_dir
3430 def default_debug_path():
3431 path = '/tmp/lustre-log'
3432 if os.path.isdir('/r'):
3437 def default_gdb_script():
3438 script = '/tmp/ogdb'
3439 if os.path.isdir('/r'):
3440 return '/r' + script
3445 DEFAULT_PATH = ('/sbin', '/usr/sbin', '/bin', '/usr/bin')
3446 # ensure basic elements are in the system path
3447 def sanitise_path():
3448 for dir in DEFAULT_PATH:
3451 # global hack for the --select handling
3453 def init_select(args):
3454 # args = [service=nodeA,service2=nodeB service3=nodeC]
3457 list = string.split(arg, ',')
3459 srv, node = string.split(entry, '=')
3460 tgt_select[srv] = node
3462 def get_select(srv):
3463 if tgt_select.has_key(srv):
3464 return tgt_select[srv]
3468 FLAG = Lustre.Options.FLAG
3469 PARAM = Lustre.Options.PARAM
3470 INTPARAM = Lustre.Options.INTPARAM
3471 PARAMLIST = Lustre.Options.PARAMLIST
3473 ('verbose,v', "Print system commands as they are run"),
3474 ('ldapurl',"LDAP server URL, eg. ldap://localhost", PARAM),
3475 ('config', "Cluster config name used for LDAP query", PARAM),
3476 ('select', "service=nodeA,service2=nodeB ", PARAMLIST),
3477 ('node', "Load config for <nodename>", PARAM),
3478 ('cleanup,d', "Cleans up config. (Shutdown)"),
3479 ('force,f', "Forced unmounting and/or obd detach during cleanup",
3481 ('single_socket', "socknal option: only use one socket instead of bundle",
3483 ('failover',"""Used to shut down without saving state.
3484 This will allow this node to "give up" a service to a
3485 another node for failover purposes. This will not
3486 be a clean shutdown.""",
3488 ('gdb', """Prints message after creating gdb module script
3489 and sleeps for 5 seconds."""),
3490 ('noexec,n', """Prints the commands and steps that will be run for a
3491 config without executing them. This can used to check if a
3492 config file is doing what it should be doing"""),
3493 ('nomod', "Skip load/unload module step."),
3494 ('nosetup', "Skip device setup/cleanup step."),
3495 ('reformat', "Reformat all devices (without question)"),
3496 ('mkfsoptions', "Additional options for the mk*fs command line", PARAM),
3497 ('mountfsoptions', "Additional options for mount fs command line", PARAM),
3498 ('clientoptions', "Additional options for Lustre", PARAM),
3499 ('dump', "Dump the kernel debug log to file before portals is unloaded",
3501 ('write_conf', "Save all the client config information on mds."),
3502 ('record', "Write config information on mds."),
3503 ('record_log', "Name of config record log.", PARAM),
3504 ('record_device', "MDS device name that will record the config commands",
3506 ('root_squash', "MDS squash root to appointed uid",
3508 ('no_root_squash', "Don't squash root for appointed nid",
3510 ('minlevel', "Minimum level of services to configure/cleanup",
3512 ('maxlevel', """Maximum level of services to configure/cleanup
3513 Levels are aproximatly like:
3518 70 - mountpoint, echo_client, osc, mdc, lov""",
3520 ('lustre', """Base directory of lustre sources. This parameter will
3521 cause lconf to load modules from a source tree.""", PARAM),
3522 ('portals', """Portals source directory. If this is a relative path,
3523 then it is assumed to be relative to lustre. """, PARAM),
3524 ('timeout', "Set recovery timeout", INTPARAM),
3525 ('upcall', "Set both portals and lustre upcall script", PARAM),
3526 ('lustre_upcall', "Set lustre upcall script", PARAM),
3527 ('portals_upcall', "Set portals upcall script", PARAM),
3528 ('lctl_dump', "Save lctl ioctls to the dumpfile argument", PARAM),
3529 ('ptldebug', "Set the portals debug level", PARAM),
3530 ('subsystem', "Set the portals debug subsystem", PARAM),
3531 ('gdb_script', "Fullname of gdb debug script", PARAM, default_gdb_script()),
3532 ('debug_path', "Path to save debug dumps", PARAM, default_debug_path()),
3533 # Client recovery options
3534 ('recover', "Recover a device"),
3535 ('group', "The group of devices to configure or cleanup", PARAM),
3536 ('tgt_uuid', "The failed target (required for recovery)", PARAM),
3537 ('client_uuid', "The failed client (required for recovery)", PARAM),
3538 ('conn_uuid', "The failed connection (required for recovery)", PARAM),
3540 ('inactive', """The name of an inactive service, to be ignored during
3541 mounting (currently OST-only). Can be repeated.""",
3546 global lctl, config, toplustreDB, CONFIG_FILE, mod_manager
3548 # in the upcall this is set to SIG_IGN
3549 signal.signal(signal.SIGCHLD, signal.SIG_DFL)
3551 cl = Lustre.Options("lconf", "config.xml", lconf_options)
3553 config, args = cl.parse(sys.argv[1:])
3554 except Lustre.OptionError, e:
3558 setupModulePath(sys.argv[0])
3560 host = socket.gethostname()
3562 # the PRNG is normally seeded with time(), which is not so good for starting
3563 # time-synchronized clusters
3564 input = open('/dev/urandom', 'r')
3566 print 'Unable to open /dev/urandom!'
3568 seed = input.read(32)
3574 init_select(config.select)
3577 # allow config to be fetched via HTTP, but only with python2
3578 if sys.version[0] != '1' and args[0].startswith('http://'):
3581 config_file = urllib2.urlopen(args[0])
3582 except (urllib2.URLError, socket.error), err:
3583 if hasattr(err, 'args'):
3585 print "Could not access '%s': %s" %(args[0], err)
3587 elif not os.access(args[0], os.R_OK):
3588 print 'File not found or readable:', args[0]
3592 config_file = open(args[0], 'r')
3594 dom = xml.dom.minidom.parse(config_file)
3596 panic("%s does not appear to be a config file." % (args[0]))
3597 sys.exit(1) # make sure to die here, even in debug mode.
3599 CONFIG_FILE = args[0]
3600 lustreDB = Lustre.LustreDB_XML(dom.documentElement, dom.documentElement)
3601 if not config.config:
3602 config.config = os.path.basename(args[0])# use full path?
3603 if config.config[-4:] == '.xml':
3604 config.config = config.config[:-4]
3605 elif config.ldapurl:
3606 if not config.config:
3607 panic("--ldapurl requires --config name")
3608 dn = "config=%s,fs=lustre" % (config.config)
3609 lustreDB = Lustre.LustreDB_LDAP('', {}, base=dn, url = config.ldapurl)
3610 elif config.ptldebug or config.subsystem:
3611 sys_set_ptldebug(None)
3612 sys_set_subsystem(None)
3615 print 'Missing config file or ldap URL.'
3616 print 'see lconf --help for command summary'
3619 toplustreDB = lustreDB
3621 ver = lustreDB.get_version()
3623 panic("No version found in config data, please recreate.")
3624 if ver != Lustre.CONFIG_VERSION:
3625 panic("Config version", ver, "does not match lconf version",
3626 Lustre.CONFIG_VERSION)
3630 node_list.append(config.node)
3633 node_list.append(host)
3634 node_list.append('localhost')
3636 debug("configuring for host: ", node_list)
3639 config.debug_path = config.debug_path + '-' + host
3640 config.gdb_script = config.gdb_script + '-' + host
3642 lctl = LCTLInterface('lctl')
3644 if config.lctl_dump:
3645 lctl.use_save_file(config.lctl_dump)
3648 if not (config.record_device and config.record_log):
3649 panic("When recording, both --record_log and --record_device must be specified.")
3650 lctl.clear_log(config.record_device, config.record_log)
3651 lctl.record(config.record_device, config.record_log)
3653 # init module manager
3654 mod_manager = kmod_manager(config.lustre, config.portals)
3656 doHost(lustreDB, node_list)
3658 if not config.record:
3663 process_updates(lustreDB, config.record_device, config.record_log)
3665 if __name__ == "__main__":
3668 except Lustre.LconfError, e:
3670 # traceback.print_exc(file=sys.stdout)
3672 except CommandError, e:
3676 if first_cleanup_error:
3677 sys.exit(first_cleanup_error)