Revision a87b4824

b/lib/utils.py
1192 1192
    raise
1193 1193

  
1194 1194

  
1195
class FileLock(object):
1196
  """Utility class for file locks.
1197

  
1198
  """
1199
  def __init__(self, filename):
1200
    self.filename = filename
1201
    self.fd = open(self.filename, "w")
1202

  
1203
  def __del__(self):
1204
    self.Close()
1205

  
1206
  def Close(self):
1207
    if self.fd:
1208
      self.fd.close()
1209
      self.fd = None
1210

  
1211
  def _flock(self, flag, blocking, errmsg):
1212
    assert self.fd, "Lock was closed"
1213

  
1214
    if not blocking:
1215
      flag |= fcntl.LOCK_NB
1216

  
1217
    try:
1218
      fcntl.flock(self.fd, flag)
1219
    except IOError, err:
1220
      logging.exception("fcntl.flock failed")
1221
      if err.errno in (errno.EAGAIN, ):
1222
        raise errors.LockError(errmsg)
1223
      raise
1224

  
1225
  def Exclusive(self, blocking=False):
1226
    """Locks the file in exclusive mode.
1227

  
1228
    """
1229
    self._flock(fcntl.LOCK_EX, blocking,
1230
                "Failed to lock %s in exclusive mode" % self.filename)
1231

  
1232
  def Shared(self, blocking=False):
1233
    """Locks the file in shared mode.
1234

  
1235
    """
1236
    self._flock(fcntl.LOCK_SH, blocking,
1237
                "Failed to lock %s in shared mode" % self.filename)
1238

  
1239
  def Unlock(self, blocking=True):
1240
    """Unlocks the file.
1241

  
1242
    According to "man flock", unlocking can also be a nonblocking operation:
1243
    "To make a non-blocking request, include LOCK_NB with any of the above
1244
    operations"
1245

  
1246
    """
1247
    self._flock(fcntl.LOCK_UN, blocking,
1248
                "Failed to unlock %s" % self.filename)
1249

  
1250

  
1195 1251
class SignalHandler(object):
1196 1252
  """Generic signal handler class.
1197 1253

  
b/test/ganeti.utils_unittest.py
32 32
import socket
33 33
import shutil
34 34
import re
35
import tempfile
36 35

  
37 36
import ganeti
38 37
import testutils
......
710 709
    self._test(["a", "b"], ["a", "b"])
711 710
    self._test(["a", "b", "a"], ["a", "b"])
712 711

  
712

  
713 713
class TestFirstFree(unittest.TestCase):
714 714
  """Test case for the FirstFree function"""
715 715

  
......
721 721
    self.failUnlessEqual(FirstFree([3, 4, 6], base=3), 5)
722 722
    self.failUnlessRaises(AssertionError, FirstFree, [0, 3, 4, 6], base=3)
723 723

  
724

  
725
class TestFileLock(unittest.TestCase):
726
  """Test case for the FileLock class"""
727

  
728
  def setUp(self):
729
    self.tmpfile = tempfile.NamedTemporaryFile()
730
    self.lock = utils.FileLock(self.tmpfile.name)
731

  
732
  def testSharedNonblocking(self):
733
    self.lock.Shared(blocking=False)
734
    self.lock.Close()
735

  
736
  def testExclusiveNonblocking(self):
737
    self.lock.Exclusive(blocking=False)
738
    self.lock.Close()
739

  
740
  def testUnlockNonblocking(self):
741
    self.lock.Unlock(blocking=False)
742
    self.lock.Close()
743

  
744
  def testSharedBlocking(self):
745
    self.lock.Shared(blocking=True)
746
    self.lock.Close()
747

  
748
  def testExclusiveBlocking(self):
749
    self.lock.Exclusive(blocking=True)
750
    self.lock.Close()
751

  
752
  def testUnlockBlocking(self):
753
    self.lock.Unlock(blocking=True)
754
    self.lock.Close()
755

  
756
  def testSharedExclusiveUnlock(self):
757
    self.lock.Shared(blocking=False)
758
    self.lock.Exclusive(blocking=False)
759
    self.lock.Unlock(blocking=False)
760
    self.lock.Close()
761

  
762
  def testExclusiveSharedUnlock(self):
763
    self.lock.Exclusive(blocking=False)
764
    self.lock.Shared(blocking=False)
765
    self.lock.Unlock(blocking=False)
766
    self.lock.Close()
767

  
768
  def testCloseShared(self):
769
    self.lock.Close()
770
    self.assertRaises(AssertionError, self.lock.Shared, blocking=False)
771

  
772
  def testCloseExclusive(self):
773
    self.lock.Close()
774
    self.assertRaises(AssertionError, self.lock.Exclusive, blocking=False)
775

  
776
  def testCloseUnlock(self):
777
    self.lock.Close()
778
    self.assertRaises(AssertionError, self.lock.Unlock, blocking=False)
779

  
780

  
724 781
if __name__ == '__main__':
725 782
  unittest.main()

Also available in: Unified diff