Statistics
| Branch: | Tag: | Revision:

root / lib / mcpu.py @ 5349519d

History | View | Annotate | Download (18.3 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 e9cf6af0 Klaus Aehlig
  # FIXME: extend reason trail, showing the derivedness
215 e9cf6af0 Klaus Aehlig
  if not getattr(dst, constants.OPCODE_REASON, None):
216 e9cf6af0 Klaus Aehlig
    dst.reason = getattr(src, constants.OPCODE_REASON, [])
217 e9cf6af0 Klaus Aehlig
218 07923a3c Michael Hanselmann
219 07923a3c Michael Hanselmann
def _ProcessResult(submit_fn, op, result):
220 07923a3c Michael Hanselmann
  """Examines opcode result.
221 07923a3c Michael Hanselmann

222 07923a3c Michael Hanselmann
  If necessary, additional processing on the result is done.
223 07923a3c Michael Hanselmann

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

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

257 e9a81214 Michael Hanselmann
  @type lu: L{cmdlib.LogicalUnit}
258 e9a81214 Michael Hanselmann
  @param lu: Logical unit instance
259 e9a81214 Michael Hanselmann
  @type glm: L{locking.GanetiLockManager}
260 e9a81214 Michael Hanselmann
  @param glm: Lock manager
261 e9a81214 Michael Hanselmann

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

298 adfa97e3 Guido Trotter
    @type context: GanetiContext
299 adfa97e3 Guido Trotter
    @param context: global Ganeti context
300 adfa97e3 Guido Trotter
    @type ec_id: string
301 adfa97e3 Guido Trotter
    @param ec_id: execution context identifier
302 adfa97e3 Guido Trotter

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

314 dc4bdf73 Michael Hanselmann
    @raise errors.ProgrammerError: In case locking is not enabled
315 dc4bdf73 Michael Hanselmann

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

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

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

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

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

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

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

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

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

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

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

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

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

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

599 3ae70d76 Michael Hanselmann
    """
600 adfa97e3 Guido Trotter
    if not self._ec_id:
601 3ae70d76 Michael Hanselmann
      raise errors.ProgrammerError("Tried to use execution context id when"
602 3ae70d76 Michael Hanselmann
                                   " not set")
603 adfa97e3 Guido Trotter
    return self._ec_id