Statistics
| Branch: | Tag: | Revision:

root / lib / mcpu.py @ a194dc28

History | View | Annotate | Download (21.3 kB)

1 2f31098c Iustin Pop
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 a1a7bc78 Iustin Pop
# Copyright (C) 2006, 2007, 2011 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 cmdlib
39 04864530 Guido Trotter
from ganeti import locking
40 557838c1 René Nussbaumer
from ganeti import utils
41 ebc75510 Michael Hanselmann
from ganeti import compat
42 a8083063 Iustin Pop
43 7c0d6283 Michael Hanselmann
44 a1a7bc78 Iustin Pop
_OP_PREFIX = "Op"
45 a1a7bc78 Iustin Pop
_LU_PREFIX = "LU"
46 a1a7bc78 Iustin Pop
47 a1a7bc78 Iustin Pop
48 831bbbc1 Michael Hanselmann
class LockAcquireTimeout(Exception):
49 831bbbc1 Michael Hanselmann
  """Exception to report timeouts on acquiring locks.
50 407339d0 Michael Hanselmann

51 407339d0 Michael Hanselmann
  """
52 407339d0 Michael Hanselmann
53 407339d0 Michael Hanselmann
54 e3200b18 Michael Hanselmann
def _CalculateLockAttemptTimeouts():
55 e3200b18 Michael Hanselmann
  """Calculate timeouts for lock attempts.
56 e3200b18 Michael Hanselmann

57 e3200b18 Michael Hanselmann
  """
58 d385a174 Iustin Pop
  result = [constants.LOCK_ATTEMPTS_MINWAIT]
59 d385a174 Iustin Pop
  running_sum = result[0]
60 e3200b18 Michael Hanselmann
61 d385a174 Iustin Pop
  # Wait for a total of at least LOCK_ATTEMPTS_TIMEOUT before doing a
62 d385a174 Iustin Pop
  # blocking acquire
63 d385a174 Iustin Pop
  while running_sum < constants.LOCK_ATTEMPTS_TIMEOUT:
64 e3200b18 Michael Hanselmann
    timeout = (result[-1] * 1.05) ** 1.25
65 e3200b18 Michael Hanselmann
66 d385a174 Iustin Pop
    # Cap max timeout. This gives other jobs a chance to run even if
67 d385a174 Iustin Pop
    # we're still trying to get our locks, before finally moving to a
68 d385a174 Iustin Pop
    # blocking acquire.
69 d385a174 Iustin Pop
    timeout = min(timeout, constants.LOCK_ATTEMPTS_MAXWAIT)
70 d385a174 Iustin Pop
    # And also cap the lower boundary for safety
71 d385a174 Iustin Pop
    timeout = max(timeout, constants.LOCK_ATTEMPTS_MINWAIT)
72 e3200b18 Michael Hanselmann
73 e3200b18 Michael Hanselmann
    result.append(timeout)
74 d385a174 Iustin Pop
    running_sum += timeout
75 e3200b18 Michael Hanselmann
76 e3200b18 Michael Hanselmann
  return result
77 e3200b18 Michael Hanselmann
78 e3200b18 Michael Hanselmann
79 a7770f03 Michael Hanselmann
class LockAttemptTimeoutStrategy(object):
80 407339d0 Michael Hanselmann
  """Class with lock acquire timeout strategy.
81 407339d0 Michael Hanselmann

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

94 e3200b18 Michael Hanselmann
    @param _time_fn: Time function for unittests
95 407339d0 Michael Hanselmann
    @param _random_fn: Random number generator for unittests
96 407339d0 Michael Hanselmann

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

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

127 031a3e57 Michael Hanselmann
  """
128 031a3e57 Michael Hanselmann
  def NotifyStart(self):
129 031a3e57 Michael Hanselmann
    """Called when we are about to execute the LU.
130 031a3e57 Michael Hanselmann

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

134 031a3e57 Michael Hanselmann
    """
135 031a3e57 Michael Hanselmann
136 031a3e57 Michael Hanselmann
  def Feedback(self, *args):
137 031a3e57 Michael Hanselmann
    """Sends feedback from the LU code to the end-user.
138 031a3e57 Michael Hanselmann

139 031a3e57 Michael Hanselmann
    """
140 031a3e57 Michael Hanselmann
141 acf931b7 Michael Hanselmann
  def CheckCancel(self):
142 acf931b7 Michael Hanselmann
    """Check whether job has been cancelled.
143 ef2df7d3 Michael Hanselmann

144 ef2df7d3 Michael Hanselmann
    """
145 ef2df7d3 Michael Hanselmann
146 6a373640 Michael Hanselmann
  def SubmitManyJobs(self, jobs):
147 6a373640 Michael Hanselmann
    """Submits jobs for processing.
148 6a373640 Michael Hanselmann

149 6a373640 Michael Hanselmann
    See L{jqueue.JobQueue.SubmitManyJobs}.
150 6a373640 Michael Hanselmann

151 6a373640 Michael Hanselmann
    """
152 6a373640 Michael Hanselmann
    raise NotImplementedError
153 6a373640 Michael Hanselmann
154 031a3e57 Michael Hanselmann
155 a1a7bc78 Iustin Pop
def _LUNameForOpName(opname):
156 a1a7bc78 Iustin Pop
  """Computes the LU name for a given OpCode name.
157 a1a7bc78 Iustin Pop

158 a1a7bc78 Iustin Pop
  """
159 a1a7bc78 Iustin Pop
  assert opname.startswith(_OP_PREFIX), \
160 a1a7bc78 Iustin Pop
      "Invalid OpCode name, doesn't start with %s: %s" % (_OP_PREFIX, opname)
161 a1a7bc78 Iustin Pop
162 a1a7bc78 Iustin Pop
  return _LU_PREFIX + opname[len(_OP_PREFIX):]
163 a1a7bc78 Iustin Pop
164 a1a7bc78 Iustin Pop
165 a1a7bc78 Iustin Pop
def _ComputeDispatchTable():
166 a1a7bc78 Iustin Pop
  """Computes the opcode-to-lu dispatch table.
167 a1a7bc78 Iustin Pop

168 a1a7bc78 Iustin Pop
  """
169 a1a7bc78 Iustin Pop
  return dict((op, getattr(cmdlib, _LUNameForOpName(op.__name__)))
170 a1a7bc78 Iustin Pop
              for op in opcodes.OP_MAPPING.values()
171 a1a7bc78 Iustin Pop
              if op.WITH_LU)
172 a1a7bc78 Iustin Pop
173 a1a7bc78 Iustin Pop
174 949dcb1d Andrea Spadaccini
def _RpcResultsToHooksResults(rpc_results):
175 949dcb1d Andrea Spadaccini
  """Function to convert RPC results to the format expected by HooksMaster.
176 949dcb1d Andrea Spadaccini

177 949dcb1d Andrea Spadaccini
  @type rpc_results: dict(node: L{rpc.RpcResult})
178 949dcb1d Andrea Spadaccini
  @param rpc_results: RPC results
179 949dcb1d Andrea Spadaccini
  @rtype: dict(node: (fail_msg, offline, hooks_results))
180 949dcb1d Andrea Spadaccini
  @return: RPC results unpacked according to the format expected by
181 949dcb1d Andrea Spadaccini
    L({mcpu.HooksMaster}
182 949dcb1d Andrea Spadaccini

183 949dcb1d Andrea Spadaccini
  """
184 949dcb1d Andrea Spadaccini
  return dict((node, (rpc_res.fail_msg, rpc_res.offline, rpc_res.payload))
185 949dcb1d Andrea Spadaccini
              for (node, rpc_res) in rpc_results.items())
186 949dcb1d Andrea Spadaccini
187 949dcb1d Andrea Spadaccini
188 a8083063 Iustin Pop
class Processor(object):
189 a8083063 Iustin Pop
  """Object which runs OpCodes"""
190 a1a7bc78 Iustin Pop
  DISPATCH_TABLE = _ComputeDispatchTable()
191 a8083063 Iustin Pop
192 adfa97e3 Guido Trotter
  def __init__(self, context, ec_id):
193 a8083063 Iustin Pop
    """Constructor for Processor
194 a8083063 Iustin Pop

195 adfa97e3 Guido Trotter
    @type context: GanetiContext
196 adfa97e3 Guido Trotter
    @param context: global Ganeti context
197 adfa97e3 Guido Trotter
    @type ec_id: string
198 adfa97e3 Guido Trotter
    @param ec_id: execution context identifier
199 adfa97e3 Guido Trotter

200 a8083063 Iustin Pop
    """
201 1c901d13 Guido Trotter
    self.context = context
202 adfa97e3 Guido Trotter
    self._ec_id = ec_id
203 031a3e57 Michael Hanselmann
    self._cbs = None
204 87b3cb26 Michael Hanselmann
    self.rpc = context.rpc
205 cd46f3b4 Luca Bigliardi
    self.hmclass = HooksMaster
206 a8083063 Iustin Pop
207 f879a9c7 Michael Hanselmann
  def _AcquireLocks(self, level, names, shared, timeout, priority):
208 211b6132 Michael Hanselmann
    """Acquires locks via the Ganeti lock manager.
209 211b6132 Michael Hanselmann

210 211b6132 Michael Hanselmann
    @type level: int
211 211b6132 Michael Hanselmann
    @param level: Lock level
212 211b6132 Michael Hanselmann
    @type names: list or string
213 211b6132 Michael Hanselmann
    @param names: Lock names
214 211b6132 Michael Hanselmann
    @type shared: bool
215 211b6132 Michael Hanselmann
    @param shared: Whether the locks should be acquired in shared mode
216 211b6132 Michael Hanselmann
    @type timeout: None or float
217 211b6132 Michael Hanselmann
    @param timeout: Timeout for acquiring the locks
218 900df6cd Michael Hanselmann
    @raise LockAcquireTimeout: In case locks couldn't be acquired in specified
219 900df6cd Michael Hanselmann
        amount of time
220 211b6132 Michael Hanselmann

221 211b6132 Michael Hanselmann
    """
222 acf931b7 Michael Hanselmann
    if self._cbs:
223 acf931b7 Michael Hanselmann
      self._cbs.CheckCancel()
224 211b6132 Michael Hanselmann
225 211b6132 Michael Hanselmann
    acquired = self.context.glm.acquire(level, names, shared=shared,
226 f879a9c7 Michael Hanselmann
                                        timeout=timeout, priority=priority)
227 211b6132 Michael Hanselmann
228 900df6cd Michael Hanselmann
    if acquired is None:
229 900df6cd Michael Hanselmann
      raise LockAcquireTimeout()
230 900df6cd Michael Hanselmann
231 211b6132 Michael Hanselmann
    return acquired
232 211b6132 Michael Hanselmann
233 6a373640 Michael Hanselmann
  def _ProcessResult(self, result):
234 eb279644 Michael Hanselmann
    """Examines opcode result.
235 eb279644 Michael Hanselmann

236 eb279644 Michael Hanselmann
    If necessary, additional processing on the result is done.
237 6a373640 Michael Hanselmann

238 6a373640 Michael Hanselmann
    """
239 6a373640 Michael Hanselmann
    if isinstance(result, cmdlib.ResultWithJobs):
240 6a373640 Michael Hanselmann
      # Submit jobs
241 6a373640 Michael Hanselmann
      job_submission = self._cbs.SubmitManyJobs(result.jobs)
242 6a373640 Michael Hanselmann
243 6a373640 Michael Hanselmann
      # Build dictionary
244 6a373640 Michael Hanselmann
      result = result.other
245 6a373640 Michael Hanselmann
246 6a373640 Michael Hanselmann
      assert constants.JOB_IDS_KEY not in result, \
247 6a373640 Michael Hanselmann
        "Key '%s' found in additional return values" % constants.JOB_IDS_KEY
248 6a373640 Michael Hanselmann
249 6a373640 Michael Hanselmann
      result[constants.JOB_IDS_KEY] = job_submission
250 6a373640 Michael Hanselmann
251 6a373640 Michael Hanselmann
    return result
252 6a373640 Michael Hanselmann
253 36c381d7 Guido Trotter
  def _ExecLU(self, lu):
254 36c381d7 Guido Trotter
    """Logical Unit execution sequence.
255 36c381d7 Guido Trotter

256 36c381d7 Guido Trotter
    """
257 36c381d7 Guido Trotter
    write_count = self.context.cfg.write_count
258 36c381d7 Guido Trotter
    lu.CheckPrereq()
259 949dcb1d Andrea Spadaccini
260 949dcb1d Andrea Spadaccini
    hm = self.BuildHooksManager(lu)
261 36c381d7 Guido Trotter
    h_results = hm.RunPhase(constants.HOOKS_PHASE_PRE)
262 36c381d7 Guido Trotter
    lu.HooksCallBack(constants.HOOKS_PHASE_PRE, h_results,
263 7b4c1cb9 Michael Hanselmann
                     self.Log, None)
264 20777413 Iustin Pop
265 20777413 Iustin Pop
    if getattr(lu.op, "dry_run", False):
266 20777413 Iustin Pop
      # in this mode, no post-hooks are run, and the config is not
267 20777413 Iustin Pop
      # written (as it might have been modified by another LU, and we
268 20777413 Iustin Pop
      # shouldn't do writeout on behalf of other threads
269 20777413 Iustin Pop
      self.LogInfo("dry-run mode requested, not actually executing"
270 20777413 Iustin Pop
                   " the operation")
271 20777413 Iustin Pop
      return lu.dry_run_result
272 20777413 Iustin Pop
273 36c381d7 Guido Trotter
    try:
274 6a373640 Michael Hanselmann
      result = self._ProcessResult(lu.Exec(self.Log))
275 36c381d7 Guido Trotter
      h_results = hm.RunPhase(constants.HOOKS_PHASE_POST)
276 36c381d7 Guido Trotter
      result = lu.HooksCallBack(constants.HOOKS_PHASE_POST, h_results,
277 7b4c1cb9 Michael Hanselmann
                                self.Log, result)
278 36c381d7 Guido Trotter
    finally:
279 36c381d7 Guido Trotter
      # FIXME: This needs locks if not lu_class.REQ_BGL
280 36c381d7 Guido Trotter
      if write_count != self.context.cfg.write_count:
281 36c381d7 Guido Trotter
        hm.RunConfigUpdate()
282 36c381d7 Guido Trotter
283 36c381d7 Guido Trotter
    return result
284 36c381d7 Guido Trotter
285 949dcb1d Andrea Spadaccini
  def BuildHooksManager(self, lu):
286 949dcb1d Andrea Spadaccini
    return self.hmclass.BuildFromLu(lu.rpc.call_hooks_runner, lu)
287 949dcb1d Andrea Spadaccini
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 0d5a0b96 Michael Hanselmann
          self._AcquireLocks(level, needed_locks, share,
323 0d5a0b96 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 ca2a79e1 Guido Trotter
        try:
338 f879a9c7 Michael Hanselmann
          result = self._LockAndExecLU(lu, level + 1, calc_timeout, priority)
339 ca2a79e1 Guido Trotter
        finally:
340 ca2a79e1 Guido Trotter
          if level in lu.remove_locks:
341 ca2a79e1 Guido Trotter
            self.context.glm.remove(level, lu.remove_locks[level])
342 68adfdb2 Guido Trotter
      finally:
343 80ee04a4 Guido Trotter
        if self.context.glm.is_owned(level):
344 68adfdb2 Guido Trotter
          self.context.glm.release(level)
345 407339d0 Michael Hanselmann
346 68adfdb2 Guido Trotter
    else:
347 f879a9c7 Michael Hanselmann
      result = self._LockAndExecLU(lu, level + 1, calc_timeout, priority)
348 68adfdb2 Guido Trotter
349 68adfdb2 Guido Trotter
    return result
350 68adfdb2 Guido Trotter
351 f879a9c7 Michael Hanselmann
  def ExecOpCode(self, op, cbs, timeout=None, priority=None):
352 a8083063 Iustin Pop
    """Execute an opcode.
353 a8083063 Iustin Pop

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

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

415 031a3e57 Michael Hanselmann
    """
416 031a3e57 Michael Hanselmann
    if self._cbs:
417 031a3e57 Michael Hanselmann
      self._cbs.Feedback(*args)
418 031a3e57 Michael Hanselmann
419 0fbbf897 Iustin Pop
  def LogStep(self, current, total, message):
420 0fbbf897 Iustin Pop
    """Log a change in LU execution progress.
421 0fbbf897 Iustin Pop

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

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

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

448 0fbbf897 Iustin Pop
    """
449 c0088fb9 Iustin Pop
    if args:
450 c0088fb9 Iustin Pop
      message = message % tuple(args)
451 a5eb7789 Iustin Pop
    logging.info(message)
452 7b4c1cb9 Michael Hanselmann
    self.Log(" - INFO: %s" % message)
453 0fbbf897 Iustin Pop
454 adfa97e3 Guido Trotter
  def GetECId(self):
455 3ae70d76 Michael Hanselmann
    """Returns the current execution context ID.
456 3ae70d76 Michael Hanselmann

457 3ae70d76 Michael Hanselmann
    """
458 adfa97e3 Guido Trotter
    if not self._ec_id:
459 3ae70d76 Michael Hanselmann
      raise errors.ProgrammerError("Tried to use execution context id when"
460 3ae70d76 Michael Hanselmann
                                   " not set")
461 adfa97e3 Guido Trotter
    return self._ec_id
462 adfa97e3 Guido Trotter
463 a8083063 Iustin Pop
464 a8083063 Iustin Pop
class HooksMaster(object):
465 949dcb1d Andrea Spadaccini
  def __init__(self, opcode, hooks_path, nodes, hooks_execution_fn,
466 949dcb1d Andrea Spadaccini
    hooks_results_adapt_fn, build_env_fn, log_fn, htype=None, cluster_name=None,
467 949dcb1d Andrea Spadaccini
    master_name=None):
468 949dcb1d Andrea Spadaccini
    """Base class for hooks masters.
469 949dcb1d Andrea Spadaccini

470 949dcb1d Andrea Spadaccini
    This class invokes the execution of hooks according to the behaviour
471 949dcb1d Andrea Spadaccini
    specified by its parameters.
472 949dcb1d Andrea Spadaccini

473 949dcb1d Andrea Spadaccini
    @type opcode: string
474 949dcb1d Andrea Spadaccini
    @param opcode: opcode of the operation to which the hooks are tied
475 949dcb1d Andrea Spadaccini
    @type hooks_path: string
476 949dcb1d Andrea Spadaccini
    @param hooks_path: prefix of the hooks directories
477 949dcb1d Andrea Spadaccini
    @type nodes: 2-tuple of lists
478 949dcb1d Andrea Spadaccini
    @param nodes: 2-tuple of lists containing nodes on which pre-hooks must be
479 949dcb1d Andrea Spadaccini
      run and nodes on which post-hooks must be run
480 949dcb1d Andrea Spadaccini
    @type hooks_execution_fn: function that accepts the following parameters:
481 949dcb1d Andrea Spadaccini
      (node_list, hooks_path, phase, environment)
482 949dcb1d Andrea Spadaccini
    @param hooks_execution_fn: function that will execute the hooks; can be
483 949dcb1d Andrea Spadaccini
      None, indicating that no conversion is necessary.
484 949dcb1d Andrea Spadaccini
    @type hooks_results_adapt_fn: function
485 949dcb1d Andrea Spadaccini
    @param hooks_results_adapt_fn: function that will adapt the return value of
486 949dcb1d Andrea Spadaccini
      hooks_execution_fn to the format expected by RunPhase
487 949dcb1d Andrea Spadaccini
    @type build_env_fn: function that returns a dictionary having strings as
488 949dcb1d Andrea Spadaccini
      keys
489 949dcb1d Andrea Spadaccini
    @param build_env_fn: function that builds the environment for the hooks
490 949dcb1d Andrea Spadaccini
    @type log_fn: function that accepts a string
491 949dcb1d Andrea Spadaccini
    @param log_fn: logging function
492 949dcb1d Andrea Spadaccini
    @type htype: string or None
493 949dcb1d Andrea Spadaccini
    @param htype: None or one of L{constants.HTYPE_CLUSTER},
494 949dcb1d Andrea Spadaccini
     L{constants.HTYPE_NODE}, L{constants.HTYPE_INSTANCE}
495 949dcb1d Andrea Spadaccini
    @type cluster_name: string
496 949dcb1d Andrea Spadaccini
    @param cluster_name: name of the cluster
497 949dcb1d Andrea Spadaccini
    @type master_name: string
498 949dcb1d Andrea Spadaccini
    @param master_name: name of the master
499 a8083063 Iustin Pop

500 949dcb1d Andrea Spadaccini
    """
501 949dcb1d Andrea Spadaccini
    self.opcode = opcode
502 949dcb1d Andrea Spadaccini
    self.hooks_path = hooks_path
503 949dcb1d Andrea Spadaccini
    self.hooks_execution_fn = hooks_execution_fn
504 949dcb1d Andrea Spadaccini
    self.hooks_results_adapt_fn = hooks_results_adapt_fn
505 949dcb1d Andrea Spadaccini
    self.build_env_fn = build_env_fn
506 949dcb1d Andrea Spadaccini
    self.log_fn = log_fn
507 949dcb1d Andrea Spadaccini
    self.htype = htype
508 949dcb1d Andrea Spadaccini
    self.cluster_name = cluster_name
509 949dcb1d Andrea Spadaccini
    self.master_name = master_name
510 a8083063 Iustin Pop
511 07e0896f Michael Hanselmann
    self.pre_env = self._BuildEnv(constants.HOOKS_PHASE_PRE)
512 07e0896f Michael Hanselmann
    (self.pre_nodes, self.post_nodes) = nodes
513 a8083063 Iustin Pop
514 dd7f6776 Michael Hanselmann
  def _BuildEnv(self, phase):
515 a8083063 Iustin Pop
    """Compute the environment and the target nodes.
516 a8083063 Iustin Pop

517 a8083063 Iustin Pop
    Based on the opcode and the current node list, this builds the
518 a8083063 Iustin Pop
    environment for the hooks and the target node list for the run.
519 a8083063 Iustin Pop

520 a8083063 Iustin Pop
    """
521 dd7f6776 Michael Hanselmann
    if phase == constants.HOOKS_PHASE_PRE:
522 dd7f6776 Michael Hanselmann
      prefix = "GANETI_"
523 dd7f6776 Michael Hanselmann
    elif phase == constants.HOOKS_PHASE_POST:
524 dd7f6776 Michael Hanselmann
      prefix = "GANETI_POST_"
525 dd7f6776 Michael Hanselmann
    else:
526 dd7f6776 Michael Hanselmann
      raise AssertionError("Unknown phase '%s'" % phase)
527 dd7f6776 Michael Hanselmann
528 dd7f6776 Michael Hanselmann
    env = {}
529 a8083063 Iustin Pop
530 949dcb1d Andrea Spadaccini
    if self.hooks_path is not None:
531 949dcb1d Andrea Spadaccini
      phase_env = self.build_env_fn()
532 949dcb1d Andrea Spadaccini
      if phase_env:
533 949dcb1d Andrea Spadaccini
        assert not compat.any(key.upper().startswith(prefix)
534 949dcb1d Andrea Spadaccini
                              for key in phase_env)
535 dd7f6776 Michael Hanselmann
        env.update(("%s%s" % (prefix, key), value)
536 949dcb1d Andrea Spadaccini
                   for (key, value) in phase_env.items())
537 a8083063 Iustin Pop
538 dd7f6776 Michael Hanselmann
    if phase == constants.HOOKS_PHASE_PRE:
539 dd7f6776 Michael Hanselmann
      assert compat.all((key.startswith("GANETI_") and
540 dd7f6776 Michael Hanselmann
                         not key.startswith("GANETI_POST_"))
541 dd7f6776 Michael Hanselmann
                        for key in env)
542 dd7f6776 Michael Hanselmann
543 dd7f6776 Michael Hanselmann
    elif phase == constants.HOOKS_PHASE_POST:
544 dd7f6776 Michael Hanselmann
      assert compat.all(key.startswith("GANETI_POST_") for key in env)
545 07e0896f Michael Hanselmann
      assert isinstance(self.pre_env, dict)
546 dd7f6776 Michael Hanselmann
547 07e0896f Michael Hanselmann
      # Merge with pre-phase environment
548 07e0896f Michael Hanselmann
      assert not compat.any(key.startswith("GANETI_POST_")
549 07e0896f Michael Hanselmann
                            for key in self.pre_env)
550 07e0896f Michael Hanselmann
      env.update(self.pre_env)
551 dd7f6776 Michael Hanselmann
    else:
552 dd7f6776 Michael Hanselmann
      raise AssertionError("Unknown phase '%s'" % phase)
553 dd7f6776 Michael Hanselmann
554 07e0896f Michael Hanselmann
    return env
555 4167825b Iustin Pop
556 dd7f6776 Michael Hanselmann
  def _RunWrapper(self, node_list, hpath, phase, phase_env):
557 4167825b Iustin Pop
    """Simple wrapper over self.callfn.
558 4167825b Iustin Pop

559 949dcb1d Andrea Spadaccini
    This method fixes the environment before executing the hooks.
560 4167825b Iustin Pop

561 4167825b Iustin Pop
    """
562 dd7f6776 Michael Hanselmann
    env = {
563 fe5ca2bb Andrea Spadaccini
      "PATH": constants.HOOKS_PATH,
564 dd7f6776 Michael Hanselmann
      "GANETI_HOOKS_VERSION": constants.HOOKS_VERSION,
565 949dcb1d Andrea Spadaccini
      "GANETI_OP_CODE": self.opcode,
566 dd7f6776 Michael Hanselmann
      "GANETI_DATA_DIR": constants.DATA_DIR,
567 dd7f6776 Michael Hanselmann
      "GANETI_HOOKS_PHASE": phase,
568 dd7f6776 Michael Hanselmann
      "GANETI_HOOKS_PATH": hpath,
569 dd7f6776 Michael Hanselmann
      }
570 dd7f6776 Michael Hanselmann
571 949dcb1d Andrea Spadaccini
    if self.htype:
572 949dcb1d Andrea Spadaccini
      env["GANETI_OBJECT_TYPE"] = self.htype
573 949dcb1d Andrea Spadaccini
574 949dcb1d Andrea Spadaccini
    if self.cluster_name is not None:
575 949dcb1d Andrea Spadaccini
      env["GANETI_CLUSTER"] = self.cluster_name
576 07e0896f Michael Hanselmann
577 949dcb1d Andrea Spadaccini
    if self.master_name is not None:
578 949dcb1d Andrea Spadaccini
      env["GANETI_MASTER"] = self.master_name
579 dd7f6776 Michael Hanselmann
580 dd7f6776 Michael Hanselmann
    if phase_env:
581 af5af644 Andrea Spadaccini
      env = utils.algo.JoinDisjointDicts(env, phase_env)
582 a8083063 Iustin Pop
583 dd7f6776 Michael Hanselmann
    # Convert everything to strings
584 4167825b Iustin Pop
    env = dict([(str(key), str(val)) for key, val in env.iteritems()])
585 a8083063 Iustin Pop
586 dd7f6776 Michael Hanselmann
    assert compat.all(key == "PATH" or key.startswith("GANETI_")
587 ebc75510 Michael Hanselmann
                      for key in env)
588 ebc75510 Michael Hanselmann
589 949dcb1d Andrea Spadaccini
    return self.hooks_execution_fn(node_list, hpath, phase, env)
590 a8083063 Iustin Pop
591 17e82923 Luca Bigliardi
  def RunPhase(self, phase, nodes=None):
592 a8083063 Iustin Pop
    """Run all the scripts for a phase.
593 a8083063 Iustin Pop

594 a8083063 Iustin Pop
    This is the main function of the HookMaster.
595 949dcb1d Andrea Spadaccini
    It executes self.hooks_execution_fn, and after running
596 949dcb1d Andrea Spadaccini
    self.hooks_results_adapt_fn on its results it expects them to be in the form
597 949dcb1d Andrea Spadaccini
    {node_name: (fail_msg, [(script, result, output), ...]}).
598 a8083063 Iustin Pop

599 8dca23a3 Iustin Pop
    @param phase: one of L{constants.HOOKS_PHASE_POST} or
600 8dca23a3 Iustin Pop
        L{constants.HOOKS_PHASE_PRE}; it denotes the hooks phase
601 17e82923 Luca Bigliardi
    @param nodes: overrides the predefined list of nodes for the given phase
602 8dca23a3 Iustin Pop
    @return: the processed results of the hooks multi-node rpc call
603 8dca23a3 Iustin Pop
    @raise errors.HooksFailure: on communication failure to the nodes
604 6ef2dc74 Luca Bigliardi
    @raise errors.HooksAbort: on failure of one of the hooks
605 b07a6922 Guido Trotter

606 a8083063 Iustin Pop
    """
607 07e0896f Michael Hanselmann
    if phase == constants.HOOKS_PHASE_PRE:
608 07e0896f Michael Hanselmann
      if nodes is None:
609 07e0896f Michael Hanselmann
        nodes = self.pre_nodes
610 07e0896f Michael Hanselmann
      env = self.pre_env
611 07e0896f Michael Hanselmann
    elif phase == constants.HOOKS_PHASE_POST:
612 07e0896f Michael Hanselmann
      if nodes is None:
613 b423c513 Michael Hanselmann
        nodes = self.post_nodes
614 07e0896f Michael Hanselmann
      env = self._BuildEnv(phase)
615 07e0896f Michael Hanselmann
    else:
616 07e0896f Michael Hanselmann
      raise AssertionError("Unknown phase '%s'" % phase)
617 0306ff62 Michael Hanselmann
618 0306ff62 Michael Hanselmann
    if not nodes:
619 9a395a76 Iustin Pop
      # empty node list, we should not attempt to run this as either
620 9a395a76 Iustin Pop
      # we're in the cluster init phase and the rpc client part can't
621 9a395a76 Iustin Pop
      # even attempt to run, or this LU doesn't do hooks at all
622 a8083063 Iustin Pop
      return
623 0306ff62 Michael Hanselmann
624 949dcb1d Andrea Spadaccini
    results = self._RunWrapper(nodes, self.hooks_path, phase, env)
625 8c4b9364 Luca Bigliardi
    if not results:
626 8c4b9364 Luca Bigliardi
      msg = "Communication Failure"
627 8c4b9364 Luca Bigliardi
      if phase == constants.HOOKS_PHASE_PRE:
628 8c4b9364 Luca Bigliardi
        raise errors.HooksFailure(msg)
629 8c4b9364 Luca Bigliardi
      else:
630 949dcb1d Andrea Spadaccini
        self.log_fn(msg)
631 640b961e Luca Bigliardi
        return results
632 0306ff62 Michael Hanselmann
633 949dcb1d Andrea Spadaccini
    converted_res = results
634 949dcb1d Andrea Spadaccini
    if self.hooks_results_adapt_fn:
635 949dcb1d Andrea Spadaccini
      converted_res = self.hooks_results_adapt_fn(results)
636 949dcb1d Andrea Spadaccini
637 0306ff62 Michael Hanselmann
    errs = []
638 949dcb1d Andrea Spadaccini
    for node_name, (fail_msg, offline, hooks_results) in converted_res.items():
639 949dcb1d Andrea Spadaccini
      if offline:
640 8c4b9364 Luca Bigliardi
        continue
641 0306ff62 Michael Hanselmann
642 949dcb1d Andrea Spadaccini
      if fail_msg:
643 949dcb1d Andrea Spadaccini
        self.log_fn("Communication failure to node %s: %s", node_name, fail_msg)
644 8c4b9364 Luca Bigliardi
        continue
645 0306ff62 Michael Hanselmann
646 949dcb1d Andrea Spadaccini
      for script, hkr, output in hooks_results:
647 8c4b9364 Luca Bigliardi
        if hkr == constants.HKR_FAIL:
648 8c4b9364 Luca Bigliardi
          if phase == constants.HOOKS_PHASE_PRE:
649 a8083063 Iustin Pop
            errs.append((node_name, script, output))
650 8c4b9364 Luca Bigliardi
          else:
651 8c4b9364 Luca Bigliardi
            if not output:
652 640b961e Luca Bigliardi
              output = "(no output)"
653 949dcb1d Andrea Spadaccini
            self.log_fn("On %s script %s failed, output: %s" %
654 949dcb1d Andrea Spadaccini
                        (node_name, script, output))
655 0306ff62 Michael Hanselmann
656 8c4b9364 Luca Bigliardi
    if errs and phase == constants.HOOKS_PHASE_PRE:
657 8c4b9364 Luca Bigliardi
      raise errors.HooksAbort(errs)
658 0306ff62 Michael Hanselmann
659 b07a6922 Guido Trotter
    return results
660 6a4aa7c1 Iustin Pop
661 6a4aa7c1 Iustin Pop
  def RunConfigUpdate(self):
662 6a4aa7c1 Iustin Pop
    """Run the special configuration update hook
663 6a4aa7c1 Iustin Pop

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

667 6a4aa7c1 Iustin Pop
    """
668 6a4aa7c1 Iustin Pop
    phase = constants.HOOKS_PHASE_POST
669 6a4aa7c1 Iustin Pop
    hpath = constants.HOOKS_NAME_CFGUPDATE
670 949dcb1d Andrea Spadaccini
    nodes = [self.master_name]
671 dd7f6776 Michael Hanselmann
    self._RunWrapper(nodes, hpath, phase, self.pre_env)
672 949dcb1d Andrea Spadaccini
673 949dcb1d Andrea Spadaccini
  @staticmethod
674 949dcb1d Andrea Spadaccini
  def BuildFromLu(hooks_execution_fn, lu):
675 949dcb1d Andrea Spadaccini
    if lu.HPATH is None:
676 949dcb1d Andrea Spadaccini
      nodes = (None, None)
677 949dcb1d Andrea Spadaccini
    else:
678 949dcb1d Andrea Spadaccini
      nodes = map(frozenset, lu.BuildHooksNodes())
679 949dcb1d Andrea Spadaccini
680 949dcb1d Andrea Spadaccini
    master_name = cluster_name = None
681 949dcb1d Andrea Spadaccini
    if lu.cfg:
682 949dcb1d Andrea Spadaccini
      master_name = lu.cfg.GetMasterNode()
683 949dcb1d Andrea Spadaccini
      cluster_name = lu.cfg.GetClusterName()
684 949dcb1d Andrea Spadaccini
685 949dcb1d Andrea Spadaccini
    return HooksMaster(lu.op.OP_ID, lu.HPATH, nodes, hooks_execution_fn,
686 949dcb1d Andrea Spadaccini
                       _RpcResultsToHooksResults, lu.BuildHooksEnv,
687 949dcb1d Andrea Spadaccini
                       lu.LogWarning, lu.HTYPE, cluster_name, master_name)