Statistics
| Branch: | Tag: | Revision:

root / lib / mcpu.py @ 84ad6b78

History | View | Annotate | Download (18.1 kB)

1 2f31098c Iustin Pop
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 5ae4945a Iustin Pop
# Copyright (C) 2006, 2007, 2011, 2012 Google Inc.
5 a8083063 Iustin Pop
#
6 a8083063 Iustin Pop
# This program is free software; you can redistribute it and/or modify
7 a8083063 Iustin Pop
# it under the terms of the GNU General Public License as published by
8 a8083063 Iustin Pop
# the Free Software Foundation; either version 2 of the License, or
9 a8083063 Iustin Pop
# (at your option) any later version.
10 a8083063 Iustin Pop
#
11 a8083063 Iustin Pop
# This program is distributed in the hope that it will be useful, but
12 a8083063 Iustin Pop
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 a8083063 Iustin Pop
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 a8083063 Iustin Pop
# General Public License for more details.
15 a8083063 Iustin Pop
#
16 a8083063 Iustin Pop
# You should have received a copy of the GNU General Public License
17 a8083063 Iustin Pop
# along with this program; if not, write to the Free Software
18 a8083063 Iustin Pop
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 a8083063 Iustin Pop
# 02110-1301, USA.
20 a8083063 Iustin Pop
21 a8083063 Iustin Pop
22 a8083063 Iustin Pop
"""Module implementing the logic behind the cluster operations
23 a8083063 Iustin Pop

24 a8083063 Iustin Pop
This module implements the logic for doing operations in the cluster. There
25 a8083063 Iustin Pop
are two kinds of classes defined:
26 a8083063 Iustin Pop
  - logical units, which know how to deal with their specific opcode only
27 a8083063 Iustin Pop
  - the processor, which dispatches the opcodes to their logical units
28 a8083063 Iustin Pop

29 a8083063 Iustin Pop
"""
30 a8083063 Iustin Pop
31 b183c4a8 Iustin Pop
import sys
32 a5eb7789 Iustin Pop
import logging
33 407339d0 Michael Hanselmann
import random
34 407339d0 Michael Hanselmann
import time
35 07923a3c Michael Hanselmann
import itertools
36 b183c4a8 Iustin Pop
import traceback
37 a8083063 Iustin Pop
38 a8083063 Iustin Pop
from ganeti import opcodes
39 580b1fdd Jose A. Lopes
from ganeti import opcodes_base
40 a8083063 Iustin Pop
from ganeti import constants
41 a8083063 Iustin Pop
from ganeti import errors
42 68d95757 Guido Trotter
from ganeti import hooksmaster
43 a8083063 Iustin Pop
from ganeti import cmdlib
44 04864530 Guido Trotter
from ganeti import locking
45 557838c1 René Nussbaumer
from ganeti import utils
46 ebc75510 Michael Hanselmann
from ganeti import compat
47 a8083063 Iustin Pop
48 7c0d6283 Michael Hanselmann
49 a1a7bc78 Iustin Pop
_OP_PREFIX = "Op"
50 a1a7bc78 Iustin Pop
_LU_PREFIX = "LU"
51 a1a7bc78 Iustin Pop
52 e9a81214 Michael Hanselmann
#: LU classes which don't need to acquire the node allocation lock
53 e9a81214 Michael Hanselmann
#: (L{locking.NAL}) when they acquire all node or node resource locks
54 b8028dcf Michael Hanselmann
_NODE_ALLOC_WHITELIST = frozenset([])
55 e9a81214 Michael Hanselmann
56 e9a81214 Michael Hanselmann
#: LU classes which don't need to acquire the node allocation lock
57 e9a81214 Michael Hanselmann
#: (L{locking.NAL}) in the same mode (shared/exclusive) as the node
58 e9a81214 Michael Hanselmann
#: or node resource locks
59 b8028dcf Michael Hanselmann
_NODE_ALLOC_MODE_WHITELIST = compat.UniqueFrozenset([
60 e9a81214 Michael Hanselmann
  cmdlib.LUBackupExport,
61 e9a81214 Michael Hanselmann
  cmdlib.LUBackupRemove,
62 e9a81214 Michael Hanselmann
  cmdlib.LUOobCommand,
63 e9a81214 Michael Hanselmann
  ])
64 e9a81214 Michael Hanselmann
65 a1a7bc78 Iustin Pop
66 831bbbc1 Michael Hanselmann
class LockAcquireTimeout(Exception):
67 831bbbc1 Michael Hanselmann
  """Exception to report timeouts on acquiring locks.
68 407339d0 Michael Hanselmann

69 407339d0 Michael Hanselmann
  """
70 407339d0 Michael Hanselmann
71 407339d0 Michael Hanselmann
72 e3200b18 Michael Hanselmann
def _CalculateLockAttemptTimeouts():
73 e3200b18 Michael Hanselmann
  """Calculate timeouts for lock attempts.
74 e3200b18 Michael Hanselmann

75 e3200b18 Michael Hanselmann
  """
76 d385a174 Iustin Pop
  result = [constants.LOCK_ATTEMPTS_MINWAIT]
77 d385a174 Iustin Pop
  running_sum = result[0]
78 e3200b18 Michael Hanselmann
79 d385a174 Iustin Pop
  # Wait for a total of at least LOCK_ATTEMPTS_TIMEOUT before doing a
80 d385a174 Iustin Pop
  # blocking acquire
81 d385a174 Iustin Pop
  while running_sum < constants.LOCK_ATTEMPTS_TIMEOUT:
82 e3200b18 Michael Hanselmann
    timeout = (result[-1] * 1.05) ** 1.25
83 e3200b18 Michael Hanselmann
84 d385a174 Iustin Pop
    # Cap max timeout. This gives other jobs a chance to run even if
85 d385a174 Iustin Pop
    # we're still trying to get our locks, before finally moving to a
86 d385a174 Iustin Pop
    # blocking acquire.
87 d385a174 Iustin Pop
    timeout = min(timeout, constants.LOCK_ATTEMPTS_MAXWAIT)
88 d385a174 Iustin Pop
    # And also cap the lower boundary for safety
89 d385a174 Iustin Pop
    timeout = max(timeout, constants.LOCK_ATTEMPTS_MINWAIT)
90 e3200b18 Michael Hanselmann
91 e3200b18 Michael Hanselmann
    result.append(timeout)
92 d385a174 Iustin Pop
    running_sum += timeout
93 e3200b18 Michael Hanselmann
94 e3200b18 Michael Hanselmann
  return result
95 e3200b18 Michael Hanselmann
96 e3200b18 Michael Hanselmann
97 a7770f03 Michael Hanselmann
class LockAttemptTimeoutStrategy(object):
98 407339d0 Michael Hanselmann
  """Class with lock acquire timeout strategy.
99 407339d0 Michael Hanselmann

100 407339d0 Michael Hanselmann
  """
101 407339d0 Michael Hanselmann
  __slots__ = [
102 a7770f03 Michael Hanselmann
    "_timeouts",
103 407339d0 Michael Hanselmann
    "_random_fn",
104 e3200b18 Michael Hanselmann
    "_time_fn",
105 407339d0 Michael Hanselmann
    ]
106 407339d0 Michael Hanselmann
107 e3200b18 Michael Hanselmann
  _TIMEOUT_PER_ATTEMPT = _CalculateLockAttemptTimeouts()
108 407339d0 Michael Hanselmann
109 a7770f03 Michael Hanselmann
  def __init__(self, _time_fn=time.time, _random_fn=random.random):
110 407339d0 Michael Hanselmann
    """Initializes this class.
111 407339d0 Michael Hanselmann

112 e3200b18 Michael Hanselmann
    @param _time_fn: Time function for unittests
113 407339d0 Michael Hanselmann
    @param _random_fn: Random number generator for unittests
114 407339d0 Michael Hanselmann

115 407339d0 Michael Hanselmann
    """
116 407339d0 Michael Hanselmann
    object.__init__(self)
117 407339d0 Michael Hanselmann
118 a7770f03 Michael Hanselmann
    self._timeouts = iter(self._TIMEOUT_PER_ATTEMPT)
119 e3200b18 Michael Hanselmann
    self._time_fn = _time_fn
120 e3200b18 Michael Hanselmann
    self._random_fn = _random_fn
121 e3200b18 Michael Hanselmann
122 407339d0 Michael Hanselmann
  def NextAttempt(self):
123 a7770f03 Michael Hanselmann
    """Returns the timeout for the next attempt.
124 407339d0 Michael Hanselmann

125 407339d0 Michael Hanselmann
    """
126 a7770f03 Michael Hanselmann
    try:
127 a7770f03 Michael Hanselmann
      timeout = self._timeouts.next()
128 a7770f03 Michael Hanselmann
    except StopIteration:
129 a7770f03 Michael Hanselmann
      # No more timeouts, do blocking acquire
130 a7770f03 Michael Hanselmann
      timeout = None
131 407339d0 Michael Hanselmann
132 a6db1af2 Michael Hanselmann
    if timeout is not None:
133 a6db1af2 Michael Hanselmann
      # Add a small variation (-/+ 5%) to timeout. This helps in situations
134 a6db1af2 Michael Hanselmann
      # where two or more jobs are fighting for the same lock(s).
135 a6db1af2 Michael Hanselmann
      variation_range = timeout * 0.1
136 a6db1af2 Michael Hanselmann
      timeout += ((self._random_fn() * variation_range) -
137 a6db1af2 Michael Hanselmann
                  (variation_range * 0.5))
138 407339d0 Michael Hanselmann
139 a6db1af2 Michael Hanselmann
    return timeout
140 407339d0 Michael Hanselmann
141 407339d0 Michael Hanselmann
142 b459a848 Andrea Spadaccini
class OpExecCbBase: # pylint: disable=W0232
143 031a3e57 Michael Hanselmann
  """Base class for OpCode execution callbacks.
144 031a3e57 Michael Hanselmann

145 031a3e57 Michael Hanselmann
  """
146 031a3e57 Michael Hanselmann
  def NotifyStart(self):
147 031a3e57 Michael Hanselmann
    """Called when we are about to execute the LU.
148 031a3e57 Michael Hanselmann

149 031a3e57 Michael Hanselmann
    This function is called when we're about to start the lu's Exec() method,
150 031a3e57 Michael Hanselmann
    that is, after we have acquired all locks.
151 031a3e57 Michael Hanselmann

152 031a3e57 Michael Hanselmann
    """
153 031a3e57 Michael Hanselmann
154 031a3e57 Michael Hanselmann
  def Feedback(self, *args):
155 031a3e57 Michael Hanselmann
    """Sends feedback from the LU code to the end-user.
156 031a3e57 Michael Hanselmann

157 031a3e57 Michael Hanselmann
    """
158 031a3e57 Michael Hanselmann
159 e4e59de8 Michael Hanselmann
  def CurrentPriority(self): # pylint: disable=R0201
160 e4e59de8 Michael Hanselmann
    """Returns current priority or C{None}.
161 ef2df7d3 Michael Hanselmann

162 ef2df7d3 Michael Hanselmann
    """
163 e4e59de8 Michael Hanselmann
    return None
164 ef2df7d3 Michael Hanselmann
165 6a373640 Michael Hanselmann
  def SubmitManyJobs(self, jobs):
166 6a373640 Michael Hanselmann
    """Submits jobs for processing.
167 6a373640 Michael Hanselmann

168 6a373640 Michael Hanselmann
    See L{jqueue.JobQueue.SubmitManyJobs}.
169 6a373640 Michael Hanselmann

170 6a373640 Michael Hanselmann
    """
171 6a373640 Michael Hanselmann
    raise NotImplementedError
172 6a373640 Michael Hanselmann
173 031a3e57 Michael Hanselmann
174 a1a7bc78 Iustin Pop
def _LUNameForOpName(opname):
175 a1a7bc78 Iustin Pop
  """Computes the LU name for a given OpCode name.
176 a1a7bc78 Iustin Pop

177 a1a7bc78 Iustin Pop
  """
178 a1a7bc78 Iustin Pop
  assert opname.startswith(_OP_PREFIX), \
179 a1a7bc78 Iustin Pop
      "Invalid OpCode name, doesn't start with %s: %s" % (_OP_PREFIX, opname)
180 a1a7bc78 Iustin Pop
181 a1a7bc78 Iustin Pop
  return _LU_PREFIX + opname[len(_OP_PREFIX):]
182 a1a7bc78 Iustin Pop
183 a1a7bc78 Iustin Pop
184 a1a7bc78 Iustin Pop
def _ComputeDispatchTable():
185 a1a7bc78 Iustin Pop
  """Computes the opcode-to-lu dispatch table.
186 a1a7bc78 Iustin Pop

187 a1a7bc78 Iustin Pop
  """
188 a1a7bc78 Iustin Pop
  return dict((op, getattr(cmdlib, _LUNameForOpName(op.__name__)))
189 a1a7bc78 Iustin Pop
              for op in opcodes.OP_MAPPING.values()
190 a1a7bc78 Iustin Pop
              if op.WITH_LU)
191 a1a7bc78 Iustin Pop
192 a1a7bc78 Iustin Pop
193 07923a3c Michael Hanselmann
def _SetBaseOpParams(src, defcomment, dst):
194 07923a3c Michael Hanselmann
  """Copies basic opcode parameters.
195 07923a3c Michael Hanselmann

196 07923a3c Michael Hanselmann
  @type src: L{opcodes.OpCode}
197 07923a3c Michael Hanselmann
  @param src: Source opcode
198 07923a3c Michael Hanselmann
  @type defcomment: string
199 07923a3c Michael Hanselmann
  @param defcomment: Comment to specify if not already given
200 07923a3c Michael Hanselmann
  @type dst: L{opcodes.OpCode}
201 07923a3c Michael Hanselmann
  @param dst: Destination opcode
202 07923a3c Michael Hanselmann

203 07923a3c Michael Hanselmann
  """
204 07923a3c Michael Hanselmann
  if hasattr(src, "debug_level"):
205 07923a3c Michael Hanselmann
    dst.debug_level = src.debug_level
206 07923a3c Michael Hanselmann
207 07923a3c Michael Hanselmann
  if (getattr(dst, "priority", None) is None and
208 07923a3c Michael Hanselmann
      hasattr(src, "priority")):
209 07923a3c Michael Hanselmann
    dst.priority = src.priority
210 07923a3c Michael Hanselmann
211 580b1fdd Jose A. Lopes
  if not getattr(dst, opcodes_base.COMMENT_ATTR, None):
212 07923a3c Michael Hanselmann
    dst.comment = defcomment
213 07923a3c Michael Hanselmann
214 07923a3c Michael Hanselmann
215 07923a3c Michael Hanselmann
def _ProcessResult(submit_fn, op, result):
216 07923a3c Michael Hanselmann
  """Examines opcode result.
217 07923a3c Michael Hanselmann

218 07923a3c Michael Hanselmann
  If necessary, additional processing on the result is done.
219 07923a3c Michael Hanselmann

220 07923a3c Michael Hanselmann
  """
221 07923a3c Michael Hanselmann
  if isinstance(result, cmdlib.ResultWithJobs):
222 07923a3c Michael Hanselmann
    # Copy basic parameters (e.g. priority)
223 07923a3c Michael Hanselmann
    map(compat.partial(_SetBaseOpParams, op,
224 07923a3c Michael Hanselmann
                       "Submitted by %s" % op.OP_ID),
225 07923a3c Michael Hanselmann
        itertools.chain(*result.jobs))
226 07923a3c Michael Hanselmann
227 07923a3c Michael Hanselmann
    # Submit jobs
228 07923a3c Michael Hanselmann
    job_submission = submit_fn(result.jobs)
229 07923a3c Michael Hanselmann
230 07923a3c Michael Hanselmann
    # Build dictionary
231 07923a3c Michael Hanselmann
    result = result.other
232 07923a3c Michael Hanselmann
233 07923a3c Michael Hanselmann
    assert constants.JOB_IDS_KEY not in result, \
234 07923a3c Michael Hanselmann
      "Key '%s' found in additional return values" % constants.JOB_IDS_KEY
235 07923a3c Michael Hanselmann
236 07923a3c Michael Hanselmann
    result[constants.JOB_IDS_KEY] = job_submission
237 07923a3c Michael Hanselmann
238 07923a3c Michael Hanselmann
  return result
239 07923a3c Michael Hanselmann
240 07923a3c Michael Hanselmann
241 abe362d3 Michael Hanselmann
def _FailingSubmitManyJobs(_):
242 abe362d3 Michael Hanselmann
  """Implementation of L{OpExecCbBase.SubmitManyJobs} to raise an exception.
243 abe362d3 Michael Hanselmann

244 abe362d3 Michael Hanselmann
  """
245 abe362d3 Michael Hanselmann
  raise errors.ProgrammerError("Opcodes processed without callbacks (e.g."
246 abe362d3 Michael Hanselmann
                               " queries) can not submit jobs")
247 abe362d3 Michael Hanselmann
248 abe362d3 Michael Hanselmann
249 e9a81214 Michael Hanselmann
def _VerifyLocks(lu, glm, _mode_whitelist=_NODE_ALLOC_MODE_WHITELIST,
250 e9a81214 Michael Hanselmann
                 _nal_whitelist=_NODE_ALLOC_WHITELIST):
251 e9a81214 Michael Hanselmann
  """Performs consistency checks on locks acquired by a logical unit.
252 e9a81214 Michael Hanselmann

253 e9a81214 Michael Hanselmann
  @type lu: L{cmdlib.LogicalUnit}
254 e9a81214 Michael Hanselmann
  @param lu: Logical unit instance
255 e9a81214 Michael Hanselmann
  @type glm: L{locking.GanetiLockManager}
256 e9a81214 Michael Hanselmann
  @param glm: Lock manager
257 e9a81214 Michael Hanselmann

258 e9a81214 Michael Hanselmann
  """
259 e9a81214 Michael Hanselmann
  if not __debug__:
260 e9a81214 Michael Hanselmann
    return
261 e9a81214 Michael Hanselmann
262 e9a81214 Michael Hanselmann
  have_nal = glm.check_owned(locking.LEVEL_NODE_ALLOC, locking.NAL)
263 e9a81214 Michael Hanselmann
264 e9a81214 Michael Hanselmann
  for level in [locking.LEVEL_NODE, locking.LEVEL_NODE_RES]:
265 e9a81214 Michael Hanselmann
    # TODO: Verify using actual lock mode, not using LU variables
266 e9a81214 Michael Hanselmann
    if level in lu.needed_locks:
267 e9a81214 Michael Hanselmann
      share_node_alloc = lu.share_locks[locking.LEVEL_NODE_ALLOC]
268 e9a81214 Michael Hanselmann
      share_level = lu.share_locks[level]
269 e9a81214 Michael Hanselmann
270 e9a81214 Michael Hanselmann
      if lu.__class__ in _mode_whitelist:
271 e9a81214 Michael Hanselmann
        assert share_node_alloc != share_level, \
272 e9a81214 Michael Hanselmann
          "LU is whitelisted to use different modes for node allocation lock"
273 e9a81214 Michael Hanselmann
      else:
274 e9a81214 Michael Hanselmann
        assert bool(share_node_alloc) == bool(share_level), \
275 e9a81214 Michael Hanselmann
          ("Node allocation lock must be acquired using the same mode as nodes"
276 e9a81214 Michael Hanselmann
           " and node resources")
277 e9a81214 Michael Hanselmann
278 e9a81214 Michael Hanselmann
      if lu.__class__ in _nal_whitelist:
279 e9a81214 Michael Hanselmann
        assert not have_nal, \
280 e9a81214 Michael Hanselmann
          "LU is whitelisted for not acquiring the node allocation lock"
281 e9a81214 Michael Hanselmann
      elif lu.needed_locks[level] == locking.ALL_SET or glm.owning_all(level):
282 e9a81214 Michael Hanselmann
        assert have_nal, \
283 e9a81214 Michael Hanselmann
          ("Node allocation lock must be used if an LU acquires all nodes"
284 e9a81214 Michael Hanselmann
           " or node resources")
285 e9a81214 Michael Hanselmann
286 e9a81214 Michael Hanselmann
287 a8083063 Iustin Pop
class Processor(object):
288 a8083063 Iustin Pop
  """Object which runs OpCodes"""
289 a1a7bc78 Iustin Pop
  DISPATCH_TABLE = _ComputeDispatchTable()
290 a8083063 Iustin Pop
291 dc4bdf73 Michael Hanselmann
  def __init__(self, context, ec_id, enable_locks=True):
292 a8083063 Iustin Pop
    """Constructor for Processor
293 a8083063 Iustin Pop

294 adfa97e3 Guido Trotter
    @type context: GanetiContext
295 adfa97e3 Guido Trotter
    @param context: global Ganeti context
296 adfa97e3 Guido Trotter
    @type ec_id: string
297 adfa97e3 Guido Trotter
    @param ec_id: execution context identifier
298 adfa97e3 Guido Trotter

299 a8083063 Iustin Pop
    """
300 1c901d13 Guido Trotter
    self.context = context
301 adfa97e3 Guido Trotter
    self._ec_id = ec_id
302 031a3e57 Michael Hanselmann
    self._cbs = None
303 87b3cb26 Michael Hanselmann
    self.rpc = context.rpc
304 68d95757 Guido Trotter
    self.hmclass = hooksmaster.HooksMaster
305 dc4bdf73 Michael Hanselmann
    self._enable_locks = enable_locks
306 dc4bdf73 Michael Hanselmann
307 dc4bdf73 Michael Hanselmann
  def _CheckLocksEnabled(self):
308 dc4bdf73 Michael Hanselmann
    """Checks if locking is enabled.
309 dc4bdf73 Michael Hanselmann

310 dc4bdf73 Michael Hanselmann
    @raise errors.ProgrammerError: In case locking is not enabled
311 dc4bdf73 Michael Hanselmann

312 dc4bdf73 Michael Hanselmann
    """
313 dc4bdf73 Michael Hanselmann
    if not self._enable_locks:
314 dc4bdf73 Michael Hanselmann
      raise errors.ProgrammerError("Attempted to use disabled locks")
315 a8083063 Iustin Pop
316 686d24f0 Michael Hanselmann
  def _AcquireLocks(self, level, names, shared, opportunistic, timeout):
317 211b6132 Michael Hanselmann
    """Acquires locks via the Ganeti lock manager.
318 211b6132 Michael Hanselmann

319 211b6132 Michael Hanselmann
    @type level: int
320 211b6132 Michael Hanselmann
    @param level: Lock level
321 211b6132 Michael Hanselmann
    @type names: list or string
322 211b6132 Michael Hanselmann
    @param names: Lock names
323 211b6132 Michael Hanselmann
    @type shared: bool
324 211b6132 Michael Hanselmann
    @param shared: Whether the locks should be acquired in shared mode
325 686d24f0 Michael Hanselmann
    @type opportunistic: bool
326 686d24f0 Michael Hanselmann
    @param opportunistic: Whether to acquire opportunistically
327 211b6132 Michael Hanselmann
    @type timeout: None or float
328 211b6132 Michael Hanselmann
    @param timeout: Timeout for acquiring the locks
329 900df6cd Michael Hanselmann
    @raise LockAcquireTimeout: In case locks couldn't be acquired in specified
330 900df6cd Michael Hanselmann
        amount of time
331 211b6132 Michael Hanselmann

332 211b6132 Michael Hanselmann
    """
333 dc4bdf73 Michael Hanselmann
    self._CheckLocksEnabled()
334 dc4bdf73 Michael Hanselmann
335 acf931b7 Michael Hanselmann
    if self._cbs:
336 e4e59de8 Michael Hanselmann
      priority = self._cbs.CurrentPriority()
337 e4e59de8 Michael Hanselmann
    else:
338 e4e59de8 Michael Hanselmann
      priority = None
339 211b6132 Michael Hanselmann
340 211b6132 Michael Hanselmann
    acquired = self.context.glm.acquire(level, names, shared=shared,
341 686d24f0 Michael Hanselmann
                                        timeout=timeout, priority=priority,
342 686d24f0 Michael Hanselmann
                                        opportunistic=opportunistic)
343 211b6132 Michael Hanselmann
344 900df6cd Michael Hanselmann
    if acquired is None:
345 900df6cd Michael Hanselmann
      raise LockAcquireTimeout()
346 900df6cd Michael Hanselmann
347 211b6132 Michael Hanselmann
    return acquired
348 211b6132 Michael Hanselmann
349 36c381d7 Guido Trotter
  def _ExecLU(self, lu):
350 36c381d7 Guido Trotter
    """Logical Unit execution sequence.
351 36c381d7 Guido Trotter

352 36c381d7 Guido Trotter
    """
353 36c381d7 Guido Trotter
    write_count = self.context.cfg.write_count
354 36c381d7 Guido Trotter
    lu.CheckPrereq()
355 949dcb1d Andrea Spadaccini
356 949dcb1d Andrea Spadaccini
    hm = self.BuildHooksManager(lu)
357 36c381d7 Guido Trotter
    h_results = hm.RunPhase(constants.HOOKS_PHASE_PRE)
358 36c381d7 Guido Trotter
    lu.HooksCallBack(constants.HOOKS_PHASE_PRE, h_results,
359 7b4c1cb9 Michael Hanselmann
                     self.Log, None)
360 20777413 Iustin Pop
361 20777413 Iustin Pop
    if getattr(lu.op, "dry_run", False):
362 20777413 Iustin Pop
      # in this mode, no post-hooks are run, and the config is not
363 20777413 Iustin Pop
      # written (as it might have been modified by another LU, and we
364 20777413 Iustin Pop
      # shouldn't do writeout on behalf of other threads
365 20777413 Iustin Pop
      self.LogInfo("dry-run mode requested, not actually executing"
366 20777413 Iustin Pop
                   " the operation")
367 20777413 Iustin Pop
      return lu.dry_run_result
368 20777413 Iustin Pop
369 abe362d3 Michael Hanselmann
    if self._cbs:
370 abe362d3 Michael Hanselmann
      submit_mj_fn = self._cbs.SubmitManyJobs
371 abe362d3 Michael Hanselmann
    else:
372 abe362d3 Michael Hanselmann
      submit_mj_fn = _FailingSubmitManyJobs
373 abe362d3 Michael Hanselmann
374 36c381d7 Guido Trotter
    try:
375 abe362d3 Michael Hanselmann
      result = _ProcessResult(submit_mj_fn, lu.op, lu.Exec(self.Log))
376 36c381d7 Guido Trotter
      h_results = hm.RunPhase(constants.HOOKS_PHASE_POST)
377 36c381d7 Guido Trotter
      result = lu.HooksCallBack(constants.HOOKS_PHASE_POST, h_results,
378 7b4c1cb9 Michael Hanselmann
                                self.Log, result)
379 36c381d7 Guido Trotter
    finally:
380 36c381d7 Guido Trotter
      # FIXME: This needs locks if not lu_class.REQ_BGL
381 36c381d7 Guido Trotter
      if write_count != self.context.cfg.write_count:
382 36c381d7 Guido Trotter
        hm.RunConfigUpdate()
383 36c381d7 Guido Trotter
384 36c381d7 Guido Trotter
    return result
385 36c381d7 Guido Trotter
386 949dcb1d Andrea Spadaccini
  def BuildHooksManager(self, lu):
387 949dcb1d Andrea Spadaccini
    return self.hmclass.BuildFromLu(lu.rpc.call_hooks_runner, lu)
388 949dcb1d Andrea Spadaccini
389 e4e59de8 Michael Hanselmann
  def _LockAndExecLU(self, lu, level, calc_timeout):
390 68adfdb2 Guido Trotter
    """Execute a Logical Unit, with the needed locks.
391 68adfdb2 Guido Trotter

392 68adfdb2 Guido Trotter
    This is a recursive function that starts locking the given level, and
393 68adfdb2 Guido Trotter
    proceeds up, till there are no more locks to acquire. Then it executes the
394 68adfdb2 Guido Trotter
    given LU and its opcodes.
395 68adfdb2 Guido Trotter

396 68adfdb2 Guido Trotter
    """
397 e9a81214 Michael Hanselmann
    glm = self.context.glm
398 ca2a79e1 Guido Trotter
    adding_locks = level in lu.add_locks
399 ca2a79e1 Guido Trotter
    acquiring_locks = level in lu.needed_locks
400 e9a81214 Michael Hanselmann
401 8a2941c4 Guido Trotter
    if level not in locking.LEVELS:
402 e9a81214 Michael Hanselmann
      _VerifyLocks(lu, glm)
403 e9a81214 Michael Hanselmann
404 031a3e57 Michael Hanselmann
      if self._cbs:
405 031a3e57 Michael Hanselmann
        self._cbs.NotifyStart()
406 031a3e57 Michael Hanselmann
407 b183c4a8 Iustin Pop
      try:
408 b183c4a8 Iustin Pop
        result = self._ExecLU(lu)
409 b183c4a8 Iustin Pop
      except AssertionError, err:
410 b183c4a8 Iustin Pop
        # this is a bit ugly, as we don't know from which phase
411 b183c4a8 Iustin Pop
        # (prereq, exec) this comes; but it's better than an exception
412 b183c4a8 Iustin Pop
        # with no information
413 b183c4a8 Iustin Pop
        (_, _, tb) = sys.exc_info()
414 b183c4a8 Iustin Pop
        err_info = traceback.format_tb(tb)
415 b183c4a8 Iustin Pop
        del tb
416 b183c4a8 Iustin Pop
        logging.exception("Detected AssertionError")
417 b183c4a8 Iustin Pop
        raise errors.OpExecError("Internal assertion error: please report"
418 b183c4a8 Iustin Pop
                                 " this as a bug.\nError message: '%s';"
419 b183c4a8 Iustin Pop
                                 " location:\n%s" % (str(err), err_info[-1]))
420 407339d0 Michael Hanselmann
421 ca2a79e1 Guido Trotter
    elif adding_locks and acquiring_locks:
422 ca2a79e1 Guido Trotter
      # We could both acquire and add locks at the same level, but for now we
423 ca2a79e1 Guido Trotter
      # don't need this, so we'll avoid the complicated code needed.
424 407339d0 Michael Hanselmann
      raise NotImplementedError("Can't declare locks to acquire when adding"
425 407339d0 Michael Hanselmann
                                " others")
426 407339d0 Michael Hanselmann
427 ca2a79e1 Guido Trotter
    elif adding_locks or acquiring_locks:
428 dc4bdf73 Michael Hanselmann
      self._CheckLocksEnabled()
429 dc4bdf73 Michael Hanselmann
430 fb8dcb62 Guido Trotter
      lu.DeclareLocks(level)
431 3977a4c1 Guido Trotter
      share = lu.share_locks[level]
432 686d24f0 Michael Hanselmann
      opportunistic = lu.opportunistic_locks[level]
433 407339d0 Michael Hanselmann
434 68adfdb2 Guido Trotter
      try:
435 407339d0 Michael Hanselmann
        assert adding_locks ^ acquiring_locks, \
436 407339d0 Michael Hanselmann
          "Locks must be either added or acquired"
437 407339d0 Michael Hanselmann
438 407339d0 Michael Hanselmann
        if acquiring_locks:
439 407339d0 Michael Hanselmann
          # Acquiring locks
440 407339d0 Michael Hanselmann
          needed_locks = lu.needed_locks[level]
441 407339d0 Michael Hanselmann
442 686d24f0 Michael Hanselmann
          self._AcquireLocks(level, needed_locks, share, opportunistic,
443 e4e59de8 Michael Hanselmann
                             calc_timeout())
444 407339d0 Michael Hanselmann
        else:
445 407339d0 Michael Hanselmann
          # Adding locks
446 407339d0 Michael Hanselmann
          add_locks = lu.add_locks[level]
447 407339d0 Michael Hanselmann
          lu.remove_locks[level] = add_locks
448 407339d0 Michael Hanselmann
449 407339d0 Michael Hanselmann
          try:
450 e9a81214 Michael Hanselmann
            glm.add(level, add_locks, acquired=1, shared=share)
451 407339d0 Michael Hanselmann
          except errors.LockError:
452 a9d40c65 Iustin Pop
            logging.exception("Detected lock error in level %s for locks"
453 a9d40c65 Iustin Pop
                              " %s, shared=%s", level, add_locks, share)
454 407339d0 Michael Hanselmann
            raise errors.OpPrereqError(
455 a9d40c65 Iustin Pop
              "Couldn't add locks (%s), most likely because of another"
456 a9d40c65 Iustin Pop
              " job who added them first" % add_locks,
457 a9d40c65 Iustin Pop
              errors.ECODE_NOTUNIQUE)
458 407339d0 Michael Hanselmann
459 ca2a79e1 Guido Trotter
        try:
460 e4e59de8 Michael Hanselmann
          result = self._LockAndExecLU(lu, level + 1, calc_timeout)
461 ca2a79e1 Guido Trotter
        finally:
462 ca2a79e1 Guido Trotter
          if level in lu.remove_locks:
463 e9a81214 Michael Hanselmann
            glm.remove(level, lu.remove_locks[level])
464 68adfdb2 Guido Trotter
      finally:
465 e9a81214 Michael Hanselmann
        if glm.is_owned(level):
466 e9a81214 Michael Hanselmann
          glm.release(level)
467 407339d0 Michael Hanselmann
468 68adfdb2 Guido Trotter
    else:
469 e4e59de8 Michael Hanselmann
      result = self._LockAndExecLU(lu, level + 1, calc_timeout)
470 68adfdb2 Guido Trotter
471 68adfdb2 Guido Trotter
    return result
472 68adfdb2 Guido Trotter
473 fdfa63cb Thomas Thrainer
  # pylint: disable=R0201
474 b8f45292 Thomas Thrainer
  def _CheckLUResult(self, op, result):
475 b8f45292 Thomas Thrainer
    """Check the LU result against the contract in the opcode.
476 b8f45292 Thomas Thrainer

477 b8f45292 Thomas Thrainer
    """
478 b8f45292 Thomas Thrainer
    resultcheck_fn = op.OP_RESULT
479 b8f45292 Thomas Thrainer
    if not (resultcheck_fn is None or resultcheck_fn(result)):
480 b8f45292 Thomas Thrainer
      logging.error("Expected opcode result matching %s, got %s",
481 b8f45292 Thomas Thrainer
                    resultcheck_fn, result)
482 b8f45292 Thomas Thrainer
      if not getattr(op, "dry_run", False):
483 b8f45292 Thomas Thrainer
        # FIXME: LUs should still behave in dry_run mode, or
484 b8f45292 Thomas Thrainer
        # alternately we should have OP_DRYRUN_RESULT; in the
485 b8f45292 Thomas Thrainer
        # meantime, we simply skip the OP_RESULT check in dry-run mode
486 b8f45292 Thomas Thrainer
        raise errors.OpResultError("Opcode result does not match %s: %s" %
487 b8f45292 Thomas Thrainer
                                   (resultcheck_fn, utils.Truncate(result, 80)))
488 b8f45292 Thomas Thrainer
489 e4e59de8 Michael Hanselmann
  def ExecOpCode(self, op, cbs, timeout=None):
490 a8083063 Iustin Pop
    """Execute an opcode.
491 a8083063 Iustin Pop

492 e92376d7 Iustin Pop
    @type op: an OpCode instance
493 e92376d7 Iustin Pop
    @param op: the opcode to be executed
494 031a3e57 Michael Hanselmann
    @type cbs: L{OpExecCbBase}
495 031a3e57 Michael Hanselmann
    @param cbs: Runtime callbacks
496 831bbbc1 Michael Hanselmann
    @type timeout: float or None
497 831bbbc1 Michael Hanselmann
    @param timeout: Maximum time to acquire all locks, None for no timeout
498 831bbbc1 Michael Hanselmann
    @raise LockAcquireTimeout: In case locks couldn't be acquired in specified
499 831bbbc1 Michael Hanselmann
        amount of time
500 a8083063 Iustin Pop

501 a8083063 Iustin Pop
    """
502 a8083063 Iustin Pop
    if not isinstance(op, opcodes.OpCode):
503 3ecf6786 Iustin Pop
      raise errors.ProgrammerError("Non-opcode instance passed"
504 c7bb3095 Michael Hanselmann
                                   " to ExecOpcode (%s)" % type(op))
505 a8083063 Iustin Pop
506 831bbbc1 Michael Hanselmann
    lu_class = self.DISPATCH_TABLE.get(op.__class__, None)
507 831bbbc1 Michael Hanselmann
    if lu_class is None:
508 831bbbc1 Michael Hanselmann
      raise errors.OpCodeUnknown("Unknown opcode")
509 831bbbc1 Michael Hanselmann
510 831bbbc1 Michael Hanselmann
    if timeout is None:
511 831bbbc1 Michael Hanselmann
      calc_timeout = lambda: None
512 831bbbc1 Michael Hanselmann
    else:
513 557838c1 René Nussbaumer
      calc_timeout = utils.RunningTimeout(timeout, False).Remaining
514 831bbbc1 Michael Hanselmann
515 031a3e57 Michael Hanselmann
    self._cbs = cbs
516 fe482621 Iustin Pop
    try:
517 dc4bdf73 Michael Hanselmann
      if self._enable_locks:
518 dc4bdf73 Michael Hanselmann
        # Acquire the Big Ganeti Lock exclusively if this LU requires it,
519 dc4bdf73 Michael Hanselmann
        # and in a shared fashion otherwise (to prevent concurrent run with
520 dc4bdf73 Michael Hanselmann
        # an exclusive LU.
521 dc4bdf73 Michael Hanselmann
        self._AcquireLocks(locking.LEVEL_CLUSTER, locking.BGL,
522 686d24f0 Michael Hanselmann
                            not lu_class.REQ_BGL, False, calc_timeout())
523 dc4bdf73 Michael Hanselmann
      elif lu_class.REQ_BGL:
524 dc4bdf73 Michael Hanselmann
        raise errors.ProgrammerError("Opcode '%s' requires BGL, but locks are"
525 dc4bdf73 Michael Hanselmann
                                     " disabled" % op.OP_ID)
526 dc4bdf73 Michael Hanselmann
527 831bbbc1 Michael Hanselmann
      try:
528 831bbbc1 Michael Hanselmann
        lu = lu_class(self, op, self.context, self.rpc)
529 831bbbc1 Michael Hanselmann
        lu.ExpandNames()
530 831bbbc1 Michael Hanselmann
        assert lu.needed_locks is not None, "needed_locks not set by LU"
531 407339d0 Michael Hanselmann
532 407339d0 Michael Hanselmann
        try:
533 46cde471 Michael Hanselmann
          result = self._LockAndExecLU(lu, locking.LEVEL_CLUSTER + 1,
534 46cde471 Michael Hanselmann
                                       calc_timeout)
535 831bbbc1 Michael Hanselmann
        finally:
536 831bbbc1 Michael Hanselmann
          if self._ec_id:
537 831bbbc1 Michael Hanselmann
            self.context.cfg.DropECReservations(self._ec_id)
538 831bbbc1 Michael Hanselmann
      finally:
539 dc4bdf73 Michael Hanselmann
        # Release BGL if owned
540 dc4bdf73 Michael Hanselmann
        if self.context.glm.is_owned(locking.LEVEL_CLUSTER):
541 dc4bdf73 Michael Hanselmann
          assert self._enable_locks
542 dc4bdf73 Michael Hanselmann
          self.context.glm.release(locking.LEVEL_CLUSTER)
543 04864530 Guido Trotter
    finally:
544 031a3e57 Michael Hanselmann
      self._cbs = None
545 6a4aa7c1 Iustin Pop
546 b8f45292 Thomas Thrainer
    self._CheckLUResult(op, result)
547 1ce03fb1 Michael Hanselmann
548 1ce03fb1 Michael Hanselmann
    return result
549 1ce03fb1 Michael Hanselmann
550 7b4c1cb9 Michael Hanselmann
  def Log(self, *args):
551 031a3e57 Michael Hanselmann
    """Forward call to feedback callback function.
552 031a3e57 Michael Hanselmann

553 031a3e57 Michael Hanselmann
    """
554 031a3e57 Michael Hanselmann
    if self._cbs:
555 031a3e57 Michael Hanselmann
      self._cbs.Feedback(*args)
556 031a3e57 Michael Hanselmann
557 0fbbf897 Iustin Pop
  def LogStep(self, current, total, message):
558 0fbbf897 Iustin Pop
    """Log a change in LU execution progress.
559 0fbbf897 Iustin Pop

560 0fbbf897 Iustin Pop
    """
561 a5eb7789 Iustin Pop
    logging.debug("Step %d/%d %s", current, total, message)
562 7b4c1cb9 Michael Hanselmann
    self.Log("STEP %d/%d %s" % (current, total, message))
563 0fbbf897 Iustin Pop
564 c0088fb9 Iustin Pop
  def LogWarning(self, message, *args, **kwargs):
565 0fbbf897 Iustin Pop
    """Log a warning to the logs and the user.
566 0fbbf897 Iustin Pop

567 c0088fb9 Iustin Pop
    The optional keyword argument is 'hint' and can be used to show a
568 c0088fb9 Iustin Pop
    hint to the user (presumably related to the warning). If the
569 c0088fb9 Iustin Pop
    message is empty, it will not be printed at all, allowing one to
570 c0088fb9 Iustin Pop
    show only a hint.
571 0fbbf897 Iustin Pop

572 c0088fb9 Iustin Pop
    """
573 c0088fb9 Iustin Pop
    assert not kwargs or (len(kwargs) == 1 and "hint" in kwargs), \
574 c0088fb9 Iustin Pop
           "Invalid keyword arguments for LogWarning (%s)" % str(kwargs)
575 c0088fb9 Iustin Pop
    if args:
576 c0088fb9 Iustin Pop
      message = message % tuple(args)
577 c0088fb9 Iustin Pop
    if message:
578 c0088fb9 Iustin Pop
      logging.warning(message)
579 7b4c1cb9 Michael Hanselmann
      self.Log(" - WARNING: %s" % message)
580 c0088fb9 Iustin Pop
    if "hint" in kwargs:
581 7b4c1cb9 Michael Hanselmann
      self.Log("      Hint: %s" % kwargs["hint"])
582 c0088fb9 Iustin Pop
583 c0088fb9 Iustin Pop
  def LogInfo(self, message, *args):
584 0fbbf897 Iustin Pop
    """Log an informational message to the logs and the user.
585 0fbbf897 Iustin Pop

586 0fbbf897 Iustin Pop
    """
587 c0088fb9 Iustin Pop
    if args:
588 c0088fb9 Iustin Pop
      message = message % tuple(args)
589 a5eb7789 Iustin Pop
    logging.info(message)
590 7b4c1cb9 Michael Hanselmann
    self.Log(" - INFO: %s" % message)
591 0fbbf897 Iustin Pop
592 adfa97e3 Guido Trotter
  def GetECId(self):
593 3ae70d76 Michael Hanselmann
    """Returns the current execution context ID.
594 3ae70d76 Michael Hanselmann

595 3ae70d76 Michael Hanselmann
    """
596 adfa97e3 Guido Trotter
    if not self._ec_id:
597 3ae70d76 Michael Hanselmann
      raise errors.ProgrammerError("Tried to use execution context id when"
598 3ae70d76 Michael Hanselmann
                                   " not set")
599 adfa97e3 Guido Trotter
    return self._ec_id