Statistics
| Branch: | Tag: | Revision:

root / lib / cmdlib.py @ fdad8c4d

History | View | Annotate | Download (337.8 kB)

1 2f31098c Iustin Pop
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 e7c6e02b Michael Hanselmann
# Copyright (C) 2006, 2007, 2008 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 880478f8 Iustin Pop
"""Module implementing the master-side code."""
23 a8083063 Iustin Pop
24 c70d2d9b Iustin Pop
# pylint: disable-msg=W0201
25 c70d2d9b Iustin Pop
26 c70d2d9b Iustin Pop
# W0201 since most LU attributes are defined in CheckPrereq or similar
27 c70d2d9b Iustin Pop
# functions
28 a8083063 Iustin Pop
29 a8083063 Iustin Pop
import os
30 a8083063 Iustin Pop
import os.path
31 a8083063 Iustin Pop
import time
32 a8083063 Iustin Pop
import re
33 a8083063 Iustin Pop
import platform
34 ffa1c0dc Iustin Pop
import logging
35 74409b12 Iustin Pop
import copy
36 b98bf262 Michael Hanselmann
import OpenSSL
37 a8083063 Iustin Pop
38 a8083063 Iustin Pop
from ganeti import ssh
39 a8083063 Iustin Pop
from ganeti import utils
40 a8083063 Iustin Pop
from ganeti import errors
41 a8083063 Iustin Pop
from ganeti import hypervisor
42 6048c986 Guido Trotter
from ganeti import locking
43 a8083063 Iustin Pop
from ganeti import constants
44 a8083063 Iustin Pop
from ganeti import objects
45 8d14b30d Iustin Pop
from ganeti import serializer
46 112f18a5 Iustin Pop
from ganeti import ssconf
47 1338f2b4 Balazs Lecz
from ganeti import uidpool
48 d61df03e Iustin Pop
49 d61df03e Iustin Pop
50 a8083063 Iustin Pop
class LogicalUnit(object):
51 396e1b78 Michael Hanselmann
  """Logical Unit base class.
52 a8083063 Iustin Pop

53 a8083063 Iustin Pop
  Subclasses must follow these rules:
54 d465bdc8 Guido Trotter
    - implement ExpandNames
55 6fd35c4d Michael Hanselmann
    - implement CheckPrereq (except when tasklets are used)
56 6fd35c4d Michael Hanselmann
    - implement Exec (except when tasklets are used)
57 a8083063 Iustin Pop
    - implement BuildHooksEnv
58 a8083063 Iustin Pop
    - redefine HPATH and HTYPE
59 05f86716 Guido Trotter
    - optionally redefine their run requirements:
60 7e55040e Guido Trotter
        REQ_BGL: the LU needs to hold the Big Ganeti Lock exclusively
61 05f86716 Guido Trotter

62 05f86716 Guido Trotter
  Note that all commands require root permissions.
63 a8083063 Iustin Pop

64 20777413 Iustin Pop
  @ivar dry_run_result: the value (if any) that will be returned to the caller
65 20777413 Iustin Pop
      in dry-run mode (signalled by opcode dry_run parameter)
66 20777413 Iustin Pop

67 a8083063 Iustin Pop
  """
68 a8083063 Iustin Pop
  HPATH = None
69 a8083063 Iustin Pop
  HTYPE = None
70 a8083063 Iustin Pop
  _OP_REQP = []
71 7e55040e Guido Trotter
  REQ_BGL = True
72 a8083063 Iustin Pop
73 72737a7f Iustin Pop
  def __init__(self, processor, op, context, rpc):
74 a8083063 Iustin Pop
    """Constructor for LogicalUnit.
75 a8083063 Iustin Pop

76 5bbd3f7f Michael Hanselmann
    This needs to be overridden in derived classes in order to check op
77 a8083063 Iustin Pop
    validity.
78 a8083063 Iustin Pop

79 a8083063 Iustin Pop
    """
80 5bfac263 Iustin Pop
    self.proc = processor
81 a8083063 Iustin Pop
    self.op = op
82 77b657a3 Guido Trotter
    self.cfg = context.cfg
83 77b657a3 Guido Trotter
    self.context = context
84 72737a7f Iustin Pop
    self.rpc = rpc
85 ca2a79e1 Guido Trotter
    # Dicts used to declare locking needs to mcpu
86 d465bdc8 Guido Trotter
    self.needed_locks = None
87 6683bba2 Guido Trotter
    self.acquired_locks = {}
88 c772d142 Michael Hanselmann
    self.share_locks = dict.fromkeys(locking.LEVELS, 0)
89 ca2a79e1 Guido Trotter
    self.add_locks = {}
90 ca2a79e1 Guido Trotter
    self.remove_locks = {}
91 c4a2fee1 Guido Trotter
    # Used to force good behavior when calling helper functions
92 c4a2fee1 Guido Trotter
    self.recalculate_locks = {}
93 c92b310a Michael Hanselmann
    self.__ssh = None
94 86d9d3bb Iustin Pop
    # logging
95 fe267188 Iustin Pop
    self.LogWarning = processor.LogWarning # pylint: disable-msg=C0103
96 fe267188 Iustin Pop
    self.LogInfo = processor.LogInfo # pylint: disable-msg=C0103
97 d984846d Iustin Pop
    self.LogStep = processor.LogStep # pylint: disable-msg=C0103
98 20777413 Iustin Pop
    # support for dry-run
99 20777413 Iustin Pop
    self.dry_run_result = None
100 ee844e20 Iustin Pop
    # support for generic debug attribute
101 ee844e20 Iustin Pop
    if (not hasattr(self.op, "debug_level") or
102 ee844e20 Iustin Pop
        not isinstance(self.op.debug_level, int)):
103 ee844e20 Iustin Pop
      self.op.debug_level = 0
104 c92b310a Michael Hanselmann
105 6fd35c4d Michael Hanselmann
    # Tasklets
106 3a012b41 Michael Hanselmann
    self.tasklets = None
107 6fd35c4d Michael Hanselmann
108 a8083063 Iustin Pop
    for attr_name in self._OP_REQP:
109 a8083063 Iustin Pop
      attr_val = getattr(op, attr_name, None)
110 a8083063 Iustin Pop
      if attr_val is None:
111 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Required parameter '%s' missing" %
112 5c983ee5 Iustin Pop
                                   attr_name, errors.ECODE_INVAL)
113 6fd35c4d Michael Hanselmann
114 4be4691d Iustin Pop
    self.CheckArguments()
115 a8083063 Iustin Pop
116 c92b310a Michael Hanselmann
  def __GetSSH(self):
117 c92b310a Michael Hanselmann
    """Returns the SshRunner object
118 c92b310a Michael Hanselmann

119 c92b310a Michael Hanselmann
    """
120 c92b310a Michael Hanselmann
    if not self.__ssh:
121 6b0469d2 Iustin Pop
      self.__ssh = ssh.SshRunner(self.cfg.GetClusterName())
122 c92b310a Michael Hanselmann
    return self.__ssh
123 c92b310a Michael Hanselmann
124 c92b310a Michael Hanselmann
  ssh = property(fget=__GetSSH)
125 c92b310a Michael Hanselmann
126 4be4691d Iustin Pop
  def CheckArguments(self):
127 4be4691d Iustin Pop
    """Check syntactic validity for the opcode arguments.
128 4be4691d Iustin Pop

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

134 4be4691d Iustin Pop
      - ExpandNames is left as as purely a lock-related function
135 5bbd3f7f Michael Hanselmann
      - CheckPrereq is run after we have acquired locks (and possible
136 4be4691d Iustin Pop
        waited for them)
137 4be4691d Iustin Pop

138 4be4691d Iustin Pop
    The function is allowed to change the self.op attribute so that
139 4be4691d Iustin Pop
    later methods can no longer worry about missing parameters.
140 4be4691d Iustin Pop

141 4be4691d Iustin Pop
    """
142 4be4691d Iustin Pop
    pass
143 4be4691d Iustin Pop
144 d465bdc8 Guido Trotter
  def ExpandNames(self):
145 d465bdc8 Guido Trotter
    """Expand names for this LU.
146 d465bdc8 Guido Trotter

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

152 d465bdc8 Guido Trotter
    LUs which implement this method must also populate the self.needed_locks
153 d465bdc8 Guido Trotter
    member, as a dict with lock levels as keys, and a list of needed lock names
154 d465bdc8 Guido Trotter
    as values. Rules:
155 e4376078 Iustin Pop

156 e4376078 Iustin Pop
      - use an empty dict if you don't need any lock
157 e4376078 Iustin Pop
      - if you don't need any lock at a particular level omit that level
158 e4376078 Iustin Pop
      - don't put anything for the BGL level
159 e4376078 Iustin Pop
      - if you want all locks at a level use locking.ALL_SET as a value
160 d465bdc8 Guido Trotter

161 3977a4c1 Guido Trotter
    If you need to share locks (rather than acquire them exclusively) at one
162 3977a4c1 Guido Trotter
    level you can modify self.share_locks, setting a true value (usually 1) for
163 3977a4c1 Guido Trotter
    that level. By default locks are not shared.
164 3977a4c1 Guido Trotter

165 6fd35c4d Michael Hanselmann
    This function can also define a list of tasklets, which then will be
166 6fd35c4d Michael Hanselmann
    executed in order instead of the usual LU-level CheckPrereq and Exec
167 6fd35c4d Michael Hanselmann
    functions, if those are not defined by the LU.
168 6fd35c4d Michael Hanselmann

169 e4376078 Iustin Pop
    Examples::
170 e4376078 Iustin Pop

171 e4376078 Iustin Pop
      # Acquire all nodes and one instance
172 e4376078 Iustin Pop
      self.needed_locks = {
173 e4376078 Iustin Pop
        locking.LEVEL_NODE: locking.ALL_SET,
174 e4376078 Iustin Pop
        locking.LEVEL_INSTANCE: ['instance1.example.tld'],
175 e4376078 Iustin Pop
      }
176 e4376078 Iustin Pop
      # Acquire just two nodes
177 e4376078 Iustin Pop
      self.needed_locks = {
178 e4376078 Iustin Pop
        locking.LEVEL_NODE: ['node1.example.tld', 'node2.example.tld'],
179 e4376078 Iustin Pop
      }
180 e4376078 Iustin Pop
      # Acquire no locks
181 e4376078 Iustin Pop
      self.needed_locks = {} # No, you can't leave it to the default value None
182 d465bdc8 Guido Trotter

183 d465bdc8 Guido Trotter
    """
184 d465bdc8 Guido Trotter
    # The implementation of this method is mandatory only if the new LU is
185 d465bdc8 Guido Trotter
    # concurrent, so that old LUs don't need to be changed all at the same
186 d465bdc8 Guido Trotter
    # time.
187 d465bdc8 Guido Trotter
    if self.REQ_BGL:
188 d465bdc8 Guido Trotter
      self.needed_locks = {} # Exclusive LUs don't need locks.
189 d465bdc8 Guido Trotter
    else:
190 d465bdc8 Guido Trotter
      raise NotImplementedError
191 d465bdc8 Guido Trotter
192 fb8dcb62 Guido Trotter
  def DeclareLocks(self, level):
193 fb8dcb62 Guido Trotter
    """Declare LU locking needs for a level
194 fb8dcb62 Guido Trotter

195 fb8dcb62 Guido Trotter
    While most LUs can just declare their locking needs at ExpandNames time,
196 fb8dcb62 Guido Trotter
    sometimes there's the need to calculate some locks after having acquired
197 fb8dcb62 Guido Trotter
    the ones before. This function is called just before acquiring locks at a
198 fb8dcb62 Guido Trotter
    particular level, but after acquiring the ones at lower levels, and permits
199 fb8dcb62 Guido Trotter
    such calculations. It can be used to modify self.needed_locks, and by
200 fb8dcb62 Guido Trotter
    default it does nothing.
201 fb8dcb62 Guido Trotter

202 fb8dcb62 Guido Trotter
    This function is only called if you have something already set in
203 fb8dcb62 Guido Trotter
    self.needed_locks for the level.
204 fb8dcb62 Guido Trotter

205 fb8dcb62 Guido Trotter
    @param level: Locking level which is going to be locked
206 fb8dcb62 Guido Trotter
    @type level: member of ganeti.locking.LEVELS
207 fb8dcb62 Guido Trotter

208 fb8dcb62 Guido Trotter
    """
209 fb8dcb62 Guido Trotter
210 a8083063 Iustin Pop
  def CheckPrereq(self):
211 a8083063 Iustin Pop
    """Check prerequisites for this LU.
212 a8083063 Iustin Pop

213 a8083063 Iustin Pop
    This method should check that the prerequisites for the execution
214 a8083063 Iustin Pop
    of this LU are fulfilled. It can do internode communication, but
215 a8083063 Iustin Pop
    it should be idempotent - no cluster or system changes are
216 a8083063 Iustin Pop
    allowed.
217 a8083063 Iustin Pop

218 a8083063 Iustin Pop
    The method should raise errors.OpPrereqError in case something is
219 a8083063 Iustin Pop
    not fulfilled. Its return value is ignored.
220 a8083063 Iustin Pop

221 a8083063 Iustin Pop
    This method should also update all the parameters of the opcode to
222 d465bdc8 Guido Trotter
    their canonical form if it hasn't been done by ExpandNames before.
223 a8083063 Iustin Pop

224 a8083063 Iustin Pop
    """
225 3a012b41 Michael Hanselmann
    if self.tasklets is not None:
226 b4a9eb66 Michael Hanselmann
      for (idx, tl) in enumerate(self.tasklets):
227 abae1b2b Michael Hanselmann
        logging.debug("Checking prerequisites for tasklet %s/%s",
228 abae1b2b Michael Hanselmann
                      idx + 1, len(self.tasklets))
229 6fd35c4d Michael Hanselmann
        tl.CheckPrereq()
230 6fd35c4d Michael Hanselmann
    else:
231 6fd35c4d Michael Hanselmann
      raise NotImplementedError
232 a8083063 Iustin Pop
233 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
234 a8083063 Iustin Pop
    """Execute the LU.
235 a8083063 Iustin Pop

236 a8083063 Iustin Pop
    This method should implement the actual work. It should raise
237 a8083063 Iustin Pop
    errors.OpExecError for failures that are somewhat dealt with in
238 a8083063 Iustin Pop
    code, or expected.
239 a8083063 Iustin Pop

240 a8083063 Iustin Pop
    """
241 3a012b41 Michael Hanselmann
    if self.tasklets is not None:
242 b4a9eb66 Michael Hanselmann
      for (idx, tl) in enumerate(self.tasklets):
243 abae1b2b Michael Hanselmann
        logging.debug("Executing tasklet %s/%s", idx + 1, len(self.tasklets))
244 6fd35c4d Michael Hanselmann
        tl.Exec(feedback_fn)
245 6fd35c4d Michael Hanselmann
    else:
246 6fd35c4d Michael Hanselmann
      raise NotImplementedError
247 a8083063 Iustin Pop
248 a8083063 Iustin Pop
  def BuildHooksEnv(self):
249 a8083063 Iustin Pop
    """Build hooks environment for this LU.
250 a8083063 Iustin Pop

251 a8083063 Iustin Pop
    This method should return a three-node tuple consisting of: a dict
252 a8083063 Iustin Pop
    containing the environment that will be used for running the
253 a8083063 Iustin Pop
    specific hook for this LU, a list of node names on which the hook
254 a8083063 Iustin Pop
    should run before the execution, and a list of node names on which
255 a8083063 Iustin Pop
    the hook should run after the execution.
256 a8083063 Iustin Pop

257 a8083063 Iustin Pop
    The keys of the dict must not have 'GANETI_' prefixed as this will
258 a8083063 Iustin Pop
    be handled in the hooks runner. Also note additional keys will be
259 a8083063 Iustin Pop
    added by the hooks runner. If the LU doesn't define any
260 a8083063 Iustin Pop
    environment, an empty dict (and not None) should be returned.
261 a8083063 Iustin Pop

262 8a3fe350 Guido Trotter
    No nodes should be returned as an empty list (and not None).
263 a8083063 Iustin Pop

264 a8083063 Iustin Pop
    Note that if the HPATH for a LU class is None, this function will
265 a8083063 Iustin Pop
    not be called.
266 a8083063 Iustin Pop

267 a8083063 Iustin Pop
    """
268 a8083063 Iustin Pop
    raise NotImplementedError
269 a8083063 Iustin Pop
270 1fce5219 Guido Trotter
  def HooksCallBack(self, phase, hook_results, feedback_fn, lu_result):
271 1fce5219 Guido Trotter
    """Notify the LU about the results of its hooks.
272 1fce5219 Guido Trotter

273 1fce5219 Guido Trotter
    This method is called every time a hooks phase is executed, and notifies
274 1fce5219 Guido Trotter
    the Logical Unit about the hooks' result. The LU can then use it to alter
275 1fce5219 Guido Trotter
    its result based on the hooks.  By default the method does nothing and the
276 1fce5219 Guido Trotter
    previous result is passed back unchanged but any LU can define it if it
277 1fce5219 Guido Trotter
    wants to use the local cluster hook-scripts somehow.
278 1fce5219 Guido Trotter

279 e4376078 Iustin Pop
    @param phase: one of L{constants.HOOKS_PHASE_POST} or
280 e4376078 Iustin Pop
        L{constants.HOOKS_PHASE_PRE}; it denotes the hooks phase
281 e4376078 Iustin Pop
    @param hook_results: the results of the multi-node hooks rpc call
282 e4376078 Iustin Pop
    @param feedback_fn: function used send feedback back to the caller
283 e4376078 Iustin Pop
    @param lu_result: the previous Exec result this LU had, or None
284 e4376078 Iustin Pop
        in the PRE phase
285 e4376078 Iustin Pop
    @return: the new Exec result, based on the previous result
286 e4376078 Iustin Pop
        and hook results
287 1fce5219 Guido Trotter

288 1fce5219 Guido Trotter
    """
289 2d54e29c Iustin Pop
    # API must be kept, thus we ignore the unused argument and could
290 2d54e29c Iustin Pop
    # be a function warnings
291 2d54e29c Iustin Pop
    # pylint: disable-msg=W0613,R0201
292 1fce5219 Guido Trotter
    return lu_result
293 1fce5219 Guido Trotter
294 43905206 Guido Trotter
  def _ExpandAndLockInstance(self):
295 43905206 Guido Trotter
    """Helper function to expand and lock an instance.
296 43905206 Guido Trotter

297 43905206 Guido Trotter
    Many LUs that work on an instance take its name in self.op.instance_name
298 43905206 Guido Trotter
    and need to expand it and then declare the expanded name for locking. This
299 43905206 Guido Trotter
    function does it, and then updates self.op.instance_name to the expanded
300 43905206 Guido Trotter
    name. It also initializes needed_locks as a dict, if this hasn't been done
301 43905206 Guido Trotter
    before.
302 43905206 Guido Trotter

303 43905206 Guido Trotter
    """
304 43905206 Guido Trotter
    if self.needed_locks is None:
305 43905206 Guido Trotter
      self.needed_locks = {}
306 43905206 Guido Trotter
    else:
307 43905206 Guido Trotter
      assert locking.LEVEL_INSTANCE not in self.needed_locks, \
308 43905206 Guido Trotter
        "_ExpandAndLockInstance called with instance-level locks set"
309 cf26a87a Iustin Pop
    self.op.instance_name = _ExpandInstanceName(self.cfg,
310 cf26a87a Iustin Pop
                                                self.op.instance_name)
311 cf26a87a Iustin Pop
    self.needed_locks[locking.LEVEL_INSTANCE] = self.op.instance_name
312 43905206 Guido Trotter
313 a82ce292 Guido Trotter
  def _LockInstancesNodes(self, primary_only=False):
314 c4a2fee1 Guido Trotter
    """Helper function to declare instances' nodes for locking.
315 c4a2fee1 Guido Trotter

316 c4a2fee1 Guido Trotter
    This function should be called after locking one or more instances to lock
317 c4a2fee1 Guido Trotter
    their nodes. Its effect is populating self.needed_locks[locking.LEVEL_NODE]
318 c4a2fee1 Guido Trotter
    with all primary or secondary nodes for instances already locked and
319 c4a2fee1 Guido Trotter
    present in self.needed_locks[locking.LEVEL_INSTANCE].
320 c4a2fee1 Guido Trotter

321 c4a2fee1 Guido Trotter
    It should be called from DeclareLocks, and for safety only works if
322 c4a2fee1 Guido Trotter
    self.recalculate_locks[locking.LEVEL_NODE] is set.
323 c4a2fee1 Guido Trotter

324 c4a2fee1 Guido Trotter
    In the future it may grow parameters to just lock some instance's nodes, or
325 c4a2fee1 Guido Trotter
    to just lock primaries or secondary nodes, if needed.
326 c4a2fee1 Guido Trotter

327 e4376078 Iustin Pop
    If should be called in DeclareLocks in a way similar to::
328 c4a2fee1 Guido Trotter

329 e4376078 Iustin Pop
      if level == locking.LEVEL_NODE:
330 e4376078 Iustin Pop
        self._LockInstancesNodes()
331 c4a2fee1 Guido Trotter

332 a82ce292 Guido Trotter
    @type primary_only: boolean
333 a82ce292 Guido Trotter
    @param primary_only: only lock primary nodes of locked instances
334 a82ce292 Guido Trotter

335 c4a2fee1 Guido Trotter
    """
336 c4a2fee1 Guido Trotter
    assert locking.LEVEL_NODE in self.recalculate_locks, \
337 c4a2fee1 Guido Trotter
      "_LockInstancesNodes helper function called with no nodes to recalculate"
338 c4a2fee1 Guido Trotter
339 c4a2fee1 Guido Trotter
    # TODO: check if we're really been called with the instance locks held
340 c4a2fee1 Guido Trotter
341 c4a2fee1 Guido Trotter
    # For now we'll replace self.needed_locks[locking.LEVEL_NODE], but in the
342 c4a2fee1 Guido Trotter
    # future we might want to have different behaviors depending on the value
343 c4a2fee1 Guido Trotter
    # of self.recalculate_locks[locking.LEVEL_NODE]
344 c4a2fee1 Guido Trotter
    wanted_nodes = []
345 6683bba2 Guido Trotter
    for instance_name in self.acquired_locks[locking.LEVEL_INSTANCE]:
346 c4a2fee1 Guido Trotter
      instance = self.context.cfg.GetInstanceInfo(instance_name)
347 c4a2fee1 Guido Trotter
      wanted_nodes.append(instance.primary_node)
348 a82ce292 Guido Trotter
      if not primary_only:
349 a82ce292 Guido Trotter
        wanted_nodes.extend(instance.secondary_nodes)
350 9513b6ab Guido Trotter
351 9513b6ab Guido Trotter
    if self.recalculate_locks[locking.LEVEL_NODE] == constants.LOCKS_REPLACE:
352 9513b6ab Guido Trotter
      self.needed_locks[locking.LEVEL_NODE] = wanted_nodes
353 9513b6ab Guido Trotter
    elif self.recalculate_locks[locking.LEVEL_NODE] == constants.LOCKS_APPEND:
354 9513b6ab Guido Trotter
      self.needed_locks[locking.LEVEL_NODE].extend(wanted_nodes)
355 c4a2fee1 Guido Trotter
356 c4a2fee1 Guido Trotter
    del self.recalculate_locks[locking.LEVEL_NODE]
357 c4a2fee1 Guido Trotter
358 a8083063 Iustin Pop
359 fe267188 Iustin Pop
class NoHooksLU(LogicalUnit): # pylint: disable-msg=W0223
360 a8083063 Iustin Pop
  """Simple LU which runs no hooks.
361 a8083063 Iustin Pop

362 a8083063 Iustin Pop
  This LU is intended as a parent for other LogicalUnits which will
363 a8083063 Iustin Pop
  run no hooks, in order to reduce duplicate code.
364 a8083063 Iustin Pop

365 a8083063 Iustin Pop
  """
366 a8083063 Iustin Pop
  HPATH = None
367 a8083063 Iustin Pop
  HTYPE = None
368 a8083063 Iustin Pop
369 fc8a6b8f Iustin Pop
  def BuildHooksEnv(self):
370 fc8a6b8f Iustin Pop
    """Empty BuildHooksEnv for NoHooksLu.
371 fc8a6b8f Iustin Pop

372 fc8a6b8f Iustin Pop
    This just raises an error.
373 fc8a6b8f Iustin Pop

374 fc8a6b8f Iustin Pop
    """
375 fc8a6b8f Iustin Pop
    assert False, "BuildHooksEnv called for NoHooksLUs"
376 fc8a6b8f Iustin Pop
377 a8083063 Iustin Pop
378 9a6800e1 Michael Hanselmann
class Tasklet:
379 9a6800e1 Michael Hanselmann
  """Tasklet base class.
380 9a6800e1 Michael Hanselmann

381 9a6800e1 Michael Hanselmann
  Tasklets are subcomponents for LUs. LUs can consist entirely of tasklets or
382 9a6800e1 Michael Hanselmann
  they can mix legacy code with tasklets. Locking needs to be done in the LU,
383 9a6800e1 Michael Hanselmann
  tasklets know nothing about locks.
384 9a6800e1 Michael Hanselmann

385 9a6800e1 Michael Hanselmann
  Subclasses must follow these rules:
386 9a6800e1 Michael Hanselmann
    - Implement CheckPrereq
387 9a6800e1 Michael Hanselmann
    - Implement Exec
388 9a6800e1 Michael Hanselmann

389 9a6800e1 Michael Hanselmann
  """
390 464243a7 Michael Hanselmann
  def __init__(self, lu):
391 464243a7 Michael Hanselmann
    self.lu = lu
392 464243a7 Michael Hanselmann
393 464243a7 Michael Hanselmann
    # Shortcuts
394 464243a7 Michael Hanselmann
    self.cfg = lu.cfg
395 464243a7 Michael Hanselmann
    self.rpc = lu.rpc
396 464243a7 Michael Hanselmann
397 9a6800e1 Michael Hanselmann
  def CheckPrereq(self):
398 9a6800e1 Michael Hanselmann
    """Check prerequisites for this tasklets.
399 9a6800e1 Michael Hanselmann

400 9a6800e1 Michael Hanselmann
    This method should check whether the prerequisites for the execution of
401 9a6800e1 Michael Hanselmann
    this tasklet are fulfilled. It can do internode communication, but it
402 9a6800e1 Michael Hanselmann
    should be idempotent - no cluster or system changes are allowed.
403 9a6800e1 Michael Hanselmann

404 9a6800e1 Michael Hanselmann
    The method should raise errors.OpPrereqError in case something is not
405 9a6800e1 Michael Hanselmann
    fulfilled. Its return value is ignored.
406 9a6800e1 Michael Hanselmann

407 9a6800e1 Michael Hanselmann
    This method should also update all parameters to their canonical form if it
408 9a6800e1 Michael Hanselmann
    hasn't been done before.
409 9a6800e1 Michael Hanselmann

410 9a6800e1 Michael Hanselmann
    """
411 9a6800e1 Michael Hanselmann
    raise NotImplementedError
412 9a6800e1 Michael Hanselmann
413 9a6800e1 Michael Hanselmann
  def Exec(self, feedback_fn):
414 9a6800e1 Michael Hanselmann
    """Execute the tasklet.
415 9a6800e1 Michael Hanselmann

416 9a6800e1 Michael Hanselmann
    This method should implement the actual work. It should raise
417 9a6800e1 Michael Hanselmann
    errors.OpExecError for failures that are somewhat dealt with in code, or
418 9a6800e1 Michael Hanselmann
    expected.
419 9a6800e1 Michael Hanselmann

420 9a6800e1 Michael Hanselmann
    """
421 9a6800e1 Michael Hanselmann
    raise NotImplementedError
422 9a6800e1 Michael Hanselmann
423 9a6800e1 Michael Hanselmann
424 dcb93971 Michael Hanselmann
def _GetWantedNodes(lu, nodes):
425 a7ba5e53 Iustin Pop
  """Returns list of checked and expanded node names.
426 83120a01 Michael Hanselmann

427 e4376078 Iustin Pop
  @type lu: L{LogicalUnit}
428 e4376078 Iustin Pop
  @param lu: the logical unit on whose behalf we execute
429 e4376078 Iustin Pop
  @type nodes: list
430 e4376078 Iustin Pop
  @param nodes: list of node names or None for all nodes
431 e4376078 Iustin Pop
  @rtype: list
432 e4376078 Iustin Pop
  @return: the list of nodes, sorted
433 083a91c9 Iustin Pop
  @raise errors.ProgrammerError: if the nodes parameter is wrong type
434 83120a01 Michael Hanselmann

435 83120a01 Michael Hanselmann
  """
436 3312b702 Iustin Pop
  if not isinstance(nodes, list):
437 5c983ee5 Iustin Pop
    raise errors.OpPrereqError("Invalid argument type 'nodes'",
438 5c983ee5 Iustin Pop
                               errors.ECODE_INVAL)
439 dcb93971 Michael Hanselmann
440 ea47808a Guido Trotter
  if not nodes:
441 ea47808a Guido Trotter
    raise errors.ProgrammerError("_GetWantedNodes should only be called with a"
442 ea47808a Guido Trotter
      " non-empty list of nodes whose name is to be expanded.")
443 dcb93971 Michael Hanselmann
444 61dabca4 Iustin Pop
  wanted = [_ExpandNodeName(lu.cfg, name) for name in nodes]
445 a7ba5e53 Iustin Pop
  return utils.NiceSort(wanted)
446 3312b702 Iustin Pop
447 3312b702 Iustin Pop
448 3312b702 Iustin Pop
def _GetWantedInstances(lu, instances):
449 a7ba5e53 Iustin Pop
  """Returns list of checked and expanded instance names.
450 3312b702 Iustin Pop

451 e4376078 Iustin Pop
  @type lu: L{LogicalUnit}
452 e4376078 Iustin Pop
  @param lu: the logical unit on whose behalf we execute
453 e4376078 Iustin Pop
  @type instances: list
454 e4376078 Iustin Pop
  @param instances: list of instance names or None for all instances
455 e4376078 Iustin Pop
  @rtype: list
456 e4376078 Iustin Pop
  @return: the list of instances, sorted
457 e4376078 Iustin Pop
  @raise errors.OpPrereqError: if the instances parameter is wrong type
458 e4376078 Iustin Pop
  @raise errors.OpPrereqError: if any of the passed instances is not found
459 3312b702 Iustin Pop

460 3312b702 Iustin Pop
  """
461 3312b702 Iustin Pop
  if not isinstance(instances, list):
462 5c983ee5 Iustin Pop
    raise errors.OpPrereqError("Invalid argument type 'instances'",
463 5c983ee5 Iustin Pop
                               errors.ECODE_INVAL)
464 3312b702 Iustin Pop
465 3312b702 Iustin Pop
  if instances:
466 cf26a87a Iustin Pop
    wanted = [_ExpandInstanceName(lu.cfg, name) for name in instances]
467 3312b702 Iustin Pop
  else:
468 a7f5dc98 Iustin Pop
    wanted = utils.NiceSort(lu.cfg.GetInstanceList())
469 a7f5dc98 Iustin Pop
  return wanted
470 dcb93971 Michael Hanselmann
471 dcb93971 Michael Hanselmann
472 dcb93971 Michael Hanselmann
def _CheckOutputFields(static, dynamic, selected):
473 83120a01 Michael Hanselmann
  """Checks whether all selected fields are valid.
474 83120a01 Michael Hanselmann

475 a2d2e1a7 Iustin Pop
  @type static: L{utils.FieldSet}
476 31bf511f Iustin Pop
  @param static: static fields set
477 a2d2e1a7 Iustin Pop
  @type dynamic: L{utils.FieldSet}
478 31bf511f Iustin Pop
  @param dynamic: dynamic fields set
479 83120a01 Michael Hanselmann

480 83120a01 Michael Hanselmann
  """
481 a2d2e1a7 Iustin Pop
  f = utils.FieldSet()
482 31bf511f Iustin Pop
  f.Extend(static)
483 31bf511f Iustin Pop
  f.Extend(dynamic)
484 dcb93971 Michael Hanselmann
485 31bf511f Iustin Pop
  delta = f.NonMatching(selected)
486 31bf511f Iustin Pop
  if delta:
487 3ecf6786 Iustin Pop
    raise errors.OpPrereqError("Unknown output fields selected: %s"
488 5c983ee5 Iustin Pop
                               % ",".join(delta), errors.ECODE_INVAL)
489 dcb93971 Michael Hanselmann
490 dcb93971 Michael Hanselmann
491 a5961235 Iustin Pop
def _CheckBooleanOpField(op, name):
492 a5961235 Iustin Pop
  """Validates boolean opcode parameters.
493 a5961235 Iustin Pop

494 a5961235 Iustin Pop
  This will ensure that an opcode parameter is either a boolean value,
495 a5961235 Iustin Pop
  or None (but that it always exists).
496 a5961235 Iustin Pop

497 a5961235 Iustin Pop
  """
498 a5961235 Iustin Pop
  val = getattr(op, name, None)
499 a5961235 Iustin Pop
  if not (val is None or isinstance(val, bool)):
500 a5961235 Iustin Pop
    raise errors.OpPrereqError("Invalid boolean parameter '%s' (%s)" %
501 5c983ee5 Iustin Pop
                               (name, str(val)), errors.ECODE_INVAL)
502 a5961235 Iustin Pop
  setattr(op, name, val)
503 a5961235 Iustin Pop
504 a5961235 Iustin Pop
505 7736a5f2 Iustin Pop
def _CheckGlobalHvParams(params):
506 7736a5f2 Iustin Pop
  """Validates that given hypervisor params are not global ones.
507 7736a5f2 Iustin Pop

508 7736a5f2 Iustin Pop
  This will ensure that instances don't get customised versions of
509 7736a5f2 Iustin Pop
  global params.
510 7736a5f2 Iustin Pop

511 7736a5f2 Iustin Pop
  """
512 7736a5f2 Iustin Pop
  used_globals = constants.HVC_GLOBALS.intersection(params)
513 7736a5f2 Iustin Pop
  if used_globals:
514 7736a5f2 Iustin Pop
    msg = ("The following hypervisor parameters are global and cannot"
515 7736a5f2 Iustin Pop
           " be customized at instance level, please modify them at"
516 1f864b60 Iustin Pop
           " cluster level: %s" % utils.CommaJoin(used_globals))
517 7736a5f2 Iustin Pop
    raise errors.OpPrereqError(msg, errors.ECODE_INVAL)
518 7736a5f2 Iustin Pop
519 7736a5f2 Iustin Pop
520 a5961235 Iustin Pop
def _CheckNodeOnline(lu, node):
521 a5961235 Iustin Pop
  """Ensure that a given node is online.
522 a5961235 Iustin Pop

523 a5961235 Iustin Pop
  @param lu: the LU on behalf of which we make the check
524 a5961235 Iustin Pop
  @param node: the node to check
525 733a2b6a Iustin Pop
  @raise errors.OpPrereqError: if the node is offline
526 a5961235 Iustin Pop

527 a5961235 Iustin Pop
  """
528 a5961235 Iustin Pop
  if lu.cfg.GetNodeInfo(node).offline:
529 5c983ee5 Iustin Pop
    raise errors.OpPrereqError("Can't use offline node %s" % node,
530 5c983ee5 Iustin Pop
                               errors.ECODE_INVAL)
531 a5961235 Iustin Pop
532 a5961235 Iustin Pop
533 733a2b6a Iustin Pop
def _CheckNodeNotDrained(lu, node):
534 733a2b6a Iustin Pop
  """Ensure that a given node is not drained.
535 733a2b6a Iustin Pop

536 733a2b6a Iustin Pop
  @param lu: the LU on behalf of which we make the check
537 733a2b6a Iustin Pop
  @param node: the node to check
538 733a2b6a Iustin Pop
  @raise errors.OpPrereqError: if the node is drained
539 733a2b6a Iustin Pop

540 733a2b6a Iustin Pop
  """
541 733a2b6a Iustin Pop
  if lu.cfg.GetNodeInfo(node).drained:
542 5c983ee5 Iustin Pop
    raise errors.OpPrereqError("Can't use drained node %s" % node,
543 5c983ee5 Iustin Pop
                               errors.ECODE_INVAL)
544 733a2b6a Iustin Pop
545 733a2b6a Iustin Pop
546 231cd901 Iustin Pop
def _CheckNodeHasOS(lu, node, os_name, force_variant):
547 231cd901 Iustin Pop
  """Ensure that a node supports a given OS.
548 231cd901 Iustin Pop

549 231cd901 Iustin Pop
  @param lu: the LU on behalf of which we make the check
550 231cd901 Iustin Pop
  @param node: the node to check
551 231cd901 Iustin Pop
  @param os_name: the OS to query about
552 231cd901 Iustin Pop
  @param force_variant: whether to ignore variant errors
553 231cd901 Iustin Pop
  @raise errors.OpPrereqError: if the node is not supporting the OS
554 231cd901 Iustin Pop

555 231cd901 Iustin Pop
  """
556 231cd901 Iustin Pop
  result = lu.rpc.call_os_get(node, os_name)
557 231cd901 Iustin Pop
  result.Raise("OS '%s' not in supported OS list for node %s" %
558 231cd901 Iustin Pop
               (os_name, node),
559 231cd901 Iustin Pop
               prereq=True, ecode=errors.ECODE_INVAL)
560 231cd901 Iustin Pop
  if not force_variant:
561 231cd901 Iustin Pop
    _CheckOSVariant(result.payload, os_name)
562 231cd901 Iustin Pop
563 231cd901 Iustin Pop
564 0e3baaf3 Iustin Pop
def _RequireFileStorage():
565 0e3baaf3 Iustin Pop
  """Checks that file storage is enabled.
566 0e3baaf3 Iustin Pop

567 0e3baaf3 Iustin Pop
  @raise errors.OpPrereqError: when file storage is disabled
568 0e3baaf3 Iustin Pop

569 0e3baaf3 Iustin Pop
  """
570 0e3baaf3 Iustin Pop
  if not constants.ENABLE_FILE_STORAGE:
571 0e3baaf3 Iustin Pop
    raise errors.OpPrereqError("File storage disabled at configure time",
572 0e3baaf3 Iustin Pop
                               errors.ECODE_INVAL)
573 0e3baaf3 Iustin Pop
574 0e3baaf3 Iustin Pop
575 5d55819e Iustin Pop
def _CheckDiskTemplate(template):
576 5d55819e Iustin Pop
  """Ensure a given disk template is valid.
577 5d55819e Iustin Pop

578 5d55819e Iustin Pop
  """
579 5d55819e Iustin Pop
  if template not in constants.DISK_TEMPLATES:
580 5d55819e Iustin Pop
    msg = ("Invalid disk template name '%s', valid templates are: %s" %
581 5d55819e Iustin Pop
           (template, utils.CommaJoin(constants.DISK_TEMPLATES)))
582 5d55819e Iustin Pop
    raise errors.OpPrereqError(msg, errors.ECODE_INVAL)
583 0e3baaf3 Iustin Pop
  if template == constants.DT_FILE:
584 0e3baaf3 Iustin Pop
    _RequireFileStorage()
585 0e3baaf3 Iustin Pop
586 0e3baaf3 Iustin Pop
587 0e3baaf3 Iustin Pop
def _CheckStorageType(storage_type):
588 0e3baaf3 Iustin Pop
  """Ensure a given storage type is valid.
589 0e3baaf3 Iustin Pop

590 0e3baaf3 Iustin Pop
  """
591 0e3baaf3 Iustin Pop
  if storage_type not in constants.VALID_STORAGE_TYPES:
592 0e3baaf3 Iustin Pop
    raise errors.OpPrereqError("Unknown storage type: %s" % storage_type,
593 f276c4b5 Iustin Pop
                               errors.ECODE_INVAL)
594 0e3baaf3 Iustin Pop
  if storage_type == constants.ST_FILE:
595 0e3baaf3 Iustin Pop
    _RequireFileStorage()
596 0e3baaf3 Iustin Pop
597 5d55819e Iustin Pop
598 5d55819e Iustin Pop
599 31624382 Iustin Pop
def _CheckInstanceDown(lu, instance, reason):
600 31624382 Iustin Pop
  """Ensure that an instance is not running."""
601 31624382 Iustin Pop
  if instance.admin_up:
602 31624382 Iustin Pop
    raise errors.OpPrereqError("Instance %s is marked to be up, %s" %
603 31624382 Iustin Pop
                               (instance.name, reason), errors.ECODE_STATE)
604 31624382 Iustin Pop
605 31624382 Iustin Pop
  pnode = instance.primary_node
606 31624382 Iustin Pop
  ins_l = lu.rpc.call_instance_list([pnode], [instance.hypervisor])[pnode]
607 31624382 Iustin Pop
  ins_l.Raise("Can't contact node %s for instance information" % pnode,
608 31624382 Iustin Pop
              prereq=True, ecode=errors.ECODE_ENVIRON)
609 31624382 Iustin Pop
610 31624382 Iustin Pop
  if instance.name in ins_l.payload:
611 31624382 Iustin Pop
    raise errors.OpPrereqError("Instance %s is running, %s" %
612 31624382 Iustin Pop
                               (instance.name, reason), errors.ECODE_STATE)
613 31624382 Iustin Pop
614 31624382 Iustin Pop
615 cf26a87a Iustin Pop
def _ExpandItemName(fn, name, kind):
616 cf26a87a Iustin Pop
  """Expand an item name.
617 cf26a87a Iustin Pop

618 cf26a87a Iustin Pop
  @param fn: the function to use for expansion
619 cf26a87a Iustin Pop
  @param name: requested item name
620 cf26a87a Iustin Pop
  @param kind: text description ('Node' or 'Instance')
621 cf26a87a Iustin Pop
  @return: the resolved (full) name
622 cf26a87a Iustin Pop
  @raise errors.OpPrereqError: if the item is not found
623 cf26a87a Iustin Pop

624 cf26a87a Iustin Pop
  """
625 cf26a87a Iustin Pop
  full_name = fn(name)
626 cf26a87a Iustin Pop
  if full_name is None:
627 cf26a87a Iustin Pop
    raise errors.OpPrereqError("%s '%s' not known" % (kind, name),
628 cf26a87a Iustin Pop
                               errors.ECODE_NOENT)
629 cf26a87a Iustin Pop
  return full_name
630 cf26a87a Iustin Pop
631 cf26a87a Iustin Pop
632 cf26a87a Iustin Pop
def _ExpandNodeName(cfg, name):
633 cf26a87a Iustin Pop
  """Wrapper over L{_ExpandItemName} for nodes."""
634 cf26a87a Iustin Pop
  return _ExpandItemName(cfg.ExpandNodeName, name, "Node")
635 cf26a87a Iustin Pop
636 cf26a87a Iustin Pop
637 cf26a87a Iustin Pop
def _ExpandInstanceName(cfg, name):
638 cf26a87a Iustin Pop
  """Wrapper over L{_ExpandItemName} for instance."""
639 cf26a87a Iustin Pop
  return _ExpandItemName(cfg.ExpandInstanceName, name, "Instance")
640 cf26a87a Iustin Pop
641 cf26a87a Iustin Pop
642 ecb215b5 Michael Hanselmann
def _BuildInstanceHookEnv(name, primary_node, secondary_nodes, os_type, status,
643 67fc3042 Iustin Pop
                          memory, vcpus, nics, disk_template, disks,
644 7c4d6c7b Michael Hanselmann
                          bep, hvp, hypervisor_name):
645 e4376078 Iustin Pop
  """Builds instance related env variables for hooks
646 e4376078 Iustin Pop

647 e4376078 Iustin Pop
  This builds the hook environment from individual variables.
648 e4376078 Iustin Pop

649 e4376078 Iustin Pop
  @type name: string
650 e4376078 Iustin Pop
  @param name: the name of the instance
651 e4376078 Iustin Pop
  @type primary_node: string
652 e4376078 Iustin Pop
  @param primary_node: the name of the instance's primary node
653 e4376078 Iustin Pop
  @type secondary_nodes: list
654 e4376078 Iustin Pop
  @param secondary_nodes: list of secondary nodes as strings
655 e4376078 Iustin Pop
  @type os_type: string
656 e4376078 Iustin Pop
  @param os_type: the name of the instance's OS
657 0d68c45d Iustin Pop
  @type status: boolean
658 0d68c45d Iustin Pop
  @param status: the should_run status of the instance
659 e4376078 Iustin Pop
  @type memory: string
660 e4376078 Iustin Pop
  @param memory: the memory size of the instance
661 e4376078 Iustin Pop
  @type vcpus: string
662 e4376078 Iustin Pop
  @param vcpus: the count of VCPUs the instance has
663 e4376078 Iustin Pop
  @type nics: list
664 5e3d3eb3 Guido Trotter
  @param nics: list of tuples (ip, mac, mode, link) representing
665 5e3d3eb3 Guido Trotter
      the NICs the instance has
666 2c2690c9 Iustin Pop
  @type disk_template: string
667 5bbd3f7f Michael Hanselmann
  @param disk_template: the disk template of the instance
668 2c2690c9 Iustin Pop
  @type disks: list
669 2c2690c9 Iustin Pop
  @param disks: the list of (size, mode) pairs
670 67fc3042 Iustin Pop
  @type bep: dict
671 67fc3042 Iustin Pop
  @param bep: the backend parameters for the instance
672 67fc3042 Iustin Pop
  @type hvp: dict
673 67fc3042 Iustin Pop
  @param hvp: the hypervisor parameters for the instance
674 7c4d6c7b Michael Hanselmann
  @type hypervisor_name: string
675 7c4d6c7b Michael Hanselmann
  @param hypervisor_name: the hypervisor for the instance
676 e4376078 Iustin Pop
  @rtype: dict
677 e4376078 Iustin Pop
  @return: the hook environment for this instance
678 ecb215b5 Michael Hanselmann

679 396e1b78 Michael Hanselmann
  """
680 0d68c45d Iustin Pop
  if status:
681 0d68c45d Iustin Pop
    str_status = "up"
682 0d68c45d Iustin Pop
  else:
683 0d68c45d Iustin Pop
    str_status = "down"
684 396e1b78 Michael Hanselmann
  env = {
685 0e137c28 Iustin Pop
    "OP_TARGET": name,
686 396e1b78 Michael Hanselmann
    "INSTANCE_NAME": name,
687 396e1b78 Michael Hanselmann
    "INSTANCE_PRIMARY": primary_node,
688 396e1b78 Michael Hanselmann
    "INSTANCE_SECONDARIES": " ".join(secondary_nodes),
689 ecb215b5 Michael Hanselmann
    "INSTANCE_OS_TYPE": os_type,
690 0d68c45d Iustin Pop
    "INSTANCE_STATUS": str_status,
691 396e1b78 Michael Hanselmann
    "INSTANCE_MEMORY": memory,
692 396e1b78 Michael Hanselmann
    "INSTANCE_VCPUS": vcpus,
693 2c2690c9 Iustin Pop
    "INSTANCE_DISK_TEMPLATE": disk_template,
694 7c4d6c7b Michael Hanselmann
    "INSTANCE_HYPERVISOR": hypervisor_name,
695 396e1b78 Michael Hanselmann
  }
696 396e1b78 Michael Hanselmann
697 396e1b78 Michael Hanselmann
  if nics:
698 396e1b78 Michael Hanselmann
    nic_count = len(nics)
699 62f0dd02 Guido Trotter
    for idx, (ip, mac, mode, link) in enumerate(nics):
700 396e1b78 Michael Hanselmann
      if ip is None:
701 396e1b78 Michael Hanselmann
        ip = ""
702 396e1b78 Michael Hanselmann
      env["INSTANCE_NIC%d_IP" % idx] = ip
703 2c2690c9 Iustin Pop
      env["INSTANCE_NIC%d_MAC" % idx] = mac
704 62f0dd02 Guido Trotter
      env["INSTANCE_NIC%d_MODE" % idx] = mode
705 62f0dd02 Guido Trotter
      env["INSTANCE_NIC%d_LINK" % idx] = link
706 62f0dd02 Guido Trotter
      if mode == constants.NIC_MODE_BRIDGED:
707 62f0dd02 Guido Trotter
        env["INSTANCE_NIC%d_BRIDGE" % idx] = link
708 396e1b78 Michael Hanselmann
  else:
709 396e1b78 Michael Hanselmann
    nic_count = 0
710 396e1b78 Michael Hanselmann
711 396e1b78 Michael Hanselmann
  env["INSTANCE_NIC_COUNT"] = nic_count
712 396e1b78 Michael Hanselmann
713 2c2690c9 Iustin Pop
  if disks:
714 2c2690c9 Iustin Pop
    disk_count = len(disks)
715 2c2690c9 Iustin Pop
    for idx, (size, mode) in enumerate(disks):
716 2c2690c9 Iustin Pop
      env["INSTANCE_DISK%d_SIZE" % idx] = size
717 2c2690c9 Iustin Pop
      env["INSTANCE_DISK%d_MODE" % idx] = mode
718 2c2690c9 Iustin Pop
  else:
719 2c2690c9 Iustin Pop
    disk_count = 0
720 2c2690c9 Iustin Pop
721 2c2690c9 Iustin Pop
  env["INSTANCE_DISK_COUNT"] = disk_count
722 2c2690c9 Iustin Pop
723 67fc3042 Iustin Pop
  for source, kind in [(bep, "BE"), (hvp, "HV")]:
724 67fc3042 Iustin Pop
    for key, value in source.items():
725 67fc3042 Iustin Pop
      env["INSTANCE_%s_%s" % (kind, key)] = value
726 67fc3042 Iustin Pop
727 396e1b78 Michael Hanselmann
  return env
728 396e1b78 Michael Hanselmann
729 96acbc09 Michael Hanselmann
730 f9b10246 Guido Trotter
def _NICListToTuple(lu, nics):
731 62f0dd02 Guido Trotter
  """Build a list of nic information tuples.
732 62f0dd02 Guido Trotter

733 f9b10246 Guido Trotter
  This list is suitable to be passed to _BuildInstanceHookEnv or as a return
734 f9b10246 Guido Trotter
  value in LUQueryInstanceData.
735 62f0dd02 Guido Trotter

736 62f0dd02 Guido Trotter
  @type lu:  L{LogicalUnit}
737 62f0dd02 Guido Trotter
  @param lu: the logical unit on whose behalf we execute
738 62f0dd02 Guido Trotter
  @type nics: list of L{objects.NIC}
739 62f0dd02 Guido Trotter
  @param nics: list of nics to convert to hooks tuples
740 62f0dd02 Guido Trotter

741 62f0dd02 Guido Trotter
  """
742 62f0dd02 Guido Trotter
  hooks_nics = []
743 62f0dd02 Guido Trotter
  c_nicparams = lu.cfg.GetClusterInfo().nicparams[constants.PP_DEFAULT]
744 62f0dd02 Guido Trotter
  for nic in nics:
745 62f0dd02 Guido Trotter
    ip = nic.ip
746 62f0dd02 Guido Trotter
    mac = nic.mac
747 62f0dd02 Guido Trotter
    filled_params = objects.FillDict(c_nicparams, nic.nicparams)
748 62f0dd02 Guido Trotter
    mode = filled_params[constants.NIC_MODE]
749 62f0dd02 Guido Trotter
    link = filled_params[constants.NIC_LINK]
750 62f0dd02 Guido Trotter
    hooks_nics.append((ip, mac, mode, link))
751 62f0dd02 Guido Trotter
  return hooks_nics
752 396e1b78 Michael Hanselmann
753 96acbc09 Michael Hanselmann
754 338e51e8 Iustin Pop
def _BuildInstanceHookEnvByObject(lu, instance, override=None):
755 ecb215b5 Michael Hanselmann
  """Builds instance related env variables for hooks from an object.
756 ecb215b5 Michael Hanselmann

757 e4376078 Iustin Pop
  @type lu: L{LogicalUnit}
758 e4376078 Iustin Pop
  @param lu: the logical unit on whose behalf we execute
759 e4376078 Iustin Pop
  @type instance: L{objects.Instance}
760 e4376078 Iustin Pop
  @param instance: the instance for which we should build the
761 e4376078 Iustin Pop
      environment
762 e4376078 Iustin Pop
  @type override: dict
763 e4376078 Iustin Pop
  @param override: dictionary with key/values that will override
764 e4376078 Iustin Pop
      our values
765 e4376078 Iustin Pop
  @rtype: dict
766 e4376078 Iustin Pop
  @return: the hook environment dictionary
767 e4376078 Iustin Pop

768 ecb215b5 Michael Hanselmann
  """
769 67fc3042 Iustin Pop
  cluster = lu.cfg.GetClusterInfo()
770 67fc3042 Iustin Pop
  bep = cluster.FillBE(instance)
771 67fc3042 Iustin Pop
  hvp = cluster.FillHV(instance)
772 396e1b78 Michael Hanselmann
  args = {
773 396e1b78 Michael Hanselmann
    'name': instance.name,
774 396e1b78 Michael Hanselmann
    'primary_node': instance.primary_node,
775 396e1b78 Michael Hanselmann
    'secondary_nodes': instance.secondary_nodes,
776 ecb215b5 Michael Hanselmann
    'os_type': instance.os,
777 0d68c45d Iustin Pop
    'status': instance.admin_up,
778 338e51e8 Iustin Pop
    'memory': bep[constants.BE_MEMORY],
779 338e51e8 Iustin Pop
    'vcpus': bep[constants.BE_VCPUS],
780 f9b10246 Guido Trotter
    'nics': _NICListToTuple(lu, instance.nics),
781 2c2690c9 Iustin Pop
    'disk_template': instance.disk_template,
782 2c2690c9 Iustin Pop
    'disks': [(disk.size, disk.mode) for disk in instance.disks],
783 67fc3042 Iustin Pop
    'bep': bep,
784 67fc3042 Iustin Pop
    'hvp': hvp,
785 b0c63e2b Iustin Pop
    'hypervisor_name': instance.hypervisor,
786 396e1b78 Michael Hanselmann
  }
787 396e1b78 Michael Hanselmann
  if override:
788 396e1b78 Michael Hanselmann
    args.update(override)
789 7260cfbe Iustin Pop
  return _BuildInstanceHookEnv(**args) # pylint: disable-msg=W0142
790 396e1b78 Michael Hanselmann
791 396e1b78 Michael Hanselmann
792 44485f49 Guido Trotter
def _AdjustCandidatePool(lu, exceptions):
793 ec0292f1 Iustin Pop
  """Adjust the candidate pool after node operations.
794 ec0292f1 Iustin Pop

795 ec0292f1 Iustin Pop
  """
796 44485f49 Guido Trotter
  mod_list = lu.cfg.MaintainCandidatePool(exceptions)
797 ec0292f1 Iustin Pop
  if mod_list:
798 ec0292f1 Iustin Pop
    lu.LogInfo("Promoted nodes to master candidate role: %s",
799 1f864b60 Iustin Pop
               utils.CommaJoin(node.name for node in mod_list))
800 ec0292f1 Iustin Pop
    for name in mod_list:
801 ec0292f1 Iustin Pop
      lu.context.ReaddNode(name)
802 44485f49 Guido Trotter
  mc_now, mc_max, _ = lu.cfg.GetMasterCandidateStats(exceptions)
803 ec0292f1 Iustin Pop
  if mc_now > mc_max:
804 ec0292f1 Iustin Pop
    lu.LogInfo("Note: more nodes are candidates (%d) than desired (%d)" %
805 ec0292f1 Iustin Pop
               (mc_now, mc_max))
806 ec0292f1 Iustin Pop
807 ec0292f1 Iustin Pop
808 6d7e1f20 Guido Trotter
def _DecideSelfPromotion(lu, exceptions=None):
809 6d7e1f20 Guido Trotter
  """Decide whether I should promote myself as a master candidate.
810 6d7e1f20 Guido Trotter

811 6d7e1f20 Guido Trotter
  """
812 6d7e1f20 Guido Trotter
  cp_size = lu.cfg.GetClusterInfo().candidate_pool_size
813 6d7e1f20 Guido Trotter
  mc_now, mc_should, _ = lu.cfg.GetMasterCandidateStats(exceptions)
814 6d7e1f20 Guido Trotter
  # the new node will increase mc_max with one, so:
815 6d7e1f20 Guido Trotter
  mc_should = min(mc_should + 1, cp_size)
816 6d7e1f20 Guido Trotter
  return mc_now < mc_should
817 6d7e1f20 Guido Trotter
818 6d7e1f20 Guido Trotter
819 b165e77e Guido Trotter
def _CheckNicsBridgesExist(lu, target_nics, target_node,
820 b165e77e Guido Trotter
                               profile=constants.PP_DEFAULT):
821 b165e77e Guido Trotter
  """Check that the brigdes needed by a list of nics exist.
822 b165e77e Guido Trotter

823 b165e77e Guido Trotter
  """
824 b165e77e Guido Trotter
  c_nicparams = lu.cfg.GetClusterInfo().nicparams[profile]
825 b165e77e Guido Trotter
  paramslist = [objects.FillDict(c_nicparams, nic.nicparams)
826 b165e77e Guido Trotter
                for nic in target_nics]
827 b165e77e Guido Trotter
  brlist = [params[constants.NIC_LINK] for params in paramslist
828 b165e77e Guido Trotter
            if params[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED]
829 b165e77e Guido Trotter
  if brlist:
830 b165e77e Guido Trotter
    result = lu.rpc.call_bridges_exist(target_node, brlist)
831 4c4e4e1e Iustin Pop
    result.Raise("Error checking bridges on destination node '%s'" %
832 045dd6d9 Iustin Pop
                 target_node, prereq=True, ecode=errors.ECODE_ENVIRON)
833 b165e77e Guido Trotter
834 b165e77e Guido Trotter
835 b165e77e Guido Trotter
def _CheckInstanceBridgesExist(lu, instance, node=None):
836 bf6929a2 Alexander Schreiber
  """Check that the brigdes needed by an instance exist.
837 bf6929a2 Alexander Schreiber

838 bf6929a2 Alexander Schreiber
  """
839 b165e77e Guido Trotter
  if node is None:
840 29921401 Iustin Pop
    node = instance.primary_node
841 b165e77e Guido Trotter
  _CheckNicsBridgesExist(lu, instance.nics, node)
842 bf6929a2 Alexander Schreiber
843 bf6929a2 Alexander Schreiber
844 c6f1af07 Iustin Pop
def _CheckOSVariant(os_obj, name):
845 f2c05717 Guido Trotter
  """Check whether an OS name conforms to the os variants specification.
846 f2c05717 Guido Trotter

847 c6f1af07 Iustin Pop
  @type os_obj: L{objects.OS}
848 c6f1af07 Iustin Pop
  @param os_obj: OS object to check
849 f2c05717 Guido Trotter
  @type name: string
850 f2c05717 Guido Trotter
  @param name: OS name passed by the user, to check for validity
851 f2c05717 Guido Trotter

852 f2c05717 Guido Trotter
  """
853 c6f1af07 Iustin Pop
  if not os_obj.supported_variants:
854 f2c05717 Guido Trotter
    return
855 f2c05717 Guido Trotter
  try:
856 f2c05717 Guido Trotter
    variant = name.split("+", 1)[1]
857 f2c05717 Guido Trotter
  except IndexError:
858 5c983ee5 Iustin Pop
    raise errors.OpPrereqError("OS name must include a variant",
859 5c983ee5 Iustin Pop
                               errors.ECODE_INVAL)
860 f2c05717 Guido Trotter
861 c6f1af07 Iustin Pop
  if variant not in os_obj.supported_variants:
862 5c983ee5 Iustin Pop
    raise errors.OpPrereqError("Unsupported OS variant", errors.ECODE_INVAL)
863 f2c05717 Guido Trotter
864 f2c05717 Guido Trotter
865 5ba9701d Michael Hanselmann
def _GetNodeInstancesInner(cfg, fn):
866 5ba9701d Michael Hanselmann
  return [i for i in cfg.GetAllInstancesInfo().values() if fn(i)]
867 5ba9701d Michael Hanselmann
868 5ba9701d Michael Hanselmann
869 e9721add Michael Hanselmann
def _GetNodeInstances(cfg, node_name):
870 e9721add Michael Hanselmann
  """Returns a list of all primary and secondary instances on a node.
871 e9721add Michael Hanselmann

872 e9721add Michael Hanselmann
  """
873 e9721add Michael Hanselmann
874 e9721add Michael Hanselmann
  return _GetNodeInstancesInner(cfg, lambda inst: node_name in inst.all_nodes)
875 e9721add Michael Hanselmann
876 e9721add Michael Hanselmann
877 80cb875c Michael Hanselmann
def _GetNodePrimaryInstances(cfg, node_name):
878 80cb875c Michael Hanselmann
  """Returns primary instances on a node.
879 80cb875c Michael Hanselmann

880 80cb875c Michael Hanselmann
  """
881 5ba9701d Michael Hanselmann
  return _GetNodeInstancesInner(cfg,
882 5ba9701d Michael Hanselmann
                                lambda inst: node_name == inst.primary_node)
883 80cb875c Michael Hanselmann
884 80cb875c Michael Hanselmann
885 692738fc Michael Hanselmann
def _GetNodeSecondaryInstances(cfg, node_name):
886 692738fc Michael Hanselmann
  """Returns secondary instances on a node.
887 692738fc Michael Hanselmann

888 692738fc Michael Hanselmann
  """
889 5ba9701d Michael Hanselmann
  return _GetNodeInstancesInner(cfg,
890 5ba9701d Michael Hanselmann
                                lambda inst: node_name in inst.secondary_nodes)
891 692738fc Michael Hanselmann
892 692738fc Michael Hanselmann
893 efb8da02 Michael Hanselmann
def _GetStorageTypeArgs(cfg, storage_type):
894 efb8da02 Michael Hanselmann
  """Returns the arguments for a storage type.
895 efb8da02 Michael Hanselmann

896 efb8da02 Michael Hanselmann
  """
897 efb8da02 Michael Hanselmann
  # Special case for file storage
898 efb8da02 Michael Hanselmann
  if storage_type == constants.ST_FILE:
899 a4d138b7 Michael Hanselmann
    # storage.FileStorage wants a list of storage directories
900 a4d138b7 Michael Hanselmann
    return [[cfg.GetFileStorageDir()]]
901 efb8da02 Michael Hanselmann
902 efb8da02 Michael Hanselmann
  return []
903 efb8da02 Michael Hanselmann
904 efb8da02 Michael Hanselmann
905 2d9005d8 Michael Hanselmann
def _FindFaultyInstanceDisks(cfg, rpc, instance, node_name, prereq):
906 2d9005d8 Michael Hanselmann
  faulty = []
907 2d9005d8 Michael Hanselmann
908 2d9005d8 Michael Hanselmann
  for dev in instance.disks:
909 2d9005d8 Michael Hanselmann
    cfg.SetDiskID(dev, node_name)
910 2d9005d8 Michael Hanselmann
911 2d9005d8 Michael Hanselmann
  result = rpc.call_blockdev_getmirrorstatus(node_name, instance.disks)
912 2d9005d8 Michael Hanselmann
  result.Raise("Failed to get disk status from node %s" % node_name,
913 045dd6d9 Iustin Pop
               prereq=prereq, ecode=errors.ECODE_ENVIRON)
914 2d9005d8 Michael Hanselmann
915 2d9005d8 Michael Hanselmann
  for idx, bdev_status in enumerate(result.payload):
916 2d9005d8 Michael Hanselmann
    if bdev_status and bdev_status.ldisk_status == constants.LDS_FAULTY:
917 2d9005d8 Michael Hanselmann
      faulty.append(idx)
918 2d9005d8 Michael Hanselmann
919 2d9005d8 Michael Hanselmann
  return faulty
920 2d9005d8 Michael Hanselmann
921 2d9005d8 Michael Hanselmann
922 b98bf262 Michael Hanselmann
def _FormatTimestamp(secs):
923 b98bf262 Michael Hanselmann
  """Formats a Unix timestamp with the local timezone.
924 b98bf262 Michael Hanselmann

925 b98bf262 Michael Hanselmann
  """
926 b98bf262 Michael Hanselmann
  return time.strftime("%F %T %Z", time.gmtime(secs))
927 b98bf262 Michael Hanselmann
928 b98bf262 Michael Hanselmann
929 b5f5fae9 Luca Bigliardi
class LUPostInitCluster(LogicalUnit):
930 b5f5fae9 Luca Bigliardi
  """Logical unit for running hooks after cluster initialization.
931 b5f5fae9 Luca Bigliardi

932 b5f5fae9 Luca Bigliardi
  """
933 b5f5fae9 Luca Bigliardi
  HPATH = "cluster-init"
934 b5f5fae9 Luca Bigliardi
  HTYPE = constants.HTYPE_CLUSTER
935 b5f5fae9 Luca Bigliardi
  _OP_REQP = []
936 b5f5fae9 Luca Bigliardi
937 b5f5fae9 Luca Bigliardi
  def BuildHooksEnv(self):
938 b5f5fae9 Luca Bigliardi
    """Build hooks env.
939 b5f5fae9 Luca Bigliardi

940 b5f5fae9 Luca Bigliardi
    """
941 b5f5fae9 Luca Bigliardi
    env = {"OP_TARGET": self.cfg.GetClusterName()}
942 b5f5fae9 Luca Bigliardi
    mn = self.cfg.GetMasterNode()
943 b5f5fae9 Luca Bigliardi
    return env, [], [mn]
944 b5f5fae9 Luca Bigliardi
945 b5f5fae9 Luca Bigliardi
  def CheckPrereq(self):
946 b5f5fae9 Luca Bigliardi
    """No prerequisites to check.
947 b5f5fae9 Luca Bigliardi

948 b5f5fae9 Luca Bigliardi
    """
949 b5f5fae9 Luca Bigliardi
    return True
950 b5f5fae9 Luca Bigliardi
951 b5f5fae9 Luca Bigliardi
  def Exec(self, feedback_fn):
952 b5f5fae9 Luca Bigliardi
    """Nothing to do.
953 b5f5fae9 Luca Bigliardi

954 b5f5fae9 Luca Bigliardi
    """
955 b5f5fae9 Luca Bigliardi
    return True
956 b5f5fae9 Luca Bigliardi
957 b5f5fae9 Luca Bigliardi
958 b2c750a4 Luca Bigliardi
class LUDestroyCluster(LogicalUnit):
959 a8083063 Iustin Pop
  """Logical unit for destroying the cluster.
960 a8083063 Iustin Pop

961 a8083063 Iustin Pop
  """
962 b2c750a4 Luca Bigliardi
  HPATH = "cluster-destroy"
963 b2c750a4 Luca Bigliardi
  HTYPE = constants.HTYPE_CLUSTER
964 a8083063 Iustin Pop
  _OP_REQP = []
965 a8083063 Iustin Pop
966 b2c750a4 Luca Bigliardi
  def BuildHooksEnv(self):
967 b2c750a4 Luca Bigliardi
    """Build hooks env.
968 b2c750a4 Luca Bigliardi

969 b2c750a4 Luca Bigliardi
    """
970 b2c750a4 Luca Bigliardi
    env = {"OP_TARGET": self.cfg.GetClusterName()}
971 b2c750a4 Luca Bigliardi
    return env, [], []
972 b2c750a4 Luca Bigliardi
973 a8083063 Iustin Pop
  def CheckPrereq(self):
974 a8083063 Iustin Pop
    """Check prerequisites.
975 a8083063 Iustin Pop

976 a8083063 Iustin Pop
    This checks whether the cluster is empty.
977 a8083063 Iustin Pop

978 5bbd3f7f Michael Hanselmann
    Any errors are signaled by raising errors.OpPrereqError.
979 a8083063 Iustin Pop

980 a8083063 Iustin Pop
    """
981 d6a02168 Michael Hanselmann
    master = self.cfg.GetMasterNode()
982 a8083063 Iustin Pop
983 a8083063 Iustin Pop
    nodelist = self.cfg.GetNodeList()
984 db915bd1 Michael Hanselmann
    if len(nodelist) != 1 or nodelist[0] != master:
985 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("There are still %d node(s) in"
986 5c983ee5 Iustin Pop
                                 " this cluster." % (len(nodelist) - 1),
987 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
988 db915bd1 Michael Hanselmann
    instancelist = self.cfg.GetInstanceList()
989 db915bd1 Michael Hanselmann
    if instancelist:
990 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("There are still %d instance(s) in"
991 5c983ee5 Iustin Pop
                                 " this cluster." % len(instancelist),
992 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
993 a8083063 Iustin Pop
994 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
995 a8083063 Iustin Pop
    """Destroys the cluster.
996 a8083063 Iustin Pop

997 a8083063 Iustin Pop
    """
998 d6a02168 Michael Hanselmann
    master = self.cfg.GetMasterNode()
999 b989b9d9 Ken Wehr
    modify_ssh_setup = self.cfg.GetClusterInfo().modify_ssh_setup
1000 3141ad3b Luca Bigliardi
1001 3141ad3b Luca Bigliardi
    # Run post hooks on master node before it's removed
1002 3141ad3b Luca Bigliardi
    hm = self.proc.hmclass(self.rpc.call_hooks_runner, self)
1003 3141ad3b Luca Bigliardi
    try:
1004 3141ad3b Luca Bigliardi
      hm.RunPhase(constants.HOOKS_PHASE_POST, [master])
1005 3141ad3b Luca Bigliardi
    except:
1006 7260cfbe Iustin Pop
      # pylint: disable-msg=W0702
1007 3141ad3b Luca Bigliardi
      self.LogWarning("Errors occurred running hooks on %s" % master)
1008 3141ad3b Luca Bigliardi
1009 781de953 Iustin Pop
    result = self.rpc.call_node_stop_master(master, False)
1010 4c4e4e1e Iustin Pop
    result.Raise("Could not disable the master role")
1011 b989b9d9 Ken Wehr
1012 b989b9d9 Ken Wehr
    if modify_ssh_setup:
1013 b989b9d9 Ken Wehr
      priv_key, pub_key, _ = ssh.GetUserFiles(constants.GANETI_RUNAS)
1014 b989b9d9 Ken Wehr
      utils.CreateBackup(priv_key)
1015 b989b9d9 Ken Wehr
      utils.CreateBackup(pub_key)
1016 b989b9d9 Ken Wehr
1017 140aa4a8 Iustin Pop
    return master
1018 a8083063 Iustin Pop
1019 a8083063 Iustin Pop
1020 b98bf262 Michael Hanselmann
def _VerifyCertificateInner(filename, expired, not_before, not_after, now,
1021 b98bf262 Michael Hanselmann
                            warn_days=constants.SSL_CERT_EXPIRATION_WARN,
1022 b98bf262 Michael Hanselmann
                            error_days=constants.SSL_CERT_EXPIRATION_ERROR):
1023 b98bf262 Michael Hanselmann
  """Verifies certificate details for LUVerifyCluster.
1024 b98bf262 Michael Hanselmann

1025 b98bf262 Michael Hanselmann
  """
1026 b98bf262 Michael Hanselmann
  if expired:
1027 b98bf262 Michael Hanselmann
    msg = "Certificate %s is expired" % filename
1028 b98bf262 Michael Hanselmann
1029 b98bf262 Michael Hanselmann
    if not_before is not None and not_after is not None:
1030 b98bf262 Michael Hanselmann
      msg += (" (valid from %s to %s)" %
1031 b98bf262 Michael Hanselmann
              (_FormatTimestamp(not_before),
1032 b98bf262 Michael Hanselmann
               _FormatTimestamp(not_after)))
1033 b98bf262 Michael Hanselmann
    elif not_before is not None:
1034 b98bf262 Michael Hanselmann
      msg += " (valid from %s)" % _FormatTimestamp(not_before)
1035 b98bf262 Michael Hanselmann
    elif not_after is not None:
1036 b98bf262 Michael Hanselmann
      msg += " (valid until %s)" % _FormatTimestamp(not_after)
1037 b98bf262 Michael Hanselmann
1038 b98bf262 Michael Hanselmann
    return (LUVerifyCluster.ETYPE_ERROR, msg)
1039 b98bf262 Michael Hanselmann
1040 b98bf262 Michael Hanselmann
  elif not_before is not None and not_before > now:
1041 b98bf262 Michael Hanselmann
    return (LUVerifyCluster.ETYPE_WARNING,
1042 b98bf262 Michael Hanselmann
            "Certificate %s not yet valid (valid from %s)" %
1043 b98bf262 Michael Hanselmann
            (filename, _FormatTimestamp(not_before)))
1044 b98bf262 Michael Hanselmann
1045 b98bf262 Michael Hanselmann
  elif not_after is not None:
1046 b98bf262 Michael Hanselmann
    remaining_days = int((not_after - now) / (24 * 3600))
1047 b98bf262 Michael Hanselmann
1048 b98bf262 Michael Hanselmann
    msg = ("Certificate %s expires in %d days" % (filename, remaining_days))
1049 b98bf262 Michael Hanselmann
1050 b98bf262 Michael Hanselmann
    if remaining_days <= error_days:
1051 b98bf262 Michael Hanselmann
      return (LUVerifyCluster.ETYPE_ERROR, msg)
1052 b98bf262 Michael Hanselmann
1053 b98bf262 Michael Hanselmann
    if remaining_days <= warn_days:
1054 b98bf262 Michael Hanselmann
      return (LUVerifyCluster.ETYPE_WARNING, msg)
1055 b98bf262 Michael Hanselmann
1056 b98bf262 Michael Hanselmann
  return (None, None)
1057 b98bf262 Michael Hanselmann
1058 b98bf262 Michael Hanselmann
1059 b98bf262 Michael Hanselmann
def _VerifyCertificate(filename):
1060 b98bf262 Michael Hanselmann
  """Verifies a certificate for LUVerifyCluster.
1061 b98bf262 Michael Hanselmann

1062 b98bf262 Michael Hanselmann
  @type filename: string
1063 b98bf262 Michael Hanselmann
  @param filename: Path to PEM file
1064 b98bf262 Michael Hanselmann

1065 b98bf262 Michael Hanselmann
  """
1066 b98bf262 Michael Hanselmann
  try:
1067 b98bf262 Michael Hanselmann
    cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
1068 b98bf262 Michael Hanselmann
                                           utils.ReadFile(filename))
1069 b98bf262 Michael Hanselmann
  except Exception, err: # pylint: disable-msg=W0703
1070 b98bf262 Michael Hanselmann
    return (LUVerifyCluster.ETYPE_ERROR,
1071 b98bf262 Michael Hanselmann
            "Failed to load X509 certificate %s: %s" % (filename, err))
1072 b98bf262 Michael Hanselmann
1073 b98bf262 Michael Hanselmann
  # Depending on the pyOpenSSL version, this can just return (None, None)
1074 b98bf262 Michael Hanselmann
  (not_before, not_after) = utils.GetX509CertValidity(cert)
1075 b98bf262 Michael Hanselmann
1076 b98bf262 Michael Hanselmann
  return _VerifyCertificateInner(filename, cert.has_expired(),
1077 b98bf262 Michael Hanselmann
                                 not_before, not_after, time.time())
1078 b98bf262 Michael Hanselmann
1079 b98bf262 Michael Hanselmann
1080 d8fff41c Guido Trotter
class LUVerifyCluster(LogicalUnit):
1081 a8083063 Iustin Pop
  """Verifies the cluster status.
1082 a8083063 Iustin Pop

1083 a8083063 Iustin Pop
  """
1084 d8fff41c Guido Trotter
  HPATH = "cluster-verify"
1085 d8fff41c Guido Trotter
  HTYPE = constants.HTYPE_CLUSTER
1086 a0c9776a Iustin Pop
  _OP_REQP = ["skip_checks", "verbose", "error_codes", "debug_simulate_errors"]
1087 d4b9d97f Guido Trotter
  REQ_BGL = False
1088 d4b9d97f Guido Trotter
1089 7c874ee1 Iustin Pop
  TCLUSTER = "cluster"
1090 7c874ee1 Iustin Pop
  TNODE = "node"
1091 7c874ee1 Iustin Pop
  TINSTANCE = "instance"
1092 7c874ee1 Iustin Pop
1093 7c874ee1 Iustin Pop
  ECLUSTERCFG = (TCLUSTER, "ECLUSTERCFG")
1094 b98bf262 Michael Hanselmann
  ECLUSTERCERT = (TCLUSTER, "ECLUSTERCERT")
1095 7c874ee1 Iustin Pop
  EINSTANCEBADNODE = (TINSTANCE, "EINSTANCEBADNODE")
1096 7c874ee1 Iustin Pop
  EINSTANCEDOWN = (TINSTANCE, "EINSTANCEDOWN")
1097 7c874ee1 Iustin Pop
  EINSTANCELAYOUT = (TINSTANCE, "EINSTANCELAYOUT")
1098 7c874ee1 Iustin Pop
  EINSTANCEMISSINGDISK = (TINSTANCE, "EINSTANCEMISSINGDISK")
1099 7c874ee1 Iustin Pop
  EINSTANCEMISSINGDISK = (TINSTANCE, "EINSTANCEMISSINGDISK")
1100 7c874ee1 Iustin Pop
  EINSTANCEWRONGNODE = (TINSTANCE, "EINSTANCEWRONGNODE")
1101 7c874ee1 Iustin Pop
  ENODEDRBD = (TNODE, "ENODEDRBD")
1102 7c874ee1 Iustin Pop
  ENODEFILECHECK = (TNODE, "ENODEFILECHECK")
1103 7c874ee1 Iustin Pop
  ENODEHOOKS = (TNODE, "ENODEHOOKS")
1104 7c874ee1 Iustin Pop
  ENODEHV = (TNODE, "ENODEHV")
1105 7c874ee1 Iustin Pop
  ENODELVM = (TNODE, "ENODELVM")
1106 7c874ee1 Iustin Pop
  ENODEN1 = (TNODE, "ENODEN1")
1107 7c874ee1 Iustin Pop
  ENODENET = (TNODE, "ENODENET")
1108 7c874ee1 Iustin Pop
  ENODEORPHANINSTANCE = (TNODE, "ENODEORPHANINSTANCE")
1109 7c874ee1 Iustin Pop
  ENODEORPHANLV = (TNODE, "ENODEORPHANLV")
1110 7c874ee1 Iustin Pop
  ENODERPC = (TNODE, "ENODERPC")
1111 7c874ee1 Iustin Pop
  ENODESSH = (TNODE, "ENODESSH")
1112 7c874ee1 Iustin Pop
  ENODEVERSION = (TNODE, "ENODEVERSION")
1113 7c0aa8e9 Iustin Pop
  ENODESETUP = (TNODE, "ENODESETUP")
1114 313b2dd4 Michael Hanselmann
  ENODETIME = (TNODE, "ENODETIME")
1115 7c874ee1 Iustin Pop
1116 a0c9776a Iustin Pop
  ETYPE_FIELD = "code"
1117 a0c9776a Iustin Pop
  ETYPE_ERROR = "ERROR"
1118 a0c9776a Iustin Pop
  ETYPE_WARNING = "WARNING"
1119 a0c9776a Iustin Pop
1120 02c521e4 Iustin Pop
  class NodeImage(object):
1121 02c521e4 Iustin Pop
    """A class representing the logical and physical status of a node.
1122 02c521e4 Iustin Pop

1123 02c521e4 Iustin Pop
    @ivar volumes: a structure as returned from
1124 3a488770 Iustin Pop
        L{ganeti.backend.GetVolumeList} (runtime)
1125 02c521e4 Iustin Pop
    @ivar instances: a list of running instances (runtime)
1126 02c521e4 Iustin Pop
    @ivar pinst: list of configured primary instances (config)
1127 02c521e4 Iustin Pop
    @ivar sinst: list of configured secondary instances (config)
1128 02c521e4 Iustin Pop
    @ivar sbp: diction of {secondary-node: list of instances} of all peers
1129 02c521e4 Iustin Pop
        of this node (config)
1130 02c521e4 Iustin Pop
    @ivar mfree: free memory, as reported by hypervisor (runtime)
1131 02c521e4 Iustin Pop
    @ivar dfree: free disk, as reported by the node (runtime)
1132 02c521e4 Iustin Pop
    @ivar offline: the offline status (config)
1133 02c521e4 Iustin Pop
    @type rpc_fail: boolean
1134 02c521e4 Iustin Pop
    @ivar rpc_fail: whether the RPC verify call was successfull (overall,
1135 02c521e4 Iustin Pop
        not whether the individual keys were correct) (runtime)
1136 02c521e4 Iustin Pop
    @type lvm_fail: boolean
1137 02c521e4 Iustin Pop
    @ivar lvm_fail: whether the RPC call didn't return valid LVM data
1138 02c521e4 Iustin Pop
    @type hyp_fail: boolean
1139 02c521e4 Iustin Pop
    @ivar hyp_fail: whether the RPC call didn't return the instance list
1140 02c521e4 Iustin Pop
    @type ghost: boolean
1141 02c521e4 Iustin Pop
    @ivar ghost: whether this is a known node or not (config)
1142 02c521e4 Iustin Pop

1143 02c521e4 Iustin Pop
    """
1144 02c521e4 Iustin Pop
    def __init__(self, offline=False):
1145 02c521e4 Iustin Pop
      self.volumes = {}
1146 02c521e4 Iustin Pop
      self.instances = []
1147 02c521e4 Iustin Pop
      self.pinst = []
1148 02c521e4 Iustin Pop
      self.sinst = []
1149 02c521e4 Iustin Pop
      self.sbp = {}
1150 02c521e4 Iustin Pop
      self.mfree = 0
1151 02c521e4 Iustin Pop
      self.dfree = 0
1152 02c521e4 Iustin Pop
      self.offline = offline
1153 02c521e4 Iustin Pop
      self.rpc_fail = False
1154 02c521e4 Iustin Pop
      self.lvm_fail = False
1155 02c521e4 Iustin Pop
      self.hyp_fail = False
1156 02c521e4 Iustin Pop
      self.ghost = False
1157 02c521e4 Iustin Pop
1158 d4b9d97f Guido Trotter
  def ExpandNames(self):
1159 d4b9d97f Guido Trotter
    self.needed_locks = {
1160 d4b9d97f Guido Trotter
      locking.LEVEL_NODE: locking.ALL_SET,
1161 d4b9d97f Guido Trotter
      locking.LEVEL_INSTANCE: locking.ALL_SET,
1162 d4b9d97f Guido Trotter
    }
1163 c772d142 Michael Hanselmann
    self.share_locks = dict.fromkeys(locking.LEVELS, 1)
1164 a8083063 Iustin Pop
1165 7c874ee1 Iustin Pop
  def _Error(self, ecode, item, msg, *args, **kwargs):
1166 7c874ee1 Iustin Pop
    """Format an error message.
1167 7c874ee1 Iustin Pop

1168 7c874ee1 Iustin Pop
    Based on the opcode's error_codes parameter, either format a
1169 7c874ee1 Iustin Pop
    parseable error code, or a simpler error string.
1170 7c874ee1 Iustin Pop

1171 7c874ee1 Iustin Pop
    This must be called only from Exec and functions called from Exec.
1172 7c874ee1 Iustin Pop

1173 7c874ee1 Iustin Pop
    """
1174 a0c9776a Iustin Pop
    ltype = kwargs.get(self.ETYPE_FIELD, self.ETYPE_ERROR)
1175 7c874ee1 Iustin Pop
    itype, etxt = ecode
1176 7c874ee1 Iustin Pop
    # first complete the msg
1177 7c874ee1 Iustin Pop
    if args:
1178 7c874ee1 Iustin Pop
      msg = msg % args
1179 7c874ee1 Iustin Pop
    # then format the whole message
1180 7c874ee1 Iustin Pop
    if self.op.error_codes:
1181 7c874ee1 Iustin Pop
      msg = "%s:%s:%s:%s:%s" % (ltype, etxt, itype, item, msg)
1182 7c874ee1 Iustin Pop
    else:
1183 7c874ee1 Iustin Pop
      if item:
1184 7c874ee1 Iustin Pop
        item = " " + item
1185 7c874ee1 Iustin Pop
      else:
1186 7c874ee1 Iustin Pop
        item = ""
1187 7c874ee1 Iustin Pop
      msg = "%s: %s%s: %s" % (ltype, itype, item, msg)
1188 7c874ee1 Iustin Pop
    # and finally report it via the feedback_fn
1189 7c874ee1 Iustin Pop
    self._feedback_fn("  - %s" % msg)
1190 7c874ee1 Iustin Pop
1191 a0c9776a Iustin Pop
  def _ErrorIf(self, cond, *args, **kwargs):
1192 a0c9776a Iustin Pop
    """Log an error message if the passed condition is True.
1193 a0c9776a Iustin Pop

1194 a0c9776a Iustin Pop
    """
1195 a0c9776a Iustin Pop
    cond = bool(cond) or self.op.debug_simulate_errors
1196 a0c9776a Iustin Pop
    if cond:
1197 a0c9776a Iustin Pop
      self._Error(*args, **kwargs)
1198 a0c9776a Iustin Pop
    # do not mark the operation as failed for WARN cases only
1199 a0c9776a Iustin Pop
    if kwargs.get(self.ETYPE_FIELD, self.ETYPE_ERROR) == self.ETYPE_ERROR:
1200 a0c9776a Iustin Pop
      self.bad = self.bad or cond
1201 a0c9776a Iustin Pop
1202 02c521e4 Iustin Pop
  def _VerifyNode(self, ninfo, nresult):
1203 a8083063 Iustin Pop
    """Run multiple tests against a node.
1204 a8083063 Iustin Pop

1205 112f18a5 Iustin Pop
    Test list:
1206 e4376078 Iustin Pop

1207 a8083063 Iustin Pop
      - compares ganeti version
1208 5bbd3f7f Michael Hanselmann
      - checks vg existence and size > 20G
1209 a8083063 Iustin Pop
      - checks config file checksum
1210 a8083063 Iustin Pop
      - checks ssh to other nodes
1211 a8083063 Iustin Pop

1212 02c521e4 Iustin Pop
    @type ninfo: L{objects.Node}
1213 02c521e4 Iustin Pop
    @param ninfo: the node to check
1214 02c521e4 Iustin Pop
    @param nresult: the results from the node
1215 02c521e4 Iustin Pop
    @rtype: boolean
1216 02c521e4 Iustin Pop
    @return: whether overall this call was successful (and we can expect
1217 02c521e4 Iustin Pop
         reasonable values in the respose)
1218 098c0958 Michael Hanselmann

1219 a8083063 Iustin Pop
    """
1220 02c521e4 Iustin Pop
    node = ninfo.name
1221 7260cfbe Iustin Pop
    _ErrorIf = self._ErrorIf # pylint: disable-msg=C0103
1222 25361b9a Iustin Pop
1223 02c521e4 Iustin Pop
    # main result, nresult should be a non-empty dict
1224 02c521e4 Iustin Pop
    test = not nresult or not isinstance(nresult, dict)
1225 a0c9776a Iustin Pop
    _ErrorIf(test, self.ENODERPC, node,
1226 7c874ee1 Iustin Pop
                  "unable to verify node: no data returned")
1227 a0c9776a Iustin Pop
    if test:
1228 02c521e4 Iustin Pop
      return False
1229 25361b9a Iustin Pop
1230 a8083063 Iustin Pop
    # compares ganeti version
1231 a8083063 Iustin Pop
    local_version = constants.PROTOCOL_VERSION
1232 02c521e4 Iustin Pop
    remote_version = nresult.get("version", None)
1233 a0c9776a Iustin Pop
    test = not (remote_version and
1234 a0c9776a Iustin Pop
                isinstance(remote_version, (list, tuple)) and
1235 a0c9776a Iustin Pop
                len(remote_version) == 2)
1236 a0c9776a Iustin Pop
    _ErrorIf(test, self.ENODERPC, node,
1237 a0c9776a Iustin Pop
             "connection to node returned invalid data")
1238 a0c9776a Iustin Pop
    if test:
1239 02c521e4 Iustin Pop
      return False
1240 a0c9776a Iustin Pop
1241 a0c9776a Iustin Pop
    test = local_version != remote_version[0]
1242 a0c9776a Iustin Pop
    _ErrorIf(test, self.ENODEVERSION, node,
1243 a0c9776a Iustin Pop
             "incompatible protocol versions: master %s,"
1244 a0c9776a Iustin Pop
             " node %s", local_version, remote_version[0])
1245 a0c9776a Iustin Pop
    if test:
1246 02c521e4 Iustin Pop
      return False
1247 a8083063 Iustin Pop
1248 e9ce0a64 Iustin Pop
    # node seems compatible, we can actually try to look into its results
1249 a8083063 Iustin Pop
1250 e9ce0a64 Iustin Pop
    # full package version
1251 a0c9776a Iustin Pop
    self._ErrorIf(constants.RELEASE_VERSION != remote_version[1],
1252 a0c9776a Iustin Pop
                  self.ENODEVERSION, node,
1253 7c874ee1 Iustin Pop
                  "software version mismatch: master %s, node %s",
1254 7c874ee1 Iustin Pop
                  constants.RELEASE_VERSION, remote_version[1],
1255 a0c9776a Iustin Pop
                  code=self.ETYPE_WARNING)
1256 e9ce0a64 Iustin Pop
1257 02c521e4 Iustin Pop
    hyp_result = nresult.get(constants.NV_HYPERVISOR, None)
1258 02c521e4 Iustin Pop
    if isinstance(hyp_result, dict):
1259 02c521e4 Iustin Pop
      for hv_name, hv_result in hyp_result.iteritems():
1260 02c521e4 Iustin Pop
        test = hv_result is not None
1261 02c521e4 Iustin Pop
        _ErrorIf(test, self.ENODEHV, node,
1262 02c521e4 Iustin Pop
                 "hypervisor %s verify failure: '%s'", hv_name, hv_result)
1263 a8083063 Iustin Pop
1264 a8083063 Iustin Pop
1265 02c521e4 Iustin Pop
    test = nresult.get(constants.NV_NODESETUP,
1266 02c521e4 Iustin Pop
                           ["Missing NODESETUP results"])
1267 02c521e4 Iustin Pop
    _ErrorIf(test, self.ENODESETUP, node, "node setup error: %s",
1268 02c521e4 Iustin Pop
             "; ".join(test))
1269 02c521e4 Iustin Pop
1270 02c521e4 Iustin Pop
    return True
1271 02c521e4 Iustin Pop
1272 02c521e4 Iustin Pop
  def _VerifyNodeTime(self, ninfo, nresult,
1273 02c521e4 Iustin Pop
                      nvinfo_starttime, nvinfo_endtime):
1274 02c521e4 Iustin Pop
    """Check the node time.
1275 02c521e4 Iustin Pop

1276 02c521e4 Iustin Pop
    @type ninfo: L{objects.Node}
1277 02c521e4 Iustin Pop
    @param ninfo: the node to check
1278 02c521e4 Iustin Pop
    @param nresult: the remote results for the node
1279 02c521e4 Iustin Pop
    @param nvinfo_starttime: the start time of the RPC call
1280 02c521e4 Iustin Pop
    @param nvinfo_endtime: the end time of the RPC call
1281 02c521e4 Iustin Pop

1282 02c521e4 Iustin Pop
    """
1283 02c521e4 Iustin Pop
    node = ninfo.name
1284 02c521e4 Iustin Pop
    _ErrorIf = self._ErrorIf # pylint: disable-msg=C0103
1285 02c521e4 Iustin Pop
1286 02c521e4 Iustin Pop
    ntime = nresult.get(constants.NV_TIME, None)
1287 02c521e4 Iustin Pop
    try:
1288 02c521e4 Iustin Pop
      ntime_merged = utils.MergeTime(ntime)
1289 02c521e4 Iustin Pop
    except (ValueError, TypeError):
1290 02c521e4 Iustin Pop
      _ErrorIf(True, self.ENODETIME, node, "Node returned invalid time")
1291 02c521e4 Iustin Pop
      return
1292 02c521e4 Iustin Pop
1293 02c521e4 Iustin Pop
    if ntime_merged < (nvinfo_starttime - constants.NODE_MAX_CLOCK_SKEW):
1294 02c521e4 Iustin Pop
      ntime_diff = "%.01fs" % abs(nvinfo_starttime - ntime_merged)
1295 02c521e4 Iustin Pop
    elif ntime_merged > (nvinfo_endtime + constants.NODE_MAX_CLOCK_SKEW):
1296 02c521e4 Iustin Pop
      ntime_diff = "%.01fs" % abs(ntime_merged - nvinfo_endtime)
1297 02c521e4 Iustin Pop
    else:
1298 02c521e4 Iustin Pop
      ntime_diff = None
1299 02c521e4 Iustin Pop
1300 02c521e4 Iustin Pop
    _ErrorIf(ntime_diff is not None, self.ENODETIME, node,
1301 02c521e4 Iustin Pop
             "Node time diverges by at least %s from master node time",
1302 02c521e4 Iustin Pop
             ntime_diff)
1303 02c521e4 Iustin Pop
1304 02c521e4 Iustin Pop
  def _VerifyNodeLVM(self, ninfo, nresult, vg_name):
1305 02c521e4 Iustin Pop
    """Check the node time.
1306 02c521e4 Iustin Pop

1307 02c521e4 Iustin Pop
    @type ninfo: L{objects.Node}
1308 02c521e4 Iustin Pop
    @param ninfo: the node to check
1309 02c521e4 Iustin Pop
    @param nresult: the remote results for the node
1310 02c521e4 Iustin Pop
    @param vg_name: the configured VG name
1311 02c521e4 Iustin Pop

1312 02c521e4 Iustin Pop
    """
1313 02c521e4 Iustin Pop
    if vg_name is None:
1314 02c521e4 Iustin Pop
      return
1315 02c521e4 Iustin Pop
1316 02c521e4 Iustin Pop
    node = ninfo.name
1317 02c521e4 Iustin Pop
    _ErrorIf = self._ErrorIf # pylint: disable-msg=C0103
1318 02c521e4 Iustin Pop
1319 02c521e4 Iustin Pop
    # checks vg existence and size > 20G
1320 02c521e4 Iustin Pop
    vglist = nresult.get(constants.NV_VGLIST, None)
1321 02c521e4 Iustin Pop
    test = not vglist
1322 02c521e4 Iustin Pop
    _ErrorIf(test, self.ENODELVM, node, "unable to check volume groups")
1323 02c521e4 Iustin Pop
    if not test:
1324 02c521e4 Iustin Pop
      vgstatus = utils.CheckVolumeGroupSize(vglist, vg_name,
1325 02c521e4 Iustin Pop
                                            constants.MIN_VG_SIZE)
1326 02c521e4 Iustin Pop
      _ErrorIf(vgstatus, self.ENODELVM, node, vgstatus)
1327 02c521e4 Iustin Pop
1328 02c521e4 Iustin Pop
    # check pv names
1329 02c521e4 Iustin Pop
    pvlist = nresult.get(constants.NV_PVLIST, None)
1330 02c521e4 Iustin Pop
    test = pvlist is None
1331 02c521e4 Iustin Pop
    _ErrorIf(test, self.ENODELVM, node, "Can't get PV list from node")
1332 a0c9776a Iustin Pop
    if not test:
1333 02c521e4 Iustin Pop
      # check that ':' is not present in PV names, since it's a
1334 02c521e4 Iustin Pop
      # special character for lvcreate (denotes the range of PEs to
1335 02c521e4 Iustin Pop
      # use on the PV)
1336 02c521e4 Iustin Pop
      for _, pvname, owner_vg in pvlist:
1337 02c521e4 Iustin Pop
        test = ":" in pvname
1338 02c521e4 Iustin Pop
        _ErrorIf(test, self.ENODELVM, node, "Invalid character ':' in PV"
1339 02c521e4 Iustin Pop
                 " '%s' of VG '%s'", pvname, owner_vg)
1340 02c521e4 Iustin Pop
1341 02c521e4 Iustin Pop
  def _VerifyNodeNetwork(self, ninfo, nresult):
1342 02c521e4 Iustin Pop
    """Check the node time.
1343 02c521e4 Iustin Pop

1344 02c521e4 Iustin Pop
    @type ninfo: L{objects.Node}
1345 02c521e4 Iustin Pop
    @param ninfo: the node to check
1346 02c521e4 Iustin Pop
    @param nresult: the remote results for the node
1347 02c521e4 Iustin Pop

1348 02c521e4 Iustin Pop
    """
1349 02c521e4 Iustin Pop
    node = ninfo.name
1350 02c521e4 Iustin Pop
    _ErrorIf = self._ErrorIf # pylint: disable-msg=C0103
1351 02c521e4 Iustin Pop
1352 02c521e4 Iustin Pop
    test = constants.NV_NODELIST not in nresult
1353 a0c9776a Iustin Pop
    _ErrorIf(test, self.ENODESSH, node,
1354 a0c9776a Iustin Pop
             "node hasn't returned node ssh connectivity data")
1355 a0c9776a Iustin Pop
    if not test:
1356 02c521e4 Iustin Pop
      if nresult[constants.NV_NODELIST]:
1357 02c521e4 Iustin Pop
        for a_node, a_msg in nresult[constants.NV_NODELIST].items():
1358 a0c9776a Iustin Pop
          _ErrorIf(True, self.ENODESSH, node,
1359 a0c9776a Iustin Pop
                   "ssh communication with node '%s': %s", a_node, a_msg)
1360 25361b9a Iustin Pop
1361 02c521e4 Iustin Pop
    test = constants.NV_NODENETTEST not in nresult
1362 a0c9776a Iustin Pop
    _ErrorIf(test, self.ENODENET, node,
1363 a0c9776a Iustin Pop
             "node hasn't returned node tcp connectivity data")
1364 a0c9776a Iustin Pop
    if not test:
1365 02c521e4 Iustin Pop
      if nresult[constants.NV_NODENETTEST]:
1366 02c521e4 Iustin Pop
        nlist = utils.NiceSort(nresult[constants.NV_NODENETTEST].keys())
1367 7c874ee1 Iustin Pop
        for anode in nlist:
1368 a0c9776a Iustin Pop
          _ErrorIf(True, self.ENODENET, node,
1369 a0c9776a Iustin Pop
                   "tcp communication with node '%s': %s",
1370 02c521e4 Iustin Pop
                   anode, nresult[constants.NV_NODENETTEST][anode])
1371 a8083063 Iustin Pop
1372 02c521e4 Iustin Pop
  def _VerifyInstance(self, instance, instanceconfig, node_image):
1373 a8083063 Iustin Pop
    """Verify an instance.
1374 a8083063 Iustin Pop

1375 a8083063 Iustin Pop
    This function checks to see if the required block devices are
1376 a8083063 Iustin Pop
    available on the instance's node.
1377 a8083063 Iustin Pop

1378 a8083063 Iustin Pop
    """
1379 7260cfbe Iustin Pop
    _ErrorIf = self._ErrorIf # pylint: disable-msg=C0103
1380 a8083063 Iustin Pop
    node_current = instanceconfig.primary_node
1381 a8083063 Iustin Pop
1382 a8083063 Iustin Pop
    node_vol_should = {}
1383 a8083063 Iustin Pop
    instanceconfig.MapLVsByNode(node_vol_should)
1384 a8083063 Iustin Pop
1385 a8083063 Iustin Pop
    for node in node_vol_should:
1386 02c521e4 Iustin Pop
      n_img = node_image[node]
1387 02c521e4 Iustin Pop
      if n_img.offline or n_img.rpc_fail or n_img.lvm_fail:
1388 02c521e4 Iustin Pop
        # ignore missing volumes on offline or broken nodes
1389 0a66c968 Iustin Pop
        continue
1390 a8083063 Iustin Pop
      for volume in node_vol_should[node]:
1391 02c521e4 Iustin Pop
        test = volume not in n_img.volumes
1392 a0c9776a Iustin Pop
        _ErrorIf(test, self.EINSTANCEMISSINGDISK, instance,
1393 a0c9776a Iustin Pop
                 "volume %s missing on node %s", volume, node)
1394 a8083063 Iustin Pop
1395 0d68c45d Iustin Pop
    if instanceconfig.admin_up:
1396 02c521e4 Iustin Pop
      pri_img = node_image[node_current]
1397 02c521e4 Iustin Pop
      test = instance not in pri_img.instances and not pri_img.offline
1398 a0c9776a Iustin Pop
      _ErrorIf(test, self.EINSTANCEDOWN, instance,
1399 a0c9776a Iustin Pop
               "instance not running on its primary node %s",
1400 a0c9776a Iustin Pop
               node_current)
1401 a8083063 Iustin Pop
1402 02c521e4 Iustin Pop
    for node, n_img in node_image.items():
1403 a8083063 Iustin Pop
      if (not node == node_current):
1404 02c521e4 Iustin Pop
        test = instance in n_img.instances
1405 a0c9776a Iustin Pop
        _ErrorIf(test, self.EINSTANCEWRONGNODE, instance,
1406 a0c9776a Iustin Pop
                 "instance should not run on node %s", node)
1407 a8083063 Iustin Pop
1408 02c521e4 Iustin Pop
  def _VerifyOrphanVolumes(self, node_vol_should, node_image):
1409 a8083063 Iustin Pop
    """Verify if there are any unknown volumes in the cluster.
1410 a8083063 Iustin Pop

1411 a8083063 Iustin Pop
    The .os, .swap and backup volumes are ignored. All other volumes are
1412 a8083063 Iustin Pop
    reported as unknown.
1413 a8083063 Iustin Pop

1414 a8083063 Iustin Pop
    """
1415 02c521e4 Iustin Pop
    for node, n_img in node_image.items():
1416 02c521e4 Iustin Pop
      if n_img.offline or n_img.rpc_fail or n_img.lvm_fail:
1417 02c521e4 Iustin Pop
        # skip non-healthy nodes
1418 02c521e4 Iustin Pop
        continue
1419 02c521e4 Iustin Pop
      for volume in n_img.volumes:
1420 a0c9776a Iustin Pop
        test = (node not in node_vol_should or
1421 a0c9776a Iustin Pop
                volume not in node_vol_should[node])
1422 a0c9776a Iustin Pop
        self._ErrorIf(test, self.ENODEORPHANLV, node,
1423 7c874ee1 Iustin Pop
                      "volume %s is unknown", volume)
1424 a8083063 Iustin Pop
1425 02c521e4 Iustin Pop
  def _VerifyOrphanInstances(self, instancelist, node_image):
1426 a8083063 Iustin Pop
    """Verify the list of running instances.
1427 a8083063 Iustin Pop

1428 a8083063 Iustin Pop
    This checks what instances are running but unknown to the cluster.
1429 a8083063 Iustin Pop

1430 a8083063 Iustin Pop
    """
1431 02c521e4 Iustin Pop
    for node, n_img in node_image.items():
1432 02c521e4 Iustin Pop
      for o_inst in n_img.instances:
1433 a0c9776a Iustin Pop
        test = o_inst not in instancelist
1434 a0c9776a Iustin Pop
        self._ErrorIf(test, self.ENODEORPHANINSTANCE, node,
1435 7c874ee1 Iustin Pop
                      "instance %s on node %s should not exist", o_inst, node)
1436 a8083063 Iustin Pop
1437 02c521e4 Iustin Pop
  def _VerifyNPlusOneMemory(self, node_image, instance_cfg):
1438 2b3b6ddd Guido Trotter
    """Verify N+1 Memory Resilience.
1439 2b3b6ddd Guido Trotter

1440 02c521e4 Iustin Pop
    Check that if one single node dies we can still start all the
1441 02c521e4 Iustin Pop
    instances it was primary for.
1442 2b3b6ddd Guido Trotter

1443 2b3b6ddd Guido Trotter
    """
1444 02c521e4 Iustin Pop
    for node, n_img in node_image.items():
1445 02c521e4 Iustin Pop
      # This code checks that every node which is now listed as
1446 02c521e4 Iustin Pop
      # secondary has enough memory to host all instances it is
1447 02c521e4 Iustin Pop
      # supposed to should a single other node in the cluster fail.
1448 2b3b6ddd Guido Trotter
      # FIXME: not ready for failover to an arbitrary node
1449 2b3b6ddd Guido Trotter
      # FIXME: does not support file-backed instances
1450 02c521e4 Iustin Pop
      # WARNING: we currently take into account down instances as well
1451 02c521e4 Iustin Pop
      # as up ones, considering that even if they're down someone
1452 02c521e4 Iustin Pop
      # might want to start them even in the event of a node failure.
1453 02c521e4 Iustin Pop
      for prinode, instances in n_img.sbp.items():
1454 2b3b6ddd Guido Trotter
        needed_mem = 0
1455 2b3b6ddd Guido Trotter
        for instance in instances:
1456 338e51e8 Iustin Pop
          bep = self.cfg.GetClusterInfo().FillBE(instance_cfg[instance])
1457 c0f2b229 Iustin Pop
          if bep[constants.BE_AUTO_BALANCE]:
1458 3924700f Iustin Pop
            needed_mem += bep[constants.BE_MEMORY]
1459 02c521e4 Iustin Pop
        test = n_img.mfree < needed_mem
1460 a0c9776a Iustin Pop
        self._ErrorIf(test, self.ENODEN1, node,
1461 7c874ee1 Iustin Pop
                      "not enough memory on to accommodate"
1462 7c874ee1 Iustin Pop
                      " failovers should peer node %s fail", prinode)
1463 2b3b6ddd Guido Trotter
1464 02c521e4 Iustin Pop
  def _VerifyNodeFiles(self, ninfo, nresult, file_list, local_cksum,
1465 02c521e4 Iustin Pop
                       master_files):
1466 02c521e4 Iustin Pop
    """Verifies and computes the node required file checksums.
1467 02c521e4 Iustin Pop

1468 02c521e4 Iustin Pop
    @type ninfo: L{objects.Node}
1469 02c521e4 Iustin Pop
    @param ninfo: the node to check
1470 02c521e4 Iustin Pop
    @param nresult: the remote results for the node
1471 02c521e4 Iustin Pop
    @param file_list: required list of files
1472 02c521e4 Iustin Pop
    @param local_cksum: dictionary of local files and their checksums
1473 02c521e4 Iustin Pop
    @param master_files: list of files that only masters should have
1474 02c521e4 Iustin Pop

1475 02c521e4 Iustin Pop
    """
1476 02c521e4 Iustin Pop
    node = ninfo.name
1477 02c521e4 Iustin Pop
    _ErrorIf = self._ErrorIf # pylint: disable-msg=C0103
1478 02c521e4 Iustin Pop
1479 02c521e4 Iustin Pop
    remote_cksum = nresult.get(constants.NV_FILELIST, None)
1480 02c521e4 Iustin Pop
    test = not isinstance(remote_cksum, dict)
1481 02c521e4 Iustin Pop
    _ErrorIf(test, self.ENODEFILECHECK, node,
1482 02c521e4 Iustin Pop
             "node hasn't returned file checksum data")
1483 02c521e4 Iustin Pop
    if test:
1484 02c521e4 Iustin Pop
      return
1485 02c521e4 Iustin Pop
1486 02c521e4 Iustin Pop
    for file_name in file_list:
1487 02c521e4 Iustin Pop
      node_is_mc = ninfo.master_candidate
1488 02c521e4 Iustin Pop
      must_have = (file_name not in master_files) or node_is_mc
1489 02c521e4 Iustin Pop
      # missing
1490 02c521e4 Iustin Pop
      test1 = file_name not in remote_cksum
1491 02c521e4 Iustin Pop
      # invalid checksum
1492 02c521e4 Iustin Pop
      test2 = not test1 and remote_cksum[file_name] != local_cksum[file_name]
1493 02c521e4 Iustin Pop
      # existing and good
1494 02c521e4 Iustin Pop
      test3 = not test1 and remote_cksum[file_name] == local_cksum[file_name]
1495 02c521e4 Iustin Pop
      _ErrorIf(test1 and must_have, self.ENODEFILECHECK, node,
1496 02c521e4 Iustin Pop
               "file '%s' missing", file_name)
1497 02c521e4 Iustin Pop
      _ErrorIf(test2 and must_have, self.ENODEFILECHECK, node,
1498 02c521e4 Iustin Pop
               "file '%s' has wrong checksum", file_name)
1499 02c521e4 Iustin Pop
      # not candidate and this is not a must-have file
1500 02c521e4 Iustin Pop
      _ErrorIf(test2 and not must_have, self.ENODEFILECHECK, node,
1501 02c521e4 Iustin Pop
               "file '%s' should not exist on non master"
1502 02c521e4 Iustin Pop
               " candidates (and the file is outdated)", file_name)
1503 02c521e4 Iustin Pop
      # all good, except non-master/non-must have combination
1504 02c521e4 Iustin Pop
      _ErrorIf(test3 and not must_have, self.ENODEFILECHECK, node,
1505 02c521e4 Iustin Pop
               "file '%s' should not exist"
1506 02c521e4 Iustin Pop
               " on non master candidates", file_name)
1507 02c521e4 Iustin Pop
1508 02c521e4 Iustin Pop
  def _VerifyNodeDrbd(self, ninfo, nresult, instanceinfo, drbd_map):
1509 02c521e4 Iustin Pop
    """Verifies and the node DRBD status.
1510 02c521e4 Iustin Pop

1511 02c521e4 Iustin Pop
    @type ninfo: L{objects.Node}
1512 02c521e4 Iustin Pop
    @param ninfo: the node to check
1513 02c521e4 Iustin Pop
    @param nresult: the remote results for the node
1514 02c521e4 Iustin Pop
    @param instanceinfo: the dict of instances
1515 02c521e4 Iustin Pop
    @param drbd_map: the DRBD map as returned by
1516 02c521e4 Iustin Pop
        L{ganeti.config.ConfigWriter.ComputeDRBDMap}
1517 02c521e4 Iustin Pop

1518 02c521e4 Iustin Pop
    """
1519 02c521e4 Iustin Pop
    node = ninfo.name
1520 02c521e4 Iustin Pop
    _ErrorIf = self._ErrorIf # pylint: disable-msg=C0103
1521 02c521e4 Iustin Pop
1522 02c521e4 Iustin Pop
    # compute the DRBD minors
1523 02c521e4 Iustin Pop
    node_drbd = {}
1524 02c521e4 Iustin Pop
    for minor, instance in drbd_map[node].items():
1525 02c521e4 Iustin Pop
      test = instance not in instanceinfo
1526 02c521e4 Iustin Pop
      _ErrorIf(test, self.ECLUSTERCFG, None,
1527 02c521e4 Iustin Pop
               "ghost instance '%s' in temporary DRBD map", instance)
1528 02c521e4 Iustin Pop
        # ghost instance should not be running, but otherwise we
1529 02c521e4 Iustin Pop
        # don't give double warnings (both ghost instance and
1530 02c521e4 Iustin Pop
        # unallocated minor in use)
1531 02c521e4 Iustin Pop
      if test:
1532 02c521e4 Iustin Pop
        node_drbd[minor] = (instance, False)
1533 02c521e4 Iustin Pop
      else:
1534 02c521e4 Iustin Pop
        instance = instanceinfo[instance]
1535 02c521e4 Iustin Pop
        node_drbd[minor] = (instance.name, instance.admin_up)
1536 02c521e4 Iustin Pop
1537 02c521e4 Iustin Pop
    # and now check them
1538 02c521e4 Iustin Pop
    used_minors = nresult.get(constants.NV_DRBDLIST, [])
1539 02c521e4 Iustin Pop
    test = not isinstance(used_minors, (tuple, list))
1540 02c521e4 Iustin Pop
    _ErrorIf(test, self.ENODEDRBD, node,
1541 02c521e4 Iustin Pop
             "cannot parse drbd status file: %s", str(used_minors))
1542 02c521e4 Iustin Pop
    if test:
1543 02c521e4 Iustin Pop
      # we cannot check drbd status
1544 02c521e4 Iustin Pop
      return
1545 02c521e4 Iustin Pop
1546 02c521e4 Iustin Pop
    for minor, (iname, must_exist) in node_drbd.items():
1547 02c521e4 Iustin Pop
      test = minor not in used_minors and must_exist
1548 02c521e4 Iustin Pop
      _ErrorIf(test, self.ENODEDRBD, node,
1549 02c521e4 Iustin Pop
               "drbd minor %d of instance %s is not active", minor, iname)
1550 02c521e4 Iustin Pop
    for minor in used_minors:
1551 02c521e4 Iustin Pop
      test = minor not in node_drbd
1552 02c521e4 Iustin Pop
      _ErrorIf(test, self.ENODEDRBD, node,
1553 02c521e4 Iustin Pop
               "unallocated drbd minor %d is in use", minor)
1554 02c521e4 Iustin Pop
1555 02c521e4 Iustin Pop
  def _UpdateNodeVolumes(self, ninfo, nresult, nimg, vg_name):
1556 02c521e4 Iustin Pop
    """Verifies and updates the node volume data.
1557 02c521e4 Iustin Pop

1558 02c521e4 Iustin Pop
    This function will update a L{NodeImage}'s internal structures
1559 02c521e4 Iustin Pop
    with data from the remote call.
1560 02c521e4 Iustin Pop

1561 02c521e4 Iustin Pop
    @type ninfo: L{objects.Node}
1562 02c521e4 Iustin Pop
    @param ninfo: the node to check
1563 02c521e4 Iustin Pop
    @param nresult: the remote results for the node
1564 02c521e4 Iustin Pop
    @param nimg: the node image object
1565 02c521e4 Iustin Pop
    @param vg_name: the configured VG name
1566 02c521e4 Iustin Pop

1567 02c521e4 Iustin Pop
    """
1568 02c521e4 Iustin Pop
    node = ninfo.name
1569 02c521e4 Iustin Pop
    _ErrorIf = self._ErrorIf # pylint: disable-msg=C0103
1570 02c521e4 Iustin Pop
1571 02c521e4 Iustin Pop
    nimg.lvm_fail = True
1572 02c521e4 Iustin Pop
    lvdata = nresult.get(constants.NV_LVLIST, "Missing LV data")
1573 02c521e4 Iustin Pop
    if vg_name is None:
1574 02c521e4 Iustin Pop
      pass
1575 02c521e4 Iustin Pop
    elif isinstance(lvdata, basestring):
1576 02c521e4 Iustin Pop
      _ErrorIf(True, self.ENODELVM, node, "LVM problem on node: %s",
1577 02c521e4 Iustin Pop
               utils.SafeEncode(lvdata))
1578 02c521e4 Iustin Pop
    elif not isinstance(lvdata, dict):
1579 02c521e4 Iustin Pop
      _ErrorIf(True, self.ENODELVM, node, "rpc call to node failed (lvlist)")
1580 02c521e4 Iustin Pop
    else:
1581 02c521e4 Iustin Pop
      nimg.volumes = lvdata
1582 02c521e4 Iustin Pop
      nimg.lvm_fail = False
1583 02c521e4 Iustin Pop
1584 02c521e4 Iustin Pop
  def _UpdateNodeInstances(self, ninfo, nresult, nimg):
1585 02c521e4 Iustin Pop
    """Verifies and updates the node instance list.
1586 02c521e4 Iustin Pop

1587 02c521e4 Iustin Pop
    If the listing was successful, then updates this node's instance
1588 02c521e4 Iustin Pop
    list. Otherwise, it marks the RPC call as failed for the instance
1589 02c521e4 Iustin Pop
    list key.
1590 02c521e4 Iustin Pop

1591 02c521e4 Iustin Pop
    @type ninfo: L{objects.Node}
1592 02c521e4 Iustin Pop
    @param ninfo: the node to check
1593 02c521e4 Iustin Pop
    @param nresult: the remote results for the node
1594 02c521e4 Iustin Pop
    @param nimg: the node image object
1595 02c521e4 Iustin Pop

1596 02c521e4 Iustin Pop
    """
1597 02c521e4 Iustin Pop
    idata = nresult.get(constants.NV_INSTANCELIST, None)
1598 02c521e4 Iustin Pop
    test = not isinstance(idata, list)
1599 02c521e4 Iustin Pop
    self._ErrorIf(test, self.ENODEHV, ninfo.name, "rpc call to node failed"
1600 02c521e4 Iustin Pop
                  " (instancelist): %s", utils.SafeEncode(str(idata)))
1601 02c521e4 Iustin Pop
    if test:
1602 02c521e4 Iustin Pop
      nimg.hyp_fail = True
1603 02c521e4 Iustin Pop
    else:
1604 02c521e4 Iustin Pop
      nimg.instances = idata
1605 02c521e4 Iustin Pop
1606 02c521e4 Iustin Pop
  def _UpdateNodeInfo(self, ninfo, nresult, nimg, vg_name):
1607 02c521e4 Iustin Pop
    """Verifies and computes a node information map
1608 02c521e4 Iustin Pop

1609 02c521e4 Iustin Pop
    @type ninfo: L{objects.Node}
1610 02c521e4 Iustin Pop
    @param ninfo: the node to check
1611 02c521e4 Iustin Pop
    @param nresult: the remote results for the node
1612 02c521e4 Iustin Pop
    @param nimg: the node image object
1613 02c521e4 Iustin Pop
    @param vg_name: the configured VG name
1614 02c521e4 Iustin Pop

1615 02c521e4 Iustin Pop
    """
1616 02c521e4 Iustin Pop
    node = ninfo.name
1617 02c521e4 Iustin Pop
    _ErrorIf = self._ErrorIf # pylint: disable-msg=C0103
1618 02c521e4 Iustin Pop
1619 02c521e4 Iustin Pop
    # try to read free memory (from the hypervisor)
1620 02c521e4 Iustin Pop
    hv_info = nresult.get(constants.NV_HVINFO, None)
1621 02c521e4 Iustin Pop
    test = not isinstance(hv_info, dict) or "memory_free" not in hv_info
1622 02c521e4 Iustin Pop
    _ErrorIf(test, self.ENODEHV, node, "rpc call to node failed (hvinfo)")
1623 02c521e4 Iustin Pop
    if not test:
1624 02c521e4 Iustin Pop
      try:
1625 02c521e4 Iustin Pop
        nimg.mfree = int(hv_info["memory_free"])
1626 02c521e4 Iustin Pop
      except (ValueError, TypeError):
1627 02c521e4 Iustin Pop
        _ErrorIf(True, self.ENODERPC, node,
1628 02c521e4 Iustin Pop
                 "node returned invalid nodeinfo, check hypervisor")
1629 02c521e4 Iustin Pop
1630 02c521e4 Iustin Pop
    # FIXME: devise a free space model for file based instances as well
1631 02c521e4 Iustin Pop
    if vg_name is not None:
1632 02c521e4 Iustin Pop
      test = (constants.NV_VGLIST not in nresult or
1633 02c521e4 Iustin Pop
              vg_name not in nresult[constants.NV_VGLIST])
1634 02c521e4 Iustin Pop
      _ErrorIf(test, self.ENODELVM, node,
1635 02c521e4 Iustin Pop
               "node didn't return data for the volume group '%s'"
1636 02c521e4 Iustin Pop
               " - it is either missing or broken", vg_name)
1637 02c521e4 Iustin Pop
      if not test:
1638 02c521e4 Iustin Pop
        try:
1639 02c521e4 Iustin Pop
          nimg.dfree = int(nresult[constants.NV_VGLIST][vg_name])
1640 02c521e4 Iustin Pop
        except (ValueError, TypeError):
1641 02c521e4 Iustin Pop
          _ErrorIf(True, self.ENODERPC, node,
1642 02c521e4 Iustin Pop
                   "node returned invalid LVM info, check LVM status")
1643 02c521e4 Iustin Pop
1644 a8083063 Iustin Pop
  def CheckPrereq(self):
1645 a8083063 Iustin Pop
    """Check prerequisites.
1646 a8083063 Iustin Pop

1647 e54c4c5e Guido Trotter
    Transform the list of checks we're going to skip into a set and check that
1648 e54c4c5e Guido Trotter
    all its members are valid.
1649 a8083063 Iustin Pop

1650 a8083063 Iustin Pop
    """
1651 e54c4c5e Guido Trotter
    self.skip_set = frozenset(self.op.skip_checks)
1652 e54c4c5e Guido Trotter
    if not constants.VERIFY_OPTIONAL_CHECKS.issuperset(self.skip_set):
1653 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Invalid checks to be skipped specified",
1654 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
1655 a8083063 Iustin Pop
1656 d8fff41c Guido Trotter
  def BuildHooksEnv(self):
1657 d8fff41c Guido Trotter
    """Build hooks env.
1658 d8fff41c Guido Trotter

1659 5bbd3f7f Michael Hanselmann
    Cluster-Verify hooks just ran in the post phase and their failure makes
1660 d8fff41c Guido Trotter
    the output be logged in the verify output and the verification to fail.
1661 d8fff41c Guido Trotter

1662 d8fff41c Guido Trotter
    """
1663 d8fff41c Guido Trotter
    all_nodes = self.cfg.GetNodeList()
1664 35e994e9 Iustin Pop
    env = {
1665 35e994e9 Iustin Pop
      "CLUSTER_TAGS": " ".join(self.cfg.GetClusterInfo().GetTags())
1666 35e994e9 Iustin Pop
      }
1667 35e994e9 Iustin Pop
    for node in self.cfg.GetAllNodesInfo().values():
1668 35e994e9 Iustin Pop
      env["NODE_TAGS_%s" % node.name] = " ".join(node.GetTags())
1669 35e994e9 Iustin Pop
1670 d8fff41c Guido Trotter
    return env, [], all_nodes
1671 d8fff41c Guido Trotter
1672 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1673 a8083063 Iustin Pop
    """Verify integrity of cluster, performing various test on nodes.
1674 a8083063 Iustin Pop

1675 a8083063 Iustin Pop
    """
1676 a0c9776a Iustin Pop
    self.bad = False
1677 7260cfbe Iustin Pop
    _ErrorIf = self._ErrorIf # pylint: disable-msg=C0103
1678 7c874ee1 Iustin Pop
    verbose = self.op.verbose
1679 7c874ee1 Iustin Pop
    self._feedback_fn = feedback_fn
1680 a8083063 Iustin Pop
    feedback_fn("* Verifying global settings")
1681 8522ceeb Iustin Pop
    for msg in self.cfg.VerifyConfig():
1682 a0c9776a Iustin Pop
      _ErrorIf(True, self.ECLUSTERCFG, None, msg)
1683 a8083063 Iustin Pop
1684 b98bf262 Michael Hanselmann
    # Check the cluster certificates
1685 b98bf262 Michael Hanselmann
    for cert_filename in constants.ALL_CERT_FILES:
1686 b98bf262 Michael Hanselmann
      (errcode, msg) = _VerifyCertificate(cert_filename)
1687 b98bf262 Michael Hanselmann
      _ErrorIf(errcode, self.ECLUSTERCERT, None, msg, code=errcode)
1688 b98bf262 Michael Hanselmann
1689 a8083063 Iustin Pop
    vg_name = self.cfg.GetVGName()
1690 e69d05fd Iustin Pop
    hypervisors = self.cfg.GetClusterInfo().enabled_hypervisors
1691 a8083063 Iustin Pop
    nodelist = utils.NiceSort(self.cfg.GetNodeList())
1692 9d4bfc96 Iustin Pop
    nodeinfo = [self.cfg.GetNodeInfo(nname) for nname in nodelist]
1693 a8083063 Iustin Pop
    instancelist = utils.NiceSort(self.cfg.GetInstanceList())
1694 6d2e83d5 Iustin Pop
    instanceinfo = dict((iname, self.cfg.GetInstanceInfo(iname))
1695 6d2e83d5 Iustin Pop
                        for iname in instancelist)
1696 93e4c50b Guido Trotter
    i_non_redundant = [] # Non redundant instances
1697 3924700f Iustin Pop
    i_non_a_balanced = [] # Non auto-balanced instances
1698 02c521e4 Iustin Pop
    n_offline = 0 # Count of offline nodes
1699 02c521e4 Iustin Pop
    n_drained = 0 # Count of nodes being drained
1700 02c521e4 Iustin Pop
    node_vol_should = {}
1701 a8083063 Iustin Pop
1702 a8083063 Iustin Pop
    # FIXME: verify OS list
1703 a8083063 Iustin Pop
    # do local checksums
1704 112f18a5 Iustin Pop
    master_files = [constants.CLUSTER_CONF_FILE]
1705 112f18a5 Iustin Pop
1706 112f18a5 Iustin Pop
    file_names = ssconf.SimpleStore().GetFileList()
1707 d3100055 Michael Hanselmann
    file_names.extend(constants.ALL_CERT_FILES)
1708 112f18a5 Iustin Pop
    file_names.extend(master_files)
1709 112f18a5 Iustin Pop
1710 a8083063 Iustin Pop
    local_checksums = utils.FingerprintFiles(file_names)
1711 a8083063 Iustin Pop
1712 a8083063 Iustin Pop
    feedback_fn("* Gathering data (%d nodes)" % len(nodelist))
1713 a8083063 Iustin Pop
    node_verify_param = {
1714 25361b9a Iustin Pop
      constants.NV_FILELIST: file_names,
1715 82e37788 Iustin Pop
      constants.NV_NODELIST: [node.name for node in nodeinfo
1716 82e37788 Iustin Pop
                              if not node.offline],
1717 25361b9a Iustin Pop
      constants.NV_HYPERVISOR: hypervisors,
1718 25361b9a Iustin Pop
      constants.NV_NODENETTEST: [(node.name, node.primary_ip,
1719 82e37788 Iustin Pop
                                  node.secondary_ip) for node in nodeinfo
1720 82e37788 Iustin Pop
                                 if not node.offline],
1721 25361b9a Iustin Pop
      constants.NV_INSTANCELIST: hypervisors,
1722 25361b9a Iustin Pop
      constants.NV_VERSION: None,
1723 25361b9a Iustin Pop
      constants.NV_HVINFO: self.cfg.GetHypervisorType(),
1724 7c0aa8e9 Iustin Pop
      constants.NV_NODESETUP: None,
1725 313b2dd4 Michael Hanselmann
      constants.NV_TIME: None,
1726 a8083063 Iustin Pop
      }
1727 313b2dd4 Michael Hanselmann
1728 cc9e1230 Guido Trotter
    if vg_name is not None:
1729 cc9e1230 Guido Trotter
      node_verify_param[constants.NV_VGLIST] = None
1730 cc9e1230 Guido Trotter
      node_verify_param[constants.NV_LVLIST] = vg_name
1731 d091393e Iustin Pop
      node_verify_param[constants.NV_PVLIST] = [vg_name]
1732 cc9e1230 Guido Trotter
      node_verify_param[constants.NV_DRBDLIST] = None
1733 313b2dd4 Michael Hanselmann
1734 02c521e4 Iustin Pop
    # Build our expected cluster state
1735 02c521e4 Iustin Pop
    node_image = dict((node.name, self.NodeImage(offline=node.offline))
1736 02c521e4 Iustin Pop
                      for node in nodeinfo)
1737 02c521e4 Iustin Pop
1738 02c521e4 Iustin Pop
    for instance in instancelist:
1739 02c521e4 Iustin Pop
      inst_config = instanceinfo[instance]
1740 02c521e4 Iustin Pop
1741 02c521e4 Iustin Pop
      for nname in inst_config.all_nodes:
1742 02c521e4 Iustin Pop
        if nname not in node_image:
1743 02c521e4 Iustin Pop
          # ghost node
1744 02c521e4 Iustin Pop
          gnode = self.NodeImage()
1745 02c521e4 Iustin Pop
          gnode.ghost = True
1746 02c521e4 Iustin Pop
          node_image[nname] = gnode
1747 02c521e4 Iustin Pop
1748 02c521e4 Iustin Pop
      inst_config.MapLVsByNode(node_vol_should)
1749 02c521e4 Iustin Pop
1750 02c521e4 Iustin Pop
      pnode = inst_config.primary_node
1751 02c521e4 Iustin Pop
      node_image[pnode].pinst.append(instance)
1752 02c521e4 Iustin Pop
1753 02c521e4 Iustin Pop
      for snode in inst_config.secondary_nodes:
1754 02c521e4 Iustin Pop
        nimg = node_image[snode]
1755 02c521e4 Iustin Pop
        nimg.sinst.append(instance)
1756 02c521e4 Iustin Pop
        if pnode not in nimg.sbp:
1757 02c521e4 Iustin Pop
          nimg.sbp[pnode] = []
1758 02c521e4 Iustin Pop
        nimg.sbp[pnode].append(instance)
1759 02c521e4 Iustin Pop
1760 02c521e4 Iustin Pop
    # At this point, we have the in-memory data structures complete,
1761 02c521e4 Iustin Pop
    # except for the runtime information, which we'll gather next
1762 02c521e4 Iustin Pop
1763 313b2dd4 Michael Hanselmann
    # Due to the way our RPC system works, exact response times cannot be
1764 313b2dd4 Michael Hanselmann
    # guaranteed (e.g. a broken node could run into a timeout). By keeping the
1765 313b2dd4 Michael Hanselmann
    # time before and after executing the request, we can at least have a time
1766 313b2dd4 Michael Hanselmann
    # window.
1767 313b2dd4 Michael Hanselmann
    nvinfo_starttime = time.time()
1768 72737a7f Iustin Pop
    all_nvinfo = self.rpc.call_node_verify(nodelist, node_verify_param,
1769 72737a7f Iustin Pop
                                           self.cfg.GetClusterName())
1770 313b2dd4 Michael Hanselmann
    nvinfo_endtime = time.time()
1771 a8083063 Iustin Pop
1772 3924700f Iustin Pop
    cluster = self.cfg.GetClusterInfo()
1773 112f18a5 Iustin Pop
    master_node = self.cfg.GetMasterNode()
1774 6d2e83d5 Iustin Pop
    all_drbd_map = self.cfg.ComputeDRBDMap()
1775 6d2e83d5 Iustin Pop
1776 7c874ee1 Iustin Pop
    feedback_fn("* Verifying node status")
1777 112f18a5 Iustin Pop
    for node_i in nodeinfo:
1778 112f18a5 Iustin Pop
      node = node_i.name
1779 02c521e4 Iustin Pop
      nimg = node_image[node]
1780 25361b9a Iustin Pop
1781 0a66c968 Iustin Pop
      if node_i.offline:
1782 7c874ee1 Iustin Pop
        if verbose:
1783 7c874ee1 Iustin Pop
          feedback_fn("* Skipping offline node %s" % (node,))
1784 02c521e4 Iustin Pop
        n_offline += 1
1785 0a66c968 Iustin Pop
        continue
1786 0a66c968 Iustin Pop
1787 112f18a5 Iustin Pop
      if node == master_node:
1788 25361b9a Iustin Pop
        ntype = "master"
1789 112f18a5 Iustin Pop
      elif node_i.master_candidate:
1790 25361b9a Iustin Pop
        ntype = "master candidate"
1791 22f0f71d Iustin Pop
      elif node_i.drained:
1792 22f0f71d Iustin Pop
        ntype = "drained"
1793 02c521e4 Iustin Pop
        n_drained += 1
1794 112f18a5 Iustin Pop
      else:
1795 25361b9a Iustin Pop
        ntype = "regular"
1796 7c874ee1 Iustin Pop
      if verbose:
1797 7c874ee1 Iustin Pop
        feedback_fn("* Verifying node %s (%s)" % (node, ntype))
1798 25361b9a Iustin Pop
1799 4c4e4e1e Iustin Pop
      msg = all_nvinfo[node].fail_msg
1800 a0c9776a Iustin Pop
      _ErrorIf(msg, self.ENODERPC, node, "while contacting node: %s", msg)
1801 6f68a739 Iustin Pop
      if msg:
1802 02c521e4 Iustin Pop
        nimg.rpc_fail = True
1803 25361b9a Iustin Pop
        continue
1804 25361b9a Iustin Pop
1805 6f68a739 Iustin Pop
      nresult = all_nvinfo[node].payload
1806 a8083063 Iustin Pop
1807 02c521e4 Iustin Pop
      nimg.call_ok = self._VerifyNode(node_i, nresult)
1808 02c521e4 Iustin Pop
      self._VerifyNodeNetwork(node_i, nresult)
1809 02c521e4 Iustin Pop
      self._VerifyNodeLVM(node_i, nresult, vg_name)
1810 02c521e4 Iustin Pop
      self._VerifyNodeFiles(node_i, nresult, file_names, local_checksums,
1811 02c521e4 Iustin Pop
                            master_files)
1812 02c521e4 Iustin Pop
      self._VerifyNodeDrbd(node_i, nresult, instanceinfo, all_drbd_map)
1813 02c521e4 Iustin Pop
      self._VerifyNodeTime(node_i, nresult, nvinfo_starttime, nvinfo_endtime)
1814 a8083063 Iustin Pop
1815 02c521e4 Iustin Pop
      self._UpdateNodeVolumes(node_i, nresult, nimg, vg_name)
1816 02c521e4 Iustin Pop
      self._UpdateNodeInstances(node_i, nresult, nimg)
1817 02c521e4 Iustin Pop
      self._UpdateNodeInfo(node_i, nresult, nimg, vg_name)
1818 a8083063 Iustin Pop
1819 7c874ee1 Iustin Pop
    feedback_fn("* Verifying instance status")
1820 a8083063 Iustin Pop
    for instance in instancelist:
1821 7c874ee1 Iustin Pop
      if verbose:
1822 7c874ee1 Iustin Pop
        feedback_fn("* Verifying instance %s" % instance)
1823 6d2e83d5 Iustin Pop
      inst_config = instanceinfo[instance]
1824 02c521e4 Iustin Pop
      self._VerifyInstance(instance, inst_config, node_image)
1825 832261fd Iustin Pop
      inst_nodes_offline = []
1826 a8083063 Iustin Pop
1827 93e4c50b Guido Trotter
      pnode = inst_config.primary_node
1828 02c521e4 Iustin Pop
      pnode_img = node_image[pnode]
1829 02c521e4 Iustin Pop
      _ErrorIf(pnode_img.rpc_fail and not pnode_img.offline,
1830 a0c9776a Iustin Pop
               self.ENODERPC, pnode, "instance %s, connection to"
1831 a0c9776a Iustin Pop
               " primary node failed", instance)
1832 93e4c50b Guido Trotter
1833 02c521e4 Iustin Pop
      if pnode_img.offline:
1834 832261fd Iustin Pop
        inst_nodes_offline.append(pnode)
1835 832261fd Iustin Pop
1836 93e4c50b Guido Trotter
      # If the instance is non-redundant we cannot survive losing its primary
1837 93e4c50b Guido Trotter
      # node, so we are not N+1 compliant. On the other hand we have no disk
1838 93e4c50b Guido Trotter
      # templates with more than one secondary so that situation is not well
1839 93e4c50b Guido Trotter
      # supported either.
1840 93e4c50b Guido Trotter
      # FIXME: does not support file-backed instances
1841 02c521e4 Iustin Pop
      if not inst_config.secondary_nodes:
1842 93e4c50b Guido Trotter
        i_non_redundant.append(instance)
1843 02c521e4 Iustin Pop
      _ErrorIf(len(inst_config.secondary_nodes) > 1, self.EINSTANCELAYOUT,
1844 02c521e4 Iustin Pop
               instance, "instance has multiple secondary nodes: %s",
1845 02c521e4 Iustin Pop
               utils.CommaJoin(inst_config.secondary_nodes),
1846 02c521e4 Iustin Pop
               code=self.ETYPE_WARNING)
1847 93e4c50b Guido Trotter
1848 c0f2b229 Iustin Pop
      if not cluster.FillBE(inst_config)[constants.BE_AUTO_BALANCE]:
1849 3924700f Iustin Pop
        i_non_a_balanced.append(instance)
1850 3924700f Iustin Pop
1851 93e4c50b Guido Trotter
      for snode in inst_config.secondary_nodes:
1852 02c521e4 Iustin Pop
        s_img = node_image[snode]
1853 02c521e4 Iustin Pop
        _ErrorIf(s_img.rpc_fail and not s_img.offline, self.ENODERPC, snode,
1854 02c521e4 Iustin Pop
                 "instance %s, connection to secondary node failed", instance)
1855 02c521e4 Iustin Pop
1856 02c521e4 Iustin Pop
        if s_img.offline:
1857 832261fd Iustin Pop
          inst_nodes_offline.append(snode)
1858 832261fd Iustin Pop
1859 a0c9776a Iustin Pop
      # warn that the instance lives on offline nodes
1860 a0c9776a Iustin Pop
      _ErrorIf(inst_nodes_offline, self.EINSTANCEBADNODE, instance,
1861 a0c9776a Iustin Pop
               "instance lives on offline node(s) %s",
1862 1f864b60 Iustin Pop
               utils.CommaJoin(inst_nodes_offline))
1863 02c521e4 Iustin Pop
      # ... or ghost nodes
1864 02c521e4 Iustin Pop
      for node in inst_config.all_nodes:
1865 02c521e4 Iustin Pop
        _ErrorIf(node_image[node].ghost, self.EINSTANCEBADNODE, instance,
1866 02c521e4 Iustin Pop
                 "instance lives on ghost node %s", node)
1867 93e4c50b Guido Trotter
1868 a8083063 Iustin Pop
    feedback_fn("* Verifying orphan volumes")
1869 02c521e4 Iustin Pop
    self._VerifyOrphanVolumes(node_vol_should, node_image)
1870 a8083063 Iustin Pop
1871 02c521e4 Iustin Pop
    feedback_fn("* Verifying oprhan instances")
1872 02c521e4 Iustin Pop
    self._VerifyOrphanInstances(instancelist, node_image)
1873 a8083063 Iustin Pop
1874 e54c4c5e Guido Trotter
    if constants.VERIFY_NPLUSONE_MEM not in self.skip_set:
1875 e54c4c5e Guido Trotter
      feedback_fn("* Verifying N+1 Memory redundancy")
1876 02c521e4 Iustin Pop
      self._VerifyNPlusOneMemory(node_image, instanceinfo)
1877 2b3b6ddd Guido Trotter
1878 2b3b6ddd Guido Trotter
    feedback_fn("* Other Notes")
1879 2b3b6ddd Guido Trotter
    if i_non_redundant:
1880 2b3b6ddd Guido Trotter
      feedback_fn("  - NOTICE: %d non-redundant instance(s) found."
1881 2b3b6ddd Guido Trotter
                  % len(i_non_redundant))
1882 2b3b6ddd Guido Trotter
1883 3924700f Iustin Pop
    if i_non_a_balanced:
1884 3924700f Iustin Pop
      feedback_fn("  - NOTICE: %d non-auto-balanced instance(s) found."
1885 3924700f Iustin Pop
                  % len(i_non_a_balanced))
1886 3924700f Iustin Pop
1887 0a66c968 Iustin Pop
    if n_offline:
1888 02c521e4 Iustin Pop
      feedback_fn("  - NOTICE: %d offline node(s) found." % n_offline)
1889 0a66c968 Iustin Pop
1890 22f0f71d Iustin Pop
    if n_drained:
1891 02c521e4 Iustin Pop
      feedback_fn("  - NOTICE: %d drained node(s) found." % n_drained)
1892 22f0f71d Iustin Pop
1893 a0c9776a Iustin Pop
    return not self.bad
1894 a8083063 Iustin Pop
1895 d8fff41c Guido Trotter
  def HooksCallBack(self, phase, hooks_results, feedback_fn, lu_result):
1896 5bbd3f7f Michael Hanselmann
    """Analyze the post-hooks' result
1897 e4376078 Iustin Pop

1898 e4376078 Iustin Pop
    This method analyses the hook result, handles it, and sends some
1899 d8fff41c Guido Trotter
    nicely-formatted feedback back to the user.
1900 d8fff41c Guido Trotter

1901 e4376078 Iustin Pop
    @param phase: one of L{constants.HOOKS_PHASE_POST} or
1902 e4376078 Iustin Pop
        L{constants.HOOKS_PHASE_PRE}; it denotes the hooks phase
1903 e4376078 Iustin Pop
    @param hooks_results: the results of the multi-node hooks rpc call
1904 e4376078 Iustin Pop
    @param feedback_fn: function used send feedback back to the caller
1905 e4376078 Iustin Pop
    @param lu_result: previous Exec result
1906 e4376078 Iustin Pop
    @return: the new Exec result, based on the previous result
1907 e4376078 Iustin Pop
        and hook results
1908 d8fff41c Guido Trotter

1909 d8fff41c Guido Trotter
    """
1910 38206f3c Iustin Pop
    # We only really run POST phase hooks, and are only interested in
1911 38206f3c Iustin Pop
    # their results
1912 d8fff41c Guido Trotter
    if phase == constants.HOOKS_PHASE_POST:
1913 d8fff41c Guido Trotter
      # Used to change hooks' output to proper indentation
1914 d8fff41c Guido Trotter
      indent_re = re.compile('^', re.M)
1915 d8fff41c Guido Trotter
      feedback_fn("* Hooks Results")
1916 7c874ee1 Iustin Pop
      assert hooks_results, "invalid result from hooks"
1917 7c874ee1 Iustin Pop
1918 7c874ee1 Iustin Pop
      for node_name in hooks_results:
1919 7c874ee1 Iustin Pop
        res = hooks_results[node_name]
1920 7c874ee1 Iustin Pop
        msg = res.fail_msg
1921 a0c9776a Iustin Pop
        test = msg and not res.offline
1922 a0c9776a Iustin Pop
        self._ErrorIf(test, self.ENODEHOOKS, node_name,
1923 7c874ee1 Iustin Pop
                      "Communication failure in hooks execution: %s", msg)
1924 dd9e9f9c Michael Hanselmann
        if res.offline or msg:
1925 dd9e9f9c Michael Hanselmann
          # No need to investigate payload if node is offline or gave an error.
1926 a0c9776a Iustin Pop
          # override manually lu_result here as _ErrorIf only
1927 a0c9776a Iustin Pop
          # overrides self.bad
1928 7c874ee1 Iustin Pop
          lu_result = 1
1929 7c874ee1 Iustin Pop
          continue
1930 7c874ee1 Iustin Pop
        for script, hkr, output in res.payload:
1931 a0c9776a Iustin Pop
          test = hkr == constants.HKR_FAIL
1932 a0c9776a Iustin Pop
          self._ErrorIf(test, self.ENODEHOOKS, node_name,
1933 7c874ee1 Iustin Pop
                        "Script %s failed, output:", script)
1934 a0c9776a Iustin Pop
          if test:
1935 7c874ee1 Iustin Pop
            output = indent_re.sub('      ', output)
1936 7c874ee1 Iustin Pop
            feedback_fn("%s" % output)
1937 6d7b472a Iustin Pop
            lu_result = 0
1938 d8fff41c Guido Trotter
1939 d8fff41c Guido Trotter
      return lu_result
1940 d8fff41c Guido Trotter
1941 a8083063 Iustin Pop
1942 2c95a8d4 Iustin Pop
class LUVerifyDisks(NoHooksLU):
1943 2c95a8d4 Iustin Pop
  """Verifies the cluster disks status.
1944 2c95a8d4 Iustin Pop

1945 2c95a8d4 Iustin Pop
  """
1946 2c95a8d4 Iustin Pop
  _OP_REQP = []
1947 d4b9d97f Guido Trotter
  REQ_BGL = False
1948 d4b9d97f Guido Trotter
1949 d4b9d97f Guido Trotter
  def ExpandNames(self):
1950 d4b9d97f Guido Trotter
    self.needed_locks = {
1951 d4b9d97f Guido Trotter
      locking.LEVEL_NODE: locking.ALL_SET,
1952 d4b9d97f Guido Trotter
      locking.LEVEL_INSTANCE: locking.ALL_SET,
1953 d4b9d97f Guido Trotter
    }
1954 c772d142 Michael Hanselmann
    self.share_locks = dict.fromkeys(locking.LEVELS, 1)
1955 2c95a8d4 Iustin Pop
1956 2c95a8d4 Iustin Pop
  def CheckPrereq(self):
1957 2c95a8d4 Iustin Pop
    """Check prerequisites.
1958 2c95a8d4 Iustin Pop

1959 2c95a8d4 Iustin Pop
    This has no prerequisites.
1960 2c95a8d4 Iustin Pop

1961 2c95a8d4 Iustin Pop
    """
1962 2c95a8d4 Iustin Pop
    pass
1963 2c95a8d4 Iustin Pop
1964 2c95a8d4 Iustin Pop
  def Exec(self, feedback_fn):
1965 2c95a8d4 Iustin Pop
    """Verify integrity of cluster disks.
1966 2c95a8d4 Iustin Pop

1967 29d376ec Iustin Pop
    @rtype: tuple of three items
1968 29d376ec Iustin Pop
    @return: a tuple of (dict of node-to-node_error, list of instances
1969 29d376ec Iustin Pop
        which need activate-disks, dict of instance: (node, volume) for
1970 29d376ec Iustin Pop
        missing volumes
1971 29d376ec Iustin Pop

1972 2c95a8d4 Iustin Pop
    """
1973 29d376ec Iustin Pop
    result = res_nodes, res_instances, res_missing = {}, [], {}
1974 2c95a8d4 Iustin Pop
1975 2c95a8d4 Iustin Pop
    vg_name = self.cfg.GetVGName()
1976 2c95a8d4 Iustin Pop
    nodes = utils.NiceSort(self.cfg.GetNodeList())
1977 2c95a8d4 Iustin Pop
    instances = [self.cfg.GetInstanceInfo(name)
1978 2c95a8d4 Iustin Pop
                 for name in self.cfg.GetInstanceList()]
1979 2c95a8d4 Iustin Pop
1980 2c95a8d4 Iustin Pop
    nv_dict = {}
1981 2c95a8d4 Iustin Pop
    for inst in instances:
1982 2c95a8d4 Iustin Pop
      inst_lvs = {}
1983 0d68c45d Iustin Pop
      if (not inst.admin_up or
1984 2c95a8d4 Iustin Pop
          inst.disk_template not in constants.DTS_NET_MIRROR):
1985 2c95a8d4 Iustin Pop
        continue
1986 2c95a8d4 Iustin Pop
      inst.MapLVsByNode(inst_lvs)
1987 2c95a8d4 Iustin Pop
      # transform { iname: {node: [vol,],},} to {(node, vol): iname}
1988 2c95a8d4 Iustin Pop
      for node, vol_list in inst_lvs.iteritems():
1989 2c95a8d4 Iustin Pop
        for vol in vol_list:
1990 2c95a8d4 Iustin Pop
          nv_dict[(node, vol)] = inst
1991 2c95a8d4 Iustin Pop
1992 2c95a8d4 Iustin Pop
    if not nv_dict:
1993 2c95a8d4 Iustin Pop
      return result
1994 2c95a8d4 Iustin Pop
1995 b2a6ccd4 Iustin Pop
    node_lvs = self.rpc.call_lv_list(nodes, vg_name)
1996 2c95a8d4 Iustin Pop
1997 2c95a8d4 Iustin Pop
    for node in nodes:
1998 2c95a8d4 Iustin Pop
      # node_volume
1999 29d376ec Iustin Pop
      node_res = node_lvs[node]
2000 29d376ec Iustin Pop
      if node_res.offline:
2001 ea9ddc07 Iustin Pop
        continue
2002 4c4e4e1e Iustin Pop
      msg = node_res.fail_msg
2003 29d376ec Iustin Pop
      if msg:
2004 29d376ec Iustin Pop
        logging.warning("Error enumerating LVs on node %s: %s", node, msg)
2005 29d376ec Iustin Pop
        res_nodes[node] = msg
2006 2c95a8d4 Iustin Pop
        continue
2007 2c95a8d4 Iustin Pop
2008 29d376ec Iustin Pop
      lvs = node_res.payload
2009 1122eb25 Iustin Pop
      for lv_name, (_, _, lv_online) in lvs.items():
2010 b63ed789 Iustin Pop
        inst = nv_dict.pop((node, lv_name), None)
2011 b63ed789 Iustin Pop
        if (not lv_online and inst is not None
2012 b63ed789 Iustin Pop
            and inst.name not in res_instances):
2013 b08d5a87 Iustin Pop
          res_instances.append(inst.name)
2014 2c95a8d4 Iustin Pop
2015 b63ed789 Iustin Pop
    # any leftover items in nv_dict are missing LVs, let's arrange the
2016 b63ed789 Iustin Pop
    # data better
2017 b63ed789 Iustin Pop
    for key, inst in nv_dict.iteritems():
2018 b63ed789 Iustin Pop
      if inst.name not in res_missing:
2019 b63ed789 Iustin Pop
        res_missing[inst.name] = []
2020 b63ed789 Iustin Pop
      res_missing[inst.name].append(key)
2021 b63ed789 Iustin Pop
2022 2c95a8d4 Iustin Pop
    return result
2023 2c95a8d4 Iustin Pop
2024 2c95a8d4 Iustin Pop
2025 60975797 Iustin Pop
class LURepairDiskSizes(NoHooksLU):
2026 60975797 Iustin Pop
  """Verifies the cluster disks sizes.
2027 60975797 Iustin Pop

2028 60975797 Iustin Pop
  """
2029 60975797 Iustin Pop
  _OP_REQP = ["instances"]
2030 60975797 Iustin Pop
  REQ_BGL = False
2031 60975797 Iustin Pop
2032 60975797 Iustin Pop
  def ExpandNames(self):
2033 60975797 Iustin Pop
    if not isinstance(self.op.instances, list):
2034 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Invalid argument type 'instances'",
2035 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
2036 60975797 Iustin Pop
2037 60975797 Iustin Pop
    if self.op.instances:
2038 60975797 Iustin Pop
      self.wanted_names = []
2039 60975797 Iustin Pop
      for name in self.op.instances:
2040 cf26a87a Iustin Pop
        full_name = _ExpandInstanceName(self.cfg, name)
2041 60975797 Iustin Pop
        self.wanted_names.append(full_name)
2042 60975797 Iustin Pop
      self.needed_locks = {
2043 60975797 Iustin Pop
        locking.LEVEL_NODE: [],
2044 60975797 Iustin Pop
        locking.LEVEL_INSTANCE: self.wanted_names,
2045 60975797 Iustin Pop
        }
2046 60975797 Iustin Pop
      self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
2047 60975797 Iustin Pop
    else:
2048 60975797 Iustin Pop
      self.wanted_names = None
2049 60975797 Iustin Pop
      self.needed_locks = {
2050 60975797 Iustin Pop
        locking.LEVEL_NODE: locking.ALL_SET,
2051 60975797 Iustin Pop
        locking.LEVEL_INSTANCE: locking.ALL_SET,
2052 60975797 Iustin Pop
        }
2053 60975797 Iustin Pop
    self.share_locks = dict(((i, 1) for i in locking.LEVELS))
2054 60975797 Iustin Pop
2055 60975797 Iustin Pop
  def DeclareLocks(self, level):
2056 60975797 Iustin Pop
    if level == locking.LEVEL_NODE and self.wanted_names is not None:
2057 60975797 Iustin Pop
      self._LockInstancesNodes(primary_only=True)
2058 60975797 Iustin Pop
2059 60975797 Iustin Pop
  def CheckPrereq(self):
2060 60975797 Iustin Pop
    """Check prerequisites.
2061 60975797 Iustin Pop

2062 60975797 Iustin Pop
    This only checks the optional instance list against the existing names.
2063 60975797 Iustin Pop

2064 60975797 Iustin Pop
    """
2065 60975797 Iustin Pop
    if self.wanted_names is None:
2066 60975797 Iustin Pop
      self.wanted_names = self.acquired_locks[locking.LEVEL_INSTANCE]
2067 60975797 Iustin Pop
2068 60975797 Iustin Pop
    self.wanted_instances = [self.cfg.GetInstanceInfo(name) for name
2069 60975797 Iustin Pop
                             in self.wanted_names]
2070 60975797 Iustin Pop
2071 b775c337 Iustin Pop
  def _EnsureChildSizes(self, disk):
2072 b775c337 Iustin Pop
    """Ensure children of the disk have the needed disk size.
2073 b775c337 Iustin Pop

2074 b775c337 Iustin Pop
    This is valid mainly for DRBD8 and fixes an issue where the
2075 b775c337 Iustin Pop
    children have smaller disk size.
2076 b775c337 Iustin Pop

2077 b775c337 Iustin Pop
    @param disk: an L{ganeti.objects.Disk} object
2078 b775c337 Iustin Pop

2079 b775c337 Iustin Pop
    """
2080 b775c337 Iustin Pop
    if disk.dev_type == constants.LD_DRBD8:
2081 b775c337 Iustin Pop
      assert disk.children, "Empty children for DRBD8?"
2082 b775c337 Iustin Pop
      fchild = disk.children[0]
2083 b775c337 Iustin Pop
      mismatch = fchild.size < disk.size
2084 b775c337 Iustin Pop
      if mismatch:
2085 b775c337 Iustin Pop
        self.LogInfo("Child disk has size %d, parent %d, fixing",
2086 b775c337 Iustin Pop
                     fchild.size, disk.size)
2087 b775c337 Iustin Pop
        fchild.size = disk.size
2088 b775c337 Iustin Pop
2089 b775c337 Iustin Pop
      # and we recurse on this child only, not on the metadev
2090 b775c337 Iustin Pop
      return self._EnsureChildSizes(fchild) or mismatch
2091 b775c337 Iustin Pop
    else:
2092 b775c337 Iustin Pop
      return False
2093 b775c337 Iustin Pop
2094 60975797 Iustin Pop
  def Exec(self, feedback_fn):
2095 60975797 Iustin Pop
    """Verify the size of cluster disks.
2096 60975797 Iustin Pop

2097 60975797 Iustin Pop
    """
2098 60975797 Iustin Pop
    # TODO: check child disks too
2099 60975797 Iustin Pop
    # TODO: check differences in size between primary/secondary nodes
2100 60975797 Iustin Pop
    per_node_disks = {}
2101 60975797 Iustin Pop
    for instance in self.wanted_instances:
2102 60975797 Iustin Pop
      pnode = instance.primary_node
2103 60975797 Iustin Pop
      if pnode not in per_node_disks:
2104 60975797 Iustin Pop
        per_node_disks[pnode] = []
2105 60975797 Iustin Pop
      for idx, disk in enumerate(instance.disks):
2106 60975797 Iustin Pop
        per_node_disks[pnode].append((instance, idx, disk))
2107 60975797 Iustin Pop
2108 60975797 Iustin Pop
    changed = []
2109 60975797 Iustin Pop
    for node, dskl in per_node_disks.items():
2110 4d9e6835 Iustin Pop
      newl = [v[2].Copy() for v in dskl]
2111 4d9e6835 Iustin Pop
      for dsk in newl:
2112 4d9e6835 Iustin Pop
        self.cfg.SetDiskID(dsk, node)
2113 4d9e6835 Iustin Pop
      result = self.rpc.call_blockdev_getsizes(node, newl)
2114 3cebe102 Michael Hanselmann
      if result.fail_msg:
2115 60975797 Iustin Pop
        self.LogWarning("Failure in blockdev_getsizes call to node"
2116 60975797 Iustin Pop
                        " %s, ignoring", node)
2117 60975797 Iustin Pop
        continue
2118 60975797 Iustin Pop
      if len(result.data) != len(dskl):
2119 60975797 Iustin Pop
        self.LogWarning("Invalid result from node %s, ignoring node results",
2120 60975797 Iustin Pop
                        node)
2121 60975797 Iustin Pop
        continue
2122 60975797 Iustin Pop
      for ((instance, idx, disk), size) in zip(dskl, result.data):
2123 60975797 Iustin Pop
        if size is None:
2124 60975797 Iustin Pop
          self.LogWarning("Disk %d of instance %s did not return size"
2125 60975797 Iustin Pop
                          " information, ignoring", idx, instance.name)
2126 60975797 Iustin Pop
          continue
2127 60975797 Iustin Pop
        if not isinstance(size, (int, long)):
2128 60975797 Iustin Pop
          self.LogWarning("Disk %d of instance %s did not return valid"
2129 60975797 Iustin Pop
                          " size information, ignoring", idx, instance.name)
2130 60975797 Iustin Pop
          continue
2131 60975797 Iustin Pop
        size = size >> 20
2132 60975797 Iustin Pop
        if size != disk.size:
2133 60975797 Iustin Pop
          self.LogInfo("Disk %d of instance %s has mismatched size,"
2134 60975797 Iustin Pop
                       " correcting: recorded %d, actual %d", idx,
2135 60975797 Iustin Pop
                       instance.name, disk.size, size)
2136 60975797 Iustin Pop
          disk.size = size
2137 a4eae71f Michael Hanselmann
          self.cfg.Update(instance, feedback_fn)
2138 60975797 Iustin Pop
          changed.append((instance.name, idx, size))
2139 b775c337 Iustin Pop
        if self._EnsureChildSizes(disk):
2140 a4eae71f Michael Hanselmann
          self.cfg.Update(instance, feedback_fn)
2141 b775c337 Iustin Pop
          changed.append((instance.name, idx, disk.size))
2142 60975797 Iustin Pop
    return changed
2143 60975797 Iustin Pop
2144 60975797 Iustin Pop
2145 07bd8a51 Iustin Pop
class LURenameCluster(LogicalUnit):
2146 07bd8a51 Iustin Pop
  """Rename the cluster.
2147 07bd8a51 Iustin Pop

2148 07bd8a51 Iustin Pop
  """
2149 07bd8a51 Iustin Pop
  HPATH = "cluster-rename"
2150 07bd8a51 Iustin Pop
  HTYPE = constants.HTYPE_CLUSTER
2151 07bd8a51 Iustin Pop
  _OP_REQP = ["name"]
2152 07bd8a51 Iustin Pop
2153 07bd8a51 Iustin Pop
  def BuildHooksEnv(self):
2154 07bd8a51 Iustin Pop
    """Build hooks env.
2155 07bd8a51 Iustin Pop

2156 07bd8a51 Iustin Pop
    """
2157 07bd8a51 Iustin Pop
    env = {
2158 d6a02168 Michael Hanselmann
      "OP_TARGET": self.cfg.GetClusterName(),
2159 07bd8a51 Iustin Pop
      "NEW_NAME": self.op.name,
2160 07bd8a51 Iustin Pop
      }
2161 d6a02168 Michael Hanselmann
    mn = self.cfg.GetMasterNode()
2162 47a72f18 Iustin Pop
    all_nodes = self.cfg.GetNodeList()
2163 47a72f18 Iustin Pop
    return env, [mn], all_nodes
2164 07bd8a51 Iustin Pop
2165 07bd8a51 Iustin Pop
  def CheckPrereq(self):
2166 07bd8a51 Iustin Pop
    """Verify that the passed name is a valid one.
2167 07bd8a51 Iustin Pop

2168 07bd8a51 Iustin Pop
    """
2169 104f4ca1 Iustin Pop
    hostname = utils.GetHostInfo(self.op.name)
2170 07bd8a51 Iustin Pop
2171 bcf043c9 Iustin Pop
    new_name = hostname.name
2172 bcf043c9 Iustin Pop
    self.ip = new_ip = hostname.ip
2173 d6a02168 Michael Hanselmann
    old_name = self.cfg.GetClusterName()
2174 d6a02168 Michael Hanselmann
    old_ip = self.cfg.GetMasterIP()
2175 07bd8a51 Iustin Pop
    if new_name == old_name and new_ip == old_ip:
2176 07bd8a51 Iustin Pop
      raise errors.OpPrereqError("Neither the name nor the IP address of the"
2177 5c983ee5 Iustin Pop
                                 " cluster has changed",
2178 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
2179 07bd8a51 Iustin Pop
    if new_ip != old_ip:
2180 937f983d Guido Trotter
      if utils.TcpPing(new_ip, constants.DEFAULT_NODED_PORT):
2181 07bd8a51 Iustin Pop
        raise errors.OpPrereqError("The given cluster IP address (%s) is"
2182 07bd8a51 Iustin Pop
                                   " reachable on the network. Aborting." %
2183 5c983ee5 Iustin Pop
                                   new_ip, errors.ECODE_NOTUNIQUE)
2184 07bd8a51 Iustin Pop
2185 07bd8a51 Iustin Pop
    self.op.name = new_name
2186 07bd8a51 Iustin Pop
2187 07bd8a51 Iustin Pop
  def Exec(self, feedback_fn):
2188 07bd8a51 Iustin Pop
    """Rename the cluster.
2189 07bd8a51 Iustin Pop

2190 07bd8a51 Iustin Pop
    """
2191 07bd8a51 Iustin Pop
    clustername = self.op.name
2192 07bd8a51 Iustin Pop
    ip = self.ip
2193 07bd8a51 Iustin Pop
2194 07bd8a51 Iustin Pop
    # shutdown the master IP
2195 d6a02168 Michael Hanselmann
    master = self.cfg.GetMasterNode()
2196 781de953 Iustin Pop
    result = self.rpc.call_node_stop_master(master, False)
2197 4c4e4e1e Iustin Pop
    result.Raise("Could not disable the master role")
2198 07bd8a51 Iustin Pop
2199 07bd8a51 Iustin Pop
    try:
2200 55cf7d83 Iustin Pop
      cluster = self.cfg.GetClusterInfo()
2201 55cf7d83 Iustin Pop
      cluster.cluster_name = clustername
2202 55cf7d83 Iustin Pop
      cluster.master_ip = ip
2203 a4eae71f Michael Hanselmann
      self.cfg.Update(cluster, feedback_fn)
2204 ec85e3d5 Iustin Pop
2205 ec85e3d5 Iustin Pop
      # update the known hosts file
2206 ec85e3d5 Iustin Pop
      ssh.WriteKnownHostsFile(self.cfg, constants.SSH_KNOWN_HOSTS_FILE)
2207 ec85e3d5 Iustin Pop
      node_list = self.cfg.GetNodeList()
2208 ec85e3d5 Iustin Pop
      try:
2209 ec85e3d5 Iustin Pop
        node_list.remove(master)
2210 ec85e3d5 Iustin Pop
      except ValueError:
2211 ec85e3d5 Iustin Pop
        pass
2212 ec85e3d5 Iustin Pop
      result = self.rpc.call_upload_file(node_list,
2213 ec85e3d5 Iustin Pop
                                         constants.SSH_KNOWN_HOSTS_FILE)
2214 ec85e3d5 Iustin Pop
      for to_node, to_result in result.iteritems():
2215 6f7d4e75 Iustin Pop
        msg = to_result.fail_msg
2216 6f7d4e75 Iustin Pop
        if msg:
2217 6f7d4e75 Iustin Pop
          msg = ("Copy of file %s to node %s failed: %s" %
2218 6f7d4e75 Iustin Pop
                 (constants.SSH_KNOWN_HOSTS_FILE, to_node, msg))
2219 6f7d4e75 Iustin Pop
          self.proc.LogWarning(msg)
2220 ec85e3d5 Iustin Pop
2221 07bd8a51 Iustin Pop
    finally:
2222 3583908a Guido Trotter
      result = self.rpc.call_node_start_master(master, False, False)
2223 4c4e4e1e Iustin Pop
      msg = result.fail_msg
2224 b726aff0 Iustin Pop
      if msg:
2225 86d9d3bb Iustin Pop
        self.LogWarning("Could not re-enable the master role on"
2226 b726aff0 Iustin Pop
                        " the master, please restart manually: %s", msg)
2227 07bd8a51 Iustin Pop
2228 07bd8a51 Iustin Pop
2229 8084f9f6 Manuel Franceschini
def _RecursiveCheckIfLVMBased(disk):
2230 8084f9f6 Manuel Franceschini
  """Check if the given disk or its children are lvm-based.
2231 8084f9f6 Manuel Franceschini

2232 e4376078 Iustin Pop
  @type disk: L{objects.Disk}
2233 e4376078 Iustin Pop
  @param disk: the disk to check
2234 5bbd3f7f Michael Hanselmann
  @rtype: boolean
2235 e4376078 Iustin Pop
  @return: boolean indicating whether a LD_LV dev_type was found or not
2236 8084f9f6 Manuel Franceschini

2237 8084f9f6 Manuel Franceschini
  """
2238 8084f9f6 Manuel Franceschini
  if disk.children:
2239 8084f9f6 Manuel Franceschini
    for chdisk in disk.children:
2240 8084f9f6 Manuel Franceschini
      if _RecursiveCheckIfLVMBased(chdisk):
2241 8084f9f6 Manuel Franceschini
        return True
2242 8084f9f6 Manuel Franceschini
  return disk.dev_type == constants.LD_LV
2243 8084f9f6 Manuel Franceschini
2244 8084f9f6 Manuel Franceschini
2245 8084f9f6 Manuel Franceschini
class LUSetClusterParams(LogicalUnit):
2246 8084f9f6 Manuel Franceschini
  """Change the parameters of the cluster.
2247 8084f9f6 Manuel Franceschini

2248 8084f9f6 Manuel Franceschini
  """
2249 8084f9f6 Manuel Franceschini
  HPATH = "cluster-modify"
2250 8084f9f6 Manuel Franceschini
  HTYPE = constants.HTYPE_CLUSTER
2251 8084f9f6 Manuel Franceschini
  _OP_REQP = []
2252 c53279cf Guido Trotter
  REQ_BGL = False
2253 c53279cf Guido Trotter
2254 3994f455 Iustin Pop
  def CheckArguments(self):
2255 4b7735f9 Iustin Pop
    """Check parameters
2256 4b7735f9 Iustin Pop

2257 4b7735f9 Iustin Pop
    """
2258 4b7735f9 Iustin Pop
    if not hasattr(self.op, "candidate_pool_size"):
2259 4b7735f9 Iustin Pop
      self.op.candidate_pool_size = None
2260 4b7735f9 Iustin Pop
    if self.op.candidate_pool_size is not None:
2261 4b7735f9 Iustin Pop
      try:
2262 4b7735f9 Iustin Pop
        self.op.candidate_pool_size = int(self.op.candidate_pool_size)
2263 3994f455 Iustin Pop
      except (ValueError, TypeError), err:
2264 4b7735f9 Iustin Pop
        raise errors.OpPrereqError("Invalid candidate_pool_size value: %s" %
2265 5c983ee5 Iustin Pop
                                   str(err), errors.ECODE_INVAL)
2266 4b7735f9 Iustin Pop
      if self.op.candidate_pool_size < 1:
2267 5c983ee5 Iustin Pop
        raise errors.OpPrereqError("At least one master candidate needed",
2268 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
2269 1338f2b4 Balazs Lecz
2270 3953242f Iustin Pop
    _CheckBooleanOpField(self.op, "maintain_node_health")
2271 4b7735f9 Iustin Pop
2272 1338f2b4 Balazs Lecz
    if self.op.uid_pool:
2273 1338f2b4 Balazs Lecz
      uidpool.CheckUidPool(self.op.uid_pool)
2274 1338f2b4 Balazs Lecz
2275 fdad8c4d Balazs Lecz
    if self.op.add_uids:
2276 fdad8c4d Balazs Lecz
      uidpool.CheckUidPool(self.op.add_uids)
2277 fdad8c4d Balazs Lecz
2278 fdad8c4d Balazs Lecz
    if self.op.remove_uids:
2279 fdad8c4d Balazs Lecz
      uidpool.CheckUidPool(self.op.remove_uids)
2280 fdad8c4d Balazs Lecz
2281 c53279cf Guido Trotter
  def ExpandNames(self):
2282 c53279cf Guido Trotter
    # FIXME: in the future maybe other cluster params won't require checking on
2283 c53279cf Guido Trotter
    # all nodes to be modified.
2284 c53279cf Guido Trotter
    self.needed_locks = {
2285 c53279cf Guido Trotter
      locking.LEVEL_NODE: locking.ALL_SET,
2286 c53279cf Guido Trotter
    }
2287 c53279cf Guido Trotter
    self.share_locks[locking.LEVEL_NODE] = 1
2288 8084f9f6 Manuel Franceschini
2289 8084f9f6 Manuel Franceschini
  def BuildHooksEnv(self):
2290 8084f9f6 Manuel Franceschini
    """Build hooks env.
2291 8084f9f6 Manuel Franceschini

2292 8084f9f6 Manuel Franceschini
    """
2293 8084f9f6 Manuel Franceschini
    env = {
2294 d6a02168 Michael Hanselmann
      "OP_TARGET": self.cfg.GetClusterName(),
2295 8084f9f6 Manuel Franceschini
      "NEW_VG_NAME": self.op.vg_name,
2296 8084f9f6 Manuel Franceschini
      }
2297 d6a02168 Michael Hanselmann
    mn = self.cfg.GetMasterNode()
2298 8084f9f6 Manuel Franceschini
    return env, [mn], [mn]
2299 8084f9f6 Manuel Franceschini
2300 8084f9f6 Manuel Franceschini
  def CheckPrereq(self):
2301 8084f9f6 Manuel Franceschini
    """Check prerequisites.
2302 8084f9f6 Manuel Franceschini

2303 8084f9f6 Manuel Franceschini
    This checks whether the given params don't conflict and
2304 5f83e263 Iustin Pop
    if the given volume group is valid.
2305 8084f9f6 Manuel Franceschini

2306 8084f9f6 Manuel Franceschini
    """
2307 779c15bb Iustin Pop
    if self.op.vg_name is not None and not self.op.vg_name:
2308 c53279cf Guido Trotter
      instances = self.cfg.GetAllInstancesInfo().values()
2309 8084f9f6 Manuel Franceschini
      for inst in instances:
2310 8084f9f6 Manuel Franceschini
        for disk in inst.disks:
2311 8084f9f6 Manuel Franceschini
          if _RecursiveCheckIfLVMBased(disk):
2312 8084f9f6 Manuel Franceschini
            raise errors.OpPrereqError("Cannot disable lvm storage while"
2313 5c983ee5 Iustin Pop
                                       " lvm-based instances exist",
2314 5c983ee5 Iustin Pop
                                       errors.ECODE_INVAL)
2315 8084f9f6 Manuel Franceschini
2316 779c15bb Iustin Pop
    node_list = self.acquired_locks[locking.LEVEL_NODE]
2317 779c15bb Iustin Pop
2318 8084f9f6 Manuel Franceschini
    # if vg_name not None, checks given volume group on all nodes
2319 8084f9f6 Manuel Franceschini
    if self.op.vg_name:
2320 72737a7f Iustin Pop
      vglist = self.rpc.call_vg_list(node_list)
2321 8084f9f6 Manuel Franceschini
      for node in node_list:
2322 4c4e4e1e Iustin Pop
        msg = vglist[node].fail_msg
2323 e480923b Iustin Pop
        if msg:
2324 781de953 Iustin Pop
          # ignoring down node
2325 e480923b Iustin Pop
          self.LogWarning("Error while gathering data on node %s"
2326 e480923b Iustin Pop
                          " (ignoring node): %s", node, msg)
2327 781de953 Iustin Pop
          continue
2328 e480923b Iustin Pop
        vgstatus = utils.CheckVolumeGroupSize(vglist[node].payload,
2329 781de953 Iustin Pop
                                              self.op.vg_name,
2330 8d1a2a64 Michael Hanselmann
                                              constants.MIN_VG_SIZE)
2331 8084f9f6 Manuel Franceschini
        if vgstatus:
2332 8084f9f6 Manuel Franceschini
          raise errors.OpPrereqError("Error on node '%s': %s" %
2333 5c983ee5 Iustin Pop
                                     (node, vgstatus), errors.ECODE_ENVIRON)
2334 8084f9f6 Manuel Franceschini
2335 779c15bb Iustin Pop
    self.cluster = cluster = self.cfg.GetClusterInfo()
2336 5af3da74 Guido Trotter
    # validate params changes
2337 779c15bb Iustin Pop
    if self.op.beparams:
2338 a5728081 Guido Trotter
      utils.ForceDictType(self.op.beparams, constants.BES_PARAMETER_TYPES)
2339 abe609b2 Guido Trotter
      self.new_beparams = objects.FillDict(
2340 4ef7f423 Guido Trotter
        cluster.beparams[constants.PP_DEFAULT], self.op.beparams)
2341 779c15bb Iustin Pop
2342 5af3da74 Guido Trotter
    if self.op.nicparams:
2343 5af3da74 Guido Trotter
      utils.ForceDictType(self.op.nicparams, constants.NICS_PARAMETER_TYPES)
2344 5af3da74 Guido Trotter
      self.new_nicparams = objects.FillDict(
2345 5af3da74 Guido Trotter
        cluster.nicparams[constants.PP_DEFAULT], self.op.nicparams)
2346 5af3da74 Guido Trotter
      objects.NIC.CheckParameterSyntax(self.new_nicparams)
2347 90b704a1 Guido Trotter
      nic_errors = []
2348 90b704a1 Guido Trotter
2349 90b704a1 Guido Trotter
      # check all instances for consistency
2350 90b704a1 Guido Trotter
      for instance in self.cfg.GetAllInstancesInfo().values():
2351 90b704a1 Guido Trotter
        for nic_idx, nic in enumerate(instance.nics):
2352 90b704a1 Guido Trotter
          params_copy = copy.deepcopy(nic.nicparams)
2353 90b704a1 Guido Trotter
          params_filled = objects.FillDict(self.new_nicparams, params_copy)
2354 90b704a1 Guido Trotter
2355 90b704a1 Guido Trotter
          # check parameter syntax
2356 90b704a1 Guido Trotter
          try:
2357 90b704a1 Guido Trotter
            objects.NIC.CheckParameterSyntax(params_filled)
2358 90b704a1 Guido Trotter
          except errors.ConfigurationError, err:
2359 90b704a1 Guido Trotter
            nic_errors.append("Instance %s, nic/%d: %s" %
2360 90b704a1 Guido Trotter
                              (instance.name, nic_idx, err))
2361 90b704a1 Guido Trotter
2362 90b704a1 Guido Trotter
          # if we're moving instances to routed, check that they have an ip
2363 90b704a1 Guido Trotter
          target_mode = params_filled[constants.NIC_MODE]
2364 90b704a1 Guido Trotter
          if target_mode == constants.NIC_MODE_ROUTED and not nic.ip:
2365 90b704a1 Guido Trotter
            nic_errors.append("Instance %s, nic/%d: routed nick with no ip" %
2366 90b704a1 Guido Trotter
                              (instance.name, nic_idx))
2367 90b704a1 Guido Trotter
      if nic_errors:
2368 90b704a1 Guido Trotter
        raise errors.OpPrereqError("Cannot apply the change, errors:\n%s" %
2369 90b704a1 Guido Trotter
                                   "\n".join(nic_errors))
2370 5af3da74 Guido Trotter
2371 779c15bb Iustin Pop
    # hypervisor list/parameters
2372 abe609b2 Guido Trotter
    self.new_hvparams = objects.FillDict(cluster.hvparams, {})
2373 779c15bb Iustin Pop
    if self.op.hvparams:
2374 779c15bb Iustin Pop
      if not isinstance(self.op.hvparams, dict):
2375 5c983ee5 Iustin Pop
        raise errors.OpPrereqError("Invalid 'hvparams' parameter on input",
2376 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
2377 779c15bb Iustin Pop
      for hv_name, hv_dict in self.op.hvparams.items():
2378 779c15bb Iustin Pop
        if hv_name not in self.new_hvparams:
2379 779c15bb Iustin Pop
          self.new_hvparams[hv_name] = hv_dict
2380 779c15bb Iustin Pop
        else:
2381 779c15bb Iustin Pop
          self.new_hvparams[hv_name].update(hv_dict)
2382 779c15bb Iustin Pop
2383 17463d22 Renรฉ Nussbaumer
    # os hypervisor parameters
2384 17463d22 Renรฉ Nussbaumer
    self.new_os_hvp = objects.FillDict(cluster.os_hvp, {})
2385 17463d22 Renรฉ Nussbaumer
    if self.op.os_hvp:
2386 17463d22 Renรฉ Nussbaumer
      if not isinstance(self.op.os_hvp, dict):
2387 17463d22 Renรฉ Nussbaumer
        raise errors.OpPrereqError("Invalid 'os_hvp' parameter on input",
2388 17463d22 Renรฉ Nussbaumer
                                   errors.ECODE_INVAL)
2389 17463d22 Renรฉ Nussbaumer
      for os_name, hvs in self.op.os_hvp.items():
2390 17463d22 Renรฉ Nussbaumer
        if not isinstance(hvs, dict):
2391 17463d22 Renรฉ Nussbaumer
          raise errors.OpPrereqError(("Invalid 'os_hvp' parameter on"
2392 17463d22 Renรฉ Nussbaumer
                                      " input"), errors.ECODE_INVAL)
2393 17463d22 Renรฉ Nussbaumer
        if os_name not in self.new_os_hvp:
2394 17463d22 Renรฉ Nussbaumer
          self.new_os_hvp[os_name] = hvs
2395 17463d22 Renรฉ Nussbaumer
        else:
2396 17463d22 Renรฉ Nussbaumer
          for hv_name, hv_dict in hvs.items():
2397 17463d22 Renรฉ Nussbaumer
            if hv_name not in self.new_os_hvp[os_name]:
2398 17463d22 Renรฉ Nussbaumer
              self.new_os_hvp[os_name][hv_name] = hv_dict
2399 17463d22 Renรฉ Nussbaumer
            else:
2400 17463d22 Renรฉ Nussbaumer
              self.new_os_hvp[os_name][hv_name].update(hv_dict)
2401 17463d22 Renรฉ Nussbaumer
2402 779c15bb Iustin Pop
    if self.op.enabled_hypervisors is not None:
2403 779c15bb Iustin Pop
      self.hv_list = self.op.enabled_hypervisors
2404 b119bccb Guido Trotter
      if not self.hv_list:
2405 b119bccb Guido Trotter
        raise errors.OpPrereqError("Enabled hypervisors list must contain at"
2406 5c983ee5 Iustin Pop
                                   " least one member",
2407 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
2408 b119bccb Guido Trotter
      invalid_hvs = set(self.hv_list) - constants.HYPER_TYPES
2409 b119bccb Guido Trotter
      if invalid_hvs:
2410 b119bccb Guido Trotter
        raise errors.OpPrereqError("Enabled hypervisors contains invalid"
2411 ab3e6da8 Iustin Pop
                                   " entries: %s" %
2412 ab3e6da8 Iustin Pop
                                   utils.CommaJoin(invalid_hvs),
2413 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
2414 779c15bb Iustin Pop
    else:
2415 779c15bb Iustin Pop
      self.hv_list = cluster.enabled_hypervisors
2416 779c15bb Iustin Pop
2417 779c15bb Iustin Pop
    if self.op.hvparams or self.op.enabled_hypervisors is not None:
2418 779c15bb Iustin Pop
      # either the enabled list has changed, or the parameters have, validate
2419 779c15bb Iustin Pop
      for hv_name, hv_params in self.new_hvparams.items():
2420 779c15bb Iustin Pop
        if ((self.op.hvparams and hv_name in self.op.hvparams) or
2421 779c15bb Iustin Pop
            (self.op.enabled_hypervisors and
2422 779c15bb Iustin Pop
             hv_name in self.op.enabled_hypervisors)):
2423 779c15bb Iustin Pop
          # either this is a new hypervisor, or its parameters have changed
2424 779c15bb Iustin Pop
          hv_class = hypervisor.GetHypervisor(hv_name)
2425 a5728081 Guido Trotter
          utils.ForceDictType(hv_params, constants.HVS_PARAMETER_TYPES)
2426 779c15bb Iustin Pop
          hv_class.CheckParameterSyntax(hv_params)
2427 779c15bb Iustin Pop
          _CheckHVParams(self, node_list, hv_name, hv_params)
2428 779c15bb Iustin Pop
2429 cced4c39 Iustin Pop
    if self.op.os_hvp:
2430 cced4c39 Iustin Pop
      # no need to check any newly-enabled hypervisors, since the
2431 cced4c39 Iustin Pop
      # defaults have already been checked in the above code-block
2432 cced4c39 Iustin Pop
      for os_name, os_hvp in self.new_os_hvp.items():
2433 cced4c39 Iustin Pop
        for hv_name, hv_params in os_hvp.items():
2434 cced4c39 Iustin Pop
          utils.ForceDictType(hv_params, constants.HVS_PARAMETER_TYPES)
2435 cced4c39 Iustin Pop
          # we need to fill in the new os_hvp on top of the actual hv_p
2436 cced4c39 Iustin Pop
          cluster_defaults = self.new_hvparams.get(hv_name, {})
2437 cced4c39 Iustin Pop
          new_osp = objects.FillDict(cluster_defaults, hv_params)
2438 cced4c39 Iustin Pop
          hv_class = hypervisor.GetHypervisor(hv_name)
2439 cced4c39 Iustin Pop
          hv_class.CheckParameterSyntax(new_osp)
2440 cced4c39 Iustin Pop
          _CheckHVParams(self, node_list, hv_name, new_osp)
2441 cced4c39 Iustin Pop
2442 cced4c39 Iustin Pop
2443 8084f9f6 Manuel Franceschini
  def Exec(self, feedback_fn):
2444 8084f9f6 Manuel Franceschini
    """Change the parameters of the cluster.
2445 8084f9f6 Manuel Franceschini

2446 8084f9f6 Manuel Franceschini
    """
2447 779c15bb Iustin Pop
    if self.op.vg_name is not None:
2448 b2482333 Guido Trotter
      new_volume = self.op.vg_name
2449 b2482333 Guido Trotter
      if not new_volume:
2450 b2482333 Guido Trotter
        new_volume = None
2451 b2482333 Guido Trotter
      if new_volume != self.cfg.GetVGName():
2452 b2482333 Guido Trotter
        self.cfg.SetVGName(new_volume)
2453 779c15bb Iustin Pop
      else:
2454 779c15bb Iustin Pop
        feedback_fn("Cluster LVM configuration already in desired"
2455 779c15bb Iustin Pop
                    " state, not changing")
2456 779c15bb Iustin Pop
    if self.op.hvparams:
2457 779c15bb Iustin Pop
      self.cluster.hvparams = self.new_hvparams
2458 17463d22 Renรฉ Nussbaumer
    if self.op.os_hvp:
2459 17463d22 Renรฉ Nussbaumer
      self.cluster.os_hvp = self.new_os_hvp
2460 779c15bb Iustin Pop
    if self.op.enabled_hypervisors is not None:
2461 779c15bb Iustin Pop
      self.cluster.enabled_hypervisors = self.op.enabled_hypervisors
2462 779c15bb Iustin Pop
    if self.op.beparams:
2463 4ef7f423 Guido Trotter
      self.cluster.beparams[constants.PP_DEFAULT] = self.new_beparams
2464 5af3da74 Guido Trotter
    if self.op.nicparams:
2465 5af3da74 Guido Trotter
      self.cluster.nicparams[constants.PP_DEFAULT] = self.new_nicparams
2466 5af3da74 Guido Trotter
2467 4b7735f9 Iustin Pop
    if self.op.candidate_pool_size is not None:
2468 4b7735f9 Iustin Pop
      self.cluster.candidate_pool_size = self.op.candidate_pool_size
2469 75e914fb Iustin Pop
      # we need to update the pool size here, otherwise the save will fail
2470 44485f49 Guido Trotter
      _AdjustCandidatePool(self, [])
2471 4b7735f9 Iustin Pop
2472 3953242f Iustin Pop
    if self.op.maintain_node_health is not None:
2473 3953242f Iustin Pop
      self.cluster.maintain_node_health = self.op.maintain_node_health
2474 3953242f Iustin Pop
2475 fdad8c4d Balazs Lecz
    if self.op.add_uids is not None:
2476 fdad8c4d Balazs Lecz
      uidpool.AddToUidPool(self.cluster.uid_pool, self.op.add_uids)
2477 fdad8c4d Balazs Lecz
2478 fdad8c4d Balazs Lecz
    if self.op.remove_uids is not None:
2479 fdad8c4d Balazs Lecz
      uidpool.RemoveFromUidPool(self.cluster.uid_pool, self.op.remove_uids)
2480 fdad8c4d Balazs Lecz
2481 1338f2b4 Balazs Lecz
    if self.op.uid_pool is not None:
2482 1338f2b4 Balazs Lecz
      self.cluster.uid_pool = self.op.uid_pool
2483 1338f2b4 Balazs Lecz
2484 a4eae71f Michael Hanselmann
    self.cfg.Update(self.cluster, feedback_fn)
2485 8084f9f6 Manuel Franceschini
2486 8084f9f6 Manuel Franceschini
2487 28eddce5 Guido Trotter
def _RedistributeAncillaryFiles(lu, additional_nodes=None):
2488 28eddce5 Guido Trotter
  """Distribute additional files which are part of the cluster configuration.
2489 28eddce5 Guido Trotter

2490 28eddce5 Guido Trotter
  ConfigWriter takes care of distributing the config and ssconf files, but
2491 28eddce5 Guido Trotter
  there are more files which should be distributed to all nodes. This function
2492 28eddce5 Guido Trotter
  makes sure those are copied.
2493 28eddce5 Guido Trotter

2494 28eddce5 Guido Trotter
  @param lu: calling logical unit
2495 28eddce5 Guido Trotter
  @param additional_nodes: list of nodes not in the config to distribute to
2496 28eddce5 Guido Trotter

2497 28eddce5 Guido Trotter
  """
2498 28eddce5 Guido Trotter
  # 1. Gather target nodes
2499 28eddce5 Guido Trotter
  myself = lu.cfg.GetNodeInfo(lu.cfg.GetMasterNode())
2500 6819dc49 Iustin Pop
  dist_nodes = lu.cfg.GetOnlineNodeList()
2501 28eddce5 Guido Trotter
  if additional_nodes is not None:
2502 28eddce5 Guido Trotter
    dist_nodes.extend(additional_nodes)
2503 28eddce5 Guido Trotter
  if myself.name in dist_nodes:
2504 28eddce5 Guido Trotter
    dist_nodes.remove(myself.name)
2505 a4eae71f Michael Hanselmann
2506 28eddce5 Guido Trotter
  # 2. Gather files to distribute
2507 28eddce5 Guido Trotter
  dist_files = set([constants.ETC_HOSTS,
2508 28eddce5 Guido Trotter
                    constants.SSH_KNOWN_HOSTS_FILE,
2509 28eddce5 Guido Trotter
                    constants.RAPI_CERT_FILE,
2510 28eddce5 Guido Trotter
                    constants.RAPI_USERS_FILE,
2511 6b7d5878 Michael Hanselmann
                    constants.CONFD_HMAC_KEY,
2512 28eddce5 Guido Trotter
                   ])
2513 e1b8653f Guido Trotter
2514 e1b8653f Guido Trotter
  enabled_hypervisors = lu.cfg.GetClusterInfo().enabled_hypervisors
2515 e1b8653f Guido Trotter
  for hv_name in enabled_hypervisors:
2516 e1b8653f Guido Trotter
    hv_class = hypervisor.GetHypervisor(hv_name)
2517 e1b8653f Guido Trotter
    dist_files.update(hv_class.GetAncillaryFiles())
2518 e1b8653f Guido Trotter
2519 28eddce5 Guido Trotter
  # 3. Perform the files upload
2520 28eddce5 Guido Trotter
  for fname in dist_files:
2521 28eddce5 Guido Trotter
    if os.path.exists(fname):
2522 28eddce5 Guido Trotter
      result = lu.rpc.call_upload_file(dist_nodes, fname)
2523 28eddce5 Guido Trotter
      for to_node, to_result in result.items():
2524 6f7d4e75 Iustin Pop
        msg = to_result.fail_msg
2525 6f7d4e75 Iustin Pop
        if msg:
2526 6f7d4e75 Iustin Pop
          msg = ("Copy of file %s to node %s failed: %s" %
2527 6f7d4e75 Iustin Pop
                 (fname, to_node, msg))
2528 6f7d4e75 Iustin Pop
          lu.proc.LogWarning(msg)
2529 28eddce5 Guido Trotter
2530 28eddce5 Guido Trotter
2531 afee0879 Iustin Pop
class LURedistributeConfig(NoHooksLU):
2532 afee0879 Iustin Pop
  """Force the redistribution of cluster configuration.
2533 afee0879 Iustin Pop

2534 afee0879 Iustin Pop
  This is a very simple LU.
2535 afee0879 Iustin Pop

2536 afee0879 Iustin Pop
  """
2537 afee0879 Iustin Pop
  _OP_REQP = []
2538 afee0879 Iustin Pop
  REQ_BGL = False
2539 afee0879 Iustin Pop
2540 afee0879 Iustin Pop
  def ExpandNames(self):
2541 afee0879 Iustin Pop
    self.needed_locks = {
2542 afee0879 Iustin Pop
      locking.LEVEL_NODE: locking.ALL_SET,
2543 afee0879 Iustin Pop
    }
2544 afee0879 Iustin Pop
    self.share_locks[locking.LEVEL_NODE] = 1
2545 afee0879 Iustin Pop
2546 afee0879 Iustin Pop
  def CheckPrereq(self):
2547 afee0879 Iustin Pop
    """Check prerequisites.
2548 afee0879 Iustin Pop

2549 afee0879 Iustin Pop
    """
2550 afee0879 Iustin Pop
2551 afee0879 Iustin Pop
  def Exec(self, feedback_fn):
2552 afee0879 Iustin Pop
    """Redistribute the configuration.
2553 afee0879 Iustin Pop

2554 afee0879 Iustin Pop
    """
2555 a4eae71f Michael Hanselmann
    self.cfg.Update(self.cfg.GetClusterInfo(), feedback_fn)
2556 28eddce5 Guido Trotter
    _RedistributeAncillaryFiles(self)
2557 afee0879 Iustin Pop
2558 afee0879 Iustin Pop
2559 b6c07b79 Michael Hanselmann
def _WaitForSync(lu, instance, oneshot=False):
2560 a8083063 Iustin Pop
  """Sleep and poll for an instance's disk to sync.
2561 a8083063 Iustin Pop

2562 a8083063 Iustin Pop
  """
2563 a8083063 Iustin Pop
  if not instance.disks:
2564 a8083063 Iustin Pop
    return True
2565 a8083063 Iustin Pop
2566 a8083063 Iustin Pop
  if not oneshot:
2567 b9bddb6b Iustin Pop
    lu.proc.LogInfo("Waiting for instance %s to sync disks." % instance.name)
2568 a8083063 Iustin Pop
2569 a8083063 Iustin Pop
  node = instance.primary_node
2570 a8083063 Iustin Pop
2571 a8083063 Iustin Pop
  for dev in instance.disks:
2572 b9bddb6b Iustin Pop
    lu.cfg.SetDiskID(dev, node)
2573 a8083063 Iustin Pop
2574 6bcb1446 Michael Hanselmann
  # TODO: Convert to utils.Retry
2575 6bcb1446 Michael Hanselmann
2576 a8083063 Iustin Pop
  retries = 0
2577 fbafd7a8 Iustin Pop
  degr_retries = 10 # in seconds, as we sleep 1 second each time
2578 a8083063 Iustin Pop
  while True:
2579 a8083063 Iustin Pop
    max_time = 0
2580 a8083063 Iustin Pop
    done = True
2581 a8083063 Iustin Pop
    cumul_degraded = False
2582 72737a7f Iustin Pop
    rstats = lu.rpc.call_blockdev_getmirrorstatus(node, instance.disks)
2583 4c4e4e1e Iustin Pop
    msg = rstats.fail_msg
2584 3efa9051 Iustin Pop
    if msg:
2585 3efa9051 Iustin Pop
      lu.LogWarning("Can't get any data from node %s: %s", node, msg)
2586 a8083063 Iustin Pop
      retries += 1
2587 a8083063 Iustin Pop
      if retries >= 10:
2588 3ecf6786 Iustin Pop
        raise errors.RemoteError("Can't contact node %s for mirror data,"
2589 3ecf6786 Iustin Pop
                                 " aborting." % node)
2590 a8083063 Iustin Pop
      time.sleep(6)
2591 a8083063 Iustin Pop
      continue
2592 3efa9051 Iustin Pop
    rstats = rstats.payload
2593 a8083063 Iustin Pop
    retries = 0
2594 1492cca7 Iustin Pop
    for i, mstat in enumerate(rstats):
2595 a8083063 Iustin Pop
      if mstat is None:
2596 86d9d3bb Iustin Pop
        lu.LogWarning("Can't compute data for node %s/%s",
2597 86d9d3bb Iustin Pop
                           node, instance.disks[i].iv_name)
2598 a8083063 Iustin Pop
        continue
2599 36145b12 Michael Hanselmann
2600 36145b12 Michael Hanselmann
      cumul_degraded = (cumul_degraded or
2601 36145b12 Michael Hanselmann
                        (mstat.is_degraded and mstat.sync_percent is None))
2602 36145b12 Michael Hanselmann
      if mstat.sync_percent is not None:
2603 a8083063 Iustin Pop
        done = False
2604 36145b12 Michael Hanselmann
        if mstat.estimated_time is not None:
2605 36145b12 Michael Hanselmann
          rem_time = "%d estimated seconds remaining" % mstat.estimated_time
2606 36145b12 Michael Hanselmann
          max_time = mstat.estimated_time
2607 a8083063 Iustin Pop
        else:
2608 a8083063 Iustin Pop
          rem_time = "no time estimate"
2609 b9bddb6b Iustin Pop
        lu.proc.LogInfo("- device %s: %5.2f%% done, %s" %
2610 4d4a651d Michael Hanselmann
                        (instance.disks[i].iv_name, mstat.sync_percent,
2611 4d4a651d Michael Hanselmann
                         rem_time))
2612 fbafd7a8 Iustin Pop
2613 fbafd7a8 Iustin Pop
    # if we're done but degraded, let's do a few small retries, to
2614 fbafd7a8 Iustin Pop
    # make sure we see a stable and not transient situation; therefore
2615 fbafd7a8 Iustin Pop
    # we force restart of the loop
2616 fbafd7a8 Iustin Pop
    if (done or oneshot) and cumul_degraded and degr_retries > 0:
2617 fbafd7a8 Iustin Pop
      logging.info("Degraded disks found, %d retries left", degr_retries)
2618 fbafd7a8 Iustin Pop
      degr_retries -= 1
2619 fbafd7a8 Iustin Pop
      time.sleep(1)
2620 fbafd7a8 Iustin Pop
      continue
2621 fbafd7a8 Iustin Pop
2622 a8083063 Iustin Pop
    if done or oneshot:
2623 a8083063 Iustin Pop
      break
2624 a8083063 Iustin Pop
2625 d4fa5c23 Iustin Pop
    time.sleep(min(60, max_time))
2626 a8083063 Iustin Pop
2627 a8083063 Iustin Pop
  if done:
2628 b9bddb6b Iustin Pop
    lu.proc.LogInfo("Instance %s's disks are in sync." % instance.name)
2629 a8083063 Iustin Pop
  return not cumul_degraded
2630 a8083063 Iustin Pop
2631 a8083063 Iustin Pop
2632 b9bddb6b Iustin Pop
def _CheckDiskConsistency(lu, dev, node, on_primary, ldisk=False):
2633 a8083063 Iustin Pop
  """Check that mirrors are not degraded.
2634 a8083063 Iustin Pop

2635 0834c866 Iustin Pop
  The ldisk parameter, if True, will change the test from the
2636 0834c866 Iustin Pop
  is_degraded attribute (which represents overall non-ok status for
2637 0834c866 Iustin Pop
  the device(s)) to the ldisk (representing the local storage status).
2638 0834c866 Iustin Pop

2639 a8083063 Iustin Pop
  """
2640 b9bddb6b Iustin Pop
  lu.cfg.SetDiskID(dev, node)
2641 a8083063 Iustin Pop
2642 a8083063 Iustin Pop
  result = True
2643 96acbc09 Michael Hanselmann
2644 a8083063 Iustin Pop
  if on_primary or dev.AssembleOnSecondary():
2645 72737a7f Iustin Pop
    rstats = lu.rpc.call_blockdev_find(node, dev)
2646 4c4e4e1e Iustin Pop
    msg = rstats.fail_msg
2647 23829f6f Iustin Pop
    if msg:
2648 23829f6f Iustin Pop
      lu.LogWarning("Can't find disk on node %s: %s", node, msg)
2649 23829f6f Iustin Pop
      result = False
2650 23829f6f Iustin Pop
    elif not rstats.payload:
2651 23829f6f Iustin Pop
      lu.LogWarning("Can't find disk on node %s", node)
2652 a8083063 Iustin Pop
      result = False
2653 a8083063 Iustin Pop
    else:
2654 96acbc09 Michael Hanselmann
      if ldisk:
2655 f208978a Michael Hanselmann
        result = result and rstats.payload.ldisk_status == constants.LDS_OKAY
2656 96acbc09 Michael Hanselmann
      else:
2657 96acbc09 Michael Hanselmann
        result = result and not rstats.payload.is_degraded
2658 96acbc09 Michael Hanselmann
2659 a8083063 Iustin Pop
  if dev.children:
2660 a8083063 Iustin Pop
    for child in dev.children:
2661 b9bddb6b Iustin Pop
      result = result and _CheckDiskConsistency(lu, child, node, on_primary)
2662 a8083063 Iustin Pop
2663 a8083063 Iustin Pop
  return result
2664 a8083063 Iustin Pop
2665 a8083063 Iustin Pop
2666 a8083063 Iustin Pop
class LUDiagnoseOS(NoHooksLU):
2667 a8083063 Iustin Pop
  """Logical unit for OS diagnose/query.
2668 a8083063 Iustin Pop

2669 a8083063 Iustin Pop
  """
2670 1f9430d6 Iustin Pop
  _OP_REQP = ["output_fields", "names"]
2671 6bf01bbb Guido Trotter
  REQ_BGL = False
2672 a2d2e1a7 Iustin Pop
  _FIELDS_STATIC = utils.FieldSet()
2673 1e288a26 Guido Trotter
  _FIELDS_DYNAMIC = utils.FieldSet("name", "valid", "node_status", "variants")
2674 1e288a26 Guido Trotter
  # Fields that need calculation of global os validity
2675 1e288a26 Guido Trotter
  _FIELDS_NEEDVALID = frozenset(["valid", "variants"])
2676 a8083063 Iustin Pop
2677 6bf01bbb Guido Trotter
  def ExpandNames(self):
2678 1f9430d6 Iustin Pop
    if self.op.names:
2679 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Selective OS query not supported",
2680 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
2681 1f9430d6 Iustin Pop
2682 31bf511f Iustin Pop
    _CheckOutputFields(static=self._FIELDS_STATIC,
2683 31bf511f Iustin Pop
                       dynamic=self._FIELDS_DYNAMIC,
2684 1f9430d6 Iustin Pop
                       selected=self.op.output_fields)
2685 1f9430d6 Iustin Pop
2686 6bf01bbb Guido Trotter
    # Lock all nodes, in shared mode
2687 a6ab004b Iustin Pop
    # Temporary removal of locks, should be reverted later
2688 a6ab004b Iustin Pop
    # TODO: reintroduce locks when they are lighter-weight
2689 6bf01bbb Guido Trotter
    self.needed_locks = {}
2690 a6ab004b Iustin Pop
    #self.share_locks[locking.LEVEL_NODE] = 1
2691 a6ab004b Iustin Pop
    #self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
2692 6bf01bbb Guido Trotter
2693 6bf01bbb Guido Trotter
  def CheckPrereq(self):
2694 6bf01bbb Guido Trotter
    """Check prerequisites.
2695 6bf01bbb Guido Trotter

2696 6bf01bbb Guido Trotter
    """
2697 6bf01bbb Guido Trotter
2698 1f9430d6 Iustin Pop
  @staticmethod
2699 857121ad Iustin Pop
  def _DiagnoseByOS(rlist):
2700 1f9430d6 Iustin Pop
    """Remaps a per-node return list into an a per-os per-node dictionary
2701 1f9430d6 Iustin Pop

2702 e4376078 Iustin Pop
    @param rlist: a map with node names as keys and OS objects as values
2703 1f9430d6 Iustin Pop

2704 e4376078 Iustin Pop
    @rtype: dict
2705 5fcc718f Iustin Pop
    @return: a dictionary with osnames as keys and as value another map, with
2706 255dcebd Iustin Pop
        nodes as keys and tuples of (path, status, diagnose) as values, eg::
2707 e4376078 Iustin Pop

2708 255dcebd Iustin Pop
          {"debian-etch": {"node1": [(/usr/lib/..., True, ""),
2709 255dcebd Iustin Pop
                                     (/srv/..., False, "invalid api")],
2710 255dcebd Iustin Pop
                           "node2": [(/srv/..., True, "")]}
2711 e4376078 Iustin Pop
          }
2712 1f9430d6 Iustin Pop

2713 1f9430d6 Iustin Pop
    """
2714 1f9430d6 Iustin Pop
    all_os = {}
2715 a6ab004b Iustin Pop
    # we build here the list of nodes that didn't fail the RPC (at RPC
2716 a6ab004b Iustin Pop
    # level), so that nodes with a non-responding node daemon don't
2717 a6ab004b Iustin Pop
    # make all OSes invalid
2718 a6ab004b Iustin Pop
    good_nodes = [node_name for node_name in rlist
2719 4c4e4e1e Iustin Pop
                  if not rlist[node_name].fail_msg]
2720 83d92ad8 Iustin Pop
    for node_name, nr in rlist.items():
2721 4c4e4e1e Iustin Pop
      if nr.fail_msg or not nr.payload:
2722 1f9430d6 Iustin Pop
        continue
2723 ba00557a Guido Trotter
      for name, path, status, diagnose, variants in nr.payload:
2724 255dcebd Iustin Pop
        if name not in all_os:
2725 1f9430d6 Iustin Pop
          # build a list of nodes for this os containing empty lists
2726 1f9430d6 Iustin Pop
          # for each node in node_list
2727 255dcebd Iustin Pop
          all_os[name] = {}
2728 a6ab004b Iustin Pop
          for nname in good_nodes:
2729 255dcebd Iustin Pop
            all_os[name][nname] = []
2730 ba00557a Guido Trotter
        all_os[name][node_name].append((path, status, diagnose, variants))
2731 1f9430d6 Iustin Pop
    return all_os
2732 a8083063 Iustin Pop
2733 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
2734 a8083063 Iustin Pop
    """Compute the list of OSes.
2735 a8083063 Iustin Pop

2736 a8083063 Iustin Pop
    """
2737 a6ab004b Iustin Pop
    valid_nodes = [node for node in self.cfg.GetOnlineNodeList()]
2738 94a02bb5 Iustin Pop
    node_data = self.rpc.call_os_diagnose(valid_nodes)
2739 857121ad Iustin Pop
    pol = self._DiagnoseByOS(node_data)
2740 1f9430d6 Iustin Pop
    output = []
2741 1e288a26 Guido Trotter
    calc_valid = self._FIELDS_NEEDVALID.intersection(self.op.output_fields)
2742 1e288a26 Guido Trotter
    calc_variants = "variants" in self.op.output_fields
2743 1e288a26 Guido Trotter
2744 83d92ad8 Iustin Pop
    for os_name, os_data in pol.items():
2745 1f9430d6 Iustin Pop
      row = []
2746 1e288a26 Guido Trotter
      if calc_valid:
2747 1e288a26 Guido Trotter
        valid = True
2748 1e288a26 Guido Trotter
        variants = None
2749 1e288a26 Guido Trotter
        for osl in os_data.values():
2750 1e288a26 Guido Trotter
          valid = valid and osl and osl[0][1]
2751 1e288a26 Guido Trotter
          if not valid:
2752 1e288a26 Guido Trotter
            variants = None
2753 1e288a26 Guido Trotter
            break
2754 1e288a26 Guido Trotter
          if calc_variants:
2755 1e288a26 Guido Trotter
            node_variants = osl[0][3]
2756 1e288a26 Guido Trotter
            if variants is None:
2757 1e288a26 Guido Trotter
              variants = node_variants
2758 1e288a26 Guido Trotter
            else:
2759 1e288a26 Guido Trotter
              variants = [v for v in variants if v in node_variants]
2760 1e288a26 Guido Trotter
2761 1f9430d6 Iustin Pop
      for field in self.op.output_fields:
2762 1f9430d6 Iustin Pop
        if field == "name":
2763 1f9430d6 Iustin Pop
          val = os_name
2764 1f9430d6 Iustin Pop
        elif field == "valid":
2765 1e288a26 Guido Trotter
          val = valid
2766 1f9430d6 Iustin Pop
        elif field == "node_status":
2767 255dcebd Iustin Pop
          # this is just a copy of the dict
2768 1f9430d6 Iustin Pop
          val = {}
2769 255dcebd Iustin Pop
          for node_name, nos_list in os_data.items():
2770 255dcebd Iustin Pop
            val[node_name] = nos_list
2771 1e288a26 Guido Trotter
        elif field == "variants":
2772 1e288a26 Guido Trotter
          val =  variants
2773 1f9430d6 Iustin Pop
        else:
2774 1f9430d6 Iustin Pop
          raise errors.ParameterError(field)
2775 1f9430d6 Iustin Pop
        row.append(val)
2776 1f9430d6 Iustin Pop
      output.append(row)
2777 1f9430d6 Iustin Pop
2778 1f9430d6 Iustin Pop
    return output
2779 a8083063 Iustin Pop
2780 a8083063 Iustin Pop
2781 a8083063 Iustin Pop
class LURemoveNode(LogicalUnit):
2782 a8083063 Iustin Pop
  """Logical unit for removing a node.
2783 a8083063 Iustin Pop

2784 a8083063 Iustin Pop
  """
2785 a8083063 Iustin Pop
  HPATH = "node-remove"
2786 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_NODE
2787 a8083063 Iustin Pop
  _OP_REQP = ["node_name"]
2788 a8083063 Iustin Pop
2789 a8083063 Iustin Pop
  def BuildHooksEnv(self):
2790 a8083063 Iustin Pop
    """Build hooks env.
2791 a8083063 Iustin Pop

2792 a8083063 Iustin Pop
    This doesn't run on the target node in the pre phase as a failed
2793 d08869ee Guido Trotter
    node would then be impossible to remove.
2794 a8083063 Iustin Pop

2795 a8083063 Iustin Pop
    """
2796 396e1b78 Michael Hanselmann
    env = {
2797 0e137c28 Iustin Pop
      "OP_TARGET": self.op.node_name,
2798 396e1b78 Michael Hanselmann
      "NODE_NAME": self.op.node_name,
2799 396e1b78 Michael Hanselmann
      }
2800 a8083063 Iustin Pop
    all_nodes = self.cfg.GetNodeList()
2801 9bb31ea8 Iustin Pop
    try:
2802 cd46f3b4 Luca Bigliardi
      all_nodes.remove(self.op.node_name)
2803 9bb31ea8 Iustin Pop
    except ValueError:
2804 9bb31ea8 Iustin Pop
      logging.warning("Node %s which is about to be removed not found"
2805 9bb31ea8 Iustin Pop
                      " in the all nodes list", self.op.node_name)
2806 396e1b78 Michael Hanselmann
    return env, all_nodes, all_nodes
2807 a8083063 Iustin Pop
2808 a8083063 Iustin Pop
  def CheckPrereq(self):
2809 a8083063 Iustin Pop
    """Check prerequisites.
2810 a8083063 Iustin Pop

2811 a8083063 Iustin Pop
    This checks:
2812 a8083063 Iustin Pop
     - the node exists in the configuration
2813 a8083063 Iustin Pop
     - it does not have primary or secondary instances
2814 a8083063 Iustin Pop
     - it's not the master
2815 a8083063 Iustin Pop

2816 5bbd3f7f Michael Hanselmann
    Any errors are signaled by raising errors.OpPrereqError.
2817 a8083063 Iustin Pop

2818 a8083063 Iustin Pop
    """
2819 cf26a87a Iustin Pop
    self.op.node_name = _ExpandNodeName(self.cfg, self.op.node_name)
2820 cf26a87a Iustin Pop
    node = self.cfg.GetNodeInfo(self.op.node_name)
2821 cf26a87a Iustin Pop
    assert node is not None
2822 a8083063 Iustin Pop
2823 a8083063 Iustin Pop
    instance_list = self.cfg.GetInstanceList()
2824 a8083063 Iustin Pop
2825 d6a02168 Michael Hanselmann
    masternode = self.cfg.GetMasterNode()
2826 a8083063 Iustin Pop
    if node.name == masternode:
2827 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Node is the master node,"
2828 5c983ee5 Iustin Pop
                                 " you need to failover first.",
2829 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
2830 a8083063 Iustin Pop
2831 a8083063 Iustin Pop
    for instance_name in instance_list:
2832 a8083063 Iustin Pop
      instance = self.cfg.GetInstanceInfo(instance_name)
2833 6b12959c Iustin Pop
      if node.name in instance.all_nodes:
2834 6b12959c Iustin Pop
        raise errors.OpPrereqError("Instance %s is still running on the node,"
2835 5c983ee5 Iustin Pop
                                   " please remove first." % instance_name,
2836 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
2837 a8083063 Iustin Pop
    self.op.node_name = node.name
2838 a8083063 Iustin Pop
    self.node = node
2839 a8083063 Iustin Pop
2840 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
2841 a8083063 Iustin Pop
    """Removes the node from the cluster.
2842 a8083063 Iustin Pop

2843 a8083063 Iustin Pop
    """
2844 a8083063 Iustin Pop
    node = self.node
2845 9a4f63d1 Iustin Pop
    logging.info("Stopping the node daemon and removing configs from node %s",
2846 9a4f63d1 Iustin Pop
                 node.name)
2847 a8083063 Iustin Pop
2848 b989b9d9 Ken Wehr
    modify_ssh_setup = self.cfg.GetClusterInfo().modify_ssh_setup
2849 b989b9d9 Ken Wehr
2850 44485f49 Guido Trotter
    # Promote nodes to master candidate as needed
2851 44485f49 Guido Trotter
    _AdjustCandidatePool(self, exceptions=[node.name])
2852 d8470559 Michael Hanselmann
    self.context.RemoveNode(node.name)
2853 a8083063 Iustin Pop
2854 cd46f3b4 Luca Bigliardi
    # Run post hooks on the node before it's removed
2855 cd46f3b4 Luca Bigliardi
    hm = self.proc.hmclass(self.rpc.call_hooks_runner, self)
2856 cd46f3b4 Luca Bigliardi
    try:
2857 1122eb25 Iustin Pop
      hm.RunPhase(constants.HOOKS_PHASE_POST, [node.name])
2858 3cb5c1e3 Luca Bigliardi
    except:
2859 7260cfbe Iustin Pop
      # pylint: disable-msg=W0702
2860 3cb5c1e3 Luca Bigliardi
      self.LogWarning("Errors occurred running hooks on %s" % node.name)
2861 cd46f3b4 Luca Bigliardi
2862 b989b9d9 Ken Wehr
    result = self.rpc.call_node_leave_cluster(node.name, modify_ssh_setup)
2863 4c4e4e1e Iustin Pop
    msg = result.fail_msg
2864 0623d351 Iustin Pop
    if msg:
2865 0623d351 Iustin Pop
      self.LogWarning("Errors encountered on the remote node while leaving"
2866 0623d351 Iustin Pop
                      " the cluster: %s", msg)
2867 c8a0948f Michael Hanselmann
2868 a8083063 Iustin Pop
2869 a8083063 Iustin Pop
class LUQueryNodes(NoHooksLU):
2870 a8083063 Iustin Pop
  """Logical unit for querying nodes.
2871 a8083063 Iustin Pop

2872 a8083063 Iustin Pop
  """
2873 7260cfbe Iustin Pop
  # pylint: disable-msg=W0142
2874 bc8e4a1a Iustin Pop
  _OP_REQP = ["output_fields", "names", "use_locking"]
2875 35705d8f Guido Trotter
  REQ_BGL = False
2876 19bed813 Iustin Pop
2877 19bed813 Iustin Pop
  _SIMPLE_FIELDS = ["name", "serial_no", "ctime", "mtime", "uuid",
2878 19bed813 Iustin Pop
                    "master_candidate", "offline", "drained"]
2879 19bed813 Iustin Pop
2880 a2d2e1a7 Iustin Pop
  _FIELDS_DYNAMIC = utils.FieldSet(
2881 31bf511f Iustin Pop
    "dtotal", "dfree",
2882 31bf511f Iustin Pop
    "mtotal", "mnode", "mfree",
2883 31bf511f Iustin Pop
    "bootid",
2884 0105bad3 Iustin Pop
    "ctotal", "cnodes", "csockets",
2885 31bf511f Iustin Pop
    )
2886 31bf511f Iustin Pop
2887 19bed813 Iustin Pop
  _FIELDS_STATIC = utils.FieldSet(*[
2888 19bed813 Iustin Pop
    "pinst_cnt", "sinst_cnt",
2889 31bf511f Iustin Pop
    "pinst_list", "sinst_list",
2890 31bf511f Iustin Pop
    "pip", "sip", "tags",
2891 0e67cdbe Iustin Pop
    "master",
2892 19bed813 Iustin Pop
    "role"] + _SIMPLE_FIELDS
2893 31bf511f Iustin Pop
    )
2894 a8083063 Iustin Pop
2895 35705d8f Guido Trotter
  def ExpandNames(self):
2896 31bf511f Iustin Pop
    _CheckOutputFields(static=self._FIELDS_STATIC,
2897 31bf511f Iustin Pop
                       dynamic=self._FIELDS_DYNAMIC,
2898 dcb93971 Michael Hanselmann
                       selected=self.op.output_fields)
2899 a8083063 Iustin Pop
2900 35705d8f Guido Trotter
    self.needed_locks = {}
2901 35705d8f Guido Trotter
    self.share_locks[locking.LEVEL_NODE] = 1
2902 c8d8b4c8 Iustin Pop
2903 c8d8b4c8 Iustin Pop
    if self.op.names:
2904 c8d8b4c8 Iustin Pop
      self.wanted = _GetWantedNodes(self, self.op.names)
2905 35705d8f Guido Trotter
    else:
2906 c8d8b4c8 Iustin Pop
      self.wanted = locking.ALL_SET
2907 c8d8b4c8 Iustin Pop
2908 bc8e4a1a Iustin Pop
    self.do_node_query = self._FIELDS_STATIC.NonMatching(self.op.output_fields)
2909 bc8e4a1a Iustin Pop
    self.do_locking = self.do_node_query and self.op.use_locking
2910 c8d8b4c8 Iustin Pop
    if self.do_locking:
2911 c8d8b4c8 Iustin Pop
      # if we don't request only static fields, we need to lock the nodes
2912 c8d8b4c8 Iustin Pop
      self.needed_locks[locking.LEVEL_NODE] = self.wanted
2913 c8d8b4c8 Iustin Pop
2914 35705d8f Guido Trotter
  def CheckPrereq(self):
2915 35705d8f Guido Trotter
    """Check prerequisites.
2916 35705d8f Guido Trotter

2917 35705d8f Guido Trotter
    """
2918 c8d8b4c8 Iustin Pop
    # The validation of the node list is done in the _GetWantedNodes,
2919 c8d8b4c8 Iustin Pop
    # if non empty, and if empty, there's no validation to do
2920 c8d8b4c8 Iustin Pop
    pass
2921 a8083063 Iustin Pop
2922 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
2923 a8083063 Iustin Pop
    """Computes the list of nodes and their attributes.
2924 a8083063 Iustin Pop

2925 a8083063 Iustin Pop
    """
2926 c8d8b4c8 Iustin Pop
    all_info = self.cfg.GetAllNodesInfo()
2927 c8d8b4c8 Iustin Pop
    if self.do_locking:
2928 c8d8b4c8 Iustin Pop
      nodenames = self.acquired_locks[locking.LEVEL_NODE]
2929 3fa93523 Guido Trotter
    elif self.wanted != locking.ALL_SET:
2930 3fa93523 Guido Trotter
      nodenames = self.wanted
2931 3fa93523 Guido Trotter
      missing = set(nodenames).difference(all_info.keys())
2932 3fa93523 Guido Trotter
      if missing:
2933 7b3a8fb5 Iustin Pop
        raise errors.OpExecError(
2934 3fa93523 Guido Trotter
          "Some nodes were removed before retrieving their data: %s" % missing)
2935 c8d8b4c8 Iustin Pop
    else:
2936 c8d8b4c8 Iustin Pop
      nodenames = all_info.keys()
2937 c1f1cbb2 Iustin Pop
2938 c1f1cbb2 Iustin Pop
    nodenames = utils.NiceSort(nodenames)
2939 c8d8b4c8 Iustin Pop
    nodelist = [all_info[name] for name in nodenames]
2940 a8083063 Iustin Pop
2941 a8083063 Iustin Pop
    # begin data gathering
2942 a8083063 Iustin Pop
2943 bc8e4a1a Iustin Pop
    if self.do_node_query:
2944 a8083063 Iustin Pop
      live_data = {}
2945 72737a7f Iustin Pop
      node_data = self.rpc.call_node_info(nodenames, self.cfg.GetVGName(),
2946 72737a7f Iustin Pop
                                          self.cfg.GetHypervisorType())
2947 a8083063 Iustin Pop
      for name in nodenames:
2948 781de953 Iustin Pop
        nodeinfo = node_data[name]
2949 4c4e4e1e Iustin Pop
        if not nodeinfo.fail_msg and nodeinfo.payload:
2950 070e998b Iustin Pop
          nodeinfo = nodeinfo.payload
2951 d599d686 Iustin Pop
          fn = utils.TryConvert
2952 a8083063 Iustin Pop
          live_data[name] = {
2953 d599d686 Iustin Pop
            "mtotal": fn(int, nodeinfo.get('memory_total', None)),
2954 d599d686 Iustin Pop
            "mnode": fn(int, nodeinfo.get('memory_dom0', None)),
2955 d599d686 Iustin Pop
            "mfree": fn(int, nodeinfo.get('memory_free', None)),
2956 d599d686 Iustin Pop
            "dtotal": fn(int, nodeinfo.get('vg_size', None)),
2957 d599d686 Iustin Pop
            "dfree": fn(int, nodeinfo.get('vg_free', None)),
2958 d599d686 Iustin Pop
            "ctotal": fn(int, nodeinfo.get('cpu_total', None)),
2959 d599d686 Iustin Pop
            "bootid": nodeinfo.get('bootid', None),
2960 0105bad3 Iustin Pop
            "cnodes": fn(int, nodeinfo.get('cpu_nodes', None)),
2961 0105bad3 Iustin Pop
            "csockets": fn(int, nodeinfo.get('cpu_sockets', None)),
2962 a8083063 Iustin Pop
            }
2963 a8083063 Iustin Pop
        else:
2964 a8083063 Iustin Pop
          live_data[name] = {}
2965 a8083063 Iustin Pop
    else:
2966 a8083063 Iustin Pop
      live_data = dict.fromkeys(nodenames, {})
2967 a8083063 Iustin Pop
2968 ec223efb Iustin Pop
    node_to_primary = dict([(name, set()) for name in nodenames])
2969 ec223efb Iustin Pop
    node_to_secondary = dict([(name, set()) for name in nodenames])
2970 a8083063 Iustin Pop
2971 ec223efb Iustin Pop
    inst_fields = frozenset(("pinst_cnt", "pinst_list",
2972 ec223efb Iustin Pop
                             "sinst_cnt", "sinst_list"))
2973 ec223efb Iustin Pop
    if inst_fields & frozenset(self.op.output_fields):
2974 4dfd6266 Iustin Pop
      inst_data = self.cfg.GetAllInstancesInfo()
2975 a8083063 Iustin Pop
2976 1122eb25 Iustin Pop
      for inst in inst_data.values():
2977 ec223efb Iustin Pop
        if inst.primary_node in node_to_primary:
2978 ec223efb Iustin Pop
          node_to_primary[inst.primary_node].add(inst.name)
2979 ec223efb Iustin Pop
        for secnode in inst.secondary_nodes:
2980 ec223efb Iustin Pop
          if secnode in node_to_secondary:
2981 ec223efb Iustin Pop
            node_to_secondary[secnode].add(inst.name)
2982 a8083063 Iustin Pop
2983 0e67cdbe Iustin Pop
    master_node = self.cfg.GetMasterNode()
2984 0e67cdbe Iustin Pop
2985 a8083063 Iustin Pop
    # end data gathering
2986 a8083063 Iustin Pop
2987 a8083063 Iustin Pop
    output = []
2988 a8083063 Iustin Pop
    for node in nodelist:
2989 a8083063 Iustin Pop
      node_output = []
2990 a8083063 Iustin Pop
      for field in self.op.output_fields:
2991 19bed813 Iustin Pop
        if field in self._SIMPLE_FIELDS:
2992 19bed813 Iustin Pop
          val = getattr(node, field)
2993 ec223efb Iustin Pop
        elif field == "pinst_list":
2994 ec223efb Iustin Pop
          val = list(node_to_primary[node.name])
2995 ec223efb Iustin Pop
        elif field == "sinst_list":
2996 ec223efb Iustin Pop
          val = list(node_to_secondary[node.name])
2997 ec223efb Iustin Pop
        elif field == "pinst_cnt":
2998 ec223efb Iustin Pop
          val = len(node_to_primary[node.name])
2999 ec223efb Iustin Pop
        elif field == "sinst_cnt":
3000 ec223efb Iustin Pop
          val = len(node_to_secondary[node.name])
3001 a8083063 Iustin Pop
        elif field == "pip":
3002 a8083063 Iustin Pop
          val = node.primary_ip
3003 a8083063 Iustin Pop
        elif field == "sip":
3004 a8083063 Iustin Pop
          val = node.secondary_ip
3005 130a6a6f Iustin Pop
        elif field == "tags":
3006 130a6a6f Iustin Pop
          val = list(node.GetTags())
3007 0e67cdbe Iustin Pop
        elif field == "master":
3008 0e67cdbe Iustin Pop
          val = node.name == master_node
3009 31bf511f Iustin Pop
        elif self._FIELDS_DYNAMIC.Matches(field):
3010 ec223efb Iustin Pop
          val = live_data[node.name].get(field, None)
3011 c120ff34 Iustin Pop
        elif field == "role":
3012 c120ff34 Iustin Pop
          if node.name == master_node:
3013 c120ff34 Iustin Pop
            val = "M"
3014 c120ff34 Iustin Pop
          elif node.master_candidate:
3015 c120ff34 Iustin Pop
            val = "C"
3016 c120ff34 Iustin Pop
          elif node.drained:
3017 c120ff34 Iustin Pop
            val = "D"
3018 c120ff34 Iustin Pop
          elif node.offline:
3019 c120ff34 Iustin Pop
            val = "O"
3020 c120ff34 Iustin Pop
          else:
3021 c120ff34 Iustin Pop
            val = "R"
3022 a8083063 Iustin Pop
        else:
3023 3ecf6786 Iustin Pop
          raise errors.ParameterError(field)
3024 a8083063 Iustin Pop
        node_output.append(val)
3025 a8083063 Iustin Pop
      output.append(node_output)
3026 a8083063 Iustin Pop
3027 a8083063 Iustin Pop
    return output
3028 a8083063 Iustin Pop
3029 a8083063 Iustin Pop
3030 dcb93971 Michael Hanselmann
class LUQueryNodeVolumes(NoHooksLU):
3031 dcb93971 Michael Hanselmann
  """Logical unit for getting volumes on node(s).
3032 dcb93971 Michael Hanselmann

3033 dcb93971 Michael Hanselmann
  """
3034 dcb93971 Michael Hanselmann
  _OP_REQP = ["nodes", "output_fields"]
3035 21a15682 Guido Trotter
  REQ_BGL = False
3036 a2d2e1a7 Iustin Pop
  _FIELDS_DYNAMIC = utils.FieldSet("phys", "vg", "name", "size", "instance")
3037 a2d2e1a7 Iustin Pop
  _FIELDS_STATIC = utils.FieldSet("node")
3038 21a15682 Guido Trotter
3039 21a15682 Guido Trotter
  def ExpandNames(self):
3040 31bf511f Iustin Pop
    _CheckOutputFields(static=self._FIELDS_STATIC,
3041 31bf511f Iustin Pop
                       dynamic=self._FIELDS_DYNAMIC,
3042 21a15682 Guido Trotter
                       selected=self.op.output_fields)
3043 21a15682 Guido Trotter
3044 21a15682 Guido Trotter
    self.needed_locks = {}
3045 21a15682 Guido Trotter
    self.share_locks[locking.LEVEL_NODE] = 1
3046 21a15682 Guido Trotter
    if not self.op.nodes:
3047 e310b019 Guido Trotter
      self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
3048 21a15682 Guido Trotter
    else:
3049 21a15682 Guido Trotter
      self.needed_locks[locking.LEVEL_NODE] = \
3050 21a15682 Guido Trotter
        _GetWantedNodes(self, self.op.nodes)
3051 dcb93971 Michael Hanselmann
3052 dcb93971 Michael Hanselmann
  def CheckPrereq(self):
3053 dcb93971 Michael Hanselmann
    """Check prerequisites.
3054 dcb93971 Michael Hanselmann

3055 dcb93971 Michael Hanselmann
    This checks that the fields required are valid output fields.
3056 dcb93971 Michael Hanselmann

3057 dcb93971 Michael Hanselmann
    """
3058 21a15682 Guido Trotter
    self.nodes = self.acquired_locks[locking.LEVEL_NODE]
3059 dcb93971 Michael Hanselmann
3060 dcb93971 Michael Hanselmann
  def Exec(self, feedback_fn):
3061 dcb93971 Michael Hanselmann
    """Computes the list of nodes and their attributes.
3062 dcb93971 Michael Hanselmann

3063 dcb93971 Michael Hanselmann
    """
3064 a7ba5e53 Iustin Pop
    nodenames = self.nodes
3065 72737a7f Iustin Pop
    volumes = self.rpc.call_node_volumes(nodenames)
3066 dcb93971 Michael Hanselmann
3067 dcb93971 Michael Hanselmann
    ilist = [self.cfg.GetInstanceInfo(iname) for iname
3068 dcb93971 Michael Hanselmann
             in self.cfg.GetInstanceList()]
3069 dcb93971 Michael Hanselmann
3070 dcb93971 Michael Hanselmann
    lv_by_node = dict([(inst, inst.MapLVsByNode()) for inst in ilist])
3071 dcb93971 Michael Hanselmann
3072 dcb93971 Michael Hanselmann
    output = []
3073 dcb93971 Michael Hanselmann
    for node in nodenames:
3074 10bfe6cb Iustin Pop
      nresult = volumes[node]
3075 10bfe6cb Iustin Pop
      if nresult.offline:
3076 10bfe6cb Iustin Pop
        continue
3077 4c4e4e1e Iustin Pop
      msg = nresult.fail_msg
3078 10bfe6cb Iustin Pop
      if msg:
3079 10bfe6cb Iustin Pop
        self.LogWarning("Can't compute volume data on node %s: %s", node, msg)
3080 37d19eb2 Michael Hanselmann
        continue
3081 37d19eb2 Michael Hanselmann
3082 10bfe6cb Iustin Pop
      node_vols = nresult.payload[:]
3083 dcb93971 Michael Hanselmann
      node_vols.sort(key=lambda vol: vol['dev'])
3084 dcb93971 Michael Hanselmann
3085 dcb93971 Michael Hanselmann
      for vol in node_vols:
3086 dcb93971 Michael Hanselmann
        node_output = []
3087 dcb93971 Michael Hanselmann
        for field in self.op.output_fields:
3088 dcb93971 Michael Hanselmann
          if field == "node":
3089 dcb93971 Michael Hanselmann
            val = node
3090 dcb93971 Michael Hanselmann
          elif field == "phys":
3091 dcb93971 Michael Hanselmann
            val = vol['dev']
3092 dcb93971 Michael Hanselmann
          elif field == "vg":
3093 dcb93971 Michael Hanselmann
            val = vol['vg']
3094 dcb93971 Michael Hanselmann
          elif field == "name":
3095 dcb93971 Michael Hanselmann
            val = vol['name']
3096 dcb93971 Michael Hanselmann
          elif field == "size":
3097 dcb93971 Michael Hanselmann
            val = int(float(vol['size']))
3098 dcb93971 Michael Hanselmann
          elif field == "instance":
3099 dcb93971 Michael Hanselmann
            for inst in ilist:
3100 dcb93971 Michael Hanselmann
              if node not in lv_by_node[inst]:
3101 dcb93971 Michael Hanselmann
                continue
3102 dcb93971 Michael Hanselmann
              if vol['name'] in lv_by_node[inst][node]:
3103 dcb93971 Michael Hanselmann
                val = inst.name
3104 dcb93971 Michael Hanselmann
                break
3105 dcb93971 Michael Hanselmann
            else:
3106 dcb93971 Michael Hanselmann
              val = '-'
3107 dcb93971 Michael Hanselmann
          else:
3108 3ecf6786 Iustin Pop
            raise errors.ParameterError(field)
3109 dcb93971 Michael Hanselmann
          node_output.append(str(val))
3110 dcb93971 Michael Hanselmann
3111 dcb93971 Michael Hanselmann
        output.append(node_output)
3112 dcb93971 Michael Hanselmann
3113 dcb93971 Michael Hanselmann
    return output
3114 dcb93971 Michael Hanselmann
3115 dcb93971 Michael Hanselmann
3116 9e5442ce Michael Hanselmann
class LUQueryNodeStorage(NoHooksLU):
3117 9e5442ce Michael Hanselmann
  """Logical unit for getting information on storage units on node(s).
3118 9e5442ce Michael Hanselmann

3119 9e5442ce Michael Hanselmann
  """
3120 9e5442ce Michael Hanselmann
  _OP_REQP = ["nodes", "storage_type", "output_fields"]
3121 9e5442ce Michael Hanselmann
  REQ_BGL = False
3122 620a85fd Iustin Pop
  _FIELDS_STATIC = utils.FieldSet(constants.SF_NODE)
3123 9e5442ce Michael Hanselmann
3124 0e3baaf3 Iustin Pop
  def CheckArguments(self):
3125 0e3baaf3 Iustin Pop
    _CheckStorageType(self.op.storage_type)
3126 9e5442ce Michael Hanselmann
3127 9e5442ce Michael Hanselmann
    _CheckOutputFields(static=self._FIELDS_STATIC,
3128 620a85fd Iustin Pop
                       dynamic=utils.FieldSet(*constants.VALID_STORAGE_FIELDS),
3129 9e5442ce Michael Hanselmann
                       selected=self.op.output_fields)
3130 9e5442ce Michael Hanselmann
3131 0e3baaf3 Iustin Pop
  def ExpandNames(self):
3132 9e5442ce Michael Hanselmann
    self.needed_locks = {}
3133 9e5442ce Michael Hanselmann
    self.share_locks[locking.LEVEL_NODE] = 1
3134 9e5442ce Michael Hanselmann
3135 9e5442ce Michael Hanselmann
    if self.op.nodes:
3136 9e5442ce Michael Hanselmann
      self.needed_locks[locking.LEVEL_NODE] = \
3137 9e5442ce Michael Hanselmann
        _GetWantedNodes(self, self.op.nodes)
3138 9e5442ce Michael Hanselmann
    else:
3139 9e5442ce Michael Hanselmann
      self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
3140 9e5442ce Michael Hanselmann
3141 9e5442ce Michael Hanselmann
  def CheckPrereq(self):
3142 9e5442ce Michael Hanselmann
    """Check prerequisites.
3143 9e5442ce Michael Hanselmann

3144 9e5442ce Michael Hanselmann
    This checks that the fields required are valid output fields.
3145 9e5442ce Michael Hanselmann

3146 9e5442ce Michael Hanselmann
    """
3147 9e5442ce Michael Hanselmann
    self.op.name = getattr(self.op, "name", None)
3148 9e5442ce Michael Hanselmann
3149 9e5442ce Michael Hanselmann
    self.nodes = self.acquired_locks[locking.LEVEL_NODE]
3150 9e5442ce Michael Hanselmann
3151 9e5442ce Michael Hanselmann
  def Exec(self, feedback_fn):
3152 9e5442ce Michael Hanselmann
    """Computes the list of nodes and their attributes.
3153 9e5442ce Michael Hanselmann

3154 9e5442ce Michael Hanselmann
    """
3155 9e5442ce Michael Hanselmann
    # Always get name to sort by
3156 9e5442ce Michael Hanselmann
    if constants.SF_NAME in self.op.output_fields:
3157 9e5442ce Michael Hanselmann
      fields = self.op.output_fields[:]
3158 9e5442ce Michael Hanselmann
    else:
3159 9e5442ce Michael Hanselmann
      fields = [constants.SF_NAME] + self.op.output_fields
3160 9e5442ce Michael Hanselmann
3161 620a85fd Iustin Pop
    # Never ask for node or type as it's only known to the LU
3162 620a85fd Iustin Pop
    for extra in [constants.SF_NODE, constants.SF_TYPE]:
3163 620a85fd Iustin Pop
      while extra in fields:
3164 620a85fd Iustin Pop
        fields.remove(extra)
3165 9e5442ce Michael Hanselmann
3166 9e5442ce Michael Hanselmann
    field_idx = dict([(name, idx) for (idx, name) in enumerate(fields)])
3167 9e5442ce Michael Hanselmann
    name_idx = field_idx[constants.SF_NAME]
3168 9e5442ce Michael Hanselmann
3169 efb8da02 Michael Hanselmann
    st_args = _GetStorageTypeArgs(self.cfg, self.op.storage_type)
3170 9e5442ce Michael Hanselmann
    data = self.rpc.call_storage_list(self.nodes,
3171 9e5442ce Michael Hanselmann
                                      self.op.storage_type, st_args,
3172 9e5442ce Michael Hanselmann
                                      self.op.name, fields)
3173 9e5442ce Michael Hanselmann
3174 9e5442ce Michael Hanselmann
    result = []
3175 9e5442ce Michael Hanselmann
3176 9e5442ce Michael Hanselmann
    for node in utils.NiceSort(self.nodes):
3177 9e5442ce Michael Hanselmann
      nresult = data[node]
3178 9e5442ce Michael Hanselmann
      if nresult.offline:
3179 9e5442ce Michael Hanselmann
        continue
3180 9e5442ce Michael Hanselmann
3181 9e5442ce Michael Hanselmann
      msg = nresult.fail_msg
3182 9e5442ce Michael Hanselmann
      if msg:
3183 9e5442ce Michael Hanselmann
        self.LogWarning("Can't get storage data from node %s: %s", node, msg)
3184 9e5442ce Michael Hanselmann
        continue
3185 9e5442ce Michael Hanselmann
3186 9e5442ce Michael Hanselmann
      rows = dict([(row[name_idx], row) for row in nresult.payload])
3187 9e5442ce Michael Hanselmann
3188 9e5442ce Michael Hanselmann
      for name in utils.NiceSort(rows.keys()):
3189 9e5442ce Michael Hanselmann
        row = rows[name]
3190 9e5442ce Michael Hanselmann
3191 9e5442ce Michael Hanselmann
        out = []
3192 9e5442ce Michael Hanselmann
3193 9e5442ce Michael Hanselmann
        for field in self.op.output_fields:
3194 620a85fd Iustin Pop
          if field == constants.SF_NODE:
3195 9e5442ce Michael Hanselmann
            val = node
3196 620a85fd Iustin Pop
          elif field == constants.SF_TYPE:
3197 620a85fd Iustin Pop
            val = self.op.storage_type
3198 9e5442ce Michael Hanselmann
          elif field in field_idx:
3199 9e5442ce Michael Hanselmann
            val = row[field_idx[field]]
3200 9e5442ce Michael Hanselmann
          else:
3201 9e5442ce Michael Hanselmann
            raise errors.ParameterError(field)
3202 9e5442ce Michael Hanselmann
3203 9e5442ce Michael Hanselmann
          out.append(val)
3204 9e5442ce Michael Hanselmann
3205 9e5442ce Michael Hanselmann
        result.append(out)
3206 9e5442ce Michael Hanselmann
3207 9e5442ce Michael Hanselmann
    return result
3208 9e5442ce Michael Hanselmann
3209 9e5442ce Michael Hanselmann
3210 efb8da02 Michael Hanselmann
class LUModifyNodeStorage(NoHooksLU):
3211 efb8da02 Michael Hanselmann
  """Logical unit for modifying a storage volume on a node.
3212 efb8da02 Michael Hanselmann

3213 efb8da02 Michael Hanselmann
  """
3214 efb8da02 Michael Hanselmann
  _OP_REQP = ["node_name", "storage_type", "name", "changes"]
3215 efb8da02 Michael Hanselmann
  REQ_BGL = False
3216 efb8da02 Michael Hanselmann
3217 efb8da02 Michael Hanselmann
  def CheckArguments(self):
3218 cf26a87a Iustin Pop
    self.opnode_name = _ExpandNodeName(self.cfg, self.op.node_name)
3219 efb8da02 Michael Hanselmann
3220 0e3baaf3 Iustin Pop
    _CheckStorageType(self.op.storage_type)
3221 efb8da02 Michael Hanselmann
3222 efb8da02 Michael Hanselmann
  def ExpandNames(self):
3223 efb8da02 Michael Hanselmann
    self.needed_locks = {
3224 efb8da02 Michael Hanselmann
      locking.LEVEL_NODE: self.op.node_name,
3225 efb8da02 Michael Hanselmann
      }
3226 efb8da02 Michael Hanselmann
3227 efb8da02 Michael Hanselmann
  def CheckPrereq(self):
3228 efb8da02 Michael Hanselmann
    """Check prerequisites.
3229 efb8da02 Michael Hanselmann

3230 efb8da02 Michael Hanselmann
    """
3231 efb8da02 Michael Hanselmann
    storage_type = self.op.storage_type
3232 efb8da02 Michael Hanselmann
3233 efb8da02 Michael Hanselmann
    try:
3234 efb8da02 Michael Hanselmann
      modifiable = constants.MODIFIABLE_STORAGE_FIELDS[storage_type]
3235 efb8da02 Michael Hanselmann
    except KeyError:
3236 efb8da02 Michael Hanselmann
      raise errors.OpPrereqError("Storage units of type '%s' can not be"
3237 5c983ee5 Iustin Pop
                                 " modified" % storage_type,
3238 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
3239 efb8da02 Michael Hanselmann
3240 efb8da02 Michael Hanselmann
    diff = set(self.op.changes.keys()) - modifiable
3241 efb8da02 Michael Hanselmann
    if diff:
3242 efb8da02 Michael Hanselmann
      raise errors.OpPrereqError("The following fields can not be modified for"
3243 efb8da02 Michael Hanselmann
                                 " storage units of type '%s': %r" %
3244 5c983ee5 Iustin Pop
                                 (storage_type, list(diff)),
3245 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
3246 efb8da02 Michael Hanselmann
3247 efb8da02 Michael Hanselmann
  def Exec(self, feedback_fn):
3248 efb8da02 Michael Hanselmann
    """Computes the list of nodes and their attributes.
3249 efb8da02 Michael Hanselmann

3250 efb8da02 Michael Hanselmann
    """
3251 efb8da02 Michael Hanselmann
    st_args = _GetStorageTypeArgs(self.cfg, self.op.storage_type)
3252 efb8da02 Michael Hanselmann
    result = self.rpc.call_storage_modify(self.op.node_name,
3253 efb8da02 Michael Hanselmann
                                          self.op.storage_type, st_args,
3254 efb8da02 Michael Hanselmann
                                          self.op.name, self.op.changes)
3255 efb8da02 Michael Hanselmann
    result.Raise("Failed to modify storage unit '%s' on %s" %
3256 efb8da02 Michael Hanselmann
                 (self.op.name, self.op.node_name))
3257 efb8da02 Michael Hanselmann
3258 efb8da02 Michael Hanselmann
3259 a8083063 Iustin Pop
class LUAddNode(LogicalUnit):
3260 a8083063 Iustin Pop
  """Logical unit for adding node to the cluster.
3261 a8083063 Iustin Pop

3262 a8083063 Iustin Pop
  """
3263 a8083063 Iustin Pop
  HPATH = "node-add"
3264 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_NODE
3265 a8083063 Iustin Pop
  _OP_REQP = ["node_name"]
3266 a8083063 Iustin Pop
3267 44caf5a8 Iustin Pop
  def CheckArguments(self):
3268 44caf5a8 Iustin Pop
    # validate/normalize the node name
3269 44caf5a8 Iustin Pop
    self.op.node_name = utils.HostInfo.NormalizeName(self.op.node_name)
3270 44caf5a8 Iustin Pop
3271 a8083063 Iustin Pop
  def BuildHooksEnv(self):
3272 a8083063 Iustin Pop
    """Build hooks env.
3273 a8083063 Iustin Pop

3274 a8083063 Iustin Pop
    This will run on all nodes before, and on all nodes + the new node after.
3275 a8083063 Iustin Pop

3276 a8083063 Iustin Pop
    """
3277 a8083063 Iustin Pop
    env = {
3278 0e137c28 Iustin Pop
      "OP_TARGET": self.op.node_name,
3279 a8083063 Iustin Pop
      "NODE_NAME": self.op.node_name,
3280 a8083063 Iustin Pop
      "NODE_PIP": self.op.primary_ip,
3281 a8083063 Iustin Pop
      "NODE_SIP": self.op.secondary_ip,
3282 a8083063 Iustin Pop
      }
3283 a8083063 Iustin Pop
    nodes_0 = self.cfg.GetNodeList()
3284 a8083063 Iustin Pop
    nodes_1 = nodes_0 + [self.op.node_name, ]
3285 a8083063 Iustin Pop
    return env, nodes_0, nodes_1
3286 a8083063 Iustin Pop
3287 a8083063 Iustin Pop
  def CheckPrereq(self):
3288 a8083063 Iustin Pop
    """Check prerequisites.
3289 a8083063 Iustin Pop

3290 a8083063 Iustin Pop
    This checks:
3291 a8083063 Iustin Pop
     - the new node is not already in the config
3292 a8083063 Iustin Pop
     - it is resolvable
3293 a8083063 Iustin Pop
     - its parameters (single/dual homed) matches the cluster
3294 a8083063 Iustin Pop

3295 5bbd3f7f Michael Hanselmann
    Any errors are signaled by raising errors.OpPrereqError.
3296 a8083063 Iustin Pop

3297 a8083063 Iustin Pop
    """
3298 a8083063 Iustin Pop
    node_name = self.op.node_name
3299 a8083063 Iustin Pop
    cfg = self.cfg
3300 a8083063 Iustin Pop
3301 104f4ca1 Iustin Pop
    dns_data = utils.GetHostInfo(node_name)
3302 a8083063 Iustin Pop
3303 bcf043c9 Iustin Pop
    node = dns_data.name
3304 bcf043c9 Iustin Pop
    primary_ip = self.op.primary_ip = dns_data.ip
3305 a8083063 Iustin Pop
    secondary_ip = getattr(self.op, "secondary_ip", None)
3306 a8083063 Iustin Pop
    if secondary_ip is None:
3307 a8083063 Iustin Pop
      secondary_ip = primary_ip
3308 a8083063 Iustin Pop
    if not utils.IsValidIP(secondary_ip):
3309 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Invalid secondary IP given",
3310 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
3311 a8083063 Iustin Pop
    self.op.secondary_ip = secondary_ip
3312 e7c6e02b Michael Hanselmann
3313 a8083063 Iustin Pop
    node_list = cfg.GetNodeList()
3314 e7c6e02b Michael Hanselmann
    if not self.op.readd and node in node_list:
3315 e7c6e02b Michael Hanselmann
      raise errors.OpPrereqError("Node %s is already in the configuration" %
3316 5c983ee5 Iustin Pop
                                 node, errors.ECODE_EXISTS)
3317 e7c6e02b Michael Hanselmann
    elif self.op.readd and node not in node_list:
3318 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Node %s is not in the configuration" % node,
3319 5c983ee5 Iustin Pop
                                 errors.ECODE_NOENT)
3320 a8083063 Iustin Pop
3321 a8083063 Iustin Pop
    for existing_node_name in node_list:
3322 a8083063 Iustin Pop
      existing_node = cfg.GetNodeInfo(existing_node_name)
3323 e7c6e02b Michael Hanselmann
3324 e7c6e02b Michael Hanselmann
      if self.op.readd and node == existing_node_name:
3325 e7c6e02b Michael Hanselmann
        if (existing_node.primary_ip != primary_ip or
3326 e7c6e02b Michael Hanselmann
            existing_node.secondary_ip != secondary_ip):
3327 e7c6e02b Michael Hanselmann
          raise errors.OpPrereqError("Readded node doesn't have the same IP"
3328 5c983ee5 Iustin Pop
                                     " address configuration as before",
3329 5c983ee5 Iustin Pop
                                     errors.ECODE_INVAL)
3330 e7c6e02b Michael Hanselmann
        continue
3331 e7c6e02b Michael Hanselmann
3332 a8083063 Iustin Pop
      if (existing_node.primary_ip == primary_ip or
3333 a8083063 Iustin Pop
          existing_node.secondary_ip == primary_ip or
3334 a8083063 Iustin Pop
          existing_node.primary_ip == secondary_ip or
3335 a8083063 Iustin Pop
          existing_node.secondary_ip == secondary_ip):
3336 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("New node ip address(es) conflict with"
3337 5c983ee5 Iustin Pop
                                   " existing node %s" % existing_node.name,
3338 5c983ee5 Iustin Pop
                                   errors.ECODE_NOTUNIQUE)
3339 a8083063 Iustin Pop
3340 a8083063 Iustin Pop
    # check that the type of the node (single versus dual homed) is the
3341 a8083063 Iustin Pop
    # same as for the master
3342 d6a02168 Michael Hanselmann
    myself = cfg.GetNodeInfo(self.cfg.GetMasterNode())
3343 a8083063 Iustin Pop
    master_singlehomed = myself.secondary_ip == myself.primary_ip
3344 a8083063 Iustin Pop
    newbie_singlehomed = secondary_ip == primary_ip
3345 a8083063 Iustin Pop
    if master_singlehomed != newbie_singlehomed:
3346 a8083063 Iustin Pop
      if master_singlehomed:
3347 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("The master has no private ip but the"
3348 5c983ee5 Iustin Pop
                                   " new node has one",
3349 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
3350 a8083063 Iustin Pop
      else:
3351 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("The master has a private ip but the"
3352 5c983ee5 Iustin Pop
                                   " new node doesn't have one",
3353 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
3354 a8083063 Iustin Pop
3355 5bbd3f7f Michael Hanselmann
    # checks reachability
3356 b15d625f Iustin Pop
    if not utils.TcpPing(primary_ip, constants.DEFAULT_NODED_PORT):
3357 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Node not reachable by ping",
3358 5c983ee5 Iustin Pop
                                 errors.ECODE_ENVIRON)
3359 a8083063 Iustin Pop
3360 a8083063 Iustin Pop
    if not newbie_singlehomed:
3361 a8083063 Iustin Pop
      # check reachability from my secondary ip to newbie's secondary ip
3362 b15d625f Iustin Pop
      if not utils.TcpPing(secondary_ip, constants.DEFAULT_NODED_PORT,
3363 b15d625f Iustin Pop
                           source=myself.secondary_ip):
3364 f4bc1f2c Michael Hanselmann
        raise errors.OpPrereqError("Node secondary ip not reachable by TCP"
3365 5c983ee5 Iustin Pop
                                   " based ping to noded port",
3366 5c983ee5 Iustin Pop
                                   errors.ECODE_ENVIRON)
3367 a8083063 Iustin Pop
3368 a8ae3eb5 Iustin Pop
    if self.op.readd:
3369 a8ae3eb5 Iustin Pop
      exceptions = [node]
3370 a8ae3eb5 Iustin Pop
    else:
3371 a8ae3eb5 Iustin Pop
      exceptions = []
3372 6d7e1f20 Guido Trotter
3373 6d7e1f20 Guido Trotter
    self.master_candidate = _DecideSelfPromotion(self, exceptions=exceptions)
3374 0fff97e9 Guido Trotter
3375 a8ae3eb5 Iustin Pop
    if self.op.readd:
3376 a8ae3eb5 Iustin Pop
      self.new_node = self.cfg.GetNodeInfo(node)
3377 a8ae3eb5 Iustin Pop
      assert self.new_node is not None, "Can't retrieve locked node %s" % node
3378 a8ae3eb5 Iustin Pop
    else:
3379 a8ae3eb5 Iustin Pop
      self.new_node = objects.Node(name=node,
3380 a8ae3eb5 Iustin Pop
                                   primary_ip=primary_ip,
3381 a8ae3eb5 Iustin Pop
                                   secondary_ip=secondary_ip,
3382 a8ae3eb5 Iustin Pop
                                   master_candidate=self.master_candidate,
3383 a8ae3eb5 Iustin Pop
                                   offline=False, drained=False)
3384 a8083063 Iustin Pop
3385 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
3386 a8083063 Iustin Pop
    """Adds the new node to the cluster.
3387 a8083063 Iustin Pop

3388 a8083063 Iustin Pop
    """
3389 a8083063 Iustin Pop
    new_node = self.new_node
3390 a8083063 Iustin Pop
    node = new_node.name
3391 a8083063 Iustin Pop
3392 a8ae3eb5 Iustin Pop
    # for re-adds, reset the offline/drained/master-candidate flags;
3393 a8ae3eb5 Iustin Pop
    # we need to reset here, otherwise offline would prevent RPC calls
3394 a8ae3eb5 Iustin Pop
    # later in the procedure; this also means that if the re-add
3395 a8ae3eb5 Iustin Pop
    # fails, we are left with a non-offlined, broken node
3396 a8ae3eb5 Iustin Pop
    if self.op.readd:
3397 7260cfbe Iustin Pop
      new_node.drained = new_node.offline = False # pylint: disable-msg=W0201
3398 a8ae3eb5 Iustin Pop
      self.LogInfo("Readding a node, the offline/drained flags were reset")
3399 a8ae3eb5 Iustin Pop
      # if we demote the node, we do cleanup later in the procedure
3400 a8ae3eb5 Iustin Pop
      new_node.master_candidate = self.master_candidate
3401 a8ae3eb5 Iustin Pop
3402 a8ae3eb5 Iustin Pop
    # notify the user about any possible mc promotion
3403 a8ae3eb5 Iustin Pop
    if new_node.master_candidate:
3404 a8ae3eb5 Iustin Pop
      self.LogInfo("Node will be a master candidate")
3405 a8ae3eb5 Iustin Pop
3406 a8083063 Iustin Pop
    # check connectivity
3407 72737a7f Iustin Pop
    result = self.rpc.call_version([node])[node]
3408 4c4e4e1e Iustin Pop
    result.Raise("Can't get version information from node %s" % node)
3409 90b54c26 Iustin Pop
    if constants.PROTOCOL_VERSION == result.payload:
3410 90b54c26 Iustin Pop
      logging.info("Communication to node %s fine, sw version %s match",
3411 90b54c26 Iustin Pop
                   node, result.payload)
3412 a8083063 Iustin Pop
    else:
3413 90b54c26 Iustin Pop
      raise errors.OpExecError("Version mismatch master version %s,"
3414 90b54c26 Iustin Pop
                               " node version %s" %
3415 90b54c26 Iustin Pop
                               (constants.PROTOCOL_VERSION, result.payload))
3416 a8083063 Iustin Pop
3417 a8083063 Iustin Pop
    # setup ssh on node
3418 b989b9d9 Ken Wehr
    if self.cfg.GetClusterInfo().modify_ssh_setup:
3419 b989b9d9 Ken Wehr
      logging.info("Copy ssh key to node %s", node)
3420 b989b9d9 Ken Wehr
      priv_key, pub_key, _ = ssh.GetUserFiles(constants.GANETI_RUNAS)
3421 b989b9d9 Ken Wehr
      keyarray = []
3422 b989b9d9 Ken Wehr
      keyfiles = [constants.SSH_HOST_DSA_PRIV, constants.SSH_HOST_DSA_PUB,
3423 b989b9d9 Ken Wehr
                  constants.SSH_HOST_RSA_PRIV, constants.SSH_HOST_RSA_PUB,
3424 b989b9d9 Ken Wehr
                  priv_key, pub_key]
3425 b989b9d9 Ken Wehr
3426 b989b9d9 Ken Wehr
      for i in keyfiles:
3427 b989b9d9 Ken Wehr
        keyarray.append(utils.ReadFile(i))
3428 b989b9d9 Ken Wehr
3429 b989b9d9 Ken Wehr
      result = self.rpc.call_node_add(node, keyarray[0], keyarray[1],
3430 b989b9d9 Ken Wehr
                                      keyarray[2], keyarray[3], keyarray[4],
3431 b989b9d9 Ken Wehr
                                      keyarray[5])
3432 b989b9d9 Ken Wehr
      result.Raise("Cannot transfer ssh keys to the new node")
3433 a8083063 Iustin Pop
3434 a8083063 Iustin Pop
    # Add node to our /etc/hosts, and add key to known_hosts
3435 b86a6bcd Guido Trotter
    if self.cfg.GetClusterInfo().modify_etc_hosts:
3436 b86a6bcd Guido Trotter
      utils.AddHostToEtcHosts(new_node.name)
3437 c8a0948f Michael Hanselmann
3438 a8083063 Iustin Pop
    if new_node.secondary_ip != new_node.primary_ip:
3439 781de953 Iustin Pop
      result = self.rpc.call_node_has_ip_address(new_node.name,
3440 781de953 Iustin Pop
                                                 new_node.secondary_ip)
3441 4c4e4e1e Iustin Pop
      result.Raise("Failure checking secondary ip on node %s" % new_node.name,
3442 045dd6d9 Iustin Pop
                   prereq=True, ecode=errors.ECODE_ENVIRON)
3443 c2fc8250 Iustin Pop
      if not result.payload:
3444 f4bc1f2c Michael Hanselmann
        raise errors.OpExecError("Node claims it doesn't have the secondary ip"
3445 f4bc1f2c Michael Hanselmann
                                 " you gave (%s). Please fix and re-run this"
3446 f4bc1f2c Michael Hanselmann
                                 " command." % new_node.secondary_ip)
3447 a8083063 Iustin Pop
3448 d6a02168 Michael Hanselmann
    node_verify_list = [self.cfg.GetMasterNode()]
3449 5c0527ed Guido Trotter
    node_verify_param = {
3450 f60759f7 Iustin Pop
      constants.NV_NODELIST: [node],
3451 5c0527ed Guido Trotter
      # TODO: do a node-net-test as well?
3452 5c0527ed Guido Trotter
    }
3453 5c0527ed Guido Trotter
3454 72737a7f Iustin Pop
    result = self.rpc.call_node_verify(node_verify_list, node_verify_param,
3455 72737a7f Iustin Pop
                                       self.cfg.GetClusterName())
3456 5c0527ed Guido Trotter
    for verifier in node_verify_list:
3457 4c4e4e1e Iustin Pop
      result[verifier].Raise("Cannot communicate with node %s" % verifier)
3458 f60759f7 Iustin Pop
      nl_payload = result[verifier].payload[constants.NV_NODELIST]
3459 6f68a739 Iustin Pop
      if nl_payload:
3460 6f68a739 Iustin Pop
        for failed in nl_payload:
3461 31821208 Iustin Pop
          feedback_fn("ssh/hostname verification failed"
3462 31821208 Iustin Pop
                      " (checking from %s): %s" %
3463 6f68a739 Iustin Pop
                      (verifier, nl_payload[failed]))
3464 5c0527ed Guido Trotter
        raise errors.OpExecError("ssh/hostname verification failed.")
3465 ff98055b Iustin Pop
3466 d8470559 Michael Hanselmann
    if self.op.readd:
3467 28eddce5 Guido Trotter
      _RedistributeAncillaryFiles(self)
3468 d8470559 Michael Hanselmann
      self.context.ReaddNode(new_node)
3469 a8ae3eb5 Iustin Pop
      # make sure we redistribute the config
3470 a4eae71f Michael Hanselmann
      self.cfg.Update(new_node, feedback_fn)
3471 a8ae3eb5 Iustin Pop
      # and make sure the new node will not have old files around
3472 a8ae3eb5 Iustin Pop
      if not new_node.master_candidate:
3473 a8ae3eb5 Iustin Pop
        result = self.rpc.call_node_demote_from_mc(new_node.name)
3474 3cebe102 Michael Hanselmann
        msg = result.fail_msg
3475 a8ae3eb5 Iustin Pop
        if msg:
3476 a8ae3eb5 Iustin Pop
          self.LogWarning("Node failed to demote itself from master"
3477 a8ae3eb5 Iustin Pop
                          " candidate status: %s" % msg)
3478 d8470559 Michael Hanselmann
    else:
3479 035566e3 Iustin Pop
      _RedistributeAncillaryFiles(self, additional_nodes=[node])
3480 0debfb35 Guido Trotter
      self.context.AddNode(new_node, self.proc.GetECId())
3481 a8083063 Iustin Pop
3482 a8083063 Iustin Pop
3483 b31c8676 Iustin Pop
class LUSetNodeParams(LogicalUnit):
3484 b31c8676 Iustin Pop
  """Modifies the parameters of a node.
3485 b31c8676 Iustin Pop

3486 b31c8676 Iustin Pop
  """
3487 b31c8676 Iustin Pop
  HPATH = "node-modify"
3488 b31c8676 Iustin Pop
  HTYPE = constants.HTYPE_NODE
3489 b31c8676 Iustin Pop
  _OP_REQP = ["node_name"]
3490 b31c8676 Iustin Pop
  REQ_BGL = False
3491 b31c8676 Iustin Pop
3492 b31c8676 Iustin Pop
  def CheckArguments(self):
3493 cf26a87a Iustin Pop
    self.op.node_name = _ExpandNodeName(self.cfg, self.op.node_name)
3494 3a5ba66a Iustin Pop
    _CheckBooleanOpField(self.op, 'master_candidate')
3495 3a5ba66a Iustin Pop
    _CheckBooleanOpField(self.op, 'offline')
3496 c9d443ea Iustin Pop
    _CheckBooleanOpField(self.op, 'drained')
3497 601908d0 Iustin Pop
    _CheckBooleanOpField(self.op, 'auto_promote')
3498 c9d443ea Iustin Pop
    all_mods = [self.op.offline, self.op.master_candidate, self.op.drained]
3499 c9d443ea Iustin Pop
    if all_mods.count(None) == 3:
3500 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Please pass at least one modification",
3501 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
3502 c9d443ea Iustin Pop
    if all_mods.count(True) > 1:
3503 c9d443ea Iustin Pop
      raise errors.OpPrereqError("Can't set the node into more than one"
3504 5c983ee5 Iustin Pop
                                 " state at the same time",
3505 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
3506 b31c8676 Iustin Pop
3507 601908d0 Iustin Pop
    # Boolean value that tells us whether we're offlining or draining the node
3508 601908d0 Iustin Pop
    self.offline_or_drain = (self.op.offline == True or
3509 601908d0 Iustin Pop
                             self.op.drained == True)
3510 601908d0 Iustin Pop
    self.deoffline_or_drain = (self.op.offline == False or
3511 601908d0 Iustin Pop
                               self.op.drained == False)
3512 601908d0 Iustin Pop
    self.might_demote = (self.op.master_candidate == False or
3513 601908d0 Iustin Pop
                         self.offline_or_drain)
3514 601908d0 Iustin Pop
3515 601908d0 Iustin Pop
    self.lock_all = self.op.auto_promote and self.might_demote
3516 601908d0 Iustin Pop
3517 601908d0 Iustin Pop
3518 b31c8676 Iustin Pop
  def ExpandNames(self):
3519 601908d0 Iustin Pop
    if self.lock_all:
3520 601908d0 Iustin Pop
      self.needed_locks = {locking.LEVEL_NODE: locking.ALL_SET}
3521 601908d0 Iustin Pop
    else:
3522 601908d0 Iustin Pop
      self.needed_locks = {locking.LEVEL_NODE: self.op.node_name}
3523 b31c8676 Iustin Pop
3524 b31c8676 Iustin Pop
  def BuildHooksEnv(self):
3525 b31c8676 Iustin Pop
    """Build hooks env.
3526 b31c8676 Iustin Pop

3527 b31c8676 Iustin Pop
    This runs on the master node.
3528 b31c8676 Iustin Pop

3529 b31c8676 Iustin Pop
    """
3530 b31c8676 Iustin Pop
    env = {
3531 b31c8676 Iustin Pop
      "OP_TARGET": self.op.node_name,
3532 b31c8676 Iustin Pop
      "MASTER_CANDIDATE": str(self.op.master_candidate),
3533 3a5ba66a Iustin Pop
      "OFFLINE": str(self.op.offline),
3534 c9d443ea Iustin Pop
      "DRAINED": str(self.op.drained),
3535 b31c8676 Iustin Pop
      }
3536 b31c8676 Iustin Pop
    nl = [self.cfg.GetMasterNode(),
3537 b31c8676 Iustin Pop
          self.op.node_name]
3538 b31c8676 Iustin Pop
    return env, nl, nl
3539 b31c8676 Iustin Pop
3540 b31c8676 Iustin Pop
  def CheckPrereq(self):
3541 b31c8676 Iustin Pop
    """Check prerequisites.
3542 b31c8676 Iustin Pop

3543 b31c8676 Iustin Pop
    This only checks the instance list against the existing names.
3544 b31c8676 Iustin Pop

3545 b31c8676 Iustin Pop
    """
3546 3a5ba66a Iustin Pop
    node = self.node = self.cfg.GetNodeInfo(self.op.node_name)
3547 b31c8676 Iustin Pop
3548 97c61d46 Iustin Pop
    if (self.op.master_candidate is not None or
3549 97c61d46 Iustin Pop
        self.op.drained is not None or
3550 97c61d46 Iustin Pop
        self.op.offline is not None):
3551 97c61d46 Iustin Pop
      # we can't change the master's node flags
3552 97c61d46 Iustin Pop
      if self.op.node_name == self.cfg.GetMasterNode():
3553 97c61d46 Iustin Pop
        raise errors.OpPrereqError("The master role can be changed"
3554 5c983ee5 Iustin Pop
                                   " only via masterfailover",
3555 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
3556 97c61d46 Iustin Pop
3557 601908d0 Iustin Pop
3558 601908d0 Iustin Pop
    if node.master_candidate and self.might_demote and not self.lock_all:
3559 601908d0 Iustin Pop
      assert not self.op.auto_promote, "auto-promote set but lock_all not"
3560 601908d0 Iustin Pop
      # check if after removing the current node, we're missing master
3561 601908d0 Iustin Pop
      # candidates
3562 601908d0 Iustin Pop
      (mc_remaining, mc_should, _) = \
3563 601908d0 Iustin Pop
          self.cfg.GetMasterCandidateStats(exceptions=[node.name])
3564 8fe9239e Iustin Pop
      if mc_remaining < mc_should:
3565 601908d0 Iustin Pop
        raise errors.OpPrereqError("Not enough master candidates, please"
3566 601908d0 Iustin Pop
                                   " pass auto_promote to allow promotion",
3567 601908d0 Iustin Pop
                                   errors.ECODE_INVAL)
3568 3e83dd48 Iustin Pop
3569 c9d443ea Iustin Pop
    if (self.op.master_candidate == True and
3570 c9d443ea Iustin Pop
        ((node.offline and not self.op.offline == False) or
3571 c9d443ea Iustin Pop
         (node.drained and not self.op.drained == False))):
3572 c9d443ea Iustin Pop
      raise errors.OpPrereqError("Node '%s' is offline or drained, can't set"
3573 5c983ee5 Iustin Pop
                                 " to master_candidate" % node.name,
3574 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
3575 3a5ba66a Iustin Pop
3576 3d9eb52b Guido Trotter
    # If we're being deofflined/drained, we'll MC ourself if needed
3577 601908d0 Iustin Pop
    if (self.deoffline_or_drain and not self.offline_or_drain and not
3578 cea0534a Guido Trotter
        self.op.master_candidate == True and not node.master_candidate):
3579 3d9eb52b Guido Trotter
      self.op.master_candidate = _DecideSelfPromotion(self)
3580 3d9eb52b Guido Trotter
      if self.op.master_candidate:
3581 3d9eb52b Guido Trotter
        self.LogInfo("Autopromoting node to master candidate")
3582 3d9eb52b Guido Trotter
3583 b31c8676 Iustin Pop
    return
3584 b31c8676 Iustin Pop
3585 b31c8676 Iustin Pop
  def Exec(self, feedback_fn):
3586 b31c8676 Iustin Pop
    """Modifies a node.
3587 b31c8676 Iustin Pop

3588 b31c8676 Iustin Pop
    """
3589 3a5ba66a Iustin Pop
    node = self.node
3590 b31c8676 Iustin Pop
3591 b31c8676 Iustin Pop
    result = []
3592 c9d443ea Iustin Pop
    changed_mc = False
3593 b31c8676 Iustin Pop
3594 3a5ba66a Iustin Pop
    if self.op.offline is not None:
3595 3a5ba66a Iustin Pop
      node.offline = self.op.offline
3596 3a5ba66a Iustin Pop
      result.append(("offline", str(self.op.offline)))
3597 c9d443ea Iustin Pop
      if self.op.offline == True:
3598 c9d443ea Iustin Pop
        if node.master_candidate:
3599 c9d443ea Iustin Pop
          node.master_candidate = False
3600 c9d443ea Iustin Pop
          changed_mc = True
3601 c9d443ea Iustin Pop
          result.append(("master_candidate", "auto-demotion due to offline"))
3602 c9d443ea Iustin Pop
        if node.drained:
3603 c9d443ea Iustin Pop
          node.drained = False
3604 c9d443ea Iustin Pop
          result.append(("drained", "clear drained status due to offline"))
3605 3a5ba66a Iustin Pop
3606 b31c8676 Iustin Pop
    if self.op.master_candidate is not None:
3607 b31c8676 Iustin Pop
      node.master_candidate = self.op.master_candidate
3608 c9d443ea Iustin Pop
      changed_mc = True
3609 b31c8676 Iustin Pop
      result.append(("master_candidate", str(self.op.master_candidate)))
3610 56aa9fd5 Iustin Pop
      if self.op.master_candidate == False:
3611 56aa9fd5 Iustin Pop
        rrc = self.rpc.call_node_demote_from_mc(node.name)
3612 4c4e4e1e Iustin Pop
        msg = rrc.fail_msg
3613 0959c824 Iustin Pop
        if msg:
3614 0959c824 Iustin Pop
          self.LogWarning("Node failed to demote itself: %s" % msg)
3615 b31c8676 Iustin Pop
3616 c9d443ea Iustin Pop
    if self.op.drained is not None:
3617 c9d443ea Iustin Pop
      node.drained = self.op.drained
3618 82e12743 Iustin Pop
      result.append(("drained", str(self.op.drained)))
3619 c9d443ea Iustin Pop
      if self.op.drained == True:
3620 c9d443ea Iustin Pop
        if node.master_candidate:
3621 c9d443ea Iustin Pop
          node.master_candidate = False
3622 c9d443ea Iustin Pop
          changed_mc = True
3623 c9d443ea Iustin Pop
          result.append(("master_candidate", "auto-demotion due to drain"))
3624 dec0d9da Iustin Pop
          rrc = self.rpc.call_node_demote_from_mc(node.name)
3625 3cebe102 Michael Hanselmann
          msg = rrc.fail_msg
3626 dec0d9da Iustin Pop
          if msg:
3627 dec0d9da Iustin Pop
            self.LogWarning("Node failed to demote itself: %s" % msg)
3628 c9d443ea Iustin Pop
        if node.offline:
3629 c9d443ea Iustin Pop
          node.offline = False
3630 c9d443ea Iustin Pop
          result.append(("offline", "clear offline status due to drain"))
3631 c9d443ea Iustin Pop
3632 601908d0 Iustin Pop
    # we locked all nodes, we adjust the CP before updating this node
3633 601908d0 Iustin Pop
    if self.lock_all:
3634 601908d0 Iustin Pop
      _AdjustCandidatePool(self, [node.name])
3635 601908d0 Iustin Pop
3636 b31c8676 Iustin Pop
    # this will trigger configuration file update, if needed
3637 a4eae71f Michael Hanselmann
    self.cfg.Update(node, feedback_fn)
3638 601908d0 Iustin Pop
3639 b31c8676 Iustin Pop
    # this will trigger job queue propagation or cleanup
3640 c9d443ea Iustin Pop
    if changed_mc:
3641 3a26773f Iustin Pop
      self.context.ReaddNode(node)
3642 b31c8676 Iustin Pop
3643 b31c8676 Iustin Pop
    return result
3644 b31c8676 Iustin Pop
3645 b31c8676 Iustin Pop
3646 f5118ade Iustin Pop
class LUPowercycleNode(NoHooksLU):
3647 f5118ade Iustin Pop
  """Powercycles a node.
3648 f5118ade Iustin Pop

3649 f5118ade Iustin Pop
  """
3650 f5118ade Iustin Pop
  _OP_REQP = ["node_name", "force"]
3651 f5118ade Iustin Pop
  REQ_BGL = False
3652 f5118ade Iustin Pop
3653 f5118ade Iustin Pop
  def CheckArguments(self):
3654 cf26a87a Iustin Pop
    self.op.node_name = _ExpandNodeName(self.cfg, self.op.node_name)
3655 cf26a87a Iustin Pop
    if self.op.node_name == self.cfg.GetMasterNode() and not self.op.force:
3656 f5118ade Iustin Pop
      raise errors.OpPrereqError("The node is the master and the force"
3657 5c983ee5 Iustin Pop
                                 " parameter was not set",
3658 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
3659 f5118ade Iustin Pop
3660 f5118ade Iustin Pop
  def ExpandNames(self):
3661 f5118ade Iustin Pop
    """Locking for PowercycleNode.
3662 f5118ade Iustin Pop

3663 efb8da02 Michael Hanselmann
    This is a last-resort option and shouldn't block on other
3664 f5118ade Iustin Pop
    jobs. Therefore, we grab no locks.
3665 f5118ade Iustin Pop

3666 f5118ade Iustin Pop
    """
3667 f5118ade Iustin Pop
    self.needed_locks = {}
3668 f5118ade Iustin Pop
3669 f5118ade Iustin Pop
  def CheckPrereq(self):
3670 f5118ade Iustin Pop
    """Check prerequisites.
3671 f5118ade Iustin Pop

3672 f5118ade Iustin Pop
    This LU has no prereqs.
3673 f5118ade Iustin Pop

3674 f5118ade Iustin Pop
    """
3675 f5118ade Iustin Pop
    pass
3676 f5118ade Iustin Pop
3677 f5118ade Iustin Pop
  def Exec(self, feedback_fn):
3678 f5118ade Iustin Pop
    """Reboots a node.
3679 f5118ade Iustin Pop

3680 f5118ade Iustin Pop
    """
3681 f5118ade Iustin Pop
    result = self.rpc.call_node_powercycle(self.op.node_name,
3682 f5118ade Iustin Pop
                                           self.cfg.GetHypervisorType())
3683 4c4e4e1e Iustin Pop
    result.Raise("Failed to schedule the reboot")
3684 f5118ade Iustin Pop
    return result.payload
3685 f5118ade Iustin Pop
3686 f5118ade Iustin Pop
3687 a8083063 Iustin Pop
class LUQueryClusterInfo(NoHooksLU):
3688 a8083063 Iustin Pop
  """Query cluster configuration.
3689 a8083063 Iustin Pop

3690 a8083063 Iustin Pop
  """
3691 a8083063 Iustin Pop
  _OP_REQP = []
3692 642339cf Guido Trotter
  REQ_BGL = False
3693 642339cf Guido Trotter
3694 642339cf Guido Trotter
  def ExpandNames(self):
3695 642339cf Guido Trotter
    self.needed_locks = {}
3696 a8083063 Iustin Pop
3697 a8083063 Iustin Pop
  def CheckPrereq(self):
3698 a8083063 Iustin Pop
    """No prerequsites needed for this LU.
3699 a8083063 Iustin Pop

3700 a8083063 Iustin Pop
    """
3701 a8083063 Iustin Pop
    pass
3702 a8083063 Iustin Pop
3703 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
3704 a8083063 Iustin Pop
    """Return cluster config.
3705 a8083063 Iustin Pop

3706 a8083063 Iustin Pop
    """
3707 469f88e1 Iustin Pop
    cluster = self.cfg.GetClusterInfo()
3708 17463d22 Renรฉ Nussbaumer
    os_hvp = {}
3709 17463d22 Renรฉ Nussbaumer
3710 17463d22 Renรฉ Nussbaumer
    # Filter just for enabled hypervisors
3711 17463d22 Renรฉ Nussbaumer
    for os_name, hv_dict in cluster.os_hvp.items():
3712 17463d22 Renรฉ Nussbaumer
      os_hvp[os_name] = {}
3713 17463d22 Renรฉ Nussbaumer
      for hv_name, hv_params in hv_dict.items():
3714 17463d22 Renรฉ Nussbaumer
        if hv_name in cluster.enabled_hypervisors:
3715 17463d22 Renรฉ Nussbaumer
          os_hvp[os_name][hv_name] = hv_params
3716 17463d22 Renรฉ Nussbaumer
3717 a8083063 Iustin Pop
    result = {
3718 a8083063 Iustin Pop
      "software_version": constants.RELEASE_VERSION,
3719 a8083063 Iustin Pop
      "protocol_version": constants.PROTOCOL_VERSION,
3720 a8083063 Iustin Pop
      "config_version": constants.CONFIG_VERSION,
3721 d1a7d66f Guido Trotter
      "os_api_version": max(constants.OS_API_VERSIONS),
3722 a8083063 Iustin Pop
      "export_version": constants.EXPORT_VERSION,
3723 a8083063 Iustin Pop
      "architecture": (platform.architecture()[0], platform.machine()),
3724 469f88e1 Iustin Pop
      "name": cluster.cluster_name,
3725 469f88e1 Iustin Pop
      "master": cluster.master_node,
3726 066f465d Guido Trotter
      "default_hypervisor": cluster.enabled_hypervisors[0],
3727 469f88e1 Iustin Pop
      "enabled_hypervisors": cluster.enabled_hypervisors,
3728 b8810fec Michael Hanselmann
      "hvparams": dict([(hypervisor_name, cluster.hvparams[hypervisor_name])
3729 7c4d6c7b Michael Hanselmann
                        for hypervisor_name in cluster.enabled_hypervisors]),
3730 17463d22 Renรฉ Nussbaumer
      "os_hvp": os_hvp,
3731 469f88e1 Iustin Pop
      "beparams": cluster.beparams,
3732 1094acda Guido Trotter
      "nicparams": cluster.nicparams,
3733 4b7735f9 Iustin Pop
      "candidate_pool_size": cluster.candidate_pool_size,
3734 7a56b411 Guido Trotter
      "master_netdev": cluster.master_netdev,
3735 7a56b411 Guido Trotter
      "volume_group_name": cluster.volume_group_name,
3736 7a56b411 Guido Trotter
      "file_storage_dir": cluster.file_storage_dir,
3737 3953242f Iustin Pop
      "maintain_node_health": cluster.maintain_node_health,
3738 90f72445 Iustin Pop
      "ctime": cluster.ctime,
3739 90f72445 Iustin Pop
      "mtime": cluster.mtime,
3740 259578eb Iustin Pop
      "uuid": cluster.uuid,
3741 c118d1f4 Michael Hanselmann
      "tags": list(cluster.GetTags()),
3742 1338f2b4 Balazs Lecz
      "uid_pool": cluster.uid_pool,
3743 a8083063 Iustin Pop
      }
3744 a8083063 Iustin Pop
3745 a8083063 Iustin Pop
    return result
3746 a8083063 Iustin Pop
3747 a8083063 Iustin Pop
3748 ae5849b5 Michael Hanselmann
class LUQueryConfigValues(NoHooksLU):
3749 ae5849b5 Michael Hanselmann
  """Return configuration values.
3750 a8083063 Iustin Pop

3751 a8083063 Iustin Pop
  """
3752 a8083063 Iustin Pop
  _OP_REQP = []
3753 642339cf Guido Trotter
  REQ_BGL = False
3754 a2d2e1a7 Iustin Pop
  _FIELDS_DYNAMIC = utils.FieldSet()
3755 05e50653 Michael Hanselmann
  _FIELDS_STATIC = utils.FieldSet("cluster_name", "master_node", "drain_flag",
3756 05e50653 Michael Hanselmann
                                  "watcher_pause")
3757 642339cf Guido Trotter
3758 642339cf Guido Trotter
  def ExpandNames(self):
3759 642339cf Guido Trotter
    self.needed_locks = {}
3760 a8083063 Iustin Pop
3761 31bf511f Iustin Pop
    _CheckOutputFields(static=self._FIELDS_STATIC,
3762 31bf511f Iustin Pop
                       dynamic=self._FIELDS_DYNAMIC,
3763 ae5849b5 Michael Hanselmann
                       selected=self.op.output_fields)
3764 ae5849b5 Michael Hanselmann
3765 a8083063 Iustin Pop
  def CheckPrereq(self):
3766 a8083063 Iustin Pop
    """No prerequisites.
3767 a8083063 Iustin Pop

3768 a8083063 Iustin Pop
    """
3769 a8083063 Iustin Pop
    pass
3770 a8083063 Iustin Pop
3771 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
3772 a8083063 Iustin Pop
    """Dump a representation of the cluster config to the standard output.
3773 a8083063 Iustin Pop

3774 a8083063 Iustin Pop
    """
3775 ae5849b5 Michael Hanselmann
    values = []
3776 ae5849b5 Michael Hanselmann
    for field in self.op.output_fields:
3777 ae5849b5 Michael Hanselmann
      if field == "cluster_name":
3778 3ccafd0e Iustin Pop
        entry = self.cfg.GetClusterName()
3779 ae5849b5 Michael Hanselmann
      elif field == "master_node":
3780 3ccafd0e Iustin Pop
        entry = self.cfg.GetMasterNode()
3781 3ccafd0e Iustin Pop
      elif field == "drain_flag":
3782 3ccafd0e Iustin Pop
        entry = os.path.exists(constants.JOB_QUEUE_DRAIN_FILE)
3783 05e50653 Michael Hanselmann
      elif field == "watcher_pause":
3784 cac599f1 Michael Hanselmann
        entry = utils.ReadWatcherPauseFile(constants.WATCHER_PAUSEFILE)
3785 ae5849b5 Michael Hanselmann
      else:
3786 ae5849b5 Michael Hanselmann
        raise errors.ParameterError(field)
3787 3ccafd0e Iustin Pop
      values.append(entry)
3788 ae5849b5 Michael Hanselmann
    return values
3789 a8083063 Iustin Pop
3790 a8083063 Iustin Pop
3791 a8083063 Iustin Pop
class LUActivateInstanceDisks(NoHooksLU):
3792 a8083063 Iustin Pop
  """Bring up an instance's disks.
3793 a8083063 Iustin Pop

3794 a8083063 Iustin Pop
  """
3795 a8083063 Iustin Pop
  _OP_REQP = ["instance_name"]
3796 f22a8ba3 Guido Trotter
  REQ_BGL = False
3797 f22a8ba3 Guido Trotter
3798 f22a8ba3 Guido Trotter
  def ExpandNames(self):
3799 f22a8ba3 Guido Trotter
    self._ExpandAndLockInstance()
3800 f22a8ba3 Guido Trotter
    self.needed_locks[locking.LEVEL_NODE] = []
3801 f22a8ba3 Guido Trotter
    self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
3802 f22a8ba3 Guido Trotter
3803 f22a8ba3 Guido Trotter
  def DeclareLocks(self, level):
3804 f22a8ba3 Guido Trotter
    if level == locking.LEVEL_NODE:
3805 f22a8ba3 Guido Trotter
      self._LockInstancesNodes()
3806 a8083063 Iustin Pop
3807 a8083063 Iustin Pop
  def CheckPrereq(self):
3808 a8083063 Iustin Pop
    """Check prerequisites.
3809 a8083063 Iustin Pop

3810 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
3811 a8083063 Iustin Pop

3812 a8083063 Iustin Pop
    """
3813 f22a8ba3 Guido Trotter
    self.instance = self.cfg.GetInstanceInfo(self.op.instance_name)
3814 f22a8ba3 Guido Trotter
    assert self.instance is not None, \
3815 f22a8ba3 Guido Trotter
      "Cannot retrieve locked instance %s" % self.op.instance_name
3816 43017d26 Iustin Pop
    _CheckNodeOnline(self, self.instance.primary_node)
3817 b4ec07f8 Iustin Pop
    if not hasattr(self.op, "ignore_size"):
3818 b4ec07f8 Iustin Pop
      self.op.ignore_size = False
3819 a8083063 Iustin Pop
3820 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
3821 a8083063 Iustin Pop
    """Activate the disks.
3822 a8083063 Iustin Pop

3823 a8083063 Iustin Pop
    """
3824 b4ec07f8 Iustin Pop
    disks_ok, disks_info = \
3825 b4ec07f8 Iustin Pop
              _AssembleInstanceDisks(self, self.instance,
3826 b4ec07f8 Iustin Pop
                                     ignore_size=self.op.ignore_size)
3827 a8083063 Iustin Pop
    if not disks_ok:
3828 3ecf6786 Iustin Pop
      raise errors.OpExecError("Cannot activate block devices")
3829 a8083063 Iustin Pop
3830 a8083063 Iustin Pop
    return disks_info
3831 a8083063 Iustin Pop
3832 a8083063 Iustin Pop
3833 e3443b36 Iustin Pop
def _AssembleInstanceDisks(lu, instance, ignore_secondaries=False,
3834 e3443b36 Iustin Pop
                           ignore_size=False):
3835 a8083063 Iustin Pop
  """Prepare the block devices for an instance.
3836 a8083063 Iustin Pop

3837 a8083063 Iustin Pop
  This sets up the block devices on all nodes.
3838 a8083063 Iustin Pop

3839 e4376078 Iustin Pop
  @type lu: L{LogicalUnit}
3840 e4376078 Iustin Pop
  @param lu: the logical unit on whose behalf we execute
3841 e4376078 Iustin Pop
  @type instance: L{objects.Instance}
3842 e4376078 Iustin Pop
  @param instance: the instance for whose disks we assemble
3843 e4376078 Iustin Pop
  @type ignore_secondaries: boolean
3844 e4376078 Iustin Pop
  @param ignore_secondaries: if true, errors on secondary nodes
3845 e4376078 Iustin Pop
      won't result in an error return from the function
3846 e3443b36 Iustin Pop
  @type ignore_size: boolean
3847 e3443b36 Iustin Pop
  @param ignore_size: if true, the current known size of the disk
3848 e3443b36 Iustin Pop
      will not be used during the disk activation, useful for cases
3849 e3443b36 Iustin Pop
      when the size is wrong
3850 e4376078 Iustin Pop
  @return: False if the operation failed, otherwise a list of
3851 e4376078 Iustin Pop
      (host, instance_visible_name, node_visible_name)
3852 e4376078 Iustin Pop
      with the mapping from node devices to instance devices
3853 a8083063 Iustin Pop

3854 a8083063 Iustin Pop
  """
3855 a8083063 Iustin Pop
  device_info = []
3856 a8083063 Iustin Pop
  disks_ok = True
3857 fdbd668d Iustin Pop
  iname = instance.name
3858 fdbd668d Iustin Pop
  # With the two passes mechanism we try to reduce the window of
3859 fdbd668d Iustin Pop
  # opportunity for the race condition of switching DRBD to primary
3860 fdbd668d Iustin Pop
  # before handshaking occured, but we do not eliminate it
3861 fdbd668d Iustin Pop
3862 fdbd668d Iustin Pop
  # The proper fix would be to wait (with some limits) until the
3863 fdbd668d Iustin Pop
  # connection has been made and drbd transitions from WFConnection
3864 fdbd668d Iustin Pop
  # into any other network-connected state (Connected, SyncTarget,
3865 fdbd668d Iustin Pop
  # SyncSource, etc.)
3866 fdbd668d Iustin Pop
3867 fdbd668d Iustin Pop
  # 1st pass, assemble on all nodes in secondary mode
3868 a8083063 Iustin Pop
  for inst_disk in instance.disks:
3869 a8083063 Iustin Pop
    for node, node_disk in inst_disk.ComputeNodeTree(instance.primary_node):
3870 e3443b36 Iustin Pop
      if ignore_size:
3871 e3443b36 Iustin Pop
        node_disk = node_disk.Copy()
3872 e3443b36 Iustin Pop
        node_disk.UnsetSize()
3873 b9bddb6b Iustin Pop
      lu.cfg.SetDiskID(node_disk, node)
3874 72737a7f Iustin Pop
      result = lu.rpc.call_blockdev_assemble(node, node_disk, iname, False)
3875 4c4e4e1e Iustin Pop
      msg = result.fail_msg
3876 53c14ef1 Iustin Pop
      if msg:
3877 86d9d3bb Iustin Pop
        lu.proc.LogWarning("Could not prepare block device %s on node %s"
3878 53c14ef1 Iustin Pop
                           " (is_primary=False, pass=1): %s",
3879 53c14ef1 Iustin Pop
                           inst_disk.iv_name, node, msg)
3880 fdbd668d Iustin Pop
        if not ignore_secondaries:
3881 a8083063 Iustin Pop
          disks_ok = False
3882 fdbd668d Iustin Pop
3883 fdbd668d Iustin Pop
  # FIXME: race condition on drbd migration to primary
3884 fdbd668d Iustin Pop
3885 fdbd668d Iustin Pop
  # 2nd pass, do only the primary node
3886 fdbd668d Iustin Pop
  for inst_disk in instance.disks:
3887 d52ea991 Michael Hanselmann
    dev_path = None
3888 d52ea991 Michael Hanselmann
3889 fdbd668d Iustin Pop
    for node, node_disk in inst_disk.ComputeNodeTree(instance.primary_node):
3890 fdbd668d Iustin Pop
      if node != instance.primary_node:
3891 fdbd668d Iustin Pop
        continue
3892 e3443b36 Iustin Pop
      if ignore_size:
3893 e3443b36 Iustin Pop
        node_disk = node_disk.Copy()
3894 e3443b36 Iustin Pop
        node_disk.UnsetSize()
3895 b9bddb6b Iustin Pop
      lu.cfg.SetDiskID(node_disk, node)
3896 72737a7f Iustin Pop
      result = lu.rpc.call_blockdev_assemble(node, node_disk, iname, True)
3897 4c4e4e1e Iustin Pop
      msg = result.fail_msg
3898 53c14ef1 Iustin Pop
      if msg:
3899 86d9d3bb Iustin Pop
        lu.proc.LogWarning("Could not prepare block device %s on node %s"
3900 53c14ef1 Iustin Pop
                           " (is_primary=True, pass=2): %s",
3901 53c14ef1 Iustin Pop
                           inst_disk.iv_name, node, msg)
3902 fdbd668d Iustin Pop
        disks_ok = False
3903 d52ea991 Michael Hanselmann
      else:
3904 d52ea991 Michael Hanselmann
        dev_path = result.payload
3905 d52ea991 Michael Hanselmann
3906 d52ea991 Michael Hanselmann
    device_info.append((instance.primary_node, inst_disk.iv_name, dev_path))
3907 a8083063 Iustin Pop
3908 b352ab5b Iustin Pop
  # leave the disks configured for the primary node
3909 b352ab5b Iustin Pop
  # this is a workaround that would be fixed better by
3910 b352ab5b Iustin Pop
  # improving the logical/physical id handling
3911 b352ab5b Iustin Pop
  for disk in instance.disks:
3912 b9bddb6b Iustin Pop
    lu.cfg.SetDiskID(disk, instance.primary_node)
3913 b352ab5b Iustin Pop
3914 a8083063 Iustin Pop
  return disks_ok, device_info
3915 a8083063 Iustin Pop
3916 a8083063 Iustin Pop
3917 b9bddb6b Iustin Pop
def _StartInstanceDisks(lu, instance, force):
3918 3ecf6786 Iustin Pop
  """Start the disks of an instance.
3919 3ecf6786 Iustin Pop

3920 3ecf6786 Iustin Pop
  """
3921 7c4d6c7b Michael Hanselmann
  disks_ok, _ = _AssembleInstanceDisks(lu, instance,
3922 fe7b0351 Michael Hanselmann
                                           ignore_secondaries=force)
3923 fe7b0351 Michael Hanselmann
  if not disks_ok:
3924 b9bddb6b Iustin Pop
    _ShutdownInstanceDisks(lu, instance)
3925 fe7b0351 Michael Hanselmann
    if force is not None and not force:
3926 86d9d3bb Iustin Pop
      lu.proc.LogWarning("", hint="If the message above refers to a"
3927 86d9d3bb Iustin Pop
                         " secondary node,"
3928 86d9d3bb Iustin Pop
                         " you can retry the operation using '--force'.")
3929 3ecf6786 Iustin Pop
    raise errors.OpExecError("Disk consistency error")
3930 fe7b0351 Michael Hanselmann
3931 fe7b0351 Michael Hanselmann
3932 a8083063 Iustin Pop
class LUDeactivateInstanceDisks(NoHooksLU):
3933 a8083063 Iustin Pop
  """Shutdown an instance's disks.
3934 a8083063 Iustin Pop

3935 a8083063 Iustin Pop
  """
3936 a8083063 Iustin Pop
  _OP_REQP = ["instance_name"]
3937 f22a8ba3 Guido Trotter
  REQ_BGL = False
3938 f22a8ba3 Guido Trotter
3939 f22a8ba3 Guido Trotter
  def ExpandNames(self):
3940 f22a8ba3 Guido Trotter
    self._ExpandAndLockInstance()
3941 f22a8ba3 Guido Trotter
    self.needed_locks[locking.LEVEL_NODE] = []
3942 f22a8ba3 Guido Trotter
    self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
3943 f22a8ba3 Guido Trotter
3944 f22a8ba3 Guido Trotter
  def DeclareLocks(self, level):
3945 f22a8ba3 Guido Trotter
    if level == locking.LEVEL_NODE:
3946 f22a8ba3 Guido Trotter
      self._LockInstancesNodes()
3947 a8083063 Iustin Pop
3948 a8083063 Iustin Pop
  def CheckPrereq(self):
3949 a8083063 Iustin Pop
    """Check prerequisites.
3950 a8083063 Iustin Pop

3951 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
3952 a8083063 Iustin Pop

3953 a8083063 Iustin Pop
    """
3954 f22a8ba3 Guido Trotter
    self.instance = self.cfg.GetInstanceInfo(self.op.instance_name)
3955 f22a8ba3 Guido Trotter
    assert self.instance is not None, \
3956 f22a8ba3 Guido Trotter
      "Cannot retrieve locked instance %s" % self.op.instance_name
3957 a8083063 Iustin Pop
3958 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
3959 a8083063 Iustin Pop
    """Deactivate the disks
3960 a8083063 Iustin Pop

3961 a8083063 Iustin Pop
    """
3962 a8083063 Iustin Pop
    instance = self.instance
3963 b9bddb6b Iustin Pop
    _SafeShutdownInstanceDisks(self, instance)
3964 a8083063 Iustin Pop
3965 a8083063 Iustin Pop
3966 b9bddb6b Iustin Pop
def _SafeShutdownInstanceDisks(lu, instance):
3967 155d6c75 Guido Trotter
  """Shutdown block devices of an instance.
3968 155d6c75 Guido Trotter

3969 155d6c75 Guido Trotter
  This function checks if an instance is running, before calling
3970 155d6c75 Guido Trotter
  _ShutdownInstanceDisks.
3971 155d6c75 Guido Trotter

3972 155d6c75 Guido Trotter
  """
3973 31624382 Iustin Pop
  _CheckInstanceDown(lu, instance, "cannot shutdown disks")
3974 b9bddb6b Iustin Pop
  _ShutdownInstanceDisks(lu, instance)
3975 a8083063 Iustin Pop
3976 a8083063 Iustin Pop
3977 b9bddb6b Iustin Pop
def _ShutdownInstanceDisks(lu, instance, ignore_primary=False):
3978 a8083063 Iustin Pop
  """Shutdown block devices of an instance.
3979 a8083063 Iustin Pop

3980 a8083063 Iustin Pop
  This does the shutdown on all nodes of the instance.
3981 a8083063 Iustin Pop

3982 a8083063 Iustin Pop
  If the ignore_primary is false, errors on the primary node are
3983 a8083063 Iustin Pop
  ignored.
3984 a8083063 Iustin Pop

3985 a8083063 Iustin Pop
  """
3986 cacfd1fd Iustin Pop
  all_result = True
3987 a8083063 Iustin Pop
  for disk in instance.disks:
3988 a8083063 Iustin Pop
    for node, top_disk in disk.ComputeNodeTree(instance.primary_node):
3989 b9bddb6b Iustin Pop
      lu.cfg.SetDiskID(top_disk, node)
3990 781de953 Iustin Pop
      result = lu.rpc.call_blockdev_shutdown(node, top_disk)
3991 4c4e4e1e Iustin Pop
      msg = result.fail_msg
3992 cacfd1fd Iustin Pop
      if msg:
3993 cacfd1fd Iustin Pop
        lu.LogWarning("Could not shutdown block device %s on node %s: %s",
3994 cacfd1fd Iustin Pop
                      disk.iv_name, node, msg)
3995 a8083063 Iustin Pop
        if not ignore_primary or node != instance.primary_node:
3996 cacfd1fd Iustin Pop
          all_result = False
3997 cacfd1fd Iustin Pop
  return all_result
3998 a8083063 Iustin Pop
3999 a8083063 Iustin Pop
4000 9ca87a96 Iustin Pop
def _CheckNodeFreeMemory(lu, node, reason, requested, hypervisor_name):
4001 d4f16fd9 Iustin Pop
  """Checks if a node has enough free memory.
4002 d4f16fd9 Iustin Pop

4003 d4f16fd9 Iustin Pop
  This function check if a given node has the needed amount of free
4004 d4f16fd9 Iustin Pop
  memory. In case the node has less memory or we cannot get the
4005 d4f16fd9 Iustin Pop
  information from the node, this function raise an OpPrereqError
4006 d4f16fd9 Iustin Pop
  exception.
4007 d4f16fd9 Iustin Pop

4008 b9bddb6b Iustin Pop
  @type lu: C{LogicalUnit}
4009 b9bddb6b Iustin Pop
  @param lu: a logical unit from which we get configuration data
4010 e69d05fd Iustin Pop
  @type node: C{str}
4011 e69d05fd Iustin Pop
  @param node: the node to check
4012 e69d05fd Iustin Pop
  @type reason: C{str}
4013 e69d05fd Iustin Pop
  @param reason: string to use in the error message
4014 e69d05fd Iustin Pop
  @type requested: C{int}
4015 e69d05fd Iustin Pop
  @param requested: the amount of memory in MiB to check for
4016 9ca87a96 Iustin Pop
  @type hypervisor_name: C{str}
4017 9ca87a96 Iustin Pop
  @param hypervisor_name: the hypervisor to ask for memory stats
4018 e69d05fd Iustin Pop
  @raise errors.OpPrereqError: if the node doesn't have enough memory, or
4019 e69d05fd Iustin Pop
      we cannot check the node
4020 d4f16fd9 Iustin Pop

4021 d4f16fd9 Iustin Pop
  """
4022 9ca87a96 Iustin Pop
  nodeinfo = lu.rpc.call_node_info([node], lu.cfg.GetVGName(), hypervisor_name)
4023 045dd6d9 Iustin Pop
  nodeinfo[node].Raise("Can't get data from node %s" % node,
4024 045dd6d9 Iustin Pop
                       prereq=True, ecode=errors.ECODE_ENVIRON)
4025 070e998b Iustin Pop
  free_mem = nodeinfo[node].payload.get('memory_free', None)
4026 d4f16fd9 Iustin Pop
  if not isinstance(free_mem, int):
4027 d4f16fd9 Iustin Pop
    raise errors.OpPrereqError("Can't compute free memory on node %s, result"
4028 5c983ee5 Iustin Pop
                               " was '%s'" % (node, free_mem),
4029 5c983ee5 Iustin Pop
                               errors.ECODE_ENVIRON)
4030 d4f16fd9 Iustin Pop
  if requested > free_mem:
4031 d4f16fd9 Iustin Pop
    raise errors.OpPrereqError("Not enough memory on node %s for %s:"
4032 070e998b Iustin Pop
                               " needed %s MiB, available %s MiB" %
4033 5c983ee5 Iustin Pop
                               (node, reason, requested, free_mem),
4034 5c983ee5 Iustin Pop
                               errors.ECODE_NORES)
4035 d4f16fd9 Iustin Pop
4036 d4f16fd9 Iustin Pop
4037 701384a9 Iustin Pop
def _CheckNodesFreeDisk(lu, nodenames, requested):
4038 701384a9 Iustin Pop
  """Checks if nodes have enough free disk space in the default VG.
4039 701384a9 Iustin Pop

4040 701384a9 Iustin Pop
  This function check if all given nodes have the needed amount of
4041 701384a9 Iustin Pop
  free disk. In case any node has less disk or we cannot get the
4042 701384a9 Iustin Pop
  information from the node, this function raise an OpPrereqError
4043 701384a9 Iustin Pop
  exception.
4044 701384a9 Iustin Pop

4045 701384a9 Iustin Pop
  @type lu: C{LogicalUnit}
4046 701384a9 Iustin Pop
  @param lu: a logical unit from which we get configuration data
4047 701384a9 Iustin Pop
  @type nodenames: C{list}
4048 3a488770 Iustin Pop
  @param nodenames: the list of node names to check
4049 701384a9 Iustin Pop
  @type requested: C{int}
4050 701384a9 Iustin Pop
  @param requested: the amount of disk in MiB to check for
4051 701384a9 Iustin Pop
  @raise errors.OpPrereqError: if the node doesn't have enough disk, or
4052 701384a9 Iustin Pop
      we cannot check the node
4053 701384a9 Iustin Pop

4054 701384a9 Iustin Pop
  """
4055 701384a9 Iustin Pop
  nodeinfo = lu.rpc.call_node_info(nodenames, lu.cfg.GetVGName(),
4056 701384a9 Iustin Pop
                                   lu.cfg.GetHypervisorType())
4057 701384a9 Iustin Pop
  for node in nodenames:
4058 701384a9 Iustin Pop
    info = nodeinfo[node]
4059 701384a9 Iustin Pop
    info.Raise("Cannot get current information from node %s" % node,
4060 701384a9 Iustin Pop
               prereq=True, ecode=errors.ECODE_ENVIRON)
4061 701384a9 Iustin Pop
    vg_free = info.payload.get("vg_free", None)
4062 701384a9 Iustin Pop
    if not isinstance(vg_free, int):
4063 701384a9 Iustin Pop
      raise errors.OpPrereqError("Can't compute free disk space on node %s,"
4064 701384a9 Iustin Pop
                                 " result was '%s'" % (node, vg_free),
4065 701384a9 Iustin Pop
                                 errors.ECODE_ENVIRON)
4066 701384a9 Iustin Pop
    if requested > vg_free:
4067 701384a9 Iustin Pop
      raise errors.OpPrereqError("Not enough disk space on target node %s:"
4068 701384a9 Iustin Pop
                                 " required %d MiB, available %d MiB" %
4069 701384a9 Iustin Pop
                                 (node, requested, vg_free),
4070 701384a9 Iustin Pop
                                 errors.ECODE_NORES)
4071 701384a9 Iustin Pop
4072 701384a9 Iustin Pop
4073 a8083063 Iustin Pop
class LUStartupInstance(LogicalUnit):
4074 a8083063 Iustin Pop
  """Starts an instance.
4075 a8083063 Iustin Pop

4076 a8083063 Iustin Pop
  """
4077 a8083063 Iustin Pop
  HPATH = "instance-start"
4078 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
4079 a8083063 Iustin Pop
  _OP_REQP = ["instance_name", "force"]
4080 e873317a Guido Trotter
  REQ_BGL = False
4081 e873317a Guido Trotter
4082 e873317a Guido Trotter
  def ExpandNames(self):
4083 e873317a Guido Trotter
    self._ExpandAndLockInstance()
4084 a8083063 Iustin Pop
4085 a8083063 Iustin Pop
  def BuildHooksEnv(self):
4086 a8083063 Iustin Pop
    """Build hooks env.
4087 a8083063 Iustin Pop

4088 a8083063 Iustin Pop
    This runs on master, primary and secondary nodes of the instance.
4089 a8083063 Iustin Pop

4090 a8083063 Iustin Pop
    """
4091 a8083063 Iustin Pop
    env = {
4092 a8083063 Iustin Pop
      "FORCE": self.op.force,
4093 a8083063 Iustin Pop
      }
4094 338e51e8 Iustin Pop
    env.update(_BuildInstanceHookEnvByObject(self, self.instance))
4095 6b12959c Iustin Pop
    nl = [self.cfg.GetMasterNode()] + list(self.instance.all_nodes)
4096 a8083063 Iustin Pop
    return env, nl, nl
4097 a8083063 Iustin Pop
4098 a8083063 Iustin Pop
  def CheckPrereq(self):
4099 a8083063 Iustin Pop
    """Check prerequisites.
4100 a8083063 Iustin Pop

4101 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
4102 a8083063 Iustin Pop

4103 a8083063 Iustin Pop
    """
4104 e873317a Guido Trotter
    self.instance = instance = self.cfg.GetInstanceInfo(self.op.instance_name)
4105 e873317a Guido Trotter
    assert self.instance is not None, \
4106 e873317a Guido Trotter
      "Cannot retrieve locked instance %s" % self.op.instance_name
4107 a8083063 Iustin Pop
4108 d04aaa2f Iustin Pop
    # extra beparams
4109 d04aaa2f Iustin Pop
    self.beparams = getattr(self.op, "beparams", {})
4110 d04aaa2f Iustin Pop
    if self.beparams:
4111 d04aaa2f Iustin Pop
      if not isinstance(self.beparams, dict):
4112 d04aaa2f Iustin Pop
        raise errors.OpPrereqError("Invalid beparams passed: %s, expected"
4113 5c983ee5 Iustin Pop
                                   " dict" % (type(self.beparams), ),
4114 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
4115 d04aaa2f Iustin Pop
      # fill the beparams dict
4116 d04aaa2f Iustin Pop
      utils.ForceDictType(self.beparams, constants.BES_PARAMETER_TYPES)
4117 d04aaa2f Iustin Pop
      self.op.beparams = self.beparams
4118 d04aaa2f Iustin Pop
4119 d04aaa2f Iustin Pop
    # extra hvparams
4120 d04aaa2f Iustin Pop
    self.hvparams = getattr(self.op, "hvparams", {})
4121 d04aaa2f Iustin Pop
    if self.hvparams:
4122 d04aaa2f Iustin Pop
      if not isinstance(self.hvparams, dict):
4123 d04aaa2f Iustin Pop
        raise errors.OpPrereqError("Invalid hvparams passed: %s, expected"
4124 5c983ee5 Iustin Pop
                                   " dict" % (type(self.hvparams), ),
4125 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
4126 d04aaa2f Iustin Pop
4127 d04aaa2f Iustin Pop
      # check hypervisor parameter syntax (locally)
4128 d04aaa2f Iustin Pop
      cluster = self.cfg.GetClusterInfo()
4129 d04aaa2f Iustin Pop
      utils.ForceDictType(self.hvparams, constants.HVS_PARAMETER_TYPES)
4130 abe609b2 Guido Trotter
      filled_hvp = objects.FillDict(cluster.hvparams[instance.hypervisor],
4131 d04aaa2f Iustin Pop
                                    instance.hvparams)
4132 d04aaa2f Iustin Pop
      filled_hvp.update(self.hvparams)
4133 d04aaa2f Iustin Pop
      hv_type = hypervisor.GetHypervisor(instance.hypervisor)
4134 d04aaa2f Iustin Pop
      hv_type.CheckParameterSyntax(filled_hvp)
4135 d04aaa2f Iustin Pop
      _CheckHVParams(self, instance.all_nodes, instance.hypervisor, filled_hvp)
4136 d04aaa2f Iustin Pop
      self.op.hvparams = self.hvparams
4137 d04aaa2f Iustin Pop
4138 7527a8a4 Iustin Pop
    _CheckNodeOnline(self, instance.primary_node)
4139 7527a8a4 Iustin Pop
4140 338e51e8 Iustin Pop
    bep = self.cfg.GetClusterInfo().FillBE(instance)
4141 5bbd3f7f Michael Hanselmann
    # check bridges existence
4142 b9bddb6b Iustin Pop
    _CheckInstanceBridgesExist(self, instance)
4143 a8083063 Iustin Pop
4144 f1926756 Guido Trotter
    remote_info = self.rpc.call_instance_info(instance.primary_node,
4145 f1926756 Guido Trotter
                                              instance.name,
4146 f1926756 Guido Trotter
                                              instance.hypervisor)
4147 4c4e4e1e Iustin Pop
    remote_info.Raise("Error checking node %s" % instance.primary_node,
4148 045dd6d9 Iustin Pop
                      prereq=True, ecode=errors.ECODE_ENVIRON)
4149 7ad1af4a Iustin Pop
    if not remote_info.payload: # not running already
4150 f1926756 Guido Trotter
      _CheckNodeFreeMemory(self, instance.primary_node,
4151 f1926756 Guido Trotter
                           "starting instance %s" % instance.name,
4152 f1926756 Guido Trotter
                           bep[constants.BE_MEMORY], instance.hypervisor)
4153 d4f16fd9 Iustin Pop
4154 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
4155 a8083063 Iustin Pop
    """Start the instance.
4156 a8083063 Iustin Pop

4157 a8083063 Iustin Pop
    """
4158 a8083063 Iustin Pop
    instance = self.instance
4159 a8083063 Iustin Pop
    force = self.op.force
4160 a8083063 Iustin Pop
4161 fe482621 Iustin Pop
    self.cfg.MarkInstanceUp(instance.name)
4162 fe482621 Iustin Pop
4163 a8083063 Iustin Pop
    node_current = instance.primary_node
4164 a8083063 Iustin Pop
4165 b9bddb6b Iustin Pop
    _StartInstanceDisks(self, instance, force)
4166 a8083063 Iustin Pop
4167 d04aaa2f Iustin Pop
    result = self.rpc.call_instance_start(node_current, instance,
4168 d04aaa2f Iustin Pop
                                          self.hvparams, self.beparams)
4169 4c4e4e1e Iustin Pop
    msg = result.fail_msg
4170 dd279568 Iustin Pop
    if msg:
4171 b9bddb6b Iustin Pop
      _ShutdownInstanceDisks(self, instance)
4172 dd279568 Iustin Pop
      raise errors.OpExecError("Could not start instance: %s" % msg)
4173 a8083063 Iustin Pop
4174 a8083063 Iustin Pop
4175 bf6929a2 Alexander Schreiber
class LURebootInstance(LogicalUnit):
4176 bf6929a2 Alexander Schreiber
  """Reboot an instance.
4177 bf6929a2 Alexander Schreiber

4178 bf6929a2 Alexander Schreiber
  """
4179 bf6929a2 Alexander Schreiber
  HPATH = "instance-reboot"
4180 bf6929a2 Alexander Schreiber
  HTYPE = constants.HTYPE_INSTANCE
4181 bf6929a2 Alexander Schreiber
  _OP_REQP = ["instance_name", "ignore_secondaries", "reboot_type"]
4182 e873317a Guido Trotter
  REQ_BGL = False
4183 e873317a Guido Trotter
4184 17c3f802 Guido Trotter
  def CheckArguments(self):
4185 17c3f802 Guido Trotter
    """Check the arguments.
4186 17c3f802 Guido Trotter

4187 17c3f802 Guido Trotter
    """
4188 17c3f802 Guido Trotter
    self.shutdown_timeout = getattr(self.op, "shutdown_timeout",
4189 17c3f802 Guido Trotter
                                    constants.DEFAULT_SHUTDOWN_TIMEOUT)
4190 17c3f802 Guido Trotter
4191 e873317a Guido Trotter
  def ExpandNames(self):
4192 0fcc5db3 Guido Trotter
    if self.op.reboot_type not in [constants.INSTANCE_REBOOT_SOFT,
4193 0fcc5db3 Guido Trotter
                                   constants.INSTANCE_REBOOT_HARD,
4194 0fcc5db3 Guido Trotter
                                   constants.INSTANCE_REBOOT_FULL]:
4195 0fcc5db3 Guido Trotter
      raise errors.ParameterError("reboot type not in [%s, %s, %s]" %
4196 0fcc5db3 Guido Trotter
                                  (constants.INSTANCE_REBOOT_SOFT,
4197 0fcc5db3 Guido Trotter
                                   constants.INSTANCE_REBOOT_HARD,
4198 0fcc5db3 Guido Trotter
                                   constants.INSTANCE_REBOOT_FULL))
4199 e873317a Guido Trotter
    self._ExpandAndLockInstance()
4200 bf6929a2 Alexander Schreiber
4201 bf6929a2 Alexander Schreiber
  def BuildHooksEnv(self):
4202 bf6929a2 Alexander Schreiber
    """Build hooks env.
4203 bf6929a2 Alexander Schreiber

4204 bf6929a2 Alexander Schreiber
    This runs on master, primary and secondary nodes of the instance.
4205 bf6929a2 Alexander Schreiber

4206 bf6929a2 Alexander Schreiber
    """
4207 bf6929a2 Alexander Schreiber
    env = {
4208 bf6929a2 Alexander Schreiber
      "IGNORE_SECONDARIES": self.op.ignore_secondaries,
4209 2c2690c9 Iustin Pop
      "REBOOT_TYPE": self.op.reboot_type,
4210 17c3f802 Guido Trotter
      "SHUTDOWN_TIMEOUT": self.shutdown_timeout,
4211 bf6929a2 Alexander Schreiber
      }
4212 338e51e8 Iustin Pop
    env.update(_BuildInstanceHookEnvByObject(self, self.instance))
4213 6b12959c Iustin Pop
    nl = [self.cfg.GetMasterNode()] + list(self.instance.all_nodes)
4214 bf6929a2 Alexander Schreiber
    return env, nl, nl
4215 bf6929a2 Alexander Schreiber
4216 bf6929a2 Alexander Schreiber
  def CheckPrereq(self):
4217 bf6929a2 Alexander Schreiber
    """Check prerequisites.
4218 bf6929a2 Alexander Schreiber

4219 bf6929a2 Alexander Schreiber
    This checks that the instance is in the cluster.
4220 bf6929a2 Alexander Schreiber

4221 bf6929a2 Alexander Schreiber
    """
4222 e873317a Guido Trotter
    self.instance = instance = self.cfg.GetInstanceInfo(self.op.instance_name)
4223 e873317a Guido Trotter
    assert self.instance is not None, \
4224 e873317a Guido Trotter
      "Cannot retrieve locked instance %s" % self.op.instance_name
4225 bf6929a2 Alexander Schreiber
4226 7527a8a4 Iustin Pop
    _CheckNodeOnline(self, instance.primary_node)
4227 7527a8a4 Iustin Pop
4228 5bbd3f7f Michael Hanselmann
    # check bridges existence
4229 b9bddb6b Iustin Pop
    _CheckInstanceBridgesExist(self, instance)
4230 bf6929a2 Alexander Schreiber
4231 bf6929a2 Alexander Schreiber
  def Exec(self, feedback_fn):
4232 bf6929a2 Alexander Schreiber
    """Reboot the instance.
4233 bf6929a2 Alexander Schreiber

4234 bf6929a2 Alexander Schreiber
    """
4235 bf6929a2 Alexander Schreiber
    instance = self.instance
4236 bf6929a2 Alexander Schreiber
    ignore_secondaries = self.op.ignore_secondaries
4237 bf6929a2 Alexander Schreiber
    reboot_type = self.op.reboot_type
4238 bf6929a2 Alexander Schreiber
4239 bf6929a2 Alexander Schreiber
    node_current = instance.primary_node
4240 bf6929a2 Alexander Schreiber
4241 bf6929a2 Alexander Schreiber
    if reboot_type in [constants.INSTANCE_REBOOT_SOFT,
4242 bf6929a2 Alexander Schreiber
                       constants.INSTANCE_REBOOT_HARD]:
4243 ae48ac32 Iustin Pop
      for disk in instance.disks:
4244 ae48ac32 Iustin Pop
        self.cfg.SetDiskID(disk, node_current)
4245 781de953 Iustin Pop
      result = self.rpc.call_instance_reboot(node_current, instance,
4246 17c3f802 Guido Trotter
                                             reboot_type,
4247 17c3f802 Guido Trotter
                                             self.shutdown_timeout)
4248 4c4e4e1e Iustin Pop
      result.Raise("Could not reboot instance")
4249 bf6929a2 Alexander Schreiber
    else:
4250 17c3f802 Guido Trotter
      result = self.rpc.call_instance_shutdown(node_current, instance,
4251 17c3f802 Guido Trotter
                                               self.shutdown_timeout)
4252 4c4e4e1e Iustin Pop
      result.Raise("Could not shutdown instance for full reboot")
4253 b9bddb6b Iustin Pop
      _ShutdownInstanceDisks(self, instance)
4254 b9bddb6b Iustin Pop
      _StartInstanceDisks(self, instance, ignore_secondaries)
4255 0eca8e0c Iustin Pop
      result = self.rpc.call_instance_start(node_current, instance, None, None)
4256 4c4e4e1e Iustin Pop
      msg = result.fail_msg
4257 dd279568 Iustin Pop
      if msg:
4258 b9bddb6b Iustin Pop
        _ShutdownInstanceDisks(self, instance)
4259 dd279568 Iustin Pop
        raise errors.OpExecError("Could not start instance for"
4260 dd279568 Iustin Pop
                                 " full reboot: %s" % msg)
4261 bf6929a2 Alexander Schreiber
4262 bf6929a2 Alexander Schreiber
    self.cfg.MarkInstanceUp(instance.name)
4263 bf6929a2 Alexander Schreiber
4264 bf6929a2 Alexander Schreiber
4265 a8083063 Iustin Pop
class LUShutdownInstance(LogicalUnit):
4266 a8083063 Iustin Pop
  """Shutdown an instance.
4267 a8083063 Iustin Pop

4268 a8083063 Iustin Pop
  """
4269 a8083063 Iustin Pop
  HPATH = "instance-stop"
4270 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
4271 a8083063 Iustin Pop
  _OP_REQP = ["instance_name"]
4272 e873317a Guido Trotter
  REQ_BGL = False
4273 e873317a Guido Trotter
4274 6263189c Guido Trotter
  def CheckArguments(self):
4275 6263189c Guido Trotter
    """Check the arguments.
4276 6263189c Guido Trotter

4277 6263189c Guido Trotter
    """
4278 6263189c Guido Trotter
    self.timeout = getattr(self.op, "timeout",
4279 6263189c Guido Trotter
                           constants.DEFAULT_SHUTDOWN_TIMEOUT)
4280 6263189c Guido Trotter
4281 e873317a Guido Trotter
  def ExpandNames(self):
4282 e873317a Guido Trotter
    self._ExpandAndLockInstance()
4283 a8083063 Iustin Pop
4284 a8083063 Iustin Pop
  def BuildHooksEnv(self):
4285 a8083063 Iustin Pop
    """Build hooks env.
4286 a8083063 Iustin Pop

4287 a8083063 Iustin Pop
    This runs on master, primary and secondary nodes of the instance.
4288 a8083063 Iustin Pop

4289 a8083063 Iustin Pop
    """
4290 338e51e8 Iustin Pop
    env = _BuildInstanceHookEnvByObject(self, self.instance)
4291 6263189c Guido Trotter
    env["TIMEOUT"] = self.timeout
4292 6b12959c Iustin Pop
    nl = [self.cfg.GetMasterNode()] + list(self.instance.all_nodes)
4293 a8083063 Iustin Pop
    return env, nl, nl
4294 a8083063 Iustin Pop
4295 a8083063 Iustin Pop
  def CheckPrereq(self):
4296 a8083063 Iustin Pop
    """Check prerequisites.
4297 a8083063 Iustin Pop

4298 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
4299 a8083063 Iustin Pop

4300 a8083063 Iustin Pop
    """
4301 e873317a Guido Trotter
    self.instance = self.cfg.GetInstanceInfo(self.op.instance_name)
4302 e873317a Guido Trotter
    assert self.instance is not None, \
4303 e873317a Guido Trotter
      "Cannot retrieve locked instance %s" % self.op.instance_name
4304 43017d26 Iustin Pop
    _CheckNodeOnline(self, self.instance.primary_node)
4305 a8083063 Iustin Pop
4306 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
4307 a8083063 Iustin Pop
    """Shutdown the instance.
4308 a8083063 Iustin Pop

4309 a8083063 Iustin Pop
    """
4310 a8083063 Iustin Pop
    instance = self.instance
4311 a8083063 Iustin Pop
    node_current = instance.primary_node
4312 6263189c Guido Trotter
    timeout = self.timeout
4313 fe482621 Iustin Pop
    self.cfg.MarkInstanceDown(instance.name)
4314 6263189c Guido Trotter
    result = self.rpc.call_instance_shutdown(node_current, instance, timeout)
4315 4c4e4e1e Iustin Pop
    msg = result.fail_msg
4316 1fae010f Iustin Pop
    if msg:
4317 1fae010f Iustin Pop
      self.proc.LogWarning("Could not shutdown instance: %s" % msg)
4318 a8083063 Iustin Pop
4319 b9bddb6b Iustin Pop
    _ShutdownInstanceDisks(self, instance)
4320 a8083063 Iustin Pop
4321 a8083063 Iustin Pop
4322 fe7b0351 Michael Hanselmann
class LUReinstallInstance(LogicalUnit):
4323 fe7b0351 Michael Hanselmann
  """Reinstall an instance.
4324 fe7b0351 Michael Hanselmann

4325 fe7b0351 Michael Hanselmann
  """
4326 fe7b0351 Michael Hanselmann
  HPATH = "instance-reinstall"
4327 fe7b0351 Michael Hanselmann
  HTYPE = constants.HTYPE_INSTANCE
4328 fe7b0351 Michael Hanselmann
  _OP_REQP = ["instance_name"]
4329 4e0b4d2d Guido Trotter
  REQ_BGL = False
4330 4e0b4d2d Guido Trotter
4331 4e0b4d2d Guido Trotter
  def ExpandNames(self):
4332 4e0b4d2d Guido Trotter
    self._ExpandAndLockInstance()
4333 fe7b0351 Michael Hanselmann
4334 fe7b0351 Michael Hanselmann
  def BuildHooksEnv(self):
4335 fe7b0351 Michael Hanselmann
    """Build hooks env.
4336 fe7b0351 Michael Hanselmann

4337 fe7b0351 Michael Hanselmann
    This runs on master, primary and secondary nodes of the instance.
4338 fe7b0351 Michael Hanselmann

4339 fe7b0351 Michael Hanselmann
    """
4340 338e51e8 Iustin Pop
    env = _BuildInstanceHookEnvByObject(self, self.instance)
4341 6b12959c Iustin Pop
    nl = [self.cfg.GetMasterNode()] + list(self.instance.all_nodes)
4342 fe7b0351 Michael Hanselmann
    return env, nl, nl
4343 fe7b0351 Michael Hanselmann
4344 fe7b0351 Michael Hanselmann
  def CheckPrereq(self):
4345 fe7b0351 Michael Hanselmann
    """Check prerequisites.
4346 fe7b0351 Michael Hanselmann

4347 fe7b0351 Michael Hanselmann
    This checks that the instance is in the cluster and is not running.
4348 fe7b0351 Michael Hanselmann

4349 fe7b0351 Michael Hanselmann
    """
4350 4e0b4d2d Guido Trotter
    instance = self.cfg.GetInstanceInfo(self.op.instance_name)
4351 4e0b4d2d Guido Trotter
    assert instance is not None, \
4352 4e0b4d2d Guido Trotter
      "Cannot retrieve locked instance %s" % self.op.instance_name
4353 7527a8a4 Iustin Pop
    _CheckNodeOnline(self, instance.primary_node)
4354 4e0b4d2d Guido Trotter
4355 fe7b0351 Michael Hanselmann
    if instance.disk_template == constants.DT_DISKLESS:
4356 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' has no disks" %
4357 5c983ee5 Iustin Pop
                                 self.op.instance_name,
4358 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
4359 31624382 Iustin Pop
    _CheckInstanceDown(self, instance, "cannot reinstall")
4360 d0834de3 Michael Hanselmann
4361 d0834de3 Michael Hanselmann
    self.op.os_type = getattr(self.op, "os_type", None)
4362 f2c05717 Guido Trotter
    self.op.force_variant = getattr(self.op, "force_variant", False)
4363 d0834de3 Michael Hanselmann
    if self.op.os_type is not None:
4364 d0834de3 Michael Hanselmann
      # OS verification
4365 cf26a87a Iustin Pop
      pnode = _ExpandNodeName(self.cfg, instance.primary_node)
4366 231cd901 Iustin Pop
      _CheckNodeHasOS(self, pnode, self.op.os_type, self.op.force_variant)
4367 d0834de3 Michael Hanselmann
4368 fe7b0351 Michael Hanselmann
    self.instance = instance
4369 fe7b0351 Michael Hanselmann
4370 fe7b0351 Michael Hanselmann
  def Exec(self, feedback_fn):
4371 fe7b0351 Michael Hanselmann
    """Reinstall the instance.
4372 fe7b0351 Michael Hanselmann

4373 fe7b0351 Michael Hanselmann
    """
4374 fe7b0351 Michael Hanselmann
    inst = self.instance
4375 fe7b0351 Michael Hanselmann
4376 d0834de3 Michael Hanselmann
    if self.op.os_type is not None:
4377 d0834de3 Michael Hanselmann
      feedback_fn("Changing OS to '%s'..." % self.op.os_type)
4378 d0834de3 Michael Hanselmann
      inst.os = self.op.os_type
4379 a4eae71f Michael Hanselmann
      self.cfg.Update(inst, feedback_fn)
4380 d0834de3 Michael Hanselmann
4381 b9bddb6b Iustin Pop
    _StartInstanceDisks(self, inst, None)
4382 fe7b0351 Michael Hanselmann
    try:
4383 fe7b0351 Michael Hanselmann
      feedback_fn("Running the instance OS create scripts...")
4384 4a0e011f Iustin Pop
      # FIXME: pass debug option from opcode to backend
4385 dd713605 Iustin Pop
      result = self.rpc.call_instance_os_add(inst.primary_node, inst, True,
4386 dd713605 Iustin Pop
                                             self.op.debug_level)
4387 4c4e4e1e Iustin Pop
      result.Raise("Could not install OS for instance %s on node %s" %
4388 4c4e4e1e Iustin Pop
                   (inst.name, inst.primary_node))
4389 fe7b0351 Michael Hanselmann
    finally:
4390 b9bddb6b Iustin Pop
      _ShutdownInstanceDisks(self, inst)
4391 fe7b0351 Michael Hanselmann
4392 fe7b0351 Michael Hanselmann
4393 bd315bfa Iustin Pop
class LURecreateInstanceDisks(LogicalUnit):
4394 bd315bfa Iustin Pop
  """Recreate an instance's missing disks.
4395 bd315bfa Iustin Pop

4396 bd315bfa Iustin Pop
  """
4397 bd315bfa Iustin Pop
  HPATH = "instance-recreate-disks"
4398 bd315bfa Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
4399 bd315bfa Iustin Pop
  _OP_REQP = ["instance_name", "disks"]
4400 bd315bfa Iustin Pop
  REQ_BGL = False
4401 bd315bfa Iustin Pop
4402 bd315bfa Iustin Pop
  def CheckArguments(self):
4403 bd315bfa Iustin Pop
    """Check the arguments.
4404 bd315bfa Iustin Pop

4405 bd315bfa Iustin Pop
    """
4406 bd315bfa Iustin Pop
    if not isinstance(self.op.disks, list):
4407 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Invalid disks parameter", errors.ECODE_INVAL)
4408 bd315bfa Iustin Pop
    for item in self.op.disks:
4409 bd315bfa Iustin Pop
      if (not isinstance(item, int) or
4410 bd315bfa Iustin Pop
          item < 0):
4411 bd315bfa Iustin Pop
        raise errors.OpPrereqError("Invalid disk specification '%s'" %
4412 5c983ee5 Iustin Pop
                                   str(item), errors.ECODE_INVAL)
4413 bd315bfa Iustin Pop
4414 bd315bfa Iustin Pop
  def ExpandNames(self):
4415 bd315bfa Iustin Pop
    self._ExpandAndLockInstance()
4416 bd315bfa Iustin Pop
4417 bd315bfa Iustin Pop
  def BuildHooksEnv(self):
4418 bd315bfa Iustin Pop
    """Build hooks env.
4419 bd315bfa Iustin Pop

4420 bd315bfa Iustin Pop
    This runs on master, primary and secondary nodes of the instance.
4421 bd315bfa Iustin Pop

4422 bd315bfa Iustin Pop
    """
4423 bd315bfa Iustin Pop
    env = _BuildInstanceHookEnvByObject(self, self.instance)
4424 bd315bfa Iustin Pop
    nl = [self.cfg.GetMasterNode()] + list(self.instance.all_nodes)
4425 bd315bfa Iustin Pop
    return env, nl, nl
4426 bd315bfa Iustin Pop
4427 bd315bfa Iustin Pop
  def CheckPrereq(self):
4428 bd315bfa Iustin Pop
    """Check prerequisites.
4429 bd315bfa Iustin Pop

4430 bd315bfa Iustin Pop
    This checks that the instance is in the cluster and is not running.
4431 bd315bfa Iustin Pop

4432 bd315bfa Iustin Pop
    """
4433 bd315bfa Iustin Pop
    instance = self.cfg.GetInstanceInfo(self.op.instance_name)
4434 bd315bfa Iustin Pop
    assert instance is not None, \
4435 bd315bfa Iustin Pop
      "Cannot retrieve locked instance %s" % self.op.instance_name
4436 bd315bfa Iustin Pop
    _CheckNodeOnline(self, instance.primary_node)
4437 bd315bfa Iustin Pop
4438 bd315bfa Iustin Pop
    if instance.disk_template == constants.DT_DISKLESS:
4439 bd315bfa Iustin Pop
      raise errors.OpPrereqError("Instance '%s' has no disks" %
4440 5c983ee5 Iustin Pop
                                 self.op.instance_name, errors.ECODE_INVAL)
4441 31624382 Iustin Pop
    _CheckInstanceDown(self, instance, "cannot recreate disks")
4442 bd315bfa Iustin Pop
4443 bd315bfa Iustin Pop
    if not self.op.disks:
4444 bd315bfa Iustin Pop
      self.op.disks = range(len(instance.disks))
4445 bd315bfa Iustin Pop
    else:
4446 bd315bfa Iustin Pop
      for idx in self.op.disks:
4447 bd315bfa Iustin Pop
        if idx >= len(instance.disks):
4448 5c983ee5 Iustin Pop
          raise errors.OpPrereqError("Invalid disk index passed '%s'" % idx,
4449 5c983ee5 Iustin Pop
                                     errors.ECODE_INVAL)
4450 bd315bfa Iustin Pop
4451 bd315bfa Iustin Pop
    self.instance = instance
4452 bd315bfa Iustin Pop
4453 bd315bfa Iustin Pop
  def Exec(self, feedback_fn):
4454 bd315bfa Iustin Pop
    """Recreate the disks.
4455 bd315bfa Iustin Pop

4456 bd315bfa Iustin Pop
    """
4457 bd315bfa Iustin Pop
    to_skip = []
4458 1122eb25 Iustin Pop
    for idx, _ in enumerate(self.instance.disks):
4459 bd315bfa Iustin Pop
      if idx not in self.op.disks: # disk idx has not been passed in
4460 bd315bfa Iustin Pop
        to_skip.append(idx)
4461 bd315bfa Iustin Pop
        continue
4462 bd315bfa Iustin Pop
4463 bd315bfa Iustin Pop
    _CreateDisks(self, self.instance, to_skip=to_skip)
4464 bd315bfa Iustin Pop
4465 bd315bfa Iustin Pop
4466 decd5f45 Iustin Pop
class LURenameInstance(LogicalUnit):
4467 decd5f45 Iustin Pop
  """Rename an instance.
4468 decd5f45 Iustin Pop

4469 decd5f45 Iustin Pop
  """
4470 decd5f45 Iustin Pop
  HPATH = "instance-rename"
4471 decd5f45 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
4472 decd5f45 Iustin Pop
  _OP_REQP = ["instance_name", "new_name"]
4473 decd5f45 Iustin Pop
4474 decd5f45 Iustin Pop
  def BuildHooksEnv(self):
4475 decd5f45 Iustin Pop
    """Build hooks env.
4476 decd5f45 Iustin Pop

4477 decd5f45 Iustin Pop
    This runs on master, primary and secondary nodes of the instance.
4478 decd5f45 Iustin Pop

4479 decd5f45 Iustin Pop
    """
4480 338e51e8 Iustin Pop
    env = _BuildInstanceHookEnvByObject(self, self.instance)
4481 decd5f45 Iustin Pop
    env["INSTANCE_NEW_NAME"] = self.op.new_name
4482 6b12959c Iustin Pop
    nl = [self.cfg.GetMasterNode()] + list(self.instance.all_nodes)
4483 decd5f45 Iustin Pop
    return env, nl, nl
4484 decd5f45 Iustin Pop
4485 decd5f45 Iustin Pop
  def CheckPrereq(self):
4486 decd5f45 Iustin Pop
    """Check prerequisites.
4487 decd5f45 Iustin Pop

4488 decd5f45 Iustin Pop
    This checks that the instance is in the cluster and is not running.
4489 decd5f45 Iustin Pop

4490 decd5f45 Iustin Pop
    """
4491 cf26a87a Iustin Pop
    self.op.instance_name = _ExpandInstanceName(self.cfg,
4492 cf26a87a Iustin Pop
                                                self.op.instance_name)
4493 cf26a87a Iustin Pop
    instance = self.cfg.GetInstanceInfo(self.op.instance_name)
4494 cf26a87a Iustin Pop
    assert instance is not None
4495 7527a8a4 Iustin Pop
    _CheckNodeOnline(self, instance.primary_node)
4496 31624382 Iustin Pop
    _CheckInstanceDown(self, instance, "cannot rename")
4497 decd5f45 Iustin Pop
    self.instance = instance
4498 decd5f45 Iustin Pop
4499 decd5f45 Iustin Pop
    # new name verification
4500 104f4ca1 Iustin Pop
    name_info = utils.GetHostInfo(self.op.new_name)
4501 decd5f45 Iustin Pop
4502 89e1fc26 Iustin Pop
    self.op.new_name = new_name = name_info.name
4503 7bde3275 Guido Trotter
    instance_list = self.cfg.GetInstanceList()
4504 7bde3275 Guido Trotter
    if new_name in instance_list:
4505 7bde3275 Guido Trotter
      raise errors.OpPrereqError("Instance '%s' is already in the cluster" %
4506 5c983ee5 Iustin Pop
                                 new_name, errors.ECODE_EXISTS)
4507 7bde3275 Guido Trotter
4508 decd5f45 Iustin Pop
    if not getattr(self.op, "ignore_ip", False):
4509 937f983d Guido Trotter
      if utils.TcpPing(name_info.ip, constants.DEFAULT_NODED_PORT):
4510 decd5f45 Iustin Pop
        raise errors.OpPrereqError("IP %s of instance %s already in use" %
4511 5c983ee5 Iustin Pop
                                   (name_info.ip, new_name),
4512 5c983ee5 Iustin Pop
                                   errors.ECODE_NOTUNIQUE)
4513 decd5f45 Iustin Pop
4514 decd5f45 Iustin Pop
4515 decd5f45 Iustin Pop
  def Exec(self, feedback_fn):
4516 decd5f45 Iustin Pop
    """Reinstall the instance.
4517 decd5f45 Iustin Pop

4518 decd5f45 Iustin Pop
    """
4519 decd5f45 Iustin Pop
    inst = self.instance
4520 decd5f45 Iustin Pop
    old_name = inst.name
4521 decd5f45 Iustin Pop
4522 b23c4333 Manuel Franceschini
    if inst.disk_template == constants.DT_FILE:
4523 b23c4333 Manuel Franceschini
      old_file_storage_dir = os.path.dirname(inst.disks[0].logical_id[1])
4524 b23c4333 Manuel Franceschini
4525 decd5f45 Iustin Pop
    self.cfg.RenameInstance(inst.name, self.op.new_name)
4526 74b5913f Guido Trotter
    # Change the instance lock. This is definitely safe while we hold the BGL
4527 cb4e8387 Iustin Pop
    self.context.glm.remove(locking.LEVEL_INSTANCE, old_name)
4528 74b5913f Guido Trotter
    self.context.glm.add(locking.LEVEL_INSTANCE, self.op.new_name)
4529 decd5f45 Iustin Pop
4530 decd5f45 Iustin Pop
    # re-read the instance from the configuration after rename
4531 decd5f45 Iustin Pop
    inst = self.cfg.GetInstanceInfo(self.op.new_name)
4532 decd5f45 Iustin Pop
4533 b23c4333 Manuel Franceschini
    if inst.disk_template == constants.DT_FILE:
4534 b23c4333 Manuel Franceschini
      new_file_storage_dir = os.path.dirname(inst.disks[0].logical_id[1])
4535 72737a7f Iustin Pop
      result = self.rpc.call_file_storage_dir_rename(inst.primary_node,
4536 72737a7f Iustin Pop
                                                     old_file_storage_dir,
4537 72737a7f Iustin Pop
                                                     new_file_storage_dir)
4538 4c4e4e1e Iustin Pop
      result.Raise("Could not rename on node %s directory '%s' to '%s'"
4539 4c4e4e1e Iustin Pop
                   " (but the instance has been renamed in Ganeti)" %
4540 4c4e4e1e Iustin Pop
                   (inst.primary_node, old_file_storage_dir,
4541 4c4e4e1e Iustin Pop
                    new_file_storage_dir))
4542 b23c4333 Manuel Franceschini
4543 b9bddb6b Iustin Pop
    _StartInstanceDisks(self, inst, None)
4544 decd5f45 Iustin Pop
    try:
4545 781de953 Iustin Pop
      result = self.rpc.call_instance_run_rename(inst.primary_node, inst,
4546 dd713605 Iustin Pop
                                                 old_name, self.op.debug_level)
4547 4c4e4e1e Iustin Pop
      msg = result.fail_msg
4548 96841384 Iustin Pop
      if msg:
4549 6291574d Alexander Schreiber
        msg = ("Could not run OS rename script for instance %s on node %s"
4550 96841384 Iustin Pop
               " (but the instance has been renamed in Ganeti): %s" %
4551 96841384 Iustin Pop
               (inst.name, inst.primary_node, msg))
4552 86d9d3bb Iustin Pop
        self.proc.LogWarning(msg)
4553 decd5f45 Iustin Pop
    finally:
4554 b9bddb6b Iustin Pop
      _ShutdownInstanceDisks(self, inst)
4555 decd5f45 Iustin Pop
4556 decd5f45 Iustin Pop
4557 a8083063 Iustin Pop
class LURemoveInstance(LogicalUnit):
4558 a8083063 Iustin Pop
  """Remove an instance.
4559 a8083063 Iustin Pop

4560 a8083063 Iustin Pop
  """
4561 a8083063 Iustin Pop
  HPATH = "instance-remove"
4562 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
4563 5c54b832 Iustin Pop
  _OP_REQP = ["instance_name", "ignore_failures"]
4564 cf472233 Guido Trotter
  REQ_BGL = False
4565 cf472233 Guido Trotter
4566 17c3f802 Guido Trotter
  def CheckArguments(self):
4567 17c3f802 Guido Trotter
    """Check the arguments.
4568 17c3f802 Guido Trotter

4569 17c3f802 Guido Trotter
    """
4570 17c3f802 Guido Trotter
    self.shutdown_timeout = getattr(self.op, "shutdown_timeout",
4571 17c3f802 Guido Trotter
                                    constants.DEFAULT_SHUTDOWN_TIMEOUT)
4572 17c3f802 Guido Trotter
4573 cf472233 Guido Trotter
  def ExpandNames(self):
4574 cf472233 Guido Trotter
    self._ExpandAndLockInstance()
4575 cf472233 Guido Trotter
    self.needed_locks[locking.LEVEL_NODE] = []
4576 cf472233 Guido Trotter
    self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
4577 cf472233 Guido Trotter
4578 cf472233 Guido Trotter
  def DeclareLocks(self, level):
4579 cf472233 Guido Trotter
    if level == locking.LEVEL_NODE:
4580 cf472233 Guido Trotter
      self._LockInstancesNodes()
4581 a8083063 Iustin Pop
4582 a8083063 Iustin Pop
  def BuildHooksEnv(self):
4583 a8083063 Iustin Pop
    """Build hooks env.
4584 a8083063 Iustin Pop

4585 a8083063 Iustin Pop
    This runs on master, primary and secondary nodes of the instance.
4586 a8083063 Iustin Pop

4587 a8083063 Iustin Pop
    """
4588 338e51e8 Iustin Pop
    env = _BuildInstanceHookEnvByObject(self, self.instance)
4589 17c3f802 Guido Trotter
    env["SHUTDOWN_TIMEOUT"] = self.shutdown_timeout
4590 d6a02168 Michael Hanselmann
    nl = [self.cfg.GetMasterNode()]
4591 abd8e836 Iustin Pop
    nl_post = list(self.instance.all_nodes) + nl
4592 abd8e836 Iustin Pop
    return env, nl, nl_post
4593 a8083063 Iustin Pop
4594 a8083063 Iustin Pop
  def CheckPrereq(self):
4595 a8083063 Iustin Pop
    """Check prerequisites.
4596 a8083063 Iustin Pop

4597 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
4598 a8083063 Iustin Pop

4599 a8083063 Iustin Pop
    """
4600 cf472233 Guido Trotter
    self.instance = self.cfg.GetInstanceInfo(self.op.instance_name)
4601 cf472233 Guido Trotter
    assert self.instance is not None, \
4602 cf472233 Guido Trotter
      "Cannot retrieve locked instance %s" % self.op.instance_name
4603 a8083063 Iustin Pop
4604 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
4605 a8083063 Iustin Pop
    """Remove the instance.
4606 a8083063 Iustin Pop

4607 a8083063 Iustin Pop
    """
4608 a8083063 Iustin Pop
    instance = self.instance
4609 9a4f63d1 Iustin Pop
    logging.info("Shutting down instance %s on node %s",
4610 9a4f63d1 Iustin Pop
                 instance.name, instance.primary_node)
4611 a8083063 Iustin Pop
4612 17c3f802 Guido Trotter
    result = self.rpc.call_instance_shutdown(instance.primary_node, instance,
4613 17c3f802 Guido Trotter
                                             self.shutdown_timeout)
4614 4c4e4e1e Iustin Pop
    msg = result.fail_msg
4615 1fae010f Iustin Pop
    if msg:
4616 1d67656e Iustin Pop
      if self.op.ignore_failures:
4617 1fae010f Iustin Pop
        feedback_fn("Warning: can't shutdown instance: %s" % msg)
4618 1d67656e Iustin Pop
      else:
4619 1fae010f Iustin Pop
        raise errors.OpExecError("Could not shutdown instance %s on"
4620 1fae010f Iustin Pop
                                 " node %s: %s" %
4621 1fae010f Iustin Pop
                                 (instance.name, instance.primary_node, msg))
4622 a8083063 Iustin Pop
4623 9a4f63d1 Iustin Pop
    logging.info("Removing block devices for instance %s", instance.name)
4624 a8083063 Iustin Pop
4625 b9bddb6b Iustin Pop
    if not _RemoveDisks(self, instance):
4626 1d67656e Iustin Pop
      if self.op.ignore_failures:
4627 1d67656e Iustin Pop
        feedback_fn("Warning: can't remove instance's disks")
4628 1d67656e Iustin Pop
      else:
4629 1d67656e Iustin Pop
        raise errors.OpExecError("Can't remove instance's disks")
4630 a8083063 Iustin Pop
4631 9a4f63d1 Iustin Pop
    logging.info("Removing instance %s out of cluster config", instance.name)
4632 a8083063 Iustin Pop
4633 a8083063 Iustin Pop
    self.cfg.RemoveInstance(instance.name)
4634 cf472233 Guido Trotter
    self.remove_locks[locking.LEVEL_INSTANCE] = instance.name
4635 a8083063 Iustin Pop
4636 a8083063 Iustin Pop
4637 a8083063 Iustin Pop
class LUQueryInstances(NoHooksLU):
4638 a8083063 Iustin Pop
  """Logical unit for querying instances.
4639 a8083063 Iustin Pop

4640 a8083063 Iustin Pop
  """
4641 7260cfbe Iustin Pop
  # pylint: disable-msg=W0142
4642 ec79568d Iustin Pop
  _OP_REQP = ["output_fields", "names", "use_locking"]
4643 7eb9d8f7 Guido Trotter
  REQ_BGL = False
4644 19bed813 Iustin Pop
  _SIMPLE_FIELDS = ["name", "os", "network_port", "hypervisor",
4645 19bed813 Iustin Pop
                    "serial_no", "ctime", "mtime", "uuid"]
4646 a2d2e1a7 Iustin Pop
  _FIELDS_STATIC = utils.FieldSet(*["name", "os", "pnode", "snodes",
4647 5b460366 Iustin Pop
                                    "admin_state",
4648 a2d2e1a7 Iustin Pop
                                    "disk_template", "ip", "mac", "bridge",
4649 638c6349 Guido Trotter
                                    "nic_mode", "nic_link",
4650 a2d2e1a7 Iustin Pop
                                    "sda_size", "sdb_size", "vcpus", "tags",
4651 a2d2e1a7 Iustin Pop
                                    "network_port", "beparams",
4652 8aec325c Iustin Pop
                                    r"(disk)\.(size)/([0-9]+)",
4653 8aec325c Iustin Pop
                                    r"(disk)\.(sizes)", "disk_usage",
4654 638c6349 Guido Trotter
                                    r"(nic)\.(mac|ip|mode|link)/([0-9]+)",
4655 638c6349 Guido Trotter
                                    r"(nic)\.(bridge)/([0-9]+)",
4656 638c6349 Guido Trotter
                                    r"(nic)\.(macs|ips|modes|links|bridges)",
4657 8aec325c Iustin Pop
                                    r"(disk|nic)\.(count)",
4658 19bed813 Iustin Pop
                                    "hvparams",
4659 19bed813 Iustin Pop
                                    ] + _SIMPLE_FIELDS +
4660 a2d2e1a7 Iustin Pop
                                  ["hv/%s" % name
4661 7736a5f2 Iustin Pop
                                   for name in constants.HVS_PARAMETERS
4662 7736a5f2 Iustin Pop
                                   if name not in constants.HVC_GLOBALS] +
4663 a2d2e1a7 Iustin Pop
                                  ["be/%s" % name
4664 a2d2e1a7 Iustin Pop
                                   for name in constants.BES_PARAMETERS])
4665 a2d2e1a7 Iustin Pop
  _FIELDS_DYNAMIC = utils.FieldSet("oper_state", "oper_ram", "status")
4666 31bf511f Iustin Pop
4667 a8083063 Iustin Pop
4668 7eb9d8f7 Guido Trotter
  def ExpandNames(self):
4669 31bf511f Iustin Pop
    _CheckOutputFields(static=self._FIELDS_STATIC,
4670 31bf511f Iustin Pop
                       dynamic=self._FIELDS_DYNAMIC,
4671 dcb93971 Michael Hanselmann
                       selected=self.op.output_fields)
4672 a8083063 Iustin Pop
4673 7eb9d8f7 Guido Trotter
    self.needed_locks = {}
4674 7eb9d8f7 Guido Trotter
    self.share_locks[locking.LEVEL_INSTANCE] = 1
4675 7eb9d8f7 Guido Trotter
    self.share_locks[locking.LEVEL_NODE] = 1
4676 7eb9d8f7 Guido Trotter
4677 57a2fb91 Iustin Pop
    if self.op.names:
4678 57a2fb91 Iustin Pop
      self.wanted = _GetWantedInstances(self, self.op.names)
4679 7eb9d8f7 Guido Trotter
    else:
4680 57a2fb91 Iustin Pop
      self.wanted = locking.ALL_SET
4681 7eb9d8f7 Guido Trotter
4682 ec79568d Iustin Pop
    self.do_node_query = self._FIELDS_STATIC.NonMatching(self.op.output_fields)
4683 ec79568d Iustin Pop
    self.do_locking = self.do_node_query and self.op.use_locking
4684 57a2fb91 Iustin Pop
    if self.do_locking:
4685 57a2fb91 Iustin Pop
      self.needed_locks[locking.LEVEL_INSTANCE] = self.wanted
4686 57a2fb91 Iustin Pop
      self.needed_locks[locking.LEVEL_NODE] = []
4687 57a2fb91 Iustin Pop
      self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
4688 7eb9d8f7 Guido Trotter
4689 7eb9d8f7 Guido Trotter
  def DeclareLocks(self, level):
4690 57a2fb91 Iustin Pop
    if level == locking.LEVEL_NODE and self.do_locking:
4691 7eb9d8f7 Guido Trotter
      self._LockInstancesNodes()
4692 7eb9d8f7 Guido Trotter
4693 7eb9d8f7 Guido Trotter
  def CheckPrereq(self):
4694 7eb9d8f7 Guido Trotter
    """Check prerequisites.
4695 7eb9d8f7 Guido Trotter

4696 7eb9d8f7 Guido Trotter
    """
4697 57a2fb91 Iustin Pop
    pass
4698 069dcc86 Iustin Pop
4699 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
4700 a8083063 Iustin Pop
    """Computes the list of nodes and their attributes.
4701 a8083063 Iustin Pop

4702 a8083063 Iustin Pop
    """
4703 7260cfbe Iustin Pop
    # pylint: disable-msg=R0912
4704 7260cfbe Iustin Pop
    # way too many branches here
4705 57a2fb91 Iustin Pop
    all_info = self.cfg.GetAllInstancesInfo()
4706 a7f5dc98 Iustin Pop
    if self.wanted == locking.ALL_SET:
4707 a7f5dc98 Iustin Pop
      # caller didn't specify instance names, so ordering is not important
4708 a7f5dc98 Iustin Pop
      if self.do_locking:
4709 a7f5dc98 Iustin Pop
        instance_names = self.acquired_locks[locking.LEVEL_INSTANCE]
4710 a7f5dc98 Iustin Pop
      else:
4711 a7f5dc98 Iustin Pop
        instance_names = all_info.keys()
4712 a7f5dc98 Iustin Pop
      instance_names = utils.NiceSort(instance_names)
4713 57a2fb91 Iustin Pop
    else:
4714 a7f5dc98 Iustin Pop
      # caller did specify names, so we must keep the ordering
4715 a7f5dc98 Iustin Pop
      if self.do_locking:
4716 a7f5dc98 Iustin Pop
        tgt_set = self.acquired_locks[locking.LEVEL_INSTANCE]
4717 a7f5dc98 Iustin Pop
      else:
4718 a7f5dc98 Iustin Pop
        tgt_set = all_info.keys()
4719 a7f5dc98 Iustin Pop
      missing = set(self.wanted).difference(tgt_set)
4720 a7f5dc98 Iustin Pop
      if missing:
4721 a7f5dc98 Iustin Pop
        raise errors.OpExecError("Some instances were removed before"
4722 a7f5dc98 Iustin Pop
                                 " retrieving their data: %s" % missing)
4723 a7f5dc98 Iustin Pop
      instance_names = self.wanted
4724 c1f1cbb2 Iustin Pop
4725 57a2fb91 Iustin Pop
    instance_list = [all_info[iname] for iname in instance_names]
4726 a8083063 Iustin Pop
4727 a8083063 Iustin Pop
    # begin data gathering
4728 a8083063 Iustin Pop
4729 a8083063 Iustin Pop
    nodes = frozenset([inst.primary_node for inst in instance_list])
4730 e69d05fd Iustin Pop
    hv_list = list(set([inst.hypervisor for inst in instance_list]))
4731 a8083063 Iustin Pop
4732 a8083063 Iustin Pop
    bad_nodes = []
4733 cbfc4681 Iustin Pop
    off_nodes = []
4734 ec79568d Iustin Pop
    if self.do_node_query:
4735 a8083063 Iustin Pop
      live_data = {}
4736 72737a7f Iustin Pop
      node_data = self.rpc.call_all_instances_info(nodes, hv_list)
4737 a8083063 Iustin Pop
      for name in nodes:
4738 a8083063 Iustin Pop
        result = node_data[name]
4739 cbfc4681 Iustin Pop
        if result.offline:
4740 cbfc4681 Iustin Pop
          # offline nodes will be in both lists
4741 cbfc4681 Iustin Pop
          off_nodes.append(name)
4742 3cebe102 Michael Hanselmann
        if result.fail_msg:
4743 a8083063 Iustin Pop
          bad_nodes.append(name)
4744 781de953 Iustin Pop
        else:
4745 2fa74ef4 Iustin Pop
          if result.payload:
4746 2fa74ef4 Iustin Pop
            live_data.update(result.payload)
4747 2fa74ef4 Iustin Pop
          # else no instance is alive
4748 a8083063 Iustin Pop
    else:
4749 a8083063 Iustin Pop
      live_data = dict([(name, {}) for name in instance_names])
4750 a8083063 Iustin Pop
4751 a8083063 Iustin Pop
    # end data gathering
4752 a8083063 Iustin Pop
4753 5018a335 Iustin Pop
    HVPREFIX = "hv/"
4754 338e51e8 Iustin Pop
    BEPREFIX = "be/"
4755 a8083063 Iustin Pop
    output = []
4756 638c6349 Guido Trotter
    cluster = self.cfg.GetClusterInfo()
4757 a8083063 Iustin Pop
    for instance in instance_list:
4758 a8083063 Iustin Pop
      iout = []
4759 7736a5f2 Iustin Pop
      i_hv = cluster.FillHV(instance, skip_globals=True)
4760 638c6349 Guido Trotter
      i_be = cluster.FillBE(instance)
4761 638c6349 Guido Trotter
      i_nicp = [objects.FillDict(cluster.nicparams[constants.PP_DEFAULT],
4762 638c6349 Guido Trotter
                                 nic.nicparams) for nic in instance.nics]
4763 a8083063 Iustin Pop
      for field in self.op.output_fields:
4764 71c1af58 Iustin Pop
        st_match = self._FIELDS_STATIC.Matches(field)
4765 19bed813 Iustin Pop
        if field in self._SIMPLE_FIELDS:
4766 19bed813 Iustin Pop
          val = getattr(instance, field)
4767 a8083063 Iustin Pop
        elif field == "pnode":
4768 a8083063 Iustin Pop
          val = instance.primary_node
4769 a8083063 Iustin Pop
        elif field == "snodes":
4770 8a23d2d3 Iustin Pop
          val = list(instance.secondary_nodes)
4771 a8083063 Iustin Pop
        elif field == "admin_state":
4772 0d68c45d Iustin Pop
          val = instance.admin_up
4773 a8083063 Iustin Pop
        elif field == "oper_state":
4774 a8083063 Iustin Pop
          if instance.primary_node in bad_nodes:
4775 8a23d2d3 Iustin Pop
            val = None
4776 a8083063 Iustin Pop
          else:
4777 8a23d2d3 Iustin Pop
            val = bool(live_data.get(instance.name))
4778 d8052456 Iustin Pop
        elif field == "status":
4779 cbfc4681 Iustin Pop
          if instance.primary_node in off_nodes:
4780 cbfc4681 Iustin Pop
            val = "ERROR_nodeoffline"
4781 cbfc4681 Iustin Pop
          elif instance.primary_node in bad_nodes:
4782 d8052456 Iustin Pop
            val = "ERROR_nodedown"
4783 d8052456 Iustin Pop
          else:
4784 d8052456 Iustin Pop
            running = bool(live_data.get(instance.name))
4785 d8052456 Iustin Pop
            if running:
4786 0d68c45d Iustin Pop
              if instance.admin_up:
4787 d8052456 Iustin Pop
                val = "running"
4788 d8052456 Iustin Pop
              else:
4789 d8052456 Iustin Pop
                val = "ERROR_up"
4790 d8052456 Iustin Pop
            else:
4791 0d68c45d Iustin Pop
              if instance.admin_up:
4792 d8052456 Iustin Pop
                val = "ERROR_down"
4793 d8052456 Iustin Pop
              else:
4794 d8052456 Iustin Pop
                val = "ADMIN_down"
4795 a8083063 Iustin Pop
        elif field == "oper_ram":
4796 a8083063 Iustin Pop
          if instance.primary_node in bad_nodes:
4797 8a23d2d3 Iustin Pop
            val = None
4798 a8083063 Iustin Pop
          elif instance.name in live_data:
4799 a8083063 Iustin Pop
            val = live_data[instance.name].get("memory", "?")
4800 a8083063 Iustin Pop
          else:
4801 a8083063 Iustin Pop
            val = "-"
4802 c1ce76bb Iustin Pop
        elif field == "vcpus":
4803 c1ce76bb Iustin Pop
          val = i_be[constants.BE_VCPUS]
4804 a8083063 Iustin Pop
        elif field == "disk_template":
4805 a8083063 Iustin Pop
          val = instance.disk_template
4806 a8083063 Iustin Pop
        elif field == "ip":
4807 39a02558 Guido Trotter
          if instance.nics:
4808 39a02558 Guido Trotter
            val = instance.nics[0].ip
4809 39a02558 Guido Trotter
          else:
4810 39a02558 Guido Trotter
            val = None
4811 638c6349 Guido Trotter
        elif field == "nic_mode":
4812 638c6349 Guido Trotter
          if instance.nics:
4813 638c6349 Guido Trotter
            val = i_nicp[0][constants.NIC_MODE]
4814 638c6349 Guido Trotter
          else:
4815 638c6349 Guido Trotter
            val = None
4816 638c6349 Guido Trotter
        elif field == "nic_link":
4817 39a02558 Guido Trotter
          if instance.nics:
4818 638c6349 Guido Trotter
            val = i_nicp[0][constants.NIC_LINK]
4819 638c6349 Guido Trotter
          else:
4820 638c6349 Guido Trotter
            val = None
4821 638c6349 Guido Trotter
        elif field == "bridge":
4822 638c6349 Guido Trotter
          if (instance.nics and
4823 638c6349 Guido Trotter
              i_nicp[0][constants.NIC_MODE] == constants.NIC_MODE_BRIDGED):
4824 638c6349 Guido Trotter
            val = i_nicp[0][constants.NIC_LINK]
4825 39a02558 Guido Trotter
          else:
4826 39a02558 Guido Trotter
            val = None
4827 a8083063 Iustin Pop
        elif field == "mac":
4828 39a02558 Guido Trotter
          if instance.nics:
4829 39a02558 Guido Trotter
            val = instance.nics[0].mac
4830 39a02558 Guido Trotter
          else:
4831 39a02558 Guido Trotter
            val = None
4832 644eeef9 Iustin Pop
        elif field == "sda_size" or field == "sdb_size":
4833 ad24e046 Iustin Pop
          idx = ord(field[2]) - ord('a')
4834 ad24e046 Iustin Pop
          try:
4835 ad24e046 Iustin Pop
            val = instance.FindDisk(idx).size
4836 ad24e046 Iustin Pop
          except errors.OpPrereqError:
4837 8a23d2d3 Iustin Pop
            val = None
4838 024e157f Iustin Pop
        elif field == "disk_usage": # total disk usage per node
4839 024e157f Iustin Pop
          disk_sizes = [{'size': disk.size} for disk in instance.disks]
4840 024e157f Iustin Pop
          val = _ComputeDiskSize(instance.disk_template, disk_sizes)
4841 130a6a6f Iustin Pop
        elif field == "tags":
4842 130a6a6f Iustin Pop
          val = list(instance.GetTags())
4843 338e51e8 Iustin Pop
        elif field == "hvparams":
4844 338e51e8 Iustin Pop
          val = i_hv
4845 5018a335 Iustin Pop
        elif (field.startswith(HVPREFIX) and
4846 7736a5f2 Iustin Pop
              field[len(HVPREFIX):] in constants.HVS_PARAMETERS and
4847 7736a5f2 Iustin Pop
              field[len(HVPREFIX):] not in constants.HVC_GLOBALS):
4848 5018a335 Iustin Pop
          val = i_hv.get(field[len(HVPREFIX):], None)
4849 338e51e8 Iustin Pop
        elif field == "beparams":
4850 338e51e8 Iustin Pop
          val = i_be
4851 338e51e8 Iustin Pop
        elif (field.startswith(BEPREFIX) and
4852 338e51e8 Iustin Pop
              field[len(BEPREFIX):] in constants.BES_PARAMETERS):
4853 338e51e8 Iustin Pop
          val = i_be.get(field[len(BEPREFIX):], None)
4854 71c1af58 Iustin Pop
        elif st_match and st_match.groups():
4855 71c1af58 Iustin Pop
          # matches a variable list
4856 71c1af58 Iustin Pop
          st_groups = st_match.groups()
4857 71c1af58 Iustin Pop
          if st_groups and st_groups[0] == "disk":
4858 71c1af58 Iustin Pop
            if st_groups[1] == "count":
4859 71c1af58 Iustin Pop
              val = len(instance.disks)
4860 41a776da Iustin Pop
            elif st_groups[1] == "sizes":
4861 41a776da Iustin Pop
              val = [disk.size for disk in instance.disks]
4862 71c1af58 Iustin Pop
            elif st_groups[1] == "size":
4863 3e0cea06 Iustin Pop
              try:
4864 3e0cea06 Iustin Pop
                val = instance.FindDisk(st_groups[2]).size
4865 3e0cea06 Iustin Pop
              except errors.OpPrereqError:
4866 71c1af58 Iustin Pop
                val = None
4867 71c1af58 Iustin Pop
            else:
4868 71c1af58 Iustin Pop
              assert False, "Unhandled disk parameter"
4869 71c1af58 Iustin Pop
          elif st_groups[0] == "nic":
4870 71c1af58 Iustin Pop
            if st_groups[1] == "count":
4871 71c1af58 Iustin Pop
              val = len(instance.nics)
4872 41a776da Iustin Pop
            elif st_groups[1] == "macs":
4873 41a776da Iustin Pop
              val = [nic.mac for nic in instance.nics]
4874 41a776da Iustin Pop
            elif st_groups[1] == "ips":
4875 41a776da Iustin Pop
              val = [nic.ip for nic in instance.nics]
4876 638c6349 Guido Trotter
            elif st_groups[1] == "modes":
4877 638c6349 Guido Trotter
              val = [nicp[constants.NIC_MODE] for nicp in i_nicp]
4878 638c6349 Guido Trotter
            elif st_groups[1] == "links":
4879 638c6349 Guido Trotter
              val = [nicp[constants.NIC_LINK] for nicp in i_nicp]
4880 41a776da Iustin Pop
            elif st_groups[1] == "bridges":
4881 638c6349 Guido Trotter
              val = []
4882 638c6349 Guido Trotter
              for nicp in i_nicp:
4883 638c6349 Guido Trotter
                if nicp[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
4884 638c6349 Guido Trotter
                  val.append(nicp[constants.NIC_LINK])
4885 638c6349 Guido Trotter
                else:
4886 638c6349 Guido Trotter
                  val.append(None)
4887 71c1af58 Iustin Pop
            else:
4888 71c1af58 Iustin Pop
              # index-based item
4889 71c1af58 Iustin Pop
              nic_idx = int(st_groups[2])
4890 71c1af58 Iustin Pop
              if nic_idx >= len(instance.nics):
4891 71c1af58 Iustin Pop
                val = None
4892 71c1af58 Iustin Pop
              else:
4893 71c1af58 Iustin Pop
                if st_groups[1] == "mac":
4894 71c1af58 Iustin Pop
                  val = instance.nics[nic_idx].mac
4895 71c1af58 Iustin Pop
                elif st_groups[1] == "ip":
4896 71c1af58 Iustin Pop
                  val = instance.nics[nic_idx].ip
4897 638c6349 Guido Trotter
                elif st_groups[1] == "mode":
4898 638c6349 Guido Trotter
                  val = i_nicp[nic_idx][constants.NIC_MODE]
4899 638c6349 Guido Trotter
                elif st_groups[1] == "link":
4900 638c6349 Guido Trotter
                  val = i_nicp[nic_idx][constants.NIC_LINK]
4901 71c1af58 Iustin Pop
                elif st_groups[1] == "bridge":
4902 638c6349 Guido Trotter
                  nic_mode = i_nicp[nic_idx][constants.NIC_MODE]
4903 638c6349 Guido Trotter
                  if nic_mode == constants.NIC_MODE_BRIDGED:
4904 638c6349 Guido Trotter
                    val = i_nicp[nic_idx][constants.NIC_LINK]
4905 638c6349 Guido Trotter
                  else:
4906 638c6349 Guido Trotter
                    val = None
4907 71c1af58 Iustin Pop
                else:
4908 71c1af58 Iustin Pop
                  assert False, "Unhandled NIC parameter"
4909 71c1af58 Iustin Pop
          else:
4910 c1ce76bb Iustin Pop
            assert False, ("Declared but unhandled variable parameter '%s'" %
4911 c1ce76bb Iustin Pop
                           field)
4912 a8083063 Iustin Pop
        else:
4913 c1ce76bb Iustin Pop
          assert False, "Declared but unhandled parameter '%s'" % field
4914 a8083063 Iustin Pop
        iout.append(val)
4915 a8083063 Iustin Pop
      output.append(iout)
4916 a8083063 Iustin Pop
4917 a8083063 Iustin Pop
    return output
4918 a8083063 Iustin Pop
4919 a8083063 Iustin Pop
4920 a8083063 Iustin Pop
class LUFailoverInstance(LogicalUnit):
4921 a8083063 Iustin Pop
  """Failover an instance.
4922 a8083063 Iustin Pop

4923 a8083063 Iustin Pop
  """
4924 a8083063 Iustin Pop
  HPATH = "instance-failover"
4925 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
4926 a8083063 Iustin Pop
  _OP_REQP = ["instance_name", "ignore_consistency"]
4927 c9e5c064 Guido Trotter
  REQ_BGL = False
4928 c9e5c064 Guido Trotter
4929 17c3f802 Guido Trotter
  def CheckArguments(self):
4930 17c3f802 Guido Trotter
    """Check the arguments.
4931 17c3f802 Guido Trotter

4932 17c3f802 Guido Trotter
    """
4933 17c3f802 Guido Trotter
    self.shutdown_timeout = getattr(self.op, "shutdown_timeout",
4934 17c3f802 Guido Trotter
                                    constants.DEFAULT_SHUTDOWN_TIMEOUT)
4935 17c3f802 Guido Trotter
4936 c9e5c064 Guido Trotter
  def ExpandNames(self):
4937 c9e5c064 Guido Trotter
    self._ExpandAndLockInstance()
4938 c9e5c064 Guido Trotter
    self.needed_locks[locking.LEVEL_NODE] = []
4939 f6d9a522 Guido Trotter
    self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
4940 c9e5c064 Guido Trotter
4941 c9e5c064 Guido Trotter
  def DeclareLocks(self, level):
4942 c9e5c064 Guido Trotter
    if level == locking.LEVEL_NODE:
4943 c9e5c064 Guido Trotter
      self._LockInstancesNodes()
4944 a8083063 Iustin Pop
4945 a8083063 Iustin Pop
  def BuildHooksEnv(self):
4946 a8083063 Iustin Pop
    """Build hooks env.
4947 a8083063 Iustin Pop

4948 a8083063 Iustin Pop
    This runs on master, primary and secondary nodes of the instance.
4949 a8083063 Iustin Pop

4950 a8083063 Iustin Pop
    """
4951 08eec276 Iustin Pop
    instance = self.instance
4952 08eec276 Iustin Pop
    source_node = instance.primary_node
4953 08eec276 Iustin Pop
    target_node = instance.secondary_nodes[0]
4954 a8083063 Iustin Pop
    env = {
4955 a8083063 Iustin Pop
      "IGNORE_CONSISTENCY": self.op.ignore_consistency,
4956 17c3f802 Guido Trotter
      "SHUTDOWN_TIMEOUT": self.shutdown_timeout,
4957 08eec276 Iustin Pop
      "OLD_PRIMARY": source_node,
4958 08eec276 Iustin Pop
      "OLD_SECONDARY": target_node,
4959 08eec276 Iustin Pop
      "NEW_PRIMARY": target_node,
4960 08eec276 Iustin Pop
      "NEW_SECONDARY": source_node,
4961 a8083063 Iustin Pop
      }
4962 08eec276 Iustin Pop
    env.update(_BuildInstanceHookEnvByObject(self, instance))
4963 08eec276 Iustin Pop
    nl = [self.cfg.GetMasterNode()] + list(instance.secondary_nodes)
4964 abd8e836 Iustin Pop
    nl_post = list(nl)
4965 abd8e836 Iustin Pop
    nl_post.append(source_node)
4966 abd8e836 Iustin Pop
    return env, nl, nl_post
4967 a8083063 Iustin Pop
4968 a8083063 Iustin Pop
  def CheckPrereq(self):
4969 a8083063 Iustin Pop
    """Check prerequisites.
4970 a8083063 Iustin Pop

4971 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
4972 a8083063 Iustin Pop

4973 a8083063 Iustin Pop
    """
4974 c9e5c064 Guido Trotter
    self.instance = instance = self.cfg.GetInstanceInfo(self.op.instance_name)
4975 c9e5c064 Guido Trotter
    assert self.instance is not None, \
4976 c9e5c064 Guido Trotter
      "Cannot retrieve locked instance %s" % self.op.instance_name
4977 a8083063 Iustin Pop
4978 338e51e8 Iustin Pop
    bep = self.cfg.GetClusterInfo().FillBE(instance)
4979 a1f445d3 Iustin Pop
    if instance.disk_template not in constants.DTS_NET_MIRROR:
4980 2a710df1 Michael Hanselmann
      raise errors.OpPrereqError("Instance's disk layout is not"
4981 5c983ee5 Iustin Pop
                                 " network mirrored, cannot failover.",
4982 5c983ee5 Iustin Pop
                                 errors.ECODE_STATE)
4983 2a710df1 Michael Hanselmann
4984 2a710df1 Michael Hanselmann
    secondary_nodes = instance.secondary_nodes
4985 2a710df1 Michael Hanselmann
    if not secondary_nodes:
4986 2a710df1 Michael Hanselmann
      raise errors.ProgrammerError("no secondary node but using "
4987 abdf0113 Iustin Pop
                                   "a mirrored disk template")
4988 2a710df1 Michael Hanselmann
4989 2a710df1 Michael Hanselmann
    target_node = secondary_nodes[0]
4990 7527a8a4 Iustin Pop
    _CheckNodeOnline(self, target_node)
4991 733a2b6a Iustin Pop
    _CheckNodeNotDrained(self, target_node)
4992 d27776f0 Iustin Pop
    if instance.admin_up:
4993 d27776f0 Iustin Pop
      # check memory requirements on the secondary node
4994 d27776f0 Iustin Pop
      _CheckNodeFreeMemory(self, target_node, "failing over instance %s" %
4995 d27776f0 Iustin Pop
                           instance.name, bep[constants.BE_MEMORY],
4996 d27776f0 Iustin Pop
                           instance.hypervisor)
4997 d27776f0 Iustin Pop
    else:
4998 d27776f0 Iustin Pop
      self.LogInfo("Not checking memory on the secondary node as"
4999 d27776f0 Iustin Pop
                   " instance will not be started")
5000 3a7c308e Guido Trotter
5001 a8083063 Iustin Pop
    # check bridge existance
5002 b165e77e Guido Trotter
    _CheckInstanceBridgesExist(self, instance, node=target_node)
5003 a8083063 Iustin Pop
5004 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
5005 a8083063 Iustin Pop
    """Failover an instance.
5006 a8083063 Iustin Pop

5007 a8083063 Iustin Pop
    The failover is done by shutting it down on its present node and
5008 a8083063 Iustin Pop
    starting it on the secondary.
5009 a8083063 Iustin Pop

5010 a8083063 Iustin Pop
    """
5011 a8083063 Iustin Pop
    instance = self.instance
5012 a8083063 Iustin Pop
5013 a8083063 Iustin Pop
    source_node = instance.primary_node
5014 a8083063 Iustin Pop
    target_node = instance.secondary_nodes[0]
5015 a8083063 Iustin Pop
5016 1df79ce6 Michael Hanselmann
    if instance.admin_up:
5017 1df79ce6 Michael Hanselmann
      feedback_fn("* checking disk consistency between source and target")
5018 1df79ce6 Michael Hanselmann
      for dev in instance.disks:
5019 1df79ce6 Michael Hanselmann
        # for drbd, these are drbd over lvm
5020 1df79ce6 Michael Hanselmann
        if not _CheckDiskConsistency(self, dev, target_node, False):
5021 1df79ce6 Michael Hanselmann
          if not self.op.ignore_consistency:
5022 1df79ce6 Michael Hanselmann
            raise errors.OpExecError("Disk %s is degraded on target node,"
5023 1df79ce6 Michael Hanselmann
                                     " aborting failover." % dev.iv_name)
5024 1df79ce6 Michael Hanselmann
    else:
5025 1df79ce6 Michael Hanselmann
      feedback_fn("* not checking disk consistency as instance is not running")
5026 a8083063 Iustin Pop
5027 a8083063 Iustin Pop
    feedback_fn("* shutting down instance on source node")
5028 9a4f63d1 Iustin Pop
    logging.info("Shutting down instance %s on node %s",
5029 9a4f63d1 Iustin Pop
                 instance.name, source_node)
5030 a8083063 Iustin Pop
5031 17c3f802 Guido Trotter
    result = self.rpc.call_instance_shutdown(source_node, instance,
5032 17c3f802 Guido Trotter
                                             self.shutdown_timeout)
5033 4c4e4e1e Iustin Pop
    msg = result.fail_msg
5034 1fae010f Iustin Pop
    if msg:
5035 24a40d57 Iustin Pop
      if self.op.ignore_consistency:
5036 86d9d3bb Iustin Pop
        self.proc.LogWarning("Could not shutdown instance %s on node %s."
5037 1fae010f Iustin Pop
                             " Proceeding anyway. Please make sure node"
5038 1fae010f Iustin Pop
                             " %s is down. Error details: %s",
5039 1fae010f Iustin Pop
                             instance.name, source_node, source_node, msg)
5040 24a40d57 Iustin Pop
      else:
5041 1fae010f Iustin Pop
        raise errors.OpExecError("Could not shutdown instance %s on"
5042 1fae010f Iustin Pop
                                 " node %s: %s" %
5043 1fae010f Iustin Pop
                                 (instance.name, source_node, msg))
5044 a8083063 Iustin Pop
5045 a8083063 Iustin Pop
    feedback_fn("* deactivating the instance's disks on source node")
5046 b9bddb6b Iustin Pop
    if not _ShutdownInstanceDisks(self, instance, ignore_primary=True):
5047 3ecf6786 Iustin Pop
      raise errors.OpExecError("Can't shut down the instance's disks.")
5048 a8083063 Iustin Pop
5049 a8083063 Iustin Pop
    instance.primary_node = target_node
5050 a8083063 Iustin Pop
    # distribute new instance config to the other nodes
5051 a4eae71f Michael Hanselmann
    self.cfg.Update(instance, feedback_fn)
5052 a8083063 Iustin Pop
5053 12a0cfbe Guido Trotter
    # Only start the instance if it's marked as up
5054 0d68c45d Iustin Pop
    if instance.admin_up:
5055 12a0cfbe Guido Trotter
      feedback_fn("* activating the instance's disks on target node")
5056 9a4f63d1 Iustin Pop
      logging.info("Starting instance %s on node %s",
5057 9a4f63d1 Iustin Pop
                   instance.name, target_node)
5058 12a0cfbe Guido Trotter
5059 7c4d6c7b Michael Hanselmann
      disks_ok, _ = _AssembleInstanceDisks(self, instance,
5060 12a0cfbe Guido Trotter
                                               ignore_secondaries=True)
5061 12a0cfbe Guido Trotter
      if not disks_ok:
5062 b9bddb6b Iustin Pop
        _ShutdownInstanceDisks(self, instance)
5063 12a0cfbe Guido Trotter
        raise errors.OpExecError("Can't activate the instance's disks")
5064 a8083063 Iustin Pop
5065 12a0cfbe Guido Trotter
      feedback_fn("* starting the instance on the target node")
5066 0eca8e0c Iustin Pop
      result = self.rpc.call_instance_start(target_node, instance, None, None)
5067 4c4e4e1e Iustin Pop
      msg = result.fail_msg
5068 dd279568 Iustin Pop
      if msg:
5069 b9bddb6b Iustin Pop
        _ShutdownInstanceDisks(self, instance)
5070 dd279568 Iustin Pop
        raise errors.OpExecError("Could not start instance %s on node %s: %s" %
5071 dd279568 Iustin Pop
                                 (instance.name, target_node, msg))
5072 a8083063 Iustin Pop
5073 a8083063 Iustin Pop
5074 53c776b5 Iustin Pop
class LUMigrateInstance(LogicalUnit):
5075 53c776b5 Iustin Pop
  """Migrate an instance.
5076 53c776b5 Iustin Pop

5077 53c776b5 Iustin Pop
  This is migration without shutting down, compared to the failover,
5078 53c776b5 Iustin Pop
  which is done with shutdown.
5079 53c776b5 Iustin Pop

5080 53c776b5 Iustin Pop
  """
5081 53c776b5 Iustin Pop
  HPATH = "instance-migrate"
5082 53c776b5 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
5083 53c776b5 Iustin Pop
  _OP_REQP = ["instance_name", "live", "cleanup"]
5084 53c776b5 Iustin Pop
5085 53c776b5 Iustin Pop
  REQ_BGL = False
5086 53c776b5 Iustin Pop
5087 53c776b5 Iustin Pop
  def ExpandNames(self):
5088 53c776b5 Iustin Pop
    self._ExpandAndLockInstance()
5089 3e06e001 Michael Hanselmann
5090 53c776b5 Iustin Pop
    self.needed_locks[locking.LEVEL_NODE] = []
5091 53c776b5 Iustin Pop
    self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
5092 53c776b5 Iustin Pop
5093 3e06e001 Michael Hanselmann
    self._migrater = TLMigrateInstance(self, self.op.instance_name,
5094 3e06e001 Michael Hanselmann
                                       self.op.live, self.op.cleanup)
5095 3a012b41 Michael Hanselmann
    self.tasklets = [self._migrater]
5096 3e06e001 Michael Hanselmann
5097 53c776b5 Iustin Pop
  def DeclareLocks(self, level):
5098 53c776b5 Iustin Pop
    if level == locking.LEVEL_NODE:
5099 53c776b5 Iustin Pop
      self._LockInstancesNodes()
5100 53c776b5 Iustin Pop
5101 53c776b5 Iustin Pop
  def BuildHooksEnv(self):
5102 53c776b5 Iustin Pop
    """Build hooks env.
5103 53c776b5 Iustin Pop

5104 53c776b5 Iustin Pop
    This runs on master, primary and secondary nodes of the instance.
5105 53c776b5 Iustin Pop

5106 53c776b5 Iustin Pop
    """
5107 3e06e001 Michael Hanselmann
    instance = self._migrater.instance
5108 08eec276 Iustin Pop
    source_node = instance.primary_node
5109 08eec276 Iustin Pop
    target_node = instance.secondary_nodes[0]
5110 3e06e001 Michael Hanselmann
    env = _BuildInstanceHookEnvByObject(self, instance)
5111 2c2690c9 Iustin Pop
    env["MIGRATE_LIVE"] = self.op.live
5112 2c2690c9 Iustin Pop
    env["MIGRATE_CLEANUP"] = self.op.cleanup
5113 08eec276 Iustin Pop
    env.update({
5114 08eec276 Iustin Pop
        "OLD_PRIMARY": source_node,
5115 08eec276 Iustin Pop
        "OLD_SECONDARY": target_node,
5116 08eec276 Iustin Pop
        "NEW_PRIMARY": target_node,
5117 08eec276 Iustin Pop
        "NEW_SECONDARY": source_node,
5118 08eec276 Iustin Pop
        })
5119 3e06e001 Michael Hanselmann
    nl = [self.cfg.GetMasterNode()] + list(instance.secondary_nodes)
5120 abd8e836 Iustin Pop
    nl_post = list(nl)
5121 abd8e836 Iustin Pop
    nl_post.append(source_node)
5122 abd8e836 Iustin Pop
    return env, nl, nl_post
5123 53c776b5 Iustin Pop
5124 3e06e001 Michael Hanselmann
5125 313bcead Iustin Pop
class LUMoveInstance(LogicalUnit):
5126 313bcead Iustin Pop
  """Move an instance by data-copying.
5127 313bcead Iustin Pop

5128 313bcead Iustin Pop
  """
5129 313bcead Iustin Pop
  HPATH = "instance-move"
5130 313bcead Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
5131 313bcead Iustin Pop
  _OP_REQP = ["instance_name", "target_node"]
5132 313bcead Iustin Pop
  REQ_BGL = False
5133 313bcead Iustin Pop
5134 17c3f802 Guido Trotter
  def CheckArguments(self):
5135 17c3f802 Guido Trotter
    """Check the arguments.
5136 17c3f802 Guido Trotter

5137 17c3f802 Guido Trotter
    """
5138 17c3f802 Guido Trotter
    self.shutdown_timeout = getattr(self.op, "shutdown_timeout",
5139 17c3f802 Guido Trotter
                                    constants.DEFAULT_SHUTDOWN_TIMEOUT)
5140 17c3f802 Guido Trotter
5141 313bcead Iustin Pop
  def ExpandNames(self):
5142 313bcead Iustin Pop
    self._ExpandAndLockInstance()
5143 cf26a87a Iustin Pop
    target_node = _ExpandNodeName(self.cfg, self.op.target_node)
5144 313bcead Iustin Pop
    self.op.target_node = target_node
5145 313bcead Iustin Pop
    self.needed_locks[locking.LEVEL_NODE] = [target_node]
5146 313bcead Iustin Pop
    self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_APPEND
5147 313bcead Iustin Pop
5148 313bcead Iustin Pop
  def DeclareLocks(self, level):
5149 313bcead Iustin Pop
    if level == locking.LEVEL_NODE:
5150 313bcead Iustin Pop
      self._LockInstancesNodes(primary_only=True)
5151 313bcead Iustin Pop
5152 313bcead Iustin Pop
  def BuildHooksEnv(self):
5153 313bcead Iustin Pop
    """Build hooks env.
5154 313bcead Iustin Pop

5155 313bcead Iustin Pop
    This runs on master, primary and secondary nodes of the instance.
5156 313bcead Iustin Pop

5157 313bcead Iustin Pop
    """
5158 313bcead Iustin Pop
    env = {
5159 313bcead Iustin Pop
      "TARGET_NODE": self.op.target_node,
5160 17c3f802 Guido Trotter
      "SHUTDOWN_TIMEOUT": self.shutdown_timeout,
5161 313bcead Iustin Pop
      }
5162 313bcead Iustin Pop
    env.update(_BuildInstanceHookEnvByObject(self, self.instance))
5163 313bcead Iustin Pop
    nl = [self.cfg.GetMasterNode()] + [self.instance.primary_node,
5164 313bcead Iustin Pop
                                       self.op.target_node]
5165 313bcead Iustin Pop
    return env, nl, nl
5166 313bcead Iustin Pop
5167 313bcead Iustin Pop
  def CheckPrereq(self):
5168 313bcead Iustin Pop
    """Check prerequisites.
5169 313bcead Iustin Pop

5170 313bcead Iustin Pop
    This checks that the instance is in the cluster.
5171 313bcead Iustin Pop

5172 313bcead Iustin Pop
    """
5173 313bcead Iustin Pop
    self.instance = instance = self.cfg.GetInstanceInfo(self.op.instance_name)
5174 313bcead Iustin Pop
    assert self.instance is not None, \
5175 313bcead Iustin Pop
      "Cannot retrieve locked instance %s" % self.op.instance_name
5176 313bcead Iustin Pop
5177 313bcead Iustin Pop
    node = self.cfg.GetNodeInfo(self.op.target_node)
5178 313bcead Iustin Pop
    assert node is not None, \
5179 313bcead Iustin Pop
      "Cannot retrieve locked node %s" % self.op.target_node
5180 313bcead Iustin Pop
5181 313bcead Iustin Pop
    self.target_node = target_node = node.name
5182 313bcead Iustin Pop
5183 313bcead Iustin Pop
    if target_node == instance.primary_node:
5184 313bcead Iustin Pop
      raise errors.OpPrereqError("Instance %s is already on the node %s" %
5185 5c983ee5 Iustin Pop
                                 (instance.name, target_node),
5186 5c983ee5 Iustin Pop
                                 errors.ECODE_STATE)
5187 313bcead Iustin Pop
5188 313bcead Iustin Pop
    bep = self.cfg.GetClusterInfo().FillBE(instance)
5189 313bcead Iustin Pop
5190 313bcead Iustin Pop
    for idx, dsk in enumerate(instance.disks):
5191 313bcead Iustin Pop
      if dsk.dev_type not in (constants.LD_LV, constants.LD_FILE):
5192 313bcead Iustin Pop
        raise errors.OpPrereqError("Instance disk %d has a complex layout,"
5193 d1b83918 Iustin Pop
                                   " cannot copy" % idx, errors.ECODE_STATE)
5194 313bcead Iustin Pop
5195 313bcead Iustin Pop
    _CheckNodeOnline(self, target_node)
5196 313bcead Iustin Pop
    _CheckNodeNotDrained(self, target_node)
5197 313bcead Iustin Pop
5198 313bcead Iustin Pop
    if instance.admin_up:
5199 313bcead Iustin Pop
      # check memory requirements on the secondary node
5200 313bcead Iustin Pop
      _CheckNodeFreeMemory(self, target_node, "failing over instance %s" %
5201 313bcead Iustin Pop
                           instance.name, bep[constants.BE_MEMORY],
5202 313bcead Iustin Pop
                           instance.hypervisor)
5203 313bcead Iustin Pop
    else:
5204 313bcead Iustin Pop
      self.LogInfo("Not checking memory on the secondary node as"
5205 313bcead Iustin Pop
                   " instance will not be started")
5206 313bcead Iustin Pop
5207 313bcead Iustin Pop
    # check bridge existance
5208 313bcead Iustin Pop
    _CheckInstanceBridgesExist(self, instance, node=target_node)
5209 313bcead Iustin Pop
5210 313bcead Iustin Pop
  def Exec(self, feedback_fn):
5211 313bcead Iustin Pop
    """Move an instance.
5212 313bcead Iustin Pop

5213 313bcead Iustin Pop
    The move is done by shutting it down on its present node, copying
5214 313bcead Iustin Pop
    the data over (slow) and starting it on the new node.
5215 313bcead Iustin Pop

5216 313bcead Iustin Pop
    """
5217 313bcead Iustin Pop
    instance = self.instance
5218 313bcead Iustin Pop
5219 313bcead Iustin Pop
    source_node = instance.primary_node
5220 313bcead Iustin Pop
    target_node = self.target_node
5221 313bcead Iustin Pop
5222 313bcead Iustin Pop
    self.LogInfo("Shutting down instance %s on source node %s",
5223 313bcead Iustin Pop
                 instance.name, source_node)
5224 313bcead Iustin Pop
5225 17c3f802 Guido Trotter
    result = self.rpc.call_instance_shutdown(source_node, instance,
5226 17c3f802 Guido Trotter
                                             self.shutdown_timeout)
5227 313bcead Iustin Pop
    msg = result.fail_msg
5228 313bcead Iustin Pop
    if msg:
5229 313bcead Iustin Pop
      if self.op.ignore_consistency:
5230 313bcead Iustin Pop
        self.proc.LogWarning("Could not shutdown instance %s on node %s."
5231 313bcead Iustin Pop
                             " Proceeding anyway. Please make sure node"
5232 313bcead Iustin Pop
                             " %s is down. Error details: %s",
5233 313bcead Iustin Pop
                             instance.name, source_node, source_node, msg)
5234 313bcead Iustin Pop
      else:
5235 313bcead Iustin Pop
        raise errors.OpExecError("Could not shutdown instance %s on"
5236 313bcead Iustin Pop
                                 " node %s: %s" %
5237 313bcead Iustin Pop
                                 (instance.name, source_node, msg))
5238 313bcead Iustin Pop
5239 313bcead Iustin Pop
    # create the target disks
5240 313bcead Iustin Pop
    try:
5241 313bcead Iustin Pop
      _CreateDisks(self, instance, target_node=target_node)
5242 313bcead Iustin Pop
    except errors.OpExecError:
5243 313bcead Iustin Pop
      self.LogWarning("Device creation failed, reverting...")
5244 313bcead Iustin Pop
      try:
5245 313bcead Iustin Pop
        _RemoveDisks(self, instance, target_node=target_node)
5246 313bcead Iustin Pop
      finally:
5247 313bcead Iustin Pop
        self.cfg.ReleaseDRBDMinors(instance.name)
5248 313bcead Iustin Pop
        raise
5249 313bcead Iustin Pop
5250 313bcead Iustin Pop
    cluster_name = self.cfg.GetClusterInfo().cluster_name
5251 313bcead Iustin Pop
5252 313bcead Iustin Pop
    errs = []
5253 313bcead Iustin Pop
    # activate, get path, copy the data over
5254 313bcead Iustin Pop
    for idx, disk in enumerate(instance.disks):
5255 313bcead Iustin Pop
      self.LogInfo("Copying data for disk %d", idx)
5256 313bcead Iustin Pop
      result = self.rpc.call_blockdev_assemble(target_node, disk,
5257 313bcead Iustin Pop
                                               instance.name, True)
5258 313bcead Iustin Pop
      if result.fail_msg:
5259 313bcead Iustin Pop
        self.LogWarning("Can't assemble newly created disk %d: %s",
5260 313bcead Iustin Pop
                        idx, result.fail_msg)
5261 313bcead Iustin Pop
        errs.append(result.fail_msg)
5262 313bcead Iustin Pop
        break
5263 313bcead Iustin Pop
      dev_path = result.payload
5264 313bcead Iustin Pop
      result = self.rpc.call_blockdev_export(source_node, disk,
5265 313bcead Iustin Pop
                                             target_node, dev_path,
5266 313bcead Iustin Pop
                                             cluster_name)
5267 313bcead Iustin Pop
      if result.fail_msg:
5268 313bcead Iustin Pop
        self.LogWarning("Can't copy data over for disk %d: %s",
5269 313bcead Iustin Pop
                        idx, result.fail_msg)
5270 313bcead Iustin Pop
        errs.append(result.fail_msg)
5271 313bcead Iustin Pop
        break
5272 313bcead Iustin Pop
5273 313bcead Iustin Pop
    if errs:
5274 313bcead Iustin Pop
      self.LogWarning("Some disks failed to copy, aborting")
5275 313bcead Iustin Pop
      try:
5276 313bcead Iustin Pop
        _RemoveDisks(self, instance, target_node=target_node)
5277 313bcead Iustin Pop
      finally:
5278 313bcead Iustin Pop
        self.cfg.ReleaseDRBDMinors(instance.name)
5279 313bcead Iustin Pop
        raise errors.OpExecError("Errors during disk copy: %s" %
5280 313bcead Iustin Pop
                                 (",".join(errs),))
5281 313bcead Iustin Pop
5282 313bcead Iustin Pop
    instance.primary_node = target_node
5283 a4eae71f Michael Hanselmann
    self.cfg.Update(instance, feedback_fn)
5284 313bcead Iustin Pop
5285 313bcead Iustin Pop
    self.LogInfo("Removing the disks on the original node")
5286 313bcead Iustin Pop
    _RemoveDisks(self, instance, target_node=source_node)
5287 313bcead Iustin Pop
5288 313bcead Iustin Pop
    # Only start the instance if it's marked as up
5289 313bcead Iustin Pop
    if instance.admin_up:
5290 313bcead Iustin Pop
      self.LogInfo("Starting instance %s on node %s",
5291 313bcead Iustin Pop
                   instance.name, target_node)
5292 313bcead Iustin Pop
5293 313bcead Iustin Pop
      disks_ok, _ = _AssembleInstanceDisks(self, instance,
5294 313bcead Iustin Pop
                                           ignore_secondaries=True)
5295 313bcead Iustin Pop
      if not disks_ok:
5296 313bcead Iustin Pop
        _ShutdownInstanceDisks(self, instance)
5297 313bcead Iustin Pop
        raise errors.OpExecError("Can't activate the instance's disks")
5298 313bcead Iustin Pop
5299 313bcead Iustin Pop
      result = self.rpc.call_instance_start(target_node, instance, None, None)
5300 313bcead Iustin Pop
      msg = result.fail_msg
5301 313bcead Iustin Pop
      if msg:
5302 313bcead Iustin Pop
        _ShutdownInstanceDisks(self, instance)
5303 313bcead Iustin Pop
        raise errors.OpExecError("Could not start instance %s on node %s: %s" %
5304 313bcead Iustin Pop
                                 (instance.name, target_node, msg))
5305 313bcead Iustin Pop
5306 313bcead Iustin Pop
5307 80cb875c Michael Hanselmann
class LUMigrateNode(LogicalUnit):
5308 80cb875c Michael Hanselmann
  """Migrate all instances from a node.
5309 80cb875c Michael Hanselmann

5310 80cb875c Michael Hanselmann
  """
5311 80cb875c Michael Hanselmann
  HPATH = "node-migrate"
5312 80cb875c Michael Hanselmann
  HTYPE = constants.HTYPE_NODE
5313 80cb875c Michael Hanselmann
  _OP_REQP = ["node_name", "live"]
5314 80cb875c Michael Hanselmann
  REQ_BGL = False
5315 80cb875c Michael Hanselmann
5316 80cb875c Michael Hanselmann
  def ExpandNames(self):
5317 cf26a87a Iustin Pop
    self.op.node_name = _ExpandNodeName(self.cfg, self.op.node_name)
5318 80cb875c Michael Hanselmann
5319 80cb875c Michael Hanselmann
    self.needed_locks = {
5320 80cb875c Michael Hanselmann
      locking.LEVEL_NODE: [self.op.node_name],
5321 80cb875c Michael Hanselmann
      }
5322 80cb875c Michael Hanselmann
5323 80cb875c Michael Hanselmann
    self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_APPEND
5324 80cb875c Michael Hanselmann
5325 80cb875c Michael Hanselmann
    # Create tasklets for migrating instances for all instances on this node
5326 80cb875c Michael Hanselmann
    names = []
5327 80cb875c Michael Hanselmann
    tasklets = []
5328 80cb875c Michael Hanselmann
5329 80cb875c Michael Hanselmann
    for inst in _GetNodePrimaryInstances(self.cfg, self.op.node_name):
5330 80cb875c Michael Hanselmann
      logging.debug("Migrating instance %s", inst.name)
5331 80cb875c Michael Hanselmann
      names.append(inst.name)
5332 80cb875c Michael Hanselmann
5333 80cb875c Michael Hanselmann
      tasklets.append(TLMigrateInstance(self, inst.name, self.op.live, False))
5334 80cb875c Michael Hanselmann
5335 80cb875c Michael Hanselmann
    self.tasklets = tasklets
5336 80cb875c Michael Hanselmann
5337 80cb875c Michael Hanselmann
    # Declare instance locks
5338 80cb875c Michael Hanselmann
    self.needed_locks[locking.LEVEL_INSTANCE] = names
5339 80cb875c Michael Hanselmann
5340 80cb875c Michael Hanselmann
  def DeclareLocks(self, level):
5341 80cb875c Michael Hanselmann
    if level == locking.LEVEL_NODE:
5342 80cb875c Michael Hanselmann
      self._LockInstancesNodes()
5343 80cb875c Michael Hanselmann
5344 80cb875c Michael Hanselmann
  def BuildHooksEnv(self):
5345 80cb875c Michael Hanselmann
    """Build hooks env.
5346 80cb875c Michael Hanselmann

5347 80cb875c Michael Hanselmann
    This runs on the master, the primary and all the secondaries.
5348 80cb875c Michael Hanselmann

5349 80cb875c Michael Hanselmann
    """
5350 80cb875c Michael Hanselmann
    env = {
5351 80cb875c Michael Hanselmann
      "NODE_NAME": self.op.node_name,
5352 80cb875c Michael Hanselmann
      }
5353 80cb875c Michael Hanselmann
5354 80cb875c Michael Hanselmann
    nl = [self.cfg.GetMasterNode()]
5355 80cb875c Michael Hanselmann
5356 80cb875c Michael Hanselmann
    return (env, nl, nl)
5357 80cb875c Michael Hanselmann
5358 80cb875c Michael Hanselmann
5359 3e06e001 Michael Hanselmann
class TLMigrateInstance(Tasklet):
5360 3e06e001 Michael Hanselmann
  def __init__(self, lu, instance_name, live, cleanup):
5361 3e06e001 Michael Hanselmann
    """Initializes this class.
5362 3e06e001 Michael Hanselmann

5363 3e06e001 Michael Hanselmann
    """
5364 464243a7 Michael Hanselmann
    Tasklet.__init__(self, lu)
5365 464243a7 Michael Hanselmann
5366 3e06e001 Michael Hanselmann
    # Parameters
5367 3e06e001 Michael Hanselmann
    self.instance_name = instance_name
5368 3e06e001 Michael Hanselmann
    self.live = live
5369 3e06e001 Michael Hanselmann
    self.cleanup = cleanup
5370 3e06e001 Michael Hanselmann
5371 53c776b5 Iustin Pop
  def CheckPrereq(self):
5372 53c776b5 Iustin Pop
    """Check prerequisites.
5373 53c776b5 Iustin Pop

5374 53c776b5 Iustin Pop
    This checks that the instance is in the cluster.
5375 53c776b5 Iustin Pop

5376 53c776b5 Iustin Pop
    """
5377 cf26a87a Iustin Pop
    instance_name = _ExpandInstanceName(self.lu.cfg, self.instance_name)
5378 cf26a87a Iustin Pop
    instance = self.cfg.GetInstanceInfo(instance_name)
5379 cf26a87a Iustin Pop
    assert instance is not None
5380 53c776b5 Iustin Pop
5381 53c776b5 Iustin Pop
    if instance.disk_template != constants.DT_DRBD8:
5382 53c776b5 Iustin Pop
      raise errors.OpPrereqError("Instance's disk layout is not"
5383 5c983ee5 Iustin Pop
                                 " drbd8, cannot migrate.", errors.ECODE_STATE)
5384 53c776b5 Iustin Pop
5385 53c776b5 Iustin Pop
    secondary_nodes = instance.secondary_nodes
5386 53c776b5 Iustin Pop
    if not secondary_nodes:
5387 733a2b6a Iustin Pop
      raise errors.ConfigurationError("No secondary node but using"
5388 733a2b6a Iustin Pop
                                      " drbd8 disk template")
5389 53c776b5 Iustin Pop
5390 53c776b5 Iustin Pop
    i_be = self.cfg.GetClusterInfo().FillBE(instance)
5391 53c776b5 Iustin Pop
5392 53c776b5 Iustin Pop
    target_node = secondary_nodes[0]
5393 53c776b5 Iustin Pop
    # check memory requirements on the secondary node
5394 53c776b5 Iustin Pop
    _CheckNodeFreeMemory(self, target_node, "migrating instance %s" %
5395 53c776b5 Iustin Pop
                         instance.name, i_be[constants.BE_MEMORY],
5396 53c776b5 Iustin Pop
                         instance.hypervisor)
5397 53c776b5 Iustin Pop
5398 53c776b5 Iustin Pop
    # check bridge existance
5399 b165e77e Guido Trotter
    _CheckInstanceBridgesExist(self, instance, node=target_node)
5400 53c776b5 Iustin Pop
5401 3e06e001 Michael Hanselmann
    if not self.cleanup:
5402 733a2b6a Iustin Pop
      _CheckNodeNotDrained(self, target_node)
5403 53c776b5 Iustin Pop
      result = self.rpc.call_instance_migratable(instance.primary_node,
5404 53c776b5 Iustin Pop
                                                 instance)
5405 045dd6d9 Iustin Pop
      result.Raise("Can't migrate, please use failover",
5406 045dd6d9 Iustin Pop
                   prereq=True, ecode=errors.ECODE_STATE)
5407 53c776b5 Iustin Pop
5408 53c776b5 Iustin Pop
    self.instance = instance
5409 53c776b5 Iustin Pop
5410 53c776b5 Iustin Pop
  def _WaitUntilSync(self):
5411 53c776b5 Iustin Pop
    """Poll with custom rpc for disk sync.
5412 53c776b5 Iustin Pop

5413 53c776b5 Iustin Pop
    This uses our own step-based rpc call.
5414 53c776b5 Iustin Pop

5415 53c776b5 Iustin Pop
    """
5416 53c776b5 Iustin Pop
    self.feedback_fn("* wait until resync is done")
5417 53c776b5 Iustin Pop
    all_done = False
5418 53c776b5 Iustin Pop
    while not all_done:
5419 53c776b5 Iustin Pop
      all_done = True
5420 53c776b5 Iustin Pop
      result = self.rpc.call_drbd_wait_sync(self.all_nodes,
5421 53c776b5 Iustin Pop
                                            self.nodes_ip,
5422 53c776b5 Iustin Pop
                                            self.instance.disks)
5423 53c776b5 Iustin Pop
      min_percent = 100
5424 53c776b5 Iustin Pop
      for node, nres in result.items():
5425 4c4e4e1e Iustin Pop
        nres.Raise("Cannot resync disks on node %s" % node)
5426 0959c824 Iustin Pop
        node_done, node_percent = nres.payload
5427 53c776b5 Iustin Pop
        all_done = all_done and node_done
5428 53c776b5 Iustin Pop
        if node_percent is not None:
5429 53c776b5 Iustin Pop
          min_percent = min(min_percent, node_percent)
5430 53c776b5 Iustin Pop
      if not all_done:
5431 53c776b5 Iustin Pop
        if min_percent < 100:
5432 53c776b5 Iustin Pop
          self.feedback_fn("   - progress: %.1f%%" % min_percent)
5433 53c776b5 Iustin Pop
        time.sleep(2)
5434 53c776b5 Iustin Pop
5435 53c776b5 Iustin Pop
  def _EnsureSecondary(self, node):
5436 53c776b5 Iustin Pop
    """Demote a node to secondary.
5437 53c776b5 Iustin Pop

5438 53c776b5 Iustin Pop
    """
5439 53c776b5 Iustin Pop
    self.feedback_fn("* switching node %s to secondary mode" % node)
5440 53c776b5 Iustin Pop
5441 53c776b5 Iustin Pop
    for dev in self.instance.disks:
5442 53c776b5 Iustin Pop
      self.cfg.SetDiskID(dev, node)
5443 53c776b5 Iustin Pop
5444 53c776b5 Iustin Pop
    result = self.rpc.call_blockdev_close(node, self.instance.name,
5445 53c776b5 Iustin Pop
                                          self.instance.disks)
5446 4c4e4e1e Iustin Pop
    result.Raise("Cannot change disk to secondary on node %s" % node)
5447 53c776b5 Iustin Pop
5448 53c776b5 Iustin Pop
  def _GoStandalone(self):
5449 53c776b5 Iustin Pop
    """Disconnect from the network.
5450 53c776b5 Iustin Pop

5451 53c776b5 Iustin Pop
    """
5452 53c776b5 Iustin Pop
    self.feedback_fn("* changing into standalone mode")
5453 53c776b5 Iustin Pop
    result = self.rpc.call_drbd_disconnect_net(self.all_nodes, self.nodes_ip,
5454 53c776b5 Iustin Pop
                                               self.instance.disks)
5455 53c776b5 Iustin Pop
    for node, nres in result.items():
5456 4c4e4e1e Iustin Pop
      nres.Raise("Cannot disconnect disks node %s" % node)
5457 53c776b5 Iustin Pop
5458 53c776b5 Iustin Pop
  def _GoReconnect(self, multimaster):
5459 53c776b5 Iustin Pop
    """Reconnect to the network.
5460 53c776b5 Iustin Pop

5461 53c776b5 Iustin Pop
    """
5462 53c776b5 Iustin Pop
    if multimaster:
5463 53c776b5 Iustin Pop
      msg = "dual-master"
5464 53c776b5 Iustin Pop
    else:
5465 53c776b5 Iustin Pop
      msg = "single-master"
5466 53c776b5 Iustin Pop
    self.feedback_fn("* changing disks into %s mode" % msg)
5467 53c776b5 Iustin Pop
    result = self.rpc.call_drbd_attach_net(self.all_nodes, self.nodes_ip,
5468 53c776b5 Iustin Pop
                                           self.instance.disks,
5469 53c776b5 Iustin Pop
                                           self.instance.name, multimaster)
5470 53c776b5 Iustin Pop
    for node, nres in result.items():
5471 4c4e4e1e Iustin Pop
      nres.Raise("Cannot change disks config on node %s" % node)
5472 53c776b5 Iustin Pop
5473 53c776b5 Iustin Pop
  def _ExecCleanup(self):
5474 53c776b5 Iustin Pop
    """Try to cleanup after a failed migration.
5475 53c776b5 Iustin Pop

5476 53c776b5 Iustin Pop
    The cleanup is done by:
5477 53c776b5 Iustin Pop
      - check that the instance is running only on one node
5478 53c776b5 Iustin Pop
        (and update the config if needed)
5479 53c776b5 Iustin Pop
      - change disks on its secondary node to secondary
5480 53c776b5 Iustin Pop
      - wait until disks are fully synchronized
5481 53c776b5 Iustin Pop
      - disconnect from the network
5482 53c776b5 Iustin Pop
      - change disks into single-master mode
5483 53c776b5 Iustin Pop
      - wait again until disks are fully synchronized
5484 53c776b5 Iustin Pop

5485 53c776b5 Iustin Pop
    """
5486 53c776b5 Iustin Pop
    instance = self.instance
5487 53c776b5 Iustin Pop
    target_node = self.target_node
5488 53c776b5 Iustin Pop
    source_node = self.source_node
5489 53c776b5 Iustin Pop
5490 53c776b5 Iustin Pop
    # check running on only one node
5491 53c776b5 Iustin Pop
    self.feedback_fn("* checking where the instance actually runs"
5492 53c776b5 Iustin Pop
                     " (if this hangs, the hypervisor might be in"
5493 53c776b5 Iustin Pop
                     " a bad state)")
5494 53c776b5 Iustin Pop
    ins_l = self.rpc.call_instance_list(self.all_nodes, [instance.hypervisor])
5495 53c776b5 Iustin Pop
    for node, result in ins_l.items():
5496 4c4e4e1e Iustin Pop
      result.Raise("Can't contact node %s" % node)
5497 53c776b5 Iustin Pop
5498 aca13712 Iustin Pop
    runningon_source = instance.name in ins_l[source_node].payload
5499 aca13712 Iustin Pop
    runningon_target = instance.name in ins_l[target_node].payload
5500 53c776b5 Iustin Pop
5501 53c776b5 Iustin Pop
    if runningon_source and runningon_target:
5502 53c776b5 Iustin Pop
      raise errors.OpExecError("Instance seems to be running on two nodes,"
5503 53c776b5 Iustin Pop
                               " or the hypervisor is confused. You will have"
5504 53c776b5 Iustin Pop
                               " to ensure manually that it runs only on one"
5505 53c776b5 Iustin Pop
                               " and restart this operation.")
5506 53c776b5 Iustin Pop
5507 53c776b5 Iustin Pop
    if not (runningon_source or runningon_target):
5508 53c776b5 Iustin Pop
      raise errors.OpExecError("Instance does not seem to be running at all."
5509 53c776b5 Iustin Pop
                               " In this case, it's safer to repair by"
5510 53c776b5 Iustin Pop
                               " running 'gnt-instance stop' to ensure disk"
5511 53c776b5 Iustin Pop
                               " shutdown, and then restarting it.")
5512 53c776b5 Iustin Pop
5513 53c776b5 Iustin Pop
    if runningon_target:
5514 53c776b5 Iustin Pop
      # the migration has actually succeeded, we need to update the config
5515 53c776b5 Iustin Pop
      self.feedback_fn("* instance running on secondary node (%s),"
5516 53c776b5 Iustin Pop
                       " updating config" % target_node)
5517 53c776b5 Iustin Pop
      instance.primary_node = target_node
5518 a4eae71f Michael Hanselmann
      self.cfg.Update(instance, self.feedback_fn)
5519 53c776b5 Iustin Pop
      demoted_node = source_node
5520 53c776b5 Iustin Pop
    else:
5521 53c776b5 Iustin Pop
      self.feedback_fn("* instance confirmed to be running on its"
5522 53c776b5 Iustin Pop
                       " primary node (%s)" % source_node)
5523 53c776b5 Iustin Pop
      demoted_node = target_node
5524 53c776b5 Iustin Pop
5525 53c776b5 Iustin Pop
    self._EnsureSecondary(demoted_node)
5526 53c776b5 Iustin Pop
    try:
5527 53c776b5 Iustin Pop
      self._WaitUntilSync()
5528 53c776b5 Iustin Pop
    except errors.OpExecError:
5529 53c776b5 Iustin Pop
      # we ignore here errors, since if the device is standalone, it
5530 53c776b5 Iustin Pop
      # won't be able to sync
5531 53c776b5 Iustin Pop
      pass
5532 53c776b5 Iustin Pop
    self._GoStandalone()
5533 53c776b5 Iustin Pop
    self._GoReconnect(False)
5534 53c776b5 Iustin Pop
    self._WaitUntilSync()
5535 53c776b5 Iustin Pop
5536 53c776b5 Iustin Pop
    self.feedback_fn("* done")
5537 53c776b5 Iustin Pop
5538 6906a9d8 Guido Trotter
  def _RevertDiskStatus(self):
5539 6906a9d8 Guido Trotter
    """Try to revert the disk status after a failed migration.
5540 6906a9d8 Guido Trotter

5541 6906a9d8 Guido Trotter
    """
5542 6906a9d8 Guido Trotter
    target_node = self.target_node
5543 6906a9d8 Guido Trotter
    try:
5544 6906a9d8 Guido Trotter
      self._EnsureSecondary(target_node)
5545 6906a9d8 Guido Trotter
      self._GoStandalone()
5546 6906a9d8 Guido Trotter
      self._GoReconnect(False)
5547 6906a9d8 Guido Trotter
      self._WaitUntilSync()
5548 6906a9d8 Guido Trotter
    except errors.OpExecError, err:
5549 3e06e001 Michael Hanselmann
      self.lu.LogWarning("Migration failed and I can't reconnect the"
5550 3e06e001 Michael Hanselmann
                         " drives: error '%s'\n"
5551 3e06e001 Michael Hanselmann
                         "Please look and recover the instance status" %
5552 3e06e001 Michael Hanselmann
                         str(err))
5553 6906a9d8 Guido Trotter
5554 6906a9d8 Guido Trotter
  def _AbortMigration(self):
5555 6906a9d8 Guido Trotter
    """Call the hypervisor code to abort a started migration.
5556 6906a9d8 Guido Trotter

5557 6906a9d8 Guido Trotter
    """
5558 6906a9d8 Guido Trotter
    instance = self.instance
5559 6906a9d8 Guido Trotter
    target_node = self.target_node
5560 6906a9d8 Guido Trotter
    migration_info = self.migration_info
5561 6906a9d8 Guido Trotter
5562 6906a9d8 Guido Trotter
    abort_result = self.rpc.call_finalize_migration(target_node,
5563 6906a9d8 Guido Trotter
                                                    instance,
5564 6906a9d8 Guido Trotter
                                                    migration_info,
5565 6906a9d8 Guido Trotter
                                                    False)
5566 4c4e4e1e Iustin Pop
    abort_msg = abort_result.fail_msg
5567 6906a9d8 Guido Trotter
    if abort_msg:
5568 099c52ad Iustin Pop
      logging.error("Aborting migration failed on target node %s: %s",
5569 099c52ad Iustin Pop
                    target_node, abort_msg)
5570 6906a9d8 Guido Trotter
      # Don't raise an exception here, as we stil have to try to revert the
5571 6906a9d8 Guido Trotter
      # disk status, even if this step failed.
5572 6906a9d8 Guido Trotter
5573 53c776b5 Iustin Pop
  def _ExecMigration(self):
5574 53c776b5 Iustin Pop
    """Migrate an instance.
5575 53c776b5 Iustin Pop

5576 53c776b5 Iustin Pop
    The migrate is done by:
5577 53c776b5 Iustin Pop
      - change the disks into dual-master mode
5578 53c776b5 Iustin Pop
      - wait until disks are fully synchronized again
5579 53c776b5 Iustin Pop
      - migrate the instance
5580 53c776b5 Iustin Pop
      - change disks on the new secondary node (the old primary) to secondary
5581 53c776b5 Iustin Pop
      - wait until disks are fully synchronized
5582 53c776b5 Iustin Pop
      - change disks into single-master mode
5583 53c776b5 Iustin Pop

5584 53c776b5 Iustin Pop
    """
5585 53c776b5 Iustin Pop
    instance = self.instance
5586 53c776b5 Iustin Pop
    target_node = self.target_node
5587 53c776b5 Iustin Pop
    source_node = self.source_node
5588 53c776b5 Iustin Pop
5589 53c776b5 Iustin Pop
    self.feedback_fn("* checking disk consistency between source and target")
5590 53c776b5 Iustin Pop
    for dev in instance.disks:
5591 53c776b5 Iustin Pop
      if not _CheckDiskConsistency(self, dev, target_node, False):
5592 53c776b5 Iustin Pop
        raise errors.OpExecError("Disk %s is degraded or not fully"
5593 53c776b5 Iustin Pop
                                 " synchronized on target node,"
5594 53c776b5 Iustin Pop
                                 " aborting migrate." % dev.iv_name)
5595 53c776b5 Iustin Pop
5596 6906a9d8 Guido Trotter
    # First get the migration information from the remote node
5597 6906a9d8 Guido Trotter
    result = self.rpc.call_migration_info(source_node, instance)
5598 4c4e4e1e Iustin Pop
    msg = result.fail_msg
5599 6906a9d8 Guido Trotter
    if msg:
5600 6906a9d8 Guido Trotter
      log_err = ("Failed fetching source migration information from %s: %s" %
5601 0959c824 Iustin Pop
                 (source_node, msg))
5602 6906a9d8 Guido Trotter
      logging.error(log_err)
5603 6906a9d8 Guido Trotter
      raise errors.OpExecError(log_err)
5604 6906a9d8 Guido Trotter
5605 0959c824 Iustin Pop
    self.migration_info = migration_info = result.payload
5606 6906a9d8 Guido Trotter
5607 6906a9d8 Guido Trotter
    # Then switch the disks to master/master mode
5608 53c776b5 Iustin Pop
    self._EnsureSecondary(target_node)
5609 53c776b5 Iustin Pop
    self._GoStandalone()
5610 53c776b5 Iustin Pop
    self._GoReconnect(True)
5611 53c776b5 Iustin Pop
    self._WaitUntilSync()
5612 53c776b5 Iustin Pop
5613 6906a9d8 Guido Trotter
    self.feedback_fn("* preparing %s to accept the instance" % target_node)
5614 6906a9d8 Guido Trotter
    result = self.rpc.call_accept_instance(target_node,
5615 6906a9d8 Guido Trotter
                                           instance,
5616 6906a9d8 Guido Trotter
                                           migration_info,
5617 6906a9d8 Guido Trotter
                                           self.nodes_ip[target_node])
5618 6906a9d8 Guido Trotter
5619 4c4e4e1e Iustin Pop
    msg = result.fail_msg
5620 6906a9d8 Guido Trotter
    if msg:
5621 6906a9d8 Guido Trotter
      logging.error("Instance pre-migration failed, trying to revert"
5622 6906a9d8 Guido Trotter
                    " disk status: %s", msg)
5623 78212a5d Iustin Pop
      self.feedback_fn("Pre-migration failed, aborting")
5624 6906a9d8 Guido Trotter
      self._AbortMigration()
5625 6906a9d8 Guido Trotter
      self._RevertDiskStatus()
5626 6906a9d8 Guido Trotter
      raise errors.OpExecError("Could not pre-migrate instance %s: %s" %
5627 6906a9d8 Guido Trotter
                               (instance.name, msg))
5628 6906a9d8 Guido Trotter
5629 53c776b5 Iustin Pop
    self.feedback_fn("* migrating instance to %s" % target_node)
5630 53c776b5 Iustin Pop
    time.sleep(10)
5631 53c776b5 Iustin Pop
    result = self.rpc.call_instance_migrate(source_node, instance,
5632 53c776b5 Iustin Pop
                                            self.nodes_ip[target_node],
5633 3e06e001 Michael Hanselmann
                                            self.live)
5634 4c4e4e1e Iustin Pop
    msg = result.fail_msg
5635 53c776b5 Iustin Pop
    if msg:
5636 53c776b5 Iustin Pop
      logging.error("Instance migration failed, trying to revert"
5637 53c776b5 Iustin Pop
                    " disk status: %s", msg)
5638 78212a5d Iustin Pop
      self.feedback_fn("Migration failed, aborting")
5639 6906a9d8 Guido Trotter
      self._AbortMigration()
5640 6906a9d8 Guido Trotter
      self._RevertDiskStatus()
5641 53c776b5 Iustin Pop
      raise errors.OpExecError("Could not migrate instance %s: %s" %
5642 53c776b5 Iustin Pop
                               (instance.name, msg))
5643 53c776b5 Iustin Pop
    time.sleep(10)
5644 53c776b5 Iustin Pop
5645 53c776b5 Iustin Pop
    instance.primary_node = target_node
5646 53c776b5 Iustin Pop
    # distribute new instance config to the other nodes
5647 a4eae71f Michael Hanselmann
    self.cfg.Update(instance, self.feedback_fn)
5648 53c776b5 Iustin Pop
5649 6906a9d8 Guido Trotter
    result = self.rpc.call_finalize_migration(target_node,
5650 6906a9d8 Guido Trotter
                                              instance,
5651 6906a9d8 Guido Trotter
                                              migration_info,
5652 6906a9d8 Guido Trotter
                                              True)
5653 4c4e4e1e Iustin Pop
    msg = result.fail_msg
5654 6906a9d8 Guido Trotter
    if msg:
5655 6906a9d8 Guido Trotter
      logging.error("Instance migration succeeded, but finalization failed:"
5656 099c52ad Iustin Pop
                    " %s", msg)
5657 6906a9d8 Guido Trotter
      raise errors.OpExecError("Could not finalize instance migration: %s" %
5658 6906a9d8 Guido Trotter
                               msg)
5659 6906a9d8 Guido Trotter
5660 53c776b5 Iustin Pop
    self._EnsureSecondary(source_node)
5661 53c776b5 Iustin Pop
    self._WaitUntilSync()
5662 53c776b5 Iustin Pop
    self._GoStandalone()
5663 53c776b5 Iustin Pop
    self._GoReconnect(False)
5664 53c776b5 Iustin Pop
    self._WaitUntilSync()
5665 53c776b5 Iustin Pop
5666 53c776b5 Iustin Pop
    self.feedback_fn("* done")
5667 53c776b5 Iustin Pop
5668 53c776b5 Iustin Pop
  def Exec(self, feedback_fn):
5669 53c776b5 Iustin Pop
    """Perform the migration.
5670 53c776b5 Iustin Pop

5671 53c776b5 Iustin Pop
    """
5672 80cb875c Michael Hanselmann
    feedback_fn("Migrating instance %s" % self.instance.name)
5673 80cb875c Michael Hanselmann
5674 53c776b5 Iustin Pop
    self.feedback_fn = feedback_fn
5675 53c776b5 Iustin Pop
5676 53c776b5 Iustin Pop
    self.source_node = self.instance.primary_node
5677 53c776b5 Iustin Pop
    self.target_node = self.instance.secondary_nodes[0]
5678 53c776b5 Iustin Pop
    self.all_nodes = [self.source_node, self.target_node]
5679 53c776b5 Iustin Pop
    self.nodes_ip = {
5680 53c776b5 Iustin Pop
      self.source_node: self.cfg.GetNodeInfo(self.source_node).secondary_ip,
5681 53c776b5 Iustin Pop
      self.target_node: self.cfg.GetNodeInfo(self.target_node).secondary_ip,
5682 53c776b5 Iustin Pop
      }
5683 3e06e001 Michael Hanselmann
5684 3e06e001 Michael Hanselmann
    if self.cleanup:
5685 53c776b5 Iustin Pop
      return self._ExecCleanup()
5686 53c776b5 Iustin Pop
    else:
5687 53c776b5 Iustin Pop
      return self._ExecMigration()
5688 53c776b5 Iustin Pop
5689 53c776b5 Iustin Pop
5690 428958aa Iustin Pop
def _CreateBlockDev(lu, node, instance, device, force_create,
5691 428958aa Iustin Pop
                    info, force_open):
5692 428958aa Iustin Pop
  """Create a tree of block devices on a given node.
5693 a8083063 Iustin Pop

5694 a8083063 Iustin Pop
  If this device type has to be created on secondaries, create it and
5695 a8083063 Iustin Pop
  all its children.
5696 a8083063 Iustin Pop

5697 a8083063 Iustin Pop
  If not, just recurse to children keeping the same 'force' value.
5698 a8083063 Iustin Pop

5699 428958aa Iustin Pop
  @param lu: the lu on whose behalf we execute
5700 428958aa Iustin Pop
  @param node: the node on which to create the device
5701 428958aa Iustin Pop
  @type instance: L{objects.Instance}
5702 428958aa Iustin Pop
  @param instance: the instance which owns the device
5703 428958aa Iustin Pop
  @type device: L{objects.Disk}
5704 428958aa Iustin Pop
  @param device: the device to create
5705 428958aa Iustin Pop
  @type force_create: boolean
5706 428958aa Iustin Pop
  @param force_create: whether to force creation of this device; this
5707 428958aa Iustin Pop
      will be change to True whenever we find a device which has
5708 428958aa Iustin Pop
      CreateOnSecondary() attribute
5709 428958aa Iustin Pop
  @param info: the extra 'metadata' we should attach to the device
5710 428958aa Iustin Pop
      (this will be represented as a LVM tag)
5711 428958aa Iustin Pop
  @type force_open: boolean
5712 428958aa Iustin Pop
  @param force_open: this parameter will be passes to the
5713 821d1bd1 Iustin Pop
      L{backend.BlockdevCreate} function where it specifies
5714 428958aa Iustin Pop
      whether we run on primary or not, and it affects both
5715 428958aa Iustin Pop
      the child assembly and the device own Open() execution
5716 428958aa Iustin Pop

5717 a8083063 Iustin Pop
  """
5718 a8083063 Iustin Pop
  if device.CreateOnSecondary():
5719 428958aa Iustin Pop
    force_create = True
5720 796cab27 Iustin Pop
5721 a8083063 Iustin Pop
  if device.children:
5722 a8083063 Iustin Pop
    for child in device.children:
5723 428958aa Iustin Pop
      _CreateBlockDev(lu, node, instance, child, force_create,
5724 428958aa Iustin Pop
                      info, force_open)
5725 a8083063 Iustin Pop
5726 428958aa Iustin Pop
  if not force_create:
5727 796cab27 Iustin Pop
    return
5728 796cab27 Iustin Pop
5729 de12473a Iustin Pop
  _CreateSingleBlockDev(lu, node, instance, device, info, force_open)
5730 de12473a Iustin Pop
5731 de12473a Iustin Pop
5732 de12473a Iustin Pop
def _CreateSingleBlockDev(lu, node, instance, device, info, force_open):
5733 de12473a Iustin Pop
  """Create a single block device on a given node.
5734 de12473a Iustin Pop

5735 de12473a Iustin Pop
  This will not recurse over children of the device, so they must be
5736 de12473a Iustin Pop
  created in advance.
5737 de12473a Iustin Pop

5738 de12473a Iustin Pop
  @param lu: the lu on whose behalf we execute
5739 de12473a Iustin Pop
  @param node: the node on which to create the device
5740 de12473a Iustin Pop
  @type instance: L{objects.Instance}
5741 de12473a Iustin Pop
  @param instance: the instance which owns the device
5742 de12473a Iustin Pop
  @type device: L{objects.Disk}
5743 de12473a Iustin Pop
  @param device: the device to create
5744 de12473a Iustin Pop
  @param info: the extra 'metadata' we should attach to the device
5745 de12473a Iustin Pop
      (this will be represented as a LVM tag)
5746 de12473a Iustin Pop
  @type force_open: boolean
5747 de12473a Iustin Pop
  @param force_open: this parameter will be passes to the
5748 821d1bd1 Iustin Pop
      L{backend.BlockdevCreate} function where it specifies
5749 de12473a Iustin Pop
      whether we run on primary or not, and it affects both
5750 de12473a Iustin Pop
      the child assembly and the device own Open() execution
5751 de12473a Iustin Pop

5752 de12473a Iustin Pop
  """
5753 b9bddb6b Iustin Pop
  lu.cfg.SetDiskID(device, node)
5754 7d81697f Iustin Pop
  result = lu.rpc.call_blockdev_create(node, device, device.size,
5755 428958aa Iustin Pop
                                       instance.name, force_open, info)
5756 4c4e4e1e Iustin Pop
  result.Raise("Can't create block device %s on"
5757 4c4e4e1e Iustin Pop
               " node %s for instance %s" % (device, node, instance.name))
5758 a8083063 Iustin Pop
  if device.physical_id is None:
5759 0959c824 Iustin Pop
    device.physical_id = result.payload
5760 a8083063 Iustin Pop
5761 a8083063 Iustin Pop
5762 b9bddb6b Iustin Pop
def _GenerateUniqueNames(lu, exts):
5763 923b1523 Iustin Pop
  """Generate a suitable LV name.
5764 923b1523 Iustin Pop

5765 923b1523 Iustin Pop
  This will generate a logical volume name for the given instance.
5766 923b1523 Iustin Pop

5767 923b1523 Iustin Pop
  """
5768 923b1523 Iustin Pop
  results = []
5769 923b1523 Iustin Pop
  for val in exts:
5770 4fae38c5 Guido Trotter
    new_id = lu.cfg.GenerateUniqueID(lu.proc.GetECId())
5771 923b1523 Iustin Pop
    results.append("%s%s" % (new_id, val))
5772 923b1523 Iustin Pop
  return results
5773 923b1523 Iustin Pop
5774 923b1523 Iustin Pop
5775 b9bddb6b Iustin Pop
def _GenerateDRBD8Branch(lu, primary, secondary, size, names, iv_name,
5776 ffa1c0dc Iustin Pop
                         p_minor, s_minor):
5777 a1f445d3 Iustin Pop
  """Generate a drbd8 device complete with its children.
5778 a1f445d3 Iustin Pop

5779 a1f445d3 Iustin Pop
  """
5780 b9bddb6b Iustin Pop
  port = lu.cfg.AllocatePort()
5781 b9bddb6b Iustin Pop
  vgname = lu.cfg.GetVGName()
5782 afa1386e Guido Trotter
  shared_secret = lu.cfg.GenerateDRBDSecret(lu.proc.GetECId())
5783 a1f445d3 Iustin Pop
  dev_data = objects.Disk(dev_type=constants.LD_LV, size=size,
5784 a1f445d3 Iustin Pop
                          logical_id=(vgname, names[0]))
5785 a1f445d3 Iustin Pop
  dev_meta = objects.Disk(dev_type=constants.LD_LV, size=128,
5786 a1f445d3 Iustin Pop
                          logical_id=(vgname, names[1]))
5787 a1f445d3 Iustin Pop
  drbd_dev = objects.Disk(dev_type=constants.LD_DRBD8, size=size,
5788 ffa1c0dc Iustin Pop
                          logical_id=(primary, secondary, port,
5789 f9518d38 Iustin Pop
                                      p_minor, s_minor,
5790 f9518d38 Iustin Pop
                                      shared_secret),
5791 ffa1c0dc Iustin Pop
                          children=[dev_data, dev_meta],
5792 a1f445d3 Iustin Pop
                          iv_name=iv_name)
5793 a1f445d3 Iustin Pop
  return drbd_dev
5794 a1f445d3 Iustin Pop
5795 7c0d6283 Michael Hanselmann
5796 b9bddb6b Iustin Pop
def _GenerateDiskTemplate(lu, template_name,
5797 a8083063 Iustin Pop
                          instance_name, primary_node,
5798 08db7c5c Iustin Pop
                          secondary_nodes, disk_info,
5799 e2a65344 Iustin Pop
                          file_storage_dir, file_driver,
5800 e2a65344 Iustin Pop
                          base_index):
5801 a8083063 Iustin Pop
  """Generate the entire disk layout for a given template type.
5802 a8083063 Iustin Pop

5803 a8083063 Iustin Pop
  """
5804 a8083063 Iustin Pop
  #TODO: compute space requirements
5805 a8083063 Iustin Pop
5806 b9bddb6b Iustin Pop
  vgname = lu.cfg.GetVGName()
5807 08db7c5c Iustin Pop
  disk_count = len(disk_info)
5808 08db7c5c Iustin Pop
  disks = []
5809 3517d9b9 Manuel Franceschini
  if template_name == constants.DT_DISKLESS:
5810 08db7c5c Iustin Pop
    pass
5811 3517d9b9 Manuel Franceschini
  elif template_name == constants.DT_PLAIN:
5812 a8083063 Iustin Pop
    if len(secondary_nodes) != 0:
5813 a8083063 Iustin Pop
      raise errors.ProgrammerError("Wrong template configuration")
5814 923b1523 Iustin Pop
5815 fb4b324b Guido Trotter
    names = _GenerateUniqueNames(lu, [".disk%d" % (base_index + i)
5816 08db7c5c Iustin Pop
                                      for i in range(disk_count)])
5817 08db7c5c Iustin Pop
    for idx, disk in enumerate(disk_info):
5818 e2a65344 Iustin Pop
      disk_index = idx + base_index
5819 08db7c5c Iustin Pop
      disk_dev = objects.Disk(dev_type=constants.LD_LV, size=disk["size"],
5820 08db7c5c Iustin Pop
                              logical_id=(vgname, names[idx]),
5821 6ec66eae Iustin Pop
                              iv_name="disk/%d" % disk_index,
5822 6ec66eae Iustin Pop
                              mode=disk["mode"])
5823 08db7c5c Iustin Pop
      disks.append(disk_dev)
5824 a1f445d3 Iustin Pop
  elif template_name == constants.DT_DRBD8:
5825 a1f445d3 Iustin Pop
    if len(secondary_nodes) != 1:
5826 a1f445d3 Iustin Pop
      raise errors.ProgrammerError("Wrong template configuration")
5827 a1f445d3 Iustin Pop
    remote_node = secondary_nodes[0]
5828 08db7c5c Iustin Pop
    minors = lu.cfg.AllocateDRBDMinor(
5829 08db7c5c Iustin Pop
      [primary_node, remote_node] * len(disk_info), instance_name)
5830 08db7c5c Iustin Pop
5831 e6c1ff2f Iustin Pop
    names = []
5832 fb4b324b Guido Trotter
    for lv_prefix in _GenerateUniqueNames(lu, [".disk%d" % (base_index + i)
5833 e6c1ff2f Iustin Pop
                                               for i in range(disk_count)]):
5834 e6c1ff2f Iustin Pop
      names.append(lv_prefix + "_data")
5835 e6c1ff2f Iustin Pop
      names.append(lv_prefix + "_meta")
5836 08db7c5c Iustin Pop
    for idx, disk in enumerate(disk_info):
5837 112050d9 Iustin Pop
      disk_index = idx + base_index
5838 08db7c5c Iustin Pop
      disk_dev = _GenerateDRBD8Branch(lu, primary_node, remote_node,
5839 08db7c5c Iustin Pop
                                      disk["size"], names[idx*2:idx*2+2],
5840 e2a65344 Iustin Pop
                                      "disk/%d" % disk_index,
5841 08db7c5c Iustin Pop
                                      minors[idx*2], minors[idx*2+1])
5842 6ec66eae Iustin Pop
      disk_dev.mode = disk["mode"]
5843 08db7c5c Iustin Pop
      disks.append(disk_dev)
5844 0f1a06e3 Manuel Franceschini
  elif template_name == constants.DT_FILE:
5845 0f1a06e3 Manuel Franceschini
    if len(secondary_nodes) != 0:
5846 0f1a06e3 Manuel Franceschini
      raise errors.ProgrammerError("Wrong template configuration")
5847 0f1a06e3 Manuel Franceschini
5848 0e3baaf3 Iustin Pop
    _RequireFileStorage()
5849 0e3baaf3 Iustin Pop
5850 08db7c5c Iustin Pop
    for idx, disk in enumerate(disk_info):
5851 112050d9 Iustin Pop
      disk_index = idx + base_index
5852 08db7c5c Iustin Pop
      disk_dev = objects.Disk(dev_type=constants.LD_FILE, size=disk["size"],
5853 e2a65344 Iustin Pop
                              iv_name="disk/%d" % disk_index,
5854 08db7c5c Iustin Pop
                              logical_id=(file_driver,
5855 08db7c5c Iustin Pop
                                          "%s/disk%d" % (file_storage_dir,
5856 43e99cff Guido Trotter
                                                         disk_index)),
5857 6ec66eae Iustin Pop
                              mode=disk["mode"])
5858 08db7c5c Iustin Pop
      disks.append(disk_dev)
5859 a8083063 Iustin Pop
  else:
5860 a8083063 Iustin Pop
    raise errors.ProgrammerError("Invalid disk template '%s'" % template_name)
5861 a8083063 Iustin Pop
  return disks
5862 a8083063 Iustin Pop
5863 a8083063 Iustin Pop
5864 a0c3fea1 Michael Hanselmann
def _GetInstanceInfoText(instance):
5865 3ecf6786 Iustin Pop
  """Compute that text that should be added to the disk's metadata.
5866 3ecf6786 Iustin Pop

5867 3ecf6786 Iustin Pop
  """
5868 a0c3fea1 Michael Hanselmann
  return "originstname+%s" % instance.name
5869 a0c3fea1 Michael Hanselmann
5870 a0c3fea1 Michael Hanselmann
5871 621b7678 Iustin Pop
def _CreateDisks(lu, instance, to_skip=None, target_node=None):
5872 a8083063 Iustin Pop
  """Create all disks for an instance.
5873 a8083063 Iustin Pop

5874 a8083063 Iustin Pop
  This abstracts away some work from AddInstance.
5875 a8083063 Iustin Pop

5876 e4376078 Iustin Pop
  @type lu: L{LogicalUnit}
5877 e4376078 Iustin Pop
  @param lu: the logical unit on whose behalf we execute
5878 e4376078 Iustin Pop
  @type instance: L{objects.Instance}
5879 e4376078 Iustin Pop
  @param instance: the instance whose disks we should create
5880 bd315bfa Iustin Pop
  @type to_skip: list
5881 bd315bfa Iustin Pop
  @param to_skip: list of indices to skip
5882 621b7678 Iustin Pop
  @type target_node: string
5883 621b7678 Iustin Pop
  @param target_node: if passed, overrides the target node for creation
5884 e4376078 Iustin Pop
  @rtype: boolean
5885 e4376078 Iustin Pop
  @return: the success of the creation
5886 a8083063 Iustin Pop

5887 a8083063 Iustin Pop
  """
5888 a0c3fea1 Michael Hanselmann
  info = _GetInstanceInfoText(instance)
5889 621b7678 Iustin Pop
  if target_node is None:
5890 621b7678 Iustin Pop
    pnode = instance.primary_node
5891 621b7678 Iustin Pop
    all_nodes = instance.all_nodes
5892 621b7678 Iustin Pop
  else:
5893 621b7678 Iustin Pop
    pnode = target_node
5894 621b7678 Iustin Pop
    all_nodes = [pnode]
5895 a0c3fea1 Michael Hanselmann
5896 0f1a06e3 Manuel Franceschini
  if instance.disk_template == constants.DT_FILE:
5897 0f1a06e3 Manuel Franceschini
    file_storage_dir = os.path.dirname(instance.disks[0].logical_id[1])
5898 428958aa Iustin Pop
    result = lu.rpc.call_file_storage_dir_create(pnode, file_storage_dir)
5899 0f1a06e3 Manuel Franceschini
5900 4c4e4e1e Iustin Pop
    result.Raise("Failed to create directory '%s' on"
5901 9b4127eb Guido Trotter
                 " node %s" % (file_storage_dir, pnode))
5902 0f1a06e3 Manuel Franceschini
5903 24991749 Iustin Pop
  # Note: this needs to be kept in sync with adding of disks in
5904 24991749 Iustin Pop
  # LUSetInstanceParams
5905 bd315bfa Iustin Pop
  for idx, device in enumerate(instance.disks):
5906 bd315bfa Iustin Pop
    if to_skip and idx in to_skip:
5907 bd315bfa Iustin Pop
      continue
5908 9a4f63d1 Iustin Pop
    logging.info("Creating volume %s for instance %s",
5909 9a4f63d1 Iustin Pop
                 device.iv_name, instance.name)
5910 a8083063 Iustin Pop
    #HARDCODE
5911 621b7678 Iustin Pop
    for node in all_nodes:
5912 428958aa Iustin Pop
      f_create = node == pnode
5913 428958aa Iustin Pop
      _CreateBlockDev(lu, node, instance, device, f_create, info, f_create)
5914 a8083063 Iustin Pop
5915 a8083063 Iustin Pop
5916 621b7678 Iustin Pop
def _RemoveDisks(lu, instance, target_node=None):
5917 a8083063 Iustin Pop
  """Remove all disks for an instance.
5918 a8083063 Iustin Pop

5919 a8083063 Iustin Pop
  This abstracts away some work from `AddInstance()` and
5920 a8083063 Iustin Pop
  `RemoveInstance()`. Note that in case some of the devices couldn't
5921 1d67656e Iustin Pop
  be removed, the removal will continue with the other ones (compare
5922 a8083063 Iustin Pop
  with `_CreateDisks()`).
5923 a8083063 Iustin Pop

5924 e4376078 Iustin Pop
  @type lu: L{LogicalUnit}
5925 e4376078 Iustin Pop
  @param lu: the logical unit on whose behalf we execute
5926 e4376078 Iustin Pop
  @type instance: L{objects.Instance}
5927 e4376078 Iustin Pop
  @param instance: the instance whose disks we should remove
5928 621b7678 Iustin Pop
  @type target_node: string
5929 621b7678 Iustin Pop
  @param target_node: used to override the node on which to remove the disks
5930 e4376078 Iustin Pop
  @rtype: boolean
5931 e4376078 Iustin Pop
  @return: the success of the removal
5932 a8083063 Iustin Pop

5933 a8083063 Iustin Pop
  """
5934 9a4f63d1 Iustin Pop
  logging.info("Removing block devices for instance %s", instance.name)
5935 a8083063 Iustin Pop
5936 e1bc0878 Iustin Pop
  all_result = True
5937 a8083063 Iustin Pop
  for device in instance.disks:
5938 621b7678 Iustin Pop
    if target_node:
5939 621b7678 Iustin Pop
      edata = [(target_node, device)]
5940 621b7678 Iustin Pop
    else:
5941 621b7678 Iustin Pop
      edata = device.ComputeNodeTree(instance.primary_node)
5942 621b7678 Iustin Pop
    for node, disk in edata:
5943 b9bddb6b Iustin Pop
      lu.cfg.SetDiskID(disk, node)
5944 4c4e4e1e Iustin Pop
      msg = lu.rpc.call_blockdev_remove(node, disk).fail_msg
5945 e1bc0878 Iustin Pop
      if msg:
5946 e1bc0878 Iustin Pop
        lu.LogWarning("Could not remove block device %s on node %s,"
5947 e1bc0878 Iustin Pop
                      " continuing anyway: %s", device.iv_name, node, msg)
5948 e1bc0878 Iustin Pop
        all_result = False
5949 0f1a06e3 Manuel Franceschini
5950 0f1a06e3 Manuel Franceschini
  if instance.disk_template == constants.DT_FILE:
5951 0f1a06e3 Manuel Franceschini
    file_storage_dir = os.path.dirname(instance.disks[0].logical_id[1])
5952 dfc2a24c Guido Trotter
    if target_node:
5953 dfc2a24c Guido Trotter
      tgt = target_node
5954 621b7678 Iustin Pop
    else:
5955 dfc2a24c Guido Trotter
      tgt = instance.primary_node
5956 621b7678 Iustin Pop
    result = lu.rpc.call_file_storage_dir_remove(tgt, file_storage_dir)
5957 621b7678 Iustin Pop
    if result.fail_msg:
5958 b2b8bcce Iustin Pop
      lu.LogWarning("Could not remove directory '%s' on node %s: %s",
5959 621b7678 Iustin Pop
                    file_storage_dir, instance.primary_node, result.fail_msg)
5960 e1bc0878 Iustin Pop
      all_result = False
5961 0f1a06e3 Manuel Franceschini
5962 e1bc0878 Iustin Pop
  return all_result
5963 a8083063 Iustin Pop
5964 a8083063 Iustin Pop
5965 08db7c5c Iustin Pop
def _ComputeDiskSize(disk_template, disks):
5966 e2fe6369 Iustin Pop
  """Compute disk size requirements in the volume group
5967 e2fe6369 Iustin Pop

5968 e2fe6369 Iustin Pop
  """
5969 e2fe6369 Iustin Pop
  # Required free disk space as a function of disk and swap space
5970 e2fe6369 Iustin Pop
  req_size_dict = {
5971 e2fe6369 Iustin Pop
    constants.DT_DISKLESS: None,
5972 08db7c5c Iustin Pop
    constants.DT_PLAIN: sum(d["size"] for d in disks),
5973 08db7c5c Iustin Pop
    # 128 MB are added for drbd metadata for each disk
5974 08db7c5c Iustin Pop
    constants.DT_DRBD8: sum(d["size"] + 128 for d in disks),
5975 e2fe6369 Iustin Pop
    constants.DT_FILE: None,
5976 e2fe6369 Iustin Pop
  }
5977 e2fe6369 Iustin Pop
5978 e2fe6369 Iustin Pop
  if disk_template not in req_size_dict:
5979 e2fe6369 Iustin Pop
    raise errors.ProgrammerError("Disk template '%s' size requirement"
5980 e2fe6369 Iustin Pop
                                 " is unknown" %  disk_template)
5981 e2fe6369 Iustin Pop
5982 e2fe6369 Iustin Pop
  return req_size_dict[disk_template]
5983 e2fe6369 Iustin Pop
5984 e2fe6369 Iustin Pop
5985 74409b12 Iustin Pop
def _CheckHVParams(lu, nodenames, hvname, hvparams):
5986 74409b12 Iustin Pop
  """Hypervisor parameter validation.
5987 74409b12 Iustin Pop

5988 74409b12 Iustin Pop
  This function abstract the hypervisor parameter validation to be
5989 74409b12 Iustin Pop
  used in both instance create and instance modify.
5990 74409b12 Iustin Pop

5991 74409b12 Iustin Pop
  @type lu: L{LogicalUnit}
5992 74409b12 Iustin Pop
  @param lu: the logical unit for which we check
5993 74409b12 Iustin Pop
  @type nodenames: list
5994 74409b12 Iustin Pop
  @param nodenames: the list of nodes on which we should check
5995 74409b12 Iustin Pop
  @type hvname: string
5996 74409b12 Iustin Pop
  @param hvname: the name of the hypervisor we should use
5997 74409b12 Iustin Pop
  @type hvparams: dict
5998 74409b12 Iustin Pop
  @param hvparams: the parameters which we need to check
5999 74409b12 Iustin Pop
  @raise errors.OpPrereqError: if the parameters are not valid
6000 74409b12 Iustin Pop

6001 74409b12 Iustin Pop
  """
6002 74409b12 Iustin Pop
  hvinfo = lu.rpc.call_hypervisor_validate_params(nodenames,
6003 74409b12 Iustin Pop
                                                  hvname,
6004 74409b12 Iustin Pop
                                                  hvparams)
6005 74409b12 Iustin Pop
  for node in nodenames:
6006 781de953 Iustin Pop
    info = hvinfo[node]
6007 68c6f21c Iustin Pop
    if info.offline:
6008 68c6f21c Iustin Pop
      continue
6009 4c4e4e1e Iustin Pop
    info.Raise("Hypervisor parameter validation failed on node %s" % node)
6010 74409b12 Iustin Pop
6011 74409b12 Iustin Pop
6012 a8083063 Iustin Pop
class LUCreateInstance(LogicalUnit):
6013 a8083063 Iustin Pop
  """Create an instance.
6014 a8083063 Iustin Pop

6015 a8083063 Iustin Pop
  """
6016 a8083063 Iustin Pop
  HPATH = "instance-add"
6017 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
6018 f276c4b5 Iustin Pop
  _OP_REQP = ["instance_name", "disks",
6019 08db7c5c Iustin Pop
              "mode", "start",
6020 08db7c5c Iustin Pop
              "wait_for_sync", "ip_check", "nics",
6021 338e51e8 Iustin Pop
              "hvparams", "beparams"]
6022 7baf741d Guido Trotter
  REQ_BGL = False
6023 7baf741d Guido Trotter
6024 5f23e043 Iustin Pop
  def CheckArguments(self):
6025 5f23e043 Iustin Pop
    """Check arguments.
6026 5f23e043 Iustin Pop

6027 5f23e043 Iustin Pop
    """
6028 df4272e5 Iustin Pop
    # set optional parameters to none if they don't exist
6029 f276c4b5 Iustin Pop
    for attr in ["pnode", "snode", "iallocator", "hypervisor",
6030 e588764d Iustin Pop
                 "disk_template", "identify_defaults"]:
6031 df4272e5 Iustin Pop
      if not hasattr(self.op, attr):
6032 df4272e5 Iustin Pop
        setattr(self.op, attr, None)
6033 df4272e5 Iustin Pop
6034 5f23e043 Iustin Pop
    # do not require name_check to ease forward/backward compatibility
6035 5f23e043 Iustin Pop
    # for tools
6036 5f23e043 Iustin Pop
    if not hasattr(self.op, "name_check"):
6037 5f23e043 Iustin Pop
      self.op.name_check = True
6038 25a8792c Iustin Pop
    if not hasattr(self.op, "no_install"):
6039 25a8792c Iustin Pop
      self.op.no_install = False
6040 25a8792c Iustin Pop
    if self.op.no_install and self.op.start:
6041 25a8792c Iustin Pop
      self.LogInfo("No-installation mode selected, disabling startup")
6042 25a8792c Iustin Pop
      self.op.start = False
6043 44caf5a8 Iustin Pop
    # validate/normalize the instance name
6044 44caf5a8 Iustin Pop
    self.op.instance_name = utils.HostInfo.NormalizeName(self.op.instance_name)
6045 5f23e043 Iustin Pop
    if self.op.ip_check and not self.op.name_check:
6046 5f23e043 Iustin Pop
      # TODO: make the ip check more flexible and not depend on the name check
6047 5f23e043 Iustin Pop
      raise errors.OpPrereqError("Cannot do ip checks without a name check",
6048 5f23e043 Iustin Pop
                                 errors.ECODE_INVAL)
6049 c3589cf8 Iustin Pop
    # check disk information: either all adopt, or no adopt
6050 c3589cf8 Iustin Pop
    has_adopt = has_no_adopt = False
6051 c3589cf8 Iustin Pop
    for disk in self.op.disks:
6052 c3589cf8 Iustin Pop
      if "adopt" in disk:
6053 c3589cf8 Iustin Pop
        has_adopt = True
6054 c3589cf8 Iustin Pop
      else:
6055 c3589cf8 Iustin Pop
        has_no_adopt = True
6056 c3589cf8 Iustin Pop
    if has_adopt and has_no_adopt:
6057 417eabe2 Iustin Pop
      raise errors.OpPrereqError("Either all disks are adopted or none is",
6058 c3589cf8 Iustin Pop
                                 errors.ECODE_INVAL)
6059 c3589cf8 Iustin Pop
    if has_adopt:
6060 c3589cf8 Iustin Pop
      if self.op.disk_template != constants.DT_PLAIN:
6061 c3589cf8 Iustin Pop
        raise errors.OpPrereqError("Disk adoption is only supported for the"
6062 c3589cf8 Iustin Pop
                                   " 'plain' disk template",
6063 c3589cf8 Iustin Pop
                                   errors.ECODE_INVAL)
6064 c3589cf8 Iustin Pop
      if self.op.iallocator is not None:
6065 c3589cf8 Iustin Pop
        raise errors.OpPrereqError("Disk adoption not allowed with an"
6066 c3589cf8 Iustin Pop
                                   " iallocator script", errors.ECODE_INVAL)
6067 c3589cf8 Iustin Pop
      if self.op.mode == constants.INSTANCE_IMPORT:
6068 c3589cf8 Iustin Pop
        raise errors.OpPrereqError("Disk adoption not allowed for"
6069 c3589cf8 Iustin Pop
                                   " instance import", errors.ECODE_INVAL)
6070 c3589cf8 Iustin Pop
6071 c3589cf8 Iustin Pop
    self.adopt_disks = has_adopt
6072 5f23e043 Iustin Pop
6073 417eabe2 Iustin Pop
    # verify creation mode
6074 417eabe2 Iustin Pop
    if self.op.mode not in (constants.INSTANCE_CREATE,
6075 417eabe2 Iustin Pop
                            constants.INSTANCE_IMPORT):
6076 417eabe2 Iustin Pop
      raise errors.OpPrereqError("Invalid instance creation mode '%s'" %
6077 417eabe2 Iustin Pop
                                 self.op.mode, errors.ECODE_INVAL)
6078 417eabe2 Iustin Pop
6079 417eabe2 Iustin Pop
    # instance name verification
6080 417eabe2 Iustin Pop
    if self.op.name_check:
6081 417eabe2 Iustin Pop
      self.hostname1 = utils.GetHostInfo(self.op.instance_name)
6082 417eabe2 Iustin Pop
      self.op.instance_name = self.hostname1.name
6083 417eabe2 Iustin Pop
      # used in CheckPrereq for ip ping check
6084 417eabe2 Iustin Pop
      self.check_ip = self.hostname1.ip
6085 417eabe2 Iustin Pop
    else:
6086 417eabe2 Iustin Pop
      self.check_ip = None
6087 417eabe2 Iustin Pop
6088 417eabe2 Iustin Pop
    # file storage checks
6089 417eabe2 Iustin Pop
    if (self.op.file_driver and
6090 417eabe2 Iustin Pop
        not self.op.file_driver in constants.FILE_DRIVER):
6091 417eabe2 Iustin Pop
      raise errors.OpPrereqError("Invalid file driver name '%s'" %
6092 417eabe2 Iustin Pop
                                 self.op.file_driver, errors.ECODE_INVAL)
6093 417eabe2 Iustin Pop
6094 417eabe2 Iustin Pop
    if self.op.file_storage_dir and os.path.isabs(self.op.file_storage_dir):
6095 417eabe2 Iustin Pop
      raise errors.OpPrereqError("File storage directory path not absolute",
6096 417eabe2 Iustin Pop
                                 errors.ECODE_INVAL)
6097 417eabe2 Iustin Pop
6098 417eabe2 Iustin Pop
    ### Node/iallocator related checks
6099 417eabe2 Iustin Pop
    if [self.op.iallocator, self.op.pnode].count(None) != 1:
6100 417eabe2 Iustin Pop
      raise errors.OpPrereqError("One and only one of iallocator and primary"
6101 417eabe2 Iustin Pop
                                 " node must be given",
6102 417eabe2 Iustin Pop
                                 errors.ECODE_INVAL)
6103 417eabe2 Iustin Pop
6104 417eabe2 Iustin Pop
    if self.op.mode == constants.INSTANCE_IMPORT:
6105 417eabe2 Iustin Pop
      # On import force_variant must be True, because if we forced it at
6106 417eabe2 Iustin Pop
      # initial install, our only chance when importing it back is that it
6107 417eabe2 Iustin Pop
      # works again!
6108 417eabe2 Iustin Pop
      self.op.force_variant = True
6109 417eabe2 Iustin Pop
6110 417eabe2 Iustin Pop
      if self.op.no_install:
6111 417eabe2 Iustin Pop
        self.LogInfo("No-installation mode has no effect during import")
6112 417eabe2 Iustin Pop
6113 417eabe2 Iustin Pop
    else: # INSTANCE_CREATE
6114 417eabe2 Iustin Pop
      if getattr(self.op, "os_type", None) is None:
6115 417eabe2 Iustin Pop
        raise errors.OpPrereqError("No guest OS specified",
6116 417eabe2 Iustin Pop
                                   errors.ECODE_INVAL)
6117 417eabe2 Iustin Pop
      self.op.force_variant = getattr(self.op, "force_variant", False)
6118 f276c4b5 Iustin Pop
      if self.op.disk_template is None:
6119 f276c4b5 Iustin Pop
        raise errors.OpPrereqError("No disk template specified",
6120 f276c4b5 Iustin Pop
                                   errors.ECODE_INVAL)
6121 417eabe2 Iustin Pop
6122 7baf741d Guido Trotter
  def ExpandNames(self):
6123 7baf741d Guido Trotter
    """ExpandNames for CreateInstance.
6124 7baf741d Guido Trotter

6125 7baf741d Guido Trotter
    Figure out the right locks for instance creation.
6126 7baf741d Guido Trotter

6127 7baf741d Guido Trotter
    """
6128 7baf741d Guido Trotter
    self.needed_locks = {}
6129 7baf741d Guido Trotter
6130 417eabe2 Iustin Pop
    instance_name = self.op.instance_name
6131 7baf741d Guido Trotter
    # this is just a preventive check, but someone might still add this
6132 7baf741d Guido Trotter
    # instance in the meantime, and creation will fail at lock-add time
6133 7baf741d Guido Trotter
    if instance_name in self.cfg.GetInstanceList():
6134 7baf741d Guido Trotter
      raise errors.OpPrereqError("Instance '%s' is already in the cluster" %
6135 5c983ee5 Iustin Pop
                                 instance_name, errors.ECODE_EXISTS)
6136 7baf741d Guido Trotter
6137 7baf741d Guido Trotter
    self.add_locks[locking.LEVEL_INSTANCE] = instance_name
6138 7baf741d Guido Trotter
6139 7baf741d Guido Trotter
    if self.op.iallocator:
6140 7baf741d Guido Trotter
      self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
6141 7baf741d Guido Trotter
    else:
6142 cf26a87a Iustin Pop
      self.op.pnode = _ExpandNodeName(self.cfg, self.op.pnode)
6143 7baf741d Guido Trotter
      nodelist = [self.op.pnode]
6144 7baf741d Guido Trotter
      if self.op.snode is not None:
6145 cf26a87a Iustin Pop
        self.op.snode = _ExpandNodeName(self.cfg, self.op.snode)
6146 7baf741d Guido Trotter
        nodelist.append(self.op.snode)
6147 7baf741d Guido Trotter
      self.needed_locks[locking.LEVEL_NODE] = nodelist
6148 7baf741d Guido Trotter
6149 7baf741d Guido Trotter
    # in case of import lock the source node too
6150 7baf741d Guido Trotter
    if self.op.mode == constants.INSTANCE_IMPORT:
6151 7baf741d Guido Trotter
      src_node = getattr(self.op, "src_node", None)
6152 7baf741d Guido Trotter
      src_path = getattr(self.op, "src_path", None)
6153 7baf741d Guido Trotter
6154 b9322a9f Guido Trotter
      if src_path is None:
6155 b9322a9f Guido Trotter
        self.op.src_path = src_path = self.op.instance_name
6156 b9322a9f Guido Trotter
6157 b9322a9f Guido Trotter
      if src_node is None:
6158 b9322a9f Guido Trotter
        self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
6159 b9322a9f Guido Trotter
        self.op.src_node = None
6160 b9322a9f Guido Trotter
        if os.path.isabs(src_path):
6161 b9322a9f Guido Trotter
          raise errors.OpPrereqError("Importing an instance from an absolute"
6162 5c983ee5 Iustin Pop
                                     " path requires a source node option.",
6163 5c983ee5 Iustin Pop
                                     errors.ECODE_INVAL)
6164 b9322a9f Guido Trotter
      else:
6165 cf26a87a Iustin Pop
        self.op.src_node = src_node = _ExpandNodeName(self.cfg, src_node)
6166 b9322a9f Guido Trotter
        if self.needed_locks[locking.LEVEL_NODE] is not locking.ALL_SET:
6167 b9322a9f Guido Trotter
          self.needed_locks[locking.LEVEL_NODE].append(src_node)
6168 b9322a9f Guido Trotter
        if not os.path.isabs(src_path):
6169 b9322a9f Guido Trotter
          self.op.src_path = src_path = \
6170 c4feafe8 Iustin Pop
            utils.PathJoin(constants.EXPORT_DIR, src_path)
6171 7baf741d Guido Trotter
6172 538475ca Iustin Pop
  def _RunAllocator(self):
6173 538475ca Iustin Pop
    """Run the allocator based on input opcode.
6174 538475ca Iustin Pop

6175 538475ca Iustin Pop
    """
6176 08db7c5c Iustin Pop
    nics = [n.ToDict() for n in self.nics]
6177 923ddac0 Michael Hanselmann
    ial = IAllocator(self.cfg, self.rpc,
6178 29859cb7 Iustin Pop
                     mode=constants.IALLOCATOR_MODE_ALLOC,
6179 d1c2dd75 Iustin Pop
                     name=self.op.instance_name,
6180 d1c2dd75 Iustin Pop
                     disk_template=self.op.disk_template,
6181 d1c2dd75 Iustin Pop
                     tags=[],
6182 d1c2dd75 Iustin Pop
                     os=self.op.os_type,
6183 338e51e8 Iustin Pop
                     vcpus=self.be_full[constants.BE_VCPUS],
6184 338e51e8 Iustin Pop
                     mem_size=self.be_full[constants.BE_MEMORY],
6185 08db7c5c Iustin Pop
                     disks=self.disks,
6186 d1c2dd75 Iustin Pop
                     nics=nics,
6187 8cc7e742 Guido Trotter
                     hypervisor=self.op.hypervisor,
6188 29859cb7 Iustin Pop
                     )
6189 d1c2dd75 Iustin Pop
6190 d1c2dd75 Iustin Pop
    ial.Run(self.op.iallocator)
6191 d1c2dd75 Iustin Pop
6192 d1c2dd75 Iustin Pop
    if not ial.success:
6193 538475ca Iustin Pop
      raise errors.OpPrereqError("Can't compute nodes using"
6194 5c983ee5 Iustin Pop
                                 " iallocator '%s': %s" %
6195 5c983ee5 Iustin Pop
                                 (self.op.iallocator, ial.info),
6196 5c983ee5 Iustin Pop
                                 errors.ECODE_NORES)
6197 680f0a89 Iustin Pop
    if len(ial.result) != ial.required_nodes:
6198 538475ca Iustin Pop
      raise errors.OpPrereqError("iallocator '%s' returned invalid number"
6199 538475ca Iustin Pop
                                 " of nodes (%s), required %s" %
6200 680f0a89 Iustin Pop
                                 (self.op.iallocator, len(ial.result),
6201 5c983ee5 Iustin Pop
                                  ial.required_nodes), errors.ECODE_FAULT)
6202 680f0a89 Iustin Pop
    self.op.pnode = ial.result[0]
6203 86d9d3bb Iustin Pop
    self.LogInfo("Selected nodes for instance %s via iallocator %s: %s",
6204 86d9d3bb Iustin Pop
                 self.op.instance_name, self.op.iallocator,
6205 680f0a89 Iustin Pop
                 utils.CommaJoin(ial.result))
6206 27579978 Iustin Pop
    if ial.required_nodes == 2:
6207 680f0a89 Iustin Pop
      self.op.snode = ial.result[1]
6208 538475ca Iustin Pop
6209 a8083063 Iustin Pop
  def BuildHooksEnv(self):
6210 a8083063 Iustin Pop
    """Build hooks env.
6211 a8083063 Iustin Pop

6212 a8083063 Iustin Pop
    This runs on master, primary and secondary nodes of the instance.
6213 a8083063 Iustin Pop

6214 a8083063 Iustin Pop
    """
6215 a8083063 Iustin Pop
    env = {
6216 2c2690c9 Iustin Pop
      "ADD_MODE": self.op.mode,
6217 a8083063 Iustin Pop
      }
6218 a8083063 Iustin Pop
    if self.op.mode == constants.INSTANCE_IMPORT:
6219 2c2690c9 Iustin Pop
      env["SRC_NODE"] = self.op.src_node
6220 2c2690c9 Iustin Pop
      env["SRC_PATH"] = self.op.src_path
6221 2c2690c9 Iustin Pop
      env["SRC_IMAGES"] = self.src_images
6222 396e1b78 Michael Hanselmann
6223 2c2690c9 Iustin Pop
    env.update(_BuildInstanceHookEnv(
6224 2c2690c9 Iustin Pop
      name=self.op.instance_name,
6225 396e1b78 Michael Hanselmann
      primary_node=self.op.pnode,
6226 396e1b78 Michael Hanselmann
      secondary_nodes=self.secondaries,
6227 4978db17 Iustin Pop
      status=self.op.start,
6228 ecb215b5 Michael Hanselmann
      os_type=self.op.os_type,
6229 338e51e8 Iustin Pop
      memory=self.be_full[constants.BE_MEMORY],
6230 338e51e8 Iustin Pop
      vcpus=self.be_full[constants.BE_VCPUS],
6231 f9b10246 Guido Trotter
      nics=_NICListToTuple(self, self.nics),
6232 2c2690c9 Iustin Pop
      disk_template=self.op.disk_template,
6233 2c2690c9 Iustin Pop
      disks=[(d["size"], d["mode"]) for d in self.disks],
6234 67fc3042 Iustin Pop
      bep=self.be_full,
6235 67fc3042 Iustin Pop
      hvp=self.hv_full,
6236 3df6e710 Iustin Pop
      hypervisor_name=self.op.hypervisor,
6237 396e1b78 Michael Hanselmann
    ))
6238 a8083063 Iustin Pop
6239 d6a02168 Michael Hanselmann
    nl = ([self.cfg.GetMasterNode(), self.op.pnode] +
6240 a8083063 Iustin Pop
          self.secondaries)
6241 a8083063 Iustin Pop
    return env, nl, nl
6242 a8083063 Iustin Pop
6243 c1c31426 Iustin Pop
  def _ReadExportInfo(self):
6244 c1c31426 Iustin Pop
    """Reads the export information from disk.
6245 c1c31426 Iustin Pop

6246 c1c31426 Iustin Pop
    It will override the opcode source node and path with the actual
6247 c1c31426 Iustin Pop
    information, if these two were not specified before.
6248 c1c31426 Iustin Pop

6249 c1c31426 Iustin Pop
    @return: the export information
6250 c1c31426 Iustin Pop

6251 c1c31426 Iustin Pop
    """
6252 c1c31426 Iustin Pop
    assert self.op.mode == constants.INSTANCE_IMPORT
6253 c1c31426 Iustin Pop
6254 c1c31426 Iustin Pop
    src_node = self.op.src_node
6255 c1c31426 Iustin Pop
    src_path = self.op.src_path
6256 c1c31426 Iustin Pop
6257 c1c31426 Iustin Pop
    if src_node is None:
6258 c1c31426 Iustin Pop
      locked_nodes = self.acquired_locks[locking.LEVEL_NODE]
6259 c1c31426 Iustin Pop
      exp_list = self.rpc.call_export_list(locked_nodes)
6260 c1c31426 Iustin Pop
      found = False
6261 c1c31426 Iustin Pop
      for node in exp_list:
6262 c1c31426 Iustin Pop
        if exp_list[node].fail_msg:
6263 c1c31426 Iustin Pop
          continue
6264 c1c31426 Iustin Pop
        if src_path in exp_list[node].payload:
6265 c1c31426 Iustin Pop
          found = True
6266 c1c31426 Iustin Pop
          self.op.src_node = src_node = node
6267 c1c31426 Iustin Pop
          self.op.src_path = src_path = utils.PathJoin(constants.EXPORT_DIR,
6268 c1c31426 Iustin Pop
                                                       src_path)
6269 c1c31426 Iustin Pop
          break
6270 c1c31426 Iustin Pop
      if not found:
6271 c1c31426 Iustin Pop
        raise errors.OpPrereqError("No export found for relative path %s" %
6272 c1c31426 Iustin Pop
                                    src_path, errors.ECODE_INVAL)
6273 c1c31426 Iustin Pop
6274 c1c31426 Iustin Pop
    _CheckNodeOnline(self, src_node)
6275 c1c31426 Iustin Pop
    result = self.rpc.call_export_info(src_node, src_path)
6276 c1c31426 Iustin Pop
    result.Raise("No export or invalid export found in dir %s" % src_path)
6277 c1c31426 Iustin Pop
6278 c1c31426 Iustin Pop
    export_info = objects.SerializableConfigParser.Loads(str(result.payload))
6279 c1c31426 Iustin Pop
    if not export_info.has_section(constants.INISECT_EXP):
6280 c1c31426 Iustin Pop
      raise errors.ProgrammerError("Corrupted export config",
6281 c1c31426 Iustin Pop
                                   errors.ECODE_ENVIRON)
6282 c1c31426 Iustin Pop
6283 c1c31426 Iustin Pop
    ei_version = export_info.get(constants.INISECT_EXP, "version")
6284 c1c31426 Iustin Pop
    if (int(ei_version) != constants.EXPORT_VERSION):
6285 c1c31426 Iustin Pop
      raise errors.OpPrereqError("Wrong export version %s (wanted %d)" %
6286 c1c31426 Iustin Pop
                                 (ei_version, constants.EXPORT_VERSION),
6287 c1c31426 Iustin Pop
                                 errors.ECODE_ENVIRON)
6288 c1c31426 Iustin Pop
    return export_info
6289 a8083063 Iustin Pop
6290 f276c4b5 Iustin Pop
  def _ReadExportParams(self, einfo):
6291 f276c4b5 Iustin Pop
    """Use export parameters as defaults.
6292 f276c4b5 Iustin Pop

6293 f276c4b5 Iustin Pop
    In case the opcode doesn't specify (as in override) some instance
6294 f276c4b5 Iustin Pop
    parameters, then try to use them from the export information, if
6295 f276c4b5 Iustin Pop
    that declares them.
6296 f276c4b5 Iustin Pop

6297 f276c4b5 Iustin Pop
    """
6298 b6cd72b2 Iustin Pop
    self.op.os_type = einfo.get(constants.INISECT_EXP, "os")
6299 b6cd72b2 Iustin Pop
6300 f276c4b5 Iustin Pop
    if self.op.disk_template is None:
6301 f276c4b5 Iustin Pop
      if einfo.has_option(constants.INISECT_INS, "disk_template"):
6302 f276c4b5 Iustin Pop
        self.op.disk_template = einfo.get(constants.INISECT_INS,
6303 f276c4b5 Iustin Pop
                                          "disk_template")
6304 f276c4b5 Iustin Pop
      else:
6305 f276c4b5 Iustin Pop
        raise errors.OpPrereqError("No disk template specified and the export"
6306 f276c4b5 Iustin Pop
                                   " is missing the disk_template information",
6307 f276c4b5 Iustin Pop
                                   errors.ECODE_INVAL)
6308 f276c4b5 Iustin Pop
6309 9b12ed0f Iustin Pop
    if not self.op.disks:
6310 9b12ed0f Iustin Pop
      if einfo.has_option(constants.INISECT_INS, "disk_count"):
6311 9b12ed0f Iustin Pop
        disks = []
6312 9b12ed0f Iustin Pop
        # TODO: import the disk iv_name too
6313 9b12ed0f Iustin Pop
        for idx in range(einfo.getint(constants.INISECT_INS, "disk_count")):
6314 9b12ed0f Iustin Pop
          disk_sz = einfo.getint(constants.INISECT_INS, "disk%d_size" % idx)
6315 9b12ed0f Iustin Pop
          disks.append({"size": disk_sz})
6316 9b12ed0f Iustin Pop
        self.op.disks = disks
6317 9b12ed0f Iustin Pop
      else:
6318 9b12ed0f Iustin Pop
        raise errors.OpPrereqError("No disk info specified and the export"
6319 9b12ed0f Iustin Pop
                                   " is missing the disk information",
6320 9b12ed0f Iustin Pop
                                   errors.ECODE_INVAL)
6321 9b12ed0f Iustin Pop
6322 0af0f641 Iustin Pop
    if (not self.op.nics and
6323 0af0f641 Iustin Pop
        einfo.has_option(constants.INISECT_INS, "nic_count")):
6324 0af0f641 Iustin Pop
      nics = []
6325 0af0f641 Iustin Pop
      for idx in range(einfo.getint(constants.INISECT_INS, "nic_count")):
6326 0af0f641 Iustin Pop
        ndict = {}
6327 0af0f641 Iustin Pop
        for name in list(constants.NICS_PARAMETERS) + ["ip", "mac"]:
6328 0af0f641 Iustin Pop
          v = einfo.get(constants.INISECT_INS, "nic%d_%s" % (idx, name))
6329 0af0f641 Iustin Pop
          ndict[name] = v
6330 0af0f641 Iustin Pop
        nics.append(ndict)
6331 0af0f641 Iustin Pop
      self.op.nics = nics
6332 0af0f641 Iustin Pop
6333 9f88b0e8 Iustin Pop
    if (self.op.hypervisor is None and
6334 9f88b0e8 Iustin Pop
        einfo.has_option(constants.INISECT_INS, "hypervisor")):
6335 9f88b0e8 Iustin Pop
      self.op.hypervisor = einfo.get(constants.INISECT_INS, "hypervisor")
6336 9f88b0e8 Iustin Pop
    if einfo.has_section(constants.INISECT_HYP):
6337 9f88b0e8 Iustin Pop
      # use the export parameters but do not override the ones
6338 9f88b0e8 Iustin Pop
      # specified by the user
6339 9f88b0e8 Iustin Pop
      for name, value in einfo.items(constants.INISECT_HYP):
6340 9f88b0e8 Iustin Pop
        if name not in self.op.hvparams:
6341 9f88b0e8 Iustin Pop
          self.op.hvparams[name] = value
6342 9f88b0e8 Iustin Pop
6343 cc0d88e9 Iustin Pop
    if einfo.has_section(constants.INISECT_BEP):
6344 cc0d88e9 Iustin Pop
      # use the parameters, without overriding
6345 cc0d88e9 Iustin Pop
      for name, value in einfo.items(constants.INISECT_BEP):
6346 cc0d88e9 Iustin Pop
        if name not in self.op.beparams:
6347 cc0d88e9 Iustin Pop
          self.op.beparams[name] = value
6348 cc0d88e9 Iustin Pop
    else:
6349 cc0d88e9 Iustin Pop
      # try to read the parameters old style, from the main section
6350 cc0d88e9 Iustin Pop
      for name in constants.BES_PARAMETERS:
6351 cc0d88e9 Iustin Pop
        if (name not in self.op.beparams and
6352 cc0d88e9 Iustin Pop
            einfo.has_option(constants.INISECT_INS, name)):
6353 cc0d88e9 Iustin Pop
          self.op.beparams[name] = einfo.get(constants.INISECT_INS, name)
6354 cc0d88e9 Iustin Pop
6355 e588764d Iustin Pop
  def _RevertToDefaults(self, cluster):
6356 e588764d Iustin Pop
    """Revert the instance parameters to the default values.
6357 e588764d Iustin Pop

6358 e588764d Iustin Pop
    """
6359 e588764d Iustin Pop
    # hvparams
6360 e588764d Iustin Pop
    hv_defs = cluster.GetHVDefaults(self.op.hypervisor, self.op.os_type)
6361 e588764d Iustin Pop
    for name in self.op.hvparams.keys():
6362 e588764d Iustin Pop
      if name in hv_defs and hv_defs[name] == self.op.hvparams[name]:
6363 e588764d Iustin Pop
        del self.op.hvparams[name]
6364 e588764d Iustin Pop
    # beparams
6365 e588764d Iustin Pop
    be_defs = cluster.beparams.get(constants.PP_DEFAULT, {})
6366 e588764d Iustin Pop
    for name in self.op.beparams.keys():
6367 e588764d Iustin Pop
      if name in be_defs and be_defs[name] == self.op.beparams[name]:
6368 e588764d Iustin Pop
        del self.op.beparams[name]
6369 e588764d Iustin Pop
    # nic params
6370 e588764d Iustin Pop
    nic_defs = cluster.nicparams.get(constants.PP_DEFAULT, {})
6371 e588764d Iustin Pop
    for nic in self.op.nics:
6372 e588764d Iustin Pop
      for name in constants.NICS_PARAMETERS:
6373 e588764d Iustin Pop
        if name in nic and name in nic_defs and nic[name] == nic_defs[name]:
6374 e588764d Iustin Pop
          del nic[name]
6375 e588764d Iustin Pop
6376 a8083063 Iustin Pop
  def CheckPrereq(self):
6377 a8083063 Iustin Pop
    """Check prerequisites.
6378 a8083063 Iustin Pop

6379 a8083063 Iustin Pop
    """
6380 c1c31426 Iustin Pop
    if self.op.mode == constants.INSTANCE_IMPORT:
6381 c1c31426 Iustin Pop
      export_info = self._ReadExportInfo()
6382 f276c4b5 Iustin Pop
      self._ReadExportParams(export_info)
6383 f276c4b5 Iustin Pop
6384 f276c4b5 Iustin Pop
    _CheckDiskTemplate(self.op.disk_template)
6385 c1c31426 Iustin Pop
6386 eedc99de Manuel Franceschini
    if (not self.cfg.GetVGName() and
6387 eedc99de Manuel Franceschini
        self.op.disk_template not in constants.DTS_NOT_LVM):
6388 eedc99de Manuel Franceschini
      raise errors.OpPrereqError("Cluster does not support lvm-based"
6389 5c983ee5 Iustin Pop
                                 " instances", errors.ECODE_STATE)
6390 eedc99de Manuel Franceschini
6391 22f50b1d Iustin Pop
    if self.op.hypervisor is None:
6392 22f50b1d Iustin Pop
      self.op.hypervisor = self.cfg.GetHypervisorType()
6393 22f50b1d Iustin Pop
6394 22f50b1d Iustin Pop
    cluster = self.cfg.GetClusterInfo()
6395 22f50b1d Iustin Pop
    enabled_hvs = cluster.enabled_hypervisors
6396 22f50b1d Iustin Pop
    if self.op.hypervisor not in enabled_hvs:
6397 22f50b1d Iustin Pop
      raise errors.OpPrereqError("Selected hypervisor (%s) not enabled in the"
6398 22f50b1d Iustin Pop
                                 " cluster (%s)" % (self.op.hypervisor,
6399 22f50b1d Iustin Pop
                                  ",".join(enabled_hvs)),
6400 22f50b1d Iustin Pop
                                 errors.ECODE_STATE)
6401 22f50b1d Iustin Pop
6402 22f50b1d Iustin Pop
    # check hypervisor parameter syntax (locally)
6403 22f50b1d Iustin Pop
    utils.ForceDictType(self.op.hvparams, constants.HVS_PARAMETER_TYPES)
6404 b6cd72b2 Iustin Pop
    filled_hvp = objects.FillDict(cluster.GetHVDefaults(self.op.hypervisor,
6405 b6cd72b2 Iustin Pop
                                                        self.op.os_type),
6406 22f50b1d Iustin Pop
                                  self.op.hvparams)
6407 22f50b1d Iustin Pop
    hv_type = hypervisor.GetHypervisor(self.op.hypervisor)
6408 22f50b1d Iustin Pop
    hv_type.CheckParameterSyntax(filled_hvp)
6409 22f50b1d Iustin Pop
    self.hv_full = filled_hvp
6410 22f50b1d Iustin Pop
    # check that we don't specify global parameters on an instance
6411 22f50b1d Iustin Pop
    _CheckGlobalHvParams(self.op.hvparams)
6412 22f50b1d Iustin Pop
6413 22f50b1d Iustin Pop
    # fill and remember the beparams dict
6414 22f50b1d Iustin Pop
    utils.ForceDictType(self.op.beparams, constants.BES_PARAMETER_TYPES)
6415 22f50b1d Iustin Pop
    self.be_full = objects.FillDict(cluster.beparams[constants.PP_DEFAULT],
6416 22f50b1d Iustin Pop
                                    self.op.beparams)
6417 22f50b1d Iustin Pop
6418 e588764d Iustin Pop
    # now that hvp/bep are in final format, let's reset to defaults,
6419 e588764d Iustin Pop
    # if told to do so
6420 e588764d Iustin Pop
    if self.op.identify_defaults:
6421 e588764d Iustin Pop
      self._RevertToDefaults(cluster)
6422 e588764d Iustin Pop
6423 22f50b1d Iustin Pop
    # NIC buildup
6424 22f50b1d Iustin Pop
    self.nics = []
6425 22f50b1d Iustin Pop
    for idx, nic in enumerate(self.op.nics):
6426 22f50b1d Iustin Pop
      nic_mode_req = nic.get("mode", None)
6427 22f50b1d Iustin Pop
      nic_mode = nic_mode_req
6428 22f50b1d Iustin Pop
      if nic_mode is None:
6429 22f50b1d Iustin Pop
        nic_mode = cluster.nicparams[constants.PP_DEFAULT][constants.NIC_MODE]
6430 22f50b1d Iustin Pop
6431 22f50b1d Iustin Pop
      # in routed mode, for the first nic, the default ip is 'auto'
6432 22f50b1d Iustin Pop
      if nic_mode == constants.NIC_MODE_ROUTED and idx == 0:
6433 22f50b1d Iustin Pop
        default_ip_mode = constants.VALUE_AUTO
6434 22f50b1d Iustin Pop
      else:
6435 22f50b1d Iustin Pop
        default_ip_mode = constants.VALUE_NONE
6436 22f50b1d Iustin Pop
6437 22f50b1d Iustin Pop
      # ip validity checks
6438 22f50b1d Iustin Pop
      ip = nic.get("ip", default_ip_mode)
6439 22f50b1d Iustin Pop
      if ip is None or ip.lower() == constants.VALUE_NONE:
6440 22f50b1d Iustin Pop
        nic_ip = None
6441 22f50b1d Iustin Pop
      elif ip.lower() == constants.VALUE_AUTO:
6442 22f50b1d Iustin Pop
        if not self.op.name_check:
6443 22f50b1d Iustin Pop
          raise errors.OpPrereqError("IP address set to auto but name checks"
6444 22f50b1d Iustin Pop
                                     " have been skipped. Aborting.",
6445 22f50b1d Iustin Pop
                                     errors.ECODE_INVAL)
6446 22f50b1d Iustin Pop
        nic_ip = self.hostname1.ip
6447 22f50b1d Iustin Pop
      else:
6448 22f50b1d Iustin Pop
        if not utils.IsValidIP(ip):
6449 22f50b1d Iustin Pop
          raise errors.OpPrereqError("Given IP address '%s' doesn't look"
6450 22f50b1d Iustin Pop
                                     " like a valid IP" % ip,
6451 22f50b1d Iustin Pop
                                     errors.ECODE_INVAL)
6452 22f50b1d Iustin Pop
        nic_ip = ip
6453 22f50b1d Iustin Pop
6454 22f50b1d Iustin Pop
      # TODO: check the ip address for uniqueness
6455 22f50b1d Iustin Pop
      if nic_mode == constants.NIC_MODE_ROUTED and not nic_ip:
6456 22f50b1d Iustin Pop
        raise errors.OpPrereqError("Routed nic mode requires an ip address",
6457 22f50b1d Iustin Pop
                                   errors.ECODE_INVAL)
6458 22f50b1d Iustin Pop
6459 22f50b1d Iustin Pop
      # MAC address verification
6460 22f50b1d Iustin Pop
      mac = nic.get("mac", constants.VALUE_AUTO)
6461 22f50b1d Iustin Pop
      if mac not in (constants.VALUE_AUTO, constants.VALUE_GENERATE):
6462 22f50b1d Iustin Pop
        mac = utils.NormalizeAndValidateMac(mac)
6463 22f50b1d Iustin Pop
6464 22f50b1d Iustin Pop
        try:
6465 22f50b1d Iustin Pop
          self.cfg.ReserveMAC(mac, self.proc.GetECId())
6466 22f50b1d Iustin Pop
        except errors.ReservationError:
6467 22f50b1d Iustin Pop
          raise errors.OpPrereqError("MAC address %s already in use"
6468 22f50b1d Iustin Pop
                                     " in cluster" % mac,
6469 22f50b1d Iustin Pop
                                     errors.ECODE_NOTUNIQUE)
6470 22f50b1d Iustin Pop
6471 22f50b1d Iustin Pop
      # bridge verification
6472 22f50b1d Iustin Pop
      bridge = nic.get("bridge", None)
6473 22f50b1d Iustin Pop
      link = nic.get("link", None)
6474 22f50b1d Iustin Pop
      if bridge and link:
6475 22f50b1d Iustin Pop
        raise errors.OpPrereqError("Cannot pass 'bridge' and 'link'"
6476 22f50b1d Iustin Pop
                                   " at the same time", errors.ECODE_INVAL)
6477 22f50b1d Iustin Pop
      elif bridge and nic_mode == constants.NIC_MODE_ROUTED:
6478 22f50b1d Iustin Pop
        raise errors.OpPrereqError("Cannot pass 'bridge' on a routed nic",
6479 22f50b1d Iustin Pop
                                   errors.ECODE_INVAL)
6480 22f50b1d Iustin Pop
      elif bridge:
6481 22f50b1d Iustin Pop
        link = bridge
6482 22f50b1d Iustin Pop
6483 22f50b1d Iustin Pop
      nicparams = {}
6484 22f50b1d Iustin Pop
      if nic_mode_req:
6485 22f50b1d Iustin Pop
        nicparams[constants.NIC_MODE] = nic_mode_req
6486 22f50b1d Iustin Pop
      if link:
6487 22f50b1d Iustin Pop
        nicparams[constants.NIC_LINK] = link
6488 22f50b1d Iustin Pop
6489 22f50b1d Iustin Pop
      check_params = objects.FillDict(cluster.nicparams[constants.PP_DEFAULT],
6490 22f50b1d Iustin Pop
                                      nicparams)
6491 22f50b1d Iustin Pop
      objects.NIC.CheckParameterSyntax(check_params)
6492 22f50b1d Iustin Pop
      self.nics.append(objects.NIC(mac=mac, ip=nic_ip, nicparams=nicparams))
6493 22f50b1d Iustin Pop
6494 22f50b1d Iustin Pop
    # disk checks/pre-build
6495 22f50b1d Iustin Pop
    self.disks = []
6496 22f50b1d Iustin Pop
    for disk in self.op.disks:
6497 22f50b1d Iustin Pop
      mode = disk.get("mode", constants.DISK_RDWR)
6498 22f50b1d Iustin Pop
      if mode not in constants.DISK_ACCESS_SET:
6499 22f50b1d Iustin Pop
        raise errors.OpPrereqError("Invalid disk access mode '%s'" %
6500 22f50b1d Iustin Pop
                                   mode, errors.ECODE_INVAL)
6501 22f50b1d Iustin Pop
      size = disk.get("size", None)
6502 22f50b1d Iustin Pop
      if size is None:
6503 22f50b1d Iustin Pop
        raise errors.OpPrereqError("Missing disk size", errors.ECODE_INVAL)
6504 22f50b1d Iustin Pop
      try:
6505 22f50b1d Iustin Pop
        size = int(size)
6506 22f50b1d Iustin Pop
      except (TypeError, ValueError):
6507 22f50b1d Iustin Pop
        raise errors.OpPrereqError("Invalid disk size '%s'" % size,
6508 22f50b1d Iustin Pop
                                   errors.ECODE_INVAL)
6509 22f50b1d Iustin Pop
      new_disk = {"size": size, "mode": mode}
6510 22f50b1d Iustin Pop
      if "adopt" in disk:
6511 22f50b1d Iustin Pop
        new_disk["adopt"] = disk["adopt"]
6512 22f50b1d Iustin Pop
      self.disks.append(new_disk)
6513 22f50b1d Iustin Pop
6514 a8083063 Iustin Pop
    if self.op.mode == constants.INSTANCE_IMPORT:
6515 a8083063 Iustin Pop
6516 09acf207 Guido Trotter
      # Check that the new instance doesn't have less disks than the export
6517 08db7c5c Iustin Pop
      instance_disks = len(self.disks)
6518 09acf207 Guido Trotter
      export_disks = export_info.getint(constants.INISECT_INS, 'disk_count')
6519 09acf207 Guido Trotter
      if instance_disks < export_disks:
6520 09acf207 Guido Trotter
        raise errors.OpPrereqError("Not enough disks to import."
6521 09acf207 Guido Trotter
                                   " (instance: %d, export: %d)" %
6522 5c983ee5 Iustin Pop
                                   (instance_disks, export_disks),
6523 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
6524 a8083063 Iustin Pop
6525 09acf207 Guido Trotter
      disk_images = []
6526 09acf207 Guido Trotter
      for idx in range(export_disks):
6527 09acf207 Guido Trotter
        option = 'disk%d_dump' % idx
6528 09acf207 Guido Trotter
        if export_info.has_option(constants.INISECT_INS, option):
6529 09acf207 Guido Trotter
          # FIXME: are the old os-es, disk sizes, etc. useful?
6530 09acf207 Guido Trotter
          export_name = export_info.get(constants.INISECT_INS, option)
6531 c1c31426 Iustin Pop
          image = utils.PathJoin(self.op.src_path, export_name)
6532 09acf207 Guido Trotter
          disk_images.append(image)
6533 09acf207 Guido Trotter
        else:
6534 09acf207 Guido Trotter
          disk_images.append(False)
6535 09acf207 Guido Trotter
6536 09acf207 Guido Trotter
      self.src_images = disk_images
6537 901a65c1 Iustin Pop
6538 b4364a6b Guido Trotter
      old_name = export_info.get(constants.INISECT_INS, 'name')
6539 2a518543 Iustin Pop
      try:
6540 2a518543 Iustin Pop
        exp_nic_count = export_info.getint(constants.INISECT_INS, 'nic_count')
6541 2a518543 Iustin Pop
      except (TypeError, ValueError), err:
6542 2a518543 Iustin Pop
        raise errors.OpPrereqError("Invalid export file, nic_count is not"
6543 2a518543 Iustin Pop
                                   " an integer: %s" % str(err),
6544 2a518543 Iustin Pop
                                   errors.ECODE_STATE)
6545 b4364a6b Guido Trotter
      if self.op.instance_name == old_name:
6546 b4364a6b Guido Trotter
        for idx, nic in enumerate(self.nics):
6547 b4364a6b Guido Trotter
          if nic.mac == constants.VALUE_AUTO and exp_nic_count >= idx:
6548 b4364a6b Guido Trotter
            nic_mac_ini = 'nic%d_mac' % idx
6549 b4364a6b Guido Trotter
            nic.mac = export_info.get(constants.INISECT_INS, nic_mac_ini)
6550 bc89efc3 Guido Trotter
6551 295728df Guido Trotter
    # ENDIF: self.op.mode == constants.INSTANCE_IMPORT
6552 901a65c1 Iustin Pop
6553 18c8f361 Iustin Pop
    # ip ping checks (we use the same ip that was resolved in ExpandNames)
6554 901a65c1 Iustin Pop
    if self.op.ip_check:
6555 7baf741d Guido Trotter
      if utils.TcpPing(self.check_ip, constants.DEFAULT_NODED_PORT):
6556 901a65c1 Iustin Pop
        raise errors.OpPrereqError("IP %s of instance %s already in use" %
6557 5c983ee5 Iustin Pop
                                   (self.check_ip, self.op.instance_name),
6558 5c983ee5 Iustin Pop
                                   errors.ECODE_NOTUNIQUE)
6559 901a65c1 Iustin Pop
6560 295728df Guido Trotter
    #### mac address generation
6561 295728df Guido Trotter
    # By generating here the mac address both the allocator and the hooks get
6562 295728df Guido Trotter
    # the real final mac address rather than the 'auto' or 'generate' value.
6563 295728df Guido Trotter
    # There is a race condition between the generation and the instance object
6564 295728df Guido Trotter
    # creation, which means that we know the mac is valid now, but we're not
6565 295728df Guido Trotter
    # sure it will be when we actually add the instance. If things go bad
6566 295728df Guido Trotter
    # adding the instance will abort because of a duplicate mac, and the
6567 295728df Guido Trotter
    # creation job will fail.
6568 295728df Guido Trotter
    for nic in self.nics:
6569 295728df Guido Trotter
      if nic.mac in (constants.VALUE_AUTO, constants.VALUE_GENERATE):
6570 36b66e6e Guido Trotter
        nic.mac = self.cfg.GenerateMAC(self.proc.GetECId())
6571 295728df Guido Trotter
6572 538475ca Iustin Pop
    #### allocator run
6573 538475ca Iustin Pop
6574 538475ca Iustin Pop
    if self.op.iallocator is not None:
6575 538475ca Iustin Pop
      self._RunAllocator()
6576 0f1a06e3 Manuel Franceschini
6577 901a65c1 Iustin Pop
    #### node related checks
6578 901a65c1 Iustin Pop
6579 901a65c1 Iustin Pop
    # check primary node
6580 7baf741d Guido Trotter
    self.pnode = pnode = self.cfg.GetNodeInfo(self.op.pnode)
6581 7baf741d Guido Trotter
    assert self.pnode is not None, \
6582 7baf741d Guido Trotter
      "Cannot retrieve locked node %s" % self.op.pnode
6583 7527a8a4 Iustin Pop
    if pnode.offline:
6584 7527a8a4 Iustin Pop
      raise errors.OpPrereqError("Cannot use offline primary node '%s'" %
6585 5c983ee5 Iustin Pop
                                 pnode.name, errors.ECODE_STATE)
6586 733a2b6a Iustin Pop
    if pnode.drained:
6587 733a2b6a Iustin Pop
      raise errors.OpPrereqError("Cannot use drained primary node '%s'" %
6588 5c983ee5 Iustin Pop
                                 pnode.name, errors.ECODE_STATE)
6589 7527a8a4 Iustin Pop
6590 901a65c1 Iustin Pop
    self.secondaries = []
6591 901a65c1 Iustin Pop
6592 901a65c1 Iustin Pop
    # mirror node verification
6593 a1f445d3 Iustin Pop
    if self.op.disk_template in constants.DTS_NET_MIRROR:
6594 7baf741d Guido Trotter
      if self.op.snode is None:
6595 a1f445d3 Iustin Pop
        raise errors.OpPrereqError("The networked disk templates need"
6596 5c983ee5 Iustin Pop
                                   " a mirror node", errors.ECODE_INVAL)
6597 7baf741d Guido Trotter
      if self.op.snode == pnode.name:
6598 5c983ee5 Iustin Pop
        raise errors.OpPrereqError("The secondary node cannot be the"
6599 5c983ee5 Iustin Pop
                                   " primary node.", errors.ECODE_INVAL)
6600 7527a8a4 Iustin Pop
      _CheckNodeOnline(self, self.op.snode)
6601 733a2b6a Iustin Pop
      _CheckNodeNotDrained(self, self.op.snode)
6602 733a2b6a Iustin Pop
      self.secondaries.append(self.op.snode)
6603 a8083063 Iustin Pop
6604 6785674e Iustin Pop
    nodenames = [pnode.name] + self.secondaries
6605 6785674e Iustin Pop
6606 e2fe6369 Iustin Pop
    req_size = _ComputeDiskSize(self.op.disk_template,
6607 08db7c5c Iustin Pop
                                self.disks)
6608 ed1ebc60 Guido Trotter
6609 c3589cf8 Iustin Pop
    # Check lv size requirements, if not adopting
6610 c3589cf8 Iustin Pop
    if req_size is not None and not self.adopt_disks:
6611 701384a9 Iustin Pop
      _CheckNodesFreeDisk(self, nodenames, req_size)
6612 ed1ebc60 Guido Trotter
6613 c3589cf8 Iustin Pop
    if self.adopt_disks: # instead, we must check the adoption data
6614 c3589cf8 Iustin Pop
      all_lvs = set([i["adopt"] for i in self.disks])
6615 c3589cf8 Iustin Pop
      if len(all_lvs) != len(self.disks):
6616 c3589cf8 Iustin Pop
        raise errors.OpPrereqError("Duplicate volume names given for adoption",
6617 c3589cf8 Iustin Pop
                                   errors.ECODE_INVAL)
6618 c3589cf8 Iustin Pop
      for lv_name in all_lvs:
6619 c3589cf8 Iustin Pop
        try:
6620 c3589cf8 Iustin Pop
          self.cfg.ReserveLV(lv_name, self.proc.GetECId())
6621 c3589cf8 Iustin Pop
        except errors.ReservationError:
6622 c3589cf8 Iustin Pop
          raise errors.OpPrereqError("LV named %s used by another instance" %
6623 c3589cf8 Iustin Pop
                                     lv_name, errors.ECODE_NOTUNIQUE)
6624 c3589cf8 Iustin Pop
6625 c3589cf8 Iustin Pop
      node_lvs = self.rpc.call_lv_list([pnode.name],
6626 c3589cf8 Iustin Pop
                                       self.cfg.GetVGName())[pnode.name]
6627 c3589cf8 Iustin Pop
      node_lvs.Raise("Cannot get LV information from node %s" % pnode.name)
6628 c3589cf8 Iustin Pop
      node_lvs = node_lvs.payload
6629 c3589cf8 Iustin Pop
      delta = all_lvs.difference(node_lvs.keys())
6630 c3589cf8 Iustin Pop
      if delta:
6631 c3589cf8 Iustin Pop
        raise errors.OpPrereqError("Missing logical volume(s): %s" %
6632 c3589cf8 Iustin Pop
                                   utils.CommaJoin(delta),
6633 c3589cf8 Iustin Pop
                                   errors.ECODE_INVAL)
6634 c3589cf8 Iustin Pop
      online_lvs = [lv for lv in all_lvs if node_lvs[lv][2]]
6635 c3589cf8 Iustin Pop
      if online_lvs:
6636 c3589cf8 Iustin Pop
        raise errors.OpPrereqError("Online logical volumes found, cannot"
6637 c3589cf8 Iustin Pop
                                   " adopt: %s" % utils.CommaJoin(online_lvs),
6638 c3589cf8 Iustin Pop
                                   errors.ECODE_STATE)
6639 c3589cf8 Iustin Pop
      # update the size of disk based on what is found
6640 c3589cf8 Iustin Pop
      for dsk in self.disks:
6641 c3589cf8 Iustin Pop
        dsk["size"] = int(float(node_lvs[dsk["adopt"]][0]))
6642 c3589cf8 Iustin Pop
6643 74409b12 Iustin Pop
    _CheckHVParams(self, nodenames, self.op.hypervisor, self.op.hvparams)
6644 6785674e Iustin Pop
6645 231cd901 Iustin Pop
    _CheckNodeHasOS(self, pnode.name, self.op.os_type, self.op.force_variant)
6646 a8083063 Iustin Pop
6647 b165e77e Guido Trotter
    _CheckNicsBridgesExist(self, self.nics, self.pnode.name)
6648 a8083063 Iustin Pop
6649 49ce1563 Iustin Pop
    # memory check on primary node
6650 49ce1563 Iustin Pop
    if self.op.start:
6651 b9bddb6b Iustin Pop
      _CheckNodeFreeMemory(self, self.pnode.name,
6652 49ce1563 Iustin Pop
                           "creating instance %s" % self.op.instance_name,
6653 338e51e8 Iustin Pop
                           self.be_full[constants.BE_MEMORY],
6654 338e51e8 Iustin Pop
                           self.op.hypervisor)
6655 49ce1563 Iustin Pop
6656 08896026 Iustin Pop
    self.dry_run_result = list(nodenames)
6657 08896026 Iustin Pop
6658 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
6659 a8083063 Iustin Pop
    """Create and add the instance to the cluster.
6660 a8083063 Iustin Pop

6661 a8083063 Iustin Pop
    """
6662 a8083063 Iustin Pop
    instance = self.op.instance_name
6663 a8083063 Iustin Pop
    pnode_name = self.pnode.name
6664 a8083063 Iustin Pop
6665 e69d05fd Iustin Pop
    ht_kind = self.op.hypervisor
6666 2a6469d5 Alexander Schreiber
    if ht_kind in constants.HTS_REQ_PORT:
6667 2a6469d5 Alexander Schreiber
      network_port = self.cfg.AllocatePort()
6668 2a6469d5 Alexander Schreiber
    else:
6669 2a6469d5 Alexander Schreiber
      network_port = None
6670 58acb49d Alexander Schreiber
6671 0e3baaf3 Iustin Pop
    if constants.ENABLE_FILE_STORAGE:
6672 0e3baaf3 Iustin Pop
      # this is needed because os.path.join does not accept None arguments
6673 0e3baaf3 Iustin Pop
      if self.op.file_storage_dir is None:
6674 0e3baaf3 Iustin Pop
        string_file_storage_dir = ""
6675 0e3baaf3 Iustin Pop
      else:
6676 0e3baaf3 Iustin Pop
        string_file_storage_dir = self.op.file_storage_dir
6677 31a853d2 Iustin Pop
6678 0e3baaf3 Iustin Pop
      # build the full file storage dir path
6679 0e3baaf3 Iustin Pop
      file_storage_dir = utils.PathJoin(self.cfg.GetFileStorageDir(),
6680 0e3baaf3 Iustin Pop
                                        string_file_storage_dir, instance)
6681 2c313123 Manuel Franceschini
    else:
6682 0e3baaf3 Iustin Pop
      file_storage_dir = ""
6683 0f1a06e3 Manuel Franceschini
6684 0f1a06e3 Manuel Franceschini
6685 b9bddb6b Iustin Pop
    disks = _GenerateDiskTemplate(self,
6686 a8083063 Iustin Pop
                                  self.op.disk_template,
6687 a8083063 Iustin Pop
                                  instance, pnode_name,
6688 08db7c5c Iustin Pop
                                  self.secondaries,
6689 08db7c5c Iustin Pop
                                  self.disks,
6690 0f1a06e3 Manuel Franceschini
                                  file_storage_dir,
6691 e2a65344 Iustin Pop
                                  self.op.file_driver,
6692 e2a65344 Iustin Pop
                                  0)
6693 a8083063 Iustin Pop
6694 a8083063 Iustin Pop
    iobj = objects.Instance(name=instance, os=self.op.os_type,
6695 a8083063 Iustin Pop
                            primary_node=pnode_name,
6696 08db7c5c Iustin Pop
                            nics=self.nics, disks=disks,
6697 a8083063 Iustin Pop
                            disk_template=self.op.disk_template,
6698 4978db17 Iustin Pop
                            admin_up=False,
6699 58acb49d Alexander Schreiber
                            network_port=network_port,
6700 338e51e8 Iustin Pop
                            beparams=self.op.beparams,
6701 6785674e Iustin Pop
                            hvparams=self.op.hvparams,
6702 e69d05fd Iustin Pop
                            hypervisor=self.op.hypervisor,
6703 a8083063 Iustin Pop
                            )
6704 a8083063 Iustin Pop
6705 c3589cf8 Iustin Pop
    if self.adopt_disks:
6706 c3589cf8 Iustin Pop
      # rename LVs to the newly-generated names; we need to construct
6707 c3589cf8 Iustin Pop
      # 'fake' LV disks with the old data, plus the new unique_id
6708 c3589cf8 Iustin Pop
      tmp_disks = [objects.Disk.FromDict(v.ToDict()) for v in disks]
6709 c3589cf8 Iustin Pop
      rename_to = []
6710 c3589cf8 Iustin Pop
      for t_dsk, a_dsk in zip (tmp_disks, self.disks):
6711 c3589cf8 Iustin Pop
        rename_to.append(t_dsk.logical_id)
6712 c3589cf8 Iustin Pop
        t_dsk.logical_id = (t_dsk.logical_id[0], a_dsk["adopt"])
6713 c3589cf8 Iustin Pop
        self.cfg.SetDiskID(t_dsk, pnode_name)
6714 c3589cf8 Iustin Pop
      result = self.rpc.call_blockdev_rename(pnode_name,
6715 c3589cf8 Iustin Pop
                                             zip(tmp_disks, rename_to))
6716 c3589cf8 Iustin Pop
      result.Raise("Failed to rename adoped LVs")
6717 c3589cf8 Iustin Pop
    else:
6718 c3589cf8 Iustin Pop
      feedback_fn("* creating instance disks...")
6719 796cab27 Iustin Pop
      try:
6720 c3589cf8 Iustin Pop
        _CreateDisks(self, iobj)
6721 c3589cf8 Iustin Pop
      except errors.OpExecError:
6722 c3589cf8 Iustin Pop
        self.LogWarning("Device creation failed, reverting...")
6723 c3589cf8 Iustin Pop
        try:
6724 c3589cf8 Iustin Pop
          _RemoveDisks(self, iobj)
6725 c3589cf8 Iustin Pop
        finally:
6726 c3589cf8 Iustin Pop
          self.cfg.ReleaseDRBDMinors(instance)
6727 c3589cf8 Iustin Pop
          raise
6728 a8083063 Iustin Pop
6729 a8083063 Iustin Pop
    feedback_fn("adding instance %s to cluster config" % instance)
6730 a8083063 Iustin Pop
6731 0debfb35 Guido Trotter
    self.cfg.AddInstance(iobj, self.proc.GetECId())
6732 0debfb35 Guido Trotter
6733 7baf741d Guido Trotter
    # Declare that we don't want to remove the instance lock anymore, as we've
6734 7baf741d Guido Trotter
    # added the instance to the config
6735 7baf741d Guido Trotter
    del self.remove_locks[locking.LEVEL_INSTANCE]
6736 e36e96b4 Guido Trotter
    # Unlock all the nodes
6737 9c8971d7 Guido Trotter
    if self.op.mode == constants.INSTANCE_IMPORT:
6738 9c8971d7 Guido Trotter
      nodes_keep = [self.op.src_node]
6739 9c8971d7 Guido Trotter
      nodes_release = [node for node in self.acquired_locks[locking.LEVEL_NODE]
6740 9c8971d7 Guido Trotter
                       if node != self.op.src_node]
6741 9c8971d7 Guido Trotter
      self.context.glm.release(locking.LEVEL_NODE, nodes_release)
6742 9c8971d7 Guido Trotter
      self.acquired_locks[locking.LEVEL_NODE] = nodes_keep
6743 9c8971d7 Guido Trotter
    else:
6744 9c8971d7 Guido Trotter
      self.context.glm.release(locking.LEVEL_NODE)
6745 9c8971d7 Guido Trotter
      del self.acquired_locks[locking.LEVEL_NODE]
6746 a8083063 Iustin Pop
6747 a8083063 Iustin Pop
    if self.op.wait_for_sync:
6748 b9bddb6b Iustin Pop
      disk_abort = not _WaitForSync(self, iobj)
6749 a1f445d3 Iustin Pop
    elif iobj.disk_template in constants.DTS_NET_MIRROR:
6750 a8083063 Iustin Pop
      # make sure the disks are not degraded (still sync-ing is ok)
6751 a8083063 Iustin Pop
      time.sleep(15)
6752 a8083063 Iustin Pop
      feedback_fn("* checking mirrors status")
6753 b9bddb6b Iustin Pop
      disk_abort = not _WaitForSync(self, iobj, oneshot=True)
6754 a8083063 Iustin Pop
    else:
6755 a8083063 Iustin Pop
      disk_abort = False
6756 a8083063 Iustin Pop
6757 a8083063 Iustin Pop
    if disk_abort:
6758 b9bddb6b Iustin Pop
      _RemoveDisks(self, iobj)
6759 a8083063 Iustin Pop
      self.cfg.RemoveInstance(iobj.name)
6760 7baf741d Guido Trotter
      # Make sure the instance lock gets removed
6761 7baf741d Guido Trotter
      self.remove_locks[locking.LEVEL_INSTANCE] = iobj.name
6762 3ecf6786 Iustin Pop
      raise errors.OpExecError("There are some degraded disks for"
6763 3ecf6786 Iustin Pop
                               " this instance")
6764 a8083063 Iustin Pop
6765 c3589cf8 Iustin Pop
    if iobj.disk_template != constants.DT_DISKLESS and not self.adopt_disks:
6766 a8083063 Iustin Pop
      if self.op.mode == constants.INSTANCE_CREATE:
6767 25a8792c Iustin Pop
        if not self.op.no_install:
6768 25a8792c Iustin Pop
          feedback_fn("* running the instance OS create scripts...")
6769 25a8792c Iustin Pop
          # FIXME: pass debug option from opcode to backend
6770 25a8792c Iustin Pop
          result = self.rpc.call_instance_os_add(pnode_name, iobj, False,
6771 25a8792c Iustin Pop
                                                 self.op.debug_level)
6772 25a8792c Iustin Pop
          result.Raise("Could not add os for instance %s"
6773 25a8792c Iustin Pop
                       " on node %s" % (instance, pnode_name))
6774 a8083063 Iustin Pop
6775 a8083063 Iustin Pop
      elif self.op.mode == constants.INSTANCE_IMPORT:
6776 a8083063 Iustin Pop
        feedback_fn("* running the instance OS import scripts...")
6777 a8083063 Iustin Pop
        src_node = self.op.src_node
6778 09acf207 Guido Trotter
        src_images = self.src_images
6779 62c9ec92 Iustin Pop
        cluster_name = self.cfg.GetClusterName()
6780 4a0e011f Iustin Pop
        # FIXME: pass debug option from opcode to backend
6781 6c0af70e Guido Trotter
        import_result = self.rpc.call_instance_os_import(pnode_name, iobj,
6782 09acf207 Guido Trotter
                                                         src_node, src_images,
6783 dd713605 Iustin Pop
                                                         cluster_name,
6784 dd713605 Iustin Pop
                                                         self.op.debug_level)
6785 4c4e4e1e Iustin Pop
        msg = import_result.fail_msg
6786 944bf548 Iustin Pop
        if msg:
6787 944bf548 Iustin Pop
          self.LogWarning("Error while importing the disk images for instance"
6788 944bf548 Iustin Pop
                          " %s on node %s: %s" % (instance, pnode_name, msg))
6789 a8083063 Iustin Pop
      else:
6790 a8083063 Iustin Pop
        # also checked in the prereq part
6791 3ecf6786 Iustin Pop
        raise errors.ProgrammerError("Unknown OS initialization mode '%s'"
6792 3ecf6786 Iustin Pop
                                     % self.op.mode)
6793 a8083063 Iustin Pop
6794 a8083063 Iustin Pop
    if self.op.start:
6795 4978db17 Iustin Pop
      iobj.admin_up = True
6796 a4eae71f Michael Hanselmann
      self.cfg.Update(iobj, feedback_fn)
6797 9a4f63d1 Iustin Pop
      logging.info("Starting instance %s on node %s", instance, pnode_name)
6798 a8083063 Iustin Pop
      feedback_fn("* starting instance...")
6799 0eca8e0c Iustin Pop
      result = self.rpc.call_instance_start(pnode_name, iobj, None, None)
6800 4c4e4e1e Iustin Pop
      result.Raise("Could not start instance")
6801 a8083063 Iustin Pop
6802 08896026 Iustin Pop
    return list(iobj.all_nodes)
6803 08896026 Iustin Pop
6804 a8083063 Iustin Pop
6805 a8083063 Iustin Pop
class LUConnectConsole(NoHooksLU):
6806 a8083063 Iustin Pop
  """Connect to an instance's console.
6807 a8083063 Iustin Pop

6808 a8083063 Iustin Pop
  This is somewhat special in that it returns the command line that
6809 a8083063 Iustin Pop
  you need to run on the master node in order to connect to the
6810 a8083063 Iustin Pop
  console.
6811 a8083063 Iustin Pop

6812 a8083063 Iustin Pop
  """
6813 a8083063 Iustin Pop
  _OP_REQP = ["instance_name"]
6814 8659b73e Guido Trotter
  REQ_BGL = False
6815 8659b73e Guido Trotter
6816 8659b73e Guido Trotter
  def ExpandNames(self):
6817 8659b73e Guido Trotter
    self._ExpandAndLockInstance()
6818 a8083063 Iustin Pop
6819 a8083063 Iustin Pop
  def CheckPrereq(self):
6820 a8083063 Iustin Pop
    """Check prerequisites.
6821 a8083063 Iustin Pop

6822 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
6823 a8083063 Iustin Pop

6824 a8083063 Iustin Pop
    """
6825 8659b73e Guido Trotter
    self.instance = self.cfg.GetInstanceInfo(self.op.instance_name)
6826 8659b73e Guido Trotter
    assert self.instance is not None, \
6827 8659b73e Guido Trotter
      "Cannot retrieve locked instance %s" % self.op.instance_name
6828 513e896d Guido Trotter
    _CheckNodeOnline(self, self.instance.primary_node)
6829 a8083063 Iustin Pop
6830 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
6831 a8083063 Iustin Pop
    """Connect to the console of an instance
6832 a8083063 Iustin Pop

6833 a8083063 Iustin Pop
    """
6834 a8083063 Iustin Pop
    instance = self.instance
6835 a8083063 Iustin Pop
    node = instance.primary_node
6836 a8083063 Iustin Pop
6837 72737a7f Iustin Pop
    node_insts = self.rpc.call_instance_list([node],
6838 72737a7f Iustin Pop
                                             [instance.hypervisor])[node]
6839 4c4e4e1e Iustin Pop
    node_insts.Raise("Can't get node information from %s" % node)
6840 a8083063 Iustin Pop
6841 aca13712 Iustin Pop
    if instance.name not in node_insts.payload:
6842 3ecf6786 Iustin Pop
      raise errors.OpExecError("Instance %s is not running." % instance.name)
6843 a8083063 Iustin Pop
6844 9a4f63d1 Iustin Pop
    logging.debug("Connecting to console of %s on %s", instance.name, node)
6845 a8083063 Iustin Pop
6846 e69d05fd Iustin Pop
    hyper = hypervisor.GetHypervisor(instance.hypervisor)
6847 5431b2e4 Guido Trotter
    cluster = self.cfg.GetClusterInfo()
6848 5431b2e4 Guido Trotter
    # beparams and hvparams are passed separately, to avoid editing the
6849 5431b2e4 Guido Trotter
    # instance and then saving the defaults in the instance itself.
6850 5431b2e4 Guido Trotter
    hvparams = cluster.FillHV(instance)
6851 5431b2e4 Guido Trotter
    beparams = cluster.FillBE(instance)
6852 5431b2e4 Guido Trotter
    console_cmd = hyper.GetShellCommandForConsole(instance, hvparams, beparams)
6853 b047857b Michael Hanselmann
6854 82122173 Iustin Pop
    # build ssh cmdline
6855 0a80a26f Michael Hanselmann
    return self.ssh.BuildCmd(node, "root", console_cmd, batch=True, tty=True)
6856 a8083063 Iustin Pop
6857 a8083063 Iustin Pop
6858 a8083063 Iustin Pop
class LUReplaceDisks(LogicalUnit):
6859 a8083063 Iustin Pop
  """Replace the disks of an instance.
6860 a8083063 Iustin Pop

6861 a8083063 Iustin Pop
  """
6862 a8083063 Iustin Pop
  HPATH = "mirrors-replace"
6863 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
6864 a9e0c397 Iustin Pop
  _OP_REQP = ["instance_name", "mode", "disks"]
6865 efd990e4 Guido Trotter
  REQ_BGL = False
6866 efd990e4 Guido Trotter
6867 7e9366f7 Iustin Pop
  def CheckArguments(self):
6868 efd990e4 Guido Trotter
    if not hasattr(self.op, "remote_node"):
6869 efd990e4 Guido Trotter
      self.op.remote_node = None
6870 7e9366f7 Iustin Pop
    if not hasattr(self.op, "iallocator"):
6871 7e9366f7 Iustin Pop
      self.op.iallocator = None
6872 7ea7bcf6 Iustin Pop
    if not hasattr(self.op, "early_release"):
6873 7ea7bcf6 Iustin Pop
      self.op.early_release = False
6874 7e9366f7 Iustin Pop
6875 c68174b6 Michael Hanselmann
    TLReplaceDisks.CheckArguments(self.op.mode, self.op.remote_node,
6876 c68174b6 Michael Hanselmann
                                  self.op.iallocator)
6877 7e9366f7 Iustin Pop
6878 7e9366f7 Iustin Pop
  def ExpandNames(self):
6879 7e9366f7 Iustin Pop
    self._ExpandAndLockInstance()
6880 7e9366f7 Iustin Pop
6881 7e9366f7 Iustin Pop
    if self.op.iallocator is not None:
6882 efd990e4 Guido Trotter
      self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
6883 2bb5c911 Michael Hanselmann
6884 efd990e4 Guido Trotter
    elif self.op.remote_node is not None:
6885 cf26a87a Iustin Pop
      remote_node = _ExpandNodeName(self.cfg, self.op.remote_node)
6886 efd990e4 Guido Trotter
      self.op.remote_node = remote_node
6887 2bb5c911 Michael Hanselmann
6888 3b559640 Iustin Pop
      # Warning: do not remove the locking of the new secondary here
6889 3b559640 Iustin Pop
      # unless DRBD8.AddChildren is changed to work in parallel;
6890 3b559640 Iustin Pop
      # currently it doesn't since parallel invocations of
6891 3b559640 Iustin Pop
      # FindUnusedMinor will conflict
6892 efd990e4 Guido Trotter
      self.needed_locks[locking.LEVEL_NODE] = [remote_node]
6893 efd990e4 Guido Trotter
      self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_APPEND
6894 2bb5c911 Michael Hanselmann
6895 efd990e4 Guido Trotter
    else:
6896 efd990e4 Guido Trotter
      self.needed_locks[locking.LEVEL_NODE] = []
6897 efd990e4 Guido Trotter
      self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
6898 efd990e4 Guido Trotter
6899 c68174b6 Michael Hanselmann
    self.replacer = TLReplaceDisks(self, self.op.instance_name, self.op.mode,
6900 c68174b6 Michael Hanselmann
                                   self.op.iallocator, self.op.remote_node,
6901 7ea7bcf6 Iustin Pop
                                   self.op.disks, False, self.op.early_release)
6902 c68174b6 Michael Hanselmann
6903 3a012b41 Michael Hanselmann
    self.tasklets = [self.replacer]
6904 2bb5c911 Michael Hanselmann
6905 efd990e4 Guido Trotter
  def DeclareLocks(self, level):
6906 efd990e4 Guido Trotter
    # If we're not already locking all nodes in the set we have to declare the
6907 efd990e4 Guido Trotter
    # instance's primary/secondary nodes.
6908 efd990e4 Guido Trotter
    if (level == locking.LEVEL_NODE and
6909 efd990e4 Guido Trotter
        self.needed_locks[locking.LEVEL_NODE] is not locking.ALL_SET):
6910 efd990e4 Guido Trotter
      self._LockInstancesNodes()
6911 a8083063 Iustin Pop
6912 a8083063 Iustin Pop
  def BuildHooksEnv(self):
6913 a8083063 Iustin Pop
    """Build hooks env.
6914 a8083063 Iustin Pop

6915 a8083063 Iustin Pop
    This runs on the master, the primary and all the secondaries.
6916 a8083063 Iustin Pop

6917 a8083063 Iustin Pop
    """
6918 2bb5c911 Michael Hanselmann
    instance = self.replacer.instance
6919 a8083063 Iustin Pop
    env = {
6920 a9e0c397 Iustin Pop
      "MODE": self.op.mode,
6921 a8083063 Iustin Pop
      "NEW_SECONDARY": self.op.remote_node,
6922 2bb5c911 Michael Hanselmann
      "OLD_SECONDARY": instance.secondary_nodes[0],
6923 a8083063 Iustin Pop
      }
6924 2bb5c911 Michael Hanselmann
    env.update(_BuildInstanceHookEnvByObject(self, instance))
6925 0834c866 Iustin Pop
    nl = [
6926 d6a02168 Michael Hanselmann
      self.cfg.GetMasterNode(),
6927 2bb5c911 Michael Hanselmann
      instance.primary_node,
6928 0834c866 Iustin Pop
      ]
6929 0834c866 Iustin Pop
    if self.op.remote_node is not None:
6930 0834c866 Iustin Pop
      nl.append(self.op.remote_node)
6931 a8083063 Iustin Pop
    return env, nl, nl
6932 a8083063 Iustin Pop
6933 2bb5c911 Michael Hanselmann
6934 7ffc5a86 Michael Hanselmann
class LUEvacuateNode(LogicalUnit):
6935 7ffc5a86 Michael Hanselmann
  """Relocate the secondary instances from a node.
6936 7ffc5a86 Michael Hanselmann

6937 7ffc5a86 Michael Hanselmann
  """
6938 7ffc5a86 Michael Hanselmann
  HPATH = "node-evacuate"
6939 7ffc5a86 Michael Hanselmann
  HTYPE = constants.HTYPE_NODE
6940 7ffc5a86 Michael Hanselmann
  _OP_REQP = ["node_name"]
6941 7ffc5a86 Michael Hanselmann
  REQ_BGL = False
6942 7ffc5a86 Michael Hanselmann
6943 7ffc5a86 Michael Hanselmann
  def CheckArguments(self):
6944 7ffc5a86 Michael Hanselmann
    if not hasattr(self.op, "remote_node"):
6945 7ffc5a86 Michael Hanselmann
      self.op.remote_node = None
6946 7ffc5a86 Michael Hanselmann
    if not hasattr(self.op, "iallocator"):
6947 7ffc5a86 Michael Hanselmann
      self.op.iallocator = None
6948 7ea7bcf6 Iustin Pop
    if not hasattr(self.op, "early_release"):
6949 7ea7bcf6 Iustin Pop
      self.op.early_release = False
6950 7ffc5a86 Michael Hanselmann
6951 7ffc5a86 Michael Hanselmann
    TLReplaceDisks.CheckArguments(constants.REPLACE_DISK_CHG,
6952 7ffc5a86 Michael Hanselmann
                                  self.op.remote_node,
6953 7ffc5a86 Michael Hanselmann
                                  self.op.iallocator)
6954 7ffc5a86 Michael Hanselmann
6955 7ffc5a86 Michael Hanselmann
  def ExpandNames(self):
6956 cf26a87a Iustin Pop
    self.op.node_name = _ExpandNodeName(self.cfg, self.op.node_name)
6957 7ffc5a86 Michael Hanselmann
6958 7ffc5a86 Michael Hanselmann
    self.needed_locks = {}
6959 7ffc5a86 Michael Hanselmann
6960 7ffc5a86 Michael Hanselmann
    # Declare node locks
6961 7ffc5a86 Michael Hanselmann
    if self.op.iallocator is not None:
6962 7ffc5a86 Michael Hanselmann
      self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
6963 7ffc5a86 Michael Hanselmann
6964 7ffc5a86 Michael Hanselmann
    elif self.op.remote_node is not None:
6965 cf26a87a Iustin Pop
      self.op.remote_node = _ExpandNodeName(self.cfg, self.op.remote_node)
6966 7ffc5a86 Michael Hanselmann
6967 7ffc5a86 Michael Hanselmann
      # Warning: do not remove the locking of the new secondary here
6968 7ffc5a86 Michael Hanselmann
      # unless DRBD8.AddChildren is changed to work in parallel;
6969 7ffc5a86 Michael Hanselmann
      # currently it doesn't since parallel invocations of
6970 7ffc5a86 Michael Hanselmann
      # FindUnusedMinor will conflict
6971 cf26a87a Iustin Pop
      self.needed_locks[locking.LEVEL_NODE] = [self.op.remote_node]
6972 7ffc5a86 Michael Hanselmann
      self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_APPEND
6973 7ffc5a86 Michael Hanselmann
6974 7ffc5a86 Michael Hanselmann
    else:
6975 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Invalid parameters", errors.ECODE_INVAL)
6976 7ffc5a86 Michael Hanselmann
6977 7ffc5a86 Michael Hanselmann
    # Create tasklets for replacing disks for all secondary instances on this
6978 7ffc5a86 Michael Hanselmann
    # node
6979 7ffc5a86 Michael Hanselmann
    names = []
6980 3a012b41 Michael Hanselmann
    tasklets = []
6981 7ffc5a86 Michael Hanselmann
6982 7ffc5a86 Michael Hanselmann
    for inst in _GetNodeSecondaryInstances(self.cfg, self.op.node_name):
6983 7ffc5a86 Michael Hanselmann
      logging.debug("Replacing disks for instance %s", inst.name)
6984 7ffc5a86 Michael Hanselmann
      names.append(inst.name)
6985 7ffc5a86 Michael Hanselmann
6986 7ffc5a86 Michael Hanselmann
      replacer = TLReplaceDisks(self, inst.name, constants.REPLACE_DISK_CHG,
6987 94a1b377 Michael Hanselmann
                                self.op.iallocator, self.op.remote_node, [],
6988 7ea7bcf6 Iustin Pop
                                True, self.op.early_release)
6989 3a012b41 Michael Hanselmann
      tasklets.append(replacer)
6990 7ffc5a86 Michael Hanselmann
6991 3a012b41 Michael Hanselmann
    self.tasklets = tasklets
6992 7ffc5a86 Michael Hanselmann
    self.instance_names = names
6993 7ffc5a86 Michael Hanselmann
6994 7ffc5a86 Michael Hanselmann
    # Declare instance locks
6995 7ffc5a86 Michael Hanselmann
    self.needed_locks[locking.LEVEL_INSTANCE] = self.instance_names
6996 7ffc5a86 Michael Hanselmann
6997 7ffc5a86 Michael Hanselmann
  def DeclareLocks(self, level):
6998 7ffc5a86 Michael Hanselmann
    # If we're not already locking all nodes in the set we have to declare the
6999 7ffc5a86 Michael Hanselmann
    # instance's primary/secondary nodes.
7000 7ffc5a86 Michael Hanselmann
    if (level == locking.LEVEL_NODE and
7001 7ffc5a86 Michael Hanselmann
        self.needed_locks[locking.LEVEL_NODE] is not locking.ALL_SET):
7002 7ffc5a86 Michael Hanselmann
      self._LockInstancesNodes()
7003 7ffc5a86 Michael Hanselmann
7004 7ffc5a86 Michael Hanselmann
  def BuildHooksEnv(self):
7005 7ffc5a86 Michael Hanselmann
    """Build hooks env.
7006 7ffc5a86 Michael Hanselmann

7007 7ffc5a86 Michael Hanselmann
    This runs on the master, the primary and all the secondaries.
7008 7ffc5a86 Michael Hanselmann

7009 7ffc5a86 Michael Hanselmann
    """
7010 7ffc5a86 Michael Hanselmann
    env = {
7011 7ffc5a86 Michael Hanselmann
      "NODE_NAME": self.op.node_name,
7012 7ffc5a86 Michael Hanselmann
      }
7013 7ffc5a86 Michael Hanselmann
7014 7ffc5a86 Michael Hanselmann
    nl = [self.cfg.GetMasterNode()]
7015 7ffc5a86 Michael Hanselmann
7016 7ffc5a86 Michael Hanselmann
    if self.op.remote_node is not None:
7017 7ffc5a86 Michael Hanselmann
      env["NEW_SECONDARY"] = self.op.remote_node
7018 7ffc5a86 Michael Hanselmann
      nl.append(self.op.remote_node)
7019 7ffc5a86 Michael Hanselmann
7020 7ffc5a86 Michael Hanselmann
    return (env, nl, nl)
7021 7ffc5a86 Michael Hanselmann
7022 7ffc5a86 Michael Hanselmann
7023 c68174b6 Michael Hanselmann
class TLReplaceDisks(Tasklet):
7024 2bb5c911 Michael Hanselmann
  """Replaces disks for an instance.
7025 2bb5c911 Michael Hanselmann

7026 2bb5c911 Michael Hanselmann
  Note: Locking is not within the scope of this class.
7027 2bb5c911 Michael Hanselmann

7028 2bb5c911 Michael Hanselmann
  """
7029 2bb5c911 Michael Hanselmann
  def __init__(self, lu, instance_name, mode, iallocator_name, remote_node,
7030 7ea7bcf6 Iustin Pop
               disks, delay_iallocator, early_release):
7031 2bb5c911 Michael Hanselmann
    """Initializes this class.
7032 2bb5c911 Michael Hanselmann

7033 2bb5c911 Michael Hanselmann
    """
7034 464243a7 Michael Hanselmann
    Tasklet.__init__(self, lu)
7035 464243a7 Michael Hanselmann
7036 2bb5c911 Michael Hanselmann
    # Parameters
7037 2bb5c911 Michael Hanselmann
    self.instance_name = instance_name
7038 2bb5c911 Michael Hanselmann
    self.mode = mode
7039 2bb5c911 Michael Hanselmann
    self.iallocator_name = iallocator_name
7040 2bb5c911 Michael Hanselmann
    self.remote_node = remote_node
7041 2bb5c911 Michael Hanselmann
    self.disks = disks
7042 94a1b377 Michael Hanselmann
    self.delay_iallocator = delay_iallocator
7043 7ea7bcf6 Iustin Pop
    self.early_release = early_release
7044 2bb5c911 Michael Hanselmann
7045 2bb5c911 Michael Hanselmann
    # Runtime data
7046 2bb5c911 Michael Hanselmann
    self.instance = None
7047 2bb5c911 Michael Hanselmann
    self.new_node = None
7048 2bb5c911 Michael Hanselmann
    self.target_node = None
7049 2bb5c911 Michael Hanselmann
    self.other_node = None
7050 2bb5c911 Michael Hanselmann
    self.remote_node_info = None
7051 2bb5c911 Michael Hanselmann
    self.node_secondary_ip = None
7052 2bb5c911 Michael Hanselmann
7053 2bb5c911 Michael Hanselmann
  @staticmethod
7054 2bb5c911 Michael Hanselmann
  def CheckArguments(mode, remote_node, iallocator):
7055 c68174b6 Michael Hanselmann
    """Helper function for users of this class.
7056 c68174b6 Michael Hanselmann

7057 c68174b6 Michael Hanselmann
    """
7058 2bb5c911 Michael Hanselmann
    # check for valid parameter combination
7059 2bb5c911 Michael Hanselmann
    if mode == constants.REPLACE_DISK_CHG:
7060 02a00186 Michael Hanselmann
      if remote_node is None and iallocator is None:
7061 2bb5c911 Michael Hanselmann
        raise errors.OpPrereqError("When changing the secondary either an"
7062 2bb5c911 Michael Hanselmann
                                   " iallocator script must be used or the"
7063 5c983ee5 Iustin Pop
                                   " new node given", errors.ECODE_INVAL)
7064 02a00186 Michael Hanselmann
7065 02a00186 Michael Hanselmann
      if remote_node is not None and iallocator is not None:
7066 2bb5c911 Michael Hanselmann
        raise errors.OpPrereqError("Give either the iallocator or the new"
7067 5c983ee5 Iustin Pop
                                   " secondary, not both", errors.ECODE_INVAL)
7068 02a00186 Michael Hanselmann
7069 02a00186 Michael Hanselmann
    elif remote_node is not None or iallocator is not None:
7070 02a00186 Michael Hanselmann
      # Not replacing the secondary
7071 02a00186 Michael Hanselmann
      raise errors.OpPrereqError("The iallocator and new node options can"
7072 02a00186 Michael Hanselmann
                                 " only be used when changing the"
7073 5c983ee5 Iustin Pop
                                 " secondary node", errors.ECODE_INVAL)
7074 2bb5c911 Michael Hanselmann
7075 2bb5c911 Michael Hanselmann
  @staticmethod
7076 2bb5c911 Michael Hanselmann
  def _RunAllocator(lu, iallocator_name, instance_name, relocate_from):
7077 2bb5c911 Michael Hanselmann
    """Compute a new secondary node using an IAllocator.
7078 2bb5c911 Michael Hanselmann

7079 2bb5c911 Michael Hanselmann
    """
7080 2bb5c911 Michael Hanselmann
    ial = IAllocator(lu.cfg, lu.rpc,
7081 2bb5c911 Michael Hanselmann
                     mode=constants.IALLOCATOR_MODE_RELOC,
7082 2bb5c911 Michael Hanselmann
                     name=instance_name,
7083 2bb5c911 Michael Hanselmann
                     relocate_from=relocate_from)
7084 2bb5c911 Michael Hanselmann
7085 2bb5c911 Michael Hanselmann
    ial.Run(iallocator_name)
7086 2bb5c911 Michael Hanselmann
7087 2bb5c911 Michael Hanselmann
    if not ial.success:
7088 2bb5c911 Michael Hanselmann
      raise errors.OpPrereqError("Can't compute nodes using iallocator '%s':"
7089 5c983ee5 Iustin Pop
                                 " %s" % (iallocator_name, ial.info),
7090 5c983ee5 Iustin Pop
                                 errors.ECODE_NORES)
7091 2bb5c911 Michael Hanselmann
7092 680f0a89 Iustin Pop
    if len(ial.result) != ial.required_nodes:
7093 2bb5c911 Michael Hanselmann
      raise errors.OpPrereqError("iallocator '%s' returned invalid number"
7094 2bb5c911 Michael Hanselmann
                                 " of nodes (%s), required %s" %
7095 d984846d Iustin Pop
                                 (iallocator_name,
7096 680f0a89 Iustin Pop
                                  len(ial.result), ial.required_nodes),
7097 5c983ee5 Iustin Pop
                                 errors.ECODE_FAULT)
7098 2bb5c911 Michael Hanselmann
7099 680f0a89 Iustin Pop
    remote_node_name = ial.result[0]
7100 2bb5c911 Michael Hanselmann
7101 2bb5c911 Michael Hanselmann
    lu.LogInfo("Selected new secondary for instance '%s': %s",
7102 2bb5c911 Michael Hanselmann
               instance_name, remote_node_name)
7103 2bb5c911 Michael Hanselmann
7104 2bb5c911 Michael Hanselmann
    return remote_node_name
7105 2bb5c911 Michael Hanselmann
7106 942be002 Michael Hanselmann
  def _FindFaultyDisks(self, node_name):
7107 2d9005d8 Michael Hanselmann
    return _FindFaultyInstanceDisks(self.cfg, self.rpc, self.instance,
7108 2d9005d8 Michael Hanselmann
                                    node_name, True)
7109 942be002 Michael Hanselmann
7110 2bb5c911 Michael Hanselmann
  def CheckPrereq(self):
7111 2bb5c911 Michael Hanselmann
    """Check prerequisites.
7112 2bb5c911 Michael Hanselmann

7113 2bb5c911 Michael Hanselmann
    This checks that the instance is in the cluster.
7114 2bb5c911 Michael Hanselmann

7115 2bb5c911 Michael Hanselmann
    """
7116 e9022531 Iustin Pop
    self.instance = instance = self.cfg.GetInstanceInfo(self.instance_name)
7117 e9022531 Iustin Pop
    assert instance is not None, \
7118 20eca47d Iustin Pop
      "Cannot retrieve locked instance %s" % self.instance_name
7119 2bb5c911 Michael Hanselmann
7120 e9022531 Iustin Pop
    if instance.disk_template != constants.DT_DRBD8:
7121 7e9366f7 Iustin Pop
      raise errors.OpPrereqError("Can only run replace disks for DRBD8-based"
7122 5c983ee5 Iustin Pop
                                 " instances", errors.ECODE_INVAL)
7123 a8083063 Iustin Pop
7124 e9022531 Iustin Pop
    if len(instance.secondary_nodes) != 1:
7125 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("The instance has a strange layout,"
7126 3ecf6786 Iustin Pop
                                 " expected one secondary but found %d" %
7127 5c983ee5 Iustin Pop
                                 len(instance.secondary_nodes),
7128 5c983ee5 Iustin Pop
                                 errors.ECODE_FAULT)
7129 a8083063 Iustin Pop
7130 94a1b377 Michael Hanselmann
    if not self.delay_iallocator:
7131 94a1b377 Michael Hanselmann
      self._CheckPrereq2()
7132 94a1b377 Michael Hanselmann
7133 94a1b377 Michael Hanselmann
  def _CheckPrereq2(self):
7134 94a1b377 Michael Hanselmann
    """Check prerequisites, second part.
7135 94a1b377 Michael Hanselmann

7136 94a1b377 Michael Hanselmann
    This function should always be part of CheckPrereq. It was separated and is
7137 94a1b377 Michael Hanselmann
    now called from Exec because during node evacuation iallocator was only
7138 94a1b377 Michael Hanselmann
    called with an unmodified cluster model, not taking planned changes into
7139 94a1b377 Michael Hanselmann
    account.
7140 94a1b377 Michael Hanselmann

7141 94a1b377 Michael Hanselmann
    """
7142 94a1b377 Michael Hanselmann
    instance = self.instance
7143 e9022531 Iustin Pop
    secondary_node = instance.secondary_nodes[0]
7144 a9e0c397 Iustin Pop
7145 2bb5c911 Michael Hanselmann
    if self.iallocator_name is None:
7146 2bb5c911 Michael Hanselmann
      remote_node = self.remote_node
7147 2bb5c911 Michael Hanselmann
    else:
7148 2bb5c911 Michael Hanselmann
      remote_node = self._RunAllocator(self.lu, self.iallocator_name,
7149 e9022531 Iustin Pop
                                       instance.name, instance.secondary_nodes)
7150 b6e82a65 Iustin Pop
7151 a9e0c397 Iustin Pop
    if remote_node is not None:
7152 a9e0c397 Iustin Pop
      self.remote_node_info = self.cfg.GetNodeInfo(remote_node)
7153 efd990e4 Guido Trotter
      assert self.remote_node_info is not None, \
7154 efd990e4 Guido Trotter
        "Cannot retrieve locked node %s" % remote_node
7155 a9e0c397 Iustin Pop
    else:
7156 a9e0c397 Iustin Pop
      self.remote_node_info = None
7157 2bb5c911 Michael Hanselmann
7158 2bb5c911 Michael Hanselmann
    if remote_node == self.instance.primary_node:
7159 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("The specified node is the primary node of"
7160 5c983ee5 Iustin Pop
                                 " the instance.", errors.ECODE_INVAL)
7161 2bb5c911 Michael Hanselmann
7162 2bb5c911 Michael Hanselmann
    if remote_node == secondary_node:
7163 7e9366f7 Iustin Pop
      raise errors.OpPrereqError("The specified node is already the"
7164 5c983ee5 Iustin Pop
                                 " secondary node of the instance.",
7165 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
7166 7e9366f7 Iustin Pop
7167 2945fd2d Michael Hanselmann
    if self.disks and self.mode in (constants.REPLACE_DISK_AUTO,
7168 2945fd2d Michael Hanselmann
                                    constants.REPLACE_DISK_CHG):
7169 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Cannot specify disks to be replaced",
7170 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
7171 942be002 Michael Hanselmann
7172 2945fd2d Michael Hanselmann
    if self.mode == constants.REPLACE_DISK_AUTO:
7173 e9022531 Iustin Pop
      faulty_primary = self._FindFaultyDisks(instance.primary_node)
7174 942be002 Michael Hanselmann
      faulty_secondary = self._FindFaultyDisks(secondary_node)
7175 942be002 Michael Hanselmann
7176 942be002 Michael Hanselmann
      if faulty_primary and faulty_secondary:
7177 942be002 Michael Hanselmann
        raise errors.OpPrereqError("Instance %s has faulty disks on more than"
7178 942be002 Michael Hanselmann
                                   " one node and can not be repaired"
7179 5c983ee5 Iustin Pop
                                   " automatically" % self.instance_name,
7180 5c983ee5 Iustin Pop
                                   errors.ECODE_STATE)
7181 942be002 Michael Hanselmann
7182 942be002 Michael Hanselmann
      if faulty_primary:
7183 942be002 Michael Hanselmann
        self.disks = faulty_primary
7184 e9022531 Iustin Pop
        self.target_node = instance.primary_node
7185 942be002 Michael Hanselmann
        self.other_node = secondary_node
7186 942be002 Michael Hanselmann
        check_nodes = [self.target_node, self.other_node]
7187 942be002 Michael Hanselmann
      elif faulty_secondary:
7188 942be002 Michael Hanselmann
        self.disks = faulty_secondary
7189 942be002 Michael Hanselmann
        self.target_node = secondary_node
7190 e9022531 Iustin Pop
        self.other_node = instance.primary_node
7191 942be002 Michael Hanselmann
        check_nodes = [self.target_node, self.other_node]
7192 942be002 Michael Hanselmann
      else:
7193 942be002 Michael Hanselmann
        self.disks = []
7194 942be002 Michael Hanselmann
        check_nodes = []
7195 942be002 Michael Hanselmann
7196 942be002 Michael Hanselmann
    else:
7197 942be002 Michael Hanselmann
      # Non-automatic modes
7198 942be002 Michael Hanselmann
      if self.mode == constants.REPLACE_DISK_PRI:
7199 e9022531 Iustin Pop
        self.target_node = instance.primary_node
7200 942be002 Michael Hanselmann
        self.other_node = secondary_node
7201 942be002 Michael Hanselmann
        check_nodes = [self.target_node, self.other_node]
7202 7e9366f7 Iustin Pop
7203 942be002 Michael Hanselmann
      elif self.mode == constants.REPLACE_DISK_SEC:
7204 942be002 Michael Hanselmann
        self.target_node = secondary_node
7205 e9022531 Iustin Pop
        self.other_node = instance.primary_node
7206 942be002 Michael Hanselmann
        check_nodes = [self.target_node, self.other_node]
7207 a9e0c397 Iustin Pop
7208 942be002 Michael Hanselmann
      elif self.mode == constants.REPLACE_DISK_CHG:
7209 942be002 Michael Hanselmann
        self.new_node = remote_node
7210 e9022531 Iustin Pop
        self.other_node = instance.primary_node
7211 942be002 Michael Hanselmann
        self.target_node = secondary_node
7212 942be002 Michael Hanselmann
        check_nodes = [self.new_node, self.other_node]
7213 54155f52 Iustin Pop
7214 942be002 Michael Hanselmann
        _CheckNodeNotDrained(self.lu, remote_node)
7215 a8083063 Iustin Pop
7216 9af0fa6a Iustin Pop
        old_node_info = self.cfg.GetNodeInfo(secondary_node)
7217 9af0fa6a Iustin Pop
        assert old_node_info is not None
7218 9af0fa6a Iustin Pop
        if old_node_info.offline and not self.early_release:
7219 9af0fa6a Iustin Pop
          # doesn't make sense to delay the release
7220 9af0fa6a Iustin Pop
          self.early_release = True
7221 9af0fa6a Iustin Pop
          self.lu.LogInfo("Old secondary %s is offline, automatically enabling"
7222 9af0fa6a Iustin Pop
                          " early-release mode", secondary_node)
7223 9af0fa6a Iustin Pop
7224 942be002 Michael Hanselmann
      else:
7225 942be002 Michael Hanselmann
        raise errors.ProgrammerError("Unhandled disk replace mode (%s)" %
7226 942be002 Michael Hanselmann
                                     self.mode)
7227 942be002 Michael Hanselmann
7228 942be002 Michael Hanselmann
      # If not specified all disks should be replaced
7229 942be002 Michael Hanselmann
      if not self.disks:
7230 942be002 Michael Hanselmann
        self.disks = range(len(self.instance.disks))
7231 a9e0c397 Iustin Pop
7232 2bb5c911 Michael Hanselmann
    for node in check_nodes:
7233 2bb5c911 Michael Hanselmann
      _CheckNodeOnline(self.lu, node)
7234 e4376078 Iustin Pop
7235 2bb5c911 Michael Hanselmann
    # Check whether disks are valid
7236 2bb5c911 Michael Hanselmann
    for disk_idx in self.disks:
7237 e9022531 Iustin Pop
      instance.FindDisk(disk_idx)
7238 e4376078 Iustin Pop
7239 2bb5c911 Michael Hanselmann
    # Get secondary node IP addresses
7240 2bb5c911 Michael Hanselmann
    node_2nd_ip = {}
7241 e4376078 Iustin Pop
7242 2bb5c911 Michael Hanselmann
    for node_name in [self.target_node, self.other_node, self.new_node]:
7243 2bb5c911 Michael Hanselmann
      if node_name is not None:
7244 2bb5c911 Michael Hanselmann
        node_2nd_ip[node_name] = self.cfg.GetNodeInfo(node_name).secondary_ip
7245 e4376078 Iustin Pop
7246 2bb5c911 Michael Hanselmann
    self.node_secondary_ip = node_2nd_ip
7247 a9e0c397 Iustin Pop
7248 c68174b6 Michael Hanselmann
  def Exec(self, feedback_fn):
7249 2bb5c911 Michael Hanselmann
    """Execute disk replacement.
7250 2bb5c911 Michael Hanselmann

7251 2bb5c911 Michael Hanselmann
    This dispatches the disk replacement to the appropriate handler.
7252 cff90b79 Iustin Pop

7253 a9e0c397 Iustin Pop
    """
7254 94a1b377 Michael Hanselmann
    if self.delay_iallocator:
7255 94a1b377 Michael Hanselmann
      self._CheckPrereq2()
7256 94a1b377 Michael Hanselmann
7257 942be002 Michael Hanselmann
    if not self.disks:
7258 942be002 Michael Hanselmann
      feedback_fn("No disks need replacement")
7259 942be002 Michael Hanselmann
      return
7260 942be002 Michael Hanselmann
7261 942be002 Michael Hanselmann
    feedback_fn("Replacing disk(s) %s for %s" %
7262 1f864b60 Iustin Pop
                (utils.CommaJoin(self.disks), self.instance.name))
7263 7ffc5a86 Michael Hanselmann
7264 2bb5c911 Michael Hanselmann
    activate_disks = (not self.instance.admin_up)
7265 2bb5c911 Michael Hanselmann
7266 2bb5c911 Michael Hanselmann
    # Activate the instance disks if we're replacing them on a down instance
7267 2bb5c911 Michael Hanselmann
    if activate_disks:
7268 2bb5c911 Michael Hanselmann
      _StartInstanceDisks(self.lu, self.instance, True)
7269 2bb5c911 Michael Hanselmann
7270 2bb5c911 Michael Hanselmann
    try:
7271 942be002 Michael Hanselmann
      # Should we replace the secondary node?
7272 942be002 Michael Hanselmann
      if self.new_node is not None:
7273 a4eae71f Michael Hanselmann
        fn = self._ExecDrbd8Secondary
7274 2bb5c911 Michael Hanselmann
      else:
7275 a4eae71f Michael Hanselmann
        fn = self._ExecDrbd8DiskOnly
7276 a4eae71f Michael Hanselmann
7277 a4eae71f Michael Hanselmann
      return fn(feedback_fn)
7278 2bb5c911 Michael Hanselmann
7279 2bb5c911 Michael Hanselmann
    finally:
7280 5c983ee5 Iustin Pop
      # Deactivate the instance disks if we're replacing them on a
7281 5c983ee5 Iustin Pop
      # down instance
7282 2bb5c911 Michael Hanselmann
      if activate_disks:
7283 2bb5c911 Michael Hanselmann
        _SafeShutdownInstanceDisks(self.lu, self.instance)
7284 2bb5c911 Michael Hanselmann
7285 2bb5c911 Michael Hanselmann
  def _CheckVolumeGroup(self, nodes):
7286 2bb5c911 Michael Hanselmann
    self.lu.LogInfo("Checking volume groups")
7287 2bb5c911 Michael Hanselmann
7288 a9e0c397 Iustin Pop
    vgname = self.cfg.GetVGName()
7289 cff90b79 Iustin Pop
7290 2bb5c911 Michael Hanselmann
    # Make sure volume group exists on all involved nodes
7291 2bb5c911 Michael Hanselmann
    results = self.rpc.call_vg_list(nodes)
7292 cff90b79 Iustin Pop
    if not results:
7293 cff90b79 Iustin Pop
      raise errors.OpExecError("Can't list volume groups on the nodes")
7294 2bb5c911 Michael Hanselmann
7295 2bb5c911 Michael Hanselmann
    for node in nodes:
7296 781de953 Iustin Pop
      res = results[node]
7297 4c4e4e1e Iustin Pop
      res.Raise("Error checking node %s" % node)
7298 2bb5c911 Michael Hanselmann
      if vgname not in res.payload:
7299 2bb5c911 Michael Hanselmann
        raise errors.OpExecError("Volume group '%s' not found on node %s" %
7300 2bb5c911 Michael Hanselmann
                                 (vgname, node))
7301 2bb5c911 Michael Hanselmann
7302 2bb5c911 Michael Hanselmann
  def _CheckDisksExistence(self, nodes):
7303 2bb5c911 Michael Hanselmann
    # Check disk existence
7304 2bb5c911 Michael Hanselmann
    for idx, dev in enumerate(self.instance.disks):
7305 2bb5c911 Michael Hanselmann
      if idx not in self.disks:
7306 cff90b79 Iustin Pop
        continue
7307 2bb5c911 Michael Hanselmann
7308 2bb5c911 Michael Hanselmann
      for node in nodes:
7309 2bb5c911 Michael Hanselmann
        self.lu.LogInfo("Checking disk/%d on %s" % (idx, node))
7310 2bb5c911 Michael Hanselmann
        self.cfg.SetDiskID(dev, node)
7311 2bb5c911 Michael Hanselmann
7312 23829f6f Iustin Pop
        result = self.rpc.call_blockdev_find(node, dev)
7313 2bb5c911 Michael Hanselmann
7314 4c4e4e1e Iustin Pop
        msg = result.fail_msg
7315 2bb5c911 Michael Hanselmann
        if msg or not result.payload:
7316 2bb5c911 Michael Hanselmann
          if not msg:
7317 2bb5c911 Michael Hanselmann
            msg = "disk not found"
7318 23829f6f Iustin Pop
          raise errors.OpExecError("Can't find disk/%d on node %s: %s" %
7319 23829f6f Iustin Pop
                                   (idx, node, msg))
7320 cff90b79 Iustin Pop
7321 2bb5c911 Michael Hanselmann
  def _CheckDisksConsistency(self, node_name, on_primary, ldisk):
7322 2bb5c911 Michael Hanselmann
    for idx, dev in enumerate(self.instance.disks):
7323 2bb5c911 Michael Hanselmann
      if idx not in self.disks:
7324 cff90b79 Iustin Pop
        continue
7325 cff90b79 Iustin Pop
7326 2bb5c911 Michael Hanselmann
      self.lu.LogInfo("Checking disk/%d consistency on node %s" %
7327 2bb5c911 Michael Hanselmann
                      (idx, node_name))
7328 2bb5c911 Michael Hanselmann
7329 2bb5c911 Michael Hanselmann
      if not _CheckDiskConsistency(self.lu, dev, node_name, on_primary,
7330 2bb5c911 Michael Hanselmann
                                   ldisk=ldisk):
7331 2bb5c911 Michael Hanselmann
        raise errors.OpExecError("Node %s has degraded storage, unsafe to"
7332 2bb5c911 Michael Hanselmann
                                 " replace disks for instance %s" %
7333 2bb5c911 Michael Hanselmann
                                 (node_name, self.instance.name))
7334 2bb5c911 Michael Hanselmann
7335 2bb5c911 Michael Hanselmann
  def _CreateNewStorage(self, node_name):
7336 2bb5c911 Michael Hanselmann
    vgname = self.cfg.GetVGName()
7337 2bb5c911 Michael Hanselmann
    iv_names = {}
7338 2bb5c911 Michael Hanselmann
7339 2bb5c911 Michael Hanselmann
    for idx, dev in enumerate(self.instance.disks):
7340 2bb5c911 Michael Hanselmann
      if idx not in self.disks:
7341 a9e0c397 Iustin Pop
        continue
7342 2bb5c911 Michael Hanselmann
7343 2bb5c911 Michael Hanselmann
      self.lu.LogInfo("Adding storage on %s for disk/%d" % (node_name, idx))
7344 2bb5c911 Michael Hanselmann
7345 2bb5c911 Michael Hanselmann
      self.cfg.SetDiskID(dev, node_name)
7346 2bb5c911 Michael Hanselmann
7347 2bb5c911 Michael Hanselmann
      lv_names = [".disk%d_%s" % (idx, suffix) for suffix in ["data", "meta"]]
7348 2bb5c911 Michael Hanselmann
      names = _GenerateUniqueNames(self.lu, lv_names)
7349 2bb5c911 Michael Hanselmann
7350 2bb5c911 Michael Hanselmann
      lv_data = objects.Disk(dev_type=constants.LD_LV, size=dev.size,
7351 a9e0c397 Iustin Pop
                             logical_id=(vgname, names[0]))
7352 a9e0c397 Iustin Pop
      lv_meta = objects.Disk(dev_type=constants.LD_LV, size=128,
7353 a9e0c397 Iustin Pop
                             logical_id=(vgname, names[1]))
7354 2bb5c911 Michael Hanselmann
7355 a9e0c397 Iustin Pop
      new_lvs = [lv_data, lv_meta]
7356 a9e0c397 Iustin Pop
      old_lvs = dev.children
7357 a9e0c397 Iustin Pop
      iv_names[dev.iv_name] = (dev, old_lvs, new_lvs)
7358 2bb5c911 Michael Hanselmann
7359 428958aa Iustin Pop
      # we pass force_create=True to force the LVM creation
7360 a9e0c397 Iustin Pop
      for new_lv in new_lvs:
7361 2bb5c911 Michael Hanselmann
        _CreateBlockDev(self.lu, node_name, self.instance, new_lv, True,
7362 2bb5c911 Michael Hanselmann
                        _GetInstanceInfoText(self.instance), False)
7363 2bb5c911 Michael Hanselmann
7364 2bb5c911 Michael Hanselmann
    return iv_names
7365 2bb5c911 Michael Hanselmann
7366 2bb5c911 Michael Hanselmann
  def _CheckDevices(self, node_name, iv_names):
7367 1122eb25 Iustin Pop
    for name, (dev, _, _) in iv_names.iteritems():
7368 2bb5c911 Michael Hanselmann
      self.cfg.SetDiskID(dev, node_name)
7369 2bb5c911 Michael Hanselmann
7370 2bb5c911 Michael Hanselmann
      result = self.rpc.call_blockdev_find(node_name, dev)
7371 2bb5c911 Michael Hanselmann
7372 2bb5c911 Michael Hanselmann
      msg = result.fail_msg
7373 2bb5c911 Michael Hanselmann
      if msg or not result.payload:
7374 2bb5c911 Michael Hanselmann
        if not msg:
7375 2bb5c911 Michael Hanselmann
          msg = "disk not found"
7376 2bb5c911 Michael Hanselmann
        raise errors.OpExecError("Can't find DRBD device %s: %s" %
7377 2bb5c911 Michael Hanselmann
                                 (name, msg))
7378 2bb5c911 Michael Hanselmann
7379 96acbc09 Michael Hanselmann
      if result.payload.is_degraded:
7380 2bb5c911 Michael Hanselmann
        raise errors.OpExecError("DRBD device %s is degraded!" % name)
7381 2bb5c911 Michael Hanselmann
7382 2bb5c911 Michael Hanselmann
  def _RemoveOldStorage(self, node_name, iv_names):
7383 1122eb25 Iustin Pop
    for name, (_, old_lvs, _) in iv_names.iteritems():
7384 2bb5c911 Michael Hanselmann
      self.lu.LogInfo("Remove logical volumes for %s" % name)
7385 2bb5c911 Michael Hanselmann
7386 2bb5c911 Michael Hanselmann
      for lv in old_lvs:
7387 2bb5c911 Michael Hanselmann
        self.cfg.SetDiskID(lv, node_name)
7388 2bb5c911 Michael Hanselmann
7389 2bb5c911 Michael Hanselmann
        msg = self.rpc.call_blockdev_remove(node_name, lv).fail_msg
7390 2bb5c911 Michael Hanselmann
        if msg:
7391 2bb5c911 Michael Hanselmann
          self.lu.LogWarning("Can't remove old LV: %s" % msg,
7392 2bb5c911 Michael Hanselmann
                             hint="remove unused LVs manually")
7393 2bb5c911 Michael Hanselmann
7394 7ea7bcf6 Iustin Pop
  def _ReleaseNodeLock(self, node_name):
7395 7ea7bcf6 Iustin Pop
    """Releases the lock for a given node."""
7396 7ea7bcf6 Iustin Pop
    self.lu.context.glm.release(locking.LEVEL_NODE, node_name)
7397 7ea7bcf6 Iustin Pop
7398 a4eae71f Michael Hanselmann
  def _ExecDrbd8DiskOnly(self, feedback_fn):
7399 2bb5c911 Michael Hanselmann
    """Replace a disk on the primary or secondary for DRBD 8.
7400 2bb5c911 Michael Hanselmann

7401 2bb5c911 Michael Hanselmann
    The algorithm for replace is quite complicated:
7402 2bb5c911 Michael Hanselmann

7403 2bb5c911 Michael Hanselmann
      1. for each disk to be replaced:
7404 2bb5c911 Michael Hanselmann

7405 2bb5c911 Michael Hanselmann
        1. create new LVs on the target node with unique names
7406 2bb5c911 Michael Hanselmann
        1. detach old LVs from the drbd device
7407 2bb5c911 Michael Hanselmann
        1. rename old LVs to name_replaced.<time_t>
7408 2bb5c911 Michael Hanselmann
        1. rename new LVs to old LVs
7409 2bb5c911 Michael Hanselmann
        1. attach the new LVs (with the old names now) to the drbd device
7410 2bb5c911 Michael Hanselmann

7411 2bb5c911 Michael Hanselmann
      1. wait for sync across all devices
7412 2bb5c911 Michael Hanselmann

7413 2bb5c911 Michael Hanselmann
      1. for each modified disk:
7414 2bb5c911 Michael Hanselmann

7415 2bb5c911 Michael Hanselmann
        1. remove old LVs (which have the name name_replaces.<time_t>)
7416 2bb5c911 Michael Hanselmann

7417 2bb5c911 Michael Hanselmann
    Failures are not very well handled.
7418 2bb5c911 Michael Hanselmann

7419 2bb5c911 Michael Hanselmann
    """
7420 2bb5c911 Michael Hanselmann
    steps_total = 6
7421 2bb5c911 Michael Hanselmann
7422 2bb5c911 Michael Hanselmann
    # Step: check device activation
7423 2bb5c911 Michael Hanselmann
    self.lu.LogStep(1, steps_total, "Check device existence")
7424 2bb5c911 Michael Hanselmann
    self._CheckDisksExistence([self.other_node, self.target_node])
7425 2bb5c911 Michael Hanselmann
    self._CheckVolumeGroup([self.target_node, self.other_node])
7426 2bb5c911 Michael Hanselmann
7427 2bb5c911 Michael Hanselmann
    # Step: check other node consistency
7428 2bb5c911 Michael Hanselmann
    self.lu.LogStep(2, steps_total, "Check peer consistency")
7429 2bb5c911 Michael Hanselmann
    self._CheckDisksConsistency(self.other_node,
7430 2bb5c911 Michael Hanselmann
                                self.other_node == self.instance.primary_node,
7431 2bb5c911 Michael Hanselmann
                                False)
7432 2bb5c911 Michael Hanselmann
7433 2bb5c911 Michael Hanselmann
    # Step: create new storage
7434 2bb5c911 Michael Hanselmann
    self.lu.LogStep(3, steps_total, "Allocate new storage")
7435 2bb5c911 Michael Hanselmann
    iv_names = self._CreateNewStorage(self.target_node)
7436 a9e0c397 Iustin Pop
7437 cff90b79 Iustin Pop
    # Step: for each lv, detach+rename*2+attach
7438 2bb5c911 Michael Hanselmann
    self.lu.LogStep(4, steps_total, "Changing drbd configuration")
7439 cff90b79 Iustin Pop
    for dev, old_lvs, new_lvs in iv_names.itervalues():
7440 2bb5c911 Michael Hanselmann
      self.lu.LogInfo("Detaching %s drbd from local storage" % dev.iv_name)
7441 2bb5c911 Michael Hanselmann
7442 4d4a651d Michael Hanselmann
      result = self.rpc.call_blockdev_removechildren(self.target_node, dev,
7443 4d4a651d Michael Hanselmann
                                                     old_lvs)
7444 4c4e4e1e Iustin Pop
      result.Raise("Can't detach drbd from local storage on node"
7445 2bb5c911 Michael Hanselmann
                   " %s for device %s" % (self.target_node, dev.iv_name))
7446 cff90b79 Iustin Pop
      #dev.children = []
7447 cff90b79 Iustin Pop
      #cfg.Update(instance)
7448 a9e0c397 Iustin Pop
7449 a9e0c397 Iustin Pop
      # ok, we created the new LVs, so now we know we have the needed
7450 a9e0c397 Iustin Pop
      # storage; as such, we proceed on the target node to rename
7451 a9e0c397 Iustin Pop
      # old_lv to _old, and new_lv to old_lv; note that we rename LVs
7452 c99a3cc0 Manuel Franceschini
      # using the assumption that logical_id == physical_id (which in
7453 a9e0c397 Iustin Pop
      # turn is the unique_id on that node)
7454 cff90b79 Iustin Pop
7455 cff90b79 Iustin Pop
      # FIXME(iustin): use a better name for the replaced LVs
7456 a9e0c397 Iustin Pop
      temp_suffix = int(time.time())
7457 a9e0c397 Iustin Pop
      ren_fn = lambda d, suff: (d.physical_id[0],
7458 a9e0c397 Iustin Pop
                                d.physical_id[1] + "_replaced-%s" % suff)
7459 2bb5c911 Michael Hanselmann
7460 2bb5c911 Michael Hanselmann
      # Build the rename list based on what LVs exist on the node
7461 2bb5c911 Michael Hanselmann
      rename_old_to_new = []
7462 cff90b79 Iustin Pop
      for to_ren in old_lvs:
7463 2bb5c911 Michael Hanselmann
        result = self.rpc.call_blockdev_find(self.target_node, to_ren)
7464 4c4e4e1e Iustin Pop
        if not result.fail_msg and result.payload:
7465 23829f6f Iustin Pop
          # device exists
7466 2bb5c911 Michael Hanselmann
          rename_old_to_new.append((to_ren, ren_fn(to_ren, temp_suffix)))
7467 cff90b79 Iustin Pop
7468 2bb5c911 Michael Hanselmann
      self.lu.LogInfo("Renaming the old LVs on the target node")
7469 4d4a651d Michael Hanselmann
      result = self.rpc.call_blockdev_rename(self.target_node,
7470 4d4a651d Michael Hanselmann
                                             rename_old_to_new)
7471 2bb5c911 Michael Hanselmann
      result.Raise("Can't rename old LVs on node %s" % self.target_node)
7472 2bb5c911 Michael Hanselmann
7473 2bb5c911 Michael Hanselmann
      # Now we rename the new LVs to the old LVs
7474 2bb5c911 Michael Hanselmann
      self.lu.LogInfo("Renaming the new LVs on the target node")
7475 2bb5c911 Michael Hanselmann
      rename_new_to_old = [(new, old.physical_id)
7476 2bb5c911 Michael Hanselmann
                           for old, new in zip(old_lvs, new_lvs)]
7477 4d4a651d Michael Hanselmann
      result = self.rpc.call_blockdev_rename(self.target_node,
7478 4d4a651d Michael Hanselmann
                                             rename_new_to_old)
7479 2bb5c911 Michael Hanselmann
      result.Raise("Can't rename new LVs on node %s" % self.target_node)
7480 cff90b79 Iustin Pop
7481 cff90b79 Iustin Pop
      for old, new in zip(old_lvs, new_lvs):
7482 cff90b79 Iustin Pop
        new.logical_id = old.logical_id
7483 2bb5c911 Michael Hanselmann
        self.cfg.SetDiskID(new, self.target_node)
7484 a9e0c397 Iustin Pop
7485 cff90b79 Iustin Pop
      for disk in old_lvs:
7486 cff90b79 Iustin Pop
        disk.logical_id = ren_fn(disk, temp_suffix)
7487 2bb5c911 Michael Hanselmann
        self.cfg.SetDiskID(disk, self.target_node)
7488 a9e0c397 Iustin Pop
7489 2bb5c911 Michael Hanselmann
      # Now that the new lvs have the old name, we can add them to the device
7490 2bb5c911 Michael Hanselmann
      self.lu.LogInfo("Adding new mirror component on %s" % self.target_node)
7491 4d4a651d Michael Hanselmann
      result = self.rpc.call_blockdev_addchildren(self.target_node, dev,
7492 4d4a651d Michael Hanselmann
                                                  new_lvs)
7493 4c4e4e1e Iustin Pop
      msg = result.fail_msg
7494 2cc1da8b Iustin Pop
      if msg:
7495 a9e0c397 Iustin Pop
        for new_lv in new_lvs:
7496 4d4a651d Michael Hanselmann
          msg2 = self.rpc.call_blockdev_remove(self.target_node,
7497 4d4a651d Michael Hanselmann
                                               new_lv).fail_msg
7498 4c4e4e1e Iustin Pop
          if msg2:
7499 2bb5c911 Michael Hanselmann
            self.lu.LogWarning("Can't rollback device %s: %s", dev, msg2,
7500 2bb5c911 Michael Hanselmann
                               hint=("cleanup manually the unused logical"
7501 2bb5c911 Michael Hanselmann
                                     "volumes"))
7502 2cc1da8b Iustin Pop
        raise errors.OpExecError("Can't add local storage to drbd: %s" % msg)
7503 a9e0c397 Iustin Pop
7504 a9e0c397 Iustin Pop
      dev.children = new_lvs
7505 a9e0c397 Iustin Pop
7506 a4eae71f Michael Hanselmann
      self.cfg.Update(self.instance, feedback_fn)
7507 a9e0c397 Iustin Pop
7508 7ea7bcf6 Iustin Pop
    cstep = 5
7509 7ea7bcf6 Iustin Pop
    if self.early_release:
7510 7ea7bcf6 Iustin Pop
      self.lu.LogStep(cstep, steps_total, "Removing old storage")
7511 7ea7bcf6 Iustin Pop
      cstep += 1
7512 7ea7bcf6 Iustin Pop
      self._RemoveOldStorage(self.target_node, iv_names)
7513 d5cd389c Iustin Pop
      # WARNING: we release both node locks here, do not do other RPCs
7514 d5cd389c Iustin Pop
      # than WaitForSync to the primary node
7515 d5cd389c Iustin Pop
      self._ReleaseNodeLock([self.target_node, self.other_node])
7516 7ea7bcf6 Iustin Pop
7517 2bb5c911 Michael Hanselmann
    # Wait for sync
7518 2bb5c911 Michael Hanselmann
    # This can fail as the old devices are degraded and _WaitForSync
7519 2bb5c911 Michael Hanselmann
    # does a combined result over all disks, so we don't check its return value
7520 7ea7bcf6 Iustin Pop
    self.lu.LogStep(cstep, steps_total, "Sync devices")
7521 7ea7bcf6 Iustin Pop
    cstep += 1
7522 b6c07b79 Michael Hanselmann
    _WaitForSync(self.lu, self.instance)
7523 a9e0c397 Iustin Pop
7524 2bb5c911 Michael Hanselmann
    # Check all devices manually
7525 2bb5c911 Michael Hanselmann
    self._CheckDevices(self.instance.primary_node, iv_names)
7526 a9e0c397 Iustin Pop
7527 cff90b79 Iustin Pop
    # Step: remove old storage
7528 7ea7bcf6 Iustin Pop
    if not self.early_release:
7529 7ea7bcf6 Iustin Pop
      self.lu.LogStep(cstep, steps_total, "Removing old storage")
7530 7ea7bcf6 Iustin Pop
      cstep += 1
7531 7ea7bcf6 Iustin Pop
      self._RemoveOldStorage(self.target_node, iv_names)
7532 a9e0c397 Iustin Pop
7533 a4eae71f Michael Hanselmann
  def _ExecDrbd8Secondary(self, feedback_fn):
7534 2bb5c911 Michael Hanselmann
    """Replace the secondary node for DRBD 8.
7535 a9e0c397 Iustin Pop

7536 a9e0c397 Iustin Pop
    The algorithm for replace is quite complicated:
7537 a9e0c397 Iustin Pop
      - for all disks of the instance:
7538 a9e0c397 Iustin Pop
        - create new LVs on the new node with same names
7539 a9e0c397 Iustin Pop
        - shutdown the drbd device on the old secondary
7540 a9e0c397 Iustin Pop
        - disconnect the drbd network on the primary
7541 a9e0c397 Iustin Pop
        - create the drbd device on the new secondary
7542 a9e0c397 Iustin Pop
        - network attach the drbd on the primary, using an artifice:
7543 a9e0c397 Iustin Pop
          the drbd code for Attach() will connect to the network if it
7544 a9e0c397 Iustin Pop
          finds a device which is connected to the good local disks but
7545 a9e0c397 Iustin Pop
          not network enabled
7546 a9e0c397 Iustin Pop
      - wait for sync across all devices
7547 a9e0c397 Iustin Pop
      - remove all disks from the old secondary
7548 a9e0c397 Iustin Pop

7549 a9e0c397 Iustin Pop
    Failures are not very well handled.
7550 0834c866 Iustin Pop

7551 a9e0c397 Iustin Pop
    """
7552 0834c866 Iustin Pop
    steps_total = 6
7553 0834c866 Iustin Pop
7554 0834c866 Iustin Pop
    # Step: check device activation
7555 2bb5c911 Michael Hanselmann
    self.lu.LogStep(1, steps_total, "Check device existence")
7556 2bb5c911 Michael Hanselmann
    self._CheckDisksExistence([self.instance.primary_node])
7557 2bb5c911 Michael Hanselmann
    self._CheckVolumeGroup([self.instance.primary_node])
7558 0834c866 Iustin Pop
7559 0834c866 Iustin Pop
    # Step: check other node consistency
7560 2bb5c911 Michael Hanselmann
    self.lu.LogStep(2, steps_total, "Check peer consistency")
7561 2bb5c911 Michael Hanselmann
    self._CheckDisksConsistency(self.instance.primary_node, True, True)
7562 0834c866 Iustin Pop
7563 0834c866 Iustin Pop
    # Step: create new storage
7564 2bb5c911 Michael Hanselmann
    self.lu.LogStep(3, steps_total, "Allocate new storage")
7565 2bb5c911 Michael Hanselmann
    for idx, dev in enumerate(self.instance.disks):
7566 2bb5c911 Michael Hanselmann
      self.lu.LogInfo("Adding new local storage on %s for disk/%d" %
7567 2bb5c911 Michael Hanselmann
                      (self.new_node, idx))
7568 428958aa Iustin Pop
      # we pass force_create=True to force LVM creation
7569 a9e0c397 Iustin Pop
      for new_lv in dev.children:
7570 2bb5c911 Michael Hanselmann
        _CreateBlockDev(self.lu, self.new_node, self.instance, new_lv, True,
7571 2bb5c911 Michael Hanselmann
                        _GetInstanceInfoText(self.instance), False)
7572 a9e0c397 Iustin Pop
7573 468b46f9 Iustin Pop
    # Step 4: dbrd minors and drbd setups changes
7574 a1578d63 Iustin Pop
    # after this, we must manually remove the drbd minors on both the
7575 a1578d63 Iustin Pop
    # error and the success paths
7576 2bb5c911 Michael Hanselmann
    self.lu.LogStep(4, steps_total, "Changing drbd configuration")
7577 4d4a651d Michael Hanselmann
    minors = self.cfg.AllocateDRBDMinor([self.new_node
7578 4d4a651d Michael Hanselmann
                                         for dev in self.instance.disks],
7579 2bb5c911 Michael Hanselmann
                                        self.instance.name)
7580 099c52ad Iustin Pop
    logging.debug("Allocated minors %r", minors)
7581 2bb5c911 Michael Hanselmann
7582 2bb5c911 Michael Hanselmann
    iv_names = {}
7583 2bb5c911 Michael Hanselmann
    for idx, (dev, new_minor) in enumerate(zip(self.instance.disks, minors)):
7584 4d4a651d Michael Hanselmann
      self.lu.LogInfo("activating a new drbd on %s for disk/%d" %
7585 4d4a651d Michael Hanselmann
                      (self.new_node, idx))
7586 a2d59d8b Iustin Pop
      # create new devices on new_node; note that we create two IDs:
7587 a2d59d8b Iustin Pop
      # one without port, so the drbd will be activated without
7588 a2d59d8b Iustin Pop
      # networking information on the new node at this stage, and one
7589 a2d59d8b Iustin Pop
      # with network, for the latter activation in step 4
7590 a2d59d8b Iustin Pop
      (o_node1, o_node2, o_port, o_minor1, o_minor2, o_secret) = dev.logical_id
7591 2bb5c911 Michael Hanselmann
      if self.instance.primary_node == o_node1:
7592 a2d59d8b Iustin Pop
        p_minor = o_minor1
7593 ffa1c0dc Iustin Pop
      else:
7594 1122eb25 Iustin Pop
        assert self.instance.primary_node == o_node2, "Three-node instance?"
7595 a2d59d8b Iustin Pop
        p_minor = o_minor2
7596 a2d59d8b Iustin Pop
7597 4d4a651d Michael Hanselmann
      new_alone_id = (self.instance.primary_node, self.new_node, None,
7598 4d4a651d Michael Hanselmann
                      p_minor, new_minor, o_secret)
7599 4d4a651d Michael Hanselmann
      new_net_id = (self.instance.primary_node, self.new_node, o_port,
7600 4d4a651d Michael Hanselmann
                    p_minor, new_minor, o_secret)
7601 a2d59d8b Iustin Pop
7602 a2d59d8b Iustin Pop
      iv_names[idx] = (dev, dev.children, new_net_id)
7603 a1578d63 Iustin Pop
      logging.debug("Allocated new_minor: %s, new_logical_id: %s", new_minor,
7604 a2d59d8b Iustin Pop
                    new_net_id)
7605 a9e0c397 Iustin Pop
      new_drbd = objects.Disk(dev_type=constants.LD_DRBD8,
7606 a2d59d8b Iustin Pop
                              logical_id=new_alone_id,
7607 8a6c7011 Iustin Pop
                              children=dev.children,
7608 8a6c7011 Iustin Pop
                              size=dev.size)
7609 796cab27 Iustin Pop
      try:
7610 2bb5c911 Michael Hanselmann
        _CreateSingleBlockDev(self.lu, self.new_node, self.instance, new_drbd,
7611 2bb5c911 Michael Hanselmann
                              _GetInstanceInfoText(self.instance), False)
7612 82759cb1 Iustin Pop
      except errors.GenericError:
7613 2bb5c911 Michael Hanselmann
        self.cfg.ReleaseDRBDMinors(self.instance.name)
7614 796cab27 Iustin Pop
        raise
7615 a9e0c397 Iustin Pop
7616 2bb5c911 Michael Hanselmann
    # We have new devices, shutdown the drbd on the old secondary
7617 2bb5c911 Michael Hanselmann
    for idx, dev in enumerate(self.instance.disks):
7618 2bb5c911 Michael Hanselmann
      self.lu.LogInfo("Shutting down drbd for disk/%d on old node" % idx)
7619 2bb5c911 Michael Hanselmann
      self.cfg.SetDiskID(dev, self.target_node)
7620 2bb5c911 Michael Hanselmann
      msg = self.rpc.call_blockdev_shutdown(self.target_node, dev).fail_msg
7621 cacfd1fd Iustin Pop
      if msg:
7622 2bb5c911 Michael Hanselmann
        self.lu.LogWarning("Failed to shutdown drbd for disk/%d on old"
7623 2bb5c911 Michael Hanselmann
                           "node: %s" % (idx, msg),
7624 2bb5c911 Michael Hanselmann
                           hint=("Please cleanup this device manually as"
7625 2bb5c911 Michael Hanselmann
                                 " soon as possible"))
7626 a9e0c397 Iustin Pop
7627 2bb5c911 Michael Hanselmann
    self.lu.LogInfo("Detaching primary drbds from the network (=> standalone)")
7628 4d4a651d Michael Hanselmann
    result = self.rpc.call_drbd_disconnect_net([self.instance.primary_node],
7629 4d4a651d Michael Hanselmann
                                               self.node_secondary_ip,
7630 4d4a651d Michael Hanselmann
                                               self.instance.disks)\
7631 4d4a651d Michael Hanselmann
                                              [self.instance.primary_node]
7632 642445d9 Iustin Pop
7633 4c4e4e1e Iustin Pop
    msg = result.fail_msg
7634 a2d59d8b Iustin Pop
    if msg:
7635 a2d59d8b Iustin Pop
      # detaches didn't succeed (unlikely)
7636 2bb5c911 Michael Hanselmann
      self.cfg.ReleaseDRBDMinors(self.instance.name)
7637 a2d59d8b Iustin Pop
      raise errors.OpExecError("Can't detach the disks from the network on"
7638 a2d59d8b Iustin Pop
                               " old node: %s" % (msg,))
7639 642445d9 Iustin Pop
7640 642445d9 Iustin Pop
    # if we managed to detach at least one, we update all the disks of
7641 642445d9 Iustin Pop
    # the instance to point to the new secondary
7642 2bb5c911 Michael Hanselmann
    self.lu.LogInfo("Updating instance configuration")
7643 468b46f9 Iustin Pop
    for dev, _, new_logical_id in iv_names.itervalues():
7644 468b46f9 Iustin Pop
      dev.logical_id = new_logical_id
7645 2bb5c911 Michael Hanselmann
      self.cfg.SetDiskID(dev, self.instance.primary_node)
7646 2bb5c911 Michael Hanselmann
7647 a4eae71f Michael Hanselmann
    self.cfg.Update(self.instance, feedback_fn)
7648 a9e0c397 Iustin Pop
7649 642445d9 Iustin Pop
    # and now perform the drbd attach
7650 2bb5c911 Michael Hanselmann
    self.lu.LogInfo("Attaching primary drbds to new secondary"
7651 2bb5c911 Michael Hanselmann
                    " (standalone => connected)")
7652 4d4a651d Michael Hanselmann
    result = self.rpc.call_drbd_attach_net([self.instance.primary_node,
7653 4d4a651d Michael Hanselmann
                                            self.new_node],
7654 4d4a651d Michael Hanselmann
                                           self.node_secondary_ip,
7655 4d4a651d Michael Hanselmann
                                           self.instance.disks,
7656 4d4a651d Michael Hanselmann
                                           self.instance.name,
7657 a2d59d8b Iustin Pop
                                           False)
7658 a2d59d8b Iustin Pop
    for to_node, to_result in result.items():
7659 4c4e4e1e Iustin Pop
      msg = to_result.fail_msg
7660 a2d59d8b Iustin Pop
      if msg:
7661 4d4a651d Michael Hanselmann
        self.lu.LogWarning("Can't attach drbd disks on node %s: %s",
7662 4d4a651d Michael Hanselmann
                           to_node, msg,
7663 2bb5c911 Michael Hanselmann
                           hint=("please do a gnt-instance info to see the"
7664 2bb5c911 Michael Hanselmann
                                 " status of disks"))
7665 7ea7bcf6 Iustin Pop
    cstep = 5
7666 7ea7bcf6 Iustin Pop
    if self.early_release:
7667 7ea7bcf6 Iustin Pop
      self.lu.LogStep(cstep, steps_total, "Removing old storage")
7668 7ea7bcf6 Iustin Pop
      cstep += 1
7669 7ea7bcf6 Iustin Pop
      self._RemoveOldStorage(self.target_node, iv_names)
7670 d5cd389c Iustin Pop
      # WARNING: we release all node locks here, do not do other RPCs
7671 d5cd389c Iustin Pop
      # than WaitForSync to the primary node
7672 d5cd389c Iustin Pop
      self._ReleaseNodeLock([self.instance.primary_node,
7673 d5cd389c Iustin Pop
                             self.target_node,
7674 d5cd389c Iustin Pop
                             self.new_node])
7675 a9e0c397 Iustin Pop
7676 2bb5c911 Michael Hanselmann
    # Wait for sync
7677 2bb5c911 Michael Hanselmann
    # This can fail as the old devices are degraded and _WaitForSync
7678 2bb5c911 Michael Hanselmann
    # does a combined result over all disks, so we don't check its return value
7679 7ea7bcf6 Iustin Pop
    self.lu.LogStep(cstep, steps_total, "Sync devices")
7680 7ea7bcf6 Iustin Pop
    cstep += 1
7681 b6c07b79 Michael Hanselmann
    _WaitForSync(self.lu, self.instance)
7682 a9e0c397 Iustin Pop
7683 2bb5c911 Michael Hanselmann
    # Check all devices manually
7684 2bb5c911 Michael Hanselmann
    self._CheckDevices(self.instance.primary_node, iv_names)
7685 22985314 Guido Trotter
7686 2bb5c911 Michael Hanselmann
    # Step: remove old storage
7687 7ea7bcf6 Iustin Pop
    if not self.early_release:
7688 7ea7bcf6 Iustin Pop
      self.lu.LogStep(cstep, steps_total, "Removing old storage")
7689 7ea7bcf6 Iustin Pop
      self._RemoveOldStorage(self.target_node, iv_names)
7690 a9e0c397 Iustin Pop
7691 a8083063 Iustin Pop
7692 76aef8fc Michael Hanselmann
class LURepairNodeStorage(NoHooksLU):
7693 76aef8fc Michael Hanselmann
  """Repairs the volume group on a node.
7694 76aef8fc Michael Hanselmann

7695 76aef8fc Michael Hanselmann
  """
7696 76aef8fc Michael Hanselmann
  _OP_REQP = ["node_name"]
7697 76aef8fc Michael Hanselmann
  REQ_BGL = False
7698 76aef8fc Michael Hanselmann
7699 76aef8fc Michael Hanselmann
  def CheckArguments(self):
7700 cf26a87a Iustin Pop
    self.op.node_name = _ExpandNodeName(self.cfg, self.op.node_name)
7701 76aef8fc Michael Hanselmann
7702 0e3baaf3 Iustin Pop
    _CheckStorageType(self.op.storage_type)
7703 0e3baaf3 Iustin Pop
7704 76aef8fc Michael Hanselmann
  def ExpandNames(self):
7705 76aef8fc Michael Hanselmann
    self.needed_locks = {
7706 76aef8fc Michael Hanselmann
      locking.LEVEL_NODE: [self.op.node_name],
7707 76aef8fc Michael Hanselmann
      }
7708 76aef8fc Michael Hanselmann
7709 76aef8fc Michael Hanselmann
  def _CheckFaultyDisks(self, instance, node_name):
7710 7e9c6a78 Iustin Pop
    """Ensure faulty disks abort the opcode or at least warn."""
7711 7e9c6a78 Iustin Pop
    try:
7712 7e9c6a78 Iustin Pop
      if _FindFaultyInstanceDisks(self.cfg, self.rpc, instance,
7713 7e9c6a78 Iustin Pop
                                  node_name, True):
7714 7e9c6a78 Iustin Pop
        raise errors.OpPrereqError("Instance '%s' has faulty disks on"
7715 7e9c6a78 Iustin Pop
                                   " node '%s'" % (instance.name, node_name),
7716 7e9c6a78 Iustin Pop
                                   errors.ECODE_STATE)
7717 7e9c6a78 Iustin Pop
    except errors.OpPrereqError, err:
7718 7e9c6a78 Iustin Pop
      if self.op.ignore_consistency:
7719 7e9c6a78 Iustin Pop
        self.proc.LogWarning(str(err.args[0]))
7720 7e9c6a78 Iustin Pop
      else:
7721 7e9c6a78 Iustin Pop
        raise
7722 76aef8fc Michael Hanselmann
7723 76aef8fc Michael Hanselmann
  def CheckPrereq(self):
7724 76aef8fc Michael Hanselmann
    """Check prerequisites.
7725 76aef8fc Michael Hanselmann

7726 76aef8fc Michael Hanselmann
    """
7727 76aef8fc Michael Hanselmann
    storage_type = self.op.storage_type
7728 76aef8fc Michael Hanselmann
7729 76aef8fc Michael Hanselmann
    if (constants.SO_FIX_CONSISTENCY not in
7730 76aef8fc Michael Hanselmann
        constants.VALID_STORAGE_OPERATIONS.get(storage_type, [])):
7731 76aef8fc Michael Hanselmann
      raise errors.OpPrereqError("Storage units of type '%s' can not be"
7732 5c983ee5 Iustin Pop
                                 " repaired" % storage_type,
7733 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
7734 76aef8fc Michael Hanselmann
7735 76aef8fc Michael Hanselmann
    # Check whether any instance on this node has faulty disks
7736 76aef8fc Michael Hanselmann
    for inst in _GetNodeInstances(self.cfg, self.op.node_name):
7737 7e9c6a78 Iustin Pop
      if not inst.admin_up:
7738 7e9c6a78 Iustin Pop
        continue
7739 76aef8fc Michael Hanselmann
      check_nodes = set(inst.all_nodes)
7740 76aef8fc Michael Hanselmann
      check_nodes.discard(self.op.node_name)
7741 76aef8fc Michael Hanselmann
      for inst_node_name in check_nodes:
7742 76aef8fc Michael Hanselmann
        self._CheckFaultyDisks(inst, inst_node_name)
7743 76aef8fc Michael Hanselmann
7744 76aef8fc Michael Hanselmann
  def Exec(self, feedback_fn):
7745 76aef8fc Michael Hanselmann
    feedback_fn("Repairing storage unit '%s' on %s ..." %
7746 76aef8fc Michael Hanselmann
                (self.op.name, self.op.node_name))
7747 76aef8fc Michael Hanselmann
7748 76aef8fc Michael Hanselmann
    st_args = _GetStorageTypeArgs(self.cfg, self.op.storage_type)
7749 76aef8fc Michael Hanselmann
    result = self.rpc.call_storage_execute(self.op.node_name,
7750 76aef8fc Michael Hanselmann
                                           self.op.storage_type, st_args,
7751 76aef8fc Michael Hanselmann
                                           self.op.name,
7752 76aef8fc Michael Hanselmann
                                           constants.SO_FIX_CONSISTENCY)
7753 76aef8fc Michael Hanselmann
    result.Raise("Failed to repair storage unit '%s' on %s" %
7754 76aef8fc Michael Hanselmann
                 (self.op.name, self.op.node_name))
7755 76aef8fc Michael Hanselmann
7756 76aef8fc Michael Hanselmann
7757 f7e7689f Iustin Pop
class LUNodeEvacuationStrategy(NoHooksLU):
7758 f7e7689f Iustin Pop
  """Computes the node evacuation strategy.
7759 f7e7689f Iustin Pop

7760 f7e7689f Iustin Pop
  """
7761 f7e7689f Iustin Pop
  _OP_REQP = ["nodes"]
7762 f7e7689f Iustin Pop
  REQ_BGL = False
7763 f7e7689f Iustin Pop
7764 f7e7689f Iustin Pop
  def CheckArguments(self):
7765 f7e7689f Iustin Pop
    if not hasattr(self.op, "remote_node"):
7766 f7e7689f Iustin Pop
      self.op.remote_node = None
7767 f7e7689f Iustin Pop
    if not hasattr(self.op, "iallocator"):
7768 f7e7689f Iustin Pop
      self.op.iallocator = None
7769 f7e7689f Iustin Pop
    if self.op.remote_node is not None and self.op.iallocator is not None:
7770 f7e7689f Iustin Pop
      raise errors.OpPrereqError("Give either the iallocator or the new"
7771 f7e7689f Iustin Pop
                                 " secondary, not both", errors.ECODE_INVAL)
7772 f7e7689f Iustin Pop
7773 f7e7689f Iustin Pop
  def ExpandNames(self):
7774 f7e7689f Iustin Pop
    self.op.nodes = _GetWantedNodes(self, self.op.nodes)
7775 f7e7689f Iustin Pop
    self.needed_locks = locks = {}
7776 f7e7689f Iustin Pop
    if self.op.remote_node is None:
7777 f7e7689f Iustin Pop
      locks[locking.LEVEL_NODE] = locking.ALL_SET
7778 f7e7689f Iustin Pop
    else:
7779 f7e7689f Iustin Pop
      self.op.remote_node = _ExpandNodeName(self.cfg, self.op.remote_node)
7780 f7e7689f Iustin Pop
      locks[locking.LEVEL_NODE] = self.op.nodes + [self.op.remote_node]
7781 f7e7689f Iustin Pop
7782 f7e7689f Iustin Pop
  def CheckPrereq(self):
7783 f7e7689f Iustin Pop
    pass
7784 f7e7689f Iustin Pop
7785 f7e7689f Iustin Pop
  def Exec(self, feedback_fn):
7786 f7e7689f Iustin Pop
    if self.op.remote_node is not None:
7787 f7e7689f Iustin Pop
      instances = []
7788 f7e7689f Iustin Pop
      for node in self.op.nodes:
7789 f7e7689f Iustin Pop
        instances.extend(_GetNodeSecondaryInstances(self.cfg, node))
7790 f7e7689f Iustin Pop
      result = []
7791 f7e7689f Iustin Pop
      for i in instances:
7792 f7e7689f Iustin Pop
        if i.primary_node == self.op.remote_node:
7793 f7e7689f Iustin Pop
          raise errors.OpPrereqError("Node %s is the primary node of"
7794 f7e7689f Iustin Pop
                                     " instance %s, cannot use it as"
7795 f7e7689f Iustin Pop
                                     " secondary" %
7796 f7e7689f Iustin Pop
                                     (self.op.remote_node, i.name),
7797 f7e7689f Iustin Pop
                                     errors.ECODE_INVAL)
7798 f7e7689f Iustin Pop
        result.append([i.name, self.op.remote_node])
7799 f7e7689f Iustin Pop
    else:
7800 f7e7689f Iustin Pop
      ial = IAllocator(self.cfg, self.rpc,
7801 f7e7689f Iustin Pop
                       mode=constants.IALLOCATOR_MODE_MEVAC,
7802 f7e7689f Iustin Pop
                       evac_nodes=self.op.nodes)
7803 f7e7689f Iustin Pop
      ial.Run(self.op.iallocator, validate=True)
7804 f7e7689f Iustin Pop
      if not ial.success:
7805 f7e7689f Iustin Pop
        raise errors.OpExecError("No valid evacuation solution: %s" % ial.info,
7806 f7e7689f Iustin Pop
                                 errors.ECODE_NORES)
7807 f7e7689f Iustin Pop
      result = ial.result
7808 f7e7689f Iustin Pop
    return result
7809 f7e7689f Iustin Pop
7810 f7e7689f Iustin Pop
7811 8729e0d7 Iustin Pop
class LUGrowDisk(LogicalUnit):
7812 8729e0d7 Iustin Pop
  """Grow a disk of an instance.
7813 8729e0d7 Iustin Pop

7814 8729e0d7 Iustin Pop
  """
7815 8729e0d7 Iustin Pop
  HPATH = "disk-grow"
7816 8729e0d7 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
7817 6605411d Iustin Pop
  _OP_REQP = ["instance_name", "disk", "amount", "wait_for_sync"]
7818 31e63dbf Guido Trotter
  REQ_BGL = False
7819 31e63dbf Guido Trotter
7820 31e63dbf Guido Trotter
  def ExpandNames(self):
7821 31e63dbf Guido Trotter
    self._ExpandAndLockInstance()
7822 31e63dbf Guido Trotter
    self.needed_locks[locking.LEVEL_NODE] = []
7823 f6d9a522 Guido Trotter
    self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
7824 31e63dbf Guido Trotter
7825 31e63dbf Guido Trotter
  def DeclareLocks(self, level):
7826 31e63dbf Guido Trotter
    if level == locking.LEVEL_NODE:
7827 31e63dbf Guido Trotter
      self._LockInstancesNodes()
7828 8729e0d7 Iustin Pop
7829 8729e0d7 Iustin Pop
  def BuildHooksEnv(self):
7830 8729e0d7 Iustin Pop
    """Build hooks env.
7831 8729e0d7 Iustin Pop

7832 8729e0d7 Iustin Pop
    This runs on the master, the primary and all the secondaries.
7833 8729e0d7 Iustin Pop

7834 8729e0d7 Iustin Pop
    """
7835 8729e0d7 Iustin Pop
    env = {
7836 8729e0d7 Iustin Pop
      "DISK": self.op.disk,
7837 8729e0d7 Iustin Pop
      "AMOUNT": self.op.amount,
7838 8729e0d7 Iustin Pop
      }
7839 338e51e8 Iustin Pop
    env.update(_BuildInstanceHookEnvByObject(self, self.instance))
7840 abd8e836 Iustin Pop
    nl = [self.cfg.GetMasterNode()] + list(self.instance.all_nodes)
7841 8729e0d7 Iustin Pop
    return env, nl, nl
7842 8729e0d7 Iustin Pop
7843 8729e0d7 Iustin Pop
  def CheckPrereq(self):
7844 8729e0d7 Iustin Pop
    """Check prerequisites.
7845 8729e0d7 Iustin Pop

7846 8729e0d7 Iustin Pop
    This checks that the instance is in the cluster.
7847 8729e0d7 Iustin Pop

7848 8729e0d7 Iustin Pop
    """
7849 31e63dbf Guido Trotter
    instance = self.cfg.GetInstanceInfo(self.op.instance_name)
7850 31e63dbf Guido Trotter
    assert instance is not None, \
7851 31e63dbf Guido Trotter
      "Cannot retrieve locked instance %s" % self.op.instance_name
7852 6b12959c Iustin Pop
    nodenames = list(instance.all_nodes)
7853 6b12959c Iustin Pop
    for node in nodenames:
7854 7527a8a4 Iustin Pop
      _CheckNodeOnline(self, node)
7855 7527a8a4 Iustin Pop
7856 31e63dbf Guido Trotter
7857 8729e0d7 Iustin Pop
    self.instance = instance
7858 8729e0d7 Iustin Pop
7859 728489a3 Guido Trotter
    if instance.disk_template not in constants.DTS_GROWABLE:
7860 8729e0d7 Iustin Pop
      raise errors.OpPrereqError("Instance's disk layout does not support"
7861 5c983ee5 Iustin Pop
                                 " growing.", errors.ECODE_INVAL)
7862 8729e0d7 Iustin Pop
7863 ad24e046 Iustin Pop
    self.disk = instance.FindDisk(self.op.disk)
7864 8729e0d7 Iustin Pop
7865 2c42c5df Guido Trotter
    if instance.disk_template != constants.DT_FILE:
7866 2c42c5df Guido Trotter
      # TODO: check the free disk space for file, when that feature will be
7867 2c42c5df Guido Trotter
      # supported
7868 2c42c5df Guido Trotter
      _CheckNodesFreeDisk(self, nodenames, self.op.amount)
7869 8729e0d7 Iustin Pop
7870 8729e0d7 Iustin Pop
  def Exec(self, feedback_fn):
7871 8729e0d7 Iustin Pop
    """Execute disk grow.
7872 8729e0d7 Iustin Pop

7873 8729e0d7 Iustin Pop
    """
7874 8729e0d7 Iustin Pop
    instance = self.instance
7875 ad24e046 Iustin Pop
    disk = self.disk
7876 6b12959c Iustin Pop
    for node in instance.all_nodes:
7877 8729e0d7 Iustin Pop
      self.cfg.SetDiskID(disk, node)
7878 72737a7f Iustin Pop
      result = self.rpc.call_blockdev_grow(node, disk, self.op.amount)
7879 4c4e4e1e Iustin Pop
      result.Raise("Grow request failed to node %s" % node)
7880 5bc556dd Michael Hanselmann
7881 5bc556dd Michael Hanselmann
      # TODO: Rewrite code to work properly
7882 5bc556dd Michael Hanselmann
      # DRBD goes into sync mode for a short amount of time after executing the
7883 5bc556dd Michael Hanselmann
      # "resize" command. DRBD 8.x below version 8.0.13 contains a bug whereby
7884 5bc556dd Michael Hanselmann
      # calling "resize" in sync mode fails. Sleeping for a short amount of
7885 5bc556dd Michael Hanselmann
      # time is a work-around.
7886 5bc556dd Michael Hanselmann
      time.sleep(5)
7887 5bc556dd Michael Hanselmann
7888 8729e0d7 Iustin Pop
    disk.RecordGrow(self.op.amount)
7889 a4eae71f Michael Hanselmann
    self.cfg.Update(instance, feedback_fn)
7890 6605411d Iustin Pop
    if self.op.wait_for_sync:
7891 cd4d138f Guido Trotter
      disk_abort = not _WaitForSync(self, instance)
7892 6605411d Iustin Pop
      if disk_abort:
7893 86d9d3bb Iustin Pop
        self.proc.LogWarning("Warning: disk sync-ing has not returned a good"
7894 86d9d3bb Iustin Pop
                             " status.\nPlease check the instance.")
7895 8729e0d7 Iustin Pop
7896 8729e0d7 Iustin Pop
7897 a8083063 Iustin Pop
class LUQueryInstanceData(NoHooksLU):
7898 a8083063 Iustin Pop
  """Query runtime instance data.
7899 a8083063 Iustin Pop

7900 a8083063 Iustin Pop
  """
7901 57821cac Iustin Pop
  _OP_REQP = ["instances", "static"]
7902 a987fa48 Guido Trotter
  REQ_BGL = False
7903 ae5849b5 Michael Hanselmann
7904 a987fa48 Guido Trotter
  def ExpandNames(self):
7905 a987fa48 Guido Trotter
    self.needed_locks = {}
7906 c772d142 Michael Hanselmann
    self.share_locks = dict.fromkeys(locking.LEVELS, 1)
7907 a987fa48 Guido Trotter
7908 a987fa48 Guido Trotter
    if not isinstance(self.op.instances, list):
7909 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Invalid argument type 'instances'",
7910 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
7911 a987fa48 Guido Trotter
7912 a987fa48 Guido Trotter
    if self.op.instances:
7913 a987fa48 Guido Trotter
      self.wanted_names = []
7914 a987fa48 Guido Trotter
      for name in self.op.instances:
7915 cf26a87a Iustin Pop
        full_name = _ExpandInstanceName(self.cfg, name)
7916 a987fa48 Guido Trotter
        self.wanted_names.append(full_name)
7917 a987fa48 Guido Trotter
      self.needed_locks[locking.LEVEL_INSTANCE] = self.wanted_names
7918 a987fa48 Guido Trotter
    else:
7919 a987fa48 Guido Trotter
      self.wanted_names = None
7920 a987fa48 Guido Trotter
      self.needed_locks[locking.LEVEL_INSTANCE] = locking.ALL_SET
7921 a987fa48 Guido Trotter
7922 a987fa48 Guido Trotter
    self.needed_locks[locking.LEVEL_NODE] = []
7923 a987fa48 Guido Trotter
    self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
7924 a987fa48 Guido Trotter
7925 a987fa48 Guido Trotter
  def DeclareLocks(self, level):
7926 a987fa48 Guido Trotter
    if level == locking.LEVEL_NODE:
7927 a987fa48 Guido Trotter
      self._LockInstancesNodes()
7928 a8083063 Iustin Pop
7929 a8083063 Iustin Pop
  def CheckPrereq(self):
7930 a8083063 Iustin Pop
    """Check prerequisites.
7931 a8083063 Iustin Pop

7932 a8083063 Iustin Pop
    This only checks the optional instance list against the existing names.
7933 a8083063 Iustin Pop

7934 a8083063 Iustin Pop
    """
7935 a987fa48 Guido Trotter
    if self.wanted_names is None:
7936 a987fa48 Guido Trotter
      self.wanted_names = self.acquired_locks[locking.LEVEL_INSTANCE]
7937 a8083063 Iustin Pop
7938 a987fa48 Guido Trotter
    self.wanted_instances = [self.cfg.GetInstanceInfo(name) for name
7939 a987fa48 Guido Trotter
                             in self.wanted_names]
7940 a987fa48 Guido Trotter
    return
7941 a8083063 Iustin Pop
7942 98825740 Michael Hanselmann
  def _ComputeBlockdevStatus(self, node, instance_name, dev):
7943 98825740 Michael Hanselmann
    """Returns the status of a block device
7944 98825740 Michael Hanselmann

7945 98825740 Michael Hanselmann
    """
7946 4dce1a83 Michael Hanselmann
    if self.op.static or not node:
7947 98825740 Michael Hanselmann
      return None
7948 98825740 Michael Hanselmann
7949 98825740 Michael Hanselmann
    self.cfg.SetDiskID(dev, node)
7950 98825740 Michael Hanselmann
7951 98825740 Michael Hanselmann
    result = self.rpc.call_blockdev_find(node, dev)
7952 98825740 Michael Hanselmann
    if result.offline:
7953 98825740 Michael Hanselmann
      return None
7954 98825740 Michael Hanselmann
7955 98825740 Michael Hanselmann
    result.Raise("Can't compute disk status for %s" % instance_name)
7956 98825740 Michael Hanselmann
7957 98825740 Michael Hanselmann
    status = result.payload
7958 ddfe2228 Michael Hanselmann
    if status is None:
7959 ddfe2228 Michael Hanselmann
      return None
7960 98825740 Michael Hanselmann
7961 98825740 Michael Hanselmann
    return (status.dev_path, status.major, status.minor,
7962 98825740 Michael Hanselmann
            status.sync_percent, status.estimated_time,
7963 f208978a Michael Hanselmann
            status.is_degraded, status.ldisk_status)
7964 98825740 Michael Hanselmann
7965 a8083063 Iustin Pop
  def _ComputeDiskStatus(self, instance, snode, dev):
7966 a8083063 Iustin Pop
    """Compute block device status.
7967 a8083063 Iustin Pop

7968 a8083063 Iustin Pop
    """
7969 a1f445d3 Iustin Pop
    if dev.dev_type in constants.LDS_DRBD:
7970 a8083063 Iustin Pop
      # we change the snode then (otherwise we use the one passed in)
7971 a8083063 Iustin Pop
      if dev.logical_id[0] == instance.primary_node:
7972 a8083063 Iustin Pop
        snode = dev.logical_id[1]
7973 a8083063 Iustin Pop
      else:
7974 a8083063 Iustin Pop
        snode = dev.logical_id[0]
7975 a8083063 Iustin Pop
7976 98825740 Michael Hanselmann
    dev_pstatus = self._ComputeBlockdevStatus(instance.primary_node,
7977 98825740 Michael Hanselmann
                                              instance.name, dev)
7978 98825740 Michael Hanselmann
    dev_sstatus = self._ComputeBlockdevStatus(snode, instance.name, dev)
7979 a8083063 Iustin Pop
7980 a8083063 Iustin Pop
    if dev.children:
7981 a8083063 Iustin Pop
      dev_children = [self._ComputeDiskStatus(instance, snode, child)
7982 a8083063 Iustin Pop
                      for child in dev.children]
7983 a8083063 Iustin Pop
    else:
7984 a8083063 Iustin Pop
      dev_children = []
7985 a8083063 Iustin Pop
7986 a8083063 Iustin Pop
    data = {
7987 a8083063 Iustin Pop
      "iv_name": dev.iv_name,
7988 a8083063 Iustin Pop
      "dev_type": dev.dev_type,
7989 a8083063 Iustin Pop
      "logical_id": dev.logical_id,
7990 a8083063 Iustin Pop
      "physical_id": dev.physical_id,
7991 a8083063 Iustin Pop
      "pstatus": dev_pstatus,
7992 a8083063 Iustin Pop
      "sstatus": dev_sstatus,
7993 a8083063 Iustin Pop
      "children": dev_children,
7994 b6fdf8b8 Iustin Pop
      "mode": dev.mode,
7995 c98162a7 Iustin Pop
      "size": dev.size,
7996 a8083063 Iustin Pop
      }
7997 a8083063 Iustin Pop
7998 a8083063 Iustin Pop
    return data
7999 a8083063 Iustin Pop
8000 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
8001 a8083063 Iustin Pop
    """Gather and return data"""
8002 a8083063 Iustin Pop
    result = {}
8003 338e51e8 Iustin Pop
8004 338e51e8 Iustin Pop
    cluster = self.cfg.GetClusterInfo()
8005 338e51e8 Iustin Pop
8006 a8083063 Iustin Pop
    for instance in self.wanted_instances:
8007 57821cac Iustin Pop
      if not self.op.static:
8008 57821cac Iustin Pop
        remote_info = self.rpc.call_instance_info(instance.primary_node,
8009 57821cac Iustin Pop
                                                  instance.name,
8010 57821cac Iustin Pop
                                                  instance.hypervisor)
8011 4c4e4e1e Iustin Pop
        remote_info.Raise("Error checking node %s" % instance.primary_node)
8012 7ad1af4a Iustin Pop
        remote_info = remote_info.payload
8013 57821cac Iustin Pop
        if remote_info and "state" in remote_info:
8014 57821cac Iustin Pop
          remote_state = "up"
8015 57821cac Iustin Pop
        else:
8016 57821cac Iustin Pop
          remote_state = "down"
8017 a8083063 Iustin Pop
      else:
8018 57821cac Iustin Pop
        remote_state = None
8019 0d68c45d Iustin Pop
      if instance.admin_up:
8020 a8083063 Iustin Pop
        config_state = "up"
8021 0d68c45d Iustin Pop
      else:
8022 0d68c45d Iustin Pop
        config_state = "down"
8023 a8083063 Iustin Pop
8024 a8083063 Iustin Pop
      disks = [self._ComputeDiskStatus(instance, None, device)
8025 a8083063 Iustin Pop
               for device in instance.disks]
8026 a8083063 Iustin Pop
8027 a8083063 Iustin Pop
      idict = {
8028 a8083063 Iustin Pop
        "name": instance.name,
8029 a8083063 Iustin Pop
        "config_state": config_state,
8030 a8083063 Iustin Pop
        "run_state": remote_state,
8031 a8083063 Iustin Pop
        "pnode": instance.primary_node,
8032 a8083063 Iustin Pop
        "snodes": instance.secondary_nodes,
8033 a8083063 Iustin Pop
        "os": instance.os,
8034 0b13832c Guido Trotter
        # this happens to be the same format used for hooks
8035 0b13832c Guido Trotter
        "nics": _NICListToTuple(self, instance.nics),
8036 a8083063 Iustin Pop
        "disks": disks,
8037 e69d05fd Iustin Pop
        "hypervisor": instance.hypervisor,
8038 24838135 Iustin Pop
        "network_port": instance.network_port,
8039 24838135 Iustin Pop
        "hv_instance": instance.hvparams,
8040 7736a5f2 Iustin Pop
        "hv_actual": cluster.FillHV(instance, skip_globals=True),
8041 338e51e8 Iustin Pop
        "be_instance": instance.beparams,
8042 338e51e8 Iustin Pop
        "be_actual": cluster.FillBE(instance),
8043 90f72445 Iustin Pop
        "serial_no": instance.serial_no,
8044 90f72445 Iustin Pop
        "mtime": instance.mtime,
8045 90f72445 Iustin Pop
        "ctime": instance.ctime,
8046 033d58b0 Iustin Pop
        "uuid": instance.uuid,
8047 a8083063 Iustin Pop
        }
8048 a8083063 Iustin Pop
8049 a8083063 Iustin Pop
      result[instance.name] = idict
8050 a8083063 Iustin Pop
8051 a8083063 Iustin Pop
    return result
8052 a8083063 Iustin Pop
8053 a8083063 Iustin Pop
8054 7767bbf5 Manuel Franceschini
class LUSetInstanceParams(LogicalUnit):
8055 a8083063 Iustin Pop
  """Modifies an instances's parameters.
8056 a8083063 Iustin Pop

8057 a8083063 Iustin Pop
  """
8058 a8083063 Iustin Pop
  HPATH = "instance-modify"
8059 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
8060 24991749 Iustin Pop
  _OP_REQP = ["instance_name"]
8061 1a5c7281 Guido Trotter
  REQ_BGL = False
8062 1a5c7281 Guido Trotter
8063 24991749 Iustin Pop
  def CheckArguments(self):
8064 24991749 Iustin Pop
    if not hasattr(self.op, 'nics'):
8065 24991749 Iustin Pop
      self.op.nics = []
8066 24991749 Iustin Pop
    if not hasattr(self.op, 'disks'):
8067 24991749 Iustin Pop
      self.op.disks = []
8068 24991749 Iustin Pop
    if not hasattr(self.op, 'beparams'):
8069 24991749 Iustin Pop
      self.op.beparams = {}
8070 24991749 Iustin Pop
    if not hasattr(self.op, 'hvparams'):
8071 24991749 Iustin Pop
      self.op.hvparams = {}
8072 e29e9550 Iustin Pop
    if not hasattr(self.op, "disk_template"):
8073 e29e9550 Iustin Pop
      self.op.disk_template = None
8074 e29e9550 Iustin Pop
    if not hasattr(self.op, "remote_node"):
8075 e29e9550 Iustin Pop
      self.op.remote_node = None
8076 96b39bcc Iustin Pop
    if not hasattr(self.op, "os_name"):
8077 96b39bcc Iustin Pop
      self.op.os_name = None
8078 96b39bcc Iustin Pop
    if not hasattr(self.op, "force_variant"):
8079 96b39bcc Iustin Pop
      self.op.force_variant = False
8080 24991749 Iustin Pop
    self.op.force = getattr(self.op, "force", False)
8081 e29e9550 Iustin Pop
    if not (self.op.nics or self.op.disks or self.op.disk_template or
8082 96b39bcc Iustin Pop
            self.op.hvparams or self.op.beparams or self.op.os_name):
8083 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("No changes submitted", errors.ECODE_INVAL)
8084 24991749 Iustin Pop
8085 7736a5f2 Iustin Pop
    if self.op.hvparams:
8086 7736a5f2 Iustin Pop
      _CheckGlobalHvParams(self.op.hvparams)
8087 7736a5f2 Iustin Pop
8088 24991749 Iustin Pop
    # Disk validation
8089 24991749 Iustin Pop
    disk_addremove = 0
8090 24991749 Iustin Pop
    for disk_op, disk_dict in self.op.disks:
8091 24991749 Iustin Pop
      if disk_op == constants.DDM_REMOVE:
8092 24991749 Iustin Pop
        disk_addremove += 1
8093 24991749 Iustin Pop
        continue
8094 24991749 Iustin Pop
      elif disk_op == constants.DDM_ADD:
8095 24991749 Iustin Pop
        disk_addremove += 1
8096 24991749 Iustin Pop
      else:
8097 24991749 Iustin Pop
        if not isinstance(disk_op, int):
8098 5c983ee5 Iustin Pop
          raise errors.OpPrereqError("Invalid disk index", errors.ECODE_INVAL)
8099 8b46606c Guido Trotter
        if not isinstance(disk_dict, dict):
8100 8b46606c Guido Trotter
          msg = "Invalid disk value: expected dict, got '%s'" % disk_dict
8101 5c983ee5 Iustin Pop
          raise errors.OpPrereqError(msg, errors.ECODE_INVAL)
8102 8b46606c Guido Trotter
8103 24991749 Iustin Pop
      if disk_op == constants.DDM_ADD:
8104 24991749 Iustin Pop
        mode = disk_dict.setdefault('mode', constants.DISK_RDWR)
8105 6ec66eae Iustin Pop
        if mode not in constants.DISK_ACCESS_SET:
8106 5c983ee5 Iustin Pop
          raise errors.OpPrereqError("Invalid disk access mode '%s'" % mode,
8107 5c983ee5 Iustin Pop
                                     errors.ECODE_INVAL)
8108 24991749 Iustin Pop
        size = disk_dict.get('size', None)
8109 24991749 Iustin Pop
        if size is None:
8110 5c983ee5 Iustin Pop
          raise errors.OpPrereqError("Required disk parameter size missing",
8111 5c983ee5 Iustin Pop
                                     errors.ECODE_INVAL)
8112 24991749 Iustin Pop
        try:
8113 24991749 Iustin Pop
          size = int(size)
8114 691744c4 Iustin Pop
        except (TypeError, ValueError), err:
8115 24991749 Iustin Pop
          raise errors.OpPrereqError("Invalid disk size parameter: %s" %
8116 5c983ee5 Iustin Pop
                                     str(err), errors.ECODE_INVAL)
8117 24991749 Iustin Pop
        disk_dict['size'] = size
8118 24991749 Iustin Pop
      else:
8119 24991749 Iustin Pop
        # modification of disk
8120 24991749 Iustin Pop
        if 'size' in disk_dict:
8121 24991749 Iustin Pop
          raise errors.OpPrereqError("Disk size change not possible, use"
8122 5c983ee5 Iustin Pop
                                     " grow-disk", errors.ECODE_INVAL)
8123 24991749 Iustin Pop
8124 24991749 Iustin Pop
    if disk_addremove > 1:
8125 24991749 Iustin Pop
      raise errors.OpPrereqError("Only one disk add or remove operation"
8126 5c983ee5 Iustin Pop
                                 " supported at a time", errors.ECODE_INVAL)
8127 24991749 Iustin Pop
8128 e29e9550 Iustin Pop
    if self.op.disks and self.op.disk_template is not None:
8129 e29e9550 Iustin Pop
      raise errors.OpPrereqError("Disk template conversion and other disk"
8130 e29e9550 Iustin Pop
                                 " changes not supported at the same time",
8131 e29e9550 Iustin Pop
                                 errors.ECODE_INVAL)
8132 e29e9550 Iustin Pop
8133 e29e9550 Iustin Pop
    if self.op.disk_template:
8134 e29e9550 Iustin Pop
      _CheckDiskTemplate(self.op.disk_template)
8135 e29e9550 Iustin Pop
      if (self.op.disk_template in constants.DTS_NET_MIRROR and
8136 e29e9550 Iustin Pop
          self.op.remote_node is None):
8137 e29e9550 Iustin Pop
        raise errors.OpPrereqError("Changing the disk template to a mirrored"
8138 e29e9550 Iustin Pop
                                   " one requires specifying a secondary node",
8139 e29e9550 Iustin Pop
                                   errors.ECODE_INVAL)
8140 e29e9550 Iustin Pop
8141 24991749 Iustin Pop
    # NIC validation
8142 24991749 Iustin Pop
    nic_addremove = 0
8143 24991749 Iustin Pop
    for nic_op, nic_dict in self.op.nics:
8144 24991749 Iustin Pop
      if nic_op == constants.DDM_REMOVE:
8145 24991749 Iustin Pop
        nic_addremove += 1
8146 24991749 Iustin Pop
        continue
8147 24991749 Iustin Pop
      elif nic_op == constants.DDM_ADD:
8148 24991749 Iustin Pop
        nic_addremove += 1
8149 24991749 Iustin Pop
      else:
8150 24991749 Iustin Pop
        if not isinstance(nic_op, int):
8151 5c983ee5 Iustin Pop
          raise errors.OpPrereqError("Invalid nic index", errors.ECODE_INVAL)
8152 8b46606c Guido Trotter
        if not isinstance(nic_dict, dict):
8153 8b46606c Guido Trotter
          msg = "Invalid nic value: expected dict, got '%s'" % nic_dict
8154 5c983ee5 Iustin Pop
          raise errors.OpPrereqError(msg, errors.ECODE_INVAL)
8155 24991749 Iustin Pop
8156 24991749 Iustin Pop
      # nic_dict should be a dict
8157 24991749 Iustin Pop
      nic_ip = nic_dict.get('ip', None)
8158 24991749 Iustin Pop
      if nic_ip is not None:
8159 5c44da6a Guido Trotter
        if nic_ip.lower() == constants.VALUE_NONE:
8160 24991749 Iustin Pop
          nic_dict['ip'] = None
8161 24991749 Iustin Pop
        else:
8162 24991749 Iustin Pop
          if not utils.IsValidIP(nic_ip):
8163 5c983ee5 Iustin Pop
            raise errors.OpPrereqError("Invalid IP address '%s'" % nic_ip,
8164 5c983ee5 Iustin Pop
                                       errors.ECODE_INVAL)
8165 5c44da6a Guido Trotter
8166 cd098c41 Guido Trotter
      nic_bridge = nic_dict.get('bridge', None)
8167 cd098c41 Guido Trotter
      nic_link = nic_dict.get('link', None)
8168 cd098c41 Guido Trotter
      if nic_bridge and nic_link:
8169 29921401 Iustin Pop
        raise errors.OpPrereqError("Cannot pass 'bridge' and 'link'"
8170 5c983ee5 Iustin Pop
                                   " at the same time", errors.ECODE_INVAL)
8171 cd098c41 Guido Trotter
      elif nic_bridge and nic_bridge.lower() == constants.VALUE_NONE:
8172 cd098c41 Guido Trotter
        nic_dict['bridge'] = None
8173 cd098c41 Guido Trotter
      elif nic_link and nic_link.lower() == constants.VALUE_NONE:
8174 cd098c41 Guido Trotter
        nic_dict['link'] = None
8175 cd098c41 Guido Trotter
8176 5c44da6a Guido Trotter
      if nic_op == constants.DDM_ADD:
8177 5c44da6a Guido Trotter
        nic_mac = nic_dict.get('mac', None)
8178 5c44da6a Guido Trotter
        if nic_mac is None:
8179 5c44da6a Guido Trotter
          nic_dict['mac'] = constants.VALUE_AUTO
8180 5c44da6a Guido Trotter
8181 5c44da6a Guido Trotter
      if 'mac' in nic_dict:
8182 5c44da6a Guido Trotter
        nic_mac = nic_dict['mac']
8183 24991749 Iustin Pop
        if nic_mac not in (constants.VALUE_AUTO, constants.VALUE_GENERATE):
8184 82187135 Renรฉ Nussbaumer
          nic_mac = utils.NormalizeAndValidateMac(nic_mac)
8185 82187135 Renรฉ Nussbaumer
8186 5c44da6a Guido Trotter
        if nic_op != constants.DDM_ADD and nic_mac == constants.VALUE_AUTO:
8187 5c44da6a Guido Trotter
          raise errors.OpPrereqError("'auto' is not a valid MAC address when"
8188 5c983ee5 Iustin Pop
                                     " modifying an existing nic",
8189 5c983ee5 Iustin Pop
                                     errors.ECODE_INVAL)
8190 5c44da6a Guido Trotter
8191 24991749 Iustin Pop
    if nic_addremove > 1:
8192 24991749 Iustin Pop
      raise errors.OpPrereqError("Only one NIC add or remove operation"
8193 5c983ee5 Iustin Pop
                                 " supported at a time", errors.ECODE_INVAL)
8194 24991749 Iustin Pop
8195 1a5c7281 Guido Trotter
  def ExpandNames(self):
8196 1a5c7281 Guido Trotter
    self._ExpandAndLockInstance()
8197 74409b12 Iustin Pop
    self.needed_locks[locking.LEVEL_NODE] = []
8198 74409b12 Iustin Pop
    self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
8199 74409b12 Iustin Pop
8200 74409b12 Iustin Pop
  def DeclareLocks(self, level):
8201 74409b12 Iustin Pop
    if level == locking.LEVEL_NODE:
8202 74409b12 Iustin Pop
      self._LockInstancesNodes()
8203 e29e9550 Iustin Pop
      if self.op.disk_template and self.op.remote_node:
8204 e29e9550 Iustin Pop
        self.op.remote_node = _ExpandNodeName(self.cfg, self.op.remote_node)
8205 e29e9550 Iustin Pop
        self.needed_locks[locking.LEVEL_NODE].append(self.op.remote_node)
8206 a8083063 Iustin Pop
8207 a8083063 Iustin Pop
  def BuildHooksEnv(self):
8208 a8083063 Iustin Pop
    """Build hooks env.
8209 a8083063 Iustin Pop

8210 a8083063 Iustin Pop
    This runs on the master, primary and secondaries.
8211 a8083063 Iustin Pop

8212 a8083063 Iustin Pop
    """
8213 396e1b78 Michael Hanselmann
    args = dict()
8214 338e51e8 Iustin Pop
    if constants.BE_MEMORY in self.be_new:
8215 338e51e8 Iustin Pop
      args['memory'] = self.be_new[constants.BE_MEMORY]
8216 338e51e8 Iustin Pop
    if constants.BE_VCPUS in self.be_new:
8217 61be6ba4 Iustin Pop
      args['vcpus'] = self.be_new[constants.BE_VCPUS]
8218 d8dcf3c9 Guido Trotter
    # TODO: export disk changes. Note: _BuildInstanceHookEnv* don't export disk
8219 d8dcf3c9 Guido Trotter
    # information at all.
8220 d8dcf3c9 Guido Trotter
    if self.op.nics:
8221 d8dcf3c9 Guido Trotter
      args['nics'] = []
8222 d8dcf3c9 Guido Trotter
      nic_override = dict(self.op.nics)
8223 62f0dd02 Guido Trotter
      c_nicparams = self.cluster.nicparams[constants.PP_DEFAULT]
8224 d8dcf3c9 Guido Trotter
      for idx, nic in enumerate(self.instance.nics):
8225 d8dcf3c9 Guido Trotter
        if idx in nic_override:
8226 d8dcf3c9 Guido Trotter
          this_nic_override = nic_override[idx]
8227 d8dcf3c9 Guido Trotter
        else:
8228 d8dcf3c9 Guido Trotter
          this_nic_override = {}
8229 d8dcf3c9 Guido Trotter
        if 'ip' in this_nic_override:
8230 d8dcf3c9 Guido Trotter
          ip = this_nic_override['ip']
8231 d8dcf3c9 Guido Trotter
        else:
8232 d8dcf3c9 Guido Trotter
          ip = nic.ip
8233 d8dcf3c9 Guido Trotter
        if 'mac' in this_nic_override:
8234 d8dcf3c9 Guido Trotter
          mac = this_nic_override['mac']
8235 d8dcf3c9 Guido Trotter
        else:
8236 d8dcf3c9 Guido Trotter
          mac = nic.mac
8237 62f0dd02 Guido Trotter
        if idx in self.nic_pnew:
8238 62f0dd02 Guido Trotter
          nicparams = self.nic_pnew[idx]
8239 62f0dd02 Guido Trotter
        else:
8240 62f0dd02 Guido Trotter
          nicparams = objects.FillDict(c_nicparams, nic.nicparams)
8241 62f0dd02 Guido Trotter
        mode = nicparams[constants.NIC_MODE]
8242 62f0dd02 Guido Trotter
        link = nicparams[constants.NIC_LINK]
8243 62f0dd02 Guido Trotter
        args['nics'].append((ip, mac, mode, link))
8244 d8dcf3c9 Guido Trotter
      if constants.DDM_ADD in nic_override:
8245 d8dcf3c9 Guido Trotter
        ip = nic_override[constants.DDM_ADD].get('ip', None)
8246 d8dcf3c9 Guido Trotter
        mac = nic_override[constants.DDM_ADD]['mac']
8247 62f0dd02 Guido Trotter
        nicparams = self.nic_pnew[constants.DDM_ADD]
8248 62f0dd02 Guido Trotter
        mode = nicparams[constants.NIC_MODE]
8249 62f0dd02 Guido Trotter
        link = nicparams[constants.NIC_LINK]
8250 62f0dd02 Guido Trotter
        args['nics'].append((ip, mac, mode, link))
8251 d8dcf3c9 Guido Trotter
      elif constants.DDM_REMOVE in nic_override:
8252 d8dcf3c9 Guido Trotter
        del args['nics'][-1]
8253 d8dcf3c9 Guido Trotter
8254 338e51e8 Iustin Pop
    env = _BuildInstanceHookEnvByObject(self, self.instance, override=args)
8255 e29e9550 Iustin Pop
    if self.op.disk_template:
8256 e29e9550 Iustin Pop
      env["NEW_DISK_TEMPLATE"] = self.op.disk_template
8257 6b12959c Iustin Pop
    nl = [self.cfg.GetMasterNode()] + list(self.instance.all_nodes)
8258 a8083063 Iustin Pop
    return env, nl, nl
8259 a8083063 Iustin Pop
8260 7e950d31 Iustin Pop
  @staticmethod
8261 7e950d31 Iustin Pop
  def _GetUpdatedParams(old_params, update_dict,
8262 0329617a Guido Trotter
                        default_values, parameter_types):
8263 0329617a Guido Trotter
    """Return the new params dict for the given params.
8264 0329617a Guido Trotter

8265 0329617a Guido Trotter
    @type old_params: dict
8266 f2fd87d7 Iustin Pop
    @param old_params: old parameters
8267 0329617a Guido Trotter
    @type update_dict: dict
8268 f2fd87d7 Iustin Pop
    @param update_dict: dict containing new parameter values,
8269 f2fd87d7 Iustin Pop
                        or constants.VALUE_DEFAULT to reset the
8270 f2fd87d7 Iustin Pop
                        parameter to its default value
8271 0329617a Guido Trotter
    @type default_values: dict
8272 0329617a Guido Trotter
    @param default_values: default values for the filled parameters
8273 0329617a Guido Trotter
    @type parameter_types: dict
8274 0329617a Guido Trotter
    @param parameter_types: dict mapping target dict keys to types
8275 0329617a Guido Trotter
                            in constants.ENFORCEABLE_TYPES
8276 0329617a Guido Trotter
    @rtype: (dict, dict)
8277 0329617a Guido Trotter
    @return: (new_parameters, filled_parameters)
8278 0329617a Guido Trotter

8279 0329617a Guido Trotter
    """
8280 0329617a Guido Trotter
    params_copy = copy.deepcopy(old_params)
8281 0329617a Guido Trotter
    for key, val in update_dict.iteritems():
8282 0329617a Guido Trotter
      if val == constants.VALUE_DEFAULT:
8283 0329617a Guido Trotter
        try:
8284 0329617a Guido Trotter
          del params_copy[key]
8285 0329617a Guido Trotter
        except KeyError:
8286 0329617a Guido Trotter
          pass
8287 0329617a Guido Trotter
      else:
8288 0329617a Guido Trotter
        params_copy[key] = val
8289 0329617a Guido Trotter
    utils.ForceDictType(params_copy, parameter_types)
8290 0329617a Guido Trotter
    params_filled = objects.FillDict(default_values, params_copy)
8291 0329617a Guido Trotter
    return (params_copy, params_filled)
8292 0329617a Guido Trotter
8293 a8083063 Iustin Pop
  def CheckPrereq(self):
8294 a8083063 Iustin Pop
    """Check prerequisites.
8295 a8083063 Iustin Pop

8296 a8083063 Iustin Pop
    This only checks the instance list against the existing names.
8297 a8083063 Iustin Pop

8298 a8083063 Iustin Pop
    """
8299 7c4d6c7b Michael Hanselmann
    self.force = self.op.force
8300 a8083063 Iustin Pop
8301 74409b12 Iustin Pop
    # checking the new params on the primary/secondary nodes
8302 31a853d2 Iustin Pop
8303 cfefe007 Guido Trotter
    instance = self.instance = self.cfg.GetInstanceInfo(self.op.instance_name)
8304 2ee88aeb Guido Trotter
    cluster = self.cluster = self.cfg.GetClusterInfo()
8305 1a5c7281 Guido Trotter
    assert self.instance is not None, \
8306 1a5c7281 Guido Trotter
      "Cannot retrieve locked instance %s" % self.op.instance_name
8307 6b12959c Iustin Pop
    pnode = instance.primary_node
8308 6b12959c Iustin Pop
    nodelist = list(instance.all_nodes)
8309 74409b12 Iustin Pop
8310 e29e9550 Iustin Pop
    if self.op.disk_template:
8311 e29e9550 Iustin Pop
      if instance.disk_template == self.op.disk_template:
8312 e29e9550 Iustin Pop
        raise errors.OpPrereqError("Instance already has disk template %s" %
8313 e29e9550 Iustin Pop
                                   instance.disk_template, errors.ECODE_INVAL)
8314 e29e9550 Iustin Pop
8315 e29e9550 Iustin Pop
      if (instance.disk_template,
8316 e29e9550 Iustin Pop
          self.op.disk_template) not in self._DISK_CONVERSIONS:
8317 e29e9550 Iustin Pop
        raise errors.OpPrereqError("Unsupported disk template conversion from"
8318 e29e9550 Iustin Pop
                                   " %s to %s" % (instance.disk_template,
8319 e29e9550 Iustin Pop
                                                  self.op.disk_template),
8320 e29e9550 Iustin Pop
                                   errors.ECODE_INVAL)
8321 e29e9550 Iustin Pop
      if self.op.disk_template in constants.DTS_NET_MIRROR:
8322 e29e9550 Iustin Pop
        _CheckNodeOnline(self, self.op.remote_node)
8323 e29e9550 Iustin Pop
        _CheckNodeNotDrained(self, self.op.remote_node)
8324 e29e9550 Iustin Pop
        disks = [{"size": d.size} for d in instance.disks]
8325 e29e9550 Iustin Pop
        required = _ComputeDiskSize(self.op.disk_template, disks)
8326 e29e9550 Iustin Pop
        _CheckNodesFreeDisk(self, [self.op.remote_node], required)
8327 e29e9550 Iustin Pop
        _CheckInstanceDown(self, instance, "cannot change disk template")
8328 e29e9550 Iustin Pop
8329 338e51e8 Iustin Pop
    # hvparams processing
8330 74409b12 Iustin Pop
    if self.op.hvparams:
8331 0329617a Guido Trotter
      i_hvdict, hv_new = self._GetUpdatedParams(
8332 0329617a Guido Trotter
                             instance.hvparams, self.op.hvparams,
8333 0329617a Guido Trotter
                             cluster.hvparams[instance.hypervisor],
8334 0329617a Guido Trotter
                             constants.HVS_PARAMETER_TYPES)
8335 74409b12 Iustin Pop
      # local check
8336 74409b12 Iustin Pop
      hypervisor.GetHypervisor(
8337 74409b12 Iustin Pop
        instance.hypervisor).CheckParameterSyntax(hv_new)
8338 74409b12 Iustin Pop
      _CheckHVParams(self, nodelist, instance.hypervisor, hv_new)
8339 338e51e8 Iustin Pop
      self.hv_new = hv_new # the new actual values
8340 338e51e8 Iustin Pop
      self.hv_inst = i_hvdict # the new dict (without defaults)
8341 338e51e8 Iustin Pop
    else:
8342 338e51e8 Iustin Pop
      self.hv_new = self.hv_inst = {}
8343 338e51e8 Iustin Pop
8344 338e51e8 Iustin Pop
    # beparams processing
8345 338e51e8 Iustin Pop
    if self.op.beparams:
8346 0329617a Guido Trotter
      i_bedict, be_new = self._GetUpdatedParams(
8347 0329617a Guido Trotter
                             instance.beparams, self.op.beparams,
8348 0329617a Guido Trotter
                             cluster.beparams[constants.PP_DEFAULT],
8349 0329617a Guido Trotter
                             constants.BES_PARAMETER_TYPES)
8350 338e51e8 Iustin Pop
      self.be_new = be_new # the new actual values
8351 338e51e8 Iustin Pop
      self.be_inst = i_bedict # the new dict (without defaults)
8352 338e51e8 Iustin Pop
    else:
8353 b637ae4d Iustin Pop
      self.be_new = self.be_inst = {}
8354 74409b12 Iustin Pop
8355 cfefe007 Guido Trotter
    self.warn = []
8356 647a5d80 Iustin Pop
8357 338e51e8 Iustin Pop
    if constants.BE_MEMORY in self.op.beparams and not self.force:
8358 647a5d80 Iustin Pop
      mem_check_list = [pnode]
8359 c0f2b229 Iustin Pop
      if be_new[constants.BE_AUTO_BALANCE]:
8360 c0f2b229 Iustin Pop
        # either we changed auto_balance to yes or it was from before
8361 647a5d80 Iustin Pop
        mem_check_list.extend(instance.secondary_nodes)
8362 72737a7f Iustin Pop
      instance_info = self.rpc.call_instance_info(pnode, instance.name,
8363 72737a7f Iustin Pop
                                                  instance.hypervisor)
8364 647a5d80 Iustin Pop
      nodeinfo = self.rpc.call_node_info(mem_check_list, self.cfg.GetVGName(),
8365 72737a7f Iustin Pop
                                         instance.hypervisor)
8366 070e998b Iustin Pop
      pninfo = nodeinfo[pnode]
8367 4c4e4e1e Iustin Pop
      msg = pninfo.fail_msg
8368 070e998b Iustin Pop
      if msg:
8369 cfefe007 Guido Trotter
        # Assume the primary node is unreachable and go ahead
8370 070e998b Iustin Pop
        self.warn.append("Can't get info from primary node %s: %s" %
8371 070e998b Iustin Pop
                         (pnode,  msg))
8372 070e998b Iustin Pop
      elif not isinstance(pninfo.payload.get('memory_free', None), int):
8373 070e998b Iustin Pop
        self.warn.append("Node data from primary node %s doesn't contain"
8374 070e998b Iustin Pop
                         " free memory information" % pnode)
8375 4c4e4e1e Iustin Pop
      elif instance_info.fail_msg:
8376 7ad1af4a Iustin Pop
        self.warn.append("Can't get instance runtime information: %s" %
8377 4c4e4e1e Iustin Pop
                        instance_info.fail_msg)
8378 cfefe007 Guido Trotter
      else:
8379 7ad1af4a Iustin Pop
        if instance_info.payload:
8380 7ad1af4a Iustin Pop
          current_mem = int(instance_info.payload['memory'])
8381 cfefe007 Guido Trotter
        else:
8382 cfefe007 Guido Trotter
          # Assume instance not running
8383 cfefe007 Guido Trotter
          # (there is a slight race condition here, but it's not very probable,
8384 cfefe007 Guido Trotter
          # and we have no other way to check)
8385 cfefe007 Guido Trotter
          current_mem = 0
8386 338e51e8 Iustin Pop
        miss_mem = (be_new[constants.BE_MEMORY] - current_mem -
8387 070e998b Iustin Pop
                    pninfo.payload['memory_free'])
8388 cfefe007 Guido Trotter
        if miss_mem > 0:
8389 cfefe007 Guido Trotter
          raise errors.OpPrereqError("This change will prevent the instance"
8390 cfefe007 Guido Trotter
                                     " from starting, due to %d MB of memory"
8391 5c983ee5 Iustin Pop
                                     " missing on its primary node" % miss_mem,
8392 5c983ee5 Iustin Pop
                                     errors.ECODE_NORES)
8393 cfefe007 Guido Trotter
8394 c0f2b229 Iustin Pop
      if be_new[constants.BE_AUTO_BALANCE]:
8395 070e998b Iustin Pop
        for node, nres in nodeinfo.items():
8396 ea33068f Iustin Pop
          if node not in instance.secondary_nodes:
8397 ea33068f Iustin Pop
            continue
8398 4c4e4e1e Iustin Pop
          msg = nres.fail_msg
8399 070e998b Iustin Pop
          if msg:
8400 070e998b Iustin Pop
            self.warn.append("Can't get info from secondary node %s: %s" %
8401 070e998b Iustin Pop
                             (node, msg))
8402 070e998b Iustin Pop
          elif not isinstance(nres.payload.get('memory_free', None), int):
8403 070e998b Iustin Pop
            self.warn.append("Secondary node %s didn't return free"
8404 070e998b Iustin Pop
                             " memory information" % node)
8405 070e998b Iustin Pop
          elif be_new[constants.BE_MEMORY] > nres.payload['memory_free']:
8406 647a5d80 Iustin Pop
            self.warn.append("Not enough memory to failover instance to"
8407 647a5d80 Iustin Pop
                             " secondary node %s" % node)
8408 5bc84f33 Alexander Schreiber
8409 24991749 Iustin Pop
    # NIC processing
8410 cd098c41 Guido Trotter
    self.nic_pnew = {}
8411 cd098c41 Guido Trotter
    self.nic_pinst = {}
8412 24991749 Iustin Pop
    for nic_op, nic_dict in self.op.nics:
8413 24991749 Iustin Pop
      if nic_op == constants.DDM_REMOVE:
8414 24991749 Iustin Pop
        if not instance.nics:
8415 5c983ee5 Iustin Pop
          raise errors.OpPrereqError("Instance has no NICs, cannot remove",
8416 5c983ee5 Iustin Pop
                                     errors.ECODE_INVAL)
8417 24991749 Iustin Pop
        continue
8418 24991749 Iustin Pop
      if nic_op != constants.DDM_ADD:
8419 24991749 Iustin Pop
        # an existing nic
8420 21bcb9aa Michael Hanselmann
        if not instance.nics:
8421 21bcb9aa Michael Hanselmann
          raise errors.OpPrereqError("Invalid NIC index %s, instance has"
8422 21bcb9aa Michael Hanselmann
                                     " no NICs" % nic_op,
8423 21bcb9aa Michael Hanselmann
                                     errors.ECODE_INVAL)
8424 24991749 Iustin Pop
        if nic_op < 0 or nic_op >= len(instance.nics):
8425 24991749 Iustin Pop
          raise errors.OpPrereqError("Invalid NIC index %s, valid values"
8426 24991749 Iustin Pop
                                     " are 0 to %d" %
8427 21bcb9aa Michael Hanselmann
                                     (nic_op, len(instance.nics) - 1),
8428 5c983ee5 Iustin Pop
                                     errors.ECODE_INVAL)
8429 cd098c41 Guido Trotter
        old_nic_params = instance.nics[nic_op].nicparams
8430 cd098c41 Guido Trotter
        old_nic_ip = instance.nics[nic_op].ip
8431 cd098c41 Guido Trotter
      else:
8432 cd098c41 Guido Trotter
        old_nic_params = {}
8433 cd098c41 Guido Trotter
        old_nic_ip = None
8434 cd098c41 Guido Trotter
8435 cd098c41 Guido Trotter
      update_params_dict = dict([(key, nic_dict[key])
8436 cd098c41 Guido Trotter
                                 for key in constants.NICS_PARAMETERS
8437 cd098c41 Guido Trotter
                                 if key in nic_dict])
8438 cd098c41 Guido Trotter
8439 5c44da6a Guido Trotter
      if 'bridge' in nic_dict:
8440 cd098c41 Guido Trotter
        update_params_dict[constants.NIC_LINK] = nic_dict['bridge']
8441 cd098c41 Guido Trotter
8442 cd098c41 Guido Trotter
      new_nic_params, new_filled_nic_params = \
8443 cd098c41 Guido Trotter
          self._GetUpdatedParams(old_nic_params, update_params_dict,
8444 cd098c41 Guido Trotter
                                 cluster.nicparams[constants.PP_DEFAULT],
8445 cd098c41 Guido Trotter
                                 constants.NICS_PARAMETER_TYPES)
8446 cd098c41 Guido Trotter
      objects.NIC.CheckParameterSyntax(new_filled_nic_params)
8447 cd098c41 Guido Trotter
      self.nic_pinst[nic_op] = new_nic_params
8448 cd098c41 Guido Trotter
      self.nic_pnew[nic_op] = new_filled_nic_params
8449 cd098c41 Guido Trotter
      new_nic_mode = new_filled_nic_params[constants.NIC_MODE]
8450 cd098c41 Guido Trotter
8451 cd098c41 Guido Trotter
      if new_nic_mode == constants.NIC_MODE_BRIDGED:
8452 cd098c41 Guido Trotter
        nic_bridge = new_filled_nic_params[constants.NIC_LINK]
8453 4c4e4e1e Iustin Pop
        msg = self.rpc.call_bridges_exist(pnode, [nic_bridge]).fail_msg
8454 35c0c8da Iustin Pop
        if msg:
8455 35c0c8da Iustin Pop
          msg = "Error checking bridges on node %s: %s" % (pnode, msg)
8456 24991749 Iustin Pop
          if self.force:
8457 24991749 Iustin Pop
            self.warn.append(msg)
8458 24991749 Iustin Pop
          else:
8459 5c983ee5 Iustin Pop
            raise errors.OpPrereqError(msg, errors.ECODE_ENVIRON)
8460 cd098c41 Guido Trotter
      if new_nic_mode == constants.NIC_MODE_ROUTED:
8461 cd098c41 Guido Trotter
        if 'ip' in nic_dict:
8462 cd098c41 Guido Trotter
          nic_ip = nic_dict['ip']
8463 cd098c41 Guido Trotter
        else:
8464 cd098c41 Guido Trotter
          nic_ip = old_nic_ip
8465 cd098c41 Guido Trotter
        if nic_ip is None:
8466 cd098c41 Guido Trotter
          raise errors.OpPrereqError('Cannot set the nic ip to None'
8467 5c983ee5 Iustin Pop
                                     ' on a routed nic', errors.ECODE_INVAL)
8468 5c44da6a Guido Trotter
      if 'mac' in nic_dict:
8469 5c44da6a Guido Trotter
        nic_mac = nic_dict['mac']
8470 5c44da6a Guido Trotter
        if nic_mac is None:
8471 5c983ee5 Iustin Pop
          raise errors.OpPrereqError('Cannot set the nic mac to None',
8472 5c983ee5 Iustin Pop
                                     errors.ECODE_INVAL)
8473 5c44da6a Guido Trotter
        elif nic_mac in (constants.VALUE_AUTO, constants.VALUE_GENERATE):
8474 5c44da6a Guido Trotter
          # otherwise generate the mac
8475 36b66e6e Guido Trotter
          nic_dict['mac'] = self.cfg.GenerateMAC(self.proc.GetECId())
8476 5c44da6a Guido Trotter
        else:
8477 5c44da6a Guido Trotter
          # or validate/reserve the current one
8478 36b66e6e Guido Trotter
          try:
8479 36b66e6e Guido Trotter
            self.cfg.ReserveMAC(nic_mac, self.proc.GetECId())
8480 36b66e6e Guido Trotter
          except errors.ReservationError:
8481 5c44da6a Guido Trotter
            raise errors.OpPrereqError("MAC address %s already in use"
8482 5c983ee5 Iustin Pop
                                       " in cluster" % nic_mac,
8483 5c983ee5 Iustin Pop
                                       errors.ECODE_NOTUNIQUE)
8484 24991749 Iustin Pop
8485 24991749 Iustin Pop
    # DISK processing
8486 24991749 Iustin Pop
    if self.op.disks and instance.disk_template == constants.DT_DISKLESS:
8487 24991749 Iustin Pop
      raise errors.OpPrereqError("Disk operations not supported for"
8488 5c983ee5 Iustin Pop
                                 " diskless instances",
8489 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
8490 1122eb25 Iustin Pop
    for disk_op, _ in self.op.disks:
8491 24991749 Iustin Pop
      if disk_op == constants.DDM_REMOVE:
8492 24991749 Iustin Pop
        if len(instance.disks) == 1:
8493 24991749 Iustin Pop
          raise errors.OpPrereqError("Cannot remove the last disk of"
8494 31624382 Iustin Pop
                                     " an instance", errors.ECODE_INVAL)
8495 31624382 Iustin Pop
        _CheckInstanceDown(self, instance, "cannot remove disks")
8496 24991749 Iustin Pop
8497 24991749 Iustin Pop
      if (disk_op == constants.DDM_ADD and
8498 24991749 Iustin Pop
          len(instance.nics) >= constants.MAX_DISKS):
8499 24991749 Iustin Pop
        raise errors.OpPrereqError("Instance has too many disks (%d), cannot"
8500 5c983ee5 Iustin Pop
                                   " add more" % constants.MAX_DISKS,
8501 5c983ee5 Iustin Pop
                                   errors.ECODE_STATE)
8502 24991749 Iustin Pop
      if disk_op not in (constants.DDM_ADD, constants.DDM_REMOVE):
8503 24991749 Iustin Pop
        # an existing disk
8504 24991749 Iustin Pop
        if disk_op < 0 or disk_op >= len(instance.disks):
8505 24991749 Iustin Pop
          raise errors.OpPrereqError("Invalid disk index %s, valid values"
8506 24991749 Iustin Pop
                                     " are 0 to %d" %
8507 5c983ee5 Iustin Pop
                                     (disk_op, len(instance.disks)),
8508 5c983ee5 Iustin Pop
                                     errors.ECODE_INVAL)
8509 24991749 Iustin Pop
8510 96b39bcc Iustin Pop
    # OS change
8511 96b39bcc Iustin Pop
    if self.op.os_name and not self.op.force:
8512 96b39bcc Iustin Pop
      _CheckNodeHasOS(self, instance.primary_node, self.op.os_name,
8513 96b39bcc Iustin Pop
                      self.op.force_variant)
8514 96b39bcc Iustin Pop
8515 a8083063 Iustin Pop
    return
8516 a8083063 Iustin Pop
8517 e29e9550 Iustin Pop
  def _ConvertPlainToDrbd(self, feedback_fn):
8518 e29e9550 Iustin Pop
    """Converts an instance from plain to drbd.
8519 e29e9550 Iustin Pop

8520 e29e9550 Iustin Pop
    """
8521 e29e9550 Iustin Pop
    feedback_fn("Converting template to drbd")
8522 e29e9550 Iustin Pop
    instance = self.instance
8523 e29e9550 Iustin Pop
    pnode = instance.primary_node
8524 e29e9550 Iustin Pop
    snode = self.op.remote_node
8525 e29e9550 Iustin Pop
8526 e29e9550 Iustin Pop
    # create a fake disk info for _GenerateDiskTemplate
8527 e29e9550 Iustin Pop
    disk_info = [{"size": d.size, "mode": d.mode} for d in instance.disks]
8528 e29e9550 Iustin Pop
    new_disks = _GenerateDiskTemplate(self, self.op.disk_template,
8529 e29e9550 Iustin Pop
                                      instance.name, pnode, [snode],
8530 e29e9550 Iustin Pop
                                      disk_info, None, None, 0)
8531 e29e9550 Iustin Pop
    info = _GetInstanceInfoText(instance)
8532 e29e9550 Iustin Pop
    feedback_fn("Creating aditional volumes...")
8533 e29e9550 Iustin Pop
    # first, create the missing data and meta devices
8534 e29e9550 Iustin Pop
    for disk in new_disks:
8535 e29e9550 Iustin Pop
      # unfortunately this is... not too nice
8536 e29e9550 Iustin Pop
      _CreateSingleBlockDev(self, pnode, instance, disk.children[1],
8537 e29e9550 Iustin Pop
                            info, True)
8538 e29e9550 Iustin Pop
      for child in disk.children:
8539 e29e9550 Iustin Pop
        _CreateSingleBlockDev(self, snode, instance, child, info, True)
8540 e29e9550 Iustin Pop
    # at this stage, all new LVs have been created, we can rename the
8541 e29e9550 Iustin Pop
    # old ones
8542 e29e9550 Iustin Pop
    feedback_fn("Renaming original volumes...")
8543 e29e9550 Iustin Pop
    rename_list = [(o, n.children[0].logical_id)
8544 e29e9550 Iustin Pop
                   for (o, n) in zip(instance.disks, new_disks)]
8545 e29e9550 Iustin Pop
    result = self.rpc.call_blockdev_rename(pnode, rename_list)
8546 e29e9550 Iustin Pop
    result.Raise("Failed to rename original LVs")
8547 e29e9550 Iustin Pop
8548 e29e9550 Iustin Pop
    feedback_fn("Initializing DRBD devices...")
8549 e29e9550 Iustin Pop
    # all child devices are in place, we can now create the DRBD devices
8550 e29e9550 Iustin Pop
    for disk in new_disks:
8551 e29e9550 Iustin Pop
      for node in [pnode, snode]:
8552 e29e9550 Iustin Pop
        f_create = node == pnode
8553 e29e9550 Iustin Pop
        _CreateSingleBlockDev(self, node, instance, disk, info, f_create)
8554 e29e9550 Iustin Pop
8555 e29e9550 Iustin Pop
    # at this point, the instance has been modified
8556 e29e9550 Iustin Pop
    instance.disk_template = constants.DT_DRBD8
8557 e29e9550 Iustin Pop
    instance.disks = new_disks
8558 e29e9550 Iustin Pop
    self.cfg.Update(instance, feedback_fn)
8559 e29e9550 Iustin Pop
8560 e29e9550 Iustin Pop
    # disks are created, waiting for sync
8561 e29e9550 Iustin Pop
    disk_abort = not _WaitForSync(self, instance)
8562 e29e9550 Iustin Pop
    if disk_abort:
8563 e29e9550 Iustin Pop
      raise errors.OpExecError("There are some degraded disks for"
8564 e29e9550 Iustin Pop
                               " this instance, please cleanup manually")
8565 e29e9550 Iustin Pop
8566 2f414c48 Iustin Pop
  def _ConvertDrbdToPlain(self, feedback_fn):
8567 2f414c48 Iustin Pop
    """Converts an instance from drbd to plain.
8568 2f414c48 Iustin Pop

8569 2f414c48 Iustin Pop
    """
8570 2f414c48 Iustin Pop
    instance = self.instance
8571 2f414c48 Iustin Pop
    assert len(instance.secondary_nodes) == 1
8572 2f414c48 Iustin Pop
    pnode = instance.primary_node
8573 2f414c48 Iustin Pop
    snode = instance.secondary_nodes[0]
8574 2f414c48 Iustin Pop
    feedback_fn("Converting template to plain")
8575 2f414c48 Iustin Pop
8576 2f414c48 Iustin Pop
    old_disks = instance.disks
8577 2f414c48 Iustin Pop
    new_disks = [d.children[0] for d in old_disks]
8578 2f414c48 Iustin Pop
8579 2f414c48 Iustin Pop
    # copy over size and mode
8580 2f414c48 Iustin Pop
    for parent, child in zip(old_disks, new_disks):
8581 2f414c48 Iustin Pop
      child.size = parent.size
8582 2f414c48 Iustin Pop
      child.mode = parent.mode
8583 2f414c48 Iustin Pop
8584 2f414c48 Iustin Pop
    # update instance structure
8585 2f414c48 Iustin Pop
    instance.disks = new_disks
8586 2f414c48 Iustin Pop
    instance.disk_template = constants.DT_PLAIN
8587 2f414c48 Iustin Pop
    self.cfg.Update(instance, feedback_fn)
8588 2f414c48 Iustin Pop
8589 2f414c48 Iustin Pop
    feedback_fn("Removing volumes on the secondary node...")
8590 2f414c48 Iustin Pop
    for disk in old_disks:
8591 2f414c48 Iustin Pop
      self.cfg.SetDiskID(disk, snode)
8592 2f414c48 Iustin Pop
      msg = self.rpc.call_blockdev_remove(snode, disk).fail_msg
8593 2f414c48 Iustin Pop
      if msg:
8594 2f414c48 Iustin Pop
        self.LogWarning("Could not remove block device %s on node %s,"
8595 2f414c48 Iustin Pop
                        " continuing anyway: %s", disk.iv_name, snode, msg)
8596 2f414c48 Iustin Pop
8597 2f414c48 Iustin Pop
    feedback_fn("Removing unneeded volumes on the primary node...")
8598 2f414c48 Iustin Pop
    for idx, disk in enumerate(old_disks):
8599 2f414c48 Iustin Pop
      meta = disk.children[1]
8600 2f414c48 Iustin Pop
      self.cfg.SetDiskID(meta, pnode)
8601 2f414c48 Iustin Pop
      msg = self.rpc.call_blockdev_remove(pnode, meta).fail_msg
8602 2f414c48 Iustin Pop
      if msg:
8603 2f414c48 Iustin Pop
        self.LogWarning("Could not remove metadata for disk %d on node %s,"
8604 2f414c48 Iustin Pop
                        " continuing anyway: %s", idx, pnode, msg)
8605 2f414c48 Iustin Pop
8606 2f414c48 Iustin Pop
8607 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
8608 a8083063 Iustin Pop
    """Modifies an instance.
8609 a8083063 Iustin Pop

8610 a8083063 Iustin Pop
    All parameters take effect only at the next restart of the instance.
8611 24991749 Iustin Pop

8612 a8083063 Iustin Pop
    """
8613 cfefe007 Guido Trotter
    # Process here the warnings from CheckPrereq, as we don't have a
8614 cfefe007 Guido Trotter
    # feedback_fn there.
8615 cfefe007 Guido Trotter
    for warn in self.warn:
8616 cfefe007 Guido Trotter
      feedback_fn("WARNING: %s" % warn)
8617 cfefe007 Guido Trotter
8618 a8083063 Iustin Pop
    result = []
8619 a8083063 Iustin Pop
    instance = self.instance
8620 24991749 Iustin Pop
    # disk changes
8621 24991749 Iustin Pop
    for disk_op, disk_dict in self.op.disks:
8622 24991749 Iustin Pop
      if disk_op == constants.DDM_REMOVE:
8623 24991749 Iustin Pop
        # remove the last disk
8624 24991749 Iustin Pop
        device = instance.disks.pop()
8625 24991749 Iustin Pop
        device_idx = len(instance.disks)
8626 24991749 Iustin Pop
        for node, disk in device.ComputeNodeTree(instance.primary_node):
8627 24991749 Iustin Pop
          self.cfg.SetDiskID(disk, node)
8628 4c4e4e1e Iustin Pop
          msg = self.rpc.call_blockdev_remove(node, disk).fail_msg
8629 e1bc0878 Iustin Pop
          if msg:
8630 e1bc0878 Iustin Pop
            self.LogWarning("Could not remove disk/%d on node %s: %s,"
8631 e1bc0878 Iustin Pop
                            " continuing anyway", device_idx, node, msg)
8632 24991749 Iustin Pop
        result.append(("disk/%d" % device_idx, "remove"))
8633 24991749 Iustin Pop
      elif disk_op == constants.DDM_ADD:
8634 24991749 Iustin Pop
        # add a new disk
8635 24991749 Iustin Pop
        if instance.disk_template == constants.DT_FILE:
8636 24991749 Iustin Pop
          file_driver, file_path = instance.disks[0].logical_id
8637 24991749 Iustin Pop
          file_path = os.path.dirname(file_path)
8638 24991749 Iustin Pop
        else:
8639 24991749 Iustin Pop
          file_driver = file_path = None
8640 24991749 Iustin Pop
        disk_idx_base = len(instance.disks)
8641 24991749 Iustin Pop
        new_disk = _GenerateDiskTemplate(self,
8642 24991749 Iustin Pop
                                         instance.disk_template,
8643 32388e6d Iustin Pop
                                         instance.name, instance.primary_node,
8644 24991749 Iustin Pop
                                         instance.secondary_nodes,
8645 24991749 Iustin Pop
                                         [disk_dict],
8646 24991749 Iustin Pop
                                         file_path,
8647 24991749 Iustin Pop
                                         file_driver,
8648 24991749 Iustin Pop
                                         disk_idx_base)[0]
8649 24991749 Iustin Pop
        instance.disks.append(new_disk)
8650 24991749 Iustin Pop
        info = _GetInstanceInfoText(instance)
8651 24991749 Iustin Pop
8652 24991749 Iustin Pop
        logging.info("Creating volume %s for instance %s",
8653 24991749 Iustin Pop
                     new_disk.iv_name, instance.name)
8654 24991749 Iustin Pop
        # Note: this needs to be kept in sync with _CreateDisks
8655 24991749 Iustin Pop
        #HARDCODE
8656 428958aa Iustin Pop
        for node in instance.all_nodes:
8657 428958aa Iustin Pop
          f_create = node == instance.primary_node
8658 796cab27 Iustin Pop
          try:
8659 428958aa Iustin Pop
            _CreateBlockDev(self, node, instance, new_disk,
8660 428958aa Iustin Pop
                            f_create, info, f_create)
8661 1492cca7 Iustin Pop
          except errors.OpExecError, err:
8662 24991749 Iustin Pop
            self.LogWarning("Failed to create volume %s (%s) on"
8663 428958aa Iustin Pop
                            " node %s: %s",
8664 428958aa Iustin Pop
                            new_disk.iv_name, new_disk, node, err)
8665 24991749 Iustin Pop
        result.append(("disk/%d" % disk_idx_base, "add:size=%s,mode=%s" %
8666 24991749 Iustin Pop
                       (new_disk.size, new_disk.mode)))
8667 24991749 Iustin Pop
      else:
8668 24991749 Iustin Pop
        # change a given disk
8669 24991749 Iustin Pop
        instance.disks[disk_op].mode = disk_dict['mode']
8670 24991749 Iustin Pop
        result.append(("disk.mode/%d" % disk_op, disk_dict['mode']))
8671 e29e9550 Iustin Pop
8672 e29e9550 Iustin Pop
    if self.op.disk_template:
8673 e29e9550 Iustin Pop
      r_shut = _ShutdownInstanceDisks(self, instance)
8674 e29e9550 Iustin Pop
      if not r_shut:
8675 e29e9550 Iustin Pop
        raise errors.OpExecError("Cannot shutdow instance disks, unable to"
8676 e29e9550 Iustin Pop
                                 " proceed with disk template conversion")
8677 e29e9550 Iustin Pop
      mode = (instance.disk_template, self.op.disk_template)
8678 e29e9550 Iustin Pop
      try:
8679 e29e9550 Iustin Pop
        self._DISK_CONVERSIONS[mode](self, feedback_fn)
8680 e29e9550 Iustin Pop
      except:
8681 e29e9550 Iustin Pop
        self.cfg.ReleaseDRBDMinors(instance.name)
8682 e29e9550 Iustin Pop
        raise
8683 e29e9550 Iustin Pop
      result.append(("disk_template", self.op.disk_template))
8684 e29e9550 Iustin Pop
8685 24991749 Iustin Pop
    # NIC changes
8686 24991749 Iustin Pop
    for nic_op, nic_dict in self.op.nics:
8687 24991749 Iustin Pop
      if nic_op == constants.DDM_REMOVE:
8688 24991749 Iustin Pop
        # remove the last nic
8689 24991749 Iustin Pop
        del instance.nics[-1]
8690 24991749 Iustin Pop
        result.append(("nic.%d" % len(instance.nics), "remove"))
8691 24991749 Iustin Pop
      elif nic_op == constants.DDM_ADD:
8692 5c44da6a Guido Trotter
        # mac and bridge should be set, by now
8693 5c44da6a Guido Trotter
        mac = nic_dict['mac']
8694 cd098c41 Guido Trotter
        ip = nic_dict.get('ip', None)
8695 cd098c41 Guido Trotter
        nicparams = self.nic_pinst[constants.DDM_ADD]
8696 cd098c41 Guido Trotter
        new_nic = objects.NIC(mac=mac, ip=ip, nicparams=nicparams)
8697 24991749 Iustin Pop
        instance.nics.append(new_nic)
8698 24991749 Iustin Pop
        result.append(("nic.%d" % (len(instance.nics) - 1),
8699 cd098c41 Guido Trotter
                       "add:mac=%s,ip=%s,mode=%s,link=%s" %
8700 cd098c41 Guido Trotter
                       (new_nic.mac, new_nic.ip,
8701 cd098c41 Guido Trotter
                        self.nic_pnew[constants.DDM_ADD][constants.NIC_MODE],
8702 cd098c41 Guido Trotter
                        self.nic_pnew[constants.DDM_ADD][constants.NIC_LINK]
8703 cd098c41 Guido Trotter
                       )))
8704 24991749 Iustin Pop
      else:
8705 cd098c41 Guido Trotter
        for key in 'mac', 'ip':
8706 24991749 Iustin Pop
          if key in nic_dict:
8707 24991749 Iustin Pop
            setattr(instance.nics[nic_op], key, nic_dict[key])
8708 beabf067 Guido Trotter
        if nic_op in self.nic_pinst:
8709 beabf067 Guido Trotter
          instance.nics[nic_op].nicparams = self.nic_pinst[nic_op]
8710 cd098c41 Guido Trotter
        for key, val in nic_dict.iteritems():
8711 cd098c41 Guido Trotter
          result.append(("nic.%s/%d" % (key, nic_op), val))
8712 24991749 Iustin Pop
8713 24991749 Iustin Pop
    # hvparams changes
8714 74409b12 Iustin Pop
    if self.op.hvparams:
8715 12649e35 Guido Trotter
      instance.hvparams = self.hv_inst
8716 74409b12 Iustin Pop
      for key, val in self.op.hvparams.iteritems():
8717 74409b12 Iustin Pop
        result.append(("hv/%s" % key, val))
8718 24991749 Iustin Pop
8719 24991749 Iustin Pop
    # beparams changes
8720 338e51e8 Iustin Pop
    if self.op.beparams:
8721 338e51e8 Iustin Pop
      instance.beparams = self.be_inst
8722 338e51e8 Iustin Pop
      for key, val in self.op.beparams.iteritems():
8723 338e51e8 Iustin Pop
        result.append(("be/%s" % key, val))
8724 a8083063 Iustin Pop
8725 96b39bcc Iustin Pop
    # OS change
8726 96b39bcc Iustin Pop
    if self.op.os_name:
8727 96b39bcc Iustin Pop
      instance.os = self.op.os_name
8728 96b39bcc Iustin Pop
8729 a4eae71f Michael Hanselmann
    self.cfg.Update(instance, feedback_fn)
8730 a8083063 Iustin Pop
8731 a8083063 Iustin Pop
    return result
8732 a8083063 Iustin Pop
8733 e29e9550 Iustin Pop
  _DISK_CONVERSIONS = {
8734 e29e9550 Iustin Pop
    (constants.DT_PLAIN, constants.DT_DRBD8): _ConvertPlainToDrbd,
8735 2f414c48 Iustin Pop
    (constants.DT_DRBD8, constants.DT_PLAIN): _ConvertDrbdToPlain,
8736 e29e9550 Iustin Pop
    }
8737 a8083063 Iustin Pop
8738 a8083063 Iustin Pop
class LUQueryExports(NoHooksLU):
8739 a8083063 Iustin Pop
  """Query the exports list
8740 a8083063 Iustin Pop

8741 a8083063 Iustin Pop
  """
8742 895ecd9c Guido Trotter
  _OP_REQP = ['nodes']
8743 21a15682 Guido Trotter
  REQ_BGL = False
8744 21a15682 Guido Trotter
8745 21a15682 Guido Trotter
  def ExpandNames(self):
8746 21a15682 Guido Trotter
    self.needed_locks = {}
8747 21a15682 Guido Trotter
    self.share_locks[locking.LEVEL_NODE] = 1
8748 21a15682 Guido Trotter
    if not self.op.nodes:
8749 e310b019 Guido Trotter
      self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
8750 21a15682 Guido Trotter
    else:
8751 21a15682 Guido Trotter
      self.needed_locks[locking.LEVEL_NODE] = \
8752 21a15682 Guido Trotter
        _GetWantedNodes(self, self.op.nodes)
8753 a8083063 Iustin Pop
8754 a8083063 Iustin Pop
  def CheckPrereq(self):
8755 21a15682 Guido Trotter
    """Check prerequisites.
8756 a8083063 Iustin Pop

8757 a8083063 Iustin Pop
    """
8758 21a15682 Guido Trotter
    self.nodes = self.acquired_locks[locking.LEVEL_NODE]
8759 a8083063 Iustin Pop
8760 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
8761 a8083063 Iustin Pop
    """Compute the list of all the exported system images.
8762 a8083063 Iustin Pop

8763 e4376078 Iustin Pop
    @rtype: dict
8764 e4376078 Iustin Pop
    @return: a dictionary with the structure node->(export-list)
8765 e4376078 Iustin Pop
        where export-list is a list of the instances exported on
8766 e4376078 Iustin Pop
        that node.
8767 a8083063 Iustin Pop

8768 a8083063 Iustin Pop
    """
8769 b04285f2 Guido Trotter
    rpcresult = self.rpc.call_export_list(self.nodes)
8770 b04285f2 Guido Trotter
    result = {}
8771 b04285f2 Guido Trotter
    for node in rpcresult:
8772 4c4e4e1e Iustin Pop
      if rpcresult[node].fail_msg:
8773 b04285f2 Guido Trotter
        result[node] = False
8774 b04285f2 Guido Trotter
      else:
8775 1b7bfbb7 Iustin Pop
        result[node] = rpcresult[node].payload
8776 b04285f2 Guido Trotter
8777 b04285f2 Guido Trotter
    return result
8778 a8083063 Iustin Pop
8779 a8083063 Iustin Pop
8780 a8083063 Iustin Pop
class LUExportInstance(LogicalUnit):
8781 a8083063 Iustin Pop
  """Export an instance to an image in the cluster.
8782 a8083063 Iustin Pop

8783 a8083063 Iustin Pop
  """
8784 a8083063 Iustin Pop
  HPATH = "instance-export"
8785 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
8786 a8083063 Iustin Pop
  _OP_REQP = ["instance_name", "target_node", "shutdown"]
8787 6657590e Guido Trotter
  REQ_BGL = False
8788 6657590e Guido Trotter
8789 17c3f802 Guido Trotter
  def CheckArguments(self):
8790 17c3f802 Guido Trotter
    """Check the arguments.
8791 17c3f802 Guido Trotter

8792 17c3f802 Guido Trotter
    """
8793 17c3f802 Guido Trotter
    self.shutdown_timeout = getattr(self.op, "shutdown_timeout",
8794 17c3f802 Guido Trotter
                                    constants.DEFAULT_SHUTDOWN_TIMEOUT)
8795 17c3f802 Guido Trotter
8796 6657590e Guido Trotter
  def ExpandNames(self):
8797 6657590e Guido Trotter
    self._ExpandAndLockInstance()
8798 6657590e Guido Trotter
    # FIXME: lock only instance primary and destination node
8799 6657590e Guido Trotter
    #
8800 6657590e Guido Trotter
    # Sad but true, for now we have do lock all nodes, as we don't know where
8801 6657590e Guido Trotter
    # the previous export might be, and and in this LU we search for it and
8802 6657590e Guido Trotter
    # remove it from its current node. In the future we could fix this by:
8803 6657590e Guido Trotter
    #  - making a tasklet to search (share-lock all), then create the new one,
8804 6657590e Guido Trotter
    #    then one to remove, after
8805 5bbd3f7f Michael Hanselmann
    #  - removing the removal operation altogether
8806 6657590e Guido Trotter
    self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
8807 6657590e Guido Trotter
8808 6657590e Guido Trotter
  def DeclareLocks(self, level):
8809 6657590e Guido Trotter
    """Last minute lock declaration."""
8810 6657590e Guido Trotter
    # All nodes are locked anyway, so nothing to do here.
8811 a8083063 Iustin Pop
8812 a8083063 Iustin Pop
  def BuildHooksEnv(self):
8813 a8083063 Iustin Pop
    """Build hooks env.
8814 a8083063 Iustin Pop

8815 a8083063 Iustin Pop
    This will run on the master, primary node and target node.
8816 a8083063 Iustin Pop

8817 a8083063 Iustin Pop
    """
8818 a8083063 Iustin Pop
    env = {
8819 a8083063 Iustin Pop
      "EXPORT_NODE": self.op.target_node,
8820 a8083063 Iustin Pop
      "EXPORT_DO_SHUTDOWN": self.op.shutdown,
8821 17c3f802 Guido Trotter
      "SHUTDOWN_TIMEOUT": self.shutdown_timeout,
8822 a8083063 Iustin Pop
      }
8823 338e51e8 Iustin Pop
    env.update(_BuildInstanceHookEnvByObject(self, self.instance))
8824 d6a02168 Michael Hanselmann
    nl = [self.cfg.GetMasterNode(), self.instance.primary_node,
8825 a8083063 Iustin Pop
          self.op.target_node]
8826 a8083063 Iustin Pop
    return env, nl, nl
8827 a8083063 Iustin Pop
8828 a8083063 Iustin Pop
  def CheckPrereq(self):
8829 a8083063 Iustin Pop
    """Check prerequisites.
8830 a8083063 Iustin Pop

8831 9ac99fda Guido Trotter
    This checks that the instance and node names are valid.
8832 a8083063 Iustin Pop

8833 a8083063 Iustin Pop
    """
8834 6657590e Guido Trotter
    instance_name = self.op.instance_name
8835 a8083063 Iustin Pop
    self.instance = self.cfg.GetInstanceInfo(instance_name)
8836 6657590e Guido Trotter
    assert self.instance is not None, \
8837 6657590e Guido Trotter
          "Cannot retrieve locked instance %s" % self.op.instance_name
8838 43017d26 Iustin Pop
    _CheckNodeOnline(self, self.instance.primary_node)
8839 a8083063 Iustin Pop
8840 cf26a87a Iustin Pop
    self.op.target_node = _ExpandNodeName(self.cfg, self.op.target_node)
8841 cf26a87a Iustin Pop
    self.dst_node = self.cfg.GetNodeInfo(self.op.target_node)
8842 cf26a87a Iustin Pop
    assert self.dst_node is not None
8843 a8083063 Iustin Pop
8844 aeb83a2b Iustin Pop
    _CheckNodeOnline(self, self.dst_node.name)
8845 733a2b6a Iustin Pop
    _CheckNodeNotDrained(self, self.dst_node.name)
8846 a8083063 Iustin Pop
8847 b6023d6c Manuel Franceschini
    # instance disk type verification
8848 b6023d6c Manuel Franceschini
    for disk in self.instance.disks:
8849 b6023d6c Manuel Franceschini
      if disk.dev_type == constants.LD_FILE:
8850 b6023d6c Manuel Franceschini
        raise errors.OpPrereqError("Export not supported for instances with"
8851 5c983ee5 Iustin Pop
                                   " file-based disks", errors.ECODE_INVAL)
8852 b6023d6c Manuel Franceschini
8853 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
8854 a8083063 Iustin Pop
    """Export an instance to an image in the cluster.
8855 a8083063 Iustin Pop

8856 a8083063 Iustin Pop
    """
8857 a8083063 Iustin Pop
    instance = self.instance
8858 a8083063 Iustin Pop
    dst_node = self.dst_node
8859 a8083063 Iustin Pop
    src_node = instance.primary_node
8860 37972df0 Michael Hanselmann
8861 a8083063 Iustin Pop
    if self.op.shutdown:
8862 fb300fb7 Guido Trotter
      # shutdown the instance, but not the disks
8863 37972df0 Michael Hanselmann
      feedback_fn("Shutting down instance %s" % instance.name)
8864 17c3f802 Guido Trotter
      result = self.rpc.call_instance_shutdown(src_node, instance,
8865 17c3f802 Guido Trotter
                                               self.shutdown_timeout)
8866 4c4e4e1e Iustin Pop
      result.Raise("Could not shutdown instance %s on"
8867 4c4e4e1e Iustin Pop
                   " node %s" % (instance.name, src_node))
8868 a8083063 Iustin Pop
8869 a8083063 Iustin Pop
    vgname = self.cfg.GetVGName()
8870 a8083063 Iustin Pop
8871 a8083063 Iustin Pop
    snap_disks = []
8872 a8083063 Iustin Pop
8873 998c712c Iustin Pop
    # set the disks ID correctly since call_instance_start needs the
8874 998c712c Iustin Pop
    # correct drbd minor to create the symlinks
8875 998c712c Iustin Pop
    for disk in instance.disks:
8876 998c712c Iustin Pop
      self.cfg.SetDiskID(disk, src_node)
8877 998c712c Iustin Pop
8878 3e53a60b Michael Hanselmann
    activate_disks = (not instance.admin_up)
8879 3e53a60b Michael Hanselmann
8880 3e53a60b Michael Hanselmann
    if activate_disks:
8881 3e53a60b Michael Hanselmann
      # Activate the instance disks if we'exporting a stopped instance
8882 3e53a60b Michael Hanselmann
      feedback_fn("Activating disks for %s" % instance.name)
8883 3e53a60b Michael Hanselmann
      _StartInstanceDisks(self, instance, None)
8884 3e53a60b Michael Hanselmann
8885 a8083063 Iustin Pop
    try:
8886 3e53a60b Michael Hanselmann
      # per-disk results
8887 3e53a60b Michael Hanselmann
      dresults = []
8888 3e53a60b Michael Hanselmann
      try:
8889 3e53a60b Michael Hanselmann
        for idx, disk in enumerate(instance.disks):
8890 3e53a60b Michael Hanselmann
          feedback_fn("Creating a snapshot of disk/%s on node %s" %
8891 3e53a60b Michael Hanselmann
                      (idx, src_node))
8892 3e53a60b Michael Hanselmann
8893 3e53a60b Michael Hanselmann
          # result.payload will be a snapshot of an lvm leaf of the one we
8894 3e53a60b Michael Hanselmann
          # passed
8895 3e53a60b Michael Hanselmann
          result = self.rpc.call_blockdev_snapshot(src_node, disk)
8896 3e53a60b Michael Hanselmann
          msg = result.fail_msg
8897 3e53a60b Michael Hanselmann
          if msg:
8898 3e53a60b Michael Hanselmann
            self.LogWarning("Could not snapshot disk/%s on node %s: %s",
8899 3e53a60b Michael Hanselmann
                            idx, src_node, msg)
8900 3e53a60b Michael Hanselmann
            snap_disks.append(False)
8901 3e53a60b Michael Hanselmann
          else:
8902 3e53a60b Michael Hanselmann
            disk_id = (vgname, result.payload)
8903 3e53a60b Michael Hanselmann
            new_dev = objects.Disk(dev_type=constants.LD_LV, size=disk.size,
8904 3e53a60b Michael Hanselmann
                                   logical_id=disk_id, physical_id=disk_id,
8905 3e53a60b Michael Hanselmann
                                   iv_name=disk.iv_name)
8906 3e53a60b Michael Hanselmann
            snap_disks.append(new_dev)
8907 37972df0 Michael Hanselmann
8908 3e53a60b Michael Hanselmann
      finally:
8909 3e53a60b Michael Hanselmann
        if self.op.shutdown and instance.admin_up:
8910 3e53a60b Michael Hanselmann
          feedback_fn("Starting instance %s" % instance.name)
8911 3e53a60b Michael Hanselmann
          result = self.rpc.call_instance_start(src_node, instance, None, None)
8912 3e53a60b Michael Hanselmann
          msg = result.fail_msg
8913 3e53a60b Michael Hanselmann
          if msg:
8914 3e53a60b Michael Hanselmann
            _ShutdownInstanceDisks(self, instance)
8915 3e53a60b Michael Hanselmann
            raise errors.OpExecError("Could not start instance: %s" % msg)
8916 3e53a60b Michael Hanselmann
8917 3e53a60b Michael Hanselmann
      # TODO: check for size
8918 3e53a60b Michael Hanselmann
8919 3e53a60b Michael Hanselmann
      cluster_name = self.cfg.GetClusterName()
8920 3e53a60b Michael Hanselmann
      for idx, dev in enumerate(snap_disks):
8921 3e53a60b Michael Hanselmann
        feedback_fn("Exporting snapshot %s from %s to %s" %
8922 3e53a60b Michael Hanselmann
                    (idx, src_node, dst_node.name))
8923 3e53a60b Michael Hanselmann
        if dev:
8924 4a0e011f Iustin Pop
          # FIXME: pass debug from opcode to backend
8925 3e53a60b Michael Hanselmann
          result = self.rpc.call_snapshot_export(src_node, dev, dst_node.name,
8926 4a0e011f Iustin Pop
                                                 instance, cluster_name,
8927 dd713605 Iustin Pop
                                                 idx, self.op.debug_level)
8928 3e53a60b Michael Hanselmann
          msg = result.fail_msg
8929 3e53a60b Michael Hanselmann
          if msg:
8930 3e53a60b Michael Hanselmann
            self.LogWarning("Could not export disk/%s from node %s to"
8931 3e53a60b Michael Hanselmann
                            " node %s: %s", idx, src_node, dst_node.name, msg)
8932 3e53a60b Michael Hanselmann
            dresults.append(False)
8933 3e53a60b Michael Hanselmann
          else:
8934 3e53a60b Michael Hanselmann
            dresults.append(True)
8935 3e53a60b Michael Hanselmann
          msg = self.rpc.call_blockdev_remove(src_node, dev).fail_msg
8936 3e53a60b Michael Hanselmann
          if msg:
8937 3e53a60b Michael Hanselmann
            self.LogWarning("Could not remove snapshot for disk/%d from node"
8938 3e53a60b Michael Hanselmann
                            " %s: %s", idx, src_node, msg)
8939 19d7f90a Guido Trotter
        else:
8940 084f05a5 Iustin Pop
          dresults.append(False)
8941 a8083063 Iustin Pop
8942 3e53a60b Michael Hanselmann
      feedback_fn("Finalizing export on %s" % dst_node.name)
8943 3e53a60b Michael Hanselmann
      result = self.rpc.call_finalize_export(dst_node.name, instance,
8944 3e53a60b Michael Hanselmann
                                             snap_disks)
8945 3e53a60b Michael Hanselmann
      fin_resu = True
8946 3e53a60b Michael Hanselmann
      msg = result.fail_msg
8947 3e53a60b Michael Hanselmann
      if msg:
8948 3e53a60b Michael Hanselmann
        self.LogWarning("Could not finalize export for instance %s"
8949 3e53a60b Michael Hanselmann
                        " on node %s: %s", instance.name, dst_node.name, msg)
8950 3e53a60b Michael Hanselmann
        fin_resu = False
8951 3e53a60b Michael Hanselmann
8952 3e53a60b Michael Hanselmann
    finally:
8953 3e53a60b Michael Hanselmann
      if activate_disks:
8954 3e53a60b Michael Hanselmann
        feedback_fn("Deactivating disks for %s" % instance.name)
8955 3e53a60b Michael Hanselmann
        _ShutdownInstanceDisks(self, instance)
8956 a8083063 Iustin Pop
8957 a8083063 Iustin Pop
    nodelist = self.cfg.GetNodeList()
8958 a8083063 Iustin Pop
    nodelist.remove(dst_node.name)
8959 a8083063 Iustin Pop
8960 a8083063 Iustin Pop
    # on one-node clusters nodelist will be empty after the removal
8961 a8083063 Iustin Pop
    # if we proceed the backup would be removed because OpQueryExports
8962 a8083063 Iustin Pop
    # substitutes an empty list with the full cluster node list.
8963 35fbcd11 Iustin Pop
    iname = instance.name
8964 a8083063 Iustin Pop
    if nodelist:
8965 37972df0 Michael Hanselmann
      feedback_fn("Removing old exports for instance %s" % iname)
8966 72737a7f Iustin Pop
      exportlist = self.rpc.call_export_list(nodelist)
8967 a8083063 Iustin Pop
      for node in exportlist:
8968 4c4e4e1e Iustin Pop
        if exportlist[node].fail_msg:
8969 781de953 Iustin Pop
          continue
8970 35fbcd11 Iustin Pop
        if iname in exportlist[node].payload:
8971 4c4e4e1e Iustin Pop
          msg = self.rpc.call_export_remove(node, iname).fail_msg
8972 35fbcd11 Iustin Pop
          if msg:
8973 19d7f90a Guido Trotter
            self.LogWarning("Could not remove older export for instance %s"
8974 35fbcd11 Iustin Pop
                            " on node %s: %s", iname, node, msg)
8975 084f05a5 Iustin Pop
    return fin_resu, dresults
8976 5c947f38 Iustin Pop
8977 5c947f38 Iustin Pop
8978 9ac99fda Guido Trotter
class LURemoveExport(NoHooksLU):
8979 9ac99fda Guido Trotter
  """Remove exports related to the named instance.
8980 9ac99fda Guido Trotter

8981 9ac99fda Guido Trotter
  """
8982 9ac99fda Guido Trotter
  _OP_REQP = ["instance_name"]
8983 3656b3af Guido Trotter
  REQ_BGL = False
8984 3656b3af Guido Trotter
8985 3656b3af Guido Trotter
  def ExpandNames(self):
8986 3656b3af Guido Trotter
    self.needed_locks = {}
8987 3656b3af Guido Trotter
    # We need all nodes to be locked in order for RemoveExport to work, but we
8988 3656b3af Guido Trotter
    # don't need to lock the instance itself, as nothing will happen to it (and
8989 3656b3af Guido Trotter
    # we can remove exports also for a removed instance)
8990 3656b3af Guido Trotter
    self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
8991 9ac99fda Guido Trotter
8992 9ac99fda Guido Trotter
  def CheckPrereq(self):
8993 9ac99fda Guido Trotter
    """Check prerequisites.
8994 9ac99fda Guido Trotter
    """
8995 9ac99fda Guido Trotter
    pass
8996 9ac99fda Guido Trotter
8997 9ac99fda Guido Trotter
  def Exec(self, feedback_fn):
8998 9ac99fda Guido Trotter
    """Remove any export.
8999 9ac99fda Guido Trotter

9000 9ac99fda Guido Trotter
    """
9001 9ac99fda Guido Trotter
    instance_name = self.cfg.ExpandInstanceName(self.op.instance_name)
9002 9ac99fda Guido Trotter
    # If the instance was not found we'll try with the name that was passed in.
9003 9ac99fda Guido Trotter
    # This will only work if it was an FQDN, though.
9004 9ac99fda Guido Trotter
    fqdn_warn = False
9005 9ac99fda Guido Trotter
    if not instance_name:
9006 9ac99fda Guido Trotter
      fqdn_warn = True
9007 9ac99fda Guido Trotter
      instance_name = self.op.instance_name
9008 9ac99fda Guido Trotter
9009 1b7bfbb7 Iustin Pop
    locked_nodes = self.acquired_locks[locking.LEVEL_NODE]
9010 1b7bfbb7 Iustin Pop
    exportlist = self.rpc.call_export_list(locked_nodes)
9011 9ac99fda Guido Trotter
    found = False
9012 9ac99fda Guido Trotter
    for node in exportlist:
9013 4c4e4e1e Iustin Pop
      msg = exportlist[node].fail_msg
9014 1b7bfbb7 Iustin Pop
      if msg:
9015 1b7bfbb7 Iustin Pop
        self.LogWarning("Failed to query node %s (continuing): %s", node, msg)
9016 781de953 Iustin Pop
        continue
9017 1b7bfbb7 Iustin Pop
      if instance_name in exportlist[node].payload:
9018 9ac99fda Guido Trotter
        found = True
9019 781de953 Iustin Pop
        result = self.rpc.call_export_remove(node, instance_name)
9020 4c4e4e1e Iustin Pop
        msg = result.fail_msg
9021 35fbcd11 Iustin Pop
        if msg:
9022 9a4f63d1 Iustin Pop
          logging.error("Could not remove export for instance %s"
9023 35fbcd11 Iustin Pop
                        " on node %s: %s", instance_name, node, msg)
9024 9ac99fda Guido Trotter
9025 9ac99fda Guido Trotter
    if fqdn_warn and not found:
9026 9ac99fda Guido Trotter
      feedback_fn("Export not found. If trying to remove an export belonging"
9027 9ac99fda Guido Trotter
                  " to a deleted instance please use its Fully Qualified"
9028 9ac99fda Guido Trotter
                  " Domain Name.")
9029 9ac99fda Guido Trotter
9030 9ac99fda Guido Trotter
9031 fe267188 Iustin Pop
class TagsLU(NoHooksLU): # pylint: disable-msg=W0223
9032 5c947f38 Iustin Pop
  """Generic tags LU.
9033 5c947f38 Iustin Pop

9034 5c947f38 Iustin Pop
  This is an abstract class which is the parent of all the other tags LUs.
9035 5c947f38 Iustin Pop

9036 5c947f38 Iustin Pop
  """
9037 5c947f38 Iustin Pop
9038 8646adce Guido Trotter
  def ExpandNames(self):
9039 8646adce Guido Trotter
    self.needed_locks = {}
9040 8646adce Guido Trotter
    if self.op.kind == constants.TAG_NODE:
9041 cf26a87a Iustin Pop
      self.op.name = _ExpandNodeName(self.cfg, self.op.name)
9042 cf26a87a Iustin Pop
      self.needed_locks[locking.LEVEL_NODE] = self.op.name
9043 5c947f38 Iustin Pop
    elif self.op.kind == constants.TAG_INSTANCE:
9044 cf26a87a Iustin Pop
      self.op.name = _ExpandInstanceName(self.cfg, self.op.name)
9045 cf26a87a Iustin Pop
      self.needed_locks[locking.LEVEL_INSTANCE] = self.op.name
9046 8646adce Guido Trotter
9047 8646adce Guido Trotter
  def CheckPrereq(self):
9048 8646adce Guido Trotter
    """Check prerequisites.
9049 8646adce Guido Trotter

9050 8646adce Guido Trotter
    """
9051 8646adce Guido Trotter
    if self.op.kind == constants.TAG_CLUSTER:
9052 8646adce Guido Trotter
      self.target = self.cfg.GetClusterInfo()
9053 8646adce Guido Trotter
    elif self.op.kind == constants.TAG_NODE:
9054 8646adce Guido Trotter
      self.target = self.cfg.GetNodeInfo(self.op.name)
9055 8646adce Guido Trotter
    elif self.op.kind == constants.TAG_INSTANCE:
9056 8646adce Guido Trotter
      self.target = self.cfg.GetInstanceInfo(self.op.name)
9057 5c947f38 Iustin Pop
    else:
9058 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Wrong tag type requested (%s)" %
9059 5c983ee5 Iustin Pop
                                 str(self.op.kind), errors.ECODE_INVAL)
9060 5c947f38 Iustin Pop
9061 5c947f38 Iustin Pop
9062 5c947f38 Iustin Pop
class LUGetTags(TagsLU):
9063 5c947f38 Iustin Pop
  """Returns the tags of a given object.
9064 5c947f38 Iustin Pop

9065 5c947f38 Iustin Pop
  """
9066 5c947f38 Iustin Pop
  _OP_REQP = ["kind", "name"]
9067 8646adce Guido Trotter
  REQ_BGL = False
9068 5c947f38 Iustin Pop
9069 5c947f38 Iustin Pop
  def Exec(self, feedback_fn):
9070 5c947f38 Iustin Pop
    """Returns the tag list.
9071 5c947f38 Iustin Pop

9072 5c947f38 Iustin Pop
    """
9073 5d414478 Oleksiy Mishchenko
    return list(self.target.GetTags())
9074 5c947f38 Iustin Pop
9075 5c947f38 Iustin Pop
9076 73415719 Iustin Pop
class LUSearchTags(NoHooksLU):
9077 73415719 Iustin Pop
  """Searches the tags for a given pattern.
9078 73415719 Iustin Pop

9079 73415719 Iustin Pop
  """
9080 73415719 Iustin Pop
  _OP_REQP = ["pattern"]
9081 8646adce Guido Trotter
  REQ_BGL = False
9082 8646adce Guido Trotter
9083 8646adce Guido Trotter
  def ExpandNames(self):
9084 8646adce Guido Trotter
    self.needed_locks = {}
9085 73415719 Iustin Pop
9086 73415719 Iustin Pop
  def CheckPrereq(self):
9087 73415719 Iustin Pop
    """Check prerequisites.
9088 73415719 Iustin Pop

9089 73415719 Iustin Pop
    This checks the pattern passed for validity by compiling it.
9090 73415719 Iustin Pop

9091 73415719 Iustin Pop
    """
9092 73415719 Iustin Pop
    try:
9093 73415719 Iustin Pop
      self.re = re.compile(self.op.pattern)
9094 73415719 Iustin Pop
    except re.error, err:
9095 73415719 Iustin Pop
      raise errors.OpPrereqError("Invalid search pattern '%s': %s" %
9096 5c983ee5 Iustin Pop
                                 (self.op.pattern, err), errors.ECODE_INVAL)
9097 73415719 Iustin Pop
9098 73415719 Iustin Pop
  def Exec(self, feedback_fn):
9099 73415719 Iustin Pop
    """Returns the tag list.
9100 73415719 Iustin Pop

9101 73415719 Iustin Pop
    """
9102 73415719 Iustin Pop
    cfg = self.cfg
9103 73415719 Iustin Pop
    tgts = [("/cluster", cfg.GetClusterInfo())]
9104 8646adce Guido Trotter
    ilist = cfg.GetAllInstancesInfo().values()
9105 73415719 Iustin Pop
    tgts.extend([("/instances/%s" % i.name, i) for i in ilist])
9106 8646adce Guido Trotter
    nlist = cfg.GetAllNodesInfo().values()
9107 73415719 Iustin Pop
    tgts.extend([("/nodes/%s" % n.name, n) for n in nlist])
9108 73415719 Iustin Pop
    results = []
9109 73415719 Iustin Pop
    for path, target in tgts:
9110 73415719 Iustin Pop
      for tag in target.GetTags():
9111 73415719 Iustin Pop
        if self.re.search(tag):
9112 73415719 Iustin Pop
          results.append((path, tag))
9113 73415719 Iustin Pop
    return results
9114 73415719 Iustin Pop
9115 73415719 Iustin Pop
9116 f27302fa Iustin Pop
class LUAddTags(TagsLU):
9117 5c947f38 Iustin Pop
  """Sets a tag on a given object.
9118 5c947f38 Iustin Pop

9119 5c947f38 Iustin Pop
  """
9120 f27302fa Iustin Pop
  _OP_REQP = ["kind", "name", "tags"]
9121 8646adce Guido Trotter
  REQ_BGL = False
9122 5c947f38 Iustin Pop
9123 5c947f38 Iustin Pop
  def CheckPrereq(self):
9124 5c947f38 Iustin Pop
    """Check prerequisites.
9125 5c947f38 Iustin Pop

9126 5c947f38 Iustin Pop
    This checks the type and length of the tag name and value.
9127 5c947f38 Iustin Pop

9128 5c947f38 Iustin Pop
    """
9129 5c947f38 Iustin Pop
    TagsLU.CheckPrereq(self)
9130 f27302fa Iustin Pop
    for tag in self.op.tags:
9131 f27302fa Iustin Pop
      objects.TaggableObject.ValidateTag(tag)
9132 5c947f38 Iustin Pop
9133 5c947f38 Iustin Pop
  def Exec(self, feedback_fn):
9134 5c947f38 Iustin Pop
    """Sets the tag.
9135 5c947f38 Iustin Pop

9136 5c947f38 Iustin Pop
    """
9137 5c947f38 Iustin Pop
    try:
9138 f27302fa Iustin Pop
      for tag in self.op.tags:
9139 f27302fa Iustin Pop
        self.target.AddTag(tag)
9140 5c947f38 Iustin Pop
    except errors.TagError, err:
9141 3ecf6786 Iustin Pop
      raise errors.OpExecError("Error while setting tag: %s" % str(err))
9142 159d4ec6 Iustin Pop
    self.cfg.Update(self.target, feedback_fn)
9143 5c947f38 Iustin Pop
9144 5c947f38 Iustin Pop
9145 f27302fa Iustin Pop
class LUDelTags(TagsLU):
9146 f27302fa Iustin Pop
  """Delete a list of tags from a given object.
9147 5c947f38 Iustin Pop

9148 5c947f38 Iustin Pop
  """
9149 f27302fa Iustin Pop
  _OP_REQP = ["kind", "name", "tags"]
9150 8646adce Guido Trotter
  REQ_BGL = False
9151 5c947f38 Iustin Pop
9152 5c947f38 Iustin Pop
  def CheckPrereq(self):
9153 5c947f38 Iustin Pop
    """Check prerequisites.
9154 5c947f38 Iustin Pop

9155 5c947f38 Iustin Pop
    This checks that we have the given tag.
9156 5c947f38 Iustin Pop

9157 5c947f38 Iustin Pop
    """
9158 5c947f38 Iustin Pop
    TagsLU.CheckPrereq(self)
9159 f27302fa Iustin Pop
    for tag in self.op.tags:
9160 f27302fa Iustin Pop
      objects.TaggableObject.ValidateTag(tag)
9161 f27302fa Iustin Pop
    del_tags = frozenset(self.op.tags)
9162 f27302fa Iustin Pop
    cur_tags = self.target.GetTags()
9163 f27302fa Iustin Pop
    if not del_tags <= cur_tags:
9164 f27302fa Iustin Pop
      diff_tags = del_tags - cur_tags
9165 f27302fa Iustin Pop
      diff_names = ["'%s'" % tag for tag in diff_tags]
9166 f27302fa Iustin Pop
      diff_names.sort()
9167 f27302fa Iustin Pop
      raise errors.OpPrereqError("Tag(s) %s not found" %
9168 5c983ee5 Iustin Pop
                                 (",".join(diff_names)), errors.ECODE_NOENT)
9169 5c947f38 Iustin Pop
9170 5c947f38 Iustin Pop
  def Exec(self, feedback_fn):
9171 5c947f38 Iustin Pop
    """Remove the tag from the object.
9172 5c947f38 Iustin Pop

9173 5c947f38 Iustin Pop
    """
9174 f27302fa Iustin Pop
    for tag in self.op.tags:
9175 f27302fa Iustin Pop
      self.target.RemoveTag(tag)
9176 159d4ec6 Iustin Pop
    self.cfg.Update(self.target, feedback_fn)
9177 06009e27 Iustin Pop
9178 0eed6e61 Guido Trotter
9179 06009e27 Iustin Pop
class LUTestDelay(NoHooksLU):
9180 06009e27 Iustin Pop
  """Sleep for a specified amount of time.
9181 06009e27 Iustin Pop

9182 0b097284 Guido Trotter
  This LU sleeps on the master and/or nodes for a specified amount of
9183 06009e27 Iustin Pop
  time.
9184 06009e27 Iustin Pop

9185 06009e27 Iustin Pop
  """
9186 06009e27 Iustin Pop
  _OP_REQP = ["duration", "on_master", "on_nodes"]
9187 fbe9022f Guido Trotter
  REQ_BGL = False
9188 06009e27 Iustin Pop
9189 fbe9022f Guido Trotter
  def ExpandNames(self):
9190 fbe9022f Guido Trotter
    """Expand names and set required locks.
9191 06009e27 Iustin Pop

9192 fbe9022f Guido Trotter
    This expands the node list, if any.
9193 06009e27 Iustin Pop

9194 06009e27 Iustin Pop
    """
9195 fbe9022f Guido Trotter
    self.needed_locks = {}
9196 06009e27 Iustin Pop
    if self.op.on_nodes:
9197 fbe9022f Guido Trotter
      # _GetWantedNodes can be used here, but is not always appropriate to use
9198 fbe9022f Guido Trotter
      # this way in ExpandNames. Check LogicalUnit.ExpandNames docstring for
9199 fbe9022f Guido Trotter
      # more information.
9200 06009e27 Iustin Pop
      self.op.on_nodes = _GetWantedNodes(self, self.op.on_nodes)
9201 fbe9022f Guido Trotter
      self.needed_locks[locking.LEVEL_NODE] = self.op.on_nodes
9202 fbe9022f Guido Trotter
9203 fbe9022f Guido Trotter
  def CheckPrereq(self):
9204 fbe9022f Guido Trotter
    """Check prerequisites.
9205 fbe9022f Guido Trotter

9206 fbe9022f Guido Trotter
    """
9207 06009e27 Iustin Pop
9208 06009e27 Iustin Pop
  def Exec(self, feedback_fn):
9209 06009e27 Iustin Pop
    """Do the actual sleep.
9210 06009e27 Iustin Pop

9211 06009e27 Iustin Pop
    """
9212 06009e27 Iustin Pop
    if self.op.on_master:
9213 06009e27 Iustin Pop
      if not utils.TestDelay(self.op.duration):
9214 06009e27 Iustin Pop
        raise errors.OpExecError("Error during master delay test")
9215 06009e27 Iustin Pop
    if self.op.on_nodes:
9216 72737a7f Iustin Pop
      result = self.rpc.call_test_delay(self.op.on_nodes, self.op.duration)
9217 06009e27 Iustin Pop
      for node, node_result in result.items():
9218 4c4e4e1e Iustin Pop
        node_result.Raise("Failure during rpc call to node %s" % node)
9219 d61df03e Iustin Pop
9220 d61df03e Iustin Pop
9221 d1c2dd75 Iustin Pop
class IAllocator(object):
9222 d1c2dd75 Iustin Pop
  """IAllocator framework.
9223 d61df03e Iustin Pop

9224 d1c2dd75 Iustin Pop
  An IAllocator instance has three sets of attributes:
9225 d6a02168 Michael Hanselmann
    - cfg that is needed to query the cluster
9226 d1c2dd75 Iustin Pop
    - input data (all members of the _KEYS class attribute are required)
9227 d1c2dd75 Iustin Pop
    - four buffer attributes (in|out_data|text), that represent the
9228 d1c2dd75 Iustin Pop
      input (to the external script) in text and data structure format,
9229 d1c2dd75 Iustin Pop
      and the output from it, again in two formats
9230 d1c2dd75 Iustin Pop
    - the result variables from the script (success, info, nodes) for
9231 d1c2dd75 Iustin Pop
      easy usage
9232 d61df03e Iustin Pop

9233 d61df03e Iustin Pop
  """
9234 7260cfbe Iustin Pop
  # pylint: disable-msg=R0902
9235 7260cfbe Iustin Pop
  # lots of instance attributes
9236 29859cb7 Iustin Pop
  _ALLO_KEYS = [
9237 8d3f86a0 Iustin Pop
    "name", "mem_size", "disks", "disk_template",
9238 8cc7e742 Guido Trotter
    "os", "tags", "nics", "vcpus", "hypervisor",
9239 d1c2dd75 Iustin Pop
    ]
9240 29859cb7 Iustin Pop
  _RELO_KEYS = [
9241 8d3f86a0 Iustin Pop
    "name", "relocate_from",
9242 29859cb7 Iustin Pop
    ]
9243 7f60a422 Iustin Pop
  _EVAC_KEYS = [
9244 7f60a422 Iustin Pop
    "evac_nodes",
9245 7f60a422 Iustin Pop
    ]
9246 d1c2dd75 Iustin Pop
9247 8d3f86a0 Iustin Pop
  def __init__(self, cfg, rpc, mode, **kwargs):
9248 923ddac0 Michael Hanselmann
    self.cfg = cfg
9249 923ddac0 Michael Hanselmann
    self.rpc = rpc
9250 d1c2dd75 Iustin Pop
    # init buffer variables
9251 d1c2dd75 Iustin Pop
    self.in_text = self.out_text = self.in_data = self.out_data = None
9252 d1c2dd75 Iustin Pop
    # init all input fields so that pylint is happy
9253 29859cb7 Iustin Pop
    self.mode = mode
9254 d1c2dd75 Iustin Pop
    self.mem_size = self.disks = self.disk_template = None
9255 d1c2dd75 Iustin Pop
    self.os = self.tags = self.nics = self.vcpus = None
9256 a0add446 Iustin Pop
    self.hypervisor = None
9257 29859cb7 Iustin Pop
    self.relocate_from = None
9258 8d3f86a0 Iustin Pop
    self.name = None
9259 7f60a422 Iustin Pop
    self.evac_nodes = None
9260 27579978 Iustin Pop
    # computed fields
9261 27579978 Iustin Pop
    self.required_nodes = None
9262 d1c2dd75 Iustin Pop
    # init result fields
9263 680f0a89 Iustin Pop
    self.success = self.info = self.result = None
9264 29859cb7 Iustin Pop
    if self.mode == constants.IALLOCATOR_MODE_ALLOC:
9265 29859cb7 Iustin Pop
      keyset = self._ALLO_KEYS
9266 9757cc90 Iustin Pop
      fn = self._AddNewInstance
9267 29859cb7 Iustin Pop
    elif self.mode == constants.IALLOCATOR_MODE_RELOC:
9268 29859cb7 Iustin Pop
      keyset = self._RELO_KEYS
9269 9757cc90 Iustin Pop
      fn = self._AddRelocateInstance
9270 7f60a422 Iustin Pop
    elif self.mode == constants.IALLOCATOR_MODE_MEVAC:
9271 7f60a422 Iustin Pop
      keyset = self._EVAC_KEYS
9272 7f60a422 Iustin Pop
      fn = self._AddEvacuateNodes
9273 29859cb7 Iustin Pop
    else:
9274 29859cb7 Iustin Pop
      raise errors.ProgrammerError("Unknown mode '%s' passed to the"
9275 29859cb7 Iustin Pop
                                   " IAllocator" % self.mode)
9276 d1c2dd75 Iustin Pop
    for key in kwargs:
9277 29859cb7 Iustin Pop
      if key not in keyset:
9278 d1c2dd75 Iustin Pop
        raise errors.ProgrammerError("Invalid input parameter '%s' to"
9279 d1c2dd75 Iustin Pop
                                     " IAllocator" % key)
9280 d1c2dd75 Iustin Pop
      setattr(self, key, kwargs[key])
9281 7f60a422 Iustin Pop
9282 29859cb7 Iustin Pop
    for key in keyset:
9283 d1c2dd75 Iustin Pop
      if key not in kwargs:
9284 d1c2dd75 Iustin Pop
        raise errors.ProgrammerError("Missing input parameter '%s' to"
9285 d1c2dd75 Iustin Pop
                                     " IAllocator" % key)
9286 9757cc90 Iustin Pop
    self._BuildInputData(fn)
9287 d1c2dd75 Iustin Pop
9288 d1c2dd75 Iustin Pop
  def _ComputeClusterData(self):
9289 d1c2dd75 Iustin Pop
    """Compute the generic allocator input data.
9290 d1c2dd75 Iustin Pop

9291 d1c2dd75 Iustin Pop
    This is the data that is independent of the actual operation.
9292 d1c2dd75 Iustin Pop

9293 d1c2dd75 Iustin Pop
    """
9294 923ddac0 Michael Hanselmann
    cfg = self.cfg
9295 e69d05fd Iustin Pop
    cluster_info = cfg.GetClusterInfo()
9296 d1c2dd75 Iustin Pop
    # cluster data
9297 d1c2dd75 Iustin Pop
    data = {
9298 77031881 Iustin Pop
      "version": constants.IALLOCATOR_VERSION,
9299 72737a7f Iustin Pop
      "cluster_name": cfg.GetClusterName(),
9300 e69d05fd Iustin Pop
      "cluster_tags": list(cluster_info.GetTags()),
9301 1325da74 Iustin Pop
      "enabled_hypervisors": list(cluster_info.enabled_hypervisors),
9302 d1c2dd75 Iustin Pop
      # we don't have job IDs
9303 d61df03e Iustin Pop
      }
9304 b57e9819 Guido Trotter
    iinfo = cfg.GetAllInstancesInfo().values()
9305 b57e9819 Guido Trotter
    i_list = [(inst, cluster_info.FillBE(inst)) for inst in iinfo]
9306 6286519f Iustin Pop
9307 d1c2dd75 Iustin Pop
    # node data
9308 d1c2dd75 Iustin Pop
    node_results = {}
9309 d1c2dd75 Iustin Pop
    node_list = cfg.GetNodeList()
9310 8cc7e742 Guido Trotter
9311 8cc7e742 Guido Trotter
    if self.mode == constants.IALLOCATOR_MODE_ALLOC:
9312 a0add446 Iustin Pop
      hypervisor_name = self.hypervisor
9313 8cc7e742 Guido Trotter
    elif self.mode == constants.IALLOCATOR_MODE_RELOC:
9314 a0add446 Iustin Pop
      hypervisor_name = cfg.GetInstanceInfo(self.name).hypervisor
9315 7f60a422 Iustin Pop
    elif self.mode == constants.IALLOCATOR_MODE_MEVAC:
9316 7f60a422 Iustin Pop
      hypervisor_name = cluster_info.enabled_hypervisors[0]
9317 8cc7e742 Guido Trotter
9318 923ddac0 Michael Hanselmann
    node_data = self.rpc.call_node_info(node_list, cfg.GetVGName(),
9319 923ddac0 Michael Hanselmann
                                        hypervisor_name)
9320 923ddac0 Michael Hanselmann
    node_iinfo = \
9321 923ddac0 Michael Hanselmann
      self.rpc.call_all_instances_info(node_list,
9322 923ddac0 Michael Hanselmann
                                       cluster_info.enabled_hypervisors)
9323 1325da74 Iustin Pop
    for nname, nresult in node_data.items():
9324 1325da74 Iustin Pop
      # first fill in static (config-based) values
9325 d1c2dd75 Iustin Pop
      ninfo = cfg.GetNodeInfo(nname)
9326 d1c2dd75 Iustin Pop
      pnr = {
9327 d1c2dd75 Iustin Pop
        "tags": list(ninfo.GetTags()),
9328 d1c2dd75 Iustin Pop
        "primary_ip": ninfo.primary_ip,
9329 d1c2dd75 Iustin Pop
        "secondary_ip": ninfo.secondary_ip,
9330 fc0fe88c Iustin Pop
        "offline": ninfo.offline,
9331 0b2454b9 Iustin Pop
        "drained": ninfo.drained,
9332 1325da74 Iustin Pop
        "master_candidate": ninfo.master_candidate,
9333 d1c2dd75 Iustin Pop
        }
9334 1325da74 Iustin Pop
9335 0d853843 Iustin Pop
      if not (ninfo.offline or ninfo.drained):
9336 4c4e4e1e Iustin Pop
        nresult.Raise("Can't get data for node %s" % nname)
9337 4c4e4e1e Iustin Pop
        node_iinfo[nname].Raise("Can't get node instance info from node %s" %
9338 4c4e4e1e Iustin Pop
                                nname)
9339 070e998b Iustin Pop
        remote_info = nresult.payload
9340 b142ef15 Iustin Pop
9341 1325da74 Iustin Pop
        for attr in ['memory_total', 'memory_free', 'memory_dom0',
9342 1325da74 Iustin Pop
                     'vg_size', 'vg_free', 'cpu_total']:
9343 1325da74 Iustin Pop
          if attr not in remote_info:
9344 1325da74 Iustin Pop
            raise errors.OpExecError("Node '%s' didn't return attribute"
9345 1325da74 Iustin Pop
                                     " '%s'" % (nname, attr))
9346 070e998b Iustin Pop
          if not isinstance(remote_info[attr], int):
9347 1325da74 Iustin Pop
            raise errors.OpExecError("Node '%s' returned invalid value"
9348 070e998b Iustin Pop
                                     " for '%s': %s" %
9349 070e998b Iustin Pop
                                     (nname, attr, remote_info[attr]))
9350 1325da74 Iustin Pop
        # compute memory used by primary instances
9351 1325da74 Iustin Pop
        i_p_mem = i_p_up_mem = 0
9352 1325da74 Iustin Pop
        for iinfo, beinfo in i_list:
9353 1325da74 Iustin Pop
          if iinfo.primary_node == nname:
9354 1325da74 Iustin Pop
            i_p_mem += beinfo[constants.BE_MEMORY]
9355 2fa74ef4 Iustin Pop
            if iinfo.name not in node_iinfo[nname].payload:
9356 1325da74 Iustin Pop
              i_used_mem = 0
9357 1325da74 Iustin Pop
            else:
9358 2fa74ef4 Iustin Pop
              i_used_mem = int(node_iinfo[nname].payload[iinfo.name]['memory'])
9359 1325da74 Iustin Pop
            i_mem_diff = beinfo[constants.BE_MEMORY] - i_used_mem
9360 1325da74 Iustin Pop
            remote_info['memory_free'] -= max(0, i_mem_diff)
9361 1325da74 Iustin Pop
9362 1325da74 Iustin Pop
            if iinfo.admin_up:
9363 1325da74 Iustin Pop
              i_p_up_mem += beinfo[constants.BE_MEMORY]
9364 1325da74 Iustin Pop
9365 1325da74 Iustin Pop
        # compute memory used by instances
9366 1325da74 Iustin Pop
        pnr_dyn = {
9367 1325da74 Iustin Pop
          "total_memory": remote_info['memory_total'],
9368 1325da74 Iustin Pop
          "reserved_memory": remote_info['memory_dom0'],
9369 1325da74 Iustin Pop
          "free_memory": remote_info['memory_free'],
9370 1325da74 Iustin Pop
          "total_disk": remote_info['vg_size'],
9371 1325da74 Iustin Pop
          "free_disk": remote_info['vg_free'],
9372 1325da74 Iustin Pop
          "total_cpus": remote_info['cpu_total'],
9373 1325da74 Iustin Pop
          "i_pri_memory": i_p_mem,
9374 1325da74 Iustin Pop
          "i_pri_up_memory": i_p_up_mem,
9375 1325da74 Iustin Pop
          }
9376 1325da74 Iustin Pop
        pnr.update(pnr_dyn)
9377 1325da74 Iustin Pop
9378 d1c2dd75 Iustin Pop
      node_results[nname] = pnr
9379 d1c2dd75 Iustin Pop
    data["nodes"] = node_results
9380 d1c2dd75 Iustin Pop
9381 d1c2dd75 Iustin Pop
    # instance data
9382 d1c2dd75 Iustin Pop
    instance_data = {}
9383 338e51e8 Iustin Pop
    for iinfo, beinfo in i_list:
9384 a9fe7e8f Guido Trotter
      nic_data = []
9385 a9fe7e8f Guido Trotter
      for nic in iinfo.nics:
9386 a9fe7e8f Guido Trotter
        filled_params = objects.FillDict(
9387 a9fe7e8f Guido Trotter
            cluster_info.nicparams[constants.PP_DEFAULT],
9388 a9fe7e8f Guido Trotter
            nic.nicparams)
9389 a9fe7e8f Guido Trotter
        nic_dict = {"mac": nic.mac,
9390 a9fe7e8f Guido Trotter
                    "ip": nic.ip,
9391 a9fe7e8f Guido Trotter
                    "mode": filled_params[constants.NIC_MODE],
9392 a9fe7e8f Guido Trotter
                    "link": filled_params[constants.NIC_LINK],
9393 a9fe7e8f Guido Trotter
                   }
9394 a9fe7e8f Guido Trotter
        if filled_params[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
9395 a9fe7e8f Guido Trotter
          nic_dict["bridge"] = filled_params[constants.NIC_LINK]
9396 a9fe7e8f Guido Trotter
        nic_data.append(nic_dict)
9397 d1c2dd75 Iustin Pop
      pir = {
9398 d1c2dd75 Iustin Pop
        "tags": list(iinfo.GetTags()),
9399 1325da74 Iustin Pop
        "admin_up": iinfo.admin_up,
9400 338e51e8 Iustin Pop
        "vcpus": beinfo[constants.BE_VCPUS],
9401 338e51e8 Iustin Pop
        "memory": beinfo[constants.BE_MEMORY],
9402 d1c2dd75 Iustin Pop
        "os": iinfo.os,
9403 1325da74 Iustin Pop
        "nodes": [iinfo.primary_node] + list(iinfo.secondary_nodes),
9404 d1c2dd75 Iustin Pop
        "nics": nic_data,
9405 1325da74 Iustin Pop
        "disks": [{"size": dsk.size, "mode": dsk.mode} for dsk in iinfo.disks],
9406 d1c2dd75 Iustin Pop
        "disk_template": iinfo.disk_template,
9407 e69d05fd Iustin Pop
        "hypervisor": iinfo.hypervisor,
9408 d1c2dd75 Iustin Pop
        }
9409 88ae4f85 Iustin Pop
      pir["disk_space_total"] = _ComputeDiskSize(iinfo.disk_template,
9410 88ae4f85 Iustin Pop
                                                 pir["disks"])
9411 768f0a80 Iustin Pop
      instance_data[iinfo.name] = pir
9412 d61df03e Iustin Pop
9413 d1c2dd75 Iustin Pop
    data["instances"] = instance_data
9414 d61df03e Iustin Pop
9415 d1c2dd75 Iustin Pop
    self.in_data = data
9416 d61df03e Iustin Pop
9417 d1c2dd75 Iustin Pop
  def _AddNewInstance(self):
9418 d1c2dd75 Iustin Pop
    """Add new instance data to allocator structure.
9419 d61df03e Iustin Pop

9420 d1c2dd75 Iustin Pop
    This in combination with _AllocatorGetClusterData will create the
9421 d1c2dd75 Iustin Pop
    correct structure needed as input for the allocator.
9422 d61df03e Iustin Pop

9423 d1c2dd75 Iustin Pop
    The checks for the completeness of the opcode must have already been
9424 d1c2dd75 Iustin Pop
    done.
9425 d61df03e Iustin Pop

9426 d1c2dd75 Iustin Pop
    """
9427 dafc7302 Guido Trotter
    disk_space = _ComputeDiskSize(self.disk_template, self.disks)
9428 d1c2dd75 Iustin Pop
9429 27579978 Iustin Pop
    if self.disk_template in constants.DTS_NET_MIRROR:
9430 27579978 Iustin Pop
      self.required_nodes = 2
9431 27579978 Iustin Pop
    else:
9432 27579978 Iustin Pop
      self.required_nodes = 1
9433 d1c2dd75 Iustin Pop
    request = {
9434 d1c2dd75 Iustin Pop
      "name": self.name,
9435 d1c2dd75 Iustin Pop
      "disk_template": self.disk_template,
9436 d1c2dd75 Iustin Pop
      "tags": self.tags,
9437 d1c2dd75 Iustin Pop
      "os": self.os,
9438 d1c2dd75 Iustin Pop
      "vcpus": self.vcpus,
9439 d1c2dd75 Iustin Pop
      "memory": self.mem_size,
9440 d1c2dd75 Iustin Pop
      "disks": self.disks,
9441 d1c2dd75 Iustin Pop
      "disk_space_total": disk_space,
9442 d1c2dd75 Iustin Pop
      "nics": self.nics,
9443 27579978 Iustin Pop
      "required_nodes": self.required_nodes,
9444 d1c2dd75 Iustin Pop
      }
9445 9757cc90 Iustin Pop
    return request
9446 298fe380 Iustin Pop
9447 d1c2dd75 Iustin Pop
  def _AddRelocateInstance(self):
9448 d1c2dd75 Iustin Pop
    """Add relocate instance data to allocator structure.
9449 298fe380 Iustin Pop

9450 d1c2dd75 Iustin Pop
    This in combination with _IAllocatorGetClusterData will create the
9451 d1c2dd75 Iustin Pop
    correct structure needed as input for the allocator.
9452 d61df03e Iustin Pop

9453 d1c2dd75 Iustin Pop
    The checks for the completeness of the opcode must have already been
9454 d1c2dd75 Iustin Pop
    done.
9455 d61df03e Iustin Pop

9456 d1c2dd75 Iustin Pop
    """
9457 923ddac0 Michael Hanselmann
    instance = self.cfg.GetInstanceInfo(self.name)
9458 27579978 Iustin Pop
    if instance is None:
9459 27579978 Iustin Pop
      raise errors.ProgrammerError("Unknown instance '%s' passed to"
9460 27579978 Iustin Pop
                                   " IAllocator" % self.name)
9461 27579978 Iustin Pop
9462 27579978 Iustin Pop
    if instance.disk_template not in constants.DTS_NET_MIRROR:
9463 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Can't relocate non-mirrored instances",
9464 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
9465 27579978 Iustin Pop
9466 2a139bb0 Iustin Pop
    if len(instance.secondary_nodes) != 1:
9467 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Instance has not exactly one secondary node",
9468 5c983ee5 Iustin Pop
                                 errors.ECODE_STATE)
9469 2a139bb0 Iustin Pop
9470 27579978 Iustin Pop
    self.required_nodes = 1
9471 dafc7302 Guido Trotter
    disk_sizes = [{'size': disk.size} for disk in instance.disks]
9472 dafc7302 Guido Trotter
    disk_space = _ComputeDiskSize(instance.disk_template, disk_sizes)
9473 27579978 Iustin Pop
9474 d1c2dd75 Iustin Pop
    request = {
9475 d1c2dd75 Iustin Pop
      "name": self.name,
9476 27579978 Iustin Pop
      "disk_space_total": disk_space,
9477 27579978 Iustin Pop
      "required_nodes": self.required_nodes,
9478 29859cb7 Iustin Pop
      "relocate_from": self.relocate_from,
9479 d1c2dd75 Iustin Pop
      }
9480 9757cc90 Iustin Pop
    return request
9481 d61df03e Iustin Pop
9482 7f60a422 Iustin Pop
  def _AddEvacuateNodes(self):
9483 7f60a422 Iustin Pop
    """Add evacuate nodes data to allocator structure.
9484 7f60a422 Iustin Pop

9485 7f60a422 Iustin Pop
    """
9486 7f60a422 Iustin Pop
    request = {
9487 7f60a422 Iustin Pop
      "evac_nodes": self.evac_nodes
9488 7f60a422 Iustin Pop
      }
9489 7f60a422 Iustin Pop
    return request
9490 7f60a422 Iustin Pop
9491 9757cc90 Iustin Pop
  def _BuildInputData(self, fn):
9492 d1c2dd75 Iustin Pop
    """Build input data structures.
9493 d61df03e Iustin Pop

9494 d1c2dd75 Iustin Pop
    """
9495 d1c2dd75 Iustin Pop
    self._ComputeClusterData()
9496 d61df03e Iustin Pop
9497 9757cc90 Iustin Pop
    request = fn()
9498 9757cc90 Iustin Pop
    request["type"] = self.mode
9499 9757cc90 Iustin Pop
    self.in_data["request"] = request
9500 d61df03e Iustin Pop
9501 d1c2dd75 Iustin Pop
    self.in_text = serializer.Dump(self.in_data)
9502 d61df03e Iustin Pop
9503 72737a7f Iustin Pop
  def Run(self, name, validate=True, call_fn=None):
9504 d1c2dd75 Iustin Pop
    """Run an instance allocator and return the results.
9505 298fe380 Iustin Pop

9506 d1c2dd75 Iustin Pop
    """
9507 72737a7f Iustin Pop
    if call_fn is None:
9508 923ddac0 Michael Hanselmann
      call_fn = self.rpc.call_iallocator_runner
9509 298fe380 Iustin Pop
9510 923ddac0 Michael Hanselmann
    result = call_fn(self.cfg.GetMasterNode(), name, self.in_text)
9511 4c4e4e1e Iustin Pop
    result.Raise("Failure while running the iallocator script")
9512 8d528b7c Iustin Pop
9513 87f5c298 Iustin Pop
    self.out_text = result.payload
9514 d1c2dd75 Iustin Pop
    if validate:
9515 d1c2dd75 Iustin Pop
      self._ValidateResult()
9516 298fe380 Iustin Pop
9517 d1c2dd75 Iustin Pop
  def _ValidateResult(self):
9518 d1c2dd75 Iustin Pop
    """Process the allocator results.
9519 538475ca Iustin Pop

9520 d1c2dd75 Iustin Pop
    This will process and if successful save the result in
9521 d1c2dd75 Iustin Pop
    self.out_data and the other parameters.
9522 538475ca Iustin Pop

9523 d1c2dd75 Iustin Pop
    """
9524 d1c2dd75 Iustin Pop
    try:
9525 d1c2dd75 Iustin Pop
      rdict = serializer.Load(self.out_text)
9526 d1c2dd75 Iustin Pop
    except Exception, err:
9527 d1c2dd75 Iustin Pop
      raise errors.OpExecError("Can't parse iallocator results: %s" % str(err))
9528 d1c2dd75 Iustin Pop
9529 d1c2dd75 Iustin Pop
    if not isinstance(rdict, dict):
9530 d1c2dd75 Iustin Pop
      raise errors.OpExecError("Can't parse iallocator results: not a dict")
9531 538475ca Iustin Pop
9532 680f0a89 Iustin Pop
    # TODO: remove backwards compatiblity in later versions
9533 680f0a89 Iustin Pop
    if "nodes" in rdict and "result" not in rdict:
9534 680f0a89 Iustin Pop
      rdict["result"] = rdict["nodes"]
9535 680f0a89 Iustin Pop
      del rdict["nodes"]
9536 680f0a89 Iustin Pop
9537 680f0a89 Iustin Pop
    for key in "success", "info", "result":
9538 d1c2dd75 Iustin Pop
      if key not in rdict:
9539 d1c2dd75 Iustin Pop
        raise errors.OpExecError("Can't parse iallocator results:"
9540 d1c2dd75 Iustin Pop
                                 " missing key '%s'" % key)
9541 d1c2dd75 Iustin Pop
      setattr(self, key, rdict[key])
9542 538475ca Iustin Pop
9543 680f0a89 Iustin Pop
    if not isinstance(rdict["result"], list):
9544 680f0a89 Iustin Pop
      raise errors.OpExecError("Can't parse iallocator results: 'result' key"
9545 d1c2dd75 Iustin Pop
                               " is not a list")
9546 d1c2dd75 Iustin Pop
    self.out_data = rdict
9547 538475ca Iustin Pop
9548 538475ca Iustin Pop
9549 d61df03e Iustin Pop
class LUTestAllocator(NoHooksLU):
9550 d61df03e Iustin Pop
  """Run allocator tests.
9551 d61df03e Iustin Pop

9552 d61df03e Iustin Pop
  This LU runs the allocator tests
9553 d61df03e Iustin Pop

9554 d61df03e Iustin Pop
  """
9555 d61df03e Iustin Pop
  _OP_REQP = ["direction", "mode", "name"]
9556 d61df03e Iustin Pop
9557 d61df03e Iustin Pop
  def CheckPrereq(self):
9558 d61df03e Iustin Pop
    """Check prerequisites.
9559 d61df03e Iustin Pop

9560 d61df03e Iustin Pop
    This checks the opcode parameters depending on the director and mode test.
9561 d61df03e Iustin Pop

9562 d61df03e Iustin Pop
    """
9563 298fe380 Iustin Pop
    if self.op.mode == constants.IALLOCATOR_MODE_ALLOC:
9564 d61df03e Iustin Pop
      for attr in ["name", "mem_size", "disks", "disk_template",
9565 d61df03e Iustin Pop
                   "os", "tags", "nics", "vcpus"]:
9566 d61df03e Iustin Pop
        if not hasattr(self.op, attr):
9567 d61df03e Iustin Pop
          raise errors.OpPrereqError("Missing attribute '%s' on opcode input" %
9568 5c983ee5 Iustin Pop
                                     attr, errors.ECODE_INVAL)
9569 d61df03e Iustin Pop
      iname = self.cfg.ExpandInstanceName(self.op.name)
9570 d61df03e Iustin Pop
      if iname is not None:
9571 d61df03e Iustin Pop
        raise errors.OpPrereqError("Instance '%s' already in the cluster" %
9572 5c983ee5 Iustin Pop
                                   iname, errors.ECODE_EXISTS)
9573 d61df03e Iustin Pop
      if not isinstance(self.op.nics, list):
9574 5c983ee5 Iustin Pop
        raise errors.OpPrereqError("Invalid parameter 'nics'",
9575 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
9576 d61df03e Iustin Pop
      for row in self.op.nics:
9577 d61df03e Iustin Pop
        if (not isinstance(row, dict) or
9578 d61df03e Iustin Pop
            "mac" not in row or
9579 d61df03e Iustin Pop
            "ip" not in row or
9580 d61df03e Iustin Pop
            "bridge" not in row):
9581 5c983ee5 Iustin Pop
          raise errors.OpPrereqError("Invalid contents of the 'nics'"
9582 5c983ee5 Iustin Pop
                                     " parameter", errors.ECODE_INVAL)
9583 d61df03e Iustin Pop
      if not isinstance(self.op.disks, list):
9584 5c983ee5 Iustin Pop
        raise errors.OpPrereqError("Invalid parameter 'disks'",
9585 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
9586 d61df03e Iustin Pop
      for row in self.op.disks:
9587 d61df03e Iustin Pop
        if (not isinstance(row, dict) or
9588 d61df03e Iustin Pop
            "size" not in row or
9589 d61df03e Iustin Pop
            not isinstance(row["size"], int) or
9590 d61df03e Iustin Pop
            "mode" not in row or
9591 d61df03e Iustin Pop
            row["mode"] not in ['r', 'w']):
9592 5c983ee5 Iustin Pop
          raise errors.OpPrereqError("Invalid contents of the 'disks'"
9593 5c983ee5 Iustin Pop
                                     " parameter", errors.ECODE_INVAL)
9594 8901997e Iustin Pop
      if not hasattr(self.op, "hypervisor") or self.op.hypervisor is None:
9595 8cc7e742 Guido Trotter
        self.op.hypervisor = self.cfg.GetHypervisorType()
9596 298fe380 Iustin Pop
    elif self.op.mode == constants.IALLOCATOR_MODE_RELOC:
9597 d61df03e Iustin Pop
      if not hasattr(self.op, "name"):
9598 5c983ee5 Iustin Pop
        raise errors.OpPrereqError("Missing attribute 'name' on opcode input",
9599 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
9600 cf26a87a Iustin Pop
      fname = _ExpandInstanceName(self.cfg, self.op.name)
9601 d61df03e Iustin Pop
      self.op.name = fname
9602 29859cb7 Iustin Pop
      self.relocate_from = self.cfg.GetInstanceInfo(fname).secondary_nodes
9603 823a72bc Iustin Pop
    elif self.op.mode == constants.IALLOCATOR_MODE_MEVAC:
9604 823a72bc Iustin Pop
      if not hasattr(self.op, "evac_nodes"):
9605 823a72bc Iustin Pop
        raise errors.OpPrereqError("Missing attribute 'evac_nodes' on"
9606 823a72bc Iustin Pop
                                   " opcode input", errors.ECODE_INVAL)
9607 d61df03e Iustin Pop
    else:
9608 d61df03e Iustin Pop
      raise errors.OpPrereqError("Invalid test allocator mode '%s'" %
9609 5c983ee5 Iustin Pop
                                 self.op.mode, errors.ECODE_INVAL)
9610 d61df03e Iustin Pop
9611 298fe380 Iustin Pop
    if self.op.direction == constants.IALLOCATOR_DIR_OUT:
9612 298fe380 Iustin Pop
      if not hasattr(self.op, "allocator") or self.op.allocator is None:
9613 5c983ee5 Iustin Pop
        raise errors.OpPrereqError("Missing allocator name",
9614 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
9615 298fe380 Iustin Pop
    elif self.op.direction != constants.IALLOCATOR_DIR_IN:
9616 d61df03e Iustin Pop
      raise errors.OpPrereqError("Wrong allocator test '%s'" %
9617 5c983ee5 Iustin Pop
                                 self.op.direction, errors.ECODE_INVAL)
9618 d61df03e Iustin Pop
9619 d61df03e Iustin Pop
  def Exec(self, feedback_fn):
9620 d61df03e Iustin Pop
    """Run the allocator test.
9621 d61df03e Iustin Pop

9622 d61df03e Iustin Pop
    """
9623 29859cb7 Iustin Pop
    if self.op.mode == constants.IALLOCATOR_MODE_ALLOC:
9624 923ddac0 Michael Hanselmann
      ial = IAllocator(self.cfg, self.rpc,
9625 29859cb7 Iustin Pop
                       mode=self.op.mode,
9626 29859cb7 Iustin Pop
                       name=self.op.name,
9627 29859cb7 Iustin Pop
                       mem_size=self.op.mem_size,
9628 29859cb7 Iustin Pop
                       disks=self.op.disks,
9629 29859cb7 Iustin Pop
                       disk_template=self.op.disk_template,
9630 29859cb7 Iustin Pop
                       os=self.op.os,
9631 29859cb7 Iustin Pop
                       tags=self.op.tags,
9632 29859cb7 Iustin Pop
                       nics=self.op.nics,
9633 29859cb7 Iustin Pop
                       vcpus=self.op.vcpus,
9634 8cc7e742 Guido Trotter
                       hypervisor=self.op.hypervisor,
9635 29859cb7 Iustin Pop
                       )
9636 823a72bc Iustin Pop
    elif self.op.mode == constants.IALLOCATOR_MODE_RELOC:
9637 923ddac0 Michael Hanselmann
      ial = IAllocator(self.cfg, self.rpc,
9638 29859cb7 Iustin Pop
                       mode=self.op.mode,
9639 29859cb7 Iustin Pop
                       name=self.op.name,
9640 29859cb7 Iustin Pop
                       relocate_from=list(self.relocate_from),
9641 29859cb7 Iustin Pop
                       )
9642 823a72bc Iustin Pop
    elif self.op.mode == constants.IALLOCATOR_MODE_MEVAC:
9643 823a72bc Iustin Pop
      ial = IAllocator(self.cfg, self.rpc,
9644 823a72bc Iustin Pop
                       mode=self.op.mode,
9645 823a72bc Iustin Pop
                       evac_nodes=self.op.evac_nodes)
9646 823a72bc Iustin Pop
    else:
9647 823a72bc Iustin Pop
      raise errors.ProgrammerError("Uncatched mode %s in"
9648 823a72bc Iustin Pop
                                   " LUTestAllocator.Exec", self.op.mode)
9649 d61df03e Iustin Pop
9650 298fe380 Iustin Pop
    if self.op.direction == constants.IALLOCATOR_DIR_IN:
9651 d1c2dd75 Iustin Pop
      result = ial.in_text
9652 298fe380 Iustin Pop
    else:
9653 d1c2dd75 Iustin Pop
      ial.Run(self.op.allocator, validate=False)
9654 d1c2dd75 Iustin Pop
      result = ial.out_text
9655 298fe380 Iustin Pop
    return result