2 # -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
3 # vim:expandtab:shiftwidth=8:tabstop=8:
5 # Copyright (C) 2002-2003 Cluster File Systems, Inc.
6 # Authors: Robert Read <rread@clusterfs.com>
7 # Mike Shaver <shaver@clusterfs.com>
8 # This file is part of Lustre, http://www.lustre.org.
10 # Lustre is free software; you can redistribute it and/or
11 # modify it under the terms of version 2 of the GNU General Public
12 # License as published by the Free Software Foundation.
14 # Lustre is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
19 # You should have received a copy of the GNU General Public License
20 # along with Lustre; if not, write to the Free Software
21 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 # lconf - lustre configuration tool
25 # lconf is the main driver script for starting and stopping
26 # lustre filesystem services.
28 # Based in part on the XML obdctl modifications done by Brian Behlendorf
30 import sys, getopt, types, errno
31 import string, os, stat, popen2, socket, time, random, fcntl, select
32 import re, exceptions, signal, traceback
33 import xml.dom.minidom
35 if sys.version[0] == '1':
36 from FCNTL import F_GETFL, F_SETFL
38 from fcntl import F_GETFL, F_SETFL
40 PYMOD_DIR = ["/usr/lib64/lustre/python", "/usr/lib/lustre/python"]
43 if string.find(sys.platform, 'linux') != -1:
45 elif string.find(sys.platform, 'darwin') != -1:
47 KEXTPATH='/System/Library/Extensions/'
49 PLATFORM='Unsupported'
51 def development_mode():
52 base = os.path.dirname(sys.argv[0])
53 if os.access(base+"/Makefile", os.R_OK):
57 if development_mode():
58 sys.path.append('../utils')
60 sys.path.extend(PYMOD_DIR)
67 # Maximum number of devices to search for.
68 # (the /dev/loop* nodes need to be created beforehand)
69 MAX_LOOP_DEVICES = 256
70 PORTALS_DIR = '../lnet'
72 # Needed to call lconf --record
75 # Please keep these in sync with the values in portals/kp30.h
87 "warning" : (1 << 10),
91 "portals" : (1 << 14),
93 "dlmtrace" : (1 << 16),
97 "rpctrace" : (1 << 20),
98 "vfstrace" : (1 << 21),
101 "config" : (1 << 24),
102 "console" : (1 << 25),
108 "undefined" : (1 << 0),
117 "portals" : (1 << 10),
119 "pinger" : (1 << 12),
120 "filter" : (1 << 13),
125 "ptlrouter" : (1 << 18),
129 "confobd" : (1 << 22),
136 first_cleanup_error = 0
137 def cleanup_error(rc):
138 global first_cleanup_error
139 if not first_cleanup_error:
140 first_cleanup_error = rc
142 # ============================================================
143 # debugging and error funcs
145 def fixme(msg = "this feature"):
146 raise Lustre.LconfError, msg + ' not implemented yet.'
149 msg = string.join(map(str,args))
150 if not config.noexec:
151 raise Lustre.LconfError(msg)
156 msg = string.join(map(str,args))
161 print string.strip(s)
164 # apparently, (non)execution of the following line affects mds device
165 # startup order (e.g. two mds's using loopback devices), so always do it.
166 msg = string.join(map(str,args))
170 # ack, python's builtin int() does not support '0x123' syntax.
171 # eval can do it, although what a hack!
174 if type(s) is types.IntType:
177 if (s[0:2] == '0x') or (s[0:1] == '0'):
178 return eval(s, {}, {})
181 except SyntaxError, e:
182 raise ValueError("not a number")
184 raise ValueError("not a number")
186 raise ValueError("not a number")
188 # ============================================================
189 # locally defined exceptions
190 class CommandError (exceptions.Exception):
191 def __init__(self, cmd_name, cmd_err, rc=None):
192 self.cmd_name = cmd_name
193 self.cmd_err = cmd_err
198 if type(self.cmd_err) == types.StringType:
200 print "! %s (%d): %s" % (self.cmd_name, self.rc, self.cmd_err)
202 print "! %s: %s" % (self.cmd_name, self.cmd_err)
203 elif type(self.cmd_err) == types.ListType:
205 print "! %s (error %d):" % (self.cmd_name, self.rc)
207 print "! %s:" % (self.cmd_name)
208 for s in self.cmd_err:
209 print "> %s" %(string.strip(s))
213 # ============================================================
214 # handle lctl interface
217 Manage communication with lctl
220 def __init__(self, cmd):
222 Initialize close by finding the lctl binary.
224 self.lctl = find_prog(cmd)
226 self.record_device = ''
229 debug('! lctl not found')
232 raise CommandError('lctl', "unable to find lctl binary.")
234 def use_save_file(self, file):
235 self.save_file = file
237 def record(self, dev_name, logname):
238 log("Recording log", logname, "on", dev_name)
239 self.record_device = dev_name
240 self.record_log = logname
242 def end_record(self):
243 log("End recording log", self.record_log, "on", self.record_device)
244 self.record_device = None
245 self.record_log = None
247 def set_nonblock(self, fd):
248 fl = fcntl.fcntl(fd, F_GETFL)
249 fcntl.fcntl(fd, F_SETFL, fl | os.O_NDELAY)
254 the cmds are written to stdin of lctl
255 lctl doesn't return errors when run in script mode, so
257 should modify command line to accept multiple commands, or
258 create complex command line options
262 cmds = '\n dump ' + self.save_file + '\n' + cmds
263 elif self.record_device:
267 %s""" % (self.record_device, self.record_log, cmds)
269 debug("+", cmd_line, cmds)
270 if config.noexec: return (0, [])
272 child = popen2.Popen3(cmd_line, 1) # Capture stdout and stderr from command
273 child.tochild.write(cmds + "\nq\n")
274 child.tochild.close()
276 # From "Python Cookbook" from O'Reilly
277 outfile = child.fromchild
278 outfd = outfile.fileno()
279 self.set_nonblock(outfd)
280 errfile = child.childerr
281 errfd = errfile.fileno()
282 self.set_nonblock(errfd)
284 outdata = errdata = ''
287 ready = select.select([outfd,errfd],[],[]) # Wait for input
288 if outfd in ready[0]:
289 outchunk = outfile.read()
290 if outchunk == '': outeof = 1
291 outdata = outdata + outchunk
292 if errfd in ready[0]:
293 errchunk = errfile.read()
294 if errchunk == '': erreof = 1
295 errdata = errdata + errchunk
296 if outeof and erreof: break
297 # end of "borrowed" code
300 if os.WIFEXITED(ret):
301 rc = os.WEXITSTATUS(ret)
304 if rc or len(errdata):
305 raise CommandError(self.lctl, errdata, rc)
308 def runcmd(self, *args):
310 run lctl using the command line
312 cmd = string.join(map(str,args))
313 debug("+", self.lctl, cmd)
314 rc, out = run(self.lctl, cmd)
316 raise CommandError(self.lctl, out, rc)
319 def unconfigure_network(self):
320 """get lnet to unreference itself"""
322 network unconfigure"""
325 def clear_log(self, dev, log):
326 """ clear an existing log """
331 quit """ % (dev, log)
334 # create a new connection
335 def add_uuid(self, net_type, uuid, nid):
336 if net_type != 'lnet' and string.find(nid,'@') < 0:
337 nidstr = nid + "@" + net_type
340 cmds = "\n add_uuid %s %s" %(uuid, nidstr)
343 def connect(self, srv):
345 panic('nid_uuid not set for ', srv.net_type, srv.nid)
346 hostaddr = srv.db.get_hostaddr()
347 if len(hostaddr) > 1:
348 panic('multiple --hostaddr for ', srv.nid_uuid, ' not supported')
349 elif len(hostaddr) == 1 and hostaddr[0] != srv.nid:
350 panic('different --hostaddr and --nid for ', srv.nid_uuid, ' not supported')
352 self.add_uuid(srv.net_type, srv.nid_uuid, srv.nid)
355 def recover(self, dev_name, new_conn):
358 recover %s""" %(dev_name, new_conn)
361 # disconnect one connection
362 def disconnect(self, srv):
364 panic('nid_uuid not set for ', srv.net_type, srv.nid)
365 self.del_uuid(srv.nid_uuid)
367 def del_uuid(self, uuid):
374 def attach(self, type, name, uuid):
377 quit""" % (type, name, uuid)
380 def setup(self, name, setup = ""):
384 quit""" % (name, setup)
387 def abort_recovery(self, name):
395 def add_conn(self, name, conn_uuid):
399 quit""" % (name, conn_uuid)
402 # create a new device with lctl
403 def newdev(self, type, name, uuid, setup = ""):
404 self.attach(type, name, uuid);
406 self.setup(name, setup)
407 except CommandError, e:
408 self.cleanup(name, uuid, 0)
410 if (config.abort_recovery):
411 if (type == 'obdfilter' or type == 'mds'):
412 self.abort_recovery(name)
415 def cleanup(self, name, uuid, force, failover = 0):
416 if failover: force = 1
422 quit""" % (name, ('', 'force')[force],
423 ('', 'failover')[failover])
427 def lov_setup(self, name, uuid, desc_uuid, mdsuuid, stripe_cnt,
428 stripe_sz, stripe_off, pattern):
431 lov_setup %s %d %d %d %s
432 quit""" % (name, uuid, desc_uuid, stripe_cnt, stripe_sz, stripe_off, pattern)
435 # add an OBD to a LOV
436 def lov_add_obd(self, name, uuid, obd_uuid, index, gen):
439 lov_modify_tgts add %s %s %s %s
440 quit""" % (name, name, obd_uuid, index, gen)
443 # delete an OBD from a LOV
444 def lov_del_obd(self, name, uuid, obd_uuid, index, gen):
447 lov_modify_tgts del %s %s %s %s
448 quit""" % (name, name, obd_uuid, index, gen)
452 def deactivate(self, name):
460 def dump(self, dump_file):
463 quit""" % (dump_file)
466 # get list of devices
467 def device_list(self):
469 if PLATFORM == 'LINUX':
470 devices = '/proc/fs/lustre/devices'
471 if os.access(devices, os.R_OK):
473 fp = open(devices, 'r')
478 elif PLATFORM == 'DARWIN':
479 rc, out = self.run("device_list")
480 ret = out.split("\n")
485 # remove the last empty line
490 def lustre_version(self):
491 rc, out = self.runcmd('version')
495 def mount_option(self, profile, osc, mdc):
497 mount_option %s %s %s
498 quit""" % (profile, osc, mdc)
501 # delete mount options
502 def del_mount_option(self, profile):
508 def set_timeout(self, timeout):
515 def set_lustre_upcall(self, upcall):
520 # ============================================================
521 # Various system-level functions
522 # (ideally moved to their own module)
524 # Run a command and return the output and status.
525 # stderr is sent to /dev/null, could use popen3 to
526 # save it if necessary
529 if config.noexec: return (0, [])
530 f = os.popen(cmd + ' 2>&1')
540 cmd = string.join(map(str,args))
543 # Run a command in the background.
544 def run_daemon(*args):
545 cmd = string.join(map(str,args))
547 if config.noexec: return 0
548 f = os.popen(cmd + ' 2>&1')
556 # Determine full path to use for an external command
557 # searches dirname(argv[0]) first, then PATH
559 syspath = string.split(os.environ['PATH'], ':')
560 cmdpath = os.path.dirname(sys.argv[0])
561 syspath.insert(0, cmdpath);
563 syspath.insert(0, os.path.join(config.portals, 'utils/'))
565 prog = os.path.join(d,cmd)
566 if os.access(prog, os.X_OK):
570 # Recursively look for file starting at base dir
571 def do_find_file(base, mod):
572 fullname = os.path.join(base, mod)
573 if os.access(fullname, os.R_OK):
575 for d in os.listdir(base):
576 dir = os.path.join(base,d)
577 if os.path.isdir(dir):
578 module = do_find_file(dir, mod)
582 def find_module(src_dir, dev_dir, modname):
583 modbase = src_dir +'/'+ dev_dir +'/'+ modname
584 for modext in '.ko', '.o':
585 module = modbase + modext
587 if os.access(module, os.R_OK):
593 # is the path a block device?
600 return stat.S_ISBLK(s[stat.ST_MODE])
602 def my_realpath(path):
604 if os.path.islink(path):
605 # get the realpath of the mount point path
606 if 'realpath' in dir(os.path):
607 real_path = os.path.realpath(path)
611 while os.path.islink(real_path) and (link_count < 20):
612 link_count = link_count + 1
613 path_link = os.readlink(real_path)
614 if os.path.isabs(path_link):
615 real_path = path_link
617 real_path = os.path.join(os.path.dirname(real_path), path_link)
619 panic("Encountered too many symbolic links resolving path:", path)
625 panic("Fatal error realpath()ing path:", path)
628 # build fs according to type
630 def mkfs(dev, devsize, fstype, jsize, isize, mkfsoptions, isblock=1):
636 panic("size of filesystem on '%s' must be larger than 8MB, but is set to %s"%
638 # devsize is in 1k, and fs block count is in 4k
639 block_cnt = devsize/4
641 if fstype in ('ext3', 'ldiskfs'):
642 # ext3 journal size is in megabytes
645 if not is_block(dev):
646 ret, out = runcmd("ls -l %s" %dev)
647 devsize = int(string.split(out[0])[4]) / 1024
649 # sfdisk works for symlink, hardlink, and realdev
650 ret, out = runcmd("sfdisk -s %s" %dev)
652 devsize = int(out[0])
654 # sfdisk -s will fail for too large block device,
655 # then, read the size of partition from /proc/partitions
657 # get the realpath of the device
658 # it may be the real device, such as /dev/hda7
659 # or the hardlink created via mknod for a device
660 real_dev = my_realpath(dev)
662 # get the major and minor number of the realpath via ls
663 # it seems python(os.stat) does not return
664 # the st_rdev member of the stat structure
665 ret, out = runcmd("ls -l %s" %real_dev)
666 major = string.split(string.split(out[0])[4], ",")[0]
667 minor = string.split(out[0])[5]
669 # get the devsize from /proc/partitions with the major and minor number
670 ret, out = runcmd("cat /proc/partitions")
673 if string.split(line)[0] == major and string.split(line)[1] == minor:
674 devsize = int(string.split(line)[2])
677 if devsize > 1024 * 1024:
678 jsize = ((devsize / 102400) * 4)
681 if jsize: jopt = "-J size=%d" %(jsize,)
682 if isize: iopt = "-I %d" %(isize,)
683 mkfs = 'mkfs.ext2 -j -b 4096 '
684 if not isblock or config.force:
686 elif fstype == 'reiserfs':
687 # reiserfs journal size is in blocks
688 if jsize: jopt = "--journal_size %d" %(jsize,)
689 mkfs = 'mkreiserfs -ff'
691 panic('unsupported fs type: ', fstype)
693 if config.mkfsoptions != None:
694 mkfs = mkfs + ' ' + config.mkfsoptions
695 if mkfsoptions != None:
696 mkfs = mkfs + ' ' + mkfsoptions
697 (ret, out) = run (mkfs, jopt, iopt, dev, block_cnt)
699 panic("Unable to build fs:", dev, string.join(out))
700 # enable hash tree indexing on fsswe
701 if fstype in ('ext3', 'ldiskfs'):
702 htree = 'tune2fs -O dir_index'
703 (ret, out) = run (htree, dev)
705 panic("Unable to enable htree:", dev)
707 # some systems use /dev/loopN, some /dev/loop/N
711 if not os.access(loop + str(0), os.R_OK):
713 if not os.access(loop + str(0), os.R_OK):
717 # find loop device assigned to the file
720 for n in xrange(0, MAX_LOOP_DEVICES):
722 if os.access(dev, os.R_OK):
723 (stat, out) = run('losetup', dev)
724 if out and stat == 0:
725 m = re.search(r'\((.*)\)', out[0])
726 if m and file == m.group(1):
732 # create file if necessary and assign the first free loop device
733 def init_loop(file, size, fstype, journal_size, inode_size, mkfsoptions, reformat):
734 dev = find_loop(file)
736 print 'WARNING file:', file, 'already mapped to', dev
738 if reformat or not os.access(file, os.R_OK | os.W_OK):
740 panic("size of loopback file '%s' must be larger than 8MB, but is set to %s" % (file,size))
741 (ret, out) = run("dd if=/dev/zero bs=1k count=0 seek=%d of=%s" %(size,
744 panic("Unable to create backing store:", file)
745 mkfs(file, size, fstype, journal_size, inode_size, mkfsoptions, isblock=0)
748 # find next free loop
749 for n in xrange(0, MAX_LOOP_DEVICES):
751 if os.access(dev, os.R_OK):
752 (stat, out) = run('losetup', dev)
754 (stat, out) = run('losetup', dev, file)
756 panic("losetup failed: (%s) %s" % (stat, out[0].strip()))
759 print "out of loop devices"
761 print "out of loop devices"
764 # undo loop assignment
765 def clean_loop(file):
766 dev = find_loop(file)
768 ret, out = run('losetup -d', dev)
770 log('unable to clean loop device:', dev, 'for file:', file)
773 # determine if dev is formatted as a <fstype> filesystem
774 def need_format(fstype, dev):
775 # FIXME don't know how to implement this
778 # initialize a block device if needed
779 def block_dev(dev, size, fstype, reformat, autoformat, journal_size,
780 inode_size, mkfsoptions):
781 if config.noexec: return dev
782 if not is_block(dev):
783 dev = init_loop(dev, size, fstype, journal_size, inode_size,
784 mkfsoptions, reformat)
785 elif reformat or (need_format(fstype, dev) and autoformat == 'yes'):
786 mkfs(dev, size, fstype, journal_size, inode_size, mkfsoptions,
789 # panic("device:", dev,
790 # "not prepared, and autoformat is not set.\n",
791 # "Rerun with --reformat option to format ALL filesystems")
795 """lookup IP address for an interface"""
796 rc, out = run("/sbin/ifconfig", iface)
799 addr = string.split(out[1])[1]
800 ip = string.split(addr, ':')[1]
803 def def_mount_options(fstype, target, blkdev):
804 """returns deafult mount options for passed fstype and target (mds, ost)"""
805 if fstype == 'ext3' or fstype == 'ldiskfs':
806 mountfsoptions = "errors=remount-ro"
808 if sys_get_branch() == '2.4':
809 mountfsoptions = "%s,asyncdel" % (mountfsoptions)
811 # mountfsoptions = "%s,extents,mballoc" % (mountfsoptions)
812 elif target == 'mds':
813 if config.user_xattr:
814 mountfsoptions = "%s,user_xattr" % (mountfsoptions)
816 mountfsoptions = "%s,acl" % (mountfsoptions)
819 # grab superblock info
820 dumpe2fs="dumpe2fs -f -h"
821 (ret, sb) = run(dumpe2fs, blkdev)
823 panic("unable to get superblock for ", blkdev)
825 # extract journal UUID
829 lst = string.split(line, ":")
830 if lst[0] == 'Journal UUID':
832 panic("cannot retrieve journal UUID for ", blkdev)
833 if string.split(lst[1])[0] != '<none>':
834 journal_UUID = string.split(lst[1])[0]
835 debug(blkdev, 'has journal UUID', journal_UUID)
836 if lst[0] == 'Journal device':
838 panic("cannot retrieve journal device for ", blkdev)
839 if string.split(lst[1])[0] != '0x0000':
840 journal_DEV = string.split(lst[1])[0]
841 debug(blkdev, 'has journal device', journal_DEV)
844 if len(journal_UUID) == 0 or len(journal_DEV) == 0:
845 debug('no external journal found for', blkdev)
846 # use internal journal
847 return mountfsoptions
850 blkid = "blkid -o device -t UUID='%s'" % (journal_UUID)
851 (ret, devname) = run(blkid)
852 if ret or len(devname) == 0:
853 panic("cannot find external journal for ", blkdev)
854 debug('found', blkdev, 'journal UUID', journal_UUID, 'on',
855 string.replace(devname[0], '\n', ''))
857 try: # sigh, python 1.5 does not support os.stat().st_rdev
858 jdevpath = my_realpath(string.replace(devname[0], '\n', ''))
859 ret, out = runcmd("ls -l %s" %jdevpath)
861 major = int(string.split(string.split(out[0])[4], ',')[0])
862 minor = int(string.split(out[0])[5])
863 debug('major', major, 'minor', minor)
864 rdev = major << 8 | minor
866 panic("cannot stat ", devname[0])
868 debug('found', blkdev, 'journal UUID', journal_UUID, 'on',
869 jdevpath, 'rdev', rdev)
872 if string.atoi(journal_DEV, 0) != rdev:
873 mountfsoptions = "%s,journal_dev=%#x" % (mountfsoptions,rdev)
875 return mountfsoptions
878 def sys_get_branch():
879 """Returns kernel release"""
880 return os.uname()[2][:3]
882 def mod_loaded(modname):
883 """Check if a module is already loaded. Look in /proc/modules for it."""
884 if PLATFORM == 'LINUX':
886 fp = open('/proc/modules')
887 lines = fp.readlines()
889 # please forgive my tired fingers for this one
890 ret = filter(lambda word, mod=modname: word == mod,
891 map(lambda line: string.split(line)[0], lines))
895 elif PLATFORM == 'DARWIN':
896 ret, out = run('/usr/sbin/kextstat | /usr/bin/grep', modname)
904 # XXX: instead of device_list, ask for $name and see what we get
905 def is_prepared(name):
906 """Return true if a device exists for the name"""
909 if (config.noexec or config.record) and config.cleanup:
912 # expect this format:
913 # 1 UP ldlm ldlm ldlm_UUID 2
914 out = lctl.device_list()
916 if name == string.split(s)[3]:
918 except CommandError, e:
922 def is_network_prepared():
923 """If the any device exists, then assume that all networking
924 has been configured"""
925 out = lctl.device_list()
928 def fs_is_mounted(path):
929 """Return true if path is a mounted lustre filesystem"""
931 real_path = my_realpath(path)
933 fp = open('/proc/mounts')
934 lines = fp.readlines()
938 if a[1] == real_path and a[2] == 'lustre_lite':
945 """Manage kernel modules"""
946 def __init__(self, lustre_dir, portals_dir):
947 self.lustre_dir = lustre_dir
948 self.portals_dir = portals_dir
949 self.kmodule_list = []
951 def add_portals_module(self, dev_dir, modname):
952 """Append a module to list of modules to load."""
953 self.kmodule_list.append((self.portals_dir, dev_dir, modname))
955 def add_lustre_module(self, dev_dir, modname):
956 """Append a module to list of modules to load."""
957 self.kmodule_list.append((self.lustre_dir, dev_dir, modname))
959 def load_module(self):
960 """Load all the modules in the list in the order they appear."""
961 for src_dir, dev_dir, mod in self.kmodule_list:
962 if mod_loaded(mod) and not config.noexec:
964 log ('loading module:', mod, 'srcdir', src_dir, 'devdir', dev_dir)
965 if PLATFORM == 'LINUX':
968 #For LNET we really need modprobe to load defined LNDs
969 run('/sbin/modprobe lnet')
970 #But if that fails, try insmod anyhow with dev option
971 #accept=all for dev liblustre testing
972 options = 'accept=all'
974 module = find_module(src_dir, dev_dir, mod)
976 panic('module not found:', mod)
977 (rc, out) = run('/sbin/insmod', module, options)
978 if rc and not mod_loaded(mod):
980 print("Bad module options? Check dmesg.")
981 raise CommandError('insmod', out, rc)
983 (rc, out) = run('/sbin/modprobe', mod)
984 if rc and not mod_loaded(mod):
986 print("Bad module options? Check dmesg.")
987 raise CommandError('modprobe', out, rc)
988 elif PLATFORM == 'DARWIN':
989 run('/sbin/kextload', KEXTPATH + mod + '.kext');
991 def cleanup_module(self):
992 """Unload the modules in the list in reverse order."""
994 rev = self.kmodule_list[:] # make *copy* of list
996 for src_dir, dev_dir, mod in rev:
997 if not mod_loaded(mod) and not config.noexec:
999 if mod == 'ksocklnd' and not config.noexec:
1000 # Ignore ksocklnd in module list (lnet will remove)
1002 log('unloading module:', mod)
1003 if mod == 'lnet' and not config.noexec:
1004 # remove any self-ref portals created
1005 lctl.unconfigure_network()
1007 debug('dumping debug log to', config.dump)
1009 lctl.dump(config.dump)
1010 log('unloading the network')
1011 lctl.unconfigure_network()
1012 if mod_loaded("ksocklnd"):
1013 if PLATFORM == 'LINUX':
1014 run('/sbin/rmmod ksocklnd')
1015 elif PLATFORM == 'DARWIN':
1016 run('/sbin/kextunload', KEXTPATH+'ksocklnd.kext')
1017 if mod_loaded("kqswlnd"):
1018 run('/sbin/rmmod kqswlnd')
1019 if mod_loaded("kgmlnd"):
1020 run('/sbin/rmmod kgmlnd')
1021 if mod_loaded("kopeniblnd"):
1022 run('/sbin/rmmod kopeniblnd')
1023 if mod_loaded("kiiblnd"):
1024 run('/sbin/rmmod kiiblnd')
1025 if mod_loaded("kviblnd"):
1026 run('/sbin/rmmod kviblnd')
1027 if mod_loaded("kralnd"):
1028 run('/sbin/rmmod kralnd')
1029 if mod_loaded("kptllnd"):
1030 run('/sbin/rmmod kptllnd')
1031 if PLATFORM == 'LINUX':
1032 (rc, out) = run('/sbin/rmmod', mod)
1033 elif PLATFORM == 'DARWIN':
1034 (rc, out) = run('/sbin/kextunload', KEXTPATH+mod+'.kext');
1036 log('! unable to unload module:', mod)
1040 # ============================================================
1041 # Classes to prepare and cleanup the various objects
1044 """ Base class for the rest of the modules. The default cleanup method is
1045 defined here, as well as some utilitiy funcs.
1047 def __init__(self, module_name, db):
1049 self.module_name = module_name
1050 self.name = self.db.getName()
1051 self.uuid = self.db.getUUID()
1054 self.kmod = kmod(config.lustre, config.portals)
1056 def info(self, *args):
1057 msg = string.join(map(str,args))
1058 log (self.module_name + ":", self.name, self.uuid, msg)
1061 """ default cleanup, used for most modules """
1064 lctl.cleanup(self.name, self.uuid, config.force)
1065 except CommandError, e:
1066 log(self.module_name, "cleanup failed: ", self.name)
1070 def add_portals_module(self, dev_dir, modname):
1071 """Append a module to list of modules to load."""
1072 self.kmod.add_portals_module(dev_dir, modname)
1074 def add_lustre_module(self, dev_dir, modname):
1075 """Append a module to list of modules to load."""
1076 self.kmod.add_lustre_module(dev_dir, modname)
1078 def load_module(self):
1079 """Load all the modules in the list in the order they appear."""
1080 self.kmod.load_module()
1082 def cleanup_module(self):
1083 """Unload the modules in the list in reverse order."""
1084 if self.safe_to_clean():
1085 self.kmod.cleanup_module()
1087 def safe_to_clean(self):
1090 def safe_to_clean_modules(self):
1091 return self.safe_to_clean()
1093 class Network(Module):
1094 def __init__(self,db,nid_uuid=0):
1095 Module.__init__(self, 'NETWORK', db)
1096 self.net_type = self.db.get_val('nettype')
1097 self.nid = self.db.get_val('nid', '*')
1098 self.cluster_id = self.db.get_val('clusterid', "0")
1099 self.port = self.db.get_val_int('port', 0)
1100 self.nid_uuid = nid_uuid
1101 self.add_portals_module('libcfs', 'libcfs')
1102 self.add_portals_module('lnet', 'lnet')
1103 # Add the socklnd for developers without modprobe.conf (umls)
1104 self.add_portals_module('klnds/socklnd', 'ksocklnd')
1107 if is_network_prepared():
1109 self.info(self.net_type, self.nid)
1110 if self.net_type == 'tcp':
1112 if self.net_type == 'elan':
1115 def safe_to_clean(self):
1116 if PLATFORM == 'LINUX':
1117 return not is_network_prepared()
1118 elif PLATFORM == 'DARWIN':
1119 # XXX always assume it's safe to clean
1124 self.info(self.net_type, self.nid)
1126 # This is only needed to load the modules; the LDLM device
1127 # is now created automatically.
1129 def __init__(self,db):
1130 Module.__init__(self, 'LDLM', db)
1131 self.add_lustre_module('lvfs', 'lvfs')
1132 self.add_lustre_module('obdclass', 'obdclass')
1133 self.add_lustre_module('ptlrpc', 'ptlrpc')
1142 def __init__(self, db, uuid, fs_name, name_override = None, config_only = None):
1143 Module.__init__(self, 'LOV', db)
1144 if name_override != None:
1145 self.name = "lov_%s" % name_override
1146 self.add_lustre_module('lov', 'lov')
1147 self.mds_uuid = self.db.get_first_ref('mds')
1148 self.stripe_sz = self.db.get_val_int('stripesize', 1048576)
1149 self.stripe_off = self.db.get_val_int('stripeoffset', 0)
1150 self.pattern = self.db.get_val_int('stripepattern', 0)
1152 self.stripe_cnt = self.db.get_val_int('stripecount', 1)
1154 self.desc_uuid = self.uuid
1155 self.uuid = generate_client_uuid(self.name)
1156 self.fs_name = fs_name
1157 # settings below here won't be seen by the MDSDEV code!
1159 self.config_only = 1
1161 self.config_only = None
1162 mds = self.db.lookup(self.mds_uuid)
1163 self.mds_name = mds.getName()
1164 self.devlist = self.db.get_lov_tgts('lov_tgt')
1165 for (obd_uuid, index, gen, active) in self.devlist:
1168 obd = self.db.lookup(obd_uuid)
1169 osc = get_osc(obd, self.uuid, fs_name)
1171 self.osclist.append((osc, index, gen, active))
1173 panic('osc not found:', obd_uuid)
1174 if self.osclist == []:
1175 debug("get_lov_tgts failed, using get_refs");
1177 self.devlist = self.db.get_refs('obd')
1178 for obd_uuid in self.devlist:
1179 obd = self.db.lookup(obd_uuid)
1180 osc = get_osc(obd, self.uuid, fs_name)
1182 self.osclist.append((osc, index, 1, 1))
1184 panic('osc not found:', obd_uuid)
1186 if self.osclist == []:
1187 panic('No OSCs configured for LOV')
1188 debug('dbg LOV __init__:', self.osclist, self.devlist, self.stripe_cnt)
1191 debug('dbg LOV prepare')
1192 if is_prepared(self.name):
1194 debug('dbg LOV prepare:', self.osclist, self.devlist)
1195 self.info(self.mds_uuid, self.stripe_cnt, self.stripe_sz,
1196 self.stripe_off, self.pattern, self.devlist,
1198 lctl.lov_setup(self.name, self.uuid,
1199 self.desc_uuid, self.mds_name, self.stripe_cnt,
1200 self.stripe_sz, self.stripe_off, self.pattern)
1201 if self.osclist == []:
1202 panic('No OSCs configured for LOV?')
1203 for (osc, index, gen, active) in self.osclist:
1204 target_uuid = osc.target_uuid
1206 # Only ignore connect failures with --force, which
1207 # isn't implemented here yet.
1209 osc.prepare(ignore_connect_failure=0)
1210 except CommandError, e:
1211 print "Error preparing OSC %s\n" % osc.uuid
1213 lctl.lov_add_obd(self.name, self.uuid, target_uuid, index, gen)
1216 if is_prepared(self.name):
1217 Module.cleanup(self)
1218 for (osc, index, gen, active) in self.osclist:
1220 if self.config_only:
1221 panic("Can't clean up config_only LOV ", self.name)
1223 def load_module(self):
1224 if self.config_only:
1225 panic("Can't load modules for config_only LOV ", self.name)
1226 for (osc, index, gen, active) in self.osclist:
1229 Module.load_module(self)
1231 def cleanup_module(self):
1232 if self.config_only:
1233 panic("Can't cleanup modules for config_only LOV ", self.name)
1234 Module.cleanup_module(self)
1235 for (osc, index, gen, active) in self.osclist:
1237 osc.cleanup_module()
1240 class MDSDEV(Module):
1241 def __init__(self,db):
1242 Module.__init__(self, 'MDSDEV', db)
1243 self.devpath = self.db.get_val('devpath','')
1244 self.size = self.db.get_val_int('devsize', 0)
1245 self.journal_size = self.db.get_val_int('journalsize', 0)
1247 self.fstype = self.db.get_val('fstype', '')
1248 if sys_get_branch() == '2.4' and self.fstype == 'ldiskfs':
1249 self.fstype = 'ext3'
1250 elif sys_get_branch() == '2.6' and self.fstype == 'ext3':
1251 self.fstype = 'ldiskfs'
1253 self.nspath = self.db.get_val('nspath', '')
1254 self.mkfsoptions = '-i 4096 ' + self.db.get_val('mkfsoptions', '')
1255 self.mountfsoptions = self.db.get_val('mountfsoptions', '')
1257 self.quota = config.quota
1259 self.quota = self.db.get_val('quota', '')
1260 # overwrite the orignal MDSDEV name and uuid with the MDS name and uuid
1261 target_uuid = self.db.get_first_ref('target')
1262 mds = self.db.lookup(target_uuid)
1263 self.name = mds.getName()
1264 self.filesystem_uuids = mds.get_refs('filesystem')
1265 # FIXME: if fstype not set, then determine based on kernel version
1266 self.format = self.db.get_val('autoformat', "no")
1267 if mds.get_val('failover', 0):
1268 self.failover_mds = 'f'
1270 self.failover_mds = 'n'
1271 active_uuid = get_active_target(mds)
1273 panic("No target device found:", target_uuid)
1274 if active_uuid == self.uuid:
1278 if self.active and config.group and config.group != mds.get_val('group', mds.get_val('name')):
1281 self.inode_size = self.db.get_val_int('inodesize', 0)
1282 debug('original inode_size ', self.inode_size)
1283 if self.inode_size == 0:
1284 # find the LOV for this MDS
1285 lovconfig_uuid = mds.get_first_ref('lovconfig')
1286 if not lovconfig_uuid:
1287 panic("No LOV config found for MDS ", mds.name)
1288 lovconfig = mds.lookup(lovconfig_uuid)
1289 lov_uuid = lovconfig.get_first_ref('lov')
1291 panic("No LOV found for lovconfig ", lovconfig.name)
1292 lov = LOV(self.db.lookup(lov_uuid), lov_uuid, 'FS_name', config_only = 1)
1294 # default stripe count controls default inode_size
1295 if (lov.stripe_cnt > 0):
1296 stripe_count = lov.stripe_cnt
1299 if stripe_count > 77:
1300 self.inode_size = 512
1301 elif stripe_count > 34:
1302 self.inode_size = 2048
1303 elif stripe_count > 13:
1304 self.inode_size = 1024
1305 #elif stripe_count < 3:
1306 # self.inode_size = 256
1308 self.inode_size = 512
1309 debug('stripe_count ', stripe_count,' inode_size ',self.inode_size)
1311 self.target_dev_uuid = self.uuid
1312 self.uuid = target_uuid
1316 self.add_lustre_module('quota', 'lquota')
1317 self.add_lustre_module('mdc', 'mdc')
1318 self.add_lustre_module('osc', 'osc')
1319 self.add_lustre_module('lov', 'lov')
1320 self.add_lustre_module('mds', 'mds')
1321 if self.fstype == 'ldiskfs':
1322 self.add_lustre_module('ldiskfs', 'ldiskfs')
1324 self.add_lustre_module('lvfs', 'fsfilt_%s' % (self.fstype))
1326 def load_module(self):
1328 Module.load_module(self)
1331 if is_prepared(self.name):
1334 debug(self.uuid, "not active")
1337 # run write_conf automatically, if --reformat used
1339 self.info(self.devpath, self.fstype, self.size, self.format)
1340 # never reformat here
1341 blkdev = block_dev(self.devpath, self.size, self.fstype, 0,
1342 self.format, self.journal_size, self.inode_size,
1344 if not is_prepared('MDT'):
1345 lctl.newdev("mdt", 'MDT', 'MDT_UUID', setup ="")
1347 mountfsoptions = def_mount_options(self.fstype, 'mds', blkdev)
1349 if config.mountfsoptions:
1351 mountfsoptions = mountfsoptions + ',' + config.mountfsoptions
1353 mountfsoptions = config.mountfsoptions
1354 if self.mountfsoptions:
1355 mountfsoptions = mountfsoptions + ',' + self.mountfsoptions
1357 if self.mountfsoptions:
1359 mountfsoptions = mountfsoptions + ',' + self.mountfsoptions
1361 mountfsoptions = self.mountfsoptions
1363 print 'MDS mount options: ' + mountfsoptions
1365 lctl.newdev("mds", self.name, self.uuid,
1366 setup ="%s %s %s %s %s" %(blkdev, self.fstype, self.name,
1367 mountfsoptions, self.quota))
1368 self.group_upcall = self.db.get_val('group_upcall','')
1369 sys_set_group_upcall(self.name, self.group_upcall)
1371 except CommandError, e:
1373 panic("MDS failed to start. Check the syslog for details." +
1374 " (May need to run lconf --write-conf)")
1378 def write_conf(self):
1379 if is_prepared(self.name):
1381 self.info(self.devpath, self.fstype, self.format)
1382 blkdev = block_dev(self.devpath, self.size, self.fstype,
1383 config.reformat, self.format, self.journal_size,
1384 self.inode_size, self.mkfsoptions)
1385 lctl.newdev("mds", self.name, self.uuid,
1386 setup ="%s %s" %(blkdev, self.fstype))
1388 # record logs for the MDS lov
1389 for uuid in self.filesystem_uuids:
1390 log("recording clients for filesystem:", uuid)
1391 fs = self.db.lookup(uuid)
1392 obd_uuid = fs.get_first_ref('obd')
1393 client_uuid = generate_client_uuid(self.name)
1394 client = VOSC(self.db.lookup(obd_uuid), client_uuid, self.name,
1397 lctl.clear_log(self.name, self.name)
1398 lctl.record(self.name, self.name)
1400 lctl.mount_option(self.name, client.get_name(), "")
1404 # record logs for each client
1406 config_options = "--ldapurl " + config.ldapurl + " --config " + config.config
1408 config_options = CONFIG_FILE
1410 for node_db in self.db.lookup_class('node'):
1411 client_name = node_db.getName()
1412 for prof_uuid in node_db.get_refs('profile'):
1413 prof_db = node_db.lookup(prof_uuid)
1414 # refactor this into a funtion to test "clientness" of a node.
1415 for ref_class, ref_uuid in prof_db.get_all_refs():
1416 if ref_class in ('mountpoint','echoclient'):
1417 thing = self.db.lookup(ref_uuid);
1418 fs_uuid = thing.get_first_ref('filesystem')
1419 if not fs_uuid in self.filesystem_uuids:
1422 debug("recording", client_name)
1423 old_noexec = config.noexec
1425 noexec_opt = ('', '-n')
1426 ret, out = run (sys.argv[0],
1427 noexec_opt[old_noexec == 1],
1428 " -v --record --nomod --old_conf",
1429 "--record_log", client_name,
1430 "--record_device", self.name,
1431 "--node", client_name,
1434 lctl.clear_log(self.name, client_name)
1437 panic("Record client log %s on %s failed" %(
1438 client_name, self.name))
1440 for s in out: log("record> ", string.strip(s))
1441 config.noexec = old_noexec
1443 lctl.cleanup(self.name, self.uuid, config.force, config.failover)
1444 except CommandError, e:
1445 log(self.module_name, "cleanup failed: ", self.name)
1448 Module.cleanup(self)
1449 clean_loop(self.devpath)
1451 #change the mtime of LLOG to match the XML creation time
1452 if toplustreDB.get_mtime():
1453 mtime = toplustreDB.get_mtime()
1454 debug("changing mtime of LOGS to %s" %mtime)
1455 ret, mktemp = runcmd("mktemp /tmp/lustre-cmd.XXXXXXXX")
1457 log(self.module_name, "create mtime LOGS cmdfile failed: ", self.name)
1459 mtimecmdfile = string.split(mktemp[0])[0]
1460 fd = os.open(mtimecmdfile, os.O_RDWR | os.O_CREAT)
1461 os.write(fd, "\n\n\n\n\n%s\n\n" %mtime)
1463 cmd = "debugfs -w -R \"mi /LOGS\" <%s %s" %(mtimecmdfile, self.devpath)
1464 ret, outs = runcmd(cmd)
1465 os.remove(mtimecmdfile)
1467 print "Can not change mtime of LOGS by debugfs."
1469 def mds_remaining(self):
1470 out = lctl.device_list()
1472 if string.split(s)[2] in ('mds',):
1473 if string.split(s)[1] in ('ST',):
1477 def safe_to_clean(self):
1480 def safe_to_clean_modules(self):
1481 return not self.mds_remaining()
1485 debug(self.uuid, "not active")
1488 if is_prepared(self.name):
1490 lctl.cleanup(self.name, self.uuid, config.force,
1492 except CommandError, e:
1493 log(self.module_name, "cleanup failed: ", self.name)
1496 Module.cleanup(self)
1497 if not self.mds_remaining() and is_prepared('MDT'):
1499 lctl.cleanup("MDT", "MDT_UUID", config.force,
1501 except CommandError, e:
1502 print "cleanup failed: ", self.name
1505 clean_loop(self.devpath)
1508 def __init__(self, db):
1509 Module.__init__(self, 'OSD', db)
1510 self.osdtype = self.db.get_val('osdtype')
1511 self.devpath = self.db.get_val('devpath', '')
1512 self.size = self.db.get_val_int('devsize', 0)
1513 self.journal_size = self.db.get_val_int('journalsize', 0)
1515 # now as we store fids in EA on OST we need to make inode bigger
1516 self.inode_size = self.db.get_val_int('inodesize', 0)
1517 if self.inode_size == 0:
1518 self.inode_size = 256
1519 self.mkfsoptions = self.db.get_val('mkfsoptions', '')
1520 # Allocate fewer inodes on large OST devices. Most filesystems
1521 # can be much more aggressive than this, but by default we can't.
1522 if self.size > 1000000:
1523 self.mkfsoptions = '-i 16384 ' + self.mkfsoptions
1524 self.mountfsoptions = self.db.get_val('mountfsoptions', '')
1526 self.quota = config.quota
1528 self.quota = self.db.get_val('quota', '')
1530 self.fstype = self.db.get_val('fstype', '')
1531 if sys_get_branch() == '2.4' and self.fstype == 'ldiskfs':
1532 self.fstype = 'ext3'
1533 elif sys_get_branch() == '2.6' and self.fstype == 'ext3':
1534 self.fstype = 'ldiskfs'
1536 self.nspath = self.db.get_val('nspath', '')
1537 target_uuid = self.db.get_first_ref('target')
1538 ost = self.db.lookup(target_uuid)
1539 self.name = ost.getName()
1540 self.format = self.db.get_val('autoformat', 'yes')
1541 if ost.get_val('failover', 1):
1542 self.failover_ost = 'f'
1544 self.failover_ost = 'n'
1546 active_uuid = get_active_target(ost)
1548 panic("No target device found:", target_uuid)
1549 if active_uuid == self.uuid:
1553 if self.active and config.group and config.group != ost.get_val('group', ost.get_val('name')):
1556 self.target_dev_uuid = self.uuid
1557 self.uuid = target_uuid
1560 self.add_lustre_module('quota', 'lquota')
1561 self.add_lustre_module('ost', 'ost')
1562 # FIXME: should we default to ext3 here?
1563 if self.fstype == 'ldiskfs':
1564 self.add_lustre_module('ldiskfs', 'ldiskfs')
1566 self.add_lustre_module('lvfs' , 'fsfilt_%s' % (self.fstype))
1567 self.add_lustre_module(self.osdtype, self.osdtype)
1569 def load_module(self):
1571 Module.load_module(self)
1573 # need to check /proc/mounts and /etc/mtab before
1574 # formatting anything.
1575 # FIXME: check if device is already formatted.
1577 if is_prepared(self.name):
1580 debug(self.uuid, "not active")
1582 self.info(self.osdtype, self.devpath, self.size, self.fstype,
1583 self.format, self.journal_size, self.inode_size)
1584 if self.osdtype == 'obdecho':
1587 blkdev = block_dev(self.devpath, self.size, self.fstype,
1588 config.reformat, self.format, self.journal_size,
1589 self.inode_size, self.mkfsoptions)
1591 mountfsoptions = def_mount_options(self.fstype, 'ost', blkdev)
1593 if config.mountfsoptions:
1595 mountfsoptions = mountfsoptions + ',' + config.mountfsoptions
1597 mountfsoptions = config.mountfsoptions
1598 if self.mountfsoptions:
1599 mountfsoptions = mountfsoptions + ',' + self.mountfsoptions
1601 if self.mountfsoptions:
1603 mountfsoptions = mountfsoptions + ',' + self.mountfsoptions
1605 mountfsoptions = self.mountfsoptions
1607 print 'OST mount options: ' + mountfsoptions
1609 lctl.newdev(self.osdtype, self.name, self.uuid,
1610 setup ="%s %s %s %s %s" %(blkdev, self.fstype,
1611 self.failover_ost, mountfsoptions,
1613 if not is_prepared('OSS'):
1614 lctl.newdev("ost", 'OSS', 'OSS_UUID', setup ="")
1616 def osd_remaining(self):
1617 out = lctl.device_list()
1619 if string.split(s)[2] in ('obdfilter', 'obdecho'):
1622 def safe_to_clean(self):
1625 def safe_to_clean_modules(self):
1626 return not self.osd_remaining()
1630 debug(self.uuid, "not active")
1632 if is_prepared(self.name):
1635 lctl.cleanup(self.name, self.uuid, config.force,
1637 except CommandError, e:
1638 log(self.module_name, "cleanup failed: ", self.name)
1641 if not self.osd_remaining() and is_prepared('OSS'):
1643 lctl.cleanup("OSS", "OSS_UUID", config.force,
1645 except CommandError, e:
1646 print "cleanup failed: ", self.name
1649 if not self.osdtype == 'obdecho':
1650 clean_loop(self.devpath)
1652 # Generic client module, used by OSC and MDC
1653 class Client(Module):
1654 def __init__(self, tgtdb, uuid, module, fs_name, self_name=None,
1656 self.target_name = tgtdb.getName()
1657 self.target_uuid = tgtdb.getUUID()
1659 self.backup_targets = []
1661 self.tgt_dev_uuid = get_active_target(tgtdb)
1662 if not self.tgt_dev_uuid:
1663 panic("No target device found for target:", self.target_name)
1665 self.kmod = kmod(config.lustre, config.portals)
1669 self.module = module
1670 self.module_name = string.upper(module)
1672 self.name = '%s_%s_%s_%s' % (self.module_name, socket.gethostname(),
1673 self.target_name, fs_name)
1675 self.name = self_name
1677 self.lookup_server(self.tgt_dev_uuid)
1678 self.lookup_backup_targets()
1679 self.fs_name = fs_name
1682 self.add_lustre_module(module_dir, module)
1684 def lookup_server(self, srv_uuid):
1685 """ Lookup a server's network information """
1686 self._server_nets = get_ost_net(self.db, srv_uuid)
1687 if len(self._server_nets) == 0:
1688 panic("Unable to find a server for:", srv_uuid)
1690 def get_servers(self):
1691 return self._server_nets
1693 def lookup_backup_targets(self):
1694 """ Lookup alternative network information """
1695 prof_list = toplustreDB.get_refs('profile')
1696 for prof_uuid in prof_list:
1697 prof_db = toplustreDB.lookup(prof_uuid)
1699 panic("profile:", prof_uuid, "not found.")
1700 for ref_class, ref_uuid in prof_db.get_all_refs():
1701 if ref_class in ('osd', 'mdsdev'):
1702 devdb = toplustreDB.lookup(ref_uuid)
1703 uuid = devdb.get_first_ref('target')
1704 if self.target_uuid == uuid and self.tgt_dev_uuid != ref_uuid:
1705 debug("add backup target", ref_uuid)
1706 self.backup_targets.append(ref_uuid)
1708 def prepare(self, ignore_connect_failure = 0):
1709 self.info(self.target_uuid)
1710 if is_prepared(self.name):
1713 srv_list = self.get_servers()
1714 debug('dbg CLIENT __prepare__:', self.target_uuid, srv_list)
1715 for srv in srv_list:
1717 if len(srv_list) == 0:
1718 panic("no servers for ", self.target_uuid)
1719 except CommandError, e:
1720 if not ignore_connect_failure:
1725 if self.target_uuid in config.inactive and self.permits_inactive():
1726 debug("%s inactive" % self.target_uuid)
1727 inactive_p = "inactive"
1729 debug("%s active" % self.target_uuid)
1731 lctl.newdev(self.module, self.name, self.uuid,
1732 setup ="%s %s %s" % (self.target_uuid, srv.nid_uuid,
1735 panic("Unable to create OSC for ", self.target_uuid)
1737 for tgt_dev_uuid in self.backup_targets:
1738 this_nets = get_ost_net(toplustreDB, tgt_dev_uuid)
1739 if len(this_nets) == 0:
1740 panic ("Unable to find a backup server for:", tgt_dev_uuid)
1742 for srv in this_nets:
1745 lctl.add_conn(self.name, srv.nid_uuid);
1749 if is_prepared(self.name):
1750 Module.cleanup(self)
1751 srv_list = self.get_servers()
1752 for srv in srv_list:
1753 lctl.disconnect(srv)
1754 for tgt_dev_uuid in self.backup_targets:
1755 this_nets = get_ost_net(toplustreDB, tgt_dev_uuid)
1756 if len(this_nets) == 0:
1757 panic ("Unable to find a backup server for:", tgt_dev_uuid)
1759 for srv in this_nets:
1760 lctl.disconnect(srv)
1763 def __init__(self, db, uuid, fs_name):
1764 Client.__init__(self, db, uuid, 'mdc', fs_name)
1766 def permits_inactive(self):
1770 def __init__(self, db, uuid, fs_name):
1771 Client.__init__(self, db, uuid, 'osc', fs_name)
1773 def permits_inactive(self):
1777 def __init__(self, db):
1778 Module.__init__(self, 'COBD', db)
1779 self.real_uuid = self.db.get_first_ref('realobd')
1780 self.cache_uuid = self.db.get_first_ref('cacheobd')
1781 self.add_lustre_module('cobd' , 'cobd')
1783 # need to check /proc/mounts and /etc/mtab before
1784 # formatting anything.
1785 # FIXME: check if device is already formatted.
1787 if is_prepared(self.name):
1789 self.info(self.real_uuid, self.cache_uuid)
1790 lctl.newdev("cobd", self.name, self.uuid,
1791 setup ="%s %s" %(self.real_uuid, self.cache_uuid))
1794 # virtual interface for OSC and LOV
1796 def __init__(self, db, uuid, fs_name, name_override = None, quota = None):
1797 Module.__init__(self, 'VOSC', db)
1799 self.add_lustre_module('quota', 'lquota')
1800 if db.get_class() == 'lov':
1801 self.osc = LOV(db, uuid, fs_name, name_override)
1803 self.osc = get_osc(db, uuid, fs_name)
1805 return self.osc.uuid
1807 return self.osc.name
1812 def load_module(self):
1813 Module.load_module(self)
1814 self.osc.load_module()
1815 def cleanup_module(self):
1816 self.osc.cleanup_module()
1817 Module.cleanup_module(self)
1820 class ECHO_CLIENT(Module):
1821 def __init__(self,db):
1822 Module.__init__(self, 'ECHO_CLIENT', db)
1823 self.add_lustre_module('obdecho', 'obdecho')
1824 self.obd_uuid = self.db.get_first_ref('obd')
1825 obd = self.db.lookup(self.obd_uuid)
1826 self.uuid = generate_client_uuid(self.name)
1827 self.osc = VOSC(obd, self.uuid, self.name)
1830 if is_prepared(self.name):
1832 self.osc.prepare() # XXX This is so cheating. -p
1833 self.info(self.obd_uuid)
1835 lctl.newdev("echo_client", self.name, self.uuid,
1836 setup = self.osc.get_name())
1839 if is_prepared(self.name):
1840 Module.cleanup(self)
1843 def load_module(self):
1844 self.osc.load_module()
1845 Module.load_module(self)
1847 def cleanup_module(self):
1848 Module.cleanup_module(self)
1849 self.osc.cleanup_module()
1852 def generate_client_uuid(name):
1853 client_uuid = '%05x_%.19s_%05x%05x' % (int(random.random() * 1048576),
1855 int(random.random() * 1048576),
1856 int(random.random() * 1048576))
1857 return client_uuid[:36]
1860 def my_rstrip(s, chars):
1861 """my_rstrip(s, chars) -> strips any instances of the characters
1862 found in chars from the right side of string s"""
1863 # XXX required because python versions pre 2.2.3 don't allow
1864 #string.rstrip() to take alternate char lists
1868 ns = string.rstrip(s, '/')
1869 except TypeError, e:
1870 for i in range(len(s) - 1, 0, -1):
1879 class Mountpoint(Module):
1880 def __init__(self,db):
1881 Module.__init__(self, 'MTPT', db)
1882 self.path = my_rstrip(self.db.get_val('path'), '/')
1883 self.clientoptions = self.db.get_val('clientoptions', '')
1884 self.fs_uuid = self.db.get_first_ref('filesystem')
1885 fs = self.db.lookup(self.fs_uuid)
1886 self.mds_uuid = fs.get_first_ref('mds')
1887 mds_db = self.db.lookup(self.mds_uuid)
1889 quota = config.quota
1891 quota = mds_db.get_val('quota', config.quota)
1892 self.obd_uuid = fs.get_first_ref('obd')
1893 obd = self.db.lookup(self.obd_uuid)
1894 client_uuid = generate_client_uuid(self.name)
1895 self.vosc = VOSC(obd, client_uuid, self.name, quota=quota)
1896 self.mdc = get_mdc(db, client_uuid, self.name, self.mds_uuid)
1898 self.add_lustre_module('mdc', 'mdc')
1899 self.add_lustre_module('llite', 'llite')
1902 if fs_is_mounted(self.path):
1903 log(self.path, "already mounted.")
1907 mdc_name = self.mdc.name
1909 self.info(self.path, self.mds_uuid, self.obd_uuid)
1910 if config.record or config.lctl_dump:
1911 lctl.mount_option(local_node_name, self.vosc.get_name(), mdc_name)
1914 if config.clientoptions:
1915 if self.clientoptions:
1916 self.clientoptions = self.clientoptions + ',' + config.clientoptions
1918 self.clientoptions = config.clientoptions
1919 if self.clientoptions:
1920 self.clientoptions = ',' + self.clientoptions
1921 # Linux kernel will deal with async and not pass it to ll_fill_super,
1922 # so replace it with Lustre async
1923 self.clientoptions = string.replace(self.clientoptions, "async", "lasync")
1925 cmd = "mount -t lustre_lite -o osc=%s,mdc=%s%s %s %s" % \
1926 (self.vosc.get_name(), mdc_name, self.clientoptions, config.config, self.path)
1927 run("mkdir", self.path)
1932 panic("mount failed:", self.path, ":", string.join(val))
1935 self.info(self.path, self.mds_uuid,self.obd_uuid)
1937 if config.record or config.lctl_dump:
1938 lctl.del_mount_option(local_node_name)
1940 if fs_is_mounted(self.path):
1942 (rc, out) = run("umount", "-f", self.path)
1944 (rc, out) = run("umount", self.path)
1946 raise CommandError('umount', out, rc)
1948 if fs_is_mounted(self.path):
1949 panic("fs is still mounted:", self.path)
1954 def load_module(self):
1955 self.vosc.load_module()
1956 Module.load_module(self)
1958 def cleanup_module(self):
1959 Module.cleanup_module(self)
1960 self.vosc.cleanup_module()
1963 # ============================================================
1964 # misc query functions
1966 def get_ost_net(self, osd_uuid):
1970 osd = self.lookup(osd_uuid)
1971 node_uuid = osd.get_first_ref('node')
1972 node = self.lookup(node_uuid)
1974 panic("unable to find node for osd_uuid:", osd_uuid,
1975 " node_ref:", node_uuid)
1976 for net_uuid in node.get_networks():
1977 db = node.lookup(net_uuid)
1978 net = Network(db, node_uuid)
1979 srv_list.append(net)
1983 # the order of iniitailization is based on level.
1984 def getServiceLevel(self):
1985 type = self.get_class()
1987 if type in ('network',):
1989 elif type in ('ldlm',):
1991 elif type in ('osd', 'cobd'):
1993 elif type in ('mdsdev',):
1995 elif type in ('mountpoint', 'echoclient'):
1998 panic("Unknown type: ", type)
2000 if ret < config.minlevel or ret > config.maxlevel:
2005 # return list of services in a profile. list is a list of tuples
2006 # [(level, db_object),]
2007 def getServices(self):
2009 for ref_class, ref_uuid in self.get_all_refs():
2010 servdb = self.lookup(ref_uuid)
2012 level = getServiceLevel(servdb)
2014 list.append((level, servdb))
2016 panic('service not found: ' + ref_uuid)
2022 ############################################################
2024 # FIXME: clean this mess up!
2026 # OSC is no longer in the xml, so we have to fake it.
2027 # this is getting ugly and begging for another refactoring
2028 def get_osc(ost_db, uuid, fs_name):
2029 osc = OSC(ost_db, uuid, fs_name)
2032 def get_mdc(db, uuid, fs_name, mds_uuid):
2033 mds_db = db.lookup(mds_uuid);
2035 panic("no mds:", mds_uuid)
2036 mdc = MDC(mds_db, uuid, fs_name)
2039 def get_active_target(db):
2040 target_uuid = db.getUUID()
2041 target_name = db.getName()
2042 node_name = get_select(target_name)
2044 tgt_dev_uuid = db.get_node_tgt_dev(node_name, target_uuid)
2046 tgt_dev_uuid = db.get_first_ref('active')
2049 def get_server_by_nid_uuid(db, nid_uuid):
2050 for n in db.lookup_class("network"):
2052 if net.nid_uuid == nid_uuid:
2056 ############################################################
2060 type = db.get_class()
2061 debug('Service:', type, db.getName(), db.getUUID())
2066 n = LOV(db, "YOU_SHOULD_NEVER_SEE_THIS_UUID")
2067 elif type == 'network':
2071 elif type == 'cobd':
2073 elif type == 'mdsdev':
2075 elif type == 'mountpoint':
2077 elif type == 'echoclient':
2080 panic("unknown service type:", type)
2084 # Prepare the system to run lustre using a particular profile
2085 # in a the configuration.
2086 # * load & the modules
2087 # * setup networking for the current node
2088 # * make sure partitions are in place and prepared
2089 # * initialize devices with lctl
2090 # Levels is important, and needs to be enforced.
2091 def for_each_profile(db, prof_list, operation):
2092 for prof_uuid in prof_list:
2093 prof_db = db.lookup(prof_uuid)
2095 panic("profile:", prof_uuid, "not found.")
2096 services = getServices(prof_db)
2099 def doWriteconf(services):
2104 if s[1].get_class() == 'mdsdev':
2105 n = newService(s[1])
2109 panic("Cannot find mds device, please run --write_conf on the mds node.")
2112 def doSetup(services):
2116 n = newService(s[1])
2119 def doModules(services):
2123 n = newService(s[1])
2126 def doCleanup(services):
2131 n = newService(s[1])
2132 if n.safe_to_clean():
2135 def doUnloadModules(services):
2140 n = newService(s[1])
2141 if n.safe_to_clean_modules():
2144 def doMakeServiceScript(services):
2148 os.makedirs(config.service_scripts)
2150 if e[0] != errno.EEXIST:
2151 panic("Couldn't create scripts dir " + config.service_scripts + ": " + e[1])
2154 if s[1].get_class() != 'osd' and s[1].get_class() != 'mdsdev':
2157 target_uuid = s[1].get_first_ref('target')
2158 target = toplustreDB.lookup(target_uuid)
2159 target_symlink = config.service_scripts + "/" + target.getName()
2163 os.unlink(target_symlink)
2165 print "Removed " + target_symlink
2167 if e[0] != errno.EISDIR:
2169 os.rmdir(target_symlink)
2171 print "Removed " + target_symlink
2173 if e[0] != errno.ENOENT:
2174 panic("Error removing " + target_symlink + ": " + e[1])
2177 os.symlink("/etc/init.d/lustre", target_symlink)
2179 print "Created service link " + target_symlink + " to /etc/init.d/lustre"
2182 if e[0] == errno.EEXIST:
2183 extra_error = " (use --force option to remove existing files)"
2186 panic("Error creating " + target_symlink + ": " + e[1] + extra_error)
2188 # Check mtime of config logs
2189 def doCheckMtime(lustreDB, hosts):
2191 node_db = lustreDB.lookup_name(h, 'node')
2198 prof_list = node_db.get_refs('profile')
2199 for prof_uuid in prof_list:
2200 prof_db = node_db.lookup(prof_uuid)
2202 services = getServices(prof_db)
2204 if s[1].get_class() == 'mdsdev':
2208 if mdsdb and lustreDB.get_mtime():
2209 debug("Checking XML modification time")
2210 devpath = mdsdb.get_val('devpath','')
2211 xmtime = string.atol(lustreDB.get_mtime())
2212 cmd = "debugfs -c -R 'stat /LOGS' %s 2>&1 | grep mtime" %devpath
2213 ret, kmtimes = runcmd(cmd)
2215 log("Can not get mtime info of MDS LOGS directory")
2217 kmtime = string.atoi(string.split(kmtimes[0])[1], 0)
2219 debug('xmtime ', xmtime, '> kmtime', kmtime)
2221 log("Warning: MDS startup logs are older than config %s."
2222 " Please run --write_conf on stopped MDS to update."
2225 panic("Error: MDS startup logs are older than config %s."
2226 " Please run --write_conf on stopped MDS to update."
2227 " Use '--old_conf' to start anyways." %CONFIG_FILE)
2232 def doHost(lustreDB, hosts):
2233 global local_node_name, tgt_select
2236 node_db = lustreDB.lookup_name(h, 'node')
2239 tgt_select[config.service] = h
2240 config.group = config.service
2243 panic('No host entry found.')
2245 local_node_name = node_db.get_val('name', 0)
2246 lustre_upcall = node_db.get_val('lustreUpcall', '')
2247 portals_upcall = node_db.get_val('portalsUpcall', '')
2248 timeout = node_db.get_val_int('timeout', 0)
2249 ptldebug = node_db.get_val('ptldebug', '')
2250 subsystem = node_db.get_val('subsystem', '')
2252 # Two step process: (1) load modules, (2) setup lustre
2253 # if not cleaning, load modules first.
2254 prof_list = node_db.get_refs('profile')
2256 if config.make_service_scripts:
2257 for_each_profile(node_db, prof_list, doMakeServiceScript)
2260 elif config.write_conf:
2261 for_each_profile(node_db, prof_list, doModules)
2262 for_each_profile(node_db, prof_list, doWriteconf)
2263 for_each_profile(node_db, prof_list, doUnloadModules)
2266 elif config.recover:
2267 if not (config.tgt_uuid and config.client_uuid and config.conn_uuid):
2268 raise Lustre.LconfError( "--recovery requires --tgt_uuid <UUID> " +
2269 "--client_uuid <UUID> --conn_uuid <UUID>")
2270 doRecovery(lustreDB, lctl, config.tgt_uuid, config.client_uuid,
2272 elif config.cleanup:
2273 if not mod_loaded('lnet'):
2276 # ugly hack, only need to run lctl commands for --dump
2277 if config.lctl_dump or config.record:
2278 for_each_profile(node_db, prof_list, doCleanup)
2281 sys_set_ptldebug(ptldebug)
2282 sys_set_subsystem(subsystem)
2283 sys_set_lustre_upcall(lustre_upcall)
2284 sys_set_portals_upcall(portals_upcall)
2286 for_each_profile(node_db, prof_list, doCleanup)
2287 for_each_profile(node_db, prof_list, doUnloadModules)
2291 # ugly hack, only need to run lctl commands for --dump
2292 if config.lctl_dump or config.record:
2293 sys_set_timeout(timeout)
2294 sys_set_lustre_upcall(lustre_upcall)
2295 for_each_profile(node_db, prof_list, doSetup)
2298 if PLATFORM == 'LINUX':
2299 sys_set_netmem_max('/proc/sys/net/core/rmem_max', MAXTCPBUF)
2300 sys_set_netmem_max('/proc/sys/net/core/wmem_max', MAXTCPBUF)
2302 for_each_profile(node_db, prof_list, doModules)
2304 if PLATFORM == 'LINUX':
2305 # XXX need to be fixed for Darwin
2306 sys_set_debug_path()
2307 sys_set_ptldebug(ptldebug)
2308 sys_set_subsystem(subsystem)
2309 script = config.gdb_script
2310 run(lctl.lctl, ' modules >', script)
2312 log ("The GDB module script is in", script)
2313 # pause, so user has time to break and
2316 sys_set_timeout(timeout)
2317 sys_set_lustre_upcall(lustre_upcall)
2318 sys_set_portals_upcall(portals_upcall)
2320 for_each_profile(node_db, prof_list, doSetup)
2323 def add_clumanager_node(node_db, nodes, services):
2325 node_name = node_db.getUUID()
2326 nodes[node_name] = []
2328 for prof_uuid in node_db.get_refs('profile'):
2329 prof_db = toplustreDB.lookup(prof_uuid)
2330 for ref_class, ref_uuid in prof_db.get_all_refs():
2331 if ref_class not in ('osd', 'mdsdev'):
2333 devdb = toplustreDB.lookup(ref_uuid)
2334 tgt_uuid = devdb.get_first_ref('target')
2336 nodes[node_name].append(ref_uuid)
2338 if not services.has_key(tgt_uuid):
2340 print "New service: " + tgt_uuid + " (originally found on " + node_name + ")"
2341 new_services.append(tgt_uuid)
2342 services[tgt_uuid] = []
2343 services[tgt_uuid].append(ref_uuid)
2347 def add_clumanager_services(new_services, nodes, dev_list):
2349 for devdb in dev_list:
2350 tgt_uuid = devdb.get_first_ref('target')
2351 if tgt_uuid in new_services:
2352 node_uuid = devdb.get_first_ref('node')
2354 if not (nodes.has_key(node_uuid) or node_uuid in new_nodes):
2356 print "New node: " + node_uuid + " for service " + tgt_uuid
2357 new_nodes.append(node_uuid)
2361 def doClumanager(lustreDB, hosts):
2367 for dev_uuid in toplustreDB.get_refs('osd') + toplustreDB.get_refs('mdsdev'):
2368 dev_list.append(lustreDB.lookup(dev_uuid))
2372 node_db = lustreDB.lookup_name(h, 'node')
2375 new_services = add_clumanager_node(node_db, nodes, services)
2379 panic('No host entry found.')
2382 if len(new_services) == 0:
2385 new_nodes = add_clumanager_services(new_services, nodes, dev_list)
2386 if len(new_nodes) == 0:
2389 if len(new_nodes) + len(nodes.keys()) > 8:
2390 panic("CluManager only supports 8 nodes per failover \"cluster.\"")
2393 for node_uuid in new_nodes:
2394 node_db = lustreDB.lookup(node_uuid)
2396 panic("No node entry for " + node_uuid + " was found.")
2398 new_services.append(add_clumanager_node(node_db, nodes, services))
2401 for node in nodes.keys():
2402 nodedb = lustreDB.lookup(node)
2403 nodenames.append(nodedb.getName())
2406 print """<?xml version="1.0"?>
2407 <cluconfig version="3.0">
2408 <clumembd broadcast="no" interval="750000" loglevel="5" multicast="yes" multicast_ipaddress="225.0.0.11" thread="yes" tko_count="20"/>
2409 <cluquorumd loglevel="5" pinginterval="2"/>
2410 <clurmtabd loglevel="5" pollinterval="4"/>
2411 <clusvcmgrd loglevel="5"/>
2412 <clulockd loglevel="5"/>
2413 <cluster config_viewnumber="1" name="%s"/>
2414 <sharedstate driver="libsharedraw.so" rawprimary="%s" rawshadow="%s" type="raw"/>
2415 <members> """ % (string.join(nodenames), config.rawprimary, config.rawsecondary)
2419 for node in nodenames:
2420 print " <member id=\"%d\" name=\"%s\" watchdog=\"yes\"/>" % (i, node)
2423 print " </members>\n <failoverdomains>"
2425 servicekeys = services.keys()
2429 for service in servicekeys:
2430 svcdb = lustreDB.lookup(service)
2431 print " <failoverdomain id=\"%d\" name=\"%s\" ordered=\"yes\" restricted=\"yes\">" % (i, svcdb.getName())
2435 active_uuid = get_active_target(svcdb)
2436 for svc_uuid in [active_uuid] + services[service]:
2437 if svc_uuid == active_uuid and j > 0:
2439 svcdb = lustreDB.lookup(svc_uuid)
2441 svc_node_uuid = svcdb.get_first_ref('node')
2442 svc_nodedb = lustreDB.lookup(svc_node_uuid)
2444 print " <failoverdomainnode id=\"%d\" name=\"%s\"/>" % (j, svc_nodedb.getName())
2447 print " </failoverdomain>"
2449 print " </failoverdomains>\n <services>"
2452 for service in servicekeys:
2453 svcdb = lustreDB.lookup(service)
2454 active_uuid = get_active_target(svcdb)
2455 activedb = lustreDB.lookup(active_uuid)
2457 svc_node_uuid = activedb.get_first_ref('node')
2458 svc_nodedb = lustreDB.lookup(svc_node_uuid)
2460 print " <service checkinterval=\"30\" failoverdomain=\"%s\" id=\"%d\" name=\"%s\" userscript=\"%s/%s\">" \
2461 % ( svcdb.getName(), i, svcdb.getName(), config.service_scripts, svcdb.getName())
2462 print " <service_ipaddresses/>\n </service>"
2465 print " </services>\n</cluconfig>"
2467 def doRecovery(lustreDB, lctl, tgt_uuid, client_uuid, nid_uuid):
2468 tgt = lustreDB.lookup(tgt_uuid)
2470 raise Lustre.LconfError("doRecovery: "+ tgt_uuid +" not found.")
2471 new_uuid = get_active_target(tgt)
2473 raise Lustre.LconfError("doRecovery: no active target found for: " +
2475 srv_list = find_local_servers(get_ost_net(lustreDB, new_uuid))
2477 raise Lustre.LconfError("Unable to find a connection to:" + new_uuid)
2479 oldsrv = get_server_by_nid_uuid(lustreDB, nid_uuid)
2482 for srv in srv_list:
2483 if oldsrv.net_type != srv.net_type:
2486 log("Reconnecting", tgt_uuid, "to", srv.nid_uuid)
2488 lctl.recover(client_uuid, srv.nid_uuid)
2491 def setupModulePath(cmd, portals_dir = PORTALS_DIR):
2492 base = os.path.dirname(cmd)
2493 if development_mode():
2494 if not config.lustre:
2495 debug('using objdir module paths')
2496 config.lustre = (os.path.join(base, ".."))
2497 # normalize the portals dir, using command line arg if set
2499 portals_dir = config.portals
2500 dir = os.path.join(config.lustre, portals_dir)
2501 config.portals = dir
2502 debug('config.portals', config.portals)
2503 elif config.lustre and config.portals:
2505 # if --lustre and --portals, normalize portals
2506 # can ignore POTRALS_DIR here, since it is probly useless here
2507 config.portals = os.path.join(config.lustre, config.portals)
2508 debug('config.portals B', config.portals)
2510 def sysctl(path, val):
2511 debug("+ sysctl", path, val)
2515 fp = open(os.path.join('/proc/sys', path), 'w')
2522 def sys_set_debug_path():
2523 sysctl('lnet/debug_path', config.debug_path)
2525 def validate_upcall(upcall):
2527 if upcall in ('DEFAULT','NONE'):
2529 elif os.path.exists(upcall):
2530 if not os.access(upcall, os.X_OK):
2531 print "WARNING upcall script not executable: %s" % upcall
2533 print "WARNING invalid upcall script specified: %s" % upcall
2535 def sys_set_lustre_upcall(upcall):
2536 # the command line overrides the value in the node config
2537 if config.lustre_upcall:
2538 upcall = config.lustre_upcall
2540 upcall = config.upcall
2542 validate_upcall(upcall)
2543 lctl.set_lustre_upcall(upcall)
2545 def sys_set_portals_upcall(upcall):
2546 # the command line overrides the value in the node config
2547 if config.portals_upcall:
2548 upcall = config.portals_upcall
2550 upcall = config.upcall
2552 validate_upcall(upcall)
2553 sysctl('lnet/upcall', upcall)
2555 def sys_set_group_upcall(mds, upcall):
2558 # the command line overrides the value in the MDS config
2559 if config.group_upcall:
2560 upcall = config.group_upcall
2562 validate_upcall(upcall)
2563 debug("setting MDS", mds, "upcall to:", upcall)
2564 path = "/proc/fs/lustre/mds/" + mds + "/group_upcall"
2565 fp = open(path, 'w')
2569 def sys_set_timeout(timeout):
2570 # the command overrides the value in the node config
2571 if config.timeout and config.timeout > 0:
2572 timeout = config.timeout
2573 if timeout != None and timeout > 0:
2574 lctl.set_timeout(timeout)
2576 def sys_tweak_socknal ():
2577 if config.single_socket:
2578 sysctl("socknal/typed", 0)
2580 def sys_optimize_elan ():
2581 procfiles = ["/proc/elan/config/eventint_punt_loops",
2582 "/proc/qsnet/elan3/config/eventint_punt_loops",
2583 "/proc/qsnet/elan4/config/elan4_mainint_punt_loops"]
2585 if os.access(p, os.W_OK):
2586 run ("echo 1 > " + p)
2588 def sys_set_ptldebug(ptldebug):
2590 ptldebug = config.ptldebug
2593 val = eval(ptldebug, ptldebug_names)
2594 val = "0x%x" % (val)
2595 sysctl('lnet/debug', val)
2596 except NameError, e:
2599 def sys_set_subsystem(subsystem):
2600 if config.subsystem:
2601 subsystem = config.subsystem
2604 val = eval(subsystem, subsystem_names)
2605 val = "0x%x" % (val)
2606 sysctl('lnet/subsystem_debug', val)
2607 except NameError, e:
2610 def sys_set_netmem_max(path, max):
2611 debug("setting", path, "to at least", max)
2619 fp = open(path, 'w')
2620 fp.write('%d\n' %(max))
2624 # Add dir to the global PATH, if not already there.
2625 def add_to_path(new_dir):
2626 syspath = string.split(os.environ['PATH'], ':')
2627 if new_dir in syspath:
2629 os.environ['PATH'] = os.environ['PATH'] + ':' + new_dir
2631 def default_debug_path():
2632 path = '/tmp/lustre-log'
2633 if os.path.isdir('/r'):
2638 def default_gdb_script():
2639 script = '/tmp/ogdb'
2640 if os.path.isdir('/r'):
2641 return '/r' + script
2645 DEFAULT_PATH = ('/sbin', '/usr/sbin', '/bin', '/usr/bin')
2646 # ensure basic elements are in the system path
2647 def sanitise_path():
2648 for dir in DEFAULT_PATH:
2651 # global hack for the --select handling
2653 def init_select(args):
2654 # args = [service=nodeA,service2=nodeB service3=nodeC]
2655 # --service <service> is analagous to:
2656 # --group <service> --select <service>=<node>
2657 # this is handled in doHost()
2660 list = string.split(arg, ',')
2662 srv, node = string.split(entry, '=')
2663 tgt_select[srv] = node
2665 def get_select(srv):
2666 if tgt_select.has_key(srv):
2667 return tgt_select[srv]
2671 FLAG = Lustre.Options.FLAG
2672 PARAM = Lustre.Options.PARAM
2673 INTPARAM = Lustre.Options.INTPARAM
2674 PARAMLIST = Lustre.Options.PARAMLIST
2676 ('verbose,v', "Print system commands as they are run"),
2677 ('ldapurl',"LDAP server URL, eg. ldap://localhost", PARAM),
2678 ('config', "Cluster config name used for LDAP query", PARAM),
2679 ('select', "service=nodeA,service2=nodeB ", PARAMLIST),
2680 ('service', "shorthand for --group <service> --select <service>=<node>", PARAM),
2681 ('node', "Load config for <nodename>", PARAM),
2682 ('cleanup,d', "Cleans up config. (Shutdown)"),
2683 ('force,f', "Forced unmounting and/or obd detach during cleanup",
2685 ('single_socket', "socknal option: only use one socket instead of bundle",
2687 ('failover',"""Used to shut down without saving state.
2688 This will allow this node to "give up" a service to a
2689 another node for failover purposes. This will not
2690 be a clean shutdown.""",
2692 ('abort_recovery',"""Used to start a service when you know recovery
2693 will not succeed. This will skip the recovery
2694 timeout period."""),
2695 ('gdb', """Prints message after creating gdb module script
2696 and sleeps for 5 seconds."""),
2697 ('noexec,n', """Prints the commands and steps that will be run for a
2698 config without executing them. This can used to check if a
2699 config file is doing what it should be doing"""),
2700 ('nomod', "Skip load/unload module step."),
2701 ('nosetup', "Skip device setup/cleanup step."),
2702 ('reformat', "Reformat all devices (without question)"),
2703 ('mkfsoptions', "Additional options for the mk*fs command line", PARAM),
2704 ('mountfsoptions', "Additional options for mount fs command line", PARAM),
2705 ('clientoptions', "Additional options for Lustre", PARAM),
2706 ('dump', "Dump the kernel debug log to file before portals is unloaded",
2708 ('write_conf', "Save all the client config information on mds."),
2709 ('old_conf', "Start up service even though config logs appear outdated."),
2710 ('record', "Write config information on mds."),
2711 ('record_log', "Name of config record log.", PARAM),
2712 ('record_device', "MDS device name that will record the config commands",
2714 ('minlevel', "Minimum level of services to configure/cleanup",
2716 ('maxlevel', """Maximum level of services to configure/cleanup
2717 Levels are aproximatly like:
2722 70 - mountpoint, echo_client, osc, mdc, lov""",
2724 ('lustre', """Base directory of lustre sources. This parameter will
2725 cause lconf to load modules from a source tree.""", PARAM),
2726 ('portals', """Portals source directory. If this is a relative path,
2727 then it is assumed to be relative to lustre. """, PARAM),
2728 ('timeout', "Set recovery timeout", INTPARAM),
2729 ('upcall', "Set both portals and lustre upcall script", PARAM),
2730 ('lustre_upcall', "Set lustre upcall script", PARAM),
2731 ('portals_upcall', "Set portals upcall script", PARAM),
2732 ('group_upcall', "Set supplementary group upcall program", PARAM),
2733 ('lctl_dump', "Save lctl ioctls to the dumpfile argument", PARAM),
2734 ('ptldebug', "Set the portals debug level", PARAM),
2735 ('subsystem', "Set the portals debug subsystem", PARAM),
2736 ('gdb_script', "Fullname of gdb debug script", PARAM, default_gdb_script()),
2737 ('debug_path', "Path to save debug dumps", PARAM, default_debug_path()),
2738 ('allow_unprivileged_port', "Allow connections from unprivileged ports"),
2739 ('clumanager', "Generate CluManager config file for this node's cluster"),
2740 ('rawprimary', "For clumanager, device of the primary quorum", PARAM, "/dev/raw/raw1"),
2741 ('rawsecondary', "For clumanager, device of the secondary quorum", PARAM, "/dev/raw/raw2"),
2742 ('service_scripts', "For clumanager, directory containing per-service scripts", PARAM, "/etc/lustre/services"),
2743 ('make_service_scripts', "Create per-service symlinks for use with clumanager"),
2744 # Client recovery options
2745 ('recover', "Recover a device"),
2746 ('group,g', "The group of devices to configure or cleanup", PARAM),
2747 ('tgt_uuid', "The failed target (required for recovery)", PARAM),
2748 ('client_uuid', "The failed client (required for recovery)", PARAM),
2749 ('conn_uuid', "The failed connection (required for recovery)", PARAM),
2751 ('inactive', """The name of an inactive service, to be ignored during
2752 mounting (currently OST-only). Can be repeated.""",
2754 ('user_xattr', """Enable user_xattr support on MDS""", FLAG, 0),
2755 ('acl', """Enable ACL support on MDS""", FLAG, 0),
2756 ('quota', "Enable quota support for client file system", PARAM),
2760 global lctl, config, toplustreDB, CONFIG_FILE
2762 # in the upcall this is set to SIG_IGN
2763 signal.signal(signal.SIGCHLD, signal.SIG_DFL)
2765 cl = Lustre.Options("lconf", "config.xml", lconf_options)
2767 config, args = cl.parse(sys.argv[1:])
2768 except Lustre.OptionError, e:
2772 setupModulePath(sys.argv[0])
2774 host = socket.gethostname()
2776 # the PRNG is normally seeded with time(), which is not so good for starting
2777 # time-synchronized clusters
2778 input = open('/dev/urandom', 'r')
2780 print 'Unable to open /dev/urandom!'
2782 seed = input.read(32)
2788 init_select(config.select)
2791 # allow config to be fetched via HTTP, but only with python2
2792 if sys.version[0] != '1' and args[0].startswith('http://'):
2795 config_file = urllib2.urlopen(args[0])
2796 except (urllib2.URLError, socket.error), err:
2797 if hasattr(err, 'args'):
2799 print "Could not access '%s': %s" %(args[0], err)
2801 elif not os.access(args[0], os.R_OK):
2802 print 'File not found or readable:', args[0]
2806 config_file = open(args[0], 'r')
2808 dom = xml.dom.minidom.parse(config_file)
2810 panic("%s does not appear to be a config file." % (args[0]))
2811 sys.exit(1) # make sure to die here, even in debug mode.
2813 CONFIG_FILE = args[0]
2814 lustreDB = Lustre.LustreDB_XML(dom.documentElement, dom.documentElement)
2815 if not config.config:
2816 config.config = os.path.basename(args[0])# use full path?
2817 if config.config[-4:] == '.xml':
2818 config.config = config.config[:-4]
2819 elif config.ldapurl:
2820 if not config.config:
2821 panic("--ldapurl requires --config name")
2822 dn = "config=%s,fs=lustre" % (config.config)
2823 lustreDB = Lustre.LustreDB_LDAP('', {}, base=dn, url = config.ldapurl)
2824 elif config.ptldebug or config.subsystem:
2825 sys_set_ptldebug(None)
2826 sys_set_subsystem(None)
2829 print 'Missing config file or ldap URL.'
2830 print 'see lconf --help for command summary'
2833 if config.reformat and config.cleanup:
2834 panic("Options \"reformat\" and \"cleanup\" are incompatible. "+
2835 "Please specify only one.")
2837 toplustreDB = lustreDB
2839 ver = lustreDB.get_version()
2841 panic("No version found in config data, please recreate.")
2842 if ver != Lustre.CONFIG_VERSION:
2843 panic("Config version", ver, "does not match lconf version",
2844 Lustre.CONFIG_VERSION)
2848 node_list.append(config.node)
2851 node_list.append(host)
2852 # node_list.append('localhost')
2854 debug("configuring for host: ", node_list)
2857 config.debug_path = config.debug_path + '-' + host
2858 config.gdb_script = config.gdb_script + '-' + host
2860 lctl = LCTLInterface('lctl')
2862 if config.lctl_dump:
2863 lctl.use_save_file(config.lctl_dump)
2865 if not (config.reformat or config.write_conf or config.cleanup):
2866 doCheckMtime(lustreDB, node_list)
2869 if not (config.record_device and config.record_log):
2870 panic("When recording, both --record_log and --record_device must be specified.")
2871 lctl.clear_log(config.record_device, config.record_log)
2872 lctl.record(config.record_device, config.record_log)
2874 if config.clumanager:
2875 doClumanager(lustreDB, node_list)
2877 doHost(lustreDB, node_list)
2882 if __name__ == "__main__":
2885 except Lustre.LconfError, e:
2887 # traceback.print_exc(file=sys.stdout)
2889 except CommandError, e:
2896 if first_cleanup_error:
2897 sys.exit(first_cleanup_error)