Statistics
| Branch: | Tag: | Revision:

root / lib / jstore.py @ 5349519d

History | View | Annotate | Download (6.1 kB)

1 8b537bb0 Michael Hanselmann
#
2 8b537bb0 Michael Hanselmann
#
3 8b537bb0 Michael Hanselmann
4 76b62028 Iustin Pop
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Google Inc.
5 8b537bb0 Michael Hanselmann
#
6 8b537bb0 Michael Hanselmann
# This program is free software; you can redistribute it and/or modify
7 8b537bb0 Michael Hanselmann
# it under the terms of the GNU General Public License as published by
8 8b537bb0 Michael Hanselmann
# the Free Software Foundation; either version 2 of the License, or
9 8b537bb0 Michael Hanselmann
# (at your option) any later version.
10 8b537bb0 Michael Hanselmann
#
11 8b537bb0 Michael Hanselmann
# This program is distributed in the hope that it will be useful, but
12 8b537bb0 Michael Hanselmann
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 8b537bb0 Michael Hanselmann
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 8b537bb0 Michael Hanselmann
# General Public License for more details.
15 8b537bb0 Michael Hanselmann
#
16 8b537bb0 Michael Hanselmann
# You should have received a copy of the GNU General Public License
17 8b537bb0 Michael Hanselmann
# along with this program; if not, write to the Free Software
18 8b537bb0 Michael Hanselmann
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 8b537bb0 Michael Hanselmann
# 02110-1301, USA.
20 8b537bb0 Michael Hanselmann
21 8b537bb0 Michael Hanselmann
22 8b537bb0 Michael Hanselmann
"""Module implementing the job queue handling."""
23 8b537bb0 Michael Hanselmann
24 8b537bb0 Michael Hanselmann
import errno
25 ff699aa9 Michael Hanselmann
import os
26 8b537bb0 Michael Hanselmann
27 8b537bb0 Michael Hanselmann
from ganeti import constants
28 8b537bb0 Michael Hanselmann
from ganeti import errors
29 82b22e19 René Nussbaumer
from ganeti import runtime
30 8b537bb0 Michael Hanselmann
from ganeti import utils
31 e2b4a7ba Michael Hanselmann
from ganeti import pathutils
32 8b537bb0 Michael Hanselmann
33 8b537bb0 Michael Hanselmann
34 5523732b Jose A. Lopes
JOBS_PER_ARCHIVE_DIRECTORY = constants.JSTORE_JOBS_PER_ARCHIVE_DIRECTORY
35 1410a389 Michael Hanselmann
36 1410a389 Michael Hanselmann
37 8b537bb0 Michael Hanselmann
def _ReadNumericFile(file_name):
38 8b537bb0 Michael Hanselmann
  """Reads a file containing a number.
39 8b537bb0 Michael Hanselmann

40 8b537bb0 Michael Hanselmann
  @rtype: None or int
41 8b537bb0 Michael Hanselmann
  @return: None if file is not found, otherwise number
42 8b537bb0 Michael Hanselmann

43 8b537bb0 Michael Hanselmann
  """
44 8b537bb0 Michael Hanselmann
  try:
45 4fdedd09 Michael Hanselmann
    contents = utils.ReadFile(file_name)
46 6358dbc2 Guido Trotter
  except EnvironmentError, err:
47 8b537bb0 Michael Hanselmann
    if err.errno in (errno.ENOENT, ):
48 8b537bb0 Michael Hanselmann
      return None
49 8b537bb0 Michael Hanselmann
    raise
50 8b537bb0 Michael Hanselmann
51 4fdedd09 Michael Hanselmann
  try:
52 4fdedd09 Michael Hanselmann
    return int(contents)
53 4fdedd09 Michael Hanselmann
  except (ValueError, TypeError), err:
54 4fdedd09 Michael Hanselmann
    # Couldn't convert to int
55 4fdedd09 Michael Hanselmann
    raise errors.JobQueueError("Content of file '%s' is not numeric: %s" %
56 4fdedd09 Michael Hanselmann
                               (file_name, err))
57 4fdedd09 Michael Hanselmann
58 8b537bb0 Michael Hanselmann
59 8b537bb0 Michael Hanselmann
def ReadSerial():
60 8b537bb0 Michael Hanselmann
  """Read the serial file.
61 8b537bb0 Michael Hanselmann

62 8b537bb0 Michael Hanselmann
  The queue should be locked while this function is called.
63 8b537bb0 Michael Hanselmann

64 8b537bb0 Michael Hanselmann
  """
65 e2b4a7ba Michael Hanselmann
  return _ReadNumericFile(pathutils.JOB_QUEUE_SERIAL_FILE)
66 8b537bb0 Michael Hanselmann
67 8b537bb0 Michael Hanselmann
68 8b537bb0 Michael Hanselmann
def ReadVersion():
69 8b537bb0 Michael Hanselmann
  """Read the queue version.
70 8b537bb0 Michael Hanselmann

71 8b537bb0 Michael Hanselmann
  The queue should be locked while this function is called.
72 8b537bb0 Michael Hanselmann

73 8b537bb0 Michael Hanselmann
  """
74 e2b4a7ba Michael Hanselmann
  return _ReadNumericFile(pathutils.JOB_QUEUE_VERSION_FILE)
75 8b537bb0 Michael Hanselmann
76 8b537bb0 Michael Hanselmann
77 5d6fb8eb Michael Hanselmann
def InitAndVerifyQueue(must_lock):
78 8b537bb0 Michael Hanselmann
  """Open and lock job queue.
79 8b537bb0 Michael Hanselmann

80 8b537bb0 Michael Hanselmann
  If necessary, the queue is automatically initialized.
81 8b537bb0 Michael Hanselmann

82 5d6fb8eb Michael Hanselmann
  @type must_lock: bool
83 5d6fb8eb Michael Hanselmann
  @param must_lock: Whether an exclusive lock must be held.
84 8b537bb0 Michael Hanselmann
  @rtype: utils.FileLock
85 8b537bb0 Michael Hanselmann
  @return: Lock object for the queue. This can be used to change the
86 8b537bb0 Michael Hanselmann
           locking mode.
87 8b537bb0 Michael Hanselmann

88 8b537bb0 Michael Hanselmann
  """
89 82b22e19 René Nussbaumer
  getents = runtime.GetEnts()
90 8b537bb0 Michael Hanselmann
91 8b537bb0 Michael Hanselmann
  # Lock queue
92 e2b4a7ba Michael Hanselmann
  queue_lock = utils.FileLock.Open(pathutils.JOB_QUEUE_LOCK_FILE)
93 8b537bb0 Michael Hanselmann
  try:
94 5d6fb8eb Michael Hanselmann
    # The queue needs to be locked in exclusive mode to write to the serial and
95 5d6fb8eb Michael Hanselmann
    # version files.
96 5d6fb8eb Michael Hanselmann
    if must_lock:
97 5d6fb8eb Michael Hanselmann
      queue_lock.Exclusive(blocking=True)
98 5d6fb8eb Michael Hanselmann
      holding_lock = True
99 8b537bb0 Michael Hanselmann
    else:
100 5d6fb8eb Michael Hanselmann
      try:
101 5d6fb8eb Michael Hanselmann
        queue_lock.Exclusive(blocking=False)
102 5d6fb8eb Michael Hanselmann
        holding_lock = True
103 5d6fb8eb Michael Hanselmann
      except errors.LockError:
104 5d6fb8eb Michael Hanselmann
        # Ignore errors and assume the process keeping the lock checked
105 5d6fb8eb Michael Hanselmann
        # everything.
106 5d6fb8eb Michael Hanselmann
        holding_lock = False
107 5d6fb8eb Michael Hanselmann
108 5d6fb8eb Michael Hanselmann
    if holding_lock:
109 5d6fb8eb Michael Hanselmann
      # Verify version
110 8b537bb0 Michael Hanselmann
      version = ReadVersion()
111 5d6fb8eb Michael Hanselmann
      if version is None:
112 5d6fb8eb Michael Hanselmann
        # Write new version file
113 e2b4a7ba Michael Hanselmann
        utils.WriteFile(pathutils.JOB_QUEUE_VERSION_FILE,
114 fe05a931 Michele Tartara
                        uid=getents.masterd_uid, gid=getents.daemons_gid,
115 fe05a931 Michele Tartara
                        mode=constants.JOB_QUEUE_FILES_PERMS,
116 5d6fb8eb Michael Hanselmann
                        data="%s\n" % constants.JOB_QUEUE_VERSION)
117 8b537bb0 Michael Hanselmann
118 5d6fb8eb Michael Hanselmann
        # Read again
119 5d6fb8eb Michael Hanselmann
        version = ReadVersion()
120 8b537bb0 Michael Hanselmann
121 5d6fb8eb Michael Hanselmann
      if version != constants.JOB_QUEUE_VERSION:
122 5d6fb8eb Michael Hanselmann
        raise errors.JobQueueError("Found job queue version %s, expected %s",
123 5d6fb8eb Michael Hanselmann
                                   version, constants.JOB_QUEUE_VERSION)
124 8b537bb0 Michael Hanselmann
125 8b537bb0 Michael Hanselmann
      serial = ReadSerial()
126 5d6fb8eb Michael Hanselmann
      if serial is None:
127 5d6fb8eb Michael Hanselmann
        # Write new serial file
128 e2b4a7ba Michael Hanselmann
        utils.WriteFile(pathutils.JOB_QUEUE_SERIAL_FILE,
129 fe05a931 Michele Tartara
                        uid=getents.masterd_uid, gid=getents.daemons_gid,
130 fe05a931 Michele Tartara
                        mode=constants.JOB_QUEUE_FILES_PERMS,
131 5d6fb8eb Michael Hanselmann
                        data="%s\n" % 0)
132 5d6fb8eb Michael Hanselmann
133 5d6fb8eb Michael Hanselmann
        # Read again
134 5d6fb8eb Michael Hanselmann
        serial = ReadSerial()
135 8b537bb0 Michael Hanselmann
136 5d6fb8eb Michael Hanselmann
      if serial is None:
137 5d6fb8eb Michael Hanselmann
        # There must be a serious problem
138 fe267188 Iustin Pop
        raise errors.JobQueueError("Can't read/parse the job queue"
139 fe267188 Iustin Pop
                                   " serial file")
140 8b537bb0 Michael Hanselmann
141 f56377a3 Michael Hanselmann
      if not must_lock:
142 fe267188 Iustin Pop
        # There's no need for more error handling. Closing the lock
143 fe267188 Iustin Pop
        # file below in case of an error will unlock it anyway.
144 f56377a3 Michael Hanselmann
        queue_lock.Unlock()
145 f56377a3 Michael Hanselmann
146 8b537bb0 Michael Hanselmann
  except:
147 8b537bb0 Michael Hanselmann
    queue_lock.Close()
148 8b537bb0 Michael Hanselmann
    raise
149 8b537bb0 Michael Hanselmann
150 8b537bb0 Michael Hanselmann
  return queue_lock
151 ff699aa9 Michael Hanselmann
152 ff699aa9 Michael Hanselmann
153 ff699aa9 Michael Hanselmann
def CheckDrainFlag():
154 ff699aa9 Michael Hanselmann
  """Check if the queue is marked to be drained.
155 ff699aa9 Michael Hanselmann

156 ff699aa9 Michael Hanselmann
  This currently uses the queue drain file, which makes it a per-node flag.
157 ff699aa9 Michael Hanselmann
  In the future this can be moved to the config file.
158 ff699aa9 Michael Hanselmann

159 ff699aa9 Michael Hanselmann
  @rtype: boolean
160 ff699aa9 Michael Hanselmann
  @return: True if the job queue is marked drained
161 ff699aa9 Michael Hanselmann

162 ff699aa9 Michael Hanselmann
  """
163 e2b4a7ba Michael Hanselmann
  return os.path.exists(pathutils.JOB_QUEUE_DRAIN_FILE)
164 ff699aa9 Michael Hanselmann
165 ff699aa9 Michael Hanselmann
166 ff699aa9 Michael Hanselmann
def SetDrainFlag(drain_flag):
167 ff699aa9 Michael Hanselmann
  """Sets the drain flag for the queue.
168 ff699aa9 Michael Hanselmann

169 ff699aa9 Michael Hanselmann
  @type drain_flag: boolean
170 ff699aa9 Michael Hanselmann
  @param drain_flag: Whether to set or unset the drain flag
171 ff699aa9 Michael Hanselmann
  @attention: This function should only called the current holder of the queue
172 ff699aa9 Michael Hanselmann
    lock
173 ff699aa9 Michael Hanselmann

174 ff699aa9 Michael Hanselmann
  """
175 ff699aa9 Michael Hanselmann
  getents = runtime.GetEnts()
176 ff699aa9 Michael Hanselmann
177 ff699aa9 Michael Hanselmann
  if drain_flag:
178 e2b4a7ba Michael Hanselmann
    utils.WriteFile(pathutils.JOB_QUEUE_DRAIN_FILE, data="",
179 fe05a931 Michele Tartara
                    uid=getents.masterd_uid, gid=getents.daemons_gid,
180 fe05a931 Michele Tartara
                    mode=constants.JOB_QUEUE_FILES_PERMS)
181 ff699aa9 Michael Hanselmann
  else:
182 e2b4a7ba Michael Hanselmann
    utils.RemoveFile(pathutils.JOB_QUEUE_DRAIN_FILE)
183 ff699aa9 Michael Hanselmann
184 ff699aa9 Michael Hanselmann
  assert (not drain_flag) ^ CheckDrainFlag()
185 1410a389 Michael Hanselmann
186 1410a389 Michael Hanselmann
187 1410a389 Michael Hanselmann
def FormatJobID(job_id):
188 76b62028 Iustin Pop
  """Convert a job ID to int format.
189 1410a389 Michael Hanselmann

190 76b62028 Iustin Pop
  Currently this just is a no-op that performs some checks, but if we
191 76b62028 Iustin Pop
  want to change the job id format this will abstract this change.
192 1410a389 Michael Hanselmann

193 1410a389 Michael Hanselmann
  @type job_id: int or long
194 1410a389 Michael Hanselmann
  @param job_id: the numeric job id
195 76b62028 Iustin Pop
  @rtype: int
196 1410a389 Michael Hanselmann
  @return: the formatted job id
197 1410a389 Michael Hanselmann

198 1410a389 Michael Hanselmann
  """
199 1410a389 Michael Hanselmann
  if not isinstance(job_id, (int, long)):
200 1410a389 Michael Hanselmann
    raise errors.ProgrammerError("Job ID '%s' not numeric" % job_id)
201 1410a389 Michael Hanselmann
  if job_id < 0:
202 1410a389 Michael Hanselmann
    raise errors.ProgrammerError("Job ID %s is negative" % job_id)
203 1410a389 Michael Hanselmann
204 76b62028 Iustin Pop
  return job_id
205 1410a389 Michael Hanselmann
206 1410a389 Michael Hanselmann
207 1410a389 Michael Hanselmann
def GetArchiveDirectory(job_id):
208 1410a389 Michael Hanselmann
  """Returns the archive directory for a job.
209 1410a389 Michael Hanselmann

210 1410a389 Michael Hanselmann
  @type job_id: str
211 1410a389 Michael Hanselmann
  @param job_id: Job identifier
212 1410a389 Michael Hanselmann
  @rtype: str
213 1410a389 Michael Hanselmann
  @return: Directory name
214 1410a389 Michael Hanselmann

215 1410a389 Michael Hanselmann
  """
216 526f866b Michael Hanselmann
  return str(ParseJobId(job_id) / JOBS_PER_ARCHIVE_DIRECTORY)
217 526f866b Michael Hanselmann
218 526f866b Michael Hanselmann
219 526f866b Michael Hanselmann
def ParseJobId(job_id):
220 526f866b Michael Hanselmann
  """Parses a job ID and converts it to integer.
221 526f866b Michael Hanselmann

222 526f866b Michael Hanselmann
  """
223 526f866b Michael Hanselmann
  try:
224 526f866b Michael Hanselmann
    return int(job_id)
225 526f866b Michael Hanselmann
  except (ValueError, TypeError):
226 526f866b Michael Hanselmann
    raise errors.ParameterError("Invalid job ID '%s'" % job_id)