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