Statistics
| Branch: | Tag: | Revision:

root / lib / mcpu.py @ 66e884e1

History | View | Annotate | Download (18.7 kB)

1 2f31098c Iustin Pop
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 a8083063 Iustin Pop
# Copyright (C) 2006, 2007 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 a5eb7789 Iustin Pop
import logging
32 407339d0 Michael Hanselmann
import random
33 407339d0 Michael Hanselmann
import time
34 a8083063 Iustin Pop
35 a8083063 Iustin Pop
from ganeti import opcodes
36 a8083063 Iustin Pop
from ganeti import constants
37 a8083063 Iustin Pop
from ganeti import errors
38 a8083063 Iustin Pop
from ganeti import rpc
39 a8083063 Iustin Pop
from ganeti import cmdlib
40 04864530 Guido Trotter
from ganeti import locking
41 557838c1 René Nussbaumer
from ganeti import utils
42 a8083063 Iustin Pop
43 7c0d6283 Michael Hanselmann
44 831bbbc1 Michael Hanselmann
class LockAcquireTimeout(Exception):
45 831bbbc1 Michael Hanselmann
  """Exception to report timeouts on acquiring locks.
46 407339d0 Michael Hanselmann

47 407339d0 Michael Hanselmann
  """
48 407339d0 Michael Hanselmann
49 407339d0 Michael Hanselmann
50 e3200b18 Michael Hanselmann
def _CalculateLockAttemptTimeouts():
51 e3200b18 Michael Hanselmann
  """Calculate timeouts for lock attempts.
52 e3200b18 Michael Hanselmann

53 e3200b18 Michael Hanselmann
  """
54 e3200b18 Michael Hanselmann
  result = [1.0]
55 e3200b18 Michael Hanselmann
56 e3200b18 Michael Hanselmann
  # Wait for a total of at least 150s before doing a blocking acquire
57 e3200b18 Michael Hanselmann
  while sum(result) < 150.0:
58 e3200b18 Michael Hanselmann
    timeout = (result[-1] * 1.05) ** 1.25
59 e3200b18 Michael Hanselmann
60 e3200b18 Michael Hanselmann
    # Cap timeout at 10 seconds. This gives other jobs a chance to run
61 e3200b18 Michael Hanselmann
    # even if we're still trying to get our locks, before finally moving
62 e3200b18 Michael Hanselmann
    # to a blocking acquire.
63 e3200b18 Michael Hanselmann
    if timeout > 10.0:
64 e3200b18 Michael Hanselmann
      timeout = 10.0
65 e3200b18 Michael Hanselmann
66 e3200b18 Michael Hanselmann
    elif timeout < 0.1:
67 e3200b18 Michael Hanselmann
      # Lower boundary for safety
68 e3200b18 Michael Hanselmann
      timeout = 0.1
69 e3200b18 Michael Hanselmann
70 e3200b18 Michael Hanselmann
    result.append(timeout)
71 e3200b18 Michael Hanselmann
72 e3200b18 Michael Hanselmann
  return result
73 e3200b18 Michael Hanselmann
74 e3200b18 Michael Hanselmann
75 a7770f03 Michael Hanselmann
class LockAttemptTimeoutStrategy(object):
76 407339d0 Michael Hanselmann
  """Class with lock acquire timeout strategy.
77 407339d0 Michael Hanselmann

78 407339d0 Michael Hanselmann
  """
79 407339d0 Michael Hanselmann
  __slots__ = [
80 a7770f03 Michael Hanselmann
    "_timeouts",
81 407339d0 Michael Hanselmann
    "_random_fn",
82 e3200b18 Michael Hanselmann
    "_time_fn",
83 407339d0 Michael Hanselmann
    ]
84 407339d0 Michael Hanselmann
85 e3200b18 Michael Hanselmann
  _TIMEOUT_PER_ATTEMPT = _CalculateLockAttemptTimeouts()
86 407339d0 Michael Hanselmann
87 a7770f03 Michael Hanselmann
  def __init__(self, _time_fn=time.time, _random_fn=random.random):
88 407339d0 Michael Hanselmann
    """Initializes this class.
89 407339d0 Michael Hanselmann

90 e3200b18 Michael Hanselmann
    @param _time_fn: Time function for unittests
91 407339d0 Michael Hanselmann
    @param _random_fn: Random number generator for unittests
92 407339d0 Michael Hanselmann

93 407339d0 Michael Hanselmann
    """
94 407339d0 Michael Hanselmann
    object.__init__(self)
95 407339d0 Michael Hanselmann
96 a7770f03 Michael Hanselmann
    self._timeouts = iter(self._TIMEOUT_PER_ATTEMPT)
97 e3200b18 Michael Hanselmann
    self._time_fn = _time_fn
98 e3200b18 Michael Hanselmann
    self._random_fn = _random_fn
99 e3200b18 Michael Hanselmann
100 407339d0 Michael Hanselmann
  def NextAttempt(self):
101 a7770f03 Michael Hanselmann
    """Returns the timeout for the next attempt.
102 407339d0 Michael Hanselmann

103 407339d0 Michael Hanselmann
    """
104 a7770f03 Michael Hanselmann
    try:
105 a7770f03 Michael Hanselmann
      timeout = self._timeouts.next()
106 a7770f03 Michael Hanselmann
    except StopIteration:
107 a7770f03 Michael Hanselmann
      # No more timeouts, do blocking acquire
108 a7770f03 Michael Hanselmann
      timeout = None
109 407339d0 Michael Hanselmann
110 a6db1af2 Michael Hanselmann
    if timeout is not None:
111 a6db1af2 Michael Hanselmann
      # Add a small variation (-/+ 5%) to timeout. This helps in situations
112 a6db1af2 Michael Hanselmann
      # where two or more jobs are fighting for the same lock(s).
113 a6db1af2 Michael Hanselmann
      variation_range = timeout * 0.1
114 a6db1af2 Michael Hanselmann
      timeout += ((self._random_fn() * variation_range) -
115 a6db1af2 Michael Hanselmann
                  (variation_range * 0.5))
116 407339d0 Michael Hanselmann
117 a6db1af2 Michael Hanselmann
    return timeout
118 407339d0 Michael Hanselmann
119 407339d0 Michael Hanselmann
120 7260cfbe Iustin Pop
class OpExecCbBase: # pylint: disable-msg=W0232
121 031a3e57 Michael Hanselmann
  """Base class for OpCode execution callbacks.
122 031a3e57 Michael Hanselmann

123 031a3e57 Michael Hanselmann
  """
124 031a3e57 Michael Hanselmann
  def NotifyStart(self):
125 031a3e57 Michael Hanselmann
    """Called when we are about to execute the LU.
126 031a3e57 Michael Hanselmann

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

130 031a3e57 Michael Hanselmann
    """
131 031a3e57 Michael Hanselmann
132 031a3e57 Michael Hanselmann
  def Feedback(self, *args):
133 031a3e57 Michael Hanselmann
    """Sends feedback from the LU code to the end-user.
134 031a3e57 Michael Hanselmann

135 031a3e57 Michael Hanselmann
    """
136 031a3e57 Michael Hanselmann
137 acf931b7 Michael Hanselmann
  def CheckCancel(self):
138 acf931b7 Michael Hanselmann
    """Check whether job has been cancelled.
139 ef2df7d3 Michael Hanselmann

140 ef2df7d3 Michael Hanselmann
    """
141 ef2df7d3 Michael Hanselmann
142 031a3e57 Michael Hanselmann
143 a8083063 Iustin Pop
class Processor(object):
144 a8083063 Iustin Pop
  """Object which runs OpCodes"""
145 a8083063 Iustin Pop
  DISPATCH_TABLE = {
146 a8083063 Iustin Pop
    # Cluster
147 b5f5fae9 Luca Bigliardi
    opcodes.OpPostInitCluster: cmdlib.LUPostInitCluster,
148 a8083063 Iustin Pop
    opcodes.OpDestroyCluster: cmdlib.LUDestroyCluster,
149 a8083063 Iustin Pop
    opcodes.OpQueryClusterInfo: cmdlib.LUQueryClusterInfo,
150 a8083063 Iustin Pop
    opcodes.OpVerifyCluster: cmdlib.LUVerifyCluster,
151 ae5849b5 Michael Hanselmann
    opcodes.OpQueryConfigValues: cmdlib.LUQueryConfigValues,
152 07bd8a51 Iustin Pop
    opcodes.OpRenameCluster: cmdlib.LURenameCluster,
153 f4d4e184 Iustin Pop
    opcodes.OpVerifyDisks: cmdlib.LUVerifyDisks,
154 0cc05d44 Manuel Franceschini
    opcodes.OpSetClusterParams: cmdlib.LUSetClusterParams,
155 afee0879 Iustin Pop
    opcodes.OpRedistributeConfig: cmdlib.LURedistributeConfig,
156 60975797 Iustin Pop
    opcodes.OpRepairDiskSizes: cmdlib.LURepairDiskSizes,
157 83f72637 Michael Hanselmann
    opcodes.OpQuery: cmdlib.LUQuery,
158 83f72637 Michael Hanselmann
    opcodes.OpQueryFields: cmdlib.LUQueryFields,
159 a8083063 Iustin Pop
    # node lu
160 a8083063 Iustin Pop
    opcodes.OpAddNode: cmdlib.LUAddNode,
161 a8083063 Iustin Pop
    opcodes.OpQueryNodes: cmdlib.LUQueryNodes,
162 dcb93971 Michael Hanselmann
    opcodes.OpQueryNodeVolumes: cmdlib.LUQueryNodeVolumes,
163 9e5442ce Michael Hanselmann
    opcodes.OpQueryNodeStorage: cmdlib.LUQueryNodeStorage,
164 efb8da02 Michael Hanselmann
    opcodes.OpModifyNodeStorage: cmdlib.LUModifyNodeStorage,
165 76aef8fc Michael Hanselmann
    opcodes.OpRepairNodeStorage: cmdlib.LURepairNodeStorage,
166 a8083063 Iustin Pop
    opcodes.OpRemoveNode: cmdlib.LURemoveNode,
167 b31c8676 Iustin Pop
    opcodes.OpSetNodeParams: cmdlib.LUSetNodeParams,
168 f5118ade Iustin Pop
    opcodes.OpPowercycleNode: cmdlib.LUPowercycleNode,
169 80cb875c Michael Hanselmann
    opcodes.OpMigrateNode: cmdlib.LUMigrateNode,
170 f7e7689f Iustin Pop
    opcodes.OpNodeEvacuationStrategy: cmdlib.LUNodeEvacuationStrategy,
171 a8083063 Iustin Pop
    # instance lu
172 a8083063 Iustin Pop
    opcodes.OpCreateInstance: cmdlib.LUCreateInstance,
173 fe7b0351 Michael Hanselmann
    opcodes.OpReinstallInstance: cmdlib.LUReinstallInstance,
174 a8083063 Iustin Pop
    opcodes.OpRemoveInstance: cmdlib.LURemoveInstance,
175 decd5f45 Iustin Pop
    opcodes.OpRenameInstance: cmdlib.LURenameInstance,
176 a8083063 Iustin Pop
    opcodes.OpActivateInstanceDisks: cmdlib.LUActivateInstanceDisks,
177 a8083063 Iustin Pop
    opcodes.OpShutdownInstance: cmdlib.LUShutdownInstance,
178 a8083063 Iustin Pop
    opcodes.OpStartupInstance: cmdlib.LUStartupInstance,
179 bf6929a2 Alexander Schreiber
    opcodes.OpRebootInstance: cmdlib.LURebootInstance,
180 a8083063 Iustin Pop
    opcodes.OpDeactivateInstanceDisks: cmdlib.LUDeactivateInstanceDisks,
181 a8083063 Iustin Pop
    opcodes.OpReplaceDisks: cmdlib.LUReplaceDisks,
182 bd315bfa Iustin Pop
    opcodes.OpRecreateInstanceDisks: cmdlib.LURecreateInstanceDisks,
183 a8083063 Iustin Pop
    opcodes.OpFailoverInstance: cmdlib.LUFailoverInstance,
184 53c776b5 Iustin Pop
    opcodes.OpMigrateInstance: cmdlib.LUMigrateInstance,
185 313bcead Iustin Pop
    opcodes.OpMoveInstance: cmdlib.LUMoveInstance,
186 a8083063 Iustin Pop
    opcodes.OpConnectConsole: cmdlib.LUConnectConsole,
187 a8083063 Iustin Pop
    opcodes.OpQueryInstances: cmdlib.LUQueryInstances,
188 a8083063 Iustin Pop
    opcodes.OpQueryInstanceData: cmdlib.LUQueryInstanceData,
189 7767bbf5 Manuel Franceschini
    opcodes.OpSetInstanceParams: cmdlib.LUSetInstanceParams,
190 8729e0d7 Iustin Pop
    opcodes.OpGrowDisk: cmdlib.LUGrowDisk,
191 70a6a926 Adeodato Simo
    # node group lu
192 b1ee5610 Adeodato Simo
    opcodes.OpAddGroup: cmdlib.LUAddGroup,
193 70a6a926 Adeodato Simo
    opcodes.OpQueryGroups: cmdlib.LUQueryGroups,
194 94bd652a Adeodato Simo
    opcodes.OpRemoveGroup: cmdlib.LURemoveGroup,
195 4fe5cf90 Adeodato Simo
    opcodes.OpRenameGroup: cmdlib.LURenameGroup,
196 a8083063 Iustin Pop
    # os lu
197 a8083063 Iustin Pop
    opcodes.OpDiagnoseOS: cmdlib.LUDiagnoseOS,
198 a8083063 Iustin Pop
    # exports lu
199 a8083063 Iustin Pop
    opcodes.OpQueryExports: cmdlib.LUQueryExports,
200 1410fa8d Michael Hanselmann
    opcodes.OpPrepareExport: cmdlib.LUPrepareExport,
201 a8083063 Iustin Pop
    opcodes.OpExportInstance: cmdlib.LUExportInstance,
202 9ac99fda Guido Trotter
    opcodes.OpRemoveExport: cmdlib.LURemoveExport,
203 5c947f38 Iustin Pop
    # tags lu
204 5c947f38 Iustin Pop
    opcodes.OpGetTags: cmdlib.LUGetTags,
205 73415719 Iustin Pop
    opcodes.OpSearchTags: cmdlib.LUSearchTags,
206 f27302fa Iustin Pop
    opcodes.OpAddTags: cmdlib.LUAddTags,
207 f27302fa Iustin Pop
    opcodes.OpDelTags: cmdlib.LUDelTags,
208 06009e27 Iustin Pop
    # test lu
209 06009e27 Iustin Pop
    opcodes.OpTestDelay: cmdlib.LUTestDelay,
210 d61df03e Iustin Pop
    opcodes.OpTestAllocator: cmdlib.LUTestAllocator,
211 e58f87a9 Michael Hanselmann
    opcodes.OpTestJobqueue: cmdlib.LUTestJobqueue,
212 eb64da59 René Nussbaumer
    # OOB lu
213 eb64da59 René Nussbaumer
    opcodes.OpOutOfBand: cmdlib.LUOutOfBand,
214 a8083063 Iustin Pop
    }
215 a8083063 Iustin Pop
216 adfa97e3 Guido Trotter
  def __init__(self, context, ec_id):
217 a8083063 Iustin Pop
    """Constructor for Processor
218 a8083063 Iustin Pop

219 adfa97e3 Guido Trotter
    @type context: GanetiContext
220 adfa97e3 Guido Trotter
    @param context: global Ganeti context
221 adfa97e3 Guido Trotter
    @type ec_id: string
222 adfa97e3 Guido Trotter
    @param ec_id: execution context identifier
223 adfa97e3 Guido Trotter

224 a8083063 Iustin Pop
    """
225 1c901d13 Guido Trotter
    self.context = context
226 adfa97e3 Guido Trotter
    self._ec_id = ec_id
227 031a3e57 Michael Hanselmann
    self._cbs = None
228 72737a7f Iustin Pop
    self.rpc = rpc.RpcRunner(context.cfg)
229 cd46f3b4 Luca Bigliardi
    self.hmclass = HooksMaster
230 a8083063 Iustin Pop
231 f879a9c7 Michael Hanselmann
  def _AcquireLocks(self, level, names, shared, timeout, priority):
232 211b6132 Michael Hanselmann
    """Acquires locks via the Ganeti lock manager.
233 211b6132 Michael Hanselmann

234 211b6132 Michael Hanselmann
    @type level: int
235 211b6132 Michael Hanselmann
    @param level: Lock level
236 211b6132 Michael Hanselmann
    @type names: list or string
237 211b6132 Michael Hanselmann
    @param names: Lock names
238 211b6132 Michael Hanselmann
    @type shared: bool
239 211b6132 Michael Hanselmann
    @param shared: Whether the locks should be acquired in shared mode
240 211b6132 Michael Hanselmann
    @type timeout: None or float
241 211b6132 Michael Hanselmann
    @param timeout: Timeout for acquiring the locks
242 900df6cd Michael Hanselmann
    @raise LockAcquireTimeout: In case locks couldn't be acquired in specified
243 900df6cd Michael Hanselmann
        amount of time
244 211b6132 Michael Hanselmann

245 211b6132 Michael Hanselmann
    """
246 acf931b7 Michael Hanselmann
    if self._cbs:
247 acf931b7 Michael Hanselmann
      self._cbs.CheckCancel()
248 211b6132 Michael Hanselmann
249 211b6132 Michael Hanselmann
    acquired = self.context.glm.acquire(level, names, shared=shared,
250 f879a9c7 Michael Hanselmann
                                        timeout=timeout, priority=priority)
251 211b6132 Michael Hanselmann
252 900df6cd Michael Hanselmann
    if acquired is None:
253 900df6cd Michael Hanselmann
      raise LockAcquireTimeout()
254 900df6cd Michael Hanselmann
255 211b6132 Michael Hanselmann
    return acquired
256 211b6132 Michael Hanselmann
257 36c381d7 Guido Trotter
  def _ExecLU(self, lu):
258 36c381d7 Guido Trotter
    """Logical Unit execution sequence.
259 36c381d7 Guido Trotter

260 36c381d7 Guido Trotter
    """
261 36c381d7 Guido Trotter
    write_count = self.context.cfg.write_count
262 36c381d7 Guido Trotter
    lu.CheckPrereq()
263 4b5e8271 Iustin Pop
    hm = HooksMaster(self.rpc.call_hooks_runner, lu)
264 36c381d7 Guido Trotter
    h_results = hm.RunPhase(constants.HOOKS_PHASE_PRE)
265 36c381d7 Guido Trotter
    lu.HooksCallBack(constants.HOOKS_PHASE_PRE, h_results,
266 7b4c1cb9 Michael Hanselmann
                     self.Log, None)
267 20777413 Iustin Pop
268 20777413 Iustin Pop
    if getattr(lu.op, "dry_run", False):
269 20777413 Iustin Pop
      # in this mode, no post-hooks are run, and the config is not
270 20777413 Iustin Pop
      # written (as it might have been modified by another LU, and we
271 20777413 Iustin Pop
      # shouldn't do writeout on behalf of other threads
272 20777413 Iustin Pop
      self.LogInfo("dry-run mode requested, not actually executing"
273 20777413 Iustin Pop
                   " the operation")
274 20777413 Iustin Pop
      return lu.dry_run_result
275 20777413 Iustin Pop
276 36c381d7 Guido Trotter
    try:
277 7b4c1cb9 Michael Hanselmann
      result = lu.Exec(self.Log)
278 36c381d7 Guido Trotter
      h_results = hm.RunPhase(constants.HOOKS_PHASE_POST)
279 36c381d7 Guido Trotter
      result = lu.HooksCallBack(constants.HOOKS_PHASE_POST, h_results,
280 7b4c1cb9 Michael Hanselmann
                                self.Log, result)
281 36c381d7 Guido Trotter
    finally:
282 36c381d7 Guido Trotter
      # FIXME: This needs locks if not lu_class.REQ_BGL
283 36c381d7 Guido Trotter
      if write_count != self.context.cfg.write_count:
284 36c381d7 Guido Trotter
        hm.RunConfigUpdate()
285 36c381d7 Guido Trotter
286 36c381d7 Guido Trotter
    return result
287 36c381d7 Guido Trotter
288 f879a9c7 Michael Hanselmann
  def _LockAndExecLU(self, lu, level, calc_timeout, priority):
289 68adfdb2 Guido Trotter
    """Execute a Logical Unit, with the needed locks.
290 68adfdb2 Guido Trotter

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

295 68adfdb2 Guido Trotter
    """
296 ca2a79e1 Guido Trotter
    adding_locks = level in lu.add_locks
297 ca2a79e1 Guido Trotter
    acquiring_locks = level in lu.needed_locks
298 8a2941c4 Guido Trotter
    if level not in locking.LEVELS:
299 031a3e57 Michael Hanselmann
      if self._cbs:
300 031a3e57 Michael Hanselmann
        self._cbs.NotifyStart()
301 031a3e57 Michael Hanselmann
302 8a2941c4 Guido Trotter
      result = self._ExecLU(lu)
303 407339d0 Michael Hanselmann
304 ca2a79e1 Guido Trotter
    elif adding_locks and acquiring_locks:
305 ca2a79e1 Guido Trotter
      # We could both acquire and add locks at the same level, but for now we
306 ca2a79e1 Guido Trotter
      # don't need this, so we'll avoid the complicated code needed.
307 407339d0 Michael Hanselmann
      raise NotImplementedError("Can't declare locks to acquire when adding"
308 407339d0 Michael Hanselmann
                                " others")
309 407339d0 Michael Hanselmann
310 ca2a79e1 Guido Trotter
    elif adding_locks or acquiring_locks:
311 fb8dcb62 Guido Trotter
      lu.DeclareLocks(level)
312 3977a4c1 Guido Trotter
      share = lu.share_locks[level]
313 407339d0 Michael Hanselmann
314 68adfdb2 Guido Trotter
      try:
315 407339d0 Michael Hanselmann
        assert adding_locks ^ acquiring_locks, \
316 407339d0 Michael Hanselmann
          "Locks must be either added or acquired"
317 407339d0 Michael Hanselmann
318 407339d0 Michael Hanselmann
        if acquiring_locks:
319 407339d0 Michael Hanselmann
          # Acquiring locks
320 407339d0 Michael Hanselmann
          needed_locks = lu.needed_locks[level]
321 407339d0 Michael Hanselmann
322 211b6132 Michael Hanselmann
          acquired = self._AcquireLocks(level, needed_locks, share,
323 f879a9c7 Michael Hanselmann
                                        calc_timeout(), priority)
324 407339d0 Michael Hanselmann
        else:
325 407339d0 Michael Hanselmann
          # Adding locks
326 407339d0 Michael Hanselmann
          add_locks = lu.add_locks[level]
327 407339d0 Michael Hanselmann
          lu.remove_locks[level] = add_locks
328 407339d0 Michael Hanselmann
329 407339d0 Michael Hanselmann
          try:
330 407339d0 Michael Hanselmann
            self.context.glm.add(level, add_locks, acquired=1, shared=share)
331 407339d0 Michael Hanselmann
          except errors.LockError:
332 407339d0 Michael Hanselmann
            raise errors.OpPrereqError(
333 407339d0 Michael Hanselmann
              "Couldn't add locks (%s), probably because of a race condition"
334 debac808 Iustin Pop
              " with another job, who added them first" % add_locks,
335 debac808 Iustin Pop
              errors.ECODE_FAULT)
336 407339d0 Michael Hanselmann
337 6f14fc27 Michael Hanselmann
          acquired = add_locks
338 6f14fc27 Michael Hanselmann
339 ca2a79e1 Guido Trotter
        try:
340 6f14fc27 Michael Hanselmann
          lu.acquired_locks[level] = acquired
341 6f14fc27 Michael Hanselmann
342 f879a9c7 Michael Hanselmann
          result = self._LockAndExecLU(lu, level + 1, calc_timeout, priority)
343 ca2a79e1 Guido Trotter
        finally:
344 ca2a79e1 Guido Trotter
          if level in lu.remove_locks:
345 ca2a79e1 Guido Trotter
            self.context.glm.remove(level, lu.remove_locks[level])
346 68adfdb2 Guido Trotter
      finally:
347 80ee04a4 Guido Trotter
        if self.context.glm.is_owned(level):
348 68adfdb2 Guido Trotter
          self.context.glm.release(level)
349 407339d0 Michael Hanselmann
350 68adfdb2 Guido Trotter
    else:
351 f879a9c7 Michael Hanselmann
      result = self._LockAndExecLU(lu, level + 1, calc_timeout, priority)
352 68adfdb2 Guido Trotter
353 68adfdb2 Guido Trotter
    return result
354 68adfdb2 Guido Trotter
355 f879a9c7 Michael Hanselmann
  def ExecOpCode(self, op, cbs, timeout=None, priority=None):
356 a8083063 Iustin Pop
    """Execute an opcode.
357 a8083063 Iustin Pop

358 e92376d7 Iustin Pop
    @type op: an OpCode instance
359 e92376d7 Iustin Pop
    @param op: the opcode to be executed
360 031a3e57 Michael Hanselmann
    @type cbs: L{OpExecCbBase}
361 031a3e57 Michael Hanselmann
    @param cbs: Runtime callbacks
362 831bbbc1 Michael Hanselmann
    @type timeout: float or None
363 831bbbc1 Michael Hanselmann
    @param timeout: Maximum time to acquire all locks, None for no timeout
364 f879a9c7 Michael Hanselmann
    @type priority: number or None
365 f879a9c7 Michael Hanselmann
    @param priority: Priority for acquiring lock(s)
366 831bbbc1 Michael Hanselmann
    @raise LockAcquireTimeout: In case locks couldn't be acquired in specified
367 831bbbc1 Michael Hanselmann
        amount of time
368 a8083063 Iustin Pop

369 a8083063 Iustin Pop
    """
370 a8083063 Iustin Pop
    if not isinstance(op, opcodes.OpCode):
371 3ecf6786 Iustin Pop
      raise errors.ProgrammerError("Non-opcode instance passed"
372 3ecf6786 Iustin Pop
                                   " to ExecOpcode")
373 a8083063 Iustin Pop
374 831bbbc1 Michael Hanselmann
    lu_class = self.DISPATCH_TABLE.get(op.__class__, None)
375 831bbbc1 Michael Hanselmann
    if lu_class is None:
376 831bbbc1 Michael Hanselmann
      raise errors.OpCodeUnknown("Unknown opcode")
377 831bbbc1 Michael Hanselmann
378 831bbbc1 Michael Hanselmann
    if timeout is None:
379 831bbbc1 Michael Hanselmann
      calc_timeout = lambda: None
380 831bbbc1 Michael Hanselmann
    else:
381 557838c1 René Nussbaumer
      calc_timeout = utils.RunningTimeout(timeout, False).Remaining
382 831bbbc1 Michael Hanselmann
383 031a3e57 Michael Hanselmann
    self._cbs = cbs
384 fe482621 Iustin Pop
    try:
385 831bbbc1 Michael Hanselmann
      # Acquire the Big Ganeti Lock exclusively if this LU requires it,
386 831bbbc1 Michael Hanselmann
      # and in a shared fashion otherwise (to prevent concurrent run with
387 831bbbc1 Michael Hanselmann
      # an exclusive LU.
388 900df6cd Michael Hanselmann
      self._AcquireLocks(locking.LEVEL_CLUSTER, locking.BGL,
389 900df6cd Michael Hanselmann
                          not lu_class.REQ_BGL, calc_timeout(),
390 900df6cd Michael Hanselmann
                          priority)
391 831bbbc1 Michael Hanselmann
      try:
392 831bbbc1 Michael Hanselmann
        lu = lu_class(self, op, self.context, self.rpc)
393 831bbbc1 Michael Hanselmann
        lu.ExpandNames()
394 831bbbc1 Michael Hanselmann
        assert lu.needed_locks is not None, "needed_locks not set by LU"
395 407339d0 Michael Hanselmann
396 407339d0 Michael Hanselmann
        try:
397 f879a9c7 Michael Hanselmann
          return self._LockAndExecLU(lu, locking.LEVEL_INSTANCE, calc_timeout,
398 f879a9c7 Michael Hanselmann
                                     priority)
399 831bbbc1 Michael Hanselmann
        finally:
400 831bbbc1 Michael Hanselmann
          if self._ec_id:
401 831bbbc1 Michael Hanselmann
            self.context.cfg.DropECReservations(self._ec_id)
402 831bbbc1 Michael Hanselmann
      finally:
403 831bbbc1 Michael Hanselmann
        self.context.glm.release(locking.LEVEL_CLUSTER)
404 04864530 Guido Trotter
    finally:
405 031a3e57 Michael Hanselmann
      self._cbs = None
406 6a4aa7c1 Iustin Pop
407 7b4c1cb9 Michael Hanselmann
  def Log(self, *args):
408 031a3e57 Michael Hanselmann
    """Forward call to feedback callback function.
409 031a3e57 Michael Hanselmann

410 031a3e57 Michael Hanselmann
    """
411 031a3e57 Michael Hanselmann
    if self._cbs:
412 031a3e57 Michael Hanselmann
      self._cbs.Feedback(*args)
413 031a3e57 Michael Hanselmann
414 0fbbf897 Iustin Pop
  def LogStep(self, current, total, message):
415 0fbbf897 Iustin Pop
    """Log a change in LU execution progress.
416 0fbbf897 Iustin Pop

417 0fbbf897 Iustin Pop
    """
418 a5eb7789 Iustin Pop
    logging.debug("Step %d/%d %s", current, total, message)
419 7b4c1cb9 Michael Hanselmann
    self.Log("STEP %d/%d %s" % (current, total, message))
420 0fbbf897 Iustin Pop
421 c0088fb9 Iustin Pop
  def LogWarning(self, message, *args, **kwargs):
422 0fbbf897 Iustin Pop
    """Log a warning to the logs and the user.
423 0fbbf897 Iustin Pop

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

429 c0088fb9 Iustin Pop
    """
430 c0088fb9 Iustin Pop
    assert not kwargs or (len(kwargs) == 1 and "hint" in kwargs), \
431 c0088fb9 Iustin Pop
           "Invalid keyword arguments for LogWarning (%s)" % str(kwargs)
432 c0088fb9 Iustin Pop
    if args:
433 c0088fb9 Iustin Pop
      message = message % tuple(args)
434 c0088fb9 Iustin Pop
    if message:
435 c0088fb9 Iustin Pop
      logging.warning(message)
436 7b4c1cb9 Michael Hanselmann
      self.Log(" - WARNING: %s" % message)
437 c0088fb9 Iustin Pop
    if "hint" in kwargs:
438 7b4c1cb9 Michael Hanselmann
      self.Log("      Hint: %s" % kwargs["hint"])
439 c0088fb9 Iustin Pop
440 c0088fb9 Iustin Pop
  def LogInfo(self, message, *args):
441 0fbbf897 Iustin Pop
    """Log an informational message to the logs and the user.
442 0fbbf897 Iustin Pop

443 0fbbf897 Iustin Pop
    """
444 c0088fb9 Iustin Pop
    if args:
445 c0088fb9 Iustin Pop
      message = message % tuple(args)
446 a5eb7789 Iustin Pop
    logging.info(message)
447 7b4c1cb9 Michael Hanselmann
    self.Log(" - INFO: %s" % message)
448 0fbbf897 Iustin Pop
449 adfa97e3 Guido Trotter
  def GetECId(self):
450 adfa97e3 Guido Trotter
    if not self._ec_id:
451 adfa97e3 Guido Trotter
      errors.ProgrammerError("Tried to use execution context id when not set")
452 adfa97e3 Guido Trotter
    return self._ec_id
453 adfa97e3 Guido Trotter
454 a8083063 Iustin Pop
455 a8083063 Iustin Pop
class HooksMaster(object):
456 a8083063 Iustin Pop
  """Hooks master.
457 a8083063 Iustin Pop

458 a8083063 Iustin Pop
  This class distributes the run commands to the nodes based on the
459 a8083063 Iustin Pop
  specific LU class.
460 a8083063 Iustin Pop

461 a8083063 Iustin Pop
  In order to remove the direct dependency on the rpc module, the
462 a8083063 Iustin Pop
  constructor needs a function which actually does the remote
463 a8083063 Iustin Pop
  call. This will usually be rpc.call_hooks_runner, but any function
464 a8083063 Iustin Pop
  which behaves the same works.
465 a8083063 Iustin Pop

466 a8083063 Iustin Pop
  """
467 4b5e8271 Iustin Pop
  def __init__(self, callfn, lu):
468 a8083063 Iustin Pop
    self.callfn = callfn
469 a8083063 Iustin Pop
    self.lu = lu
470 a8083063 Iustin Pop
    self.op = lu.op
471 a8083063 Iustin Pop
    self.env, node_list_pre, node_list_post = self._BuildEnv()
472 a8083063 Iustin Pop
    self.node_list = {constants.HOOKS_PHASE_PRE: node_list_pre,
473 a8083063 Iustin Pop
                      constants.HOOKS_PHASE_POST: node_list_post}
474 a8083063 Iustin Pop
475 a8083063 Iustin Pop
  def _BuildEnv(self):
476 a8083063 Iustin Pop
    """Compute the environment and the target nodes.
477 a8083063 Iustin Pop

478 a8083063 Iustin Pop
    Based on the opcode and the current node list, this builds the
479 a8083063 Iustin Pop
    environment for the hooks and the target node list for the run.
480 a8083063 Iustin Pop

481 a8083063 Iustin Pop
    """
482 a8083063 Iustin Pop
    env = {
483 a8083063 Iustin Pop
      "PATH": "/sbin:/bin:/usr/sbin:/usr/bin",
484 a8083063 Iustin Pop
      "GANETI_HOOKS_VERSION": constants.HOOKS_VERSION,
485 a8083063 Iustin Pop
      "GANETI_OP_CODE": self.op.OP_ID,
486 a8083063 Iustin Pop
      "GANETI_OBJECT_TYPE": self.lu.HTYPE,
487 6a4aa7c1 Iustin Pop
      "GANETI_DATA_DIR": constants.DATA_DIR,
488 a8083063 Iustin Pop
      }
489 a8083063 Iustin Pop
490 9a395a76 Iustin Pop
    if self.lu.HPATH is not None:
491 9a395a76 Iustin Pop
      lu_env, lu_nodes_pre, lu_nodes_post = self.lu.BuildHooksEnv()
492 9a395a76 Iustin Pop
      if lu_env:
493 9a395a76 Iustin Pop
        for key in lu_env:
494 9a395a76 Iustin Pop
          env["GANETI_" + key] = lu_env[key]
495 9a395a76 Iustin Pop
    else:
496 9a395a76 Iustin Pop
      lu_nodes_pre = lu_nodes_post = []
497 a8083063 Iustin Pop
498 4167825b Iustin Pop
    return env, frozenset(lu_nodes_pre), frozenset(lu_nodes_post)
499 4167825b Iustin Pop
500 4167825b Iustin Pop
  def _RunWrapper(self, node_list, hpath, phase):
501 4167825b Iustin Pop
    """Simple wrapper over self.callfn.
502 4167825b Iustin Pop

503 4167825b Iustin Pop
    This method fixes the environment before doing the rpc call.
504 4167825b Iustin Pop

505 4167825b Iustin Pop
    """
506 4167825b Iustin Pop
    env = self.env.copy()
507 4167825b Iustin Pop
    env["GANETI_HOOKS_PHASE"] = phase
508 4167825b Iustin Pop
    env["GANETI_HOOKS_PATH"] = hpath
509 437138c9 Michael Hanselmann
    if self.lu.cfg is not None:
510 437138c9 Michael Hanselmann
      env["GANETI_CLUSTER"] = self.lu.cfg.GetClusterName()
511 437138c9 Michael Hanselmann
      env["GANETI_MASTER"] = self.lu.cfg.GetMasterNode()
512 a8083063 Iustin Pop
513 4167825b Iustin Pop
    env = dict([(str(key), str(val)) for key, val in env.iteritems()])
514 a8083063 Iustin Pop
515 4167825b Iustin Pop
    return self.callfn(node_list, hpath, phase, env)
516 a8083063 Iustin Pop
517 17e82923 Luca Bigliardi
  def RunPhase(self, phase, nodes=None):
518 a8083063 Iustin Pop
    """Run all the scripts for a phase.
519 a8083063 Iustin Pop

520 a8083063 Iustin Pop
    This is the main function of the HookMaster.
521 a8083063 Iustin Pop

522 8dca23a3 Iustin Pop
    @param phase: one of L{constants.HOOKS_PHASE_POST} or
523 8dca23a3 Iustin Pop
        L{constants.HOOKS_PHASE_PRE}; it denotes the hooks phase
524 17e82923 Luca Bigliardi
    @param nodes: overrides the predefined list of nodes for the given phase
525 8dca23a3 Iustin Pop
    @return: the processed results of the hooks multi-node rpc call
526 8dca23a3 Iustin Pop
    @raise errors.HooksFailure: on communication failure to the nodes
527 6ef2dc74 Luca Bigliardi
    @raise errors.HooksAbort: on failure of one of the hooks
528 b07a6922 Guido Trotter

529 a8083063 Iustin Pop
    """
530 17e82923 Luca Bigliardi
    if not self.node_list[phase] and not nodes:
531 9a395a76 Iustin Pop
      # empty node list, we should not attempt to run this as either
532 9a395a76 Iustin Pop
      # we're in the cluster init phase and the rpc client part can't
533 9a395a76 Iustin Pop
      # even attempt to run, or this LU doesn't do hooks at all
534 a8083063 Iustin Pop
      return
535 4167825b Iustin Pop
    hpath = self.lu.HPATH
536 17e82923 Luca Bigliardi
    if nodes is not None:
537 17e82923 Luca Bigliardi
      results = self._RunWrapper(nodes, hpath, phase)
538 17e82923 Luca Bigliardi
    else:
539 17e82923 Luca Bigliardi
      results = self._RunWrapper(self.node_list[phase], hpath, phase)
540 8c4b9364 Luca Bigliardi
    errs = []
541 8c4b9364 Luca Bigliardi
    if not results:
542 8c4b9364 Luca Bigliardi
      msg = "Communication Failure"
543 8c4b9364 Luca Bigliardi
      if phase == constants.HOOKS_PHASE_PRE:
544 8c4b9364 Luca Bigliardi
        raise errors.HooksFailure(msg)
545 8c4b9364 Luca Bigliardi
      else:
546 8c4b9364 Luca Bigliardi
        self.lu.LogWarning(msg)
547 640b961e Luca Bigliardi
        return results
548 8c4b9364 Luca Bigliardi
    for node_name in results:
549 8c4b9364 Luca Bigliardi
      res = results[node_name]
550 8c4b9364 Luca Bigliardi
      if res.offline:
551 8c4b9364 Luca Bigliardi
        continue
552 3cebe102 Michael Hanselmann
      msg = res.fail_msg
553 8c4b9364 Luca Bigliardi
      if msg:
554 8c4b9364 Luca Bigliardi
        self.lu.LogWarning("Communication failure to node %s: %s",
555 8c4b9364 Luca Bigliardi
                           node_name, msg)
556 8c4b9364 Luca Bigliardi
        continue
557 8c4b9364 Luca Bigliardi
      for script, hkr, output in res.payload:
558 8c4b9364 Luca Bigliardi
        if hkr == constants.HKR_FAIL:
559 8c4b9364 Luca Bigliardi
          if phase == constants.HOOKS_PHASE_PRE:
560 a8083063 Iustin Pop
            errs.append((node_name, script, output))
561 8c4b9364 Luca Bigliardi
          else:
562 8c4b9364 Luca Bigliardi
            if not output:
563 640b961e Luca Bigliardi
              output = "(no output)"
564 8c4b9364 Luca Bigliardi
            self.lu.LogWarning("On %s script %s failed, output: %s" %
565 8c4b9364 Luca Bigliardi
                               (node_name, script, output))
566 8c4b9364 Luca Bigliardi
    if errs and phase == constants.HOOKS_PHASE_PRE:
567 8c4b9364 Luca Bigliardi
      raise errors.HooksAbort(errs)
568 b07a6922 Guido Trotter
    return results
569 6a4aa7c1 Iustin Pop
570 6a4aa7c1 Iustin Pop
  def RunConfigUpdate(self):
571 6a4aa7c1 Iustin Pop
    """Run the special configuration update hook
572 6a4aa7c1 Iustin Pop

573 6a4aa7c1 Iustin Pop
    This is a special hook that runs only on the master after each
574 6a4aa7c1 Iustin Pop
    top-level LI if the configuration has been updated.
575 6a4aa7c1 Iustin Pop

576 6a4aa7c1 Iustin Pop
    """
577 6a4aa7c1 Iustin Pop
    phase = constants.HOOKS_PHASE_POST
578 6a4aa7c1 Iustin Pop
    hpath = constants.HOOKS_NAME_CFGUPDATE
579 437138c9 Michael Hanselmann
    nodes = [self.lu.cfg.GetMasterNode()]
580 29921401 Iustin Pop
    self._RunWrapper(nodes, hpath, phase)