jstore.py 3.31 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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
#
#

# Copyright (C) 2006, 2007 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.


"""Module implementing the job queue handling."""

import os
import logging
import errno
import re

from ganeti import constants
from ganeti import errors
from ganeti import utils


def _ReadNumericFile(file_name):
  """Reads a file containing a number.

  @rtype: None or int
  @return: None if file is not found, otherwise number

  """
  try:
    fd = open(file_name, "r")
  except IOError, err:
    if err.errno in (errno.ENOENT, ):
      return None
    raise

  try:
    return int(fd.read(128))
  finally:
    fd.close()


def ReadSerial():
  """Read the serial file.

  The queue should be locked while this function is called.

  """
  return _ReadNumericFile(constants.JOB_QUEUE_SERIAL_FILE)


def ReadVersion():
  """Read the queue version.

  The queue should be locked while this function is called.

  """
  return _ReadNumericFile(constants.JOB_QUEUE_VERSION_FILE)


def InitAndVerifyQueue(exclusive):
  """Open and lock job queue.

  If necessary, the queue is automatically initialized.

  @type exclusive: bool
  @param exclusive: Whether to lock the queue in exclusive mode. Shared
                    mode otherwise.
  @rtype: utils.FileLock
  @return: Lock object for the queue. This can be used to change the
           locking mode.

  """
  # Make sure our directories exists
  for path in (constants.QUEUE_DIR, constants.JOB_QUEUE_ARCHIVE_DIR):
    try:
      os.mkdir(path, 0700)
    except OSError, err:
      if err.errno not in (errno.EEXIST, ):
        raise

  # Lock queue
  queue_lock = utils.FileLock(constants.JOB_QUEUE_LOCK_FILE)
  try:
    # Determine locking function and call it
    if exclusive:
      fn = queue_lock.Exclusive
    else:
      fn = queue_lock.Shared

    fn(blocking=False)

    # Verify version
    version = ReadVersion()
    if version is None:
      # Write new version file
      utils.WriteFile(constants.JOB_QUEUE_VERSION_FILE,
                      data="%s\n" % constants.JOB_QUEUE_VERSION)

      # Read again
      version = ReadVersion()

    if version != constants.JOB_QUEUE_VERSION:
      raise errors.JobQueueError("Found job queue version %s, expected %s",
                                 version, constants.JOB_QUEUE_VERSION)

    serial = ReadSerial()
    if serial is None:
      # Write new serial file
      utils.WriteFile(constants.JOB_QUEUE_SERIAL_FILE,
                      data="%s\n" % 0)

      # Read again
      serial = ReadSerial()

    if serial is None:
      # There must be a serious problem
      raise errors.JobQueueError("Can't read/parse the job queue serial file")

  except:
    queue_lock.Close()
    raise

  return queue_lock