Statistics
| Branch: | Tag: | Revision:

root / lib / mcpu.py @ 70a6a926

History | View | Annotate | Download (18.5 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 70a6a926 Adeodato Simo
    opcodes.OpQueryGroups: cmdlib.LUQueryGroups,
193 a8083063 Iustin Pop
    # os lu
194 a8083063 Iustin Pop
    opcodes.OpDiagnoseOS: cmdlib.LUDiagnoseOS,
195 a8083063 Iustin Pop
    # exports lu
196 a8083063 Iustin Pop
    opcodes.OpQueryExports: cmdlib.LUQueryExports,
197 1410fa8d Michael Hanselmann
    opcodes.OpPrepareExport: cmdlib.LUPrepareExport,
198 a8083063 Iustin Pop
    opcodes.OpExportInstance: cmdlib.LUExportInstance,
199 9ac99fda Guido Trotter
    opcodes.OpRemoveExport: cmdlib.LURemoveExport,
200 5c947f38 Iustin Pop
    # tags lu
201 5c947f38 Iustin Pop
    opcodes.OpGetTags: cmdlib.LUGetTags,
202 73415719 Iustin Pop
    opcodes.OpSearchTags: cmdlib.LUSearchTags,
203 f27302fa Iustin Pop
    opcodes.OpAddTags: cmdlib.LUAddTags,
204 f27302fa Iustin Pop
    opcodes.OpDelTags: cmdlib.LUDelTags,
205 06009e27 Iustin Pop
    # test lu
206 06009e27 Iustin Pop
    opcodes.OpTestDelay: cmdlib.LUTestDelay,
207 d61df03e Iustin Pop
    opcodes.OpTestAllocator: cmdlib.LUTestAllocator,
208 e58f87a9 Michael Hanselmann
    opcodes.OpTestJobqueue: cmdlib.LUTestJobqueue,
209 a8083063 Iustin Pop
    }
210 a8083063 Iustin Pop
211 adfa97e3 Guido Trotter
  def __init__(self, context, ec_id):
212 a8083063 Iustin Pop
    """Constructor for Processor
213 a8083063 Iustin Pop

214 adfa97e3 Guido Trotter
    @type context: GanetiContext
215 adfa97e3 Guido Trotter
    @param context: global Ganeti context
216 adfa97e3 Guido Trotter
    @type ec_id: string
217 adfa97e3 Guido Trotter
    @param ec_id: execution context identifier
218 adfa97e3 Guido Trotter

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

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

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

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

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

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

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

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

405 031a3e57 Michael Hanselmann
    """
406 031a3e57 Michael Hanselmann
    if self._cbs:
407 031a3e57 Michael Hanselmann
      self._cbs.Feedback(*args)
408 031a3e57 Michael Hanselmann
409 0fbbf897 Iustin Pop
  def LogStep(self, current, total, message):
410 0fbbf897 Iustin Pop
    """Log a change in LU execution progress.
411 0fbbf897 Iustin Pop

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

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

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

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

453 a8083063 Iustin Pop
  This class distributes the run commands to the nodes based on the
454 a8083063 Iustin Pop
  specific LU class.
455 a8083063 Iustin Pop

456 a8083063 Iustin Pop
  In order to remove the direct dependency on the rpc module, the
457 a8083063 Iustin Pop
  constructor needs a function which actually does the remote
458 a8083063 Iustin Pop
  call. This will usually be rpc.call_hooks_runner, but any function
459 a8083063 Iustin Pop
  which behaves the same works.
460 a8083063 Iustin Pop

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

473 a8083063 Iustin Pop
    Based on the opcode and the current node list, this builds the
474 a8083063 Iustin Pop
    environment for the hooks and the target node list for the run.
475 a8083063 Iustin Pop

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

498 4167825b Iustin Pop
    This method fixes the environment before doing the rpc call.
499 4167825b Iustin Pop

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

515 a8083063 Iustin Pop
    This is the main function of the HookMaster.
516 a8083063 Iustin Pop

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

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

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

571 6a4aa7c1 Iustin Pop
    """
572 6a4aa7c1 Iustin Pop
    phase = constants.HOOKS_PHASE_POST
573 6a4aa7c1 Iustin Pop
    hpath = constants.HOOKS_NAME_CFGUPDATE
574 437138c9 Michael Hanselmann
    nodes = [self.lu.cfg.GetMasterNode()]
575 29921401 Iustin Pop
    self._RunWrapper(nodes, hpath, phase)