livelock.py 2.59 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
#
#

# Copyright (C) 2014 Google Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.

"""Lockfiles to prove liveliness

When requesting resources, like locks, from wconfd, requesters have
to provide the name of a file they own an exclusive lock on, to prove
that they are still alive. Provide methods to obtain such a file.
"""

import fcntl
import os
import struct
import time

33
from ganeti.utils.algo import NiceSort
34 35 36
from ganeti import pathutils


37 38 39 40 41 42 43 44 45 46 47 48 49
class LiveLockName(object):
  def __init__(self, name):
    self._name = name

  def GetPath(self):
    return self._name

  def close(self):
    """Clean up the lockfile.

    """
    os.remove(self._name)

50 51 52
  def __str__(self):
    return "LiveLockName(" + self.GetPath() + ")"

53

54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
class LiveLock(object):
  """Utility for a lockfile needed to request resources from WconfD.

  """
  def __init__(self, name=None):
    if name is None:
      name = "pid%d_" % os.getpid()
    # to avoid reusing existing lock files, extend name
    # by the current time
    name = "%s_%d" % (name, int(time.time()))
    fname = os.path.join(pathutils.LIVELOCK_DIR, name)
    self.lockfile = open(fname, 'w')
    fcntl.fcntl(self.lockfile, fcntl.F_SETLKW,
                struct.pack('hhllhh', fcntl.F_WRLCK, 0, 0, 0, 0, 0))

69 70 71
  def GetPath(self):
    return self.lockfile.name

72 73 74 75 76 77
  def close(self):
    """Close the lockfile and clean it up.

    """
    self.lockfile.close()
    os.remove(self.lockfile.name)
78

79 80 81
  def __str__(self):
    return "LiveLock(" + self.GetPath() + ")"

82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97

def GuessLockfileFor(name):
  """For a given name, take the latest file matching.

  @return: the file with the latest name matching the given
      prefix in LIVELOCK_DIR, or the plain name, if none
      exists.
  """
  lockfiles = filter(lambda n: n.startswith(name),
                     os.listdir(pathutils.LIVELOCK_DIR))
  if len(lockfiles) > 0:
    lockfile = NiceSort(lockfiles)[-1]
  else:
    lockfile = name

  return os.path.join(pathutils.LIVELOCK_DIR, lockfile)