From debed9aefaba1cc98bc05e908e2ee85f85eea304 Mon Sep 17 00:00:00 2001 From: Michael Hanselmann <hansmi@google.com> Date: Tue, 20 Apr 2010 18:18:06 +0200 Subject: [PATCH] utils: Add function to read locked PID file This is useful in combination with utils.StartDaemon and will be used for reading the import/export daemon's PID file. Signed-off-by: Michael Hanselmann <hansmi@google.com> Reviewed-by: Guido Trotter <ultrotter@google.com> --- lib/backend.py | 19 +----------------- lib/utils.py | 31 +++++++++++++++++++++++++++++ test/ganeti.utils_unittest.py | 37 +++++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 18 deletions(-) diff --git a/lib/backend.py b/lib/backend.py index beeca61c2..69ac800c9 100644 --- a/lib/backend.py +++ b/lib/backend.py @@ -2855,25 +2855,8 @@ def CleanupImportExport(name): logging.info("Finalizing import/export %s", name) status_dir = utils.PathJoin(constants.IMPORT_EXPORT_DIR, name) - pid_file = utils.PathJoin(status_dir, _IES_PID_FILE) - pid = None - try: - fd = os.open(pid_file, os.O_RDONLY) - except EnvironmentError, err: - if err.errno != errno.ENOENT: - raise - # PID file doesn't exist - else: - try: - try: - # Try to acquire lock - utils.LockFile(fd) - except errors.LockError: - # Couldn't lock, daemon is running - pid = int(os.read(fd, 100)) - finally: - os.close(fd) + pid = utils.ReadLockedPidFile(utils.PathJoin(status_dir, _IES_PID_FILE)) if pid: logging.info("Import/export %s is still running with PID %s", diff --git a/lib/utils.py b/lib/utils.py index 9076558a3..48b427ac3 100644 --- a/lib/utils.py +++ b/lib/utils.py @@ -840,6 +840,37 @@ def ReadPidFile(pidfile): return pid +def ReadLockedPidFile(path): + """Reads a locked PID file. + + This can be used together with L{StartDaemon}. + + @type path: string + @param path: Path to PID file + @return: PID as integer or, if file was unlocked or couldn't be opened, None + + """ + try: + fd = os.open(path, os.O_RDONLY) + except EnvironmentError, err: + if err.errno == errno.ENOENT: + # PID file doesn't exist + return None + raise + + try: + try: + # Try to acquire lock + LockFile(fd) + except errors.LockError: + # Couldn't lock, daemon is running + return int(os.read(fd, 100)) + finally: + os.close(fd) + + return None + + def MatchNameComponent(key, name_list, case_sensitive=True): """Try to match a name against a list. diff --git a/test/ganeti.utils_unittest.py b/test/ganeti.utils_unittest.py index 2d8a79417..7fc48a963 100755 --- a/test/ganeti.utils_unittest.py +++ b/test/ganeti.utils_unittest.py @@ -1840,5 +1840,42 @@ class TestLineSplitter(unittest.TestCase): "", "x"]) +class TestReadLockedPidFile(unittest.TestCase): + def setUp(self): + self.tmpdir = tempfile.mkdtemp() + + def tearDown(self): + shutil.rmtree(self.tmpdir) + + def testNonExistent(self): + path = utils.PathJoin(self.tmpdir, "nonexist") + self.assert_(utils.ReadLockedPidFile(path) is None) + + def testUnlocked(self): + path = utils.PathJoin(self.tmpdir, "pid") + utils.WriteFile(path, data="123") + self.assert_(utils.ReadLockedPidFile(path) is None) + + def testLocked(self): + path = utils.PathJoin(self.tmpdir, "pid") + utils.WriteFile(path, data="123") + + fl = utils.FileLock.Open(path) + try: + fl.Exclusive(blocking=True) + + self.assertEqual(utils.ReadLockedPidFile(path), 123) + finally: + fl.Close() + + self.assert_(utils.ReadLockedPidFile(path) is None) + + def testError(self): + path = utils.PathJoin(self.tmpdir, "foobar", "pid") + utils.WriteFile(utils.PathJoin(self.tmpdir, "foobar"), data="") + # open(2) should return ENOTDIR + self.assertRaises(EnvironmentError, utils.ReadLockedPidFile, path) + + if __name__ == '__main__': testutils.GanetiTestProgram() -- GitLab