Statistics
| Branch: | Tag: | Revision:

root / lib / mcpu.py @ 26d3fd2f

History | View | Annotate | Download (18.1 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 a8083063 Iustin Pop
42 7c0d6283 Michael Hanselmann
43 831bbbc1 Michael Hanselmann
class LockAcquireTimeout(Exception):
44 831bbbc1 Michael Hanselmann
  """Exception to report timeouts on acquiring locks.
45 407339d0 Michael Hanselmann

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

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

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

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

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

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

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

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

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

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

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

209 adfa97e3 Guido Trotter
    @type context: GanetiContext
210 adfa97e3 Guido Trotter
    @param context: global Ganeti context
211 adfa97e3 Guido Trotter
    @type ec_id: string
212 adfa97e3 Guido Trotter
    @param ec_id: execution context identifier
213 adfa97e3 Guido Trotter

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

224 211b6132 Michael Hanselmann
    @type level: int
225 211b6132 Michael Hanselmann
    @param level: Lock level
226 211b6132 Michael Hanselmann
    @type names: list or string
227 211b6132 Michael Hanselmann
    @param names: Lock names
228 211b6132 Michael Hanselmann
    @type shared: bool
229 211b6132 Michael Hanselmann
    @param shared: Whether the locks should be acquired in shared mode
230 211b6132 Michael Hanselmann
    @type timeout: None or float
231 211b6132 Michael Hanselmann
    @param timeout: Timeout for acquiring the locks
232 211b6132 Michael Hanselmann

233 211b6132 Michael Hanselmann
    """
234 acf931b7 Michael Hanselmann
    if self._cbs:
235 acf931b7 Michael Hanselmann
      self._cbs.CheckCancel()
236 211b6132 Michael Hanselmann
237 211b6132 Michael Hanselmann
    acquired = self.context.glm.acquire(level, names, shared=shared,
238 211b6132 Michael Hanselmann
                                        timeout=timeout)
239 211b6132 Michael Hanselmann
240 211b6132 Michael Hanselmann
    return acquired
241 211b6132 Michael Hanselmann
242 36c381d7 Guido Trotter
  def _ExecLU(self, lu):
243 36c381d7 Guido Trotter
    """Logical Unit execution sequence.
244 36c381d7 Guido Trotter

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

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

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

347 e92376d7 Iustin Pop
    @type op: an OpCode instance
348 e92376d7 Iustin Pop
    @param op: the opcode to be executed
349 031a3e57 Michael Hanselmann
    @type cbs: L{OpExecCbBase}
350 031a3e57 Michael Hanselmann
    @param cbs: Runtime callbacks
351 831bbbc1 Michael Hanselmann
    @type timeout: float or None
352 831bbbc1 Michael Hanselmann
    @param timeout: Maximum time to acquire all locks, None for no timeout
353 831bbbc1 Michael Hanselmann
    @raise LockAcquireTimeout: In case locks couldn't be acquired in specified
354 831bbbc1 Michael Hanselmann
        amount of time
355 a8083063 Iustin Pop

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

397 031a3e57 Michael Hanselmann
    """
398 031a3e57 Michael Hanselmann
    if self._cbs:
399 031a3e57 Michael Hanselmann
      self._cbs.Feedback(*args)
400 031a3e57 Michael Hanselmann
401 0fbbf897 Iustin Pop
  def LogStep(self, current, total, message):
402 0fbbf897 Iustin Pop
    """Log a change in LU execution progress.
403 0fbbf897 Iustin Pop

404 0fbbf897 Iustin Pop
    """
405 a5eb7789 Iustin Pop
    logging.debug("Step %d/%d %s", current, total, message)
406 7b4c1cb9 Michael Hanselmann
    self.Log("STEP %d/%d %s" % (current, total, message))
407 0fbbf897 Iustin Pop
408 c0088fb9 Iustin Pop
  def LogWarning(self, message, *args, **kwargs):
409 0fbbf897 Iustin Pop
    """Log a warning to the logs and the user.
410 0fbbf897 Iustin Pop

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

416 c0088fb9 Iustin Pop
    """
417 c0088fb9 Iustin Pop
    assert not kwargs or (len(kwargs) == 1 and "hint" in kwargs), \
418 c0088fb9 Iustin Pop
           "Invalid keyword arguments for LogWarning (%s)" % str(kwargs)
419 c0088fb9 Iustin Pop
    if args:
420 c0088fb9 Iustin Pop
      message = message % tuple(args)
421 c0088fb9 Iustin Pop
    if message:
422 c0088fb9 Iustin Pop
      logging.warning(message)
423 7b4c1cb9 Michael Hanselmann
      self.Log(" - WARNING: %s" % message)
424 c0088fb9 Iustin Pop
    if "hint" in kwargs:
425 7b4c1cb9 Michael Hanselmann
      self.Log("      Hint: %s" % kwargs["hint"])
426 c0088fb9 Iustin Pop
427 c0088fb9 Iustin Pop
  def LogInfo(self, message, *args):
428 0fbbf897 Iustin Pop
    """Log an informational message to the logs and the user.
429 0fbbf897 Iustin Pop

430 0fbbf897 Iustin Pop
    """
431 c0088fb9 Iustin Pop
    if args:
432 c0088fb9 Iustin Pop
      message = message % tuple(args)
433 a5eb7789 Iustin Pop
    logging.info(message)
434 7b4c1cb9 Michael Hanselmann
    self.Log(" - INFO: %s" % message)
435 0fbbf897 Iustin Pop
436 adfa97e3 Guido Trotter
  def GetECId(self):
437 adfa97e3 Guido Trotter
    if not self._ec_id:
438 adfa97e3 Guido Trotter
      errors.ProgrammerError("Tried to use execution context id when not set")
439 adfa97e3 Guido Trotter
    return self._ec_id
440 adfa97e3 Guido Trotter
441 a8083063 Iustin Pop
442 a8083063 Iustin Pop
class HooksMaster(object):
443 a8083063 Iustin Pop
  """Hooks master.
444 a8083063 Iustin Pop

445 a8083063 Iustin Pop
  This class distributes the run commands to the nodes based on the
446 a8083063 Iustin Pop
  specific LU class.
447 a8083063 Iustin Pop

448 a8083063 Iustin Pop
  In order to remove the direct dependency on the rpc module, the
449 a8083063 Iustin Pop
  constructor needs a function which actually does the remote
450 a8083063 Iustin Pop
  call. This will usually be rpc.call_hooks_runner, but any function
451 a8083063 Iustin Pop
  which behaves the same works.
452 a8083063 Iustin Pop

453 a8083063 Iustin Pop
  """
454 4b5e8271 Iustin Pop
  def __init__(self, callfn, lu):
455 a8083063 Iustin Pop
    self.callfn = callfn
456 a8083063 Iustin Pop
    self.lu = lu
457 a8083063 Iustin Pop
    self.op = lu.op
458 a8083063 Iustin Pop
    self.env, node_list_pre, node_list_post = self._BuildEnv()
459 a8083063 Iustin Pop
    self.node_list = {constants.HOOKS_PHASE_PRE: node_list_pre,
460 a8083063 Iustin Pop
                      constants.HOOKS_PHASE_POST: node_list_post}
461 a8083063 Iustin Pop
462 a8083063 Iustin Pop
  def _BuildEnv(self):
463 a8083063 Iustin Pop
    """Compute the environment and the target nodes.
464 a8083063 Iustin Pop

465 a8083063 Iustin Pop
    Based on the opcode and the current node list, this builds the
466 a8083063 Iustin Pop
    environment for the hooks and the target node list for the run.
467 a8083063 Iustin Pop

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

490 4167825b Iustin Pop
    This method fixes the environment before doing the rpc call.
491 4167825b Iustin Pop

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

507 a8083063 Iustin Pop
    This is the main function of the HookMaster.
508 a8083063 Iustin Pop

509 8dca23a3 Iustin Pop
    @param phase: one of L{constants.HOOKS_PHASE_POST} or
510 8dca23a3 Iustin Pop
        L{constants.HOOKS_PHASE_PRE}; it denotes the hooks phase
511 17e82923 Luca Bigliardi
    @param nodes: overrides the predefined list of nodes for the given phase
512 8dca23a3 Iustin Pop
    @return: the processed results of the hooks multi-node rpc call
513 8dca23a3 Iustin Pop
    @raise errors.HooksFailure: on communication failure to the nodes
514 6ef2dc74 Luca Bigliardi
    @raise errors.HooksAbort: on failure of one of the hooks
515 b07a6922 Guido Trotter

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

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

563 6a4aa7c1 Iustin Pop
    """
564 6a4aa7c1 Iustin Pop
    phase = constants.HOOKS_PHASE_POST
565 6a4aa7c1 Iustin Pop
    hpath = constants.HOOKS_NAME_CFGUPDATE
566 437138c9 Michael Hanselmann
    nodes = [self.lu.cfg.GetMasterNode()]
567 29921401 Iustin Pop
    self._RunWrapper(nodes, hpath, phase)