diff --git a/nfsometerlib/cmd.py b/nfsometerlib/cmd.py index 9b6dbdd..a2ebcef 100644 --- a/nfsometerlib/cmd.py +++ b/nfsometerlib/cmd.py @@ -25,7 +25,15 @@ class CmdError(Exception): pass class CmdErrorCode(CmdError): - pass + def __init__(self, cmd, code, errstr): + self.cmd = cmd + self.code = code + self.errstr = errstr + + def __str__(self): + return str.format( + 'command "{:s}" exited with non-zero status: {:d}{:s}', + self.cmd, self.code, self.errstr) class CmdErrorOut(CmdError): pass @@ -67,8 +75,7 @@ def cmd(args, raiseerrorcode=True, raiseerrorout=True, instr='', errstr = '\n%s' % errstr if raiseerrorcode and ret != 0: - raise CmdErrorCode('command "%s" exited with non-zero status: %u%s' % - (args, ret, errstr)) + raise CmdErrorCode(args, ret, errstr) if raiseerrorout and errstr: raise CmdErrorOut('command "%s" has output to stderr: %s' % diff --git a/nfsometerlib/trace.py b/nfsometerlib/trace.py index cd1d3c3..9ce396e 100644 --- a/nfsometerlib/trace.py +++ b/nfsometerlib/trace.py @@ -20,6 +20,7 @@ import multiprocessing import signal import random import atexit +import pwd from cmd import * from config import * @@ -382,7 +383,7 @@ def _save_start_stats(attrs): {'cmd': 'dmesg', 'file': 'dmesg.start' }, - {'cmd': 'sudo sysctl -a | grep nfs', + {'cmd': 'sudo sysctl -a 2>/dev/null | grep nfs', 'file': 'nfs_sysctls.start' }, {'cmd': 'cat /proc/self/mountstats', @@ -422,7 +423,7 @@ def _save_stop_stats(attrs): {'cmd': 'nfsiostat', 'file': 'nfsiostat' }, - {'cmd': 'sudo sysctl -a | grep nfs', + {'cmd': 'sudo sysctl -a 2>/dev/null | grep nfs', 'file': 'nfs_sysctls.stop' }, {'cmd': 'sudo klist -ke /etc/krb5.keytab 2> /dev/null || echo', @@ -517,6 +518,77 @@ def probe_detect(probe_trace_dir, mountopt): return detect +def _is_auth_gss(): + lines = [ x.strip() for x in file('/proc/self/mountstats') ] + mounted_on = ' mounted on %s with ' % MOUNTDIR + start = -1 + end = -1 + + for i, line in enumerate(lines): + if line.find(mounted_on) >= 0: + assert start == -1 + start = i + elif start >= 0 and line.startswith('device '): + assert end == -1 + end = i + + if end < 0: + end = len(lines) + + if start >= 0: + lines = lines[start:end] + else: + return False + + for line in lines: + if line.startswith('sec:'): + label, data = line.split(':') + data = data.strip() + if data.startswith('flavor=6'): + return True + return False + +def _has_creds(): + return os.stat(os.path.join(RUNNING_TRACE_DIR, + 'klist_user.start')).st_size != 1 + +def _has_tkt(server): + princ = re.compile('nfs/' + server + '\S+$') + lines = [ x.strip() for x in file(os.path.join(RUNNING_TRACE_DIR, + 'klist_user.start')) ] + for i, line in enumerate(lines): + if re.search(princ, line): + return True + return False + +def _eperm_helper(opts): + server, path = opts.serverpath.split(':') + if _is_auth_gss(): + if _has_creds(): + if _has_tkt(server): + info = str.format( + ' Check {:s} on {:s} and ensure user {:s} has the correct' + ' permission.', path, server, + pwd.getpwuid(os.getuid())[0]) + else: + info = str.format( + ' No nfs service ticket for {:s} in user {:s}\'s' + ' credential cache.', server, + pwd.getpwuid(os.getuid())[0]) + else: + info = str.format( + ' User {:s} has no kerberos credentials.', + pwd.getpwuid(os.getuid())[0]) + elif os.getuid() == 0: + info = str.format( + ' Check for root squashing in the export options for {:s} on' + ' {:s}.', path, server) + else: + info = str.format( + ' Check {:s} on {:s} and ensure user {:s} has the correct' + ' permission.', path, server, pwd.getpwuid(os.getuid())[0]) + return info + # # public api commands # @@ -746,7 +818,18 @@ def probe_mounts(opts): start(m, opts.serverpath, '__nfsometer-probe', [], [], is_probe=True) fpath = os.path.join(RUNROOT, '__nfsometer-probe') - cmd('mkdir -p "%s"' % RUNROOT) + try: + cmd('mkdir -p "%s"' % RUNROOT) + except CmdErrorCode, e: + msg = str.format('"mkdir -p {:s}" failed.', RUNROOT) + # try to hint why it failed + if e.code == errno.EPERM: + msg += _eperm_helper(opts) + else: + msg += e.errstr + warn(msg) + # and bail out right now + sys.exit(1) f = file(fpath, 'w+') f.write('nfsometer probe to determine server features: %s' % m)