Statistics
| Branch: | Tag: | Revision:

root / lib / mcpu.py @ b54ecf12

History | View | Annotate | Download (17.9 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 a8083063 Iustin Pop
from ganeti import constants
40 a8083063 Iustin Pop
from ganeti import errors
41 68d95757 Guido Trotter
from ganeti import hooksmaster
42 a8083063 Iustin Pop
from ganeti import cmdlib
43 04864530 Guido Trotter
from ganeti import locking
44 557838c1 René Nussbaumer
from ganeti import utils
45 ebc75510 Michael Hanselmann
from ganeti import compat
46 a8083063 Iustin Pop
47 7c0d6283 Michael Hanselmann
48 a1a7bc78 Iustin Pop
_OP_PREFIX = "Op"
49 a1a7bc78 Iustin Pop
_LU_PREFIX = "LU"
50 a1a7bc78 Iustin Pop
51 e9a81214 Michael Hanselmann
#: LU classes which don't need to acquire the node allocation lock
52 e9a81214 Michael Hanselmann
#: (L{locking.NAL}) when they acquire all node or node resource locks
53 b8028dcf Michael Hanselmann
_NODE_ALLOC_WHITELIST = frozenset([])
54 e9a81214 Michael Hanselmann
55 e9a81214 Michael Hanselmann
#: LU classes which don't need to acquire the node allocation lock
56 e9a81214 Michael Hanselmann
#: (L{locking.NAL}) in the same mode (shared/exclusive) as the node
57 e9a81214 Michael Hanselmann
#: or node resource locks
58 b8028dcf Michael Hanselmann
_NODE_ALLOC_MODE_WHITELIST = compat.UniqueFrozenset([
59 e9a81214 Michael Hanselmann
  cmdlib.LUBackupExport,
60 e9a81214 Michael Hanselmann
  cmdlib.LUBackupRemove,
61 e9a81214 Michael Hanselmann
  cmdlib.LUOobCommand,
62 e9a81214 Michael Hanselmann
  ])
63 e9a81214 Michael Hanselmann
64 a1a7bc78 Iustin Pop
65 831bbbc1 Michael Hanselmann
class LockAcquireTimeout(Exception):
66 831bbbc1 Michael Hanselmann
  """Exception to report timeouts on acquiring locks.
67 407339d0 Michael Hanselmann

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

475 e92376d7 Iustin Pop
    @type op: an OpCode instance
476 e92376d7 Iustin Pop
    @param op: the opcode to be executed
477 031a3e57 Michael Hanselmann
    @type cbs: L{OpExecCbBase}
478 031a3e57 Michael Hanselmann
    @param cbs: Runtime callbacks
479 831bbbc1 Michael Hanselmann
    @type timeout: float or None
480 831bbbc1 Michael Hanselmann
    @param timeout: Maximum time to acquire all locks, None for no timeout
481 831bbbc1 Michael Hanselmann
    @raise LockAcquireTimeout: In case locks couldn't be acquired in specified
482 831bbbc1 Michael Hanselmann
        amount of time
483 a8083063 Iustin Pop

484 a8083063 Iustin Pop
    """
485 a8083063 Iustin Pop
    if not isinstance(op, opcodes.OpCode):
486 3ecf6786 Iustin Pop
      raise errors.ProgrammerError("Non-opcode instance passed"
487 c7bb3095 Michael Hanselmann
                                   " to ExecOpcode (%s)" % type(op))
488 a8083063 Iustin Pop
489 831bbbc1 Michael Hanselmann
    lu_class = self.DISPATCH_TABLE.get(op.__class__, None)
490 831bbbc1 Michael Hanselmann
    if lu_class is None:
491 831bbbc1 Michael Hanselmann
      raise errors.OpCodeUnknown("Unknown opcode")
492 831bbbc1 Michael Hanselmann
493 831bbbc1 Michael Hanselmann
    if timeout is None:
494 831bbbc1 Michael Hanselmann
      calc_timeout = lambda: None
495 831bbbc1 Michael Hanselmann
    else:
496 557838c1 René Nussbaumer
      calc_timeout = utils.RunningTimeout(timeout, False).Remaining
497 831bbbc1 Michael Hanselmann
498 031a3e57 Michael Hanselmann
    self._cbs = cbs
499 fe482621 Iustin Pop
    try:
500 dc4bdf73 Michael Hanselmann
      if self._enable_locks:
501 dc4bdf73 Michael Hanselmann
        # Acquire the Big Ganeti Lock exclusively if this LU requires it,
502 dc4bdf73 Michael Hanselmann
        # and in a shared fashion otherwise (to prevent concurrent run with
503 dc4bdf73 Michael Hanselmann
        # an exclusive LU.
504 dc4bdf73 Michael Hanselmann
        self._AcquireLocks(locking.LEVEL_CLUSTER, locking.BGL,
505 686d24f0 Michael Hanselmann
                            not lu_class.REQ_BGL, False, calc_timeout())
506 dc4bdf73 Michael Hanselmann
      elif lu_class.REQ_BGL:
507 dc4bdf73 Michael Hanselmann
        raise errors.ProgrammerError("Opcode '%s' requires BGL, but locks are"
508 dc4bdf73 Michael Hanselmann
                                     " disabled" % op.OP_ID)
509 dc4bdf73 Michael Hanselmann
510 831bbbc1 Michael Hanselmann
      try:
511 831bbbc1 Michael Hanselmann
        lu = lu_class(self, op, self.context, self.rpc)
512 831bbbc1 Michael Hanselmann
        lu.ExpandNames()
513 831bbbc1 Michael Hanselmann
        assert lu.needed_locks is not None, "needed_locks not set by LU"
514 407339d0 Michael Hanselmann
515 407339d0 Michael Hanselmann
        try:
516 46cde471 Michael Hanselmann
          result = self._LockAndExecLU(lu, locking.LEVEL_CLUSTER + 1,
517 46cde471 Michael Hanselmann
                                       calc_timeout)
518 831bbbc1 Michael Hanselmann
        finally:
519 831bbbc1 Michael Hanselmann
          if self._ec_id:
520 831bbbc1 Michael Hanselmann
            self.context.cfg.DropECReservations(self._ec_id)
521 831bbbc1 Michael Hanselmann
      finally:
522 dc4bdf73 Michael Hanselmann
        # Release BGL if owned
523 dc4bdf73 Michael Hanselmann
        if self.context.glm.is_owned(locking.LEVEL_CLUSTER):
524 dc4bdf73 Michael Hanselmann
          assert self._enable_locks
525 dc4bdf73 Michael Hanselmann
          self.context.glm.release(locking.LEVEL_CLUSTER)
526 04864530 Guido Trotter
    finally:
527 031a3e57 Michael Hanselmann
      self._cbs = None
528 6a4aa7c1 Iustin Pop
529 1ce03fb1 Michael Hanselmann
    resultcheck_fn = op.OP_RESULT
530 1ce03fb1 Michael Hanselmann
    if not (resultcheck_fn is None or resultcheck_fn(result)):
531 1ce03fb1 Michael Hanselmann
      logging.error("Expected opcode result matching %s, got %s",
532 1ce03fb1 Michael Hanselmann
                    resultcheck_fn, result)
533 80b207df Iustin Pop
      if not getattr(op, "dry_run", False):
534 80b207df Iustin Pop
        # FIXME: LUs should still behave in dry_run mode, or
535 80b207df Iustin Pop
        # alternately we should have OP_DRYRUN_RESULT; in the
536 80b207df Iustin Pop
        # meantime, we simply skip the OP_RESULT check in dry-run mode
537 80b207df Iustin Pop
        raise errors.OpResultError("Opcode result does not match %s: %s" %
538 80b207df Iustin Pop
                                   (resultcheck_fn, utils.Truncate(result, 80)))
539 1ce03fb1 Michael Hanselmann
540 1ce03fb1 Michael Hanselmann
    return result
541 1ce03fb1 Michael Hanselmann
542 7b4c1cb9 Michael Hanselmann
  def Log(self, *args):
543 031a3e57 Michael Hanselmann
    """Forward call to feedback callback function.
544 031a3e57 Michael Hanselmann

545 031a3e57 Michael Hanselmann
    """
546 031a3e57 Michael Hanselmann
    if self._cbs:
547 031a3e57 Michael Hanselmann
      self._cbs.Feedback(*args)
548 031a3e57 Michael Hanselmann
549 0fbbf897 Iustin Pop
  def LogStep(self, current, total, message):
550 0fbbf897 Iustin Pop
    """Log a change in LU execution progress.
551 0fbbf897 Iustin Pop

552 0fbbf897 Iustin Pop
    """
553 a5eb7789 Iustin Pop
    logging.debug("Step %d/%d %s", current, total, message)
554 7b4c1cb9 Michael Hanselmann
    self.Log("STEP %d/%d %s" % (current, total, message))
555 0fbbf897 Iustin Pop
556 c0088fb9 Iustin Pop
  def LogWarning(self, message, *args, **kwargs):
557 0fbbf897 Iustin Pop
    """Log a warning to the logs and the user.
558 0fbbf897 Iustin Pop

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

564 c0088fb9 Iustin Pop
    """
565 c0088fb9 Iustin Pop
    assert not kwargs or (len(kwargs) == 1 and "hint" in kwargs), \
566 c0088fb9 Iustin Pop
           "Invalid keyword arguments for LogWarning (%s)" % str(kwargs)
567 c0088fb9 Iustin Pop
    if args:
568 c0088fb9 Iustin Pop
      message = message % tuple(args)
569 c0088fb9 Iustin Pop
    if message:
570 c0088fb9 Iustin Pop
      logging.warning(message)
571 7b4c1cb9 Michael Hanselmann
      self.Log(" - WARNING: %s" % message)
572 c0088fb9 Iustin Pop
    if "hint" in kwargs:
573 7b4c1cb9 Michael Hanselmann
      self.Log("      Hint: %s" % kwargs["hint"])
574 c0088fb9 Iustin Pop
575 c0088fb9 Iustin Pop
  def LogInfo(self, message, *args):
576 0fbbf897 Iustin Pop
    """Log an informational message to the logs and the user.
577 0fbbf897 Iustin Pop

578 0fbbf897 Iustin Pop
    """
579 c0088fb9 Iustin Pop
    if args:
580 c0088fb9 Iustin Pop
      message = message % tuple(args)
581 a5eb7789 Iustin Pop
    logging.info(message)
582 7b4c1cb9 Michael Hanselmann
    self.Log(" - INFO: %s" % message)
583 0fbbf897 Iustin Pop
584 adfa97e3 Guido Trotter
  def GetECId(self):
585 3ae70d76 Michael Hanselmann
    """Returns the current execution context ID.
586 3ae70d76 Michael Hanselmann

587 3ae70d76 Michael Hanselmann
    """
588 adfa97e3 Guido Trotter
    if not self._ec_id:
589 3ae70d76 Michael Hanselmann
      raise errors.ProgrammerError("Tried to use execution context id when"
590 3ae70d76 Michael Hanselmann
                                   " not set")
591 adfa97e3 Guido Trotter
    return self._ec_id