Commit b4478d34 authored by Michael Hanselmann's avatar Michael Hanselmann
Browse files

Support passing in file object in utils.FileLock

This way we can re-use file objects opened in other places. Also add more
Signed-off-by: default avatarMichael Hanselmann <>
Reviewed-by: default avatarGuido Trotter <>
Reviewed-by: default avatarIustin Pop <>
parent cc4c9b91
......@@ -88,7 +88,7 @@ def InitAndVerifyQueue(must_lock):
# Lock queue
queue_lock = utils.FileLock(constants.JOB_QUEUE_LOCK_FILE)
queue_lock = utils.FileLock.Open(constants.JOB_QUEUE_LOCK_FILE)
# The queue needs to be locked in exclusive mode to write to the serial and
# version files.
......@@ -307,7 +307,7 @@ class SimpleStore(object):
@param values: Dictionary of (name, value)
ssconf_lock = utils.FileLock(constants.SSCONF_LOCK_FILE)
ssconf_lock = utils.FileLock.Open(constants.SSCONF_LOCK_FILE)
# Get lock while writing files
ssconf_lock.Exclusive(blocking=True, timeout=SSCONF_LOCK_TIMEOUT)
......@@ -2446,17 +2446,31 @@ class FileLock(object):
"""Utility class for file locks.
def __init__(self, filename):
def __init__(self, fd, filename):
"""Constructor for FileLock.
This will open the file denoted by the I{filename} argument.
@type fd: file
@param fd: File object
@type filename: str
@param filename: path to the file to be locked
@param filename: Path of the file opened at I{fd}
self.fd = fd
self.filename = filename
self.fd = open(self.filename, "w")
def Open(cls, filename):
"""Creates and opens a file to be used as a file-based lock.
@type filename: string
@param filename: path to the file to be locked
# Using "" is necessary to allow both opening existing file
# read/write and creating if not existing. Vanilla "open" will truncate an
# existing file -or- allow creating if not existing.
return cls(os.fdopen(, os.O_RDWR | os.O_CREAT), "w+"),
def __del__(self):
......@@ -992,13 +992,9 @@ class TestTailFile(testutils.GanetiTestCase):
self.failUnlessEqual(TailFile(fname, lines=i), data[-i:])
class TestFileLock(unittest.TestCase):
class _BaseFileLockTest:
"""Test case for the FileLock class"""
def setUp(self):
self.tmpfile = tempfile.NamedTemporaryFile()
self.lock = utils.FileLock(
def testSharedNonblocking(self):
......@@ -1035,6 +1031,45 @@ class TestFileLock(unittest.TestCase):
def testSimpleTimeout(self):
# These will succeed on the first attempt, hence a short timeout
self.lock.Shared(blocking=True, timeout=10.0)
self.lock.Exclusive(blocking=False, timeout=10.0)
self.lock.Unlock(blocking=True, timeout=10.0)
def _TryLockInner(filename, shared, blocking):
lock = utils.FileLock.Open(filename)
if shared:
fn = lock.Shared
fn = lock.Exclusive
# The timeout doesn't really matter as the parent process waits for us to
# finish anyway.
fn(blocking=blocking, timeout=0.01)
except errors.LockError, err:
return False
return True
def _TryLock(self, *args):
return utils.RunInSeparateProcess(self._TryLockInner,,
def testTimeout(self):
for blocking in [True, False]:
self.failIf(self._TryLock(False, blocking))
self.failIf(self._TryLock(True, blocking))
self.assert_(self._TryLock(True, blocking))
self.failIf(self._TryLock(False, blocking))
def testCloseShared(self):
self.assertRaises(AssertionError, self.lock.Shared, blocking=False)
......@@ -1048,6 +1083,31 @@ class TestFileLock(unittest.TestCase):
self.assertRaises(AssertionError, self.lock.Unlock, blocking=False)
class TestFileLockWithFilename(testutils.GanetiTestCase, _BaseFileLockTest):
TESTDATA = "Hello World\n" * 10
def setUp(self):
self.tmpfile = tempfile.NamedTemporaryFile()
utils.WriteFile(, data=self.TESTDATA)
self.lock = utils.FileLock.Open(
# Ensure "Open" didn't truncate file
self.assertFileContent(, self.TESTDATA)
def tearDown(self):
self.assertFileContent(, self.TESTDATA)
class TestFileLockWithFileObject(unittest.TestCase, _BaseFileLockTest):
def setUp(self):
self.tmpfile = tempfile.NamedTemporaryFile()
self.lock = utils.FileLock(open(, "w"),
class TestTimeFunctions(unittest.TestCase):
"""Test case for time functions"""
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment