Statistics
| Branch: | Tag: | Revision:

root / lib / mcpu.py @ 808cb0ee

History | View | Annotate | Download (20.5 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 87ed6b79 Klaus Aehlig
from ganeti import wconfd
48 a8083063 Iustin Pop
49 7c0d6283 Michael Hanselmann
50 a1a7bc78 Iustin Pop
_OP_PREFIX = "Op"
51 a1a7bc78 Iustin Pop
_LU_PREFIX = "LU"
52 a1a7bc78 Iustin Pop
53 e9a81214 Michael Hanselmann
#: LU classes which don't need to acquire the node allocation lock
54 e9a81214 Michael Hanselmann
#: (L{locking.NAL}) when they acquire all node or node resource locks
55 b8028dcf Michael Hanselmann
_NODE_ALLOC_WHITELIST = frozenset([])
56 e9a81214 Michael Hanselmann
57 e9a81214 Michael Hanselmann
#: LU classes which don't need to acquire the node allocation lock
58 e9a81214 Michael Hanselmann
#: (L{locking.NAL}) in the same mode (shared/exclusive) as the node
59 e9a81214 Michael Hanselmann
#: or node resource locks
60 b8028dcf Michael Hanselmann
_NODE_ALLOC_MODE_WHITELIST = compat.UniqueFrozenset([
61 e9a81214 Michael Hanselmann
  cmdlib.LUBackupExport,
62 e9a81214 Michael Hanselmann
  cmdlib.LUBackupRemove,
63 e9a81214 Michael Hanselmann
  cmdlib.LUOobCommand,
64 e9a81214 Michael Hanselmann
  ])
65 e9a81214 Michael Hanselmann
66 a1a7bc78 Iustin Pop
67 831bbbc1 Michael Hanselmann
class LockAcquireTimeout(Exception):
68 831bbbc1 Michael Hanselmann
  """Exception to report timeouts on acquiring locks.
69 407339d0 Michael Hanselmann

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

204 07923a3c Michael Hanselmann
  """
205 07923a3c Michael Hanselmann
  if hasattr(src, "debug_level"):
206 07923a3c Michael Hanselmann
    dst.debug_level = src.debug_level
207 07923a3c Michael Hanselmann
208 07923a3c Michael Hanselmann
  if (getattr(dst, "priority", None) is None and
209 07923a3c Michael Hanselmann
      hasattr(src, "priority")):
210 07923a3c Michael Hanselmann
    dst.priority = src.priority
211 07923a3c Michael Hanselmann
212 580b1fdd Jose A. Lopes
  if not getattr(dst, opcodes_base.COMMENT_ATTR, None):
213 07923a3c Michael Hanselmann
    dst.comment = defcomment
214 07923a3c Michael Hanselmann
215 0511c075 Klaus Aehlig
  if hasattr(src, constants.OPCODE_REASON):
216 0511c075 Klaus Aehlig
    dst.reason = getattr(dst, constants.OPCODE_REASON, [])
217 0511c075 Klaus Aehlig
    dst.reason.extend(getattr(src, constants.OPCODE_REASON, []))
218 e9cf6af0 Klaus Aehlig
219 07923a3c Michael Hanselmann
220 07923a3c Michael Hanselmann
def _ProcessResult(submit_fn, op, result):
221 07923a3c Michael Hanselmann
  """Examines opcode result.
222 07923a3c Michael Hanselmann

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

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

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

258 e9a81214 Michael Hanselmann
  @type lu: L{cmdlib.LogicalUnit}
259 e9a81214 Michael Hanselmann
  @param lu: Logical unit instance
260 e9a81214 Michael Hanselmann

261 e9a81214 Michael Hanselmann
  """
262 e9a81214 Michael Hanselmann
  if not __debug__:
263 e9a81214 Michael Hanselmann
    return
264 e9a81214 Michael Hanselmann
265 87ed6b79 Klaus Aehlig
  allocset = lu.owned_locks(locking.LEVEL_NODE_ALLOC)
266 87ed6b79 Klaus Aehlig
  have_nal = locking.NAL in allocset
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 87ed6b79 Klaus Aehlig
      elif lu.needed_locks[level] == locking.ALL_SET:
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 185192f2 Petr Pudlak
def _LockList(names):
292 7dc359f0 Petr Pudlak
  """If 'names' is a string, make it a single-element list.
293 185192f2 Petr Pudlak

294 7dc359f0 Petr Pudlak
  @type names: list or string
295 7dc359f0 Petr Pudlak
  @param names: Lock names
296 7dc359f0 Petr Pudlak
  @rtype: a list of strings
297 7dc359f0 Petr Pudlak
  @return: if 'names' argument is an iterable, a list of it;
298 7dc359f0 Petr Pudlak
      if it's a string, make it a one-element list
299 185192f2 Petr Pudlak

300 7dc359f0 Petr Pudlak
  """
301 7dc359f0 Petr Pudlak
  return [names] if isinstance(names, basestring) else list(names)
302 185192f2 Petr Pudlak
303 185192f2 Petr Pudlak
304 a8083063 Iustin Pop
class Processor(object):
305 a8083063 Iustin Pop
  """Object which runs OpCodes"""
306 a1a7bc78 Iustin Pop
  DISPATCH_TABLE = _ComputeDispatchTable()
307 a8083063 Iustin Pop
308 dc4bdf73 Michael Hanselmann
  def __init__(self, context, ec_id, enable_locks=True):
309 a8083063 Iustin Pop
    """Constructor for Processor
310 a8083063 Iustin Pop

311 adfa97e3 Guido Trotter
    @type context: GanetiContext
312 adfa97e3 Guido Trotter
    @param context: global Ganeti context
313 adfa97e3 Guido Trotter
    @type ec_id: string
314 adfa97e3 Guido Trotter
    @param ec_id: execution context identifier
315 adfa97e3 Guido Trotter

316 a8083063 Iustin Pop
    """
317 1c901d13 Guido Trotter
    self.context = context
318 adfa97e3 Guido Trotter
    self._ec_id = ec_id
319 031a3e57 Michael Hanselmann
    self._cbs = None
320 f47b32a8 Petr Pudlak
    self.cfg = context.GetConfig(ec_id)
321 f47b32a8 Petr Pudlak
    self.rpc = context.GetRpc(self.cfg)
322 68d95757 Guido Trotter
    self.hmclass = hooksmaster.HooksMaster
323 dc4bdf73 Michael Hanselmann
    self._enable_locks = enable_locks
324 87ed6b79 Klaus Aehlig
    self.wconfd = wconfd # Indirection to allow testing
325 a13e1743 Petr Pudlak
    self._wconfdcontext = context.GetWConfdContext(ec_id)
326 a13e1743 Petr Pudlak
327 dc4bdf73 Michael Hanselmann
  def _CheckLocksEnabled(self):
328 dc4bdf73 Michael Hanselmann
    """Checks if locking is enabled.
329 dc4bdf73 Michael Hanselmann

330 dc4bdf73 Michael Hanselmann
    @raise errors.ProgrammerError: In case locking is not enabled
331 dc4bdf73 Michael Hanselmann

332 dc4bdf73 Michael Hanselmann
    """
333 dc4bdf73 Michael Hanselmann
    if not self._enable_locks:
334 dc4bdf73 Michael Hanselmann
      raise errors.ProgrammerError("Attempted to use disabled locks")
335 a8083063 Iustin Pop
336 686d24f0 Michael Hanselmann
  def _AcquireLocks(self, level, names, shared, opportunistic, timeout):
337 211b6132 Michael Hanselmann
    """Acquires locks via the Ganeti lock manager.
338 211b6132 Michael Hanselmann

339 211b6132 Michael Hanselmann
    @type level: int
340 211b6132 Michael Hanselmann
    @param level: Lock level
341 211b6132 Michael Hanselmann
    @type names: list or string
342 211b6132 Michael Hanselmann
    @param names: Lock names
343 211b6132 Michael Hanselmann
    @type shared: bool
344 211b6132 Michael Hanselmann
    @param shared: Whether the locks should be acquired in shared mode
345 686d24f0 Michael Hanselmann
    @type opportunistic: bool
346 686d24f0 Michael Hanselmann
    @param opportunistic: Whether to acquire opportunistically
347 211b6132 Michael Hanselmann
    @type timeout: None or float
348 211b6132 Michael Hanselmann
    @param timeout: Timeout for acquiring the locks
349 900df6cd Michael Hanselmann
    @raise LockAcquireTimeout: In case locks couldn't be acquired in specified
350 900df6cd Michael Hanselmann
        amount of time
351 211b6132 Michael Hanselmann

352 211b6132 Michael Hanselmann
    """
353 dc4bdf73 Michael Hanselmann
    self._CheckLocksEnabled()
354 dc4bdf73 Michael Hanselmann
355 87ed6b79 Klaus Aehlig
    # TODO: honor priority in lock allocation
356 acf931b7 Michael Hanselmann
    if self._cbs:
357 87ed6b79 Klaus Aehlig
      priority = self._cbs.CurrentPriority() # pylint: disable=W0612
358 e4e59de8 Michael Hanselmann
    else:
359 e4e59de8 Michael Hanselmann
      priority = None
360 211b6132 Michael Hanselmann
361 87ed6b79 Klaus Aehlig
    if names == locking.ALL_SET:
362 87ed6b79 Klaus Aehlig
      if opportunistic:
363 87ed6b79 Klaus Aehlig
        expand_fns = {
364 87ed6b79 Klaus Aehlig
          locking.LEVEL_CLUSTER: (lambda: [locking.BGL]),
365 f47b32a8 Petr Pudlak
          locking.LEVEL_INSTANCE: self.cfg.GetInstanceList,
366 87ed6b79 Klaus Aehlig
          locking.LEVEL_NODE_ALLOC: (lambda: [locking.NAL]),
367 f47b32a8 Petr Pudlak
          locking.LEVEL_NODEGROUP: self.cfg.GetNodeGroupList,
368 f47b32a8 Petr Pudlak
          locking.LEVEL_NODE: self.cfg.GetNodeList,
369 f47b32a8 Petr Pudlak
          locking.LEVEL_NODE_RES: self.cfg.GetNodeList,
370 f47b32a8 Petr Pudlak
          locking.LEVEL_NETWORK: self.cfg.GetNetworkList,
371 87ed6b79 Klaus Aehlig
          }
372 87ed6b79 Klaus Aehlig
        names = expand_fns[level]()
373 87ed6b79 Klaus Aehlig
      else:
374 87ed6b79 Klaus Aehlig
        names = locking.LOCKSET_NAME
375 87ed6b79 Klaus Aehlig
376 185192f2 Petr Pudlak
    names = _LockList(names)
377 87ed6b79 Klaus Aehlig
378 87ed6b79 Klaus Aehlig
    levelname = locking.LEVEL_NAMES[level]
379 87ed6b79 Klaus Aehlig
380 87ed6b79 Klaus Aehlig
    locks = ["%s/%s" % (levelname, lock) for lock in list(names)]
381 211b6132 Michael Hanselmann
382 87ed6b79 Klaus Aehlig
    if not names:
383 6ea039ef Petr Pudlak
      logging.debug("Acquiring no locks for (%s) at level %s",
384 6ea039ef Petr Pudlak
                    self._wconfdcontext, levelname)
385 87ed6b79 Klaus Aehlig
      return []
386 900df6cd Michael Hanselmann
387 87ed6b79 Klaus Aehlig
    if shared:
388 87ed6b79 Klaus Aehlig
      request = [[lock, "shared"] for lock in locks]
389 87ed6b79 Klaus Aehlig
    else:
390 87ed6b79 Klaus Aehlig
      request = [[lock, "exclusive"] for lock in locks]
391 87ed6b79 Klaus Aehlig
392 87ed6b79 Klaus Aehlig
    if opportunistic:
393 6ea039ef Petr Pudlak
      logging.debug("Opportunistically acquring some of %s for %s.",
394 6ea039ef Petr Pudlak
                    locks, self._wconfdcontext)
395 6ea039ef Petr Pudlak
      locks = self.wconfd.Client().OpportunisticLockUnion(self._wconfdcontext,
396 87ed6b79 Klaus Aehlig
                                                          request)
397 87ed6b79 Klaus Aehlig
    elif timeout is None:
398 87ed6b79 Klaus Aehlig
      while True:
399 87ed6b79 Klaus Aehlig
        ## TODO: use asynchronous wait instead of polling
400 6ea039ef Petr Pudlak
        blockedon = self.wconfd.Client().TryUpdateLocks(self._wconfdcontext,
401 87ed6b79 Klaus Aehlig
                                                        request)
402 6ea039ef Petr Pudlak
        logging.debug("Requesting %s for %s blocked on %s",
403 6ea039ef Petr Pudlak
                      request, self._wconfdcontext, blockedon)
404 87ed6b79 Klaus Aehlig
        if not blockedon:
405 87ed6b79 Klaus Aehlig
          break
406 87ed6b79 Klaus Aehlig
        time.sleep(random.random())
407 87ed6b79 Klaus Aehlig
    else:
408 6ea039ef Petr Pudlak
      logging.debug("Trying %ss to request %s for %s",
409 6ea039ef Petr Pudlak
                    timeout, request, self._wconfdcontext)
410 87ed6b79 Klaus Aehlig
      ## TODO: use blocking wait instead of polling
411 87ed6b79 Klaus Aehlig
      blocked = utils.SimpleRetry([], self.wconfd.Client().TryUpdateLocks, 0.1,
412 6ea039ef Petr Pudlak
                                  timeout, args=[self._wconfdcontext, request])
413 87ed6b79 Klaus Aehlig
      if blocked:
414 87ed6b79 Klaus Aehlig
        raise LockAcquireTimeout()
415 87ed6b79 Klaus Aehlig
416 87ed6b79 Klaus Aehlig
    return locks
417 211b6132 Michael Hanselmann
418 36c381d7 Guido Trotter
  def _ExecLU(self, lu):
419 36c381d7 Guido Trotter
    """Logical Unit execution sequence.
420 36c381d7 Guido Trotter

421 36c381d7 Guido Trotter
    """
422 f47b32a8 Petr Pudlak
    write_count = self.cfg.write_count
423 36c381d7 Guido Trotter
    lu.CheckPrereq()
424 949dcb1d Andrea Spadaccini
425 949dcb1d Andrea Spadaccini
    hm = self.BuildHooksManager(lu)
426 36c381d7 Guido Trotter
    h_results = hm.RunPhase(constants.HOOKS_PHASE_PRE)
427 36c381d7 Guido Trotter
    lu.HooksCallBack(constants.HOOKS_PHASE_PRE, h_results,
428 7b4c1cb9 Michael Hanselmann
                     self.Log, None)
429 20777413 Iustin Pop
430 20777413 Iustin Pop
    if getattr(lu.op, "dry_run", False):
431 20777413 Iustin Pop
      # in this mode, no post-hooks are run, and the config is not
432 20777413 Iustin Pop
      # written (as it might have been modified by another LU, and we
433 20777413 Iustin Pop
      # shouldn't do writeout on behalf of other threads
434 20777413 Iustin Pop
      self.LogInfo("dry-run mode requested, not actually executing"
435 20777413 Iustin Pop
                   " the operation")
436 20777413 Iustin Pop
      return lu.dry_run_result
437 20777413 Iustin Pop
438 abe362d3 Michael Hanselmann
    if self._cbs:
439 abe362d3 Michael Hanselmann
      submit_mj_fn = self._cbs.SubmitManyJobs
440 abe362d3 Michael Hanselmann
    else:
441 abe362d3 Michael Hanselmann
      submit_mj_fn = _FailingSubmitManyJobs
442 abe362d3 Michael Hanselmann
443 36c381d7 Guido Trotter
    try:
444 abe362d3 Michael Hanselmann
      result = _ProcessResult(submit_mj_fn, lu.op, lu.Exec(self.Log))
445 36c381d7 Guido Trotter
      h_results = hm.RunPhase(constants.HOOKS_PHASE_POST)
446 36c381d7 Guido Trotter
      result = lu.HooksCallBack(constants.HOOKS_PHASE_POST, h_results,
447 7b4c1cb9 Michael Hanselmann
                                self.Log, result)
448 36c381d7 Guido Trotter
    finally:
449 36c381d7 Guido Trotter
      # FIXME: This needs locks if not lu_class.REQ_BGL
450 f47b32a8 Petr Pudlak
      if write_count != self.cfg.write_count:
451 36c381d7 Guido Trotter
        hm.RunConfigUpdate()
452 36c381d7 Guido Trotter
453 36c381d7 Guido Trotter
    return result
454 36c381d7 Guido Trotter
455 949dcb1d Andrea Spadaccini
  def BuildHooksManager(self, lu):
456 949dcb1d Andrea Spadaccini
    return self.hmclass.BuildFromLu(lu.rpc.call_hooks_runner, lu)
457 949dcb1d Andrea Spadaccini
458 e4e59de8 Michael Hanselmann
  def _LockAndExecLU(self, lu, level, calc_timeout):
459 68adfdb2 Guido Trotter
    """Execute a Logical Unit, with the needed locks.
460 68adfdb2 Guido Trotter

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

465 68adfdb2 Guido Trotter
    """
466 ca2a79e1 Guido Trotter
    adding_locks = level in lu.add_locks
467 ca2a79e1 Guido Trotter
    acquiring_locks = level in lu.needed_locks
468 e9a81214 Michael Hanselmann
469 8a2941c4 Guido Trotter
    if level not in locking.LEVELS:
470 87ed6b79 Klaus Aehlig
      _VerifyLocks(lu)
471 e9a81214 Michael Hanselmann
472 031a3e57 Michael Hanselmann
      if self._cbs:
473 031a3e57 Michael Hanselmann
        self._cbs.NotifyStart()
474 031a3e57 Michael Hanselmann
475 b183c4a8 Iustin Pop
      try:
476 b183c4a8 Iustin Pop
        result = self._ExecLU(lu)
477 b183c4a8 Iustin Pop
      except AssertionError, err:
478 b183c4a8 Iustin Pop
        # this is a bit ugly, as we don't know from which phase
479 b183c4a8 Iustin Pop
        # (prereq, exec) this comes; but it's better than an exception
480 b183c4a8 Iustin Pop
        # with no information
481 b183c4a8 Iustin Pop
        (_, _, tb) = sys.exc_info()
482 b183c4a8 Iustin Pop
        err_info = traceback.format_tb(tb)
483 b183c4a8 Iustin Pop
        del tb
484 b183c4a8 Iustin Pop
        logging.exception("Detected AssertionError")
485 b183c4a8 Iustin Pop
        raise errors.OpExecError("Internal assertion error: please report"
486 b183c4a8 Iustin Pop
                                 " this as a bug.\nError message: '%s';"
487 b183c4a8 Iustin Pop
                                 " location:\n%s" % (str(err), err_info[-1]))
488 407339d0 Michael Hanselmann
489 ca2a79e1 Guido Trotter
    elif adding_locks and acquiring_locks:
490 ca2a79e1 Guido Trotter
      # We could both acquire and add locks at the same level, but for now we
491 ca2a79e1 Guido Trotter
      # don't need this, so we'll avoid the complicated code needed.
492 407339d0 Michael Hanselmann
      raise NotImplementedError("Can't declare locks to acquire when adding"
493 407339d0 Michael Hanselmann
                                " others")
494 407339d0 Michael Hanselmann
495 ca2a79e1 Guido Trotter
    elif adding_locks or acquiring_locks:
496 dc4bdf73 Michael Hanselmann
      self._CheckLocksEnabled()
497 dc4bdf73 Michael Hanselmann
498 fb8dcb62 Guido Trotter
      lu.DeclareLocks(level)
499 3977a4c1 Guido Trotter
      share = lu.share_locks[level]
500 686d24f0 Michael Hanselmann
      opportunistic = lu.opportunistic_locks[level]
501 407339d0 Michael Hanselmann
502 68adfdb2 Guido Trotter
      try:
503 407339d0 Michael Hanselmann
        assert adding_locks ^ acquiring_locks, \
504 407339d0 Michael Hanselmann
          "Locks must be either added or acquired"
505 407339d0 Michael Hanselmann
506 407339d0 Michael Hanselmann
        if acquiring_locks:
507 407339d0 Michael Hanselmann
          # Acquiring locks
508 407339d0 Michael Hanselmann
          needed_locks = lu.needed_locks[level]
509 bb38965c Klaus Aehlig
          use_opportunistic = opportunistic
510 407339d0 Michael Hanselmann
        else:
511 407339d0 Michael Hanselmann
          # Adding locks
512 bb38965c Klaus Aehlig
          needed_locks = _LockList(lu.add_locks[level])
513 bb38965c Klaus Aehlig
          use_opportunistic = False
514 87ed6b79 Klaus Aehlig
515 bb38965c Klaus Aehlig
        self._AcquireLocks(level, needed_locks, share, use_opportunistic,
516 bb38965c Klaus Aehlig
                           calc_timeout())
517 bb38965c Klaus Aehlig
        lu.wconfdlocks = self.wconfd.Client().ListLocks(self._wconfdcontext)
518 407339d0 Michael Hanselmann
519 0d730682 Klaus Aehlig
        result = self._LockAndExecLU(lu, level + 1, calc_timeout)
520 68adfdb2 Guido Trotter
      finally:
521 87ed6b79 Klaus Aehlig
        levelname = locking.LEVEL_NAMES[level]
522 6ea039ef Petr Pudlak
        logging.debug("Freeing locks at level %s for %s",
523 6ea039ef Petr Pudlak
                      levelname, self._wconfdcontext)
524 6ea039ef Petr Pudlak
        self.wconfd.Client().FreeLocksLevel(self._wconfdcontext, levelname)
525 68adfdb2 Guido Trotter
    else:
526 e4e59de8 Michael Hanselmann
      result = self._LockAndExecLU(lu, level + 1, calc_timeout)
527 68adfdb2 Guido Trotter
528 68adfdb2 Guido Trotter
    return result
529 68adfdb2 Guido Trotter
530 fdfa63cb Thomas Thrainer
  # pylint: disable=R0201
531 b8f45292 Thomas Thrainer
  def _CheckLUResult(self, op, result):
532 b8f45292 Thomas Thrainer
    """Check the LU result against the contract in the opcode.
533 b8f45292 Thomas Thrainer

534 b8f45292 Thomas Thrainer
    """
535 b8f45292 Thomas Thrainer
    resultcheck_fn = op.OP_RESULT
536 b8f45292 Thomas Thrainer
    if not (resultcheck_fn is None or resultcheck_fn(result)):
537 b8f45292 Thomas Thrainer
      logging.error("Expected opcode result matching %s, got %s",
538 b8f45292 Thomas Thrainer
                    resultcheck_fn, result)
539 b8f45292 Thomas Thrainer
      if not getattr(op, "dry_run", False):
540 b8f45292 Thomas Thrainer
        # FIXME: LUs should still behave in dry_run mode, or
541 b8f45292 Thomas Thrainer
        # alternately we should have OP_DRYRUN_RESULT; in the
542 b8f45292 Thomas Thrainer
        # meantime, we simply skip the OP_RESULT check in dry-run mode
543 b8f45292 Thomas Thrainer
        raise errors.OpResultError("Opcode result does not match %s: %s" %
544 b8f45292 Thomas Thrainer
                                   (resultcheck_fn, utils.Truncate(result, 80)))
545 b8f45292 Thomas Thrainer
546 e4e59de8 Michael Hanselmann
  def ExecOpCode(self, op, cbs, timeout=None):
547 a8083063 Iustin Pop
    """Execute an opcode.
548 a8083063 Iustin Pop

549 e92376d7 Iustin Pop
    @type op: an OpCode instance
550 e92376d7 Iustin Pop
    @param op: the opcode to be executed
551 031a3e57 Michael Hanselmann
    @type cbs: L{OpExecCbBase}
552 031a3e57 Michael Hanselmann
    @param cbs: Runtime callbacks
553 831bbbc1 Michael Hanselmann
    @type timeout: float or None
554 831bbbc1 Michael Hanselmann
    @param timeout: Maximum time to acquire all locks, None for no timeout
555 831bbbc1 Michael Hanselmann
    @raise LockAcquireTimeout: In case locks couldn't be acquired in specified
556 831bbbc1 Michael Hanselmann
        amount of time
557 a8083063 Iustin Pop

558 a8083063 Iustin Pop
    """
559 a8083063 Iustin Pop
    if not isinstance(op, opcodes.OpCode):
560 3ecf6786 Iustin Pop
      raise errors.ProgrammerError("Non-opcode instance passed"
561 c7bb3095 Michael Hanselmann
                                   " to ExecOpcode (%s)" % type(op))
562 a8083063 Iustin Pop
563 831bbbc1 Michael Hanselmann
    lu_class = self.DISPATCH_TABLE.get(op.__class__, None)
564 831bbbc1 Michael Hanselmann
    if lu_class is None:
565 831bbbc1 Michael Hanselmann
      raise errors.OpCodeUnknown("Unknown opcode")
566 831bbbc1 Michael Hanselmann
567 831bbbc1 Michael Hanselmann
    if timeout is None:
568 831bbbc1 Michael Hanselmann
      calc_timeout = lambda: None
569 831bbbc1 Michael Hanselmann
    else:
570 557838c1 René Nussbaumer
      calc_timeout = utils.RunningTimeout(timeout, False).Remaining
571 831bbbc1 Michael Hanselmann
572 031a3e57 Michael Hanselmann
    self._cbs = cbs
573 fe482621 Iustin Pop
    try:
574 dc4bdf73 Michael Hanselmann
      if self._enable_locks:
575 dc4bdf73 Michael Hanselmann
        # Acquire the Big Ganeti Lock exclusively if this LU requires it,
576 dc4bdf73 Michael Hanselmann
        # and in a shared fashion otherwise (to prevent concurrent run with
577 dc4bdf73 Michael Hanselmann
        # an exclusive LU.
578 dc4bdf73 Michael Hanselmann
        self._AcquireLocks(locking.LEVEL_CLUSTER, locking.BGL,
579 686d24f0 Michael Hanselmann
                            not lu_class.REQ_BGL, False, calc_timeout())
580 dc4bdf73 Michael Hanselmann
      elif lu_class.REQ_BGL:
581 dc4bdf73 Michael Hanselmann
        raise errors.ProgrammerError("Opcode '%s' requires BGL, but locks are"
582 dc4bdf73 Michael Hanselmann
                                     " disabled" % op.OP_ID)
583 dc4bdf73 Michael Hanselmann
584 831bbbc1 Michael Hanselmann
      try:
585 f47b32a8 Petr Pudlak
        lu = lu_class(self, op, self.context, self.cfg, self.rpc,
586 f47b32a8 Petr Pudlak
                      self._wconfdcontext, self.wconfd)
587 6ea039ef Petr Pudlak
        lu.wconfdlocks = self.wconfd.Client().ListLocks(self._wconfdcontext)
588 831bbbc1 Michael Hanselmann
        lu.ExpandNames()
589 831bbbc1 Michael Hanselmann
        assert lu.needed_locks is not None, "needed_locks not set by LU"
590 407339d0 Michael Hanselmann
591 407339d0 Michael Hanselmann
        try:
592 46cde471 Michael Hanselmann
          result = self._LockAndExecLU(lu, locking.LEVEL_CLUSTER + 1,
593 46cde471 Michael Hanselmann
                                       calc_timeout)
594 831bbbc1 Michael Hanselmann
        finally:
595 831bbbc1 Michael Hanselmann
          if self._ec_id:
596 f47b32a8 Petr Pudlak
            self.cfg.DropECReservations(self._ec_id)
597 831bbbc1 Michael Hanselmann
      finally:
598 dc4bdf73 Michael Hanselmann
        # Release BGL if owned
599 87ed6b79 Klaus Aehlig
        bglname = "%s/%s" % (locking.LEVEL_NAMES[locking.LEVEL_CLUSTER],
600 87ed6b79 Klaus Aehlig
                             locking.BGL)
601 6ea039ef Petr Pudlak
        self.wconfd.Client().TryUpdateLocks(self._wconfdcontext,
602 87ed6b79 Klaus Aehlig
                                            [[bglname, "release"]])
603 04864530 Guido Trotter
    finally:
604 031a3e57 Michael Hanselmann
      self._cbs = None
605 6a4aa7c1 Iustin Pop
606 b8f45292 Thomas Thrainer
    self._CheckLUResult(op, result)
607 1ce03fb1 Michael Hanselmann
608 1ce03fb1 Michael Hanselmann
    return result
609 1ce03fb1 Michael Hanselmann
610 7b4c1cb9 Michael Hanselmann
  def Log(self, *args):
611 031a3e57 Michael Hanselmann
    """Forward call to feedback callback function.
612 031a3e57 Michael Hanselmann

613 031a3e57 Michael Hanselmann
    """
614 031a3e57 Michael Hanselmann
    if self._cbs:
615 031a3e57 Michael Hanselmann
      self._cbs.Feedback(*args)
616 031a3e57 Michael Hanselmann
617 0fbbf897 Iustin Pop
  def LogStep(self, current, total, message):
618 0fbbf897 Iustin Pop
    """Log a change in LU execution progress.
619 0fbbf897 Iustin Pop

620 0fbbf897 Iustin Pop
    """
621 a5eb7789 Iustin Pop
    logging.debug("Step %d/%d %s", current, total, message)
622 7b4c1cb9 Michael Hanselmann
    self.Log("STEP %d/%d %s" % (current, total, message))
623 0fbbf897 Iustin Pop
624 c0088fb9 Iustin Pop
  def LogWarning(self, message, *args, **kwargs):
625 0fbbf897 Iustin Pop
    """Log a warning to the logs and the user.
626 0fbbf897 Iustin Pop

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

632 c0088fb9 Iustin Pop
    """
633 c0088fb9 Iustin Pop
    assert not kwargs or (len(kwargs) == 1 and "hint" in kwargs), \
634 c0088fb9 Iustin Pop
           "Invalid keyword arguments for LogWarning (%s)" % str(kwargs)
635 c0088fb9 Iustin Pop
    if args:
636 c0088fb9 Iustin Pop
      message = message % tuple(args)
637 c0088fb9 Iustin Pop
    if message:
638 c0088fb9 Iustin Pop
      logging.warning(message)
639 7b4c1cb9 Michael Hanselmann
      self.Log(" - WARNING: %s" % message)
640 c0088fb9 Iustin Pop
    if "hint" in kwargs:
641 7b4c1cb9 Michael Hanselmann
      self.Log("      Hint: %s" % kwargs["hint"])
642 c0088fb9 Iustin Pop
643 c0088fb9 Iustin Pop
  def LogInfo(self, message, *args):
644 0fbbf897 Iustin Pop
    """Log an informational message to the logs and the user.
645 0fbbf897 Iustin Pop

646 0fbbf897 Iustin Pop
    """
647 c0088fb9 Iustin Pop
    if args:
648 c0088fb9 Iustin Pop
      message = message % tuple(args)
649 a5eb7789 Iustin Pop
    logging.info(message)
650 7b4c1cb9 Michael Hanselmann
    self.Log(" - INFO: %s" % message)
651 0fbbf897 Iustin Pop
652 adfa97e3 Guido Trotter
  def GetECId(self):
653 3ae70d76 Michael Hanselmann
    """Returns the current execution context ID.
654 3ae70d76 Michael Hanselmann

655 3ae70d76 Michael Hanselmann
    """
656 adfa97e3 Guido Trotter
    if not self._ec_id:
657 3ae70d76 Michael Hanselmann
      raise errors.ProgrammerError("Tried to use execution context id when"
658 3ae70d76 Michael Hanselmann
                                   " not set")
659 adfa97e3 Guido Trotter
    return self._ec_id