jstore: Add queue helper functions
[ganeti-local] / lib / jstore.py
1 #
2 #
3
4 # Copyright (C) 2006, 2007 Google Inc.
5 #
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 # General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 # 02110-1301, USA.
20
21
22 """Module implementing the job queue handling."""
23
24 import os
25 import logging
26 import errno
27 import re
28
29 from ganeti import constants
30 from ganeti import errors
31 from ganeti import utils
32
33
34 def _ReadNumericFile(file_name):
35   """Reads a file containing a number.
36
37   @rtype: None or int
38   @return: None if file is not found, otherwise number
39
40   """
41   try:
42     fd = open(file_name, "r")
43   except IOError, err:
44     if err.errno in (errno.ENOENT, ):
45       return None
46     raise
47
48   try:
49     return int(fd.read(128))
50   finally:
51     fd.close()
52
53
54 def ReadSerial():
55   """Read the serial file.
56
57   The queue should be locked while this function is called.
58
59   """
60   return _ReadNumericFile(constants.JOB_QUEUE_SERIAL_FILE)
61
62
63 def ReadVersion():
64   """Read the queue version.
65
66   The queue should be locked while this function is called.
67
68   """
69   return _ReadNumericFile(constants.JOB_QUEUE_VERSION_FILE)
70
71
72 def InitAndVerifyQueue(exclusive):
73   """Open and lock job queue.
74
75   If necessary, the queue is automatically initialized.
76
77   @type exclusive: bool
78   @param exclusive: Whether to lock the queue in exclusive mode. Shared
79                     mode otherwise.
80   @rtype: utils.FileLock
81   @return: Lock object for the queue. This can be used to change the
82            locking mode.
83
84   """
85   # Make sure our directories exists
86   for path in (constants.QUEUE_DIR, constants.JOB_QUEUE_ARCHIVE_DIR):
87     try:
88       os.mkdir(path, 0700)
89     except OSError, err:
90       if err.errno not in (errno.EEXIST, ):
91         raise
92
93   # Lock queue
94   queue_lock = utils.FileLock(constants.JOB_QUEUE_LOCK_FILE)
95   try:
96     # Determine locking function and call it
97     if exclusive:
98       fn = queue_lock.Exclusive
99     else:
100       fn = queue_lock.Shared
101
102     fn(blocking=False)
103
104     # Verify version
105     version = ReadVersion()
106     if version is None:
107       # Write new version file
108       utils.WriteFile(constants.JOB_QUEUE_VERSION_FILE,
109                       data="%s\n" % constants.JOB_QUEUE_VERSION)
110
111       # Read again
112       version = ReadVersion()
113
114     if version != constants.JOB_QUEUE_VERSION:
115       raise errors.JobQueueError("Found job queue version %s, expected %s",
116                                  version, constants.JOB_QUEUE_VERSION)
117
118     serial = ReadSerial()
119     if serial is None:
120       # Write new serial file
121       utils.WriteFile(constants.JOB_QUEUE_SERIAL_FILE,
122                       data="%s\n" % 0)
123
124       # Read again
125       serial = ReadSerial()
126
127     if serial is None:
128       # There must be a serious problem
129       raise errors.JobQueueError("Can't read/parse the job queue serial file")
130
131   except:
132     queue_lock.Close()
133     raise
134
135   return queue_lock