Statistics
| Branch: | Tag: | Revision:

root / lib / cmdlib / base.py @ 1a732a74

History | View | Annotate | Download (17.5 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 1a732a74 Thomas Thrainer
from ganeti.cmdlib.common import _ExpandInstanceName
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 1a732a74 Thomas Thrainer
        locking.LEVEL_NODE: ['node1.example.com', 'node2.example.com'],
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 1a732a74 Thomas Thrainer
    @rtype: tuple; (list, list)
273 1a732a74 Thomas Thrainer
    @return: Tuple containing a list of node names on which the hook
274 1a732a74 Thomas Thrainer
      should run before the execution and a list of node names on which the
275 1a732a74 Thomas Thrainer
      hook should run after the execution. No nodes should be returned as an
276 1a732a74 Thomas Thrainer
      empty list (and not None).
277 1a732a74 Thomas Thrainer
    @note: If the C{HPATH} attribute of the LU class is C{None}, this function
278 1a732a74 Thomas Thrainer
      will not be called.
279 1a732a74 Thomas Thrainer

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

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

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

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

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

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

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

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

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

341 1a732a74 Thomas Thrainer
    If should be called in DeclareLocks in a way similar to::
342 1a732a74 Thomas Thrainer

343 1a732a74 Thomas Thrainer
      if level == locking.LEVEL_NODE:
344 1a732a74 Thomas Thrainer
        self._LockInstancesNodes()
345 1a732a74 Thomas Thrainer

346 1a732a74 Thomas Thrainer
    @type primary_only: boolean
347 1a732a74 Thomas Thrainer
    @param primary_only: only lock primary nodes of locked instances
348 1a732a74 Thomas Thrainer
    @param level: Which lock level to use for locking nodes
349 1a732a74 Thomas Thrainer

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

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

382 1a732a74 Thomas Thrainer
  """
383 1a732a74 Thomas Thrainer
  HPATH = None
384 1a732a74 Thomas Thrainer
  HTYPE = None
385 1a732a74 Thomas Thrainer
386 1a732a74 Thomas Thrainer
  def BuildHooksEnv(self):
387 1a732a74 Thomas Thrainer
    """Empty BuildHooksEnv for NoHooksLu.
388 1a732a74 Thomas Thrainer

389 1a732a74 Thomas Thrainer
    This just raises an error.
390 1a732a74 Thomas Thrainer

391 1a732a74 Thomas Thrainer
    """
392 1a732a74 Thomas Thrainer
    raise AssertionError("BuildHooksEnv called for NoHooksLUs")
393 1a732a74 Thomas Thrainer
394 1a732a74 Thomas Thrainer
  def BuildHooksNodes(self):
395 1a732a74 Thomas Thrainer
    """Empty BuildHooksNodes for NoHooksLU.
396 1a732a74 Thomas Thrainer

397 1a732a74 Thomas Thrainer
    """
398 1a732a74 Thomas Thrainer
    raise AssertionError("BuildHooksNodes called for NoHooksLU")
399 1a732a74 Thomas Thrainer
400 1a732a74 Thomas Thrainer
401 1a732a74 Thomas Thrainer
class Tasklet:
402 1a732a74 Thomas Thrainer
  """Tasklet base class.
403 1a732a74 Thomas Thrainer

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

408 1a732a74 Thomas Thrainer
  Subclasses must follow these rules:
409 1a732a74 Thomas Thrainer
    - Implement CheckPrereq
410 1a732a74 Thomas Thrainer
    - Implement Exec
411 1a732a74 Thomas Thrainer

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

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

427 1a732a74 Thomas Thrainer
    The method should raise errors.OpPrereqError in case something is not
428 1a732a74 Thomas Thrainer
    fulfilled. Its return value is ignored.
429 1a732a74 Thomas Thrainer

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

433 1a732a74 Thomas Thrainer
    """
434 1a732a74 Thomas Thrainer
    pass
435 1a732a74 Thomas Thrainer
436 1a732a74 Thomas Thrainer
  def Exec(self, feedback_fn):
437 1a732a74 Thomas Thrainer
    """Execute the tasklet.
438 1a732a74 Thomas Thrainer

439 1a732a74 Thomas Thrainer
    This method should implement the actual work. It should raise
440 1a732a74 Thomas Thrainer
    errors.OpExecError for failures that are somewhat dealt with in code, or
441 1a732a74 Thomas Thrainer
    expected.
442 1a732a74 Thomas Thrainer

443 1a732a74 Thomas Thrainer
    """
444 1a732a74 Thomas Thrainer
    raise NotImplementedError
445 1a732a74 Thomas Thrainer
446 1a732a74 Thomas Thrainer
447 1a732a74 Thomas Thrainer
class _QueryBase:
448 1a732a74 Thomas Thrainer
  """Base for query utility classes.
449 1a732a74 Thomas Thrainer

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

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

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

503 1a732a74 Thomas Thrainer
    See L{LogicalUnit.ExpandNames}.
504 1a732a74 Thomas Thrainer

505 1a732a74 Thomas Thrainer
    """
506 1a732a74 Thomas Thrainer
    raise NotImplementedError()
507 1a732a74 Thomas Thrainer
508 1a732a74 Thomas Thrainer
  def DeclareLocks(self, lu, level):
509 1a732a74 Thomas Thrainer
    """Declare locks for this query.
510 1a732a74 Thomas Thrainer

511 1a732a74 Thomas Thrainer
    See L{LogicalUnit.DeclareLocks}.
512 1a732a74 Thomas Thrainer

513 1a732a74 Thomas Thrainer
    """
514 1a732a74 Thomas Thrainer
    raise NotImplementedError()
515 1a732a74 Thomas Thrainer
516 1a732a74 Thomas Thrainer
  def _GetQueryData(self, lu):
517 1a732a74 Thomas Thrainer
    """Collects all data for this query.
518 1a732a74 Thomas Thrainer

519 1a732a74 Thomas Thrainer
    @return: Query data object
520 1a732a74 Thomas Thrainer

521 1a732a74 Thomas Thrainer
    """
522 1a732a74 Thomas Thrainer
    raise NotImplementedError()
523 1a732a74 Thomas Thrainer
524 1a732a74 Thomas Thrainer
  def NewStyleQuery(self, lu):
525 1a732a74 Thomas Thrainer
    """Collect data and execute query.
526 1a732a74 Thomas Thrainer

527 1a732a74 Thomas Thrainer
    """
528 1a732a74 Thomas Thrainer
    return query.GetQueryResponse(self.query, self._GetQueryData(lu),
529 1a732a74 Thomas Thrainer
                                  sort_by_name=self.sort_by_name)
530 1a732a74 Thomas Thrainer
531 1a732a74 Thomas Thrainer
  def OldStyleQuery(self, lu):
532 1a732a74 Thomas Thrainer
    """Collect data and execute query.
533 1a732a74 Thomas Thrainer

534 1a732a74 Thomas Thrainer
    """
535 1a732a74 Thomas Thrainer
    return self.query.OldStyleQuery(self._GetQueryData(lu),
536 1a732a74 Thomas Thrainer
                                    sort_by_name=self.sort_by_name)