3 # Copyright (C) 2002-2003 Cluster File Systems, Inc.
4 # Authors: Robert Read <rread@clusterfs.com>
5 # Mike Shaver <shaver@clusterfs.com>
6 # This file is part of Lustre, http://www.lustre.org.
8 # Lustre is free software; you can redistribute it and/or
9 # modify it under the terms of version 2 of the GNU General Public
10 # License as published by the Free Software Foundation.
12 # Lustre is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with Lustre; if not, write to the Free Software
19 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 # lconf - lustre configuration tool
23 # lconf is the main driver script for starting and stopping
24 # lustre filesystem services.
26 # Based in part on the XML obdctl modifications done by Brian Behlendorf
28 import sys, getopt, types
29 import string, os, stat, popen2, socket, time, random, fcntl, select
30 import re, exceptions, signal, traceback
31 import xml.dom.minidom
33 if sys.version[0] == '1':
34 from FCNTL import F_GETFL, F_SETFL
36 from fcntl import F_GETFL, F_SETFL
38 PYMOD_DIR = "/usr/lib/lustre/python"
40 def development_mode():
41 base = os.path.dirname(sys.argv[0])
42 if os.access(base+"/Makefile", os.R_OK):
46 if development_mode():
47 sys.path.append('../utils')
49 sys.path.append(PYMOD_DIR)
55 DEFAULT_TCPBUF = 8388608
58 # Maximum number of devices to search for.
59 # (the /dev/loop* nodes need to be created beforehand)
60 MAX_LOOP_DEVICES = 256
61 PORTALS_DIR = 'portals'
63 # Needed to call lconf --record
66 # Please keep these in sync with the values in portals/kp30.h
78 "warning" : (1 << 10),
82 "portals" : (1 << 14),
84 "dlmtrace" : (1 << 16),
88 "rpctrace" : (1 << 20),
89 "vfstrace" : (1 << 21),
96 "undefined" : (1 << 0),
106 "portals" : (1 << 10),
107 "socknal" : (1 << 11),
108 "qswnal" : (1 << 12),
109 "pinger" : (1 << 13),
110 "filter" : (1 << 14),
116 "ptlrouter" : (1 << 20),
127 first_cleanup_error = 0
128 def cleanup_error(rc):
129 global first_cleanup_error
130 if not first_cleanup_error:
131 first_cleanup_error = rc
133 # ============================================================
134 # debugging and error funcs
136 def fixme(msg = "this feature"):
137 raise Lustre.LconfError, msg + ' not implemented yet.'
140 msg = string.join(map(str,args))
141 if not config.noexec:
142 raise Lustre.LconfError(msg)
147 msg = string.join(map(str,args))
152 print string.strip(s)
156 msg = string.join(map(str,args))
159 # ack, python's builtin int() does not support '0x123' syntax.
160 # eval can do it, although what a hack!
164 return eval(s, {}, {})
167 except SyntaxError, e:
168 raise ValueError("not a number")
170 raise ValueError("not a number")
172 # ============================================================
173 # locally defined exceptions
174 class CommandError (exceptions.Exception):
175 def __init__(self, cmd_name, cmd_err, rc=None):
176 self.cmd_name = cmd_name
177 self.cmd_err = cmd_err
182 if type(self.cmd_err) == types.StringType:
184 print "! %s (%d): %s" % (self.cmd_name, self.rc, self.cmd_err)
186 print "! %s: %s" % (self.cmd_name, self.cmd_err)
187 elif type(self.cmd_err) == types.ListType:
189 print "! %s (error %d):" % (self.cmd_name, self.rc)
191 print "! %s:" % (self.cmd_name)
192 for s in self.cmd_err:
193 print "> %s" %(string.strip(s))
198 # ============================================================
199 # handle daemons, like the acceptor
201 """ Manage starting and stopping a daemon. Assumes daemon manages
202 it's own pid file. """
204 def __init__(self, cmd):
210 log(self.command, "already running.")
212 self.path = find_prog(self.command)
214 panic(self.command, "not found.")
215 ret, out = runcmd(self.path +' '+ self.command_line())
217 raise CommandError(self.path, out, ret)
221 pid = self.read_pidfile()
224 log ("killing process", pid)
227 log("was unable to find pid of " + self.command)
228 #time.sleep(1) # let daemon die
230 log("unable to kill", self.command, e)
232 log("unable to kill", self.command)
235 pid = self.read_pidfile()
241 log("was unable to find pid of " + self.command)
248 def read_pidfile(self):
250 fp = open(self.pidfile(), 'r')
260 def clean_pidfile(self):
261 """ Remove a stale pidfile """
262 log("removing stale pidfile:", self.pidfile())
264 os.unlink(self.pidfile())
266 log(self.pidfile(), e)
268 class AcceptorHandler(DaemonHandler):
269 def __init__(self, port, net_type):
270 DaemonHandler.__init__(self, "acceptor")
275 return "/var/run/%s-%d.pid" % (self.command, self.port)
277 def command_line(self):
278 return string.join(map(str,(self.flags, self.port)))
282 # start the acceptors
284 if config.lctl_dump or config.record:
286 for port in acceptors.keys():
287 daemon = acceptors[port]
288 if not daemon.running():
291 def run_one_acceptor(port):
292 if config.lctl_dump or config.record:
294 if acceptors.has_key(port):
295 daemon = acceptors[port]
296 if not daemon.running():
299 panic("run_one_acceptor: No acceptor defined for port:", port)
301 def stop_acceptor(port):
302 if acceptors.has_key(port):
303 daemon = acceptors[port]
308 # ============================================================
309 # handle lctl interface
312 Manage communication with lctl
315 def __init__(self, cmd):
317 Initialize close by finding the lctl binary.
319 self.lctl = find_prog(cmd)
321 self.record_device = ''
324 debug('! lctl not found')
327 raise CommandError('lctl', "unable to find lctl binary.")
329 def use_save_file(self, file):
330 self.save_file = file
332 def record(self, dev_name, logname):
333 log("Recording log", logname, "on", dev_name)
334 self.record_device = dev_name
335 self.record_log = logname
337 def end_record(self):
338 log("End recording log", self.record_log, "on", self.record_device)
339 self.record_device = None
340 self.record_log = None
342 def set_nonblock(self, fd):
343 fl = fcntl.fcntl(fd, F_GETFL)
344 fcntl.fcntl(fd, F_SETFL, fl | os.O_NDELAY)
349 the cmds are written to stdin of lctl
350 lctl doesn't return errors when run in script mode, so
352 should modify command line to accept multiple commands, or
353 create complex command line options
357 cmds = '\n dump ' + self.save_file + '\n' + cmds
358 elif self.record_device:
362 %s""" % (self.record_device, self.record_log, cmds)
364 debug("+", cmd_line, cmds)
365 if config.noexec: return (0, [])
367 child = popen2.Popen3(cmd_line, 1) # Capture stdout and stderr from command
368 child.tochild.write(cmds + "\n")
369 child.tochild.close()
370 # print "LCTL:", cmds
372 # From "Python Cookbook" from O'Reilly
373 outfile = child.fromchild
374 outfd = outfile.fileno()
375 self.set_nonblock(outfd)
376 errfile = child.childerr
377 errfd = errfile.fileno()
378 self.set_nonblock(errfd)
380 outdata = errdata = ''
383 ready = select.select([outfd,errfd],[],[]) # Wait for input
384 if outfd in ready[0]:
385 outchunk = outfile.read()
386 if outchunk == '': outeof = 1
387 outdata = outdata + outchunk
388 if errfd in ready[0]:
389 errchunk = errfile.read()
390 if errchunk == '': erreof = 1
391 errdata = errdata + errchunk
392 if outeof and erreof: break
393 # end of "borrowed" code
396 if os.WIFEXITED(ret):
397 rc = os.WEXITSTATUS(ret)
400 if rc or len(errdata):
401 raise CommandError(self.lctl, errdata, rc)
404 def runcmd(self, *args):
406 run lctl using the command line
408 cmd = string.join(map(str,args))
409 debug("+", self.lctl, cmd)
410 rc, out = run(self.lctl, cmd)
412 raise CommandError(self.lctl, out, rc)
415 def clear_log(self, dev, log):
416 """ clear an existing log """
421 quit """ % (dev, log)
424 def root_squash(self, name, uid, nid):
428 quit""" % (name, uid, nid)
431 def network(self, net, nid):
436 quit """ % (net, nid)
440 def add_interface(self, net, ip, netmask = ""):
441 """ add an interface """
445 quit """ % (net, ip, netmask)
448 # delete an interface
449 def del_interface(self, net, ip):
450 """ delete an interface """
457 # create a new connection
458 def add_uuid(self, net_type, uuid, nid):
459 cmds = "\n add_uuid %s %s %s" %(uuid, nid, net_type)
462 def add_peer(self, net_type, nid, hostaddr, port):
463 if net_type in ('tcp',) and not config.lctl_dump:
468 nid, hostaddr, port )
470 elif net_type in ('openib','iib',) and not config.lctl_dump:
478 def connect(self, srv):
479 self.add_uuid(srv.net_type, srv.nid_uuid, srv.nid)
480 if srv.net_type in ('tcp','openib','iib',) and not config.lctl_dump:
482 hostaddr = string.split(srv.hostaddr[0], '/')[0]
483 self.add_peer(srv.net_type, srv.nid, hostaddr, srv.port)
486 def recover(self, dev_name, new_conn):
489 recover %s""" %(dev_name, new_conn)
492 # add a route to a range
493 def add_route(self, net, gw, lo, hi):
501 except CommandError, e:
505 def del_route(self, net, gw, lo, hi):
510 quit """ % (net, gw, lo, hi)
513 # add a route to a host
514 def add_route_host(self, net, uuid, gw, tgt):
515 self.add_uuid(net, uuid, tgt)
523 except CommandError, e:
527 # add a route to a range
528 def del_route_host(self, net, uuid, gw, tgt):
534 quit """ % (net, gw, tgt)
538 def del_peer(self, net_type, nid, hostaddr):
539 if net_type in ('tcp',) and not config.lctl_dump:
543 del_peer %s %s single_share
547 elif net_type in ('openib','iib',) and not config.lctl_dump:
551 del_peer %s single_share
556 # disconnect one connection
557 def disconnect(self, srv):
558 self.del_uuid(srv.nid_uuid)
559 if srv.net_type in ('tcp','openib','iib',) and not config.lctl_dump:
561 hostaddr = string.split(srv.hostaddr[0], '/')[0]
562 self.del_peer(srv.net_type, srv.nid, hostaddr)
564 def del_uuid(self, uuid):
572 def disconnectAll(self, net):
580 def attach(self, type, name, uuid):
583 quit""" % (type, name, uuid)
586 def setup(self, name, setup = ""):
590 quit""" % (name, setup)
593 def add_conn(self, name, conn_uuid):
597 quit""" % (name, conn_uuid)
601 # create a new device with lctl
602 def newdev(self, type, name, uuid, setup = ""):
603 self.attach(type, name, uuid);
605 self.setup(name, setup)
606 except CommandError, e:
607 self.cleanup(name, uuid, 0)
612 def cleanup(self, name, uuid, force, failover = 0):
613 if failover: force = 1
619 quit""" % (name, ('', 'force')[force],
620 ('', 'failover')[failover])
624 def lov_setup(self, name, uuid, desc_uuid, stripe_cnt,
625 stripe_sz, stripe_off, pattern, devlist = None):
628 lov_setup %s %d %d %d %s %s
629 quit""" % (name, uuid, desc_uuid, stripe_cnt, stripe_sz, stripe_off,
633 # add an OBD to a LOV
634 def lov_add_obd(self, name, uuid, obd_uuid, index, gen):
636 lov_modify_tgts add %s %s %s %s
637 quit""" % (name, obd_uuid, index, gen)
641 def lmv_setup(self, name, uuid, desc_uuid, devlist):
645 quit""" % (name, uuid, desc_uuid, devlist)
648 # delete an OBD from a LOV
649 def lov_del_obd(self, name, uuid, obd_uuid, index, gen):
651 lov_modify_tgts del %s %s %s %s
652 quit""" % (name, obd_uuid, index, gen)
656 def deactivate(self, name):
664 def dump(self, dump_file):
667 quit""" % (dump_file)
670 # get list of devices
671 def device_list(self):
672 devices = '/proc/fs/lustre/devices'
674 if os.access(devices, os.R_OK):
676 fp = open(devices, 'r')
684 def lustre_version(self):
685 rc, out = self.runcmd('version')
689 def mount_option(self, profile, osc, mdc):
691 mount_option %s %s %s
692 quit""" % (profile, osc, mdc)
695 # delete mount options
696 def del_mount_option(self, profile):
702 def set_timeout(self, timeout):
708 def set_lustre_upcall(self, upcall):
713 # ============================================================
714 # Various system-level functions
715 # (ideally moved to their own module)
717 # Run a command and return the output and status.
718 # stderr is sent to /dev/null, could use popen3 to
719 # save it if necessary
722 if config.noexec: return (0, [])
723 f = os.popen(cmd + ' 2>&1')
733 cmd = string.join(map(str,args))
736 # Run a command in the background.
737 def run_daemon(*args):
738 cmd = string.join(map(str,args))
740 if config.noexec: return 0
741 f = os.popen(cmd + ' 2>&1')
749 # Determine full path to use for an external command
750 # searches dirname(argv[0]) first, then PATH
752 syspath = string.split(os.environ['PATH'], ':')
753 cmdpath = os.path.dirname(sys.argv[0])
754 syspath.insert(0, cmdpath);
756 syspath.insert(0, os.path.join(config.portals, 'utils/'))
758 prog = os.path.join(d,cmd)
759 if os.access(prog, os.X_OK):
763 # Recursively look for file starting at base dir
764 def do_find_file(base, mod):
765 fullname = os.path.join(base, mod)
766 if os.access(fullname, os.R_OK):
768 for d in os.listdir(base):
769 dir = os.path.join(base,d)
770 if os.path.isdir(dir):
771 module = do_find_file(dir, mod)
775 # is the path a block device?
782 return stat.S_ISBLK(s[stat.ST_MODE])
784 # find the journal device from mkfs options
790 while i < len(x) - 1:
791 if x[i] == '-J' and x[i+1].startswith('device='):
797 # build fs according to type
799 def mkfs(dev, devsize, fstype, jsize, isize, mkfsoptions, isblock=1):
805 panic("size of filesystem on '%s' must be larger than 8MB, but is set to %s"%
807 # devsize is in 1k, and fs block count is in 4k
808 block_cnt = devsize/4
810 if fstype in ('ext3', 'extN', 'ldiskfs'):
811 # ext3 journal size is in megabytes
812 # but don't set jsize if mkfsoptions indicates a separate journal device
813 if jsize == 0 and jdev(mkfsoptions) == '':
815 if not is_block(dev):
816 ret, out = runcmd("ls -l %s" %dev)
817 devsize = int(string.split(out[0])[4]) / 1024
819 # sfdisk works for symlink, hardlink, and realdev
820 ret, out = runcmd("sfdisk -s %s" %dev)
822 devsize = int(out[0])
824 # sfdisk -s will fail for too large block device,
825 # then, read the size of partition from /proc/partitions
827 # get the realpath of the device
828 # it may be the real device, such as /dev/hda7
829 # or the hardlink created via mknod for a device
830 if 'realpath' in dir(os.path):
831 real_dev = os.path.realpath(dev)
835 while os.path.islink(real_dev) and (link_count < 20):
836 link_count = link_count + 1
837 dev_link = os.readlink(real_dev)
838 if os.path.isabs(dev_link):
841 real_dev = os.path.join(os.path.dirname(real_dev), dev_link)
843 panic("Entountered too many symbolic links resolving block device:", dev)
845 # get the major and minor number of the realpath via ls
846 # it seems python(os.stat) does not return
847 # the st_rdev member of the stat structure
848 ret, out = runcmd("ls -l %s" %real_dev)
849 major = string.split(string.split(out[0])[4], ",")[0]
850 minor = string.split(out[0])[5]
852 # get the devsize from /proc/partitions with the major and minor number
853 ret, out = runcmd("cat /proc/partitions")
856 if string.split(line)[0] == major and string.split(line)[1] == minor:
857 devsize = int(string.split(line)[2])
860 if devsize > 1024 * 1024:
861 jsize = ((devsize / 102400) * 4)
864 if jsize: jopt = "-J size=%d" %(jsize,)
865 if isize: iopt = "-I %d" %(isize,)
866 mkfs = 'mkfs.ext2 -j -b 4096 '
867 if not isblock or config.force:
869 if jdev(mkfsoptions) != '':
870 jmkfs = 'mkfs.ext2 -b 4096 -O journal_dev '
872 jmkfs = jmkfs + '-F '
873 jmkfs = jmkfs + jdev(mkfsoptions)
874 (ret, out) = run (jmkfs)
876 panic("Unable format journal device:", jdev(mkfsoptions), string.join(out))
877 elif fstype == 'reiserfs':
878 # reiserfs journal size is in blocks
879 if jsize: jopt = "--journal_size %d" %(jsize,)
880 mkfs = 'mkreiserfs -ff'
882 panic('unsupported fs type: ', fstype)
884 if config.mkfsoptions != None:
885 mkfs = mkfs + ' ' + config.mkfsoptions
886 if mkfsoptions != None:
887 mkfs = mkfs + ' ' + mkfsoptions
888 (ret, out) = run (mkfs, jopt, iopt, dev, block_cnt)
890 panic("Unable to build fs:", dev, string.join(out))
891 # enable hash tree indexing on fsswe
892 if fstype in ('ext3', 'extN', 'ldiskfs'):
893 htree = 'echo "feature FEATURE_C5" | debugfs -w'
894 (ret, out) = run (htree, dev)
896 panic("Unable to enable htree:", dev)
898 # some systems use /dev/loopN, some /dev/loop/N
902 if not os.access(loop + str(0), os.R_OK):
904 if not os.access(loop + str(0), os.R_OK):
905 panic ("can't access loop devices")
908 # find loop device assigned to the file
909 def find_assigned_loop(file):
911 for n in xrange(0, MAX_LOOP_DEVICES):
913 if os.access(dev, os.R_OK):
914 (stat, out) = run('losetup', dev)
915 if out and stat == 0:
916 m = re.search(r'\((.*)\)', out[0])
917 if m and file == m.group(1):
923 # create file if necessary and assign the first free loop device
924 def init_loop(file, size, fstype, journal_size, inode_size,
925 mkfsoptions, reformat, autoformat, backfstype, backfile):
928 realfstype = backfstype
929 if is_block(backfile):
930 if reformat or (need_format(realfstype, backfile) and autoformat == 'yes'):
931 mkfs(realfile, size, realfstype, journal_size, inode_size, mkfsoptions, isblock=0)
937 dev = find_assigned_loop(realfile)
939 print 'WARNING: file ', realfile, 'already mapped to', dev
942 if reformat or not os.access(realfile, os.R_OK | os.W_OK):
944 panic("size of loopback file '%s' must be larger than 8MB, but is set to %s" % (realfile, size))
945 (ret, out) = run("dd if=/dev/zero bs=1k count=0 seek=%d of=%s" %(size, realfile))
947 panic("Unable to create backing store:", realfile)
949 mkfs(realfile, size, realfstype, journal_size, inode_size,
950 mkfsoptions, isblock=0)
953 # find next free loop
954 for n in xrange(0, MAX_LOOP_DEVICES):
956 if os.access(dev, os.R_OK):
957 (stat, out) = run('losetup', dev)
959 print "attach " + realfile + " <-> " + dev
960 run('losetup', dev, realfile)
963 print "out of loop devices"
965 print "out of loop devices"
968 # undo loop assignment
969 def clean_loop(dev, fstype, backfstype, backdev):
974 if not is_block(realfile):
975 dev = find_assigned_loop(realfile)
977 print "detach " + dev + " <-> " + realfile
978 ret, out = run('losetup -d', dev)
980 log('unable to clean loop device:', dev, 'for file:', realfile)
983 # finilizes passed device
984 def clean_dev(dev, fstype, backfstype, backdev):
985 if fstype == 'smfs' or not is_block(dev):
986 clean_loop(dev, fstype, backfstype, backdev)
988 # determine if dev is formatted as a <fstype> filesystem
989 def need_format(fstype, dev):
990 # FIXME don't know how to implement this
993 # initialize a block device if needed
994 def block_dev(dev, size, fstype, reformat, autoformat, journal_size,
995 inode_size, mkfsoptions, backfstype, backdev):
999 if fstype == 'smfs' or not is_block(dev):
1000 dev = init_loop(dev, size, fstype, journal_size, inode_size,
1001 mkfsoptions, reformat, autoformat, backfstype, backdev)
1002 elif reformat or (need_format(fstype, dev) and autoformat == 'yes'):
1003 mkfs(dev, size, fstype, journal_size, inode_size, mkfsoptions,
1006 # panic("device:", dev,
1007 # "not prepared, and autoformat is not set.\n",
1008 # "Rerun with --reformat option to format ALL filesystems")
1013 """lookup IP address for an interface"""
1014 rc, out = run("/sbin/ifconfig", iface)
1017 addr = string.split(out[1])[1]
1018 ip = string.split(addr, ':')[1]
1021 def def_mount_options(fstype, target):
1022 """returns deafult mount options for passed fstype and target (mds, ost)"""
1023 if fstype == 'ext3' or fstype == 'ldiskfs':
1024 mountfsoptions = "errors=remount-ro"
1025 if target == 'ost' and sys_get_branch() == '2.4':
1026 mountfsoptions = "%s,asyncdel" % (mountfsoptions)
1027 return mountfsoptions
1030 def sys_get_elan_position_file():
1031 procfiles = ["/proc/elan/device0/position",
1032 "/proc/qsnet/elan4/device0/position",
1033 "/proc/qsnet/elan3/device0/position"]
1035 if os.access(p, os.R_OK):
1039 def sys_get_local_nid(net_type, wildcard, cluster_id):
1040 """Return the local nid."""
1042 if sys_get_elan_position_file():
1043 local = sys_get_local_address('elan', '*', cluster_id)
1045 local = sys_get_local_address(net_type, wildcard, cluster_id)
1048 def sys_get_local_address(net_type, wildcard, cluster_id):
1049 """Return the local address for the network type."""
1051 if net_type in ('tcp','openib','iib',):
1053 iface, star = string.split(wildcard, ':')
1054 local = if2addr(iface)
1056 panic ("unable to determine ip for:", wildcard)
1058 host = socket.gethostname()
1059 local = socket.gethostbyname(host)
1060 elif net_type == 'elan':
1061 # awk '/NodeId/ { print $2 }' 'sys_get_elan_position_file()'
1062 f = sys_get_elan_position_file()
1064 panic ("unable to determine local Elan ID")
1067 lines = fp.readlines()
1071 if a[0] == 'NodeId':
1075 nid = my_int(cluster_id) + my_int(elan_id)
1076 local = "%d" % (nid)
1077 except ValueError, e:
1081 elif net_type == 'lo':
1082 fixme("automatic local address for loopback")
1083 elif net_type == 'gm':
1084 fixme("automatic local address for GM")
1088 def sys_get_branch():
1089 """Returns kernel release"""
1091 fp = open('/proc/sys/kernel/osrelease')
1092 lines = fp.readlines()
1096 version = string.split(l)
1097 a = string.split(version[0], '.')
1098 return a[0] + '.' + a[1]
1103 # XXX: instead of device_list, ask for $name and see what we get
1104 def is_prepared(name):
1105 """Return true if a device exists for the name"""
1106 if config.lctl_dump:
1108 if (config.noexec or config.record) and config.cleanup:
1111 # expect this format:
1112 # 1 UP ldlm ldlm ldlm_UUID 2
1113 out = lctl.device_list()
1115 if name == string.split(s)[3]:
1117 except CommandError, e:
1121 def net_is_prepared():
1122 """If the any device exists, then assume that all networking
1123 has been configured"""
1124 out = lctl.device_list()
1127 def fs_is_mounted(path):
1128 """Return true if path is a mounted lustre filesystem"""
1130 fp = open('/proc/mounts')
1131 lines = fp.readlines()
1135 if a[1] == path and a[2] == 'lustre_lite':
1141 def kmod_find(src_dir, dev_dir, modname):
1142 modbase = src_dir +'/'+ dev_dir +'/'+ modname
1143 for modext in '.ko', '.o':
1144 module = modbase + modext
1146 if os.access(module, os.R_OK):
1152 def kmod_info(modname):
1153 """Returns reference count for passed module name."""
1155 fp = open('/proc/modules')
1156 lines = fp.readlines()
1159 # please forgive my tired fingers for this one
1160 ret = filter(lambda word, mod = modname: word[0] == mod,
1161 map(lambda line: string.split(line), lines))
1165 except Exception, e:
1169 """Presents kernel module"""
1170 def __init__(self, src_dir, dev_dir, name):
1171 self.src_dir = src_dir
1172 self.dev_dir = dev_dir
1177 log ('loading module:', self.name, 'srcdir',
1178 self.src_dir, 'devdir', self.dev_dir)
1180 module = kmod_find(self.src_dir, self.dev_dir,
1183 panic('module not found:', self.name)
1184 (rc, out) = run('/sbin/insmod', module)
1186 raise CommandError('insmod', out, rc)
1188 (rc, out) = run('/sbin/modprobe', self.name)
1190 raise CommandError('modprobe', out, rc)
1194 log('unloading module:', self.name)
1195 (rc, out) = run('/sbin/rmmod', self.name)
1197 log('unable to unload module:', self.name +
1198 "(" + self.refcount() + ")")
1202 """Returns module info if any."""
1203 return kmod_info(self.name)
1206 """Returns 1 if module is loaded. Otherwise 0 is returned."""
1213 """Returns module refcount."""
1220 """Returns 1 if module is used, otherwise 0 is returned."""
1226 if users and users != '(unused)' and users != '-':
1234 """Returns 1 if module is busy, otherwise 0 is returned."""
1235 if self.loaded() and (self.used() or self.refcount() != '0'):
1241 """Manage kernel modules"""
1242 def __init__(self, lustre_dir, portals_dir):
1243 self.lustre_dir = lustre_dir
1244 self.portals_dir = portals_dir
1245 self.kmodule_list = []
1247 def find_module(self, modname):
1248 """Find module by module name"""
1249 for mod in self.kmodule_list:
1250 if mod.name == modname:
1254 def add_portals_module(self, dev_dir, modname):
1255 """Append a module to list of modules to load."""
1257 mod = self.find_module(modname)
1259 mod = kmod(self.portals_dir, dev_dir, modname)
1260 self.kmodule_list.append(mod)
1262 def add_lustre_module(self, dev_dir, modname):
1263 """Append a module to list of modules to load."""
1265 mod = self.find_module(modname)
1267 mod = kmod(self.lustre_dir, dev_dir, modname)
1268 self.kmodule_list.append(mod)
1270 def load_modules(self):
1271 """Load all the modules in the list in the order they appear."""
1272 for mod in self.kmodule_list:
1273 if mod.loaded() and not config.noexec:
1277 def cleanup_modules(self):
1278 """Unload the modules in the list in reverse order."""
1279 rev = self.kmodule_list
1282 if (not mod.loaded() or mod.busy()) and not config.noexec:
1285 if mod.name == 'portals' and config.dump:
1286 lctl.dump(config.dump)
1289 # ============================================================
1290 # Classes to prepare and cleanup the various objects
1293 """ Base class for the rest of the modules. The default cleanup method is
1294 defined here, as well as some utilitiy funcs.
1296 def __init__(self, module_name, db):
1298 self.module_name = module_name
1299 self.name = self.db.getName()
1300 self.uuid = self.db.getUUID()
1304 def info(self, *args):
1305 msg = string.join(map(str,args))
1306 print self.module_name + ":", self.name, self.uuid, msg
1309 """ default cleanup, used for most modules """
1312 lctl.cleanup(self.name, self.uuid, config.force)
1313 except CommandError, e:
1314 log(self.module_name, "cleanup failed: ", self.name)
1318 def add_module(self, manager):
1319 """Adds all needed modules in the order they appear."""
1322 def safe_to_clean(self):
1325 def safe_to_clean_modules(self):
1326 return self.safe_to_clean()
1328 class Network(Module):
1329 def __init__(self,db):
1330 Module.__init__(self, 'NETWORK', db)
1331 self.net_type = self.db.get_val('nettype')
1332 self.nid = self.db.get_val('nid', '*')
1333 self.cluster_id = self.db.get_val('clusterid', "0")
1334 self.port = self.db.get_val_int('port', 0)
1337 self.nid = sys_get_local_nid(self.net_type, self.nid, self.cluster_id)
1339 panic("unable to set nid for", self.net_type, self.nid, cluster_id)
1340 self.generic_nid = 1
1341 debug("nid:", self.nid)
1343 self.generic_nid = 0
1345 self.nid_uuid = self.nid_to_uuid(self.nid)
1346 self.hostaddr = self.db.get_hostaddr()
1347 if len(self.hostaddr) == 0:
1348 self.hostaddr.append(self.nid)
1349 if '*' in self.hostaddr[0]:
1350 self.hostaddr[0] = sys_get_local_address(self.net_type, self.hostaddr[0], self.cluster_id)
1351 if not self.hostaddr[0]:
1352 panic("unable to set hostaddr for", self.net_type, self.hostaddr[0], self.cluster_id)
1353 debug("hostaddr:", self.hostaddr[0])
1355 def add_module(self, manager):
1356 manager.add_portals_module("libcfs", 'libcfs')
1357 manager.add_portals_module("portals", 'portals')
1358 if node_needs_router():
1359 manager.add_portals_module("router", 'kptlrouter')
1360 if self.net_type == 'tcp':
1361 manager.add_portals_module("knals/socknal", 'ksocknal')
1362 if self.net_type == 'elan':
1363 manager.add_portals_module("knals/qswnal", 'kqswnal')
1364 if self.net_type == 'gm':
1365 manager.add_portals_module("knals/gmnal", 'kgmnal')
1366 if self.net_type == 'openib':
1367 manager.add_portals_module("knals/openibnal", 'kopenibnal')
1368 if self.net_type == 'iib':
1369 manager.add_portals_module("knals/iibnal", 'kiibnal')
1370 if self.net_type == 'lo':
1371 manager.add_portals_module("knals/lonal", 'klonal')
1373 def nid_to_uuid(self, nid):
1374 return "NID_%s_UUID" %(nid,)
1377 if not config.record and net_is_prepared():
1379 self.info(self.net_type, self.nid, self.port)
1380 if not (config.record and self.generic_nid):
1381 lctl.network(self.net_type, self.nid)
1382 if self.net_type == 'tcp':
1384 for hostaddr in self.db.get_hostaddr():
1385 ip = string.split(hostaddr, '/')[0]
1386 if len(string.split(hostaddr, '/')) == 2:
1387 netmask = string.split(hostaddr, '/')[1]
1390 lctl.add_interface(self.net_type, ip, netmask)
1391 if self.net_type == 'elan':
1393 if self.port and node_is_router():
1394 run_one_acceptor(self.port)
1395 self.connect_peer_gateways()
1397 def connect_peer_gateways(self):
1398 for router in self.db.lookup_class('node'):
1399 if router.get_val_int('router', 0):
1400 for netuuid in router.get_networks():
1401 net = self.db.lookup(netuuid)
1403 if (gw.cluster_id == self.cluster_id and
1404 gw.net_type == self.net_type):
1405 if gw.nid != self.nid:
1408 def disconnect_peer_gateways(self):
1409 for router in self.db.lookup_class('node'):
1410 if router.get_val_int('router', 0):
1411 for netuuid in router.get_networks():
1412 net = self.db.lookup(netuuid)
1414 if (gw.cluster_id == self.cluster_id and
1415 gw.net_type == self.net_type):
1416 if gw.nid != self.nid:
1419 except CommandError, e:
1420 print "disconnect failed: ", self.name
1424 def safe_to_clean(self):
1425 return not net_is_prepared()
1428 self.info(self.net_type, self.nid, self.port)
1430 stop_acceptor(self.port)
1431 if node_is_router():
1432 self.disconnect_peer_gateways()
1433 if self.net_type == 'tcp':
1434 for hostaddr in self.db.get_hostaddr():
1435 ip = string.split(hostaddr, '/')[0]
1436 lctl.del_interface(self.net_type, ip)
1438 def correct_level(self, level, op=None):
1441 class RouteTable(Module):
1442 def __init__(self,db):
1443 Module.__init__(self, 'ROUTES', db)
1445 def server_for_route(self, net_type, gw, gw_cluster_id, tgt_cluster_id,
1447 # only setup connections for tcp, openib, and iib NALs
1449 if not net_type in ('tcp','openib','iib',):
1452 # connect to target if route is to single node and this node is the gw
1453 if lo == hi and local_interface(net_type, gw_cluster_id, gw):
1454 if not local_cluster(net_type, tgt_cluster_id):
1455 panic("target", lo, " not on the local cluster")
1456 srvdb = self.db.nid2server(lo, net_type, gw_cluster_id)
1457 # connect to gateway if this node is not the gw
1458 elif (local_cluster(net_type, gw_cluster_id)
1459 and not local_interface(net_type, gw_cluster_id, gw)):
1460 srvdb = self.db.nid2server(gw, net_type, gw_cluster_id)
1465 panic("no server for nid", lo)
1468 return Network(srvdb)
1471 if not config.record and net_is_prepared():
1474 for net_type, gw, gw_cluster_id, tgt_cluster_id, lo, hi in self.db.get_route_tbl():
1475 lctl.add_route(net_type, gw, lo, hi)
1476 srv = self.server_for_route(net_type, gw, gw_cluster_id, tgt_cluster_id, lo, hi)
1480 def safe_to_clean(self):
1481 return not net_is_prepared()
1484 if net_is_prepared():
1485 # the network is still being used, don't clean it up
1487 for net_type, gw, gw_cluster_id, tgt_cluster_id, lo, hi in self.db.get_route_tbl():
1488 srv = self.server_for_route(net_type, gw, gw_cluster_id, tgt_cluster_id, lo, hi)
1491 lctl.disconnect(srv)
1492 except CommandError, e:
1493 print "disconnect failed: ", self.name
1498 lctl.del_route(net_type, gw, lo, hi)
1499 except CommandError, e:
1500 print "del_route failed: ", self.name
1504 class Management(Module):
1505 def __init__(self, db):
1506 Module.__init__(self, 'MGMT', db)
1508 def add_module(self, manager):
1509 manager.add_lustre_module('lvfs', 'lvfs')
1510 manager.add_lustre_module('obdclass', 'obdclass')
1511 manager.add_lustre_module('ptlrpc', 'ptlrpc')
1512 manager.add_lustre_module('mgmt', 'mgmt_svc')
1515 if not config.record and is_prepared(self.name):
1518 lctl.newdev("mgmt", self.name, self.uuid)
1520 def safe_to_clean(self):
1524 if is_prepared(self.name):
1525 Module.cleanup(self)
1527 def correct_level(self, level, op=None):
1530 # This is only needed to load the modules; the LDLM device
1531 # is now created automatically.
1533 def __init__(self,db):
1534 Module.__init__(self, 'LDLM', db)
1536 def add_module(self, manager):
1537 manager.add_lustre_module('lvfs', 'lvfs')
1538 manager.add_lustre_module('obdclass', 'obdclass')
1539 manager.add_lustre_module('ptlrpc', 'ptlrpc')
1547 def correct_level(self, level, op=None):
1551 def __init__(self, db, uuid, fs_name, name_override = None, config_only = None):
1552 Module.__init__(self, 'LOV', db)
1553 if name_override != None:
1554 self.name = "lov_%s" % name_override
1555 self.mds_uuid = self.db.get_first_ref('mds')
1556 self.stripe_sz = self.db.get_val_int('stripesize', 1048576)
1557 self.stripe_off = self.db.get_val_int('stripeoffset', 0)
1558 self.pattern = self.db.get_val_int('stripepattern', 0)
1559 self.devlist = self.db.get_lov_tgts('lov_tgt')
1560 self.stripe_cnt = self.db.get_val_int('stripecount', len(self.devlist))
1563 self.desc_uuid = self.uuid
1564 self.uuid = generate_client_uuid(self.name)
1565 self.fs_name = fs_name
1567 self.config_only = 1
1569 self.config_only = None
1570 mds = self.db.lookup(self.mds_uuid)
1571 self.mds_name = mds.getName()
1572 for (obd_uuid, index, gen, active) in self.devlist:
1575 self.obdlist.append(obd_uuid)
1576 obd = self.db.lookup(obd_uuid)
1577 osc = get_osc(obd, self.uuid, fs_name)
1579 self.osclist.append((osc, index, gen, active))
1581 panic('osc not found:', obd_uuid)
1587 if not config.record and is_prepared(self.name):
1589 self.info(self.mds_uuid, self.stripe_cnt, self.stripe_sz,
1590 self.stripe_off, self.pattern, self.devlist,
1592 lctl.lov_setup(self.name, self.uuid, self.desc_uuid, self.stripe_cnt,
1593 self.stripe_sz, self.stripe_off, self.pattern,
1594 string.join(self.obdlist))
1595 for (osc, index, gen, active) in self.osclist:
1596 target_uuid = osc.target_uuid
1598 # Only ignore connect failures with --force, which
1599 # isn't implemented here yet.
1601 osc.prepare(ignore_connect_failure=0)
1602 except CommandError, e:
1603 print "Error preparing OSC %s\n" % osc.uuid
1605 lctl.lov_add_obd(self.name, self.uuid, target_uuid, index, gen)
1608 for (osc, index, gen, active) in self.osclist:
1609 target_uuid = osc.target_uuid
1611 if is_prepared(self.name):
1612 Module.cleanup(self)
1613 if self.config_only:
1614 panic("Can't clean up config_only LOV ", self.name)
1616 def add_module(self, manager):
1617 if self.config_only:
1618 panic("Can't load modules for config_only LOV ", self.name)
1619 for (osc, index, gen, active) in self.osclist:
1620 osc.add_module(manager)
1622 manager.add_lustre_module('lov', 'lov')
1624 def correct_level(self, level, op=None):
1628 def __init__(self, db, uuid, fs_name, name_override = None):
1629 Module.__init__(self, 'LMV', db)
1630 if name_override != None:
1631 self.name = "lmv_%s" % name_override
1632 self.devlist = self.db.get_refs('mds')
1634 self.desc_uuid = self.uuid
1636 self.fs_name = fs_name
1637 for mds_uuid in self.devlist:
1638 mds = self.db.lookup(mds_uuid)
1640 panic("MDS not found!")
1641 mdc = MDC(mds, self.uuid, fs_name)
1643 self.mdclist.append(mdc)
1645 panic('mdc not found:', mds_uuid)
1648 if is_prepared(self.name):
1652 for mdc in self.mdclist:
1654 # Only ignore connect failures with --force, which
1655 # isn't implemented here yet.
1656 mdc.prepare(ignore_connect_failure=0)
1657 except CommandError, e:
1658 print "Error preparing LMV %s\n" % mdc.uuid
1661 lctl.lmv_setup(self.name, self.uuid, self.desc_uuid,
1662 string.join(self.devlist))
1665 for mdc in self.mdclist:
1667 if is_prepared(self.name):
1668 Module.cleanup(self)
1670 def add_module(self, manager):
1671 for mdc in self.mdclist:
1672 mdc.add_module(manager)
1674 manager.add_lustre_module('lmv', 'lmv')
1676 def correct_level(self, level, op=None):
1679 class MDSDEV(Module):
1680 def __init__(self,db):
1681 Module.__init__(self, 'MDSDEV', db)
1682 self.devpath = self.db.get_val('devpath','')
1683 self.backdevpath = self.db.get_val('backdevpath','')
1684 self.size = self.db.get_val_int('devsize', 0)
1685 self.journal_size = self.db.get_val_int('journalsize', 0)
1686 self.fstype = self.db.get_val('fstype', '')
1687 self.backfstype = self.db.get_val('backfstype', '')
1688 self.nspath = self.db.get_val('nspath', '')
1689 self.mkfsoptions = self.db.get_val('mkfsoptions', '')
1690 self.mountfsoptions = self.db.get_val('mountfsoptions', '')
1691 self.obdtype = self.db.get_val('obdtype', '')
1692 self.root_squash = self.db.get_val('root_squash', '')
1693 self.no_root_squash = self.db.get_val('no_root_squash', '')
1694 # overwrite the orignal MDSDEV name and uuid with the MDS name and uuid
1695 target_uuid = self.db.get_first_ref('target')
1696 self.mds = self.db.lookup(target_uuid)
1697 self.name = self.mds.getName()
1698 self.client_uuids = self.mds.get_refs('client')
1703 lmv_uuid = self.db.get_first_ref('lmv')
1704 if lmv_uuid != None:
1705 self.lmv = self.db.lookup(lmv_uuid)
1706 if self.lmv != None:
1707 self.client_uuids = self.lmv.get_refs('client')
1709 # FIXME: if fstype not set, then determine based on kernel version
1710 self.format = self.db.get_val('autoformat', "no")
1711 if self.mds.get_val('failover', 0):
1712 self.failover_mds = 'f'
1714 self.failover_mds = 'n'
1715 active_uuid = get_active_target(self.mds)
1717 panic("No target device found:", target_uuid)
1718 if active_uuid == self.uuid:
1722 if self.active and config.group and config.group != self.mds.get_val('group'):
1725 # default inode inode for case when neither LOV either
1726 # LMV is accessible.
1727 self.inode_size = 256
1729 inode_size = self.db.get_val_int('inodesize', 0)
1730 if not inode_size == 0:
1731 self.inode_size = inode_size
1733 # find the LOV for this MDS
1734 lovconfig_uuid = self.mds.get_first_ref('lovconfig')
1735 if lovconfig_uuid or self.lmv != None:
1736 if self.lmv != None:
1737 lovconfig_uuid = self.lmv.get_first_ref('lovconfig')
1738 lovconfig = self.lmv.lookup(lovconfig_uuid)
1739 lov_uuid = lovconfig.get_first_ref('lov')
1740 if lov_uuid == None:
1741 panic(self.mds.getName() + ": No LOV found for lovconfig ",
1744 lovconfig = self.mds.lookup(lovconfig_uuid)
1745 lov_uuid = lovconfig.get_first_ref('lov')
1746 if lov_uuid == None:
1747 panic(self.mds.getName() + ": No LOV found for lovconfig ",
1750 if self.lmv != None:
1751 lovconfig_uuid = self.lmv.get_first_ref('lovconfig')
1752 lovconfig = self.lmv.lookup(lovconfig_uuid)
1753 lov_uuid = lovconfig.get_first_ref('lov')
1755 lov = LOV(self.db.lookup(lov_uuid), lov_uuid, self.name,
1758 # default stripe count controls default inode_size
1759 stripe_count = lov.stripe_cnt
1760 if stripe_count > 77:
1761 self.inode_size = 4096
1762 elif stripe_count > 35:
1763 self.inode_size = 2048
1764 elif stripe_count > 13:
1765 self.inode_size = 1024
1766 elif stripe_count > 3:
1767 self.inode_size = 512
1769 self.inode_size = 256
1771 self.target_dev_uuid = self.uuid
1772 self.uuid = target_uuid
1775 if self.lmv != None:
1776 client_uuid = self.name + "_lmv_UUID"
1777 self.master = LMV(self.lmv, client_uuid,
1778 self.name, self.name)
1780 def add_module(self, manager):
1782 manager.add_lustre_module('mdc', 'mdc')
1783 manager.add_lustre_module('osc', 'osc')
1784 manager.add_lustre_module('ost', 'ost')
1785 manager.add_lustre_module('lov', 'lov')
1786 manager.add_lustre_module('mds', 'mds')
1788 if self.fstype == 'smfs':
1789 manager.add_lustre_module('smfs', 'smfs')
1791 if self.fstype == 'ldiskfs':
1792 manager.add_lustre_module('ldiskfs', 'ldiskfs')
1795 manager.add_lustre_module('lvfs', 'fsfilt_%s' % (self.fstype))
1797 # if fstype is smfs, then we should also take care about backing
1799 if self.fstype == 'smfs':
1800 manager.add_lustre_module('lvfs', 'fsfilt_%s' % (self.backfstype))
1802 for option in string.split(self.mountfsoptions, ','):
1803 if option == 'snap':
1804 if not self.fstype == 'smfs':
1805 panic("mountoptions has 'snap', but fstype is not smfs.")
1806 manager.add_lustre_module('lvfs', 'fsfilt_snap_%s' % (self.fstype))
1807 manager.add_lustre_module('lvfs', 'fsfilt_snap_%s' % (self.backfstype))
1810 if self.master != None:
1811 self.master.add_module(manager)
1813 def get_mount_options(self, blkdev):
1814 options = def_mount_options(self.fstype, 'mds')
1816 if config.mountfsoptions != None:
1818 options = "%s,%s" %(options, config.mountfsoptions)
1820 options = config.mountfsoptions
1821 if self.mountfsoptions != None:
1822 options = "%s,%s" %(options, self.mountfsoptions)
1824 if self.mountfsoptions != None:
1826 options = "%s,%s" %(options, self.mountfsoptions)
1828 options = self.mountfsoptions
1830 if self.fstype == 'smfs':
1832 options = "%s,type=%s,dev=%s" %(options,
1833 self.backfstype, blkdev)
1835 options = "type=%s,dev=%s" %(self.backfstype, blkdev)
1839 if not config.record and is_prepared(self.name):
1842 debug(self.uuid, "not active")
1845 # run write_conf automatically, if --reformat used
1850 if self.master != None:
1851 self.master.prepare()
1853 # never reformat here
1854 blkdev = block_dev(self.devpath, self.size, self.fstype, 0,
1855 self.format, self.journal_size, self.inode_size,
1856 self.mkfsoptions, self.backfstype, self.backdevpath)
1858 if not is_prepared('MDT'):
1859 lctl.newdev("mdt", 'MDT', 'MDT_UUID', setup ="")
1861 if self.fstype == 'smfs':
1862 realdev = self.fstype
1866 if self.obdtype == None:
1867 self.obdtype = 'dumb'
1869 if self.master == None:
1870 master_name = 'dumb'
1872 master_name = self.master.name
1874 if self.client_uuids == None:
1875 profile_name = 'dumb'
1877 profile_name = self.name
1879 mountfsoptions = self.get_mount_options(blkdev)
1881 self.info("mds", realdev, mountfsoptions, self.fstype, self.size,
1882 self.format, master_name, profile_name, self.obdtype)
1884 lctl.newdev("mds", self.name, self.uuid,
1885 setup = "%s %s %s %s %s %s" %(realdev,
1886 self.fstype, profile_name, mountfsoptions,
1887 master_name, self.obdtype))
1889 if development_mode():
1890 procentry = "/proc/fs/lustre/mds/grp_hash_upcall"
1891 upcall = os.path.abspath(os.path.dirname(sys.argv[0]) + "/l_getgroups")
1892 if not (os.access(procentry, os.R_OK) and os.access(upcall, os.R_OK)):
1893 print "MDS Warning: failed to set group-hash upcall"
1895 run("echo ", upcall, " > ", procentry)
1897 except CommandError, e:
1899 panic("MDS is missing the config log. Need to run " +
1900 "lconf --write_conf.")
1904 if config.root_squash == None:
1905 config.root_squash = self.root_squash
1906 if config.no_root_squash == None:
1907 config.no_root_squash = self.no_root_squash
1908 if config.root_squash:
1909 if config.no_root_squash:
1910 nsnid = config.no_root_squash
1913 lctl.root_squash(self.name, config.root_squash, nsnid)
1915 def write_conf(self):
1916 if not self.client_uuids:
1920 if not is_prepared(self.name):
1921 blkdev = block_dev(self.devpath, self.size, self.fstype,
1922 config.reformat, self.format, self.journal_size,
1923 self.inode_size, self.mkfsoptions,
1924 self.backfstype, self.backdevpath)
1926 if self.fstype == 'smfs':
1927 realdev = self.fstype
1931 # Even for writing logs we mount mds with supplied mount options
1932 # because it will not mount smfs (if used) otherwise.
1933 mountfsoptions = self.get_mount_options(blkdev)
1935 if self.obdtype == None:
1936 self.obdtype = 'dumb'
1938 self.info("mds", realdev, mountfsoptions, self.fstype, self.size,
1939 self.format, "dumb", "dumb", self.obdtype)
1941 lctl.newdev("mds", self.name, self.uuid,
1942 setup ="%s %s %s %s %s %s" %(realdev, self.fstype,
1943 'dumb', mountfsoptions,
1944 'dumb', self.obdtype))
1947 # record logs for all MDS clients
1948 for obd_uuid in self.client_uuids:
1949 log("recording client:", obd_uuid)
1951 client_uuid = generate_client_uuid(self.name)
1952 client = VOSC(self.db.lookup(obd_uuid), client_uuid,
1953 self.name, self.name)
1955 lctl.clear_log(self.name, self.name)
1956 lctl.record(self.name, self.name)
1958 lctl.mount_option(self.name, client.get_name(), "")
1960 process_updates(self.db, self.name, self.name, client)
1963 lctl.clear_log(self.name, self.name + '-clean')
1964 lctl.record(self.name, self.name + '-clean')
1966 lctl.del_mount_option(self.name)
1968 process_updates(self.db, self.name, self.name + '-clean', client)
1972 # record logs for each client
1978 config_options = "--ldapurl " + config.ldapurl + " --config " + config.config
1980 config_options = CONFIG_FILE
1982 for node_db in self.db.lookup_class('node'):
1983 client_name = node_db.getName()
1984 for prof_uuid in node_db.get_refs('profile'):
1985 prof_db = node_db.lookup(prof_uuid)
1986 # refactor this into a funtion to test "clientness"
1988 for ref_class, ref_uuid in prof_db.get_all_refs():
1989 if ref_class in ('mountpoint','echoclient'):
1990 debug("recording", client_name)
1991 old_noexec = config.noexec
1993 ret, out = run (sys.argv[0], noexec_opt,
1994 " -v --record --nomod",
1995 "--record_log", client_name,
1996 "--record_device", self.name,
1997 "--node", client_name,
2000 for s in out: log("record> ", string.strip(s))
2001 ret, out = run (sys.argv[0], noexec_opt,
2002 "--cleanup -v --record --nomod",
2003 "--record_log", client_name + "-clean",
2004 "--record_device", self.name,
2005 "--node", client_name,
2008 for s in out: log("record> ", string.strip(s))
2009 config.noexec = old_noexec
2012 lctl.cleanup(self.name, self.uuid, 0, 0)
2013 except CommandError, e:
2014 log(self.module_name, "cleanup failed: ", self.name)
2017 Module.cleanup(self)
2019 clean_dev(self.devpath, self.fstype, self.backfstype,
2022 def msd_remaining(self):
2023 out = lctl.device_list()
2025 if string.split(s)[2] in ('mds',):
2028 def safe_to_clean(self):
2031 def safe_to_clean_modules(self):
2032 return not self.msd_remaining()
2036 debug(self.uuid, "not active")
2039 if is_prepared(self.name):
2041 lctl.cleanup(self.name, self.uuid, config.force,
2043 except CommandError, e:
2044 log(self.module_name, "cleanup failed: ", self.name)
2047 Module.cleanup(self)
2049 if self.master != None:
2050 self.master.cleanup()
2051 if not self.msd_remaining() and is_prepared('MDT'):
2053 lctl.cleanup("MDT", "MDT_UUID", config.force,
2055 except CommandError, e:
2056 print "cleanup failed: ", self.name
2060 clean_dev(self.devpath, self.fstype, self.backfstype,
2063 def correct_level(self, level, op=None):
2064 #if self.master != None:
2069 def __init__(self, db):
2070 Module.__init__(self, 'OSD', db)
2071 self.osdtype = self.db.get_val('osdtype')
2072 self.devpath = self.db.get_val('devpath', '')
2073 self.backdevpath = self.db.get_val('backdevpath', '')
2074 self.size = self.db.get_val_int('devsize', 0)
2075 self.journal_size = self.db.get_val_int('journalsize', 0)
2076 self.inode_size = self.db.get_val_int('inodesize', 0)
2077 self.mkfsoptions = self.db.get_val('mkfsoptions', '')
2078 self.mountfsoptions = self.db.get_val('mountfsoptions', '')
2079 self.fstype = self.db.get_val('fstype', '')
2080 self.backfstype = self.db.get_val('backfstype', '')
2081 self.nspath = self.db.get_val('nspath', '')
2082 target_uuid = self.db.get_first_ref('target')
2083 ost = self.db.lookup(target_uuid)
2084 self.name = ost.getName()
2085 self.format = self.db.get_val('autoformat', 'yes')
2086 if ost.get_val('failover', 0):
2087 self.failover_ost = 'f'
2089 self.failover_ost = 'n'
2091 active_uuid = get_active_target(ost)
2093 panic("No target device found:", target_uuid)
2094 if active_uuid == self.uuid:
2098 if self.active and config.group and config.group != ost.get_val('group'):
2101 self.target_dev_uuid = self.uuid
2102 self.uuid = target_uuid
2104 def add_module(self, manager):
2106 manager.add_lustre_module('ost', 'ost')
2108 if self.fstype == 'smfs':
2109 manager.add_lustre_module('smfs', 'smfs')
2111 if self.fstype == 'ldiskfs':
2112 manager.add_lustre_module('ldiskfs', 'ldiskfs')
2114 manager.add_lustre_module('lvfs' , 'fsfilt_%s' % (self.fstype))
2115 if self.fstype == 'smfs':
2116 manager.add_lustre_module('lvfs' , 'fsfilt_%s' % (self.backfstype))
2118 for option in self.mountfsoptions:
2119 if option == 'snap':
2120 if not self.fstype == 'smfs':
2121 panic("mountoptions with snap, but fstype is not smfs\n")
2122 manager.add_lustre_module('lvfs', 'fsfilt_snap_%s' % (self.fstype))
2123 manager.add_lustre_module('lvfs', 'fsfilt_snap_%s' % (self.backfstype))
2125 manager.add_lustre_module(self.osdtype, self.osdtype)
2127 def get_mount_options(self, blkdev):
2128 options = def_mount_options(self.fstype, 'ost')
2130 if config.mountfsoptions != None:
2132 options = "%s,%s" %(options, config.mountfsoptions)
2134 options = config.mountfsoptions
2135 if self.mountfsoptions != None:
2136 options = "%s,%s" %(options, self.mountfsoptions)
2138 if self.mountfsoptions != None:
2140 options = "%s,%s" %(options, self.mountfsoptions)
2142 options = self.mountfsoptions
2144 if self.fstype == 'smfs':
2146 options = "%s,type=%s,dev=%s" %(options,
2147 self.backfstype, blkdev)
2149 options = "type=%s,dev=%s" %(self.backfstype,
2153 # need to check /proc/mounts and /etc/mtab before
2154 # formatting anything.
2155 # FIXME: check if device is already formatted.
2157 if is_prepared(self.name):
2160 debug(self.uuid, "not active")
2163 if self.osdtype == 'obdecho':
2166 blkdev = block_dev(self.devpath, self.size, self.fstype,
2167 config.reformat, self.format, self.journal_size,
2168 self.inode_size, self.mkfsoptions, self.backfstype,
2171 if self.fstype == 'smfs':
2172 realdev = self.fstype
2176 mountfsoptions = self.get_mount_options(blkdev)
2178 self.info(self.osdtype, realdev, mountfsoptions, self.fstype,
2179 self.size, self.format, self.journal_size, self.inode_size)
2181 lctl.newdev(self.osdtype, self.name, self.uuid,
2182 setup ="%s %s %s %s" %(realdev, self.fstype,
2185 if not is_prepared('OSS'):
2186 lctl.newdev("ost", 'OSS', 'OSS_UUID', setup ="")
2188 def osd_remaining(self):
2189 out = lctl.device_list()
2191 if string.split(s)[2] in ('obdfilter', 'obdecho'):
2194 def safe_to_clean(self):
2197 def safe_to_clean_modules(self):
2198 return not self.osd_remaining()
2202 debug(self.uuid, "not active")
2204 if is_prepared(self.name):
2207 lctl.cleanup(self.name, self.uuid, config.force,
2209 except CommandError, e:
2210 log(self.module_name, "cleanup failed: ", self.name)
2213 if not self.osd_remaining() and is_prepared('OSS'):
2215 lctl.cleanup("OSS", "OSS_UUID", config.force,
2217 except CommandError, e:
2218 print "cleanup failed: ", self.name
2221 if not self.osdtype == 'obdecho':
2222 clean_dev(self.devpath, self.fstype, self.backfstype,
2225 def correct_level(self, level, op=None):
2228 def mgmt_uuid_for_fs(mtpt_name):
2231 mtpt_db = toplustreDB.lookup_name(mtpt_name)
2232 fs_uuid = mtpt_db.get_first_ref('filesystem')
2233 fs = toplustreDB.lookup(fs_uuid)
2236 return fs.get_first_ref('mgmt')
2238 # Generic client module, used by OSC and MDC
2239 class Client(Module):
2240 def __init__(self, tgtdb, uuid, module, fs_name, self_name=None,
2242 self.target_name = tgtdb.getName()
2243 self.target_uuid = tgtdb.getUUID()
2244 self.module_dir = module_dir
2245 self.module = module
2249 self.tgt_dev_uuid = get_active_target(tgtdb)
2250 if not self.tgt_dev_uuid:
2251 panic("No target device found for target(1):", self.target_name)
2256 self.module = module
2257 self.module_name = string.upper(module)
2259 self.name = '%s_%s_%s_%s' % (self.module_name, socket.gethostname(),
2260 self.target_name, fs_name)
2262 self.name = self_name
2264 self.lookup_server(self.tgt_dev_uuid)
2265 mgmt_uuid = mgmt_uuid_for_fs(fs_name)
2267 self.mgmt_name = mgmtcli_name_for_uuid(mgmt_uuid)
2270 self.fs_name = fs_name
2271 if not self.module_dir:
2272 self.module_dir = module
2274 def add_module(self, manager):
2275 manager.add_lustre_module(self.module_dir, self.module)
2277 def lookup_server(self, srv_uuid):
2278 """ Lookup a server's network information """
2279 self._server_nets = get_ost_net(self.db, srv_uuid)
2280 if len(self._server_nets) == 0:
2281 panic ("Unable to find a server for:", srv_uuid)
2286 def get_servers(self):
2287 return self._server_nets
2289 def prepare(self, ignore_connect_failure = 0):
2290 self.info(self.target_uuid)
2291 if not config.record and is_prepared(self.name):
2294 srv = choose_local_server(self.get_servers())
2298 routes = find_route(self.get_servers())
2299 if len(routes) == 0:
2300 panic ("no route to", self.target_uuid)
2301 for (srv, r) in routes:
2302 lctl.add_route_host(r[0], srv.nid_uuid, r[1], r[3])
2303 except CommandError, e:
2304 if not ignore_connect_failure:
2307 if self.permits_inactive() and (self.target_uuid in config.inactive or self.active == 0):
2308 debug("%s inactive" % self.target_uuid)
2309 inactive_p = "inactive"
2311 debug("%s active" % self.target_uuid)
2313 lctl.newdev(self.module, self.name, self.uuid,
2314 setup ="%s %s %s %s" % (self.target_uuid, srv.nid_uuid,
2315 inactive_p, self.mgmt_name))
2318 if is_prepared(self.name):
2319 Module.cleanup(self)
2321 srv = choose_local_server(self.get_servers())
2323 lctl.disconnect(srv)
2325 for (srv, r) in find_route(self.get_servers()):
2326 lctl.del_route_host(r[0], srv.nid_uuid, r[1], r[3])
2327 except CommandError, e:
2328 log(self.module_name, "cleanup failed: ", self.name)
2332 def correct_level(self, level, op=None):
2335 def deactivate(self):
2337 lctl.deactivate(self.name)
2338 except CommandError, e:
2339 log(self.module_name, "deactivate failed: ", self.name)
2344 def __init__(self, db, uuid, fs_name):
2345 Client.__init__(self, db, uuid, 'mdc', fs_name)
2347 def permits_inactive(self):
2351 def __init__(self, db, uuid, fs_name):
2352 Client.__init__(self, db, uuid, 'osc', fs_name)
2354 def permits_inactive(self):
2357 def mgmtcli_name_for_uuid(uuid):
2358 return 'MGMTCLI_%s' % uuid
2360 class ManagementClient(Client):
2361 def __init__(self, db, uuid):
2362 Client.__init__(self, db, uuid, 'mgmt_cli', '',
2363 self_name = mgmtcli_name_for_uuid(db.getUUID()),
2364 module_dir = 'mgmt')
2366 class CMOBD(Module):
2367 def __init__(self, db):
2368 Module.__init__(self, 'CMOBD', db)
2369 self.name = self.db.getName();
2370 self.uuid = generate_client_uuid(self.name)
2371 self.master_uuid = self.db.get_first_ref('masterobd')
2372 self.cache_uuid = self.db.get_first_ref('cacheobd')
2374 master_obd = self.db.lookup(self.master_uuid)
2376 panic('master obd not found:', self.master_uuid)
2378 cache_obd = self.db.lookup(self.cache_uuid)
2380 panic('cache obd not found:', self.cache_uuid)
2382 master_class = master_obd.get_class()
2383 cache_class = cache_obd.get_class()
2385 if master_class == 'ost' or master_class == 'lov':
2386 client_uuid = "%s_lov_master_UUID" % (self.name)
2387 self.master = LOV(master_obd, client_uuid, self.name,
2388 "%s_master" % (self.name));
2389 client_uuid = "%s_lov_cache_UUID" % (self.name)
2390 self.cache = LOV(cache_obd, client_uuid, self.name,
2391 "%s_cache" % (self.name));
2392 if master_class == 'mds':
2393 self.master = get_mdc(db, self.name, self.master_uuid)
2394 if cache_class == 'mds':
2395 self.cache = get_mdc(db, self.name, self.cache_uuid)
2397 if master_class == 'lmv':
2398 client_uuid = "%s_lmv_master_UUID" % (self.name)
2399 self.master = LMV(master_obd, client_uuid, self.name,
2400 "%s_master" % (self.name));
2401 if cache_class == 'lmv':
2402 client_uuid = "%s_lmv_cache_UUID" % (self.name)
2403 self.cache = LMV(cache_obd, client_uuid, self.name,
2404 "%s_cache" % (self.name));
2406 # need to check /proc/mounts and /etc/mtab before
2407 # formatting anything.
2408 # FIXME: check if device is already formatted.
2410 self.master.prepare()
2411 if not config.record and is_prepared(self.name):
2413 self.info(self.master_uuid, self.cache_uuid)
2414 lctl.newdev("cmobd", self.name, self.uuid,
2415 setup ="%s %s" %(self.master_uuid,
2424 def get_master_name(self):
2425 return self.master.name
2427 def get_cache_name(self):
2428 return self.cache.name
2431 if is_prepared(self.name):
2432 Module.cleanup(self)
2434 self.master.cleanup()
2436 def add_module(self, manager):
2437 manager.add_lustre_module('cmobd', 'cmobd')
2438 self.master.add_module(manager)
2440 def correct_level(self, level, op=None):
2444 def __init__(self, db, uuid, name):
2445 Module.__init__(self, 'COBD', db)
2446 self.name = self.db.getName();
2447 self.uuid = generate_client_uuid(self.name)
2448 self.master_uuid = self.db.get_first_ref('masterobd')
2449 self.cache_uuid = self.db.get_first_ref('cacheobd')
2451 master_obd = self.db.lookup(self.master_uuid)
2453 panic('master obd not found:', self.master_uuid)
2455 cache_obd = self.db.lookup(self.cache_uuid)
2457 panic('cache obd not found:', self.cache_uuid)
2459 master_class = master_obd.get_class()
2460 cache_class = cache_obd.get_class()
2462 if master_class == 'ost' or master_class == 'lov':
2463 client_uuid = "%s_lov_master_UUID" % (self.name)
2464 self.master = LOV(master_obd, client_uuid, name,
2465 "%s_master" % (self.name));
2466 client_uuid = "%s_lov_cache_UUID" % (self.name)
2467 self.cache = LOV(cache_obd, client_uuid, name,
2468 "%s_cache" % (self.name));
2469 if master_class == 'mds':
2470 self.master = get_mdc(db, name, self.master_uuid)
2471 if cache_class == 'mds':
2472 self.cache = get_mdc(db, name, self.cache_uuid)
2474 if master_class == 'lmv':
2475 client_uuid = "%s_lmv_master_UUID" % (self.name)
2476 self.master = LMV(master_obd, client_uuid, self.name,
2477 "%s_master" % (self.name));
2478 if cache_class == 'lmv':
2479 client_uuid = "%s_lmv_cache_UUID" % (self.name)
2480 self.cache = LMV(cache_obd, client_uuid, self.name,
2481 "%s_cache" % (self.name));
2483 # need to check /proc/mounts and /etc/mtab before
2484 # formatting anything.
2485 # FIXME: check if device is already formatted.
2492 def get_master_name(self):
2493 return self.master.name
2495 def get_cache_name(self):
2496 return self.cache.name
2499 self.master.prepare()
2500 self.cache.prepare()
2501 if not config.record and is_prepared(self.name):
2503 self.info(self.master_uuid, self.cache_uuid)
2504 lctl.newdev("cobd", self.name, self.uuid,
2505 setup ="%s %s" %(self.master.name,
2509 if is_prepared(self.name):
2510 Module.cleanup(self)
2511 self.master.cleanup()
2512 self.cache.cleanup()
2514 def add_module(self, manager):
2515 manager.add_lustre_module('cobd', 'cobd')
2516 self.master.add_module(manager)
2518 # virtual interface for OSC and LOV
2520 def __init__(self, db, client_uuid, name, name_override = None):
2521 Module.__init__(self, 'VOSC', db)
2522 if db.get_class() == 'lov':
2523 self.osc = LOV(db, client_uuid, name, name_override)
2525 elif db.get_class() == 'cobd':
2526 self.osc = COBD(db, client_uuid, name)
2529 self.osc = OSC(db, client_uuid, name)
2533 return self.osc.get_uuid()
2536 return self.osc.get_name()
2544 def add_module(self, manager):
2545 self.osc.add_module(manager)
2547 def correct_level(self, level, op=None):
2548 return self.osc.correct_level(level, op)
2550 # virtual interface for MDC and LMV
2552 def __init__(self, db, client_uuid, name, name_override = None):
2553 Module.__init__(self, 'VMDC', db)
2554 if db.get_class() == 'lmv':
2555 self.mdc = LMV(db, client_uuid, name, name_override)
2556 elif db.get_class() == 'cobd':
2557 self.mdc = COBD(db, client_uuid, name)
2559 self.mdc = MDC(db, client_uuid, name)
2562 return self.mdc.uuid
2565 return self.mdc.name
2573 def add_module(self, manager):
2574 self.mdc.add_module(manager)
2576 def correct_level(self, level, op=None):
2577 return self.mdc.correct_level(level, op)
2579 class ECHO_CLIENT(Module):
2580 def __init__(self,db):
2581 Module.__init__(self, 'ECHO_CLIENT', db)
2582 self.obd_uuid = self.db.get_first_ref('obd')
2583 obd = self.db.lookup(self.obd_uuid)
2584 self.uuid = generate_client_uuid(self.name)
2585 self.osc = VOSC(obd, self.uuid, self.name)
2588 if not config.record and is_prepared(self.name):
2591 self.osc.prepare() # XXX This is so cheating. -p
2592 self.info(self.obd_uuid)
2594 lctl.newdev("echo_client", self.name, self.uuid,
2595 setup = self.osc.get_name())
2598 if is_prepared(self.name):
2599 Module.cleanup(self)
2602 def add_module(self, manager):
2603 self.osc.add_module(manager)
2604 manager.add_lustre_module('obdecho', 'obdecho')
2606 def correct_level(self, level, op=None):
2609 def generate_client_uuid(name):
2610 client_uuid = '%05x_%.19s_%05x%05x' % (int(random.random() * 1048576),
2612 int(random.random() * 1048576),
2613 int(random.random() * 1048576))
2614 return client_uuid[:36]
2616 class Mountpoint(Module):
2617 def __init__(self,db):
2618 Module.__init__(self, 'MTPT', db)
2619 self.path = self.db.get_val('path')
2620 self.clientoptions = self.db.get_val('clientoptions', '')
2621 self.fs_uuid = self.db.get_first_ref('filesystem')
2622 fs = self.db.lookup(self.fs_uuid)
2623 self.mds_uuid = fs.get_first_ref('lmv')
2624 if not self.mds_uuid:
2625 self.mds_uuid = fs.get_first_ref('mds')
2626 self.obd_uuid = fs.get_first_ref('obd')
2627 self.mgmt_uuid = fs.get_first_ref('mgmt')
2628 client_uuid = generate_client_uuid(self.name)
2630 ost = self.db.lookup(self.obd_uuid)
2632 panic("no ost: ", self.obd_uuid)
2634 mds = self.db.lookup(self.mds_uuid)
2636 panic("no mds: ", self.mds_uuid)
2638 self.vosc = VOSC(ost, client_uuid, self.name, self.name)
2639 self.vmdc = VMDC(mds, client_uuid, self.name, self.name)
2642 self.mgmtcli = ManagementClient(db.lookup(self.mgmt_uuid),
2648 if not config.record and fs_is_mounted(self.path):
2649 log(self.path, "already mounted.")
2653 self.mgmtcli.prepare()
2656 vmdc_name = self.vmdc.get_name()
2658 self.info(self.path, self.mds_uuid, self.obd_uuid)
2659 if config.record or config.lctl_dump:
2660 lctl.mount_option(local_node_name, self.vosc.get_name(), vmdc_name)
2663 if config.clientoptions:
2664 if self.clientoptions:
2665 self.clientoptions = self.clientoptions + ',' + \
2666 config.clientoptions
2668 self.clientoptions = config.clientoptions
2669 if self.clientoptions:
2670 self.clientoptions = ',' + self.clientoptions
2671 # Linux kernel will deal with async and not pass it to ll_fill_super,
2672 # so replace it with Lustre async
2673 self.clientoptions = string.replace(self.clientoptions, "async",
2676 cmd = "mount -t lustre_lite -o osc=%s,mdc=%s%s %s %s" % \
2677 (self.vosc.get_name(), vmdc_name, self.clientoptions,
2678 config.config, self.path)
2679 run("mkdir", self.path)
2684 panic("mount failed:", self.path, ":", string.join(val))
2687 self.info(self.path, self.mds_uuid,self.obd_uuid)
2689 if config.record or config.lctl_dump:
2690 lctl.del_mount_option(local_node_name)
2692 if fs_is_mounted(self.path):
2694 (rc, out) = run("umount", "-f", self.path)
2696 (rc, out) = run("umount", self.path)
2698 raise CommandError('umount', out, rc)
2700 if fs_is_mounted(self.path):
2701 panic("fs is still mounted:", self.path)
2706 self.mgmtcli.cleanup()
2708 def add_module(self, manager):
2709 manager.add_lustre_module('mdc', 'mdc')
2712 self.mgmtcli.add_module(manager)
2714 self.vosc.add_module(manager)
2715 self.vmdc.add_module(manager)
2717 manager.add_lustre_module('llite', 'llite')
2719 def correct_level(self, level, op=None):
2722 # ============================================================
2723 # misc query functions
2725 def get_ost_net(self, osd_uuid):
2729 osd = self.lookup(osd_uuid)
2730 node_uuid = osd.get_first_ref('node')
2731 node = self.lookup(node_uuid)
2733 panic("unable to find node for osd_uuid:", osd_uuid,
2734 " node_ref:", node_uuid_)
2735 for net_uuid in node.get_networks():
2736 db = node.lookup(net_uuid)
2737 srv_list.append(Network(db))
2741 # the order of iniitailization is based on level.
2742 def getServiceLevel(self):
2743 type = self.get_class()
2745 if type in ('network',):
2747 elif type in ('routetbl',):
2749 elif type in ('ldlm',):
2751 elif type in ('osd', 'cobd'):
2753 elif type in ('mdsdev',):
2755 elif type in ('lmv',):
2757 elif type in ('cmobd',):
2759 elif type in ('mountpoint', 'echoclient'):
2762 panic("Unknown type: ", type)
2764 if ret < config.minlevel or ret > config.maxlevel:
2769 # return list of services in a profile. list is a list of tuples
2770 # [(level, db_object),]
2771 def getServices(self):
2773 for ref_class, ref_uuid in self.get_all_refs():
2774 servdb = self.lookup(ref_uuid)
2776 level = getServiceLevel(servdb)
2778 list.append((level, servdb))
2780 panic('service not found: ' + ref_uuid)
2786 ############################################################
2788 # FIXME: clean this mess up!
2790 # OSC is no longer in the xml, so we have to fake it.
2791 # this is getting ugly and begging for another refactoring
2792 def get_osc(ost_db, uuid, fs_name):
2793 osc = OSC(ost_db, uuid, fs_name)
2796 def get_mdc(db, fs_name, mds_uuid):
2797 mds_db = db.lookup(mds_uuid);
2799 error("no mds:", mds_uuid)
2800 mdc = MDC(mds_db, mds_uuid, fs_name)
2803 ############################################################
2804 # routing ("rooting")
2806 # list of (nettype, cluster_id, nid)
2809 def find_local_clusters(node_db):
2810 global local_clusters
2811 for netuuid in node_db.get_networks():
2812 net = node_db.lookup(netuuid)
2814 debug("add_local", netuuid)
2815 local_clusters.append((srv.net_type, srv.cluster_id, srv.nid))
2817 if acceptors.has_key(srv.port):
2818 panic("duplicate port:", srv.port)
2819 acceptors[srv.port] = AcceptorHandler(srv.port, srv.net_type)
2821 # This node is a gateway.
2823 def node_is_router():
2826 # If there are any routers found in the config, then this will be true
2827 # and all nodes will load kptlrouter.
2829 def node_needs_router():
2830 return needs_router or is_router
2832 # list of (nettype, gw, tgt_cluster_id, lo, hi)
2833 # Currently, these local routes are only added to kptlrouter route
2834 # table if they are needed to connect to a specific server. This
2835 # should be changed so all available routes are loaded, and the
2836 # ptlrouter can make all the decisions.
2839 def find_local_routes(lustre):
2840 """ Scan the lustre config looking for routers . Build list of
2842 global local_routes, needs_router
2844 list = lustre.lookup_class('node')
2846 if router.get_val_int('router', 0):
2848 for (local_type, local_cluster_id, local_nid) in local_clusters:
2850 for netuuid in router.get_networks():
2851 db = router.lookup(netuuid)
2852 if (local_type == db.get_val('nettype') and
2853 local_cluster_id == db.get_val('clusterid')):
2854 gw = db.get_val('nid')
2857 debug("find_local_routes: gw is", gw)
2858 for route in router.get_local_routes(local_type, gw):
2859 local_routes.append(route)
2860 debug("find_local_routes:", local_routes)
2863 def choose_local_server(srv_list):
2864 for srv in srv_list:
2865 if local_cluster(srv.net_type, srv.cluster_id):
2868 def local_cluster(net_type, cluster_id):
2869 for cluster in local_clusters:
2870 if net_type == cluster[0] and cluster_id == cluster[1]:
2874 def local_interface(net_type, cluster_id, nid):
2875 for cluster in local_clusters:
2876 if (net_type == cluster[0] and cluster_id == cluster[1]
2877 and nid == cluster[2]):
2881 def find_route(srv_list):
2883 frm_type = local_clusters[0][0]
2884 for srv in srv_list:
2885 debug("find_route: srv:", srv.nid, "type: ", srv.net_type)
2886 to_type = srv.net_type
2888 cluster_id = srv.cluster_id
2889 debug ('looking for route to', to_type, to)
2890 for r in local_routes:
2891 debug("find_route: ", r)
2892 if (r[3] <= to and to <= r[4]) and cluster_id == r[2]:
2893 result.append((srv, r))
2896 def get_active_target(db):
2897 target_uuid = db.getUUID()
2898 target_name = db.getName()
2899 node_name = get_select(target_name)
2901 tgt_dev_uuid = db.get_node_tgt_dev(node_name, target_uuid)
2903 tgt_dev_uuid = db.get_first_ref('active')
2906 def get_server_by_nid_uuid(db, nid_uuid):
2907 for n in db.lookup_class("network"):
2909 if net.nid_uuid == nid_uuid:
2913 ############################################################
2917 type = db.get_class()
2918 debug('Service:', type, db.getName(), db.getUUID())
2923 n = LOV(db, "YOU_SHOULD_NEVER_SEE_THIS_UUID")
2924 elif type == 'network':
2926 elif type == 'routetbl':
2930 elif type == 'cobd':
2931 n = COBD(db, "YOU_SHOULD_NEVER_SEE_THIS_UUID")
2932 elif type == 'cmobd':
2934 elif type == 'mdsdev':
2936 elif type == 'mountpoint':
2938 elif type == 'echoclient':
2943 panic ("unknown service type:", type)
2947 # Prepare the system to run lustre using a particular profile
2948 # in a the configuration.
2949 # * load & the modules
2950 # * setup networking for the current node
2951 # * make sure partitions are in place and prepared
2952 # * initialize devices with lctl
2953 # Levels is important, and needs to be enforced.
2954 def for_each_profile(db, prof_list, operation):
2955 for prof_uuid in prof_list:
2956 prof_db = db.lookup(prof_uuid)
2958 panic("profile:", prof_uuid, "not found.")
2959 services = getServices(prof_db)
2962 def magic_get_osc(db, rec, lov):
2964 lov_uuid = lov.get_uuid()
2965 lov_name = lov.osc.fs_name
2967 lov_uuid = rec.getAttribute('lov_uuidref')
2968 # FIXME: better way to find the mountpoint?
2969 filesystems = db.root_node.getElementsByTagName('filesystem')
2971 for fs in filesystems:
2972 ref = fs.getElementsByTagName('obd_ref')
2973 if ref[0].getAttribute('uuidref') == lov_uuid:
2974 fsuuid = fs.getAttribute('uuid')
2978 panic("malformed xml: lov uuid '" + lov_uuid + "' referenced in 'add' record is not used by any filesystems.")
2980 mtpts = db.root_node.getElementsByTagName('mountpoint')
2983 ref = fs.getElementsByTagName('filesystem_ref')
2984 if ref[0].getAttribute('uuidref') == fsuuid:
2985 lov_name = fs.getAttribute('name')
2989 panic("malformed xml: 'add' record references lov uuid '" + lov_uuid + "', which references filesystem uuid '" + fsuuid + "', which does not reference a mountpoint.")
2991 print "lov_uuid: " + lov_uuid + "; lov_name: " + lov_name
2993 ost_uuid = rec.getAttribute('ost_uuidref')
2994 obd = db.lookup(ost_uuid)
2997 panic("malformed xml: 'add' record references ost uuid '" + ost_uuid + "' which cannot be found.")
2999 osc = get_osc(obd, lov_uuid, lov_name)
3001 panic('osc not found:', obd_uuid)
3004 # write logs for update records. sadly, logs of all types -- and updates in
3005 # particular -- are something of an afterthought. lconf needs rewritten with
3006 # these as core concepts. so this is a pretty big hack.
3007 def process_update_record(db, update, lov):
3008 for rec in update.childNodes:
3009 if rec.nodeType != rec.ELEMENT_NODE:
3012 log("found "+rec.nodeName+" record in update version " +
3013 str(update.getAttribute('version')))
3015 lov_uuid = rec.getAttribute('lov_uuidref')
3016 ost_uuid = rec.getAttribute('ost_uuidref')
3017 index = rec.getAttribute('index')
3018 gen = rec.getAttribute('generation')
3020 if not lov_uuid or not ost_uuid or not index or not gen:
3021 panic("malformed xml: 'update' record requires lov_uuid, ost_uuid, index, and generation.")
3024 tmplov = db.lookup(lov_uuid)
3026 panic("malformed xml: 'delete' record contains lov UUID '" + lov_uuid + "', which cannot be located.")
3027 lov_name = tmplov.getName()
3029 lov_name = lov.osc.name
3031 # ------------------------------------------------------------- add
3032 if rec.nodeName == 'add':
3034 lctl.lov_del_obd(lov_name, lov_uuid, ost_uuid, index, gen)
3037 osc = magic_get_osc(db, rec, lov)
3040 # Only ignore connect failures with --force, which
3041 # isn't implemented here yet.
3042 osc.prepare(ignore_connect_failure=0)
3043 except CommandError, e:
3044 print "Error preparing OSC %s\n" % osc.uuid
3047 lctl.lov_add_obd(lov_name, lov_uuid, ost_uuid, index, gen)
3049 # ------------------------------------------------------ deactivate
3050 elif rec.nodeName == 'deactivate':
3054 osc = magic_get_osc(db, rec, lov)
3058 except CommandError, e:
3059 print "Error deactivating OSC %s\n" % osc.uuid
3062 # ---------------------------------------------------------- delete
3063 elif rec.nodeName == 'delete':
3067 osc = magic_get_osc(db, rec, lov)
3073 except CommandError, e:
3074 print "Error cleaning up OSC %s\n" % osc.uuid
3077 lctl.lov_del_obd(lov_name, lov_uuid, ost_uuid, index, gen)
3079 def process_updates(db, log_device, log_name, lov = None):
3080 updates = db.root_node.getElementsByTagName('update')
3082 if not u.childNodes:
3083 log("ignoring empty update record (version " +
3084 str(u.getAttribute('version')) + ")")
3087 version = u.getAttribute('version')
3088 real_name = "%s-%s" % (log_name, version)
3089 lctl.clear_log(log_device, real_name)
3090 lctl.record(log_device, real_name)
3092 process_update_record(db, u, lov)
3096 def doWriteconf(services):
3100 if s[1].get_class() == 'mdsdev':
3101 n = newService(s[1])
3104 def doSetup(services):
3109 n = newService(s[1])
3111 slist.append((n.level, n))
3114 nl = n[1].correct_level(n[0])
3115 nlist.append((nl, n[1]))
3120 def doLoadModules(services):
3124 # adding all needed modules from all services
3126 n = newService(s[1])
3127 n.add_module(mod_manager)
3129 # loading all registered modules
3130 mod_manager.load_modules()
3132 def doUnloadModules(services):
3136 # adding all needed modules from all services
3138 n = newService(s[1])
3139 if n.safe_to_clean_modules():
3140 n.add_module(mod_manager)
3142 # unloading all registered modules
3143 mod_manager.cleanup_modules()
3145 def doCleanup(services):
3151 n = newService(s[1])
3153 slist.append((n.level, n))
3156 nl = n[1].correct_level(n[0])
3157 nlist.append((nl, n[1]))
3162 if n[1].safe_to_clean():
3167 def doHost(lustreDB, hosts):
3168 global is_router, local_node_name
3171 node_db = lustreDB.lookup_name(h, 'node')
3175 panic('No host entry found.')
3177 local_node_name = node_db.get_val('name', 0)
3178 is_router = node_db.get_val_int('router', 0)
3179 lustre_upcall = node_db.get_val('lustreUpcall', '')
3180 portals_upcall = node_db.get_val('portalsUpcall', '')
3181 timeout = node_db.get_val_int('timeout', 0)
3182 ptldebug = node_db.get_val('ptldebug', '')
3183 subsystem = node_db.get_val('subsystem', '')
3185 find_local_clusters(node_db)
3187 find_local_routes(lustreDB)
3189 # Two step process: (1) load modules, (2) setup lustre
3190 # if not cleaning, load modules first.
3191 prof_list = node_db.get_refs('profile')
3193 if config.write_conf:
3194 for_each_profile(node_db, prof_list, doLoadModules)
3196 for_each_profile(node_db, prof_list, doWriteconf)
3197 for_each_profile(node_db, prof_list, doUnloadModules)
3200 elif config.recover:
3201 if not (config.tgt_uuid and config.client_uuid and config.conn_uuid):
3202 raise Lustre.LconfError( "--recovery requires --tgt_uuid <UUID> " +
3203 "--client_uuid <UUID> --conn_uuid <UUID>")
3204 doRecovery(lustreDB, lctl, config.tgt_uuid, config.client_uuid,
3206 elif config.cleanup:
3208 # the command line can override this value
3210 # ugly hack, only need to run lctl commands for --dump
3211 if config.lctl_dump or config.record:
3212 for_each_profile(node_db, prof_list, doCleanup)
3215 sys_set_timeout(timeout)
3216 sys_set_ptldebug(ptldebug)
3217 sys_set_subsystem(subsystem)
3218 sys_set_lustre_upcall(lustre_upcall)
3219 sys_set_portals_upcall(portals_upcall)
3221 for_each_profile(node_db, prof_list, doCleanup)
3222 for_each_profile(node_db, prof_list, doUnloadModules)
3226 # ugly hack, only need to run lctl commands for --dump
3227 if config.lctl_dump or config.record:
3228 sys_set_timeout(timeout)
3229 sys_set_lustre_upcall(lustre_upcall)
3230 for_each_profile(node_db, prof_list, doSetup)
3234 sys_set_netmem_max('/proc/sys/net/core/rmem_max', MAXTCPBUF)
3235 sys_set_netmem_max('/proc/sys/net/core/wmem_max', MAXTCPBUF)
3237 for_each_profile(node_db, prof_list, doLoadModules)
3239 sys_set_debug_path()
3240 sys_set_ptldebug(ptldebug)
3241 sys_set_subsystem(subsystem)
3242 script = config.gdb_script
3243 run(lctl.lctl, ' modules >', script)
3245 log ("The GDB module script is in", script)
3246 # pause, so user has time to break and
3249 sys_set_timeout(timeout)
3250 sys_set_lustre_upcall(lustre_upcall)
3251 sys_set_portals_upcall(portals_upcall)
3253 for_each_profile(node_db, prof_list, doSetup)
3256 def doRecovery(lustreDB, lctl, tgt_uuid, client_uuid, nid_uuid):
3257 tgt = lustreDB.lookup(tgt_uuid)
3259 raise Lustre.LconfError("doRecovery: "+ tgt_uuid +" not found.")
3260 new_uuid = get_active_target(tgt)
3262 raise Lustre.LconfError("doRecovery: no active target found for: " +
3264 net = choose_local_server(get_ost_net(lustreDB, new_uuid))
3266 raise Lustre.LconfError("Unable to find a connection to:" + new_uuid)
3268 log("Reconnecting", tgt_uuid, " to ", net.nid_uuid);
3270 oldnet = get_server_by_nid_uuid(lustreDB, nid_uuid)
3273 lctl.disconnect(oldnet)
3274 except CommandError, e:
3275 log("recover: disconnect", nid_uuid, "failed: ")
3280 except CommandError, e:
3281 log("recover: connect failed")
3284 lctl.recover(client_uuid, net.nid_uuid)
3287 def setupModulePath(cmd, portals_dir = PORTALS_DIR):
3288 base = os.path.dirname(cmd)
3289 if development_mode():
3290 if not config.lustre:
3291 debug('using objdir module paths')
3292 config.lustre = (os.path.join(base, ".."))
3293 # normalize the portals dir, using command line arg if set
3295 portals_dir = config.portals
3296 dir = os.path.join(config.lustre, portals_dir)
3297 config.portals = dir
3298 debug('config.portals', config.portals)
3299 elif config.lustre and config.portals:
3301 # if --lustre and --portals, normalize portals
3302 # can ignore POTRALS_DIR here, since it is probly useless here
3303 config.portals = os.path.join(config.lustre, config.portals)
3304 debug('config.portals B', config.portals)
3306 def sysctl(path, val):
3307 debug("+ sysctl", path, val)
3311 fp = open(os.path.join('/proc/sys', path), 'w')
3318 def sys_set_debug_path():
3319 sysctl('portals/debug_path', config.debug_path)
3321 def sys_set_lustre_upcall(upcall):
3322 # the command overrides the value in the node config
3323 if config.lustre_upcall:
3324 upcall = config.lustre_upcall
3326 upcall = config.upcall
3328 lctl.set_lustre_upcall(upcall)
3330 def sys_set_portals_upcall(upcall):
3331 # the command overrides the value in the node config
3332 if config.portals_upcall:
3333 upcall = config.portals_upcall
3335 upcall = config.upcall
3337 sysctl('portals/upcall', upcall)
3339 def sys_set_timeout(timeout):
3340 # the command overrides the value in the node config
3341 if config.timeout and config.timeout > 0:
3342 timeout = config.timeout
3343 if timeout != None and timeout > 0:
3344 lctl.set_timeout(timeout)
3346 def sys_tweak_socknal ():
3347 # reserve at least 8MB, or we run out of RAM in skb_alloc under read
3348 if sys_get_branch() == '2.6':
3349 fp = open('/proc/meminfo')
3350 lines = fp.readlines()
3355 if a[0] == 'MemTotal:':
3357 debug("memtotal" + memtotal)
3358 if int(memtotal) < 262144:
3359 minfree = int(memtotal) / 16
3362 debug("+ minfree ", minfree)
3363 sysctl("vm/min_free_kbytes", minfree)
3364 if config.single_socket:
3365 sysctl("socknal/typed", 0)
3367 def sys_optimize_elan ():
3368 procfiles = ["/proc/elan/config/eventint_punt_loops",
3369 "/proc/qsnet/elan3/config/eventint_punt_loops",
3370 "/proc/qsnet/elan4/config/elan4_mainint_punt_loops"]
3372 if os.access(p, os.W_OK):
3373 run ("echo 1 > " + p)
3375 def sys_set_ptldebug(ptldebug):
3377 ptldebug = config.ptldebug
3380 val = eval(ptldebug, ptldebug_names)
3381 val = "0x%x" % (val)
3382 sysctl('portals/debug', val)
3383 except NameError, e:
3386 def sys_set_subsystem(subsystem):
3387 if config.subsystem:
3388 subsystem = config.subsystem
3391 val = eval(subsystem, subsystem_names)
3392 val = "0x%x" % (val)
3393 sysctl('portals/subsystem_debug', val)
3394 except NameError, e:
3397 def sys_set_netmem_max(path, max):
3398 debug("setting", path, "to at least", max)
3406 fp = open(path, 'w')
3407 fp.write('%d\n' %(max))
3411 def sys_make_devices():
3412 if not os.access('/dev/portals', os.R_OK):
3413 run('mknod /dev/portals c 10 240')
3414 if not os.access('/dev/obd', os.R_OK):
3415 run('mknod /dev/obd c 10 241')
3418 # Add dir to the global PATH, if not already there.
3419 def add_to_path(new_dir):
3420 syspath = string.split(os.environ['PATH'], ':')
3421 if new_dir in syspath:
3423 os.environ['PATH'] = os.environ['PATH'] + ':' + new_dir
3425 def default_debug_path():
3426 path = '/tmp/lustre-log'
3427 if os.path.isdir('/r'):
3432 def default_gdb_script():
3433 script = '/tmp/ogdb'
3434 if os.path.isdir('/r'):
3435 return '/r' + script
3440 DEFAULT_PATH = ('/sbin', '/usr/sbin', '/bin', '/usr/bin')
3441 # ensure basic elements are in the system path
3442 def sanitise_path():
3443 for dir in DEFAULT_PATH:
3446 # global hack for the --select handling
3448 def init_select(args):
3449 # args = [service=nodeA,service2=nodeB service3=nodeC]
3452 list = string.split(arg, ',')
3454 srv, node = string.split(entry, '=')
3455 tgt_select[srv] = node
3457 def get_select(srv):
3458 if tgt_select.has_key(srv):
3459 return tgt_select[srv]
3463 FLAG = Lustre.Options.FLAG
3464 PARAM = Lustre.Options.PARAM
3465 INTPARAM = Lustre.Options.INTPARAM
3466 PARAMLIST = Lustre.Options.PARAMLIST
3468 ('verbose,v', "Print system commands as they are run"),
3469 ('ldapurl',"LDAP server URL, eg. ldap://localhost", PARAM),
3470 ('config', "Cluster config name used for LDAP query", PARAM),
3471 ('select', "service=nodeA,service2=nodeB ", PARAMLIST),
3472 ('node', "Load config for <nodename>", PARAM),
3473 ('cleanup,d', "Cleans up config. (Shutdown)"),
3474 ('force,f', "Forced unmounting and/or obd detach during cleanup",
3476 ('single_socket', "socknal option: only use one socket instead of bundle",
3478 ('failover',"""Used to shut down without saving state.
3479 This will allow this node to "give up" a service to a
3480 another node for failover purposes. This will not
3481 be a clean shutdown.""",
3483 ('gdb', """Prints message after creating gdb module script
3484 and sleeps for 5 seconds."""),
3485 ('noexec,n', """Prints the commands and steps that will be run for a
3486 config without executing them. This can used to check if a
3487 config file is doing what it should be doing"""),
3488 ('nomod', "Skip load/unload module step."),
3489 ('nosetup', "Skip device setup/cleanup step."),
3490 ('reformat', "Reformat all devices (without question)"),
3491 ('mkfsoptions', "Additional options for the mk*fs command line", PARAM),
3492 ('mountfsoptions', "Additional options for mount fs command line", PARAM),
3493 ('clientoptions', "Additional options for Lustre", PARAM),
3494 ('dump', "Dump the kernel debug log to file before portals is unloaded",
3496 ('write_conf', "Save all the client config information on mds."),
3497 ('record', "Write config information on mds."),
3498 ('record_log', "Name of config record log.", PARAM),
3499 ('record_device', "MDS device name that will record the config commands",
3501 ('root_squash', "MDS squash root to appointed uid",
3503 ('no_root_squash', "Don't squash root for appointed nid",
3505 ('minlevel', "Minimum level of services to configure/cleanup",
3507 ('maxlevel', """Maximum level of services to configure/cleanup
3508 Levels are aproximatly like:
3513 70 - mountpoint, echo_client, osc, mdc, lov""",
3515 ('lustre', """Base directory of lustre sources. This parameter will
3516 cause lconf to load modules from a source tree.""", PARAM),
3517 ('portals', """Portals source directory. If this is a relative path,
3518 then it is assumed to be relative to lustre. """, PARAM),
3519 ('timeout', "Set recovery timeout", INTPARAM),
3520 ('upcall', "Set both portals and lustre upcall script", PARAM),
3521 ('lustre_upcall', "Set lustre upcall script", PARAM),
3522 ('portals_upcall', "Set portals upcall script", PARAM),
3523 ('lctl_dump', "Save lctl ioctls to the dumpfile argument", PARAM),
3524 ('ptldebug', "Set the portals debug level", PARAM),
3525 ('subsystem', "Set the portals debug subsystem", PARAM),
3526 ('gdb_script', "Fullname of gdb debug script", PARAM, default_gdb_script()),
3527 ('debug_path', "Path to save debug dumps", PARAM, default_debug_path()),
3528 # Client recovery options
3529 ('recover', "Recover a device"),
3530 ('group', "The group of devices to configure or cleanup", PARAM),
3531 ('tgt_uuid', "The failed target (required for recovery)", PARAM),
3532 ('client_uuid', "The failed client (required for recovery)", PARAM),
3533 ('conn_uuid', "The failed connection (required for recovery)", PARAM),
3535 ('inactive', """The name of an inactive service, to be ignored during
3536 mounting (currently OST-only). Can be repeated.""",
3541 global lctl, config, toplustreDB, CONFIG_FILE, mod_manager
3543 # in the upcall this is set to SIG_IGN
3544 signal.signal(signal.SIGCHLD, signal.SIG_DFL)
3546 cl = Lustre.Options("lconf", "config.xml", lconf_options)
3548 config, args = cl.parse(sys.argv[1:])
3549 except Lustre.OptionError, e:
3553 setupModulePath(sys.argv[0])
3555 host = socket.gethostname()
3557 # the PRNG is normally seeded with time(), which is not so good for starting
3558 # time-synchronized clusters
3559 input = open('/dev/urandom', 'r')
3561 print 'Unable to open /dev/urandom!'
3563 seed = input.read(32)
3569 init_select(config.select)
3572 # allow config to be fetched via HTTP, but only with python2
3573 if sys.version[0] != '1' and args[0].startswith('http://'):
3576 config_file = urllib2.urlopen(args[0])
3577 except (urllib2.URLError, socket.error), err:
3578 if hasattr(err, 'args'):
3580 print "Could not access '%s': %s" %(args[0], err)
3582 elif not os.access(args[0], os.R_OK):
3583 print 'File not found or readable:', args[0]
3587 config_file = open(args[0], 'r')
3589 dom = xml.dom.minidom.parse(config_file)
3591 panic("%s does not appear to be a config file." % (args[0]))
3592 sys.exit(1) # make sure to die here, even in debug mode.
3594 CONFIG_FILE = args[0]
3595 lustreDB = Lustre.LustreDB_XML(dom.documentElement, dom.documentElement)
3596 if not config.config:
3597 config.config = os.path.basename(args[0])# use full path?
3598 if config.config[-4:] == '.xml':
3599 config.config = config.config[:-4]
3600 elif config.ldapurl:
3601 if not config.config:
3602 panic("--ldapurl requires --config name")
3603 dn = "config=%s,fs=lustre" % (config.config)
3604 lustreDB = Lustre.LustreDB_LDAP('', {}, base=dn, url = config.ldapurl)
3605 elif config.ptldebug or config.subsystem:
3606 sys_set_ptldebug(None)
3607 sys_set_subsystem(None)
3610 print 'Missing config file or ldap URL.'
3611 print 'see lconf --help for command summary'
3614 toplustreDB = lustreDB
3616 ver = lustreDB.get_version()
3618 panic("No version found in config data, please recreate.")
3619 if ver != Lustre.CONFIG_VERSION:
3620 panic("Config version", ver, "does not match lconf version",
3621 Lustre.CONFIG_VERSION)
3625 node_list.append(config.node)
3628 node_list.append(host)
3629 node_list.append('localhost')
3631 debug("configuring for host: ", node_list)
3634 config.debug_path = config.debug_path + '-' + host
3635 config.gdb_script = config.gdb_script + '-' + host
3637 lctl = LCTLInterface('lctl')
3639 if config.lctl_dump:
3640 lctl.use_save_file(config.lctl_dump)
3643 if not (config.record_device and config.record_log):
3644 panic("When recording, both --record_log and --record_device must be specified.")
3645 lctl.clear_log(config.record_device, config.record_log)
3646 lctl.record(config.record_device, config.record_log)
3648 # init module manager
3649 mod_manager = kmod_manager(config.lustre, config.portals)
3651 doHost(lustreDB, node_list)
3653 if not config.record:
3658 process_updates(lustreDB, config.record_device, config.record_log)
3660 if __name__ == "__main__":
3663 except Lustre.LconfError, e:
3665 # traceback.print_exc(file=sys.stdout)
3667 except CommandError, e:
3671 if first_cleanup_error:
3672 sys.exit(first_cleanup_error)