Statistics
| Branch: | Tag: | Revision:

root / lib / cmdlib / base.py @ 31d3b918

History | View | Annotate | Download (17.8 kB)

1 1a732a74 Thomas Thrainer
#
2 1a732a74 Thomas Thrainer
#
3 1a732a74 Thomas Thrainer
4 1a732a74 Thomas Thrainer
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Google Inc.
5 1a732a74 Thomas Thrainer
#
6 1a732a74 Thomas Thrainer
# This program is free software; you can redistribute it and/or modify
7 1a732a74 Thomas Thrainer
# it under the terms of the GNU General Public License as published by
8 1a732a74 Thomas Thrainer
# the Free Software Foundation; either version 2 of the License, or
9 1a732a74 Thomas Thrainer
# (at your option) any later version.
10 1a732a74 Thomas Thrainer
#
11 1a732a74 Thomas Thrainer
# This program is distributed in the hope that it will be useful, but
12 1a732a74 Thomas Thrainer
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 1a732a74 Thomas Thrainer
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 1a732a74 Thomas Thrainer
# General Public License for more details.
15 1a732a74 Thomas Thrainer
#
16 1a732a74 Thomas Thrainer
# You should have received a copy of the GNU General Public License
17 1a732a74 Thomas Thrainer
# along with this program; if not, write to the Free Software
18 1a732a74 Thomas Thrainer
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 1a732a74 Thomas Thrainer
# 02110-1301, USA.
20 1a732a74 Thomas Thrainer
21 1a732a74 Thomas Thrainer
22 1a732a74 Thomas Thrainer
"""Base classes and functions for cmdlib."""
23 1a732a74 Thomas Thrainer
24 1a732a74 Thomas Thrainer
import logging
25 1a732a74 Thomas Thrainer
26 1a732a74 Thomas Thrainer
from ganeti import errors
27 1a732a74 Thomas Thrainer
from ganeti import constants
28 1a732a74 Thomas Thrainer
from ganeti import locking
29 1a732a74 Thomas Thrainer
from ganeti import query
30 1a732a74 Thomas Thrainer
from ganeti import utils
31 da4a52a3 Thomas Thrainer
from ganeti.cmdlib.common import ExpandInstanceUuidAndName
32 1a732a74 Thomas Thrainer
33 1a732a74 Thomas Thrainer
34 1a732a74 Thomas Thrainer
class ResultWithJobs:
35 1a732a74 Thomas Thrainer
  """Data container for LU results with jobs.
36 1a732a74 Thomas Thrainer

37 1a732a74 Thomas Thrainer
  Instances of this class returned from L{LogicalUnit.Exec} will be recognized
38 1a732a74 Thomas Thrainer
  by L{mcpu._ProcessResult}. The latter will then submit the jobs
39 1a732a74 Thomas Thrainer
  contained in the C{jobs} attribute and include the job IDs in the opcode
40 1a732a74 Thomas Thrainer
  result.
41 1a732a74 Thomas Thrainer

42 1a732a74 Thomas Thrainer
  """
43 1a732a74 Thomas Thrainer
  def __init__(self, jobs, **kwargs):
44 1a732a74 Thomas Thrainer
    """Initializes this class.
45 1a732a74 Thomas Thrainer

46 1a732a74 Thomas Thrainer
    Additional return values can be specified as keyword arguments.
47 1a732a74 Thomas Thrainer

48 1a732a74 Thomas Thrainer
    @type jobs: list of lists of L{opcode.OpCode}
49 1a732a74 Thomas Thrainer
    @param jobs: A list of lists of opcode objects
50 1a732a74 Thomas Thrainer

51 1a732a74 Thomas Thrainer
    """
52 1a732a74 Thomas Thrainer
    self.jobs = jobs
53 1a732a74 Thomas Thrainer
    self.other = kwargs
54 1a732a74 Thomas Thrainer
55 1a732a74 Thomas Thrainer
56 1a732a74 Thomas Thrainer
class LogicalUnit(object):
57 1a732a74 Thomas Thrainer
  """Logical Unit base class.
58 1a732a74 Thomas Thrainer

59 1a732a74 Thomas Thrainer
  Subclasses must follow these rules:
60 1a732a74 Thomas Thrainer
    - implement ExpandNames
61 1a732a74 Thomas Thrainer
    - implement CheckPrereq (except when tasklets are used)
62 1a732a74 Thomas Thrainer
    - implement Exec (except when tasklets are used)
63 1a732a74 Thomas Thrainer
    - implement BuildHooksEnv
64 1a732a74 Thomas Thrainer
    - implement BuildHooksNodes
65 1a732a74 Thomas Thrainer
    - redefine HPATH and HTYPE
66 1a732a74 Thomas Thrainer
    - optionally redefine their run requirements:
67 1a732a74 Thomas Thrainer
        REQ_BGL: the LU needs to hold the Big Ganeti Lock exclusively
68 1a732a74 Thomas Thrainer

69 1a732a74 Thomas Thrainer
  Note that all commands require root permissions.
70 1a732a74 Thomas Thrainer

71 1a732a74 Thomas Thrainer
  @ivar dry_run_result: the value (if any) that will be returned to the caller
72 1a732a74 Thomas Thrainer
      in dry-run mode (signalled by opcode dry_run parameter)
73 1a732a74 Thomas Thrainer

74 1a732a74 Thomas Thrainer
  """
75 1a732a74 Thomas Thrainer
  HPATH = None
76 1a732a74 Thomas Thrainer
  HTYPE = None
77 1a732a74 Thomas Thrainer
  REQ_BGL = True
78 1a732a74 Thomas Thrainer
79 1a732a74 Thomas Thrainer
  def __init__(self, processor, op, context, rpc_runner):
80 1a732a74 Thomas Thrainer
    """Constructor for LogicalUnit.
81 1a732a74 Thomas Thrainer

82 1a732a74 Thomas Thrainer
    This needs to be overridden in derived classes in order to check op
83 1a732a74 Thomas Thrainer
    validity.
84 1a732a74 Thomas Thrainer

85 1a732a74 Thomas Thrainer
    """
86 1a732a74 Thomas Thrainer
    self.proc = processor
87 1a732a74 Thomas Thrainer
    self.op = op
88 1a732a74 Thomas Thrainer
    self.cfg = context.cfg
89 1a732a74 Thomas Thrainer
    self.glm = context.glm
90 1a732a74 Thomas Thrainer
    # readability alias
91 1a732a74 Thomas Thrainer
    self.owned_locks = context.glm.list_owned
92 1a732a74 Thomas Thrainer
    self.context = context
93 1a732a74 Thomas Thrainer
    self.rpc = rpc_runner
94 1a732a74 Thomas Thrainer
95 1a732a74 Thomas Thrainer
    # Dictionaries used to declare locking needs to mcpu
96 1a732a74 Thomas Thrainer
    self.needed_locks = None
97 1a732a74 Thomas Thrainer
    self.share_locks = dict.fromkeys(locking.LEVELS, 0)
98 1a732a74 Thomas Thrainer
    self.opportunistic_locks = dict.fromkeys(locking.LEVELS, False)
99 1a732a74 Thomas Thrainer
100 1a732a74 Thomas Thrainer
    self.add_locks = {}
101 1a732a74 Thomas Thrainer
    self.remove_locks = {}
102 1a732a74 Thomas Thrainer
103 1a732a74 Thomas Thrainer
    # Used to force good behavior when calling helper functions
104 1a732a74 Thomas Thrainer
    self.recalculate_locks = {}
105 1a732a74 Thomas Thrainer
106 1a732a74 Thomas Thrainer
    # logging
107 1a732a74 Thomas Thrainer
    self.Log = processor.Log # pylint: disable=C0103
108 1a732a74 Thomas Thrainer
    self.LogWarning = processor.LogWarning # pylint: disable=C0103
109 1a732a74 Thomas Thrainer
    self.LogInfo = processor.LogInfo # pylint: disable=C0103
110 1a732a74 Thomas Thrainer
    self.LogStep = processor.LogStep # pylint: disable=C0103
111 1a732a74 Thomas Thrainer
    # support for dry-run
112 1a732a74 Thomas Thrainer
    self.dry_run_result = None
113 1a732a74 Thomas Thrainer
    # support for generic debug attribute
114 1a732a74 Thomas Thrainer
    if (not hasattr(self.op, "debug_level") or
115 1a732a74 Thomas Thrainer
        not isinstance(self.op.debug_level, int)):
116 1a732a74 Thomas Thrainer
      self.op.debug_level = 0
117 1a732a74 Thomas Thrainer
118 1a732a74 Thomas Thrainer
    # Tasklets
119 1a732a74 Thomas Thrainer
    self.tasklets = None
120 1a732a74 Thomas Thrainer
121 1a732a74 Thomas Thrainer
    # Validate opcode parameters and set defaults
122 1a732a74 Thomas Thrainer
    self.op.Validate(True)
123 1a732a74 Thomas Thrainer
124 1a732a74 Thomas Thrainer
    self.CheckArguments()
125 1a732a74 Thomas Thrainer
126 1a732a74 Thomas Thrainer
  def CheckArguments(self):
127 1a732a74 Thomas Thrainer
    """Check syntactic validity for the opcode arguments.
128 1a732a74 Thomas Thrainer

129 1a732a74 Thomas Thrainer
    This method is for doing a simple syntactic check and ensure
130 1a732a74 Thomas Thrainer
    validity of opcode parameters, without any cluster-related
131 1a732a74 Thomas Thrainer
    checks. While the same can be accomplished in ExpandNames and/or
132 1a732a74 Thomas Thrainer
    CheckPrereq, doing these separate is better because:
133 1a732a74 Thomas Thrainer

134 1a732a74 Thomas Thrainer
      - ExpandNames is left as as purely a lock-related function
135 1a732a74 Thomas Thrainer
      - CheckPrereq is run after we have acquired locks (and possible
136 1a732a74 Thomas Thrainer
        waited for them)
137 1a732a74 Thomas Thrainer

138 1a732a74 Thomas Thrainer
    The function is allowed to change the self.op attribute so that
139 1a732a74 Thomas Thrainer
    later methods can no longer worry about missing parameters.
140 1a732a74 Thomas Thrainer

141 1a732a74 Thomas Thrainer
    """
142 1a732a74 Thomas Thrainer
    pass
143 1a732a74 Thomas Thrainer
144 1a732a74 Thomas Thrainer
  def ExpandNames(self):
145 1a732a74 Thomas Thrainer
    """Expand names for this LU.
146 1a732a74 Thomas Thrainer

147 1a732a74 Thomas Thrainer
    This method is called before starting to execute the opcode, and it should
148 1a732a74 Thomas Thrainer
    update all the parameters of the opcode to their canonical form (e.g. a
149 1a732a74 Thomas Thrainer
    short node name must be fully expanded after this method has successfully
150 1a732a74 Thomas Thrainer
    completed). This way locking, hooks, logging, etc. can work correctly.
151 1a732a74 Thomas Thrainer

152 1a732a74 Thomas Thrainer
    LUs which implement this method must also populate the self.needed_locks
153 1a732a74 Thomas Thrainer
    member, as a dict with lock levels as keys, and a list of needed lock names
154 1a732a74 Thomas Thrainer
    as values. Rules:
155 1a732a74 Thomas Thrainer

156 1a732a74 Thomas Thrainer
      - use an empty dict if you don't need any lock
157 1a732a74 Thomas Thrainer
      - if you don't need any lock at a particular level omit that
158 1a732a74 Thomas Thrainer
        level (note that in this case C{DeclareLocks} won't be called
159 1a732a74 Thomas Thrainer
        at all for that level)
160 1a732a74 Thomas Thrainer
      - if you need locks at a level, but you can't calculate it in
161 1a732a74 Thomas Thrainer
        this function, initialise that level with an empty list and do
162 1a732a74 Thomas Thrainer
        further processing in L{LogicalUnit.DeclareLocks} (see that
163 1a732a74 Thomas Thrainer
        function's docstring)
164 1a732a74 Thomas Thrainer
      - don't put anything for the BGL level
165 1a732a74 Thomas Thrainer
      - if you want all locks at a level use L{locking.ALL_SET} as a value
166 1a732a74 Thomas Thrainer

167 1a732a74 Thomas Thrainer
    If you need to share locks (rather than acquire them exclusively) at one
168 1a732a74 Thomas Thrainer
    level you can modify self.share_locks, setting a true value (usually 1) for
169 1a732a74 Thomas Thrainer
    that level. By default locks are not shared.
170 1a732a74 Thomas Thrainer

171 1a732a74 Thomas Thrainer
    This function can also define a list of tasklets, which then will be
172 1a732a74 Thomas Thrainer
    executed in order instead of the usual LU-level CheckPrereq and Exec
173 1a732a74 Thomas Thrainer
    functions, if those are not defined by the LU.
174 1a732a74 Thomas Thrainer

175 1a732a74 Thomas Thrainer
    Examples::
176 1a732a74 Thomas Thrainer

177 1a732a74 Thomas Thrainer
      # Acquire all nodes and one instance
178 1a732a74 Thomas Thrainer
      self.needed_locks = {
179 1a732a74 Thomas Thrainer
        locking.LEVEL_NODE: locking.ALL_SET,
180 1a732a74 Thomas Thrainer
        locking.LEVEL_INSTANCE: ['instance1.example.com'],
181 1a732a74 Thomas Thrainer
      }
182 1a732a74 Thomas Thrainer
      # Acquire just two nodes
183 1a732a74 Thomas Thrainer
      self.needed_locks = {
184 1c3231aa Thomas Thrainer
        locking.LEVEL_NODE: ['node1-uuid', 'node2-uuid'],
185 1a732a74 Thomas Thrainer
      }
186 1a732a74 Thomas Thrainer
      # Acquire no locks
187 1a732a74 Thomas Thrainer
      self.needed_locks = {} # No, you can't leave it to the default value None
188 1a732a74 Thomas Thrainer

189 1a732a74 Thomas Thrainer
    """
190 1a732a74 Thomas Thrainer
    # The implementation of this method is mandatory only if the new LU is
191 1a732a74 Thomas Thrainer
    # concurrent, so that old LUs don't need to be changed all at the same
192 1a732a74 Thomas Thrainer
    # time.
193 1a732a74 Thomas Thrainer
    if self.REQ_BGL:
194 1a732a74 Thomas Thrainer
      self.needed_locks = {} # Exclusive LUs don't need locks.
195 1a732a74 Thomas Thrainer
    else:
196 1a732a74 Thomas Thrainer
      raise NotImplementedError
197 1a732a74 Thomas Thrainer
198 1a732a74 Thomas Thrainer
  def DeclareLocks(self, level):
199 1a732a74 Thomas Thrainer
    """Declare LU locking needs for a level
200 1a732a74 Thomas Thrainer

201 1a732a74 Thomas Thrainer
    While most LUs can just declare their locking needs at ExpandNames time,
202 1a732a74 Thomas Thrainer
    sometimes there's the need to calculate some locks after having acquired
203 1a732a74 Thomas Thrainer
    the ones before. This function is called just before acquiring locks at a
204 1a732a74 Thomas Thrainer
    particular level, but after acquiring the ones at lower levels, and permits
205 1a732a74 Thomas Thrainer
    such calculations. It can be used to modify self.needed_locks, and by
206 1a732a74 Thomas Thrainer
    default it does nothing.
207 1a732a74 Thomas Thrainer

208 1a732a74 Thomas Thrainer
    This function is only called if you have something already set in
209 1a732a74 Thomas Thrainer
    self.needed_locks for the level.
210 1a732a74 Thomas Thrainer

211 1a732a74 Thomas Thrainer
    @param level: Locking level which is going to be locked
212 1a732a74 Thomas Thrainer
    @type level: member of L{ganeti.locking.LEVELS}
213 1a732a74 Thomas Thrainer

214 1a732a74 Thomas Thrainer
    """
215 1a732a74 Thomas Thrainer
216 1a732a74 Thomas Thrainer
  def CheckPrereq(self):
217 1a732a74 Thomas Thrainer
    """Check prerequisites for this LU.
218 1a732a74 Thomas Thrainer

219 1a732a74 Thomas Thrainer
    This method should check that the prerequisites for the execution
220 1a732a74 Thomas Thrainer
    of this LU are fulfilled. It can do internode communication, but
221 1a732a74 Thomas Thrainer
    it should be idempotent - no cluster or system changes are
222 1a732a74 Thomas Thrainer
    allowed.
223 1a732a74 Thomas Thrainer

224 1a732a74 Thomas Thrainer
    The method should raise errors.OpPrereqError in case something is
225 1a732a74 Thomas Thrainer
    not fulfilled. Its return value is ignored.
226 1a732a74 Thomas Thrainer

227 1a732a74 Thomas Thrainer
    This method should also update all the parameters of the opcode to
228 1a732a74 Thomas Thrainer
    their canonical form if it hasn't been done by ExpandNames before.
229 1a732a74 Thomas Thrainer

230 1a732a74 Thomas Thrainer
    """
231 1a732a74 Thomas Thrainer
    if self.tasklets is not None:
232 1a732a74 Thomas Thrainer
      for (idx, tl) in enumerate(self.tasklets):
233 1a732a74 Thomas Thrainer
        logging.debug("Checking prerequisites for tasklet %s/%s",
234 1a732a74 Thomas Thrainer
                      idx + 1, len(self.tasklets))
235 1a732a74 Thomas Thrainer
        tl.CheckPrereq()
236 1a732a74 Thomas Thrainer
    else:
237 1a732a74 Thomas Thrainer
      pass
238 1a732a74 Thomas Thrainer
239 1a732a74 Thomas Thrainer
  def Exec(self, feedback_fn):
240 1a732a74 Thomas Thrainer
    """Execute the LU.
241 1a732a74 Thomas Thrainer

242 1a732a74 Thomas Thrainer
    This method should implement the actual work. It should raise
243 1a732a74 Thomas Thrainer
    errors.OpExecError for failures that are somewhat dealt with in
244 1a732a74 Thomas Thrainer
    code, or expected.
245 1a732a74 Thomas Thrainer

246 1a732a74 Thomas Thrainer
    """
247 1a732a74 Thomas Thrainer
    if self.tasklets is not None:
248 1a732a74 Thomas Thrainer
      for (idx, tl) in enumerate(self.tasklets):
249 1a732a74 Thomas Thrainer
        logging.debug("Executing tasklet %s/%s", idx + 1, len(self.tasklets))
250 1a732a74 Thomas Thrainer
        tl.Exec(feedback_fn)
251 1a732a74 Thomas Thrainer
    else:
252 1a732a74 Thomas Thrainer
      raise NotImplementedError
253 1a732a74 Thomas Thrainer
254 1a732a74 Thomas Thrainer
  def BuildHooksEnv(self):
255 1a732a74 Thomas Thrainer
    """Build hooks environment for this LU.
256 1a732a74 Thomas Thrainer

257 1a732a74 Thomas Thrainer
    @rtype: dict
258 1a732a74 Thomas Thrainer
    @return: Dictionary containing the environment that will be used for
259 1a732a74 Thomas Thrainer
      running the hooks for this LU. The keys of the dict must not be prefixed
260 1a732a74 Thomas Thrainer
      with "GANETI_"--that'll be added by the hooks runner. The hooks runner
261 1a732a74 Thomas Thrainer
      will extend the environment with additional variables. If no environment
262 1a732a74 Thomas Thrainer
      should be defined, an empty dictionary should be returned (not C{None}).
263 1a732a74 Thomas Thrainer
    @note: If the C{HPATH} attribute of the LU class is C{None}, this function
264 1a732a74 Thomas Thrainer
      will not be called.
265 1a732a74 Thomas Thrainer

266 1a732a74 Thomas Thrainer
    """
267 1a732a74 Thomas Thrainer
    raise NotImplementedError
268 1a732a74 Thomas Thrainer
269 1a732a74 Thomas Thrainer
  def BuildHooksNodes(self):
270 1a732a74 Thomas Thrainer
    """Build list of nodes to run LU's hooks.
271 1a732a74 Thomas Thrainer

272 1c3231aa Thomas Thrainer
    @rtype: tuple; (list, list) or (list, list, list)
273 1c3231aa Thomas Thrainer
    @return: Tuple containing a list of node UUIDs on which the hook
274 1c3231aa Thomas Thrainer
      should run before the execution and a list of node UUIDs on which the
275 1c3231aa Thomas Thrainer
      hook should run after the execution. As it might be possible that the
276 1c3231aa Thomas Thrainer
      node UUID is not known at the time this method is invoked, an optional
277 1c3231aa Thomas Thrainer
      third list can be added which contains node names on which the hook
278 1c3231aa Thomas Thrainer
      should run after the execution (in case of node add, for instance).
279 1c3231aa Thomas Thrainer
      No nodes should be returned as an empty list (and not None).
280 1a732a74 Thomas Thrainer
    @note: If the C{HPATH} attribute of the LU class is C{None}, this function
281 1a732a74 Thomas Thrainer
      will not be called.
282 1a732a74 Thomas Thrainer

283 1a732a74 Thomas Thrainer
    """
284 1a732a74 Thomas Thrainer
    raise NotImplementedError
285 1a732a74 Thomas Thrainer
286 1a732a74 Thomas Thrainer
  def HooksCallBack(self, phase, hook_results, feedback_fn, lu_result):
287 1a732a74 Thomas Thrainer
    """Notify the LU about the results of its hooks.
288 1a732a74 Thomas Thrainer

289 1a732a74 Thomas Thrainer
    This method is called every time a hooks phase is executed, and notifies
290 1a732a74 Thomas Thrainer
    the Logical Unit about the hooks' result. The LU can then use it to alter
291 1a732a74 Thomas Thrainer
    its result based on the hooks.  By default the method does nothing and the
292 1a732a74 Thomas Thrainer
    previous result is passed back unchanged but any LU can define it if it
293 1a732a74 Thomas Thrainer
    wants to use the local cluster hook-scripts somehow.
294 1a732a74 Thomas Thrainer

295 1a732a74 Thomas Thrainer
    @param phase: one of L{constants.HOOKS_PHASE_POST} or
296 1a732a74 Thomas Thrainer
        L{constants.HOOKS_PHASE_PRE}; it denotes the hooks phase
297 1a732a74 Thomas Thrainer
    @param hook_results: the results of the multi-node hooks rpc call
298 1a732a74 Thomas Thrainer
    @param feedback_fn: function used send feedback back to the caller
299 1a732a74 Thomas Thrainer
    @param lu_result: the previous Exec result this LU had, or None
300 1a732a74 Thomas Thrainer
        in the PRE phase
301 1a732a74 Thomas Thrainer
    @return: the new Exec result, based on the previous result
302 1a732a74 Thomas Thrainer
        and hook results
303 1a732a74 Thomas Thrainer

304 1a732a74 Thomas Thrainer
    """
305 1a732a74 Thomas Thrainer
    # API must be kept, thus we ignore the unused argument and could
306 1a732a74 Thomas Thrainer
    # be a function warnings
307 1a732a74 Thomas Thrainer
    # pylint: disable=W0613,R0201
308 1a732a74 Thomas Thrainer
    return lu_result
309 1a732a74 Thomas Thrainer
310 1a732a74 Thomas Thrainer
  def _ExpandAndLockInstance(self):
311 1a732a74 Thomas Thrainer
    """Helper function to expand and lock an instance.
312 1a732a74 Thomas Thrainer

313 1a732a74 Thomas Thrainer
    Many LUs that work on an instance take its name in self.op.instance_name
314 1a732a74 Thomas Thrainer
    and need to expand it and then declare the expanded name for locking. This
315 1a732a74 Thomas Thrainer
    function does it, and then updates self.op.instance_name to the expanded
316 1a732a74 Thomas Thrainer
    name. It also initializes needed_locks as a dict, if this hasn't been done
317 1a732a74 Thomas Thrainer
    before.
318 1a732a74 Thomas Thrainer

319 1a732a74 Thomas Thrainer
    """
320 1a732a74 Thomas Thrainer
    if self.needed_locks is None:
321 1a732a74 Thomas Thrainer
      self.needed_locks = {}
322 1a732a74 Thomas Thrainer
    else:
323 1a732a74 Thomas Thrainer
      assert locking.LEVEL_INSTANCE not in self.needed_locks, \
324 1a732a74 Thomas Thrainer
        "_ExpandAndLockInstance called with instance-level locks set"
325 da4a52a3 Thomas Thrainer
    (self.op.instance_uuid, self.op.instance_name) = \
326 da4a52a3 Thomas Thrainer
      ExpandInstanceUuidAndName(self.cfg, self.op.instance_uuid,
327 da4a52a3 Thomas Thrainer
                                self.op.instance_name)
328 1a732a74 Thomas Thrainer
    self.needed_locks[locking.LEVEL_INSTANCE] = self.op.instance_name
329 1a732a74 Thomas Thrainer
330 1a732a74 Thomas Thrainer
  def _LockInstancesNodes(self, primary_only=False,
331 1a732a74 Thomas Thrainer
                          level=locking.LEVEL_NODE):
332 1a732a74 Thomas Thrainer
    """Helper function to declare instances' nodes for locking.
333 1a732a74 Thomas Thrainer

334 1a732a74 Thomas Thrainer
    This function should be called after locking one or more instances to lock
335 1a732a74 Thomas Thrainer
    their nodes. Its effect is populating self.needed_locks[locking.LEVEL_NODE]
336 1a732a74 Thomas Thrainer
    with all primary or secondary nodes for instances already locked and
337 1a732a74 Thomas Thrainer
    present in self.needed_locks[locking.LEVEL_INSTANCE].
338 1a732a74 Thomas Thrainer

339 1a732a74 Thomas Thrainer
    It should be called from DeclareLocks, and for safety only works if
340 1a732a74 Thomas Thrainer
    self.recalculate_locks[locking.LEVEL_NODE] is set.
341 1a732a74 Thomas Thrainer

342 1a732a74 Thomas Thrainer
    In the future it may grow parameters to just lock some instance's nodes, or
343 1a732a74 Thomas Thrainer
    to just lock primaries or secondary nodes, if needed.
344 1a732a74 Thomas Thrainer

345 1a732a74 Thomas Thrainer
    If should be called in DeclareLocks in a way similar to::
346 1a732a74 Thomas Thrainer

347 1a732a74 Thomas Thrainer
      if level == locking.LEVEL_NODE:
348 1a732a74 Thomas Thrainer
        self._LockInstancesNodes()
349 1a732a74 Thomas Thrainer

350 1a732a74 Thomas Thrainer
    @type primary_only: boolean
351 1a732a74 Thomas Thrainer
    @param primary_only: only lock primary nodes of locked instances
352 1a732a74 Thomas Thrainer
    @param level: Which lock level to use for locking nodes
353 1a732a74 Thomas Thrainer

354 1a732a74 Thomas Thrainer
    """
355 1a732a74 Thomas Thrainer
    assert level in self.recalculate_locks, \
356 1a732a74 Thomas Thrainer
      "_LockInstancesNodes helper function called with no nodes to recalculate"
357 1a732a74 Thomas Thrainer
358 1a732a74 Thomas Thrainer
    # TODO: check if we're really been called with the instance locks held
359 1a732a74 Thomas Thrainer
360 1a732a74 Thomas Thrainer
    # For now we'll replace self.needed_locks[locking.LEVEL_NODE], but in the
361 1a732a74 Thomas Thrainer
    # future we might want to have different behaviors depending on the value
362 1a732a74 Thomas Thrainer
    # of self.recalculate_locks[locking.LEVEL_NODE]
363 1c3231aa Thomas Thrainer
    wanted_node_uuids = []
364 1a732a74 Thomas Thrainer
    locked_i = self.owned_locks(locking.LEVEL_INSTANCE)
365 da4a52a3 Thomas Thrainer
    for _, instance in self.cfg.GetMultiInstanceInfoByName(locked_i):
366 1c3231aa Thomas Thrainer
      wanted_node_uuids.append(instance.primary_node)
367 1a732a74 Thomas Thrainer
      if not primary_only:
368 1c3231aa Thomas Thrainer
        wanted_node_uuids.extend(instance.secondary_nodes)
369 1a732a74 Thomas Thrainer
370 1a732a74 Thomas Thrainer
    if self.recalculate_locks[level] == constants.LOCKS_REPLACE:
371 1c3231aa Thomas Thrainer
      self.needed_locks[level] = wanted_node_uuids
372 1a732a74 Thomas Thrainer
    elif self.recalculate_locks[level] == constants.LOCKS_APPEND:
373 1c3231aa Thomas Thrainer
      self.needed_locks[level].extend(wanted_node_uuids)
374 1a732a74 Thomas Thrainer
    else:
375 1a732a74 Thomas Thrainer
      raise errors.ProgrammerError("Unknown recalculation mode")
376 1a732a74 Thomas Thrainer
377 1a732a74 Thomas Thrainer
    del self.recalculate_locks[level]
378 1a732a74 Thomas Thrainer
379 1a732a74 Thomas Thrainer
380 1a732a74 Thomas Thrainer
class NoHooksLU(LogicalUnit): # pylint: disable=W0223
381 1a732a74 Thomas Thrainer
  """Simple LU which runs no hooks.
382 1a732a74 Thomas Thrainer

383 1a732a74 Thomas Thrainer
  This LU is intended as a parent for other LogicalUnits which will
384 1a732a74 Thomas Thrainer
  run no hooks, in order to reduce duplicate code.
385 1a732a74 Thomas Thrainer

386 1a732a74 Thomas Thrainer
  """
387 1a732a74 Thomas Thrainer
  HPATH = None
388 1a732a74 Thomas Thrainer
  HTYPE = None
389 1a732a74 Thomas Thrainer
390 1a732a74 Thomas Thrainer
  def BuildHooksEnv(self):
391 1a732a74 Thomas Thrainer
    """Empty BuildHooksEnv for NoHooksLu.
392 1a732a74 Thomas Thrainer

393 1a732a74 Thomas Thrainer
    This just raises an error.
394 1a732a74 Thomas Thrainer

395 1a732a74 Thomas Thrainer
    """
396 1a732a74 Thomas Thrainer
    raise AssertionError("BuildHooksEnv called for NoHooksLUs")
397 1a732a74 Thomas Thrainer
398 1a732a74 Thomas Thrainer
  def BuildHooksNodes(self):
399 1a732a74 Thomas Thrainer
    """Empty BuildHooksNodes for NoHooksLU.
400 1a732a74 Thomas Thrainer

401 1a732a74 Thomas Thrainer
    """
402 1a732a74 Thomas Thrainer
    raise AssertionError("BuildHooksNodes called for NoHooksLU")
403 1a732a74 Thomas Thrainer
404 1a732a74 Thomas Thrainer
405 1a732a74 Thomas Thrainer
class Tasklet:
406 1a732a74 Thomas Thrainer
  """Tasklet base class.
407 1a732a74 Thomas Thrainer

408 1a732a74 Thomas Thrainer
  Tasklets are subcomponents for LUs. LUs can consist entirely of tasklets or
409 1a732a74 Thomas Thrainer
  they can mix legacy code with tasklets. Locking needs to be done in the LU,
410 1a732a74 Thomas Thrainer
  tasklets know nothing about locks.
411 1a732a74 Thomas Thrainer

412 1a732a74 Thomas Thrainer
  Subclasses must follow these rules:
413 1a732a74 Thomas Thrainer
    - Implement CheckPrereq
414 1a732a74 Thomas Thrainer
    - Implement Exec
415 1a732a74 Thomas Thrainer

416 1a732a74 Thomas Thrainer
  """
417 1a732a74 Thomas Thrainer
  def __init__(self, lu):
418 1a732a74 Thomas Thrainer
    self.lu = lu
419 1a732a74 Thomas Thrainer
420 1a732a74 Thomas Thrainer
    # Shortcuts
421 1a732a74 Thomas Thrainer
    self.cfg = lu.cfg
422 1a732a74 Thomas Thrainer
    self.rpc = lu.rpc
423 1a732a74 Thomas Thrainer
424 1a732a74 Thomas Thrainer
  def CheckPrereq(self):
425 1a732a74 Thomas Thrainer
    """Check prerequisites for this tasklets.
426 1a732a74 Thomas Thrainer

427 1a732a74 Thomas Thrainer
    This method should check whether the prerequisites for the execution of
428 1a732a74 Thomas Thrainer
    this tasklet are fulfilled. It can do internode communication, but it
429 1a732a74 Thomas Thrainer
    should be idempotent - no cluster or system changes are allowed.
430 1a732a74 Thomas Thrainer

431 1a732a74 Thomas Thrainer
    The method should raise errors.OpPrereqError in case something is not
432 1a732a74 Thomas Thrainer
    fulfilled. Its return value is ignored.
433 1a732a74 Thomas Thrainer

434 1a732a74 Thomas Thrainer
    This method should also update all parameters to their canonical form if it
435 1a732a74 Thomas Thrainer
    hasn't been done before.
436 1a732a74 Thomas Thrainer

437 1a732a74 Thomas Thrainer
    """
438 1a732a74 Thomas Thrainer
    pass
439 1a732a74 Thomas Thrainer
440 1a732a74 Thomas Thrainer
  def Exec(self, feedback_fn):
441 1a732a74 Thomas Thrainer
    """Execute the tasklet.
442 1a732a74 Thomas Thrainer

443 1a732a74 Thomas Thrainer
    This method should implement the actual work. It should raise
444 1a732a74 Thomas Thrainer
    errors.OpExecError for failures that are somewhat dealt with in code, or
445 1a732a74 Thomas Thrainer
    expected.
446 1a732a74 Thomas Thrainer

447 1a732a74 Thomas Thrainer
    """
448 1a732a74 Thomas Thrainer
    raise NotImplementedError
449 1a732a74 Thomas Thrainer
450 1a732a74 Thomas Thrainer
451 5eacbcae Thomas Thrainer
class QueryBase:
452 1a732a74 Thomas Thrainer
  """Base for query utility classes.
453 1a732a74 Thomas Thrainer

454 1a732a74 Thomas Thrainer
  """
455 1a732a74 Thomas Thrainer
  #: Attribute holding field definitions
456 1a732a74 Thomas Thrainer
  FIELDS = None
457 1a732a74 Thomas Thrainer
458 1a732a74 Thomas Thrainer
  #: Field to sort by
459 1a732a74 Thomas Thrainer
  SORT_FIELD = "name"
460 1a732a74 Thomas Thrainer
461 1a732a74 Thomas Thrainer
  def __init__(self, qfilter, fields, use_locking):
462 1a732a74 Thomas Thrainer
    """Initializes this class.
463 1a732a74 Thomas Thrainer

464 1a732a74 Thomas Thrainer
    """
465 1a732a74 Thomas Thrainer
    self.use_locking = use_locking
466 1a732a74 Thomas Thrainer
467 1a732a74 Thomas Thrainer
    self.query = query.Query(self.FIELDS, fields, qfilter=qfilter,
468 1a732a74 Thomas Thrainer
                             namefield=self.SORT_FIELD)
469 1a732a74 Thomas Thrainer
    self.requested_data = self.query.RequestedData()
470 1a732a74 Thomas Thrainer
    self.names = self.query.RequestedNames()
471 1a732a74 Thomas Thrainer
472 1a732a74 Thomas Thrainer
    # Sort only if no names were requested
473 1a732a74 Thomas Thrainer
    self.sort_by_name = not self.names
474 1a732a74 Thomas Thrainer
475 1a732a74 Thomas Thrainer
    self.do_locking = None
476 1a732a74 Thomas Thrainer
    self.wanted = None
477 1a732a74 Thomas Thrainer
478 1a732a74 Thomas Thrainer
  def _GetNames(self, lu, all_names, lock_level):
479 1a732a74 Thomas Thrainer
    """Helper function to determine names asked for in the query.
480 1a732a74 Thomas Thrainer

481 1a732a74 Thomas Thrainer
    """
482 1a732a74 Thomas Thrainer
    if self.do_locking:
483 1a732a74 Thomas Thrainer
      names = lu.owned_locks(lock_level)
484 1a732a74 Thomas Thrainer
    else:
485 1a732a74 Thomas Thrainer
      names = all_names
486 1a732a74 Thomas Thrainer
487 1a732a74 Thomas Thrainer
    if self.wanted == locking.ALL_SET:
488 1a732a74 Thomas Thrainer
      assert not self.names
489 1a732a74 Thomas Thrainer
      # caller didn't specify names, so ordering is not important
490 1a732a74 Thomas Thrainer
      return utils.NiceSort(names)
491 1a732a74 Thomas Thrainer
492 1a732a74 Thomas Thrainer
    # caller specified names and we must keep the same order
493 1a732a74 Thomas Thrainer
    assert self.names
494 1a732a74 Thomas Thrainer
    assert not self.do_locking or lu.glm.is_owned(lock_level)
495 1a732a74 Thomas Thrainer
496 1a732a74 Thomas Thrainer
    missing = set(self.wanted).difference(names)
497 1a732a74 Thomas Thrainer
    if missing:
498 1a732a74 Thomas Thrainer
      raise errors.OpExecError("Some items were removed before retrieving"
499 1a732a74 Thomas Thrainer
                               " their data: %s" % missing)
500 1a732a74 Thomas Thrainer
501 1a732a74 Thomas Thrainer
    # Return expanded names
502 1a732a74 Thomas Thrainer
    return self.wanted
503 1a732a74 Thomas Thrainer
504 1a732a74 Thomas Thrainer
  def ExpandNames(self, lu):
505 1a732a74 Thomas Thrainer
    """Expand names for this query.
506 1a732a74 Thomas Thrainer

507 1a732a74 Thomas Thrainer
    See L{LogicalUnit.ExpandNames}.
508 1a732a74 Thomas Thrainer

509 1a732a74 Thomas Thrainer
    """
510 1a732a74 Thomas Thrainer
    raise NotImplementedError()
511 1a732a74 Thomas Thrainer
512 1a732a74 Thomas Thrainer
  def DeclareLocks(self, lu, level):
513 1a732a74 Thomas Thrainer
    """Declare locks for this query.
514 1a732a74 Thomas Thrainer

515 1a732a74 Thomas Thrainer
    See L{LogicalUnit.DeclareLocks}.
516 1a732a74 Thomas Thrainer

517 1a732a74 Thomas Thrainer
    """
518 1a732a74 Thomas Thrainer
    raise NotImplementedError()
519 1a732a74 Thomas Thrainer
520 1a732a74 Thomas Thrainer
  def _GetQueryData(self, lu):
521 1a732a74 Thomas Thrainer
    """Collects all data for this query.
522 1a732a74 Thomas Thrainer

523 1a732a74 Thomas Thrainer
    @return: Query data object
524 1a732a74 Thomas Thrainer

525 1a732a74 Thomas Thrainer
    """
526 1a732a74 Thomas Thrainer
    raise NotImplementedError()
527 1a732a74 Thomas Thrainer
528 1a732a74 Thomas Thrainer
  def NewStyleQuery(self, lu):
529 1a732a74 Thomas Thrainer
    """Collect data and execute query.
530 1a732a74 Thomas Thrainer

531 1a732a74 Thomas Thrainer
    """
532 1a732a74 Thomas Thrainer
    return query.GetQueryResponse(self.query, self._GetQueryData(lu),
533 1a732a74 Thomas Thrainer
                                  sort_by_name=self.sort_by_name)
534 1a732a74 Thomas Thrainer
535 1a732a74 Thomas Thrainer
  def OldStyleQuery(self, lu):
536 1a732a74 Thomas Thrainer
    """Collect data and execute query.
537 1a732a74 Thomas Thrainer

538 1a732a74 Thomas Thrainer
    """
539 1a732a74 Thomas Thrainer
    return self.query.OldStyleQuery(self._GetQueryData(lu),
540 1a732a74 Thomas Thrainer
                                    sort_by_name=self.sort_by_name)