Statistics
| Branch: | Tag: | Revision:

root / lib / cmdlib.py @ 1b67be9b

History | View | Annotate | Download (342.9 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 e311ed53 Michael Hanselmann
from ganeti import compat
49 d61df03e Iustin Pop
50 d61df03e Iustin Pop
51 a8083063 Iustin Pop
class LogicalUnit(object):
52 396e1b78 Michael Hanselmann
  """Logical Unit base class.
53 a8083063 Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

170 e4376078 Iustin Pop
    Examples::
171 e4376078 Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1349 02c521e4 Iustin Pop
    """
1350 02c521e4 Iustin Pop
    node = ninfo.name
1351 02c521e4 Iustin Pop
    _ErrorIf = self._ErrorIf # pylint: disable-msg=C0103
1352 02c521e4 Iustin Pop
1353 02c521e4 Iustin Pop
    test = constants.NV_NODELIST not in nresult
1354 a0c9776a Iustin Pop
    _ErrorIf(test, self.ENODESSH, node,
1355 a0c9776a Iustin Pop
             "node hasn't returned node ssh connectivity data")
1356 a0c9776a Iustin Pop
    if not test:
1357 02c521e4 Iustin Pop
      if nresult[constants.NV_NODELIST]:
1358 02c521e4 Iustin Pop
        for a_node, a_msg in nresult[constants.NV_NODELIST].items():
1359 a0c9776a Iustin Pop
          _ErrorIf(True, self.ENODESSH, node,
1360 a0c9776a Iustin Pop
                   "ssh communication with node '%s': %s", a_node, a_msg)
1361 25361b9a Iustin Pop
1362 02c521e4 Iustin Pop
    test = constants.NV_NODENETTEST not in nresult
1363 a0c9776a Iustin Pop
    _ErrorIf(test, self.ENODENET, node,
1364 a0c9776a Iustin Pop
             "node hasn't returned node tcp connectivity data")
1365 a0c9776a Iustin Pop
    if not test:
1366 02c521e4 Iustin Pop
      if nresult[constants.NV_NODENETTEST]:
1367 02c521e4 Iustin Pop
        nlist = utils.NiceSort(nresult[constants.NV_NODENETTEST].keys())
1368 7c874ee1 Iustin Pop
        for anode in nlist:
1369 a0c9776a Iustin Pop
          _ErrorIf(True, self.ENODENET, node,
1370 a0c9776a Iustin Pop
                   "tcp communication with node '%s': %s",
1371 02c521e4 Iustin Pop
                   anode, nresult[constants.NV_NODENETTEST][anode])
1372 a8083063 Iustin Pop
1373 a3a5f850 Iustin Pop
    test = constants.NV_MASTERIP not in nresult
1374 a3a5f850 Iustin Pop
    _ErrorIf(test, self.ENODENET, node,
1375 a3a5f850 Iustin Pop
             "node hasn't returned node master IP reachability data")
1376 a3a5f850 Iustin Pop
    if not test:
1377 a3a5f850 Iustin Pop
      if not nresult[constants.NV_MASTERIP]:
1378 a3a5f850 Iustin Pop
        if node == self.master_node:
1379 a3a5f850 Iustin Pop
          msg = "the master node cannot reach the master IP (not configured?)"
1380 a3a5f850 Iustin Pop
        else:
1381 a3a5f850 Iustin Pop
          msg = "cannot reach the master IP"
1382 a3a5f850 Iustin Pop
        _ErrorIf(True, self.ENODENET, node, msg)
1383 a3a5f850 Iustin Pop
1384 a3a5f850 Iustin Pop
1385 02c521e4 Iustin Pop
  def _VerifyInstance(self, instance, instanceconfig, node_image):
1386 a8083063 Iustin Pop
    """Verify an instance.
1387 a8083063 Iustin Pop

1388 a8083063 Iustin Pop
    This function checks to see if the required block devices are
1389 a8083063 Iustin Pop
    available on the instance's node.
1390 a8083063 Iustin Pop

1391 a8083063 Iustin Pop
    """
1392 7260cfbe Iustin Pop
    _ErrorIf = self._ErrorIf # pylint: disable-msg=C0103
1393 a8083063 Iustin Pop
    node_current = instanceconfig.primary_node
1394 a8083063 Iustin Pop
1395 a8083063 Iustin Pop
    node_vol_should = {}
1396 a8083063 Iustin Pop
    instanceconfig.MapLVsByNode(node_vol_should)
1397 a8083063 Iustin Pop
1398 a8083063 Iustin Pop
    for node in node_vol_should:
1399 02c521e4 Iustin Pop
      n_img = node_image[node]
1400 02c521e4 Iustin Pop
      if n_img.offline or n_img.rpc_fail or n_img.lvm_fail:
1401 02c521e4 Iustin Pop
        # ignore missing volumes on offline or broken nodes
1402 0a66c968 Iustin Pop
        continue
1403 a8083063 Iustin Pop
      for volume in node_vol_should[node]:
1404 02c521e4 Iustin Pop
        test = volume not in n_img.volumes
1405 a0c9776a Iustin Pop
        _ErrorIf(test, self.EINSTANCEMISSINGDISK, instance,
1406 a0c9776a Iustin Pop
                 "volume %s missing on node %s", volume, node)
1407 a8083063 Iustin Pop
1408 0d68c45d Iustin Pop
    if instanceconfig.admin_up:
1409 02c521e4 Iustin Pop
      pri_img = node_image[node_current]
1410 02c521e4 Iustin Pop
      test = instance not in pri_img.instances and not pri_img.offline
1411 a0c9776a Iustin Pop
      _ErrorIf(test, self.EINSTANCEDOWN, instance,
1412 a0c9776a Iustin Pop
               "instance not running on its primary node %s",
1413 a0c9776a Iustin Pop
               node_current)
1414 a8083063 Iustin Pop
1415 02c521e4 Iustin Pop
    for node, n_img in node_image.items():
1416 a8083063 Iustin Pop
      if (not node == node_current):
1417 02c521e4 Iustin Pop
        test = instance in n_img.instances
1418 a0c9776a Iustin Pop
        _ErrorIf(test, self.EINSTANCEWRONGNODE, instance,
1419 a0c9776a Iustin Pop
                 "instance should not run on node %s", node)
1420 a8083063 Iustin Pop
1421 02c521e4 Iustin Pop
  def _VerifyOrphanVolumes(self, node_vol_should, node_image):
1422 a8083063 Iustin Pop
    """Verify if there are any unknown volumes in the cluster.
1423 a8083063 Iustin Pop

1424 a8083063 Iustin Pop
    The .os, .swap and backup volumes are ignored. All other volumes are
1425 a8083063 Iustin Pop
    reported as unknown.
1426 a8083063 Iustin Pop

1427 a8083063 Iustin Pop
    """
1428 02c521e4 Iustin Pop
    for node, n_img in node_image.items():
1429 02c521e4 Iustin Pop
      if n_img.offline or n_img.rpc_fail or n_img.lvm_fail:
1430 02c521e4 Iustin Pop
        # skip non-healthy nodes
1431 02c521e4 Iustin Pop
        continue
1432 02c521e4 Iustin Pop
      for volume in n_img.volumes:
1433 a0c9776a Iustin Pop
        test = (node not in node_vol_should or
1434 a0c9776a Iustin Pop
                volume not in node_vol_should[node])
1435 a0c9776a Iustin Pop
        self._ErrorIf(test, self.ENODEORPHANLV, node,
1436 7c874ee1 Iustin Pop
                      "volume %s is unknown", volume)
1437 a8083063 Iustin Pop
1438 02c521e4 Iustin Pop
  def _VerifyOrphanInstances(self, instancelist, node_image):
1439 a8083063 Iustin Pop
    """Verify the list of running instances.
1440 a8083063 Iustin Pop

1441 a8083063 Iustin Pop
    This checks what instances are running but unknown to the cluster.
1442 a8083063 Iustin Pop

1443 a8083063 Iustin Pop
    """
1444 02c521e4 Iustin Pop
    for node, n_img in node_image.items():
1445 02c521e4 Iustin Pop
      for o_inst in n_img.instances:
1446 a0c9776a Iustin Pop
        test = o_inst not in instancelist
1447 a0c9776a Iustin Pop
        self._ErrorIf(test, self.ENODEORPHANINSTANCE, node,
1448 7c874ee1 Iustin Pop
                      "instance %s on node %s should not exist", o_inst, node)
1449 a8083063 Iustin Pop
1450 02c521e4 Iustin Pop
  def _VerifyNPlusOneMemory(self, node_image, instance_cfg):
1451 2b3b6ddd Guido Trotter
    """Verify N+1 Memory Resilience.
1452 2b3b6ddd Guido Trotter

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

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

1481 02c521e4 Iustin Pop
    @type ninfo: L{objects.Node}
1482 02c521e4 Iustin Pop
    @param ninfo: the node to check
1483 02c521e4 Iustin Pop
    @param nresult: the remote results for the node
1484 02c521e4 Iustin Pop
    @param file_list: required list of files
1485 02c521e4 Iustin Pop
    @param local_cksum: dictionary of local files and their checksums
1486 02c521e4 Iustin Pop
    @param master_files: list of files that only masters should have
1487 02c521e4 Iustin Pop

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

1524 02c521e4 Iustin Pop
    @type ninfo: L{objects.Node}
1525 02c521e4 Iustin Pop
    @param ninfo: the node to check
1526 02c521e4 Iustin Pop
    @param nresult: the remote results for the node
1527 02c521e4 Iustin Pop
    @param instanceinfo: the dict of instances
1528 02c521e4 Iustin Pop
    @param drbd_map: the DRBD map as returned by
1529 02c521e4 Iustin Pop
        L{ganeti.config.ConfigWriter.ComputeDRBDMap}
1530 02c521e4 Iustin Pop

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

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

1574 02c521e4 Iustin Pop
    @type ninfo: L{objects.Node}
1575 02c521e4 Iustin Pop
    @param ninfo: the node to check
1576 02c521e4 Iustin Pop
    @param nresult: the remote results for the node
1577 02c521e4 Iustin Pop
    @param nimg: the node image object
1578 02c521e4 Iustin Pop
    @param vg_name: the configured VG name
1579 02c521e4 Iustin Pop

1580 02c521e4 Iustin Pop
    """
1581 02c521e4 Iustin Pop
    node = ninfo.name
1582 02c521e4 Iustin Pop
    _ErrorIf = self._ErrorIf # pylint: disable-msg=C0103
1583 02c521e4 Iustin Pop
1584 02c521e4 Iustin Pop
    nimg.lvm_fail = True
1585 02c521e4 Iustin Pop
    lvdata = nresult.get(constants.NV_LVLIST, "Missing LV data")
1586 02c521e4 Iustin Pop
    if vg_name is None:
1587 02c521e4 Iustin Pop
      pass
1588 02c521e4 Iustin Pop
    elif isinstance(lvdata, basestring):
1589 02c521e4 Iustin Pop
      _ErrorIf(True, self.ENODELVM, node, "LVM problem on node: %s",
1590 02c521e4 Iustin Pop
               utils.SafeEncode(lvdata))
1591 02c521e4 Iustin Pop
    elif not isinstance(lvdata, dict):
1592 02c521e4 Iustin Pop
      _ErrorIf(True, self.ENODELVM, node, "rpc call to node failed (lvlist)")
1593 02c521e4 Iustin Pop
    else:
1594 02c521e4 Iustin Pop
      nimg.volumes = lvdata
1595 02c521e4 Iustin Pop
      nimg.lvm_fail = False
1596 02c521e4 Iustin Pop
1597 02c521e4 Iustin Pop
  def _UpdateNodeInstances(self, ninfo, nresult, nimg):
1598 02c521e4 Iustin Pop
    """Verifies and updates the node instance list.
1599 02c521e4 Iustin Pop

1600 02c521e4 Iustin Pop
    If the listing was successful, then updates this node's instance
1601 02c521e4 Iustin Pop
    list. Otherwise, it marks the RPC call as failed for the instance
1602 02c521e4 Iustin Pop
    list key.
1603 02c521e4 Iustin Pop

1604 02c521e4 Iustin Pop
    @type ninfo: L{objects.Node}
1605 02c521e4 Iustin Pop
    @param ninfo: the node to check
1606 02c521e4 Iustin Pop
    @param nresult: the remote results for the node
1607 02c521e4 Iustin Pop
    @param nimg: the node image object
1608 02c521e4 Iustin Pop

1609 02c521e4 Iustin Pop
    """
1610 02c521e4 Iustin Pop
    idata = nresult.get(constants.NV_INSTANCELIST, None)
1611 02c521e4 Iustin Pop
    test = not isinstance(idata, list)
1612 02c521e4 Iustin Pop
    self._ErrorIf(test, self.ENODEHV, ninfo.name, "rpc call to node failed"
1613 02c521e4 Iustin Pop
                  " (instancelist): %s", utils.SafeEncode(str(idata)))
1614 02c521e4 Iustin Pop
    if test:
1615 02c521e4 Iustin Pop
      nimg.hyp_fail = True
1616 02c521e4 Iustin Pop
    else:
1617 02c521e4 Iustin Pop
      nimg.instances = idata
1618 02c521e4 Iustin Pop
1619 02c521e4 Iustin Pop
  def _UpdateNodeInfo(self, ninfo, nresult, nimg, vg_name):
1620 02c521e4 Iustin Pop
    """Verifies and computes a node information map
1621 02c521e4 Iustin Pop

1622 02c521e4 Iustin Pop
    @type ninfo: L{objects.Node}
1623 02c521e4 Iustin Pop
    @param ninfo: the node to check
1624 02c521e4 Iustin Pop
    @param nresult: the remote results for the node
1625 02c521e4 Iustin Pop
    @param nimg: the node image object
1626 02c521e4 Iustin Pop
    @param vg_name: the configured VG name
1627 02c521e4 Iustin Pop

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

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

1663 a8083063 Iustin Pop
    """
1664 e54c4c5e Guido Trotter
    self.skip_set = frozenset(self.op.skip_checks)
1665 e54c4c5e Guido Trotter
    if not constants.VERIFY_OPTIONAL_CHECKS.issuperset(self.skip_set):
1666 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Invalid checks to be skipped specified",
1667 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
1668 a8083063 Iustin Pop
1669 d8fff41c Guido Trotter
  def BuildHooksEnv(self):
1670 d8fff41c Guido Trotter
    """Build hooks env.
1671 d8fff41c Guido Trotter

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

1675 d8fff41c Guido Trotter
    """
1676 d8fff41c Guido Trotter
    all_nodes = self.cfg.GetNodeList()
1677 35e994e9 Iustin Pop
    env = {
1678 35e994e9 Iustin Pop
      "CLUSTER_TAGS": " ".join(self.cfg.GetClusterInfo().GetTags())
1679 35e994e9 Iustin Pop
      }
1680 35e994e9 Iustin Pop
    for node in self.cfg.GetAllNodesInfo().values():
1681 35e994e9 Iustin Pop
      env["NODE_TAGS_%s" % node.name] = " ".join(node.GetTags())
1682 35e994e9 Iustin Pop
1683 d8fff41c Guido Trotter
    return env, [], all_nodes
1684 d8fff41c Guido Trotter
1685 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1686 a8083063 Iustin Pop
    """Verify integrity of cluster, performing various test on nodes.
1687 a8083063 Iustin Pop

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

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

1918 e4376078 Iustin Pop
    @param phase: one of L{constants.HOOKS_PHASE_POST} or
1919 e4376078 Iustin Pop
        L{constants.HOOKS_PHASE_PRE}; it denotes the hooks phase
1920 e4376078 Iustin Pop
    @param hooks_results: the results of the multi-node hooks rpc call
1921 e4376078 Iustin Pop
    @param feedback_fn: function used send feedback back to the caller
1922 e4376078 Iustin Pop
    @param lu_result: previous Exec result
1923 e4376078 Iustin Pop
    @return: the new Exec result, based on the previous result
1924 e4376078 Iustin Pop
        and hook results
1925 d8fff41c Guido Trotter

1926 d8fff41c Guido Trotter
    """
1927 38206f3c Iustin Pop
    # We only really run POST phase hooks, and are only interested in
1928 38206f3c Iustin Pop
    # their results
1929 d8fff41c Guido Trotter
    if phase == constants.HOOKS_PHASE_POST:
1930 d8fff41c Guido Trotter
      # Used to change hooks' output to proper indentation
1931 d8fff41c Guido Trotter
      indent_re = re.compile('^', re.M)
1932 d8fff41c Guido Trotter
      feedback_fn("* Hooks Results")
1933 7c874ee1 Iustin Pop
      assert hooks_results, "invalid result from hooks"
1934 7c874ee1 Iustin Pop
1935 7c874ee1 Iustin Pop
      for node_name in hooks_results:
1936 7c874ee1 Iustin Pop
        res = hooks_results[node_name]
1937 7c874ee1 Iustin Pop
        msg = res.fail_msg
1938 a0c9776a Iustin Pop
        test = msg and not res.offline
1939 a0c9776a Iustin Pop
        self._ErrorIf(test, self.ENODEHOOKS, node_name,
1940 7c874ee1 Iustin Pop
                      "Communication failure in hooks execution: %s", msg)
1941 dd9e9f9c Michael Hanselmann
        if res.offline or msg:
1942 dd9e9f9c Michael Hanselmann
          # No need to investigate payload if node is offline or gave an error.
1943 a0c9776a Iustin Pop
          # override manually lu_result here as _ErrorIf only
1944 a0c9776a Iustin Pop
          # overrides self.bad
1945 7c874ee1 Iustin Pop
          lu_result = 1
1946 7c874ee1 Iustin Pop
          continue
1947 7c874ee1 Iustin Pop
        for script, hkr, output in res.payload:
1948 a0c9776a Iustin Pop
          test = hkr == constants.HKR_FAIL
1949 a0c9776a Iustin Pop
          self._ErrorIf(test, self.ENODEHOOKS, node_name,
1950 7c874ee1 Iustin Pop
                        "Script %s failed, output:", script)
1951 a0c9776a Iustin Pop
          if test:
1952 7c874ee1 Iustin Pop
            output = indent_re.sub('      ', output)
1953 7c874ee1 Iustin Pop
            feedback_fn("%s" % output)
1954 6d7b472a Iustin Pop
            lu_result = 0
1955 d8fff41c Guido Trotter
1956 d8fff41c Guido Trotter
      return lu_result
1957 d8fff41c Guido Trotter
1958 a8083063 Iustin Pop
1959 2c95a8d4 Iustin Pop
class LUVerifyDisks(NoHooksLU):
1960 2c95a8d4 Iustin Pop
  """Verifies the cluster disks status.
1961 2c95a8d4 Iustin Pop

1962 2c95a8d4 Iustin Pop
  """
1963 2c95a8d4 Iustin Pop
  _OP_REQP = []
1964 d4b9d97f Guido Trotter
  REQ_BGL = False
1965 d4b9d97f Guido Trotter
1966 d4b9d97f Guido Trotter
  def ExpandNames(self):
1967 d4b9d97f Guido Trotter
    self.needed_locks = {
1968 d4b9d97f Guido Trotter
      locking.LEVEL_NODE: locking.ALL_SET,
1969 d4b9d97f Guido Trotter
      locking.LEVEL_INSTANCE: locking.ALL_SET,
1970 d4b9d97f Guido Trotter
    }
1971 c772d142 Michael Hanselmann
    self.share_locks = dict.fromkeys(locking.LEVELS, 1)
1972 2c95a8d4 Iustin Pop
1973 2c95a8d4 Iustin Pop
  def CheckPrereq(self):
1974 2c95a8d4 Iustin Pop
    """Check prerequisites.
1975 2c95a8d4 Iustin Pop

1976 2c95a8d4 Iustin Pop
    This has no prerequisites.
1977 2c95a8d4 Iustin Pop

1978 2c95a8d4 Iustin Pop
    """
1979 2c95a8d4 Iustin Pop
    pass
1980 2c95a8d4 Iustin Pop
1981 2c95a8d4 Iustin Pop
  def Exec(self, feedback_fn):
1982 2c95a8d4 Iustin Pop
    """Verify integrity of cluster disks.
1983 2c95a8d4 Iustin Pop

1984 29d376ec Iustin Pop
    @rtype: tuple of three items
1985 29d376ec Iustin Pop
    @return: a tuple of (dict of node-to-node_error, list of instances
1986 29d376ec Iustin Pop
        which need activate-disks, dict of instance: (node, volume) for
1987 29d376ec Iustin Pop
        missing volumes
1988 29d376ec Iustin Pop

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

2045 60975797 Iustin Pop
  """
2046 60975797 Iustin Pop
  _OP_REQP = ["instances"]
2047 60975797 Iustin Pop
  REQ_BGL = False
2048 60975797 Iustin Pop
2049 60975797 Iustin Pop
  def ExpandNames(self):
2050 60975797 Iustin Pop
    if not isinstance(self.op.instances, list):
2051 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Invalid argument type 'instances'",
2052 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
2053 60975797 Iustin Pop
2054 60975797 Iustin Pop
    if self.op.instances:
2055 60975797 Iustin Pop
      self.wanted_names = []
2056 60975797 Iustin Pop
      for name in self.op.instances:
2057 cf26a87a Iustin Pop
        full_name = _ExpandInstanceName(self.cfg, name)
2058 60975797 Iustin Pop
        self.wanted_names.append(full_name)
2059 60975797 Iustin Pop
      self.needed_locks = {
2060 60975797 Iustin Pop
        locking.LEVEL_NODE: [],
2061 60975797 Iustin Pop
        locking.LEVEL_INSTANCE: self.wanted_names,
2062 60975797 Iustin Pop
        }
2063 60975797 Iustin Pop
      self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
2064 60975797 Iustin Pop
    else:
2065 60975797 Iustin Pop
      self.wanted_names = None
2066 60975797 Iustin Pop
      self.needed_locks = {
2067 60975797 Iustin Pop
        locking.LEVEL_NODE: locking.ALL_SET,
2068 60975797 Iustin Pop
        locking.LEVEL_INSTANCE: locking.ALL_SET,
2069 60975797 Iustin Pop
        }
2070 60975797 Iustin Pop
    self.share_locks = dict(((i, 1) for i in locking.LEVELS))
2071 60975797 Iustin Pop
2072 60975797 Iustin Pop
  def DeclareLocks(self, level):
2073 60975797 Iustin Pop
    if level == locking.LEVEL_NODE and self.wanted_names is not None:
2074 60975797 Iustin Pop
      self._LockInstancesNodes(primary_only=True)
2075 60975797 Iustin Pop
2076 60975797 Iustin Pop
  def CheckPrereq(self):
2077 60975797 Iustin Pop
    """Check prerequisites.
2078 60975797 Iustin Pop

2079 60975797 Iustin Pop
    This only checks the optional instance list against the existing names.
2080 60975797 Iustin Pop

2081 60975797 Iustin Pop
    """
2082 60975797 Iustin Pop
    if self.wanted_names is None:
2083 60975797 Iustin Pop
      self.wanted_names = self.acquired_locks[locking.LEVEL_INSTANCE]
2084 60975797 Iustin Pop
2085 60975797 Iustin Pop
    self.wanted_instances = [self.cfg.GetInstanceInfo(name) for name
2086 60975797 Iustin Pop
                             in self.wanted_names]
2087 60975797 Iustin Pop
2088 b775c337 Iustin Pop
  def _EnsureChildSizes(self, disk):
2089 b775c337 Iustin Pop
    """Ensure children of the disk have the needed disk size.
2090 b775c337 Iustin Pop

2091 b775c337 Iustin Pop
    This is valid mainly for DRBD8 and fixes an issue where the
2092 b775c337 Iustin Pop
    children have smaller disk size.
2093 b775c337 Iustin Pop

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

2096 b775c337 Iustin Pop
    """
2097 b775c337 Iustin Pop
    if disk.dev_type == constants.LD_DRBD8:
2098 b775c337 Iustin Pop
      assert disk.children, "Empty children for DRBD8?"
2099 b775c337 Iustin Pop
      fchild = disk.children[0]
2100 b775c337 Iustin Pop
      mismatch = fchild.size < disk.size
2101 b775c337 Iustin Pop
      if mismatch:
2102 b775c337 Iustin Pop
        self.LogInfo("Child disk has size %d, parent %d, fixing",
2103 b775c337 Iustin Pop
                     fchild.size, disk.size)
2104 b775c337 Iustin Pop
        fchild.size = disk.size
2105 b775c337 Iustin Pop
2106 b775c337 Iustin Pop
      # and we recurse on this child only, not on the metadev
2107 b775c337 Iustin Pop
      return self._EnsureChildSizes(fchild) or mismatch
2108 b775c337 Iustin Pop
    else:
2109 b775c337 Iustin Pop
      return False
2110 b775c337 Iustin Pop
2111 60975797 Iustin Pop
  def Exec(self, feedback_fn):
2112 60975797 Iustin Pop
    """Verify the size of cluster disks.
2113 60975797 Iustin Pop

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

2165 07bd8a51 Iustin Pop
  """
2166 07bd8a51 Iustin Pop
  HPATH = "cluster-rename"
2167 07bd8a51 Iustin Pop
  HTYPE = constants.HTYPE_CLUSTER
2168 07bd8a51 Iustin Pop
  _OP_REQP = ["name"]
2169 07bd8a51 Iustin Pop
2170 07bd8a51 Iustin Pop
  def BuildHooksEnv(self):
2171 07bd8a51 Iustin Pop
    """Build hooks env.
2172 07bd8a51 Iustin Pop

2173 07bd8a51 Iustin Pop
    """
2174 07bd8a51 Iustin Pop
    env = {
2175 d6a02168 Michael Hanselmann
      "OP_TARGET": self.cfg.GetClusterName(),
2176 07bd8a51 Iustin Pop
      "NEW_NAME": self.op.name,
2177 07bd8a51 Iustin Pop
      }
2178 d6a02168 Michael Hanselmann
    mn = self.cfg.GetMasterNode()
2179 47a72f18 Iustin Pop
    all_nodes = self.cfg.GetNodeList()
2180 47a72f18 Iustin Pop
    return env, [mn], all_nodes
2181 07bd8a51 Iustin Pop
2182 07bd8a51 Iustin Pop
  def CheckPrereq(self):
2183 07bd8a51 Iustin Pop
    """Verify that the passed name is a valid one.
2184 07bd8a51 Iustin Pop

2185 07bd8a51 Iustin Pop
    """
2186 104f4ca1 Iustin Pop
    hostname = utils.GetHostInfo(self.op.name)
2187 07bd8a51 Iustin Pop
2188 bcf043c9 Iustin Pop
    new_name = hostname.name
2189 bcf043c9 Iustin Pop
    self.ip = new_ip = hostname.ip
2190 d6a02168 Michael Hanselmann
    old_name = self.cfg.GetClusterName()
2191 d6a02168 Michael Hanselmann
    old_ip = self.cfg.GetMasterIP()
2192 07bd8a51 Iustin Pop
    if new_name == old_name and new_ip == old_ip:
2193 07bd8a51 Iustin Pop
      raise errors.OpPrereqError("Neither the name nor the IP address of the"
2194 5c983ee5 Iustin Pop
                                 " cluster has changed",
2195 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
2196 07bd8a51 Iustin Pop
    if new_ip != old_ip:
2197 937f983d Guido Trotter
      if utils.TcpPing(new_ip, constants.DEFAULT_NODED_PORT):
2198 07bd8a51 Iustin Pop
        raise errors.OpPrereqError("The given cluster IP address (%s) is"
2199 07bd8a51 Iustin Pop
                                   " reachable on the network. Aborting." %
2200 5c983ee5 Iustin Pop
                                   new_ip, errors.ECODE_NOTUNIQUE)
2201 07bd8a51 Iustin Pop
2202 07bd8a51 Iustin Pop
    self.op.name = new_name
2203 07bd8a51 Iustin Pop
2204 07bd8a51 Iustin Pop
  def Exec(self, feedback_fn):
2205 07bd8a51 Iustin Pop
    """Rename the cluster.
2206 07bd8a51 Iustin Pop

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

2249 e4376078 Iustin Pop
  @type disk: L{objects.Disk}
2250 e4376078 Iustin Pop
  @param disk: the disk to check
2251 5bbd3f7f Michael Hanselmann
  @rtype: boolean
2252 e4376078 Iustin Pop
  @return: boolean indicating whether a LD_LV dev_type was found or not
2253 8084f9f6 Manuel Franceschini

2254 8084f9f6 Manuel Franceschini
  """
2255 8084f9f6 Manuel Franceschini
  if disk.children:
2256 8084f9f6 Manuel Franceschini
    for chdisk in disk.children:
2257 8084f9f6 Manuel Franceschini
      if _RecursiveCheckIfLVMBased(chdisk):
2258 8084f9f6 Manuel Franceschini
        return True
2259 8084f9f6 Manuel Franceschini
  return disk.dev_type == constants.LD_LV
2260 8084f9f6 Manuel Franceschini
2261 8084f9f6 Manuel Franceschini
2262 8084f9f6 Manuel Franceschini
class LUSetClusterParams(LogicalUnit):
2263 8084f9f6 Manuel Franceschini
  """Change the parameters of the cluster.
2264 8084f9f6 Manuel Franceschini

2265 8084f9f6 Manuel Franceschini
  """
2266 8084f9f6 Manuel Franceschini
  HPATH = "cluster-modify"
2267 8084f9f6 Manuel Franceschini
  HTYPE = constants.HTYPE_CLUSTER
2268 8084f9f6 Manuel Franceschini
  _OP_REQP = []
2269 c53279cf Guido Trotter
  REQ_BGL = False
2270 c53279cf Guido Trotter
2271 3994f455 Iustin Pop
  def CheckArguments(self):
2272 4b7735f9 Iustin Pop
    """Check parameters
2273 4b7735f9 Iustin Pop

2274 4b7735f9 Iustin Pop
    """
2275 96d1a0c5 Iustin Pop
    for attr in ["candidate_pool_size",
2276 96d1a0c5 Iustin Pop
                 "uid_pool", "add_uids", "remove_uids"]:
2277 96d1a0c5 Iustin Pop
      if not hasattr(self.op, attr):
2278 96d1a0c5 Iustin Pop
        setattr(self.op, attr, None)
2279 96d1a0c5 Iustin Pop
2280 4b7735f9 Iustin Pop
    if self.op.candidate_pool_size is not None:
2281 4b7735f9 Iustin Pop
      try:
2282 4b7735f9 Iustin Pop
        self.op.candidate_pool_size = int(self.op.candidate_pool_size)
2283 3994f455 Iustin Pop
      except (ValueError, TypeError), err:
2284 4b7735f9 Iustin Pop
        raise errors.OpPrereqError("Invalid candidate_pool_size value: %s" %
2285 5c983ee5 Iustin Pop
                                   str(err), errors.ECODE_INVAL)
2286 4b7735f9 Iustin Pop
      if self.op.candidate_pool_size < 1:
2287 5c983ee5 Iustin Pop
        raise errors.OpPrereqError("At least one master candidate needed",
2288 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
2289 1338f2b4 Balazs Lecz
2290 3953242f Iustin Pop
    _CheckBooleanOpField(self.op, "maintain_node_health")
2291 4b7735f9 Iustin Pop
2292 1338f2b4 Balazs Lecz
    if self.op.uid_pool:
2293 1338f2b4 Balazs Lecz
      uidpool.CheckUidPool(self.op.uid_pool)
2294 1338f2b4 Balazs Lecz
2295 fdad8c4d Balazs Lecz
    if self.op.add_uids:
2296 fdad8c4d Balazs Lecz
      uidpool.CheckUidPool(self.op.add_uids)
2297 fdad8c4d Balazs Lecz
2298 fdad8c4d Balazs Lecz
    if self.op.remove_uids:
2299 fdad8c4d Balazs Lecz
      uidpool.CheckUidPool(self.op.remove_uids)
2300 fdad8c4d Balazs Lecz
2301 c53279cf Guido Trotter
  def ExpandNames(self):
2302 c53279cf Guido Trotter
    # FIXME: in the future maybe other cluster params won't require checking on
2303 c53279cf Guido Trotter
    # all nodes to be modified.
2304 c53279cf Guido Trotter
    self.needed_locks = {
2305 c53279cf Guido Trotter
      locking.LEVEL_NODE: locking.ALL_SET,
2306 c53279cf Guido Trotter
    }
2307 c53279cf Guido Trotter
    self.share_locks[locking.LEVEL_NODE] = 1
2308 8084f9f6 Manuel Franceschini
2309 8084f9f6 Manuel Franceschini
  def BuildHooksEnv(self):
2310 8084f9f6 Manuel Franceschini
    """Build hooks env.
2311 8084f9f6 Manuel Franceschini

2312 8084f9f6 Manuel Franceschini
    """
2313 8084f9f6 Manuel Franceschini
    env = {
2314 d6a02168 Michael Hanselmann
      "OP_TARGET": self.cfg.GetClusterName(),
2315 8084f9f6 Manuel Franceschini
      "NEW_VG_NAME": self.op.vg_name,
2316 8084f9f6 Manuel Franceschini
      }
2317 d6a02168 Michael Hanselmann
    mn = self.cfg.GetMasterNode()
2318 8084f9f6 Manuel Franceschini
    return env, [mn], [mn]
2319 8084f9f6 Manuel Franceschini
2320 8084f9f6 Manuel Franceschini
  def CheckPrereq(self):
2321 8084f9f6 Manuel Franceschini
    """Check prerequisites.
2322 8084f9f6 Manuel Franceschini

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

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

2477 8084f9f6 Manuel Franceschini
    """
2478 779c15bb Iustin Pop
    if self.op.vg_name is not None:
2479 b2482333 Guido Trotter
      new_volume = self.op.vg_name
2480 b2482333 Guido Trotter
      if not new_volume:
2481 b2482333 Guido Trotter
        new_volume = None
2482 b2482333 Guido Trotter
      if new_volume != self.cfg.GetVGName():
2483 b2482333 Guido Trotter
        self.cfg.SetVGName(new_volume)
2484 779c15bb Iustin Pop
      else:
2485 779c15bb Iustin Pop
        feedback_fn("Cluster LVM configuration already in desired"
2486 779c15bb Iustin Pop
                    " state, not changing")
2487 779c15bb Iustin Pop
    if self.op.hvparams:
2488 779c15bb Iustin Pop
      self.cluster.hvparams = self.new_hvparams
2489 17463d22 René Nussbaumer
    if self.op.os_hvp:
2490 17463d22 René Nussbaumer
      self.cluster.os_hvp = self.new_os_hvp
2491 779c15bb Iustin Pop
    if self.op.enabled_hypervisors is not None:
2492 9f3ac970 Iustin Pop
      self.cluster.hvparams = self.new_hvparams
2493 779c15bb Iustin Pop
      self.cluster.enabled_hypervisors = self.op.enabled_hypervisors
2494 779c15bb Iustin Pop
    if self.op.beparams:
2495 4ef7f423 Guido Trotter
      self.cluster.beparams[constants.PP_DEFAULT] = self.new_beparams
2496 5af3da74 Guido Trotter
    if self.op.nicparams:
2497 5af3da74 Guido Trotter
      self.cluster.nicparams[constants.PP_DEFAULT] = self.new_nicparams
2498 5af3da74 Guido Trotter
2499 4b7735f9 Iustin Pop
    if self.op.candidate_pool_size is not None:
2500 4b7735f9 Iustin Pop
      self.cluster.candidate_pool_size = self.op.candidate_pool_size
2501 75e914fb Iustin Pop
      # we need to update the pool size here, otherwise the save will fail
2502 44485f49 Guido Trotter
      _AdjustCandidatePool(self, [])
2503 4b7735f9 Iustin Pop
2504 3953242f Iustin Pop
    if self.op.maintain_node_health is not None:
2505 3953242f Iustin Pop
      self.cluster.maintain_node_health = self.op.maintain_node_health
2506 3953242f Iustin Pop
2507 fdad8c4d Balazs Lecz
    if self.op.add_uids is not None:
2508 fdad8c4d Balazs Lecz
      uidpool.AddToUidPool(self.cluster.uid_pool, self.op.add_uids)
2509 fdad8c4d Balazs Lecz
2510 fdad8c4d Balazs Lecz
    if self.op.remove_uids is not None:
2511 fdad8c4d Balazs Lecz
      uidpool.RemoveFromUidPool(self.cluster.uid_pool, self.op.remove_uids)
2512 fdad8c4d Balazs Lecz
2513 1338f2b4 Balazs Lecz
    if self.op.uid_pool is not None:
2514 1338f2b4 Balazs Lecz
      self.cluster.uid_pool = self.op.uid_pool
2515 1338f2b4 Balazs Lecz
2516 a4eae71f Michael Hanselmann
    self.cfg.Update(self.cluster, feedback_fn)
2517 8084f9f6 Manuel Franceschini
2518 8084f9f6 Manuel Franceschini
2519 28eddce5 Guido Trotter
def _RedistributeAncillaryFiles(lu, additional_nodes=None):
2520 28eddce5 Guido Trotter
  """Distribute additional files which are part of the cluster configuration.
2521 28eddce5 Guido Trotter

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

2526 28eddce5 Guido Trotter
  @param lu: calling logical unit
2527 28eddce5 Guido Trotter
  @param additional_nodes: list of nodes not in the config to distribute to
2528 28eddce5 Guido Trotter

2529 28eddce5 Guido Trotter
  """
2530 28eddce5 Guido Trotter
  # 1. Gather target nodes
2531 28eddce5 Guido Trotter
  myself = lu.cfg.GetNodeInfo(lu.cfg.GetMasterNode())
2532 6819dc49 Iustin Pop
  dist_nodes = lu.cfg.GetOnlineNodeList()
2533 28eddce5 Guido Trotter
  if additional_nodes is not None:
2534 28eddce5 Guido Trotter
    dist_nodes.extend(additional_nodes)
2535 28eddce5 Guido Trotter
  if myself.name in dist_nodes:
2536 28eddce5 Guido Trotter
    dist_nodes.remove(myself.name)
2537 a4eae71f Michael Hanselmann
2538 28eddce5 Guido Trotter
  # 2. Gather files to distribute
2539 28eddce5 Guido Trotter
  dist_files = set([constants.ETC_HOSTS,
2540 28eddce5 Guido Trotter
                    constants.SSH_KNOWN_HOSTS_FILE,
2541 28eddce5 Guido Trotter
                    constants.RAPI_CERT_FILE,
2542 28eddce5 Guido Trotter
                    constants.RAPI_USERS_FILE,
2543 6b7d5878 Michael Hanselmann
                    constants.CONFD_HMAC_KEY,
2544 28eddce5 Guido Trotter
                   ])
2545 e1b8653f Guido Trotter
2546 e1b8653f Guido Trotter
  enabled_hypervisors = lu.cfg.GetClusterInfo().enabled_hypervisors
2547 e1b8653f Guido Trotter
  for hv_name in enabled_hypervisors:
2548 e1b8653f Guido Trotter
    hv_class = hypervisor.GetHypervisor(hv_name)
2549 e1b8653f Guido Trotter
    dist_files.update(hv_class.GetAncillaryFiles())
2550 e1b8653f Guido Trotter
2551 28eddce5 Guido Trotter
  # 3. Perform the files upload
2552 28eddce5 Guido Trotter
  for fname in dist_files:
2553 28eddce5 Guido Trotter
    if os.path.exists(fname):
2554 28eddce5 Guido Trotter
      result = lu.rpc.call_upload_file(dist_nodes, fname)
2555 28eddce5 Guido Trotter
      for to_node, to_result in result.items():
2556 6f7d4e75 Iustin Pop
        msg = to_result.fail_msg
2557 6f7d4e75 Iustin Pop
        if msg:
2558 6f7d4e75 Iustin Pop
          msg = ("Copy of file %s to node %s failed: %s" %
2559 6f7d4e75 Iustin Pop
                 (fname, to_node, msg))
2560 6f7d4e75 Iustin Pop
          lu.proc.LogWarning(msg)
2561 28eddce5 Guido Trotter
2562 28eddce5 Guido Trotter
2563 afee0879 Iustin Pop
class LURedistributeConfig(NoHooksLU):
2564 afee0879 Iustin Pop
  """Force the redistribution of cluster configuration.
2565 afee0879 Iustin Pop

2566 afee0879 Iustin Pop
  This is a very simple LU.
2567 afee0879 Iustin Pop

2568 afee0879 Iustin Pop
  """
2569 afee0879 Iustin Pop
  _OP_REQP = []
2570 afee0879 Iustin Pop
  REQ_BGL = False
2571 afee0879 Iustin Pop
2572 afee0879 Iustin Pop
  def ExpandNames(self):
2573 afee0879 Iustin Pop
    self.needed_locks = {
2574 afee0879 Iustin Pop
      locking.LEVEL_NODE: locking.ALL_SET,
2575 afee0879 Iustin Pop
    }
2576 afee0879 Iustin Pop
    self.share_locks[locking.LEVEL_NODE] = 1
2577 afee0879 Iustin Pop
2578 afee0879 Iustin Pop
  def CheckPrereq(self):
2579 afee0879 Iustin Pop
    """Check prerequisites.
2580 afee0879 Iustin Pop

2581 afee0879 Iustin Pop
    """
2582 afee0879 Iustin Pop
2583 afee0879 Iustin Pop
  def Exec(self, feedback_fn):
2584 afee0879 Iustin Pop
    """Redistribute the configuration.
2585 afee0879 Iustin Pop

2586 afee0879 Iustin Pop
    """
2587 a4eae71f Michael Hanselmann
    self.cfg.Update(self.cfg.GetClusterInfo(), feedback_fn)
2588 28eddce5 Guido Trotter
    _RedistributeAncillaryFiles(self)
2589 afee0879 Iustin Pop
2590 afee0879 Iustin Pop
2591 ef628379 Guido Trotter
def _WaitForSync(lu, instance, disks=None, oneshot=False):
2592 a8083063 Iustin Pop
  """Sleep and poll for an instance's disk to sync.
2593 a8083063 Iustin Pop

2594 a8083063 Iustin Pop
  """
2595 ef628379 Guido Trotter
  if not instance.disks or disks is not None and not disks:
2596 a8083063 Iustin Pop
    return True
2597 a8083063 Iustin Pop
2598 ef628379 Guido Trotter
  disks = _ExpandCheckDisks(instance, disks)
2599 ef628379 Guido Trotter
2600 a8083063 Iustin Pop
  if not oneshot:
2601 b9bddb6b Iustin Pop
    lu.proc.LogInfo("Waiting for instance %s to sync disks." % instance.name)
2602 a8083063 Iustin Pop
2603 a8083063 Iustin Pop
  node = instance.primary_node
2604 a8083063 Iustin Pop
2605 ef628379 Guido Trotter
  for dev in disks:
2606 b9bddb6b Iustin Pop
    lu.cfg.SetDiskID(dev, node)
2607 a8083063 Iustin Pop
2608 6bcb1446 Michael Hanselmann
  # TODO: Convert to utils.Retry
2609 6bcb1446 Michael Hanselmann
2610 a8083063 Iustin Pop
  retries = 0
2611 fbafd7a8 Iustin Pop
  degr_retries = 10 # in seconds, as we sleep 1 second each time
2612 a8083063 Iustin Pop
  while True:
2613 a8083063 Iustin Pop
    max_time = 0
2614 a8083063 Iustin Pop
    done = True
2615 a8083063 Iustin Pop
    cumul_degraded = False
2616 ef628379 Guido Trotter
    rstats = lu.rpc.call_blockdev_getmirrorstatus(node, disks)
2617 4c4e4e1e Iustin Pop
    msg = rstats.fail_msg
2618 3efa9051 Iustin Pop
    if msg:
2619 3efa9051 Iustin Pop
      lu.LogWarning("Can't get any data from node %s: %s", node, msg)
2620 a8083063 Iustin Pop
      retries += 1
2621 a8083063 Iustin Pop
      if retries >= 10:
2622 3ecf6786 Iustin Pop
        raise errors.RemoteError("Can't contact node %s for mirror data,"
2623 3ecf6786 Iustin Pop
                                 " aborting." % node)
2624 a8083063 Iustin Pop
      time.sleep(6)
2625 a8083063 Iustin Pop
      continue
2626 3efa9051 Iustin Pop
    rstats = rstats.payload
2627 a8083063 Iustin Pop
    retries = 0
2628 1492cca7 Iustin Pop
    for i, mstat in enumerate(rstats):
2629 a8083063 Iustin Pop
      if mstat is None:
2630 86d9d3bb Iustin Pop
        lu.LogWarning("Can't compute data for node %s/%s",
2631 ef628379 Guido Trotter
                           node, disks[i].iv_name)
2632 a8083063 Iustin Pop
        continue
2633 36145b12 Michael Hanselmann
2634 36145b12 Michael Hanselmann
      cumul_degraded = (cumul_degraded or
2635 36145b12 Michael Hanselmann
                        (mstat.is_degraded and mstat.sync_percent is None))
2636 36145b12 Michael Hanselmann
      if mstat.sync_percent is not None:
2637 a8083063 Iustin Pop
        done = False
2638 36145b12 Michael Hanselmann
        if mstat.estimated_time is not None:
2639 36145b12 Michael Hanselmann
          rem_time = "%d estimated seconds remaining" % mstat.estimated_time
2640 36145b12 Michael Hanselmann
          max_time = mstat.estimated_time
2641 a8083063 Iustin Pop
        else:
2642 a8083063 Iustin Pop
          rem_time = "no time estimate"
2643 b9bddb6b Iustin Pop
        lu.proc.LogInfo("- device %s: %5.2f%% done, %s" %
2644 ef628379 Guido Trotter
                        (disks[i].iv_name, mstat.sync_percent, rem_time))
2645 fbafd7a8 Iustin Pop
2646 fbafd7a8 Iustin Pop
    # if we're done but degraded, let's do a few small retries, to
2647 fbafd7a8 Iustin Pop
    # make sure we see a stable and not transient situation; therefore
2648 fbafd7a8 Iustin Pop
    # we force restart of the loop
2649 fbafd7a8 Iustin Pop
    if (done or oneshot) and cumul_degraded and degr_retries > 0:
2650 fbafd7a8 Iustin Pop
      logging.info("Degraded disks found, %d retries left", degr_retries)
2651 fbafd7a8 Iustin Pop
      degr_retries -= 1
2652 fbafd7a8 Iustin Pop
      time.sleep(1)
2653 fbafd7a8 Iustin Pop
      continue
2654 fbafd7a8 Iustin Pop
2655 a8083063 Iustin Pop
    if done or oneshot:
2656 a8083063 Iustin Pop
      break
2657 a8083063 Iustin Pop
2658 d4fa5c23 Iustin Pop
    time.sleep(min(60, max_time))
2659 a8083063 Iustin Pop
2660 a8083063 Iustin Pop
  if done:
2661 b9bddb6b Iustin Pop
    lu.proc.LogInfo("Instance %s's disks are in sync." % instance.name)
2662 a8083063 Iustin Pop
  return not cumul_degraded
2663 a8083063 Iustin Pop
2664 a8083063 Iustin Pop
2665 b9bddb6b Iustin Pop
def _CheckDiskConsistency(lu, dev, node, on_primary, ldisk=False):
2666 a8083063 Iustin Pop
  """Check that mirrors are not degraded.
2667 a8083063 Iustin Pop

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

2672 a8083063 Iustin Pop
  """
2673 b9bddb6b Iustin Pop
  lu.cfg.SetDiskID(dev, node)
2674 a8083063 Iustin Pop
2675 a8083063 Iustin Pop
  result = True
2676 96acbc09 Michael Hanselmann
2677 a8083063 Iustin Pop
  if on_primary or dev.AssembleOnSecondary():
2678 72737a7f Iustin Pop
    rstats = lu.rpc.call_blockdev_find(node, dev)
2679 4c4e4e1e Iustin Pop
    msg = rstats.fail_msg
2680 23829f6f Iustin Pop
    if msg:
2681 23829f6f Iustin Pop
      lu.LogWarning("Can't find disk on node %s: %s", node, msg)
2682 23829f6f Iustin Pop
      result = False
2683 23829f6f Iustin Pop
    elif not rstats.payload:
2684 23829f6f Iustin Pop
      lu.LogWarning("Can't find disk on node %s", node)
2685 a8083063 Iustin Pop
      result = False
2686 a8083063 Iustin Pop
    else:
2687 96acbc09 Michael Hanselmann
      if ldisk:
2688 f208978a Michael Hanselmann
        result = result and rstats.payload.ldisk_status == constants.LDS_OKAY
2689 96acbc09 Michael Hanselmann
      else:
2690 96acbc09 Michael Hanselmann
        result = result and not rstats.payload.is_degraded
2691 96acbc09 Michael Hanselmann
2692 a8083063 Iustin Pop
  if dev.children:
2693 a8083063 Iustin Pop
    for child in dev.children:
2694 b9bddb6b Iustin Pop
      result = result and _CheckDiskConsistency(lu, child, node, on_primary)
2695 a8083063 Iustin Pop
2696 a8083063 Iustin Pop
  return result
2697 a8083063 Iustin Pop
2698 a8083063 Iustin Pop
2699 a8083063 Iustin Pop
class LUDiagnoseOS(NoHooksLU):
2700 a8083063 Iustin Pop
  """Logical unit for OS diagnose/query.
2701 a8083063 Iustin Pop

2702 a8083063 Iustin Pop
  """
2703 1f9430d6 Iustin Pop
  _OP_REQP = ["output_fields", "names"]
2704 6bf01bbb Guido Trotter
  REQ_BGL = False
2705 a2d2e1a7 Iustin Pop
  _FIELDS_STATIC = utils.FieldSet()
2706 1e288a26 Guido Trotter
  _FIELDS_DYNAMIC = utils.FieldSet("name", "valid", "node_status", "variants")
2707 1e288a26 Guido Trotter
  # Fields that need calculation of global os validity
2708 1e288a26 Guido Trotter
  _FIELDS_NEEDVALID = frozenset(["valid", "variants"])
2709 a8083063 Iustin Pop
2710 6bf01bbb Guido Trotter
  def ExpandNames(self):
2711 1f9430d6 Iustin Pop
    if self.op.names:
2712 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Selective OS query not supported",
2713 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
2714 1f9430d6 Iustin Pop
2715 31bf511f Iustin Pop
    _CheckOutputFields(static=self._FIELDS_STATIC,
2716 31bf511f Iustin Pop
                       dynamic=self._FIELDS_DYNAMIC,
2717 1f9430d6 Iustin Pop
                       selected=self.op.output_fields)
2718 1f9430d6 Iustin Pop
2719 6bf01bbb Guido Trotter
    # Lock all nodes, in shared mode
2720 a6ab004b Iustin Pop
    # Temporary removal of locks, should be reverted later
2721 a6ab004b Iustin Pop
    # TODO: reintroduce locks when they are lighter-weight
2722 6bf01bbb Guido Trotter
    self.needed_locks = {}
2723 a6ab004b Iustin Pop
    #self.share_locks[locking.LEVEL_NODE] = 1
2724 a6ab004b Iustin Pop
    #self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
2725 6bf01bbb Guido Trotter
2726 6bf01bbb Guido Trotter
  def CheckPrereq(self):
2727 6bf01bbb Guido Trotter
    """Check prerequisites.
2728 6bf01bbb Guido Trotter

2729 6bf01bbb Guido Trotter
    """
2730 6bf01bbb Guido Trotter
2731 1f9430d6 Iustin Pop
  @staticmethod
2732 857121ad Iustin Pop
  def _DiagnoseByOS(rlist):
2733 1f9430d6 Iustin Pop
    """Remaps a per-node return list into an a per-os per-node dictionary
2734 1f9430d6 Iustin Pop

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

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

2741 255dcebd Iustin Pop
          {"debian-etch": {"node1": [(/usr/lib/..., True, ""),
2742 255dcebd Iustin Pop
                                     (/srv/..., False, "invalid api")],
2743 255dcebd Iustin Pop
                           "node2": [(/srv/..., True, "")]}
2744 e4376078 Iustin Pop
          }
2745 1f9430d6 Iustin Pop

2746 1f9430d6 Iustin Pop
    """
2747 1f9430d6 Iustin Pop
    all_os = {}
2748 a6ab004b Iustin Pop
    # we build here the list of nodes that didn't fail the RPC (at RPC
2749 a6ab004b Iustin Pop
    # level), so that nodes with a non-responding node daemon don't
2750 a6ab004b Iustin Pop
    # make all OSes invalid
2751 a6ab004b Iustin Pop
    good_nodes = [node_name for node_name in rlist
2752 4c4e4e1e Iustin Pop
                  if not rlist[node_name].fail_msg]
2753 83d92ad8 Iustin Pop
    for node_name, nr in rlist.items():
2754 4c4e4e1e Iustin Pop
      if nr.fail_msg or not nr.payload:
2755 1f9430d6 Iustin Pop
        continue
2756 ba00557a Guido Trotter
      for name, path, status, diagnose, variants in nr.payload:
2757 255dcebd Iustin Pop
        if name not in all_os:
2758 1f9430d6 Iustin Pop
          # build a list of nodes for this os containing empty lists
2759 1f9430d6 Iustin Pop
          # for each node in node_list
2760 255dcebd Iustin Pop
          all_os[name] = {}
2761 a6ab004b Iustin Pop
          for nname in good_nodes:
2762 255dcebd Iustin Pop
            all_os[name][nname] = []
2763 ba00557a Guido Trotter
        all_os[name][node_name].append((path, status, diagnose, variants))
2764 1f9430d6 Iustin Pop
    return all_os
2765 a8083063 Iustin Pop
2766 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
2767 a8083063 Iustin Pop
    """Compute the list of OSes.
2768 a8083063 Iustin Pop

2769 a8083063 Iustin Pop
    """
2770 a6ab004b Iustin Pop
    valid_nodes = [node for node in self.cfg.GetOnlineNodeList()]
2771 94a02bb5 Iustin Pop
    node_data = self.rpc.call_os_diagnose(valid_nodes)
2772 857121ad Iustin Pop
    pol = self._DiagnoseByOS(node_data)
2773 1f9430d6 Iustin Pop
    output = []
2774 1e288a26 Guido Trotter
    calc_valid = self._FIELDS_NEEDVALID.intersection(self.op.output_fields)
2775 1e288a26 Guido Trotter
    calc_variants = "variants" in self.op.output_fields
2776 1e288a26 Guido Trotter
2777 83d92ad8 Iustin Pop
    for os_name, os_data in pol.items():
2778 1f9430d6 Iustin Pop
      row = []
2779 1e288a26 Guido Trotter
      if calc_valid:
2780 1e288a26 Guido Trotter
        valid = True
2781 1e288a26 Guido Trotter
        variants = None
2782 1e288a26 Guido Trotter
        for osl in os_data.values():
2783 1e288a26 Guido Trotter
          valid = valid and osl and osl[0][1]
2784 1e288a26 Guido Trotter
          if not valid:
2785 1e288a26 Guido Trotter
            variants = None
2786 1e288a26 Guido Trotter
            break
2787 1e288a26 Guido Trotter
          if calc_variants:
2788 1e288a26 Guido Trotter
            node_variants = osl[0][3]
2789 1e288a26 Guido Trotter
            if variants is None:
2790 1e288a26 Guido Trotter
              variants = node_variants
2791 1e288a26 Guido Trotter
            else:
2792 1e288a26 Guido Trotter
              variants = [v for v in variants if v in node_variants]
2793 1e288a26 Guido Trotter
2794 1f9430d6 Iustin Pop
      for field in self.op.output_fields:
2795 1f9430d6 Iustin Pop
        if field == "name":
2796 1f9430d6 Iustin Pop
          val = os_name
2797 1f9430d6 Iustin Pop
        elif field == "valid":
2798 1e288a26 Guido Trotter
          val = valid
2799 1f9430d6 Iustin Pop
        elif field == "node_status":
2800 255dcebd Iustin Pop
          # this is just a copy of the dict
2801 1f9430d6 Iustin Pop
          val = {}
2802 255dcebd Iustin Pop
          for node_name, nos_list in os_data.items():
2803 255dcebd Iustin Pop
            val[node_name] = nos_list
2804 1e288a26 Guido Trotter
        elif field == "variants":
2805 1e288a26 Guido Trotter
          val =  variants
2806 1f9430d6 Iustin Pop
        else:
2807 1f9430d6 Iustin Pop
          raise errors.ParameterError(field)
2808 1f9430d6 Iustin Pop
        row.append(val)
2809 1f9430d6 Iustin Pop
      output.append(row)
2810 1f9430d6 Iustin Pop
2811 1f9430d6 Iustin Pop
    return output
2812 a8083063 Iustin Pop
2813 a8083063 Iustin Pop
2814 a8083063 Iustin Pop
class LURemoveNode(LogicalUnit):
2815 a8083063 Iustin Pop
  """Logical unit for removing a node.
2816 a8083063 Iustin Pop

2817 a8083063 Iustin Pop
  """
2818 a8083063 Iustin Pop
  HPATH = "node-remove"
2819 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_NODE
2820 a8083063 Iustin Pop
  _OP_REQP = ["node_name"]
2821 a8083063 Iustin Pop
2822 a8083063 Iustin Pop
  def BuildHooksEnv(self):
2823 a8083063 Iustin Pop
    """Build hooks env.
2824 a8083063 Iustin Pop

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

2828 a8083063 Iustin Pop
    """
2829 396e1b78 Michael Hanselmann
    env = {
2830 0e137c28 Iustin Pop
      "OP_TARGET": self.op.node_name,
2831 396e1b78 Michael Hanselmann
      "NODE_NAME": self.op.node_name,
2832 396e1b78 Michael Hanselmann
      }
2833 a8083063 Iustin Pop
    all_nodes = self.cfg.GetNodeList()
2834 9bb31ea8 Iustin Pop
    try:
2835 cd46f3b4 Luca Bigliardi
      all_nodes.remove(self.op.node_name)
2836 9bb31ea8 Iustin Pop
    except ValueError:
2837 9bb31ea8 Iustin Pop
      logging.warning("Node %s which is about to be removed not found"
2838 9bb31ea8 Iustin Pop
                      " in the all nodes list", self.op.node_name)
2839 396e1b78 Michael Hanselmann
    return env, all_nodes, all_nodes
2840 a8083063 Iustin Pop
2841 a8083063 Iustin Pop
  def CheckPrereq(self):
2842 a8083063 Iustin Pop
    """Check prerequisites.
2843 a8083063 Iustin Pop

2844 a8083063 Iustin Pop
    This checks:
2845 a8083063 Iustin Pop
     - the node exists in the configuration
2846 a8083063 Iustin Pop
     - it does not have primary or secondary instances
2847 a8083063 Iustin Pop
     - it's not the master
2848 a8083063 Iustin Pop

2849 5bbd3f7f Michael Hanselmann
    Any errors are signaled by raising errors.OpPrereqError.
2850 a8083063 Iustin Pop

2851 a8083063 Iustin Pop
    """
2852 cf26a87a Iustin Pop
    self.op.node_name = _ExpandNodeName(self.cfg, self.op.node_name)
2853 cf26a87a Iustin Pop
    node = self.cfg.GetNodeInfo(self.op.node_name)
2854 cf26a87a Iustin Pop
    assert node is not None
2855 a8083063 Iustin Pop
2856 a8083063 Iustin Pop
    instance_list = self.cfg.GetInstanceList()
2857 a8083063 Iustin Pop
2858 d6a02168 Michael Hanselmann
    masternode = self.cfg.GetMasterNode()
2859 a8083063 Iustin Pop
    if node.name == masternode:
2860 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Node is the master node,"
2861 5c983ee5 Iustin Pop
                                 " you need to failover first.",
2862 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
2863 a8083063 Iustin Pop
2864 a8083063 Iustin Pop
    for instance_name in instance_list:
2865 a8083063 Iustin Pop
      instance = self.cfg.GetInstanceInfo(instance_name)
2866 6b12959c Iustin Pop
      if node.name in instance.all_nodes:
2867 6b12959c Iustin Pop
        raise errors.OpPrereqError("Instance %s is still running on the node,"
2868 5c983ee5 Iustin Pop
                                   " please remove first." % instance_name,
2869 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
2870 a8083063 Iustin Pop
    self.op.node_name = node.name
2871 a8083063 Iustin Pop
    self.node = node
2872 a8083063 Iustin Pop
2873 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
2874 a8083063 Iustin Pop
    """Removes the node from the cluster.
2875 a8083063 Iustin Pop

2876 a8083063 Iustin Pop
    """
2877 a8083063 Iustin Pop
    node = self.node
2878 9a4f63d1 Iustin Pop
    logging.info("Stopping the node daemon and removing configs from node %s",
2879 9a4f63d1 Iustin Pop
                 node.name)
2880 a8083063 Iustin Pop
2881 b989b9d9 Ken Wehr
    modify_ssh_setup = self.cfg.GetClusterInfo().modify_ssh_setup
2882 b989b9d9 Ken Wehr
2883 44485f49 Guido Trotter
    # Promote nodes to master candidate as needed
2884 44485f49 Guido Trotter
    _AdjustCandidatePool(self, exceptions=[node.name])
2885 d8470559 Michael Hanselmann
    self.context.RemoveNode(node.name)
2886 a8083063 Iustin Pop
2887 cd46f3b4 Luca Bigliardi
    # Run post hooks on the node before it's removed
2888 cd46f3b4 Luca Bigliardi
    hm = self.proc.hmclass(self.rpc.call_hooks_runner, self)
2889 cd46f3b4 Luca Bigliardi
    try:
2890 1122eb25 Iustin Pop
      hm.RunPhase(constants.HOOKS_PHASE_POST, [node.name])
2891 3cb5c1e3 Luca Bigliardi
    except:
2892 7260cfbe Iustin Pop
      # pylint: disable-msg=W0702
2893 3cb5c1e3 Luca Bigliardi
      self.LogWarning("Errors occurred running hooks on %s" % node.name)
2894 cd46f3b4 Luca Bigliardi
2895 b989b9d9 Ken Wehr
    result = self.rpc.call_node_leave_cluster(node.name, modify_ssh_setup)
2896 4c4e4e1e Iustin Pop
    msg = result.fail_msg
2897 0623d351 Iustin Pop
    if msg:
2898 0623d351 Iustin Pop
      self.LogWarning("Errors encountered on the remote node while leaving"
2899 0623d351 Iustin Pop
                      " the cluster: %s", msg)
2900 c8a0948f Michael Hanselmann
2901 7672a621 Iustin Pop
    # Remove node from our /etc/hosts
2902 7672a621 Iustin Pop
    if self.cfg.GetClusterInfo().modify_etc_hosts:
2903 7672a621 Iustin Pop
      # FIXME: this should be done via an rpc call to node daemon
2904 7672a621 Iustin Pop
      utils.RemoveHostFromEtcHosts(node.name)
2905 7672a621 Iustin Pop
      _RedistributeAncillaryFiles(self)
2906 7672a621 Iustin Pop
2907 a8083063 Iustin Pop
2908 a8083063 Iustin Pop
class LUQueryNodes(NoHooksLU):
2909 a8083063 Iustin Pop
  """Logical unit for querying nodes.
2910 a8083063 Iustin Pop

2911 a8083063 Iustin Pop
  """
2912 7260cfbe Iustin Pop
  # pylint: disable-msg=W0142
2913 bc8e4a1a Iustin Pop
  _OP_REQP = ["output_fields", "names", "use_locking"]
2914 35705d8f Guido Trotter
  REQ_BGL = False
2915 19bed813 Iustin Pop
2916 19bed813 Iustin Pop
  _SIMPLE_FIELDS = ["name", "serial_no", "ctime", "mtime", "uuid",
2917 19bed813 Iustin Pop
                    "master_candidate", "offline", "drained"]
2918 19bed813 Iustin Pop
2919 a2d2e1a7 Iustin Pop
  _FIELDS_DYNAMIC = utils.FieldSet(
2920 31bf511f Iustin Pop
    "dtotal", "dfree",
2921 31bf511f Iustin Pop
    "mtotal", "mnode", "mfree",
2922 31bf511f Iustin Pop
    "bootid",
2923 0105bad3 Iustin Pop
    "ctotal", "cnodes", "csockets",
2924 31bf511f Iustin Pop
    )
2925 31bf511f Iustin Pop
2926 19bed813 Iustin Pop
  _FIELDS_STATIC = utils.FieldSet(*[
2927 19bed813 Iustin Pop
    "pinst_cnt", "sinst_cnt",
2928 31bf511f Iustin Pop
    "pinst_list", "sinst_list",
2929 31bf511f Iustin Pop
    "pip", "sip", "tags",
2930 0e67cdbe Iustin Pop
    "master",
2931 19bed813 Iustin Pop
    "role"] + _SIMPLE_FIELDS
2932 31bf511f Iustin Pop
    )
2933 a8083063 Iustin Pop
2934 35705d8f Guido Trotter
  def ExpandNames(self):
2935 31bf511f Iustin Pop
    _CheckOutputFields(static=self._FIELDS_STATIC,
2936 31bf511f Iustin Pop
                       dynamic=self._FIELDS_DYNAMIC,
2937 dcb93971 Michael Hanselmann
                       selected=self.op.output_fields)
2938 a8083063 Iustin Pop
2939 35705d8f Guido Trotter
    self.needed_locks = {}
2940 35705d8f Guido Trotter
    self.share_locks[locking.LEVEL_NODE] = 1
2941 c8d8b4c8 Iustin Pop
2942 c8d8b4c8 Iustin Pop
    if self.op.names:
2943 c8d8b4c8 Iustin Pop
      self.wanted = _GetWantedNodes(self, self.op.names)
2944 35705d8f Guido Trotter
    else:
2945 c8d8b4c8 Iustin Pop
      self.wanted = locking.ALL_SET
2946 c8d8b4c8 Iustin Pop
2947 bc8e4a1a Iustin Pop
    self.do_node_query = self._FIELDS_STATIC.NonMatching(self.op.output_fields)
2948 bc8e4a1a Iustin Pop
    self.do_locking = self.do_node_query and self.op.use_locking
2949 c8d8b4c8 Iustin Pop
    if self.do_locking:
2950 c8d8b4c8 Iustin Pop
      # if we don't request only static fields, we need to lock the nodes
2951 c8d8b4c8 Iustin Pop
      self.needed_locks[locking.LEVEL_NODE] = self.wanted
2952 c8d8b4c8 Iustin Pop
2953 35705d8f Guido Trotter
  def CheckPrereq(self):
2954 35705d8f Guido Trotter
    """Check prerequisites.
2955 35705d8f Guido Trotter

2956 35705d8f Guido Trotter
    """
2957 c8d8b4c8 Iustin Pop
    # The validation of the node list is done in the _GetWantedNodes,
2958 c8d8b4c8 Iustin Pop
    # if non empty, and if empty, there's no validation to do
2959 c8d8b4c8 Iustin Pop
    pass
2960 a8083063 Iustin Pop
2961 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
2962 a8083063 Iustin Pop
    """Computes the list of nodes and their attributes.
2963 a8083063 Iustin Pop

2964 a8083063 Iustin Pop
    """
2965 c8d8b4c8 Iustin Pop
    all_info = self.cfg.GetAllNodesInfo()
2966 c8d8b4c8 Iustin Pop
    if self.do_locking:
2967 c8d8b4c8 Iustin Pop
      nodenames = self.acquired_locks[locking.LEVEL_NODE]
2968 3fa93523 Guido Trotter
    elif self.wanted != locking.ALL_SET:
2969 3fa93523 Guido Trotter
      nodenames = self.wanted
2970 3fa93523 Guido Trotter
      missing = set(nodenames).difference(all_info.keys())
2971 3fa93523 Guido Trotter
      if missing:
2972 7b3a8fb5 Iustin Pop
        raise errors.OpExecError(
2973 3fa93523 Guido Trotter
          "Some nodes were removed before retrieving their data: %s" % missing)
2974 c8d8b4c8 Iustin Pop
    else:
2975 c8d8b4c8 Iustin Pop
      nodenames = all_info.keys()
2976 c1f1cbb2 Iustin Pop
2977 c1f1cbb2 Iustin Pop
    nodenames = utils.NiceSort(nodenames)
2978 c8d8b4c8 Iustin Pop
    nodelist = [all_info[name] for name in nodenames]
2979 a8083063 Iustin Pop
2980 a8083063 Iustin Pop
    # begin data gathering
2981 a8083063 Iustin Pop
2982 bc8e4a1a Iustin Pop
    if self.do_node_query:
2983 a8083063 Iustin Pop
      live_data = {}
2984 72737a7f Iustin Pop
      node_data = self.rpc.call_node_info(nodenames, self.cfg.GetVGName(),
2985 72737a7f Iustin Pop
                                          self.cfg.GetHypervisorType())
2986 a8083063 Iustin Pop
      for name in nodenames:
2987 781de953 Iustin Pop
        nodeinfo = node_data[name]
2988 4c4e4e1e Iustin Pop
        if not nodeinfo.fail_msg and nodeinfo.payload:
2989 070e998b Iustin Pop
          nodeinfo = nodeinfo.payload
2990 d599d686 Iustin Pop
          fn = utils.TryConvert
2991 a8083063 Iustin Pop
          live_data[name] = {
2992 d599d686 Iustin Pop
            "mtotal": fn(int, nodeinfo.get('memory_total', None)),
2993 d599d686 Iustin Pop
            "mnode": fn(int, nodeinfo.get('memory_dom0', None)),
2994 d599d686 Iustin Pop
            "mfree": fn(int, nodeinfo.get('memory_free', None)),
2995 d599d686 Iustin Pop
            "dtotal": fn(int, nodeinfo.get('vg_size', None)),
2996 d599d686 Iustin Pop
            "dfree": fn(int, nodeinfo.get('vg_free', None)),
2997 d599d686 Iustin Pop
            "ctotal": fn(int, nodeinfo.get('cpu_total', None)),
2998 d599d686 Iustin Pop
            "bootid": nodeinfo.get('bootid', None),
2999 0105bad3 Iustin Pop
            "cnodes": fn(int, nodeinfo.get('cpu_nodes', None)),
3000 0105bad3 Iustin Pop
            "csockets": fn(int, nodeinfo.get('cpu_sockets', None)),
3001 a8083063 Iustin Pop
            }
3002 a8083063 Iustin Pop
        else:
3003 a8083063 Iustin Pop
          live_data[name] = {}
3004 a8083063 Iustin Pop
    else:
3005 a8083063 Iustin Pop
      live_data = dict.fromkeys(nodenames, {})
3006 a8083063 Iustin Pop
3007 ec223efb Iustin Pop
    node_to_primary = dict([(name, set()) for name in nodenames])
3008 ec223efb Iustin Pop
    node_to_secondary = dict([(name, set()) for name in nodenames])
3009 a8083063 Iustin Pop
3010 ec223efb Iustin Pop
    inst_fields = frozenset(("pinst_cnt", "pinst_list",
3011 ec223efb Iustin Pop
                             "sinst_cnt", "sinst_list"))
3012 ec223efb Iustin Pop
    if inst_fields & frozenset(self.op.output_fields):
3013 4dfd6266 Iustin Pop
      inst_data = self.cfg.GetAllInstancesInfo()
3014 a8083063 Iustin Pop
3015 1122eb25 Iustin Pop
      for inst in inst_data.values():
3016 ec223efb Iustin Pop
        if inst.primary_node in node_to_primary:
3017 ec223efb Iustin Pop
          node_to_primary[inst.primary_node].add(inst.name)
3018 ec223efb Iustin Pop
        for secnode in inst.secondary_nodes:
3019 ec223efb Iustin Pop
          if secnode in node_to_secondary:
3020 ec223efb Iustin Pop
            node_to_secondary[secnode].add(inst.name)
3021 a8083063 Iustin Pop
3022 0e67cdbe Iustin Pop
    master_node = self.cfg.GetMasterNode()
3023 0e67cdbe Iustin Pop
3024 a8083063 Iustin Pop
    # end data gathering
3025 a8083063 Iustin Pop
3026 a8083063 Iustin Pop
    output = []
3027 a8083063 Iustin Pop
    for node in nodelist:
3028 a8083063 Iustin Pop
      node_output = []
3029 a8083063 Iustin Pop
      for field in self.op.output_fields:
3030 19bed813 Iustin Pop
        if field in self._SIMPLE_FIELDS:
3031 19bed813 Iustin Pop
          val = getattr(node, field)
3032 ec223efb Iustin Pop
        elif field == "pinst_list":
3033 ec223efb Iustin Pop
          val = list(node_to_primary[node.name])
3034 ec223efb Iustin Pop
        elif field == "sinst_list":
3035 ec223efb Iustin Pop
          val = list(node_to_secondary[node.name])
3036 ec223efb Iustin Pop
        elif field == "pinst_cnt":
3037 ec223efb Iustin Pop
          val = len(node_to_primary[node.name])
3038 ec223efb Iustin Pop
        elif field == "sinst_cnt":
3039 ec223efb Iustin Pop
          val = len(node_to_secondary[node.name])
3040 a8083063 Iustin Pop
        elif field == "pip":
3041 a8083063 Iustin Pop
          val = node.primary_ip
3042 a8083063 Iustin Pop
        elif field == "sip":
3043 a8083063 Iustin Pop
          val = node.secondary_ip
3044 130a6a6f Iustin Pop
        elif field == "tags":
3045 130a6a6f Iustin Pop
          val = list(node.GetTags())
3046 0e67cdbe Iustin Pop
        elif field == "master":
3047 0e67cdbe Iustin Pop
          val = node.name == master_node
3048 31bf511f Iustin Pop
        elif self._FIELDS_DYNAMIC.Matches(field):
3049 ec223efb Iustin Pop
          val = live_data[node.name].get(field, None)
3050 c120ff34 Iustin Pop
        elif field == "role":
3051 c120ff34 Iustin Pop
          if node.name == master_node:
3052 c120ff34 Iustin Pop
            val = "M"
3053 c120ff34 Iustin Pop
          elif node.master_candidate:
3054 c120ff34 Iustin Pop
            val = "C"
3055 c120ff34 Iustin Pop
          elif node.drained:
3056 c120ff34 Iustin Pop
            val = "D"
3057 c120ff34 Iustin Pop
          elif node.offline:
3058 c120ff34 Iustin Pop
            val = "O"
3059 c120ff34 Iustin Pop
          else:
3060 c120ff34 Iustin Pop
            val = "R"
3061 a8083063 Iustin Pop
        else:
3062 3ecf6786 Iustin Pop
          raise errors.ParameterError(field)
3063 a8083063 Iustin Pop
        node_output.append(val)
3064 a8083063 Iustin Pop
      output.append(node_output)
3065 a8083063 Iustin Pop
3066 a8083063 Iustin Pop
    return output
3067 a8083063 Iustin Pop
3068 a8083063 Iustin Pop
3069 dcb93971 Michael Hanselmann
class LUQueryNodeVolumes(NoHooksLU):
3070 dcb93971 Michael Hanselmann
  """Logical unit for getting volumes on node(s).
3071 dcb93971 Michael Hanselmann

3072 dcb93971 Michael Hanselmann
  """
3073 dcb93971 Michael Hanselmann
  _OP_REQP = ["nodes", "output_fields"]
3074 21a15682 Guido Trotter
  REQ_BGL = False
3075 a2d2e1a7 Iustin Pop
  _FIELDS_DYNAMIC = utils.FieldSet("phys", "vg", "name", "size", "instance")
3076 a2d2e1a7 Iustin Pop
  _FIELDS_STATIC = utils.FieldSet("node")
3077 21a15682 Guido Trotter
3078 21a15682 Guido Trotter
  def ExpandNames(self):
3079 31bf511f Iustin Pop
    _CheckOutputFields(static=self._FIELDS_STATIC,
3080 31bf511f Iustin Pop
                       dynamic=self._FIELDS_DYNAMIC,
3081 21a15682 Guido Trotter
                       selected=self.op.output_fields)
3082 21a15682 Guido Trotter
3083 21a15682 Guido Trotter
    self.needed_locks = {}
3084 21a15682 Guido Trotter
    self.share_locks[locking.LEVEL_NODE] = 1
3085 21a15682 Guido Trotter
    if not self.op.nodes:
3086 e310b019 Guido Trotter
      self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
3087 21a15682 Guido Trotter
    else:
3088 21a15682 Guido Trotter
      self.needed_locks[locking.LEVEL_NODE] = \
3089 21a15682 Guido Trotter
        _GetWantedNodes(self, self.op.nodes)
3090 dcb93971 Michael Hanselmann
3091 dcb93971 Michael Hanselmann
  def CheckPrereq(self):
3092 dcb93971 Michael Hanselmann
    """Check prerequisites.
3093 dcb93971 Michael Hanselmann

3094 dcb93971 Michael Hanselmann
    This checks that the fields required are valid output fields.
3095 dcb93971 Michael Hanselmann

3096 dcb93971 Michael Hanselmann
    """
3097 21a15682 Guido Trotter
    self.nodes = self.acquired_locks[locking.LEVEL_NODE]
3098 dcb93971 Michael Hanselmann
3099 dcb93971 Michael Hanselmann
  def Exec(self, feedback_fn):
3100 dcb93971 Michael Hanselmann
    """Computes the list of nodes and their attributes.
3101 dcb93971 Michael Hanselmann

3102 dcb93971 Michael Hanselmann
    """
3103 a7ba5e53 Iustin Pop
    nodenames = self.nodes
3104 72737a7f Iustin Pop
    volumes = self.rpc.call_node_volumes(nodenames)
3105 dcb93971 Michael Hanselmann
3106 dcb93971 Michael Hanselmann
    ilist = [self.cfg.GetInstanceInfo(iname) for iname
3107 dcb93971 Michael Hanselmann
             in self.cfg.GetInstanceList()]
3108 dcb93971 Michael Hanselmann
3109 dcb93971 Michael Hanselmann
    lv_by_node = dict([(inst, inst.MapLVsByNode()) for inst in ilist])
3110 dcb93971 Michael Hanselmann
3111 dcb93971 Michael Hanselmann
    output = []
3112 dcb93971 Michael Hanselmann
    for node in nodenames:
3113 10bfe6cb Iustin Pop
      nresult = volumes[node]
3114 10bfe6cb Iustin Pop
      if nresult.offline:
3115 10bfe6cb Iustin Pop
        continue
3116 4c4e4e1e Iustin Pop
      msg = nresult.fail_msg
3117 10bfe6cb Iustin Pop
      if msg:
3118 10bfe6cb Iustin Pop
        self.LogWarning("Can't compute volume data on node %s: %s", node, msg)
3119 37d19eb2 Michael Hanselmann
        continue
3120 37d19eb2 Michael Hanselmann
3121 10bfe6cb Iustin Pop
      node_vols = nresult.payload[:]
3122 dcb93971 Michael Hanselmann
      node_vols.sort(key=lambda vol: vol['dev'])
3123 dcb93971 Michael Hanselmann
3124 dcb93971 Michael Hanselmann
      for vol in node_vols:
3125 dcb93971 Michael Hanselmann
        node_output = []
3126 dcb93971 Michael Hanselmann
        for field in self.op.output_fields:
3127 dcb93971 Michael Hanselmann
          if field == "node":
3128 dcb93971 Michael Hanselmann
            val = node
3129 dcb93971 Michael Hanselmann
          elif field == "phys":
3130 dcb93971 Michael Hanselmann
            val = vol['dev']
3131 dcb93971 Michael Hanselmann
          elif field == "vg":
3132 dcb93971 Michael Hanselmann
            val = vol['vg']
3133 dcb93971 Michael Hanselmann
          elif field == "name":
3134 dcb93971 Michael Hanselmann
            val = vol['name']
3135 dcb93971 Michael Hanselmann
          elif field == "size":
3136 dcb93971 Michael Hanselmann
            val = int(float(vol['size']))
3137 dcb93971 Michael Hanselmann
          elif field == "instance":
3138 dcb93971 Michael Hanselmann
            for inst in ilist:
3139 dcb93971 Michael Hanselmann
              if node not in lv_by_node[inst]:
3140 dcb93971 Michael Hanselmann
                continue
3141 dcb93971 Michael Hanselmann
              if vol['name'] in lv_by_node[inst][node]:
3142 dcb93971 Michael Hanselmann
                val = inst.name
3143 dcb93971 Michael Hanselmann
                break
3144 dcb93971 Michael Hanselmann
            else:
3145 dcb93971 Michael Hanselmann
              val = '-'
3146 dcb93971 Michael Hanselmann
          else:
3147 3ecf6786 Iustin Pop
            raise errors.ParameterError(field)
3148 dcb93971 Michael Hanselmann
          node_output.append(str(val))
3149 dcb93971 Michael Hanselmann
3150 dcb93971 Michael Hanselmann
        output.append(node_output)
3151 dcb93971 Michael Hanselmann
3152 dcb93971 Michael Hanselmann
    return output
3153 dcb93971 Michael Hanselmann
3154 dcb93971 Michael Hanselmann
3155 9e5442ce Michael Hanselmann
class LUQueryNodeStorage(NoHooksLU):
3156 9e5442ce Michael Hanselmann
  """Logical unit for getting information on storage units on node(s).
3157 9e5442ce Michael Hanselmann

3158 9e5442ce Michael Hanselmann
  """
3159 9e5442ce Michael Hanselmann
  _OP_REQP = ["nodes", "storage_type", "output_fields"]
3160 9e5442ce Michael Hanselmann
  REQ_BGL = False
3161 620a85fd Iustin Pop
  _FIELDS_STATIC = utils.FieldSet(constants.SF_NODE)
3162 9e5442ce Michael Hanselmann
3163 0e3baaf3 Iustin Pop
  def CheckArguments(self):
3164 0e3baaf3 Iustin Pop
    _CheckStorageType(self.op.storage_type)
3165 9e5442ce Michael Hanselmann
3166 9e5442ce Michael Hanselmann
    _CheckOutputFields(static=self._FIELDS_STATIC,
3167 620a85fd Iustin Pop
                       dynamic=utils.FieldSet(*constants.VALID_STORAGE_FIELDS),
3168 9e5442ce Michael Hanselmann
                       selected=self.op.output_fields)
3169 9e5442ce Michael Hanselmann
3170 0e3baaf3 Iustin Pop
  def ExpandNames(self):
3171 9e5442ce Michael Hanselmann
    self.needed_locks = {}
3172 9e5442ce Michael Hanselmann
    self.share_locks[locking.LEVEL_NODE] = 1
3173 9e5442ce Michael Hanselmann
3174 9e5442ce Michael Hanselmann
    if self.op.nodes:
3175 9e5442ce Michael Hanselmann
      self.needed_locks[locking.LEVEL_NODE] = \
3176 9e5442ce Michael Hanselmann
        _GetWantedNodes(self, self.op.nodes)
3177 9e5442ce Michael Hanselmann
    else:
3178 9e5442ce Michael Hanselmann
      self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
3179 9e5442ce Michael Hanselmann
3180 9e5442ce Michael Hanselmann
  def CheckPrereq(self):
3181 9e5442ce Michael Hanselmann
    """Check prerequisites.
3182 9e5442ce Michael Hanselmann

3183 9e5442ce Michael Hanselmann
    This checks that the fields required are valid output fields.
3184 9e5442ce Michael Hanselmann

3185 9e5442ce Michael Hanselmann
    """
3186 9e5442ce Michael Hanselmann
    self.op.name = getattr(self.op, "name", None)
3187 9e5442ce Michael Hanselmann
3188 9e5442ce Michael Hanselmann
    self.nodes = self.acquired_locks[locking.LEVEL_NODE]
3189 9e5442ce Michael Hanselmann
3190 9e5442ce Michael Hanselmann
  def Exec(self, feedback_fn):
3191 9e5442ce Michael Hanselmann
    """Computes the list of nodes and their attributes.
3192 9e5442ce Michael Hanselmann

3193 9e5442ce Michael Hanselmann
    """
3194 9e5442ce Michael Hanselmann
    # Always get name to sort by
3195 9e5442ce Michael Hanselmann
    if constants.SF_NAME in self.op.output_fields:
3196 9e5442ce Michael Hanselmann
      fields = self.op.output_fields[:]
3197 9e5442ce Michael Hanselmann
    else:
3198 9e5442ce Michael Hanselmann
      fields = [constants.SF_NAME] + self.op.output_fields
3199 9e5442ce Michael Hanselmann
3200 620a85fd Iustin Pop
    # Never ask for node or type as it's only known to the LU
3201 620a85fd Iustin Pop
    for extra in [constants.SF_NODE, constants.SF_TYPE]:
3202 620a85fd Iustin Pop
      while extra in fields:
3203 620a85fd Iustin Pop
        fields.remove(extra)
3204 9e5442ce Michael Hanselmann
3205 9e5442ce Michael Hanselmann
    field_idx = dict([(name, idx) for (idx, name) in enumerate(fields)])
3206 9e5442ce Michael Hanselmann
    name_idx = field_idx[constants.SF_NAME]
3207 9e5442ce Michael Hanselmann
3208 efb8da02 Michael Hanselmann
    st_args = _GetStorageTypeArgs(self.cfg, self.op.storage_type)
3209 9e5442ce Michael Hanselmann
    data = self.rpc.call_storage_list(self.nodes,
3210 9e5442ce Michael Hanselmann
                                      self.op.storage_type, st_args,
3211 9e5442ce Michael Hanselmann
                                      self.op.name, fields)
3212 9e5442ce Michael Hanselmann
3213 9e5442ce Michael Hanselmann
    result = []
3214 9e5442ce Michael Hanselmann
3215 9e5442ce Michael Hanselmann
    for node in utils.NiceSort(self.nodes):
3216 9e5442ce Michael Hanselmann
      nresult = data[node]
3217 9e5442ce Michael Hanselmann
      if nresult.offline:
3218 9e5442ce Michael Hanselmann
        continue
3219 9e5442ce Michael Hanselmann
3220 9e5442ce Michael Hanselmann
      msg = nresult.fail_msg
3221 9e5442ce Michael Hanselmann
      if msg:
3222 9e5442ce Michael Hanselmann
        self.LogWarning("Can't get storage data from node %s: %s", node, msg)
3223 9e5442ce Michael Hanselmann
        continue
3224 9e5442ce Michael Hanselmann
3225 9e5442ce Michael Hanselmann
      rows = dict([(row[name_idx], row) for row in nresult.payload])
3226 9e5442ce Michael Hanselmann
3227 9e5442ce Michael Hanselmann
      for name in utils.NiceSort(rows.keys()):
3228 9e5442ce Michael Hanselmann
        row = rows[name]
3229 9e5442ce Michael Hanselmann
3230 9e5442ce Michael Hanselmann
        out = []
3231 9e5442ce Michael Hanselmann
3232 9e5442ce Michael Hanselmann
        for field in self.op.output_fields:
3233 620a85fd Iustin Pop
          if field == constants.SF_NODE:
3234 9e5442ce Michael Hanselmann
            val = node
3235 620a85fd Iustin Pop
          elif field == constants.SF_TYPE:
3236 620a85fd Iustin Pop
            val = self.op.storage_type
3237 9e5442ce Michael Hanselmann
          elif field in field_idx:
3238 9e5442ce Michael Hanselmann
            val = row[field_idx[field]]
3239 9e5442ce Michael Hanselmann
          else:
3240 9e5442ce Michael Hanselmann
            raise errors.ParameterError(field)
3241 9e5442ce Michael Hanselmann
3242 9e5442ce Michael Hanselmann
          out.append(val)
3243 9e5442ce Michael Hanselmann
3244 9e5442ce Michael Hanselmann
        result.append(out)
3245 9e5442ce Michael Hanselmann
3246 9e5442ce Michael Hanselmann
    return result
3247 9e5442ce Michael Hanselmann
3248 9e5442ce Michael Hanselmann
3249 efb8da02 Michael Hanselmann
class LUModifyNodeStorage(NoHooksLU):
3250 efb8da02 Michael Hanselmann
  """Logical unit for modifying a storage volume on a node.
3251 efb8da02 Michael Hanselmann

3252 efb8da02 Michael Hanselmann
  """
3253 efb8da02 Michael Hanselmann
  _OP_REQP = ["node_name", "storage_type", "name", "changes"]
3254 efb8da02 Michael Hanselmann
  REQ_BGL = False
3255 efb8da02 Michael Hanselmann
3256 efb8da02 Michael Hanselmann
  def CheckArguments(self):
3257 cf26a87a Iustin Pop
    self.opnode_name = _ExpandNodeName(self.cfg, self.op.node_name)
3258 efb8da02 Michael Hanselmann
3259 0e3baaf3 Iustin Pop
    _CheckStorageType(self.op.storage_type)
3260 efb8da02 Michael Hanselmann
3261 efb8da02 Michael Hanselmann
  def ExpandNames(self):
3262 efb8da02 Michael Hanselmann
    self.needed_locks = {
3263 efb8da02 Michael Hanselmann
      locking.LEVEL_NODE: self.op.node_name,
3264 efb8da02 Michael Hanselmann
      }
3265 efb8da02 Michael Hanselmann
3266 efb8da02 Michael Hanselmann
  def CheckPrereq(self):
3267 efb8da02 Michael Hanselmann
    """Check prerequisites.
3268 efb8da02 Michael Hanselmann

3269 efb8da02 Michael Hanselmann
    """
3270 efb8da02 Michael Hanselmann
    storage_type = self.op.storage_type
3271 efb8da02 Michael Hanselmann
3272 efb8da02 Michael Hanselmann
    try:
3273 efb8da02 Michael Hanselmann
      modifiable = constants.MODIFIABLE_STORAGE_FIELDS[storage_type]
3274 efb8da02 Michael Hanselmann
    except KeyError:
3275 efb8da02 Michael Hanselmann
      raise errors.OpPrereqError("Storage units of type '%s' can not be"
3276 5c983ee5 Iustin Pop
                                 " modified" % storage_type,
3277 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
3278 efb8da02 Michael Hanselmann
3279 efb8da02 Michael Hanselmann
    diff = set(self.op.changes.keys()) - modifiable
3280 efb8da02 Michael Hanselmann
    if diff:
3281 efb8da02 Michael Hanselmann
      raise errors.OpPrereqError("The following fields can not be modified for"
3282 efb8da02 Michael Hanselmann
                                 " storage units of type '%s': %r" %
3283 5c983ee5 Iustin Pop
                                 (storage_type, list(diff)),
3284 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
3285 efb8da02 Michael Hanselmann
3286 efb8da02 Michael Hanselmann
  def Exec(self, feedback_fn):
3287 efb8da02 Michael Hanselmann
    """Computes the list of nodes and their attributes.
3288 efb8da02 Michael Hanselmann

3289 efb8da02 Michael Hanselmann
    """
3290 efb8da02 Michael Hanselmann
    st_args = _GetStorageTypeArgs(self.cfg, self.op.storage_type)
3291 efb8da02 Michael Hanselmann
    result = self.rpc.call_storage_modify(self.op.node_name,
3292 efb8da02 Michael Hanselmann
                                          self.op.storage_type, st_args,
3293 efb8da02 Michael Hanselmann
                                          self.op.name, self.op.changes)
3294 efb8da02 Michael Hanselmann
    result.Raise("Failed to modify storage unit '%s' on %s" %
3295 efb8da02 Michael Hanselmann
                 (self.op.name, self.op.node_name))
3296 efb8da02 Michael Hanselmann
3297 efb8da02 Michael Hanselmann
3298 a8083063 Iustin Pop
class LUAddNode(LogicalUnit):
3299 a8083063 Iustin Pop
  """Logical unit for adding node to the cluster.
3300 a8083063 Iustin Pop

3301 a8083063 Iustin Pop
  """
3302 a8083063 Iustin Pop
  HPATH = "node-add"
3303 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_NODE
3304 a8083063 Iustin Pop
  _OP_REQP = ["node_name"]
3305 a8083063 Iustin Pop
3306 44caf5a8 Iustin Pop
  def CheckArguments(self):
3307 44caf5a8 Iustin Pop
    # validate/normalize the node name
3308 44caf5a8 Iustin Pop
    self.op.node_name = utils.HostInfo.NormalizeName(self.op.node_name)
3309 44caf5a8 Iustin Pop
3310 a8083063 Iustin Pop
  def BuildHooksEnv(self):
3311 a8083063 Iustin Pop
    """Build hooks env.
3312 a8083063 Iustin Pop

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

3315 a8083063 Iustin Pop
    """
3316 a8083063 Iustin Pop
    env = {
3317 0e137c28 Iustin Pop
      "OP_TARGET": self.op.node_name,
3318 a8083063 Iustin Pop
      "NODE_NAME": self.op.node_name,
3319 a8083063 Iustin Pop
      "NODE_PIP": self.op.primary_ip,
3320 a8083063 Iustin Pop
      "NODE_SIP": self.op.secondary_ip,
3321 a8083063 Iustin Pop
      }
3322 a8083063 Iustin Pop
    nodes_0 = self.cfg.GetNodeList()
3323 a8083063 Iustin Pop
    nodes_1 = nodes_0 + [self.op.node_name, ]
3324 a8083063 Iustin Pop
    return env, nodes_0, nodes_1
3325 a8083063 Iustin Pop
3326 a8083063 Iustin Pop
  def CheckPrereq(self):
3327 a8083063 Iustin Pop
    """Check prerequisites.
3328 a8083063 Iustin Pop

3329 a8083063 Iustin Pop
    This checks:
3330 a8083063 Iustin Pop
     - the new node is not already in the config
3331 a8083063 Iustin Pop
     - it is resolvable
3332 a8083063 Iustin Pop
     - its parameters (single/dual homed) matches the cluster
3333 a8083063 Iustin Pop

3334 5bbd3f7f Michael Hanselmann
    Any errors are signaled by raising errors.OpPrereqError.
3335 a8083063 Iustin Pop

3336 a8083063 Iustin Pop
    """
3337 a8083063 Iustin Pop
    node_name = self.op.node_name
3338 a8083063 Iustin Pop
    cfg = self.cfg
3339 a8083063 Iustin Pop
3340 104f4ca1 Iustin Pop
    dns_data = utils.GetHostInfo(node_name)
3341 a8083063 Iustin Pop
3342 bcf043c9 Iustin Pop
    node = dns_data.name
3343 bcf043c9 Iustin Pop
    primary_ip = self.op.primary_ip = dns_data.ip
3344 a8083063 Iustin Pop
    secondary_ip = getattr(self.op, "secondary_ip", None)
3345 a8083063 Iustin Pop
    if secondary_ip is None:
3346 a8083063 Iustin Pop
      secondary_ip = primary_ip
3347 a8083063 Iustin Pop
    if not utils.IsValidIP(secondary_ip):
3348 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Invalid secondary IP given",
3349 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
3350 a8083063 Iustin Pop
    self.op.secondary_ip = secondary_ip
3351 e7c6e02b Michael Hanselmann
3352 a8083063 Iustin Pop
    node_list = cfg.GetNodeList()
3353 e7c6e02b Michael Hanselmann
    if not self.op.readd and node in node_list:
3354 e7c6e02b Michael Hanselmann
      raise errors.OpPrereqError("Node %s is already in the configuration" %
3355 5c983ee5 Iustin Pop
                                 node, errors.ECODE_EXISTS)
3356 e7c6e02b Michael Hanselmann
    elif self.op.readd and node not in node_list:
3357 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Node %s is not in the configuration" % node,
3358 5c983ee5 Iustin Pop
                                 errors.ECODE_NOENT)
3359 a8083063 Iustin Pop
3360 1513e2dd Iustin Pop
    self.changed_primary_ip = False
3361 1513e2dd Iustin Pop
3362 a8083063 Iustin Pop
    for existing_node_name in node_list:
3363 a8083063 Iustin Pop
      existing_node = cfg.GetNodeInfo(existing_node_name)
3364 e7c6e02b Michael Hanselmann
3365 e7c6e02b Michael Hanselmann
      if self.op.readd and node == existing_node_name:
3366 1513e2dd Iustin Pop
        if existing_node.secondary_ip != secondary_ip:
3367 e7c6e02b Michael Hanselmann
          raise errors.OpPrereqError("Readded node doesn't have the same IP"
3368 5c983ee5 Iustin Pop
                                     " address configuration as before",
3369 5c983ee5 Iustin Pop
                                     errors.ECODE_INVAL)
3370 1513e2dd Iustin Pop
        if existing_node.primary_ip != primary_ip:
3371 1513e2dd Iustin Pop
          self.changed_primary_ip = True
3372 1513e2dd Iustin Pop
3373 e7c6e02b Michael Hanselmann
        continue
3374 e7c6e02b Michael Hanselmann
3375 a8083063 Iustin Pop
      if (existing_node.primary_ip == primary_ip or
3376 a8083063 Iustin Pop
          existing_node.secondary_ip == primary_ip or
3377 a8083063 Iustin Pop
          existing_node.primary_ip == secondary_ip or
3378 a8083063 Iustin Pop
          existing_node.secondary_ip == secondary_ip):
3379 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("New node ip address(es) conflict with"
3380 5c983ee5 Iustin Pop
                                   " existing node %s" % existing_node.name,
3381 5c983ee5 Iustin Pop
                                   errors.ECODE_NOTUNIQUE)
3382 a8083063 Iustin Pop
3383 a8083063 Iustin Pop
    # check that the type of the node (single versus dual homed) is the
3384 a8083063 Iustin Pop
    # same as for the master
3385 d6a02168 Michael Hanselmann
    myself = cfg.GetNodeInfo(self.cfg.GetMasterNode())
3386 a8083063 Iustin Pop
    master_singlehomed = myself.secondary_ip == myself.primary_ip
3387 a8083063 Iustin Pop
    newbie_singlehomed = secondary_ip == primary_ip
3388 a8083063 Iustin Pop
    if master_singlehomed != newbie_singlehomed:
3389 a8083063 Iustin Pop
      if master_singlehomed:
3390 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("The master has no private ip but the"
3391 5c983ee5 Iustin Pop
                                   " new node has one",
3392 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
3393 a8083063 Iustin Pop
      else:
3394 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("The master has a private ip but the"
3395 5c983ee5 Iustin Pop
                                   " new node doesn't have one",
3396 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
3397 a8083063 Iustin Pop
3398 5bbd3f7f Michael Hanselmann
    # checks reachability
3399 b15d625f Iustin Pop
    if not utils.TcpPing(primary_ip, constants.DEFAULT_NODED_PORT):
3400 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Node not reachable by ping",
3401 5c983ee5 Iustin Pop
                                 errors.ECODE_ENVIRON)
3402 a8083063 Iustin Pop
3403 a8083063 Iustin Pop
    if not newbie_singlehomed:
3404 a8083063 Iustin Pop
      # check reachability from my secondary ip to newbie's secondary ip
3405 b15d625f Iustin Pop
      if not utils.TcpPing(secondary_ip, constants.DEFAULT_NODED_PORT,
3406 b15d625f Iustin Pop
                           source=myself.secondary_ip):
3407 f4bc1f2c Michael Hanselmann
        raise errors.OpPrereqError("Node secondary ip not reachable by TCP"
3408 5c983ee5 Iustin Pop
                                   " based ping to noded port",
3409 5c983ee5 Iustin Pop
                                   errors.ECODE_ENVIRON)
3410 a8083063 Iustin Pop
3411 a8ae3eb5 Iustin Pop
    if self.op.readd:
3412 a8ae3eb5 Iustin Pop
      exceptions = [node]
3413 a8ae3eb5 Iustin Pop
    else:
3414 a8ae3eb5 Iustin Pop
      exceptions = []
3415 6d7e1f20 Guido Trotter
3416 6d7e1f20 Guido Trotter
    self.master_candidate = _DecideSelfPromotion(self, exceptions=exceptions)
3417 0fff97e9 Guido Trotter
3418 a8ae3eb5 Iustin Pop
    if self.op.readd:
3419 a8ae3eb5 Iustin Pop
      self.new_node = self.cfg.GetNodeInfo(node)
3420 a8ae3eb5 Iustin Pop
      assert self.new_node is not None, "Can't retrieve locked node %s" % node
3421 a8ae3eb5 Iustin Pop
    else:
3422 a8ae3eb5 Iustin Pop
      self.new_node = objects.Node(name=node,
3423 a8ae3eb5 Iustin Pop
                                   primary_ip=primary_ip,
3424 a8ae3eb5 Iustin Pop
                                   secondary_ip=secondary_ip,
3425 a8ae3eb5 Iustin Pop
                                   master_candidate=self.master_candidate,
3426 a8ae3eb5 Iustin Pop
                                   offline=False, drained=False)
3427 a8083063 Iustin Pop
3428 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
3429 a8083063 Iustin Pop
    """Adds the new node to the cluster.
3430 a8083063 Iustin Pop

3431 a8083063 Iustin Pop
    """
3432 a8083063 Iustin Pop
    new_node = self.new_node
3433 a8083063 Iustin Pop
    node = new_node.name
3434 a8083063 Iustin Pop
3435 a8ae3eb5 Iustin Pop
    # for re-adds, reset the offline/drained/master-candidate flags;
3436 a8ae3eb5 Iustin Pop
    # we need to reset here, otherwise offline would prevent RPC calls
3437 a8ae3eb5 Iustin Pop
    # later in the procedure; this also means that if the re-add
3438 a8ae3eb5 Iustin Pop
    # fails, we are left with a non-offlined, broken node
3439 a8ae3eb5 Iustin Pop
    if self.op.readd:
3440 7260cfbe Iustin Pop
      new_node.drained = new_node.offline = False # pylint: disable-msg=W0201
3441 a8ae3eb5 Iustin Pop
      self.LogInfo("Readding a node, the offline/drained flags were reset")
3442 a8ae3eb5 Iustin Pop
      # if we demote the node, we do cleanup later in the procedure
3443 a8ae3eb5 Iustin Pop
      new_node.master_candidate = self.master_candidate
3444 1513e2dd Iustin Pop
      if self.changed_primary_ip:
3445 1513e2dd Iustin Pop
        new_node.primary_ip = self.op.primary_ip
3446 a8ae3eb5 Iustin Pop
3447 a8ae3eb5 Iustin Pop
    # notify the user about any possible mc promotion
3448 a8ae3eb5 Iustin Pop
    if new_node.master_candidate:
3449 a8ae3eb5 Iustin Pop
      self.LogInfo("Node will be a master candidate")
3450 a8ae3eb5 Iustin Pop
3451 a8083063 Iustin Pop
    # check connectivity
3452 72737a7f Iustin Pop
    result = self.rpc.call_version([node])[node]
3453 4c4e4e1e Iustin Pop
    result.Raise("Can't get version information from node %s" % node)
3454 90b54c26 Iustin Pop
    if constants.PROTOCOL_VERSION == result.payload:
3455 90b54c26 Iustin Pop
      logging.info("Communication to node %s fine, sw version %s match",
3456 90b54c26 Iustin Pop
                   node, result.payload)
3457 a8083063 Iustin Pop
    else:
3458 90b54c26 Iustin Pop
      raise errors.OpExecError("Version mismatch master version %s,"
3459 90b54c26 Iustin Pop
                               " node version %s" %
3460 90b54c26 Iustin Pop
                               (constants.PROTOCOL_VERSION, result.payload))
3461 a8083063 Iustin Pop
3462 a8083063 Iustin Pop
    # setup ssh on node
3463 b989b9d9 Ken Wehr
    if self.cfg.GetClusterInfo().modify_ssh_setup:
3464 b989b9d9 Ken Wehr
      logging.info("Copy ssh key to node %s", node)
3465 b989b9d9 Ken Wehr
      priv_key, pub_key, _ = ssh.GetUserFiles(constants.GANETI_RUNAS)
3466 b989b9d9 Ken Wehr
      keyarray = []
3467 b989b9d9 Ken Wehr
      keyfiles = [constants.SSH_HOST_DSA_PRIV, constants.SSH_HOST_DSA_PUB,
3468 b989b9d9 Ken Wehr
                  constants.SSH_HOST_RSA_PRIV, constants.SSH_HOST_RSA_PUB,
3469 b989b9d9 Ken Wehr
                  priv_key, pub_key]
3470 b989b9d9 Ken Wehr
3471 b989b9d9 Ken Wehr
      for i in keyfiles:
3472 b989b9d9 Ken Wehr
        keyarray.append(utils.ReadFile(i))
3473 b989b9d9 Ken Wehr
3474 b989b9d9 Ken Wehr
      result = self.rpc.call_node_add(node, keyarray[0], keyarray[1],
3475 b989b9d9 Ken Wehr
                                      keyarray[2], keyarray[3], keyarray[4],
3476 b989b9d9 Ken Wehr
                                      keyarray[5])
3477 b989b9d9 Ken Wehr
      result.Raise("Cannot transfer ssh keys to the new node")
3478 a8083063 Iustin Pop
3479 a8083063 Iustin Pop
    # Add node to our /etc/hosts, and add key to known_hosts
3480 b86a6bcd Guido Trotter
    if self.cfg.GetClusterInfo().modify_etc_hosts:
3481 7672a621 Iustin Pop
      # FIXME: this should be done via an rpc call to node daemon
3482 b86a6bcd Guido Trotter
      utils.AddHostToEtcHosts(new_node.name)
3483 c8a0948f Michael Hanselmann
3484 a8083063 Iustin Pop
    if new_node.secondary_ip != new_node.primary_ip:
3485 781de953 Iustin Pop
      result = self.rpc.call_node_has_ip_address(new_node.name,
3486 781de953 Iustin Pop
                                                 new_node.secondary_ip)
3487 4c4e4e1e Iustin Pop
      result.Raise("Failure checking secondary ip on node %s" % new_node.name,
3488 045dd6d9 Iustin Pop
                   prereq=True, ecode=errors.ECODE_ENVIRON)
3489 c2fc8250 Iustin Pop
      if not result.payload:
3490 f4bc1f2c Michael Hanselmann
        raise errors.OpExecError("Node claims it doesn't have the secondary ip"
3491 f4bc1f2c Michael Hanselmann
                                 " you gave (%s). Please fix and re-run this"
3492 f4bc1f2c Michael Hanselmann
                                 " command." % new_node.secondary_ip)
3493 a8083063 Iustin Pop
3494 d6a02168 Michael Hanselmann
    node_verify_list = [self.cfg.GetMasterNode()]
3495 5c0527ed Guido Trotter
    node_verify_param = {
3496 f60759f7 Iustin Pop
      constants.NV_NODELIST: [node],
3497 5c0527ed Guido Trotter
      # TODO: do a node-net-test as well?
3498 5c0527ed Guido Trotter
    }
3499 5c0527ed Guido Trotter
3500 72737a7f Iustin Pop
    result = self.rpc.call_node_verify(node_verify_list, node_verify_param,
3501 72737a7f Iustin Pop
                                       self.cfg.GetClusterName())
3502 5c0527ed Guido Trotter
    for verifier in node_verify_list:
3503 4c4e4e1e Iustin Pop
      result[verifier].Raise("Cannot communicate with node %s" % verifier)
3504 f60759f7 Iustin Pop
      nl_payload = result[verifier].payload[constants.NV_NODELIST]
3505 6f68a739 Iustin Pop
      if nl_payload:
3506 6f68a739 Iustin Pop
        for failed in nl_payload:
3507 31821208 Iustin Pop
          feedback_fn("ssh/hostname verification failed"
3508 31821208 Iustin Pop
                      " (checking from %s): %s" %
3509 6f68a739 Iustin Pop
                      (verifier, nl_payload[failed]))
3510 5c0527ed Guido Trotter
        raise errors.OpExecError("ssh/hostname verification failed.")
3511 ff98055b Iustin Pop
3512 d8470559 Michael Hanselmann
    if self.op.readd:
3513 28eddce5 Guido Trotter
      _RedistributeAncillaryFiles(self)
3514 d8470559 Michael Hanselmann
      self.context.ReaddNode(new_node)
3515 a8ae3eb5 Iustin Pop
      # make sure we redistribute the config
3516 a4eae71f Michael Hanselmann
      self.cfg.Update(new_node, feedback_fn)
3517 a8ae3eb5 Iustin Pop
      # and make sure the new node will not have old files around
3518 a8ae3eb5 Iustin Pop
      if not new_node.master_candidate:
3519 a8ae3eb5 Iustin Pop
        result = self.rpc.call_node_demote_from_mc(new_node.name)
3520 3cebe102 Michael Hanselmann
        msg = result.fail_msg
3521 a8ae3eb5 Iustin Pop
        if msg:
3522 a8ae3eb5 Iustin Pop
          self.LogWarning("Node failed to demote itself from master"
3523 a8ae3eb5 Iustin Pop
                          " candidate status: %s" % msg)
3524 d8470559 Michael Hanselmann
    else:
3525 035566e3 Iustin Pop
      _RedistributeAncillaryFiles(self, additional_nodes=[node])
3526 0debfb35 Guido Trotter
      self.context.AddNode(new_node, self.proc.GetECId())
3527 a8083063 Iustin Pop
3528 a8083063 Iustin Pop
3529 b31c8676 Iustin Pop
class LUSetNodeParams(LogicalUnit):
3530 b31c8676 Iustin Pop
  """Modifies the parameters of a node.
3531 b31c8676 Iustin Pop

3532 b31c8676 Iustin Pop
  """
3533 b31c8676 Iustin Pop
  HPATH = "node-modify"
3534 b31c8676 Iustin Pop
  HTYPE = constants.HTYPE_NODE
3535 b31c8676 Iustin Pop
  _OP_REQP = ["node_name"]
3536 b31c8676 Iustin Pop
  REQ_BGL = False
3537 b31c8676 Iustin Pop
3538 b31c8676 Iustin Pop
  def CheckArguments(self):
3539 cf26a87a Iustin Pop
    self.op.node_name = _ExpandNodeName(self.cfg, self.op.node_name)
3540 3a5ba66a Iustin Pop
    _CheckBooleanOpField(self.op, 'master_candidate')
3541 3a5ba66a Iustin Pop
    _CheckBooleanOpField(self.op, 'offline')
3542 c9d443ea Iustin Pop
    _CheckBooleanOpField(self.op, 'drained')
3543 601908d0 Iustin Pop
    _CheckBooleanOpField(self.op, 'auto_promote')
3544 c9d443ea Iustin Pop
    all_mods = [self.op.offline, self.op.master_candidate, self.op.drained]
3545 c9d443ea Iustin Pop
    if all_mods.count(None) == 3:
3546 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Please pass at least one modification",
3547 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
3548 c9d443ea Iustin Pop
    if all_mods.count(True) > 1:
3549 c9d443ea Iustin Pop
      raise errors.OpPrereqError("Can't set the node into more than one"
3550 5c983ee5 Iustin Pop
                                 " state at the same time",
3551 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
3552 b31c8676 Iustin Pop
3553 601908d0 Iustin Pop
    # Boolean value that tells us whether we're offlining or draining the node
3554 601908d0 Iustin Pop
    self.offline_or_drain = (self.op.offline == True or
3555 601908d0 Iustin Pop
                             self.op.drained == True)
3556 601908d0 Iustin Pop
    self.deoffline_or_drain = (self.op.offline == False or
3557 601908d0 Iustin Pop
                               self.op.drained == False)
3558 601908d0 Iustin Pop
    self.might_demote = (self.op.master_candidate == False or
3559 601908d0 Iustin Pop
                         self.offline_or_drain)
3560 601908d0 Iustin Pop
3561 601908d0 Iustin Pop
    self.lock_all = self.op.auto_promote and self.might_demote
3562 601908d0 Iustin Pop
3563 601908d0 Iustin Pop
3564 b31c8676 Iustin Pop
  def ExpandNames(self):
3565 601908d0 Iustin Pop
    if self.lock_all:
3566 601908d0 Iustin Pop
      self.needed_locks = {locking.LEVEL_NODE: locking.ALL_SET}
3567 601908d0 Iustin Pop
    else:
3568 601908d0 Iustin Pop
      self.needed_locks = {locking.LEVEL_NODE: self.op.node_name}
3569 b31c8676 Iustin Pop
3570 b31c8676 Iustin Pop
  def BuildHooksEnv(self):
3571 b31c8676 Iustin Pop
    """Build hooks env.
3572 b31c8676 Iustin Pop

3573 b31c8676 Iustin Pop
    This runs on the master node.
3574 b31c8676 Iustin Pop

3575 b31c8676 Iustin Pop
    """
3576 b31c8676 Iustin Pop
    env = {
3577 b31c8676 Iustin Pop
      "OP_TARGET": self.op.node_name,
3578 b31c8676 Iustin Pop
      "MASTER_CANDIDATE": str(self.op.master_candidate),
3579 3a5ba66a Iustin Pop
      "OFFLINE": str(self.op.offline),
3580 c9d443ea Iustin Pop
      "DRAINED": str(self.op.drained),
3581 b31c8676 Iustin Pop
      }
3582 b31c8676 Iustin Pop
    nl = [self.cfg.GetMasterNode(),
3583 b31c8676 Iustin Pop
          self.op.node_name]
3584 b31c8676 Iustin Pop
    return env, nl, nl
3585 b31c8676 Iustin Pop
3586 b31c8676 Iustin Pop
  def CheckPrereq(self):
3587 b31c8676 Iustin Pop
    """Check prerequisites.
3588 b31c8676 Iustin Pop

3589 b31c8676 Iustin Pop
    This only checks the instance list against the existing names.
3590 b31c8676 Iustin Pop

3591 b31c8676 Iustin Pop
    """
3592 3a5ba66a Iustin Pop
    node = self.node = self.cfg.GetNodeInfo(self.op.node_name)
3593 b31c8676 Iustin Pop
3594 97c61d46 Iustin Pop
    if (self.op.master_candidate is not None or
3595 97c61d46 Iustin Pop
        self.op.drained is not None or
3596 97c61d46 Iustin Pop
        self.op.offline is not None):
3597 97c61d46 Iustin Pop
      # we can't change the master's node flags
3598 97c61d46 Iustin Pop
      if self.op.node_name == self.cfg.GetMasterNode():
3599 97c61d46 Iustin Pop
        raise errors.OpPrereqError("The master role can be changed"
3600 5c983ee5 Iustin Pop
                                   " only via masterfailover",
3601 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
3602 97c61d46 Iustin Pop
3603 601908d0 Iustin Pop
3604 601908d0 Iustin Pop
    if node.master_candidate and self.might_demote and not self.lock_all:
3605 601908d0 Iustin Pop
      assert not self.op.auto_promote, "auto-promote set but lock_all not"
3606 601908d0 Iustin Pop
      # check if after removing the current node, we're missing master
3607 601908d0 Iustin Pop
      # candidates
3608 601908d0 Iustin Pop
      (mc_remaining, mc_should, _) = \
3609 601908d0 Iustin Pop
          self.cfg.GetMasterCandidateStats(exceptions=[node.name])
3610 8fe9239e Iustin Pop
      if mc_remaining < mc_should:
3611 601908d0 Iustin Pop
        raise errors.OpPrereqError("Not enough master candidates, please"
3612 601908d0 Iustin Pop
                                   " pass auto_promote to allow promotion",
3613 601908d0 Iustin Pop
                                   errors.ECODE_INVAL)
3614 3e83dd48 Iustin Pop
3615 c9d443ea Iustin Pop
    if (self.op.master_candidate == True and
3616 c9d443ea Iustin Pop
        ((node.offline and not self.op.offline == False) or
3617 c9d443ea Iustin Pop
         (node.drained and not self.op.drained == False))):
3618 c9d443ea Iustin Pop
      raise errors.OpPrereqError("Node '%s' is offline or drained, can't set"
3619 5c983ee5 Iustin Pop
                                 " to master_candidate" % node.name,
3620 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
3621 3a5ba66a Iustin Pop
3622 3d9eb52b Guido Trotter
    # If we're being deofflined/drained, we'll MC ourself if needed
3623 601908d0 Iustin Pop
    if (self.deoffline_or_drain and not self.offline_or_drain and not
3624 cea0534a Guido Trotter
        self.op.master_candidate == True and not node.master_candidate):
3625 3d9eb52b Guido Trotter
      self.op.master_candidate = _DecideSelfPromotion(self)
3626 3d9eb52b Guido Trotter
      if self.op.master_candidate:
3627 3d9eb52b Guido Trotter
        self.LogInfo("Autopromoting node to master candidate")
3628 3d9eb52b Guido Trotter
3629 b31c8676 Iustin Pop
    return
3630 b31c8676 Iustin Pop
3631 b31c8676 Iustin Pop
  def Exec(self, feedback_fn):
3632 b31c8676 Iustin Pop
    """Modifies a node.
3633 b31c8676 Iustin Pop

3634 b31c8676 Iustin Pop
    """
3635 3a5ba66a Iustin Pop
    node = self.node
3636 b31c8676 Iustin Pop
3637 b31c8676 Iustin Pop
    result = []
3638 c9d443ea Iustin Pop
    changed_mc = False
3639 b31c8676 Iustin Pop
3640 3a5ba66a Iustin Pop
    if self.op.offline is not None:
3641 3a5ba66a Iustin Pop
      node.offline = self.op.offline
3642 3a5ba66a Iustin Pop
      result.append(("offline", str(self.op.offline)))
3643 c9d443ea Iustin Pop
      if self.op.offline == True:
3644 c9d443ea Iustin Pop
        if node.master_candidate:
3645 c9d443ea Iustin Pop
          node.master_candidate = False
3646 c9d443ea Iustin Pop
          changed_mc = True
3647 c9d443ea Iustin Pop
          result.append(("master_candidate", "auto-demotion due to offline"))
3648 c9d443ea Iustin Pop
        if node.drained:
3649 c9d443ea Iustin Pop
          node.drained = False
3650 c9d443ea Iustin Pop
          result.append(("drained", "clear drained status due to offline"))
3651 3a5ba66a Iustin Pop
3652 b31c8676 Iustin Pop
    if self.op.master_candidate is not None:
3653 b31c8676 Iustin Pop
      node.master_candidate = self.op.master_candidate
3654 c9d443ea Iustin Pop
      changed_mc = True
3655 b31c8676 Iustin Pop
      result.append(("master_candidate", str(self.op.master_candidate)))
3656 56aa9fd5 Iustin Pop
      if self.op.master_candidate == False:
3657 56aa9fd5 Iustin Pop
        rrc = self.rpc.call_node_demote_from_mc(node.name)
3658 4c4e4e1e Iustin Pop
        msg = rrc.fail_msg
3659 0959c824 Iustin Pop
        if msg:
3660 0959c824 Iustin Pop
          self.LogWarning("Node failed to demote itself: %s" % msg)
3661 b31c8676 Iustin Pop
3662 c9d443ea Iustin Pop
    if self.op.drained is not None:
3663 c9d443ea Iustin Pop
      node.drained = self.op.drained
3664 82e12743 Iustin Pop
      result.append(("drained", str(self.op.drained)))
3665 c9d443ea Iustin Pop
      if self.op.drained == True:
3666 c9d443ea Iustin Pop
        if node.master_candidate:
3667 c9d443ea Iustin Pop
          node.master_candidate = False
3668 c9d443ea Iustin Pop
          changed_mc = True
3669 c9d443ea Iustin Pop
          result.append(("master_candidate", "auto-demotion due to drain"))
3670 dec0d9da Iustin Pop
          rrc = self.rpc.call_node_demote_from_mc(node.name)
3671 3cebe102 Michael Hanselmann
          msg = rrc.fail_msg
3672 dec0d9da Iustin Pop
          if msg:
3673 dec0d9da Iustin Pop
            self.LogWarning("Node failed to demote itself: %s" % msg)
3674 c9d443ea Iustin Pop
        if node.offline:
3675 c9d443ea Iustin Pop
          node.offline = False
3676 c9d443ea Iustin Pop
          result.append(("offline", "clear offline status due to drain"))
3677 c9d443ea Iustin Pop
3678 601908d0 Iustin Pop
    # we locked all nodes, we adjust the CP before updating this node
3679 601908d0 Iustin Pop
    if self.lock_all:
3680 601908d0 Iustin Pop
      _AdjustCandidatePool(self, [node.name])
3681 601908d0 Iustin Pop
3682 b31c8676 Iustin Pop
    # this will trigger configuration file update, if needed
3683 a4eae71f Michael Hanselmann
    self.cfg.Update(node, feedback_fn)
3684 601908d0 Iustin Pop
3685 b31c8676 Iustin Pop
    # this will trigger job queue propagation or cleanup
3686 c9d443ea Iustin Pop
    if changed_mc:
3687 3a26773f Iustin Pop
      self.context.ReaddNode(node)
3688 b31c8676 Iustin Pop
3689 b31c8676 Iustin Pop
    return result
3690 b31c8676 Iustin Pop
3691 b31c8676 Iustin Pop
3692 f5118ade Iustin Pop
class LUPowercycleNode(NoHooksLU):
3693 f5118ade Iustin Pop
  """Powercycles a node.
3694 f5118ade Iustin Pop

3695 f5118ade Iustin Pop
  """
3696 f5118ade Iustin Pop
  _OP_REQP = ["node_name", "force"]
3697 f5118ade Iustin Pop
  REQ_BGL = False
3698 f5118ade Iustin Pop
3699 f5118ade Iustin Pop
  def CheckArguments(self):
3700 cf26a87a Iustin Pop
    self.op.node_name = _ExpandNodeName(self.cfg, self.op.node_name)
3701 cf26a87a Iustin Pop
    if self.op.node_name == self.cfg.GetMasterNode() and not self.op.force:
3702 f5118ade Iustin Pop
      raise errors.OpPrereqError("The node is the master and the force"
3703 5c983ee5 Iustin Pop
                                 " parameter was not set",
3704 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
3705 f5118ade Iustin Pop
3706 f5118ade Iustin Pop
  def ExpandNames(self):
3707 f5118ade Iustin Pop
    """Locking for PowercycleNode.
3708 f5118ade Iustin Pop

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

3712 f5118ade Iustin Pop
    """
3713 f5118ade Iustin Pop
    self.needed_locks = {}
3714 f5118ade Iustin Pop
3715 f5118ade Iustin Pop
  def CheckPrereq(self):
3716 f5118ade Iustin Pop
    """Check prerequisites.
3717 f5118ade Iustin Pop

3718 f5118ade Iustin Pop
    This LU has no prereqs.
3719 f5118ade Iustin Pop

3720 f5118ade Iustin Pop
    """
3721 f5118ade Iustin Pop
    pass
3722 f5118ade Iustin Pop
3723 f5118ade Iustin Pop
  def Exec(self, feedback_fn):
3724 f5118ade Iustin Pop
    """Reboots a node.
3725 f5118ade Iustin Pop

3726 f5118ade Iustin Pop
    """
3727 f5118ade Iustin Pop
    result = self.rpc.call_node_powercycle(self.op.node_name,
3728 f5118ade Iustin Pop
                                           self.cfg.GetHypervisorType())
3729 4c4e4e1e Iustin Pop
    result.Raise("Failed to schedule the reboot")
3730 f5118ade Iustin Pop
    return result.payload
3731 f5118ade Iustin Pop
3732 f5118ade Iustin Pop
3733 a8083063 Iustin Pop
class LUQueryClusterInfo(NoHooksLU):
3734 a8083063 Iustin Pop
  """Query cluster configuration.
3735 a8083063 Iustin Pop

3736 a8083063 Iustin Pop
  """
3737 a8083063 Iustin Pop
  _OP_REQP = []
3738 642339cf Guido Trotter
  REQ_BGL = False
3739 642339cf Guido Trotter
3740 642339cf Guido Trotter
  def ExpandNames(self):
3741 642339cf Guido Trotter
    self.needed_locks = {}
3742 a8083063 Iustin Pop
3743 a8083063 Iustin Pop
  def CheckPrereq(self):
3744 a8083063 Iustin Pop
    """No prerequsites needed for this LU.
3745 a8083063 Iustin Pop

3746 a8083063 Iustin Pop
    """
3747 a8083063 Iustin Pop
    pass
3748 a8083063 Iustin Pop
3749 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
3750 a8083063 Iustin Pop
    """Return cluster config.
3751 a8083063 Iustin Pop

3752 a8083063 Iustin Pop
    """
3753 469f88e1 Iustin Pop
    cluster = self.cfg.GetClusterInfo()
3754 17463d22 René Nussbaumer
    os_hvp = {}
3755 17463d22 René Nussbaumer
3756 17463d22 René Nussbaumer
    # Filter just for enabled hypervisors
3757 17463d22 René Nussbaumer
    for os_name, hv_dict in cluster.os_hvp.items():
3758 17463d22 René Nussbaumer
      os_hvp[os_name] = {}
3759 17463d22 René Nussbaumer
      for hv_name, hv_params in hv_dict.items():
3760 17463d22 René Nussbaumer
        if hv_name in cluster.enabled_hypervisors:
3761 17463d22 René Nussbaumer
          os_hvp[os_name][hv_name] = hv_params
3762 17463d22 René Nussbaumer
3763 a8083063 Iustin Pop
    result = {
3764 a8083063 Iustin Pop
      "software_version": constants.RELEASE_VERSION,
3765 a8083063 Iustin Pop
      "protocol_version": constants.PROTOCOL_VERSION,
3766 a8083063 Iustin Pop
      "config_version": constants.CONFIG_VERSION,
3767 d1a7d66f Guido Trotter
      "os_api_version": max(constants.OS_API_VERSIONS),
3768 a8083063 Iustin Pop
      "export_version": constants.EXPORT_VERSION,
3769 a8083063 Iustin Pop
      "architecture": (platform.architecture()[0], platform.machine()),
3770 469f88e1 Iustin Pop
      "name": cluster.cluster_name,
3771 469f88e1 Iustin Pop
      "master": cluster.master_node,
3772 066f465d Guido Trotter
      "default_hypervisor": cluster.enabled_hypervisors[0],
3773 469f88e1 Iustin Pop
      "enabled_hypervisors": cluster.enabled_hypervisors,
3774 b8810fec Michael Hanselmann
      "hvparams": dict([(hypervisor_name, cluster.hvparams[hypervisor_name])
3775 7c4d6c7b Michael Hanselmann
                        for hypervisor_name in cluster.enabled_hypervisors]),
3776 17463d22 René Nussbaumer
      "os_hvp": os_hvp,
3777 469f88e1 Iustin Pop
      "beparams": cluster.beparams,
3778 1094acda Guido Trotter
      "nicparams": cluster.nicparams,
3779 4b7735f9 Iustin Pop
      "candidate_pool_size": cluster.candidate_pool_size,
3780 7a56b411 Guido Trotter
      "master_netdev": cluster.master_netdev,
3781 7a56b411 Guido Trotter
      "volume_group_name": cluster.volume_group_name,
3782 7a56b411 Guido Trotter
      "file_storage_dir": cluster.file_storage_dir,
3783 3953242f Iustin Pop
      "maintain_node_health": cluster.maintain_node_health,
3784 90f72445 Iustin Pop
      "ctime": cluster.ctime,
3785 90f72445 Iustin Pop
      "mtime": cluster.mtime,
3786 259578eb Iustin Pop
      "uuid": cluster.uuid,
3787 c118d1f4 Michael Hanselmann
      "tags": list(cluster.GetTags()),
3788 1338f2b4 Balazs Lecz
      "uid_pool": cluster.uid_pool,
3789 a8083063 Iustin Pop
      }
3790 a8083063 Iustin Pop
3791 a8083063 Iustin Pop
    return result
3792 a8083063 Iustin Pop
3793 a8083063 Iustin Pop
3794 ae5849b5 Michael Hanselmann
class LUQueryConfigValues(NoHooksLU):
3795 ae5849b5 Michael Hanselmann
  """Return configuration values.
3796 a8083063 Iustin Pop

3797 a8083063 Iustin Pop
  """
3798 a8083063 Iustin Pop
  _OP_REQP = []
3799 642339cf Guido Trotter
  REQ_BGL = False
3800 a2d2e1a7 Iustin Pop
  _FIELDS_DYNAMIC = utils.FieldSet()
3801 05e50653 Michael Hanselmann
  _FIELDS_STATIC = utils.FieldSet("cluster_name", "master_node", "drain_flag",
3802 05e50653 Michael Hanselmann
                                  "watcher_pause")
3803 642339cf Guido Trotter
3804 642339cf Guido Trotter
  def ExpandNames(self):
3805 642339cf Guido Trotter
    self.needed_locks = {}
3806 a8083063 Iustin Pop
3807 31bf511f Iustin Pop
    _CheckOutputFields(static=self._FIELDS_STATIC,
3808 31bf511f Iustin Pop
                       dynamic=self._FIELDS_DYNAMIC,
3809 ae5849b5 Michael Hanselmann
                       selected=self.op.output_fields)
3810 ae5849b5 Michael Hanselmann
3811 a8083063 Iustin Pop
  def CheckPrereq(self):
3812 a8083063 Iustin Pop
    """No prerequisites.
3813 a8083063 Iustin Pop

3814 a8083063 Iustin Pop
    """
3815 a8083063 Iustin Pop
    pass
3816 a8083063 Iustin Pop
3817 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
3818 a8083063 Iustin Pop
    """Dump a representation of the cluster config to the standard output.
3819 a8083063 Iustin Pop

3820 a8083063 Iustin Pop
    """
3821 ae5849b5 Michael Hanselmann
    values = []
3822 ae5849b5 Michael Hanselmann
    for field in self.op.output_fields:
3823 ae5849b5 Michael Hanselmann
      if field == "cluster_name":
3824 3ccafd0e Iustin Pop
        entry = self.cfg.GetClusterName()
3825 ae5849b5 Michael Hanselmann
      elif field == "master_node":
3826 3ccafd0e Iustin Pop
        entry = self.cfg.GetMasterNode()
3827 3ccafd0e Iustin Pop
      elif field == "drain_flag":
3828 3ccafd0e Iustin Pop
        entry = os.path.exists(constants.JOB_QUEUE_DRAIN_FILE)
3829 05e50653 Michael Hanselmann
      elif field == "watcher_pause":
3830 cac599f1 Michael Hanselmann
        entry = utils.ReadWatcherPauseFile(constants.WATCHER_PAUSEFILE)
3831 ae5849b5 Michael Hanselmann
      else:
3832 ae5849b5 Michael Hanselmann
        raise errors.ParameterError(field)
3833 3ccafd0e Iustin Pop
      values.append(entry)
3834 ae5849b5 Michael Hanselmann
    return values
3835 a8083063 Iustin Pop
3836 a8083063 Iustin Pop
3837 a8083063 Iustin Pop
class LUActivateInstanceDisks(NoHooksLU):
3838 a8083063 Iustin Pop
  """Bring up an instance's disks.
3839 a8083063 Iustin Pop

3840 a8083063 Iustin Pop
  """
3841 a8083063 Iustin Pop
  _OP_REQP = ["instance_name"]
3842 f22a8ba3 Guido Trotter
  REQ_BGL = False
3843 f22a8ba3 Guido Trotter
3844 f22a8ba3 Guido Trotter
  def ExpandNames(self):
3845 f22a8ba3 Guido Trotter
    self._ExpandAndLockInstance()
3846 f22a8ba3 Guido Trotter
    self.needed_locks[locking.LEVEL_NODE] = []
3847 f22a8ba3 Guido Trotter
    self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
3848 f22a8ba3 Guido Trotter
3849 f22a8ba3 Guido Trotter
  def DeclareLocks(self, level):
3850 f22a8ba3 Guido Trotter
    if level == locking.LEVEL_NODE:
3851 f22a8ba3 Guido Trotter
      self._LockInstancesNodes()
3852 a8083063 Iustin Pop
3853 a8083063 Iustin Pop
  def CheckPrereq(self):
3854 a8083063 Iustin Pop
    """Check prerequisites.
3855 a8083063 Iustin Pop

3856 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
3857 a8083063 Iustin Pop

3858 a8083063 Iustin Pop
    """
3859 f22a8ba3 Guido Trotter
    self.instance = self.cfg.GetInstanceInfo(self.op.instance_name)
3860 f22a8ba3 Guido Trotter
    assert self.instance is not None, \
3861 f22a8ba3 Guido Trotter
      "Cannot retrieve locked instance %s" % self.op.instance_name
3862 43017d26 Iustin Pop
    _CheckNodeOnline(self, self.instance.primary_node)
3863 b4ec07f8 Iustin Pop
    if not hasattr(self.op, "ignore_size"):
3864 b4ec07f8 Iustin Pop
      self.op.ignore_size = False
3865 a8083063 Iustin Pop
3866 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
3867 a8083063 Iustin Pop
    """Activate the disks.
3868 a8083063 Iustin Pop

3869 a8083063 Iustin Pop
    """
3870 b4ec07f8 Iustin Pop
    disks_ok, disks_info = \
3871 b4ec07f8 Iustin Pop
              _AssembleInstanceDisks(self, self.instance,
3872 b4ec07f8 Iustin Pop
                                     ignore_size=self.op.ignore_size)
3873 a8083063 Iustin Pop
    if not disks_ok:
3874 3ecf6786 Iustin Pop
      raise errors.OpExecError("Cannot activate block devices")
3875 a8083063 Iustin Pop
3876 a8083063 Iustin Pop
    return disks_info
3877 a8083063 Iustin Pop
3878 a8083063 Iustin Pop
3879 ef628379 Guido Trotter
def _AssembleInstanceDisks(lu, instance, disks=None, ignore_secondaries=False,
3880 e3443b36 Iustin Pop
                           ignore_size=False):
3881 a8083063 Iustin Pop
  """Prepare the block devices for an instance.
3882 a8083063 Iustin Pop

3883 a8083063 Iustin Pop
  This sets up the block devices on all nodes.
3884 a8083063 Iustin Pop

3885 e4376078 Iustin Pop
  @type lu: L{LogicalUnit}
3886 e4376078 Iustin Pop
  @param lu: the logical unit on whose behalf we execute
3887 e4376078 Iustin Pop
  @type instance: L{objects.Instance}
3888 e4376078 Iustin Pop
  @param instance: the instance for whose disks we assemble
3889 ef628379 Guido Trotter
  @type disks: list of L{objects.Disk} or None
3890 ef628379 Guido Trotter
  @param disks: which disks to assemble (or all, if None)
3891 e4376078 Iustin Pop
  @type ignore_secondaries: boolean
3892 e4376078 Iustin Pop
  @param ignore_secondaries: if true, errors on secondary nodes
3893 e4376078 Iustin Pop
      won't result in an error return from the function
3894 e3443b36 Iustin Pop
  @type ignore_size: boolean
3895 e3443b36 Iustin Pop
  @param ignore_size: if true, the current known size of the disk
3896 e3443b36 Iustin Pop
      will not be used during the disk activation, useful for cases
3897 e3443b36 Iustin Pop
      when the size is wrong
3898 e4376078 Iustin Pop
  @return: False if the operation failed, otherwise a list of
3899 e4376078 Iustin Pop
      (host, instance_visible_name, node_visible_name)
3900 e4376078 Iustin Pop
      with the mapping from node devices to instance devices
3901 a8083063 Iustin Pop

3902 a8083063 Iustin Pop
  """
3903 a8083063 Iustin Pop
  device_info = []
3904 a8083063 Iustin Pop
  disks_ok = True
3905 fdbd668d Iustin Pop
  iname = instance.name
3906 ef628379 Guido Trotter
  disks = _ExpandCheckDisks(instance, disks)
3907 ef628379 Guido Trotter
3908 fdbd668d Iustin Pop
  # With the two passes mechanism we try to reduce the window of
3909 fdbd668d Iustin Pop
  # opportunity for the race condition of switching DRBD to primary
3910 fdbd668d Iustin Pop
  # before handshaking occured, but we do not eliminate it
3911 fdbd668d Iustin Pop
3912 fdbd668d Iustin Pop
  # The proper fix would be to wait (with some limits) until the
3913 fdbd668d Iustin Pop
  # connection has been made and drbd transitions from WFConnection
3914 fdbd668d Iustin Pop
  # into any other network-connected state (Connected, SyncTarget,
3915 fdbd668d Iustin Pop
  # SyncSource, etc.)
3916 fdbd668d Iustin Pop
3917 fdbd668d Iustin Pop
  # 1st pass, assemble on all nodes in secondary mode
3918 ef628379 Guido Trotter
  for inst_disk in disks:
3919 a8083063 Iustin Pop
    for node, node_disk in inst_disk.ComputeNodeTree(instance.primary_node):
3920 e3443b36 Iustin Pop
      if ignore_size:
3921 e3443b36 Iustin Pop
        node_disk = node_disk.Copy()
3922 e3443b36 Iustin Pop
        node_disk.UnsetSize()
3923 b9bddb6b Iustin Pop
      lu.cfg.SetDiskID(node_disk, node)
3924 72737a7f Iustin Pop
      result = lu.rpc.call_blockdev_assemble(node, node_disk, iname, False)
3925 4c4e4e1e Iustin Pop
      msg = result.fail_msg
3926 53c14ef1 Iustin Pop
      if msg:
3927 86d9d3bb Iustin Pop
        lu.proc.LogWarning("Could not prepare block device %s on node %s"
3928 53c14ef1 Iustin Pop
                           " (is_primary=False, pass=1): %s",
3929 53c14ef1 Iustin Pop
                           inst_disk.iv_name, node, msg)
3930 fdbd668d Iustin Pop
        if not ignore_secondaries:
3931 a8083063 Iustin Pop
          disks_ok = False
3932 fdbd668d Iustin Pop
3933 fdbd668d Iustin Pop
  # FIXME: race condition on drbd migration to primary
3934 fdbd668d Iustin Pop
3935 fdbd668d Iustin Pop
  # 2nd pass, do only the primary node
3936 ef628379 Guido Trotter
  for inst_disk in disks:
3937 d52ea991 Michael Hanselmann
    dev_path = None
3938 d52ea991 Michael Hanselmann
3939 fdbd668d Iustin Pop
    for node, node_disk in inst_disk.ComputeNodeTree(instance.primary_node):
3940 fdbd668d Iustin Pop
      if node != instance.primary_node:
3941 fdbd668d Iustin Pop
        continue
3942 e3443b36 Iustin Pop
      if ignore_size:
3943 e3443b36 Iustin Pop
        node_disk = node_disk.Copy()
3944 e3443b36 Iustin Pop
        node_disk.UnsetSize()
3945 b9bddb6b Iustin Pop
      lu.cfg.SetDiskID(node_disk, node)
3946 72737a7f Iustin Pop
      result = lu.rpc.call_blockdev_assemble(node, node_disk, iname, True)
3947 4c4e4e1e Iustin Pop
      msg = result.fail_msg
3948 53c14ef1 Iustin Pop
      if msg:
3949 86d9d3bb Iustin Pop
        lu.proc.LogWarning("Could not prepare block device %s on node %s"
3950 53c14ef1 Iustin Pop
                           " (is_primary=True, pass=2): %s",
3951 53c14ef1 Iustin Pop
                           inst_disk.iv_name, node, msg)
3952 fdbd668d Iustin Pop
        disks_ok = False
3953 d52ea991 Michael Hanselmann
      else:
3954 d52ea991 Michael Hanselmann
        dev_path = result.payload
3955 d52ea991 Michael Hanselmann
3956 d52ea991 Michael Hanselmann
    device_info.append((instance.primary_node, inst_disk.iv_name, dev_path))
3957 a8083063 Iustin Pop
3958 b352ab5b Iustin Pop
  # leave the disks configured for the primary node
3959 b352ab5b Iustin Pop
  # this is a workaround that would be fixed better by
3960 b352ab5b Iustin Pop
  # improving the logical/physical id handling
3961 ef628379 Guido Trotter
  for disk in disks:
3962 b9bddb6b Iustin Pop
    lu.cfg.SetDiskID(disk, instance.primary_node)
3963 b352ab5b Iustin Pop
3964 a8083063 Iustin Pop
  return disks_ok, device_info
3965 a8083063 Iustin Pop
3966 a8083063 Iustin Pop
3967 b9bddb6b Iustin Pop
def _StartInstanceDisks(lu, instance, force):
3968 3ecf6786 Iustin Pop
  """Start the disks of an instance.
3969 3ecf6786 Iustin Pop

3970 3ecf6786 Iustin Pop
  """
3971 7c4d6c7b Michael Hanselmann
  disks_ok, _ = _AssembleInstanceDisks(lu, instance,
3972 fe7b0351 Michael Hanselmann
                                           ignore_secondaries=force)
3973 fe7b0351 Michael Hanselmann
  if not disks_ok:
3974 b9bddb6b Iustin Pop
    _ShutdownInstanceDisks(lu, instance)
3975 fe7b0351 Michael Hanselmann
    if force is not None and not force:
3976 86d9d3bb Iustin Pop
      lu.proc.LogWarning("", hint="If the message above refers to a"
3977 86d9d3bb Iustin Pop
                         " secondary node,"
3978 86d9d3bb Iustin Pop
                         " you can retry the operation using '--force'.")
3979 3ecf6786 Iustin Pop
    raise errors.OpExecError("Disk consistency error")
3980 fe7b0351 Michael Hanselmann
3981 fe7b0351 Michael Hanselmann
3982 a8083063 Iustin Pop
class LUDeactivateInstanceDisks(NoHooksLU):
3983 a8083063 Iustin Pop
  """Shutdown an instance's disks.
3984 a8083063 Iustin Pop

3985 a8083063 Iustin Pop
  """
3986 a8083063 Iustin Pop
  _OP_REQP = ["instance_name"]
3987 f22a8ba3 Guido Trotter
  REQ_BGL = False
3988 f22a8ba3 Guido Trotter
3989 f22a8ba3 Guido Trotter
  def ExpandNames(self):
3990 f22a8ba3 Guido Trotter
    self._ExpandAndLockInstance()
3991 f22a8ba3 Guido Trotter
    self.needed_locks[locking.LEVEL_NODE] = []
3992 f22a8ba3 Guido Trotter
    self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
3993 f22a8ba3 Guido Trotter
3994 f22a8ba3 Guido Trotter
  def DeclareLocks(self, level):
3995 f22a8ba3 Guido Trotter
    if level == locking.LEVEL_NODE:
3996 f22a8ba3 Guido Trotter
      self._LockInstancesNodes()
3997 a8083063 Iustin Pop
3998 a8083063 Iustin Pop
  def CheckPrereq(self):
3999 a8083063 Iustin Pop
    """Check prerequisites.
4000 a8083063 Iustin Pop

4001 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
4002 a8083063 Iustin Pop

4003 a8083063 Iustin Pop
    """
4004 f22a8ba3 Guido Trotter
    self.instance = self.cfg.GetInstanceInfo(self.op.instance_name)
4005 f22a8ba3 Guido Trotter
    assert self.instance is not None, \
4006 f22a8ba3 Guido Trotter
      "Cannot retrieve locked instance %s" % self.op.instance_name
4007 a8083063 Iustin Pop
4008 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
4009 a8083063 Iustin Pop
    """Deactivate the disks
4010 a8083063 Iustin Pop

4011 a8083063 Iustin Pop
    """
4012 a8083063 Iustin Pop
    instance = self.instance
4013 b9bddb6b Iustin Pop
    _SafeShutdownInstanceDisks(self, instance)
4014 a8083063 Iustin Pop
4015 a8083063 Iustin Pop
4016 ef628379 Guido Trotter
def _SafeShutdownInstanceDisks(lu, instance, disks=None):
4017 155d6c75 Guido Trotter
  """Shutdown block devices of an instance.
4018 155d6c75 Guido Trotter

4019 155d6c75 Guido Trotter
  This function checks if an instance is running, before calling
4020 155d6c75 Guido Trotter
  _ShutdownInstanceDisks.
4021 155d6c75 Guido Trotter

4022 155d6c75 Guido Trotter
  """
4023 31624382 Iustin Pop
  _CheckInstanceDown(lu, instance, "cannot shutdown disks")
4024 ef628379 Guido Trotter
  _ShutdownInstanceDisks(lu, instance, disks=disks)
4025 ef628379 Guido Trotter
4026 ef628379 Guido Trotter
4027 ef628379 Guido Trotter
def _ExpandCheckDisks(instance, disks):
4028 ef628379 Guido Trotter
  """Return the instance disks selected by the disks list
4029 a8083063 Iustin Pop

4030 ef628379 Guido Trotter
  @type disks: list of L{objects.Disk} or None
4031 ef628379 Guido Trotter
  @param disks: selected disks
4032 ef628379 Guido Trotter
  @rtype: list of L{objects.Disk}
4033 ef628379 Guido Trotter
  @return: selected instance disks to act on
4034 a8083063 Iustin Pop

4035 ef628379 Guido Trotter
  """
4036 ef628379 Guido Trotter
  if disks is None:
4037 ef628379 Guido Trotter
    return instance.disks
4038 ef628379 Guido Trotter
  else:
4039 ef628379 Guido Trotter
    if not set(disks).issubset(instance.disks):
4040 ef628379 Guido Trotter
      raise errors.ProgrammerError("Can only act on disks belonging to the"
4041 ef628379 Guido Trotter
                                   " target instance")
4042 ef628379 Guido Trotter
    return disks
4043 ef628379 Guido Trotter
4044 ef628379 Guido Trotter
4045 ef628379 Guido Trotter
def _ShutdownInstanceDisks(lu, instance, disks=None, ignore_primary=False):
4046 a8083063 Iustin Pop
  """Shutdown block devices of an instance.
4047 a8083063 Iustin Pop

4048 a8083063 Iustin Pop
  This does the shutdown on all nodes of the instance.
4049 a8083063 Iustin Pop

4050 a8083063 Iustin Pop
  If the ignore_primary is false, errors on the primary node are
4051 a8083063 Iustin Pop
  ignored.
4052 a8083063 Iustin Pop

4053 a8083063 Iustin Pop
  """
4054 cacfd1fd Iustin Pop
  all_result = True
4055 ef628379 Guido Trotter
  disks = _ExpandCheckDisks(instance, disks)
4056 ef628379 Guido Trotter
4057 ef628379 Guido Trotter
  for disk in disks:
4058 a8083063 Iustin Pop
    for node, top_disk in disk.ComputeNodeTree(instance.primary_node):
4059 b9bddb6b Iustin Pop
      lu.cfg.SetDiskID(top_disk, node)
4060 781de953 Iustin Pop
      result = lu.rpc.call_blockdev_shutdown(node, top_disk)
4061 4c4e4e1e Iustin Pop
      msg = result.fail_msg
4062 cacfd1fd Iustin Pop
      if msg:
4063 cacfd1fd Iustin Pop
        lu.LogWarning("Could not shutdown block device %s on node %s: %s",
4064 cacfd1fd Iustin Pop
                      disk.iv_name, node, msg)
4065 a8083063 Iustin Pop
        if not ignore_primary or node != instance.primary_node:
4066 cacfd1fd Iustin Pop
          all_result = False
4067 cacfd1fd Iustin Pop
  return all_result
4068 a8083063 Iustin Pop
4069 a8083063 Iustin Pop
4070 9ca87a96 Iustin Pop
def _CheckNodeFreeMemory(lu, node, reason, requested, hypervisor_name):
4071 d4f16fd9 Iustin Pop
  """Checks if a node has enough free memory.
4072 d4f16fd9 Iustin Pop

4073 d4f16fd9 Iustin Pop
  This function check if a given node has the needed amount of free
4074 d4f16fd9 Iustin Pop
  memory. In case the node has less memory or we cannot get the
4075 d4f16fd9 Iustin Pop
  information from the node, this function raise an OpPrereqError
4076 d4f16fd9 Iustin Pop
  exception.
4077 d4f16fd9 Iustin Pop

4078 b9bddb6b Iustin Pop
  @type lu: C{LogicalUnit}
4079 b9bddb6b Iustin Pop
  @param lu: a logical unit from which we get configuration data
4080 e69d05fd Iustin Pop
  @type node: C{str}
4081 e69d05fd Iustin Pop
  @param node: the node to check
4082 e69d05fd Iustin Pop
  @type reason: C{str}
4083 e69d05fd Iustin Pop
  @param reason: string to use in the error message
4084 e69d05fd Iustin Pop
  @type requested: C{int}
4085 e69d05fd Iustin Pop
  @param requested: the amount of memory in MiB to check for
4086 9ca87a96 Iustin Pop
  @type hypervisor_name: C{str}
4087 9ca87a96 Iustin Pop
  @param hypervisor_name: the hypervisor to ask for memory stats
4088 e69d05fd Iustin Pop
  @raise errors.OpPrereqError: if the node doesn't have enough memory, or
4089 e69d05fd Iustin Pop
      we cannot check the node
4090 d4f16fd9 Iustin Pop

4091 d4f16fd9 Iustin Pop
  """
4092 9ca87a96 Iustin Pop
  nodeinfo = lu.rpc.call_node_info([node], lu.cfg.GetVGName(), hypervisor_name)
4093 045dd6d9 Iustin Pop
  nodeinfo[node].Raise("Can't get data from node %s" % node,
4094 045dd6d9 Iustin Pop
                       prereq=True, ecode=errors.ECODE_ENVIRON)
4095 070e998b Iustin Pop
  free_mem = nodeinfo[node].payload.get('memory_free', None)
4096 d4f16fd9 Iustin Pop
  if not isinstance(free_mem, int):
4097 d4f16fd9 Iustin Pop
    raise errors.OpPrereqError("Can't compute free memory on node %s, result"
4098 5c983ee5 Iustin Pop
                               " was '%s'" % (node, free_mem),
4099 5c983ee5 Iustin Pop
                               errors.ECODE_ENVIRON)
4100 d4f16fd9 Iustin Pop
  if requested > free_mem:
4101 d4f16fd9 Iustin Pop
    raise errors.OpPrereqError("Not enough memory on node %s for %s:"
4102 070e998b Iustin Pop
                               " needed %s MiB, available %s MiB" %
4103 5c983ee5 Iustin Pop
                               (node, reason, requested, free_mem),
4104 5c983ee5 Iustin Pop
                               errors.ECODE_NORES)
4105 d4f16fd9 Iustin Pop
4106 d4f16fd9 Iustin Pop
4107 701384a9 Iustin Pop
def _CheckNodesFreeDisk(lu, nodenames, requested):
4108 701384a9 Iustin Pop
  """Checks if nodes have enough free disk space in the default VG.
4109 701384a9 Iustin Pop

4110 701384a9 Iustin Pop
  This function check if all given nodes have the needed amount of
4111 701384a9 Iustin Pop
  free disk. In case any node has less disk or we cannot get the
4112 701384a9 Iustin Pop
  information from the node, this function raise an OpPrereqError
4113 701384a9 Iustin Pop
  exception.
4114 701384a9 Iustin Pop

4115 701384a9 Iustin Pop
  @type lu: C{LogicalUnit}
4116 701384a9 Iustin Pop
  @param lu: a logical unit from which we get configuration data
4117 701384a9 Iustin Pop
  @type nodenames: C{list}
4118 3a488770 Iustin Pop
  @param nodenames: the list of node names to check
4119 701384a9 Iustin Pop
  @type requested: C{int}
4120 701384a9 Iustin Pop
  @param requested: the amount of disk in MiB to check for
4121 701384a9 Iustin Pop
  @raise errors.OpPrereqError: if the node doesn't have enough disk, or
4122 701384a9 Iustin Pop
      we cannot check the node
4123 701384a9 Iustin Pop

4124 701384a9 Iustin Pop
  """
4125 701384a9 Iustin Pop
  nodeinfo = lu.rpc.call_node_info(nodenames, lu.cfg.GetVGName(),
4126 701384a9 Iustin Pop
                                   lu.cfg.GetHypervisorType())
4127 701384a9 Iustin Pop
  for node in nodenames:
4128 701384a9 Iustin Pop
    info = nodeinfo[node]
4129 701384a9 Iustin Pop
    info.Raise("Cannot get current information from node %s" % node,
4130 701384a9 Iustin Pop
               prereq=True, ecode=errors.ECODE_ENVIRON)
4131 701384a9 Iustin Pop
    vg_free = info.payload.get("vg_free", None)
4132 701384a9 Iustin Pop
    if not isinstance(vg_free, int):
4133 701384a9 Iustin Pop
      raise errors.OpPrereqError("Can't compute free disk space on node %s,"
4134 701384a9 Iustin Pop
                                 " result was '%s'" % (node, vg_free),
4135 701384a9 Iustin Pop
                                 errors.ECODE_ENVIRON)
4136 701384a9 Iustin Pop
    if requested > vg_free:
4137 701384a9 Iustin Pop
      raise errors.OpPrereqError("Not enough disk space on target node %s:"
4138 701384a9 Iustin Pop
                                 " required %d MiB, available %d MiB" %
4139 701384a9 Iustin Pop
                                 (node, requested, vg_free),
4140 701384a9 Iustin Pop
                                 errors.ECODE_NORES)
4141 701384a9 Iustin Pop
4142 701384a9 Iustin Pop
4143 a8083063 Iustin Pop
class LUStartupInstance(LogicalUnit):
4144 a8083063 Iustin Pop
  """Starts an instance.
4145 a8083063 Iustin Pop

4146 a8083063 Iustin Pop
  """
4147 a8083063 Iustin Pop
  HPATH = "instance-start"
4148 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
4149 a8083063 Iustin Pop
  _OP_REQP = ["instance_name", "force"]
4150 e873317a Guido Trotter
  REQ_BGL = False
4151 e873317a Guido Trotter
4152 e873317a Guido Trotter
  def ExpandNames(self):
4153 e873317a Guido Trotter
    self._ExpandAndLockInstance()
4154 a8083063 Iustin Pop
4155 a8083063 Iustin Pop
  def BuildHooksEnv(self):
4156 a8083063 Iustin Pop
    """Build hooks env.
4157 a8083063 Iustin Pop

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

4160 a8083063 Iustin Pop
    """
4161 a8083063 Iustin Pop
    env = {
4162 a8083063 Iustin Pop
      "FORCE": self.op.force,
4163 a8083063 Iustin Pop
      }
4164 338e51e8 Iustin Pop
    env.update(_BuildInstanceHookEnvByObject(self, self.instance))
4165 6b12959c Iustin Pop
    nl = [self.cfg.GetMasterNode()] + list(self.instance.all_nodes)
4166 a8083063 Iustin Pop
    return env, nl, nl
4167 a8083063 Iustin Pop
4168 a8083063 Iustin Pop
  def CheckPrereq(self):
4169 a8083063 Iustin Pop
    """Check prerequisites.
4170 a8083063 Iustin Pop

4171 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
4172 a8083063 Iustin Pop

4173 a8083063 Iustin Pop
    """
4174 e873317a Guido Trotter
    self.instance = instance = self.cfg.GetInstanceInfo(self.op.instance_name)
4175 e873317a Guido Trotter
    assert self.instance is not None, \
4176 e873317a Guido Trotter
      "Cannot retrieve locked instance %s" % self.op.instance_name
4177 a8083063 Iustin Pop
4178 d04aaa2f Iustin Pop
    # extra beparams
4179 d04aaa2f Iustin Pop
    self.beparams = getattr(self.op, "beparams", {})
4180 d04aaa2f Iustin Pop
    if self.beparams:
4181 d04aaa2f Iustin Pop
      if not isinstance(self.beparams, dict):
4182 d04aaa2f Iustin Pop
        raise errors.OpPrereqError("Invalid beparams passed: %s, expected"
4183 5c983ee5 Iustin Pop
                                   " dict" % (type(self.beparams), ),
4184 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
4185 d04aaa2f Iustin Pop
      # fill the beparams dict
4186 d04aaa2f Iustin Pop
      utils.ForceDictType(self.beparams, constants.BES_PARAMETER_TYPES)
4187 d04aaa2f Iustin Pop
      self.op.beparams = self.beparams
4188 d04aaa2f Iustin Pop
4189 d04aaa2f Iustin Pop
    # extra hvparams
4190 d04aaa2f Iustin Pop
    self.hvparams = getattr(self.op, "hvparams", {})
4191 d04aaa2f Iustin Pop
    if self.hvparams:
4192 d04aaa2f Iustin Pop
      if not isinstance(self.hvparams, dict):
4193 d04aaa2f Iustin Pop
        raise errors.OpPrereqError("Invalid hvparams passed: %s, expected"
4194 5c983ee5 Iustin Pop
                                   " dict" % (type(self.hvparams), ),
4195 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
4196 d04aaa2f Iustin Pop
4197 d04aaa2f Iustin Pop
      # check hypervisor parameter syntax (locally)
4198 d04aaa2f Iustin Pop
      cluster = self.cfg.GetClusterInfo()
4199 d04aaa2f Iustin Pop
      utils.ForceDictType(self.hvparams, constants.HVS_PARAMETER_TYPES)
4200 abe609b2 Guido Trotter
      filled_hvp = objects.FillDict(cluster.hvparams[instance.hypervisor],
4201 d04aaa2f Iustin Pop
                                    instance.hvparams)
4202 d04aaa2f Iustin Pop
      filled_hvp.update(self.hvparams)
4203 d04aaa2f Iustin Pop
      hv_type = hypervisor.GetHypervisor(instance.hypervisor)
4204 d04aaa2f Iustin Pop
      hv_type.CheckParameterSyntax(filled_hvp)
4205 d04aaa2f Iustin Pop
      _CheckHVParams(self, instance.all_nodes, instance.hypervisor, filled_hvp)
4206 d04aaa2f Iustin Pop
      self.op.hvparams = self.hvparams
4207 d04aaa2f Iustin Pop
4208 7527a8a4 Iustin Pop
    _CheckNodeOnline(self, instance.primary_node)
4209 7527a8a4 Iustin Pop
4210 338e51e8 Iustin Pop
    bep = self.cfg.GetClusterInfo().FillBE(instance)
4211 5bbd3f7f Michael Hanselmann
    # check bridges existence
4212 b9bddb6b Iustin Pop
    _CheckInstanceBridgesExist(self, instance)
4213 a8083063 Iustin Pop
4214 f1926756 Guido Trotter
    remote_info = self.rpc.call_instance_info(instance.primary_node,
4215 f1926756 Guido Trotter
                                              instance.name,
4216 f1926756 Guido Trotter
                                              instance.hypervisor)
4217 4c4e4e1e Iustin Pop
    remote_info.Raise("Error checking node %s" % instance.primary_node,
4218 045dd6d9 Iustin Pop
                      prereq=True, ecode=errors.ECODE_ENVIRON)
4219 7ad1af4a Iustin Pop
    if not remote_info.payload: # not running already
4220 f1926756 Guido Trotter
      _CheckNodeFreeMemory(self, instance.primary_node,
4221 f1926756 Guido Trotter
                           "starting instance %s" % instance.name,
4222 f1926756 Guido Trotter
                           bep[constants.BE_MEMORY], instance.hypervisor)
4223 d4f16fd9 Iustin Pop
4224 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
4225 a8083063 Iustin Pop
    """Start the instance.
4226 a8083063 Iustin Pop

4227 a8083063 Iustin Pop
    """
4228 a8083063 Iustin Pop
    instance = self.instance
4229 a8083063 Iustin Pop
    force = self.op.force
4230 a8083063 Iustin Pop
4231 fe482621 Iustin Pop
    self.cfg.MarkInstanceUp(instance.name)
4232 fe482621 Iustin Pop
4233 a8083063 Iustin Pop
    node_current = instance.primary_node
4234 a8083063 Iustin Pop
4235 b9bddb6b Iustin Pop
    _StartInstanceDisks(self, instance, force)
4236 a8083063 Iustin Pop
4237 d04aaa2f Iustin Pop
    result = self.rpc.call_instance_start(node_current, instance,
4238 d04aaa2f Iustin Pop
                                          self.hvparams, self.beparams)
4239 4c4e4e1e Iustin Pop
    msg = result.fail_msg
4240 dd279568 Iustin Pop
    if msg:
4241 b9bddb6b Iustin Pop
      _ShutdownInstanceDisks(self, instance)
4242 dd279568 Iustin Pop
      raise errors.OpExecError("Could not start instance: %s" % msg)
4243 a8083063 Iustin Pop
4244 a8083063 Iustin Pop
4245 bf6929a2 Alexander Schreiber
class LURebootInstance(LogicalUnit):
4246 bf6929a2 Alexander Schreiber
  """Reboot an instance.
4247 bf6929a2 Alexander Schreiber

4248 bf6929a2 Alexander Schreiber
  """
4249 bf6929a2 Alexander Schreiber
  HPATH = "instance-reboot"
4250 bf6929a2 Alexander Schreiber
  HTYPE = constants.HTYPE_INSTANCE
4251 bf6929a2 Alexander Schreiber
  _OP_REQP = ["instance_name", "ignore_secondaries", "reboot_type"]
4252 e873317a Guido Trotter
  REQ_BGL = False
4253 e873317a Guido Trotter
4254 17c3f802 Guido Trotter
  def CheckArguments(self):
4255 17c3f802 Guido Trotter
    """Check the arguments.
4256 17c3f802 Guido Trotter

4257 17c3f802 Guido Trotter
    """
4258 17c3f802 Guido Trotter
    self.shutdown_timeout = getattr(self.op, "shutdown_timeout",
4259 17c3f802 Guido Trotter
                                    constants.DEFAULT_SHUTDOWN_TIMEOUT)
4260 17c3f802 Guido Trotter
4261 e873317a Guido Trotter
  def ExpandNames(self):
4262 0fcc5db3 Guido Trotter
    if self.op.reboot_type not in [constants.INSTANCE_REBOOT_SOFT,
4263 0fcc5db3 Guido Trotter
                                   constants.INSTANCE_REBOOT_HARD,
4264 0fcc5db3 Guido Trotter
                                   constants.INSTANCE_REBOOT_FULL]:
4265 0fcc5db3 Guido Trotter
      raise errors.ParameterError("reboot type not in [%s, %s, %s]" %
4266 0fcc5db3 Guido Trotter
                                  (constants.INSTANCE_REBOOT_SOFT,
4267 0fcc5db3 Guido Trotter
                                   constants.INSTANCE_REBOOT_HARD,
4268 0fcc5db3 Guido Trotter
                                   constants.INSTANCE_REBOOT_FULL))
4269 e873317a Guido Trotter
    self._ExpandAndLockInstance()
4270 bf6929a2 Alexander Schreiber
4271 bf6929a2 Alexander Schreiber
  def BuildHooksEnv(self):
4272 bf6929a2 Alexander Schreiber
    """Build hooks env.
4273 bf6929a2 Alexander Schreiber

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

4276 bf6929a2 Alexander Schreiber
    """
4277 bf6929a2 Alexander Schreiber
    env = {
4278 bf6929a2 Alexander Schreiber
      "IGNORE_SECONDARIES": self.op.ignore_secondaries,
4279 2c2690c9 Iustin Pop
      "REBOOT_TYPE": self.op.reboot_type,
4280 17c3f802 Guido Trotter
      "SHUTDOWN_TIMEOUT": self.shutdown_timeout,
4281 bf6929a2 Alexander Schreiber
      }
4282 338e51e8 Iustin Pop
    env.update(_BuildInstanceHookEnvByObject(self, self.instance))
4283 6b12959c Iustin Pop
    nl = [self.cfg.GetMasterNode()] + list(self.instance.all_nodes)
4284 bf6929a2 Alexander Schreiber
    return env, nl, nl
4285 bf6929a2 Alexander Schreiber
4286 bf6929a2 Alexander Schreiber
  def CheckPrereq(self):
4287 bf6929a2 Alexander Schreiber
    """Check prerequisites.
4288 bf6929a2 Alexander Schreiber

4289 bf6929a2 Alexander Schreiber
    This checks that the instance is in the cluster.
4290 bf6929a2 Alexander Schreiber

4291 bf6929a2 Alexander Schreiber
    """
4292 e873317a Guido Trotter
    self.instance = instance = self.cfg.GetInstanceInfo(self.op.instance_name)
4293 e873317a Guido Trotter
    assert self.instance is not None, \
4294 e873317a Guido Trotter
      "Cannot retrieve locked instance %s" % self.op.instance_name
4295 bf6929a2 Alexander Schreiber
4296 7527a8a4 Iustin Pop
    _CheckNodeOnline(self, instance.primary_node)
4297 7527a8a4 Iustin Pop
4298 5bbd3f7f Michael Hanselmann
    # check bridges existence
4299 b9bddb6b Iustin Pop
    _CheckInstanceBridgesExist(self, instance)
4300 bf6929a2 Alexander Schreiber
4301 bf6929a2 Alexander Schreiber
  def Exec(self, feedback_fn):
4302 bf6929a2 Alexander Schreiber
    """Reboot the instance.
4303 bf6929a2 Alexander Schreiber

4304 bf6929a2 Alexander Schreiber
    """
4305 bf6929a2 Alexander Schreiber
    instance = self.instance
4306 bf6929a2 Alexander Schreiber
    ignore_secondaries = self.op.ignore_secondaries
4307 bf6929a2 Alexander Schreiber
    reboot_type = self.op.reboot_type
4308 bf6929a2 Alexander Schreiber
4309 bf6929a2 Alexander Schreiber
    node_current = instance.primary_node
4310 bf6929a2 Alexander Schreiber
4311 bf6929a2 Alexander Schreiber
    if reboot_type in [constants.INSTANCE_REBOOT_SOFT,
4312 bf6929a2 Alexander Schreiber
                       constants.INSTANCE_REBOOT_HARD]:
4313 ae48ac32 Iustin Pop
      for disk in instance.disks:
4314 ae48ac32 Iustin Pop
        self.cfg.SetDiskID(disk, node_current)
4315 781de953 Iustin Pop
      result = self.rpc.call_instance_reboot(node_current, instance,
4316 17c3f802 Guido Trotter
                                             reboot_type,
4317 17c3f802 Guido Trotter
                                             self.shutdown_timeout)
4318 4c4e4e1e Iustin Pop
      result.Raise("Could not reboot instance")
4319 bf6929a2 Alexander Schreiber
    else:
4320 17c3f802 Guido Trotter
      result = self.rpc.call_instance_shutdown(node_current, instance,
4321 17c3f802 Guido Trotter
                                               self.shutdown_timeout)
4322 4c4e4e1e Iustin Pop
      result.Raise("Could not shutdown instance for full reboot")
4323 b9bddb6b Iustin Pop
      _ShutdownInstanceDisks(self, instance)
4324 b9bddb6b Iustin Pop
      _StartInstanceDisks(self, instance, ignore_secondaries)
4325 0eca8e0c Iustin Pop
      result = self.rpc.call_instance_start(node_current, instance, None, None)
4326 4c4e4e1e Iustin Pop
      msg = result.fail_msg
4327 dd279568 Iustin Pop
      if msg:
4328 b9bddb6b Iustin Pop
        _ShutdownInstanceDisks(self, instance)
4329 dd279568 Iustin Pop
        raise errors.OpExecError("Could not start instance for"
4330 dd279568 Iustin Pop
                                 " full reboot: %s" % msg)
4331 bf6929a2 Alexander Schreiber
4332 bf6929a2 Alexander Schreiber
    self.cfg.MarkInstanceUp(instance.name)
4333 bf6929a2 Alexander Schreiber
4334 bf6929a2 Alexander Schreiber
4335 a8083063 Iustin Pop
class LUShutdownInstance(LogicalUnit):
4336 a8083063 Iustin Pop
  """Shutdown an instance.
4337 a8083063 Iustin Pop

4338 a8083063 Iustin Pop
  """
4339 a8083063 Iustin Pop
  HPATH = "instance-stop"
4340 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
4341 a8083063 Iustin Pop
  _OP_REQP = ["instance_name"]
4342 e873317a Guido Trotter
  REQ_BGL = False
4343 e873317a Guido Trotter
4344 6263189c Guido Trotter
  def CheckArguments(self):
4345 6263189c Guido Trotter
    """Check the arguments.
4346 6263189c Guido Trotter

4347 6263189c Guido Trotter
    """
4348 6263189c Guido Trotter
    self.timeout = getattr(self.op, "timeout",
4349 6263189c Guido Trotter
                           constants.DEFAULT_SHUTDOWN_TIMEOUT)
4350 6263189c Guido Trotter
4351 e873317a Guido Trotter
  def ExpandNames(self):
4352 e873317a Guido Trotter
    self._ExpandAndLockInstance()
4353 a8083063 Iustin Pop
4354 a8083063 Iustin Pop
  def BuildHooksEnv(self):
4355 a8083063 Iustin Pop
    """Build hooks env.
4356 a8083063 Iustin Pop

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

4359 a8083063 Iustin Pop
    """
4360 338e51e8 Iustin Pop
    env = _BuildInstanceHookEnvByObject(self, self.instance)
4361 6263189c Guido Trotter
    env["TIMEOUT"] = self.timeout
4362 6b12959c Iustin Pop
    nl = [self.cfg.GetMasterNode()] + list(self.instance.all_nodes)
4363 a8083063 Iustin Pop
    return env, nl, nl
4364 a8083063 Iustin Pop
4365 a8083063 Iustin Pop
  def CheckPrereq(self):
4366 a8083063 Iustin Pop
    """Check prerequisites.
4367 a8083063 Iustin Pop

4368 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
4369 a8083063 Iustin Pop

4370 a8083063 Iustin Pop
    """
4371 e873317a Guido Trotter
    self.instance = self.cfg.GetInstanceInfo(self.op.instance_name)
4372 e873317a Guido Trotter
    assert self.instance is not None, \
4373 e873317a Guido Trotter
      "Cannot retrieve locked instance %s" % self.op.instance_name
4374 43017d26 Iustin Pop
    _CheckNodeOnline(self, self.instance.primary_node)
4375 a8083063 Iustin Pop
4376 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
4377 a8083063 Iustin Pop
    """Shutdown the instance.
4378 a8083063 Iustin Pop

4379 a8083063 Iustin Pop
    """
4380 a8083063 Iustin Pop
    instance = self.instance
4381 a8083063 Iustin Pop
    node_current = instance.primary_node
4382 6263189c Guido Trotter
    timeout = self.timeout
4383 fe482621 Iustin Pop
    self.cfg.MarkInstanceDown(instance.name)
4384 6263189c Guido Trotter
    result = self.rpc.call_instance_shutdown(node_current, instance, timeout)
4385 4c4e4e1e Iustin Pop
    msg = result.fail_msg
4386 1fae010f Iustin Pop
    if msg:
4387 1fae010f Iustin Pop
      self.proc.LogWarning("Could not shutdown instance: %s" % msg)
4388 a8083063 Iustin Pop
4389 b9bddb6b Iustin Pop
    _ShutdownInstanceDisks(self, instance)
4390 a8083063 Iustin Pop
4391 a8083063 Iustin Pop
4392 fe7b0351 Michael Hanselmann
class LUReinstallInstance(LogicalUnit):
4393 fe7b0351 Michael Hanselmann
  """Reinstall an instance.
4394 fe7b0351 Michael Hanselmann

4395 fe7b0351 Michael Hanselmann
  """
4396 fe7b0351 Michael Hanselmann
  HPATH = "instance-reinstall"
4397 fe7b0351 Michael Hanselmann
  HTYPE = constants.HTYPE_INSTANCE
4398 fe7b0351 Michael Hanselmann
  _OP_REQP = ["instance_name"]
4399 4e0b4d2d Guido Trotter
  REQ_BGL = False
4400 4e0b4d2d Guido Trotter
4401 4e0b4d2d Guido Trotter
  def ExpandNames(self):
4402 4e0b4d2d Guido Trotter
    self._ExpandAndLockInstance()
4403 fe7b0351 Michael Hanselmann
4404 fe7b0351 Michael Hanselmann
  def BuildHooksEnv(self):
4405 fe7b0351 Michael Hanselmann
    """Build hooks env.
4406 fe7b0351 Michael Hanselmann

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

4409 fe7b0351 Michael Hanselmann
    """
4410 338e51e8 Iustin Pop
    env = _BuildInstanceHookEnvByObject(self, self.instance)
4411 6b12959c Iustin Pop
    nl = [self.cfg.GetMasterNode()] + list(self.instance.all_nodes)
4412 fe7b0351 Michael Hanselmann
    return env, nl, nl
4413 fe7b0351 Michael Hanselmann
4414 fe7b0351 Michael Hanselmann
  def CheckPrereq(self):
4415 fe7b0351 Michael Hanselmann
    """Check prerequisites.
4416 fe7b0351 Michael Hanselmann

4417 fe7b0351 Michael Hanselmann
    This checks that the instance is in the cluster and is not running.
4418 fe7b0351 Michael Hanselmann

4419 fe7b0351 Michael Hanselmann
    """
4420 4e0b4d2d Guido Trotter
    instance = self.cfg.GetInstanceInfo(self.op.instance_name)
4421 4e0b4d2d Guido Trotter
    assert instance is not None, \
4422 4e0b4d2d Guido Trotter
      "Cannot retrieve locked instance %s" % self.op.instance_name
4423 7527a8a4 Iustin Pop
    _CheckNodeOnline(self, instance.primary_node)
4424 4e0b4d2d Guido Trotter
4425 fe7b0351 Michael Hanselmann
    if instance.disk_template == constants.DT_DISKLESS:
4426 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' has no disks" %
4427 5c983ee5 Iustin Pop
                                 self.op.instance_name,
4428 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
4429 31624382 Iustin Pop
    _CheckInstanceDown(self, instance, "cannot reinstall")
4430 d0834de3 Michael Hanselmann
4431 d0834de3 Michael Hanselmann
    self.op.os_type = getattr(self.op, "os_type", None)
4432 f2c05717 Guido Trotter
    self.op.force_variant = getattr(self.op, "force_variant", False)
4433 d0834de3 Michael Hanselmann
    if self.op.os_type is not None:
4434 d0834de3 Michael Hanselmann
      # OS verification
4435 cf26a87a Iustin Pop
      pnode = _ExpandNodeName(self.cfg, instance.primary_node)
4436 231cd901 Iustin Pop
      _CheckNodeHasOS(self, pnode, self.op.os_type, self.op.force_variant)
4437 d0834de3 Michael Hanselmann
4438 fe7b0351 Michael Hanselmann
    self.instance = instance
4439 fe7b0351 Michael Hanselmann
4440 fe7b0351 Michael Hanselmann
  def Exec(self, feedback_fn):
4441 fe7b0351 Michael Hanselmann
    """Reinstall the instance.
4442 fe7b0351 Michael Hanselmann

4443 fe7b0351 Michael Hanselmann
    """
4444 fe7b0351 Michael Hanselmann
    inst = self.instance
4445 fe7b0351 Michael Hanselmann
4446 d0834de3 Michael Hanselmann
    if self.op.os_type is not None:
4447 d0834de3 Michael Hanselmann
      feedback_fn("Changing OS to '%s'..." % self.op.os_type)
4448 d0834de3 Michael Hanselmann
      inst.os = self.op.os_type
4449 a4eae71f Michael Hanselmann
      self.cfg.Update(inst, feedback_fn)
4450 d0834de3 Michael Hanselmann
4451 b9bddb6b Iustin Pop
    _StartInstanceDisks(self, inst, None)
4452 fe7b0351 Michael Hanselmann
    try:
4453 fe7b0351 Michael Hanselmann
      feedback_fn("Running the instance OS create scripts...")
4454 4a0e011f Iustin Pop
      # FIXME: pass debug option from opcode to backend
4455 dd713605 Iustin Pop
      result = self.rpc.call_instance_os_add(inst.primary_node, inst, True,
4456 dd713605 Iustin Pop
                                             self.op.debug_level)
4457 4c4e4e1e Iustin Pop
      result.Raise("Could not install OS for instance %s on node %s" %
4458 4c4e4e1e Iustin Pop
                   (inst.name, inst.primary_node))
4459 fe7b0351 Michael Hanselmann
    finally:
4460 b9bddb6b Iustin Pop
      _ShutdownInstanceDisks(self, inst)
4461 fe7b0351 Michael Hanselmann
4462 fe7b0351 Michael Hanselmann
4463 bd315bfa Iustin Pop
class LURecreateInstanceDisks(LogicalUnit):
4464 bd315bfa Iustin Pop
  """Recreate an instance's missing disks.
4465 bd315bfa Iustin Pop

4466 bd315bfa Iustin Pop
  """
4467 bd315bfa Iustin Pop
  HPATH = "instance-recreate-disks"
4468 bd315bfa Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
4469 bd315bfa Iustin Pop
  _OP_REQP = ["instance_name", "disks"]
4470 bd315bfa Iustin Pop
  REQ_BGL = False
4471 bd315bfa Iustin Pop
4472 bd315bfa Iustin Pop
  def CheckArguments(self):
4473 bd315bfa Iustin Pop
    """Check the arguments.
4474 bd315bfa Iustin Pop

4475 bd315bfa Iustin Pop
    """
4476 bd315bfa Iustin Pop
    if not isinstance(self.op.disks, list):
4477 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Invalid disks parameter", errors.ECODE_INVAL)
4478 bd315bfa Iustin Pop
    for item in self.op.disks:
4479 bd315bfa Iustin Pop
      if (not isinstance(item, int) or
4480 bd315bfa Iustin Pop
          item < 0):
4481 bd315bfa Iustin Pop
        raise errors.OpPrereqError("Invalid disk specification '%s'" %
4482 5c983ee5 Iustin Pop
                                   str(item), errors.ECODE_INVAL)
4483 bd315bfa Iustin Pop
4484 bd315bfa Iustin Pop
  def ExpandNames(self):
4485 bd315bfa Iustin Pop
    self._ExpandAndLockInstance()
4486 bd315bfa Iustin Pop
4487 bd315bfa Iustin Pop
  def BuildHooksEnv(self):
4488 bd315bfa Iustin Pop
    """Build hooks env.
4489 bd315bfa Iustin Pop

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

4492 bd315bfa Iustin Pop
    """
4493 bd315bfa Iustin Pop
    env = _BuildInstanceHookEnvByObject(self, self.instance)
4494 bd315bfa Iustin Pop
    nl = [self.cfg.GetMasterNode()] + list(self.instance.all_nodes)
4495 bd315bfa Iustin Pop
    return env, nl, nl
4496 bd315bfa Iustin Pop
4497 bd315bfa Iustin Pop
  def CheckPrereq(self):
4498 bd315bfa Iustin Pop
    """Check prerequisites.
4499 bd315bfa Iustin Pop

4500 bd315bfa Iustin Pop
    This checks that the instance is in the cluster and is not running.
4501 bd315bfa Iustin Pop

4502 bd315bfa Iustin Pop
    """
4503 bd315bfa Iustin Pop
    instance = self.cfg.GetInstanceInfo(self.op.instance_name)
4504 bd315bfa Iustin Pop
    assert instance is not None, \
4505 bd315bfa Iustin Pop
      "Cannot retrieve locked instance %s" % self.op.instance_name
4506 bd315bfa Iustin Pop
    _CheckNodeOnline(self, instance.primary_node)
4507 bd315bfa Iustin Pop
4508 bd315bfa Iustin Pop
    if instance.disk_template == constants.DT_DISKLESS:
4509 bd315bfa Iustin Pop
      raise errors.OpPrereqError("Instance '%s' has no disks" %
4510 5c983ee5 Iustin Pop
                                 self.op.instance_name, errors.ECODE_INVAL)
4511 31624382 Iustin Pop
    _CheckInstanceDown(self, instance, "cannot recreate disks")
4512 bd315bfa Iustin Pop
4513 bd315bfa Iustin Pop
    if not self.op.disks:
4514 bd315bfa Iustin Pop
      self.op.disks = range(len(instance.disks))
4515 bd315bfa Iustin Pop
    else:
4516 bd315bfa Iustin Pop
      for idx in self.op.disks:
4517 bd315bfa Iustin Pop
        if idx >= len(instance.disks):
4518 5c983ee5 Iustin Pop
          raise errors.OpPrereqError("Invalid disk index passed '%s'" % idx,
4519 5c983ee5 Iustin Pop
                                     errors.ECODE_INVAL)
4520 bd315bfa Iustin Pop
4521 bd315bfa Iustin Pop
    self.instance = instance
4522 bd315bfa Iustin Pop
4523 bd315bfa Iustin Pop
  def Exec(self, feedback_fn):
4524 bd315bfa Iustin Pop
    """Recreate the disks.
4525 bd315bfa Iustin Pop

4526 bd315bfa Iustin Pop
    """
4527 bd315bfa Iustin Pop
    to_skip = []
4528 1122eb25 Iustin Pop
    for idx, _ in enumerate(self.instance.disks):
4529 bd315bfa Iustin Pop
      if idx not in self.op.disks: # disk idx has not been passed in
4530 bd315bfa Iustin Pop
        to_skip.append(idx)
4531 bd315bfa Iustin Pop
        continue
4532 bd315bfa Iustin Pop
4533 bd315bfa Iustin Pop
    _CreateDisks(self, self.instance, to_skip=to_skip)
4534 bd315bfa Iustin Pop
4535 bd315bfa Iustin Pop
4536 decd5f45 Iustin Pop
class LURenameInstance(LogicalUnit):
4537 decd5f45 Iustin Pop
  """Rename an instance.
4538 decd5f45 Iustin Pop

4539 decd5f45 Iustin Pop
  """
4540 decd5f45 Iustin Pop
  HPATH = "instance-rename"
4541 decd5f45 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
4542 decd5f45 Iustin Pop
  _OP_REQP = ["instance_name", "new_name"]
4543 decd5f45 Iustin Pop
4544 decd5f45 Iustin Pop
  def BuildHooksEnv(self):
4545 decd5f45 Iustin Pop
    """Build hooks env.
4546 decd5f45 Iustin Pop

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

4549 decd5f45 Iustin Pop
    """
4550 338e51e8 Iustin Pop
    env = _BuildInstanceHookEnvByObject(self, self.instance)
4551 decd5f45 Iustin Pop
    env["INSTANCE_NEW_NAME"] = self.op.new_name
4552 6b12959c Iustin Pop
    nl = [self.cfg.GetMasterNode()] + list(self.instance.all_nodes)
4553 decd5f45 Iustin Pop
    return env, nl, nl
4554 decd5f45 Iustin Pop
4555 decd5f45 Iustin Pop
  def CheckPrereq(self):
4556 decd5f45 Iustin Pop
    """Check prerequisites.
4557 decd5f45 Iustin Pop

4558 decd5f45 Iustin Pop
    This checks that the instance is in the cluster and is not running.
4559 decd5f45 Iustin Pop

4560 decd5f45 Iustin Pop
    """
4561 cf26a87a Iustin Pop
    self.op.instance_name = _ExpandInstanceName(self.cfg,
4562 cf26a87a Iustin Pop
                                                self.op.instance_name)
4563 cf26a87a Iustin Pop
    instance = self.cfg.GetInstanceInfo(self.op.instance_name)
4564 cf26a87a Iustin Pop
    assert instance is not None
4565 7527a8a4 Iustin Pop
    _CheckNodeOnline(self, instance.primary_node)
4566 31624382 Iustin Pop
    _CheckInstanceDown(self, instance, "cannot rename")
4567 decd5f45 Iustin Pop
    self.instance = instance
4568 decd5f45 Iustin Pop
4569 decd5f45 Iustin Pop
    # new name verification
4570 104f4ca1 Iustin Pop
    name_info = utils.GetHostInfo(self.op.new_name)
4571 decd5f45 Iustin Pop
4572 89e1fc26 Iustin Pop
    self.op.new_name = new_name = name_info.name
4573 7bde3275 Guido Trotter
    instance_list = self.cfg.GetInstanceList()
4574 7bde3275 Guido Trotter
    if new_name in instance_list:
4575 7bde3275 Guido Trotter
      raise errors.OpPrereqError("Instance '%s' is already in the cluster" %
4576 5c983ee5 Iustin Pop
                                 new_name, errors.ECODE_EXISTS)
4577 7bde3275 Guido Trotter
4578 decd5f45 Iustin Pop
    if not getattr(self.op, "ignore_ip", False):
4579 937f983d Guido Trotter
      if utils.TcpPing(name_info.ip, constants.DEFAULT_NODED_PORT):
4580 decd5f45 Iustin Pop
        raise errors.OpPrereqError("IP %s of instance %s already in use" %
4581 5c983ee5 Iustin Pop
                                   (name_info.ip, new_name),
4582 5c983ee5 Iustin Pop
                                   errors.ECODE_NOTUNIQUE)
4583 decd5f45 Iustin Pop
4584 decd5f45 Iustin Pop
4585 decd5f45 Iustin Pop
  def Exec(self, feedback_fn):
4586 decd5f45 Iustin Pop
    """Reinstall the instance.
4587 decd5f45 Iustin Pop

4588 decd5f45 Iustin Pop
    """
4589 decd5f45 Iustin Pop
    inst = self.instance
4590 decd5f45 Iustin Pop
    old_name = inst.name
4591 decd5f45 Iustin Pop
4592 b23c4333 Manuel Franceschini
    if inst.disk_template == constants.DT_FILE:
4593 b23c4333 Manuel Franceschini
      old_file_storage_dir = os.path.dirname(inst.disks[0].logical_id[1])
4594 b23c4333 Manuel Franceschini
4595 decd5f45 Iustin Pop
    self.cfg.RenameInstance(inst.name, self.op.new_name)
4596 74b5913f Guido Trotter
    # Change the instance lock. This is definitely safe while we hold the BGL
4597 cb4e8387 Iustin Pop
    self.context.glm.remove(locking.LEVEL_INSTANCE, old_name)
4598 74b5913f Guido Trotter
    self.context.glm.add(locking.LEVEL_INSTANCE, self.op.new_name)
4599 decd5f45 Iustin Pop
4600 decd5f45 Iustin Pop
    # re-read the instance from the configuration after rename
4601 decd5f45 Iustin Pop
    inst = self.cfg.GetInstanceInfo(self.op.new_name)
4602 decd5f45 Iustin Pop
4603 b23c4333 Manuel Franceschini
    if inst.disk_template == constants.DT_FILE:
4604 b23c4333 Manuel Franceschini
      new_file_storage_dir = os.path.dirname(inst.disks[0].logical_id[1])
4605 72737a7f Iustin Pop
      result = self.rpc.call_file_storage_dir_rename(inst.primary_node,
4606 72737a7f Iustin Pop
                                                     old_file_storage_dir,
4607 72737a7f Iustin Pop
                                                     new_file_storage_dir)
4608 4c4e4e1e Iustin Pop
      result.Raise("Could not rename on node %s directory '%s' to '%s'"
4609 4c4e4e1e Iustin Pop
                   " (but the instance has been renamed in Ganeti)" %
4610 4c4e4e1e Iustin Pop
                   (inst.primary_node, old_file_storage_dir,
4611 4c4e4e1e Iustin Pop
                    new_file_storage_dir))
4612 b23c4333 Manuel Franceschini
4613 b9bddb6b Iustin Pop
    _StartInstanceDisks(self, inst, None)
4614 decd5f45 Iustin Pop
    try:
4615 781de953 Iustin Pop
      result = self.rpc.call_instance_run_rename(inst.primary_node, inst,
4616 dd713605 Iustin Pop
                                                 old_name, self.op.debug_level)
4617 4c4e4e1e Iustin Pop
      msg = result.fail_msg
4618 96841384 Iustin Pop
      if msg:
4619 6291574d Alexander Schreiber
        msg = ("Could not run OS rename script for instance %s on node %s"
4620 96841384 Iustin Pop
               " (but the instance has been renamed in Ganeti): %s" %
4621 96841384 Iustin Pop
               (inst.name, inst.primary_node, msg))
4622 86d9d3bb Iustin Pop
        self.proc.LogWarning(msg)
4623 decd5f45 Iustin Pop
    finally:
4624 b9bddb6b Iustin Pop
      _ShutdownInstanceDisks(self, inst)
4625 decd5f45 Iustin Pop
4626 decd5f45 Iustin Pop
4627 a8083063 Iustin Pop
class LURemoveInstance(LogicalUnit):
4628 a8083063 Iustin Pop
  """Remove an instance.
4629 a8083063 Iustin Pop

4630 a8083063 Iustin Pop
  """
4631 a8083063 Iustin Pop
  HPATH = "instance-remove"
4632 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
4633 5c54b832 Iustin Pop
  _OP_REQP = ["instance_name", "ignore_failures"]
4634 cf472233 Guido Trotter
  REQ_BGL = False
4635 cf472233 Guido Trotter
4636 17c3f802 Guido Trotter
  def CheckArguments(self):
4637 17c3f802 Guido Trotter
    """Check the arguments.
4638 17c3f802 Guido Trotter

4639 17c3f802 Guido Trotter
    """
4640 17c3f802 Guido Trotter
    self.shutdown_timeout = getattr(self.op, "shutdown_timeout",
4641 17c3f802 Guido Trotter
                                    constants.DEFAULT_SHUTDOWN_TIMEOUT)
4642 17c3f802 Guido Trotter
4643 cf472233 Guido Trotter
  def ExpandNames(self):
4644 cf472233 Guido Trotter
    self._ExpandAndLockInstance()
4645 cf472233 Guido Trotter
    self.needed_locks[locking.LEVEL_NODE] = []
4646 cf472233 Guido Trotter
    self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
4647 cf472233 Guido Trotter
4648 cf472233 Guido Trotter
  def DeclareLocks(self, level):
4649 cf472233 Guido Trotter
    if level == locking.LEVEL_NODE:
4650 cf472233 Guido Trotter
      self._LockInstancesNodes()
4651 a8083063 Iustin Pop
4652 a8083063 Iustin Pop
  def BuildHooksEnv(self):
4653 a8083063 Iustin Pop
    """Build hooks env.
4654 a8083063 Iustin Pop

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

4657 a8083063 Iustin Pop
    """
4658 338e51e8 Iustin Pop
    env = _BuildInstanceHookEnvByObject(self, self.instance)
4659 17c3f802 Guido Trotter
    env["SHUTDOWN_TIMEOUT"] = self.shutdown_timeout
4660 d6a02168 Michael Hanselmann
    nl = [self.cfg.GetMasterNode()]
4661 abd8e836 Iustin Pop
    nl_post = list(self.instance.all_nodes) + nl
4662 abd8e836 Iustin Pop
    return env, nl, nl_post
4663 a8083063 Iustin Pop
4664 a8083063 Iustin Pop
  def CheckPrereq(self):
4665 a8083063 Iustin Pop
    """Check prerequisites.
4666 a8083063 Iustin Pop

4667 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
4668 a8083063 Iustin Pop

4669 a8083063 Iustin Pop
    """
4670 cf472233 Guido Trotter
    self.instance = self.cfg.GetInstanceInfo(self.op.instance_name)
4671 cf472233 Guido Trotter
    assert self.instance is not None, \
4672 cf472233 Guido Trotter
      "Cannot retrieve locked instance %s" % self.op.instance_name
4673 a8083063 Iustin Pop
4674 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
4675 a8083063 Iustin Pop
    """Remove the instance.
4676 a8083063 Iustin Pop

4677 a8083063 Iustin Pop
    """
4678 a8083063 Iustin Pop
    instance = self.instance
4679 9a4f63d1 Iustin Pop
    logging.info("Shutting down instance %s on node %s",
4680 9a4f63d1 Iustin Pop
                 instance.name, instance.primary_node)
4681 a8083063 Iustin Pop
4682 17c3f802 Guido Trotter
    result = self.rpc.call_instance_shutdown(instance.primary_node, instance,
4683 17c3f802 Guido Trotter
                                             self.shutdown_timeout)
4684 4c4e4e1e Iustin Pop
    msg = result.fail_msg
4685 1fae010f Iustin Pop
    if msg:
4686 1d67656e Iustin Pop
      if self.op.ignore_failures:
4687 1fae010f Iustin Pop
        feedback_fn("Warning: can't shutdown instance: %s" % msg)
4688 1d67656e Iustin Pop
      else:
4689 1fae010f Iustin Pop
        raise errors.OpExecError("Could not shutdown instance %s on"
4690 1fae010f Iustin Pop
                                 " node %s: %s" %
4691 1fae010f Iustin Pop
                                 (instance.name, instance.primary_node, msg))
4692 a8083063 Iustin Pop
4693 9a4f63d1 Iustin Pop
    logging.info("Removing block devices for instance %s", instance.name)
4694 a8083063 Iustin Pop
4695 b9bddb6b Iustin Pop
    if not _RemoveDisks(self, instance):
4696 1d67656e Iustin Pop
      if self.op.ignore_failures:
4697 1d67656e Iustin Pop
        feedback_fn("Warning: can't remove instance's disks")
4698 1d67656e Iustin Pop
      else:
4699 1d67656e Iustin Pop
        raise errors.OpExecError("Can't remove instance's disks")
4700 a8083063 Iustin Pop
4701 9a4f63d1 Iustin Pop
    logging.info("Removing instance %s out of cluster config", instance.name)
4702 a8083063 Iustin Pop
4703 a8083063 Iustin Pop
    self.cfg.RemoveInstance(instance.name)
4704 cf472233 Guido Trotter
    self.remove_locks[locking.LEVEL_INSTANCE] = instance.name
4705 a8083063 Iustin Pop
4706 a8083063 Iustin Pop
4707 a8083063 Iustin Pop
class LUQueryInstances(NoHooksLU):
4708 a8083063 Iustin Pop
  """Logical unit for querying instances.
4709 a8083063 Iustin Pop

4710 a8083063 Iustin Pop
  """
4711 7260cfbe Iustin Pop
  # pylint: disable-msg=W0142
4712 ec79568d Iustin Pop
  _OP_REQP = ["output_fields", "names", "use_locking"]
4713 7eb9d8f7 Guido Trotter
  REQ_BGL = False
4714 19bed813 Iustin Pop
  _SIMPLE_FIELDS = ["name", "os", "network_port", "hypervisor",
4715 19bed813 Iustin Pop
                    "serial_no", "ctime", "mtime", "uuid"]
4716 a2d2e1a7 Iustin Pop
  _FIELDS_STATIC = utils.FieldSet(*["name", "os", "pnode", "snodes",
4717 5b460366 Iustin Pop
                                    "admin_state",
4718 a2d2e1a7 Iustin Pop
                                    "disk_template", "ip", "mac", "bridge",
4719 638c6349 Guido Trotter
                                    "nic_mode", "nic_link",
4720 a2d2e1a7 Iustin Pop
                                    "sda_size", "sdb_size", "vcpus", "tags",
4721 a2d2e1a7 Iustin Pop
                                    "network_port", "beparams",
4722 8aec325c Iustin Pop
                                    r"(disk)\.(size)/([0-9]+)",
4723 8aec325c Iustin Pop
                                    r"(disk)\.(sizes)", "disk_usage",
4724 638c6349 Guido Trotter
                                    r"(nic)\.(mac|ip|mode|link)/([0-9]+)",
4725 638c6349 Guido Trotter
                                    r"(nic)\.(bridge)/([0-9]+)",
4726 638c6349 Guido Trotter
                                    r"(nic)\.(macs|ips|modes|links|bridges)",
4727 8aec325c Iustin Pop
                                    r"(disk|nic)\.(count)",
4728 19bed813 Iustin Pop
                                    "hvparams",
4729 19bed813 Iustin Pop
                                    ] + _SIMPLE_FIELDS +
4730 a2d2e1a7 Iustin Pop
                                  ["hv/%s" % name
4731 7736a5f2 Iustin Pop
                                   for name in constants.HVS_PARAMETERS
4732 7736a5f2 Iustin Pop
                                   if name not in constants.HVC_GLOBALS] +
4733 a2d2e1a7 Iustin Pop
                                  ["be/%s" % name
4734 a2d2e1a7 Iustin Pop
                                   for name in constants.BES_PARAMETERS])
4735 a2d2e1a7 Iustin Pop
  _FIELDS_DYNAMIC = utils.FieldSet("oper_state", "oper_ram", "status")
4736 31bf511f Iustin Pop
4737 a8083063 Iustin Pop
4738 7eb9d8f7 Guido Trotter
  def ExpandNames(self):
4739 31bf511f Iustin Pop
    _CheckOutputFields(static=self._FIELDS_STATIC,
4740 31bf511f Iustin Pop
                       dynamic=self._FIELDS_DYNAMIC,
4741 dcb93971 Michael Hanselmann
                       selected=self.op.output_fields)
4742 a8083063 Iustin Pop
4743 7eb9d8f7 Guido Trotter
    self.needed_locks = {}
4744 7eb9d8f7 Guido Trotter
    self.share_locks[locking.LEVEL_INSTANCE] = 1
4745 7eb9d8f7 Guido Trotter
    self.share_locks[locking.LEVEL_NODE] = 1
4746 7eb9d8f7 Guido Trotter
4747 57a2fb91 Iustin Pop
    if self.op.names:
4748 57a2fb91 Iustin Pop
      self.wanted = _GetWantedInstances(self, self.op.names)
4749 7eb9d8f7 Guido Trotter
    else:
4750 57a2fb91 Iustin Pop
      self.wanted = locking.ALL_SET
4751 7eb9d8f7 Guido Trotter
4752 ec79568d Iustin Pop
    self.do_node_query = self._FIELDS_STATIC.NonMatching(self.op.output_fields)
4753 ec79568d Iustin Pop
    self.do_locking = self.do_node_query and self.op.use_locking
4754 57a2fb91 Iustin Pop
    if self.do_locking:
4755 57a2fb91 Iustin Pop
      self.needed_locks[locking.LEVEL_INSTANCE] = self.wanted
4756 57a2fb91 Iustin Pop
      self.needed_locks[locking.LEVEL_NODE] = []
4757 57a2fb91 Iustin Pop
      self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
4758 7eb9d8f7 Guido Trotter
4759 7eb9d8f7 Guido Trotter
  def DeclareLocks(self, level):
4760 57a2fb91 Iustin Pop
    if level == locking.LEVEL_NODE and self.do_locking:
4761 7eb9d8f7 Guido Trotter
      self._LockInstancesNodes()
4762 7eb9d8f7 Guido Trotter
4763 7eb9d8f7 Guido Trotter
  def CheckPrereq(self):
4764 7eb9d8f7 Guido Trotter
    """Check prerequisites.
4765 7eb9d8f7 Guido Trotter

4766 7eb9d8f7 Guido Trotter
    """
4767 57a2fb91 Iustin Pop
    pass
4768 069dcc86 Iustin Pop
4769 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
4770 a8083063 Iustin Pop
    """Computes the list of nodes and their attributes.
4771 a8083063 Iustin Pop

4772 a8083063 Iustin Pop
    """
4773 7260cfbe Iustin Pop
    # pylint: disable-msg=R0912
4774 7260cfbe Iustin Pop
    # way too many branches here
4775 57a2fb91 Iustin Pop
    all_info = self.cfg.GetAllInstancesInfo()
4776 a7f5dc98 Iustin Pop
    if self.wanted == locking.ALL_SET:
4777 a7f5dc98 Iustin Pop
      # caller didn't specify instance names, so ordering is not important
4778 a7f5dc98 Iustin Pop
      if self.do_locking:
4779 a7f5dc98 Iustin Pop
        instance_names = self.acquired_locks[locking.LEVEL_INSTANCE]
4780 a7f5dc98 Iustin Pop
      else:
4781 a7f5dc98 Iustin Pop
        instance_names = all_info.keys()
4782 a7f5dc98 Iustin Pop
      instance_names = utils.NiceSort(instance_names)
4783 57a2fb91 Iustin Pop
    else:
4784 a7f5dc98 Iustin Pop
      # caller did specify names, so we must keep the ordering
4785 a7f5dc98 Iustin Pop
      if self.do_locking:
4786 a7f5dc98 Iustin Pop
        tgt_set = self.acquired_locks[locking.LEVEL_INSTANCE]
4787 a7f5dc98 Iustin Pop
      else:
4788 a7f5dc98 Iustin Pop
        tgt_set = all_info.keys()
4789 a7f5dc98 Iustin Pop
      missing = set(self.wanted).difference(tgt_set)
4790 a7f5dc98 Iustin Pop
      if missing:
4791 a7f5dc98 Iustin Pop
        raise errors.OpExecError("Some instances were removed before"
4792 a7f5dc98 Iustin Pop
                                 " retrieving their data: %s" % missing)
4793 a7f5dc98 Iustin Pop
      instance_names = self.wanted
4794 c1f1cbb2 Iustin Pop
4795 57a2fb91 Iustin Pop
    instance_list = [all_info[iname] for iname in instance_names]
4796 a8083063 Iustin Pop
4797 a8083063 Iustin Pop
    # begin data gathering
4798 a8083063 Iustin Pop
4799 a8083063 Iustin Pop
    nodes = frozenset([inst.primary_node for inst in instance_list])
4800 e69d05fd Iustin Pop
    hv_list = list(set([inst.hypervisor for inst in instance_list]))
4801 a8083063 Iustin Pop
4802 a8083063 Iustin Pop
    bad_nodes = []
4803 cbfc4681 Iustin Pop
    off_nodes = []
4804 ec79568d Iustin Pop
    if self.do_node_query:
4805 a8083063 Iustin Pop
      live_data = {}
4806 72737a7f Iustin Pop
      node_data = self.rpc.call_all_instances_info(nodes, hv_list)
4807 a8083063 Iustin Pop
      for name in nodes:
4808 a8083063 Iustin Pop
        result = node_data[name]
4809 cbfc4681 Iustin Pop
        if result.offline:
4810 cbfc4681 Iustin Pop
          # offline nodes will be in both lists
4811 cbfc4681 Iustin Pop
          off_nodes.append(name)
4812 3cebe102 Michael Hanselmann
        if result.fail_msg:
4813 a8083063 Iustin Pop
          bad_nodes.append(name)
4814 781de953 Iustin Pop
        else:
4815 2fa74ef4 Iustin Pop
          if result.payload:
4816 2fa74ef4 Iustin Pop
            live_data.update(result.payload)
4817 2fa74ef4 Iustin Pop
          # else no instance is alive
4818 a8083063 Iustin Pop
    else:
4819 a8083063 Iustin Pop
      live_data = dict([(name, {}) for name in instance_names])
4820 a8083063 Iustin Pop
4821 a8083063 Iustin Pop
    # end data gathering
4822 a8083063 Iustin Pop
4823 5018a335 Iustin Pop
    HVPREFIX = "hv/"
4824 338e51e8 Iustin Pop
    BEPREFIX = "be/"
4825 a8083063 Iustin Pop
    output = []
4826 638c6349 Guido Trotter
    cluster = self.cfg.GetClusterInfo()
4827 a8083063 Iustin Pop
    for instance in instance_list:
4828 a8083063 Iustin Pop
      iout = []
4829 7736a5f2 Iustin Pop
      i_hv = cluster.FillHV(instance, skip_globals=True)
4830 638c6349 Guido Trotter
      i_be = cluster.FillBE(instance)
4831 638c6349 Guido Trotter
      i_nicp = [objects.FillDict(cluster.nicparams[constants.PP_DEFAULT],
4832 638c6349 Guido Trotter
                                 nic.nicparams) for nic in instance.nics]
4833 a8083063 Iustin Pop
      for field in self.op.output_fields:
4834 71c1af58 Iustin Pop
        st_match = self._FIELDS_STATIC.Matches(field)
4835 19bed813 Iustin Pop
        if field in self._SIMPLE_FIELDS:
4836 19bed813 Iustin Pop
          val = getattr(instance, field)
4837 a8083063 Iustin Pop
        elif field == "pnode":
4838 a8083063 Iustin Pop
          val = instance.primary_node
4839 a8083063 Iustin Pop
        elif field == "snodes":
4840 8a23d2d3 Iustin Pop
          val = list(instance.secondary_nodes)
4841 a8083063 Iustin Pop
        elif field == "admin_state":
4842 0d68c45d Iustin Pop
          val = instance.admin_up
4843 a8083063 Iustin Pop
        elif field == "oper_state":
4844 a8083063 Iustin Pop
          if instance.primary_node in bad_nodes:
4845 8a23d2d3 Iustin Pop
            val = None
4846 a8083063 Iustin Pop
          else:
4847 8a23d2d3 Iustin Pop
            val = bool(live_data.get(instance.name))
4848 d8052456 Iustin Pop
        elif field == "status":
4849 cbfc4681 Iustin Pop
          if instance.primary_node in off_nodes:
4850 cbfc4681 Iustin Pop
            val = "ERROR_nodeoffline"
4851 cbfc4681 Iustin Pop
          elif instance.primary_node in bad_nodes:
4852 d8052456 Iustin Pop
            val = "ERROR_nodedown"
4853 d8052456 Iustin Pop
          else:
4854 d8052456 Iustin Pop
            running = bool(live_data.get(instance.name))
4855 d8052456 Iustin Pop
            if running:
4856 0d68c45d Iustin Pop
              if instance.admin_up:
4857 d8052456 Iustin Pop
                val = "running"
4858 d8052456 Iustin Pop
              else:
4859 d8052456 Iustin Pop
                val = "ERROR_up"
4860 d8052456 Iustin Pop
            else:
4861 0d68c45d Iustin Pop
              if instance.admin_up:
4862 d8052456 Iustin Pop
                val = "ERROR_down"
4863 d8052456 Iustin Pop
              else:
4864 d8052456 Iustin Pop
                val = "ADMIN_down"
4865 a8083063 Iustin Pop
        elif field == "oper_ram":
4866 a8083063 Iustin Pop
          if instance.primary_node in bad_nodes:
4867 8a23d2d3 Iustin Pop
            val = None
4868 a8083063 Iustin Pop
          elif instance.name in live_data:
4869 a8083063 Iustin Pop
            val = live_data[instance.name].get("memory", "?")
4870 a8083063 Iustin Pop
          else:
4871 a8083063 Iustin Pop
            val = "-"
4872 c1ce76bb Iustin Pop
        elif field == "vcpus":
4873 c1ce76bb Iustin Pop
          val = i_be[constants.BE_VCPUS]
4874 a8083063 Iustin Pop
        elif field == "disk_template":
4875 a8083063 Iustin Pop
          val = instance.disk_template
4876 a8083063 Iustin Pop
        elif field == "ip":
4877 39a02558 Guido Trotter
          if instance.nics:
4878 39a02558 Guido Trotter
            val = instance.nics[0].ip
4879 39a02558 Guido Trotter
          else:
4880 39a02558 Guido Trotter
            val = None
4881 638c6349 Guido Trotter
        elif field == "nic_mode":
4882 638c6349 Guido Trotter
          if instance.nics:
4883 638c6349 Guido Trotter
            val = i_nicp[0][constants.NIC_MODE]
4884 638c6349 Guido Trotter
          else:
4885 638c6349 Guido Trotter
            val = None
4886 638c6349 Guido Trotter
        elif field == "nic_link":
4887 39a02558 Guido Trotter
          if instance.nics:
4888 638c6349 Guido Trotter
            val = i_nicp[0][constants.NIC_LINK]
4889 638c6349 Guido Trotter
          else:
4890 638c6349 Guido Trotter
            val = None
4891 638c6349 Guido Trotter
        elif field == "bridge":
4892 638c6349 Guido Trotter
          if (instance.nics and
4893 638c6349 Guido Trotter
              i_nicp[0][constants.NIC_MODE] == constants.NIC_MODE_BRIDGED):
4894 638c6349 Guido Trotter
            val = i_nicp[0][constants.NIC_LINK]
4895 39a02558 Guido Trotter
          else:
4896 39a02558 Guido Trotter
            val = None
4897 a8083063 Iustin Pop
        elif field == "mac":
4898 39a02558 Guido Trotter
          if instance.nics:
4899 39a02558 Guido Trotter
            val = instance.nics[0].mac
4900 39a02558 Guido Trotter
          else:
4901 39a02558 Guido Trotter
            val = None
4902 644eeef9 Iustin Pop
        elif field == "sda_size" or field == "sdb_size":
4903 ad24e046 Iustin Pop
          idx = ord(field[2]) - ord('a')
4904 ad24e046 Iustin Pop
          try:
4905 ad24e046 Iustin Pop
            val = instance.FindDisk(idx).size
4906 ad24e046 Iustin Pop
          except errors.OpPrereqError:
4907 8a23d2d3 Iustin Pop
            val = None
4908 024e157f Iustin Pop
        elif field == "disk_usage": # total disk usage per node
4909 024e157f Iustin Pop
          disk_sizes = [{'size': disk.size} for disk in instance.disks]
4910 024e157f Iustin Pop
          val = _ComputeDiskSize(instance.disk_template, disk_sizes)
4911 130a6a6f Iustin Pop
        elif field == "tags":
4912 130a6a6f Iustin Pop
          val = list(instance.GetTags())
4913 338e51e8 Iustin Pop
        elif field == "hvparams":
4914 338e51e8 Iustin Pop
          val = i_hv
4915 5018a335 Iustin Pop
        elif (field.startswith(HVPREFIX) and
4916 7736a5f2 Iustin Pop
              field[len(HVPREFIX):] in constants.HVS_PARAMETERS and
4917 7736a5f2 Iustin Pop
              field[len(HVPREFIX):] not in constants.HVC_GLOBALS):
4918 5018a335 Iustin Pop
          val = i_hv.get(field[len(HVPREFIX):], None)
4919 338e51e8 Iustin Pop
        elif field == "beparams":
4920 338e51e8 Iustin Pop
          val = i_be
4921 338e51e8 Iustin Pop
        elif (field.startswith(BEPREFIX) and
4922 338e51e8 Iustin Pop
              field[len(BEPREFIX):] in constants.BES_PARAMETERS):
4923 338e51e8 Iustin Pop
          val = i_be.get(field[len(BEPREFIX):], None)
4924 71c1af58 Iustin Pop
        elif st_match and st_match.groups():
4925 71c1af58 Iustin Pop
          # matches a variable list
4926 71c1af58 Iustin Pop
          st_groups = st_match.groups()
4927 71c1af58 Iustin Pop
          if st_groups and st_groups[0] == "disk":
4928 71c1af58 Iustin Pop
            if st_groups[1] == "count":
4929 71c1af58 Iustin Pop
              val = len(instance.disks)
4930 41a776da Iustin Pop
            elif st_groups[1] == "sizes":
4931 41a776da Iustin Pop
              val = [disk.size for disk in instance.disks]
4932 71c1af58 Iustin Pop
            elif st_groups[1] == "size":
4933 3e0cea06 Iustin Pop
              try:
4934 3e0cea06 Iustin Pop
                val = instance.FindDisk(st_groups[2]).size
4935 3e0cea06 Iustin Pop
              except errors.OpPrereqError:
4936 71c1af58 Iustin Pop
                val = None
4937 71c1af58 Iustin Pop
            else:
4938 71c1af58 Iustin Pop
              assert False, "Unhandled disk parameter"
4939 71c1af58 Iustin Pop
          elif st_groups[0] == "nic":
4940 71c1af58 Iustin Pop
            if st_groups[1] == "count":
4941 71c1af58 Iustin Pop
              val = len(instance.nics)
4942 41a776da Iustin Pop
            elif st_groups[1] == "macs":
4943 41a776da Iustin Pop
              val = [nic.mac for nic in instance.nics]
4944 41a776da Iustin Pop
            elif st_groups[1] == "ips":
4945 41a776da Iustin Pop
              val = [nic.ip for nic in instance.nics]
4946 638c6349 Guido Trotter
            elif st_groups[1] == "modes":
4947 638c6349 Guido Trotter
              val = [nicp[constants.NIC_MODE] for nicp in i_nicp]
4948 638c6349 Guido Trotter
            elif st_groups[1] == "links":
4949 638c6349 Guido Trotter
              val = [nicp[constants.NIC_LINK] for nicp in i_nicp]
4950 41a776da Iustin Pop
            elif st_groups[1] == "bridges":
4951 638c6349 Guido Trotter
              val = []
4952 638c6349 Guido Trotter
              for nicp in i_nicp:
4953 638c6349 Guido Trotter
                if nicp[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
4954 638c6349 Guido Trotter
                  val.append(nicp[constants.NIC_LINK])
4955 638c6349 Guido Trotter
                else:
4956 638c6349 Guido Trotter
                  val.append(None)
4957 71c1af58 Iustin Pop
            else:
4958 71c1af58 Iustin Pop
              # index-based item
4959 71c1af58 Iustin Pop
              nic_idx = int(st_groups[2])
4960 71c1af58 Iustin Pop
              if nic_idx >= len(instance.nics):
4961 71c1af58 Iustin Pop
                val = None
4962 71c1af58 Iustin Pop
              else:
4963 71c1af58 Iustin Pop
                if st_groups[1] == "mac":
4964 71c1af58 Iustin Pop
                  val = instance.nics[nic_idx].mac
4965 71c1af58 Iustin Pop
                elif st_groups[1] == "ip":
4966 71c1af58 Iustin Pop
                  val = instance.nics[nic_idx].ip
4967 638c6349 Guido Trotter
                elif st_groups[1] == "mode":
4968 638c6349 Guido Trotter
                  val = i_nicp[nic_idx][constants.NIC_MODE]
4969 638c6349 Guido Trotter
                elif st_groups[1] == "link":
4970 638c6349 Guido Trotter
                  val = i_nicp[nic_idx][constants.NIC_LINK]
4971 71c1af58 Iustin Pop
                elif st_groups[1] == "bridge":
4972 638c6349 Guido Trotter
                  nic_mode = i_nicp[nic_idx][constants.NIC_MODE]
4973 638c6349 Guido Trotter
                  if nic_mode == constants.NIC_MODE_BRIDGED:
4974 638c6349 Guido Trotter
                    val = i_nicp[nic_idx][constants.NIC_LINK]
4975 638c6349 Guido Trotter
                  else:
4976 638c6349 Guido Trotter
                    val = None
4977 71c1af58 Iustin Pop
                else:
4978 71c1af58 Iustin Pop
                  assert False, "Unhandled NIC parameter"
4979 71c1af58 Iustin Pop
          else:
4980 c1ce76bb Iustin Pop
            assert False, ("Declared but unhandled variable parameter '%s'" %
4981 c1ce76bb Iustin Pop
                           field)
4982 a8083063 Iustin Pop
        else:
4983 c1ce76bb Iustin Pop
          assert False, "Declared but unhandled parameter '%s'" % field
4984 a8083063 Iustin Pop
        iout.append(val)
4985 a8083063 Iustin Pop
      output.append(iout)
4986 a8083063 Iustin Pop
4987 a8083063 Iustin Pop
    return output
4988 a8083063 Iustin Pop
4989 a8083063 Iustin Pop
4990 a8083063 Iustin Pop
class LUFailoverInstance(LogicalUnit):
4991 a8083063 Iustin Pop
  """Failover an instance.
4992 a8083063 Iustin Pop

4993 a8083063 Iustin Pop
  """
4994 a8083063 Iustin Pop
  HPATH = "instance-failover"
4995 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
4996 a8083063 Iustin Pop
  _OP_REQP = ["instance_name", "ignore_consistency"]
4997 c9e5c064 Guido Trotter
  REQ_BGL = False
4998 c9e5c064 Guido Trotter
4999 17c3f802 Guido Trotter
  def CheckArguments(self):
5000 17c3f802 Guido Trotter
    """Check the arguments.
5001 17c3f802 Guido Trotter

5002 17c3f802 Guido Trotter
    """
5003 17c3f802 Guido Trotter
    self.shutdown_timeout = getattr(self.op, "shutdown_timeout",
5004 17c3f802 Guido Trotter
                                    constants.DEFAULT_SHUTDOWN_TIMEOUT)
5005 17c3f802 Guido Trotter
5006 c9e5c064 Guido Trotter
  def ExpandNames(self):
5007 c9e5c064 Guido Trotter
    self._ExpandAndLockInstance()
5008 c9e5c064 Guido Trotter
    self.needed_locks[locking.LEVEL_NODE] = []
5009 f6d9a522 Guido Trotter
    self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
5010 c9e5c064 Guido Trotter
5011 c9e5c064 Guido Trotter
  def DeclareLocks(self, level):
5012 c9e5c064 Guido Trotter
    if level == locking.LEVEL_NODE:
5013 c9e5c064 Guido Trotter
      self._LockInstancesNodes()
5014 a8083063 Iustin Pop
5015 a8083063 Iustin Pop
  def BuildHooksEnv(self):
5016 a8083063 Iustin Pop
    """Build hooks env.
5017 a8083063 Iustin Pop

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

5020 a8083063 Iustin Pop
    """
5021 08eec276 Iustin Pop
    instance = self.instance
5022 08eec276 Iustin Pop
    source_node = instance.primary_node
5023 08eec276 Iustin Pop
    target_node = instance.secondary_nodes[0]
5024 a8083063 Iustin Pop
    env = {
5025 a8083063 Iustin Pop
      "IGNORE_CONSISTENCY": self.op.ignore_consistency,
5026 17c3f802 Guido Trotter
      "SHUTDOWN_TIMEOUT": self.shutdown_timeout,
5027 08eec276 Iustin Pop
      "OLD_PRIMARY": source_node,
5028 08eec276 Iustin Pop
      "OLD_SECONDARY": target_node,
5029 08eec276 Iustin Pop
      "NEW_PRIMARY": target_node,
5030 08eec276 Iustin Pop
      "NEW_SECONDARY": source_node,
5031 a8083063 Iustin Pop
      }
5032 08eec276 Iustin Pop
    env.update(_BuildInstanceHookEnvByObject(self, instance))
5033 08eec276 Iustin Pop
    nl = [self.cfg.GetMasterNode()] + list(instance.secondary_nodes)
5034 abd8e836 Iustin Pop
    nl_post = list(nl)
5035 abd8e836 Iustin Pop
    nl_post.append(source_node)
5036 abd8e836 Iustin Pop
    return env, nl, nl_post
5037 a8083063 Iustin Pop
5038 a8083063 Iustin Pop
  def CheckPrereq(self):
5039 a8083063 Iustin Pop
    """Check prerequisites.
5040 a8083063 Iustin Pop

5041 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
5042 a8083063 Iustin Pop

5043 a8083063 Iustin Pop
    """
5044 c9e5c064 Guido Trotter
    self.instance = instance = self.cfg.GetInstanceInfo(self.op.instance_name)
5045 c9e5c064 Guido Trotter
    assert self.instance is not None, \
5046 c9e5c064 Guido Trotter
      "Cannot retrieve locked instance %s" % self.op.instance_name
5047 a8083063 Iustin Pop
5048 338e51e8 Iustin Pop
    bep = self.cfg.GetClusterInfo().FillBE(instance)
5049 a1f445d3 Iustin Pop
    if instance.disk_template not in constants.DTS_NET_MIRROR:
5050 2a710df1 Michael Hanselmann
      raise errors.OpPrereqError("Instance's disk layout is not"
5051 5c983ee5 Iustin Pop
                                 " network mirrored, cannot failover.",
5052 5c983ee5 Iustin Pop
                                 errors.ECODE_STATE)
5053 2a710df1 Michael Hanselmann
5054 2a710df1 Michael Hanselmann
    secondary_nodes = instance.secondary_nodes
5055 2a710df1 Michael Hanselmann
    if not secondary_nodes:
5056 2a710df1 Michael Hanselmann
      raise errors.ProgrammerError("no secondary node but using "
5057 abdf0113 Iustin Pop
                                   "a mirrored disk template")
5058 2a710df1 Michael Hanselmann
5059 2a710df1 Michael Hanselmann
    target_node = secondary_nodes[0]
5060 7527a8a4 Iustin Pop
    _CheckNodeOnline(self, target_node)
5061 733a2b6a Iustin Pop
    _CheckNodeNotDrained(self, target_node)
5062 d27776f0 Iustin Pop
    if instance.admin_up:
5063 d27776f0 Iustin Pop
      # check memory requirements on the secondary node
5064 d27776f0 Iustin Pop
      _CheckNodeFreeMemory(self, target_node, "failing over instance %s" %
5065 d27776f0 Iustin Pop
                           instance.name, bep[constants.BE_MEMORY],
5066 d27776f0 Iustin Pop
                           instance.hypervisor)
5067 d27776f0 Iustin Pop
    else:
5068 d27776f0 Iustin Pop
      self.LogInfo("Not checking memory on the secondary node as"
5069 d27776f0 Iustin Pop
                   " instance will not be started")
5070 3a7c308e Guido Trotter
5071 a8083063 Iustin Pop
    # check bridge existance
5072 b165e77e Guido Trotter
    _CheckInstanceBridgesExist(self, instance, node=target_node)
5073 a8083063 Iustin Pop
5074 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
5075 a8083063 Iustin Pop
    """Failover an instance.
5076 a8083063 Iustin Pop

5077 a8083063 Iustin Pop
    The failover is done by shutting it down on its present node and
5078 a8083063 Iustin Pop
    starting it on the secondary.
5079 a8083063 Iustin Pop

5080 a8083063 Iustin Pop
    """
5081 a8083063 Iustin Pop
    instance = self.instance
5082 a8083063 Iustin Pop
5083 a8083063 Iustin Pop
    source_node = instance.primary_node
5084 a8083063 Iustin Pop
    target_node = instance.secondary_nodes[0]
5085 a8083063 Iustin Pop
5086 1df79ce6 Michael Hanselmann
    if instance.admin_up:
5087 1df79ce6 Michael Hanselmann
      feedback_fn("* checking disk consistency between source and target")
5088 1df79ce6 Michael Hanselmann
      for dev in instance.disks:
5089 1df79ce6 Michael Hanselmann
        # for drbd, these are drbd over lvm
5090 1df79ce6 Michael Hanselmann
        if not _CheckDiskConsistency(self, dev, target_node, False):
5091 1df79ce6 Michael Hanselmann
          if not self.op.ignore_consistency:
5092 1df79ce6 Michael Hanselmann
            raise errors.OpExecError("Disk %s is degraded on target node,"
5093 1df79ce6 Michael Hanselmann
                                     " aborting failover." % dev.iv_name)
5094 1df79ce6 Michael Hanselmann
    else:
5095 1df79ce6 Michael Hanselmann
      feedback_fn("* not checking disk consistency as instance is not running")
5096 a8083063 Iustin Pop
5097 a8083063 Iustin Pop
    feedback_fn("* shutting down instance on source node")
5098 9a4f63d1 Iustin Pop
    logging.info("Shutting down instance %s on node %s",
5099 9a4f63d1 Iustin Pop
                 instance.name, source_node)
5100 a8083063 Iustin Pop
5101 17c3f802 Guido Trotter
    result = self.rpc.call_instance_shutdown(source_node, instance,
5102 17c3f802 Guido Trotter
                                             self.shutdown_timeout)
5103 4c4e4e1e Iustin Pop
    msg = result.fail_msg
5104 1fae010f Iustin Pop
    if msg:
5105 24a40d57 Iustin Pop
      if self.op.ignore_consistency:
5106 86d9d3bb Iustin Pop
        self.proc.LogWarning("Could not shutdown instance %s on node %s."
5107 1fae010f Iustin Pop
                             " Proceeding anyway. Please make sure node"
5108 1fae010f Iustin Pop
                             " %s is down. Error details: %s",
5109 1fae010f Iustin Pop
                             instance.name, source_node, source_node, msg)
5110 24a40d57 Iustin Pop
      else:
5111 1fae010f Iustin Pop
        raise errors.OpExecError("Could not shutdown instance %s on"
5112 1fae010f Iustin Pop
                                 " node %s: %s" %
5113 1fae010f Iustin Pop
                                 (instance.name, source_node, msg))
5114 a8083063 Iustin Pop
5115 a8083063 Iustin Pop
    feedback_fn("* deactivating the instance's disks on source node")
5116 b9bddb6b Iustin Pop
    if not _ShutdownInstanceDisks(self, instance, ignore_primary=True):
5117 3ecf6786 Iustin Pop
      raise errors.OpExecError("Can't shut down the instance's disks.")
5118 a8083063 Iustin Pop
5119 a8083063 Iustin Pop
    instance.primary_node = target_node
5120 a8083063 Iustin Pop
    # distribute new instance config to the other nodes
5121 a4eae71f Michael Hanselmann
    self.cfg.Update(instance, feedback_fn)
5122 a8083063 Iustin Pop
5123 12a0cfbe Guido Trotter
    # Only start the instance if it's marked as up
5124 0d68c45d Iustin Pop
    if instance.admin_up:
5125 12a0cfbe Guido Trotter
      feedback_fn("* activating the instance's disks on target node")
5126 9a4f63d1 Iustin Pop
      logging.info("Starting instance %s on node %s",
5127 9a4f63d1 Iustin Pop
                   instance.name, target_node)
5128 12a0cfbe Guido Trotter
5129 7c4d6c7b Michael Hanselmann
      disks_ok, _ = _AssembleInstanceDisks(self, instance,
5130 12a0cfbe Guido Trotter
                                               ignore_secondaries=True)
5131 12a0cfbe Guido Trotter
      if not disks_ok:
5132 b9bddb6b Iustin Pop
        _ShutdownInstanceDisks(self, instance)
5133 12a0cfbe Guido Trotter
        raise errors.OpExecError("Can't activate the instance's disks")
5134 a8083063 Iustin Pop
5135 12a0cfbe Guido Trotter
      feedback_fn("* starting the instance on the target node")
5136 0eca8e0c Iustin Pop
      result = self.rpc.call_instance_start(target_node, instance, None, None)
5137 4c4e4e1e Iustin Pop
      msg = result.fail_msg
5138 dd279568 Iustin Pop
      if msg:
5139 b9bddb6b Iustin Pop
        _ShutdownInstanceDisks(self, instance)
5140 dd279568 Iustin Pop
        raise errors.OpExecError("Could not start instance %s on node %s: %s" %
5141 dd279568 Iustin Pop
                                 (instance.name, target_node, msg))
5142 a8083063 Iustin Pop
5143 a8083063 Iustin Pop
5144 53c776b5 Iustin Pop
class LUMigrateInstance(LogicalUnit):
5145 53c776b5 Iustin Pop
  """Migrate an instance.
5146 53c776b5 Iustin Pop

5147 53c776b5 Iustin Pop
  This is migration without shutting down, compared to the failover,
5148 53c776b5 Iustin Pop
  which is done with shutdown.
5149 53c776b5 Iustin Pop

5150 53c776b5 Iustin Pop
  """
5151 53c776b5 Iustin Pop
  HPATH = "instance-migrate"
5152 53c776b5 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
5153 53c776b5 Iustin Pop
  _OP_REQP = ["instance_name", "live", "cleanup"]
5154 53c776b5 Iustin Pop
5155 53c776b5 Iustin Pop
  REQ_BGL = False
5156 53c776b5 Iustin Pop
5157 53c776b5 Iustin Pop
  def ExpandNames(self):
5158 53c776b5 Iustin Pop
    self._ExpandAndLockInstance()
5159 3e06e001 Michael Hanselmann
5160 53c776b5 Iustin Pop
    self.needed_locks[locking.LEVEL_NODE] = []
5161 53c776b5 Iustin Pop
    self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
5162 53c776b5 Iustin Pop
5163 3e06e001 Michael Hanselmann
    self._migrater = TLMigrateInstance(self, self.op.instance_name,
5164 3e06e001 Michael Hanselmann
                                       self.op.live, self.op.cleanup)
5165 3a012b41 Michael Hanselmann
    self.tasklets = [self._migrater]
5166 3e06e001 Michael Hanselmann
5167 53c776b5 Iustin Pop
  def DeclareLocks(self, level):
5168 53c776b5 Iustin Pop
    if level == locking.LEVEL_NODE:
5169 53c776b5 Iustin Pop
      self._LockInstancesNodes()
5170 53c776b5 Iustin Pop
5171 53c776b5 Iustin Pop
  def BuildHooksEnv(self):
5172 53c776b5 Iustin Pop
    """Build hooks env.
5173 53c776b5 Iustin Pop

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

5176 53c776b5 Iustin Pop
    """
5177 3e06e001 Michael Hanselmann
    instance = self._migrater.instance
5178 08eec276 Iustin Pop
    source_node = instance.primary_node
5179 08eec276 Iustin Pop
    target_node = instance.secondary_nodes[0]
5180 3e06e001 Michael Hanselmann
    env = _BuildInstanceHookEnvByObject(self, instance)
5181 2c2690c9 Iustin Pop
    env["MIGRATE_LIVE"] = self.op.live
5182 2c2690c9 Iustin Pop
    env["MIGRATE_CLEANUP"] = self.op.cleanup
5183 08eec276 Iustin Pop
    env.update({
5184 08eec276 Iustin Pop
        "OLD_PRIMARY": source_node,
5185 08eec276 Iustin Pop
        "OLD_SECONDARY": target_node,
5186 08eec276 Iustin Pop
        "NEW_PRIMARY": target_node,
5187 08eec276 Iustin Pop
        "NEW_SECONDARY": source_node,
5188 08eec276 Iustin Pop
        })
5189 3e06e001 Michael Hanselmann
    nl = [self.cfg.GetMasterNode()] + list(instance.secondary_nodes)
5190 abd8e836 Iustin Pop
    nl_post = list(nl)
5191 abd8e836 Iustin Pop
    nl_post.append(source_node)
5192 abd8e836 Iustin Pop
    return env, nl, nl_post
5193 53c776b5 Iustin Pop
5194 3e06e001 Michael Hanselmann
5195 313bcead Iustin Pop
class LUMoveInstance(LogicalUnit):
5196 313bcead Iustin Pop
  """Move an instance by data-copying.
5197 313bcead Iustin Pop

5198 313bcead Iustin Pop
  """
5199 313bcead Iustin Pop
  HPATH = "instance-move"
5200 313bcead Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
5201 313bcead Iustin Pop
  _OP_REQP = ["instance_name", "target_node"]
5202 313bcead Iustin Pop
  REQ_BGL = False
5203 313bcead Iustin Pop
5204 17c3f802 Guido Trotter
  def CheckArguments(self):
5205 17c3f802 Guido Trotter
    """Check the arguments.
5206 17c3f802 Guido Trotter

5207 17c3f802 Guido Trotter
    """
5208 17c3f802 Guido Trotter
    self.shutdown_timeout = getattr(self.op, "shutdown_timeout",
5209 17c3f802 Guido Trotter
                                    constants.DEFAULT_SHUTDOWN_TIMEOUT)
5210 17c3f802 Guido Trotter
5211 313bcead Iustin Pop
  def ExpandNames(self):
5212 313bcead Iustin Pop
    self._ExpandAndLockInstance()
5213 cf26a87a Iustin Pop
    target_node = _ExpandNodeName(self.cfg, self.op.target_node)
5214 313bcead Iustin Pop
    self.op.target_node = target_node
5215 313bcead Iustin Pop
    self.needed_locks[locking.LEVEL_NODE] = [target_node]
5216 313bcead Iustin Pop
    self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_APPEND
5217 313bcead Iustin Pop
5218 313bcead Iustin Pop
  def DeclareLocks(self, level):
5219 313bcead Iustin Pop
    if level == locking.LEVEL_NODE:
5220 313bcead Iustin Pop
      self._LockInstancesNodes(primary_only=True)
5221 313bcead Iustin Pop
5222 313bcead Iustin Pop
  def BuildHooksEnv(self):
5223 313bcead Iustin Pop
    """Build hooks env.
5224 313bcead Iustin Pop

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

5227 313bcead Iustin Pop
    """
5228 313bcead Iustin Pop
    env = {
5229 313bcead Iustin Pop
      "TARGET_NODE": self.op.target_node,
5230 17c3f802 Guido Trotter
      "SHUTDOWN_TIMEOUT": self.shutdown_timeout,
5231 313bcead Iustin Pop
      }
5232 313bcead Iustin Pop
    env.update(_BuildInstanceHookEnvByObject(self, self.instance))
5233 313bcead Iustin Pop
    nl = [self.cfg.GetMasterNode()] + [self.instance.primary_node,
5234 313bcead Iustin Pop
                                       self.op.target_node]
5235 313bcead Iustin Pop
    return env, nl, nl
5236 313bcead Iustin Pop
5237 313bcead Iustin Pop
  def CheckPrereq(self):
5238 313bcead Iustin Pop
    """Check prerequisites.
5239 313bcead Iustin Pop

5240 313bcead Iustin Pop
    This checks that the instance is in the cluster.
5241 313bcead Iustin Pop

5242 313bcead Iustin Pop
    """
5243 313bcead Iustin Pop
    self.instance = instance = self.cfg.GetInstanceInfo(self.op.instance_name)
5244 313bcead Iustin Pop
    assert self.instance is not None, \
5245 313bcead Iustin Pop
      "Cannot retrieve locked instance %s" % self.op.instance_name
5246 313bcead Iustin Pop
5247 313bcead Iustin Pop
    node = self.cfg.GetNodeInfo(self.op.target_node)
5248 313bcead Iustin Pop
    assert node is not None, \
5249 313bcead Iustin Pop
      "Cannot retrieve locked node %s" % self.op.target_node
5250 313bcead Iustin Pop
5251 313bcead Iustin Pop
    self.target_node = target_node = node.name
5252 313bcead Iustin Pop
5253 313bcead Iustin Pop
    if target_node == instance.primary_node:
5254 313bcead Iustin Pop
      raise errors.OpPrereqError("Instance %s is already on the node %s" %
5255 5c983ee5 Iustin Pop
                                 (instance.name, target_node),
5256 5c983ee5 Iustin Pop
                                 errors.ECODE_STATE)
5257 313bcead Iustin Pop
5258 313bcead Iustin Pop
    bep = self.cfg.GetClusterInfo().FillBE(instance)
5259 313bcead Iustin Pop
5260 313bcead Iustin Pop
    for idx, dsk in enumerate(instance.disks):
5261 313bcead Iustin Pop
      if dsk.dev_type not in (constants.LD_LV, constants.LD_FILE):
5262 313bcead Iustin Pop
        raise errors.OpPrereqError("Instance disk %d has a complex layout,"
5263 d1b83918 Iustin Pop
                                   " cannot copy" % idx, errors.ECODE_STATE)
5264 313bcead Iustin Pop
5265 313bcead Iustin Pop
    _CheckNodeOnline(self, target_node)
5266 313bcead Iustin Pop
    _CheckNodeNotDrained(self, target_node)
5267 313bcead Iustin Pop
5268 313bcead Iustin Pop
    if instance.admin_up:
5269 313bcead Iustin Pop
      # check memory requirements on the secondary node
5270 313bcead Iustin Pop
      _CheckNodeFreeMemory(self, target_node, "failing over instance %s" %
5271 313bcead Iustin Pop
                           instance.name, bep[constants.BE_MEMORY],
5272 313bcead Iustin Pop
                           instance.hypervisor)
5273 313bcead Iustin Pop
    else:
5274 313bcead Iustin Pop
      self.LogInfo("Not checking memory on the secondary node as"
5275 313bcead Iustin Pop
                   " instance will not be started")
5276 313bcead Iustin Pop
5277 313bcead Iustin Pop
    # check bridge existance
5278 313bcead Iustin Pop
    _CheckInstanceBridgesExist(self, instance, node=target_node)
5279 313bcead Iustin Pop
5280 313bcead Iustin Pop
  def Exec(self, feedback_fn):
5281 313bcead Iustin Pop
    """Move an instance.
5282 313bcead Iustin Pop

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

5286 313bcead Iustin Pop
    """
5287 313bcead Iustin Pop
    instance = self.instance
5288 313bcead Iustin Pop
5289 313bcead Iustin Pop
    source_node = instance.primary_node
5290 313bcead Iustin Pop
    target_node = self.target_node
5291 313bcead Iustin Pop
5292 313bcead Iustin Pop
    self.LogInfo("Shutting down instance %s on source node %s",
5293 313bcead Iustin Pop
                 instance.name, source_node)
5294 313bcead Iustin Pop
5295 17c3f802 Guido Trotter
    result = self.rpc.call_instance_shutdown(source_node, instance,
5296 17c3f802 Guido Trotter
                                             self.shutdown_timeout)
5297 313bcead Iustin Pop
    msg = result.fail_msg
5298 313bcead Iustin Pop
    if msg:
5299 313bcead Iustin Pop
      if self.op.ignore_consistency:
5300 313bcead Iustin Pop
        self.proc.LogWarning("Could not shutdown instance %s on node %s."
5301 313bcead Iustin Pop
                             " Proceeding anyway. Please make sure node"
5302 313bcead Iustin Pop
                             " %s is down. Error details: %s",
5303 313bcead Iustin Pop
                             instance.name, source_node, source_node, msg)
5304 313bcead Iustin Pop
      else:
5305 313bcead Iustin Pop
        raise errors.OpExecError("Could not shutdown instance %s on"
5306 313bcead Iustin Pop
                                 " node %s: %s" %
5307 313bcead Iustin Pop
                                 (instance.name, source_node, msg))
5308 313bcead Iustin Pop
5309 313bcead Iustin Pop
    # create the target disks
5310 313bcead Iustin Pop
    try:
5311 313bcead Iustin Pop
      _CreateDisks(self, instance, target_node=target_node)
5312 313bcead Iustin Pop
    except errors.OpExecError:
5313 313bcead Iustin Pop
      self.LogWarning("Device creation failed, reverting...")
5314 313bcead Iustin Pop
      try:
5315 313bcead Iustin Pop
        _RemoveDisks(self, instance, target_node=target_node)
5316 313bcead Iustin Pop
      finally:
5317 313bcead Iustin Pop
        self.cfg.ReleaseDRBDMinors(instance.name)
5318 313bcead Iustin Pop
        raise
5319 313bcead Iustin Pop
5320 313bcead Iustin Pop
    cluster_name = self.cfg.GetClusterInfo().cluster_name
5321 313bcead Iustin Pop
5322 313bcead Iustin Pop
    errs = []
5323 313bcead Iustin Pop
    # activate, get path, copy the data over
5324 313bcead Iustin Pop
    for idx, disk in enumerate(instance.disks):
5325 313bcead Iustin Pop
      self.LogInfo("Copying data for disk %d", idx)
5326 313bcead Iustin Pop
      result = self.rpc.call_blockdev_assemble(target_node, disk,
5327 313bcead Iustin Pop
                                               instance.name, True)
5328 313bcead Iustin Pop
      if result.fail_msg:
5329 313bcead Iustin Pop
        self.LogWarning("Can't assemble newly created disk %d: %s",
5330 313bcead Iustin Pop
                        idx, result.fail_msg)
5331 313bcead Iustin Pop
        errs.append(result.fail_msg)
5332 313bcead Iustin Pop
        break
5333 313bcead Iustin Pop
      dev_path = result.payload
5334 313bcead Iustin Pop
      result = self.rpc.call_blockdev_export(source_node, disk,
5335 313bcead Iustin Pop
                                             target_node, dev_path,
5336 313bcead Iustin Pop
                                             cluster_name)
5337 313bcead Iustin Pop
      if result.fail_msg:
5338 313bcead Iustin Pop
        self.LogWarning("Can't copy data over for disk %d: %s",
5339 313bcead Iustin Pop
                        idx, result.fail_msg)
5340 313bcead Iustin Pop
        errs.append(result.fail_msg)
5341 313bcead Iustin Pop
        break
5342 313bcead Iustin Pop
5343 313bcead Iustin Pop
    if errs:
5344 313bcead Iustin Pop
      self.LogWarning("Some disks failed to copy, aborting")
5345 313bcead Iustin Pop
      try:
5346 313bcead Iustin Pop
        _RemoveDisks(self, instance, target_node=target_node)
5347 313bcead Iustin Pop
      finally:
5348 313bcead Iustin Pop
        self.cfg.ReleaseDRBDMinors(instance.name)
5349 313bcead Iustin Pop
        raise errors.OpExecError("Errors during disk copy: %s" %
5350 313bcead Iustin Pop
                                 (",".join(errs),))
5351 313bcead Iustin Pop
5352 313bcead Iustin Pop
    instance.primary_node = target_node
5353 a4eae71f Michael Hanselmann
    self.cfg.Update(instance, feedback_fn)
5354 313bcead Iustin Pop
5355 313bcead Iustin Pop
    self.LogInfo("Removing the disks on the original node")
5356 313bcead Iustin Pop
    _RemoveDisks(self, instance, target_node=source_node)
5357 313bcead Iustin Pop
5358 313bcead Iustin Pop
    # Only start the instance if it's marked as up
5359 313bcead Iustin Pop
    if instance.admin_up:
5360 313bcead Iustin Pop
      self.LogInfo("Starting instance %s on node %s",
5361 313bcead Iustin Pop
                   instance.name, target_node)
5362 313bcead Iustin Pop
5363 313bcead Iustin Pop
      disks_ok, _ = _AssembleInstanceDisks(self, instance,
5364 313bcead Iustin Pop
                                           ignore_secondaries=True)
5365 313bcead Iustin Pop
      if not disks_ok:
5366 313bcead Iustin Pop
        _ShutdownInstanceDisks(self, instance)
5367 313bcead Iustin Pop
        raise errors.OpExecError("Can't activate the instance's disks")
5368 313bcead Iustin Pop
5369 313bcead Iustin Pop
      result = self.rpc.call_instance_start(target_node, instance, None, None)
5370 313bcead Iustin Pop
      msg = result.fail_msg
5371 313bcead Iustin Pop
      if msg:
5372 313bcead Iustin Pop
        _ShutdownInstanceDisks(self, instance)
5373 313bcead Iustin Pop
        raise errors.OpExecError("Could not start instance %s on node %s: %s" %
5374 313bcead Iustin Pop
                                 (instance.name, target_node, msg))
5375 313bcead Iustin Pop
5376 313bcead Iustin Pop
5377 80cb875c Michael Hanselmann
class LUMigrateNode(LogicalUnit):
5378 80cb875c Michael Hanselmann
  """Migrate all instances from a node.
5379 80cb875c Michael Hanselmann

5380 80cb875c Michael Hanselmann
  """
5381 80cb875c Michael Hanselmann
  HPATH = "node-migrate"
5382 80cb875c Michael Hanselmann
  HTYPE = constants.HTYPE_NODE
5383 80cb875c Michael Hanselmann
  _OP_REQP = ["node_name", "live"]
5384 80cb875c Michael Hanselmann
  REQ_BGL = False
5385 80cb875c Michael Hanselmann
5386 80cb875c Michael Hanselmann
  def ExpandNames(self):
5387 cf26a87a Iustin Pop
    self.op.node_name = _ExpandNodeName(self.cfg, self.op.node_name)
5388 80cb875c Michael Hanselmann
5389 80cb875c Michael Hanselmann
    self.needed_locks = {
5390 80cb875c Michael Hanselmann
      locking.LEVEL_NODE: [self.op.node_name],
5391 80cb875c Michael Hanselmann
      }
5392 80cb875c Michael Hanselmann
5393 80cb875c Michael Hanselmann
    self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_APPEND
5394 80cb875c Michael Hanselmann
5395 80cb875c Michael Hanselmann
    # Create tasklets for migrating instances for all instances on this node
5396 80cb875c Michael Hanselmann
    names = []
5397 80cb875c Michael Hanselmann
    tasklets = []
5398 80cb875c Michael Hanselmann
5399 80cb875c Michael Hanselmann
    for inst in _GetNodePrimaryInstances(self.cfg, self.op.node_name):
5400 80cb875c Michael Hanselmann
      logging.debug("Migrating instance %s", inst.name)
5401 80cb875c Michael Hanselmann
      names.append(inst.name)
5402 80cb875c Michael Hanselmann
5403 80cb875c Michael Hanselmann
      tasklets.append(TLMigrateInstance(self, inst.name, self.op.live, False))
5404 80cb875c Michael Hanselmann
5405 80cb875c Michael Hanselmann
    self.tasklets = tasklets
5406 80cb875c Michael Hanselmann
5407 80cb875c Michael Hanselmann
    # Declare instance locks
5408 80cb875c Michael Hanselmann
    self.needed_locks[locking.LEVEL_INSTANCE] = names
5409 80cb875c Michael Hanselmann
5410 80cb875c Michael Hanselmann
  def DeclareLocks(self, level):
5411 80cb875c Michael Hanselmann
    if level == locking.LEVEL_NODE:
5412 80cb875c Michael Hanselmann
      self._LockInstancesNodes()
5413 80cb875c Michael Hanselmann
5414 80cb875c Michael Hanselmann
  def BuildHooksEnv(self):
5415 80cb875c Michael Hanselmann
    """Build hooks env.
5416 80cb875c Michael Hanselmann

5417 80cb875c Michael Hanselmann
    This runs on the master, the primary and all the secondaries.
5418 80cb875c Michael Hanselmann

5419 80cb875c Michael Hanselmann
    """
5420 80cb875c Michael Hanselmann
    env = {
5421 80cb875c Michael Hanselmann
      "NODE_NAME": self.op.node_name,
5422 80cb875c Michael Hanselmann
      }
5423 80cb875c Michael Hanselmann
5424 80cb875c Michael Hanselmann
    nl = [self.cfg.GetMasterNode()]
5425 80cb875c Michael Hanselmann
5426 80cb875c Michael Hanselmann
    return (env, nl, nl)
5427 80cb875c Michael Hanselmann
5428 80cb875c Michael Hanselmann
5429 3e06e001 Michael Hanselmann
class TLMigrateInstance(Tasklet):
5430 3e06e001 Michael Hanselmann
  def __init__(self, lu, instance_name, live, cleanup):
5431 3e06e001 Michael Hanselmann
    """Initializes this class.
5432 3e06e001 Michael Hanselmann

5433 3e06e001 Michael Hanselmann
    """
5434 464243a7 Michael Hanselmann
    Tasklet.__init__(self, lu)
5435 464243a7 Michael Hanselmann
5436 3e06e001 Michael Hanselmann
    # Parameters
5437 3e06e001 Michael Hanselmann
    self.instance_name = instance_name
5438 3e06e001 Michael Hanselmann
    self.live = live
5439 3e06e001 Michael Hanselmann
    self.cleanup = cleanup
5440 3e06e001 Michael Hanselmann
5441 53c776b5 Iustin Pop
  def CheckPrereq(self):
5442 53c776b5 Iustin Pop
    """Check prerequisites.
5443 53c776b5 Iustin Pop

5444 53c776b5 Iustin Pop
    This checks that the instance is in the cluster.
5445 53c776b5 Iustin Pop

5446 53c776b5 Iustin Pop
    """
5447 cf26a87a Iustin Pop
    instance_name = _ExpandInstanceName(self.lu.cfg, self.instance_name)
5448 cf26a87a Iustin Pop
    instance = self.cfg.GetInstanceInfo(instance_name)
5449 cf26a87a Iustin Pop
    assert instance is not None
5450 53c776b5 Iustin Pop
5451 53c776b5 Iustin Pop
    if instance.disk_template != constants.DT_DRBD8:
5452 53c776b5 Iustin Pop
      raise errors.OpPrereqError("Instance's disk layout is not"
5453 5c983ee5 Iustin Pop
                                 " drbd8, cannot migrate.", errors.ECODE_STATE)
5454 53c776b5 Iustin Pop
5455 53c776b5 Iustin Pop
    secondary_nodes = instance.secondary_nodes
5456 53c776b5 Iustin Pop
    if not secondary_nodes:
5457 733a2b6a Iustin Pop
      raise errors.ConfigurationError("No secondary node but using"
5458 733a2b6a Iustin Pop
                                      " drbd8 disk template")
5459 53c776b5 Iustin Pop
5460 53c776b5 Iustin Pop
    i_be = self.cfg.GetClusterInfo().FillBE(instance)
5461 53c776b5 Iustin Pop
5462 53c776b5 Iustin Pop
    target_node = secondary_nodes[0]
5463 53c776b5 Iustin Pop
    # check memory requirements on the secondary node
5464 1b67be9b Guido Trotter
    _CheckNodeFreeMemory(self.lu, target_node, "migrating instance %s" %
5465 53c776b5 Iustin Pop
                         instance.name, i_be[constants.BE_MEMORY],
5466 53c776b5 Iustin Pop
                         instance.hypervisor)
5467 53c776b5 Iustin Pop
5468 53c776b5 Iustin Pop
    # check bridge existance
5469 1b67be9b Guido Trotter
    _CheckInstanceBridgesExist(self.lu, instance, node=target_node)
5470 53c776b5 Iustin Pop
5471 3e06e001 Michael Hanselmann
    if not self.cleanup:
5472 1b67be9b Guido Trotter
      _CheckNodeNotDrained(self.lu, target_node)
5473 53c776b5 Iustin Pop
      result = self.rpc.call_instance_migratable(instance.primary_node,
5474 53c776b5 Iustin Pop
                                                 instance)
5475 045dd6d9 Iustin Pop
      result.Raise("Can't migrate, please use failover",
5476 045dd6d9 Iustin Pop
                   prereq=True, ecode=errors.ECODE_STATE)
5477 53c776b5 Iustin Pop
5478 53c776b5 Iustin Pop
    self.instance = instance
5479 53c776b5 Iustin Pop
5480 53c776b5 Iustin Pop
  def _WaitUntilSync(self):
5481 53c776b5 Iustin Pop
    """Poll with custom rpc for disk sync.
5482 53c776b5 Iustin Pop

5483 53c776b5 Iustin Pop
    This uses our own step-based rpc call.
5484 53c776b5 Iustin Pop

5485 53c776b5 Iustin Pop
    """
5486 53c776b5 Iustin Pop
    self.feedback_fn("* wait until resync is done")
5487 53c776b5 Iustin Pop
    all_done = False
5488 53c776b5 Iustin Pop
    while not all_done:
5489 53c776b5 Iustin Pop
      all_done = True
5490 53c776b5 Iustin Pop
      result = self.rpc.call_drbd_wait_sync(self.all_nodes,
5491 53c776b5 Iustin Pop
                                            self.nodes_ip,
5492 53c776b5 Iustin Pop
                                            self.instance.disks)
5493 53c776b5 Iustin Pop
      min_percent = 100
5494 53c776b5 Iustin Pop
      for node, nres in result.items():
5495 4c4e4e1e Iustin Pop
        nres.Raise("Cannot resync disks on node %s" % node)
5496 0959c824 Iustin Pop
        node_done, node_percent = nres.payload
5497 53c776b5 Iustin Pop
        all_done = all_done and node_done
5498 53c776b5 Iustin Pop
        if node_percent is not None:
5499 53c776b5 Iustin Pop
          min_percent = min(min_percent, node_percent)
5500 53c776b5 Iustin Pop
      if not all_done:
5501 53c776b5 Iustin Pop
        if min_percent < 100:
5502 53c776b5 Iustin Pop
          self.feedback_fn("   - progress: %.1f%%" % min_percent)
5503 53c776b5 Iustin Pop
        time.sleep(2)
5504 53c776b5 Iustin Pop
5505 53c776b5 Iustin Pop
  def _EnsureSecondary(self, node):
5506 53c776b5 Iustin Pop
    """Demote a node to secondary.
5507 53c776b5 Iustin Pop

5508 53c776b5 Iustin Pop
    """
5509 53c776b5 Iustin Pop
    self.feedback_fn("* switching node %s to secondary mode" % node)
5510 53c776b5 Iustin Pop
5511 53c776b5 Iustin Pop
    for dev in self.instance.disks:
5512 53c776b5 Iustin Pop
      self.cfg.SetDiskID(dev, node)
5513 53c776b5 Iustin Pop
5514 53c776b5 Iustin Pop
    result = self.rpc.call_blockdev_close(node, self.instance.name,
5515 53c776b5 Iustin Pop
                                          self.instance.disks)
5516 4c4e4e1e Iustin Pop
    result.Raise("Cannot change disk to secondary on node %s" % node)
5517 53c776b5 Iustin Pop
5518 53c776b5 Iustin Pop
  def _GoStandalone(self):
5519 53c776b5 Iustin Pop
    """Disconnect from the network.
5520 53c776b5 Iustin Pop

5521 53c776b5 Iustin Pop
    """
5522 53c776b5 Iustin Pop
    self.feedback_fn("* changing into standalone mode")
5523 53c776b5 Iustin Pop
    result = self.rpc.call_drbd_disconnect_net(self.all_nodes, self.nodes_ip,
5524 53c776b5 Iustin Pop
                                               self.instance.disks)
5525 53c776b5 Iustin Pop
    for node, nres in result.items():
5526 4c4e4e1e Iustin Pop
      nres.Raise("Cannot disconnect disks node %s" % node)
5527 53c776b5 Iustin Pop
5528 53c776b5 Iustin Pop
  def _GoReconnect(self, multimaster):
5529 53c776b5 Iustin Pop
    """Reconnect to the network.
5530 53c776b5 Iustin Pop

5531 53c776b5 Iustin Pop
    """
5532 53c776b5 Iustin Pop
    if multimaster:
5533 53c776b5 Iustin Pop
      msg = "dual-master"
5534 53c776b5 Iustin Pop
    else:
5535 53c776b5 Iustin Pop
      msg = "single-master"
5536 53c776b5 Iustin Pop
    self.feedback_fn("* changing disks into %s mode" % msg)
5537 53c776b5 Iustin Pop
    result = self.rpc.call_drbd_attach_net(self.all_nodes, self.nodes_ip,
5538 53c776b5 Iustin Pop
                                           self.instance.disks,
5539 53c776b5 Iustin Pop
                                           self.instance.name, multimaster)
5540 53c776b5 Iustin Pop
    for node, nres in result.items():
5541 4c4e4e1e Iustin Pop
      nres.Raise("Cannot change disks config on node %s" % node)
5542 53c776b5 Iustin Pop
5543 53c776b5 Iustin Pop
  def _ExecCleanup(self):
5544 53c776b5 Iustin Pop
    """Try to cleanup after a failed migration.
5545 53c776b5 Iustin Pop

5546 53c776b5 Iustin Pop
    The cleanup is done by:
5547 53c776b5 Iustin Pop
      - check that the instance is running only on one node
5548 53c776b5 Iustin Pop
        (and update the config if needed)
5549 53c776b5 Iustin Pop
      - change disks on its secondary node to secondary
5550 53c776b5 Iustin Pop
      - wait until disks are fully synchronized
5551 53c776b5 Iustin Pop
      - disconnect from the network
5552 53c776b5 Iustin Pop
      - change disks into single-master mode
5553 53c776b5 Iustin Pop
      - wait again until disks are fully synchronized
5554 53c776b5 Iustin Pop

5555 53c776b5 Iustin Pop
    """
5556 53c776b5 Iustin Pop
    instance = self.instance
5557 53c776b5 Iustin Pop
    target_node = self.target_node
5558 53c776b5 Iustin Pop
    source_node = self.source_node
5559 53c776b5 Iustin Pop
5560 53c776b5 Iustin Pop
    # check running on only one node
5561 53c776b5 Iustin Pop
    self.feedback_fn("* checking where the instance actually runs"
5562 53c776b5 Iustin Pop
                     " (if this hangs, the hypervisor might be in"
5563 53c776b5 Iustin Pop
                     " a bad state)")
5564 53c776b5 Iustin Pop
    ins_l = self.rpc.call_instance_list(self.all_nodes, [instance.hypervisor])
5565 53c776b5 Iustin Pop
    for node, result in ins_l.items():
5566 4c4e4e1e Iustin Pop
      result.Raise("Can't contact node %s" % node)
5567 53c776b5 Iustin Pop
5568 aca13712 Iustin Pop
    runningon_source = instance.name in ins_l[source_node].payload
5569 aca13712 Iustin Pop
    runningon_target = instance.name in ins_l[target_node].payload
5570 53c776b5 Iustin Pop
5571 53c776b5 Iustin Pop
    if runningon_source and runningon_target:
5572 53c776b5 Iustin Pop
      raise errors.OpExecError("Instance seems to be running on two nodes,"
5573 53c776b5 Iustin Pop
                               " or the hypervisor is confused. You will have"
5574 53c776b5 Iustin Pop
                               " to ensure manually that it runs only on one"
5575 53c776b5 Iustin Pop
                               " and restart this operation.")
5576 53c776b5 Iustin Pop
5577 53c776b5 Iustin Pop
    if not (runningon_source or runningon_target):
5578 53c776b5 Iustin Pop
      raise errors.OpExecError("Instance does not seem to be running at all."
5579 53c776b5 Iustin Pop
                               " In this case, it's safer to repair by"
5580 53c776b5 Iustin Pop
                               " running 'gnt-instance stop' to ensure disk"
5581 53c776b5 Iustin Pop
                               " shutdown, and then restarting it.")
5582 53c776b5 Iustin Pop
5583 53c776b5 Iustin Pop
    if runningon_target:
5584 53c776b5 Iustin Pop
      # the migration has actually succeeded, we need to update the config
5585 53c776b5 Iustin Pop
      self.feedback_fn("* instance running on secondary node (%s),"
5586 53c776b5 Iustin Pop
                       " updating config" % target_node)
5587 53c776b5 Iustin Pop
      instance.primary_node = target_node
5588 a4eae71f Michael Hanselmann
      self.cfg.Update(instance, self.feedback_fn)
5589 53c776b5 Iustin Pop
      demoted_node = source_node
5590 53c776b5 Iustin Pop
    else:
5591 53c776b5 Iustin Pop
      self.feedback_fn("* instance confirmed to be running on its"
5592 53c776b5 Iustin Pop
                       " primary node (%s)" % source_node)
5593 53c776b5 Iustin Pop
      demoted_node = target_node
5594 53c776b5 Iustin Pop
5595 53c776b5 Iustin Pop
    self._EnsureSecondary(demoted_node)
5596 53c776b5 Iustin Pop
    try:
5597 53c776b5 Iustin Pop
      self._WaitUntilSync()
5598 53c776b5 Iustin Pop
    except errors.OpExecError:
5599 53c776b5 Iustin Pop
      # we ignore here errors, since if the device is standalone, it
5600 53c776b5 Iustin Pop
      # won't be able to sync
5601 53c776b5 Iustin Pop
      pass
5602 53c776b5 Iustin Pop
    self._GoStandalone()
5603 53c776b5 Iustin Pop
    self._GoReconnect(False)
5604 53c776b5 Iustin Pop
    self._WaitUntilSync()
5605 53c776b5 Iustin Pop
5606 53c776b5 Iustin Pop
    self.feedback_fn("* done")
5607 53c776b5 Iustin Pop
5608 6906a9d8 Guido Trotter
  def _RevertDiskStatus(self):
5609 6906a9d8 Guido Trotter
    """Try to revert the disk status after a failed migration.
5610 6906a9d8 Guido Trotter

5611 6906a9d8 Guido Trotter
    """
5612 6906a9d8 Guido Trotter
    target_node = self.target_node
5613 6906a9d8 Guido Trotter
    try:
5614 6906a9d8 Guido Trotter
      self._EnsureSecondary(target_node)
5615 6906a9d8 Guido Trotter
      self._GoStandalone()
5616 6906a9d8 Guido Trotter
      self._GoReconnect(False)
5617 6906a9d8 Guido Trotter
      self._WaitUntilSync()
5618 6906a9d8 Guido Trotter
    except errors.OpExecError, err:
5619 3e06e001 Michael Hanselmann
      self.lu.LogWarning("Migration failed and I can't reconnect the"
5620 3e06e001 Michael Hanselmann
                         " drives: error '%s'\n"
5621 3e06e001 Michael Hanselmann
                         "Please look and recover the instance status" %
5622 3e06e001 Michael Hanselmann
                         str(err))
5623 6906a9d8 Guido Trotter
5624 6906a9d8 Guido Trotter
  def _AbortMigration(self):
5625 6906a9d8 Guido Trotter
    """Call the hypervisor code to abort a started migration.
5626 6906a9d8 Guido Trotter

5627 6906a9d8 Guido Trotter
    """
5628 6906a9d8 Guido Trotter
    instance = self.instance
5629 6906a9d8 Guido Trotter
    target_node = self.target_node
5630 6906a9d8 Guido Trotter
    migration_info = self.migration_info
5631 6906a9d8 Guido Trotter
5632 6906a9d8 Guido Trotter
    abort_result = self.rpc.call_finalize_migration(target_node,
5633 6906a9d8 Guido Trotter
                                                    instance,
5634 6906a9d8 Guido Trotter
                                                    migration_info,
5635 6906a9d8 Guido Trotter
                                                    False)
5636 4c4e4e1e Iustin Pop
    abort_msg = abort_result.fail_msg
5637 6906a9d8 Guido Trotter
    if abort_msg:
5638 099c52ad Iustin Pop
      logging.error("Aborting migration failed on target node %s: %s",
5639 099c52ad Iustin Pop
                    target_node, abort_msg)
5640 6906a9d8 Guido Trotter
      # Don't raise an exception here, as we stil have to try to revert the
5641 6906a9d8 Guido Trotter
      # disk status, even if this step failed.
5642 6906a9d8 Guido Trotter
5643 53c776b5 Iustin Pop
  def _ExecMigration(self):
5644 53c776b5 Iustin Pop
    """Migrate an instance.
5645 53c776b5 Iustin Pop

5646 53c776b5 Iustin Pop
    The migrate is done by:
5647 53c776b5 Iustin Pop
      - change the disks into dual-master mode
5648 53c776b5 Iustin Pop
      - wait until disks are fully synchronized again
5649 53c776b5 Iustin Pop
      - migrate the instance
5650 53c776b5 Iustin Pop
      - change disks on the new secondary node (the old primary) to secondary
5651 53c776b5 Iustin Pop
      - wait until disks are fully synchronized
5652 53c776b5 Iustin Pop
      - change disks into single-master mode
5653 53c776b5 Iustin Pop

5654 53c776b5 Iustin Pop
    """
5655 53c776b5 Iustin Pop
    instance = self.instance
5656 53c776b5 Iustin Pop
    target_node = self.target_node
5657 53c776b5 Iustin Pop
    source_node = self.source_node
5658 53c776b5 Iustin Pop
5659 53c776b5 Iustin Pop
    self.feedback_fn("* checking disk consistency between source and target")
5660 53c776b5 Iustin Pop
    for dev in instance.disks:
5661 1b67be9b Guido Trotter
      if not _CheckDiskConsistency(self.lu, dev, target_node, False):
5662 53c776b5 Iustin Pop
        raise errors.OpExecError("Disk %s is degraded or not fully"
5663 53c776b5 Iustin Pop
                                 " synchronized on target node,"
5664 53c776b5 Iustin Pop
                                 " aborting migrate." % dev.iv_name)
5665 53c776b5 Iustin Pop
5666 6906a9d8 Guido Trotter
    # First get the migration information from the remote node
5667 6906a9d8 Guido Trotter
    result = self.rpc.call_migration_info(source_node, instance)
5668 4c4e4e1e Iustin Pop
    msg = result.fail_msg
5669 6906a9d8 Guido Trotter
    if msg:
5670 6906a9d8 Guido Trotter
      log_err = ("Failed fetching source migration information from %s: %s" %
5671 0959c824 Iustin Pop
                 (source_node, msg))
5672 6906a9d8 Guido Trotter
      logging.error(log_err)
5673 6906a9d8 Guido Trotter
      raise errors.OpExecError(log_err)
5674 6906a9d8 Guido Trotter
5675 0959c824 Iustin Pop
    self.migration_info = migration_info = result.payload
5676 6906a9d8 Guido Trotter
5677 6906a9d8 Guido Trotter
    # Then switch the disks to master/master mode
5678 53c776b5 Iustin Pop
    self._EnsureSecondary(target_node)
5679 53c776b5 Iustin Pop
    self._GoStandalone()
5680 53c776b5 Iustin Pop
    self._GoReconnect(True)
5681 53c776b5 Iustin Pop
    self._WaitUntilSync()
5682 53c776b5 Iustin Pop
5683 6906a9d8 Guido Trotter
    self.feedback_fn("* preparing %s to accept the instance" % target_node)
5684 6906a9d8 Guido Trotter
    result = self.rpc.call_accept_instance(target_node,
5685 6906a9d8 Guido Trotter
                                           instance,
5686 6906a9d8 Guido Trotter
                                           migration_info,
5687 6906a9d8 Guido Trotter
                                           self.nodes_ip[target_node])
5688 6906a9d8 Guido Trotter
5689 4c4e4e1e Iustin Pop
    msg = result.fail_msg
5690 6906a9d8 Guido Trotter
    if msg:
5691 6906a9d8 Guido Trotter
      logging.error("Instance pre-migration failed, trying to revert"
5692 6906a9d8 Guido Trotter
                    " disk status: %s", msg)
5693 78212a5d Iustin Pop
      self.feedback_fn("Pre-migration failed, aborting")
5694 6906a9d8 Guido Trotter
      self._AbortMigration()
5695 6906a9d8 Guido Trotter
      self._RevertDiskStatus()
5696 6906a9d8 Guido Trotter
      raise errors.OpExecError("Could not pre-migrate instance %s: %s" %
5697 6906a9d8 Guido Trotter
                               (instance.name, msg))
5698 6906a9d8 Guido Trotter
5699 53c776b5 Iustin Pop
    self.feedback_fn("* migrating instance to %s" % target_node)
5700 53c776b5 Iustin Pop
    time.sleep(10)
5701 53c776b5 Iustin Pop
    result = self.rpc.call_instance_migrate(source_node, instance,
5702 53c776b5 Iustin Pop
                                            self.nodes_ip[target_node],
5703 3e06e001 Michael Hanselmann
                                            self.live)
5704 4c4e4e1e Iustin Pop
    msg = result.fail_msg
5705 53c776b5 Iustin Pop
    if msg:
5706 53c776b5 Iustin Pop
      logging.error("Instance migration failed, trying to revert"
5707 53c776b5 Iustin Pop
                    " disk status: %s", msg)
5708 78212a5d Iustin Pop
      self.feedback_fn("Migration failed, aborting")
5709 6906a9d8 Guido Trotter
      self._AbortMigration()
5710 6906a9d8 Guido Trotter
      self._RevertDiskStatus()
5711 53c776b5 Iustin Pop
      raise errors.OpExecError("Could not migrate instance %s: %s" %
5712 53c776b5 Iustin Pop
                               (instance.name, msg))
5713 53c776b5 Iustin Pop
    time.sleep(10)
5714 53c776b5 Iustin Pop
5715 53c776b5 Iustin Pop
    instance.primary_node = target_node
5716 53c776b5 Iustin Pop
    # distribute new instance config to the other nodes
5717 a4eae71f Michael Hanselmann
    self.cfg.Update(instance, self.feedback_fn)
5718 53c776b5 Iustin Pop
5719 6906a9d8 Guido Trotter
    result = self.rpc.call_finalize_migration(target_node,
5720 6906a9d8 Guido Trotter
                                              instance,
5721 6906a9d8 Guido Trotter
                                              migration_info,
5722 6906a9d8 Guido Trotter
                                              True)
5723 4c4e4e1e Iustin Pop
    msg = result.fail_msg
5724 6906a9d8 Guido Trotter
    if msg:
5725 6906a9d8 Guido Trotter
      logging.error("Instance migration succeeded, but finalization failed:"
5726 099c52ad Iustin Pop
                    " %s", msg)
5727 6906a9d8 Guido Trotter
      raise errors.OpExecError("Could not finalize instance migration: %s" %
5728 6906a9d8 Guido Trotter
                               msg)
5729 6906a9d8 Guido Trotter
5730 53c776b5 Iustin Pop
    self._EnsureSecondary(source_node)
5731 53c776b5 Iustin Pop
    self._WaitUntilSync()
5732 53c776b5 Iustin Pop
    self._GoStandalone()
5733 53c776b5 Iustin Pop
    self._GoReconnect(False)
5734 53c776b5 Iustin Pop
    self._WaitUntilSync()
5735 53c776b5 Iustin Pop
5736 53c776b5 Iustin Pop
    self.feedback_fn("* done")
5737 53c776b5 Iustin Pop
5738 53c776b5 Iustin Pop
  def Exec(self, feedback_fn):
5739 53c776b5 Iustin Pop
    """Perform the migration.
5740 53c776b5 Iustin Pop

5741 53c776b5 Iustin Pop
    """
5742 80cb875c Michael Hanselmann
    feedback_fn("Migrating instance %s" % self.instance.name)
5743 80cb875c Michael Hanselmann
5744 53c776b5 Iustin Pop
    self.feedback_fn = feedback_fn
5745 53c776b5 Iustin Pop
5746 53c776b5 Iustin Pop
    self.source_node = self.instance.primary_node
5747 53c776b5 Iustin Pop
    self.target_node = self.instance.secondary_nodes[0]
5748 53c776b5 Iustin Pop
    self.all_nodes = [self.source_node, self.target_node]
5749 53c776b5 Iustin Pop
    self.nodes_ip = {
5750 53c776b5 Iustin Pop
      self.source_node: self.cfg.GetNodeInfo(self.source_node).secondary_ip,
5751 53c776b5 Iustin Pop
      self.target_node: self.cfg.GetNodeInfo(self.target_node).secondary_ip,
5752 53c776b5 Iustin Pop
      }
5753 3e06e001 Michael Hanselmann
5754 3e06e001 Michael Hanselmann
    if self.cleanup:
5755 53c776b5 Iustin Pop
      return self._ExecCleanup()
5756 53c776b5 Iustin Pop
    else:
5757 53c776b5 Iustin Pop
      return self._ExecMigration()
5758 53c776b5 Iustin Pop
5759 53c776b5 Iustin Pop
5760 428958aa Iustin Pop
def _CreateBlockDev(lu, node, instance, device, force_create,
5761 428958aa Iustin Pop
                    info, force_open):
5762 428958aa Iustin Pop
  """Create a tree of block devices on a given node.
5763 a8083063 Iustin Pop

5764 a8083063 Iustin Pop
  If this device type has to be created on secondaries, create it and
5765 a8083063 Iustin Pop
  all its children.
5766 a8083063 Iustin Pop

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

5769 428958aa Iustin Pop
  @param lu: the lu on whose behalf we execute
5770 428958aa Iustin Pop
  @param node: the node on which to create the device
5771 428958aa Iustin Pop
  @type instance: L{objects.Instance}
5772 428958aa Iustin Pop
  @param instance: the instance which owns the device
5773 428958aa Iustin Pop
  @type device: L{objects.Disk}
5774 428958aa Iustin Pop
  @param device: the device to create
5775 428958aa Iustin Pop
  @type force_create: boolean
5776 428958aa Iustin Pop
  @param force_create: whether to force creation of this device; this
5777 428958aa Iustin Pop
      will be change to True whenever we find a device which has
5778 428958aa Iustin Pop
      CreateOnSecondary() attribute
5779 428958aa Iustin Pop
  @param info: the extra 'metadata' we should attach to the device
5780 428958aa Iustin Pop
      (this will be represented as a LVM tag)
5781 428958aa Iustin Pop
  @type force_open: boolean
5782 428958aa Iustin Pop
  @param force_open: this parameter will be passes to the
5783 821d1bd1 Iustin Pop
      L{backend.BlockdevCreate} function where it specifies
5784 428958aa Iustin Pop
      whether we run on primary or not, and it affects both
5785 428958aa Iustin Pop
      the child assembly and the device own Open() execution
5786 428958aa Iustin Pop

5787 a8083063 Iustin Pop
  """
5788 a8083063 Iustin Pop
  if device.CreateOnSecondary():
5789 428958aa Iustin Pop
    force_create = True
5790 796cab27 Iustin Pop
5791 a8083063 Iustin Pop
  if device.children:
5792 a8083063 Iustin Pop
    for child in device.children:
5793 428958aa Iustin Pop
      _CreateBlockDev(lu, node, instance, child, force_create,
5794 428958aa Iustin Pop
                      info, force_open)
5795 a8083063 Iustin Pop
5796 428958aa Iustin Pop
  if not force_create:
5797 796cab27 Iustin Pop
    return
5798 796cab27 Iustin Pop
5799 de12473a Iustin Pop
  _CreateSingleBlockDev(lu, node, instance, device, info, force_open)
5800 de12473a Iustin Pop
5801 de12473a Iustin Pop
5802 de12473a Iustin Pop
def _CreateSingleBlockDev(lu, node, instance, device, info, force_open):
5803 de12473a Iustin Pop
  """Create a single block device on a given node.
5804 de12473a Iustin Pop

5805 de12473a Iustin Pop
  This will not recurse over children of the device, so they must be
5806 de12473a Iustin Pop
  created in advance.
5807 de12473a Iustin Pop

5808 de12473a Iustin Pop
  @param lu: the lu on whose behalf we execute
5809 de12473a Iustin Pop
  @param node: the node on which to create the device
5810 de12473a Iustin Pop
  @type instance: L{objects.Instance}
5811 de12473a Iustin Pop
  @param instance: the instance which owns the device
5812 de12473a Iustin Pop
  @type device: L{objects.Disk}
5813 de12473a Iustin Pop
  @param device: the device to create
5814 de12473a Iustin Pop
  @param info: the extra 'metadata' we should attach to the device
5815 de12473a Iustin Pop
      (this will be represented as a LVM tag)
5816 de12473a Iustin Pop
  @type force_open: boolean
5817 de12473a Iustin Pop
  @param force_open: this parameter will be passes to the
5818 821d1bd1 Iustin Pop
      L{backend.BlockdevCreate} function where it specifies
5819 de12473a Iustin Pop
      whether we run on primary or not, and it affects both
5820 de12473a Iustin Pop
      the child assembly and the device own Open() execution
5821 de12473a Iustin Pop

5822 de12473a Iustin Pop
  """
5823 b9bddb6b Iustin Pop
  lu.cfg.SetDiskID(device, node)
5824 7d81697f Iustin Pop
  result = lu.rpc.call_blockdev_create(node, device, device.size,
5825 428958aa Iustin Pop
                                       instance.name, force_open, info)
5826 4c4e4e1e Iustin Pop
  result.Raise("Can't create block device %s on"
5827 4c4e4e1e Iustin Pop
               " node %s for instance %s" % (device, node, instance.name))
5828 a8083063 Iustin Pop
  if device.physical_id is None:
5829 0959c824 Iustin Pop
    device.physical_id = result.payload
5830 a8083063 Iustin Pop
5831 a8083063 Iustin Pop
5832 b9bddb6b Iustin Pop
def _GenerateUniqueNames(lu, exts):
5833 923b1523 Iustin Pop
  """Generate a suitable LV name.
5834 923b1523 Iustin Pop

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

5837 923b1523 Iustin Pop
  """
5838 923b1523 Iustin Pop
  results = []
5839 923b1523 Iustin Pop
  for val in exts:
5840 4fae38c5 Guido Trotter
    new_id = lu.cfg.GenerateUniqueID(lu.proc.GetECId())
5841 923b1523 Iustin Pop
    results.append("%s%s" % (new_id, val))
5842 923b1523 Iustin Pop
  return results
5843 923b1523 Iustin Pop
5844 923b1523 Iustin Pop
5845 b9bddb6b Iustin Pop
def _GenerateDRBD8Branch(lu, primary, secondary, size, names, iv_name,
5846 ffa1c0dc Iustin Pop
                         p_minor, s_minor):
5847 a1f445d3 Iustin Pop
  """Generate a drbd8 device complete with its children.
5848 a1f445d3 Iustin Pop

5849 a1f445d3 Iustin Pop
  """
5850 b9bddb6b Iustin Pop
  port = lu.cfg.AllocatePort()
5851 b9bddb6b Iustin Pop
  vgname = lu.cfg.GetVGName()
5852 afa1386e Guido Trotter
  shared_secret = lu.cfg.GenerateDRBDSecret(lu.proc.GetECId())
5853 a1f445d3 Iustin Pop
  dev_data = objects.Disk(dev_type=constants.LD_LV, size=size,
5854 a1f445d3 Iustin Pop
                          logical_id=(vgname, names[0]))
5855 a1f445d3 Iustin Pop
  dev_meta = objects.Disk(dev_type=constants.LD_LV, size=128,
5856 a1f445d3 Iustin Pop
                          logical_id=(vgname, names[1]))
5857 a1f445d3 Iustin Pop
  drbd_dev = objects.Disk(dev_type=constants.LD_DRBD8, size=size,
5858 ffa1c0dc Iustin Pop
                          logical_id=(primary, secondary, port,
5859 f9518d38 Iustin Pop
                                      p_minor, s_minor,
5860 f9518d38 Iustin Pop
                                      shared_secret),
5861 ffa1c0dc Iustin Pop
                          children=[dev_data, dev_meta],
5862 a1f445d3 Iustin Pop
                          iv_name=iv_name)
5863 a1f445d3 Iustin Pop
  return drbd_dev
5864 a1f445d3 Iustin Pop
5865 7c0d6283 Michael Hanselmann
5866 b9bddb6b Iustin Pop
def _GenerateDiskTemplate(lu, template_name,
5867 a8083063 Iustin Pop
                          instance_name, primary_node,
5868 08db7c5c Iustin Pop
                          secondary_nodes, disk_info,
5869 e2a65344 Iustin Pop
                          file_storage_dir, file_driver,
5870 e2a65344 Iustin Pop
                          base_index):
5871 a8083063 Iustin Pop
  """Generate the entire disk layout for a given template type.
5872 a8083063 Iustin Pop

5873 a8083063 Iustin Pop
  """
5874 a8083063 Iustin Pop
  #TODO: compute space requirements
5875 a8083063 Iustin Pop
5876 b9bddb6b Iustin Pop
  vgname = lu.cfg.GetVGName()
5877 08db7c5c Iustin Pop
  disk_count = len(disk_info)
5878 08db7c5c Iustin Pop
  disks = []
5879 3517d9b9 Manuel Franceschini
  if template_name == constants.DT_DISKLESS:
5880 08db7c5c Iustin Pop
    pass
5881 3517d9b9 Manuel Franceschini
  elif template_name == constants.DT_PLAIN:
5882 a8083063 Iustin Pop
    if len(secondary_nodes) != 0:
5883 a8083063 Iustin Pop
      raise errors.ProgrammerError("Wrong template configuration")
5884 923b1523 Iustin Pop
5885 fb4b324b Guido Trotter
    names = _GenerateUniqueNames(lu, [".disk%d" % (base_index + i)
5886 08db7c5c Iustin Pop
                                      for i in range(disk_count)])
5887 08db7c5c Iustin Pop
    for idx, disk in enumerate(disk_info):
5888 e2a65344 Iustin Pop
      disk_index = idx + base_index
5889 08db7c5c Iustin Pop
      disk_dev = objects.Disk(dev_type=constants.LD_LV, size=disk["size"],
5890 08db7c5c Iustin Pop
                              logical_id=(vgname, names[idx]),
5891 6ec66eae Iustin Pop
                              iv_name="disk/%d" % disk_index,
5892 6ec66eae Iustin Pop
                              mode=disk["mode"])
5893 08db7c5c Iustin Pop
      disks.append(disk_dev)
5894 a1f445d3 Iustin Pop
  elif template_name == constants.DT_DRBD8:
5895 a1f445d3 Iustin Pop
    if len(secondary_nodes) != 1:
5896 a1f445d3 Iustin Pop
      raise errors.ProgrammerError("Wrong template configuration")
5897 a1f445d3 Iustin Pop
    remote_node = secondary_nodes[0]
5898 08db7c5c Iustin Pop
    minors = lu.cfg.AllocateDRBDMinor(
5899 08db7c5c Iustin Pop
      [primary_node, remote_node] * len(disk_info), instance_name)
5900 08db7c5c Iustin Pop
5901 e6c1ff2f Iustin Pop
    names = []
5902 fb4b324b Guido Trotter
    for lv_prefix in _GenerateUniqueNames(lu, [".disk%d" % (base_index + i)
5903 e6c1ff2f Iustin Pop
                                               for i in range(disk_count)]):
5904 e6c1ff2f Iustin Pop
      names.append(lv_prefix + "_data")
5905 e6c1ff2f Iustin Pop
      names.append(lv_prefix + "_meta")
5906 08db7c5c Iustin Pop
    for idx, disk in enumerate(disk_info):
5907 112050d9 Iustin Pop
      disk_index = idx + base_index
5908 08db7c5c Iustin Pop
      disk_dev = _GenerateDRBD8Branch(lu, primary_node, remote_node,
5909 08db7c5c Iustin Pop
                                      disk["size"], names[idx*2:idx*2+2],
5910 e2a65344 Iustin Pop
                                      "disk/%d" % disk_index,
5911 08db7c5c Iustin Pop
                                      minors[idx*2], minors[idx*2+1])
5912 6ec66eae Iustin Pop
      disk_dev.mode = disk["mode"]
5913 08db7c5c Iustin Pop
      disks.append(disk_dev)
5914 0f1a06e3 Manuel Franceschini
  elif template_name == constants.DT_FILE:
5915 0f1a06e3 Manuel Franceschini
    if len(secondary_nodes) != 0:
5916 0f1a06e3 Manuel Franceschini
      raise errors.ProgrammerError("Wrong template configuration")
5917 0f1a06e3 Manuel Franceschini
5918 0e3baaf3 Iustin Pop
    _RequireFileStorage()
5919 0e3baaf3 Iustin Pop
5920 08db7c5c Iustin Pop
    for idx, disk in enumerate(disk_info):
5921 112050d9 Iustin Pop
      disk_index = idx + base_index
5922 08db7c5c Iustin Pop
      disk_dev = objects.Disk(dev_type=constants.LD_FILE, size=disk["size"],
5923 e2a65344 Iustin Pop
                              iv_name="disk/%d" % disk_index,
5924 08db7c5c Iustin Pop
                              logical_id=(file_driver,
5925 08db7c5c Iustin Pop
                                          "%s/disk%d" % (file_storage_dir,
5926 43e99cff Guido Trotter
                                                         disk_index)),
5927 6ec66eae Iustin Pop
                              mode=disk["mode"])
5928 08db7c5c Iustin Pop
      disks.append(disk_dev)
5929 a8083063 Iustin Pop
  else:
5930 a8083063 Iustin Pop
    raise errors.ProgrammerError("Invalid disk template '%s'" % template_name)
5931 a8083063 Iustin Pop
  return disks
5932 a8083063 Iustin Pop
5933 a8083063 Iustin Pop
5934 a0c3fea1 Michael Hanselmann
def _GetInstanceInfoText(instance):
5935 3ecf6786 Iustin Pop
  """Compute that text that should be added to the disk's metadata.
5936 3ecf6786 Iustin Pop

5937 3ecf6786 Iustin Pop
  """
5938 a0c3fea1 Michael Hanselmann
  return "originstname+%s" % instance.name
5939 a0c3fea1 Michael Hanselmann
5940 a0c3fea1 Michael Hanselmann
5941 621b7678 Iustin Pop
def _CreateDisks(lu, instance, to_skip=None, target_node=None):
5942 a8083063 Iustin Pop
  """Create all disks for an instance.
5943 a8083063 Iustin Pop

5944 a8083063 Iustin Pop
  This abstracts away some work from AddInstance.
5945 a8083063 Iustin Pop

5946 e4376078 Iustin Pop
  @type lu: L{LogicalUnit}
5947 e4376078 Iustin Pop
  @param lu: the logical unit on whose behalf we execute
5948 e4376078 Iustin Pop
  @type instance: L{objects.Instance}
5949 e4376078 Iustin Pop
  @param instance: the instance whose disks we should create
5950 bd315bfa Iustin Pop
  @type to_skip: list
5951 bd315bfa Iustin Pop
  @param to_skip: list of indices to skip
5952 621b7678 Iustin Pop
  @type target_node: string
5953 621b7678 Iustin Pop
  @param target_node: if passed, overrides the target node for creation
5954 e4376078 Iustin Pop
  @rtype: boolean
5955 e4376078 Iustin Pop
  @return: the success of the creation
5956 a8083063 Iustin Pop

5957 a8083063 Iustin Pop
  """
5958 a0c3fea1 Michael Hanselmann
  info = _GetInstanceInfoText(instance)
5959 621b7678 Iustin Pop
  if target_node is None:
5960 621b7678 Iustin Pop
    pnode = instance.primary_node
5961 621b7678 Iustin Pop
    all_nodes = instance.all_nodes
5962 621b7678 Iustin Pop
  else:
5963 621b7678 Iustin Pop
    pnode = target_node
5964 621b7678 Iustin Pop
    all_nodes = [pnode]
5965 a0c3fea1 Michael Hanselmann
5966 0f1a06e3 Manuel Franceschini
  if instance.disk_template == constants.DT_FILE:
5967 0f1a06e3 Manuel Franceschini
    file_storage_dir = os.path.dirname(instance.disks[0].logical_id[1])
5968 428958aa Iustin Pop
    result = lu.rpc.call_file_storage_dir_create(pnode, file_storage_dir)
5969 0f1a06e3 Manuel Franceschini
5970 4c4e4e1e Iustin Pop
    result.Raise("Failed to create directory '%s' on"
5971 9b4127eb Guido Trotter
                 " node %s" % (file_storage_dir, pnode))
5972 0f1a06e3 Manuel Franceschini
5973 24991749 Iustin Pop
  # Note: this needs to be kept in sync with adding of disks in
5974 24991749 Iustin Pop
  # LUSetInstanceParams
5975 bd315bfa Iustin Pop
  for idx, device in enumerate(instance.disks):
5976 bd315bfa Iustin Pop
    if to_skip and idx in to_skip:
5977 bd315bfa Iustin Pop
      continue
5978 9a4f63d1 Iustin Pop
    logging.info("Creating volume %s for instance %s",
5979 9a4f63d1 Iustin Pop
                 device.iv_name, instance.name)
5980 a8083063 Iustin Pop
    #HARDCODE
5981 621b7678 Iustin Pop
    for node in all_nodes:
5982 428958aa Iustin Pop
      f_create = node == pnode
5983 428958aa Iustin Pop
      _CreateBlockDev(lu, node, instance, device, f_create, info, f_create)
5984 a8083063 Iustin Pop
5985 a8083063 Iustin Pop
5986 621b7678 Iustin Pop
def _RemoveDisks(lu, instance, target_node=None):
5987 a8083063 Iustin Pop
  """Remove all disks for an instance.
5988 a8083063 Iustin Pop

5989 a8083063 Iustin Pop
  This abstracts away some work from `AddInstance()` and
5990 a8083063 Iustin Pop
  `RemoveInstance()`. Note that in case some of the devices couldn't
5991 1d67656e Iustin Pop
  be removed, the removal will continue with the other ones (compare
5992 a8083063 Iustin Pop
  with `_CreateDisks()`).
5993 a8083063 Iustin Pop

5994 e4376078 Iustin Pop
  @type lu: L{LogicalUnit}
5995 e4376078 Iustin Pop
  @param lu: the logical unit on whose behalf we execute
5996 e4376078 Iustin Pop
  @type instance: L{objects.Instance}
5997 e4376078 Iustin Pop
  @param instance: the instance whose disks we should remove
5998 621b7678 Iustin Pop
  @type target_node: string
5999 621b7678 Iustin Pop
  @param target_node: used to override the node on which to remove the disks
6000 e4376078 Iustin Pop
  @rtype: boolean
6001 e4376078 Iustin Pop
  @return: the success of the removal
6002 a8083063 Iustin Pop

6003 a8083063 Iustin Pop
  """
6004 9a4f63d1 Iustin Pop
  logging.info("Removing block devices for instance %s", instance.name)
6005 a8083063 Iustin Pop
6006 e1bc0878 Iustin Pop
  all_result = True
6007 a8083063 Iustin Pop
  for device in instance.disks:
6008 621b7678 Iustin Pop
    if target_node:
6009 621b7678 Iustin Pop
      edata = [(target_node, device)]
6010 621b7678 Iustin Pop
    else:
6011 621b7678 Iustin Pop
      edata = device.ComputeNodeTree(instance.primary_node)
6012 621b7678 Iustin Pop
    for node, disk in edata:
6013 b9bddb6b Iustin Pop
      lu.cfg.SetDiskID(disk, node)
6014 4c4e4e1e Iustin Pop
      msg = lu.rpc.call_blockdev_remove(node, disk).fail_msg
6015 e1bc0878 Iustin Pop
      if msg:
6016 e1bc0878 Iustin Pop
        lu.LogWarning("Could not remove block device %s on node %s,"
6017 e1bc0878 Iustin Pop
                      " continuing anyway: %s", device.iv_name, node, msg)
6018 e1bc0878 Iustin Pop
        all_result = False
6019 0f1a06e3 Manuel Franceschini
6020 0f1a06e3 Manuel Franceschini
  if instance.disk_template == constants.DT_FILE:
6021 0f1a06e3 Manuel Franceschini
    file_storage_dir = os.path.dirname(instance.disks[0].logical_id[1])
6022 dfc2a24c Guido Trotter
    if target_node:
6023 dfc2a24c Guido Trotter
      tgt = target_node
6024 621b7678 Iustin Pop
    else:
6025 dfc2a24c Guido Trotter
      tgt = instance.primary_node
6026 621b7678 Iustin Pop
    result = lu.rpc.call_file_storage_dir_remove(tgt, file_storage_dir)
6027 621b7678 Iustin Pop
    if result.fail_msg:
6028 b2b8bcce Iustin Pop
      lu.LogWarning("Could not remove directory '%s' on node %s: %s",
6029 621b7678 Iustin Pop
                    file_storage_dir, instance.primary_node, result.fail_msg)
6030 e1bc0878 Iustin Pop
      all_result = False
6031 0f1a06e3 Manuel Franceschini
6032 e1bc0878 Iustin Pop
  return all_result
6033 a8083063 Iustin Pop
6034 a8083063 Iustin Pop
6035 08db7c5c Iustin Pop
def _ComputeDiskSize(disk_template, disks):
6036 e2fe6369 Iustin Pop
  """Compute disk size requirements in the volume group
6037 e2fe6369 Iustin Pop

6038 e2fe6369 Iustin Pop
  """
6039 e2fe6369 Iustin Pop
  # Required free disk space as a function of disk and swap space
6040 e2fe6369 Iustin Pop
  req_size_dict = {
6041 e2fe6369 Iustin Pop
    constants.DT_DISKLESS: None,
6042 08db7c5c Iustin Pop
    constants.DT_PLAIN: sum(d["size"] for d in disks),
6043 08db7c5c Iustin Pop
    # 128 MB are added for drbd metadata for each disk
6044 08db7c5c Iustin Pop
    constants.DT_DRBD8: sum(d["size"] + 128 for d in disks),
6045 e2fe6369 Iustin Pop
    constants.DT_FILE: None,
6046 e2fe6369 Iustin Pop
  }
6047 e2fe6369 Iustin Pop
6048 e2fe6369 Iustin Pop
  if disk_template not in req_size_dict:
6049 e2fe6369 Iustin Pop
    raise errors.ProgrammerError("Disk template '%s' size requirement"
6050 e2fe6369 Iustin Pop
                                 " is unknown" %  disk_template)
6051 e2fe6369 Iustin Pop
6052 e2fe6369 Iustin Pop
  return req_size_dict[disk_template]
6053 e2fe6369 Iustin Pop
6054 e2fe6369 Iustin Pop
6055 74409b12 Iustin Pop
def _CheckHVParams(lu, nodenames, hvname, hvparams):
6056 74409b12 Iustin Pop
  """Hypervisor parameter validation.
6057 74409b12 Iustin Pop

6058 74409b12 Iustin Pop
  This function abstract the hypervisor parameter validation to be
6059 74409b12 Iustin Pop
  used in both instance create and instance modify.
6060 74409b12 Iustin Pop

6061 74409b12 Iustin Pop
  @type lu: L{LogicalUnit}
6062 74409b12 Iustin Pop
  @param lu: the logical unit for which we check
6063 74409b12 Iustin Pop
  @type nodenames: list
6064 74409b12 Iustin Pop
  @param nodenames: the list of nodes on which we should check
6065 74409b12 Iustin Pop
  @type hvname: string
6066 74409b12 Iustin Pop
  @param hvname: the name of the hypervisor we should use
6067 74409b12 Iustin Pop
  @type hvparams: dict
6068 74409b12 Iustin Pop
  @param hvparams: the parameters which we need to check
6069 74409b12 Iustin Pop
  @raise errors.OpPrereqError: if the parameters are not valid
6070 74409b12 Iustin Pop

6071 74409b12 Iustin Pop
  """
6072 74409b12 Iustin Pop
  hvinfo = lu.rpc.call_hypervisor_validate_params(nodenames,
6073 74409b12 Iustin Pop
                                                  hvname,
6074 74409b12 Iustin Pop
                                                  hvparams)
6075 74409b12 Iustin Pop
  for node in nodenames:
6076 781de953 Iustin Pop
    info = hvinfo[node]
6077 68c6f21c Iustin Pop
    if info.offline:
6078 68c6f21c Iustin Pop
      continue
6079 4c4e4e1e Iustin Pop
    info.Raise("Hypervisor parameter validation failed on node %s" % node)
6080 74409b12 Iustin Pop
6081 74409b12 Iustin Pop
6082 a8083063 Iustin Pop
class LUCreateInstance(LogicalUnit):
6083 a8083063 Iustin Pop
  """Create an instance.
6084 a8083063 Iustin Pop

6085 a8083063 Iustin Pop
  """
6086 a8083063 Iustin Pop
  HPATH = "instance-add"
6087 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
6088 f276c4b5 Iustin Pop
  _OP_REQP = ["instance_name", "disks",
6089 08db7c5c Iustin Pop
              "mode", "start",
6090 08db7c5c Iustin Pop
              "wait_for_sync", "ip_check", "nics",
6091 338e51e8 Iustin Pop
              "hvparams", "beparams"]
6092 7baf741d Guido Trotter
  REQ_BGL = False
6093 7baf741d Guido Trotter
6094 5f23e043 Iustin Pop
  def CheckArguments(self):
6095 5f23e043 Iustin Pop
    """Check arguments.
6096 5f23e043 Iustin Pop

6097 5f23e043 Iustin Pop
    """
6098 df4272e5 Iustin Pop
    # set optional parameters to none if they don't exist
6099 f276c4b5 Iustin Pop
    for attr in ["pnode", "snode", "iallocator", "hypervisor",
6100 e588764d Iustin Pop
                 "disk_template", "identify_defaults"]:
6101 df4272e5 Iustin Pop
      if not hasattr(self.op, attr):
6102 df4272e5 Iustin Pop
        setattr(self.op, attr, None)
6103 df4272e5 Iustin Pop
6104 5f23e043 Iustin Pop
    # do not require name_check to ease forward/backward compatibility
6105 5f23e043 Iustin Pop
    # for tools
6106 5f23e043 Iustin Pop
    if not hasattr(self.op, "name_check"):
6107 5f23e043 Iustin Pop
      self.op.name_check = True
6108 25a8792c Iustin Pop
    if not hasattr(self.op, "no_install"):
6109 25a8792c Iustin Pop
      self.op.no_install = False
6110 25a8792c Iustin Pop
    if self.op.no_install and self.op.start:
6111 25a8792c Iustin Pop
      self.LogInfo("No-installation mode selected, disabling startup")
6112 25a8792c Iustin Pop
      self.op.start = False
6113 44caf5a8 Iustin Pop
    # validate/normalize the instance name
6114 44caf5a8 Iustin Pop
    self.op.instance_name = utils.HostInfo.NormalizeName(self.op.instance_name)
6115 5f23e043 Iustin Pop
    if self.op.ip_check and not self.op.name_check:
6116 5f23e043 Iustin Pop
      # TODO: make the ip check more flexible and not depend on the name check
6117 5f23e043 Iustin Pop
      raise errors.OpPrereqError("Cannot do ip checks without a name check",
6118 5f23e043 Iustin Pop
                                 errors.ECODE_INVAL)
6119 c3589cf8 Iustin Pop
    # check disk information: either all adopt, or no adopt
6120 c3589cf8 Iustin Pop
    has_adopt = has_no_adopt = False
6121 c3589cf8 Iustin Pop
    for disk in self.op.disks:
6122 c3589cf8 Iustin Pop
      if "adopt" in disk:
6123 c3589cf8 Iustin Pop
        has_adopt = True
6124 c3589cf8 Iustin Pop
      else:
6125 c3589cf8 Iustin Pop
        has_no_adopt = True
6126 c3589cf8 Iustin Pop
    if has_adopt and has_no_adopt:
6127 417eabe2 Iustin Pop
      raise errors.OpPrereqError("Either all disks are adopted or none is",
6128 c3589cf8 Iustin Pop
                                 errors.ECODE_INVAL)
6129 c3589cf8 Iustin Pop
    if has_adopt:
6130 c3589cf8 Iustin Pop
      if self.op.disk_template != constants.DT_PLAIN:
6131 c3589cf8 Iustin Pop
        raise errors.OpPrereqError("Disk adoption is only supported for the"
6132 c3589cf8 Iustin Pop
                                   " 'plain' disk template",
6133 c3589cf8 Iustin Pop
                                   errors.ECODE_INVAL)
6134 c3589cf8 Iustin Pop
      if self.op.iallocator is not None:
6135 c3589cf8 Iustin Pop
        raise errors.OpPrereqError("Disk adoption not allowed with an"
6136 c3589cf8 Iustin Pop
                                   " iallocator script", errors.ECODE_INVAL)
6137 c3589cf8 Iustin Pop
      if self.op.mode == constants.INSTANCE_IMPORT:
6138 c3589cf8 Iustin Pop
        raise errors.OpPrereqError("Disk adoption not allowed for"
6139 c3589cf8 Iustin Pop
                                   " instance import", errors.ECODE_INVAL)
6140 c3589cf8 Iustin Pop
6141 c3589cf8 Iustin Pop
    self.adopt_disks = has_adopt
6142 5f23e043 Iustin Pop
6143 417eabe2 Iustin Pop
    # verify creation mode
6144 417eabe2 Iustin Pop
    if self.op.mode not in (constants.INSTANCE_CREATE,
6145 417eabe2 Iustin Pop
                            constants.INSTANCE_IMPORT):
6146 417eabe2 Iustin Pop
      raise errors.OpPrereqError("Invalid instance creation mode '%s'" %
6147 417eabe2 Iustin Pop
                                 self.op.mode, errors.ECODE_INVAL)
6148 417eabe2 Iustin Pop
6149 417eabe2 Iustin Pop
    # instance name verification
6150 417eabe2 Iustin Pop
    if self.op.name_check:
6151 417eabe2 Iustin Pop
      self.hostname1 = utils.GetHostInfo(self.op.instance_name)
6152 417eabe2 Iustin Pop
      self.op.instance_name = self.hostname1.name
6153 417eabe2 Iustin Pop
      # used in CheckPrereq for ip ping check
6154 417eabe2 Iustin Pop
      self.check_ip = self.hostname1.ip
6155 417eabe2 Iustin Pop
    else:
6156 417eabe2 Iustin Pop
      self.check_ip = None
6157 417eabe2 Iustin Pop
6158 417eabe2 Iustin Pop
    # file storage checks
6159 417eabe2 Iustin Pop
    if (self.op.file_driver and
6160 417eabe2 Iustin Pop
        not self.op.file_driver in constants.FILE_DRIVER):
6161 417eabe2 Iustin Pop
      raise errors.OpPrereqError("Invalid file driver name '%s'" %
6162 417eabe2 Iustin Pop
                                 self.op.file_driver, errors.ECODE_INVAL)
6163 417eabe2 Iustin Pop
6164 417eabe2 Iustin Pop
    if self.op.file_storage_dir and os.path.isabs(self.op.file_storage_dir):
6165 417eabe2 Iustin Pop
      raise errors.OpPrereqError("File storage directory path not absolute",
6166 417eabe2 Iustin Pop
                                 errors.ECODE_INVAL)
6167 417eabe2 Iustin Pop
6168 417eabe2 Iustin Pop
    ### Node/iallocator related checks
6169 417eabe2 Iustin Pop
    if [self.op.iallocator, self.op.pnode].count(None) != 1:
6170 417eabe2 Iustin Pop
      raise errors.OpPrereqError("One and only one of iallocator and primary"
6171 417eabe2 Iustin Pop
                                 " node must be given",
6172 417eabe2 Iustin Pop
                                 errors.ECODE_INVAL)
6173 417eabe2 Iustin Pop
6174 417eabe2 Iustin Pop
    if self.op.mode == constants.INSTANCE_IMPORT:
6175 417eabe2 Iustin Pop
      # On import force_variant must be True, because if we forced it at
6176 417eabe2 Iustin Pop
      # initial install, our only chance when importing it back is that it
6177 417eabe2 Iustin Pop
      # works again!
6178 417eabe2 Iustin Pop
      self.op.force_variant = True
6179 417eabe2 Iustin Pop
6180 417eabe2 Iustin Pop
      if self.op.no_install:
6181 417eabe2 Iustin Pop
        self.LogInfo("No-installation mode has no effect during import")
6182 417eabe2 Iustin Pop
6183 417eabe2 Iustin Pop
    else: # INSTANCE_CREATE
6184 417eabe2 Iustin Pop
      if getattr(self.op, "os_type", None) is None:
6185 417eabe2 Iustin Pop
        raise errors.OpPrereqError("No guest OS specified",
6186 417eabe2 Iustin Pop
                                   errors.ECODE_INVAL)
6187 417eabe2 Iustin Pop
      self.op.force_variant = getattr(self.op, "force_variant", False)
6188 f276c4b5 Iustin Pop
      if self.op.disk_template is None:
6189 f276c4b5 Iustin Pop
        raise errors.OpPrereqError("No disk template specified",
6190 f276c4b5 Iustin Pop
                                   errors.ECODE_INVAL)
6191 417eabe2 Iustin Pop
6192 7baf741d Guido Trotter
  def ExpandNames(self):
6193 7baf741d Guido Trotter
    """ExpandNames for CreateInstance.
6194 7baf741d Guido Trotter

6195 7baf741d Guido Trotter
    Figure out the right locks for instance creation.
6196 7baf741d Guido Trotter

6197 7baf741d Guido Trotter
    """
6198 7baf741d Guido Trotter
    self.needed_locks = {}
6199 7baf741d Guido Trotter
6200 417eabe2 Iustin Pop
    instance_name = self.op.instance_name
6201 7baf741d Guido Trotter
    # this is just a preventive check, but someone might still add this
6202 7baf741d Guido Trotter
    # instance in the meantime, and creation will fail at lock-add time
6203 7baf741d Guido Trotter
    if instance_name in self.cfg.GetInstanceList():
6204 7baf741d Guido Trotter
      raise errors.OpPrereqError("Instance '%s' is already in the cluster" %
6205 5c983ee5 Iustin Pop
                                 instance_name, errors.ECODE_EXISTS)
6206 7baf741d Guido Trotter
6207 7baf741d Guido Trotter
    self.add_locks[locking.LEVEL_INSTANCE] = instance_name
6208 7baf741d Guido Trotter
6209 7baf741d Guido Trotter
    if self.op.iallocator:
6210 7baf741d Guido Trotter
      self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
6211 7baf741d Guido Trotter
    else:
6212 cf26a87a Iustin Pop
      self.op.pnode = _ExpandNodeName(self.cfg, self.op.pnode)
6213 7baf741d Guido Trotter
      nodelist = [self.op.pnode]
6214 7baf741d Guido Trotter
      if self.op.snode is not None:
6215 cf26a87a Iustin Pop
        self.op.snode = _ExpandNodeName(self.cfg, self.op.snode)
6216 7baf741d Guido Trotter
        nodelist.append(self.op.snode)
6217 7baf741d Guido Trotter
      self.needed_locks[locking.LEVEL_NODE] = nodelist
6218 7baf741d Guido Trotter
6219 7baf741d Guido Trotter
    # in case of import lock the source node too
6220 7baf741d Guido Trotter
    if self.op.mode == constants.INSTANCE_IMPORT:
6221 7baf741d Guido Trotter
      src_node = getattr(self.op, "src_node", None)
6222 7baf741d Guido Trotter
      src_path = getattr(self.op, "src_path", None)
6223 7baf741d Guido Trotter
6224 b9322a9f Guido Trotter
      if src_path is None:
6225 b9322a9f Guido Trotter
        self.op.src_path = src_path = self.op.instance_name
6226 b9322a9f Guido Trotter
6227 b9322a9f Guido Trotter
      if src_node is None:
6228 b9322a9f Guido Trotter
        self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
6229 b9322a9f Guido Trotter
        self.op.src_node = None
6230 b9322a9f Guido Trotter
        if os.path.isabs(src_path):
6231 b9322a9f Guido Trotter
          raise errors.OpPrereqError("Importing an instance from an absolute"
6232 5c983ee5 Iustin Pop
                                     " path requires a source node option.",
6233 5c983ee5 Iustin Pop
                                     errors.ECODE_INVAL)
6234 b9322a9f Guido Trotter
      else:
6235 cf26a87a Iustin Pop
        self.op.src_node = src_node = _ExpandNodeName(self.cfg, src_node)
6236 b9322a9f Guido Trotter
        if self.needed_locks[locking.LEVEL_NODE] is not locking.ALL_SET:
6237 b9322a9f Guido Trotter
          self.needed_locks[locking.LEVEL_NODE].append(src_node)
6238 b9322a9f Guido Trotter
        if not os.path.isabs(src_path):
6239 b9322a9f Guido Trotter
          self.op.src_path = src_path = \
6240 c4feafe8 Iustin Pop
            utils.PathJoin(constants.EXPORT_DIR, src_path)
6241 7baf741d Guido Trotter
6242 538475ca Iustin Pop
  def _RunAllocator(self):
6243 538475ca Iustin Pop
    """Run the allocator based on input opcode.
6244 538475ca Iustin Pop

6245 538475ca Iustin Pop
    """
6246 08db7c5c Iustin Pop
    nics = [n.ToDict() for n in self.nics]
6247 923ddac0 Michael Hanselmann
    ial = IAllocator(self.cfg, self.rpc,
6248 29859cb7 Iustin Pop
                     mode=constants.IALLOCATOR_MODE_ALLOC,
6249 d1c2dd75 Iustin Pop
                     name=self.op.instance_name,
6250 d1c2dd75 Iustin Pop
                     disk_template=self.op.disk_template,
6251 d1c2dd75 Iustin Pop
                     tags=[],
6252 d1c2dd75 Iustin Pop
                     os=self.op.os_type,
6253 338e51e8 Iustin Pop
                     vcpus=self.be_full[constants.BE_VCPUS],
6254 338e51e8 Iustin Pop
                     mem_size=self.be_full[constants.BE_MEMORY],
6255 08db7c5c Iustin Pop
                     disks=self.disks,
6256 d1c2dd75 Iustin Pop
                     nics=nics,
6257 8cc7e742 Guido Trotter
                     hypervisor=self.op.hypervisor,
6258 29859cb7 Iustin Pop
                     )
6259 d1c2dd75 Iustin Pop
6260 d1c2dd75 Iustin Pop
    ial.Run(self.op.iallocator)
6261 d1c2dd75 Iustin Pop
6262 d1c2dd75 Iustin Pop
    if not ial.success:
6263 538475ca Iustin Pop
      raise errors.OpPrereqError("Can't compute nodes using"
6264 5c983ee5 Iustin Pop
                                 " iallocator '%s': %s" %
6265 5c983ee5 Iustin Pop
                                 (self.op.iallocator, ial.info),
6266 5c983ee5 Iustin Pop
                                 errors.ECODE_NORES)
6267 680f0a89 Iustin Pop
    if len(ial.result) != ial.required_nodes:
6268 538475ca Iustin Pop
      raise errors.OpPrereqError("iallocator '%s' returned invalid number"
6269 538475ca Iustin Pop
                                 " of nodes (%s), required %s" %
6270 680f0a89 Iustin Pop
                                 (self.op.iallocator, len(ial.result),
6271 5c983ee5 Iustin Pop
                                  ial.required_nodes), errors.ECODE_FAULT)
6272 680f0a89 Iustin Pop
    self.op.pnode = ial.result[0]
6273 86d9d3bb Iustin Pop
    self.LogInfo("Selected nodes for instance %s via iallocator %s: %s",
6274 86d9d3bb Iustin Pop
                 self.op.instance_name, self.op.iallocator,
6275 680f0a89 Iustin Pop
                 utils.CommaJoin(ial.result))
6276 27579978 Iustin Pop
    if ial.required_nodes == 2:
6277 680f0a89 Iustin Pop
      self.op.snode = ial.result[1]
6278 538475ca Iustin Pop
6279 a8083063 Iustin Pop
  def BuildHooksEnv(self):
6280 a8083063 Iustin Pop
    """Build hooks env.
6281 a8083063 Iustin Pop

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

6284 a8083063 Iustin Pop
    """
6285 a8083063 Iustin Pop
    env = {
6286 2c2690c9 Iustin Pop
      "ADD_MODE": self.op.mode,
6287 a8083063 Iustin Pop
      }
6288 a8083063 Iustin Pop
    if self.op.mode == constants.INSTANCE_IMPORT:
6289 2c2690c9 Iustin Pop
      env["SRC_NODE"] = self.op.src_node
6290 2c2690c9 Iustin Pop
      env["SRC_PATH"] = self.op.src_path
6291 2c2690c9 Iustin Pop
      env["SRC_IMAGES"] = self.src_images
6292 396e1b78 Michael Hanselmann
6293 2c2690c9 Iustin Pop
    env.update(_BuildInstanceHookEnv(
6294 2c2690c9 Iustin Pop
      name=self.op.instance_name,
6295 396e1b78 Michael Hanselmann
      primary_node=self.op.pnode,
6296 396e1b78 Michael Hanselmann
      secondary_nodes=self.secondaries,
6297 4978db17 Iustin Pop
      status=self.op.start,
6298 ecb215b5 Michael Hanselmann
      os_type=self.op.os_type,
6299 338e51e8 Iustin Pop
      memory=self.be_full[constants.BE_MEMORY],
6300 338e51e8 Iustin Pop
      vcpus=self.be_full[constants.BE_VCPUS],
6301 f9b10246 Guido Trotter
      nics=_NICListToTuple(self, self.nics),
6302 2c2690c9 Iustin Pop
      disk_template=self.op.disk_template,
6303 2c2690c9 Iustin Pop
      disks=[(d["size"], d["mode"]) for d in self.disks],
6304 67fc3042 Iustin Pop
      bep=self.be_full,
6305 67fc3042 Iustin Pop
      hvp=self.hv_full,
6306 3df6e710 Iustin Pop
      hypervisor_name=self.op.hypervisor,
6307 396e1b78 Michael Hanselmann
    ))
6308 a8083063 Iustin Pop
6309 d6a02168 Michael Hanselmann
    nl = ([self.cfg.GetMasterNode(), self.op.pnode] +
6310 a8083063 Iustin Pop
          self.secondaries)
6311 a8083063 Iustin Pop
    return env, nl, nl
6312 a8083063 Iustin Pop
6313 c1c31426 Iustin Pop
  def _ReadExportInfo(self):
6314 c1c31426 Iustin Pop
    """Reads the export information from disk.
6315 c1c31426 Iustin Pop

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

6319 c1c31426 Iustin Pop
    @return: the export information
6320 c1c31426 Iustin Pop

6321 c1c31426 Iustin Pop
    """
6322 c1c31426 Iustin Pop
    assert self.op.mode == constants.INSTANCE_IMPORT
6323 c1c31426 Iustin Pop
6324 c1c31426 Iustin Pop
    src_node = self.op.src_node
6325 c1c31426 Iustin Pop
    src_path = self.op.src_path
6326 c1c31426 Iustin Pop
6327 c1c31426 Iustin Pop
    if src_node is None:
6328 c1c31426 Iustin Pop
      locked_nodes = self.acquired_locks[locking.LEVEL_NODE]
6329 c1c31426 Iustin Pop
      exp_list = self.rpc.call_export_list(locked_nodes)
6330 c1c31426 Iustin Pop
      found = False
6331 c1c31426 Iustin Pop
      for node in exp_list:
6332 c1c31426 Iustin Pop
        if exp_list[node].fail_msg:
6333 c1c31426 Iustin Pop
          continue
6334 c1c31426 Iustin Pop
        if src_path in exp_list[node].payload:
6335 c1c31426 Iustin Pop
          found = True
6336 c1c31426 Iustin Pop
          self.op.src_node = src_node = node
6337 c1c31426 Iustin Pop
          self.op.src_path = src_path = utils.PathJoin(constants.EXPORT_DIR,
6338 c1c31426 Iustin Pop
                                                       src_path)
6339 c1c31426 Iustin Pop
          break
6340 c1c31426 Iustin Pop
      if not found:
6341 c1c31426 Iustin Pop
        raise errors.OpPrereqError("No export found for relative path %s" %
6342 c1c31426 Iustin Pop
                                    src_path, errors.ECODE_INVAL)
6343 c1c31426 Iustin Pop
6344 c1c31426 Iustin Pop
    _CheckNodeOnline(self, src_node)
6345 c1c31426 Iustin Pop
    result = self.rpc.call_export_info(src_node, src_path)
6346 c1c31426 Iustin Pop
    result.Raise("No export or invalid export found in dir %s" % src_path)
6347 c1c31426 Iustin Pop
6348 c1c31426 Iustin Pop
    export_info = objects.SerializableConfigParser.Loads(str(result.payload))
6349 c1c31426 Iustin Pop
    if not export_info.has_section(constants.INISECT_EXP):
6350 c1c31426 Iustin Pop
      raise errors.ProgrammerError("Corrupted export config",
6351 c1c31426 Iustin Pop
                                   errors.ECODE_ENVIRON)
6352 c1c31426 Iustin Pop
6353 c1c31426 Iustin Pop
    ei_version = export_info.get(constants.INISECT_EXP, "version")
6354 c1c31426 Iustin Pop
    if (int(ei_version) != constants.EXPORT_VERSION):
6355 c1c31426 Iustin Pop
      raise errors.OpPrereqError("Wrong export version %s (wanted %d)" %
6356 c1c31426 Iustin Pop
                                 (ei_version, constants.EXPORT_VERSION),
6357 c1c31426 Iustin Pop
                                 errors.ECODE_ENVIRON)
6358 c1c31426 Iustin Pop
    return export_info
6359 a8083063 Iustin Pop
6360 f276c4b5 Iustin Pop
  def _ReadExportParams(self, einfo):
6361 f276c4b5 Iustin Pop
    """Use export parameters as defaults.
6362 f276c4b5 Iustin Pop

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

6367 f276c4b5 Iustin Pop
    """
6368 b6cd72b2 Iustin Pop
    self.op.os_type = einfo.get(constants.INISECT_EXP, "os")
6369 b6cd72b2 Iustin Pop
6370 f276c4b5 Iustin Pop
    if self.op.disk_template is None:
6371 f276c4b5 Iustin Pop
      if einfo.has_option(constants.INISECT_INS, "disk_template"):
6372 f276c4b5 Iustin Pop
        self.op.disk_template = einfo.get(constants.INISECT_INS,
6373 f276c4b5 Iustin Pop
                                          "disk_template")
6374 f276c4b5 Iustin Pop
      else:
6375 f276c4b5 Iustin Pop
        raise errors.OpPrereqError("No disk template specified and the export"
6376 f276c4b5 Iustin Pop
                                   " is missing the disk_template information",
6377 f276c4b5 Iustin Pop
                                   errors.ECODE_INVAL)
6378 f276c4b5 Iustin Pop
6379 9b12ed0f Iustin Pop
    if not self.op.disks:
6380 9b12ed0f Iustin Pop
      if einfo.has_option(constants.INISECT_INS, "disk_count"):
6381 9b12ed0f Iustin Pop
        disks = []
6382 9b12ed0f Iustin Pop
        # TODO: import the disk iv_name too
6383 9b12ed0f Iustin Pop
        for idx in range(einfo.getint(constants.INISECT_INS, "disk_count")):
6384 9b12ed0f Iustin Pop
          disk_sz = einfo.getint(constants.INISECT_INS, "disk%d_size" % idx)
6385 9b12ed0f Iustin Pop
          disks.append({"size": disk_sz})
6386 9b12ed0f Iustin Pop
        self.op.disks = disks
6387 9b12ed0f Iustin Pop
      else:
6388 9b12ed0f Iustin Pop
        raise errors.OpPrereqError("No disk info specified and the export"
6389 9b12ed0f Iustin Pop
                                   " is missing the disk information",
6390 9b12ed0f Iustin Pop
                                   errors.ECODE_INVAL)
6391 9b12ed0f Iustin Pop
6392 0af0f641 Iustin Pop
    if (not self.op.nics and
6393 0af0f641 Iustin Pop
        einfo.has_option(constants.INISECT_INS, "nic_count")):
6394 0af0f641 Iustin Pop
      nics = []
6395 0af0f641 Iustin Pop
      for idx in range(einfo.getint(constants.INISECT_INS, "nic_count")):
6396 0af0f641 Iustin Pop
        ndict = {}
6397 0af0f641 Iustin Pop
        for name in list(constants.NICS_PARAMETERS) + ["ip", "mac"]:
6398 0af0f641 Iustin Pop
          v = einfo.get(constants.INISECT_INS, "nic%d_%s" % (idx, name))
6399 0af0f641 Iustin Pop
          ndict[name] = v
6400 0af0f641 Iustin Pop
        nics.append(ndict)
6401 0af0f641 Iustin Pop
      self.op.nics = nics
6402 0af0f641 Iustin Pop
6403 9f88b0e8 Iustin Pop
    if (self.op.hypervisor is None and
6404 9f88b0e8 Iustin Pop
        einfo.has_option(constants.INISECT_INS, "hypervisor")):
6405 9f88b0e8 Iustin Pop
      self.op.hypervisor = einfo.get(constants.INISECT_INS, "hypervisor")
6406 9f88b0e8 Iustin Pop
    if einfo.has_section(constants.INISECT_HYP):
6407 9f88b0e8 Iustin Pop
      # use the export parameters but do not override the ones
6408 9f88b0e8 Iustin Pop
      # specified by the user
6409 9f88b0e8 Iustin Pop
      for name, value in einfo.items(constants.INISECT_HYP):
6410 9f88b0e8 Iustin Pop
        if name not in self.op.hvparams:
6411 9f88b0e8 Iustin Pop
          self.op.hvparams[name] = value
6412 9f88b0e8 Iustin Pop
6413 cc0d88e9 Iustin Pop
    if einfo.has_section(constants.INISECT_BEP):
6414 cc0d88e9 Iustin Pop
      # use the parameters, without overriding
6415 cc0d88e9 Iustin Pop
      for name, value in einfo.items(constants.INISECT_BEP):
6416 cc0d88e9 Iustin Pop
        if name not in self.op.beparams:
6417 cc0d88e9 Iustin Pop
          self.op.beparams[name] = value
6418 cc0d88e9 Iustin Pop
    else:
6419 cc0d88e9 Iustin Pop
      # try to read the parameters old style, from the main section
6420 cc0d88e9 Iustin Pop
      for name in constants.BES_PARAMETERS:
6421 cc0d88e9 Iustin Pop
        if (name not in self.op.beparams and
6422 cc0d88e9 Iustin Pop
            einfo.has_option(constants.INISECT_INS, name)):
6423 cc0d88e9 Iustin Pop
          self.op.beparams[name] = einfo.get(constants.INISECT_INS, name)
6424 cc0d88e9 Iustin Pop
6425 e588764d Iustin Pop
  def _RevertToDefaults(self, cluster):
6426 e588764d Iustin Pop
    """Revert the instance parameters to the default values.
6427 e588764d Iustin Pop

6428 e588764d Iustin Pop
    """
6429 e588764d Iustin Pop
    # hvparams
6430 e588764d Iustin Pop
    hv_defs = cluster.GetHVDefaults(self.op.hypervisor, self.op.os_type)
6431 e588764d Iustin Pop
    for name in self.op.hvparams.keys():
6432 e588764d Iustin Pop
      if name in hv_defs and hv_defs[name] == self.op.hvparams[name]:
6433 e588764d Iustin Pop
        del self.op.hvparams[name]
6434 e588764d Iustin Pop
    # beparams
6435 e588764d Iustin Pop
    be_defs = cluster.beparams.get(constants.PP_DEFAULT, {})
6436 e588764d Iustin Pop
    for name in self.op.beparams.keys():
6437 e588764d Iustin Pop
      if name in be_defs and be_defs[name] == self.op.beparams[name]:
6438 e588764d Iustin Pop
        del self.op.beparams[name]
6439 e588764d Iustin Pop
    # nic params
6440 e588764d Iustin Pop
    nic_defs = cluster.nicparams.get(constants.PP_DEFAULT, {})
6441 e588764d Iustin Pop
    for nic in self.op.nics:
6442 e588764d Iustin Pop
      for name in constants.NICS_PARAMETERS:
6443 e588764d Iustin Pop
        if name in nic and name in nic_defs and nic[name] == nic_defs[name]:
6444 e588764d Iustin Pop
          del nic[name]
6445 e588764d Iustin Pop
6446 a8083063 Iustin Pop
  def CheckPrereq(self):
6447 a8083063 Iustin Pop
    """Check prerequisites.
6448 a8083063 Iustin Pop

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

6731 a8083063 Iustin Pop
    """
6732 a8083063 Iustin Pop
    instance = self.op.instance_name
6733 a8083063 Iustin Pop
    pnode_name = self.pnode.name
6734 a8083063 Iustin Pop
6735 e69d05fd Iustin Pop
    ht_kind = self.op.hypervisor
6736 2a6469d5 Alexander Schreiber
    if ht_kind in constants.HTS_REQ_PORT:
6737 2a6469d5 Alexander Schreiber
      network_port = self.cfg.AllocatePort()
6738 2a6469d5 Alexander Schreiber
    else:
6739 2a6469d5 Alexander Schreiber
      network_port = None
6740 58acb49d Alexander Schreiber
6741 0e3baaf3 Iustin Pop
    if constants.ENABLE_FILE_STORAGE:
6742 0e3baaf3 Iustin Pop
      # this is needed because os.path.join does not accept None arguments
6743 0e3baaf3 Iustin Pop
      if self.op.file_storage_dir is None:
6744 0e3baaf3 Iustin Pop
        string_file_storage_dir = ""
6745 0e3baaf3 Iustin Pop
      else:
6746 0e3baaf3 Iustin Pop
        string_file_storage_dir = self.op.file_storage_dir
6747 31a853d2 Iustin Pop
6748 0e3baaf3 Iustin Pop
      # build the full file storage dir path
6749 0e3baaf3 Iustin Pop
      file_storage_dir = utils.PathJoin(self.cfg.GetFileStorageDir(),
6750 0e3baaf3 Iustin Pop
                                        string_file_storage_dir, instance)
6751 2c313123 Manuel Franceschini
    else:
6752 0e3baaf3 Iustin Pop
      file_storage_dir = ""
6753 0f1a06e3 Manuel Franceschini
6754 0f1a06e3 Manuel Franceschini
6755 b9bddb6b Iustin Pop
    disks = _GenerateDiskTemplate(self,
6756 a8083063 Iustin Pop
                                  self.op.disk_template,
6757 a8083063 Iustin Pop
                                  instance, pnode_name,
6758 08db7c5c Iustin Pop
                                  self.secondaries,
6759 08db7c5c Iustin Pop
                                  self.disks,
6760 0f1a06e3 Manuel Franceschini
                                  file_storage_dir,
6761 e2a65344 Iustin Pop
                                  self.op.file_driver,
6762 e2a65344 Iustin Pop
                                  0)
6763 a8083063 Iustin Pop
6764 a8083063 Iustin Pop
    iobj = objects.Instance(name=instance, os=self.op.os_type,
6765 a8083063 Iustin Pop
                            primary_node=pnode_name,
6766 08db7c5c Iustin Pop
                            nics=self.nics, disks=disks,
6767 a8083063 Iustin Pop
                            disk_template=self.op.disk_template,
6768 4978db17 Iustin Pop
                            admin_up=False,
6769 58acb49d Alexander Schreiber
                            network_port=network_port,
6770 338e51e8 Iustin Pop
                            beparams=self.op.beparams,
6771 6785674e Iustin Pop
                            hvparams=self.op.hvparams,
6772 e69d05fd Iustin Pop
                            hypervisor=self.op.hypervisor,
6773 a8083063 Iustin Pop
                            )
6774 a8083063 Iustin Pop
6775 c3589cf8 Iustin Pop
    if self.adopt_disks:
6776 c3589cf8 Iustin Pop
      # rename LVs to the newly-generated names; we need to construct
6777 c3589cf8 Iustin Pop
      # 'fake' LV disks with the old data, plus the new unique_id
6778 c3589cf8 Iustin Pop
      tmp_disks = [objects.Disk.FromDict(v.ToDict()) for v in disks]
6779 c3589cf8 Iustin Pop
      rename_to = []
6780 c3589cf8 Iustin Pop
      for t_dsk, a_dsk in zip (tmp_disks, self.disks):
6781 c3589cf8 Iustin Pop
        rename_to.append(t_dsk.logical_id)
6782 c3589cf8 Iustin Pop
        t_dsk.logical_id = (t_dsk.logical_id[0], a_dsk["adopt"])
6783 c3589cf8 Iustin Pop
        self.cfg.SetDiskID(t_dsk, pnode_name)
6784 c3589cf8 Iustin Pop
      result = self.rpc.call_blockdev_rename(pnode_name,
6785 c3589cf8 Iustin Pop
                                             zip(tmp_disks, rename_to))
6786 c3589cf8 Iustin Pop
      result.Raise("Failed to rename adoped LVs")
6787 c3589cf8 Iustin Pop
    else:
6788 c3589cf8 Iustin Pop
      feedback_fn("* creating instance disks...")
6789 796cab27 Iustin Pop
      try:
6790 c3589cf8 Iustin Pop
        _CreateDisks(self, iobj)
6791 c3589cf8 Iustin Pop
      except errors.OpExecError:
6792 c3589cf8 Iustin Pop
        self.LogWarning("Device creation failed, reverting...")
6793 c3589cf8 Iustin Pop
        try:
6794 c3589cf8 Iustin Pop
          _RemoveDisks(self, iobj)
6795 c3589cf8 Iustin Pop
        finally:
6796 c3589cf8 Iustin Pop
          self.cfg.ReleaseDRBDMinors(instance)
6797 c3589cf8 Iustin Pop
          raise
6798 a8083063 Iustin Pop
6799 a8083063 Iustin Pop
    feedback_fn("adding instance %s to cluster config" % instance)
6800 a8083063 Iustin Pop
6801 0debfb35 Guido Trotter
    self.cfg.AddInstance(iobj, self.proc.GetECId())
6802 0debfb35 Guido Trotter
6803 7baf741d Guido Trotter
    # Declare that we don't want to remove the instance lock anymore, as we've
6804 7baf741d Guido Trotter
    # added the instance to the config
6805 7baf741d Guido Trotter
    del self.remove_locks[locking.LEVEL_INSTANCE]
6806 e36e96b4 Guido Trotter
    # Unlock all the nodes
6807 9c8971d7 Guido Trotter
    if self.op.mode == constants.INSTANCE_IMPORT:
6808 9c8971d7 Guido Trotter
      nodes_keep = [self.op.src_node]
6809 9c8971d7 Guido Trotter
      nodes_release = [node for node in self.acquired_locks[locking.LEVEL_NODE]
6810 9c8971d7 Guido Trotter
                       if node != self.op.src_node]
6811 9c8971d7 Guido Trotter
      self.context.glm.release(locking.LEVEL_NODE, nodes_release)
6812 9c8971d7 Guido Trotter
      self.acquired_locks[locking.LEVEL_NODE] = nodes_keep
6813 9c8971d7 Guido Trotter
    else:
6814 9c8971d7 Guido Trotter
      self.context.glm.release(locking.LEVEL_NODE)
6815 9c8971d7 Guido Trotter
      del self.acquired_locks[locking.LEVEL_NODE]
6816 a8083063 Iustin Pop
6817 a8083063 Iustin Pop
    if self.op.wait_for_sync:
6818 b9bddb6b Iustin Pop
      disk_abort = not _WaitForSync(self, iobj)
6819 a1f445d3 Iustin Pop
    elif iobj.disk_template in constants.DTS_NET_MIRROR:
6820 a8083063 Iustin Pop
      # make sure the disks are not degraded (still sync-ing is ok)
6821 a8083063 Iustin Pop
      time.sleep(15)
6822 a8083063 Iustin Pop
      feedback_fn("* checking mirrors status")
6823 b9bddb6b Iustin Pop
      disk_abort = not _WaitForSync(self, iobj, oneshot=True)
6824 a8083063 Iustin Pop
    else:
6825 a8083063 Iustin Pop
      disk_abort = False
6826 a8083063 Iustin Pop
6827 a8083063 Iustin Pop
    if disk_abort:
6828 b9bddb6b Iustin Pop
      _RemoveDisks(self, iobj)
6829 a8083063 Iustin Pop
      self.cfg.RemoveInstance(iobj.name)
6830 7baf741d Guido Trotter
      # Make sure the instance lock gets removed
6831 7baf741d Guido Trotter
      self.remove_locks[locking.LEVEL_INSTANCE] = iobj.name
6832 3ecf6786 Iustin Pop
      raise errors.OpExecError("There are some degraded disks for"
6833 3ecf6786 Iustin Pop
                               " this instance")
6834 a8083063 Iustin Pop
6835 c3589cf8 Iustin Pop
    if iobj.disk_template != constants.DT_DISKLESS and not self.adopt_disks:
6836 a8083063 Iustin Pop
      if self.op.mode == constants.INSTANCE_CREATE:
6837 25a8792c Iustin Pop
        if not self.op.no_install:
6838 25a8792c Iustin Pop
          feedback_fn("* running the instance OS create scripts...")
6839 25a8792c Iustin Pop
          # FIXME: pass debug option from opcode to backend
6840 25a8792c Iustin Pop
          result = self.rpc.call_instance_os_add(pnode_name, iobj, False,
6841 25a8792c Iustin Pop
                                                 self.op.debug_level)
6842 25a8792c Iustin Pop
          result.Raise("Could not add os for instance %s"
6843 25a8792c Iustin Pop
                       " on node %s" % (instance, pnode_name))
6844 a8083063 Iustin Pop
6845 a8083063 Iustin Pop
      elif self.op.mode == constants.INSTANCE_IMPORT:
6846 a8083063 Iustin Pop
        feedback_fn("* running the instance OS import scripts...")
6847 a8083063 Iustin Pop
        src_node = self.op.src_node
6848 09acf207 Guido Trotter
        src_images = self.src_images
6849 62c9ec92 Iustin Pop
        cluster_name = self.cfg.GetClusterName()
6850 4a0e011f Iustin Pop
        # FIXME: pass debug option from opcode to backend
6851 6c0af70e Guido Trotter
        import_result = self.rpc.call_instance_os_import(pnode_name, iobj,
6852 09acf207 Guido Trotter
                                                         src_node, src_images,
6853 dd713605 Iustin Pop
                                                         cluster_name,
6854 dd713605 Iustin Pop
                                                         self.op.debug_level)
6855 4c4e4e1e Iustin Pop
        msg = import_result.fail_msg
6856 944bf548 Iustin Pop
        if msg:
6857 944bf548 Iustin Pop
          self.LogWarning("Error while importing the disk images for instance"
6858 944bf548 Iustin Pop
                          " %s on node %s: %s" % (instance, pnode_name, msg))
6859 a8083063 Iustin Pop
      else:
6860 a8083063 Iustin Pop
        # also checked in the prereq part
6861 3ecf6786 Iustin Pop
        raise errors.ProgrammerError("Unknown OS initialization mode '%s'"
6862 3ecf6786 Iustin Pop
                                     % self.op.mode)
6863 a8083063 Iustin Pop
6864 a8083063 Iustin Pop
    if self.op.start:
6865 4978db17 Iustin Pop
      iobj.admin_up = True
6866 a4eae71f Michael Hanselmann
      self.cfg.Update(iobj, feedback_fn)
6867 9a4f63d1 Iustin Pop
      logging.info("Starting instance %s on node %s", instance, pnode_name)
6868 a8083063 Iustin Pop
      feedback_fn("* starting instance...")
6869 0eca8e0c Iustin Pop
      result = self.rpc.call_instance_start(pnode_name, iobj, None, None)
6870 4c4e4e1e Iustin Pop
      result.Raise("Could not start instance")
6871 a8083063 Iustin Pop
6872 08896026 Iustin Pop
    return list(iobj.all_nodes)
6873 08896026 Iustin Pop
6874 a8083063 Iustin Pop
6875 a8083063 Iustin Pop
class LUConnectConsole(NoHooksLU):
6876 a8083063 Iustin Pop
  """Connect to an instance's console.
6877 a8083063 Iustin Pop

6878 a8083063 Iustin Pop
  This is somewhat special in that it returns the command line that
6879 a8083063 Iustin Pop
  you need to run on the master node in order to connect to the
6880 a8083063 Iustin Pop
  console.
6881 a8083063 Iustin Pop

6882 a8083063 Iustin Pop
  """
6883 a8083063 Iustin Pop
  _OP_REQP = ["instance_name"]
6884 8659b73e Guido Trotter
  REQ_BGL = False
6885 8659b73e Guido Trotter
6886 8659b73e Guido Trotter
  def ExpandNames(self):
6887 8659b73e Guido Trotter
    self._ExpandAndLockInstance()
6888 a8083063 Iustin Pop
6889 a8083063 Iustin Pop
  def CheckPrereq(self):
6890 a8083063 Iustin Pop
    """Check prerequisites.
6891 a8083063 Iustin Pop

6892 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
6893 a8083063 Iustin Pop

6894 a8083063 Iustin Pop
    """
6895 8659b73e Guido Trotter
    self.instance = self.cfg.GetInstanceInfo(self.op.instance_name)
6896 8659b73e Guido Trotter
    assert self.instance is not None, \
6897 8659b73e Guido Trotter
      "Cannot retrieve locked instance %s" % self.op.instance_name
6898 513e896d Guido Trotter
    _CheckNodeOnline(self, self.instance.primary_node)
6899 a8083063 Iustin Pop
6900 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
6901 a8083063 Iustin Pop
    """Connect to the console of an instance
6902 a8083063 Iustin Pop

6903 a8083063 Iustin Pop
    """
6904 a8083063 Iustin Pop
    instance = self.instance
6905 a8083063 Iustin Pop
    node = instance.primary_node
6906 a8083063 Iustin Pop
6907 72737a7f Iustin Pop
    node_insts = self.rpc.call_instance_list([node],
6908 72737a7f Iustin Pop
                                             [instance.hypervisor])[node]
6909 4c4e4e1e Iustin Pop
    node_insts.Raise("Can't get node information from %s" % node)
6910 a8083063 Iustin Pop
6911 aca13712 Iustin Pop
    if instance.name not in node_insts.payload:
6912 3ecf6786 Iustin Pop
      raise errors.OpExecError("Instance %s is not running." % instance.name)
6913 a8083063 Iustin Pop
6914 9a4f63d1 Iustin Pop
    logging.debug("Connecting to console of %s on %s", instance.name, node)
6915 a8083063 Iustin Pop
6916 e69d05fd Iustin Pop
    hyper = hypervisor.GetHypervisor(instance.hypervisor)
6917 5431b2e4 Guido Trotter
    cluster = self.cfg.GetClusterInfo()
6918 5431b2e4 Guido Trotter
    # beparams and hvparams are passed separately, to avoid editing the
6919 5431b2e4 Guido Trotter
    # instance and then saving the defaults in the instance itself.
6920 5431b2e4 Guido Trotter
    hvparams = cluster.FillHV(instance)
6921 5431b2e4 Guido Trotter
    beparams = cluster.FillBE(instance)
6922 5431b2e4 Guido Trotter
    console_cmd = hyper.GetShellCommandForConsole(instance, hvparams, beparams)
6923 b047857b Michael Hanselmann
6924 82122173 Iustin Pop
    # build ssh cmdline
6925 0a80a26f Michael Hanselmann
    return self.ssh.BuildCmd(node, "root", console_cmd, batch=True, tty=True)
6926 a8083063 Iustin Pop
6927 a8083063 Iustin Pop
6928 a8083063 Iustin Pop
class LUReplaceDisks(LogicalUnit):
6929 a8083063 Iustin Pop
  """Replace the disks of an instance.
6930 a8083063 Iustin Pop

6931 a8083063 Iustin Pop
  """
6932 a8083063 Iustin Pop
  HPATH = "mirrors-replace"
6933 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
6934 a9e0c397 Iustin Pop
  _OP_REQP = ["instance_name", "mode", "disks"]
6935 efd990e4 Guido Trotter
  REQ_BGL = False
6936 efd990e4 Guido Trotter
6937 7e9366f7 Iustin Pop
  def CheckArguments(self):
6938 efd990e4 Guido Trotter
    if not hasattr(self.op, "remote_node"):
6939 efd990e4 Guido Trotter
      self.op.remote_node = None
6940 7e9366f7 Iustin Pop
    if not hasattr(self.op, "iallocator"):
6941 7e9366f7 Iustin Pop
      self.op.iallocator = None
6942 7ea7bcf6 Iustin Pop
    if not hasattr(self.op, "early_release"):
6943 7ea7bcf6 Iustin Pop
      self.op.early_release = False
6944 7e9366f7 Iustin Pop
6945 c68174b6 Michael Hanselmann
    TLReplaceDisks.CheckArguments(self.op.mode, self.op.remote_node,
6946 c68174b6 Michael Hanselmann
                                  self.op.iallocator)
6947 7e9366f7 Iustin Pop
6948 7e9366f7 Iustin Pop
  def ExpandNames(self):
6949 7e9366f7 Iustin Pop
    self._ExpandAndLockInstance()
6950 7e9366f7 Iustin Pop
6951 7e9366f7 Iustin Pop
    if self.op.iallocator is not None:
6952 efd990e4 Guido Trotter
      self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
6953 2bb5c911 Michael Hanselmann
6954 efd990e4 Guido Trotter
    elif self.op.remote_node is not None:
6955 cf26a87a Iustin Pop
      remote_node = _ExpandNodeName(self.cfg, self.op.remote_node)
6956 efd990e4 Guido Trotter
      self.op.remote_node = remote_node
6957 2bb5c911 Michael Hanselmann
6958 3b559640 Iustin Pop
      # Warning: do not remove the locking of the new secondary here
6959 3b559640 Iustin Pop
      # unless DRBD8.AddChildren is changed to work in parallel;
6960 3b559640 Iustin Pop
      # currently it doesn't since parallel invocations of
6961 3b559640 Iustin Pop
      # FindUnusedMinor will conflict
6962 efd990e4 Guido Trotter
      self.needed_locks[locking.LEVEL_NODE] = [remote_node]
6963 efd990e4 Guido Trotter
      self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_APPEND
6964 2bb5c911 Michael Hanselmann
6965 efd990e4 Guido Trotter
    else:
6966 efd990e4 Guido Trotter
      self.needed_locks[locking.LEVEL_NODE] = []
6967 efd990e4 Guido Trotter
      self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
6968 efd990e4 Guido Trotter
6969 c68174b6 Michael Hanselmann
    self.replacer = TLReplaceDisks(self, self.op.instance_name, self.op.mode,
6970 c68174b6 Michael Hanselmann
                                   self.op.iallocator, self.op.remote_node,
6971 7ea7bcf6 Iustin Pop
                                   self.op.disks, False, self.op.early_release)
6972 c68174b6 Michael Hanselmann
6973 3a012b41 Michael Hanselmann
    self.tasklets = [self.replacer]
6974 2bb5c911 Michael Hanselmann
6975 efd990e4 Guido Trotter
  def DeclareLocks(self, level):
6976 efd990e4 Guido Trotter
    # If we're not already locking all nodes in the set we have to declare the
6977 efd990e4 Guido Trotter
    # instance's primary/secondary nodes.
6978 efd990e4 Guido Trotter
    if (level == locking.LEVEL_NODE and
6979 efd990e4 Guido Trotter
        self.needed_locks[locking.LEVEL_NODE] is not locking.ALL_SET):
6980 efd990e4 Guido Trotter
      self._LockInstancesNodes()
6981 a8083063 Iustin Pop
6982 a8083063 Iustin Pop
  def BuildHooksEnv(self):
6983 a8083063 Iustin Pop
    """Build hooks env.
6984 a8083063 Iustin Pop

6985 a8083063 Iustin Pop
    This runs on the master, the primary and all the secondaries.
6986 a8083063 Iustin Pop

6987 a8083063 Iustin Pop
    """
6988 2bb5c911 Michael Hanselmann
    instance = self.replacer.instance
6989 a8083063 Iustin Pop
    env = {
6990 a9e0c397 Iustin Pop
      "MODE": self.op.mode,
6991 a8083063 Iustin Pop
      "NEW_SECONDARY": self.op.remote_node,
6992 2bb5c911 Michael Hanselmann
      "OLD_SECONDARY": instance.secondary_nodes[0],
6993 a8083063 Iustin Pop
      }
6994 2bb5c911 Michael Hanselmann
    env.update(_BuildInstanceHookEnvByObject(self, instance))
6995 0834c866 Iustin Pop
    nl = [
6996 d6a02168 Michael Hanselmann
      self.cfg.GetMasterNode(),
6997 2bb5c911 Michael Hanselmann
      instance.primary_node,
6998 0834c866 Iustin Pop
      ]
6999 0834c866 Iustin Pop
    if self.op.remote_node is not None:
7000 0834c866 Iustin Pop
      nl.append(self.op.remote_node)
7001 a8083063 Iustin Pop
    return env, nl, nl
7002 a8083063 Iustin Pop
7003 2bb5c911 Michael Hanselmann
7004 7ffc5a86 Michael Hanselmann
class LUEvacuateNode(LogicalUnit):
7005 7ffc5a86 Michael Hanselmann
  """Relocate the secondary instances from a node.
7006 7ffc5a86 Michael Hanselmann

7007 7ffc5a86 Michael Hanselmann
  """
7008 7ffc5a86 Michael Hanselmann
  HPATH = "node-evacuate"
7009 7ffc5a86 Michael Hanselmann
  HTYPE = constants.HTYPE_NODE
7010 7ffc5a86 Michael Hanselmann
  _OP_REQP = ["node_name"]
7011 7ffc5a86 Michael Hanselmann
  REQ_BGL = False
7012 7ffc5a86 Michael Hanselmann
7013 7ffc5a86 Michael Hanselmann
  def CheckArguments(self):
7014 7ffc5a86 Michael Hanselmann
    if not hasattr(self.op, "remote_node"):
7015 7ffc5a86 Michael Hanselmann
      self.op.remote_node = None
7016 7ffc5a86 Michael Hanselmann
    if not hasattr(self.op, "iallocator"):
7017 7ffc5a86 Michael Hanselmann
      self.op.iallocator = None
7018 7ea7bcf6 Iustin Pop
    if not hasattr(self.op, "early_release"):
7019 7ea7bcf6 Iustin Pop
      self.op.early_release = False
7020 7ffc5a86 Michael Hanselmann
7021 7ffc5a86 Michael Hanselmann
    TLReplaceDisks.CheckArguments(constants.REPLACE_DISK_CHG,
7022 7ffc5a86 Michael Hanselmann
                                  self.op.remote_node,
7023 7ffc5a86 Michael Hanselmann
                                  self.op.iallocator)
7024 7ffc5a86 Michael Hanselmann
7025 7ffc5a86 Michael Hanselmann
  def ExpandNames(self):
7026 cf26a87a Iustin Pop
    self.op.node_name = _ExpandNodeName(self.cfg, self.op.node_name)
7027 7ffc5a86 Michael Hanselmann
7028 7ffc5a86 Michael Hanselmann
    self.needed_locks = {}
7029 7ffc5a86 Michael Hanselmann
7030 7ffc5a86 Michael Hanselmann
    # Declare node locks
7031 7ffc5a86 Michael Hanselmann
    if self.op.iallocator is not None:
7032 7ffc5a86 Michael Hanselmann
      self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
7033 7ffc5a86 Michael Hanselmann
7034 7ffc5a86 Michael Hanselmann
    elif self.op.remote_node is not None:
7035 cf26a87a Iustin Pop
      self.op.remote_node = _ExpandNodeName(self.cfg, self.op.remote_node)
7036 7ffc5a86 Michael Hanselmann
7037 7ffc5a86 Michael Hanselmann
      # Warning: do not remove the locking of the new secondary here
7038 7ffc5a86 Michael Hanselmann
      # unless DRBD8.AddChildren is changed to work in parallel;
7039 7ffc5a86 Michael Hanselmann
      # currently it doesn't since parallel invocations of
7040 7ffc5a86 Michael Hanselmann
      # FindUnusedMinor will conflict
7041 cf26a87a Iustin Pop
      self.needed_locks[locking.LEVEL_NODE] = [self.op.remote_node]
7042 7ffc5a86 Michael Hanselmann
      self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_APPEND
7043 7ffc5a86 Michael Hanselmann
7044 7ffc5a86 Michael Hanselmann
    else:
7045 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Invalid parameters", errors.ECODE_INVAL)
7046 7ffc5a86 Michael Hanselmann
7047 7ffc5a86 Michael Hanselmann
    # Create tasklets for replacing disks for all secondary instances on this
7048 7ffc5a86 Michael Hanselmann
    # node
7049 7ffc5a86 Michael Hanselmann
    names = []
7050 3a012b41 Michael Hanselmann
    tasklets = []
7051 7ffc5a86 Michael Hanselmann
7052 7ffc5a86 Michael Hanselmann
    for inst in _GetNodeSecondaryInstances(self.cfg, self.op.node_name):
7053 7ffc5a86 Michael Hanselmann
      logging.debug("Replacing disks for instance %s", inst.name)
7054 7ffc5a86 Michael Hanselmann
      names.append(inst.name)
7055 7ffc5a86 Michael Hanselmann
7056 7ffc5a86 Michael Hanselmann
      replacer = TLReplaceDisks(self, inst.name, constants.REPLACE_DISK_CHG,
7057 94a1b377 Michael Hanselmann
                                self.op.iallocator, self.op.remote_node, [],
7058 7ea7bcf6 Iustin Pop
                                True, self.op.early_release)
7059 3a012b41 Michael Hanselmann
      tasklets.append(replacer)
7060 7ffc5a86 Michael Hanselmann
7061 3a012b41 Michael Hanselmann
    self.tasklets = tasklets
7062 7ffc5a86 Michael Hanselmann
    self.instance_names = names
7063 7ffc5a86 Michael Hanselmann
7064 7ffc5a86 Michael Hanselmann
    # Declare instance locks
7065 7ffc5a86 Michael Hanselmann
    self.needed_locks[locking.LEVEL_INSTANCE] = self.instance_names
7066 7ffc5a86 Michael Hanselmann
7067 7ffc5a86 Michael Hanselmann
  def DeclareLocks(self, level):
7068 7ffc5a86 Michael Hanselmann
    # If we're not already locking all nodes in the set we have to declare the
7069 7ffc5a86 Michael Hanselmann
    # instance's primary/secondary nodes.
7070 7ffc5a86 Michael Hanselmann
    if (level == locking.LEVEL_NODE and
7071 7ffc5a86 Michael Hanselmann
        self.needed_locks[locking.LEVEL_NODE] is not locking.ALL_SET):
7072 7ffc5a86 Michael Hanselmann
      self._LockInstancesNodes()
7073 7ffc5a86 Michael Hanselmann
7074 7ffc5a86 Michael Hanselmann
  def BuildHooksEnv(self):
7075 7ffc5a86 Michael Hanselmann
    """Build hooks env.
7076 7ffc5a86 Michael Hanselmann

7077 7ffc5a86 Michael Hanselmann
    This runs on the master, the primary and all the secondaries.
7078 7ffc5a86 Michael Hanselmann

7079 7ffc5a86 Michael Hanselmann
    """
7080 7ffc5a86 Michael Hanselmann
    env = {
7081 7ffc5a86 Michael Hanselmann
      "NODE_NAME": self.op.node_name,
7082 7ffc5a86 Michael Hanselmann
      }
7083 7ffc5a86 Michael Hanselmann
7084 7ffc5a86 Michael Hanselmann
    nl = [self.cfg.GetMasterNode()]
7085 7ffc5a86 Michael Hanselmann
7086 7ffc5a86 Michael Hanselmann
    if self.op.remote_node is not None:
7087 7ffc5a86 Michael Hanselmann
      env["NEW_SECONDARY"] = self.op.remote_node
7088 7ffc5a86 Michael Hanselmann
      nl.append(self.op.remote_node)
7089 7ffc5a86 Michael Hanselmann
7090 7ffc5a86 Michael Hanselmann
    return (env, nl, nl)
7091 7ffc5a86 Michael Hanselmann
7092 7ffc5a86 Michael Hanselmann
7093 c68174b6 Michael Hanselmann
class TLReplaceDisks(Tasklet):
7094 2bb5c911 Michael Hanselmann
  """Replaces disks for an instance.
7095 2bb5c911 Michael Hanselmann

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

7098 2bb5c911 Michael Hanselmann
  """
7099 2bb5c911 Michael Hanselmann
  def __init__(self, lu, instance_name, mode, iallocator_name, remote_node,
7100 7ea7bcf6 Iustin Pop
               disks, delay_iallocator, early_release):
7101 2bb5c911 Michael Hanselmann
    """Initializes this class.
7102 2bb5c911 Michael Hanselmann

7103 2bb5c911 Michael Hanselmann
    """
7104 464243a7 Michael Hanselmann
    Tasklet.__init__(self, lu)
7105 464243a7 Michael Hanselmann
7106 2bb5c911 Michael Hanselmann
    # Parameters
7107 2bb5c911 Michael Hanselmann
    self.instance_name = instance_name
7108 2bb5c911 Michael Hanselmann
    self.mode = mode
7109 2bb5c911 Michael Hanselmann
    self.iallocator_name = iallocator_name
7110 2bb5c911 Michael Hanselmann
    self.remote_node = remote_node
7111 2bb5c911 Michael Hanselmann
    self.disks = disks
7112 94a1b377 Michael Hanselmann
    self.delay_iallocator = delay_iallocator
7113 7ea7bcf6 Iustin Pop
    self.early_release = early_release
7114 2bb5c911 Michael Hanselmann
7115 2bb5c911 Michael Hanselmann
    # Runtime data
7116 2bb5c911 Michael Hanselmann
    self.instance = None
7117 2bb5c911 Michael Hanselmann
    self.new_node = None
7118 2bb5c911 Michael Hanselmann
    self.target_node = None
7119 2bb5c911 Michael Hanselmann
    self.other_node = None
7120 2bb5c911 Michael Hanselmann
    self.remote_node_info = None
7121 2bb5c911 Michael Hanselmann
    self.node_secondary_ip = None
7122 2bb5c911 Michael Hanselmann
7123 2bb5c911 Michael Hanselmann
  @staticmethod
7124 2bb5c911 Michael Hanselmann
  def CheckArguments(mode, remote_node, iallocator):
7125 c68174b6 Michael Hanselmann
    """Helper function for users of this class.
7126 c68174b6 Michael Hanselmann

7127 c68174b6 Michael Hanselmann
    """
7128 2bb5c911 Michael Hanselmann
    # check for valid parameter combination
7129 2bb5c911 Michael Hanselmann
    if mode == constants.REPLACE_DISK_CHG:
7130 02a00186 Michael Hanselmann
      if remote_node is None and iallocator is None:
7131 2bb5c911 Michael Hanselmann
        raise errors.OpPrereqError("When changing the secondary either an"
7132 2bb5c911 Michael Hanselmann
                                   " iallocator script must be used or the"
7133 5c983ee5 Iustin Pop
                                   " new node given", errors.ECODE_INVAL)
7134 02a00186 Michael Hanselmann
7135 02a00186 Michael Hanselmann
      if remote_node is not None and iallocator is not None:
7136 2bb5c911 Michael Hanselmann
        raise errors.OpPrereqError("Give either the iallocator or the new"
7137 5c983ee5 Iustin Pop
                                   " secondary, not both", errors.ECODE_INVAL)
7138 02a00186 Michael Hanselmann
7139 02a00186 Michael Hanselmann
    elif remote_node is not None or iallocator is not None:
7140 02a00186 Michael Hanselmann
      # Not replacing the secondary
7141 02a00186 Michael Hanselmann
      raise errors.OpPrereqError("The iallocator and new node options can"
7142 02a00186 Michael Hanselmann
                                 " only be used when changing the"
7143 5c983ee5 Iustin Pop
                                 " secondary node", errors.ECODE_INVAL)
7144 2bb5c911 Michael Hanselmann
7145 2bb5c911 Michael Hanselmann
  @staticmethod
7146 2bb5c911 Michael Hanselmann
  def _RunAllocator(lu, iallocator_name, instance_name, relocate_from):
7147 2bb5c911 Michael Hanselmann
    """Compute a new secondary node using an IAllocator.
7148 2bb5c911 Michael Hanselmann

7149 2bb5c911 Michael Hanselmann
    """
7150 2bb5c911 Michael Hanselmann
    ial = IAllocator(lu.cfg, lu.rpc,
7151 2bb5c911 Michael Hanselmann
                     mode=constants.IALLOCATOR_MODE_RELOC,
7152 2bb5c911 Michael Hanselmann
                     name=instance_name,
7153 2bb5c911 Michael Hanselmann
                     relocate_from=relocate_from)
7154 2bb5c911 Michael Hanselmann
7155 2bb5c911 Michael Hanselmann
    ial.Run(iallocator_name)
7156 2bb5c911 Michael Hanselmann
7157 2bb5c911 Michael Hanselmann
    if not ial.success:
7158 2bb5c911 Michael Hanselmann
      raise errors.OpPrereqError("Can't compute nodes using iallocator '%s':"
7159 5c983ee5 Iustin Pop
                                 " %s" % (iallocator_name, ial.info),
7160 5c983ee5 Iustin Pop
                                 errors.ECODE_NORES)
7161 2bb5c911 Michael Hanselmann
7162 680f0a89 Iustin Pop
    if len(ial.result) != ial.required_nodes:
7163 2bb5c911 Michael Hanselmann
      raise errors.OpPrereqError("iallocator '%s' returned invalid number"
7164 2bb5c911 Michael Hanselmann
                                 " of nodes (%s), required %s" %
7165 d984846d Iustin Pop
                                 (iallocator_name,
7166 680f0a89 Iustin Pop
                                  len(ial.result), ial.required_nodes),
7167 5c983ee5 Iustin Pop
                                 errors.ECODE_FAULT)
7168 2bb5c911 Michael Hanselmann
7169 680f0a89 Iustin Pop
    remote_node_name = ial.result[0]
7170 2bb5c911 Michael Hanselmann
7171 2bb5c911 Michael Hanselmann
    lu.LogInfo("Selected new secondary for instance '%s': %s",
7172 2bb5c911 Michael Hanselmann
               instance_name, remote_node_name)
7173 2bb5c911 Michael Hanselmann
7174 2bb5c911 Michael Hanselmann
    return remote_node_name
7175 2bb5c911 Michael Hanselmann
7176 942be002 Michael Hanselmann
  def _FindFaultyDisks(self, node_name):
7177 2d9005d8 Michael Hanselmann
    return _FindFaultyInstanceDisks(self.cfg, self.rpc, self.instance,
7178 2d9005d8 Michael Hanselmann
                                    node_name, True)
7179 942be002 Michael Hanselmann
7180 2bb5c911 Michael Hanselmann
  def CheckPrereq(self):
7181 2bb5c911 Michael Hanselmann
    """Check prerequisites.
7182 2bb5c911 Michael Hanselmann

7183 2bb5c911 Michael Hanselmann
    This checks that the instance is in the cluster.
7184 2bb5c911 Michael Hanselmann

7185 2bb5c911 Michael Hanselmann
    """
7186 e9022531 Iustin Pop
    self.instance = instance = self.cfg.GetInstanceInfo(self.instance_name)
7187 e9022531 Iustin Pop
    assert instance is not None, \
7188 20eca47d Iustin Pop
      "Cannot retrieve locked instance %s" % self.instance_name
7189 2bb5c911 Michael Hanselmann
7190 e9022531 Iustin Pop
    if instance.disk_template != constants.DT_DRBD8:
7191 7e9366f7 Iustin Pop
      raise errors.OpPrereqError("Can only run replace disks for DRBD8-based"
7192 5c983ee5 Iustin Pop
                                 " instances", errors.ECODE_INVAL)
7193 a8083063 Iustin Pop
7194 e9022531 Iustin Pop
    if len(instance.secondary_nodes) != 1:
7195 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("The instance has a strange layout,"
7196 3ecf6786 Iustin Pop
                                 " expected one secondary but found %d" %
7197 5c983ee5 Iustin Pop
                                 len(instance.secondary_nodes),
7198 5c983ee5 Iustin Pop
                                 errors.ECODE_FAULT)
7199 a8083063 Iustin Pop
7200 94a1b377 Michael Hanselmann
    if not self.delay_iallocator:
7201 94a1b377 Michael Hanselmann
      self._CheckPrereq2()
7202 94a1b377 Michael Hanselmann
7203 94a1b377 Michael Hanselmann
  def _CheckPrereq2(self):
7204 94a1b377 Michael Hanselmann
    """Check prerequisites, second part.
7205 94a1b377 Michael Hanselmann

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

7211 94a1b377 Michael Hanselmann
    """
7212 94a1b377 Michael Hanselmann
    instance = self.instance
7213 e9022531 Iustin Pop
    secondary_node = instance.secondary_nodes[0]
7214 a9e0c397 Iustin Pop
7215 2bb5c911 Michael Hanselmann
    if self.iallocator_name is None:
7216 2bb5c911 Michael Hanselmann
      remote_node = self.remote_node
7217 2bb5c911 Michael Hanselmann
    else:
7218 2bb5c911 Michael Hanselmann
      remote_node = self._RunAllocator(self.lu, self.iallocator_name,
7219 e9022531 Iustin Pop
                                       instance.name, instance.secondary_nodes)
7220 b6e82a65 Iustin Pop
7221 a9e0c397 Iustin Pop
    if remote_node is not None:
7222 a9e0c397 Iustin Pop
      self.remote_node_info = self.cfg.GetNodeInfo(remote_node)
7223 efd990e4 Guido Trotter
      assert self.remote_node_info is not None, \
7224 efd990e4 Guido Trotter
        "Cannot retrieve locked node %s" % remote_node
7225 a9e0c397 Iustin Pop
    else:
7226 a9e0c397 Iustin Pop
      self.remote_node_info = None
7227 2bb5c911 Michael Hanselmann
7228 2bb5c911 Michael Hanselmann
    if remote_node == self.instance.primary_node:
7229 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("The specified node is the primary node of"
7230 5c983ee5 Iustin Pop
                                 " the instance.", errors.ECODE_INVAL)
7231 2bb5c911 Michael Hanselmann
7232 2bb5c911 Michael Hanselmann
    if remote_node == secondary_node:
7233 7e9366f7 Iustin Pop
      raise errors.OpPrereqError("The specified node is already the"
7234 5c983ee5 Iustin Pop
                                 " secondary node of the instance.",
7235 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
7236 7e9366f7 Iustin Pop
7237 2945fd2d Michael Hanselmann
    if self.disks and self.mode in (constants.REPLACE_DISK_AUTO,
7238 2945fd2d Michael Hanselmann
                                    constants.REPLACE_DISK_CHG):
7239 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Cannot specify disks to be replaced",
7240 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
7241 942be002 Michael Hanselmann
7242 2945fd2d Michael Hanselmann
    if self.mode == constants.REPLACE_DISK_AUTO:
7243 e9022531 Iustin Pop
      faulty_primary = self._FindFaultyDisks(instance.primary_node)
7244 942be002 Michael Hanselmann
      faulty_secondary = self._FindFaultyDisks(secondary_node)
7245 942be002 Michael Hanselmann
7246 942be002 Michael Hanselmann
      if faulty_primary and faulty_secondary:
7247 942be002 Michael Hanselmann
        raise errors.OpPrereqError("Instance %s has faulty disks on more than"
7248 942be002 Michael Hanselmann
                                   " one node and can not be repaired"
7249 5c983ee5 Iustin Pop
                                   " automatically" % self.instance_name,
7250 5c983ee5 Iustin Pop
                                   errors.ECODE_STATE)
7251 942be002 Michael Hanselmann
7252 942be002 Michael Hanselmann
      if faulty_primary:
7253 942be002 Michael Hanselmann
        self.disks = faulty_primary
7254 e9022531 Iustin Pop
        self.target_node = instance.primary_node
7255 942be002 Michael Hanselmann
        self.other_node = secondary_node
7256 942be002 Michael Hanselmann
        check_nodes = [self.target_node, self.other_node]
7257 942be002 Michael Hanselmann
      elif faulty_secondary:
7258 942be002 Michael Hanselmann
        self.disks = faulty_secondary
7259 942be002 Michael Hanselmann
        self.target_node = secondary_node
7260 e9022531 Iustin Pop
        self.other_node = instance.primary_node
7261 942be002 Michael Hanselmann
        check_nodes = [self.target_node, self.other_node]
7262 942be002 Michael Hanselmann
      else:
7263 942be002 Michael Hanselmann
        self.disks = []
7264 942be002 Michael Hanselmann
        check_nodes = []
7265 942be002 Michael Hanselmann
7266 942be002 Michael Hanselmann
    else:
7267 942be002 Michael Hanselmann
      # Non-automatic modes
7268 942be002 Michael Hanselmann
      if self.mode == constants.REPLACE_DISK_PRI:
7269 e9022531 Iustin Pop
        self.target_node = instance.primary_node
7270 942be002 Michael Hanselmann
        self.other_node = secondary_node
7271 942be002 Michael Hanselmann
        check_nodes = [self.target_node, self.other_node]
7272 7e9366f7 Iustin Pop
7273 942be002 Michael Hanselmann
      elif self.mode == constants.REPLACE_DISK_SEC:
7274 942be002 Michael Hanselmann
        self.target_node = secondary_node
7275 e9022531 Iustin Pop
        self.other_node = instance.primary_node
7276 942be002 Michael Hanselmann
        check_nodes = [self.target_node, self.other_node]
7277 a9e0c397 Iustin Pop
7278 942be002 Michael Hanselmann
      elif self.mode == constants.REPLACE_DISK_CHG:
7279 942be002 Michael Hanselmann
        self.new_node = remote_node
7280 e9022531 Iustin Pop
        self.other_node = instance.primary_node
7281 942be002 Michael Hanselmann
        self.target_node = secondary_node
7282 942be002 Michael Hanselmann
        check_nodes = [self.new_node, self.other_node]
7283 54155f52 Iustin Pop
7284 942be002 Michael Hanselmann
        _CheckNodeNotDrained(self.lu, remote_node)
7285 a8083063 Iustin Pop
7286 9af0fa6a Iustin Pop
        old_node_info = self.cfg.GetNodeInfo(secondary_node)
7287 9af0fa6a Iustin Pop
        assert old_node_info is not None
7288 9af0fa6a Iustin Pop
        if old_node_info.offline and not self.early_release:
7289 9af0fa6a Iustin Pop
          # doesn't make sense to delay the release
7290 9af0fa6a Iustin Pop
          self.early_release = True
7291 9af0fa6a Iustin Pop
          self.lu.LogInfo("Old secondary %s is offline, automatically enabling"
7292 9af0fa6a Iustin Pop
                          " early-release mode", secondary_node)
7293 9af0fa6a Iustin Pop
7294 942be002 Michael Hanselmann
      else:
7295 942be002 Michael Hanselmann
        raise errors.ProgrammerError("Unhandled disk replace mode (%s)" %
7296 942be002 Michael Hanselmann
                                     self.mode)
7297 942be002 Michael Hanselmann
7298 942be002 Michael Hanselmann
      # If not specified all disks should be replaced
7299 942be002 Michael Hanselmann
      if not self.disks:
7300 942be002 Michael Hanselmann
        self.disks = range(len(self.instance.disks))
7301 a9e0c397 Iustin Pop
7302 2bb5c911 Michael Hanselmann
    for node in check_nodes:
7303 2bb5c911 Michael Hanselmann
      _CheckNodeOnline(self.lu, node)
7304 e4376078 Iustin Pop
7305 2bb5c911 Michael Hanselmann
    # Check whether disks are valid
7306 2bb5c911 Michael Hanselmann
    for disk_idx in self.disks:
7307 e9022531 Iustin Pop
      instance.FindDisk(disk_idx)
7308 e4376078 Iustin Pop
7309 2bb5c911 Michael Hanselmann
    # Get secondary node IP addresses
7310 2bb5c911 Michael Hanselmann
    node_2nd_ip = {}
7311 e4376078 Iustin Pop
7312 2bb5c911 Michael Hanselmann
    for node_name in [self.target_node, self.other_node, self.new_node]:
7313 2bb5c911 Michael Hanselmann
      if node_name is not None:
7314 2bb5c911 Michael Hanselmann
        node_2nd_ip[node_name] = self.cfg.GetNodeInfo(node_name).secondary_ip
7315 e4376078 Iustin Pop
7316 2bb5c911 Michael Hanselmann
    self.node_secondary_ip = node_2nd_ip
7317 a9e0c397 Iustin Pop
7318 c68174b6 Michael Hanselmann
  def Exec(self, feedback_fn):
7319 2bb5c911 Michael Hanselmann
    """Execute disk replacement.
7320 2bb5c911 Michael Hanselmann

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

7323 a9e0c397 Iustin Pop
    """
7324 94a1b377 Michael Hanselmann
    if self.delay_iallocator:
7325 94a1b377 Michael Hanselmann
      self._CheckPrereq2()
7326 94a1b377 Michael Hanselmann
7327 942be002 Michael Hanselmann
    if not self.disks:
7328 942be002 Michael Hanselmann
      feedback_fn("No disks need replacement")
7329 942be002 Michael Hanselmann
      return
7330 942be002 Michael Hanselmann
7331 942be002 Michael Hanselmann
    feedback_fn("Replacing disk(s) %s for %s" %
7332 1f864b60 Iustin Pop
                (utils.CommaJoin(self.disks), self.instance.name))
7333 7ffc5a86 Michael Hanselmann
7334 2bb5c911 Michael Hanselmann
    activate_disks = (not self.instance.admin_up)
7335 2bb5c911 Michael Hanselmann
7336 2bb5c911 Michael Hanselmann
    # Activate the instance disks if we're replacing them on a down instance
7337 2bb5c911 Michael Hanselmann
    if activate_disks:
7338 2bb5c911 Michael Hanselmann
      _StartInstanceDisks(self.lu, self.instance, True)
7339 2bb5c911 Michael Hanselmann
7340 2bb5c911 Michael Hanselmann
    try:
7341 942be002 Michael Hanselmann
      # Should we replace the secondary node?
7342 942be002 Michael Hanselmann
      if self.new_node is not None:
7343 a4eae71f Michael Hanselmann
        fn = self._ExecDrbd8Secondary
7344 2bb5c911 Michael Hanselmann
      else:
7345 a4eae71f Michael Hanselmann
        fn = self._ExecDrbd8DiskOnly
7346 a4eae71f Michael Hanselmann
7347 a4eae71f Michael Hanselmann
      return fn(feedback_fn)
7348 2bb5c911 Michael Hanselmann
7349 2bb5c911 Michael Hanselmann
    finally:
7350 5c983ee5 Iustin Pop
      # Deactivate the instance disks if we're replacing them on a
7351 5c983ee5 Iustin Pop
      # down instance
7352 2bb5c911 Michael Hanselmann
      if activate_disks:
7353 2bb5c911 Michael Hanselmann
        _SafeShutdownInstanceDisks(self.lu, self.instance)
7354 2bb5c911 Michael Hanselmann
7355 2bb5c911 Michael Hanselmann
  def _CheckVolumeGroup(self, nodes):
7356 2bb5c911 Michael Hanselmann
    self.lu.LogInfo("Checking volume groups")
7357 2bb5c911 Michael Hanselmann
7358 a9e0c397 Iustin Pop
    vgname = self.cfg.GetVGName()
7359 cff90b79 Iustin Pop
7360 2bb5c911 Michael Hanselmann
    # Make sure volume group exists on all involved nodes
7361 2bb5c911 Michael Hanselmann
    results = self.rpc.call_vg_list(nodes)
7362 cff90b79 Iustin Pop
    if not results:
7363 cff90b79 Iustin Pop
      raise errors.OpExecError("Can't list volume groups on the nodes")
7364 2bb5c911 Michael Hanselmann
7365 2bb5c911 Michael Hanselmann
    for node in nodes:
7366 781de953 Iustin Pop
      res = results[node]
7367 4c4e4e1e Iustin Pop
      res.Raise("Error checking node %s" % node)
7368 2bb5c911 Michael Hanselmann
      if vgname not in res.payload:
7369 2bb5c911 Michael Hanselmann
        raise errors.OpExecError("Volume group '%s' not found on node %s" %
7370 2bb5c911 Michael Hanselmann
                                 (vgname, node))
7371 2bb5c911 Michael Hanselmann
7372 2bb5c911 Michael Hanselmann
  def _CheckDisksExistence(self, nodes):
7373 2bb5c911 Michael Hanselmann
    # Check disk existence
7374 2bb5c911 Michael Hanselmann
    for idx, dev in enumerate(self.instance.disks):
7375 2bb5c911 Michael Hanselmann
      if idx not in self.disks:
7376 cff90b79 Iustin Pop
        continue
7377 2bb5c911 Michael Hanselmann
7378 2bb5c911 Michael Hanselmann
      for node in nodes:
7379 2bb5c911 Michael Hanselmann
        self.lu.LogInfo("Checking disk/%d on %s" % (idx, node))
7380 2bb5c911 Michael Hanselmann
        self.cfg.SetDiskID(dev, node)
7381 2bb5c911 Michael Hanselmann
7382 23829f6f Iustin Pop
        result = self.rpc.call_blockdev_find(node, dev)
7383 2bb5c911 Michael Hanselmann
7384 4c4e4e1e Iustin Pop
        msg = result.fail_msg
7385 2bb5c911 Michael Hanselmann
        if msg or not result.payload:
7386 2bb5c911 Michael Hanselmann
          if not msg:
7387 2bb5c911 Michael Hanselmann
            msg = "disk not found"
7388 23829f6f Iustin Pop
          raise errors.OpExecError("Can't find disk/%d on node %s: %s" %
7389 23829f6f Iustin Pop
                                   (idx, node, msg))
7390 cff90b79 Iustin Pop
7391 2bb5c911 Michael Hanselmann
  def _CheckDisksConsistency(self, node_name, on_primary, ldisk):
7392 2bb5c911 Michael Hanselmann
    for idx, dev in enumerate(self.instance.disks):
7393 2bb5c911 Michael Hanselmann
      if idx not in self.disks:
7394 cff90b79 Iustin Pop
        continue
7395 cff90b79 Iustin Pop
7396 2bb5c911 Michael Hanselmann
      self.lu.LogInfo("Checking disk/%d consistency on node %s" %
7397 2bb5c911 Michael Hanselmann
                      (idx, node_name))
7398 2bb5c911 Michael Hanselmann
7399 2bb5c911 Michael Hanselmann
      if not _CheckDiskConsistency(self.lu, dev, node_name, on_primary,
7400 2bb5c911 Michael Hanselmann
                                   ldisk=ldisk):
7401 2bb5c911 Michael Hanselmann
        raise errors.OpExecError("Node %s has degraded storage, unsafe to"
7402 2bb5c911 Michael Hanselmann
                                 " replace disks for instance %s" %
7403 2bb5c911 Michael Hanselmann
                                 (node_name, self.instance.name))
7404 2bb5c911 Michael Hanselmann
7405 2bb5c911 Michael Hanselmann
  def _CreateNewStorage(self, node_name):
7406 2bb5c911 Michael Hanselmann
    vgname = self.cfg.GetVGName()
7407 2bb5c911 Michael Hanselmann
    iv_names = {}
7408 2bb5c911 Michael Hanselmann
7409 2bb5c911 Michael Hanselmann
    for idx, dev in enumerate(self.instance.disks):
7410 2bb5c911 Michael Hanselmann
      if idx not in self.disks:
7411 a9e0c397 Iustin Pop
        continue
7412 2bb5c911 Michael Hanselmann
7413 2bb5c911 Michael Hanselmann
      self.lu.LogInfo("Adding storage on %s for disk/%d" % (node_name, idx))
7414 2bb5c911 Michael Hanselmann
7415 2bb5c911 Michael Hanselmann
      self.cfg.SetDiskID(dev, node_name)
7416 2bb5c911 Michael Hanselmann
7417 2bb5c911 Michael Hanselmann
      lv_names = [".disk%d_%s" % (idx, suffix) for suffix in ["data", "meta"]]
7418 2bb5c911 Michael Hanselmann
      names = _GenerateUniqueNames(self.lu, lv_names)
7419 2bb5c911 Michael Hanselmann
7420 2bb5c911 Michael Hanselmann
      lv_data = objects.Disk(dev_type=constants.LD_LV, size=dev.size,
7421 a9e0c397 Iustin Pop
                             logical_id=(vgname, names[0]))
7422 a9e0c397 Iustin Pop
      lv_meta = objects.Disk(dev_type=constants.LD_LV, size=128,
7423 a9e0c397 Iustin Pop
                             logical_id=(vgname, names[1]))
7424 2bb5c911 Michael Hanselmann
7425 a9e0c397 Iustin Pop
      new_lvs = [lv_data, lv_meta]
7426 a9e0c397 Iustin Pop
      old_lvs = dev.children
7427 a9e0c397 Iustin Pop
      iv_names[dev.iv_name] = (dev, old_lvs, new_lvs)
7428 2bb5c911 Michael Hanselmann
7429 428958aa Iustin Pop
      # we pass force_create=True to force the LVM creation
7430 a9e0c397 Iustin Pop
      for new_lv in new_lvs:
7431 2bb5c911 Michael Hanselmann
        _CreateBlockDev(self.lu, node_name, self.instance, new_lv, True,
7432 2bb5c911 Michael Hanselmann
                        _GetInstanceInfoText(self.instance), False)
7433 2bb5c911 Michael Hanselmann
7434 2bb5c911 Michael Hanselmann
    return iv_names
7435 2bb5c911 Michael Hanselmann
7436 2bb5c911 Michael Hanselmann
  def _CheckDevices(self, node_name, iv_names):
7437 1122eb25 Iustin Pop
    for name, (dev, _, _) in iv_names.iteritems():
7438 2bb5c911 Michael Hanselmann
      self.cfg.SetDiskID(dev, node_name)
7439 2bb5c911 Michael Hanselmann
7440 2bb5c911 Michael Hanselmann
      result = self.rpc.call_blockdev_find(node_name, dev)
7441 2bb5c911 Michael Hanselmann
7442 2bb5c911 Michael Hanselmann
      msg = result.fail_msg
7443 2bb5c911 Michael Hanselmann
      if msg or not result.payload:
7444 2bb5c911 Michael Hanselmann
        if not msg:
7445 2bb5c911 Michael Hanselmann
          msg = "disk not found"
7446 2bb5c911 Michael Hanselmann
        raise errors.OpExecError("Can't find DRBD device %s: %s" %
7447 2bb5c911 Michael Hanselmann
                                 (name, msg))
7448 2bb5c911 Michael Hanselmann
7449 96acbc09 Michael Hanselmann
      if result.payload.is_degraded:
7450 2bb5c911 Michael Hanselmann
        raise errors.OpExecError("DRBD device %s is degraded!" % name)
7451 2bb5c911 Michael Hanselmann
7452 2bb5c911 Michael Hanselmann
  def _RemoveOldStorage(self, node_name, iv_names):
7453 1122eb25 Iustin Pop
    for name, (_, old_lvs, _) in iv_names.iteritems():
7454 2bb5c911 Michael Hanselmann
      self.lu.LogInfo("Remove logical volumes for %s" % name)
7455 2bb5c911 Michael Hanselmann
7456 2bb5c911 Michael Hanselmann
      for lv in old_lvs:
7457 2bb5c911 Michael Hanselmann
        self.cfg.SetDiskID(lv, node_name)
7458 2bb5c911 Michael Hanselmann
7459 2bb5c911 Michael Hanselmann
        msg = self.rpc.call_blockdev_remove(node_name, lv).fail_msg
7460 2bb5c911 Michael Hanselmann
        if msg:
7461 2bb5c911 Michael Hanselmann
          self.lu.LogWarning("Can't remove old LV: %s" % msg,
7462 2bb5c911 Michael Hanselmann
                             hint="remove unused LVs manually")
7463 2bb5c911 Michael Hanselmann
7464 7ea7bcf6 Iustin Pop
  def _ReleaseNodeLock(self, node_name):
7465 7ea7bcf6 Iustin Pop
    """Releases the lock for a given node."""
7466 7ea7bcf6 Iustin Pop
    self.lu.context.glm.release(locking.LEVEL_NODE, node_name)
7467 7ea7bcf6 Iustin Pop
7468 a4eae71f Michael Hanselmann
  def _ExecDrbd8DiskOnly(self, feedback_fn):
7469 2bb5c911 Michael Hanselmann
    """Replace a disk on the primary or secondary for DRBD 8.
7470 2bb5c911 Michael Hanselmann

7471 2bb5c911 Michael Hanselmann
    The algorithm for replace is quite complicated:
7472 2bb5c911 Michael Hanselmann

7473 2bb5c911 Michael Hanselmann
      1. for each disk to be replaced:
7474 2bb5c911 Michael Hanselmann

7475 2bb5c911 Michael Hanselmann
        1. create new LVs on the target node with unique names
7476 2bb5c911 Michael Hanselmann
        1. detach old LVs from the drbd device
7477 2bb5c911 Michael Hanselmann
        1. rename old LVs to name_replaced.<time_t>
7478 2bb5c911 Michael Hanselmann
        1. rename new LVs to old LVs
7479 2bb5c911 Michael Hanselmann
        1. attach the new LVs (with the old names now) to the drbd device
7480 2bb5c911 Michael Hanselmann

7481 2bb5c911 Michael Hanselmann
      1. wait for sync across all devices
7482 2bb5c911 Michael Hanselmann

7483 2bb5c911 Michael Hanselmann
      1. for each modified disk:
7484 2bb5c911 Michael Hanselmann

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

7487 2bb5c911 Michael Hanselmann
    Failures are not very well handled.
7488 2bb5c911 Michael Hanselmann

7489 2bb5c911 Michael Hanselmann
    """
7490 2bb5c911 Michael Hanselmann
    steps_total = 6
7491 2bb5c911 Michael Hanselmann
7492 2bb5c911 Michael Hanselmann
    # Step: check device activation
7493 2bb5c911 Michael Hanselmann
    self.lu.LogStep(1, steps_total, "Check device existence")
7494 2bb5c911 Michael Hanselmann
    self._CheckDisksExistence([self.other_node, self.target_node])
7495 2bb5c911 Michael Hanselmann
    self._CheckVolumeGroup([self.target_node, self.other_node])
7496 2bb5c911 Michael Hanselmann
7497 2bb5c911 Michael Hanselmann
    # Step: check other node consistency
7498 2bb5c911 Michael Hanselmann
    self.lu.LogStep(2, steps_total, "Check peer consistency")
7499 2bb5c911 Michael Hanselmann
    self._CheckDisksConsistency(self.other_node,
7500 2bb5c911 Michael Hanselmann
                                self.other_node == self.instance.primary_node,
7501 2bb5c911 Michael Hanselmann
                                False)
7502 2bb5c911 Michael Hanselmann
7503 2bb5c911 Michael Hanselmann
    # Step: create new storage
7504 2bb5c911 Michael Hanselmann
    self.lu.LogStep(3, steps_total, "Allocate new storage")
7505 2bb5c911 Michael Hanselmann
    iv_names = self._CreateNewStorage(self.target_node)
7506 a9e0c397 Iustin Pop
7507 cff90b79 Iustin Pop
    # Step: for each lv, detach+rename*2+attach
7508 2bb5c911 Michael Hanselmann
    self.lu.LogStep(4, steps_total, "Changing drbd configuration")
7509 cff90b79 Iustin Pop
    for dev, old_lvs, new_lvs in iv_names.itervalues():
7510 2bb5c911 Michael Hanselmann
      self.lu.LogInfo("Detaching %s drbd from local storage" % dev.iv_name)
7511 2bb5c911 Michael Hanselmann
7512 4d4a651d Michael Hanselmann
      result = self.rpc.call_blockdev_removechildren(self.target_node, dev,
7513 4d4a651d Michael Hanselmann
                                                     old_lvs)
7514 4c4e4e1e Iustin Pop
      result.Raise("Can't detach drbd from local storage on node"
7515 2bb5c911 Michael Hanselmann
                   " %s for device %s" % (self.target_node, dev.iv_name))
7516 cff90b79 Iustin Pop
      #dev.children = []
7517 cff90b79 Iustin Pop
      #cfg.Update(instance)
7518 a9e0c397 Iustin Pop
7519 a9e0c397 Iustin Pop
      # ok, we created the new LVs, so now we know we have the needed
7520 a9e0c397 Iustin Pop
      # storage; as such, we proceed on the target node to rename
7521 a9e0c397 Iustin Pop
      # old_lv to _old, and new_lv to old_lv; note that we rename LVs
7522 c99a3cc0 Manuel Franceschini
      # using the assumption that logical_id == physical_id (which in
7523 a9e0c397 Iustin Pop
      # turn is the unique_id on that node)
7524 cff90b79 Iustin Pop
7525 cff90b79 Iustin Pop
      # FIXME(iustin): use a better name for the replaced LVs
7526 a9e0c397 Iustin Pop
      temp_suffix = int(time.time())
7527 a9e0c397 Iustin Pop
      ren_fn = lambda d, suff: (d.physical_id[0],
7528 a9e0c397 Iustin Pop
                                d.physical_id[1] + "_replaced-%s" % suff)
7529 2bb5c911 Michael Hanselmann
7530 2bb5c911 Michael Hanselmann
      # Build the rename list based on what LVs exist on the node
7531 2bb5c911 Michael Hanselmann
      rename_old_to_new = []
7532 cff90b79 Iustin Pop
      for to_ren in old_lvs:
7533 2bb5c911 Michael Hanselmann
        result = self.rpc.call_blockdev_find(self.target_node, to_ren)
7534 4c4e4e1e Iustin Pop
        if not result.fail_msg and result.payload:
7535 23829f6f Iustin Pop
          # device exists
7536 2bb5c911 Michael Hanselmann
          rename_old_to_new.append((to_ren, ren_fn(to_ren, temp_suffix)))
7537 cff90b79 Iustin Pop
7538 2bb5c911 Michael Hanselmann
      self.lu.LogInfo("Renaming the old LVs on the target node")
7539 4d4a651d Michael Hanselmann
      result = self.rpc.call_blockdev_rename(self.target_node,
7540 4d4a651d Michael Hanselmann
                                             rename_old_to_new)
7541 2bb5c911 Michael Hanselmann
      result.Raise("Can't rename old LVs on node %s" % self.target_node)
7542 2bb5c911 Michael Hanselmann
7543 2bb5c911 Michael Hanselmann
      # Now we rename the new LVs to the old LVs
7544 2bb5c911 Michael Hanselmann
      self.lu.LogInfo("Renaming the new LVs on the target node")
7545 2bb5c911 Michael Hanselmann
      rename_new_to_old = [(new, old.physical_id)
7546 2bb5c911 Michael Hanselmann
                           for old, new in zip(old_lvs, new_lvs)]
7547 4d4a651d Michael Hanselmann
      result = self.rpc.call_blockdev_rename(self.target_node,
7548 4d4a651d Michael Hanselmann
                                             rename_new_to_old)
7549 2bb5c911 Michael Hanselmann
      result.Raise("Can't rename new LVs on node %s" % self.target_node)
7550 cff90b79 Iustin Pop
7551 cff90b79 Iustin Pop
      for old, new in zip(old_lvs, new_lvs):
7552 cff90b79 Iustin Pop
        new.logical_id = old.logical_id
7553 2bb5c911 Michael Hanselmann
        self.cfg.SetDiskID(new, self.target_node)
7554 a9e0c397 Iustin Pop
7555 cff90b79 Iustin Pop
      for disk in old_lvs:
7556 cff90b79 Iustin Pop
        disk.logical_id = ren_fn(disk, temp_suffix)
7557 2bb5c911 Michael Hanselmann
        self.cfg.SetDiskID(disk, self.target_node)
7558 a9e0c397 Iustin Pop
7559 2bb5c911 Michael Hanselmann
      # Now that the new lvs have the old name, we can add them to the device
7560 2bb5c911 Michael Hanselmann
      self.lu.LogInfo("Adding new mirror component on %s" % self.target_node)
7561 4d4a651d Michael Hanselmann
      result = self.rpc.call_blockdev_addchildren(self.target_node, dev,
7562 4d4a651d Michael Hanselmann
                                                  new_lvs)
7563 4c4e4e1e Iustin Pop
      msg = result.fail_msg
7564 2cc1da8b Iustin Pop
      if msg:
7565 a9e0c397 Iustin Pop
        for new_lv in new_lvs:
7566 4d4a651d Michael Hanselmann
          msg2 = self.rpc.call_blockdev_remove(self.target_node,
7567 4d4a651d Michael Hanselmann
                                               new_lv).fail_msg
7568 4c4e4e1e Iustin Pop
          if msg2:
7569 2bb5c911 Michael Hanselmann
            self.lu.LogWarning("Can't rollback device %s: %s", dev, msg2,
7570 2bb5c911 Michael Hanselmann
                               hint=("cleanup manually the unused logical"
7571 2bb5c911 Michael Hanselmann
                                     "volumes"))
7572 2cc1da8b Iustin Pop
        raise errors.OpExecError("Can't add local storage to drbd: %s" % msg)
7573 a9e0c397 Iustin Pop
7574 a9e0c397 Iustin Pop
      dev.children = new_lvs
7575 a9e0c397 Iustin Pop
7576 a4eae71f Michael Hanselmann
      self.cfg.Update(self.instance, feedback_fn)
7577 a9e0c397 Iustin Pop
7578 7ea7bcf6 Iustin Pop
    cstep = 5
7579 7ea7bcf6 Iustin Pop
    if self.early_release:
7580 7ea7bcf6 Iustin Pop
      self.lu.LogStep(cstep, steps_total, "Removing old storage")
7581 7ea7bcf6 Iustin Pop
      cstep += 1
7582 7ea7bcf6 Iustin Pop
      self._RemoveOldStorage(self.target_node, iv_names)
7583 d5cd389c Iustin Pop
      # WARNING: we release both node locks here, do not do other RPCs
7584 d5cd389c Iustin Pop
      # than WaitForSync to the primary node
7585 d5cd389c Iustin Pop
      self._ReleaseNodeLock([self.target_node, self.other_node])
7586 7ea7bcf6 Iustin Pop
7587 2bb5c911 Michael Hanselmann
    # Wait for sync
7588 2bb5c911 Michael Hanselmann
    # This can fail as the old devices are degraded and _WaitForSync
7589 2bb5c911 Michael Hanselmann
    # does a combined result over all disks, so we don't check its return value
7590 7ea7bcf6 Iustin Pop
    self.lu.LogStep(cstep, steps_total, "Sync devices")
7591 7ea7bcf6 Iustin Pop
    cstep += 1
7592 b6c07b79 Michael Hanselmann
    _WaitForSync(self.lu, self.instance)
7593 a9e0c397 Iustin Pop
7594 2bb5c911 Michael Hanselmann
    # Check all devices manually
7595 2bb5c911 Michael Hanselmann
    self._CheckDevices(self.instance.primary_node, iv_names)
7596 a9e0c397 Iustin Pop
7597 cff90b79 Iustin Pop
    # Step: remove old storage
7598 7ea7bcf6 Iustin Pop
    if not self.early_release:
7599 7ea7bcf6 Iustin Pop
      self.lu.LogStep(cstep, steps_total, "Removing old storage")
7600 7ea7bcf6 Iustin Pop
      cstep += 1
7601 7ea7bcf6 Iustin Pop
      self._RemoveOldStorage(self.target_node, iv_names)
7602 a9e0c397 Iustin Pop
7603 a4eae71f Michael Hanselmann
  def _ExecDrbd8Secondary(self, feedback_fn):
7604 2bb5c911 Michael Hanselmann
    """Replace the secondary node for DRBD 8.
7605 a9e0c397 Iustin Pop

7606 a9e0c397 Iustin Pop
    The algorithm for replace is quite complicated:
7607 a9e0c397 Iustin Pop
      - for all disks of the instance:
7608 a9e0c397 Iustin Pop
        - create new LVs on the new node with same names
7609 a9e0c397 Iustin Pop
        - shutdown the drbd device on the old secondary
7610 a9e0c397 Iustin Pop
        - disconnect the drbd network on the primary
7611 a9e0c397 Iustin Pop
        - create the drbd device on the new secondary
7612 a9e0c397 Iustin Pop
        - network attach the drbd on the primary, using an artifice:
7613 a9e0c397 Iustin Pop
          the drbd code for Attach() will connect to the network if it
7614 a9e0c397 Iustin Pop
          finds a device which is connected to the good local disks but
7615 a9e0c397 Iustin Pop
          not network enabled
7616 a9e0c397 Iustin Pop
      - wait for sync across all devices
7617 a9e0c397 Iustin Pop
      - remove all disks from the old secondary
7618 a9e0c397 Iustin Pop

7619 a9e0c397 Iustin Pop
    Failures are not very well handled.
7620 0834c866 Iustin Pop

7621 a9e0c397 Iustin Pop
    """
7622 0834c866 Iustin Pop
    steps_total = 6
7623 0834c866 Iustin Pop
7624 0834c866 Iustin Pop
    # Step: check device activation
7625 2bb5c911 Michael Hanselmann
    self.lu.LogStep(1, steps_total, "Check device existence")
7626 2bb5c911 Michael Hanselmann
    self._CheckDisksExistence([self.instance.primary_node])
7627 2bb5c911 Michael Hanselmann
    self._CheckVolumeGroup([self.instance.primary_node])
7628 0834c866 Iustin Pop
7629 0834c866 Iustin Pop
    # Step: check other node consistency
7630 2bb5c911 Michael Hanselmann
    self.lu.LogStep(2, steps_total, "Check peer consistency")
7631 2bb5c911 Michael Hanselmann
    self._CheckDisksConsistency(self.instance.primary_node, True, True)
7632 0834c866 Iustin Pop
7633 0834c866 Iustin Pop
    # Step: create new storage
7634 2bb5c911 Michael Hanselmann
    self.lu.LogStep(3, steps_total, "Allocate new storage")
7635 2bb5c911 Michael Hanselmann
    for idx, dev in enumerate(self.instance.disks):
7636 2bb5c911 Michael Hanselmann
      self.lu.LogInfo("Adding new local storage on %s for disk/%d" %
7637 2bb5c911 Michael Hanselmann
                      (self.new_node, idx))
7638 428958aa Iustin Pop
      # we pass force_create=True to force LVM creation
7639 a9e0c397 Iustin Pop
      for new_lv in dev.children:
7640 2bb5c911 Michael Hanselmann
        _CreateBlockDev(self.lu, self.new_node, self.instance, new_lv, True,
7641 2bb5c911 Michael Hanselmann
                        _GetInstanceInfoText(self.instance), False)
7642 a9e0c397 Iustin Pop
7643 468b46f9 Iustin Pop
    # Step 4: dbrd minors and drbd setups changes
7644 a1578d63 Iustin Pop
    # after this, we must manually remove the drbd minors on both the
7645 a1578d63 Iustin Pop
    # error and the success paths
7646 2bb5c911 Michael Hanselmann
    self.lu.LogStep(4, steps_total, "Changing drbd configuration")
7647 4d4a651d Michael Hanselmann
    minors = self.cfg.AllocateDRBDMinor([self.new_node
7648 4d4a651d Michael Hanselmann
                                         for dev in self.instance.disks],
7649 2bb5c911 Michael Hanselmann
                                        self.instance.name)
7650 099c52ad Iustin Pop
    logging.debug("Allocated minors %r", minors)
7651 2bb5c911 Michael Hanselmann
7652 2bb5c911 Michael Hanselmann
    iv_names = {}
7653 2bb5c911 Michael Hanselmann
    for idx, (dev, new_minor) in enumerate(zip(self.instance.disks, minors)):
7654 4d4a651d Michael Hanselmann
      self.lu.LogInfo("activating a new drbd on %s for disk/%d" %
7655 4d4a651d Michael Hanselmann
                      (self.new_node, idx))
7656 a2d59d8b Iustin Pop
      # create new devices on new_node; note that we create two IDs:
7657 a2d59d8b Iustin Pop
      # one without port, so the drbd will be activated without
7658 a2d59d8b Iustin Pop
      # networking information on the new node at this stage, and one
7659 a2d59d8b Iustin Pop
      # with network, for the latter activation in step 4
7660 a2d59d8b Iustin Pop
      (o_node1, o_node2, o_port, o_minor1, o_minor2, o_secret) = dev.logical_id
7661 2bb5c911 Michael Hanselmann
      if self.instance.primary_node == o_node1:
7662 a2d59d8b Iustin Pop
        p_minor = o_minor1
7663 ffa1c0dc Iustin Pop
      else:
7664 1122eb25 Iustin Pop
        assert self.instance.primary_node == o_node2, "Three-node instance?"
7665 a2d59d8b Iustin Pop
        p_minor = o_minor2
7666 a2d59d8b Iustin Pop
7667 4d4a651d Michael Hanselmann
      new_alone_id = (self.instance.primary_node, self.new_node, None,
7668 4d4a651d Michael Hanselmann
                      p_minor, new_minor, o_secret)
7669 4d4a651d Michael Hanselmann
      new_net_id = (self.instance.primary_node, self.new_node, o_port,
7670 4d4a651d Michael Hanselmann
                    p_minor, new_minor, o_secret)
7671 a2d59d8b Iustin Pop
7672 a2d59d8b Iustin Pop
      iv_names[idx] = (dev, dev.children, new_net_id)
7673 a1578d63 Iustin Pop
      logging.debug("Allocated new_minor: %s, new_logical_id: %s", new_minor,
7674 a2d59d8b Iustin Pop
                    new_net_id)
7675 a9e0c397 Iustin Pop
      new_drbd = objects.Disk(dev_type=constants.LD_DRBD8,
7676 a2d59d8b Iustin Pop
                              logical_id=new_alone_id,
7677 8a6c7011 Iustin Pop
                              children=dev.children,
7678 8a6c7011 Iustin Pop
                              size=dev.size)
7679 796cab27 Iustin Pop
      try:
7680 2bb5c911 Michael Hanselmann
        _CreateSingleBlockDev(self.lu, self.new_node, self.instance, new_drbd,
7681 2bb5c911 Michael Hanselmann
                              _GetInstanceInfoText(self.instance), False)
7682 82759cb1 Iustin Pop
      except errors.GenericError:
7683 2bb5c911 Michael Hanselmann
        self.cfg.ReleaseDRBDMinors(self.instance.name)
7684 796cab27 Iustin Pop
        raise
7685 a9e0c397 Iustin Pop
7686 2bb5c911 Michael Hanselmann
    # We have new devices, shutdown the drbd on the old secondary
7687 2bb5c911 Michael Hanselmann
    for idx, dev in enumerate(self.instance.disks):
7688 2bb5c911 Michael Hanselmann
      self.lu.LogInfo("Shutting down drbd for disk/%d on old node" % idx)
7689 2bb5c911 Michael Hanselmann
      self.cfg.SetDiskID(dev, self.target_node)
7690 2bb5c911 Michael Hanselmann
      msg = self.rpc.call_blockdev_shutdown(self.target_node, dev).fail_msg
7691 cacfd1fd Iustin Pop
      if msg:
7692 2bb5c911 Michael Hanselmann
        self.lu.LogWarning("Failed to shutdown drbd for disk/%d on old"
7693 2bb5c911 Michael Hanselmann
                           "node: %s" % (idx, msg),
7694 2bb5c911 Michael Hanselmann
                           hint=("Please cleanup this device manually as"
7695 2bb5c911 Michael Hanselmann
                                 " soon as possible"))
7696 a9e0c397 Iustin Pop
7697 2bb5c911 Michael Hanselmann
    self.lu.LogInfo("Detaching primary drbds from the network (=> standalone)")
7698 4d4a651d Michael Hanselmann
    result = self.rpc.call_drbd_disconnect_net([self.instance.primary_node],
7699 4d4a651d Michael Hanselmann
                                               self.node_secondary_ip,
7700 4d4a651d Michael Hanselmann
                                               self.instance.disks)\
7701 4d4a651d Michael Hanselmann
                                              [self.instance.primary_node]
7702 642445d9 Iustin Pop
7703 4c4e4e1e Iustin Pop
    msg = result.fail_msg
7704 a2d59d8b Iustin Pop
    if msg:
7705 a2d59d8b Iustin Pop
      # detaches didn't succeed (unlikely)
7706 2bb5c911 Michael Hanselmann
      self.cfg.ReleaseDRBDMinors(self.instance.name)
7707 a2d59d8b Iustin Pop
      raise errors.OpExecError("Can't detach the disks from the network on"
7708 a2d59d8b Iustin Pop
                               " old node: %s" % (msg,))
7709 642445d9 Iustin Pop
7710 642445d9 Iustin Pop
    # if we managed to detach at least one, we update all the disks of
7711 642445d9 Iustin Pop
    # the instance to point to the new secondary
7712 2bb5c911 Michael Hanselmann
    self.lu.LogInfo("Updating instance configuration")
7713 468b46f9 Iustin Pop
    for dev, _, new_logical_id in iv_names.itervalues():
7714 468b46f9 Iustin Pop
      dev.logical_id = new_logical_id
7715 2bb5c911 Michael Hanselmann
      self.cfg.SetDiskID(dev, self.instance.primary_node)
7716 2bb5c911 Michael Hanselmann
7717 a4eae71f Michael Hanselmann
    self.cfg.Update(self.instance, feedback_fn)
7718 a9e0c397 Iustin Pop
7719 642445d9 Iustin Pop
    # and now perform the drbd attach
7720 2bb5c911 Michael Hanselmann
    self.lu.LogInfo("Attaching primary drbds to new secondary"
7721 2bb5c911 Michael Hanselmann
                    " (standalone => connected)")
7722 4d4a651d Michael Hanselmann
    result = self.rpc.call_drbd_attach_net([self.instance.primary_node,
7723 4d4a651d Michael Hanselmann
                                            self.new_node],
7724 4d4a651d Michael Hanselmann
                                           self.node_secondary_ip,
7725 4d4a651d Michael Hanselmann
                                           self.instance.disks,
7726 4d4a651d Michael Hanselmann
                                           self.instance.name,
7727 a2d59d8b Iustin Pop
                                           False)
7728 a2d59d8b Iustin Pop
    for to_node, to_result in result.items():
7729 4c4e4e1e Iustin Pop
      msg = to_result.fail_msg
7730 a2d59d8b Iustin Pop
      if msg:
7731 4d4a651d Michael Hanselmann
        self.lu.LogWarning("Can't attach drbd disks on node %s: %s",
7732 4d4a651d Michael Hanselmann
                           to_node, msg,
7733 2bb5c911 Michael Hanselmann
                           hint=("please do a gnt-instance info to see the"
7734 2bb5c911 Michael Hanselmann
                                 " status of disks"))
7735 7ea7bcf6 Iustin Pop
    cstep = 5
7736 7ea7bcf6 Iustin Pop
    if self.early_release:
7737 7ea7bcf6 Iustin Pop
      self.lu.LogStep(cstep, steps_total, "Removing old storage")
7738 7ea7bcf6 Iustin Pop
      cstep += 1
7739 7ea7bcf6 Iustin Pop
      self._RemoveOldStorage(self.target_node, iv_names)
7740 d5cd389c Iustin Pop
      # WARNING: we release all node locks here, do not do other RPCs
7741 d5cd389c Iustin Pop
      # than WaitForSync to the primary node
7742 d5cd389c Iustin Pop
      self._ReleaseNodeLock([self.instance.primary_node,
7743 d5cd389c Iustin Pop
                             self.target_node,
7744 d5cd389c Iustin Pop
                             self.new_node])
7745 a9e0c397 Iustin Pop
7746 2bb5c911 Michael Hanselmann
    # Wait for sync
7747 2bb5c911 Michael Hanselmann
    # This can fail as the old devices are degraded and _WaitForSync
7748 2bb5c911 Michael Hanselmann
    # does a combined result over all disks, so we don't check its return value
7749 7ea7bcf6 Iustin Pop
    self.lu.LogStep(cstep, steps_total, "Sync devices")
7750 7ea7bcf6 Iustin Pop
    cstep += 1
7751 b6c07b79 Michael Hanselmann
    _WaitForSync(self.lu, self.instance)
7752 a9e0c397 Iustin Pop
7753 2bb5c911 Michael Hanselmann
    # Check all devices manually
7754 2bb5c911 Michael Hanselmann
    self._CheckDevices(self.instance.primary_node, iv_names)
7755 22985314 Guido Trotter
7756 2bb5c911 Michael Hanselmann
    # Step: remove old storage
7757 7ea7bcf6 Iustin Pop
    if not self.early_release:
7758 7ea7bcf6 Iustin Pop
      self.lu.LogStep(cstep, steps_total, "Removing old storage")
7759 7ea7bcf6 Iustin Pop
      self._RemoveOldStorage(self.target_node, iv_names)
7760 a9e0c397 Iustin Pop
7761 a8083063 Iustin Pop
7762 76aef8fc Michael Hanselmann
class LURepairNodeStorage(NoHooksLU):
7763 76aef8fc Michael Hanselmann
  """Repairs the volume group on a node.
7764 76aef8fc Michael Hanselmann

7765 76aef8fc Michael Hanselmann
  """
7766 76aef8fc Michael Hanselmann
  _OP_REQP = ["node_name"]
7767 76aef8fc Michael Hanselmann
  REQ_BGL = False
7768 76aef8fc Michael Hanselmann
7769 76aef8fc Michael Hanselmann
  def CheckArguments(self):
7770 cf26a87a Iustin Pop
    self.op.node_name = _ExpandNodeName(self.cfg, self.op.node_name)
7771 76aef8fc Michael Hanselmann
7772 0e3baaf3 Iustin Pop
    _CheckStorageType(self.op.storage_type)
7773 0e3baaf3 Iustin Pop
7774 76aef8fc Michael Hanselmann
  def ExpandNames(self):
7775 76aef8fc Michael Hanselmann
    self.needed_locks = {
7776 76aef8fc Michael Hanselmann
      locking.LEVEL_NODE: [self.op.node_name],
7777 76aef8fc Michael Hanselmann
      }
7778 76aef8fc Michael Hanselmann
7779 76aef8fc Michael Hanselmann
  def _CheckFaultyDisks(self, instance, node_name):
7780 7e9c6a78 Iustin Pop
    """Ensure faulty disks abort the opcode or at least warn."""
7781 7e9c6a78 Iustin Pop
    try:
7782 7e9c6a78 Iustin Pop
      if _FindFaultyInstanceDisks(self.cfg, self.rpc, instance,
7783 7e9c6a78 Iustin Pop
                                  node_name, True):
7784 7e9c6a78 Iustin Pop
        raise errors.OpPrereqError("Instance '%s' has faulty disks on"
7785 7e9c6a78 Iustin Pop
                                   " node '%s'" % (instance.name, node_name),
7786 7e9c6a78 Iustin Pop
                                   errors.ECODE_STATE)
7787 7e9c6a78 Iustin Pop
    except errors.OpPrereqError, err:
7788 7e9c6a78 Iustin Pop
      if self.op.ignore_consistency:
7789 7e9c6a78 Iustin Pop
        self.proc.LogWarning(str(err.args[0]))
7790 7e9c6a78 Iustin Pop
      else:
7791 7e9c6a78 Iustin Pop
        raise
7792 76aef8fc Michael Hanselmann
7793 76aef8fc Michael Hanselmann
  def CheckPrereq(self):
7794 76aef8fc Michael Hanselmann
    """Check prerequisites.
7795 76aef8fc Michael Hanselmann

7796 76aef8fc Michael Hanselmann
    """
7797 76aef8fc Michael Hanselmann
    storage_type = self.op.storage_type
7798 76aef8fc Michael Hanselmann
7799 76aef8fc Michael Hanselmann
    if (constants.SO_FIX_CONSISTENCY not in
7800 76aef8fc Michael Hanselmann
        constants.VALID_STORAGE_OPERATIONS.get(storage_type, [])):
7801 76aef8fc Michael Hanselmann
      raise errors.OpPrereqError("Storage units of type '%s' can not be"
7802 5c983ee5 Iustin Pop
                                 " repaired" % storage_type,
7803 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
7804 76aef8fc Michael Hanselmann
7805 76aef8fc Michael Hanselmann
    # Check whether any instance on this node has faulty disks
7806 76aef8fc Michael Hanselmann
    for inst in _GetNodeInstances(self.cfg, self.op.node_name):
7807 7e9c6a78 Iustin Pop
      if not inst.admin_up:
7808 7e9c6a78 Iustin Pop
        continue
7809 76aef8fc Michael Hanselmann
      check_nodes = set(inst.all_nodes)
7810 76aef8fc Michael Hanselmann
      check_nodes.discard(self.op.node_name)
7811 76aef8fc Michael Hanselmann
      for inst_node_name in check_nodes:
7812 76aef8fc Michael Hanselmann
        self._CheckFaultyDisks(inst, inst_node_name)
7813 76aef8fc Michael Hanselmann
7814 76aef8fc Michael Hanselmann
  def Exec(self, feedback_fn):
7815 76aef8fc Michael Hanselmann
    feedback_fn("Repairing storage unit '%s' on %s ..." %
7816 76aef8fc Michael Hanselmann
                (self.op.name, self.op.node_name))
7817 76aef8fc Michael Hanselmann
7818 76aef8fc Michael Hanselmann
    st_args = _GetStorageTypeArgs(self.cfg, self.op.storage_type)
7819 76aef8fc Michael Hanselmann
    result = self.rpc.call_storage_execute(self.op.node_name,
7820 76aef8fc Michael Hanselmann
                                           self.op.storage_type, st_args,
7821 76aef8fc Michael Hanselmann
                                           self.op.name,
7822 76aef8fc Michael Hanselmann
                                           constants.SO_FIX_CONSISTENCY)
7823 76aef8fc Michael Hanselmann
    result.Raise("Failed to repair storage unit '%s' on %s" %
7824 76aef8fc Michael Hanselmann
                 (self.op.name, self.op.node_name))
7825 76aef8fc Michael Hanselmann
7826 76aef8fc Michael Hanselmann
7827 f7e7689f Iustin Pop
class LUNodeEvacuationStrategy(NoHooksLU):
7828 f7e7689f Iustin Pop
  """Computes the node evacuation strategy.
7829 f7e7689f Iustin Pop

7830 f7e7689f Iustin Pop
  """
7831 f7e7689f Iustin Pop
  _OP_REQP = ["nodes"]
7832 f7e7689f Iustin Pop
  REQ_BGL = False
7833 f7e7689f Iustin Pop
7834 f7e7689f Iustin Pop
  def CheckArguments(self):
7835 f7e7689f Iustin Pop
    if not hasattr(self.op, "remote_node"):
7836 f7e7689f Iustin Pop
      self.op.remote_node = None
7837 f7e7689f Iustin Pop
    if not hasattr(self.op, "iallocator"):
7838 f7e7689f Iustin Pop
      self.op.iallocator = None
7839 f7e7689f Iustin Pop
    if self.op.remote_node is not None and self.op.iallocator is not None:
7840 f7e7689f Iustin Pop
      raise errors.OpPrereqError("Give either the iallocator or the new"
7841 f7e7689f Iustin Pop
                                 " secondary, not both", errors.ECODE_INVAL)
7842 f7e7689f Iustin Pop
7843 f7e7689f Iustin Pop
  def ExpandNames(self):
7844 f7e7689f Iustin Pop
    self.op.nodes = _GetWantedNodes(self, self.op.nodes)
7845 f7e7689f Iustin Pop
    self.needed_locks = locks = {}
7846 f7e7689f Iustin Pop
    if self.op.remote_node is None:
7847 f7e7689f Iustin Pop
      locks[locking.LEVEL_NODE] = locking.ALL_SET
7848 f7e7689f Iustin Pop
    else:
7849 f7e7689f Iustin Pop
      self.op.remote_node = _ExpandNodeName(self.cfg, self.op.remote_node)
7850 f7e7689f Iustin Pop
      locks[locking.LEVEL_NODE] = self.op.nodes + [self.op.remote_node]
7851 f7e7689f Iustin Pop
7852 f7e7689f Iustin Pop
  def CheckPrereq(self):
7853 f7e7689f Iustin Pop
    pass
7854 f7e7689f Iustin Pop
7855 f7e7689f Iustin Pop
  def Exec(self, feedback_fn):
7856 f7e7689f Iustin Pop
    if self.op.remote_node is not None:
7857 f7e7689f Iustin Pop
      instances = []
7858 f7e7689f Iustin Pop
      for node in self.op.nodes:
7859 f7e7689f Iustin Pop
        instances.extend(_GetNodeSecondaryInstances(self.cfg, node))
7860 f7e7689f Iustin Pop
      result = []
7861 f7e7689f Iustin Pop
      for i in instances:
7862 f7e7689f Iustin Pop
        if i.primary_node == self.op.remote_node:
7863 f7e7689f Iustin Pop
          raise errors.OpPrereqError("Node %s is the primary node of"
7864 f7e7689f Iustin Pop
                                     " instance %s, cannot use it as"
7865 f7e7689f Iustin Pop
                                     " secondary" %
7866 f7e7689f Iustin Pop
                                     (self.op.remote_node, i.name),
7867 f7e7689f Iustin Pop
                                     errors.ECODE_INVAL)
7868 f7e7689f Iustin Pop
        result.append([i.name, self.op.remote_node])
7869 f7e7689f Iustin Pop
    else:
7870 f7e7689f Iustin Pop
      ial = IAllocator(self.cfg, self.rpc,
7871 f7e7689f Iustin Pop
                       mode=constants.IALLOCATOR_MODE_MEVAC,
7872 f7e7689f Iustin Pop
                       evac_nodes=self.op.nodes)
7873 f7e7689f Iustin Pop
      ial.Run(self.op.iallocator, validate=True)
7874 f7e7689f Iustin Pop
      if not ial.success:
7875 f7e7689f Iustin Pop
        raise errors.OpExecError("No valid evacuation solution: %s" % ial.info,
7876 f7e7689f Iustin Pop
                                 errors.ECODE_NORES)
7877 f7e7689f Iustin Pop
      result = ial.result
7878 f7e7689f Iustin Pop
    return result
7879 f7e7689f Iustin Pop
7880 f7e7689f Iustin Pop
7881 8729e0d7 Iustin Pop
class LUGrowDisk(LogicalUnit):
7882 8729e0d7 Iustin Pop
  """Grow a disk of an instance.
7883 8729e0d7 Iustin Pop

7884 8729e0d7 Iustin Pop
  """
7885 8729e0d7 Iustin Pop
  HPATH = "disk-grow"
7886 8729e0d7 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
7887 6605411d Iustin Pop
  _OP_REQP = ["instance_name", "disk", "amount", "wait_for_sync"]
7888 31e63dbf Guido Trotter
  REQ_BGL = False
7889 31e63dbf Guido Trotter
7890 31e63dbf Guido Trotter
  def ExpandNames(self):
7891 31e63dbf Guido Trotter
    self._ExpandAndLockInstance()
7892 31e63dbf Guido Trotter
    self.needed_locks[locking.LEVEL_NODE] = []
7893 f6d9a522 Guido Trotter
    self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
7894 31e63dbf Guido Trotter
7895 31e63dbf Guido Trotter
  def DeclareLocks(self, level):
7896 31e63dbf Guido Trotter
    if level == locking.LEVEL_NODE:
7897 31e63dbf Guido Trotter
      self._LockInstancesNodes()
7898 8729e0d7 Iustin Pop
7899 8729e0d7 Iustin Pop
  def BuildHooksEnv(self):
7900 8729e0d7 Iustin Pop
    """Build hooks env.
7901 8729e0d7 Iustin Pop

7902 8729e0d7 Iustin Pop
    This runs on the master, the primary and all the secondaries.
7903 8729e0d7 Iustin Pop

7904 8729e0d7 Iustin Pop
    """
7905 8729e0d7 Iustin Pop
    env = {
7906 8729e0d7 Iustin Pop
      "DISK": self.op.disk,
7907 8729e0d7 Iustin Pop
      "AMOUNT": self.op.amount,
7908 8729e0d7 Iustin Pop
      }
7909 338e51e8 Iustin Pop
    env.update(_BuildInstanceHookEnvByObject(self, self.instance))
7910 abd8e836 Iustin Pop
    nl = [self.cfg.GetMasterNode()] + list(self.instance.all_nodes)
7911 8729e0d7 Iustin Pop
    return env, nl, nl
7912 8729e0d7 Iustin Pop
7913 8729e0d7 Iustin Pop
  def CheckPrereq(self):
7914 8729e0d7 Iustin Pop
    """Check prerequisites.
7915 8729e0d7 Iustin Pop

7916 8729e0d7 Iustin Pop
    This checks that the instance is in the cluster.
7917 8729e0d7 Iustin Pop

7918 8729e0d7 Iustin Pop
    """
7919 31e63dbf Guido Trotter
    instance = self.cfg.GetInstanceInfo(self.op.instance_name)
7920 31e63dbf Guido Trotter
    assert instance is not None, \
7921 31e63dbf Guido Trotter
      "Cannot retrieve locked instance %s" % self.op.instance_name
7922 6b12959c Iustin Pop
    nodenames = list(instance.all_nodes)
7923 6b12959c Iustin Pop
    for node in nodenames:
7924 7527a8a4 Iustin Pop
      _CheckNodeOnline(self, node)
7925 7527a8a4 Iustin Pop
7926 31e63dbf Guido Trotter
7927 8729e0d7 Iustin Pop
    self.instance = instance
7928 8729e0d7 Iustin Pop
7929 728489a3 Guido Trotter
    if instance.disk_template not in constants.DTS_GROWABLE:
7930 8729e0d7 Iustin Pop
      raise errors.OpPrereqError("Instance's disk layout does not support"
7931 5c983ee5 Iustin Pop
                                 " growing.", errors.ECODE_INVAL)
7932 8729e0d7 Iustin Pop
7933 ad24e046 Iustin Pop
    self.disk = instance.FindDisk(self.op.disk)
7934 8729e0d7 Iustin Pop
7935 2c42c5df Guido Trotter
    if instance.disk_template != constants.DT_FILE:
7936 2c42c5df Guido Trotter
      # TODO: check the free disk space for file, when that feature will be
7937 2c42c5df Guido Trotter
      # supported
7938 2c42c5df Guido Trotter
      _CheckNodesFreeDisk(self, nodenames, self.op.amount)
7939 8729e0d7 Iustin Pop
7940 8729e0d7 Iustin Pop
  def Exec(self, feedback_fn):
7941 8729e0d7 Iustin Pop
    """Execute disk grow.
7942 8729e0d7 Iustin Pop

7943 8729e0d7 Iustin Pop
    """
7944 8729e0d7 Iustin Pop
    instance = self.instance
7945 ad24e046 Iustin Pop
    disk = self.disk
7946 41bbdb52 Guido Trotter
7947 41bbdb52 Guido Trotter
    disks_ok, _ = _AssembleInstanceDisks(self, self.instance, disks=[disk])
7948 41bbdb52 Guido Trotter
    if not disks_ok:
7949 41bbdb52 Guido Trotter
      raise errors.OpExecError("Cannot activate block device to grow")
7950 41bbdb52 Guido Trotter
7951 6b12959c Iustin Pop
    for node in instance.all_nodes:
7952 8729e0d7 Iustin Pop
      self.cfg.SetDiskID(disk, node)
7953 72737a7f Iustin Pop
      result = self.rpc.call_blockdev_grow(node, disk, self.op.amount)
7954 4c4e4e1e Iustin Pop
      result.Raise("Grow request failed to node %s" % node)
7955 5bc556dd Michael Hanselmann
7956 5bc556dd Michael Hanselmann
      # TODO: Rewrite code to work properly
7957 5bc556dd Michael Hanselmann
      # DRBD goes into sync mode for a short amount of time after executing the
7958 5bc556dd Michael Hanselmann
      # "resize" command. DRBD 8.x below version 8.0.13 contains a bug whereby
7959 5bc556dd Michael Hanselmann
      # calling "resize" in sync mode fails. Sleeping for a short amount of
7960 5bc556dd Michael Hanselmann
      # time is a work-around.
7961 5bc556dd Michael Hanselmann
      time.sleep(5)
7962 5bc556dd Michael Hanselmann
7963 8729e0d7 Iustin Pop
    disk.RecordGrow(self.op.amount)
7964 a4eae71f Michael Hanselmann
    self.cfg.Update(instance, feedback_fn)
7965 6605411d Iustin Pop
    if self.op.wait_for_sync:
7966 41bbdb52 Guido Trotter
      disk_abort = not _WaitForSync(self, instance, disks=[disk])
7967 6605411d Iustin Pop
      if disk_abort:
7968 86d9d3bb Iustin Pop
        self.proc.LogWarning("Warning: disk sync-ing has not returned a good"
7969 86d9d3bb Iustin Pop
                             " status.\nPlease check the instance.")
7970 41bbdb52 Guido Trotter
      if not instance.admin_up:
7971 41bbdb52 Guido Trotter
        _SafeShutdownInstanceDisks(self, instance, disks=[disk])
7972 41bbdb52 Guido Trotter
    elif not instance.admin_up:
7973 41bbdb52 Guido Trotter
      self.proc.LogWarning("Not shutting down the disk even if the instance is"
7974 41bbdb52 Guido Trotter
                           " not supposed to be running because no wait for"
7975 41bbdb52 Guido Trotter
                           " sync mode was requested.")
7976 8729e0d7 Iustin Pop
7977 8729e0d7 Iustin Pop
7978 a8083063 Iustin Pop
class LUQueryInstanceData(NoHooksLU):
7979 a8083063 Iustin Pop
  """Query runtime instance data.
7980 a8083063 Iustin Pop

7981 a8083063 Iustin Pop
  """
7982 57821cac Iustin Pop
  _OP_REQP = ["instances", "static"]
7983 a987fa48 Guido Trotter
  REQ_BGL = False
7984 ae5849b5 Michael Hanselmann
7985 a987fa48 Guido Trotter
  def ExpandNames(self):
7986 a987fa48 Guido Trotter
    self.needed_locks = {}
7987 c772d142 Michael Hanselmann
    self.share_locks = dict.fromkeys(locking.LEVELS, 1)
7988 a987fa48 Guido Trotter
7989 a987fa48 Guido Trotter
    if not isinstance(self.op.instances, list):
7990 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Invalid argument type 'instances'",
7991 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
7992 a987fa48 Guido Trotter
7993 a987fa48 Guido Trotter
    if self.op.instances:
7994 a987fa48 Guido Trotter
      self.wanted_names = []
7995 a987fa48 Guido Trotter
      for name in self.op.instances:
7996 cf26a87a Iustin Pop
        full_name = _ExpandInstanceName(self.cfg, name)
7997 a987fa48 Guido Trotter
        self.wanted_names.append(full_name)
7998 a987fa48 Guido Trotter
      self.needed_locks[locking.LEVEL_INSTANCE] = self.wanted_names
7999 a987fa48 Guido Trotter
    else:
8000 a987fa48 Guido Trotter
      self.wanted_names = None
8001 a987fa48 Guido Trotter
      self.needed_locks[locking.LEVEL_INSTANCE] = locking.ALL_SET
8002 a987fa48 Guido Trotter
8003 a987fa48 Guido Trotter
    self.needed_locks[locking.LEVEL_NODE] = []
8004 a987fa48 Guido Trotter
    self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
8005 a987fa48 Guido Trotter
8006 a987fa48 Guido Trotter
  def DeclareLocks(self, level):
8007 a987fa48 Guido Trotter
    if level == locking.LEVEL_NODE:
8008 a987fa48 Guido Trotter
      self._LockInstancesNodes()
8009 a8083063 Iustin Pop
8010 a8083063 Iustin Pop
  def CheckPrereq(self):
8011 a8083063 Iustin Pop
    """Check prerequisites.
8012 a8083063 Iustin Pop

8013 a8083063 Iustin Pop
    This only checks the optional instance list against the existing names.
8014 a8083063 Iustin Pop

8015 a8083063 Iustin Pop
    """
8016 a987fa48 Guido Trotter
    if self.wanted_names is None:
8017 a987fa48 Guido Trotter
      self.wanted_names = self.acquired_locks[locking.LEVEL_INSTANCE]
8018 a8083063 Iustin Pop
8019 a987fa48 Guido Trotter
    self.wanted_instances = [self.cfg.GetInstanceInfo(name) for name
8020 a987fa48 Guido Trotter
                             in self.wanted_names]
8021 a987fa48 Guido Trotter
    return
8022 a8083063 Iustin Pop
8023 98825740 Michael Hanselmann
  def _ComputeBlockdevStatus(self, node, instance_name, dev):
8024 98825740 Michael Hanselmann
    """Returns the status of a block device
8025 98825740 Michael Hanselmann

8026 98825740 Michael Hanselmann
    """
8027 4dce1a83 Michael Hanselmann
    if self.op.static or not node:
8028 98825740 Michael Hanselmann
      return None
8029 98825740 Michael Hanselmann
8030 98825740 Michael Hanselmann
    self.cfg.SetDiskID(dev, node)
8031 98825740 Michael Hanselmann
8032 98825740 Michael Hanselmann
    result = self.rpc.call_blockdev_find(node, dev)
8033 98825740 Michael Hanselmann
    if result.offline:
8034 98825740 Michael Hanselmann
      return None
8035 98825740 Michael Hanselmann
8036 98825740 Michael Hanselmann
    result.Raise("Can't compute disk status for %s" % instance_name)
8037 98825740 Michael Hanselmann
8038 98825740 Michael Hanselmann
    status = result.payload
8039 ddfe2228 Michael Hanselmann
    if status is None:
8040 ddfe2228 Michael Hanselmann
      return None
8041 98825740 Michael Hanselmann
8042 98825740 Michael Hanselmann
    return (status.dev_path, status.major, status.minor,
8043 98825740 Michael Hanselmann
            status.sync_percent, status.estimated_time,
8044 f208978a Michael Hanselmann
            status.is_degraded, status.ldisk_status)
8045 98825740 Michael Hanselmann
8046 a8083063 Iustin Pop
  def _ComputeDiskStatus(self, instance, snode, dev):
8047 a8083063 Iustin Pop
    """Compute block device status.
8048 a8083063 Iustin Pop

8049 a8083063 Iustin Pop
    """
8050 a1f445d3 Iustin Pop
    if dev.dev_type in constants.LDS_DRBD:
8051 a8083063 Iustin Pop
      # we change the snode then (otherwise we use the one passed in)
8052 a8083063 Iustin Pop
      if dev.logical_id[0] == instance.primary_node:
8053 a8083063 Iustin Pop
        snode = dev.logical_id[1]
8054 a8083063 Iustin Pop
      else:
8055 a8083063 Iustin Pop
        snode = dev.logical_id[0]
8056 a8083063 Iustin Pop
8057 98825740 Michael Hanselmann
    dev_pstatus = self._ComputeBlockdevStatus(instance.primary_node,
8058 98825740 Michael Hanselmann
                                              instance.name, dev)
8059 98825740 Michael Hanselmann
    dev_sstatus = self._ComputeBlockdevStatus(snode, instance.name, dev)
8060 a8083063 Iustin Pop
8061 a8083063 Iustin Pop
    if dev.children:
8062 a8083063 Iustin Pop
      dev_children = [self._ComputeDiskStatus(instance, snode, child)
8063 a8083063 Iustin Pop
                      for child in dev.children]
8064 a8083063 Iustin Pop
    else:
8065 a8083063 Iustin Pop
      dev_children = []
8066 a8083063 Iustin Pop
8067 a8083063 Iustin Pop
    data = {
8068 a8083063 Iustin Pop
      "iv_name": dev.iv_name,
8069 a8083063 Iustin Pop
      "dev_type": dev.dev_type,
8070 a8083063 Iustin Pop
      "logical_id": dev.logical_id,
8071 a8083063 Iustin Pop
      "physical_id": dev.physical_id,
8072 a8083063 Iustin Pop
      "pstatus": dev_pstatus,
8073 a8083063 Iustin Pop
      "sstatus": dev_sstatus,
8074 a8083063 Iustin Pop
      "children": dev_children,
8075 b6fdf8b8 Iustin Pop
      "mode": dev.mode,
8076 c98162a7 Iustin Pop
      "size": dev.size,
8077 a8083063 Iustin Pop
      }
8078 a8083063 Iustin Pop
8079 a8083063 Iustin Pop
    return data
8080 a8083063 Iustin Pop
8081 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
8082 a8083063 Iustin Pop
    """Gather and return data"""
8083 a8083063 Iustin Pop
    result = {}
8084 338e51e8 Iustin Pop
8085 338e51e8 Iustin Pop
    cluster = self.cfg.GetClusterInfo()
8086 338e51e8 Iustin Pop
8087 a8083063 Iustin Pop
    for instance in self.wanted_instances:
8088 57821cac Iustin Pop
      if not self.op.static:
8089 57821cac Iustin Pop
        remote_info = self.rpc.call_instance_info(instance.primary_node,
8090 57821cac Iustin Pop
                                                  instance.name,
8091 57821cac Iustin Pop
                                                  instance.hypervisor)
8092 4c4e4e1e Iustin Pop
        remote_info.Raise("Error checking node %s" % instance.primary_node)
8093 7ad1af4a Iustin Pop
        remote_info = remote_info.payload
8094 57821cac Iustin Pop
        if remote_info and "state" in remote_info:
8095 57821cac Iustin Pop
          remote_state = "up"
8096 57821cac Iustin Pop
        else:
8097 57821cac Iustin Pop
          remote_state = "down"
8098 a8083063 Iustin Pop
      else:
8099 57821cac Iustin Pop
        remote_state = None
8100 0d68c45d Iustin Pop
      if instance.admin_up:
8101 a8083063 Iustin Pop
        config_state = "up"
8102 0d68c45d Iustin Pop
      else:
8103 0d68c45d Iustin Pop
        config_state = "down"
8104 a8083063 Iustin Pop
8105 a8083063 Iustin Pop
      disks = [self._ComputeDiskStatus(instance, None, device)
8106 a8083063 Iustin Pop
               for device in instance.disks]
8107 a8083063 Iustin Pop
8108 a8083063 Iustin Pop
      idict = {
8109 a8083063 Iustin Pop
        "name": instance.name,
8110 a8083063 Iustin Pop
        "config_state": config_state,
8111 a8083063 Iustin Pop
        "run_state": remote_state,
8112 a8083063 Iustin Pop
        "pnode": instance.primary_node,
8113 a8083063 Iustin Pop
        "snodes": instance.secondary_nodes,
8114 a8083063 Iustin Pop
        "os": instance.os,
8115 0b13832c Guido Trotter
        # this happens to be the same format used for hooks
8116 0b13832c Guido Trotter
        "nics": _NICListToTuple(self, instance.nics),
8117 f02fbd30 Michael Hanselmann
        "disk_template": instance.disk_template,
8118 a8083063 Iustin Pop
        "disks": disks,
8119 e69d05fd Iustin Pop
        "hypervisor": instance.hypervisor,
8120 24838135 Iustin Pop
        "network_port": instance.network_port,
8121 24838135 Iustin Pop
        "hv_instance": instance.hvparams,
8122 7736a5f2 Iustin Pop
        "hv_actual": cluster.FillHV(instance, skip_globals=True),
8123 338e51e8 Iustin Pop
        "be_instance": instance.beparams,
8124 338e51e8 Iustin Pop
        "be_actual": cluster.FillBE(instance),
8125 90f72445 Iustin Pop
        "serial_no": instance.serial_no,
8126 90f72445 Iustin Pop
        "mtime": instance.mtime,
8127 90f72445 Iustin Pop
        "ctime": instance.ctime,
8128 033d58b0 Iustin Pop
        "uuid": instance.uuid,
8129 a8083063 Iustin Pop
        }
8130 a8083063 Iustin Pop
8131 a8083063 Iustin Pop
      result[instance.name] = idict
8132 a8083063 Iustin Pop
8133 a8083063 Iustin Pop
    return result
8134 a8083063 Iustin Pop
8135 a8083063 Iustin Pop
8136 7767bbf5 Manuel Franceschini
class LUSetInstanceParams(LogicalUnit):
8137 a8083063 Iustin Pop
  """Modifies an instances's parameters.
8138 a8083063 Iustin Pop

8139 a8083063 Iustin Pop
  """
8140 a8083063 Iustin Pop
  HPATH = "instance-modify"
8141 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
8142 24991749 Iustin Pop
  _OP_REQP = ["instance_name"]
8143 1a5c7281 Guido Trotter
  REQ_BGL = False
8144 1a5c7281 Guido Trotter
8145 24991749 Iustin Pop
  def CheckArguments(self):
8146 24991749 Iustin Pop
    if not hasattr(self.op, 'nics'):
8147 24991749 Iustin Pop
      self.op.nics = []
8148 24991749 Iustin Pop
    if not hasattr(self.op, 'disks'):
8149 24991749 Iustin Pop
      self.op.disks = []
8150 24991749 Iustin Pop
    if not hasattr(self.op, 'beparams'):
8151 24991749 Iustin Pop
      self.op.beparams = {}
8152 24991749 Iustin Pop
    if not hasattr(self.op, 'hvparams'):
8153 24991749 Iustin Pop
      self.op.hvparams = {}
8154 e29e9550 Iustin Pop
    if not hasattr(self.op, "disk_template"):
8155 e29e9550 Iustin Pop
      self.op.disk_template = None
8156 e29e9550 Iustin Pop
    if not hasattr(self.op, "remote_node"):
8157 e29e9550 Iustin Pop
      self.op.remote_node = None
8158 96b39bcc Iustin Pop
    if not hasattr(self.op, "os_name"):
8159 96b39bcc Iustin Pop
      self.op.os_name = None
8160 96b39bcc Iustin Pop
    if not hasattr(self.op, "force_variant"):
8161 96b39bcc Iustin Pop
      self.op.force_variant = False
8162 24991749 Iustin Pop
    self.op.force = getattr(self.op, "force", False)
8163 e29e9550 Iustin Pop
    if not (self.op.nics or self.op.disks or self.op.disk_template or
8164 96b39bcc Iustin Pop
            self.op.hvparams or self.op.beparams or self.op.os_name):
8165 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("No changes submitted", errors.ECODE_INVAL)
8166 24991749 Iustin Pop
8167 7736a5f2 Iustin Pop
    if self.op.hvparams:
8168 7736a5f2 Iustin Pop
      _CheckGlobalHvParams(self.op.hvparams)
8169 7736a5f2 Iustin Pop
8170 24991749 Iustin Pop
    # Disk validation
8171 24991749 Iustin Pop
    disk_addremove = 0
8172 24991749 Iustin Pop
    for disk_op, disk_dict in self.op.disks:
8173 24991749 Iustin Pop
      if disk_op == constants.DDM_REMOVE:
8174 24991749 Iustin Pop
        disk_addremove += 1
8175 24991749 Iustin Pop
        continue
8176 24991749 Iustin Pop
      elif disk_op == constants.DDM_ADD:
8177 24991749 Iustin Pop
        disk_addremove += 1
8178 24991749 Iustin Pop
      else:
8179 24991749 Iustin Pop
        if not isinstance(disk_op, int):
8180 5c983ee5 Iustin Pop
          raise errors.OpPrereqError("Invalid disk index", errors.ECODE_INVAL)
8181 8b46606c Guido Trotter
        if not isinstance(disk_dict, dict):
8182 8b46606c Guido Trotter
          msg = "Invalid disk value: expected dict, got '%s'" % disk_dict
8183 5c983ee5 Iustin Pop
          raise errors.OpPrereqError(msg, errors.ECODE_INVAL)
8184 8b46606c Guido Trotter
8185 24991749 Iustin Pop
      if disk_op == constants.DDM_ADD:
8186 24991749 Iustin Pop
        mode = disk_dict.setdefault('mode', constants.DISK_RDWR)
8187 6ec66eae Iustin Pop
        if mode not in constants.DISK_ACCESS_SET:
8188 5c983ee5 Iustin Pop
          raise errors.OpPrereqError("Invalid disk access mode '%s'" % mode,
8189 5c983ee5 Iustin Pop
                                     errors.ECODE_INVAL)
8190 24991749 Iustin Pop
        size = disk_dict.get('size', None)
8191 24991749 Iustin Pop
        if size is None:
8192 5c983ee5 Iustin Pop
          raise errors.OpPrereqError("Required disk parameter size missing",
8193 5c983ee5 Iustin Pop
                                     errors.ECODE_INVAL)
8194 24991749 Iustin Pop
        try:
8195 24991749 Iustin Pop
          size = int(size)
8196 691744c4 Iustin Pop
        except (TypeError, ValueError), err:
8197 24991749 Iustin Pop
          raise errors.OpPrereqError("Invalid disk size parameter: %s" %
8198 5c983ee5 Iustin Pop
                                     str(err), errors.ECODE_INVAL)
8199 24991749 Iustin Pop
        disk_dict['size'] = size
8200 24991749 Iustin Pop
      else:
8201 24991749 Iustin Pop
        # modification of disk
8202 24991749 Iustin Pop
        if 'size' in disk_dict:
8203 24991749 Iustin Pop
          raise errors.OpPrereqError("Disk size change not possible, use"
8204 5c983ee5 Iustin Pop
                                     " grow-disk", errors.ECODE_INVAL)
8205 24991749 Iustin Pop
8206 24991749 Iustin Pop
    if disk_addremove > 1:
8207 24991749 Iustin Pop
      raise errors.OpPrereqError("Only one disk add or remove operation"
8208 5c983ee5 Iustin Pop
                                 " supported at a time", errors.ECODE_INVAL)
8209 24991749 Iustin Pop
8210 e29e9550 Iustin Pop
    if self.op.disks and self.op.disk_template is not None:
8211 e29e9550 Iustin Pop
      raise errors.OpPrereqError("Disk template conversion and other disk"
8212 e29e9550 Iustin Pop
                                 " changes not supported at the same time",
8213 e29e9550 Iustin Pop
                                 errors.ECODE_INVAL)
8214 e29e9550 Iustin Pop
8215 e29e9550 Iustin Pop
    if self.op.disk_template:
8216 e29e9550 Iustin Pop
      _CheckDiskTemplate(self.op.disk_template)
8217 e29e9550 Iustin Pop
      if (self.op.disk_template in constants.DTS_NET_MIRROR and
8218 e29e9550 Iustin Pop
          self.op.remote_node is None):
8219 e29e9550 Iustin Pop
        raise errors.OpPrereqError("Changing the disk template to a mirrored"
8220 e29e9550 Iustin Pop
                                   " one requires specifying a secondary node",
8221 e29e9550 Iustin Pop
                                   errors.ECODE_INVAL)
8222 e29e9550 Iustin Pop
8223 24991749 Iustin Pop
    # NIC validation
8224 24991749 Iustin Pop
    nic_addremove = 0
8225 24991749 Iustin Pop
    for nic_op, nic_dict in self.op.nics:
8226 24991749 Iustin Pop
      if nic_op == constants.DDM_REMOVE:
8227 24991749 Iustin Pop
        nic_addremove += 1
8228 24991749 Iustin Pop
        continue
8229 24991749 Iustin Pop
      elif nic_op == constants.DDM_ADD:
8230 24991749 Iustin Pop
        nic_addremove += 1
8231 24991749 Iustin Pop
      else:
8232 24991749 Iustin Pop
        if not isinstance(nic_op, int):
8233 5c983ee5 Iustin Pop
          raise errors.OpPrereqError("Invalid nic index", errors.ECODE_INVAL)
8234 8b46606c Guido Trotter
        if not isinstance(nic_dict, dict):
8235 8b46606c Guido Trotter
          msg = "Invalid nic value: expected dict, got '%s'" % nic_dict
8236 5c983ee5 Iustin Pop
          raise errors.OpPrereqError(msg, errors.ECODE_INVAL)
8237 24991749 Iustin Pop
8238 24991749 Iustin Pop
      # nic_dict should be a dict
8239 24991749 Iustin Pop
      nic_ip = nic_dict.get('ip', None)
8240 24991749 Iustin Pop
      if nic_ip is not None:
8241 5c44da6a Guido Trotter
        if nic_ip.lower() == constants.VALUE_NONE:
8242 24991749 Iustin Pop
          nic_dict['ip'] = None
8243 24991749 Iustin Pop
        else:
8244 24991749 Iustin Pop
          if not utils.IsValidIP(nic_ip):
8245 5c983ee5 Iustin Pop
            raise errors.OpPrereqError("Invalid IP address '%s'" % nic_ip,
8246 5c983ee5 Iustin Pop
                                       errors.ECODE_INVAL)
8247 5c44da6a Guido Trotter
8248 cd098c41 Guido Trotter
      nic_bridge = nic_dict.get('bridge', None)
8249 cd098c41 Guido Trotter
      nic_link = nic_dict.get('link', None)
8250 cd098c41 Guido Trotter
      if nic_bridge and nic_link:
8251 29921401 Iustin Pop
        raise errors.OpPrereqError("Cannot pass 'bridge' and 'link'"
8252 5c983ee5 Iustin Pop
                                   " at the same time", errors.ECODE_INVAL)
8253 cd098c41 Guido Trotter
      elif nic_bridge and nic_bridge.lower() == constants.VALUE_NONE:
8254 cd098c41 Guido Trotter
        nic_dict['bridge'] = None
8255 cd098c41 Guido Trotter
      elif nic_link and nic_link.lower() == constants.VALUE_NONE:
8256 cd098c41 Guido Trotter
        nic_dict['link'] = None
8257 cd098c41 Guido Trotter
8258 5c44da6a Guido Trotter
      if nic_op == constants.DDM_ADD:
8259 5c44da6a Guido Trotter
        nic_mac = nic_dict.get('mac', None)
8260 5c44da6a Guido Trotter
        if nic_mac is None:
8261 5c44da6a Guido Trotter
          nic_dict['mac'] = constants.VALUE_AUTO
8262 5c44da6a Guido Trotter
8263 5c44da6a Guido Trotter
      if 'mac' in nic_dict:
8264 5c44da6a Guido Trotter
        nic_mac = nic_dict['mac']
8265 24991749 Iustin Pop
        if nic_mac not in (constants.VALUE_AUTO, constants.VALUE_GENERATE):
8266 82187135 René Nussbaumer
          nic_mac = utils.NormalizeAndValidateMac(nic_mac)
8267 82187135 René Nussbaumer
8268 5c44da6a Guido Trotter
        if nic_op != constants.DDM_ADD and nic_mac == constants.VALUE_AUTO:
8269 5c44da6a Guido Trotter
          raise errors.OpPrereqError("'auto' is not a valid MAC address when"
8270 5c983ee5 Iustin Pop
                                     " modifying an existing nic",
8271 5c983ee5 Iustin Pop
                                     errors.ECODE_INVAL)
8272 5c44da6a Guido Trotter
8273 24991749 Iustin Pop
    if nic_addremove > 1:
8274 24991749 Iustin Pop
      raise errors.OpPrereqError("Only one NIC add or remove operation"
8275 5c983ee5 Iustin Pop
                                 " supported at a time", errors.ECODE_INVAL)
8276 24991749 Iustin Pop
8277 1a5c7281 Guido Trotter
  def ExpandNames(self):
8278 1a5c7281 Guido Trotter
    self._ExpandAndLockInstance()
8279 74409b12 Iustin Pop
    self.needed_locks[locking.LEVEL_NODE] = []
8280 74409b12 Iustin Pop
    self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
8281 74409b12 Iustin Pop
8282 74409b12 Iustin Pop
  def DeclareLocks(self, level):
8283 74409b12 Iustin Pop
    if level == locking.LEVEL_NODE:
8284 74409b12 Iustin Pop
      self._LockInstancesNodes()
8285 e29e9550 Iustin Pop
      if self.op.disk_template and self.op.remote_node:
8286 e29e9550 Iustin Pop
        self.op.remote_node = _ExpandNodeName(self.cfg, self.op.remote_node)
8287 e29e9550 Iustin Pop
        self.needed_locks[locking.LEVEL_NODE].append(self.op.remote_node)
8288 a8083063 Iustin Pop
8289 a8083063 Iustin Pop
  def BuildHooksEnv(self):
8290 a8083063 Iustin Pop
    """Build hooks env.
8291 a8083063 Iustin Pop

8292 a8083063 Iustin Pop
    This runs on the master, primary and secondaries.
8293 a8083063 Iustin Pop

8294 a8083063 Iustin Pop
    """
8295 396e1b78 Michael Hanselmann
    args = dict()
8296 338e51e8 Iustin Pop
    if constants.BE_MEMORY in self.be_new:
8297 338e51e8 Iustin Pop
      args['memory'] = self.be_new[constants.BE_MEMORY]
8298 338e51e8 Iustin Pop
    if constants.BE_VCPUS in self.be_new:
8299 61be6ba4 Iustin Pop
      args['vcpus'] = self.be_new[constants.BE_VCPUS]
8300 d8dcf3c9 Guido Trotter
    # TODO: export disk changes. Note: _BuildInstanceHookEnv* don't export disk
8301 d8dcf3c9 Guido Trotter
    # information at all.
8302 d8dcf3c9 Guido Trotter
    if self.op.nics:
8303 d8dcf3c9 Guido Trotter
      args['nics'] = []
8304 d8dcf3c9 Guido Trotter
      nic_override = dict(self.op.nics)
8305 62f0dd02 Guido Trotter
      c_nicparams = self.cluster.nicparams[constants.PP_DEFAULT]
8306 d8dcf3c9 Guido Trotter
      for idx, nic in enumerate(self.instance.nics):
8307 d8dcf3c9 Guido Trotter
        if idx in nic_override:
8308 d8dcf3c9 Guido Trotter
          this_nic_override = nic_override[idx]
8309 d8dcf3c9 Guido Trotter
        else:
8310 d8dcf3c9 Guido Trotter
          this_nic_override = {}
8311 d8dcf3c9 Guido Trotter
        if 'ip' in this_nic_override:
8312 d8dcf3c9 Guido Trotter
          ip = this_nic_override['ip']
8313 d8dcf3c9 Guido Trotter
        else:
8314 d8dcf3c9 Guido Trotter
          ip = nic.ip
8315 d8dcf3c9 Guido Trotter
        if 'mac' in this_nic_override:
8316 d8dcf3c9 Guido Trotter
          mac = this_nic_override['mac']
8317 d8dcf3c9 Guido Trotter
        else:
8318 d8dcf3c9 Guido Trotter
          mac = nic.mac
8319 62f0dd02 Guido Trotter
        if idx in self.nic_pnew:
8320 62f0dd02 Guido Trotter
          nicparams = self.nic_pnew[idx]
8321 62f0dd02 Guido Trotter
        else:
8322 62f0dd02 Guido Trotter
          nicparams = objects.FillDict(c_nicparams, nic.nicparams)
8323 62f0dd02 Guido Trotter
        mode = nicparams[constants.NIC_MODE]
8324 62f0dd02 Guido Trotter
        link = nicparams[constants.NIC_LINK]
8325 62f0dd02 Guido Trotter
        args['nics'].append((ip, mac, mode, link))
8326 d8dcf3c9 Guido Trotter
      if constants.DDM_ADD in nic_override:
8327 d8dcf3c9 Guido Trotter
        ip = nic_override[constants.DDM_ADD].get('ip', None)
8328 d8dcf3c9 Guido Trotter
        mac = nic_override[constants.DDM_ADD]['mac']
8329 62f0dd02 Guido Trotter
        nicparams = self.nic_pnew[constants.DDM_ADD]
8330 62f0dd02 Guido Trotter
        mode = nicparams[constants.NIC_MODE]
8331 62f0dd02 Guido Trotter
        link = nicparams[constants.NIC_LINK]
8332 62f0dd02 Guido Trotter
        args['nics'].append((ip, mac, mode, link))
8333 d8dcf3c9 Guido Trotter
      elif constants.DDM_REMOVE in nic_override:
8334 d8dcf3c9 Guido Trotter
        del args['nics'][-1]
8335 d8dcf3c9 Guido Trotter
8336 338e51e8 Iustin Pop
    env = _BuildInstanceHookEnvByObject(self, self.instance, override=args)
8337 e29e9550 Iustin Pop
    if self.op.disk_template:
8338 e29e9550 Iustin Pop
      env["NEW_DISK_TEMPLATE"] = self.op.disk_template
8339 6b12959c Iustin Pop
    nl = [self.cfg.GetMasterNode()] + list(self.instance.all_nodes)
8340 a8083063 Iustin Pop
    return env, nl, nl
8341 a8083063 Iustin Pop
8342 7e950d31 Iustin Pop
  @staticmethod
8343 7e950d31 Iustin Pop
  def _GetUpdatedParams(old_params, update_dict,
8344 0329617a Guido Trotter
                        default_values, parameter_types):
8345 0329617a Guido Trotter
    """Return the new params dict for the given params.
8346 0329617a Guido Trotter

8347 0329617a Guido Trotter
    @type old_params: dict
8348 f2fd87d7 Iustin Pop
    @param old_params: old parameters
8349 0329617a Guido Trotter
    @type update_dict: dict
8350 f2fd87d7 Iustin Pop
    @param update_dict: dict containing new parameter values,
8351 f2fd87d7 Iustin Pop
                        or constants.VALUE_DEFAULT to reset the
8352 f2fd87d7 Iustin Pop
                        parameter to its default value
8353 0329617a Guido Trotter
    @type default_values: dict
8354 0329617a Guido Trotter
    @param default_values: default values for the filled parameters
8355 0329617a Guido Trotter
    @type parameter_types: dict
8356 0329617a Guido Trotter
    @param parameter_types: dict mapping target dict keys to types
8357 0329617a Guido Trotter
                            in constants.ENFORCEABLE_TYPES
8358 0329617a Guido Trotter
    @rtype: (dict, dict)
8359 0329617a Guido Trotter
    @return: (new_parameters, filled_parameters)
8360 0329617a Guido Trotter

8361 0329617a Guido Trotter
    """
8362 0329617a Guido Trotter
    params_copy = copy.deepcopy(old_params)
8363 0329617a Guido Trotter
    for key, val in update_dict.iteritems():
8364 0329617a Guido Trotter
      if val == constants.VALUE_DEFAULT:
8365 0329617a Guido Trotter
        try:
8366 0329617a Guido Trotter
          del params_copy[key]
8367 0329617a Guido Trotter
        except KeyError:
8368 0329617a Guido Trotter
          pass
8369 0329617a Guido Trotter
      else:
8370 0329617a Guido Trotter
        params_copy[key] = val
8371 0329617a Guido Trotter
    utils.ForceDictType(params_copy, parameter_types)
8372 0329617a Guido Trotter
    params_filled = objects.FillDict(default_values, params_copy)
8373 0329617a Guido Trotter
    return (params_copy, params_filled)
8374 0329617a Guido Trotter
8375 a8083063 Iustin Pop
  def CheckPrereq(self):
8376 a8083063 Iustin Pop
    """Check prerequisites.
8377 a8083063 Iustin Pop

8378 a8083063 Iustin Pop
    This only checks the instance list against the existing names.
8379 a8083063 Iustin Pop

8380 a8083063 Iustin Pop
    """
8381 7c4d6c7b Michael Hanselmann
    self.force = self.op.force
8382 a8083063 Iustin Pop
8383 74409b12 Iustin Pop
    # checking the new params on the primary/secondary nodes
8384 31a853d2 Iustin Pop
8385 cfefe007 Guido Trotter
    instance = self.instance = self.cfg.GetInstanceInfo(self.op.instance_name)
8386 2ee88aeb Guido Trotter
    cluster = self.cluster = self.cfg.GetClusterInfo()
8387 1a5c7281 Guido Trotter
    assert self.instance is not None, \
8388 1a5c7281 Guido Trotter
      "Cannot retrieve locked instance %s" % self.op.instance_name
8389 6b12959c Iustin Pop
    pnode = instance.primary_node
8390 6b12959c Iustin Pop
    nodelist = list(instance.all_nodes)
8391 74409b12 Iustin Pop
8392 e29e9550 Iustin Pop
    if self.op.disk_template:
8393 e29e9550 Iustin Pop
      if instance.disk_template == self.op.disk_template:
8394 e29e9550 Iustin Pop
        raise errors.OpPrereqError("Instance already has disk template %s" %
8395 e29e9550 Iustin Pop
                                   instance.disk_template, errors.ECODE_INVAL)
8396 e29e9550 Iustin Pop
8397 e29e9550 Iustin Pop
      if (instance.disk_template,
8398 e29e9550 Iustin Pop
          self.op.disk_template) not in self._DISK_CONVERSIONS:
8399 e29e9550 Iustin Pop
        raise errors.OpPrereqError("Unsupported disk template conversion from"
8400 e29e9550 Iustin Pop
                                   " %s to %s" % (instance.disk_template,
8401 e29e9550 Iustin Pop
                                                  self.op.disk_template),
8402 e29e9550 Iustin Pop
                                   errors.ECODE_INVAL)
8403 e29e9550 Iustin Pop
      if self.op.disk_template in constants.DTS_NET_MIRROR:
8404 e29e9550 Iustin Pop
        _CheckNodeOnline(self, self.op.remote_node)
8405 e29e9550 Iustin Pop
        _CheckNodeNotDrained(self, self.op.remote_node)
8406 e29e9550 Iustin Pop
        disks = [{"size": d.size} for d in instance.disks]
8407 e29e9550 Iustin Pop
        required = _ComputeDiskSize(self.op.disk_template, disks)
8408 e29e9550 Iustin Pop
        _CheckNodesFreeDisk(self, [self.op.remote_node], required)
8409 e29e9550 Iustin Pop
        _CheckInstanceDown(self, instance, "cannot change disk template")
8410 e29e9550 Iustin Pop
8411 338e51e8 Iustin Pop
    # hvparams processing
8412 74409b12 Iustin Pop
    if self.op.hvparams:
8413 0329617a Guido Trotter
      i_hvdict, hv_new = self._GetUpdatedParams(
8414 0329617a Guido Trotter
                             instance.hvparams, self.op.hvparams,
8415 0329617a Guido Trotter
                             cluster.hvparams[instance.hypervisor],
8416 0329617a Guido Trotter
                             constants.HVS_PARAMETER_TYPES)
8417 74409b12 Iustin Pop
      # local check
8418 74409b12 Iustin Pop
      hypervisor.GetHypervisor(
8419 74409b12 Iustin Pop
        instance.hypervisor).CheckParameterSyntax(hv_new)
8420 74409b12 Iustin Pop
      _CheckHVParams(self, nodelist, instance.hypervisor, hv_new)
8421 338e51e8 Iustin Pop
      self.hv_new = hv_new # the new actual values
8422 338e51e8 Iustin Pop
      self.hv_inst = i_hvdict # the new dict (without defaults)
8423 338e51e8 Iustin Pop
    else:
8424 338e51e8 Iustin Pop
      self.hv_new = self.hv_inst = {}
8425 338e51e8 Iustin Pop
8426 338e51e8 Iustin Pop
    # beparams processing
8427 338e51e8 Iustin Pop
    if self.op.beparams:
8428 0329617a Guido Trotter
      i_bedict, be_new = self._GetUpdatedParams(
8429 0329617a Guido Trotter
                             instance.beparams, self.op.beparams,
8430 0329617a Guido Trotter
                             cluster.beparams[constants.PP_DEFAULT],
8431 0329617a Guido Trotter
                             constants.BES_PARAMETER_TYPES)
8432 338e51e8 Iustin Pop
      self.be_new = be_new # the new actual values
8433 338e51e8 Iustin Pop
      self.be_inst = i_bedict # the new dict (without defaults)
8434 338e51e8 Iustin Pop
    else:
8435 b637ae4d Iustin Pop
      self.be_new = self.be_inst = {}
8436 74409b12 Iustin Pop
8437 cfefe007 Guido Trotter
    self.warn = []
8438 647a5d80 Iustin Pop
8439 338e51e8 Iustin Pop
    if constants.BE_MEMORY in self.op.beparams and not self.force:
8440 647a5d80 Iustin Pop
      mem_check_list = [pnode]
8441 c0f2b229 Iustin Pop
      if be_new[constants.BE_AUTO_BALANCE]:
8442 c0f2b229 Iustin Pop
        # either we changed auto_balance to yes or it was from before
8443 647a5d80 Iustin Pop
        mem_check_list.extend(instance.secondary_nodes)
8444 72737a7f Iustin Pop
      instance_info = self.rpc.call_instance_info(pnode, instance.name,
8445 72737a7f Iustin Pop
                                                  instance.hypervisor)
8446 647a5d80 Iustin Pop
      nodeinfo = self.rpc.call_node_info(mem_check_list, self.cfg.GetVGName(),
8447 72737a7f Iustin Pop
                                         instance.hypervisor)
8448 070e998b Iustin Pop
      pninfo = nodeinfo[pnode]
8449 4c4e4e1e Iustin Pop
      msg = pninfo.fail_msg
8450 070e998b Iustin Pop
      if msg:
8451 cfefe007 Guido Trotter
        # Assume the primary node is unreachable and go ahead
8452 070e998b Iustin Pop
        self.warn.append("Can't get info from primary node %s: %s" %
8453 070e998b Iustin Pop
                         (pnode,  msg))
8454 070e998b Iustin Pop
      elif not isinstance(pninfo.payload.get('memory_free', None), int):
8455 070e998b Iustin Pop
        self.warn.append("Node data from primary node %s doesn't contain"
8456 070e998b Iustin Pop
                         " free memory information" % pnode)
8457 4c4e4e1e Iustin Pop
      elif instance_info.fail_msg:
8458 7ad1af4a Iustin Pop
        self.warn.append("Can't get instance runtime information: %s" %
8459 4c4e4e1e Iustin Pop
                        instance_info.fail_msg)
8460 cfefe007 Guido Trotter
      else:
8461 7ad1af4a Iustin Pop
        if instance_info.payload:
8462 7ad1af4a Iustin Pop
          current_mem = int(instance_info.payload['memory'])
8463 cfefe007 Guido Trotter
        else:
8464 cfefe007 Guido Trotter
          # Assume instance not running
8465 cfefe007 Guido Trotter
          # (there is a slight race condition here, but it's not very probable,
8466 cfefe007 Guido Trotter
          # and we have no other way to check)
8467 cfefe007 Guido Trotter
          current_mem = 0
8468 338e51e8 Iustin Pop
        miss_mem = (be_new[constants.BE_MEMORY] - current_mem -
8469 070e998b Iustin Pop
                    pninfo.payload['memory_free'])
8470 cfefe007 Guido Trotter
        if miss_mem > 0:
8471 cfefe007 Guido Trotter
          raise errors.OpPrereqError("This change will prevent the instance"
8472 cfefe007 Guido Trotter
                                     " from starting, due to %d MB of memory"
8473 5c983ee5 Iustin Pop
                                     " missing on its primary node" % miss_mem,
8474 5c983ee5 Iustin Pop
                                     errors.ECODE_NORES)
8475 cfefe007 Guido Trotter
8476 c0f2b229 Iustin Pop
      if be_new[constants.BE_AUTO_BALANCE]:
8477 070e998b Iustin Pop
        for node, nres in nodeinfo.items():
8478 ea33068f Iustin Pop
          if node not in instance.secondary_nodes:
8479 ea33068f Iustin Pop
            continue
8480 4c4e4e1e Iustin Pop
          msg = nres.fail_msg
8481 070e998b Iustin Pop
          if msg:
8482 070e998b Iustin Pop
            self.warn.append("Can't get info from secondary node %s: %s" %
8483 070e998b Iustin Pop
                             (node, msg))
8484 070e998b Iustin Pop
          elif not isinstance(nres.payload.get('memory_free', None), int):
8485 070e998b Iustin Pop
            self.warn.append("Secondary node %s didn't return free"
8486 070e998b Iustin Pop
                             " memory information" % node)
8487 070e998b Iustin Pop
          elif be_new[constants.BE_MEMORY] > nres.payload['memory_free']:
8488 647a5d80 Iustin Pop
            self.warn.append("Not enough memory to failover instance to"
8489 647a5d80 Iustin Pop
                             " secondary node %s" % node)
8490 5bc84f33 Alexander Schreiber
8491 24991749 Iustin Pop
    # NIC processing
8492 cd098c41 Guido Trotter
    self.nic_pnew = {}
8493 cd098c41 Guido Trotter
    self.nic_pinst = {}
8494 24991749 Iustin Pop
    for nic_op, nic_dict in self.op.nics:
8495 24991749 Iustin Pop
      if nic_op == constants.DDM_REMOVE:
8496 24991749 Iustin Pop
        if not instance.nics:
8497 5c983ee5 Iustin Pop
          raise errors.OpPrereqError("Instance has no NICs, cannot remove",
8498 5c983ee5 Iustin Pop
                                     errors.ECODE_INVAL)
8499 24991749 Iustin Pop
        continue
8500 24991749 Iustin Pop
      if nic_op != constants.DDM_ADD:
8501 24991749 Iustin Pop
        # an existing nic
8502 21bcb9aa Michael Hanselmann
        if not instance.nics:
8503 21bcb9aa Michael Hanselmann
          raise errors.OpPrereqError("Invalid NIC index %s, instance has"
8504 21bcb9aa Michael Hanselmann
                                     " no NICs" % nic_op,
8505 21bcb9aa Michael Hanselmann
                                     errors.ECODE_INVAL)
8506 24991749 Iustin Pop
        if nic_op < 0 or nic_op >= len(instance.nics):
8507 24991749 Iustin Pop
          raise errors.OpPrereqError("Invalid NIC index %s, valid values"
8508 24991749 Iustin Pop
                                     " are 0 to %d" %
8509 21bcb9aa Michael Hanselmann
                                     (nic_op, len(instance.nics) - 1),
8510 5c983ee5 Iustin Pop
                                     errors.ECODE_INVAL)
8511 cd098c41 Guido Trotter
        old_nic_params = instance.nics[nic_op].nicparams
8512 cd098c41 Guido Trotter
        old_nic_ip = instance.nics[nic_op].ip
8513 cd098c41 Guido Trotter
      else:
8514 cd098c41 Guido Trotter
        old_nic_params = {}
8515 cd098c41 Guido Trotter
        old_nic_ip = None
8516 cd098c41 Guido Trotter
8517 cd098c41 Guido Trotter
      update_params_dict = dict([(key, nic_dict[key])
8518 cd098c41 Guido Trotter
                                 for key in constants.NICS_PARAMETERS
8519 cd098c41 Guido Trotter
                                 if key in nic_dict])
8520 cd098c41 Guido Trotter
8521 5c44da6a Guido Trotter
      if 'bridge' in nic_dict:
8522 cd098c41 Guido Trotter
        update_params_dict[constants.NIC_LINK] = nic_dict['bridge']
8523 cd098c41 Guido Trotter
8524 cd098c41 Guido Trotter
      new_nic_params, new_filled_nic_params = \
8525 cd098c41 Guido Trotter
          self._GetUpdatedParams(old_nic_params, update_params_dict,
8526 cd098c41 Guido Trotter
                                 cluster.nicparams[constants.PP_DEFAULT],
8527 cd098c41 Guido Trotter
                                 constants.NICS_PARAMETER_TYPES)
8528 cd098c41 Guido Trotter
      objects.NIC.CheckParameterSyntax(new_filled_nic_params)
8529 cd098c41 Guido Trotter
      self.nic_pinst[nic_op] = new_nic_params
8530 cd098c41 Guido Trotter
      self.nic_pnew[nic_op] = new_filled_nic_params
8531 cd098c41 Guido Trotter
      new_nic_mode = new_filled_nic_params[constants.NIC_MODE]
8532 cd098c41 Guido Trotter
8533 cd098c41 Guido Trotter
      if new_nic_mode == constants.NIC_MODE_BRIDGED:
8534 cd098c41 Guido Trotter
        nic_bridge = new_filled_nic_params[constants.NIC_LINK]
8535 4c4e4e1e Iustin Pop
        msg = self.rpc.call_bridges_exist(pnode, [nic_bridge]).fail_msg
8536 35c0c8da Iustin Pop
        if msg:
8537 35c0c8da Iustin Pop
          msg = "Error checking bridges on node %s: %s" % (pnode, msg)
8538 24991749 Iustin Pop
          if self.force:
8539 24991749 Iustin Pop
            self.warn.append(msg)
8540 24991749 Iustin Pop
          else:
8541 5c983ee5 Iustin Pop
            raise errors.OpPrereqError(msg, errors.ECODE_ENVIRON)
8542 cd098c41 Guido Trotter
      if new_nic_mode == constants.NIC_MODE_ROUTED:
8543 cd098c41 Guido Trotter
        if 'ip' in nic_dict:
8544 cd098c41 Guido Trotter
          nic_ip = nic_dict['ip']
8545 cd098c41 Guido Trotter
        else:
8546 cd098c41 Guido Trotter
          nic_ip = old_nic_ip
8547 cd098c41 Guido Trotter
        if nic_ip is None:
8548 cd098c41 Guido Trotter
          raise errors.OpPrereqError('Cannot set the nic ip to None'
8549 5c983ee5 Iustin Pop
                                     ' on a routed nic', errors.ECODE_INVAL)
8550 5c44da6a Guido Trotter
      if 'mac' in nic_dict:
8551 5c44da6a Guido Trotter
        nic_mac = nic_dict['mac']
8552 5c44da6a Guido Trotter
        if nic_mac is None:
8553 5c983ee5 Iustin Pop
          raise errors.OpPrereqError('Cannot set the nic mac to None',
8554 5c983ee5 Iustin Pop
                                     errors.ECODE_INVAL)
8555 5c44da6a Guido Trotter
        elif nic_mac in (constants.VALUE_AUTO, constants.VALUE_GENERATE):
8556 5c44da6a Guido Trotter
          # otherwise generate the mac
8557 36b66e6e Guido Trotter
          nic_dict['mac'] = self.cfg.GenerateMAC(self.proc.GetECId())
8558 5c44da6a Guido Trotter
        else:
8559 5c44da6a Guido Trotter
          # or validate/reserve the current one
8560 36b66e6e Guido Trotter
          try:
8561 36b66e6e Guido Trotter
            self.cfg.ReserveMAC(nic_mac, self.proc.GetECId())
8562 36b66e6e Guido Trotter
          except errors.ReservationError:
8563 5c44da6a Guido Trotter
            raise errors.OpPrereqError("MAC address %s already in use"
8564 5c983ee5 Iustin Pop
                                       " in cluster" % nic_mac,
8565 5c983ee5 Iustin Pop
                                       errors.ECODE_NOTUNIQUE)
8566 24991749 Iustin Pop
8567 24991749 Iustin Pop
    # DISK processing
8568 24991749 Iustin Pop
    if self.op.disks and instance.disk_template == constants.DT_DISKLESS:
8569 24991749 Iustin Pop
      raise errors.OpPrereqError("Disk operations not supported for"
8570 5c983ee5 Iustin Pop
                                 " diskless instances",
8571 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
8572 1122eb25 Iustin Pop
    for disk_op, _ in self.op.disks:
8573 24991749 Iustin Pop
      if disk_op == constants.DDM_REMOVE:
8574 24991749 Iustin Pop
        if len(instance.disks) == 1:
8575 24991749 Iustin Pop
          raise errors.OpPrereqError("Cannot remove the last disk of"
8576 31624382 Iustin Pop
                                     " an instance", errors.ECODE_INVAL)
8577 31624382 Iustin Pop
        _CheckInstanceDown(self, instance, "cannot remove disks")
8578 24991749 Iustin Pop
8579 24991749 Iustin Pop
      if (disk_op == constants.DDM_ADD and
8580 24991749 Iustin Pop
          len(instance.nics) >= constants.MAX_DISKS):
8581 24991749 Iustin Pop
        raise errors.OpPrereqError("Instance has too many disks (%d), cannot"
8582 5c983ee5 Iustin Pop
                                   " add more" % constants.MAX_DISKS,
8583 5c983ee5 Iustin Pop
                                   errors.ECODE_STATE)
8584 24991749 Iustin Pop
      if disk_op not in (constants.DDM_ADD, constants.DDM_REMOVE):
8585 24991749 Iustin Pop
        # an existing disk
8586 24991749 Iustin Pop
        if disk_op < 0 or disk_op >= len(instance.disks):
8587 24991749 Iustin Pop
          raise errors.OpPrereqError("Invalid disk index %s, valid values"
8588 24991749 Iustin Pop
                                     " are 0 to %d" %
8589 5c983ee5 Iustin Pop
                                     (disk_op, len(instance.disks)),
8590 5c983ee5 Iustin Pop
                                     errors.ECODE_INVAL)
8591 24991749 Iustin Pop
8592 96b39bcc Iustin Pop
    # OS change
8593 96b39bcc Iustin Pop
    if self.op.os_name and not self.op.force:
8594 96b39bcc Iustin Pop
      _CheckNodeHasOS(self, instance.primary_node, self.op.os_name,
8595 96b39bcc Iustin Pop
                      self.op.force_variant)
8596 96b39bcc Iustin Pop
8597 a8083063 Iustin Pop
    return
8598 a8083063 Iustin Pop
8599 e29e9550 Iustin Pop
  def _ConvertPlainToDrbd(self, feedback_fn):
8600 e29e9550 Iustin Pop
    """Converts an instance from plain to drbd.
8601 e29e9550 Iustin Pop

8602 e29e9550 Iustin Pop
    """
8603 e29e9550 Iustin Pop
    feedback_fn("Converting template to drbd")
8604 e29e9550 Iustin Pop
    instance = self.instance
8605 e29e9550 Iustin Pop
    pnode = instance.primary_node
8606 e29e9550 Iustin Pop
    snode = self.op.remote_node
8607 e29e9550 Iustin Pop
8608 e29e9550 Iustin Pop
    # create a fake disk info for _GenerateDiskTemplate
8609 e29e9550 Iustin Pop
    disk_info = [{"size": d.size, "mode": d.mode} for d in instance.disks]
8610 e29e9550 Iustin Pop
    new_disks = _GenerateDiskTemplate(self, self.op.disk_template,
8611 e29e9550 Iustin Pop
                                      instance.name, pnode, [snode],
8612 e29e9550 Iustin Pop
                                      disk_info, None, None, 0)
8613 e29e9550 Iustin Pop
    info = _GetInstanceInfoText(instance)
8614 e29e9550 Iustin Pop
    feedback_fn("Creating aditional volumes...")
8615 e29e9550 Iustin Pop
    # first, create the missing data and meta devices
8616 e29e9550 Iustin Pop
    for disk in new_disks:
8617 e29e9550 Iustin Pop
      # unfortunately this is... not too nice
8618 e29e9550 Iustin Pop
      _CreateSingleBlockDev(self, pnode, instance, disk.children[1],
8619 e29e9550 Iustin Pop
                            info, True)
8620 e29e9550 Iustin Pop
      for child in disk.children:
8621 e29e9550 Iustin Pop
        _CreateSingleBlockDev(self, snode, instance, child, info, True)
8622 e29e9550 Iustin Pop
    # at this stage, all new LVs have been created, we can rename the
8623 e29e9550 Iustin Pop
    # old ones
8624 e29e9550 Iustin Pop
    feedback_fn("Renaming original volumes...")
8625 e29e9550 Iustin Pop
    rename_list = [(o, n.children[0].logical_id)
8626 e29e9550 Iustin Pop
                   for (o, n) in zip(instance.disks, new_disks)]
8627 e29e9550 Iustin Pop
    result = self.rpc.call_blockdev_rename(pnode, rename_list)
8628 e29e9550 Iustin Pop
    result.Raise("Failed to rename original LVs")
8629 e29e9550 Iustin Pop
8630 e29e9550 Iustin Pop
    feedback_fn("Initializing DRBD devices...")
8631 e29e9550 Iustin Pop
    # all child devices are in place, we can now create the DRBD devices
8632 e29e9550 Iustin Pop
    for disk in new_disks:
8633 e29e9550 Iustin Pop
      for node in [pnode, snode]:
8634 e29e9550 Iustin Pop
        f_create = node == pnode
8635 e29e9550 Iustin Pop
        _CreateSingleBlockDev(self, node, instance, disk, info, f_create)
8636 e29e9550 Iustin Pop
8637 e29e9550 Iustin Pop
    # at this point, the instance has been modified
8638 e29e9550 Iustin Pop
    instance.disk_template = constants.DT_DRBD8
8639 e29e9550 Iustin Pop
    instance.disks = new_disks
8640 e29e9550 Iustin Pop
    self.cfg.Update(instance, feedback_fn)
8641 e29e9550 Iustin Pop
8642 e29e9550 Iustin Pop
    # disks are created, waiting for sync
8643 e29e9550 Iustin Pop
    disk_abort = not _WaitForSync(self, instance)
8644 e29e9550 Iustin Pop
    if disk_abort:
8645 e29e9550 Iustin Pop
      raise errors.OpExecError("There are some degraded disks for"
8646 e29e9550 Iustin Pop
                               " this instance, please cleanup manually")
8647 e29e9550 Iustin Pop
8648 2f414c48 Iustin Pop
  def _ConvertDrbdToPlain(self, feedback_fn):
8649 2f414c48 Iustin Pop
    """Converts an instance from drbd to plain.
8650 2f414c48 Iustin Pop

8651 2f414c48 Iustin Pop
    """
8652 2f414c48 Iustin Pop
    instance = self.instance
8653 2f414c48 Iustin Pop
    assert len(instance.secondary_nodes) == 1
8654 2f414c48 Iustin Pop
    pnode = instance.primary_node
8655 2f414c48 Iustin Pop
    snode = instance.secondary_nodes[0]
8656 2f414c48 Iustin Pop
    feedback_fn("Converting template to plain")
8657 2f414c48 Iustin Pop
8658 2f414c48 Iustin Pop
    old_disks = instance.disks
8659 2f414c48 Iustin Pop
    new_disks = [d.children[0] for d in old_disks]
8660 2f414c48 Iustin Pop
8661 2f414c48 Iustin Pop
    # copy over size and mode
8662 2f414c48 Iustin Pop
    for parent, child in zip(old_disks, new_disks):
8663 2f414c48 Iustin Pop
      child.size = parent.size
8664 2f414c48 Iustin Pop
      child.mode = parent.mode
8665 2f414c48 Iustin Pop
8666 2f414c48 Iustin Pop
    # update instance structure
8667 2f414c48 Iustin Pop
    instance.disks = new_disks
8668 2f414c48 Iustin Pop
    instance.disk_template = constants.DT_PLAIN
8669 2f414c48 Iustin Pop
    self.cfg.Update(instance, feedback_fn)
8670 2f414c48 Iustin Pop
8671 2f414c48 Iustin Pop
    feedback_fn("Removing volumes on the secondary node...")
8672 2f414c48 Iustin Pop
    for disk in old_disks:
8673 2f414c48 Iustin Pop
      self.cfg.SetDiskID(disk, snode)
8674 2f414c48 Iustin Pop
      msg = self.rpc.call_blockdev_remove(snode, disk).fail_msg
8675 2f414c48 Iustin Pop
      if msg:
8676 2f414c48 Iustin Pop
        self.LogWarning("Could not remove block device %s on node %s,"
8677 2f414c48 Iustin Pop
                        " continuing anyway: %s", disk.iv_name, snode, msg)
8678 2f414c48 Iustin Pop
8679 2f414c48 Iustin Pop
    feedback_fn("Removing unneeded volumes on the primary node...")
8680 2f414c48 Iustin Pop
    for idx, disk in enumerate(old_disks):
8681 2f414c48 Iustin Pop
      meta = disk.children[1]
8682 2f414c48 Iustin Pop
      self.cfg.SetDiskID(meta, pnode)
8683 2f414c48 Iustin Pop
      msg = self.rpc.call_blockdev_remove(pnode, meta).fail_msg
8684 2f414c48 Iustin Pop
      if msg:
8685 2f414c48 Iustin Pop
        self.LogWarning("Could not remove metadata for disk %d on node %s,"
8686 2f414c48 Iustin Pop
                        " continuing anyway: %s", idx, pnode, msg)
8687 2f414c48 Iustin Pop
8688 2f414c48 Iustin Pop
8689 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
8690 a8083063 Iustin Pop
    """Modifies an instance.
8691 a8083063 Iustin Pop

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

8694 a8083063 Iustin Pop
    """
8695 cfefe007 Guido Trotter
    # Process here the warnings from CheckPrereq, as we don't have a
8696 cfefe007 Guido Trotter
    # feedback_fn there.
8697 cfefe007 Guido Trotter
    for warn in self.warn:
8698 cfefe007 Guido Trotter
      feedback_fn("WARNING: %s" % warn)
8699 cfefe007 Guido Trotter
8700 a8083063 Iustin Pop
    result = []
8701 a8083063 Iustin Pop
    instance = self.instance
8702 24991749 Iustin Pop
    # disk changes
8703 24991749 Iustin Pop
    for disk_op, disk_dict in self.op.disks:
8704 24991749 Iustin Pop
      if disk_op == constants.DDM_REMOVE:
8705 24991749 Iustin Pop
        # remove the last disk
8706 24991749 Iustin Pop
        device = instance.disks.pop()
8707 24991749 Iustin Pop
        device_idx = len(instance.disks)
8708 24991749 Iustin Pop
        for node, disk in device.ComputeNodeTree(instance.primary_node):
8709 24991749 Iustin Pop
          self.cfg.SetDiskID(disk, node)
8710 4c4e4e1e Iustin Pop
          msg = self.rpc.call_blockdev_remove(node, disk).fail_msg
8711 e1bc0878 Iustin Pop
          if msg:
8712 e1bc0878 Iustin Pop
            self.LogWarning("Could not remove disk/%d on node %s: %s,"
8713 e1bc0878 Iustin Pop
                            " continuing anyway", device_idx, node, msg)
8714 24991749 Iustin Pop
        result.append(("disk/%d" % device_idx, "remove"))
8715 24991749 Iustin Pop
      elif disk_op == constants.DDM_ADD:
8716 24991749 Iustin Pop
        # add a new disk
8717 24991749 Iustin Pop
        if instance.disk_template == constants.DT_FILE:
8718 24991749 Iustin Pop
          file_driver, file_path = instance.disks[0].logical_id
8719 24991749 Iustin Pop
          file_path = os.path.dirname(file_path)
8720 24991749 Iustin Pop
        else:
8721 24991749 Iustin Pop
          file_driver = file_path = None
8722 24991749 Iustin Pop
        disk_idx_base = len(instance.disks)
8723 24991749 Iustin Pop
        new_disk = _GenerateDiskTemplate(self,
8724 24991749 Iustin Pop
                                         instance.disk_template,
8725 32388e6d Iustin Pop
                                         instance.name, instance.primary_node,
8726 24991749 Iustin Pop
                                         instance.secondary_nodes,
8727 24991749 Iustin Pop
                                         [disk_dict],
8728 24991749 Iustin Pop
                                         file_path,
8729 24991749 Iustin Pop
                                         file_driver,
8730 24991749 Iustin Pop
                                         disk_idx_base)[0]
8731 24991749 Iustin Pop
        instance.disks.append(new_disk)
8732 24991749 Iustin Pop
        info = _GetInstanceInfoText(instance)
8733 24991749 Iustin Pop
8734 24991749 Iustin Pop
        logging.info("Creating volume %s for instance %s",
8735 24991749 Iustin Pop
                     new_disk.iv_name, instance.name)
8736 24991749 Iustin Pop
        # Note: this needs to be kept in sync with _CreateDisks
8737 24991749 Iustin Pop
        #HARDCODE
8738 428958aa Iustin Pop
        for node in instance.all_nodes:
8739 428958aa Iustin Pop
          f_create = node == instance.primary_node
8740 796cab27 Iustin Pop
          try:
8741 428958aa Iustin Pop
            _CreateBlockDev(self, node, instance, new_disk,
8742 428958aa Iustin Pop
                            f_create, info, f_create)
8743 1492cca7 Iustin Pop
          except errors.OpExecError, err:
8744 24991749 Iustin Pop
            self.LogWarning("Failed to create volume %s (%s) on"
8745 428958aa Iustin Pop
                            " node %s: %s",
8746 428958aa Iustin Pop
                            new_disk.iv_name, new_disk, node, err)
8747 24991749 Iustin Pop
        result.append(("disk/%d" % disk_idx_base, "add:size=%s,mode=%s" %
8748 24991749 Iustin Pop
                       (new_disk.size, new_disk.mode)))
8749 24991749 Iustin Pop
      else:
8750 24991749 Iustin Pop
        # change a given disk
8751 24991749 Iustin Pop
        instance.disks[disk_op].mode = disk_dict['mode']
8752 24991749 Iustin Pop
        result.append(("disk.mode/%d" % disk_op, disk_dict['mode']))
8753 e29e9550 Iustin Pop
8754 e29e9550 Iustin Pop
    if self.op.disk_template:
8755 e29e9550 Iustin Pop
      r_shut = _ShutdownInstanceDisks(self, instance)
8756 e29e9550 Iustin Pop
      if not r_shut:
8757 e29e9550 Iustin Pop
        raise errors.OpExecError("Cannot shutdow instance disks, unable to"
8758 e29e9550 Iustin Pop
                                 " proceed with disk template conversion")
8759 e29e9550 Iustin Pop
      mode = (instance.disk_template, self.op.disk_template)
8760 e29e9550 Iustin Pop
      try:
8761 e29e9550 Iustin Pop
        self._DISK_CONVERSIONS[mode](self, feedback_fn)
8762 e29e9550 Iustin Pop
      except:
8763 e29e9550 Iustin Pop
        self.cfg.ReleaseDRBDMinors(instance.name)
8764 e29e9550 Iustin Pop
        raise
8765 e29e9550 Iustin Pop
      result.append(("disk_template", self.op.disk_template))
8766 e29e9550 Iustin Pop
8767 24991749 Iustin Pop
    # NIC changes
8768 24991749 Iustin Pop
    for nic_op, nic_dict in self.op.nics:
8769 24991749 Iustin Pop
      if nic_op == constants.DDM_REMOVE:
8770 24991749 Iustin Pop
        # remove the last nic
8771 24991749 Iustin Pop
        del instance.nics[-1]
8772 24991749 Iustin Pop
        result.append(("nic.%d" % len(instance.nics), "remove"))
8773 24991749 Iustin Pop
      elif nic_op == constants.DDM_ADD:
8774 5c44da6a Guido Trotter
        # mac and bridge should be set, by now
8775 5c44da6a Guido Trotter
        mac = nic_dict['mac']
8776 cd098c41 Guido Trotter
        ip = nic_dict.get('ip', None)
8777 cd098c41 Guido Trotter
        nicparams = self.nic_pinst[constants.DDM_ADD]
8778 cd098c41 Guido Trotter
        new_nic = objects.NIC(mac=mac, ip=ip, nicparams=nicparams)
8779 24991749 Iustin Pop
        instance.nics.append(new_nic)
8780 24991749 Iustin Pop
        result.append(("nic.%d" % (len(instance.nics) - 1),
8781 cd098c41 Guido Trotter
                       "add:mac=%s,ip=%s,mode=%s,link=%s" %
8782 cd098c41 Guido Trotter
                       (new_nic.mac, new_nic.ip,
8783 cd098c41 Guido Trotter
                        self.nic_pnew[constants.DDM_ADD][constants.NIC_MODE],
8784 cd098c41 Guido Trotter
                        self.nic_pnew[constants.DDM_ADD][constants.NIC_LINK]
8785 cd098c41 Guido Trotter
                       )))
8786 24991749 Iustin Pop
      else:
8787 cd098c41 Guido Trotter
        for key in 'mac', 'ip':
8788 24991749 Iustin Pop
          if key in nic_dict:
8789 24991749 Iustin Pop
            setattr(instance.nics[nic_op], key, nic_dict[key])
8790 beabf067 Guido Trotter
        if nic_op in self.nic_pinst:
8791 beabf067 Guido Trotter
          instance.nics[nic_op].nicparams = self.nic_pinst[nic_op]
8792 cd098c41 Guido Trotter
        for key, val in nic_dict.iteritems():
8793 cd098c41 Guido Trotter
          result.append(("nic.%s/%d" % (key, nic_op), val))
8794 24991749 Iustin Pop
8795 24991749 Iustin Pop
    # hvparams changes
8796 74409b12 Iustin Pop
    if self.op.hvparams:
8797 12649e35 Guido Trotter
      instance.hvparams = self.hv_inst
8798 74409b12 Iustin Pop
      for key, val in self.op.hvparams.iteritems():
8799 74409b12 Iustin Pop
        result.append(("hv/%s" % key, val))
8800 24991749 Iustin Pop
8801 24991749 Iustin Pop
    # beparams changes
8802 338e51e8 Iustin Pop
    if self.op.beparams:
8803 338e51e8 Iustin Pop
      instance.beparams = self.be_inst
8804 338e51e8 Iustin Pop
      for key, val in self.op.beparams.iteritems():
8805 338e51e8 Iustin Pop
        result.append(("be/%s" % key, val))
8806 a8083063 Iustin Pop
8807 96b39bcc Iustin Pop
    # OS change
8808 96b39bcc Iustin Pop
    if self.op.os_name:
8809 96b39bcc Iustin Pop
      instance.os = self.op.os_name
8810 96b39bcc Iustin Pop
8811 a4eae71f Michael Hanselmann
    self.cfg.Update(instance, feedback_fn)
8812 a8083063 Iustin Pop
8813 a8083063 Iustin Pop
    return result
8814 a8083063 Iustin Pop
8815 e29e9550 Iustin Pop
  _DISK_CONVERSIONS = {
8816 e29e9550 Iustin Pop
    (constants.DT_PLAIN, constants.DT_DRBD8): _ConvertPlainToDrbd,
8817 2f414c48 Iustin Pop
    (constants.DT_DRBD8, constants.DT_PLAIN): _ConvertDrbdToPlain,
8818 e29e9550 Iustin Pop
    }
8819 a8083063 Iustin Pop
8820 a8083063 Iustin Pop
class LUQueryExports(NoHooksLU):
8821 a8083063 Iustin Pop
  """Query the exports list
8822 a8083063 Iustin Pop

8823 a8083063 Iustin Pop
  """
8824 895ecd9c Guido Trotter
  _OP_REQP = ['nodes']
8825 21a15682 Guido Trotter
  REQ_BGL = False
8826 21a15682 Guido Trotter
8827 21a15682 Guido Trotter
  def ExpandNames(self):
8828 21a15682 Guido Trotter
    self.needed_locks = {}
8829 21a15682 Guido Trotter
    self.share_locks[locking.LEVEL_NODE] = 1
8830 21a15682 Guido Trotter
    if not self.op.nodes:
8831 e310b019 Guido Trotter
      self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
8832 21a15682 Guido Trotter
    else:
8833 21a15682 Guido Trotter
      self.needed_locks[locking.LEVEL_NODE] = \
8834 21a15682 Guido Trotter
        _GetWantedNodes(self, self.op.nodes)
8835 a8083063 Iustin Pop
8836 a8083063 Iustin Pop
  def CheckPrereq(self):
8837 21a15682 Guido Trotter
    """Check prerequisites.
8838 a8083063 Iustin Pop

8839 a8083063 Iustin Pop
    """
8840 21a15682 Guido Trotter
    self.nodes = self.acquired_locks[locking.LEVEL_NODE]
8841 a8083063 Iustin Pop
8842 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
8843 a8083063 Iustin Pop
    """Compute the list of all the exported system images.
8844 a8083063 Iustin Pop

8845 e4376078 Iustin Pop
    @rtype: dict
8846 e4376078 Iustin Pop
    @return: a dictionary with the structure node->(export-list)
8847 e4376078 Iustin Pop
        where export-list is a list of the instances exported on
8848 e4376078 Iustin Pop
        that node.
8849 a8083063 Iustin Pop

8850 a8083063 Iustin Pop
    """
8851 b04285f2 Guido Trotter
    rpcresult = self.rpc.call_export_list(self.nodes)
8852 b04285f2 Guido Trotter
    result = {}
8853 b04285f2 Guido Trotter
    for node in rpcresult:
8854 4c4e4e1e Iustin Pop
      if rpcresult[node].fail_msg:
8855 b04285f2 Guido Trotter
        result[node] = False
8856 b04285f2 Guido Trotter
      else:
8857 1b7bfbb7 Iustin Pop
        result[node] = rpcresult[node].payload
8858 b04285f2 Guido Trotter
8859 b04285f2 Guido Trotter
    return result
8860 a8083063 Iustin Pop
8861 a8083063 Iustin Pop
8862 a8083063 Iustin Pop
class LUExportInstance(LogicalUnit):
8863 a8083063 Iustin Pop
  """Export an instance to an image in the cluster.
8864 a8083063 Iustin Pop

8865 a8083063 Iustin Pop
  """
8866 a8083063 Iustin Pop
  HPATH = "instance-export"
8867 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
8868 a8083063 Iustin Pop
  _OP_REQP = ["instance_name", "target_node", "shutdown"]
8869 6657590e Guido Trotter
  REQ_BGL = False
8870 6657590e Guido Trotter
8871 17c3f802 Guido Trotter
  def CheckArguments(self):
8872 17c3f802 Guido Trotter
    """Check the arguments.
8873 17c3f802 Guido Trotter

8874 17c3f802 Guido Trotter
    """
8875 17c3f802 Guido Trotter
    self.shutdown_timeout = getattr(self.op, "shutdown_timeout",
8876 17c3f802 Guido Trotter
                                    constants.DEFAULT_SHUTDOWN_TIMEOUT)
8877 17c3f802 Guido Trotter
8878 6657590e Guido Trotter
  def ExpandNames(self):
8879 6657590e Guido Trotter
    self._ExpandAndLockInstance()
8880 6657590e Guido Trotter
    # FIXME: lock only instance primary and destination node
8881 6657590e Guido Trotter
    #
8882 6657590e Guido Trotter
    # Sad but true, for now we have do lock all nodes, as we don't know where
8883 6657590e Guido Trotter
    # the previous export might be, and and in this LU we search for it and
8884 6657590e Guido Trotter
    # remove it from its current node. In the future we could fix this by:
8885 6657590e Guido Trotter
    #  - making a tasklet to search (share-lock all), then create the new one,
8886 6657590e Guido Trotter
    #    then one to remove, after
8887 5bbd3f7f Michael Hanselmann
    #  - removing the removal operation altogether
8888 6657590e Guido Trotter
    self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
8889 6657590e Guido Trotter
8890 6657590e Guido Trotter
  def DeclareLocks(self, level):
8891 6657590e Guido Trotter
    """Last minute lock declaration."""
8892 6657590e Guido Trotter
    # All nodes are locked anyway, so nothing to do here.
8893 a8083063 Iustin Pop
8894 a8083063 Iustin Pop
  def BuildHooksEnv(self):
8895 a8083063 Iustin Pop
    """Build hooks env.
8896 a8083063 Iustin Pop

8897 a8083063 Iustin Pop
    This will run on the master, primary node and target node.
8898 a8083063 Iustin Pop

8899 a8083063 Iustin Pop
    """
8900 a8083063 Iustin Pop
    env = {
8901 a8083063 Iustin Pop
      "EXPORT_NODE": self.op.target_node,
8902 a8083063 Iustin Pop
      "EXPORT_DO_SHUTDOWN": self.op.shutdown,
8903 17c3f802 Guido Trotter
      "SHUTDOWN_TIMEOUT": self.shutdown_timeout,
8904 a8083063 Iustin Pop
      }
8905 338e51e8 Iustin Pop
    env.update(_BuildInstanceHookEnvByObject(self, self.instance))
8906 d6a02168 Michael Hanselmann
    nl = [self.cfg.GetMasterNode(), self.instance.primary_node,
8907 a8083063 Iustin Pop
          self.op.target_node]
8908 a8083063 Iustin Pop
    return env, nl, nl
8909 a8083063 Iustin Pop
8910 a8083063 Iustin Pop
  def CheckPrereq(self):
8911 a8083063 Iustin Pop
    """Check prerequisites.
8912 a8083063 Iustin Pop

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

8915 a8083063 Iustin Pop
    """
8916 6657590e Guido Trotter
    instance_name = self.op.instance_name
8917 a8083063 Iustin Pop
    self.instance = self.cfg.GetInstanceInfo(instance_name)
8918 6657590e Guido Trotter
    assert self.instance is not None, \
8919 6657590e Guido Trotter
          "Cannot retrieve locked instance %s" % self.op.instance_name
8920 43017d26 Iustin Pop
    _CheckNodeOnline(self, self.instance.primary_node)
8921 a8083063 Iustin Pop
8922 cf26a87a Iustin Pop
    self.op.target_node = _ExpandNodeName(self.cfg, self.op.target_node)
8923 cf26a87a Iustin Pop
    self.dst_node = self.cfg.GetNodeInfo(self.op.target_node)
8924 cf26a87a Iustin Pop
    assert self.dst_node is not None
8925 a8083063 Iustin Pop
8926 aeb83a2b Iustin Pop
    _CheckNodeOnline(self, self.dst_node.name)
8927 733a2b6a Iustin Pop
    _CheckNodeNotDrained(self, self.dst_node.name)
8928 a8083063 Iustin Pop
8929 b6023d6c Manuel Franceschini
    # instance disk type verification
8930 b6023d6c Manuel Franceschini
    for disk in self.instance.disks:
8931 b6023d6c Manuel Franceschini
      if disk.dev_type == constants.LD_FILE:
8932 b6023d6c Manuel Franceschini
        raise errors.OpPrereqError("Export not supported for instances with"
8933 5c983ee5 Iustin Pop
                                   " file-based disks", errors.ECODE_INVAL)
8934 b6023d6c Manuel Franceschini
8935 e311ed53 Michael Hanselmann
  def _CreateSnapshots(self, feedback_fn):
8936 e311ed53 Michael Hanselmann
    """Creates an LVM snapshot for every disk of the instance.
8937 e311ed53 Michael Hanselmann

8938 e311ed53 Michael Hanselmann
    @return: List of snapshots as L{objects.Disk} instances
8939 e311ed53 Michael Hanselmann

8940 e311ed53 Michael Hanselmann
    """
8941 e311ed53 Michael Hanselmann
    instance = self.instance
8942 e311ed53 Michael Hanselmann
    src_node = instance.primary_node
8943 e311ed53 Michael Hanselmann
8944 e311ed53 Michael Hanselmann
    vgname = self.cfg.GetVGName()
8945 e311ed53 Michael Hanselmann
8946 e311ed53 Michael Hanselmann
    snap_disks = []
8947 e311ed53 Michael Hanselmann
8948 e311ed53 Michael Hanselmann
    for idx, disk in enumerate(instance.disks):
8949 e311ed53 Michael Hanselmann
      feedback_fn("Creating a snapshot of disk/%s on node %s" %
8950 e311ed53 Michael Hanselmann
                  (idx, src_node))
8951 e311ed53 Michael Hanselmann
8952 e311ed53 Michael Hanselmann
      # result.payload will be a snapshot of an lvm leaf of the one we
8953 e311ed53 Michael Hanselmann
      # passed
8954 e311ed53 Michael Hanselmann
      result = self.rpc.call_blockdev_snapshot(src_node, disk)
8955 e311ed53 Michael Hanselmann
      msg = result.fail_msg
8956 e311ed53 Michael Hanselmann
      if msg:
8957 e311ed53 Michael Hanselmann
        self.LogWarning("Could not snapshot disk/%s on node %s: %s",
8958 e311ed53 Michael Hanselmann
                        idx, src_node, msg)
8959 e311ed53 Michael Hanselmann
        snap_disks.append(False)
8960 e311ed53 Michael Hanselmann
      else:
8961 e311ed53 Michael Hanselmann
        disk_id = (vgname, result.payload)
8962 e311ed53 Michael Hanselmann
        new_dev = objects.Disk(dev_type=constants.LD_LV, size=disk.size,
8963 e311ed53 Michael Hanselmann
                               logical_id=disk_id, physical_id=disk_id,
8964 e311ed53 Michael Hanselmann
                               iv_name=disk.iv_name)
8965 e311ed53 Michael Hanselmann
        snap_disks.append(new_dev)
8966 e311ed53 Michael Hanselmann
8967 e311ed53 Michael Hanselmann
    return snap_disks
8968 e311ed53 Michael Hanselmann
8969 e311ed53 Michael Hanselmann
  def _RemoveSnapshot(self, feedback_fn, snap_disks, disk_index):
8970 e311ed53 Michael Hanselmann
    """Removes an LVM snapshot.
8971 e311ed53 Michael Hanselmann

8972 e311ed53 Michael Hanselmann
    @type snap_disks: list
8973 e311ed53 Michael Hanselmann
    @param snap_disks: The list of all snapshots as returned by
8974 e311ed53 Michael Hanselmann
                       L{_CreateSnapshots}
8975 e311ed53 Michael Hanselmann
    @type disk_index: number
8976 e311ed53 Michael Hanselmann
    @param disk_index: Index of the snapshot to be removed
8977 e311ed53 Michael Hanselmann
    @rtype: bool
8978 e311ed53 Michael Hanselmann
    @return: Whether removal was successful or not
8979 e311ed53 Michael Hanselmann

8980 e311ed53 Michael Hanselmann
    """
8981 e311ed53 Michael Hanselmann
    disk = snap_disks[disk_index]
8982 e311ed53 Michael Hanselmann
    if disk:
8983 e311ed53 Michael Hanselmann
      src_node = self.instance.primary_node
8984 e311ed53 Michael Hanselmann
8985 e311ed53 Michael Hanselmann
      feedback_fn("Removing snapshot of disk/%s on node %s" %
8986 e311ed53 Michael Hanselmann
                  (disk_index, src_node))
8987 e311ed53 Michael Hanselmann
8988 e311ed53 Michael Hanselmann
      result = self.rpc.call_blockdev_remove(src_node, disk)
8989 e311ed53 Michael Hanselmann
      if not result.fail_msg:
8990 e311ed53 Michael Hanselmann
        return True
8991 e311ed53 Michael Hanselmann
8992 e311ed53 Michael Hanselmann
      self.LogWarning("Could not remove snapshot for disk/%d from node"
8993 e311ed53 Michael Hanselmann
                      " %s: %s", disk_index, src_node, result.fail_msg)
8994 e311ed53 Michael Hanselmann
8995 e311ed53 Michael Hanselmann
    return False
8996 e311ed53 Michael Hanselmann
8997 e311ed53 Michael Hanselmann
  def _CleanupExports(self, feedback_fn):
8998 e311ed53 Michael Hanselmann
    """Removes exports of current instance from all other nodes.
8999 e311ed53 Michael Hanselmann

9000 e311ed53 Michael Hanselmann
    If an instance in a cluster with nodes A..D was exported to node C, its
9001 e311ed53 Michael Hanselmann
    exports will be removed from the nodes A, B and D.
9002 e311ed53 Michael Hanselmann

9003 e311ed53 Michael Hanselmann
    """
9004 e311ed53 Michael Hanselmann
    nodelist = self.cfg.GetNodeList()
9005 e311ed53 Michael Hanselmann
    nodelist.remove(self.dst_node.name)
9006 e311ed53 Michael Hanselmann
9007 e311ed53 Michael Hanselmann
    # on one-node clusters nodelist will be empty after the removal
9008 e311ed53 Michael Hanselmann
    # if we proceed the backup would be removed because OpQueryExports
9009 e311ed53 Michael Hanselmann
    # substitutes an empty list with the full cluster node list.
9010 e311ed53 Michael Hanselmann
    iname = self.instance.name
9011 e311ed53 Michael Hanselmann
    if nodelist:
9012 e311ed53 Michael Hanselmann
      feedback_fn("Removing old exports for instance %s" % iname)
9013 e311ed53 Michael Hanselmann
      exportlist = self.rpc.call_export_list(nodelist)
9014 e311ed53 Michael Hanselmann
      for node in exportlist:
9015 e311ed53 Michael Hanselmann
        if exportlist[node].fail_msg:
9016 e311ed53 Michael Hanselmann
          continue
9017 e311ed53 Michael Hanselmann
        if iname in exportlist[node].payload:
9018 e311ed53 Michael Hanselmann
          msg = self.rpc.call_export_remove(node, iname).fail_msg
9019 e311ed53 Michael Hanselmann
          if msg:
9020 e311ed53 Michael Hanselmann
            self.LogWarning("Could not remove older export for instance %s"
9021 e311ed53 Michael Hanselmann
                            " on node %s: %s", iname, node, msg)
9022 e311ed53 Michael Hanselmann
9023 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
9024 a8083063 Iustin Pop
    """Export an instance to an image in the cluster.
9025 a8083063 Iustin Pop

9026 a8083063 Iustin Pop
    """
9027 a8083063 Iustin Pop
    instance = self.instance
9028 a8083063 Iustin Pop
    dst_node = self.dst_node
9029 a8083063 Iustin Pop
    src_node = instance.primary_node
9030 37972df0 Michael Hanselmann
9031 a8083063 Iustin Pop
    if self.op.shutdown:
9032 fb300fb7 Guido Trotter
      # shutdown the instance, but not the disks
9033 37972df0 Michael Hanselmann
      feedback_fn("Shutting down instance %s" % instance.name)
9034 17c3f802 Guido Trotter
      result = self.rpc.call_instance_shutdown(src_node, instance,
9035 17c3f802 Guido Trotter
                                               self.shutdown_timeout)
9036 4c4e4e1e Iustin Pop
      result.Raise("Could not shutdown instance %s on"
9037 4c4e4e1e Iustin Pop
                   " node %s" % (instance.name, src_node))
9038 a8083063 Iustin Pop
9039 998c712c Iustin Pop
    # set the disks ID correctly since call_instance_start needs the
9040 998c712c Iustin Pop
    # correct drbd minor to create the symlinks
9041 998c712c Iustin Pop
    for disk in instance.disks:
9042 998c712c Iustin Pop
      self.cfg.SetDiskID(disk, src_node)
9043 998c712c Iustin Pop
9044 3e53a60b Michael Hanselmann
    activate_disks = (not instance.admin_up)
9045 3e53a60b Michael Hanselmann
9046 3e53a60b Michael Hanselmann
    if activate_disks:
9047 3e53a60b Michael Hanselmann
      # Activate the instance disks if we'exporting a stopped instance
9048 3e53a60b Michael Hanselmann
      feedback_fn("Activating disks for %s" % instance.name)
9049 3e53a60b Michael Hanselmann
      _StartInstanceDisks(self, instance, None)
9050 3e53a60b Michael Hanselmann
9051 a8083063 Iustin Pop
    try:
9052 3e53a60b Michael Hanselmann
      # per-disk results
9053 3e53a60b Michael Hanselmann
      dresults = []
9054 e311ed53 Michael Hanselmann
      removed_snaps = [False] * len(instance.disks)
9055 e311ed53 Michael Hanselmann
9056 e311ed53 Michael Hanselmann
      snap_disks = None
9057 3e53a60b Michael Hanselmann
      try:
9058 e311ed53 Michael Hanselmann
        try:
9059 e311ed53 Michael Hanselmann
          snap_disks = self._CreateSnapshots(feedback_fn)
9060 e311ed53 Michael Hanselmann
        finally:
9061 e311ed53 Michael Hanselmann
          if self.op.shutdown and instance.admin_up:
9062 e311ed53 Michael Hanselmann
            feedback_fn("Starting instance %s" % instance.name)
9063 e311ed53 Michael Hanselmann
            result = self.rpc.call_instance_start(src_node, instance,
9064 e311ed53 Michael Hanselmann
                                                  None, None)
9065 e311ed53 Michael Hanselmann
            msg = result.fail_msg
9066 e311ed53 Michael Hanselmann
            if msg:
9067 e311ed53 Michael Hanselmann
              _ShutdownInstanceDisks(self, instance)
9068 e311ed53 Michael Hanselmann
              raise errors.OpExecError("Could not start instance: %s" % msg)
9069 37972df0 Michael Hanselmann
9070 e311ed53 Michael Hanselmann
        assert len(snap_disks) == len(instance.disks)
9071 e311ed53 Michael Hanselmann
        assert len(removed_snaps) == len(instance.disks)
9072 e311ed53 Michael Hanselmann
9073 e311ed53 Michael Hanselmann
        # TODO: check for size
9074 e311ed53 Michael Hanselmann
9075 e311ed53 Michael Hanselmann
        cluster_name = self.cfg.GetClusterName()
9076 e311ed53 Michael Hanselmann
        for idx, dev in enumerate(snap_disks):
9077 e311ed53 Michael Hanselmann
          feedback_fn("Exporting snapshot %s from %s to %s" %
9078 e311ed53 Michael Hanselmann
                      (idx, src_node, dst_node.name))
9079 e311ed53 Michael Hanselmann
          if dev:
9080 e311ed53 Michael Hanselmann
            # FIXME: pass debug from opcode to backend
9081 e311ed53 Michael Hanselmann
            result = self.rpc.call_snapshot_export(src_node, dev, dst_node.name,
9082 e311ed53 Michael Hanselmann
                                                   instance, cluster_name,
9083 e311ed53 Michael Hanselmann
                                                   idx, self.op.debug_level)
9084 e311ed53 Michael Hanselmann
            msg = result.fail_msg
9085 e311ed53 Michael Hanselmann
            if msg:
9086 e311ed53 Michael Hanselmann
              self.LogWarning("Could not export disk/%s from node %s to"
9087 e311ed53 Michael Hanselmann
                              " node %s: %s", idx, src_node, dst_node.name, msg)
9088 e311ed53 Michael Hanselmann
              dresults.append(False)
9089 e311ed53 Michael Hanselmann
            else:
9090 e311ed53 Michael Hanselmann
              dresults.append(True)
9091 e311ed53 Michael Hanselmann
9092 e311ed53 Michael Hanselmann
            # Remove snapshot
9093 e311ed53 Michael Hanselmann
            if self._RemoveSnapshot(feedback_fn, snap_disks, idx):
9094 e311ed53 Michael Hanselmann
              removed_snaps[idx] = True
9095 3e53a60b Michael Hanselmann
          else:
9096 e311ed53 Michael Hanselmann
            dresults.append(False)
9097 a8083063 Iustin Pop
9098 e311ed53 Michael Hanselmann
        assert len(dresults) == len(instance.disks)
9099 e311ed53 Michael Hanselmann
9100 e311ed53 Michael Hanselmann
        # Check for backwards compatibility
9101 e311ed53 Michael Hanselmann
        assert compat.all(isinstance(i, bool) for i in dresults), \
9102 e311ed53 Michael Hanselmann
               "Not all results are boolean: %r" % dresults
9103 e311ed53 Michael Hanselmann
9104 e311ed53 Michael Hanselmann
        feedback_fn("Finalizing export on %s" % dst_node.name)
9105 e311ed53 Michael Hanselmann
        result = self.rpc.call_finalize_export(dst_node.name, instance,
9106 e311ed53 Michael Hanselmann
                                               snap_disks)
9107 e311ed53 Michael Hanselmann
        msg = result.fail_msg
9108 e311ed53 Michael Hanselmann
        fin_resu = not msg
9109 e311ed53 Michael Hanselmann
        if msg:
9110 e311ed53 Michael Hanselmann
          self.LogWarning("Could not finalize export for instance %s"
9111 e311ed53 Michael Hanselmann
                          " on node %s: %s", instance.name, dst_node.name, msg)
9112 e311ed53 Michael Hanselmann
9113 e311ed53 Michael Hanselmann
      finally:
9114 e311ed53 Michael Hanselmann
        # Remove all snapshots
9115 e311ed53 Michael Hanselmann
        assert len(removed_snaps) == len(instance.disks)
9116 e311ed53 Michael Hanselmann
        for idx, removed in enumerate(removed_snaps):
9117 e311ed53 Michael Hanselmann
          if not removed:
9118 e311ed53 Michael Hanselmann
            self._RemoveSnapshot(feedback_fn, snap_disks, idx)
9119 3e53a60b Michael Hanselmann
9120 3e53a60b Michael Hanselmann
    finally:
9121 3e53a60b Michael Hanselmann
      if activate_disks:
9122 3e53a60b Michael Hanselmann
        feedback_fn("Deactivating disks for %s" % instance.name)
9123 3e53a60b Michael Hanselmann
        _ShutdownInstanceDisks(self, instance)
9124 a8083063 Iustin Pop
9125 e311ed53 Michael Hanselmann
    self._CleanupExports(feedback_fn)
9126 a8083063 Iustin Pop
9127 084f05a5 Iustin Pop
    return fin_resu, dresults
9128 5c947f38 Iustin Pop
9129 5c947f38 Iustin Pop
9130 9ac99fda Guido Trotter
class LURemoveExport(NoHooksLU):
9131 9ac99fda Guido Trotter
  """Remove exports related to the named instance.
9132 9ac99fda Guido Trotter

9133 9ac99fda Guido Trotter
  """
9134 9ac99fda Guido Trotter
  _OP_REQP = ["instance_name"]
9135 3656b3af Guido Trotter
  REQ_BGL = False
9136 3656b3af Guido Trotter
9137 3656b3af Guido Trotter
  def ExpandNames(self):
9138 3656b3af Guido Trotter
    self.needed_locks = {}
9139 3656b3af Guido Trotter
    # We need all nodes to be locked in order for RemoveExport to work, but we
9140 3656b3af Guido Trotter
    # don't need to lock the instance itself, as nothing will happen to it (and
9141 3656b3af Guido Trotter
    # we can remove exports also for a removed instance)
9142 3656b3af Guido Trotter
    self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
9143 9ac99fda Guido Trotter
9144 9ac99fda Guido Trotter
  def CheckPrereq(self):
9145 9ac99fda Guido Trotter
    """Check prerequisites.
9146 9ac99fda Guido Trotter
    """
9147 9ac99fda Guido Trotter
    pass
9148 9ac99fda Guido Trotter
9149 9ac99fda Guido Trotter
  def Exec(self, feedback_fn):
9150 9ac99fda Guido Trotter
    """Remove any export.
9151 9ac99fda Guido Trotter

9152 9ac99fda Guido Trotter
    """
9153 9ac99fda Guido Trotter
    instance_name = self.cfg.ExpandInstanceName(self.op.instance_name)
9154 9ac99fda Guido Trotter
    # If the instance was not found we'll try with the name that was passed in.
9155 9ac99fda Guido Trotter
    # This will only work if it was an FQDN, though.
9156 9ac99fda Guido Trotter
    fqdn_warn = False
9157 9ac99fda Guido Trotter
    if not instance_name:
9158 9ac99fda Guido Trotter
      fqdn_warn = True
9159 9ac99fda Guido Trotter
      instance_name = self.op.instance_name
9160 9ac99fda Guido Trotter
9161 1b7bfbb7 Iustin Pop
    locked_nodes = self.acquired_locks[locking.LEVEL_NODE]
9162 1b7bfbb7 Iustin Pop
    exportlist = self.rpc.call_export_list(locked_nodes)
9163 9ac99fda Guido Trotter
    found = False
9164 9ac99fda Guido Trotter
    for node in exportlist:
9165 4c4e4e1e Iustin Pop
      msg = exportlist[node].fail_msg
9166 1b7bfbb7 Iustin Pop
      if msg:
9167 1b7bfbb7 Iustin Pop
        self.LogWarning("Failed to query node %s (continuing): %s", node, msg)
9168 781de953 Iustin Pop
        continue
9169 1b7bfbb7 Iustin Pop
      if instance_name in exportlist[node].payload:
9170 9ac99fda Guido Trotter
        found = True
9171 781de953 Iustin Pop
        result = self.rpc.call_export_remove(node, instance_name)
9172 4c4e4e1e Iustin Pop
        msg = result.fail_msg
9173 35fbcd11 Iustin Pop
        if msg:
9174 9a4f63d1 Iustin Pop
          logging.error("Could not remove export for instance %s"
9175 35fbcd11 Iustin Pop
                        " on node %s: %s", instance_name, node, msg)
9176 9ac99fda Guido Trotter
9177 9ac99fda Guido Trotter
    if fqdn_warn and not found:
9178 9ac99fda Guido Trotter
      feedback_fn("Export not found. If trying to remove an export belonging"
9179 9ac99fda Guido Trotter
                  " to a deleted instance please use its Fully Qualified"
9180 9ac99fda Guido Trotter
                  " Domain Name.")
9181 9ac99fda Guido Trotter
9182 9ac99fda Guido Trotter
9183 fe267188 Iustin Pop
class TagsLU(NoHooksLU): # pylint: disable-msg=W0223
9184 5c947f38 Iustin Pop
  """Generic tags LU.
9185 5c947f38 Iustin Pop

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

9188 5c947f38 Iustin Pop
  """
9189 5c947f38 Iustin Pop
9190 8646adce Guido Trotter
  def ExpandNames(self):
9191 8646adce Guido Trotter
    self.needed_locks = {}
9192 8646adce Guido Trotter
    if self.op.kind == constants.TAG_NODE:
9193 cf26a87a Iustin Pop
      self.op.name = _ExpandNodeName(self.cfg, self.op.name)
9194 cf26a87a Iustin Pop
      self.needed_locks[locking.LEVEL_NODE] = self.op.name
9195 5c947f38 Iustin Pop
    elif self.op.kind == constants.TAG_INSTANCE:
9196 cf26a87a Iustin Pop
      self.op.name = _ExpandInstanceName(self.cfg, self.op.name)
9197 cf26a87a Iustin Pop
      self.needed_locks[locking.LEVEL_INSTANCE] = self.op.name
9198 8646adce Guido Trotter
9199 8646adce Guido Trotter
  def CheckPrereq(self):
9200 8646adce Guido Trotter
    """Check prerequisites.
9201 8646adce Guido Trotter

9202 8646adce Guido Trotter
    """
9203 8646adce Guido Trotter
    if self.op.kind == constants.TAG_CLUSTER:
9204 8646adce Guido Trotter
      self.target = self.cfg.GetClusterInfo()
9205 8646adce Guido Trotter
    elif self.op.kind == constants.TAG_NODE:
9206 8646adce Guido Trotter
      self.target = self.cfg.GetNodeInfo(self.op.name)
9207 8646adce Guido Trotter
    elif self.op.kind == constants.TAG_INSTANCE:
9208 8646adce Guido Trotter
      self.target = self.cfg.GetInstanceInfo(self.op.name)
9209 5c947f38 Iustin Pop
    else:
9210 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Wrong tag type requested (%s)" %
9211 5c983ee5 Iustin Pop
                                 str(self.op.kind), errors.ECODE_INVAL)
9212 5c947f38 Iustin Pop
9213 5c947f38 Iustin Pop
9214 5c947f38 Iustin Pop
class LUGetTags(TagsLU):
9215 5c947f38 Iustin Pop
  """Returns the tags of a given object.
9216 5c947f38 Iustin Pop

9217 5c947f38 Iustin Pop
  """
9218 5c947f38 Iustin Pop
  _OP_REQP = ["kind", "name"]
9219 8646adce Guido Trotter
  REQ_BGL = False
9220 5c947f38 Iustin Pop
9221 5c947f38 Iustin Pop
  def Exec(self, feedback_fn):
9222 5c947f38 Iustin Pop
    """Returns the tag list.
9223 5c947f38 Iustin Pop

9224 5c947f38 Iustin Pop
    """
9225 5d414478 Oleksiy Mishchenko
    return list(self.target.GetTags())
9226 5c947f38 Iustin Pop
9227 5c947f38 Iustin Pop
9228 73415719 Iustin Pop
class LUSearchTags(NoHooksLU):
9229 73415719 Iustin Pop
  """Searches the tags for a given pattern.
9230 73415719 Iustin Pop

9231 73415719 Iustin Pop
  """
9232 73415719 Iustin Pop
  _OP_REQP = ["pattern"]
9233 8646adce Guido Trotter
  REQ_BGL = False
9234 8646adce Guido Trotter
9235 8646adce Guido Trotter
  def ExpandNames(self):
9236 8646adce Guido Trotter
    self.needed_locks = {}
9237 73415719 Iustin Pop
9238 73415719 Iustin Pop
  def CheckPrereq(self):
9239 73415719 Iustin Pop
    """Check prerequisites.
9240 73415719 Iustin Pop

9241 73415719 Iustin Pop
    This checks the pattern passed for validity by compiling it.
9242 73415719 Iustin Pop

9243 73415719 Iustin Pop
    """
9244 73415719 Iustin Pop
    try:
9245 73415719 Iustin Pop
      self.re = re.compile(self.op.pattern)
9246 73415719 Iustin Pop
    except re.error, err:
9247 73415719 Iustin Pop
      raise errors.OpPrereqError("Invalid search pattern '%s': %s" %
9248 5c983ee5 Iustin Pop
                                 (self.op.pattern, err), errors.ECODE_INVAL)
9249 73415719 Iustin Pop
9250 73415719 Iustin Pop
  def Exec(self, feedback_fn):
9251 73415719 Iustin Pop
    """Returns the tag list.
9252 73415719 Iustin Pop

9253 73415719 Iustin Pop
    """
9254 73415719 Iustin Pop
    cfg = self.cfg
9255 73415719 Iustin Pop
    tgts = [("/cluster", cfg.GetClusterInfo())]
9256 8646adce Guido Trotter
    ilist = cfg.GetAllInstancesInfo().values()
9257 73415719 Iustin Pop
    tgts.extend([("/instances/%s" % i.name, i) for i in ilist])
9258 8646adce Guido Trotter
    nlist = cfg.GetAllNodesInfo().values()
9259 73415719 Iustin Pop
    tgts.extend([("/nodes/%s" % n.name, n) for n in nlist])
9260 73415719 Iustin Pop
    results = []
9261 73415719 Iustin Pop
    for path, target in tgts:
9262 73415719 Iustin Pop
      for tag in target.GetTags():
9263 73415719 Iustin Pop
        if self.re.search(tag):
9264 73415719 Iustin Pop
          results.append((path, tag))
9265 73415719 Iustin Pop
    return results
9266 73415719 Iustin Pop
9267 73415719 Iustin Pop
9268 f27302fa Iustin Pop
class LUAddTags(TagsLU):
9269 5c947f38 Iustin Pop
  """Sets a tag on a given object.
9270 5c947f38 Iustin Pop

9271 5c947f38 Iustin Pop
  """
9272 f27302fa Iustin Pop
  _OP_REQP = ["kind", "name", "tags"]
9273 8646adce Guido Trotter
  REQ_BGL = False
9274 5c947f38 Iustin Pop
9275 5c947f38 Iustin Pop
  def CheckPrereq(self):
9276 5c947f38 Iustin Pop
    """Check prerequisites.
9277 5c947f38 Iustin Pop

9278 5c947f38 Iustin Pop
    This checks the type and length of the tag name and value.
9279 5c947f38 Iustin Pop

9280 5c947f38 Iustin Pop
    """
9281 5c947f38 Iustin Pop
    TagsLU.CheckPrereq(self)
9282 f27302fa Iustin Pop
    for tag in self.op.tags:
9283 f27302fa Iustin Pop
      objects.TaggableObject.ValidateTag(tag)
9284 5c947f38 Iustin Pop
9285 5c947f38 Iustin Pop
  def Exec(self, feedback_fn):
9286 5c947f38 Iustin Pop
    """Sets the tag.
9287 5c947f38 Iustin Pop

9288 5c947f38 Iustin Pop
    """
9289 5c947f38 Iustin Pop
    try:
9290 f27302fa Iustin Pop
      for tag in self.op.tags:
9291 f27302fa Iustin Pop
        self.target.AddTag(tag)
9292 5c947f38 Iustin Pop
    except errors.TagError, err:
9293 3ecf6786 Iustin Pop
      raise errors.OpExecError("Error while setting tag: %s" % str(err))
9294 159d4ec6 Iustin Pop
    self.cfg.Update(self.target, feedback_fn)
9295 5c947f38 Iustin Pop
9296 5c947f38 Iustin Pop
9297 f27302fa Iustin Pop
class LUDelTags(TagsLU):
9298 f27302fa Iustin Pop
  """Delete a list of tags from a given object.
9299 5c947f38 Iustin Pop

9300 5c947f38 Iustin Pop
  """
9301 f27302fa Iustin Pop
  _OP_REQP = ["kind", "name", "tags"]
9302 8646adce Guido Trotter
  REQ_BGL = False
9303 5c947f38 Iustin Pop
9304 5c947f38 Iustin Pop
  def CheckPrereq(self):
9305 5c947f38 Iustin Pop
    """Check prerequisites.
9306 5c947f38 Iustin Pop

9307 5c947f38 Iustin Pop
    This checks that we have the given tag.
9308 5c947f38 Iustin Pop

9309 5c947f38 Iustin Pop
    """
9310 5c947f38 Iustin Pop
    TagsLU.CheckPrereq(self)
9311 f27302fa Iustin Pop
    for tag in self.op.tags:
9312 f27302fa Iustin Pop
      objects.TaggableObject.ValidateTag(tag)
9313 f27302fa Iustin Pop
    del_tags = frozenset(self.op.tags)
9314 f27302fa Iustin Pop
    cur_tags = self.target.GetTags()
9315 f27302fa Iustin Pop
    if not del_tags <= cur_tags:
9316 f27302fa Iustin Pop
      diff_tags = del_tags - cur_tags
9317 f27302fa Iustin Pop
      diff_names = ["'%s'" % tag for tag in diff_tags]
9318 f27302fa Iustin Pop
      diff_names.sort()
9319 f27302fa Iustin Pop
      raise errors.OpPrereqError("Tag(s) %s not found" %
9320 5c983ee5 Iustin Pop
                                 (",".join(diff_names)), errors.ECODE_NOENT)
9321 5c947f38 Iustin Pop
9322 5c947f38 Iustin Pop
  def Exec(self, feedback_fn):
9323 5c947f38 Iustin Pop
    """Remove the tag from the object.
9324 5c947f38 Iustin Pop

9325 5c947f38 Iustin Pop
    """
9326 f27302fa Iustin Pop
    for tag in self.op.tags:
9327 f27302fa Iustin Pop
      self.target.RemoveTag(tag)
9328 159d4ec6 Iustin Pop
    self.cfg.Update(self.target, feedback_fn)
9329 06009e27 Iustin Pop
9330 0eed6e61 Guido Trotter
9331 06009e27 Iustin Pop
class LUTestDelay(NoHooksLU):
9332 06009e27 Iustin Pop
  """Sleep for a specified amount of time.
9333 06009e27 Iustin Pop

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

9337 06009e27 Iustin Pop
  """
9338 06009e27 Iustin Pop
  _OP_REQP = ["duration", "on_master", "on_nodes"]
9339 fbe9022f Guido Trotter
  REQ_BGL = False
9340 06009e27 Iustin Pop
9341 fbe9022f Guido Trotter
  def ExpandNames(self):
9342 fbe9022f Guido Trotter
    """Expand names and set required locks.
9343 06009e27 Iustin Pop

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

9346 06009e27 Iustin Pop
    """
9347 fbe9022f Guido Trotter
    self.needed_locks = {}
9348 06009e27 Iustin Pop
    if self.op.on_nodes:
9349 fbe9022f Guido Trotter
      # _GetWantedNodes can be used here, but is not always appropriate to use
9350 fbe9022f Guido Trotter
      # this way in ExpandNames. Check LogicalUnit.ExpandNames docstring for
9351 fbe9022f Guido Trotter
      # more information.
9352 06009e27 Iustin Pop
      self.op.on_nodes = _GetWantedNodes(self, self.op.on_nodes)
9353 fbe9022f Guido Trotter
      self.needed_locks[locking.LEVEL_NODE] = self.op.on_nodes
9354 fbe9022f Guido Trotter
9355 fbe9022f Guido Trotter
  def CheckPrereq(self):
9356 fbe9022f Guido Trotter
    """Check prerequisites.
9357 fbe9022f Guido Trotter

9358 fbe9022f Guido Trotter
    """
9359 06009e27 Iustin Pop
9360 06009e27 Iustin Pop
  def Exec(self, feedback_fn):
9361 06009e27 Iustin Pop
    """Do the actual sleep.
9362 06009e27 Iustin Pop

9363 06009e27 Iustin Pop
    """
9364 06009e27 Iustin Pop
    if self.op.on_master:
9365 06009e27 Iustin Pop
      if not utils.TestDelay(self.op.duration):
9366 06009e27 Iustin Pop
        raise errors.OpExecError("Error during master delay test")
9367 06009e27 Iustin Pop
    if self.op.on_nodes:
9368 72737a7f Iustin Pop
      result = self.rpc.call_test_delay(self.op.on_nodes, self.op.duration)
9369 06009e27 Iustin Pop
      for node, node_result in result.items():
9370 4c4e4e1e Iustin Pop
        node_result.Raise("Failure during rpc call to node %s" % node)
9371 d61df03e Iustin Pop
9372 d61df03e Iustin Pop
9373 d1c2dd75 Iustin Pop
class IAllocator(object):
9374 d1c2dd75 Iustin Pop
  """IAllocator framework.
9375 d61df03e Iustin Pop

9376 d1c2dd75 Iustin Pop
  An IAllocator instance has three sets of attributes:
9377 d6a02168 Michael Hanselmann
    - cfg that is needed to query the cluster
9378 d1c2dd75 Iustin Pop
    - input data (all members of the _KEYS class attribute are required)
9379 d1c2dd75 Iustin Pop
    - four buffer attributes (in|out_data|text), that represent the
9380 d1c2dd75 Iustin Pop
      input (to the external script) in text and data structure format,
9381 d1c2dd75 Iustin Pop
      and the output from it, again in two formats
9382 d1c2dd75 Iustin Pop
    - the result variables from the script (success, info, nodes) for
9383 d1c2dd75 Iustin Pop
      easy usage
9384 d61df03e Iustin Pop

9385 d61df03e Iustin Pop
  """
9386 7260cfbe Iustin Pop
  # pylint: disable-msg=R0902
9387 7260cfbe Iustin Pop
  # lots of instance attributes
9388 29859cb7 Iustin Pop
  _ALLO_KEYS = [
9389 8d3f86a0 Iustin Pop
    "name", "mem_size", "disks", "disk_template",
9390 8cc7e742 Guido Trotter
    "os", "tags", "nics", "vcpus", "hypervisor",
9391 d1c2dd75 Iustin Pop
    ]
9392 29859cb7 Iustin Pop
  _RELO_KEYS = [
9393 8d3f86a0 Iustin Pop
    "name", "relocate_from",
9394 29859cb7 Iustin Pop
    ]
9395 7f60a422 Iustin Pop
  _EVAC_KEYS = [
9396 7f60a422 Iustin Pop
    "evac_nodes",
9397 7f60a422 Iustin Pop
    ]
9398 d1c2dd75 Iustin Pop
9399 8d3f86a0 Iustin Pop
  def __init__(self, cfg, rpc, mode, **kwargs):
9400 923ddac0 Michael Hanselmann
    self.cfg = cfg
9401 923ddac0 Michael Hanselmann
    self.rpc = rpc
9402 d1c2dd75 Iustin Pop
    # init buffer variables
9403 d1c2dd75 Iustin Pop
    self.in_text = self.out_text = self.in_data = self.out_data = None
9404 d1c2dd75 Iustin Pop
    # init all input fields so that pylint is happy
9405 29859cb7 Iustin Pop
    self.mode = mode
9406 d1c2dd75 Iustin Pop
    self.mem_size = self.disks = self.disk_template = None
9407 d1c2dd75 Iustin Pop
    self.os = self.tags = self.nics = self.vcpus = None
9408 a0add446 Iustin Pop
    self.hypervisor = None
9409 29859cb7 Iustin Pop
    self.relocate_from = None
9410 8d3f86a0 Iustin Pop
    self.name = None
9411 7f60a422 Iustin Pop
    self.evac_nodes = None
9412 27579978 Iustin Pop
    # computed fields
9413 27579978 Iustin Pop
    self.required_nodes = None
9414 d1c2dd75 Iustin Pop
    # init result fields
9415 680f0a89 Iustin Pop
    self.success = self.info = self.result = None
9416 29859cb7 Iustin Pop
    if self.mode == constants.IALLOCATOR_MODE_ALLOC:
9417 29859cb7 Iustin Pop
      keyset = self._ALLO_KEYS
9418 9757cc90 Iustin Pop
      fn = self._AddNewInstance
9419 29859cb7 Iustin Pop
    elif self.mode == constants.IALLOCATOR_MODE_RELOC:
9420 29859cb7 Iustin Pop
      keyset = self._RELO_KEYS
9421 9757cc90 Iustin Pop
      fn = self._AddRelocateInstance
9422 7f60a422 Iustin Pop
    elif self.mode == constants.IALLOCATOR_MODE_MEVAC:
9423 7f60a422 Iustin Pop
      keyset = self._EVAC_KEYS
9424 7f60a422 Iustin Pop
      fn = self._AddEvacuateNodes
9425 29859cb7 Iustin Pop
    else:
9426 29859cb7 Iustin Pop
      raise errors.ProgrammerError("Unknown mode '%s' passed to the"
9427 29859cb7 Iustin Pop
                                   " IAllocator" % self.mode)
9428 d1c2dd75 Iustin Pop
    for key in kwargs:
9429 29859cb7 Iustin Pop
      if key not in keyset:
9430 d1c2dd75 Iustin Pop
        raise errors.ProgrammerError("Invalid input parameter '%s' to"
9431 d1c2dd75 Iustin Pop
                                     " IAllocator" % key)
9432 d1c2dd75 Iustin Pop
      setattr(self, key, kwargs[key])
9433 7f60a422 Iustin Pop
9434 29859cb7 Iustin Pop
    for key in keyset:
9435 d1c2dd75 Iustin Pop
      if key not in kwargs:
9436 d1c2dd75 Iustin Pop
        raise errors.ProgrammerError("Missing input parameter '%s' to"
9437 d1c2dd75 Iustin Pop
                                     " IAllocator" % key)
9438 9757cc90 Iustin Pop
    self._BuildInputData(fn)
9439 d1c2dd75 Iustin Pop
9440 d1c2dd75 Iustin Pop
  def _ComputeClusterData(self):
9441 d1c2dd75 Iustin Pop
    """Compute the generic allocator input data.
9442 d1c2dd75 Iustin Pop

9443 d1c2dd75 Iustin Pop
    This is the data that is independent of the actual operation.
9444 d1c2dd75 Iustin Pop

9445 d1c2dd75 Iustin Pop
    """
9446 923ddac0 Michael Hanselmann
    cfg = self.cfg
9447 e69d05fd Iustin Pop
    cluster_info = cfg.GetClusterInfo()
9448 d1c2dd75 Iustin Pop
    # cluster data
9449 d1c2dd75 Iustin Pop
    data = {
9450 77031881 Iustin Pop
      "version": constants.IALLOCATOR_VERSION,
9451 72737a7f Iustin Pop
      "cluster_name": cfg.GetClusterName(),
9452 e69d05fd Iustin Pop
      "cluster_tags": list(cluster_info.GetTags()),
9453 1325da74 Iustin Pop
      "enabled_hypervisors": list(cluster_info.enabled_hypervisors),
9454 d1c2dd75 Iustin Pop
      # we don't have job IDs
9455 d61df03e Iustin Pop
      }
9456 b57e9819 Guido Trotter
    iinfo = cfg.GetAllInstancesInfo().values()
9457 b57e9819 Guido Trotter
    i_list = [(inst, cluster_info.FillBE(inst)) for inst in iinfo]
9458 6286519f Iustin Pop
9459 d1c2dd75 Iustin Pop
    # node data
9460 d1c2dd75 Iustin Pop
    node_results = {}
9461 d1c2dd75 Iustin Pop
    node_list = cfg.GetNodeList()
9462 8cc7e742 Guido Trotter
9463 8cc7e742 Guido Trotter
    if self.mode == constants.IALLOCATOR_MODE_ALLOC:
9464 a0add446 Iustin Pop
      hypervisor_name = self.hypervisor
9465 8cc7e742 Guido Trotter
    elif self.mode == constants.IALLOCATOR_MODE_RELOC:
9466 a0add446 Iustin Pop
      hypervisor_name = cfg.GetInstanceInfo(self.name).hypervisor
9467 7f60a422 Iustin Pop
    elif self.mode == constants.IALLOCATOR_MODE_MEVAC:
9468 7f60a422 Iustin Pop
      hypervisor_name = cluster_info.enabled_hypervisors[0]
9469 8cc7e742 Guido Trotter
9470 923ddac0 Michael Hanselmann
    node_data = self.rpc.call_node_info(node_list, cfg.GetVGName(),
9471 923ddac0 Michael Hanselmann
                                        hypervisor_name)
9472 923ddac0 Michael Hanselmann
    node_iinfo = \
9473 923ddac0 Michael Hanselmann
      self.rpc.call_all_instances_info(node_list,
9474 923ddac0 Michael Hanselmann
                                       cluster_info.enabled_hypervisors)
9475 1325da74 Iustin Pop
    for nname, nresult in node_data.items():
9476 1325da74 Iustin Pop
      # first fill in static (config-based) values
9477 d1c2dd75 Iustin Pop
      ninfo = cfg.GetNodeInfo(nname)
9478 d1c2dd75 Iustin Pop
      pnr = {
9479 d1c2dd75 Iustin Pop
        "tags": list(ninfo.GetTags()),
9480 d1c2dd75 Iustin Pop
        "primary_ip": ninfo.primary_ip,
9481 d1c2dd75 Iustin Pop
        "secondary_ip": ninfo.secondary_ip,
9482 fc0fe88c Iustin Pop
        "offline": ninfo.offline,
9483 0b2454b9 Iustin Pop
        "drained": ninfo.drained,
9484 1325da74 Iustin Pop
        "master_candidate": ninfo.master_candidate,
9485 d1c2dd75 Iustin Pop
        }
9486 1325da74 Iustin Pop
9487 0d853843 Iustin Pop
      if not (ninfo.offline or ninfo.drained):
9488 4c4e4e1e Iustin Pop
        nresult.Raise("Can't get data for node %s" % nname)
9489 4c4e4e1e Iustin Pop
        node_iinfo[nname].Raise("Can't get node instance info from node %s" %
9490 4c4e4e1e Iustin Pop
                                nname)
9491 070e998b Iustin Pop
        remote_info = nresult.payload
9492 b142ef15 Iustin Pop
9493 1325da74 Iustin Pop
        for attr in ['memory_total', 'memory_free', 'memory_dom0',
9494 1325da74 Iustin Pop
                     'vg_size', 'vg_free', 'cpu_total']:
9495 1325da74 Iustin Pop
          if attr not in remote_info:
9496 1325da74 Iustin Pop
            raise errors.OpExecError("Node '%s' didn't return attribute"
9497 1325da74 Iustin Pop
                                     " '%s'" % (nname, attr))
9498 070e998b Iustin Pop
          if not isinstance(remote_info[attr], int):
9499 1325da74 Iustin Pop
            raise errors.OpExecError("Node '%s' returned invalid value"
9500 070e998b Iustin Pop
                                     " for '%s': %s" %
9501 070e998b Iustin Pop
                                     (nname, attr, remote_info[attr]))
9502 1325da74 Iustin Pop
        # compute memory used by primary instances
9503 1325da74 Iustin Pop
        i_p_mem = i_p_up_mem = 0
9504 1325da74 Iustin Pop
        for iinfo, beinfo in i_list:
9505 1325da74 Iustin Pop
          if iinfo.primary_node == nname:
9506 1325da74 Iustin Pop
            i_p_mem += beinfo[constants.BE_MEMORY]
9507 2fa74ef4 Iustin Pop
            if iinfo.name not in node_iinfo[nname].payload:
9508 1325da74 Iustin Pop
              i_used_mem = 0
9509 1325da74 Iustin Pop
            else:
9510 2fa74ef4 Iustin Pop
              i_used_mem = int(node_iinfo[nname].payload[iinfo.name]['memory'])
9511 1325da74 Iustin Pop
            i_mem_diff = beinfo[constants.BE_MEMORY] - i_used_mem
9512 1325da74 Iustin Pop
            remote_info['memory_free'] -= max(0, i_mem_diff)
9513 1325da74 Iustin Pop
9514 1325da74 Iustin Pop
            if iinfo.admin_up:
9515 1325da74 Iustin Pop
              i_p_up_mem += beinfo[constants.BE_MEMORY]
9516 1325da74 Iustin Pop
9517 1325da74 Iustin Pop
        # compute memory used by instances
9518 1325da74 Iustin Pop
        pnr_dyn = {
9519 1325da74 Iustin Pop
          "total_memory": remote_info['memory_total'],
9520 1325da74 Iustin Pop
          "reserved_memory": remote_info['memory_dom0'],
9521 1325da74 Iustin Pop
          "free_memory": remote_info['memory_free'],
9522 1325da74 Iustin Pop
          "total_disk": remote_info['vg_size'],
9523 1325da74 Iustin Pop
          "free_disk": remote_info['vg_free'],
9524 1325da74 Iustin Pop
          "total_cpus": remote_info['cpu_total'],
9525 1325da74 Iustin Pop
          "i_pri_memory": i_p_mem,
9526 1325da74 Iustin Pop
          "i_pri_up_memory": i_p_up_mem,
9527 1325da74 Iustin Pop
          }
9528 1325da74 Iustin Pop
        pnr.update(pnr_dyn)
9529 1325da74 Iustin Pop
9530 d1c2dd75 Iustin Pop
      node_results[nname] = pnr
9531 d1c2dd75 Iustin Pop
    data["nodes"] = node_results
9532 d1c2dd75 Iustin Pop
9533 d1c2dd75 Iustin Pop
    # instance data
9534 d1c2dd75 Iustin Pop
    instance_data = {}
9535 338e51e8 Iustin Pop
    for iinfo, beinfo in i_list:
9536 a9fe7e8f Guido Trotter
      nic_data = []
9537 a9fe7e8f Guido Trotter
      for nic in iinfo.nics:
9538 a9fe7e8f Guido Trotter
        filled_params = objects.FillDict(
9539 a9fe7e8f Guido Trotter
            cluster_info.nicparams[constants.PP_DEFAULT],
9540 a9fe7e8f Guido Trotter
            nic.nicparams)
9541 a9fe7e8f Guido Trotter
        nic_dict = {"mac": nic.mac,
9542 a9fe7e8f Guido Trotter
                    "ip": nic.ip,
9543 a9fe7e8f Guido Trotter
                    "mode": filled_params[constants.NIC_MODE],
9544 a9fe7e8f Guido Trotter
                    "link": filled_params[constants.NIC_LINK],
9545 a9fe7e8f Guido Trotter
                   }
9546 a9fe7e8f Guido Trotter
        if filled_params[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
9547 a9fe7e8f Guido Trotter
          nic_dict["bridge"] = filled_params[constants.NIC_LINK]
9548 a9fe7e8f Guido Trotter
        nic_data.append(nic_dict)
9549 d1c2dd75 Iustin Pop
      pir = {
9550 d1c2dd75 Iustin Pop
        "tags": list(iinfo.GetTags()),
9551 1325da74 Iustin Pop
        "admin_up": iinfo.admin_up,
9552 338e51e8 Iustin Pop
        "vcpus": beinfo[constants.BE_VCPUS],
9553 338e51e8 Iustin Pop
        "memory": beinfo[constants.BE_MEMORY],
9554 d1c2dd75 Iustin Pop
        "os": iinfo.os,
9555 1325da74 Iustin Pop
        "nodes": [iinfo.primary_node] + list(iinfo.secondary_nodes),
9556 d1c2dd75 Iustin Pop
        "nics": nic_data,
9557 1325da74 Iustin Pop
        "disks": [{"size": dsk.size, "mode": dsk.mode} for dsk in iinfo.disks],
9558 d1c2dd75 Iustin Pop
        "disk_template": iinfo.disk_template,
9559 e69d05fd Iustin Pop
        "hypervisor": iinfo.hypervisor,
9560 d1c2dd75 Iustin Pop
        }
9561 88ae4f85 Iustin Pop
      pir["disk_space_total"] = _ComputeDiskSize(iinfo.disk_template,
9562 88ae4f85 Iustin Pop
                                                 pir["disks"])
9563 768f0a80 Iustin Pop
      instance_data[iinfo.name] = pir
9564 d61df03e Iustin Pop
9565 d1c2dd75 Iustin Pop
    data["instances"] = instance_data
9566 d61df03e Iustin Pop
9567 d1c2dd75 Iustin Pop
    self.in_data = data
9568 d61df03e Iustin Pop
9569 d1c2dd75 Iustin Pop
  def _AddNewInstance(self):
9570 d1c2dd75 Iustin Pop
    """Add new instance data to allocator structure.
9571 d61df03e Iustin Pop

9572 d1c2dd75 Iustin Pop
    This in combination with _AllocatorGetClusterData will create the
9573 d1c2dd75 Iustin Pop
    correct structure needed as input for the allocator.
9574 d61df03e Iustin Pop

9575 d1c2dd75 Iustin Pop
    The checks for the completeness of the opcode must have already been
9576 d1c2dd75 Iustin Pop
    done.
9577 d61df03e Iustin Pop

9578 d1c2dd75 Iustin Pop
    """
9579 dafc7302 Guido Trotter
    disk_space = _ComputeDiskSize(self.disk_template, self.disks)
9580 d1c2dd75 Iustin Pop
9581 27579978 Iustin Pop
    if self.disk_template in constants.DTS_NET_MIRROR:
9582 27579978 Iustin Pop
      self.required_nodes = 2
9583 27579978 Iustin Pop
    else:
9584 27579978 Iustin Pop
      self.required_nodes = 1
9585 d1c2dd75 Iustin Pop
    request = {
9586 d1c2dd75 Iustin Pop
      "name": self.name,
9587 d1c2dd75 Iustin Pop
      "disk_template": self.disk_template,
9588 d1c2dd75 Iustin Pop
      "tags": self.tags,
9589 d1c2dd75 Iustin Pop
      "os": self.os,
9590 d1c2dd75 Iustin Pop
      "vcpus": self.vcpus,
9591 d1c2dd75 Iustin Pop
      "memory": self.mem_size,
9592 d1c2dd75 Iustin Pop
      "disks": self.disks,
9593 d1c2dd75 Iustin Pop
      "disk_space_total": disk_space,
9594 d1c2dd75 Iustin Pop
      "nics": self.nics,
9595 27579978 Iustin Pop
      "required_nodes": self.required_nodes,
9596 d1c2dd75 Iustin Pop
      }
9597 9757cc90 Iustin Pop
    return request
9598 298fe380 Iustin Pop
9599 d1c2dd75 Iustin Pop
  def _AddRelocateInstance(self):
9600 d1c2dd75 Iustin Pop
    """Add relocate instance data to allocator structure.
9601 298fe380 Iustin Pop

9602 d1c2dd75 Iustin Pop
    This in combination with _IAllocatorGetClusterData will create the
9603 d1c2dd75 Iustin Pop
    correct structure needed as input for the allocator.
9604 d61df03e Iustin Pop

9605 d1c2dd75 Iustin Pop
    The checks for the completeness of the opcode must have already been
9606 d1c2dd75 Iustin Pop
    done.
9607 d61df03e Iustin Pop

9608 d1c2dd75 Iustin Pop
    """
9609 923ddac0 Michael Hanselmann
    instance = self.cfg.GetInstanceInfo(self.name)
9610 27579978 Iustin Pop
    if instance is None:
9611 27579978 Iustin Pop
      raise errors.ProgrammerError("Unknown instance '%s' passed to"
9612 27579978 Iustin Pop
                                   " IAllocator" % self.name)
9613 27579978 Iustin Pop
9614 27579978 Iustin Pop
    if instance.disk_template not in constants.DTS_NET_MIRROR:
9615 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Can't relocate non-mirrored instances",
9616 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
9617 27579978 Iustin Pop
9618 2a139bb0 Iustin Pop
    if len(instance.secondary_nodes) != 1:
9619 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Instance has not exactly one secondary node",
9620 5c983ee5 Iustin Pop
                                 errors.ECODE_STATE)
9621 2a139bb0 Iustin Pop
9622 27579978 Iustin Pop
    self.required_nodes = 1
9623 dafc7302 Guido Trotter
    disk_sizes = [{'size': disk.size} for disk in instance.disks]
9624 dafc7302 Guido Trotter
    disk_space = _ComputeDiskSize(instance.disk_template, disk_sizes)
9625 27579978 Iustin Pop
9626 d1c2dd75 Iustin Pop
    request = {
9627 d1c2dd75 Iustin Pop
      "name": self.name,
9628 27579978 Iustin Pop
      "disk_space_total": disk_space,
9629 27579978 Iustin Pop
      "required_nodes": self.required_nodes,
9630 29859cb7 Iustin Pop
      "relocate_from": self.relocate_from,
9631 d1c2dd75 Iustin Pop
      }
9632 9757cc90 Iustin Pop
    return request
9633 d61df03e Iustin Pop
9634 7f60a422 Iustin Pop
  def _AddEvacuateNodes(self):
9635 7f60a422 Iustin Pop
    """Add evacuate nodes data to allocator structure.
9636 7f60a422 Iustin Pop

9637 7f60a422 Iustin Pop
    """
9638 7f60a422 Iustin Pop
    request = {
9639 7f60a422 Iustin Pop
      "evac_nodes": self.evac_nodes
9640 7f60a422 Iustin Pop
      }
9641 7f60a422 Iustin Pop
    return request
9642 7f60a422 Iustin Pop
9643 9757cc90 Iustin Pop
  def _BuildInputData(self, fn):
9644 d1c2dd75 Iustin Pop
    """Build input data structures.
9645 d61df03e Iustin Pop

9646 d1c2dd75 Iustin Pop
    """
9647 d1c2dd75 Iustin Pop
    self._ComputeClusterData()
9648 d61df03e Iustin Pop
9649 9757cc90 Iustin Pop
    request = fn()
9650 9757cc90 Iustin Pop
    request["type"] = self.mode
9651 9757cc90 Iustin Pop
    self.in_data["request"] = request
9652 d61df03e Iustin Pop
9653 d1c2dd75 Iustin Pop
    self.in_text = serializer.Dump(self.in_data)
9654 d61df03e Iustin Pop
9655 72737a7f Iustin Pop
  def Run(self, name, validate=True, call_fn=None):
9656 d1c2dd75 Iustin Pop
    """Run an instance allocator and return the results.
9657 298fe380 Iustin Pop

9658 d1c2dd75 Iustin Pop
    """
9659 72737a7f Iustin Pop
    if call_fn is None:
9660 923ddac0 Michael Hanselmann
      call_fn = self.rpc.call_iallocator_runner
9661 298fe380 Iustin Pop
9662 923ddac0 Michael Hanselmann
    result = call_fn(self.cfg.GetMasterNode(), name, self.in_text)
9663 4c4e4e1e Iustin Pop
    result.Raise("Failure while running the iallocator script")
9664 8d528b7c Iustin Pop
9665 87f5c298 Iustin Pop
    self.out_text = result.payload
9666 d1c2dd75 Iustin Pop
    if validate:
9667 d1c2dd75 Iustin Pop
      self._ValidateResult()
9668 298fe380 Iustin Pop
9669 d1c2dd75 Iustin Pop
  def _ValidateResult(self):
9670 d1c2dd75 Iustin Pop
    """Process the allocator results.
9671 538475ca Iustin Pop

9672 d1c2dd75 Iustin Pop
    This will process and if successful save the result in
9673 d1c2dd75 Iustin Pop
    self.out_data and the other parameters.
9674 538475ca Iustin Pop

9675 d1c2dd75 Iustin Pop
    """
9676 d1c2dd75 Iustin Pop
    try:
9677 d1c2dd75 Iustin Pop
      rdict = serializer.Load(self.out_text)
9678 d1c2dd75 Iustin Pop
    except Exception, err:
9679 d1c2dd75 Iustin Pop
      raise errors.OpExecError("Can't parse iallocator results: %s" % str(err))
9680 d1c2dd75 Iustin Pop
9681 d1c2dd75 Iustin Pop
    if not isinstance(rdict, dict):
9682 d1c2dd75 Iustin Pop
      raise errors.OpExecError("Can't parse iallocator results: not a dict")
9683 538475ca Iustin Pop
9684 680f0a89 Iustin Pop
    # TODO: remove backwards compatiblity in later versions
9685 680f0a89 Iustin Pop
    if "nodes" in rdict and "result" not in rdict:
9686 680f0a89 Iustin Pop
      rdict["result"] = rdict["nodes"]
9687 680f0a89 Iustin Pop
      del rdict["nodes"]
9688 680f0a89 Iustin Pop
9689 680f0a89 Iustin Pop
    for key in "success", "info", "result":
9690 d1c2dd75 Iustin Pop
      if key not in rdict:
9691 d1c2dd75 Iustin Pop
        raise errors.OpExecError("Can't parse iallocator results:"
9692 d1c2dd75 Iustin Pop
                                 " missing key '%s'" % key)
9693 d1c2dd75 Iustin Pop
      setattr(self, key, rdict[key])
9694 538475ca Iustin Pop
9695 680f0a89 Iustin Pop
    if not isinstance(rdict["result"], list):
9696 680f0a89 Iustin Pop
      raise errors.OpExecError("Can't parse iallocator results: 'result' key"
9697 d1c2dd75 Iustin Pop
                               " is not a list")
9698 d1c2dd75 Iustin Pop
    self.out_data = rdict
9699 538475ca Iustin Pop
9700 538475ca Iustin Pop
9701 d61df03e Iustin Pop
class LUTestAllocator(NoHooksLU):
9702 d61df03e Iustin Pop
  """Run allocator tests.
9703 d61df03e Iustin Pop

9704 d61df03e Iustin Pop
  This LU runs the allocator tests
9705 d61df03e Iustin Pop

9706 d61df03e Iustin Pop
  """
9707 d61df03e Iustin Pop
  _OP_REQP = ["direction", "mode", "name"]
9708 d61df03e Iustin Pop
9709 d61df03e Iustin Pop
  def CheckPrereq(self):
9710 d61df03e Iustin Pop
    """Check prerequisites.
9711 d61df03e Iustin Pop

9712 d61df03e Iustin Pop
    This checks the opcode parameters depending on the director and mode test.
9713 d61df03e Iustin Pop

9714 d61df03e Iustin Pop
    """
9715 298fe380 Iustin Pop
    if self.op.mode == constants.IALLOCATOR_MODE_ALLOC:
9716 d61df03e Iustin Pop
      for attr in ["name", "mem_size", "disks", "disk_template",
9717 d61df03e Iustin Pop
                   "os", "tags", "nics", "vcpus"]:
9718 d61df03e Iustin Pop
        if not hasattr(self.op, attr):
9719 d61df03e Iustin Pop
          raise errors.OpPrereqError("Missing attribute '%s' on opcode input" %
9720 5c983ee5 Iustin Pop
                                     attr, errors.ECODE_INVAL)
9721 d61df03e Iustin Pop
      iname = self.cfg.ExpandInstanceName(self.op.name)
9722 d61df03e Iustin Pop
      if iname is not None:
9723 d61df03e Iustin Pop
        raise errors.OpPrereqError("Instance '%s' already in the cluster" %
9724 5c983ee5 Iustin Pop
                                   iname, errors.ECODE_EXISTS)
9725 d61df03e Iustin Pop
      if not isinstance(self.op.nics, list):
9726 5c983ee5 Iustin Pop
        raise errors.OpPrereqError("Invalid parameter 'nics'",
9727 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
9728 d61df03e Iustin Pop
      for row in self.op.nics:
9729 d61df03e Iustin Pop
        if (not isinstance(row, dict) or
9730 d61df03e Iustin Pop
            "mac" not in row or
9731 d61df03e Iustin Pop
            "ip" not in row or
9732 d61df03e Iustin Pop
            "bridge" not in row):
9733 5c983ee5 Iustin Pop
          raise errors.OpPrereqError("Invalid contents of the 'nics'"
9734 5c983ee5 Iustin Pop
                                     " parameter", errors.ECODE_INVAL)
9735 d61df03e Iustin Pop
      if not isinstance(self.op.disks, list):
9736 5c983ee5 Iustin Pop
        raise errors.OpPrereqError("Invalid parameter 'disks'",
9737 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
9738 d61df03e Iustin Pop
      for row in self.op.disks:
9739 d61df03e Iustin Pop
        if (not isinstance(row, dict) or
9740 d61df03e Iustin Pop
            "size" not in row or
9741 d61df03e Iustin Pop
            not isinstance(row["size"], int) or
9742 d61df03e Iustin Pop
            "mode" not in row or
9743 d61df03e Iustin Pop
            row["mode"] not in ['r', 'w']):
9744 5c983ee5 Iustin Pop
          raise errors.OpPrereqError("Invalid contents of the 'disks'"
9745 5c983ee5 Iustin Pop
                                     " parameter", errors.ECODE_INVAL)
9746 8901997e Iustin Pop
      if not hasattr(self.op, "hypervisor") or self.op.hypervisor is None:
9747 8cc7e742 Guido Trotter
        self.op.hypervisor = self.cfg.GetHypervisorType()
9748 298fe380 Iustin Pop
    elif self.op.mode == constants.IALLOCATOR_MODE_RELOC:
9749 d61df03e Iustin Pop
      if not hasattr(self.op, "name"):
9750 5c983ee5 Iustin Pop
        raise errors.OpPrereqError("Missing attribute 'name' on opcode input",
9751 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
9752 cf26a87a Iustin Pop
      fname = _ExpandInstanceName(self.cfg, self.op.name)
9753 d61df03e Iustin Pop
      self.op.name = fname
9754 29859cb7 Iustin Pop
      self.relocate_from = self.cfg.GetInstanceInfo(fname).secondary_nodes
9755 823a72bc Iustin Pop
    elif self.op.mode == constants.IALLOCATOR_MODE_MEVAC:
9756 823a72bc Iustin Pop
      if not hasattr(self.op, "evac_nodes"):
9757 823a72bc Iustin Pop
        raise errors.OpPrereqError("Missing attribute 'evac_nodes' on"
9758 823a72bc Iustin Pop
                                   " opcode input", errors.ECODE_INVAL)
9759 d61df03e Iustin Pop
    else:
9760 d61df03e Iustin Pop
      raise errors.OpPrereqError("Invalid test allocator mode '%s'" %
9761 5c983ee5 Iustin Pop
                                 self.op.mode, errors.ECODE_INVAL)
9762 d61df03e Iustin Pop
9763 298fe380 Iustin Pop
    if self.op.direction == constants.IALLOCATOR_DIR_OUT:
9764 298fe380 Iustin Pop
      if not hasattr(self.op, "allocator") or self.op.allocator is None:
9765 5c983ee5 Iustin Pop
        raise errors.OpPrereqError("Missing allocator name",
9766 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
9767 298fe380 Iustin Pop
    elif self.op.direction != constants.IALLOCATOR_DIR_IN:
9768 d61df03e Iustin Pop
      raise errors.OpPrereqError("Wrong allocator test '%s'" %
9769 5c983ee5 Iustin Pop
                                 self.op.direction, errors.ECODE_INVAL)
9770 d61df03e Iustin Pop
9771 d61df03e Iustin Pop
  def Exec(self, feedback_fn):
9772 d61df03e Iustin Pop
    """Run the allocator test.
9773 d61df03e Iustin Pop

9774 d61df03e Iustin Pop
    """
9775 29859cb7 Iustin Pop
    if self.op.mode == constants.IALLOCATOR_MODE_ALLOC:
9776 923ddac0 Michael Hanselmann
      ial = IAllocator(self.cfg, self.rpc,
9777 29859cb7 Iustin Pop
                       mode=self.op.mode,
9778 29859cb7 Iustin Pop
                       name=self.op.name,
9779 29859cb7 Iustin Pop
                       mem_size=self.op.mem_size,
9780 29859cb7 Iustin Pop
                       disks=self.op.disks,
9781 29859cb7 Iustin Pop
                       disk_template=self.op.disk_template,
9782 29859cb7 Iustin Pop
                       os=self.op.os,
9783 29859cb7 Iustin Pop
                       tags=self.op.tags,
9784 29859cb7 Iustin Pop
                       nics=self.op.nics,
9785 29859cb7 Iustin Pop
                       vcpus=self.op.vcpus,
9786 8cc7e742 Guido Trotter
                       hypervisor=self.op.hypervisor,
9787 29859cb7 Iustin Pop
                       )
9788 823a72bc Iustin Pop
    elif self.op.mode == constants.IALLOCATOR_MODE_RELOC:
9789 923ddac0 Michael Hanselmann
      ial = IAllocator(self.cfg, self.rpc,
9790 29859cb7 Iustin Pop
                       mode=self.op.mode,
9791 29859cb7 Iustin Pop
                       name=self.op.name,
9792 29859cb7 Iustin Pop
                       relocate_from=list(self.relocate_from),
9793 29859cb7 Iustin Pop
                       )
9794 823a72bc Iustin Pop
    elif self.op.mode == constants.IALLOCATOR_MODE_MEVAC:
9795 823a72bc Iustin Pop
      ial = IAllocator(self.cfg, self.rpc,
9796 823a72bc Iustin Pop
                       mode=self.op.mode,
9797 823a72bc Iustin Pop
                       evac_nodes=self.op.evac_nodes)
9798 823a72bc Iustin Pop
    else:
9799 823a72bc Iustin Pop
      raise errors.ProgrammerError("Uncatched mode %s in"
9800 823a72bc Iustin Pop
                                   " LUTestAllocator.Exec", self.op.mode)
9801 d61df03e Iustin Pop
9802 298fe380 Iustin Pop
    if self.op.direction == constants.IALLOCATOR_DIR_IN:
9803 d1c2dd75 Iustin Pop
      result = ial.in_text
9804 298fe380 Iustin Pop
    else:
9805 d1c2dd75 Iustin Pop
      ial.Run(self.op.allocator, validate=False)
9806 d1c2dd75 Iustin Pop
      result = ial.out_text
9807 298fe380 Iustin Pop
    return result