Fix RPC result handling in _AssembleInstanceDisks
[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(must_lock):
73   """Open and lock job queue.
74
75   If necessary, the queue is automatically initialized.
76
77   @type must_lock: bool
78   @param must_lock: Whether an exclusive lock must be held.
79   @rtype: utils.FileLock
80   @return: Lock object for the queue. This can be used to change the
81            locking mode.
82
83   """
84   # Make sure our directories exists
85   for path in (constants.QUEUE_DIR, constants.JOB_QUEUE_ARCHIVE_DIR):
86     try:
87       os.mkdir(path, 0700)
88     except OSError, err:
89       if err.errno not in (errno.EEXIST, ):
90         raise
91
92   # Lock queue
93   queue_lock = utils.FileLock(constants.JOB_QUEUE_LOCK_FILE)
94   try:
95     # The queue needs to be locked in exclusive mode to write to the serial and
96     # version files.
97     if must_lock:
98       queue_lock.Exclusive(blocking=True)
99       holding_lock = True
100     else:
101       try:
102         queue_lock.Exclusive(blocking=False)
103         holding_lock = True
104       except errors.LockError:
105         # Ignore errors and assume the process keeping the lock checked
106         # everything.
107         holding_lock = False
108
109     if holding_lock:
110       # Verify version
111       version = ReadVersion()
112       if version is None:
113         # Write new version file
114         utils.WriteFile(constants.JOB_QUEUE_VERSION_FILE,
115                         data="%s\n" % constants.JOB_QUEUE_VERSION)
116
117         # Read again
118         version = ReadVersion()
119
120       if version != constants.JOB_QUEUE_VERSION:
121         raise errors.JobQueueError("Found job queue version %s, expected %s",
122                                    version, constants.JOB_QUEUE_VERSION)
123
124       serial = ReadSerial()
125       if serial is None:
126         # Write new serial file
127         utils.WriteFile(constants.JOB_QUEUE_SERIAL_FILE,
128                         data="%s\n" % 0)
129
130         # Read again
131         serial = ReadSerial()
132
133       if serial is None:
134         # There must be a serious problem
135         raise errors.JobQueueError("Can't read/parse the job queue serial file")
136
137       if not must_lock:
138         # There's no need for more error handling. Closing the lock file below in
139         # case of an error will unlock it anyway.
140         queue_lock.Unlock()
141
142   except:
143     queue_lock.Close()
144     raise
145
146   return queue_lock