From d9f311d78e983c98343954c85e7415115fb22885 Mon Sep 17 00:00:00 2001 From: Iustin Pop <iustin@google.com> Date: Tue, 29 Jul 2008 08:49:34 +0000 Subject: [PATCH] Change IsPidFileAlive into ReadPidFile We already have a function to test if a PID is alive, so it makes more sense to use function composition that force calling (since we need to read PIDs from files in other places too). Now IsProcessAlive returns False for PIDs <= 0, since this is the error return from ReadPidFile. The patch also adds a unittest for checking that WriteFile raises the correct exception, and checks that an invalid or missing file causes ReadPidFile to return zero. The unittest tearDown method will try to cleanup the temp directory too (otherwise it leaves stuff after it). Reviewed-by: ultrotter --- lib/utils.py | 37 ++++++++++++++++++++--------------- test/ganeti.utils_unittest.py | 30 +++++++++++++++++++++++----- 2 files changed, 46 insertions(+), 21 deletions(-) diff --git a/lib/utils.py b/lib/utils.py index a9cdfc0b8..a9b71b5fb 100644 --- a/lib/utils.py +++ b/lib/utils.py @@ -268,9 +268,13 @@ def IsProcessAlive(pid): Returns: true or false, depending on if the pid exists or not - Remarks: zombie processes treated as not alive + Remarks: zombie processes treated as not alive, and giving a pid <= + 0 makes the function to return False. """ + if pid <= 0: + return False + try: f = open("/proc/%d/status" % pid) except IOError, err: @@ -290,29 +294,30 @@ def IsProcessAlive(pid): return alive -def IsPidFileAlive(pidfile): - """Check whether the given pidfile points to a live process. +def ReadPidFile(pidfile): + """Read the pid from a file. - @param pidfile: Path to a file containing the pid to be checked - @type pidfile: string (filename) + @param pidfile: Path to a file containing the pid to be checked + @type pidfile: string (filename) + @return: The process id, if the file exista and contains a valid PID, + otherwise 0 + @rtype: int """ try: pf = open(pidfile, 'r') - except EnvironmentError, open_err: - if open_err.errno == errno.ENOENT: - return False - else: - raise errors.GenericError("Cannot open file %s. Error: %s" % - (pidfile, str(open_err))) + except EnvironmentError, err: + if err.errno != errno.ENOENT: + logging.exception("Can't read pid file?!") + return 0 try: pid = int(pf.read()) - except ValueError: - raise errors.GenericError("Invalid pid string in %s" % - (pidfile,)) + except ValueError, err: + logging.info("Can't parse pid file contents", exc_info=err) + return 0 - return IsProcessAlive(pid) + return pid def MatchNameComponent(key, name_list): @@ -1066,7 +1071,7 @@ def WritePidFile(name): """ pid = os.getpid() pidfilename = _DaemonPidFileName(name) - if IsPidFileAlive(pidfilename): + if IsProcessAlive(ReadPidFile(pidfilename)): raise errors.GenericError("%s contains a live process" % pidfilename) WriteFile(pidfilename, data="%d\n" % pid) diff --git a/test/ganeti.utils_unittest.py b/test/ganeti.utils_unittest.py index 7a9c64f5c..23a8b6b75 100755 --- a/test/ganeti.utils_unittest.py +++ b/test/ganeti.utils_unittest.py @@ -43,12 +43,13 @@ from ganeti.utils import IsProcessAlive, RunCmd, \ ParseUnit, AddAuthorizedKey, RemoveAuthorizedKey, \ ShellQuote, ShellQuoteArgs, TcpPing, ListVisibleFiles, \ SetEtcHostsEntry, RemoveEtcHostsEntry, FirstFree -from ganeti.errors import LockError, UnitParseError +from ganeti.errors import LockError, UnitParseError, GenericError def _ChildHandler(signal, stack): global _ChildFlag _ChildFlag = True + class TestIsProcessAlive(unittest.TestCase): """Testing case for IsProcessAlive""" @@ -99,8 +100,9 @@ class TestIsProcessAlive(unittest.TestCase): self.assert_(not IsProcessAlive(self.pid_non_existing), "noexisting process detected") + class TestPidFileFunctions(unittest.TestCase): - """Tests for WritePidFile, RemovePidFile and IsPidFileAlive""" + """Tests for WritePidFile, RemovePidFile and ReadPidFile""" def setUp(self): self.dir = tempfile.mkdtemp() @@ -108,13 +110,31 @@ class TestPidFileFunctions(unittest.TestCase): utils._DaemonPidFileName = self.f_dpn def testPidFileFunctions(self): + pid_file = self.f_dpn('test') utils.WritePidFile('test') - self.assert_(os.path.exists(self.f_dpn('test'))) - self.assert_(utils.IsPidFileAlive(self.f_dpn('test'))) + self.failUnless(os.path.exists(pid_file), + "PID file should have been created") + read_pid = utils.ReadPidFile(pid_file) + self.failUnlessEqual(read_pid, os.getpid()) + self.failUnless(utils.IsProcessAlive(read_pid)) + self.failUnlessRaises(GenericError, utils.WritePidFile, 'test') + utils.RemovePidFile('test') + self.failIf(os.path.exists(pid_file), + "PID file should not exist anymore") + self.failUnlessEqual(utils.ReadPidFile(pid_file), 0, + "ReadPidFile should return 0 for missing pid file") + fh = open(pid_file, "w") + fh.write("blah\n") + fh.close() + self.failUnlessEqual(utils.ReadPidFile(pid_file), 0, + "ReadPidFile should return 0 for invalid pid file") utils.RemovePidFile('test') - self.assert_(not os.path.exists(self.f_dpn('test'))) + self.failIf(os.path.exists(pid_file), + "PID file should not exist anymore") def tearDown(self): + for name in os.listdir(self.dir): + os.unlink(os.path.join(self.dir, name)) os.rmdir(self.dir) -- GitLab