From f65f63ef8d43adbec08450e4ca7e77e7ba0629f5 Mon Sep 17 00:00:00 2001 From: Iustin Pop <iustin@google.com> Date: Tue, 20 Jan 2009 11:18:20 +0000 Subject: [PATCH] Add a TailFile function This patch adds a tail file function, to be used for parsing and returning in the job log OS installation failures. Reviewed-by: ultrotter --- lib/utils.py | 26 ++++++++++++++++++++ test/ganeti.utils_unittest.py | 46 ++++++++++++++++++++++++++++++++++- 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/lib/utils.py b/lib/utils.py index 6a6679c3f..8a4087a42 100644 --- a/lib/utils.py +++ b/lib/utils.py @@ -1713,6 +1713,32 @@ def SetupLogging(logfile, debug=False, stderr_logging=False, program=""): raise +def TailFile(fname, lines=20): + """Return the last lines from a file. + + @note: this function will only read and parse the last 4KB of + the file; if the lines are very long, it could be that less + than the requested number of lines are returned + + @param fname: the file name + @type lines: int + @param lines: the (maximum) number of lines to return + + """ + fd = open(fname, "r") + try: + fd.seek(0, 2) + pos = fd.tell() + pos = max(0, pos-4096) + fd.seek(pos, 0) + raw_data = fd.read() + finally: + fd.close() + + rows = raw_data.splitlines() + return rows[-lines:] + + def LockedMethod(fn): """Synchronized object access decorator. diff --git a/test/ganeti.utils_unittest.py b/test/ganeti.utils_unittest.py index 133d68765..423f5fa0b 100755 --- a/test/ganeti.utils_unittest.py +++ b/test/ganeti.utils_unittest.py @@ -42,7 +42,9 @@ from ganeti.utils import IsProcessAlive, RunCmd, \ RemoveFile, CheckDict, MatchNameComponent, FormatUnit, \ ParseUnit, AddAuthorizedKey, RemoveAuthorizedKey, \ ShellQuote, ShellQuoteArgs, TcpPing, ListVisibleFiles, \ - SetEtcHostsEntry, RemoveEtcHostsEntry, FirstFree, OwnIpAddress + SetEtcHostsEntry, RemoveEtcHostsEntry, FirstFree, OwnIpAddress, \ + TailFile + from ganeti.errors import LockError, UnitParseError, GenericError, \ ProgrammerError @@ -772,6 +774,48 @@ class TestFirstFree(unittest.TestCase): self.failUnlessRaises(AssertionError, FirstFree, [0, 3, 4, 6], base=3) +class TestTailFile(testutils.GanetiTestCase): + """Test case for the TailFile function""" + + def testEmpty(self): + fname = self._CreateTempFile() + self.failUnlessEqual(TailFile(fname), []) + self.failUnlessEqual(TailFile(fname, lines=25), []) + + def testAllLines(self): + data = ["test %d" % i for i in range(30)] + for i in range(30): + fname = self._CreateTempFile() + fd = open(fname, "w") + fd.write("\n".join(data[:i])) + if i > 0: + fd.write("\n") + fd.close() + self.failUnlessEqual(TailFile(fname, lines=i), data[:i]) + + def testPartialLines(self): + data = ["test %d" % i for i in range(30)] + fname = self._CreateTempFile() + fd = open(fname, "w") + fd.write("\n".join(data)) + fd.write("\n") + fd.close() + for i in range(1, 30): + self.failUnlessEqual(TailFile(fname, lines=i), data[-i:]) + + def testBigFile(self): + data = ["test %d" % i for i in range(30)] + fname = self._CreateTempFile() + fd = open(fname, "w") + fd.write("X" * 1048576) + fd.write("\n") + fd.write("\n".join(data)) + fd.write("\n") + fd.close() + for i in range(1, 30): + self.failUnlessEqual(TailFile(fname, lines=i), data[-i:]) + + class TestFileLock(unittest.TestCase): """Test case for the FileLock class""" -- GitLab