Statistics
| Branch: | Tag: | Revision:

root / lib / cmdlib.py @ afa1386e

History | View | Annotate | Download (305.7 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 a8083063 Iustin Pop
# pylint: disable-msg=W0613,W0201
25 a8083063 Iustin Pop
26 a8083063 Iustin Pop
import os
27 a8083063 Iustin Pop
import os.path
28 a8083063 Iustin Pop
import time
29 a8083063 Iustin Pop
import re
30 a8083063 Iustin Pop
import platform
31 ffa1c0dc Iustin Pop
import logging
32 74409b12 Iustin Pop
import copy
33 a8083063 Iustin Pop
34 a8083063 Iustin Pop
from ganeti import ssh
35 a8083063 Iustin Pop
from ganeti import utils
36 a8083063 Iustin Pop
from ganeti import errors
37 a8083063 Iustin Pop
from ganeti import hypervisor
38 6048c986 Guido Trotter
from ganeti import locking
39 a8083063 Iustin Pop
from ganeti import constants
40 a8083063 Iustin Pop
from ganeti import objects
41 8d14b30d Iustin Pop
from ganeti import serializer
42 112f18a5 Iustin Pop
from ganeti import ssconf
43 d61df03e Iustin Pop
44 d61df03e Iustin Pop
45 a8083063 Iustin Pop
class LogicalUnit(object):
46 396e1b78 Michael Hanselmann
  """Logical Unit base class.
47 a8083063 Iustin Pop

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

57 05f86716 Guido Trotter
  Note that all commands require root permissions.
58 a8083063 Iustin Pop

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

62 a8083063 Iustin Pop
  """
63 a8083063 Iustin Pop
  HPATH = None
64 a8083063 Iustin Pop
  HTYPE = None
65 a8083063 Iustin Pop
  _OP_REQP = []
66 7e55040e Guido Trotter
  REQ_BGL = True
67 a8083063 Iustin Pop
68 72737a7f Iustin Pop
  def __init__(self, processor, op, context, rpc):
69 a8083063 Iustin Pop
    """Constructor for LogicalUnit.
70 a8083063 Iustin Pop

71 5bbd3f7f Michael Hanselmann
    This needs to be overridden in derived classes in order to check op
72 a8083063 Iustin Pop
    validity.
73 a8083063 Iustin Pop

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

110 c92b310a Michael Hanselmann
    """
111 c92b310a Michael Hanselmann
    if not self.__ssh:
112 6b0469d2 Iustin Pop
      self.__ssh = ssh.SshRunner(self.cfg.GetClusterName())
113 c92b310a Michael Hanselmann
    return self.__ssh
114 c92b310a Michael Hanselmann
115 c92b310a Michael Hanselmann
  ssh = property(fget=__GetSSH)
116 c92b310a Michael Hanselmann
117 4be4691d Iustin Pop
  def CheckArguments(self):
118 4be4691d Iustin Pop
    """Check syntactic validity for the opcode arguments.
119 4be4691d Iustin Pop

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

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

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

132 4be4691d Iustin Pop
    """
133 4be4691d Iustin Pop
    pass
134 4be4691d Iustin Pop
135 d465bdc8 Guido Trotter
  def ExpandNames(self):
136 d465bdc8 Guido Trotter
    """Expand names for this LU.
137 d465bdc8 Guido Trotter

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

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

147 e4376078 Iustin Pop
      - use an empty dict if you don't need any lock
148 e4376078 Iustin Pop
      - if you don't need any lock at a particular level omit that level
149 e4376078 Iustin Pop
      - don't put anything for the BGL level
150 e4376078 Iustin Pop
      - if you want all locks at a level use locking.ALL_SET as a value
151 d465bdc8 Guido Trotter

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

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

160 e4376078 Iustin Pop
    Examples::
161 e4376078 Iustin Pop

162 e4376078 Iustin Pop
      # Acquire all nodes and one instance
163 e4376078 Iustin Pop
      self.needed_locks = {
164 e4376078 Iustin Pop
        locking.LEVEL_NODE: locking.ALL_SET,
165 e4376078 Iustin Pop
        locking.LEVEL_INSTANCE: ['instance1.example.tld'],
166 e4376078 Iustin Pop
      }
167 e4376078 Iustin Pop
      # Acquire just two nodes
168 e4376078 Iustin Pop
      self.needed_locks = {
169 e4376078 Iustin Pop
        locking.LEVEL_NODE: ['node1.example.tld', 'node2.example.tld'],
170 e4376078 Iustin Pop
      }
171 e4376078 Iustin Pop
      # Acquire no locks
172 e4376078 Iustin Pop
      self.needed_locks = {} # No, you can't leave it to the default value None
173 d465bdc8 Guido Trotter

174 d465bdc8 Guido Trotter
    """
175 d465bdc8 Guido Trotter
    # The implementation of this method is mandatory only if the new LU is
176 d465bdc8 Guido Trotter
    # concurrent, so that old LUs don't need to be changed all at the same
177 d465bdc8 Guido Trotter
    # time.
178 d465bdc8 Guido Trotter
    if self.REQ_BGL:
179 d465bdc8 Guido Trotter
      self.needed_locks = {} # Exclusive LUs don't need locks.
180 d465bdc8 Guido Trotter
    else:
181 d465bdc8 Guido Trotter
      raise NotImplementedError
182 d465bdc8 Guido Trotter
183 fb8dcb62 Guido Trotter
  def DeclareLocks(self, level):
184 fb8dcb62 Guido Trotter
    """Declare LU locking needs for a level
185 fb8dcb62 Guido Trotter

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

193 fb8dcb62 Guido Trotter
    This function is only called if you have something already set in
194 fb8dcb62 Guido Trotter
    self.needed_locks for the level.
195 fb8dcb62 Guido Trotter

196 fb8dcb62 Guido Trotter
    @param level: Locking level which is going to be locked
197 fb8dcb62 Guido Trotter
    @type level: member of ganeti.locking.LEVELS
198 fb8dcb62 Guido Trotter

199 fb8dcb62 Guido Trotter
    """
200 fb8dcb62 Guido Trotter
201 a8083063 Iustin Pop
  def CheckPrereq(self):
202 a8083063 Iustin Pop
    """Check prerequisites for this LU.
203 a8083063 Iustin Pop

204 a8083063 Iustin Pop
    This method should check that the prerequisites for the execution
205 a8083063 Iustin Pop
    of this LU are fulfilled. It can do internode communication, but
206 a8083063 Iustin Pop
    it should be idempotent - no cluster or system changes are
207 a8083063 Iustin Pop
    allowed.
208 a8083063 Iustin Pop

209 a8083063 Iustin Pop
    The method should raise errors.OpPrereqError in case something is
210 a8083063 Iustin Pop
    not fulfilled. Its return value is ignored.
211 a8083063 Iustin Pop

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

215 a8083063 Iustin Pop
    """
216 3a012b41 Michael Hanselmann
    if self.tasklets is not None:
217 b4a9eb66 Michael Hanselmann
      for (idx, tl) in enumerate(self.tasklets):
218 abae1b2b Michael Hanselmann
        logging.debug("Checking prerequisites for tasklet %s/%s",
219 abae1b2b Michael Hanselmann
                      idx + 1, len(self.tasklets))
220 6fd35c4d Michael Hanselmann
        tl.CheckPrereq()
221 6fd35c4d Michael Hanselmann
    else:
222 6fd35c4d Michael Hanselmann
      raise NotImplementedError
223 a8083063 Iustin Pop
224 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
225 a8083063 Iustin Pop
    """Execute the LU.
226 a8083063 Iustin Pop

227 a8083063 Iustin Pop
    This method should implement the actual work. It should raise
228 a8083063 Iustin Pop
    errors.OpExecError for failures that are somewhat dealt with in
229 a8083063 Iustin Pop
    code, or expected.
230 a8083063 Iustin Pop

231 a8083063 Iustin Pop
    """
232 3a012b41 Michael Hanselmann
    if self.tasklets is not None:
233 b4a9eb66 Michael Hanselmann
      for (idx, tl) in enumerate(self.tasklets):
234 abae1b2b Michael Hanselmann
        logging.debug("Executing tasklet %s/%s", idx + 1, len(self.tasklets))
235 6fd35c4d Michael Hanselmann
        tl.Exec(feedback_fn)
236 6fd35c4d Michael Hanselmann
    else:
237 6fd35c4d Michael Hanselmann
      raise NotImplementedError
238 a8083063 Iustin Pop
239 a8083063 Iustin Pop
  def BuildHooksEnv(self):
240 a8083063 Iustin Pop
    """Build hooks environment for this LU.
241 a8083063 Iustin Pop

242 a8083063 Iustin Pop
    This method should return a three-node tuple consisting of: a dict
243 a8083063 Iustin Pop
    containing the environment that will be used for running the
244 a8083063 Iustin Pop
    specific hook for this LU, a list of node names on which the hook
245 a8083063 Iustin Pop
    should run before the execution, and a list of node names on which
246 a8083063 Iustin Pop
    the hook should run after the execution.
247 a8083063 Iustin Pop

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

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

255 a8083063 Iustin Pop
    Note that if the HPATH for a LU class is None, this function will
256 a8083063 Iustin Pop
    not be called.
257 a8083063 Iustin Pop

258 a8083063 Iustin Pop
    """
259 a8083063 Iustin Pop
    raise NotImplementedError
260 a8083063 Iustin Pop
261 1fce5219 Guido Trotter
  def HooksCallBack(self, phase, hook_results, feedback_fn, lu_result):
262 1fce5219 Guido Trotter
    """Notify the LU about the results of its hooks.
263 1fce5219 Guido Trotter

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

270 e4376078 Iustin Pop
    @param phase: one of L{constants.HOOKS_PHASE_POST} or
271 e4376078 Iustin Pop
        L{constants.HOOKS_PHASE_PRE}; it denotes the hooks phase
272 e4376078 Iustin Pop
    @param hook_results: the results of the multi-node hooks rpc call
273 e4376078 Iustin Pop
    @param feedback_fn: function used send feedback back to the caller
274 e4376078 Iustin Pop
    @param lu_result: the previous Exec result this LU had, or None
275 e4376078 Iustin Pop
        in the PRE phase
276 e4376078 Iustin Pop
    @return: the new Exec result, based on the previous result
277 e4376078 Iustin Pop
        and hook results
278 1fce5219 Guido Trotter

279 1fce5219 Guido Trotter
    """
280 1fce5219 Guido Trotter
    return lu_result
281 1fce5219 Guido Trotter
282 43905206 Guido Trotter
  def _ExpandAndLockInstance(self):
283 43905206 Guido Trotter
    """Helper function to expand and lock an instance.
284 43905206 Guido Trotter

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

291 43905206 Guido Trotter
    """
292 43905206 Guido Trotter
    if self.needed_locks is None:
293 43905206 Guido Trotter
      self.needed_locks = {}
294 43905206 Guido Trotter
    else:
295 43905206 Guido Trotter
      assert locking.LEVEL_INSTANCE not in self.needed_locks, \
296 43905206 Guido Trotter
        "_ExpandAndLockInstance called with instance-level locks set"
297 43905206 Guido Trotter
    expanded_name = self.cfg.ExpandInstanceName(self.op.instance_name)
298 43905206 Guido Trotter
    if expanded_name is None:
299 43905206 Guido Trotter
      raise errors.OpPrereqError("Instance '%s' not known" %
300 5c983ee5 Iustin Pop
                                 self.op.instance_name, errors.ECODE_NOENT)
301 43905206 Guido Trotter
    self.needed_locks[locking.LEVEL_INSTANCE] = expanded_name
302 43905206 Guido Trotter
    self.op.instance_name = expanded_name
303 43905206 Guido Trotter
304 a82ce292 Guido Trotter
  def _LockInstancesNodes(self, primary_only=False):
305 c4a2fee1 Guido Trotter
    """Helper function to declare instances' nodes for locking.
306 c4a2fee1 Guido Trotter

307 c4a2fee1 Guido Trotter
    This function should be called after locking one or more instances to lock
308 c4a2fee1 Guido Trotter
    their nodes. Its effect is populating self.needed_locks[locking.LEVEL_NODE]
309 c4a2fee1 Guido Trotter
    with all primary or secondary nodes for instances already locked and
310 c4a2fee1 Guido Trotter
    present in self.needed_locks[locking.LEVEL_INSTANCE].
311 c4a2fee1 Guido Trotter

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

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

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

320 e4376078 Iustin Pop
      if level == locking.LEVEL_NODE:
321 e4376078 Iustin Pop
        self._LockInstancesNodes()
322 c4a2fee1 Guido Trotter

323 a82ce292 Guido Trotter
    @type primary_only: boolean
324 a82ce292 Guido Trotter
    @param primary_only: only lock primary nodes of locked instances
325 a82ce292 Guido Trotter

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

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

356 a8083063 Iustin Pop
  """
357 a8083063 Iustin Pop
  HPATH = None
358 a8083063 Iustin Pop
  HTYPE = None
359 a8083063 Iustin Pop
360 a8083063 Iustin Pop
361 9a6800e1 Michael Hanselmann
class Tasklet:
362 9a6800e1 Michael Hanselmann
  """Tasklet base class.
363 9a6800e1 Michael Hanselmann

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

368 9a6800e1 Michael Hanselmann
  Subclasses must follow these rules:
369 9a6800e1 Michael Hanselmann
    - Implement CheckPrereq
370 9a6800e1 Michael Hanselmann
    - Implement Exec
371 9a6800e1 Michael Hanselmann

372 9a6800e1 Michael Hanselmann
  """
373 464243a7 Michael Hanselmann
  def __init__(self, lu):
374 464243a7 Michael Hanselmann
    self.lu = lu
375 464243a7 Michael Hanselmann
376 464243a7 Michael Hanselmann
    # Shortcuts
377 464243a7 Michael Hanselmann
    self.cfg = lu.cfg
378 464243a7 Michael Hanselmann
    self.rpc = lu.rpc
379 464243a7 Michael Hanselmann
380 9a6800e1 Michael Hanselmann
  def CheckPrereq(self):
381 9a6800e1 Michael Hanselmann
    """Check prerequisites for this tasklets.
382 9a6800e1 Michael Hanselmann

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

387 9a6800e1 Michael Hanselmann
    The method should raise errors.OpPrereqError in case something is not
388 9a6800e1 Michael Hanselmann
    fulfilled. Its return value is ignored.
389 9a6800e1 Michael Hanselmann

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

393 9a6800e1 Michael Hanselmann
    """
394 9a6800e1 Michael Hanselmann
    raise NotImplementedError
395 9a6800e1 Michael Hanselmann
396 9a6800e1 Michael Hanselmann
  def Exec(self, feedback_fn):
397 9a6800e1 Michael Hanselmann
    """Execute the tasklet.
398 9a6800e1 Michael Hanselmann

399 9a6800e1 Michael Hanselmann
    This method should implement the actual work. It should raise
400 9a6800e1 Michael Hanselmann
    errors.OpExecError for failures that are somewhat dealt with in code, or
401 9a6800e1 Michael Hanselmann
    expected.
402 9a6800e1 Michael Hanselmann

403 9a6800e1 Michael Hanselmann
    """
404 9a6800e1 Michael Hanselmann
    raise NotImplementedError
405 9a6800e1 Michael Hanselmann
406 9a6800e1 Michael Hanselmann
407 dcb93971 Michael Hanselmann
def _GetWantedNodes(lu, nodes):
408 a7ba5e53 Iustin Pop
  """Returns list of checked and expanded node names.
409 83120a01 Michael Hanselmann

410 e4376078 Iustin Pop
  @type lu: L{LogicalUnit}
411 e4376078 Iustin Pop
  @param lu: the logical unit on whose behalf we execute
412 e4376078 Iustin Pop
  @type nodes: list
413 e4376078 Iustin Pop
  @param nodes: list of node names or None for all nodes
414 e4376078 Iustin Pop
  @rtype: list
415 e4376078 Iustin Pop
  @return: the list of nodes, sorted
416 e4376078 Iustin Pop
  @raise errors.OpProgrammerError: if the nodes parameter is wrong type
417 83120a01 Michael Hanselmann

418 83120a01 Michael Hanselmann
  """
419 3312b702 Iustin Pop
  if not isinstance(nodes, list):
420 5c983ee5 Iustin Pop
    raise errors.OpPrereqError("Invalid argument type 'nodes'",
421 5c983ee5 Iustin Pop
                               errors.ECODE_INVAL)
422 dcb93971 Michael Hanselmann
423 ea47808a Guido Trotter
  if not nodes:
424 ea47808a Guido Trotter
    raise errors.ProgrammerError("_GetWantedNodes should only be called with a"
425 ea47808a Guido Trotter
      " non-empty list of nodes whose name is to be expanded.")
426 dcb93971 Michael Hanselmann
427 ea47808a Guido Trotter
  wanted = []
428 ea47808a Guido Trotter
  for name in nodes:
429 ea47808a Guido Trotter
    node = lu.cfg.ExpandNodeName(name)
430 ea47808a Guido Trotter
    if node is None:
431 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("No such node name '%s'" % name,
432 5c983ee5 Iustin Pop
                                 errors.ECODE_NOENT)
433 ea47808a Guido Trotter
    wanted.append(node)
434 dcb93971 Michael Hanselmann
435 a7ba5e53 Iustin Pop
  return utils.NiceSort(wanted)
436 3312b702 Iustin Pop
437 3312b702 Iustin Pop
438 3312b702 Iustin Pop
def _GetWantedInstances(lu, instances):
439 a7ba5e53 Iustin Pop
  """Returns list of checked and expanded instance names.
440 3312b702 Iustin Pop

441 e4376078 Iustin Pop
  @type lu: L{LogicalUnit}
442 e4376078 Iustin Pop
  @param lu: the logical unit on whose behalf we execute
443 e4376078 Iustin Pop
  @type instances: list
444 e4376078 Iustin Pop
  @param instances: list of instance names or None for all instances
445 e4376078 Iustin Pop
  @rtype: list
446 e4376078 Iustin Pop
  @return: the list of instances, sorted
447 e4376078 Iustin Pop
  @raise errors.OpPrereqError: if the instances parameter is wrong type
448 e4376078 Iustin Pop
  @raise errors.OpPrereqError: if any of the passed instances is not found
449 3312b702 Iustin Pop

450 3312b702 Iustin Pop
  """
451 3312b702 Iustin Pop
  if not isinstance(instances, list):
452 5c983ee5 Iustin Pop
    raise errors.OpPrereqError("Invalid argument type 'instances'",
453 5c983ee5 Iustin Pop
                               errors.ECODE_INVAL)
454 3312b702 Iustin Pop
455 3312b702 Iustin Pop
  if instances:
456 3312b702 Iustin Pop
    wanted = []
457 3312b702 Iustin Pop
458 3312b702 Iustin Pop
    for name in instances:
459 a7ba5e53 Iustin Pop
      instance = lu.cfg.ExpandInstanceName(name)
460 3312b702 Iustin Pop
      if instance is None:
461 5c983ee5 Iustin Pop
        raise errors.OpPrereqError("No such instance name '%s'" % name,
462 5c983ee5 Iustin Pop
                                   errors.ECODE_NOENT)
463 3312b702 Iustin Pop
      wanted.append(instance)
464 3312b702 Iustin Pop
465 3312b702 Iustin Pop
  else:
466 a7f5dc98 Iustin Pop
    wanted = utils.NiceSort(lu.cfg.GetInstanceList())
467 a7f5dc98 Iustin Pop
  return wanted
468 dcb93971 Michael Hanselmann
469 dcb93971 Michael Hanselmann
470 dcb93971 Michael Hanselmann
def _CheckOutputFields(static, dynamic, selected):
471 83120a01 Michael Hanselmann
  """Checks whether all selected fields are valid.
472 83120a01 Michael Hanselmann

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

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

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

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

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

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

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

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

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

538 733a2b6a Iustin Pop
  """
539 733a2b6a Iustin Pop
  if lu.cfg.GetNodeInfo(node).drained:
540 5c983ee5 Iustin Pop
    raise errors.OpPrereqError("Can't use drained node %s" % node,
541 5c983ee5 Iustin Pop
                               errors.ECODE_INVAL)
542 733a2b6a Iustin Pop
543 733a2b6a Iustin Pop
544 ecb215b5 Michael Hanselmann
def _BuildInstanceHookEnv(name, primary_node, secondary_nodes, os_type, status,
545 67fc3042 Iustin Pop
                          memory, vcpus, nics, disk_template, disks,
546 7c4d6c7b Michael Hanselmann
                          bep, hvp, hypervisor_name):
547 e4376078 Iustin Pop
  """Builds instance related env variables for hooks
548 e4376078 Iustin Pop

549 e4376078 Iustin Pop
  This builds the hook environment from individual variables.
550 e4376078 Iustin Pop

551 e4376078 Iustin Pop
  @type name: string
552 e4376078 Iustin Pop
  @param name: the name of the instance
553 e4376078 Iustin Pop
  @type primary_node: string
554 e4376078 Iustin Pop
  @param primary_node: the name of the instance's primary node
555 e4376078 Iustin Pop
  @type secondary_nodes: list
556 e4376078 Iustin Pop
  @param secondary_nodes: list of secondary nodes as strings
557 e4376078 Iustin Pop
  @type os_type: string
558 e4376078 Iustin Pop
  @param os_type: the name of the instance's OS
559 0d68c45d Iustin Pop
  @type status: boolean
560 0d68c45d Iustin Pop
  @param status: the should_run status of the instance
561 e4376078 Iustin Pop
  @type memory: string
562 e4376078 Iustin Pop
  @param memory: the memory size of the instance
563 e4376078 Iustin Pop
  @type vcpus: string
564 e4376078 Iustin Pop
  @param vcpus: the count of VCPUs the instance has
565 e4376078 Iustin Pop
  @type nics: list
566 5e3d3eb3 Guido Trotter
  @param nics: list of tuples (ip, mac, mode, link) representing
567 5e3d3eb3 Guido Trotter
      the NICs the instance has
568 2c2690c9 Iustin Pop
  @type disk_template: string
569 5bbd3f7f Michael Hanselmann
  @param disk_template: the disk template of the instance
570 2c2690c9 Iustin Pop
  @type disks: list
571 2c2690c9 Iustin Pop
  @param disks: the list of (size, mode) pairs
572 67fc3042 Iustin Pop
  @type bep: dict
573 67fc3042 Iustin Pop
  @param bep: the backend parameters for the instance
574 67fc3042 Iustin Pop
  @type hvp: dict
575 67fc3042 Iustin Pop
  @param hvp: the hypervisor parameters for the instance
576 7c4d6c7b Michael Hanselmann
  @type hypervisor_name: string
577 7c4d6c7b Michael Hanselmann
  @param hypervisor_name: the hypervisor for the instance
578 e4376078 Iustin Pop
  @rtype: dict
579 e4376078 Iustin Pop
  @return: the hook environment for this instance
580 ecb215b5 Michael Hanselmann

581 396e1b78 Michael Hanselmann
  """
582 0d68c45d Iustin Pop
  if status:
583 0d68c45d Iustin Pop
    str_status = "up"
584 0d68c45d Iustin Pop
  else:
585 0d68c45d Iustin Pop
    str_status = "down"
586 396e1b78 Michael Hanselmann
  env = {
587 0e137c28 Iustin Pop
    "OP_TARGET": name,
588 396e1b78 Michael Hanselmann
    "INSTANCE_NAME": name,
589 396e1b78 Michael Hanselmann
    "INSTANCE_PRIMARY": primary_node,
590 396e1b78 Michael Hanselmann
    "INSTANCE_SECONDARIES": " ".join(secondary_nodes),
591 ecb215b5 Michael Hanselmann
    "INSTANCE_OS_TYPE": os_type,
592 0d68c45d Iustin Pop
    "INSTANCE_STATUS": str_status,
593 396e1b78 Michael Hanselmann
    "INSTANCE_MEMORY": memory,
594 396e1b78 Michael Hanselmann
    "INSTANCE_VCPUS": vcpus,
595 2c2690c9 Iustin Pop
    "INSTANCE_DISK_TEMPLATE": disk_template,
596 7c4d6c7b Michael Hanselmann
    "INSTANCE_HYPERVISOR": hypervisor_name,
597 396e1b78 Michael Hanselmann
  }
598 396e1b78 Michael Hanselmann
599 396e1b78 Michael Hanselmann
  if nics:
600 396e1b78 Michael Hanselmann
    nic_count = len(nics)
601 62f0dd02 Guido Trotter
    for idx, (ip, mac, mode, link) in enumerate(nics):
602 396e1b78 Michael Hanselmann
      if ip is None:
603 396e1b78 Michael Hanselmann
        ip = ""
604 396e1b78 Michael Hanselmann
      env["INSTANCE_NIC%d_IP" % idx] = ip
605 2c2690c9 Iustin Pop
      env["INSTANCE_NIC%d_MAC" % idx] = mac
606 62f0dd02 Guido Trotter
      env["INSTANCE_NIC%d_MODE" % idx] = mode
607 62f0dd02 Guido Trotter
      env["INSTANCE_NIC%d_LINK" % idx] = link
608 62f0dd02 Guido Trotter
      if mode == constants.NIC_MODE_BRIDGED:
609 62f0dd02 Guido Trotter
        env["INSTANCE_NIC%d_BRIDGE" % idx] = link
610 396e1b78 Michael Hanselmann
  else:
611 396e1b78 Michael Hanselmann
    nic_count = 0
612 396e1b78 Michael Hanselmann
613 396e1b78 Michael Hanselmann
  env["INSTANCE_NIC_COUNT"] = nic_count
614 396e1b78 Michael Hanselmann
615 2c2690c9 Iustin Pop
  if disks:
616 2c2690c9 Iustin Pop
    disk_count = len(disks)
617 2c2690c9 Iustin Pop
    for idx, (size, mode) in enumerate(disks):
618 2c2690c9 Iustin Pop
      env["INSTANCE_DISK%d_SIZE" % idx] = size
619 2c2690c9 Iustin Pop
      env["INSTANCE_DISK%d_MODE" % idx] = mode
620 2c2690c9 Iustin Pop
  else:
621 2c2690c9 Iustin Pop
    disk_count = 0
622 2c2690c9 Iustin Pop
623 2c2690c9 Iustin Pop
  env["INSTANCE_DISK_COUNT"] = disk_count
624 2c2690c9 Iustin Pop
625 67fc3042 Iustin Pop
  for source, kind in [(bep, "BE"), (hvp, "HV")]:
626 67fc3042 Iustin Pop
    for key, value in source.items():
627 67fc3042 Iustin Pop
      env["INSTANCE_%s_%s" % (kind, key)] = value
628 67fc3042 Iustin Pop
629 396e1b78 Michael Hanselmann
  return env
630 396e1b78 Michael Hanselmann
631 96acbc09 Michael Hanselmann
632 f9b10246 Guido Trotter
def _NICListToTuple(lu, nics):
633 62f0dd02 Guido Trotter
  """Build a list of nic information tuples.
634 62f0dd02 Guido Trotter

635 f9b10246 Guido Trotter
  This list is suitable to be passed to _BuildInstanceHookEnv or as a return
636 f9b10246 Guido Trotter
  value in LUQueryInstanceData.
637 62f0dd02 Guido Trotter

638 62f0dd02 Guido Trotter
  @type lu:  L{LogicalUnit}
639 62f0dd02 Guido Trotter
  @param lu: the logical unit on whose behalf we execute
640 62f0dd02 Guido Trotter
  @type nics: list of L{objects.NIC}
641 62f0dd02 Guido Trotter
  @param nics: list of nics to convert to hooks tuples
642 62f0dd02 Guido Trotter

643 62f0dd02 Guido Trotter
  """
644 62f0dd02 Guido Trotter
  hooks_nics = []
645 62f0dd02 Guido Trotter
  c_nicparams = lu.cfg.GetClusterInfo().nicparams[constants.PP_DEFAULT]
646 62f0dd02 Guido Trotter
  for nic in nics:
647 62f0dd02 Guido Trotter
    ip = nic.ip
648 62f0dd02 Guido Trotter
    mac = nic.mac
649 62f0dd02 Guido Trotter
    filled_params = objects.FillDict(c_nicparams, nic.nicparams)
650 62f0dd02 Guido Trotter
    mode = filled_params[constants.NIC_MODE]
651 62f0dd02 Guido Trotter
    link = filled_params[constants.NIC_LINK]
652 62f0dd02 Guido Trotter
    hooks_nics.append((ip, mac, mode, link))
653 62f0dd02 Guido Trotter
  return hooks_nics
654 396e1b78 Michael Hanselmann
655 96acbc09 Michael Hanselmann
656 338e51e8 Iustin Pop
def _BuildInstanceHookEnvByObject(lu, instance, override=None):
657 ecb215b5 Michael Hanselmann
  """Builds instance related env variables for hooks from an object.
658 ecb215b5 Michael Hanselmann

659 e4376078 Iustin Pop
  @type lu: L{LogicalUnit}
660 e4376078 Iustin Pop
  @param lu: the logical unit on whose behalf we execute
661 e4376078 Iustin Pop
  @type instance: L{objects.Instance}
662 e4376078 Iustin Pop
  @param instance: the instance for which we should build the
663 e4376078 Iustin Pop
      environment
664 e4376078 Iustin Pop
  @type override: dict
665 e4376078 Iustin Pop
  @param override: dictionary with key/values that will override
666 e4376078 Iustin Pop
      our values
667 e4376078 Iustin Pop
  @rtype: dict
668 e4376078 Iustin Pop
  @return: the hook environment dictionary
669 e4376078 Iustin Pop

670 ecb215b5 Michael Hanselmann
  """
671 67fc3042 Iustin Pop
  cluster = lu.cfg.GetClusterInfo()
672 67fc3042 Iustin Pop
  bep = cluster.FillBE(instance)
673 67fc3042 Iustin Pop
  hvp = cluster.FillHV(instance)
674 396e1b78 Michael Hanselmann
  args = {
675 396e1b78 Michael Hanselmann
    'name': instance.name,
676 396e1b78 Michael Hanselmann
    'primary_node': instance.primary_node,
677 396e1b78 Michael Hanselmann
    'secondary_nodes': instance.secondary_nodes,
678 ecb215b5 Michael Hanselmann
    'os_type': instance.os,
679 0d68c45d Iustin Pop
    'status': instance.admin_up,
680 338e51e8 Iustin Pop
    'memory': bep[constants.BE_MEMORY],
681 338e51e8 Iustin Pop
    'vcpus': bep[constants.BE_VCPUS],
682 f9b10246 Guido Trotter
    'nics': _NICListToTuple(lu, instance.nics),
683 2c2690c9 Iustin Pop
    'disk_template': instance.disk_template,
684 2c2690c9 Iustin Pop
    'disks': [(disk.size, disk.mode) for disk in instance.disks],
685 67fc3042 Iustin Pop
    'bep': bep,
686 67fc3042 Iustin Pop
    'hvp': hvp,
687 b0c63e2b Iustin Pop
    'hypervisor_name': instance.hypervisor,
688 396e1b78 Michael Hanselmann
  }
689 396e1b78 Michael Hanselmann
  if override:
690 396e1b78 Michael Hanselmann
    args.update(override)
691 396e1b78 Michael Hanselmann
  return _BuildInstanceHookEnv(**args)
692 396e1b78 Michael Hanselmann
693 396e1b78 Michael Hanselmann
694 44485f49 Guido Trotter
def _AdjustCandidatePool(lu, exceptions):
695 ec0292f1 Iustin Pop
  """Adjust the candidate pool after node operations.
696 ec0292f1 Iustin Pop

697 ec0292f1 Iustin Pop
  """
698 44485f49 Guido Trotter
  mod_list = lu.cfg.MaintainCandidatePool(exceptions)
699 ec0292f1 Iustin Pop
  if mod_list:
700 ec0292f1 Iustin Pop
    lu.LogInfo("Promoted nodes to master candidate role: %s",
701 ee513a66 Iustin Pop
               ", ".join(node.name for node in mod_list))
702 ec0292f1 Iustin Pop
    for name in mod_list:
703 ec0292f1 Iustin Pop
      lu.context.ReaddNode(name)
704 44485f49 Guido Trotter
  mc_now, mc_max, _ = lu.cfg.GetMasterCandidateStats(exceptions)
705 ec0292f1 Iustin Pop
  if mc_now > mc_max:
706 ec0292f1 Iustin Pop
    lu.LogInfo("Note: more nodes are candidates (%d) than desired (%d)" %
707 ec0292f1 Iustin Pop
               (mc_now, mc_max))
708 ec0292f1 Iustin Pop
709 ec0292f1 Iustin Pop
710 6d7e1f20 Guido Trotter
def _DecideSelfPromotion(lu, exceptions=None):
711 6d7e1f20 Guido Trotter
  """Decide whether I should promote myself as a master candidate.
712 6d7e1f20 Guido Trotter

713 6d7e1f20 Guido Trotter
  """
714 6d7e1f20 Guido Trotter
  cp_size = lu.cfg.GetClusterInfo().candidate_pool_size
715 6d7e1f20 Guido Trotter
  mc_now, mc_should, _ = lu.cfg.GetMasterCandidateStats(exceptions)
716 6d7e1f20 Guido Trotter
  # the new node will increase mc_max with one, so:
717 6d7e1f20 Guido Trotter
  mc_should = min(mc_should + 1, cp_size)
718 6d7e1f20 Guido Trotter
  return mc_now < mc_should
719 6d7e1f20 Guido Trotter
720 6d7e1f20 Guido Trotter
721 b165e77e Guido Trotter
def _CheckNicsBridgesExist(lu, target_nics, target_node,
722 b165e77e Guido Trotter
                               profile=constants.PP_DEFAULT):
723 b165e77e Guido Trotter
  """Check that the brigdes needed by a list of nics exist.
724 b165e77e Guido Trotter

725 b165e77e Guido Trotter
  """
726 b165e77e Guido Trotter
  c_nicparams = lu.cfg.GetClusterInfo().nicparams[profile]
727 b165e77e Guido Trotter
  paramslist = [objects.FillDict(c_nicparams, nic.nicparams)
728 b165e77e Guido Trotter
                for nic in target_nics]
729 b165e77e Guido Trotter
  brlist = [params[constants.NIC_LINK] for params in paramslist
730 b165e77e Guido Trotter
            if params[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED]
731 b165e77e Guido Trotter
  if brlist:
732 b165e77e Guido Trotter
    result = lu.rpc.call_bridges_exist(target_node, brlist)
733 4c4e4e1e Iustin Pop
    result.Raise("Error checking bridges on destination node '%s'" %
734 045dd6d9 Iustin Pop
                 target_node, prereq=True, ecode=errors.ECODE_ENVIRON)
735 b165e77e Guido Trotter
736 b165e77e Guido Trotter
737 b165e77e Guido Trotter
def _CheckInstanceBridgesExist(lu, instance, node=None):
738 bf6929a2 Alexander Schreiber
  """Check that the brigdes needed by an instance exist.
739 bf6929a2 Alexander Schreiber

740 bf6929a2 Alexander Schreiber
  """
741 b165e77e Guido Trotter
  if node is None:
742 29921401 Iustin Pop
    node = instance.primary_node
743 b165e77e Guido Trotter
  _CheckNicsBridgesExist(lu, instance.nics, node)
744 bf6929a2 Alexander Schreiber
745 bf6929a2 Alexander Schreiber
746 c6f1af07 Iustin Pop
def _CheckOSVariant(os_obj, name):
747 f2c05717 Guido Trotter
  """Check whether an OS name conforms to the os variants specification.
748 f2c05717 Guido Trotter

749 c6f1af07 Iustin Pop
  @type os_obj: L{objects.OS}
750 c6f1af07 Iustin Pop
  @param os_obj: OS object to check
751 f2c05717 Guido Trotter
  @type name: string
752 f2c05717 Guido Trotter
  @param name: OS name passed by the user, to check for validity
753 f2c05717 Guido Trotter

754 f2c05717 Guido Trotter
  """
755 c6f1af07 Iustin Pop
  if not os_obj.supported_variants:
756 f2c05717 Guido Trotter
    return
757 f2c05717 Guido Trotter
  try:
758 f2c05717 Guido Trotter
    variant = name.split("+", 1)[1]
759 f2c05717 Guido Trotter
  except IndexError:
760 5c983ee5 Iustin Pop
    raise errors.OpPrereqError("OS name must include a variant",
761 5c983ee5 Iustin Pop
                               errors.ECODE_INVAL)
762 f2c05717 Guido Trotter
763 c6f1af07 Iustin Pop
  if variant not in os_obj.supported_variants:
764 5c983ee5 Iustin Pop
    raise errors.OpPrereqError("Unsupported OS variant", errors.ECODE_INVAL)
765 f2c05717 Guido Trotter
766 f2c05717 Guido Trotter
767 5ba9701d Michael Hanselmann
def _GetNodeInstancesInner(cfg, fn):
768 5ba9701d Michael Hanselmann
  return [i for i in cfg.GetAllInstancesInfo().values() if fn(i)]
769 5ba9701d Michael Hanselmann
770 5ba9701d Michael Hanselmann
771 e9721add Michael Hanselmann
def _GetNodeInstances(cfg, node_name):
772 e9721add Michael Hanselmann
  """Returns a list of all primary and secondary instances on a node.
773 e9721add Michael Hanselmann

774 e9721add Michael Hanselmann
  """
775 e9721add Michael Hanselmann
776 e9721add Michael Hanselmann
  return _GetNodeInstancesInner(cfg, lambda inst: node_name in inst.all_nodes)
777 e9721add Michael Hanselmann
778 e9721add Michael Hanselmann
779 80cb875c Michael Hanselmann
def _GetNodePrimaryInstances(cfg, node_name):
780 80cb875c Michael Hanselmann
  """Returns primary instances on a node.
781 80cb875c Michael Hanselmann

782 80cb875c Michael Hanselmann
  """
783 5ba9701d Michael Hanselmann
  return _GetNodeInstancesInner(cfg,
784 5ba9701d Michael Hanselmann
                                lambda inst: node_name == inst.primary_node)
785 80cb875c Michael Hanselmann
786 80cb875c Michael Hanselmann
787 692738fc Michael Hanselmann
def _GetNodeSecondaryInstances(cfg, node_name):
788 692738fc Michael Hanselmann
  """Returns secondary instances on a node.
789 692738fc Michael Hanselmann

790 692738fc Michael Hanselmann
  """
791 5ba9701d Michael Hanselmann
  return _GetNodeInstancesInner(cfg,
792 5ba9701d Michael Hanselmann
                                lambda inst: node_name in inst.secondary_nodes)
793 692738fc Michael Hanselmann
794 692738fc Michael Hanselmann
795 efb8da02 Michael Hanselmann
def _GetStorageTypeArgs(cfg, storage_type):
796 efb8da02 Michael Hanselmann
  """Returns the arguments for a storage type.
797 efb8da02 Michael Hanselmann

798 efb8da02 Michael Hanselmann
  """
799 efb8da02 Michael Hanselmann
  # Special case for file storage
800 efb8da02 Michael Hanselmann
  if storage_type == constants.ST_FILE:
801 a4d138b7 Michael Hanselmann
    # storage.FileStorage wants a list of storage directories
802 a4d138b7 Michael Hanselmann
    return [[cfg.GetFileStorageDir()]]
803 efb8da02 Michael Hanselmann
804 efb8da02 Michael Hanselmann
  return []
805 efb8da02 Michael Hanselmann
806 efb8da02 Michael Hanselmann
807 2d9005d8 Michael Hanselmann
def _FindFaultyInstanceDisks(cfg, rpc, instance, node_name, prereq):
808 2d9005d8 Michael Hanselmann
  faulty = []
809 2d9005d8 Michael Hanselmann
810 2d9005d8 Michael Hanselmann
  for dev in instance.disks:
811 2d9005d8 Michael Hanselmann
    cfg.SetDiskID(dev, node_name)
812 2d9005d8 Michael Hanselmann
813 2d9005d8 Michael Hanselmann
  result = rpc.call_blockdev_getmirrorstatus(node_name, instance.disks)
814 2d9005d8 Michael Hanselmann
  result.Raise("Failed to get disk status from node %s" % node_name,
815 045dd6d9 Iustin Pop
               prereq=prereq, ecode=errors.ECODE_ENVIRON)
816 2d9005d8 Michael Hanselmann
817 2d9005d8 Michael Hanselmann
  for idx, bdev_status in enumerate(result.payload):
818 2d9005d8 Michael Hanselmann
    if bdev_status and bdev_status.ldisk_status == constants.LDS_FAULTY:
819 2d9005d8 Michael Hanselmann
      faulty.append(idx)
820 2d9005d8 Michael Hanselmann
821 2d9005d8 Michael Hanselmann
  return faulty
822 2d9005d8 Michael Hanselmann
823 2d9005d8 Michael Hanselmann
824 b5f5fae9 Luca Bigliardi
class LUPostInitCluster(LogicalUnit):
825 b5f5fae9 Luca Bigliardi
  """Logical unit for running hooks after cluster initialization.
826 b5f5fae9 Luca Bigliardi

827 b5f5fae9 Luca Bigliardi
  """
828 b5f5fae9 Luca Bigliardi
  HPATH = "cluster-init"
829 b5f5fae9 Luca Bigliardi
  HTYPE = constants.HTYPE_CLUSTER
830 b5f5fae9 Luca Bigliardi
  _OP_REQP = []
831 b5f5fae9 Luca Bigliardi
832 b5f5fae9 Luca Bigliardi
  def BuildHooksEnv(self):
833 b5f5fae9 Luca Bigliardi
    """Build hooks env.
834 b5f5fae9 Luca Bigliardi

835 b5f5fae9 Luca Bigliardi
    """
836 b5f5fae9 Luca Bigliardi
    env = {"OP_TARGET": self.cfg.GetClusterName()}
837 b5f5fae9 Luca Bigliardi
    mn = self.cfg.GetMasterNode()
838 b5f5fae9 Luca Bigliardi
    return env, [], [mn]
839 b5f5fae9 Luca Bigliardi
840 b5f5fae9 Luca Bigliardi
  def CheckPrereq(self):
841 b5f5fae9 Luca Bigliardi
    """No prerequisites to check.
842 b5f5fae9 Luca Bigliardi

843 b5f5fae9 Luca Bigliardi
    """
844 b5f5fae9 Luca Bigliardi
    return True
845 b5f5fae9 Luca Bigliardi
846 b5f5fae9 Luca Bigliardi
  def Exec(self, feedback_fn):
847 b5f5fae9 Luca Bigliardi
    """Nothing to do.
848 b5f5fae9 Luca Bigliardi

849 b5f5fae9 Luca Bigliardi
    """
850 b5f5fae9 Luca Bigliardi
    return True
851 b5f5fae9 Luca Bigliardi
852 b5f5fae9 Luca Bigliardi
853 b2c750a4 Luca Bigliardi
class LUDestroyCluster(LogicalUnit):
854 a8083063 Iustin Pop
  """Logical unit for destroying the cluster.
855 a8083063 Iustin Pop

856 a8083063 Iustin Pop
  """
857 b2c750a4 Luca Bigliardi
  HPATH = "cluster-destroy"
858 b2c750a4 Luca Bigliardi
  HTYPE = constants.HTYPE_CLUSTER
859 a8083063 Iustin Pop
  _OP_REQP = []
860 a8083063 Iustin Pop
861 b2c750a4 Luca Bigliardi
  def BuildHooksEnv(self):
862 b2c750a4 Luca Bigliardi
    """Build hooks env.
863 b2c750a4 Luca Bigliardi

864 b2c750a4 Luca Bigliardi
    """
865 b2c750a4 Luca Bigliardi
    env = {"OP_TARGET": self.cfg.GetClusterName()}
866 b2c750a4 Luca Bigliardi
    return env, [], []
867 b2c750a4 Luca Bigliardi
868 a8083063 Iustin Pop
  def CheckPrereq(self):
869 a8083063 Iustin Pop
    """Check prerequisites.
870 a8083063 Iustin Pop

871 a8083063 Iustin Pop
    This checks whether the cluster is empty.
872 a8083063 Iustin Pop

873 5bbd3f7f Michael Hanselmann
    Any errors are signaled by raising errors.OpPrereqError.
874 a8083063 Iustin Pop

875 a8083063 Iustin Pop
    """
876 d6a02168 Michael Hanselmann
    master = self.cfg.GetMasterNode()
877 a8083063 Iustin Pop
878 a8083063 Iustin Pop
    nodelist = self.cfg.GetNodeList()
879 db915bd1 Michael Hanselmann
    if len(nodelist) != 1 or nodelist[0] != master:
880 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("There are still %d node(s) in"
881 5c983ee5 Iustin Pop
                                 " this cluster." % (len(nodelist) - 1),
882 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
883 db915bd1 Michael Hanselmann
    instancelist = self.cfg.GetInstanceList()
884 db915bd1 Michael Hanselmann
    if instancelist:
885 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("There are still %d instance(s) in"
886 5c983ee5 Iustin Pop
                                 " this cluster." % len(instancelist),
887 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
888 a8083063 Iustin Pop
889 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
890 a8083063 Iustin Pop
    """Destroys the cluster.
891 a8083063 Iustin Pop

892 a8083063 Iustin Pop
    """
893 d6a02168 Michael Hanselmann
    master = self.cfg.GetMasterNode()
894 b989b9d9 Ken Wehr
    modify_ssh_setup = self.cfg.GetClusterInfo().modify_ssh_setup
895 3141ad3b Luca Bigliardi
896 3141ad3b Luca Bigliardi
    # Run post hooks on master node before it's removed
897 3141ad3b Luca Bigliardi
    hm = self.proc.hmclass(self.rpc.call_hooks_runner, self)
898 3141ad3b Luca Bigliardi
    try:
899 3141ad3b Luca Bigliardi
      hm.RunPhase(constants.HOOKS_PHASE_POST, [master])
900 3141ad3b Luca Bigliardi
    except:
901 3141ad3b Luca Bigliardi
      self.LogWarning("Errors occurred running hooks on %s" % master)
902 3141ad3b Luca Bigliardi
903 781de953 Iustin Pop
    result = self.rpc.call_node_stop_master(master, False)
904 4c4e4e1e Iustin Pop
    result.Raise("Could not disable the master role")
905 b989b9d9 Ken Wehr
906 b989b9d9 Ken Wehr
    if modify_ssh_setup:
907 b989b9d9 Ken Wehr
      priv_key, pub_key, _ = ssh.GetUserFiles(constants.GANETI_RUNAS)
908 b989b9d9 Ken Wehr
      utils.CreateBackup(priv_key)
909 b989b9d9 Ken Wehr
      utils.CreateBackup(pub_key)
910 b989b9d9 Ken Wehr
911 140aa4a8 Iustin Pop
    return master
912 a8083063 Iustin Pop
913 a8083063 Iustin Pop
914 d8fff41c Guido Trotter
class LUVerifyCluster(LogicalUnit):
915 a8083063 Iustin Pop
  """Verifies the cluster status.
916 a8083063 Iustin Pop

917 a8083063 Iustin Pop
  """
918 d8fff41c Guido Trotter
  HPATH = "cluster-verify"
919 d8fff41c Guido Trotter
  HTYPE = constants.HTYPE_CLUSTER
920 a0c9776a Iustin Pop
  _OP_REQP = ["skip_checks", "verbose", "error_codes", "debug_simulate_errors"]
921 d4b9d97f Guido Trotter
  REQ_BGL = False
922 d4b9d97f Guido Trotter
923 7c874ee1 Iustin Pop
  TCLUSTER = "cluster"
924 7c874ee1 Iustin Pop
  TNODE = "node"
925 7c874ee1 Iustin Pop
  TINSTANCE = "instance"
926 7c874ee1 Iustin Pop
927 7c874ee1 Iustin Pop
  ECLUSTERCFG = (TCLUSTER, "ECLUSTERCFG")
928 7c874ee1 Iustin Pop
  EINSTANCEBADNODE = (TINSTANCE, "EINSTANCEBADNODE")
929 7c874ee1 Iustin Pop
  EINSTANCEDOWN = (TINSTANCE, "EINSTANCEDOWN")
930 7c874ee1 Iustin Pop
  EINSTANCELAYOUT = (TINSTANCE, "EINSTANCELAYOUT")
931 7c874ee1 Iustin Pop
  EINSTANCEMISSINGDISK = (TINSTANCE, "EINSTANCEMISSINGDISK")
932 7c874ee1 Iustin Pop
  EINSTANCEMISSINGDISK = (TINSTANCE, "EINSTANCEMISSINGDISK")
933 7c874ee1 Iustin Pop
  EINSTANCEWRONGNODE = (TINSTANCE, "EINSTANCEWRONGNODE")
934 7c874ee1 Iustin Pop
  ENODEDRBD = (TNODE, "ENODEDRBD")
935 7c874ee1 Iustin Pop
  ENODEFILECHECK = (TNODE, "ENODEFILECHECK")
936 7c874ee1 Iustin Pop
  ENODEHOOKS = (TNODE, "ENODEHOOKS")
937 7c874ee1 Iustin Pop
  ENODEHV = (TNODE, "ENODEHV")
938 7c874ee1 Iustin Pop
  ENODELVM = (TNODE, "ENODELVM")
939 7c874ee1 Iustin Pop
  ENODEN1 = (TNODE, "ENODEN1")
940 7c874ee1 Iustin Pop
  ENODENET = (TNODE, "ENODENET")
941 7c874ee1 Iustin Pop
  ENODEORPHANINSTANCE = (TNODE, "ENODEORPHANINSTANCE")
942 7c874ee1 Iustin Pop
  ENODEORPHANLV = (TNODE, "ENODEORPHANLV")
943 7c874ee1 Iustin Pop
  ENODERPC = (TNODE, "ENODERPC")
944 7c874ee1 Iustin Pop
  ENODESSH = (TNODE, "ENODESSH")
945 7c874ee1 Iustin Pop
  ENODEVERSION = (TNODE, "ENODEVERSION")
946 7c0aa8e9 Iustin Pop
  ENODESETUP = (TNODE, "ENODESETUP")
947 7c874ee1 Iustin Pop
948 a0c9776a Iustin Pop
  ETYPE_FIELD = "code"
949 a0c9776a Iustin Pop
  ETYPE_ERROR = "ERROR"
950 a0c9776a Iustin Pop
  ETYPE_WARNING = "WARNING"
951 a0c9776a Iustin Pop
952 d4b9d97f Guido Trotter
  def ExpandNames(self):
953 d4b9d97f Guido Trotter
    self.needed_locks = {
954 d4b9d97f Guido Trotter
      locking.LEVEL_NODE: locking.ALL_SET,
955 d4b9d97f Guido Trotter
      locking.LEVEL_INSTANCE: locking.ALL_SET,
956 d4b9d97f Guido Trotter
    }
957 c772d142 Michael Hanselmann
    self.share_locks = dict.fromkeys(locking.LEVELS, 1)
958 a8083063 Iustin Pop
959 7c874ee1 Iustin Pop
  def _Error(self, ecode, item, msg, *args, **kwargs):
960 7c874ee1 Iustin Pop
    """Format an error message.
961 7c874ee1 Iustin Pop

962 7c874ee1 Iustin Pop
    Based on the opcode's error_codes parameter, either format a
963 7c874ee1 Iustin Pop
    parseable error code, or a simpler error string.
964 7c874ee1 Iustin Pop

965 7c874ee1 Iustin Pop
    This must be called only from Exec and functions called from Exec.
966 7c874ee1 Iustin Pop

967 7c874ee1 Iustin Pop
    """
968 a0c9776a Iustin Pop
    ltype = kwargs.get(self.ETYPE_FIELD, self.ETYPE_ERROR)
969 7c874ee1 Iustin Pop
    itype, etxt = ecode
970 7c874ee1 Iustin Pop
    # first complete the msg
971 7c874ee1 Iustin Pop
    if args:
972 7c874ee1 Iustin Pop
      msg = msg % args
973 7c874ee1 Iustin Pop
    # then format the whole message
974 7c874ee1 Iustin Pop
    if self.op.error_codes:
975 7c874ee1 Iustin Pop
      msg = "%s:%s:%s:%s:%s" % (ltype, etxt, itype, item, msg)
976 7c874ee1 Iustin Pop
    else:
977 7c874ee1 Iustin Pop
      if item:
978 7c874ee1 Iustin Pop
        item = " " + item
979 7c874ee1 Iustin Pop
      else:
980 7c874ee1 Iustin Pop
        item = ""
981 7c874ee1 Iustin Pop
      msg = "%s: %s%s: %s" % (ltype, itype, item, msg)
982 7c874ee1 Iustin Pop
    # and finally report it via the feedback_fn
983 7c874ee1 Iustin Pop
    self._feedback_fn("  - %s" % msg)
984 7c874ee1 Iustin Pop
985 a0c9776a Iustin Pop
  def _ErrorIf(self, cond, *args, **kwargs):
986 a0c9776a Iustin Pop
    """Log an error message if the passed condition is True.
987 a0c9776a Iustin Pop

988 a0c9776a Iustin Pop
    """
989 a0c9776a Iustin Pop
    cond = bool(cond) or self.op.debug_simulate_errors
990 a0c9776a Iustin Pop
    if cond:
991 a0c9776a Iustin Pop
      self._Error(*args, **kwargs)
992 a0c9776a Iustin Pop
    # do not mark the operation as failed for WARN cases only
993 a0c9776a Iustin Pop
    if kwargs.get(self.ETYPE_FIELD, self.ETYPE_ERROR) == self.ETYPE_ERROR:
994 a0c9776a Iustin Pop
      self.bad = self.bad or cond
995 a0c9776a Iustin Pop
996 25361b9a Iustin Pop
  def _VerifyNode(self, nodeinfo, file_list, local_cksum,
997 7c874ee1 Iustin Pop
                  node_result, master_files, drbd_map, vg_name):
998 a8083063 Iustin Pop
    """Run multiple tests against a node.
999 a8083063 Iustin Pop

1000 112f18a5 Iustin Pop
    Test list:
1001 e4376078 Iustin Pop

1002 a8083063 Iustin Pop
      - compares ganeti version
1003 5bbd3f7f Michael Hanselmann
      - checks vg existence and size > 20G
1004 a8083063 Iustin Pop
      - checks config file checksum
1005 a8083063 Iustin Pop
      - checks ssh to other nodes
1006 a8083063 Iustin Pop

1007 112f18a5 Iustin Pop
    @type nodeinfo: L{objects.Node}
1008 112f18a5 Iustin Pop
    @param nodeinfo: the node to check
1009 e4376078 Iustin Pop
    @param file_list: required list of files
1010 e4376078 Iustin Pop
    @param local_cksum: dictionary of local files and their checksums
1011 e4376078 Iustin Pop
    @param node_result: the results from the node
1012 112f18a5 Iustin Pop
    @param master_files: list of files that only masters should have
1013 6d2e83d5 Iustin Pop
    @param drbd_map: the useddrbd minors for this node, in
1014 6d2e83d5 Iustin Pop
        form of minor: (instance, must_exist) which correspond to instances
1015 6d2e83d5 Iustin Pop
        and their running status
1016 cc9e1230 Guido Trotter
    @param vg_name: Ganeti Volume Group (result of self.cfg.GetVGName())
1017 098c0958 Michael Hanselmann

1018 a8083063 Iustin Pop
    """
1019 112f18a5 Iustin Pop
    node = nodeinfo.name
1020 a0c9776a Iustin Pop
    _ErrorIf = self._ErrorIf
1021 25361b9a Iustin Pop
1022 25361b9a Iustin Pop
    # main result, node_result should be a non-empty dict
1023 a0c9776a Iustin Pop
    test = not node_result or not isinstance(node_result, dict)
1024 a0c9776a Iustin Pop
    _ErrorIf(test, self.ENODERPC, node,
1025 7c874ee1 Iustin Pop
                  "unable to verify node: no data returned")
1026 a0c9776a Iustin Pop
    if test:
1027 a0c9776a Iustin Pop
      return
1028 25361b9a Iustin Pop
1029 a8083063 Iustin Pop
    # compares ganeti version
1030 a8083063 Iustin Pop
    local_version = constants.PROTOCOL_VERSION
1031 25361b9a Iustin Pop
    remote_version = node_result.get('version', None)
1032 a0c9776a Iustin Pop
    test = not (remote_version and
1033 a0c9776a Iustin Pop
                isinstance(remote_version, (list, tuple)) and
1034 a0c9776a Iustin Pop
                len(remote_version) == 2)
1035 a0c9776a Iustin Pop
    _ErrorIf(test, self.ENODERPC, node,
1036 a0c9776a Iustin Pop
             "connection to node returned invalid data")
1037 a0c9776a Iustin Pop
    if test:
1038 a0c9776a Iustin Pop
      return
1039 a0c9776a Iustin Pop
1040 a0c9776a Iustin Pop
    test = local_version != remote_version[0]
1041 a0c9776a Iustin Pop
    _ErrorIf(test, self.ENODEVERSION, node,
1042 a0c9776a Iustin Pop
             "incompatible protocol versions: master %s,"
1043 a0c9776a Iustin Pop
             " node %s", local_version, remote_version[0])
1044 a0c9776a Iustin Pop
    if test:
1045 a0c9776a Iustin Pop
      return
1046 a8083063 Iustin Pop
1047 e9ce0a64 Iustin Pop
    # node seems compatible, we can actually try to look into its results
1048 a8083063 Iustin Pop
1049 e9ce0a64 Iustin Pop
    # full package version
1050 a0c9776a Iustin Pop
    self._ErrorIf(constants.RELEASE_VERSION != remote_version[1],
1051 a0c9776a Iustin Pop
                  self.ENODEVERSION, node,
1052 7c874ee1 Iustin Pop
                  "software version mismatch: master %s, node %s",
1053 7c874ee1 Iustin Pop
                  constants.RELEASE_VERSION, remote_version[1],
1054 a0c9776a Iustin Pop
                  code=self.ETYPE_WARNING)
1055 e9ce0a64 Iustin Pop
1056 e9ce0a64 Iustin Pop
    # checks vg existence and size > 20G
1057 cc9e1230 Guido Trotter
    if vg_name is not None:
1058 cc9e1230 Guido Trotter
      vglist = node_result.get(constants.NV_VGLIST, None)
1059 a0c9776a Iustin Pop
      test = not vglist
1060 a0c9776a Iustin Pop
      _ErrorIf(test, self.ENODELVM, node, "unable to check volume groups")
1061 a0c9776a Iustin Pop
      if not test:
1062 cc9e1230 Guido Trotter
        vgstatus = utils.CheckVolumeGroupSize(vglist, vg_name,
1063 cc9e1230 Guido Trotter
                                              constants.MIN_VG_SIZE)
1064 a0c9776a Iustin Pop
        _ErrorIf(vgstatus, self.ENODELVM, node, vgstatus)
1065 a8083063 Iustin Pop
1066 a8083063 Iustin Pop
    # checks config file checksum
1067 a8083063 Iustin Pop
1068 25361b9a Iustin Pop
    remote_cksum = node_result.get(constants.NV_FILELIST, None)
1069 a0c9776a Iustin Pop
    test = not isinstance(remote_cksum, dict)
1070 a0c9776a Iustin Pop
    _ErrorIf(test, self.ENODEFILECHECK, node,
1071 a0c9776a Iustin Pop
             "node hasn't returned file checksum data")
1072 a0c9776a Iustin Pop
    if not test:
1073 a8083063 Iustin Pop
      for file_name in file_list:
1074 112f18a5 Iustin Pop
        node_is_mc = nodeinfo.master_candidate
1075 a0c9776a Iustin Pop
        must_have = (file_name not in master_files) or node_is_mc
1076 a0c9776a Iustin Pop
        # missing
1077 a0c9776a Iustin Pop
        test1 = file_name not in remote_cksum
1078 a0c9776a Iustin Pop
        # invalid checksum
1079 a0c9776a Iustin Pop
        test2 = not test1 and remote_cksum[file_name] != local_cksum[file_name]
1080 a0c9776a Iustin Pop
        # existing and good
1081 a0c9776a Iustin Pop
        test3 = not test1 and remote_cksum[file_name] == local_cksum[file_name]
1082 a0c9776a Iustin Pop
        _ErrorIf(test1 and must_have, self.ENODEFILECHECK, node,
1083 a0c9776a Iustin Pop
                 "file '%s' missing", file_name)
1084 a0c9776a Iustin Pop
        _ErrorIf(test2 and must_have, self.ENODEFILECHECK, node,
1085 a0c9776a Iustin Pop
                 "file '%s' has wrong checksum", file_name)
1086 a0c9776a Iustin Pop
        # not candidate and this is not a must-have file
1087 a0c9776a Iustin Pop
        _ErrorIf(test2 and not must_have, self.ENODEFILECHECK, node,
1088 a0c9776a Iustin Pop
                 "file '%s' should not exist on non master"
1089 a0c9776a Iustin Pop
                 " candidates (and the file is outdated)", file_name)
1090 a0c9776a Iustin Pop
        # all good, except non-master/non-must have combination
1091 a0c9776a Iustin Pop
        _ErrorIf(test3 and not must_have, self.ENODEFILECHECK, node,
1092 a0c9776a Iustin Pop
                 "file '%s' should not exist"
1093 a0c9776a Iustin Pop
                 " on non master candidates", file_name)
1094 a8083063 Iustin Pop
1095 25361b9a Iustin Pop
    # checks ssh to any
1096 25361b9a Iustin Pop
1097 a0c9776a Iustin Pop
    test = constants.NV_NODELIST not in node_result
1098 a0c9776a Iustin Pop
    _ErrorIf(test, self.ENODESSH, node,
1099 a0c9776a Iustin Pop
             "node hasn't returned node ssh connectivity data")
1100 a0c9776a Iustin Pop
    if not test:
1101 25361b9a Iustin Pop
      if node_result[constants.NV_NODELIST]:
1102 7c874ee1 Iustin Pop
        for a_node, a_msg in node_result[constants.NV_NODELIST].items():
1103 a0c9776a Iustin Pop
          _ErrorIf(True, self.ENODESSH, node,
1104 a0c9776a Iustin Pop
                   "ssh communication with node '%s': %s", a_node, a_msg)
1105 25361b9a Iustin Pop
1106 a0c9776a Iustin Pop
    test = constants.NV_NODENETTEST not in node_result
1107 a0c9776a Iustin Pop
    _ErrorIf(test, self.ENODENET, node,
1108 a0c9776a Iustin Pop
             "node hasn't returned node tcp connectivity data")
1109 a0c9776a Iustin Pop
    if not test:
1110 25361b9a Iustin Pop
      if node_result[constants.NV_NODENETTEST]:
1111 25361b9a Iustin Pop
        nlist = utils.NiceSort(node_result[constants.NV_NODENETTEST].keys())
1112 7c874ee1 Iustin Pop
        for anode in nlist:
1113 a0c9776a Iustin Pop
          _ErrorIf(True, self.ENODENET, node,
1114 a0c9776a Iustin Pop
                   "tcp communication with node '%s': %s",
1115 a0c9776a Iustin Pop
                   anode, node_result[constants.NV_NODENETTEST][anode])
1116 9d4bfc96 Iustin Pop
1117 25361b9a Iustin Pop
    hyp_result = node_result.get(constants.NV_HYPERVISOR, None)
1118 e69d05fd Iustin Pop
    if isinstance(hyp_result, dict):
1119 e69d05fd Iustin Pop
      for hv_name, hv_result in hyp_result.iteritems():
1120 a0c9776a Iustin Pop
        test = hv_result is not None
1121 a0c9776a Iustin Pop
        _ErrorIf(test, self.ENODEHV, node,
1122 a0c9776a Iustin Pop
                 "hypervisor %s verify failure: '%s'", hv_name, hv_result)
1123 6d2e83d5 Iustin Pop
1124 6d2e83d5 Iustin Pop
    # check used drbd list
1125 cc9e1230 Guido Trotter
    if vg_name is not None:
1126 cc9e1230 Guido Trotter
      used_minors = node_result.get(constants.NV_DRBDLIST, [])
1127 a0c9776a Iustin Pop
      test = not isinstance(used_minors, (tuple, list))
1128 a0c9776a Iustin Pop
      _ErrorIf(test, self.ENODEDRBD, node,
1129 a0c9776a Iustin Pop
               "cannot parse drbd status file: %s", str(used_minors))
1130 a0c9776a Iustin Pop
      if not test:
1131 cc9e1230 Guido Trotter
        for minor, (iname, must_exist) in drbd_map.items():
1132 a0c9776a Iustin Pop
          test = minor not in used_minors and must_exist
1133 a0c9776a Iustin Pop
          _ErrorIf(test, self.ENODEDRBD, node,
1134 a0c9776a Iustin Pop
                   "drbd minor %d of instance %s is not active",
1135 a0c9776a Iustin Pop
                   minor, iname)
1136 cc9e1230 Guido Trotter
        for minor in used_minors:
1137 a0c9776a Iustin Pop
          test = minor not in drbd_map
1138 a0c9776a Iustin Pop
          _ErrorIf(test, self.ENODEDRBD, node,
1139 a0c9776a Iustin Pop
                   "unallocated drbd minor %d is in use", minor)
1140 7c0aa8e9 Iustin Pop
    test = node_result.get(constants.NV_NODESETUP,
1141 7c0aa8e9 Iustin Pop
                           ["Missing NODESETUP results"])
1142 7c0aa8e9 Iustin Pop
    _ErrorIf(test, self.ENODESETUP, node, "node setup error: %s",
1143 7c0aa8e9 Iustin Pop
             "; ".join(test))
1144 a8083063 Iustin Pop
1145 d091393e Iustin Pop
    # check pv names
1146 d091393e Iustin Pop
    if vg_name is not None:
1147 d091393e Iustin Pop
      pvlist = node_result.get(constants.NV_PVLIST, None)
1148 d091393e Iustin Pop
      test = pvlist is None
1149 d091393e Iustin Pop
      _ErrorIf(test, self.ENODELVM, node, "Can't get PV list from node")
1150 d091393e Iustin Pop
      if not test:
1151 d091393e Iustin Pop
        # check that ':' is not present in PV names, since it's a
1152 d091393e Iustin Pop
        # special character for lvcreate (denotes the range of PEs to
1153 d091393e Iustin Pop
        # use on the PV)
1154 d091393e Iustin Pop
        for size, pvname, owner_vg in pvlist:
1155 d091393e Iustin Pop
          test = ":" in pvname
1156 d091393e Iustin Pop
          _ErrorIf(test, self.ENODELVM, node, "Invalid character ':' in PV"
1157 d091393e Iustin Pop
                   " '%s' of VG '%s'", pvname, owner_vg)
1158 d091393e Iustin Pop
1159 c5705f58 Guido Trotter
  def _VerifyInstance(self, instance, instanceconfig, node_vol_is,
1160 7c874ee1 Iustin Pop
                      node_instance, n_offline):
1161 a8083063 Iustin Pop
    """Verify an instance.
1162 a8083063 Iustin Pop

1163 a8083063 Iustin Pop
    This function checks to see if the required block devices are
1164 a8083063 Iustin Pop
    available on the instance's node.
1165 a8083063 Iustin Pop

1166 a8083063 Iustin Pop
    """
1167 a0c9776a Iustin Pop
    _ErrorIf = self._ErrorIf
1168 a8083063 Iustin Pop
    node_current = instanceconfig.primary_node
1169 a8083063 Iustin Pop
1170 a8083063 Iustin Pop
    node_vol_should = {}
1171 a8083063 Iustin Pop
    instanceconfig.MapLVsByNode(node_vol_should)
1172 a8083063 Iustin Pop
1173 a8083063 Iustin Pop
    for node in node_vol_should:
1174 0a66c968 Iustin Pop
      if node in n_offline:
1175 0a66c968 Iustin Pop
        # ignore missing volumes on offline nodes
1176 0a66c968 Iustin Pop
        continue
1177 a8083063 Iustin Pop
      for volume in node_vol_should[node]:
1178 a0c9776a Iustin Pop
        test = node not in node_vol_is or volume not in node_vol_is[node]
1179 a0c9776a Iustin Pop
        _ErrorIf(test, self.EINSTANCEMISSINGDISK, instance,
1180 a0c9776a Iustin Pop
                 "volume %s missing on node %s", volume, node)
1181 a8083063 Iustin Pop
1182 0d68c45d Iustin Pop
    if instanceconfig.admin_up:
1183 a0c9776a Iustin Pop
      test = ((node_current not in node_instance or
1184 a0c9776a Iustin Pop
               not instance in node_instance[node_current]) and
1185 a0c9776a Iustin Pop
              node_current not in n_offline)
1186 a0c9776a Iustin Pop
      _ErrorIf(test, self.EINSTANCEDOWN, instance,
1187 a0c9776a Iustin Pop
               "instance not running on its primary node %s",
1188 a0c9776a Iustin Pop
               node_current)
1189 a8083063 Iustin Pop
1190 a8083063 Iustin Pop
    for node in node_instance:
1191 a8083063 Iustin Pop
      if (not node == node_current):
1192 a0c9776a Iustin Pop
        test = instance in node_instance[node]
1193 a0c9776a Iustin Pop
        _ErrorIf(test, self.EINSTANCEWRONGNODE, instance,
1194 a0c9776a Iustin Pop
                 "instance should not run on node %s", node)
1195 a8083063 Iustin Pop
1196 7c874ee1 Iustin Pop
  def _VerifyOrphanVolumes(self, node_vol_should, node_vol_is):
1197 a8083063 Iustin Pop
    """Verify if there are any unknown volumes in the cluster.
1198 a8083063 Iustin Pop

1199 a8083063 Iustin Pop
    The .os, .swap and backup volumes are ignored. All other volumes are
1200 a8083063 Iustin Pop
    reported as unknown.
1201 a8083063 Iustin Pop

1202 a8083063 Iustin Pop
    """
1203 a8083063 Iustin Pop
    for node in node_vol_is:
1204 a8083063 Iustin Pop
      for volume in node_vol_is[node]:
1205 a0c9776a Iustin Pop
        test = (node not in node_vol_should or
1206 a0c9776a Iustin Pop
                volume not in node_vol_should[node])
1207 a0c9776a Iustin Pop
        self._ErrorIf(test, self.ENODEORPHANLV, node,
1208 7c874ee1 Iustin Pop
                      "volume %s is unknown", volume)
1209 a8083063 Iustin Pop
1210 7c874ee1 Iustin Pop
  def _VerifyOrphanInstances(self, instancelist, node_instance):
1211 a8083063 Iustin Pop
    """Verify the list of running instances.
1212 a8083063 Iustin Pop

1213 a8083063 Iustin Pop
    This checks what instances are running but unknown to the cluster.
1214 a8083063 Iustin Pop

1215 a8083063 Iustin Pop
    """
1216 a8083063 Iustin Pop
    for node in node_instance:
1217 7c874ee1 Iustin Pop
      for o_inst in node_instance[node]:
1218 a0c9776a Iustin Pop
        test = o_inst not in instancelist
1219 a0c9776a Iustin Pop
        self._ErrorIf(test, self.ENODEORPHANINSTANCE, node,
1220 7c874ee1 Iustin Pop
                      "instance %s on node %s should not exist", o_inst, node)
1221 a8083063 Iustin Pop
1222 7c874ee1 Iustin Pop
  def _VerifyNPlusOneMemory(self, node_info, instance_cfg):
1223 2b3b6ddd Guido Trotter
    """Verify N+1 Memory Resilience.
1224 2b3b6ddd Guido Trotter

1225 2b3b6ddd Guido Trotter
    Check that if one single node dies we can still start all the instances it
1226 2b3b6ddd Guido Trotter
    was primary for.
1227 2b3b6ddd Guido Trotter

1228 2b3b6ddd Guido Trotter
    """
1229 2b3b6ddd Guido Trotter
    for node, nodeinfo in node_info.iteritems():
1230 2b3b6ddd Guido Trotter
      # This code checks that every node which is now listed as secondary has
1231 2b3b6ddd Guido Trotter
      # enough memory to host all instances it is supposed to should a single
1232 2b3b6ddd Guido Trotter
      # other node in the cluster fail.
1233 2b3b6ddd Guido Trotter
      # FIXME: not ready for failover to an arbitrary node
1234 2b3b6ddd Guido Trotter
      # FIXME: does not support file-backed instances
1235 2b3b6ddd Guido Trotter
      # WARNING: we currently take into account down instances as well as up
1236 2b3b6ddd Guido Trotter
      # ones, considering that even if they're down someone might want to start
1237 2b3b6ddd Guido Trotter
      # them even in the event of a node failure.
1238 2b3b6ddd Guido Trotter
      for prinode, instances in nodeinfo['sinst-by-pnode'].iteritems():
1239 2b3b6ddd Guido Trotter
        needed_mem = 0
1240 2b3b6ddd Guido Trotter
        for instance in instances:
1241 338e51e8 Iustin Pop
          bep = self.cfg.GetClusterInfo().FillBE(instance_cfg[instance])
1242 c0f2b229 Iustin Pop
          if bep[constants.BE_AUTO_BALANCE]:
1243 3924700f Iustin Pop
            needed_mem += bep[constants.BE_MEMORY]
1244 a0c9776a Iustin Pop
        test = nodeinfo['mfree'] < needed_mem
1245 a0c9776a Iustin Pop
        self._ErrorIf(test, self.ENODEN1, node,
1246 7c874ee1 Iustin Pop
                      "not enough memory on to accommodate"
1247 7c874ee1 Iustin Pop
                      " failovers should peer node %s fail", prinode)
1248 2b3b6ddd Guido Trotter
1249 a8083063 Iustin Pop
  def CheckPrereq(self):
1250 a8083063 Iustin Pop
    """Check prerequisites.
1251 a8083063 Iustin Pop

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

1255 a8083063 Iustin Pop
    """
1256 e54c4c5e Guido Trotter
    self.skip_set = frozenset(self.op.skip_checks)
1257 e54c4c5e Guido Trotter
    if not constants.VERIFY_OPTIONAL_CHECKS.issuperset(self.skip_set):
1258 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Invalid checks to be skipped specified",
1259 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
1260 a8083063 Iustin Pop
1261 d8fff41c Guido Trotter
  def BuildHooksEnv(self):
1262 d8fff41c Guido Trotter
    """Build hooks env.
1263 d8fff41c Guido Trotter

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

1267 d8fff41c Guido Trotter
    """
1268 d8fff41c Guido Trotter
    all_nodes = self.cfg.GetNodeList()
1269 35e994e9 Iustin Pop
    env = {
1270 35e994e9 Iustin Pop
      "CLUSTER_TAGS": " ".join(self.cfg.GetClusterInfo().GetTags())
1271 35e994e9 Iustin Pop
      }
1272 35e994e9 Iustin Pop
    for node in self.cfg.GetAllNodesInfo().values():
1273 35e994e9 Iustin Pop
      env["NODE_TAGS_%s" % node.name] = " ".join(node.GetTags())
1274 35e994e9 Iustin Pop
1275 d8fff41c Guido Trotter
    return env, [], all_nodes
1276 d8fff41c Guido Trotter
1277 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1278 a8083063 Iustin Pop
    """Verify integrity of cluster, performing various test on nodes.
1279 a8083063 Iustin Pop

1280 a8083063 Iustin Pop
    """
1281 a0c9776a Iustin Pop
    self.bad = False
1282 a0c9776a Iustin Pop
    _ErrorIf = self._ErrorIf
1283 7c874ee1 Iustin Pop
    verbose = self.op.verbose
1284 7c874ee1 Iustin Pop
    self._feedback_fn = feedback_fn
1285 a8083063 Iustin Pop
    feedback_fn("* Verifying global settings")
1286 8522ceeb Iustin Pop
    for msg in self.cfg.VerifyConfig():
1287 a0c9776a Iustin Pop
      _ErrorIf(True, self.ECLUSTERCFG, None, msg)
1288 a8083063 Iustin Pop
1289 a8083063 Iustin Pop
    vg_name = self.cfg.GetVGName()
1290 e69d05fd Iustin Pop
    hypervisors = self.cfg.GetClusterInfo().enabled_hypervisors
1291 a8083063 Iustin Pop
    nodelist = utils.NiceSort(self.cfg.GetNodeList())
1292 9d4bfc96 Iustin Pop
    nodeinfo = [self.cfg.GetNodeInfo(nname) for nname in nodelist]
1293 a8083063 Iustin Pop
    instancelist = utils.NiceSort(self.cfg.GetInstanceList())
1294 6d2e83d5 Iustin Pop
    instanceinfo = dict((iname, self.cfg.GetInstanceInfo(iname))
1295 6d2e83d5 Iustin Pop
                        for iname in instancelist)
1296 93e4c50b Guido Trotter
    i_non_redundant = [] # Non redundant instances
1297 3924700f Iustin Pop
    i_non_a_balanced = [] # Non auto-balanced instances
1298 0a66c968 Iustin Pop
    n_offline = [] # List of offline nodes
1299 22f0f71d Iustin Pop
    n_drained = [] # List of nodes being drained
1300 a8083063 Iustin Pop
    node_volume = {}
1301 a8083063 Iustin Pop
    node_instance = {}
1302 9c9c7d30 Guido Trotter
    node_info = {}
1303 26b6af5e Guido Trotter
    instance_cfg = {}
1304 a8083063 Iustin Pop
1305 a8083063 Iustin Pop
    # FIXME: verify OS list
1306 a8083063 Iustin Pop
    # do local checksums
1307 112f18a5 Iustin Pop
    master_files = [constants.CLUSTER_CONF_FILE]
1308 112f18a5 Iustin Pop
1309 112f18a5 Iustin Pop
    file_names = ssconf.SimpleStore().GetFileList()
1310 cb91d46e Iustin Pop
    file_names.append(constants.SSL_CERT_FILE)
1311 699777f2 Michael Hanselmann
    file_names.append(constants.RAPI_CERT_FILE)
1312 112f18a5 Iustin Pop
    file_names.extend(master_files)
1313 112f18a5 Iustin Pop
1314 a8083063 Iustin Pop
    local_checksums = utils.FingerprintFiles(file_names)
1315 a8083063 Iustin Pop
1316 a8083063 Iustin Pop
    feedback_fn("* Gathering data (%d nodes)" % len(nodelist))
1317 a8083063 Iustin Pop
    node_verify_param = {
1318 25361b9a Iustin Pop
      constants.NV_FILELIST: file_names,
1319 82e37788 Iustin Pop
      constants.NV_NODELIST: [node.name for node in nodeinfo
1320 82e37788 Iustin Pop
                              if not node.offline],
1321 25361b9a Iustin Pop
      constants.NV_HYPERVISOR: hypervisors,
1322 25361b9a Iustin Pop
      constants.NV_NODENETTEST: [(node.name, node.primary_ip,
1323 82e37788 Iustin Pop
                                  node.secondary_ip) for node in nodeinfo
1324 82e37788 Iustin Pop
                                 if not node.offline],
1325 25361b9a Iustin Pop
      constants.NV_INSTANCELIST: hypervisors,
1326 25361b9a Iustin Pop
      constants.NV_VERSION: None,
1327 25361b9a Iustin Pop
      constants.NV_HVINFO: self.cfg.GetHypervisorType(),
1328 7c0aa8e9 Iustin Pop
      constants.NV_NODESETUP: None,
1329 a8083063 Iustin Pop
      }
1330 cc9e1230 Guido Trotter
    if vg_name is not None:
1331 cc9e1230 Guido Trotter
      node_verify_param[constants.NV_VGLIST] = None
1332 cc9e1230 Guido Trotter
      node_verify_param[constants.NV_LVLIST] = vg_name
1333 d091393e Iustin Pop
      node_verify_param[constants.NV_PVLIST] = [vg_name]
1334 cc9e1230 Guido Trotter
      node_verify_param[constants.NV_DRBDLIST] = None
1335 72737a7f Iustin Pop
    all_nvinfo = self.rpc.call_node_verify(nodelist, node_verify_param,
1336 72737a7f Iustin Pop
                                           self.cfg.GetClusterName())
1337 a8083063 Iustin Pop
1338 3924700f Iustin Pop
    cluster = self.cfg.GetClusterInfo()
1339 112f18a5 Iustin Pop
    master_node = self.cfg.GetMasterNode()
1340 6d2e83d5 Iustin Pop
    all_drbd_map = self.cfg.ComputeDRBDMap()
1341 6d2e83d5 Iustin Pop
1342 7c874ee1 Iustin Pop
    feedback_fn("* Verifying node status")
1343 112f18a5 Iustin Pop
    for node_i in nodeinfo:
1344 112f18a5 Iustin Pop
      node = node_i.name
1345 25361b9a Iustin Pop
1346 0a66c968 Iustin Pop
      if node_i.offline:
1347 7c874ee1 Iustin Pop
        if verbose:
1348 7c874ee1 Iustin Pop
          feedback_fn("* Skipping offline node %s" % (node,))
1349 0a66c968 Iustin Pop
        n_offline.append(node)
1350 0a66c968 Iustin Pop
        continue
1351 0a66c968 Iustin Pop
1352 112f18a5 Iustin Pop
      if node == master_node:
1353 25361b9a Iustin Pop
        ntype = "master"
1354 112f18a5 Iustin Pop
      elif node_i.master_candidate:
1355 25361b9a Iustin Pop
        ntype = "master candidate"
1356 22f0f71d Iustin Pop
      elif node_i.drained:
1357 22f0f71d Iustin Pop
        ntype = "drained"
1358 22f0f71d Iustin Pop
        n_drained.append(node)
1359 112f18a5 Iustin Pop
      else:
1360 25361b9a Iustin Pop
        ntype = "regular"
1361 7c874ee1 Iustin Pop
      if verbose:
1362 7c874ee1 Iustin Pop
        feedback_fn("* Verifying node %s (%s)" % (node, ntype))
1363 25361b9a Iustin Pop
1364 4c4e4e1e Iustin Pop
      msg = all_nvinfo[node].fail_msg
1365 a0c9776a Iustin Pop
      _ErrorIf(msg, self.ENODERPC, node, "while contacting node: %s", msg)
1366 6f68a739 Iustin Pop
      if msg:
1367 25361b9a Iustin Pop
        continue
1368 25361b9a Iustin Pop
1369 6f68a739 Iustin Pop
      nresult = all_nvinfo[node].payload
1370 6d2e83d5 Iustin Pop
      node_drbd = {}
1371 6d2e83d5 Iustin Pop
      for minor, instance in all_drbd_map[node].items():
1372 a0c9776a Iustin Pop
        test = instance not in instanceinfo
1373 a0c9776a Iustin Pop
        _ErrorIf(test, self.ECLUSTERCFG, None,
1374 a0c9776a Iustin Pop
                 "ghost instance '%s' in temporary DRBD map", instance)
1375 c614e5fb Iustin Pop
          # ghost instance should not be running, but otherwise we
1376 c614e5fb Iustin Pop
          # don't give double warnings (both ghost instance and
1377 c614e5fb Iustin Pop
          # unallocated minor in use)
1378 a0c9776a Iustin Pop
        if test:
1379 c614e5fb Iustin Pop
          node_drbd[minor] = (instance, False)
1380 c614e5fb Iustin Pop
        else:
1381 c614e5fb Iustin Pop
          instance = instanceinfo[instance]
1382 c614e5fb Iustin Pop
          node_drbd[minor] = (instance.name, instance.admin_up)
1383 a0c9776a Iustin Pop
      self._VerifyNode(node_i, file_names, local_checksums,
1384 a0c9776a Iustin Pop
                       nresult, master_files, node_drbd, vg_name)
1385 a8083063 Iustin Pop
1386 25361b9a Iustin Pop
      lvdata = nresult.get(constants.NV_LVLIST, "Missing LV data")
1387 cc9e1230 Guido Trotter
      if vg_name is None:
1388 cc9e1230 Guido Trotter
        node_volume[node] = {}
1389 cc9e1230 Guido Trotter
      elif isinstance(lvdata, basestring):
1390 a0c9776a Iustin Pop
        _ErrorIf(True, self.ENODELVM, node, "LVM problem on node: %s",
1391 a0c9776a Iustin Pop
                 utils.SafeEncode(lvdata))
1392 b63ed789 Iustin Pop
        node_volume[node] = {}
1393 25361b9a Iustin Pop
      elif not isinstance(lvdata, dict):
1394 a0c9776a Iustin Pop
        _ErrorIf(True, self.ENODELVM, node, "rpc call to node failed (lvlist)")
1395 a8083063 Iustin Pop
        continue
1396 b63ed789 Iustin Pop
      else:
1397 25361b9a Iustin Pop
        node_volume[node] = lvdata
1398 a8083063 Iustin Pop
1399 a8083063 Iustin Pop
      # node_instance
1400 25361b9a Iustin Pop
      idata = nresult.get(constants.NV_INSTANCELIST, None)
1401 a0c9776a Iustin Pop
      test = not isinstance(idata, list)
1402 a0c9776a Iustin Pop
      _ErrorIf(test, self.ENODEHV, node,
1403 a0c9776a Iustin Pop
               "rpc call to node failed (instancelist)")
1404 a0c9776a Iustin Pop
      if test:
1405 a8083063 Iustin Pop
        continue
1406 a8083063 Iustin Pop
1407 25361b9a Iustin Pop
      node_instance[node] = idata
1408 a8083063 Iustin Pop
1409 9c9c7d30 Guido Trotter
      # node_info
1410 25361b9a Iustin Pop
      nodeinfo = nresult.get(constants.NV_HVINFO, None)
1411 a0c9776a Iustin Pop
      test = not isinstance(nodeinfo, dict)
1412 a0c9776a Iustin Pop
      _ErrorIf(test, self.ENODEHV, node, "rpc call to node failed (hvinfo)")
1413 a0c9776a Iustin Pop
      if test:
1414 9c9c7d30 Guido Trotter
        continue
1415 9c9c7d30 Guido Trotter
1416 9c9c7d30 Guido Trotter
      try:
1417 9c9c7d30 Guido Trotter
        node_info[node] = {
1418 9c9c7d30 Guido Trotter
          "mfree": int(nodeinfo['memory_free']),
1419 93e4c50b Guido Trotter
          "pinst": [],
1420 93e4c50b Guido Trotter
          "sinst": [],
1421 36e7da50 Guido Trotter
          # dictionary holding all instances this node is secondary for,
1422 36e7da50 Guido Trotter
          # grouped by their primary node. Each key is a cluster node, and each
1423 36e7da50 Guido Trotter
          # value is a list of instances which have the key as primary and the
1424 36e7da50 Guido Trotter
          # current node as secondary.  this is handy to calculate N+1 memory
1425 36e7da50 Guido Trotter
          # availability if you can only failover from a primary to its
1426 36e7da50 Guido Trotter
          # secondary.
1427 36e7da50 Guido Trotter
          "sinst-by-pnode": {},
1428 9c9c7d30 Guido Trotter
        }
1429 cc9e1230 Guido Trotter
        # FIXME: devise a free space model for file based instances as well
1430 cc9e1230 Guido Trotter
        if vg_name is not None:
1431 a0c9776a Iustin Pop
          test = (constants.NV_VGLIST not in nresult or
1432 a0c9776a Iustin Pop
                  vg_name not in nresult[constants.NV_VGLIST])
1433 a0c9776a Iustin Pop
          _ErrorIf(test, self.ENODELVM, node,
1434 a0c9776a Iustin Pop
                   "node didn't return data for the volume group '%s'"
1435 a0c9776a Iustin Pop
                   " - it is either missing or broken", vg_name)
1436 a0c9776a Iustin Pop
          if test:
1437 9a198532 Iustin Pop
            continue
1438 cc9e1230 Guido Trotter
          node_info[node]["dfree"] = int(nresult[constants.NV_VGLIST][vg_name])
1439 9a198532 Iustin Pop
      except (ValueError, KeyError):
1440 a0c9776a Iustin Pop
        _ErrorIf(True, self.ENODERPC, node,
1441 a0c9776a Iustin Pop
                 "node returned invalid nodeinfo, check lvm/hypervisor")
1442 9c9c7d30 Guido Trotter
        continue
1443 9c9c7d30 Guido Trotter
1444 a8083063 Iustin Pop
    node_vol_should = {}
1445 a8083063 Iustin Pop
1446 7c874ee1 Iustin Pop
    feedback_fn("* Verifying instance status")
1447 a8083063 Iustin Pop
    for instance in instancelist:
1448 7c874ee1 Iustin Pop
      if verbose:
1449 7c874ee1 Iustin Pop
        feedback_fn("* Verifying instance %s" % instance)
1450 6d2e83d5 Iustin Pop
      inst_config = instanceinfo[instance]
1451 a0c9776a Iustin Pop
      self._VerifyInstance(instance, inst_config, node_volume,
1452 a0c9776a Iustin Pop
                           node_instance, n_offline)
1453 832261fd Iustin Pop
      inst_nodes_offline = []
1454 a8083063 Iustin Pop
1455 a8083063 Iustin Pop
      inst_config.MapLVsByNode(node_vol_should)
1456 a8083063 Iustin Pop
1457 26b6af5e Guido Trotter
      instance_cfg[instance] = inst_config
1458 26b6af5e Guido Trotter
1459 93e4c50b Guido Trotter
      pnode = inst_config.primary_node
1460 a0c9776a Iustin Pop
      _ErrorIf(pnode not in node_info and pnode not in n_offline,
1461 a0c9776a Iustin Pop
               self.ENODERPC, pnode, "instance %s, connection to"
1462 a0c9776a Iustin Pop
               " primary node failed", instance)
1463 93e4c50b Guido Trotter
      if pnode in node_info:
1464 93e4c50b Guido Trotter
        node_info[pnode]['pinst'].append(instance)
1465 93e4c50b Guido Trotter
1466 832261fd Iustin Pop
      if pnode in n_offline:
1467 832261fd Iustin Pop
        inst_nodes_offline.append(pnode)
1468 832261fd Iustin Pop
1469 93e4c50b Guido Trotter
      # If the instance is non-redundant we cannot survive losing its primary
1470 93e4c50b Guido Trotter
      # node, so we are not N+1 compliant. On the other hand we have no disk
1471 93e4c50b Guido Trotter
      # templates with more than one secondary so that situation is not well
1472 93e4c50b Guido Trotter
      # supported either.
1473 93e4c50b Guido Trotter
      # FIXME: does not support file-backed instances
1474 93e4c50b Guido Trotter
      if len(inst_config.secondary_nodes) == 0:
1475 93e4c50b Guido Trotter
        i_non_redundant.append(instance)
1476 a0c9776a Iustin Pop
      _ErrorIf(len(inst_config.secondary_nodes) > 1,
1477 a0c9776a Iustin Pop
               self.EINSTANCELAYOUT, instance,
1478 a0c9776a Iustin Pop
               "instance has multiple secondary nodes", code="WARNING")
1479 93e4c50b Guido Trotter
1480 c0f2b229 Iustin Pop
      if not cluster.FillBE(inst_config)[constants.BE_AUTO_BALANCE]:
1481 3924700f Iustin Pop
        i_non_a_balanced.append(instance)
1482 3924700f Iustin Pop
1483 93e4c50b Guido Trotter
      for snode in inst_config.secondary_nodes:
1484 a0c9776a Iustin Pop
        _ErrorIf(snode not in node_info and snode not in n_offline,
1485 a0c9776a Iustin Pop
                 self.ENODERPC, snode,
1486 a0c9776a Iustin Pop
                 "instance %s, connection to secondary node"
1487 a0c9776a Iustin Pop
                 "failed", instance)
1488 a0c9776a Iustin Pop
1489 93e4c50b Guido Trotter
        if snode in node_info:
1490 93e4c50b Guido Trotter
          node_info[snode]['sinst'].append(instance)
1491 36e7da50 Guido Trotter
          if pnode not in node_info[snode]['sinst-by-pnode']:
1492 36e7da50 Guido Trotter
            node_info[snode]['sinst-by-pnode'][pnode] = []
1493 36e7da50 Guido Trotter
          node_info[snode]['sinst-by-pnode'][pnode].append(instance)
1494 a0c9776a Iustin Pop
1495 832261fd Iustin Pop
        if snode in n_offline:
1496 832261fd Iustin Pop
          inst_nodes_offline.append(snode)
1497 832261fd Iustin Pop
1498 a0c9776a Iustin Pop
      # warn that the instance lives on offline nodes
1499 a0c9776a Iustin Pop
      _ErrorIf(inst_nodes_offline, self.EINSTANCEBADNODE, instance,
1500 a0c9776a Iustin Pop
               "instance lives on offline node(s) %s",
1501 a0c9776a Iustin Pop
               ", ".join(inst_nodes_offline))
1502 93e4c50b Guido Trotter
1503 a8083063 Iustin Pop
    feedback_fn("* Verifying orphan volumes")
1504 a0c9776a Iustin Pop
    self._VerifyOrphanVolumes(node_vol_should, node_volume)
1505 a8083063 Iustin Pop
1506 a8083063 Iustin Pop
    feedback_fn("* Verifying remaining instances")
1507 a0c9776a Iustin Pop
    self._VerifyOrphanInstances(instancelist, node_instance)
1508 a8083063 Iustin Pop
1509 e54c4c5e Guido Trotter
    if constants.VERIFY_NPLUSONE_MEM not in self.skip_set:
1510 e54c4c5e Guido Trotter
      feedback_fn("* Verifying N+1 Memory redundancy")
1511 a0c9776a Iustin Pop
      self._VerifyNPlusOneMemory(node_info, instance_cfg)
1512 2b3b6ddd Guido Trotter
1513 2b3b6ddd Guido Trotter
    feedback_fn("* Other Notes")
1514 2b3b6ddd Guido Trotter
    if i_non_redundant:
1515 2b3b6ddd Guido Trotter
      feedback_fn("  - NOTICE: %d non-redundant instance(s) found."
1516 2b3b6ddd Guido Trotter
                  % len(i_non_redundant))
1517 2b3b6ddd Guido Trotter
1518 3924700f Iustin Pop
    if i_non_a_balanced:
1519 3924700f Iustin Pop
      feedback_fn("  - NOTICE: %d non-auto-balanced instance(s) found."
1520 3924700f Iustin Pop
                  % len(i_non_a_balanced))
1521 3924700f Iustin Pop
1522 0a66c968 Iustin Pop
    if n_offline:
1523 0a66c968 Iustin Pop
      feedback_fn("  - NOTICE: %d offline node(s) found." % len(n_offline))
1524 0a66c968 Iustin Pop
1525 22f0f71d Iustin Pop
    if n_drained:
1526 22f0f71d Iustin Pop
      feedback_fn("  - NOTICE: %d drained node(s) found." % len(n_drained))
1527 22f0f71d Iustin Pop
1528 a0c9776a Iustin Pop
    return not self.bad
1529 a8083063 Iustin Pop
1530 d8fff41c Guido Trotter
  def HooksCallBack(self, phase, hooks_results, feedback_fn, lu_result):
1531 5bbd3f7f Michael Hanselmann
    """Analyze the post-hooks' result
1532 e4376078 Iustin Pop

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

1536 e4376078 Iustin Pop
    @param phase: one of L{constants.HOOKS_PHASE_POST} or
1537 e4376078 Iustin Pop
        L{constants.HOOKS_PHASE_PRE}; it denotes the hooks phase
1538 e4376078 Iustin Pop
    @param hooks_results: the results of the multi-node hooks rpc call
1539 e4376078 Iustin Pop
    @param feedback_fn: function used send feedback back to the caller
1540 e4376078 Iustin Pop
    @param lu_result: previous Exec result
1541 e4376078 Iustin Pop
    @return: the new Exec result, based on the previous result
1542 e4376078 Iustin Pop
        and hook results
1543 d8fff41c Guido Trotter

1544 d8fff41c Guido Trotter
    """
1545 38206f3c Iustin Pop
    # We only really run POST phase hooks, and are only interested in
1546 38206f3c Iustin Pop
    # their results
1547 d8fff41c Guido Trotter
    if phase == constants.HOOKS_PHASE_POST:
1548 d8fff41c Guido Trotter
      # Used to change hooks' output to proper indentation
1549 d8fff41c Guido Trotter
      indent_re = re.compile('^', re.M)
1550 d8fff41c Guido Trotter
      feedback_fn("* Hooks Results")
1551 7c874ee1 Iustin Pop
      assert hooks_results, "invalid result from hooks"
1552 7c874ee1 Iustin Pop
1553 7c874ee1 Iustin Pop
      for node_name in hooks_results:
1554 7c874ee1 Iustin Pop
        show_node_header = True
1555 7c874ee1 Iustin Pop
        res = hooks_results[node_name]
1556 7c874ee1 Iustin Pop
        msg = res.fail_msg
1557 a0c9776a Iustin Pop
        test = msg and not res.offline
1558 a0c9776a Iustin Pop
        self._ErrorIf(test, self.ENODEHOOKS, node_name,
1559 7c874ee1 Iustin Pop
                      "Communication failure in hooks execution: %s", msg)
1560 a0c9776a Iustin Pop
        if test:
1561 a0c9776a Iustin Pop
          # override manually lu_result here as _ErrorIf only
1562 a0c9776a Iustin Pop
          # overrides self.bad
1563 7c874ee1 Iustin Pop
          lu_result = 1
1564 7c874ee1 Iustin Pop
          continue
1565 7c874ee1 Iustin Pop
        for script, hkr, output in res.payload:
1566 a0c9776a Iustin Pop
          test = hkr == constants.HKR_FAIL
1567 a0c9776a Iustin Pop
          self._ErrorIf(test, self.ENODEHOOKS, node_name,
1568 7c874ee1 Iustin Pop
                        "Script %s failed, output:", script)
1569 a0c9776a Iustin Pop
          if test:
1570 7c874ee1 Iustin Pop
            output = indent_re.sub('      ', output)
1571 7c874ee1 Iustin Pop
            feedback_fn("%s" % output)
1572 7c874ee1 Iustin Pop
            lu_result = 1
1573 d8fff41c Guido Trotter
1574 d8fff41c Guido Trotter
      return lu_result
1575 d8fff41c Guido Trotter
1576 a8083063 Iustin Pop
1577 2c95a8d4 Iustin Pop
class LUVerifyDisks(NoHooksLU):
1578 2c95a8d4 Iustin Pop
  """Verifies the cluster disks status.
1579 2c95a8d4 Iustin Pop

1580 2c95a8d4 Iustin Pop
  """
1581 2c95a8d4 Iustin Pop
  _OP_REQP = []
1582 d4b9d97f Guido Trotter
  REQ_BGL = False
1583 d4b9d97f Guido Trotter
1584 d4b9d97f Guido Trotter
  def ExpandNames(self):
1585 d4b9d97f Guido Trotter
    self.needed_locks = {
1586 d4b9d97f Guido Trotter
      locking.LEVEL_NODE: locking.ALL_SET,
1587 d4b9d97f Guido Trotter
      locking.LEVEL_INSTANCE: locking.ALL_SET,
1588 d4b9d97f Guido Trotter
    }
1589 c772d142 Michael Hanselmann
    self.share_locks = dict.fromkeys(locking.LEVELS, 1)
1590 2c95a8d4 Iustin Pop
1591 2c95a8d4 Iustin Pop
  def CheckPrereq(self):
1592 2c95a8d4 Iustin Pop
    """Check prerequisites.
1593 2c95a8d4 Iustin Pop

1594 2c95a8d4 Iustin Pop
    This has no prerequisites.
1595 2c95a8d4 Iustin Pop

1596 2c95a8d4 Iustin Pop
    """
1597 2c95a8d4 Iustin Pop
    pass
1598 2c95a8d4 Iustin Pop
1599 2c95a8d4 Iustin Pop
  def Exec(self, feedback_fn):
1600 2c95a8d4 Iustin Pop
    """Verify integrity of cluster disks.
1601 2c95a8d4 Iustin Pop

1602 29d376ec Iustin Pop
    @rtype: tuple of three items
1603 29d376ec Iustin Pop
    @return: a tuple of (dict of node-to-node_error, list of instances
1604 29d376ec Iustin Pop
        which need activate-disks, dict of instance: (node, volume) for
1605 29d376ec Iustin Pop
        missing volumes
1606 29d376ec Iustin Pop

1607 2c95a8d4 Iustin Pop
    """
1608 29d376ec Iustin Pop
    result = res_nodes, res_instances, res_missing = {}, [], {}
1609 2c95a8d4 Iustin Pop
1610 2c95a8d4 Iustin Pop
    vg_name = self.cfg.GetVGName()
1611 2c95a8d4 Iustin Pop
    nodes = utils.NiceSort(self.cfg.GetNodeList())
1612 2c95a8d4 Iustin Pop
    instances = [self.cfg.GetInstanceInfo(name)
1613 2c95a8d4 Iustin Pop
                 for name in self.cfg.GetInstanceList()]
1614 2c95a8d4 Iustin Pop
1615 2c95a8d4 Iustin Pop
    nv_dict = {}
1616 2c95a8d4 Iustin Pop
    for inst in instances:
1617 2c95a8d4 Iustin Pop
      inst_lvs = {}
1618 0d68c45d Iustin Pop
      if (not inst.admin_up or
1619 2c95a8d4 Iustin Pop
          inst.disk_template not in constants.DTS_NET_MIRROR):
1620 2c95a8d4 Iustin Pop
        continue
1621 2c95a8d4 Iustin Pop
      inst.MapLVsByNode(inst_lvs)
1622 2c95a8d4 Iustin Pop
      # transform { iname: {node: [vol,],},} to {(node, vol): iname}
1623 2c95a8d4 Iustin Pop
      for node, vol_list in inst_lvs.iteritems():
1624 2c95a8d4 Iustin Pop
        for vol in vol_list:
1625 2c95a8d4 Iustin Pop
          nv_dict[(node, vol)] = inst
1626 2c95a8d4 Iustin Pop
1627 2c95a8d4 Iustin Pop
    if not nv_dict:
1628 2c95a8d4 Iustin Pop
      return result
1629 2c95a8d4 Iustin Pop
1630 b2a6ccd4 Iustin Pop
    node_lvs = self.rpc.call_lv_list(nodes, vg_name)
1631 2c95a8d4 Iustin Pop
1632 2c95a8d4 Iustin Pop
    for node in nodes:
1633 2c95a8d4 Iustin Pop
      # node_volume
1634 29d376ec Iustin Pop
      node_res = node_lvs[node]
1635 29d376ec Iustin Pop
      if node_res.offline:
1636 ea9ddc07 Iustin Pop
        continue
1637 4c4e4e1e Iustin Pop
      msg = node_res.fail_msg
1638 29d376ec Iustin Pop
      if msg:
1639 29d376ec Iustin Pop
        logging.warning("Error enumerating LVs on node %s: %s", node, msg)
1640 29d376ec Iustin Pop
        res_nodes[node] = msg
1641 2c95a8d4 Iustin Pop
        continue
1642 2c95a8d4 Iustin Pop
1643 29d376ec Iustin Pop
      lvs = node_res.payload
1644 29d376ec Iustin Pop
      for lv_name, (_, lv_inactive, lv_online) in lvs.items():
1645 b63ed789 Iustin Pop
        inst = nv_dict.pop((node, lv_name), None)
1646 b63ed789 Iustin Pop
        if (not lv_online and inst is not None
1647 b63ed789 Iustin Pop
            and inst.name not in res_instances):
1648 b08d5a87 Iustin Pop
          res_instances.append(inst.name)
1649 2c95a8d4 Iustin Pop
1650 b63ed789 Iustin Pop
    # any leftover items in nv_dict are missing LVs, let's arrange the
1651 b63ed789 Iustin Pop
    # data better
1652 b63ed789 Iustin Pop
    for key, inst in nv_dict.iteritems():
1653 b63ed789 Iustin Pop
      if inst.name not in res_missing:
1654 b63ed789 Iustin Pop
        res_missing[inst.name] = []
1655 b63ed789 Iustin Pop
      res_missing[inst.name].append(key)
1656 b63ed789 Iustin Pop
1657 2c95a8d4 Iustin Pop
    return result
1658 2c95a8d4 Iustin Pop
1659 2c95a8d4 Iustin Pop
1660 60975797 Iustin Pop
class LURepairDiskSizes(NoHooksLU):
1661 60975797 Iustin Pop
  """Verifies the cluster disks sizes.
1662 60975797 Iustin Pop

1663 60975797 Iustin Pop
  """
1664 60975797 Iustin Pop
  _OP_REQP = ["instances"]
1665 60975797 Iustin Pop
  REQ_BGL = False
1666 60975797 Iustin Pop
1667 60975797 Iustin Pop
  def ExpandNames(self):
1668 60975797 Iustin Pop
    if not isinstance(self.op.instances, list):
1669 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Invalid argument type 'instances'",
1670 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
1671 60975797 Iustin Pop
1672 60975797 Iustin Pop
    if self.op.instances:
1673 60975797 Iustin Pop
      self.wanted_names = []
1674 60975797 Iustin Pop
      for name in self.op.instances:
1675 60975797 Iustin Pop
        full_name = self.cfg.ExpandInstanceName(name)
1676 60975797 Iustin Pop
        if full_name is None:
1677 5c983ee5 Iustin Pop
          raise errors.OpPrereqError("Instance '%s' not known" % name,
1678 5c983ee5 Iustin Pop
                                     errors.ECODE_NOENT)
1679 60975797 Iustin Pop
        self.wanted_names.append(full_name)
1680 60975797 Iustin Pop
      self.needed_locks = {
1681 60975797 Iustin Pop
        locking.LEVEL_NODE: [],
1682 60975797 Iustin Pop
        locking.LEVEL_INSTANCE: self.wanted_names,
1683 60975797 Iustin Pop
        }
1684 60975797 Iustin Pop
      self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
1685 60975797 Iustin Pop
    else:
1686 60975797 Iustin Pop
      self.wanted_names = None
1687 60975797 Iustin Pop
      self.needed_locks = {
1688 60975797 Iustin Pop
        locking.LEVEL_NODE: locking.ALL_SET,
1689 60975797 Iustin Pop
        locking.LEVEL_INSTANCE: locking.ALL_SET,
1690 60975797 Iustin Pop
        }
1691 60975797 Iustin Pop
    self.share_locks = dict(((i, 1) for i in locking.LEVELS))
1692 60975797 Iustin Pop
1693 60975797 Iustin Pop
  def DeclareLocks(self, level):
1694 60975797 Iustin Pop
    if level == locking.LEVEL_NODE and self.wanted_names is not None:
1695 60975797 Iustin Pop
      self._LockInstancesNodes(primary_only=True)
1696 60975797 Iustin Pop
1697 60975797 Iustin Pop
  def CheckPrereq(self):
1698 60975797 Iustin Pop
    """Check prerequisites.
1699 60975797 Iustin Pop

1700 60975797 Iustin Pop
    This only checks the optional instance list against the existing names.
1701 60975797 Iustin Pop

1702 60975797 Iustin Pop
    """
1703 60975797 Iustin Pop
    if self.wanted_names is None:
1704 60975797 Iustin Pop
      self.wanted_names = self.acquired_locks[locking.LEVEL_INSTANCE]
1705 60975797 Iustin Pop
1706 60975797 Iustin Pop
    self.wanted_instances = [self.cfg.GetInstanceInfo(name) for name
1707 60975797 Iustin Pop
                             in self.wanted_names]
1708 60975797 Iustin Pop
1709 b775c337 Iustin Pop
  def _EnsureChildSizes(self, disk):
1710 b775c337 Iustin Pop
    """Ensure children of the disk have the needed disk size.
1711 b775c337 Iustin Pop

1712 b775c337 Iustin Pop
    This is valid mainly for DRBD8 and fixes an issue where the
1713 b775c337 Iustin Pop
    children have smaller disk size.
1714 b775c337 Iustin Pop

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

1717 b775c337 Iustin Pop
    """
1718 b775c337 Iustin Pop
    if disk.dev_type == constants.LD_DRBD8:
1719 b775c337 Iustin Pop
      assert disk.children, "Empty children for DRBD8?"
1720 b775c337 Iustin Pop
      fchild = disk.children[0]
1721 b775c337 Iustin Pop
      mismatch = fchild.size < disk.size
1722 b775c337 Iustin Pop
      if mismatch:
1723 b775c337 Iustin Pop
        self.LogInfo("Child disk has size %d, parent %d, fixing",
1724 b775c337 Iustin Pop
                     fchild.size, disk.size)
1725 b775c337 Iustin Pop
        fchild.size = disk.size
1726 b775c337 Iustin Pop
1727 b775c337 Iustin Pop
      # and we recurse on this child only, not on the metadev
1728 b775c337 Iustin Pop
      return self._EnsureChildSizes(fchild) or mismatch
1729 b775c337 Iustin Pop
    else:
1730 b775c337 Iustin Pop
      return False
1731 b775c337 Iustin Pop
1732 60975797 Iustin Pop
  def Exec(self, feedback_fn):
1733 60975797 Iustin Pop
    """Verify the size of cluster disks.
1734 60975797 Iustin Pop

1735 60975797 Iustin Pop
    """
1736 60975797 Iustin Pop
    # TODO: check child disks too
1737 60975797 Iustin Pop
    # TODO: check differences in size between primary/secondary nodes
1738 60975797 Iustin Pop
    per_node_disks = {}
1739 60975797 Iustin Pop
    for instance in self.wanted_instances:
1740 60975797 Iustin Pop
      pnode = instance.primary_node
1741 60975797 Iustin Pop
      if pnode not in per_node_disks:
1742 60975797 Iustin Pop
        per_node_disks[pnode] = []
1743 60975797 Iustin Pop
      for idx, disk in enumerate(instance.disks):
1744 60975797 Iustin Pop
        per_node_disks[pnode].append((instance, idx, disk))
1745 60975797 Iustin Pop
1746 60975797 Iustin Pop
    changed = []
1747 60975797 Iustin Pop
    for node, dskl in per_node_disks.items():
1748 4d9e6835 Iustin Pop
      newl = [v[2].Copy() for v in dskl]
1749 4d9e6835 Iustin Pop
      for dsk in newl:
1750 4d9e6835 Iustin Pop
        self.cfg.SetDiskID(dsk, node)
1751 4d9e6835 Iustin Pop
      result = self.rpc.call_blockdev_getsizes(node, newl)
1752 3cebe102 Michael Hanselmann
      if result.fail_msg:
1753 60975797 Iustin Pop
        self.LogWarning("Failure in blockdev_getsizes call to node"
1754 60975797 Iustin Pop
                        " %s, ignoring", node)
1755 60975797 Iustin Pop
        continue
1756 60975797 Iustin Pop
      if len(result.data) != len(dskl):
1757 60975797 Iustin Pop
        self.LogWarning("Invalid result from node %s, ignoring node results",
1758 60975797 Iustin Pop
                        node)
1759 60975797 Iustin Pop
        continue
1760 60975797 Iustin Pop
      for ((instance, idx, disk), size) in zip(dskl, result.data):
1761 60975797 Iustin Pop
        if size is None:
1762 60975797 Iustin Pop
          self.LogWarning("Disk %d of instance %s did not return size"
1763 60975797 Iustin Pop
                          " information, ignoring", idx, instance.name)
1764 60975797 Iustin Pop
          continue
1765 60975797 Iustin Pop
        if not isinstance(size, (int, long)):
1766 60975797 Iustin Pop
          self.LogWarning("Disk %d of instance %s did not return valid"
1767 60975797 Iustin Pop
                          " size information, ignoring", idx, instance.name)
1768 60975797 Iustin Pop
          continue
1769 60975797 Iustin Pop
        size = size >> 20
1770 60975797 Iustin Pop
        if size != disk.size:
1771 60975797 Iustin Pop
          self.LogInfo("Disk %d of instance %s has mismatched size,"
1772 60975797 Iustin Pop
                       " correcting: recorded %d, actual %d", idx,
1773 60975797 Iustin Pop
                       instance.name, disk.size, size)
1774 60975797 Iustin Pop
          disk.size = size
1775 a4eae71f Michael Hanselmann
          self.cfg.Update(instance, feedback_fn)
1776 60975797 Iustin Pop
          changed.append((instance.name, idx, size))
1777 b775c337 Iustin Pop
        if self._EnsureChildSizes(disk):
1778 a4eae71f Michael Hanselmann
          self.cfg.Update(instance, feedback_fn)
1779 b775c337 Iustin Pop
          changed.append((instance.name, idx, disk.size))
1780 60975797 Iustin Pop
    return changed
1781 60975797 Iustin Pop
1782 60975797 Iustin Pop
1783 07bd8a51 Iustin Pop
class LURenameCluster(LogicalUnit):
1784 07bd8a51 Iustin Pop
  """Rename the cluster.
1785 07bd8a51 Iustin Pop

1786 07bd8a51 Iustin Pop
  """
1787 07bd8a51 Iustin Pop
  HPATH = "cluster-rename"
1788 07bd8a51 Iustin Pop
  HTYPE = constants.HTYPE_CLUSTER
1789 07bd8a51 Iustin Pop
  _OP_REQP = ["name"]
1790 07bd8a51 Iustin Pop
1791 07bd8a51 Iustin Pop
  def BuildHooksEnv(self):
1792 07bd8a51 Iustin Pop
    """Build hooks env.
1793 07bd8a51 Iustin Pop

1794 07bd8a51 Iustin Pop
    """
1795 07bd8a51 Iustin Pop
    env = {
1796 d6a02168 Michael Hanselmann
      "OP_TARGET": self.cfg.GetClusterName(),
1797 07bd8a51 Iustin Pop
      "NEW_NAME": self.op.name,
1798 07bd8a51 Iustin Pop
      }
1799 d6a02168 Michael Hanselmann
    mn = self.cfg.GetMasterNode()
1800 07bd8a51 Iustin Pop
    return env, [mn], [mn]
1801 07bd8a51 Iustin Pop
1802 07bd8a51 Iustin Pop
  def CheckPrereq(self):
1803 07bd8a51 Iustin Pop
    """Verify that the passed name is a valid one.
1804 07bd8a51 Iustin Pop

1805 07bd8a51 Iustin Pop
    """
1806 104f4ca1 Iustin Pop
    hostname = utils.GetHostInfo(self.op.name)
1807 07bd8a51 Iustin Pop
1808 bcf043c9 Iustin Pop
    new_name = hostname.name
1809 bcf043c9 Iustin Pop
    self.ip = new_ip = hostname.ip
1810 d6a02168 Michael Hanselmann
    old_name = self.cfg.GetClusterName()
1811 d6a02168 Michael Hanselmann
    old_ip = self.cfg.GetMasterIP()
1812 07bd8a51 Iustin Pop
    if new_name == old_name and new_ip == old_ip:
1813 07bd8a51 Iustin Pop
      raise errors.OpPrereqError("Neither the name nor the IP address of the"
1814 5c983ee5 Iustin Pop
                                 " cluster has changed",
1815 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
1816 07bd8a51 Iustin Pop
    if new_ip != old_ip:
1817 937f983d Guido Trotter
      if utils.TcpPing(new_ip, constants.DEFAULT_NODED_PORT):
1818 07bd8a51 Iustin Pop
        raise errors.OpPrereqError("The given cluster IP address (%s) is"
1819 07bd8a51 Iustin Pop
                                   " reachable on the network. Aborting." %
1820 5c983ee5 Iustin Pop
                                   new_ip, errors.ECODE_NOTUNIQUE)
1821 07bd8a51 Iustin Pop
1822 07bd8a51 Iustin Pop
    self.op.name = new_name
1823 07bd8a51 Iustin Pop
1824 07bd8a51 Iustin Pop
  def Exec(self, feedback_fn):
1825 07bd8a51 Iustin Pop
    """Rename the cluster.
1826 07bd8a51 Iustin Pop

1827 07bd8a51 Iustin Pop
    """
1828 07bd8a51 Iustin Pop
    clustername = self.op.name
1829 07bd8a51 Iustin Pop
    ip = self.ip
1830 07bd8a51 Iustin Pop
1831 07bd8a51 Iustin Pop
    # shutdown the master IP
1832 d6a02168 Michael Hanselmann
    master = self.cfg.GetMasterNode()
1833 781de953 Iustin Pop
    result = self.rpc.call_node_stop_master(master, False)
1834 4c4e4e1e Iustin Pop
    result.Raise("Could not disable the master role")
1835 07bd8a51 Iustin Pop
1836 07bd8a51 Iustin Pop
    try:
1837 55cf7d83 Iustin Pop
      cluster = self.cfg.GetClusterInfo()
1838 55cf7d83 Iustin Pop
      cluster.cluster_name = clustername
1839 55cf7d83 Iustin Pop
      cluster.master_ip = ip
1840 a4eae71f Michael Hanselmann
      self.cfg.Update(cluster, feedback_fn)
1841 ec85e3d5 Iustin Pop
1842 ec85e3d5 Iustin Pop
      # update the known hosts file
1843 ec85e3d5 Iustin Pop
      ssh.WriteKnownHostsFile(self.cfg, constants.SSH_KNOWN_HOSTS_FILE)
1844 ec85e3d5 Iustin Pop
      node_list = self.cfg.GetNodeList()
1845 ec85e3d5 Iustin Pop
      try:
1846 ec85e3d5 Iustin Pop
        node_list.remove(master)
1847 ec85e3d5 Iustin Pop
      except ValueError:
1848 ec85e3d5 Iustin Pop
        pass
1849 ec85e3d5 Iustin Pop
      result = self.rpc.call_upload_file(node_list,
1850 ec85e3d5 Iustin Pop
                                         constants.SSH_KNOWN_HOSTS_FILE)
1851 ec85e3d5 Iustin Pop
      for to_node, to_result in result.iteritems():
1852 6f7d4e75 Iustin Pop
        msg = to_result.fail_msg
1853 6f7d4e75 Iustin Pop
        if msg:
1854 6f7d4e75 Iustin Pop
          msg = ("Copy of file %s to node %s failed: %s" %
1855 6f7d4e75 Iustin Pop
                 (constants.SSH_KNOWN_HOSTS_FILE, to_node, msg))
1856 6f7d4e75 Iustin Pop
          self.proc.LogWarning(msg)
1857 ec85e3d5 Iustin Pop
1858 07bd8a51 Iustin Pop
    finally:
1859 3583908a Guido Trotter
      result = self.rpc.call_node_start_master(master, False, False)
1860 4c4e4e1e Iustin Pop
      msg = result.fail_msg
1861 b726aff0 Iustin Pop
      if msg:
1862 86d9d3bb Iustin Pop
        self.LogWarning("Could not re-enable the master role on"
1863 b726aff0 Iustin Pop
                        " the master, please restart manually: %s", msg)
1864 07bd8a51 Iustin Pop
1865 07bd8a51 Iustin Pop
1866 8084f9f6 Manuel Franceschini
def _RecursiveCheckIfLVMBased(disk):
1867 8084f9f6 Manuel Franceschini
  """Check if the given disk or its children are lvm-based.
1868 8084f9f6 Manuel Franceschini

1869 e4376078 Iustin Pop
  @type disk: L{objects.Disk}
1870 e4376078 Iustin Pop
  @param disk: the disk to check
1871 5bbd3f7f Michael Hanselmann
  @rtype: boolean
1872 e4376078 Iustin Pop
  @return: boolean indicating whether a LD_LV dev_type was found or not
1873 8084f9f6 Manuel Franceschini

1874 8084f9f6 Manuel Franceschini
  """
1875 8084f9f6 Manuel Franceschini
  if disk.children:
1876 8084f9f6 Manuel Franceschini
    for chdisk in disk.children:
1877 8084f9f6 Manuel Franceschini
      if _RecursiveCheckIfLVMBased(chdisk):
1878 8084f9f6 Manuel Franceschini
        return True
1879 8084f9f6 Manuel Franceschini
  return disk.dev_type == constants.LD_LV
1880 8084f9f6 Manuel Franceschini
1881 8084f9f6 Manuel Franceschini
1882 8084f9f6 Manuel Franceschini
class LUSetClusterParams(LogicalUnit):
1883 8084f9f6 Manuel Franceschini
  """Change the parameters of the cluster.
1884 8084f9f6 Manuel Franceschini

1885 8084f9f6 Manuel Franceschini
  """
1886 8084f9f6 Manuel Franceschini
  HPATH = "cluster-modify"
1887 8084f9f6 Manuel Franceschini
  HTYPE = constants.HTYPE_CLUSTER
1888 8084f9f6 Manuel Franceschini
  _OP_REQP = []
1889 c53279cf Guido Trotter
  REQ_BGL = False
1890 c53279cf Guido Trotter
1891 3994f455 Iustin Pop
  def CheckArguments(self):
1892 4b7735f9 Iustin Pop
    """Check parameters
1893 4b7735f9 Iustin Pop

1894 4b7735f9 Iustin Pop
    """
1895 4b7735f9 Iustin Pop
    if not hasattr(self.op, "candidate_pool_size"):
1896 4b7735f9 Iustin Pop
      self.op.candidate_pool_size = None
1897 4b7735f9 Iustin Pop
    if self.op.candidate_pool_size is not None:
1898 4b7735f9 Iustin Pop
      try:
1899 4b7735f9 Iustin Pop
        self.op.candidate_pool_size = int(self.op.candidate_pool_size)
1900 3994f455 Iustin Pop
      except (ValueError, TypeError), err:
1901 4b7735f9 Iustin Pop
        raise errors.OpPrereqError("Invalid candidate_pool_size value: %s" %
1902 5c983ee5 Iustin Pop
                                   str(err), errors.ECODE_INVAL)
1903 4b7735f9 Iustin Pop
      if self.op.candidate_pool_size < 1:
1904 5c983ee5 Iustin Pop
        raise errors.OpPrereqError("At least one master candidate needed",
1905 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
1906 4b7735f9 Iustin Pop
1907 c53279cf Guido Trotter
  def ExpandNames(self):
1908 c53279cf Guido Trotter
    # FIXME: in the future maybe other cluster params won't require checking on
1909 c53279cf Guido Trotter
    # all nodes to be modified.
1910 c53279cf Guido Trotter
    self.needed_locks = {
1911 c53279cf Guido Trotter
      locking.LEVEL_NODE: locking.ALL_SET,
1912 c53279cf Guido Trotter
    }
1913 c53279cf Guido Trotter
    self.share_locks[locking.LEVEL_NODE] = 1
1914 8084f9f6 Manuel Franceschini
1915 8084f9f6 Manuel Franceschini
  def BuildHooksEnv(self):
1916 8084f9f6 Manuel Franceschini
    """Build hooks env.
1917 8084f9f6 Manuel Franceschini

1918 8084f9f6 Manuel Franceschini
    """
1919 8084f9f6 Manuel Franceschini
    env = {
1920 d6a02168 Michael Hanselmann
      "OP_TARGET": self.cfg.GetClusterName(),
1921 8084f9f6 Manuel Franceschini
      "NEW_VG_NAME": self.op.vg_name,
1922 8084f9f6 Manuel Franceschini
      }
1923 d6a02168 Michael Hanselmann
    mn = self.cfg.GetMasterNode()
1924 8084f9f6 Manuel Franceschini
    return env, [mn], [mn]
1925 8084f9f6 Manuel Franceschini
1926 8084f9f6 Manuel Franceschini
  def CheckPrereq(self):
1927 8084f9f6 Manuel Franceschini
    """Check prerequisites.
1928 8084f9f6 Manuel Franceschini

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

1932 8084f9f6 Manuel Franceschini
    """
1933 779c15bb Iustin Pop
    if self.op.vg_name is not None and not self.op.vg_name:
1934 c53279cf Guido Trotter
      instances = self.cfg.GetAllInstancesInfo().values()
1935 8084f9f6 Manuel Franceschini
      for inst in instances:
1936 8084f9f6 Manuel Franceschini
        for disk in inst.disks:
1937 8084f9f6 Manuel Franceschini
          if _RecursiveCheckIfLVMBased(disk):
1938 8084f9f6 Manuel Franceschini
            raise errors.OpPrereqError("Cannot disable lvm storage while"
1939 5c983ee5 Iustin Pop
                                       " lvm-based instances exist",
1940 5c983ee5 Iustin Pop
                                       errors.ECODE_INVAL)
1941 8084f9f6 Manuel Franceschini
1942 779c15bb Iustin Pop
    node_list = self.acquired_locks[locking.LEVEL_NODE]
1943 779c15bb Iustin Pop
1944 8084f9f6 Manuel Franceschini
    # if vg_name not None, checks given volume group on all nodes
1945 8084f9f6 Manuel Franceschini
    if self.op.vg_name:
1946 72737a7f Iustin Pop
      vglist = self.rpc.call_vg_list(node_list)
1947 8084f9f6 Manuel Franceschini
      for node in node_list:
1948 4c4e4e1e Iustin Pop
        msg = vglist[node].fail_msg
1949 e480923b Iustin Pop
        if msg:
1950 781de953 Iustin Pop
          # ignoring down node
1951 e480923b Iustin Pop
          self.LogWarning("Error while gathering data on node %s"
1952 e480923b Iustin Pop
                          " (ignoring node): %s", node, msg)
1953 781de953 Iustin Pop
          continue
1954 e480923b Iustin Pop
        vgstatus = utils.CheckVolumeGroupSize(vglist[node].payload,
1955 781de953 Iustin Pop
                                              self.op.vg_name,
1956 8d1a2a64 Michael Hanselmann
                                              constants.MIN_VG_SIZE)
1957 8084f9f6 Manuel Franceschini
        if vgstatus:
1958 8084f9f6 Manuel Franceschini
          raise errors.OpPrereqError("Error on node '%s': %s" %
1959 5c983ee5 Iustin Pop
                                     (node, vgstatus), errors.ECODE_ENVIRON)
1960 8084f9f6 Manuel Franceschini
1961 779c15bb Iustin Pop
    self.cluster = cluster = self.cfg.GetClusterInfo()
1962 5af3da74 Guido Trotter
    # validate params changes
1963 779c15bb Iustin Pop
    if self.op.beparams:
1964 a5728081 Guido Trotter
      utils.ForceDictType(self.op.beparams, constants.BES_PARAMETER_TYPES)
1965 abe609b2 Guido Trotter
      self.new_beparams = objects.FillDict(
1966 4ef7f423 Guido Trotter
        cluster.beparams[constants.PP_DEFAULT], self.op.beparams)
1967 779c15bb Iustin Pop
1968 5af3da74 Guido Trotter
    if self.op.nicparams:
1969 5af3da74 Guido Trotter
      utils.ForceDictType(self.op.nicparams, constants.NICS_PARAMETER_TYPES)
1970 5af3da74 Guido Trotter
      self.new_nicparams = objects.FillDict(
1971 5af3da74 Guido Trotter
        cluster.nicparams[constants.PP_DEFAULT], self.op.nicparams)
1972 5af3da74 Guido Trotter
      objects.NIC.CheckParameterSyntax(self.new_nicparams)
1973 5af3da74 Guido Trotter
1974 779c15bb Iustin Pop
    # hypervisor list/parameters
1975 abe609b2 Guido Trotter
    self.new_hvparams = objects.FillDict(cluster.hvparams, {})
1976 779c15bb Iustin Pop
    if self.op.hvparams:
1977 779c15bb Iustin Pop
      if not isinstance(self.op.hvparams, dict):
1978 5c983ee5 Iustin Pop
        raise errors.OpPrereqError("Invalid 'hvparams' parameter on input",
1979 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
1980 779c15bb Iustin Pop
      for hv_name, hv_dict in self.op.hvparams.items():
1981 779c15bb Iustin Pop
        if hv_name not in self.new_hvparams:
1982 779c15bb Iustin Pop
          self.new_hvparams[hv_name] = hv_dict
1983 779c15bb Iustin Pop
        else:
1984 779c15bb Iustin Pop
          self.new_hvparams[hv_name].update(hv_dict)
1985 779c15bb Iustin Pop
1986 779c15bb Iustin Pop
    if self.op.enabled_hypervisors is not None:
1987 779c15bb Iustin Pop
      self.hv_list = self.op.enabled_hypervisors
1988 b119bccb Guido Trotter
      if not self.hv_list:
1989 b119bccb Guido Trotter
        raise errors.OpPrereqError("Enabled hypervisors list must contain at"
1990 5c983ee5 Iustin Pop
                                   " least one member",
1991 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
1992 b119bccb Guido Trotter
      invalid_hvs = set(self.hv_list) - constants.HYPER_TYPES
1993 b119bccb Guido Trotter
      if invalid_hvs:
1994 b119bccb Guido Trotter
        raise errors.OpPrereqError("Enabled hypervisors contains invalid"
1995 5c983ee5 Iustin Pop
                                   " entries: %s" % " ,".join(invalid_hvs),
1996 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
1997 779c15bb Iustin Pop
    else:
1998 779c15bb Iustin Pop
      self.hv_list = cluster.enabled_hypervisors
1999 779c15bb Iustin Pop
2000 779c15bb Iustin Pop
    if self.op.hvparams or self.op.enabled_hypervisors is not None:
2001 779c15bb Iustin Pop
      # either the enabled list has changed, or the parameters have, validate
2002 779c15bb Iustin Pop
      for hv_name, hv_params in self.new_hvparams.items():
2003 779c15bb Iustin Pop
        if ((self.op.hvparams and hv_name in self.op.hvparams) or
2004 779c15bb Iustin Pop
            (self.op.enabled_hypervisors and
2005 779c15bb Iustin Pop
             hv_name in self.op.enabled_hypervisors)):
2006 779c15bb Iustin Pop
          # either this is a new hypervisor, or its parameters have changed
2007 779c15bb Iustin Pop
          hv_class = hypervisor.GetHypervisor(hv_name)
2008 a5728081 Guido Trotter
          utils.ForceDictType(hv_params, constants.HVS_PARAMETER_TYPES)
2009 779c15bb Iustin Pop
          hv_class.CheckParameterSyntax(hv_params)
2010 779c15bb Iustin Pop
          _CheckHVParams(self, node_list, hv_name, hv_params)
2011 779c15bb Iustin Pop
2012 8084f9f6 Manuel Franceschini
  def Exec(self, feedback_fn):
2013 8084f9f6 Manuel Franceschini
    """Change the parameters of the cluster.
2014 8084f9f6 Manuel Franceschini

2015 8084f9f6 Manuel Franceschini
    """
2016 779c15bb Iustin Pop
    if self.op.vg_name is not None:
2017 b2482333 Guido Trotter
      new_volume = self.op.vg_name
2018 b2482333 Guido Trotter
      if not new_volume:
2019 b2482333 Guido Trotter
        new_volume = None
2020 b2482333 Guido Trotter
      if new_volume != self.cfg.GetVGName():
2021 b2482333 Guido Trotter
        self.cfg.SetVGName(new_volume)
2022 779c15bb Iustin Pop
      else:
2023 779c15bb Iustin Pop
        feedback_fn("Cluster LVM configuration already in desired"
2024 779c15bb Iustin Pop
                    " state, not changing")
2025 779c15bb Iustin Pop
    if self.op.hvparams:
2026 779c15bb Iustin Pop
      self.cluster.hvparams = self.new_hvparams
2027 779c15bb Iustin Pop
    if self.op.enabled_hypervisors is not None:
2028 779c15bb Iustin Pop
      self.cluster.enabled_hypervisors = self.op.enabled_hypervisors
2029 779c15bb Iustin Pop
    if self.op.beparams:
2030 4ef7f423 Guido Trotter
      self.cluster.beparams[constants.PP_DEFAULT] = self.new_beparams
2031 5af3da74 Guido Trotter
    if self.op.nicparams:
2032 5af3da74 Guido Trotter
      self.cluster.nicparams[constants.PP_DEFAULT] = self.new_nicparams
2033 5af3da74 Guido Trotter
2034 4b7735f9 Iustin Pop
    if self.op.candidate_pool_size is not None:
2035 4b7735f9 Iustin Pop
      self.cluster.candidate_pool_size = self.op.candidate_pool_size
2036 75e914fb Iustin Pop
      # we need to update the pool size here, otherwise the save will fail
2037 44485f49 Guido Trotter
      _AdjustCandidatePool(self, [])
2038 4b7735f9 Iustin Pop
2039 a4eae71f Michael Hanselmann
    self.cfg.Update(self.cluster, feedback_fn)
2040 8084f9f6 Manuel Franceschini
2041 8084f9f6 Manuel Franceschini
2042 28eddce5 Guido Trotter
def _RedistributeAncillaryFiles(lu, additional_nodes=None):
2043 28eddce5 Guido Trotter
  """Distribute additional files which are part of the cluster configuration.
2044 28eddce5 Guido Trotter

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

2049 28eddce5 Guido Trotter
  @param lu: calling logical unit
2050 28eddce5 Guido Trotter
  @param additional_nodes: list of nodes not in the config to distribute to
2051 28eddce5 Guido Trotter

2052 28eddce5 Guido Trotter
  """
2053 28eddce5 Guido Trotter
  # 1. Gather target nodes
2054 28eddce5 Guido Trotter
  myself = lu.cfg.GetNodeInfo(lu.cfg.GetMasterNode())
2055 28eddce5 Guido Trotter
  dist_nodes = lu.cfg.GetNodeList()
2056 28eddce5 Guido Trotter
  if additional_nodes is not None:
2057 28eddce5 Guido Trotter
    dist_nodes.extend(additional_nodes)
2058 28eddce5 Guido Trotter
  if myself.name in dist_nodes:
2059 28eddce5 Guido Trotter
    dist_nodes.remove(myself.name)
2060 a4eae71f Michael Hanselmann
2061 28eddce5 Guido Trotter
  # 2. Gather files to distribute
2062 28eddce5 Guido Trotter
  dist_files = set([constants.ETC_HOSTS,
2063 28eddce5 Guido Trotter
                    constants.SSH_KNOWN_HOSTS_FILE,
2064 28eddce5 Guido Trotter
                    constants.RAPI_CERT_FILE,
2065 28eddce5 Guido Trotter
                    constants.RAPI_USERS_FILE,
2066 4a34c5cf Guido Trotter
                    constants.HMAC_CLUSTER_KEY,
2067 28eddce5 Guido Trotter
                   ])
2068 e1b8653f Guido Trotter
2069 e1b8653f Guido Trotter
  enabled_hypervisors = lu.cfg.GetClusterInfo().enabled_hypervisors
2070 e1b8653f Guido Trotter
  for hv_name in enabled_hypervisors:
2071 e1b8653f Guido Trotter
    hv_class = hypervisor.GetHypervisor(hv_name)
2072 e1b8653f Guido Trotter
    dist_files.update(hv_class.GetAncillaryFiles())
2073 e1b8653f Guido Trotter
2074 28eddce5 Guido Trotter
  # 3. Perform the files upload
2075 28eddce5 Guido Trotter
  for fname in dist_files:
2076 28eddce5 Guido Trotter
    if os.path.exists(fname):
2077 28eddce5 Guido Trotter
      result = lu.rpc.call_upload_file(dist_nodes, fname)
2078 28eddce5 Guido Trotter
      for to_node, to_result in result.items():
2079 6f7d4e75 Iustin Pop
        msg = to_result.fail_msg
2080 6f7d4e75 Iustin Pop
        if msg:
2081 6f7d4e75 Iustin Pop
          msg = ("Copy of file %s to node %s failed: %s" %
2082 6f7d4e75 Iustin Pop
                 (fname, to_node, msg))
2083 6f7d4e75 Iustin Pop
          lu.proc.LogWarning(msg)
2084 28eddce5 Guido Trotter
2085 28eddce5 Guido Trotter
2086 afee0879 Iustin Pop
class LURedistributeConfig(NoHooksLU):
2087 afee0879 Iustin Pop
  """Force the redistribution of cluster configuration.
2088 afee0879 Iustin Pop

2089 afee0879 Iustin Pop
  This is a very simple LU.
2090 afee0879 Iustin Pop

2091 afee0879 Iustin Pop
  """
2092 afee0879 Iustin Pop
  _OP_REQP = []
2093 afee0879 Iustin Pop
  REQ_BGL = False
2094 afee0879 Iustin Pop
2095 afee0879 Iustin Pop
  def ExpandNames(self):
2096 afee0879 Iustin Pop
    self.needed_locks = {
2097 afee0879 Iustin Pop
      locking.LEVEL_NODE: locking.ALL_SET,
2098 afee0879 Iustin Pop
    }
2099 afee0879 Iustin Pop
    self.share_locks[locking.LEVEL_NODE] = 1
2100 afee0879 Iustin Pop
2101 afee0879 Iustin Pop
  def CheckPrereq(self):
2102 afee0879 Iustin Pop
    """Check prerequisites.
2103 afee0879 Iustin Pop

2104 afee0879 Iustin Pop
    """
2105 afee0879 Iustin Pop
2106 afee0879 Iustin Pop
  def Exec(self, feedback_fn):
2107 afee0879 Iustin Pop
    """Redistribute the configuration.
2108 afee0879 Iustin Pop

2109 afee0879 Iustin Pop
    """
2110 a4eae71f Michael Hanselmann
    self.cfg.Update(self.cfg.GetClusterInfo(), feedback_fn)
2111 28eddce5 Guido Trotter
    _RedistributeAncillaryFiles(self)
2112 afee0879 Iustin Pop
2113 afee0879 Iustin Pop
2114 b9bddb6b Iustin Pop
def _WaitForSync(lu, instance, oneshot=False, unlock=False):
2115 a8083063 Iustin Pop
  """Sleep and poll for an instance's disk to sync.
2116 a8083063 Iustin Pop

2117 a8083063 Iustin Pop
  """
2118 a8083063 Iustin Pop
  if not instance.disks:
2119 a8083063 Iustin Pop
    return True
2120 a8083063 Iustin Pop
2121 a8083063 Iustin Pop
  if not oneshot:
2122 b9bddb6b Iustin Pop
    lu.proc.LogInfo("Waiting for instance %s to sync disks." % instance.name)
2123 a8083063 Iustin Pop
2124 a8083063 Iustin Pop
  node = instance.primary_node
2125 a8083063 Iustin Pop
2126 a8083063 Iustin Pop
  for dev in instance.disks:
2127 b9bddb6b Iustin Pop
    lu.cfg.SetDiskID(dev, node)
2128 a8083063 Iustin Pop
2129 6bcb1446 Michael Hanselmann
  # TODO: Convert to utils.Retry
2130 6bcb1446 Michael Hanselmann
2131 a8083063 Iustin Pop
  retries = 0
2132 fbafd7a8 Iustin Pop
  degr_retries = 10 # in seconds, as we sleep 1 second each time
2133 a8083063 Iustin Pop
  while True:
2134 a8083063 Iustin Pop
    max_time = 0
2135 a8083063 Iustin Pop
    done = True
2136 a8083063 Iustin Pop
    cumul_degraded = False
2137 72737a7f Iustin Pop
    rstats = lu.rpc.call_blockdev_getmirrorstatus(node, instance.disks)
2138 4c4e4e1e Iustin Pop
    msg = rstats.fail_msg
2139 3efa9051 Iustin Pop
    if msg:
2140 3efa9051 Iustin Pop
      lu.LogWarning("Can't get any data from node %s: %s", node, msg)
2141 a8083063 Iustin Pop
      retries += 1
2142 a8083063 Iustin Pop
      if retries >= 10:
2143 3ecf6786 Iustin Pop
        raise errors.RemoteError("Can't contact node %s for mirror data,"
2144 3ecf6786 Iustin Pop
                                 " aborting." % node)
2145 a8083063 Iustin Pop
      time.sleep(6)
2146 a8083063 Iustin Pop
      continue
2147 3efa9051 Iustin Pop
    rstats = rstats.payload
2148 a8083063 Iustin Pop
    retries = 0
2149 1492cca7 Iustin Pop
    for i, mstat in enumerate(rstats):
2150 a8083063 Iustin Pop
      if mstat is None:
2151 86d9d3bb Iustin Pop
        lu.LogWarning("Can't compute data for node %s/%s",
2152 86d9d3bb Iustin Pop
                           node, instance.disks[i].iv_name)
2153 a8083063 Iustin Pop
        continue
2154 36145b12 Michael Hanselmann
2155 36145b12 Michael Hanselmann
      cumul_degraded = (cumul_degraded or
2156 36145b12 Michael Hanselmann
                        (mstat.is_degraded and mstat.sync_percent is None))
2157 36145b12 Michael Hanselmann
      if mstat.sync_percent is not None:
2158 a8083063 Iustin Pop
        done = False
2159 36145b12 Michael Hanselmann
        if mstat.estimated_time is not None:
2160 36145b12 Michael Hanselmann
          rem_time = "%d estimated seconds remaining" % mstat.estimated_time
2161 36145b12 Michael Hanselmann
          max_time = mstat.estimated_time
2162 a8083063 Iustin Pop
        else:
2163 a8083063 Iustin Pop
          rem_time = "no time estimate"
2164 b9bddb6b Iustin Pop
        lu.proc.LogInfo("- device %s: %5.2f%% done, %s" %
2165 4d4a651d Michael Hanselmann
                        (instance.disks[i].iv_name, mstat.sync_percent,
2166 4d4a651d Michael Hanselmann
                         rem_time))
2167 fbafd7a8 Iustin Pop
2168 fbafd7a8 Iustin Pop
    # if we're done but degraded, let's do a few small retries, to
2169 fbafd7a8 Iustin Pop
    # make sure we see a stable and not transient situation; therefore
2170 fbafd7a8 Iustin Pop
    # we force restart of the loop
2171 fbafd7a8 Iustin Pop
    if (done or oneshot) and cumul_degraded and degr_retries > 0:
2172 fbafd7a8 Iustin Pop
      logging.info("Degraded disks found, %d retries left", degr_retries)
2173 fbafd7a8 Iustin Pop
      degr_retries -= 1
2174 fbafd7a8 Iustin Pop
      time.sleep(1)
2175 fbafd7a8 Iustin Pop
      continue
2176 fbafd7a8 Iustin Pop
2177 a8083063 Iustin Pop
    if done or oneshot:
2178 a8083063 Iustin Pop
      break
2179 a8083063 Iustin Pop
2180 d4fa5c23 Iustin Pop
    time.sleep(min(60, max_time))
2181 a8083063 Iustin Pop
2182 a8083063 Iustin Pop
  if done:
2183 b9bddb6b Iustin Pop
    lu.proc.LogInfo("Instance %s's disks are in sync." % instance.name)
2184 a8083063 Iustin Pop
  return not cumul_degraded
2185 a8083063 Iustin Pop
2186 a8083063 Iustin Pop
2187 b9bddb6b Iustin Pop
def _CheckDiskConsistency(lu, dev, node, on_primary, ldisk=False):
2188 a8083063 Iustin Pop
  """Check that mirrors are not degraded.
2189 a8083063 Iustin Pop

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

2194 a8083063 Iustin Pop
  """
2195 b9bddb6b Iustin Pop
  lu.cfg.SetDiskID(dev, node)
2196 a8083063 Iustin Pop
2197 a8083063 Iustin Pop
  result = True
2198 96acbc09 Michael Hanselmann
2199 a8083063 Iustin Pop
  if on_primary or dev.AssembleOnSecondary():
2200 72737a7f Iustin Pop
    rstats = lu.rpc.call_blockdev_find(node, dev)
2201 4c4e4e1e Iustin Pop
    msg = rstats.fail_msg
2202 23829f6f Iustin Pop
    if msg:
2203 23829f6f Iustin Pop
      lu.LogWarning("Can't find disk on node %s: %s", node, msg)
2204 23829f6f Iustin Pop
      result = False
2205 23829f6f Iustin Pop
    elif not rstats.payload:
2206 23829f6f Iustin Pop
      lu.LogWarning("Can't find disk on node %s", node)
2207 a8083063 Iustin Pop
      result = False
2208 a8083063 Iustin Pop
    else:
2209 96acbc09 Michael Hanselmann
      if ldisk:
2210 f208978a Michael Hanselmann
        result = result and rstats.payload.ldisk_status == constants.LDS_OKAY
2211 96acbc09 Michael Hanselmann
      else:
2212 96acbc09 Michael Hanselmann
        result = result and not rstats.payload.is_degraded
2213 96acbc09 Michael Hanselmann
2214 a8083063 Iustin Pop
  if dev.children:
2215 a8083063 Iustin Pop
    for child in dev.children:
2216 b9bddb6b Iustin Pop
      result = result and _CheckDiskConsistency(lu, child, node, on_primary)
2217 a8083063 Iustin Pop
2218 a8083063 Iustin Pop
  return result
2219 a8083063 Iustin Pop
2220 a8083063 Iustin Pop
2221 a8083063 Iustin Pop
class LUDiagnoseOS(NoHooksLU):
2222 a8083063 Iustin Pop
  """Logical unit for OS diagnose/query.
2223 a8083063 Iustin Pop

2224 a8083063 Iustin Pop
  """
2225 1f9430d6 Iustin Pop
  _OP_REQP = ["output_fields", "names"]
2226 6bf01bbb Guido Trotter
  REQ_BGL = False
2227 a2d2e1a7 Iustin Pop
  _FIELDS_STATIC = utils.FieldSet()
2228 1e288a26 Guido Trotter
  _FIELDS_DYNAMIC = utils.FieldSet("name", "valid", "node_status", "variants")
2229 1e288a26 Guido Trotter
  # Fields that need calculation of global os validity
2230 1e288a26 Guido Trotter
  _FIELDS_NEEDVALID = frozenset(["valid", "variants"])
2231 a8083063 Iustin Pop
2232 6bf01bbb Guido Trotter
  def ExpandNames(self):
2233 1f9430d6 Iustin Pop
    if self.op.names:
2234 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Selective OS query not supported",
2235 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
2236 1f9430d6 Iustin Pop
2237 31bf511f Iustin Pop
    _CheckOutputFields(static=self._FIELDS_STATIC,
2238 31bf511f Iustin Pop
                       dynamic=self._FIELDS_DYNAMIC,
2239 1f9430d6 Iustin Pop
                       selected=self.op.output_fields)
2240 1f9430d6 Iustin Pop
2241 6bf01bbb Guido Trotter
    # Lock all nodes, in shared mode
2242 a6ab004b Iustin Pop
    # Temporary removal of locks, should be reverted later
2243 a6ab004b Iustin Pop
    # TODO: reintroduce locks when they are lighter-weight
2244 6bf01bbb Guido Trotter
    self.needed_locks = {}
2245 a6ab004b Iustin Pop
    #self.share_locks[locking.LEVEL_NODE] = 1
2246 a6ab004b Iustin Pop
    #self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
2247 6bf01bbb Guido Trotter
2248 6bf01bbb Guido Trotter
  def CheckPrereq(self):
2249 6bf01bbb Guido Trotter
    """Check prerequisites.
2250 6bf01bbb Guido Trotter

2251 6bf01bbb Guido Trotter
    """
2252 6bf01bbb Guido Trotter
2253 1f9430d6 Iustin Pop
  @staticmethod
2254 1f9430d6 Iustin Pop
  def _DiagnoseByOS(node_list, rlist):
2255 1f9430d6 Iustin Pop
    """Remaps a per-node return list into an a per-os per-node dictionary
2256 1f9430d6 Iustin Pop

2257 e4376078 Iustin Pop
    @param node_list: a list with the names of all nodes
2258 e4376078 Iustin Pop
    @param rlist: a map with node names as keys and OS objects as values
2259 1f9430d6 Iustin Pop

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

2264 255dcebd Iustin Pop
          {"debian-etch": {"node1": [(/usr/lib/..., True, ""),
2265 255dcebd Iustin Pop
                                     (/srv/..., False, "invalid api")],
2266 255dcebd Iustin Pop
                           "node2": [(/srv/..., True, "")]}
2267 e4376078 Iustin Pop
          }
2268 1f9430d6 Iustin Pop

2269 1f9430d6 Iustin Pop
    """
2270 1f9430d6 Iustin Pop
    all_os = {}
2271 a6ab004b Iustin Pop
    # we build here the list of nodes that didn't fail the RPC (at RPC
2272 a6ab004b Iustin Pop
    # level), so that nodes with a non-responding node daemon don't
2273 a6ab004b Iustin Pop
    # make all OSes invalid
2274 a6ab004b Iustin Pop
    good_nodes = [node_name for node_name in rlist
2275 4c4e4e1e Iustin Pop
                  if not rlist[node_name].fail_msg]
2276 83d92ad8 Iustin Pop
    for node_name, nr in rlist.items():
2277 4c4e4e1e Iustin Pop
      if nr.fail_msg or not nr.payload:
2278 1f9430d6 Iustin Pop
        continue
2279 ba00557a Guido Trotter
      for name, path, status, diagnose, variants in nr.payload:
2280 255dcebd Iustin Pop
        if name not in all_os:
2281 1f9430d6 Iustin Pop
          # build a list of nodes for this os containing empty lists
2282 1f9430d6 Iustin Pop
          # for each node in node_list
2283 255dcebd Iustin Pop
          all_os[name] = {}
2284 a6ab004b Iustin Pop
          for nname in good_nodes:
2285 255dcebd Iustin Pop
            all_os[name][nname] = []
2286 ba00557a Guido Trotter
        all_os[name][node_name].append((path, status, diagnose, variants))
2287 1f9430d6 Iustin Pop
    return all_os
2288 a8083063 Iustin Pop
2289 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
2290 a8083063 Iustin Pop
    """Compute the list of OSes.
2291 a8083063 Iustin Pop

2292 a8083063 Iustin Pop
    """
2293 a6ab004b Iustin Pop
    valid_nodes = [node for node in self.cfg.GetOnlineNodeList()]
2294 94a02bb5 Iustin Pop
    node_data = self.rpc.call_os_diagnose(valid_nodes)
2295 94a02bb5 Iustin Pop
    pol = self._DiagnoseByOS(valid_nodes, node_data)
2296 1f9430d6 Iustin Pop
    output = []
2297 1e288a26 Guido Trotter
    calc_valid = self._FIELDS_NEEDVALID.intersection(self.op.output_fields)
2298 1e288a26 Guido Trotter
    calc_variants = "variants" in self.op.output_fields
2299 1e288a26 Guido Trotter
2300 83d92ad8 Iustin Pop
    for os_name, os_data in pol.items():
2301 1f9430d6 Iustin Pop
      row = []
2302 1e288a26 Guido Trotter
      if calc_valid:
2303 1e288a26 Guido Trotter
        valid = True
2304 1e288a26 Guido Trotter
        variants = None
2305 1e288a26 Guido Trotter
        for osl in os_data.values():
2306 1e288a26 Guido Trotter
          valid = valid and osl and osl[0][1]
2307 1e288a26 Guido Trotter
          if not valid:
2308 1e288a26 Guido Trotter
            variants = None
2309 1e288a26 Guido Trotter
            break
2310 1e288a26 Guido Trotter
          if calc_variants:
2311 1e288a26 Guido Trotter
            node_variants = osl[0][3]
2312 1e288a26 Guido Trotter
            if variants is None:
2313 1e288a26 Guido Trotter
              variants = node_variants
2314 1e288a26 Guido Trotter
            else:
2315 1e288a26 Guido Trotter
              variants = [v for v in variants if v in node_variants]
2316 1e288a26 Guido Trotter
2317 1f9430d6 Iustin Pop
      for field in self.op.output_fields:
2318 1f9430d6 Iustin Pop
        if field == "name":
2319 1f9430d6 Iustin Pop
          val = os_name
2320 1f9430d6 Iustin Pop
        elif field == "valid":
2321 1e288a26 Guido Trotter
          val = valid
2322 1f9430d6 Iustin Pop
        elif field == "node_status":
2323 255dcebd Iustin Pop
          # this is just a copy of the dict
2324 1f9430d6 Iustin Pop
          val = {}
2325 255dcebd Iustin Pop
          for node_name, nos_list in os_data.items():
2326 255dcebd Iustin Pop
            val[node_name] = nos_list
2327 1e288a26 Guido Trotter
        elif field == "variants":
2328 1e288a26 Guido Trotter
          val =  variants
2329 1f9430d6 Iustin Pop
        else:
2330 1f9430d6 Iustin Pop
          raise errors.ParameterError(field)
2331 1f9430d6 Iustin Pop
        row.append(val)
2332 1f9430d6 Iustin Pop
      output.append(row)
2333 1f9430d6 Iustin Pop
2334 1f9430d6 Iustin Pop
    return output
2335 a8083063 Iustin Pop
2336 a8083063 Iustin Pop
2337 a8083063 Iustin Pop
class LURemoveNode(LogicalUnit):
2338 a8083063 Iustin Pop
  """Logical unit for removing a node.
2339 a8083063 Iustin Pop

2340 a8083063 Iustin Pop
  """
2341 a8083063 Iustin Pop
  HPATH = "node-remove"
2342 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_NODE
2343 a8083063 Iustin Pop
  _OP_REQP = ["node_name"]
2344 a8083063 Iustin Pop
2345 a8083063 Iustin Pop
  def BuildHooksEnv(self):
2346 a8083063 Iustin Pop
    """Build hooks env.
2347 a8083063 Iustin Pop

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

2351 a8083063 Iustin Pop
    """
2352 396e1b78 Michael Hanselmann
    env = {
2353 0e137c28 Iustin Pop
      "OP_TARGET": self.op.node_name,
2354 396e1b78 Michael Hanselmann
      "NODE_NAME": self.op.node_name,
2355 396e1b78 Michael Hanselmann
      }
2356 a8083063 Iustin Pop
    all_nodes = self.cfg.GetNodeList()
2357 cd46f3b4 Luca Bigliardi
    if self.op.node_name in all_nodes:
2358 cd46f3b4 Luca Bigliardi
      all_nodes.remove(self.op.node_name)
2359 396e1b78 Michael Hanselmann
    return env, all_nodes, all_nodes
2360 a8083063 Iustin Pop
2361 a8083063 Iustin Pop
  def CheckPrereq(self):
2362 a8083063 Iustin Pop
    """Check prerequisites.
2363 a8083063 Iustin Pop

2364 a8083063 Iustin Pop
    This checks:
2365 a8083063 Iustin Pop
     - the node exists in the configuration
2366 a8083063 Iustin Pop
     - it does not have primary or secondary instances
2367 a8083063 Iustin Pop
     - it's not the master
2368 a8083063 Iustin Pop

2369 5bbd3f7f Michael Hanselmann
    Any errors are signaled by raising errors.OpPrereqError.
2370 a8083063 Iustin Pop

2371 a8083063 Iustin Pop
    """
2372 a8083063 Iustin Pop
    node = self.cfg.GetNodeInfo(self.cfg.ExpandNodeName(self.op.node_name))
2373 a8083063 Iustin Pop
    if node is None:
2374 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Node '%s' is unknown." % self.op.node_name,
2375 5c983ee5 Iustin Pop
                                 errors.ECODE_NOENT)
2376 a8083063 Iustin Pop
2377 a8083063 Iustin Pop
    instance_list = self.cfg.GetInstanceList()
2378 a8083063 Iustin Pop
2379 d6a02168 Michael Hanselmann
    masternode = self.cfg.GetMasterNode()
2380 a8083063 Iustin Pop
    if node.name == masternode:
2381 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Node is the master node,"
2382 5c983ee5 Iustin Pop
                                 " you need to failover first.",
2383 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
2384 a8083063 Iustin Pop
2385 a8083063 Iustin Pop
    for instance_name in instance_list:
2386 a8083063 Iustin Pop
      instance = self.cfg.GetInstanceInfo(instance_name)
2387 6b12959c Iustin Pop
      if node.name in instance.all_nodes:
2388 6b12959c Iustin Pop
        raise errors.OpPrereqError("Instance %s is still running on the node,"
2389 5c983ee5 Iustin Pop
                                   " please remove first." % instance_name,
2390 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
2391 a8083063 Iustin Pop
    self.op.node_name = node.name
2392 a8083063 Iustin Pop
    self.node = node
2393 a8083063 Iustin Pop
2394 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
2395 a8083063 Iustin Pop
    """Removes the node from the cluster.
2396 a8083063 Iustin Pop

2397 a8083063 Iustin Pop
    """
2398 a8083063 Iustin Pop
    node = self.node
2399 9a4f63d1 Iustin Pop
    logging.info("Stopping the node daemon and removing configs from node %s",
2400 9a4f63d1 Iustin Pop
                 node.name)
2401 a8083063 Iustin Pop
2402 b989b9d9 Ken Wehr
    modify_ssh_setup = self.cfg.GetClusterInfo().modify_ssh_setup
2403 b989b9d9 Ken Wehr
2404 44485f49 Guido Trotter
    # Promote nodes to master candidate as needed
2405 44485f49 Guido Trotter
    _AdjustCandidatePool(self, exceptions=[node.name])
2406 d8470559 Michael Hanselmann
    self.context.RemoveNode(node.name)
2407 a8083063 Iustin Pop
2408 cd46f3b4 Luca Bigliardi
    # Run post hooks on the node before it's removed
2409 cd46f3b4 Luca Bigliardi
    hm = self.proc.hmclass(self.rpc.call_hooks_runner, self)
2410 cd46f3b4 Luca Bigliardi
    try:
2411 cd46f3b4 Luca Bigliardi
      h_results = hm.RunPhase(constants.HOOKS_PHASE_POST, [node.name])
2412 3cb5c1e3 Luca Bigliardi
    except:
2413 3cb5c1e3 Luca Bigliardi
      self.LogWarning("Errors occurred running hooks on %s" % node.name)
2414 cd46f3b4 Luca Bigliardi
2415 b989b9d9 Ken Wehr
    result = self.rpc.call_node_leave_cluster(node.name, modify_ssh_setup)
2416 4c4e4e1e Iustin Pop
    msg = result.fail_msg
2417 0623d351 Iustin Pop
    if msg:
2418 0623d351 Iustin Pop
      self.LogWarning("Errors encountered on the remote node while leaving"
2419 0623d351 Iustin Pop
                      " the cluster: %s", msg)
2420 c8a0948f Michael Hanselmann
2421 a8083063 Iustin Pop
2422 a8083063 Iustin Pop
class LUQueryNodes(NoHooksLU):
2423 a8083063 Iustin Pop
  """Logical unit for querying nodes.
2424 a8083063 Iustin Pop

2425 a8083063 Iustin Pop
  """
2426 bc8e4a1a Iustin Pop
  _OP_REQP = ["output_fields", "names", "use_locking"]
2427 35705d8f Guido Trotter
  REQ_BGL = False
2428 19bed813 Iustin Pop
2429 19bed813 Iustin Pop
  _SIMPLE_FIELDS = ["name", "serial_no", "ctime", "mtime", "uuid",
2430 19bed813 Iustin Pop
                    "master_candidate", "offline", "drained"]
2431 19bed813 Iustin Pop
2432 a2d2e1a7 Iustin Pop
  _FIELDS_DYNAMIC = utils.FieldSet(
2433 31bf511f Iustin Pop
    "dtotal", "dfree",
2434 31bf511f Iustin Pop
    "mtotal", "mnode", "mfree",
2435 31bf511f Iustin Pop
    "bootid",
2436 0105bad3 Iustin Pop
    "ctotal", "cnodes", "csockets",
2437 31bf511f Iustin Pop
    )
2438 31bf511f Iustin Pop
2439 19bed813 Iustin Pop
  _FIELDS_STATIC = utils.FieldSet(*[
2440 19bed813 Iustin Pop
    "pinst_cnt", "sinst_cnt",
2441 31bf511f Iustin Pop
    "pinst_list", "sinst_list",
2442 31bf511f Iustin Pop
    "pip", "sip", "tags",
2443 0e67cdbe Iustin Pop
    "master",
2444 19bed813 Iustin Pop
    "role"] + _SIMPLE_FIELDS
2445 31bf511f Iustin Pop
    )
2446 a8083063 Iustin Pop
2447 35705d8f Guido Trotter
  def ExpandNames(self):
2448 31bf511f Iustin Pop
    _CheckOutputFields(static=self._FIELDS_STATIC,
2449 31bf511f Iustin Pop
                       dynamic=self._FIELDS_DYNAMIC,
2450 dcb93971 Michael Hanselmann
                       selected=self.op.output_fields)
2451 a8083063 Iustin Pop
2452 35705d8f Guido Trotter
    self.needed_locks = {}
2453 35705d8f Guido Trotter
    self.share_locks[locking.LEVEL_NODE] = 1
2454 c8d8b4c8 Iustin Pop
2455 c8d8b4c8 Iustin Pop
    if self.op.names:
2456 c8d8b4c8 Iustin Pop
      self.wanted = _GetWantedNodes(self, self.op.names)
2457 35705d8f Guido Trotter
    else:
2458 c8d8b4c8 Iustin Pop
      self.wanted = locking.ALL_SET
2459 c8d8b4c8 Iustin Pop
2460 bc8e4a1a Iustin Pop
    self.do_node_query = self._FIELDS_STATIC.NonMatching(self.op.output_fields)
2461 bc8e4a1a Iustin Pop
    self.do_locking = self.do_node_query and self.op.use_locking
2462 c8d8b4c8 Iustin Pop
    if self.do_locking:
2463 c8d8b4c8 Iustin Pop
      # if we don't request only static fields, we need to lock the nodes
2464 c8d8b4c8 Iustin Pop
      self.needed_locks[locking.LEVEL_NODE] = self.wanted
2465 c8d8b4c8 Iustin Pop
2466 35705d8f Guido Trotter
  def CheckPrereq(self):
2467 35705d8f Guido Trotter
    """Check prerequisites.
2468 35705d8f Guido Trotter

2469 35705d8f Guido Trotter
    """
2470 c8d8b4c8 Iustin Pop
    # The validation of the node list is done in the _GetWantedNodes,
2471 c8d8b4c8 Iustin Pop
    # if non empty, and if empty, there's no validation to do
2472 c8d8b4c8 Iustin Pop
    pass
2473 a8083063 Iustin Pop
2474 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
2475 a8083063 Iustin Pop
    """Computes the list of nodes and their attributes.
2476 a8083063 Iustin Pop

2477 a8083063 Iustin Pop
    """
2478 c8d8b4c8 Iustin Pop
    all_info = self.cfg.GetAllNodesInfo()
2479 c8d8b4c8 Iustin Pop
    if self.do_locking:
2480 c8d8b4c8 Iustin Pop
      nodenames = self.acquired_locks[locking.LEVEL_NODE]
2481 3fa93523 Guido Trotter
    elif self.wanted != locking.ALL_SET:
2482 3fa93523 Guido Trotter
      nodenames = self.wanted
2483 3fa93523 Guido Trotter
      missing = set(nodenames).difference(all_info.keys())
2484 3fa93523 Guido Trotter
      if missing:
2485 7b3a8fb5 Iustin Pop
        raise errors.OpExecError(
2486 3fa93523 Guido Trotter
          "Some nodes were removed before retrieving their data: %s" % missing)
2487 c8d8b4c8 Iustin Pop
    else:
2488 c8d8b4c8 Iustin Pop
      nodenames = all_info.keys()
2489 c1f1cbb2 Iustin Pop
2490 c1f1cbb2 Iustin Pop
    nodenames = utils.NiceSort(nodenames)
2491 c8d8b4c8 Iustin Pop
    nodelist = [all_info[name] for name in nodenames]
2492 a8083063 Iustin Pop
2493 a8083063 Iustin Pop
    # begin data gathering
2494 a8083063 Iustin Pop
2495 bc8e4a1a Iustin Pop
    if self.do_node_query:
2496 a8083063 Iustin Pop
      live_data = {}
2497 72737a7f Iustin Pop
      node_data = self.rpc.call_node_info(nodenames, self.cfg.GetVGName(),
2498 72737a7f Iustin Pop
                                          self.cfg.GetHypervisorType())
2499 a8083063 Iustin Pop
      for name in nodenames:
2500 781de953 Iustin Pop
        nodeinfo = node_data[name]
2501 4c4e4e1e Iustin Pop
        if not nodeinfo.fail_msg and nodeinfo.payload:
2502 070e998b Iustin Pop
          nodeinfo = nodeinfo.payload
2503 d599d686 Iustin Pop
          fn = utils.TryConvert
2504 a8083063 Iustin Pop
          live_data[name] = {
2505 d599d686 Iustin Pop
            "mtotal": fn(int, nodeinfo.get('memory_total', None)),
2506 d599d686 Iustin Pop
            "mnode": fn(int, nodeinfo.get('memory_dom0', None)),
2507 d599d686 Iustin Pop
            "mfree": fn(int, nodeinfo.get('memory_free', None)),
2508 d599d686 Iustin Pop
            "dtotal": fn(int, nodeinfo.get('vg_size', None)),
2509 d599d686 Iustin Pop
            "dfree": fn(int, nodeinfo.get('vg_free', None)),
2510 d599d686 Iustin Pop
            "ctotal": fn(int, nodeinfo.get('cpu_total', None)),
2511 d599d686 Iustin Pop
            "bootid": nodeinfo.get('bootid', None),
2512 0105bad3 Iustin Pop
            "cnodes": fn(int, nodeinfo.get('cpu_nodes', None)),
2513 0105bad3 Iustin Pop
            "csockets": fn(int, nodeinfo.get('cpu_sockets', None)),
2514 a8083063 Iustin Pop
            }
2515 a8083063 Iustin Pop
        else:
2516 a8083063 Iustin Pop
          live_data[name] = {}
2517 a8083063 Iustin Pop
    else:
2518 a8083063 Iustin Pop
      live_data = dict.fromkeys(nodenames, {})
2519 a8083063 Iustin Pop
2520 ec223efb Iustin Pop
    node_to_primary = dict([(name, set()) for name in nodenames])
2521 ec223efb Iustin Pop
    node_to_secondary = dict([(name, set()) for name in nodenames])
2522 a8083063 Iustin Pop
2523 ec223efb Iustin Pop
    inst_fields = frozenset(("pinst_cnt", "pinst_list",
2524 ec223efb Iustin Pop
                             "sinst_cnt", "sinst_list"))
2525 ec223efb Iustin Pop
    if inst_fields & frozenset(self.op.output_fields):
2526 a8083063 Iustin Pop
      instancelist = self.cfg.GetInstanceList()
2527 a8083063 Iustin Pop
2528 ec223efb Iustin Pop
      for instance_name in instancelist:
2529 ec223efb Iustin Pop
        inst = self.cfg.GetInstanceInfo(instance_name)
2530 ec223efb Iustin Pop
        if inst.primary_node in node_to_primary:
2531 ec223efb Iustin Pop
          node_to_primary[inst.primary_node].add(inst.name)
2532 ec223efb Iustin Pop
        for secnode in inst.secondary_nodes:
2533 ec223efb Iustin Pop
          if secnode in node_to_secondary:
2534 ec223efb Iustin Pop
            node_to_secondary[secnode].add(inst.name)
2535 a8083063 Iustin Pop
2536 0e67cdbe Iustin Pop
    master_node = self.cfg.GetMasterNode()
2537 0e67cdbe Iustin Pop
2538 a8083063 Iustin Pop
    # end data gathering
2539 a8083063 Iustin Pop
2540 a8083063 Iustin Pop
    output = []
2541 a8083063 Iustin Pop
    for node in nodelist:
2542 a8083063 Iustin Pop
      node_output = []
2543 a8083063 Iustin Pop
      for field in self.op.output_fields:
2544 19bed813 Iustin Pop
        if field in self._SIMPLE_FIELDS:
2545 19bed813 Iustin Pop
          val = getattr(node, field)
2546 ec223efb Iustin Pop
        elif field == "pinst_list":
2547 ec223efb Iustin Pop
          val = list(node_to_primary[node.name])
2548 ec223efb Iustin Pop
        elif field == "sinst_list":
2549 ec223efb Iustin Pop
          val = list(node_to_secondary[node.name])
2550 ec223efb Iustin Pop
        elif field == "pinst_cnt":
2551 ec223efb Iustin Pop
          val = len(node_to_primary[node.name])
2552 ec223efb Iustin Pop
        elif field == "sinst_cnt":
2553 ec223efb Iustin Pop
          val = len(node_to_secondary[node.name])
2554 a8083063 Iustin Pop
        elif field == "pip":
2555 a8083063 Iustin Pop
          val = node.primary_ip
2556 a8083063 Iustin Pop
        elif field == "sip":
2557 a8083063 Iustin Pop
          val = node.secondary_ip
2558 130a6a6f Iustin Pop
        elif field == "tags":
2559 130a6a6f Iustin Pop
          val = list(node.GetTags())
2560 0e67cdbe Iustin Pop
        elif field == "master":
2561 0e67cdbe Iustin Pop
          val = node.name == master_node
2562 31bf511f Iustin Pop
        elif self._FIELDS_DYNAMIC.Matches(field):
2563 ec223efb Iustin Pop
          val = live_data[node.name].get(field, None)
2564 c120ff34 Iustin Pop
        elif field == "role":
2565 c120ff34 Iustin Pop
          if node.name == master_node:
2566 c120ff34 Iustin Pop
            val = "M"
2567 c120ff34 Iustin Pop
          elif node.master_candidate:
2568 c120ff34 Iustin Pop
            val = "C"
2569 c120ff34 Iustin Pop
          elif node.drained:
2570 c120ff34 Iustin Pop
            val = "D"
2571 c120ff34 Iustin Pop
          elif node.offline:
2572 c120ff34 Iustin Pop
            val = "O"
2573 c120ff34 Iustin Pop
          else:
2574 c120ff34 Iustin Pop
            val = "R"
2575 a8083063 Iustin Pop
        else:
2576 3ecf6786 Iustin Pop
          raise errors.ParameterError(field)
2577 a8083063 Iustin Pop
        node_output.append(val)
2578 a8083063 Iustin Pop
      output.append(node_output)
2579 a8083063 Iustin Pop
2580 a8083063 Iustin Pop
    return output
2581 a8083063 Iustin Pop
2582 a8083063 Iustin Pop
2583 dcb93971 Michael Hanselmann
class LUQueryNodeVolumes(NoHooksLU):
2584 dcb93971 Michael Hanselmann
  """Logical unit for getting volumes on node(s).
2585 dcb93971 Michael Hanselmann

2586 dcb93971 Michael Hanselmann
  """
2587 dcb93971 Michael Hanselmann
  _OP_REQP = ["nodes", "output_fields"]
2588 21a15682 Guido Trotter
  REQ_BGL = False
2589 a2d2e1a7 Iustin Pop
  _FIELDS_DYNAMIC = utils.FieldSet("phys", "vg", "name", "size", "instance")
2590 a2d2e1a7 Iustin Pop
  _FIELDS_STATIC = utils.FieldSet("node")
2591 21a15682 Guido Trotter
2592 21a15682 Guido Trotter
  def ExpandNames(self):
2593 31bf511f Iustin Pop
    _CheckOutputFields(static=self._FIELDS_STATIC,
2594 31bf511f Iustin Pop
                       dynamic=self._FIELDS_DYNAMIC,
2595 21a15682 Guido Trotter
                       selected=self.op.output_fields)
2596 21a15682 Guido Trotter
2597 21a15682 Guido Trotter
    self.needed_locks = {}
2598 21a15682 Guido Trotter
    self.share_locks[locking.LEVEL_NODE] = 1
2599 21a15682 Guido Trotter
    if not self.op.nodes:
2600 e310b019 Guido Trotter
      self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
2601 21a15682 Guido Trotter
    else:
2602 21a15682 Guido Trotter
      self.needed_locks[locking.LEVEL_NODE] = \
2603 21a15682 Guido Trotter
        _GetWantedNodes(self, self.op.nodes)
2604 dcb93971 Michael Hanselmann
2605 dcb93971 Michael Hanselmann
  def CheckPrereq(self):
2606 dcb93971 Michael Hanselmann
    """Check prerequisites.
2607 dcb93971 Michael Hanselmann

2608 dcb93971 Michael Hanselmann
    This checks that the fields required are valid output fields.
2609 dcb93971 Michael Hanselmann

2610 dcb93971 Michael Hanselmann
    """
2611 21a15682 Guido Trotter
    self.nodes = self.acquired_locks[locking.LEVEL_NODE]
2612 dcb93971 Michael Hanselmann
2613 dcb93971 Michael Hanselmann
  def Exec(self, feedback_fn):
2614 dcb93971 Michael Hanselmann
    """Computes the list of nodes and their attributes.
2615 dcb93971 Michael Hanselmann

2616 dcb93971 Michael Hanselmann
    """
2617 a7ba5e53 Iustin Pop
    nodenames = self.nodes
2618 72737a7f Iustin Pop
    volumes = self.rpc.call_node_volumes(nodenames)
2619 dcb93971 Michael Hanselmann
2620 dcb93971 Michael Hanselmann
    ilist = [self.cfg.GetInstanceInfo(iname) for iname
2621 dcb93971 Michael Hanselmann
             in self.cfg.GetInstanceList()]
2622 dcb93971 Michael Hanselmann
2623 dcb93971 Michael Hanselmann
    lv_by_node = dict([(inst, inst.MapLVsByNode()) for inst in ilist])
2624 dcb93971 Michael Hanselmann
2625 dcb93971 Michael Hanselmann
    output = []
2626 dcb93971 Michael Hanselmann
    for node in nodenames:
2627 10bfe6cb Iustin Pop
      nresult = volumes[node]
2628 10bfe6cb Iustin Pop
      if nresult.offline:
2629 10bfe6cb Iustin Pop
        continue
2630 4c4e4e1e Iustin Pop
      msg = nresult.fail_msg
2631 10bfe6cb Iustin Pop
      if msg:
2632 10bfe6cb Iustin Pop
        self.LogWarning("Can't compute volume data on node %s: %s", node, msg)
2633 37d19eb2 Michael Hanselmann
        continue
2634 37d19eb2 Michael Hanselmann
2635 10bfe6cb Iustin Pop
      node_vols = nresult.payload[:]
2636 dcb93971 Michael Hanselmann
      node_vols.sort(key=lambda vol: vol['dev'])
2637 dcb93971 Michael Hanselmann
2638 dcb93971 Michael Hanselmann
      for vol in node_vols:
2639 dcb93971 Michael Hanselmann
        node_output = []
2640 dcb93971 Michael Hanselmann
        for field in self.op.output_fields:
2641 dcb93971 Michael Hanselmann
          if field == "node":
2642 dcb93971 Michael Hanselmann
            val = node
2643 dcb93971 Michael Hanselmann
          elif field == "phys":
2644 dcb93971 Michael Hanselmann
            val = vol['dev']
2645 dcb93971 Michael Hanselmann
          elif field == "vg":
2646 dcb93971 Michael Hanselmann
            val = vol['vg']
2647 dcb93971 Michael Hanselmann
          elif field == "name":
2648 dcb93971 Michael Hanselmann
            val = vol['name']
2649 dcb93971 Michael Hanselmann
          elif field == "size":
2650 dcb93971 Michael Hanselmann
            val = int(float(vol['size']))
2651 dcb93971 Michael Hanselmann
          elif field == "instance":
2652 dcb93971 Michael Hanselmann
            for inst in ilist:
2653 dcb93971 Michael Hanselmann
              if node not in lv_by_node[inst]:
2654 dcb93971 Michael Hanselmann
                continue
2655 dcb93971 Michael Hanselmann
              if vol['name'] in lv_by_node[inst][node]:
2656 dcb93971 Michael Hanselmann
                val = inst.name
2657 dcb93971 Michael Hanselmann
                break
2658 dcb93971 Michael Hanselmann
            else:
2659 dcb93971 Michael Hanselmann
              val = '-'
2660 dcb93971 Michael Hanselmann
          else:
2661 3ecf6786 Iustin Pop
            raise errors.ParameterError(field)
2662 dcb93971 Michael Hanselmann
          node_output.append(str(val))
2663 dcb93971 Michael Hanselmann
2664 dcb93971 Michael Hanselmann
        output.append(node_output)
2665 dcb93971 Michael Hanselmann
2666 dcb93971 Michael Hanselmann
    return output
2667 dcb93971 Michael Hanselmann
2668 dcb93971 Michael Hanselmann
2669 9e5442ce Michael Hanselmann
class LUQueryNodeStorage(NoHooksLU):
2670 9e5442ce Michael Hanselmann
  """Logical unit for getting information on storage units on node(s).
2671 9e5442ce Michael Hanselmann

2672 9e5442ce Michael Hanselmann
  """
2673 9e5442ce Michael Hanselmann
  _OP_REQP = ["nodes", "storage_type", "output_fields"]
2674 9e5442ce Michael Hanselmann
  REQ_BGL = False
2675 620a85fd Iustin Pop
  _FIELDS_STATIC = utils.FieldSet(constants.SF_NODE)
2676 9e5442ce Michael Hanselmann
2677 9e5442ce Michael Hanselmann
  def ExpandNames(self):
2678 9e5442ce Michael Hanselmann
    storage_type = self.op.storage_type
2679 9e5442ce Michael Hanselmann
2680 620a85fd Iustin Pop
    if storage_type not in constants.VALID_STORAGE_TYPES:
2681 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Unknown storage type: %s" % storage_type,
2682 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
2683 9e5442ce Michael Hanselmann
2684 9e5442ce Michael Hanselmann
    _CheckOutputFields(static=self._FIELDS_STATIC,
2685 620a85fd Iustin Pop
                       dynamic=utils.FieldSet(*constants.VALID_STORAGE_FIELDS),
2686 9e5442ce Michael Hanselmann
                       selected=self.op.output_fields)
2687 9e5442ce Michael Hanselmann
2688 9e5442ce Michael Hanselmann
    self.needed_locks = {}
2689 9e5442ce Michael Hanselmann
    self.share_locks[locking.LEVEL_NODE] = 1
2690 9e5442ce Michael Hanselmann
2691 9e5442ce Michael Hanselmann
    if self.op.nodes:
2692 9e5442ce Michael Hanselmann
      self.needed_locks[locking.LEVEL_NODE] = \
2693 9e5442ce Michael Hanselmann
        _GetWantedNodes(self, self.op.nodes)
2694 9e5442ce Michael Hanselmann
    else:
2695 9e5442ce Michael Hanselmann
      self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
2696 9e5442ce Michael Hanselmann
2697 9e5442ce Michael Hanselmann
  def CheckPrereq(self):
2698 9e5442ce Michael Hanselmann
    """Check prerequisites.
2699 9e5442ce Michael Hanselmann

2700 9e5442ce Michael Hanselmann
    This checks that the fields required are valid output fields.
2701 9e5442ce Michael Hanselmann

2702 9e5442ce Michael Hanselmann
    """
2703 9e5442ce Michael Hanselmann
    self.op.name = getattr(self.op, "name", None)
2704 9e5442ce Michael Hanselmann
2705 9e5442ce Michael Hanselmann
    self.nodes = self.acquired_locks[locking.LEVEL_NODE]
2706 9e5442ce Michael Hanselmann
2707 9e5442ce Michael Hanselmann
  def Exec(self, feedback_fn):
2708 9e5442ce Michael Hanselmann
    """Computes the list of nodes and their attributes.
2709 9e5442ce Michael Hanselmann

2710 9e5442ce Michael Hanselmann
    """
2711 9e5442ce Michael Hanselmann
    # Always get name to sort by
2712 9e5442ce Michael Hanselmann
    if constants.SF_NAME in self.op.output_fields:
2713 9e5442ce Michael Hanselmann
      fields = self.op.output_fields[:]
2714 9e5442ce Michael Hanselmann
    else:
2715 9e5442ce Michael Hanselmann
      fields = [constants.SF_NAME] + self.op.output_fields
2716 9e5442ce Michael Hanselmann
2717 620a85fd Iustin Pop
    # Never ask for node or type as it's only known to the LU
2718 620a85fd Iustin Pop
    for extra in [constants.SF_NODE, constants.SF_TYPE]:
2719 620a85fd Iustin Pop
      while extra in fields:
2720 620a85fd Iustin Pop
        fields.remove(extra)
2721 9e5442ce Michael Hanselmann
2722 9e5442ce Michael Hanselmann
    field_idx = dict([(name, idx) for (idx, name) in enumerate(fields)])
2723 9e5442ce Michael Hanselmann
    name_idx = field_idx[constants.SF_NAME]
2724 9e5442ce Michael Hanselmann
2725 efb8da02 Michael Hanselmann
    st_args = _GetStorageTypeArgs(self.cfg, self.op.storage_type)
2726 9e5442ce Michael Hanselmann
    data = self.rpc.call_storage_list(self.nodes,
2727 9e5442ce Michael Hanselmann
                                      self.op.storage_type, st_args,
2728 9e5442ce Michael Hanselmann
                                      self.op.name, fields)
2729 9e5442ce Michael Hanselmann
2730 9e5442ce Michael Hanselmann
    result = []
2731 9e5442ce Michael Hanselmann
2732 9e5442ce Michael Hanselmann
    for node in utils.NiceSort(self.nodes):
2733 9e5442ce Michael Hanselmann
      nresult = data[node]
2734 9e5442ce Michael Hanselmann
      if nresult.offline:
2735 9e5442ce Michael Hanselmann
        continue
2736 9e5442ce Michael Hanselmann
2737 9e5442ce Michael Hanselmann
      msg = nresult.fail_msg
2738 9e5442ce Michael Hanselmann
      if msg:
2739 9e5442ce Michael Hanselmann
        self.LogWarning("Can't get storage data from node %s: %s", node, msg)
2740 9e5442ce Michael Hanselmann
        continue
2741 9e5442ce Michael Hanselmann
2742 9e5442ce Michael Hanselmann
      rows = dict([(row[name_idx], row) for row in nresult.payload])
2743 9e5442ce Michael Hanselmann
2744 9e5442ce Michael Hanselmann
      for name in utils.NiceSort(rows.keys()):
2745 9e5442ce Michael Hanselmann
        row = rows[name]
2746 9e5442ce Michael Hanselmann
2747 9e5442ce Michael Hanselmann
        out = []
2748 9e5442ce Michael Hanselmann
2749 9e5442ce Michael Hanselmann
        for field in self.op.output_fields:
2750 620a85fd Iustin Pop
          if field == constants.SF_NODE:
2751 9e5442ce Michael Hanselmann
            val = node
2752 620a85fd Iustin Pop
          elif field == constants.SF_TYPE:
2753 620a85fd Iustin Pop
            val = self.op.storage_type
2754 9e5442ce Michael Hanselmann
          elif field in field_idx:
2755 9e5442ce Michael Hanselmann
            val = row[field_idx[field]]
2756 9e5442ce Michael Hanselmann
          else:
2757 9e5442ce Michael Hanselmann
            raise errors.ParameterError(field)
2758 9e5442ce Michael Hanselmann
2759 9e5442ce Michael Hanselmann
          out.append(val)
2760 9e5442ce Michael Hanselmann
2761 9e5442ce Michael Hanselmann
        result.append(out)
2762 9e5442ce Michael Hanselmann
2763 9e5442ce Michael Hanselmann
    return result
2764 9e5442ce Michael Hanselmann
2765 9e5442ce Michael Hanselmann
2766 efb8da02 Michael Hanselmann
class LUModifyNodeStorage(NoHooksLU):
2767 efb8da02 Michael Hanselmann
  """Logical unit for modifying a storage volume on a node.
2768 efb8da02 Michael Hanselmann

2769 efb8da02 Michael Hanselmann
  """
2770 efb8da02 Michael Hanselmann
  _OP_REQP = ["node_name", "storage_type", "name", "changes"]
2771 efb8da02 Michael Hanselmann
  REQ_BGL = False
2772 efb8da02 Michael Hanselmann
2773 efb8da02 Michael Hanselmann
  def CheckArguments(self):
2774 efb8da02 Michael Hanselmann
    node_name = self.cfg.ExpandNodeName(self.op.node_name)
2775 efb8da02 Michael Hanselmann
    if node_name is None:
2776 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Invalid node name '%s'" % self.op.node_name,
2777 5c983ee5 Iustin Pop
                                 errors.ECODE_NOENT)
2778 efb8da02 Michael Hanselmann
2779 efb8da02 Michael Hanselmann
    self.op.node_name = node_name
2780 efb8da02 Michael Hanselmann
2781 efb8da02 Michael Hanselmann
    storage_type = self.op.storage_type
2782 620a85fd Iustin Pop
    if storage_type not in constants.VALID_STORAGE_TYPES:
2783 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Unknown storage type: %s" % storage_type,
2784 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
2785 efb8da02 Michael Hanselmann
2786 efb8da02 Michael Hanselmann
  def ExpandNames(self):
2787 efb8da02 Michael Hanselmann
    self.needed_locks = {
2788 efb8da02 Michael Hanselmann
      locking.LEVEL_NODE: self.op.node_name,
2789 efb8da02 Michael Hanselmann
      }
2790 efb8da02 Michael Hanselmann
2791 efb8da02 Michael Hanselmann
  def CheckPrereq(self):
2792 efb8da02 Michael Hanselmann
    """Check prerequisites.
2793 efb8da02 Michael Hanselmann

2794 efb8da02 Michael Hanselmann
    """
2795 efb8da02 Michael Hanselmann
    storage_type = self.op.storage_type
2796 efb8da02 Michael Hanselmann
2797 efb8da02 Michael Hanselmann
    try:
2798 efb8da02 Michael Hanselmann
      modifiable = constants.MODIFIABLE_STORAGE_FIELDS[storage_type]
2799 efb8da02 Michael Hanselmann
    except KeyError:
2800 efb8da02 Michael Hanselmann
      raise errors.OpPrereqError("Storage units of type '%s' can not be"
2801 5c983ee5 Iustin Pop
                                 " modified" % storage_type,
2802 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
2803 efb8da02 Michael Hanselmann
2804 efb8da02 Michael Hanselmann
    diff = set(self.op.changes.keys()) - modifiable
2805 efb8da02 Michael Hanselmann
    if diff:
2806 efb8da02 Michael Hanselmann
      raise errors.OpPrereqError("The following fields can not be modified for"
2807 efb8da02 Michael Hanselmann
                                 " storage units of type '%s': %r" %
2808 5c983ee5 Iustin Pop
                                 (storage_type, list(diff)),
2809 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
2810 efb8da02 Michael Hanselmann
2811 efb8da02 Michael Hanselmann
  def Exec(self, feedback_fn):
2812 efb8da02 Michael Hanselmann
    """Computes the list of nodes and their attributes.
2813 efb8da02 Michael Hanselmann

2814 efb8da02 Michael Hanselmann
    """
2815 efb8da02 Michael Hanselmann
    st_args = _GetStorageTypeArgs(self.cfg, self.op.storage_type)
2816 efb8da02 Michael Hanselmann
    result = self.rpc.call_storage_modify(self.op.node_name,
2817 efb8da02 Michael Hanselmann
                                          self.op.storage_type, st_args,
2818 efb8da02 Michael Hanselmann
                                          self.op.name, self.op.changes)
2819 efb8da02 Michael Hanselmann
    result.Raise("Failed to modify storage unit '%s' on %s" %
2820 efb8da02 Michael Hanselmann
                 (self.op.name, self.op.node_name))
2821 efb8da02 Michael Hanselmann
2822 efb8da02 Michael Hanselmann
2823 a8083063 Iustin Pop
class LUAddNode(LogicalUnit):
2824 a8083063 Iustin Pop
  """Logical unit for adding node to the cluster.
2825 a8083063 Iustin Pop

2826 a8083063 Iustin Pop
  """
2827 a8083063 Iustin Pop
  HPATH = "node-add"
2828 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_NODE
2829 a8083063 Iustin Pop
  _OP_REQP = ["node_name"]
2830 a8083063 Iustin Pop
2831 a8083063 Iustin Pop
  def BuildHooksEnv(self):
2832 a8083063 Iustin Pop
    """Build hooks env.
2833 a8083063 Iustin Pop

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

2836 a8083063 Iustin Pop
    """
2837 a8083063 Iustin Pop
    env = {
2838 0e137c28 Iustin Pop
      "OP_TARGET": self.op.node_name,
2839 a8083063 Iustin Pop
      "NODE_NAME": self.op.node_name,
2840 a8083063 Iustin Pop
      "NODE_PIP": self.op.primary_ip,
2841 a8083063 Iustin Pop
      "NODE_SIP": self.op.secondary_ip,
2842 a8083063 Iustin Pop
      }
2843 a8083063 Iustin Pop
    nodes_0 = self.cfg.GetNodeList()
2844 a8083063 Iustin Pop
    nodes_1 = nodes_0 + [self.op.node_name, ]
2845 a8083063 Iustin Pop
    return env, nodes_0, nodes_1
2846 a8083063 Iustin Pop
2847 a8083063 Iustin Pop
  def CheckPrereq(self):
2848 a8083063 Iustin Pop
    """Check prerequisites.
2849 a8083063 Iustin Pop

2850 a8083063 Iustin Pop
    This checks:
2851 a8083063 Iustin Pop
     - the new node is not already in the config
2852 a8083063 Iustin Pop
     - it is resolvable
2853 a8083063 Iustin Pop
     - its parameters (single/dual homed) matches the cluster
2854 a8083063 Iustin Pop

2855 5bbd3f7f Michael Hanselmann
    Any errors are signaled by raising errors.OpPrereqError.
2856 a8083063 Iustin Pop

2857 a8083063 Iustin Pop
    """
2858 a8083063 Iustin Pop
    node_name = self.op.node_name
2859 a8083063 Iustin Pop
    cfg = self.cfg
2860 a8083063 Iustin Pop
2861 104f4ca1 Iustin Pop
    dns_data = utils.GetHostInfo(node_name)
2862 a8083063 Iustin Pop
2863 bcf043c9 Iustin Pop
    node = dns_data.name
2864 bcf043c9 Iustin Pop
    primary_ip = self.op.primary_ip = dns_data.ip
2865 a8083063 Iustin Pop
    secondary_ip = getattr(self.op, "secondary_ip", None)
2866 a8083063 Iustin Pop
    if secondary_ip is None:
2867 a8083063 Iustin Pop
      secondary_ip = primary_ip
2868 a8083063 Iustin Pop
    if not utils.IsValidIP(secondary_ip):
2869 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Invalid secondary IP given",
2870 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
2871 a8083063 Iustin Pop
    self.op.secondary_ip = secondary_ip
2872 e7c6e02b Michael Hanselmann
2873 a8083063 Iustin Pop
    node_list = cfg.GetNodeList()
2874 e7c6e02b Michael Hanselmann
    if not self.op.readd and node in node_list:
2875 e7c6e02b Michael Hanselmann
      raise errors.OpPrereqError("Node %s is already in the configuration" %
2876 5c983ee5 Iustin Pop
                                 node, errors.ECODE_EXISTS)
2877 e7c6e02b Michael Hanselmann
    elif self.op.readd and node not in node_list:
2878 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Node %s is not in the configuration" % node,
2879 5c983ee5 Iustin Pop
                                 errors.ECODE_NOENT)
2880 a8083063 Iustin Pop
2881 a8083063 Iustin Pop
    for existing_node_name in node_list:
2882 a8083063 Iustin Pop
      existing_node = cfg.GetNodeInfo(existing_node_name)
2883 e7c6e02b Michael Hanselmann
2884 e7c6e02b Michael Hanselmann
      if self.op.readd and node == existing_node_name:
2885 e7c6e02b Michael Hanselmann
        if (existing_node.primary_ip != primary_ip or
2886 e7c6e02b Michael Hanselmann
            existing_node.secondary_ip != secondary_ip):
2887 e7c6e02b Michael Hanselmann
          raise errors.OpPrereqError("Readded node doesn't have the same IP"
2888 5c983ee5 Iustin Pop
                                     " address configuration as before",
2889 5c983ee5 Iustin Pop
                                     errors.ECODE_INVAL)
2890 e7c6e02b Michael Hanselmann
        continue
2891 e7c6e02b Michael Hanselmann
2892 a8083063 Iustin Pop
      if (existing_node.primary_ip == primary_ip or
2893 a8083063 Iustin Pop
          existing_node.secondary_ip == primary_ip or
2894 a8083063 Iustin Pop
          existing_node.primary_ip == secondary_ip or
2895 a8083063 Iustin Pop
          existing_node.secondary_ip == secondary_ip):
2896 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("New node ip address(es) conflict with"
2897 5c983ee5 Iustin Pop
                                   " existing node %s" % existing_node.name,
2898 5c983ee5 Iustin Pop
                                   errors.ECODE_NOTUNIQUE)
2899 a8083063 Iustin Pop
2900 a8083063 Iustin Pop
    # check that the type of the node (single versus dual homed) is the
2901 a8083063 Iustin Pop
    # same as for the master
2902 d6a02168 Michael Hanselmann
    myself = cfg.GetNodeInfo(self.cfg.GetMasterNode())
2903 a8083063 Iustin Pop
    master_singlehomed = myself.secondary_ip == myself.primary_ip
2904 a8083063 Iustin Pop
    newbie_singlehomed = secondary_ip == primary_ip
2905 a8083063 Iustin Pop
    if master_singlehomed != newbie_singlehomed:
2906 a8083063 Iustin Pop
      if master_singlehomed:
2907 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("The master has no private ip but the"
2908 5c983ee5 Iustin Pop
                                   " new node has one",
2909 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
2910 a8083063 Iustin Pop
      else:
2911 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("The master has a private ip but the"
2912 5c983ee5 Iustin Pop
                                   " new node doesn't have one",
2913 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
2914 a8083063 Iustin Pop
2915 5bbd3f7f Michael Hanselmann
    # checks reachability
2916 b15d625f Iustin Pop
    if not utils.TcpPing(primary_ip, constants.DEFAULT_NODED_PORT):
2917 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Node not reachable by ping",
2918 5c983ee5 Iustin Pop
                                 errors.ECODE_ENVIRON)
2919 a8083063 Iustin Pop
2920 a8083063 Iustin Pop
    if not newbie_singlehomed:
2921 a8083063 Iustin Pop
      # check reachability from my secondary ip to newbie's secondary ip
2922 b15d625f Iustin Pop
      if not utils.TcpPing(secondary_ip, constants.DEFAULT_NODED_PORT,
2923 b15d625f Iustin Pop
                           source=myself.secondary_ip):
2924 f4bc1f2c Michael Hanselmann
        raise errors.OpPrereqError("Node secondary ip not reachable by TCP"
2925 5c983ee5 Iustin Pop
                                   " based ping to noded port",
2926 5c983ee5 Iustin Pop
                                   errors.ECODE_ENVIRON)
2927 a8083063 Iustin Pop
2928 a8ae3eb5 Iustin Pop
    if self.op.readd:
2929 a8ae3eb5 Iustin Pop
      exceptions = [node]
2930 a8ae3eb5 Iustin Pop
    else:
2931 a8ae3eb5 Iustin Pop
      exceptions = []
2932 6d7e1f20 Guido Trotter
2933 6d7e1f20 Guido Trotter
    self.master_candidate = _DecideSelfPromotion(self, exceptions=exceptions)
2934 0fff97e9 Guido Trotter
2935 a8ae3eb5 Iustin Pop
    if self.op.readd:
2936 a8ae3eb5 Iustin Pop
      self.new_node = self.cfg.GetNodeInfo(node)
2937 a8ae3eb5 Iustin Pop
      assert self.new_node is not None, "Can't retrieve locked node %s" % node
2938 a8ae3eb5 Iustin Pop
    else:
2939 a8ae3eb5 Iustin Pop
      self.new_node = objects.Node(name=node,
2940 a8ae3eb5 Iustin Pop
                                   primary_ip=primary_ip,
2941 a8ae3eb5 Iustin Pop
                                   secondary_ip=secondary_ip,
2942 a8ae3eb5 Iustin Pop
                                   master_candidate=self.master_candidate,
2943 a8ae3eb5 Iustin Pop
                                   offline=False, drained=False)
2944 a8083063 Iustin Pop
2945 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
2946 a8083063 Iustin Pop
    """Adds the new node to the cluster.
2947 a8083063 Iustin Pop

2948 a8083063 Iustin Pop
    """
2949 a8083063 Iustin Pop
    new_node = self.new_node
2950 a8083063 Iustin Pop
    node = new_node.name
2951 a8083063 Iustin Pop
2952 a8ae3eb5 Iustin Pop
    # for re-adds, reset the offline/drained/master-candidate flags;
2953 a8ae3eb5 Iustin Pop
    # we need to reset here, otherwise offline would prevent RPC calls
2954 a8ae3eb5 Iustin Pop
    # later in the procedure; this also means that if the re-add
2955 a8ae3eb5 Iustin Pop
    # fails, we are left with a non-offlined, broken node
2956 a8ae3eb5 Iustin Pop
    if self.op.readd:
2957 a8ae3eb5 Iustin Pop
      new_node.drained = new_node.offline = False
2958 a8ae3eb5 Iustin Pop
      self.LogInfo("Readding a node, the offline/drained flags were reset")
2959 a8ae3eb5 Iustin Pop
      # if we demote the node, we do cleanup later in the procedure
2960 a8ae3eb5 Iustin Pop
      new_node.master_candidate = self.master_candidate
2961 a8ae3eb5 Iustin Pop
2962 a8ae3eb5 Iustin Pop
    # notify the user about any possible mc promotion
2963 a8ae3eb5 Iustin Pop
    if new_node.master_candidate:
2964 a8ae3eb5 Iustin Pop
      self.LogInfo("Node will be a master candidate")
2965 a8ae3eb5 Iustin Pop
2966 a8083063 Iustin Pop
    # check connectivity
2967 72737a7f Iustin Pop
    result = self.rpc.call_version([node])[node]
2968 4c4e4e1e Iustin Pop
    result.Raise("Can't get version information from node %s" % node)
2969 90b54c26 Iustin Pop
    if constants.PROTOCOL_VERSION == result.payload:
2970 90b54c26 Iustin Pop
      logging.info("Communication to node %s fine, sw version %s match",
2971 90b54c26 Iustin Pop
                   node, result.payload)
2972 a8083063 Iustin Pop
    else:
2973 90b54c26 Iustin Pop
      raise errors.OpExecError("Version mismatch master version %s,"
2974 90b54c26 Iustin Pop
                               " node version %s" %
2975 90b54c26 Iustin Pop
                               (constants.PROTOCOL_VERSION, result.payload))
2976 a8083063 Iustin Pop
2977 a8083063 Iustin Pop
    # setup ssh on node
2978 b989b9d9 Ken Wehr
    if self.cfg.GetClusterInfo().modify_ssh_setup:
2979 b989b9d9 Ken Wehr
      logging.info("Copy ssh key to node %s", node)
2980 b989b9d9 Ken Wehr
      priv_key, pub_key, _ = ssh.GetUserFiles(constants.GANETI_RUNAS)
2981 b989b9d9 Ken Wehr
      keyarray = []
2982 b989b9d9 Ken Wehr
      keyfiles = [constants.SSH_HOST_DSA_PRIV, constants.SSH_HOST_DSA_PUB,
2983 b989b9d9 Ken Wehr
                  constants.SSH_HOST_RSA_PRIV, constants.SSH_HOST_RSA_PUB,
2984 b989b9d9 Ken Wehr
                  priv_key, pub_key]
2985 b989b9d9 Ken Wehr
2986 b989b9d9 Ken Wehr
      for i in keyfiles:
2987 b989b9d9 Ken Wehr
        keyarray.append(utils.ReadFile(i))
2988 b989b9d9 Ken Wehr
2989 b989b9d9 Ken Wehr
      result = self.rpc.call_node_add(node, keyarray[0], keyarray[1],
2990 b989b9d9 Ken Wehr
                                      keyarray[2], keyarray[3], keyarray[4],
2991 b989b9d9 Ken Wehr
                                      keyarray[5])
2992 b989b9d9 Ken Wehr
      result.Raise("Cannot transfer ssh keys to the new node")
2993 a8083063 Iustin Pop
2994 a8083063 Iustin Pop
    # Add node to our /etc/hosts, and add key to known_hosts
2995 b86a6bcd Guido Trotter
    if self.cfg.GetClusterInfo().modify_etc_hosts:
2996 b86a6bcd Guido Trotter
      utils.AddHostToEtcHosts(new_node.name)
2997 c8a0948f Michael Hanselmann
2998 a8083063 Iustin Pop
    if new_node.secondary_ip != new_node.primary_ip:
2999 781de953 Iustin Pop
      result = self.rpc.call_node_has_ip_address(new_node.name,
3000 781de953 Iustin Pop
                                                 new_node.secondary_ip)
3001 4c4e4e1e Iustin Pop
      result.Raise("Failure checking secondary ip on node %s" % new_node.name,
3002 045dd6d9 Iustin Pop
                   prereq=True, ecode=errors.ECODE_ENVIRON)
3003 c2fc8250 Iustin Pop
      if not result.payload:
3004 f4bc1f2c Michael Hanselmann
        raise errors.OpExecError("Node claims it doesn't have the secondary ip"
3005 f4bc1f2c Michael Hanselmann
                                 " you gave (%s). Please fix and re-run this"
3006 f4bc1f2c Michael Hanselmann
                                 " command." % new_node.secondary_ip)
3007 a8083063 Iustin Pop
3008 d6a02168 Michael Hanselmann
    node_verify_list = [self.cfg.GetMasterNode()]
3009 5c0527ed Guido Trotter
    node_verify_param = {
3010 f60759f7 Iustin Pop
      constants.NV_NODELIST: [node],
3011 5c0527ed Guido Trotter
      # TODO: do a node-net-test as well?
3012 5c0527ed Guido Trotter
    }
3013 5c0527ed Guido Trotter
3014 72737a7f Iustin Pop
    result = self.rpc.call_node_verify(node_verify_list, node_verify_param,
3015 72737a7f Iustin Pop
                                       self.cfg.GetClusterName())
3016 5c0527ed Guido Trotter
    for verifier in node_verify_list:
3017 4c4e4e1e Iustin Pop
      result[verifier].Raise("Cannot communicate with node %s" % verifier)
3018 f60759f7 Iustin Pop
      nl_payload = result[verifier].payload[constants.NV_NODELIST]
3019 6f68a739 Iustin Pop
      if nl_payload:
3020 6f68a739 Iustin Pop
        for failed in nl_payload:
3021 31821208 Iustin Pop
          feedback_fn("ssh/hostname verification failed"
3022 31821208 Iustin Pop
                      " (checking from %s): %s" %
3023 6f68a739 Iustin Pop
                      (verifier, nl_payload[failed]))
3024 5c0527ed Guido Trotter
        raise errors.OpExecError("ssh/hostname verification failed.")
3025 ff98055b Iustin Pop
3026 d8470559 Michael Hanselmann
    if self.op.readd:
3027 28eddce5 Guido Trotter
      _RedistributeAncillaryFiles(self)
3028 d8470559 Michael Hanselmann
      self.context.ReaddNode(new_node)
3029 a8ae3eb5 Iustin Pop
      # make sure we redistribute the config
3030 a4eae71f Michael Hanselmann
      self.cfg.Update(new_node, feedback_fn)
3031 a8ae3eb5 Iustin Pop
      # and make sure the new node will not have old files around
3032 a8ae3eb5 Iustin Pop
      if not new_node.master_candidate:
3033 a8ae3eb5 Iustin Pop
        result = self.rpc.call_node_demote_from_mc(new_node.name)
3034 3cebe102 Michael Hanselmann
        msg = result.fail_msg
3035 a8ae3eb5 Iustin Pop
        if msg:
3036 a8ae3eb5 Iustin Pop
          self.LogWarning("Node failed to demote itself from master"
3037 a8ae3eb5 Iustin Pop
                          " candidate status: %s" % msg)
3038 d8470559 Michael Hanselmann
    else:
3039 035566e3 Iustin Pop
      _RedistributeAncillaryFiles(self, additional_nodes=[node])
3040 0debfb35 Guido Trotter
      self.context.AddNode(new_node, self.proc.GetECId())
3041 a8083063 Iustin Pop
3042 a8083063 Iustin Pop
3043 b31c8676 Iustin Pop
class LUSetNodeParams(LogicalUnit):
3044 b31c8676 Iustin Pop
  """Modifies the parameters of a node.
3045 b31c8676 Iustin Pop

3046 b31c8676 Iustin Pop
  """
3047 b31c8676 Iustin Pop
  HPATH = "node-modify"
3048 b31c8676 Iustin Pop
  HTYPE = constants.HTYPE_NODE
3049 b31c8676 Iustin Pop
  _OP_REQP = ["node_name"]
3050 b31c8676 Iustin Pop
  REQ_BGL = False
3051 b31c8676 Iustin Pop
3052 b31c8676 Iustin Pop
  def CheckArguments(self):
3053 b31c8676 Iustin Pop
    node_name = self.cfg.ExpandNodeName(self.op.node_name)
3054 b31c8676 Iustin Pop
    if node_name is None:
3055 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Invalid node name '%s'" % self.op.node_name,
3056 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
3057 b31c8676 Iustin Pop
    self.op.node_name = node_name
3058 3a5ba66a Iustin Pop
    _CheckBooleanOpField(self.op, 'master_candidate')
3059 3a5ba66a Iustin Pop
    _CheckBooleanOpField(self.op, 'offline')
3060 c9d443ea Iustin Pop
    _CheckBooleanOpField(self.op, 'drained')
3061 c9d443ea Iustin Pop
    all_mods = [self.op.offline, self.op.master_candidate, self.op.drained]
3062 c9d443ea Iustin Pop
    if all_mods.count(None) == 3:
3063 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Please pass at least one modification",
3064 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
3065 c9d443ea Iustin Pop
    if all_mods.count(True) > 1:
3066 c9d443ea Iustin Pop
      raise errors.OpPrereqError("Can't set the node into more than one"
3067 5c983ee5 Iustin Pop
                                 " state at the same time",
3068 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
3069 b31c8676 Iustin Pop
3070 b31c8676 Iustin Pop
  def ExpandNames(self):
3071 b31c8676 Iustin Pop
    self.needed_locks = {locking.LEVEL_NODE: self.op.node_name}
3072 b31c8676 Iustin Pop
3073 b31c8676 Iustin Pop
  def BuildHooksEnv(self):
3074 b31c8676 Iustin Pop
    """Build hooks env.
3075 b31c8676 Iustin Pop

3076 b31c8676 Iustin Pop
    This runs on the master node.
3077 b31c8676 Iustin Pop

3078 b31c8676 Iustin Pop
    """
3079 b31c8676 Iustin Pop
    env = {
3080 b31c8676 Iustin Pop
      "OP_TARGET": self.op.node_name,
3081 b31c8676 Iustin Pop
      "MASTER_CANDIDATE": str(self.op.master_candidate),
3082 3a5ba66a Iustin Pop
      "OFFLINE": str(self.op.offline),
3083 c9d443ea Iustin Pop
      "DRAINED": str(self.op.drained),
3084 b31c8676 Iustin Pop
      }
3085 b31c8676 Iustin Pop
    nl = [self.cfg.GetMasterNode(),
3086 b31c8676 Iustin Pop
          self.op.node_name]
3087 b31c8676 Iustin Pop
    return env, nl, nl
3088 b31c8676 Iustin Pop
3089 b31c8676 Iustin Pop
  def CheckPrereq(self):
3090 b31c8676 Iustin Pop
    """Check prerequisites.
3091 b31c8676 Iustin Pop

3092 b31c8676 Iustin Pop
    This only checks the instance list against the existing names.
3093 b31c8676 Iustin Pop

3094 b31c8676 Iustin Pop
    """
3095 3a5ba66a Iustin Pop
    node = self.node = self.cfg.GetNodeInfo(self.op.node_name)
3096 b31c8676 Iustin Pop
3097 97c61d46 Iustin Pop
    if (self.op.master_candidate is not None or
3098 97c61d46 Iustin Pop
        self.op.drained is not None or
3099 97c61d46 Iustin Pop
        self.op.offline is not None):
3100 97c61d46 Iustin Pop
      # we can't change the master's node flags
3101 97c61d46 Iustin Pop
      if self.op.node_name == self.cfg.GetMasterNode():
3102 97c61d46 Iustin Pop
        raise errors.OpPrereqError("The master role can be changed"
3103 5c983ee5 Iustin Pop
                                   " only via masterfailover",
3104 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
3105 97c61d46 Iustin Pop
3106 8fbf5ac7 Guido Trotter
    # Boolean value that tells us whether we're offlining or draining the node
3107 8fbf5ac7 Guido Trotter
    offline_or_drain = self.op.offline == True or self.op.drained == True
3108 3d9eb52b Guido Trotter
    deoffline_or_drain = self.op.offline == False or self.op.drained == False
3109 8fbf5ac7 Guido Trotter
3110 8fbf5ac7 Guido Trotter
    if (node.master_candidate and
3111 8fbf5ac7 Guido Trotter
        (self.op.master_candidate == False or offline_or_drain)):
3112 3e83dd48 Iustin Pop
      cp_size = self.cfg.GetClusterInfo().candidate_pool_size
3113 8fbf5ac7 Guido Trotter
      mc_now, mc_should, mc_max = self.cfg.GetMasterCandidateStats()
3114 8fbf5ac7 Guido Trotter
      if mc_now <= cp_size:
3115 3e83dd48 Iustin Pop
        msg = ("Not enough master candidates (desired"
3116 8fbf5ac7 Guido Trotter
               " %d, new value will be %d)" % (cp_size, mc_now-1))
3117 8fbf5ac7 Guido Trotter
        # Only allow forcing the operation if it's an offline/drain operation,
3118 8fbf5ac7 Guido Trotter
        # and we could not possibly promote more nodes.
3119 8fbf5ac7 Guido Trotter
        # FIXME: this can still lead to issues if in any way another node which
3120 8fbf5ac7 Guido Trotter
        # could be promoted appears in the meantime.
3121 8fbf5ac7 Guido Trotter
        if self.op.force and offline_or_drain and mc_should == mc_max:
3122 3e83dd48 Iustin Pop
          self.LogWarning(msg)
3123 3e83dd48 Iustin Pop
        else:
3124 5c983ee5 Iustin Pop
          raise errors.OpPrereqError(msg, errors.ECODE_INVAL)
3125 3e83dd48 Iustin Pop
3126 c9d443ea Iustin Pop
    if (self.op.master_candidate == True and
3127 c9d443ea Iustin Pop
        ((node.offline and not self.op.offline == False) or
3128 c9d443ea Iustin Pop
         (node.drained and not self.op.drained == False))):
3129 c9d443ea Iustin Pop
      raise errors.OpPrereqError("Node '%s' is offline or drained, can't set"
3130 5c983ee5 Iustin Pop
                                 " to master_candidate" % node.name,
3131 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
3132 3a5ba66a Iustin Pop
3133 3d9eb52b Guido Trotter
    # If we're being deofflined/drained, we'll MC ourself if needed
3134 3d9eb52b Guido Trotter
    if (deoffline_or_drain and not offline_or_drain and not
3135 3d9eb52b Guido Trotter
        self.op.master_candidate == True):
3136 3d9eb52b Guido Trotter
      self.op.master_candidate = _DecideSelfPromotion(self)
3137 3d9eb52b Guido Trotter
      if self.op.master_candidate:
3138 3d9eb52b Guido Trotter
        self.LogInfo("Autopromoting node to master candidate")
3139 3d9eb52b Guido Trotter
3140 b31c8676 Iustin Pop
    return
3141 b31c8676 Iustin Pop
3142 b31c8676 Iustin Pop
  def Exec(self, feedback_fn):
3143 b31c8676 Iustin Pop
    """Modifies a node.
3144 b31c8676 Iustin Pop

3145 b31c8676 Iustin Pop
    """
3146 3a5ba66a Iustin Pop
    node = self.node
3147 b31c8676 Iustin Pop
3148 b31c8676 Iustin Pop
    result = []
3149 c9d443ea Iustin Pop
    changed_mc = False
3150 b31c8676 Iustin Pop
3151 3a5ba66a Iustin Pop
    if self.op.offline is not None:
3152 3a5ba66a Iustin Pop
      node.offline = self.op.offline
3153 3a5ba66a Iustin Pop
      result.append(("offline", str(self.op.offline)))
3154 c9d443ea Iustin Pop
      if self.op.offline == True:
3155 c9d443ea Iustin Pop
        if node.master_candidate:
3156 c9d443ea Iustin Pop
          node.master_candidate = False
3157 c9d443ea Iustin Pop
          changed_mc = True
3158 c9d443ea Iustin Pop
          result.append(("master_candidate", "auto-demotion due to offline"))
3159 c9d443ea Iustin Pop
        if node.drained:
3160 c9d443ea Iustin Pop
          node.drained = False
3161 c9d443ea Iustin Pop
          result.append(("drained", "clear drained status due to offline"))
3162 3a5ba66a Iustin Pop
3163 b31c8676 Iustin Pop
    if self.op.master_candidate is not None:
3164 b31c8676 Iustin Pop
      node.master_candidate = self.op.master_candidate
3165 c9d443ea Iustin Pop
      changed_mc = True
3166 b31c8676 Iustin Pop
      result.append(("master_candidate", str(self.op.master_candidate)))
3167 56aa9fd5 Iustin Pop
      if self.op.master_candidate == False:
3168 56aa9fd5 Iustin Pop
        rrc = self.rpc.call_node_demote_from_mc(node.name)
3169 4c4e4e1e Iustin Pop
        msg = rrc.fail_msg
3170 0959c824 Iustin Pop
        if msg:
3171 0959c824 Iustin Pop
          self.LogWarning("Node failed to demote itself: %s" % msg)
3172 b31c8676 Iustin Pop
3173 c9d443ea Iustin Pop
    if self.op.drained is not None:
3174 c9d443ea Iustin Pop
      node.drained = self.op.drained
3175 82e12743 Iustin Pop
      result.append(("drained", str(self.op.drained)))
3176 c9d443ea Iustin Pop
      if self.op.drained == True:
3177 c9d443ea Iustin Pop
        if node.master_candidate:
3178 c9d443ea Iustin Pop
          node.master_candidate = False
3179 c9d443ea Iustin Pop
          changed_mc = True
3180 c9d443ea Iustin Pop
          result.append(("master_candidate", "auto-demotion due to drain"))
3181 dec0d9da Iustin Pop
          rrc = self.rpc.call_node_demote_from_mc(node.name)
3182 3cebe102 Michael Hanselmann
          msg = rrc.fail_msg
3183 dec0d9da Iustin Pop
          if msg:
3184 dec0d9da Iustin Pop
            self.LogWarning("Node failed to demote itself: %s" % msg)
3185 c9d443ea Iustin Pop
        if node.offline:
3186 c9d443ea Iustin Pop
          node.offline = False
3187 c9d443ea Iustin Pop
          result.append(("offline", "clear offline status due to drain"))
3188 c9d443ea Iustin Pop
3189 b31c8676 Iustin Pop
    # this will trigger configuration file update, if needed
3190 a4eae71f Michael Hanselmann
    self.cfg.Update(node, feedback_fn)
3191 b31c8676 Iustin Pop
    # this will trigger job queue propagation or cleanup
3192 c9d443ea Iustin Pop
    if changed_mc:
3193 3a26773f Iustin Pop
      self.context.ReaddNode(node)
3194 b31c8676 Iustin Pop
3195 b31c8676 Iustin Pop
    return result
3196 b31c8676 Iustin Pop
3197 b31c8676 Iustin Pop
3198 f5118ade Iustin Pop
class LUPowercycleNode(NoHooksLU):
3199 f5118ade Iustin Pop
  """Powercycles a node.
3200 f5118ade Iustin Pop

3201 f5118ade Iustin Pop
  """
3202 f5118ade Iustin Pop
  _OP_REQP = ["node_name", "force"]
3203 f5118ade Iustin Pop
  REQ_BGL = False
3204 f5118ade Iustin Pop
3205 f5118ade Iustin Pop
  def CheckArguments(self):
3206 f5118ade Iustin Pop
    node_name = self.cfg.ExpandNodeName(self.op.node_name)
3207 f5118ade Iustin Pop
    if node_name is None:
3208 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Invalid node name '%s'" % self.op.node_name,
3209 5c983ee5 Iustin Pop
                                 errors.ECODE_NOENT)
3210 f5118ade Iustin Pop
    self.op.node_name = node_name
3211 f5118ade Iustin Pop
    if node_name == self.cfg.GetMasterNode() and not self.op.force:
3212 f5118ade Iustin Pop
      raise errors.OpPrereqError("The node is the master and the force"
3213 5c983ee5 Iustin Pop
                                 " parameter was not set",
3214 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
3215 f5118ade Iustin Pop
3216 f5118ade Iustin Pop
  def ExpandNames(self):
3217 f5118ade Iustin Pop
    """Locking for PowercycleNode.
3218 f5118ade Iustin Pop

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

3222 f5118ade Iustin Pop
    """
3223 f5118ade Iustin Pop
    self.needed_locks = {}
3224 f5118ade Iustin Pop
3225 f5118ade Iustin Pop
  def CheckPrereq(self):
3226 f5118ade Iustin Pop
    """Check prerequisites.
3227 f5118ade Iustin Pop

3228 f5118ade Iustin Pop
    This LU has no prereqs.
3229 f5118ade Iustin Pop

3230 f5118ade Iustin Pop
    """
3231 f5118ade Iustin Pop
    pass
3232 f5118ade Iustin Pop
3233 f5118ade Iustin Pop
  def Exec(self, feedback_fn):
3234 f5118ade Iustin Pop
    """Reboots a node.
3235 f5118ade Iustin Pop

3236 f5118ade Iustin Pop
    """
3237 f5118ade Iustin Pop
    result = self.rpc.call_node_powercycle(self.op.node_name,
3238 f5118ade Iustin Pop
                                           self.cfg.GetHypervisorType())
3239 4c4e4e1e Iustin Pop
    result.Raise("Failed to schedule the reboot")
3240 f5118ade Iustin Pop
    return result.payload
3241 f5118ade Iustin Pop
3242 f5118ade Iustin Pop
3243 a8083063 Iustin Pop
class LUQueryClusterInfo(NoHooksLU):
3244 a8083063 Iustin Pop
  """Query cluster configuration.
3245 a8083063 Iustin Pop

3246 a8083063 Iustin Pop
  """
3247 a8083063 Iustin Pop
  _OP_REQP = []
3248 642339cf Guido Trotter
  REQ_BGL = False
3249 642339cf Guido Trotter
3250 642339cf Guido Trotter
  def ExpandNames(self):
3251 642339cf Guido Trotter
    self.needed_locks = {}
3252 a8083063 Iustin Pop
3253 a8083063 Iustin Pop
  def CheckPrereq(self):
3254 a8083063 Iustin Pop
    """No prerequsites needed for this LU.
3255 a8083063 Iustin Pop

3256 a8083063 Iustin Pop
    """
3257 a8083063 Iustin Pop
    pass
3258 a8083063 Iustin Pop
3259 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
3260 a8083063 Iustin Pop
    """Return cluster config.
3261 a8083063 Iustin Pop

3262 a8083063 Iustin Pop
    """
3263 469f88e1 Iustin Pop
    cluster = self.cfg.GetClusterInfo()
3264 a8083063 Iustin Pop
    result = {
3265 a8083063 Iustin Pop
      "software_version": constants.RELEASE_VERSION,
3266 a8083063 Iustin Pop
      "protocol_version": constants.PROTOCOL_VERSION,
3267 a8083063 Iustin Pop
      "config_version": constants.CONFIG_VERSION,
3268 d1a7d66f Guido Trotter
      "os_api_version": max(constants.OS_API_VERSIONS),
3269 a8083063 Iustin Pop
      "export_version": constants.EXPORT_VERSION,
3270 a8083063 Iustin Pop
      "architecture": (platform.architecture()[0], platform.machine()),
3271 469f88e1 Iustin Pop
      "name": cluster.cluster_name,
3272 469f88e1 Iustin Pop
      "master": cluster.master_node,
3273 066f465d Guido Trotter
      "default_hypervisor": cluster.enabled_hypervisors[0],
3274 469f88e1 Iustin Pop
      "enabled_hypervisors": cluster.enabled_hypervisors,
3275 b8810fec Michael Hanselmann
      "hvparams": dict([(hypervisor_name, cluster.hvparams[hypervisor_name])
3276 7c4d6c7b Michael Hanselmann
                        for hypervisor_name in cluster.enabled_hypervisors]),
3277 469f88e1 Iustin Pop
      "beparams": cluster.beparams,
3278 1094acda Guido Trotter
      "nicparams": cluster.nicparams,
3279 4b7735f9 Iustin Pop
      "candidate_pool_size": cluster.candidate_pool_size,
3280 7a56b411 Guido Trotter
      "master_netdev": cluster.master_netdev,
3281 7a56b411 Guido Trotter
      "volume_group_name": cluster.volume_group_name,
3282 7a56b411 Guido Trotter
      "file_storage_dir": cluster.file_storage_dir,
3283 90f72445 Iustin Pop
      "ctime": cluster.ctime,
3284 90f72445 Iustin Pop
      "mtime": cluster.mtime,
3285 259578eb Iustin Pop
      "uuid": cluster.uuid,
3286 c118d1f4 Michael Hanselmann
      "tags": list(cluster.GetTags()),
3287 a8083063 Iustin Pop
      }
3288 a8083063 Iustin Pop
3289 a8083063 Iustin Pop
    return result
3290 a8083063 Iustin Pop
3291 a8083063 Iustin Pop
3292 ae5849b5 Michael Hanselmann
class LUQueryConfigValues(NoHooksLU):
3293 ae5849b5 Michael Hanselmann
  """Return configuration values.
3294 a8083063 Iustin Pop

3295 a8083063 Iustin Pop
  """
3296 a8083063 Iustin Pop
  _OP_REQP = []
3297 642339cf Guido Trotter
  REQ_BGL = False
3298 a2d2e1a7 Iustin Pop
  _FIELDS_DYNAMIC = utils.FieldSet()
3299 05e50653 Michael Hanselmann
  _FIELDS_STATIC = utils.FieldSet("cluster_name", "master_node", "drain_flag",
3300 05e50653 Michael Hanselmann
                                  "watcher_pause")
3301 642339cf Guido Trotter
3302 642339cf Guido Trotter
  def ExpandNames(self):
3303 642339cf Guido Trotter
    self.needed_locks = {}
3304 a8083063 Iustin Pop
3305 31bf511f Iustin Pop
    _CheckOutputFields(static=self._FIELDS_STATIC,
3306 31bf511f Iustin Pop
                       dynamic=self._FIELDS_DYNAMIC,
3307 ae5849b5 Michael Hanselmann
                       selected=self.op.output_fields)
3308 ae5849b5 Michael Hanselmann
3309 a8083063 Iustin Pop
  def CheckPrereq(self):
3310 a8083063 Iustin Pop
    """No prerequisites.
3311 a8083063 Iustin Pop

3312 a8083063 Iustin Pop
    """
3313 a8083063 Iustin Pop
    pass
3314 a8083063 Iustin Pop
3315 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
3316 a8083063 Iustin Pop
    """Dump a representation of the cluster config to the standard output.
3317 a8083063 Iustin Pop

3318 a8083063 Iustin Pop
    """
3319 ae5849b5 Michael Hanselmann
    values = []
3320 ae5849b5 Michael Hanselmann
    for field in self.op.output_fields:
3321 ae5849b5 Michael Hanselmann
      if field == "cluster_name":
3322 3ccafd0e Iustin Pop
        entry = self.cfg.GetClusterName()
3323 ae5849b5 Michael Hanselmann
      elif field == "master_node":
3324 3ccafd0e Iustin Pop
        entry = self.cfg.GetMasterNode()
3325 3ccafd0e Iustin Pop
      elif field == "drain_flag":
3326 3ccafd0e Iustin Pop
        entry = os.path.exists(constants.JOB_QUEUE_DRAIN_FILE)
3327 05e50653 Michael Hanselmann
      elif field == "watcher_pause":
3328 05e50653 Michael Hanselmann
        return utils.ReadWatcherPauseFile(constants.WATCHER_PAUSEFILE)
3329 ae5849b5 Michael Hanselmann
      else:
3330 ae5849b5 Michael Hanselmann
        raise errors.ParameterError(field)
3331 3ccafd0e Iustin Pop
      values.append(entry)
3332 ae5849b5 Michael Hanselmann
    return values
3333 a8083063 Iustin Pop
3334 a8083063 Iustin Pop
3335 a8083063 Iustin Pop
class LUActivateInstanceDisks(NoHooksLU):
3336 a8083063 Iustin Pop
  """Bring up an instance's disks.
3337 a8083063 Iustin Pop

3338 a8083063 Iustin Pop
  """
3339 a8083063 Iustin Pop
  _OP_REQP = ["instance_name"]
3340 f22a8ba3 Guido Trotter
  REQ_BGL = False
3341 f22a8ba3 Guido Trotter
3342 f22a8ba3 Guido Trotter
  def ExpandNames(self):
3343 f22a8ba3 Guido Trotter
    self._ExpandAndLockInstance()
3344 f22a8ba3 Guido Trotter
    self.needed_locks[locking.LEVEL_NODE] = []
3345 f22a8ba3 Guido Trotter
    self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
3346 f22a8ba3 Guido Trotter
3347 f22a8ba3 Guido Trotter
  def DeclareLocks(self, level):
3348 f22a8ba3 Guido Trotter
    if level == locking.LEVEL_NODE:
3349 f22a8ba3 Guido Trotter
      self._LockInstancesNodes()
3350 a8083063 Iustin Pop
3351 a8083063 Iustin Pop
  def CheckPrereq(self):
3352 a8083063 Iustin Pop
    """Check prerequisites.
3353 a8083063 Iustin Pop

3354 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
3355 a8083063 Iustin Pop

3356 a8083063 Iustin Pop
    """
3357 f22a8ba3 Guido Trotter
    self.instance = self.cfg.GetInstanceInfo(self.op.instance_name)
3358 f22a8ba3 Guido Trotter
    assert self.instance is not None, \
3359 f22a8ba3 Guido Trotter
      "Cannot retrieve locked instance %s" % self.op.instance_name
3360 43017d26 Iustin Pop
    _CheckNodeOnline(self, self.instance.primary_node)
3361 b4ec07f8 Iustin Pop
    if not hasattr(self.op, "ignore_size"):
3362 b4ec07f8 Iustin Pop
      self.op.ignore_size = False
3363 a8083063 Iustin Pop
3364 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
3365 a8083063 Iustin Pop
    """Activate the disks.
3366 a8083063 Iustin Pop

3367 a8083063 Iustin Pop
    """
3368 b4ec07f8 Iustin Pop
    disks_ok, disks_info = \
3369 b4ec07f8 Iustin Pop
              _AssembleInstanceDisks(self, self.instance,
3370 b4ec07f8 Iustin Pop
                                     ignore_size=self.op.ignore_size)
3371 a8083063 Iustin Pop
    if not disks_ok:
3372 3ecf6786 Iustin Pop
      raise errors.OpExecError("Cannot activate block devices")
3373 a8083063 Iustin Pop
3374 a8083063 Iustin Pop
    return disks_info
3375 a8083063 Iustin Pop
3376 a8083063 Iustin Pop
3377 e3443b36 Iustin Pop
def _AssembleInstanceDisks(lu, instance, ignore_secondaries=False,
3378 e3443b36 Iustin Pop
                           ignore_size=False):
3379 a8083063 Iustin Pop
  """Prepare the block devices for an instance.
3380 a8083063 Iustin Pop

3381 a8083063 Iustin Pop
  This sets up the block devices on all nodes.
3382 a8083063 Iustin Pop

3383 e4376078 Iustin Pop
  @type lu: L{LogicalUnit}
3384 e4376078 Iustin Pop
  @param lu: the logical unit on whose behalf we execute
3385 e4376078 Iustin Pop
  @type instance: L{objects.Instance}
3386 e4376078 Iustin Pop
  @param instance: the instance for whose disks we assemble
3387 e4376078 Iustin Pop
  @type ignore_secondaries: boolean
3388 e4376078 Iustin Pop
  @param ignore_secondaries: if true, errors on secondary nodes
3389 e4376078 Iustin Pop
      won't result in an error return from the function
3390 e3443b36 Iustin Pop
  @type ignore_size: boolean
3391 e3443b36 Iustin Pop
  @param ignore_size: if true, the current known size of the disk
3392 e3443b36 Iustin Pop
      will not be used during the disk activation, useful for cases
3393 e3443b36 Iustin Pop
      when the size is wrong
3394 e4376078 Iustin Pop
  @return: False if the operation failed, otherwise a list of
3395 e4376078 Iustin Pop
      (host, instance_visible_name, node_visible_name)
3396 e4376078 Iustin Pop
      with the mapping from node devices to instance devices
3397 a8083063 Iustin Pop

3398 a8083063 Iustin Pop
  """
3399 a8083063 Iustin Pop
  device_info = []
3400 a8083063 Iustin Pop
  disks_ok = True
3401 fdbd668d Iustin Pop
  iname = instance.name
3402 fdbd668d Iustin Pop
  # With the two passes mechanism we try to reduce the window of
3403 fdbd668d Iustin Pop
  # opportunity for the race condition of switching DRBD to primary
3404 fdbd668d Iustin Pop
  # before handshaking occured, but we do not eliminate it
3405 fdbd668d Iustin Pop
3406 fdbd668d Iustin Pop
  # The proper fix would be to wait (with some limits) until the
3407 fdbd668d Iustin Pop
  # connection has been made and drbd transitions from WFConnection
3408 fdbd668d Iustin Pop
  # into any other network-connected state (Connected, SyncTarget,
3409 fdbd668d Iustin Pop
  # SyncSource, etc.)
3410 fdbd668d Iustin Pop
3411 fdbd668d Iustin Pop
  # 1st pass, assemble on all nodes in secondary mode
3412 a8083063 Iustin Pop
  for inst_disk in instance.disks:
3413 a8083063 Iustin Pop
    for node, node_disk in inst_disk.ComputeNodeTree(instance.primary_node):
3414 e3443b36 Iustin Pop
      if ignore_size:
3415 e3443b36 Iustin Pop
        node_disk = node_disk.Copy()
3416 e3443b36 Iustin Pop
        node_disk.UnsetSize()
3417 b9bddb6b Iustin Pop
      lu.cfg.SetDiskID(node_disk, node)
3418 72737a7f Iustin Pop
      result = lu.rpc.call_blockdev_assemble(node, node_disk, iname, False)
3419 4c4e4e1e Iustin Pop
      msg = result.fail_msg
3420 53c14ef1 Iustin Pop
      if msg:
3421 86d9d3bb Iustin Pop
        lu.proc.LogWarning("Could not prepare block device %s on node %s"
3422 53c14ef1 Iustin Pop
                           " (is_primary=False, pass=1): %s",
3423 53c14ef1 Iustin Pop
                           inst_disk.iv_name, node, msg)
3424 fdbd668d Iustin Pop
        if not ignore_secondaries:
3425 a8083063 Iustin Pop
          disks_ok = False
3426 fdbd668d Iustin Pop
3427 fdbd668d Iustin Pop
  # FIXME: race condition on drbd migration to primary
3428 fdbd668d Iustin Pop
3429 fdbd668d Iustin Pop
  # 2nd pass, do only the primary node
3430 fdbd668d Iustin Pop
  for inst_disk in instance.disks:
3431 d52ea991 Michael Hanselmann
    dev_path = None
3432 d52ea991 Michael Hanselmann
3433 fdbd668d Iustin Pop
    for node, node_disk in inst_disk.ComputeNodeTree(instance.primary_node):
3434 fdbd668d Iustin Pop
      if node != instance.primary_node:
3435 fdbd668d Iustin Pop
        continue
3436 e3443b36 Iustin Pop
      if ignore_size:
3437 e3443b36 Iustin Pop
        node_disk = node_disk.Copy()
3438 e3443b36 Iustin Pop
        node_disk.UnsetSize()
3439 b9bddb6b Iustin Pop
      lu.cfg.SetDiskID(node_disk, node)
3440 72737a7f Iustin Pop
      result = lu.rpc.call_blockdev_assemble(node, node_disk, iname, True)
3441 4c4e4e1e Iustin Pop
      msg = result.fail_msg
3442 53c14ef1 Iustin Pop
      if msg:
3443 86d9d3bb Iustin Pop
        lu.proc.LogWarning("Could not prepare block device %s on node %s"
3444 53c14ef1 Iustin Pop
                           " (is_primary=True, pass=2): %s",
3445 53c14ef1 Iustin Pop
                           inst_disk.iv_name, node, msg)
3446 fdbd668d Iustin Pop
        disks_ok = False
3447 d52ea991 Michael Hanselmann
      else:
3448 d52ea991 Michael Hanselmann
        dev_path = result.payload
3449 d52ea991 Michael Hanselmann
3450 d52ea991 Michael Hanselmann
    device_info.append((instance.primary_node, inst_disk.iv_name, dev_path))
3451 a8083063 Iustin Pop
3452 b352ab5b Iustin Pop
  # leave the disks configured for the primary node
3453 b352ab5b Iustin Pop
  # this is a workaround that would be fixed better by
3454 b352ab5b Iustin Pop
  # improving the logical/physical id handling
3455 b352ab5b Iustin Pop
  for disk in instance.disks:
3456 b9bddb6b Iustin Pop
    lu.cfg.SetDiskID(disk, instance.primary_node)
3457 b352ab5b Iustin Pop
3458 a8083063 Iustin Pop
  return disks_ok, device_info
3459 a8083063 Iustin Pop
3460 a8083063 Iustin Pop
3461 b9bddb6b Iustin Pop
def _StartInstanceDisks(lu, instance, force):
3462 3ecf6786 Iustin Pop
  """Start the disks of an instance.
3463 3ecf6786 Iustin Pop

3464 3ecf6786 Iustin Pop
  """
3465 7c4d6c7b Michael Hanselmann
  disks_ok, _ = _AssembleInstanceDisks(lu, instance,
3466 fe7b0351 Michael Hanselmann
                                           ignore_secondaries=force)
3467 fe7b0351 Michael Hanselmann
  if not disks_ok:
3468 b9bddb6b Iustin Pop
    _ShutdownInstanceDisks(lu, instance)
3469 fe7b0351 Michael Hanselmann
    if force is not None and not force:
3470 86d9d3bb Iustin Pop
      lu.proc.LogWarning("", hint="If the message above refers to a"
3471 86d9d3bb Iustin Pop
                         " secondary node,"
3472 86d9d3bb Iustin Pop
                         " you can retry the operation using '--force'.")
3473 3ecf6786 Iustin Pop
    raise errors.OpExecError("Disk consistency error")
3474 fe7b0351 Michael Hanselmann
3475 fe7b0351 Michael Hanselmann
3476 a8083063 Iustin Pop
class LUDeactivateInstanceDisks(NoHooksLU):
3477 a8083063 Iustin Pop
  """Shutdown an instance's disks.
3478 a8083063 Iustin Pop

3479 a8083063 Iustin Pop
  """
3480 a8083063 Iustin Pop
  _OP_REQP = ["instance_name"]
3481 f22a8ba3 Guido Trotter
  REQ_BGL = False
3482 f22a8ba3 Guido Trotter
3483 f22a8ba3 Guido Trotter
  def ExpandNames(self):
3484 f22a8ba3 Guido Trotter
    self._ExpandAndLockInstance()
3485 f22a8ba3 Guido Trotter
    self.needed_locks[locking.LEVEL_NODE] = []
3486 f22a8ba3 Guido Trotter
    self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
3487 f22a8ba3 Guido Trotter
3488 f22a8ba3 Guido Trotter
  def DeclareLocks(self, level):
3489 f22a8ba3 Guido Trotter
    if level == locking.LEVEL_NODE:
3490 f22a8ba3 Guido Trotter
      self._LockInstancesNodes()
3491 a8083063 Iustin Pop
3492 a8083063 Iustin Pop
  def CheckPrereq(self):
3493 a8083063 Iustin Pop
    """Check prerequisites.
3494 a8083063 Iustin Pop

3495 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
3496 a8083063 Iustin Pop

3497 a8083063 Iustin Pop
    """
3498 f22a8ba3 Guido Trotter
    self.instance = self.cfg.GetInstanceInfo(self.op.instance_name)
3499 f22a8ba3 Guido Trotter
    assert self.instance is not None, \
3500 f22a8ba3 Guido Trotter
      "Cannot retrieve locked instance %s" % self.op.instance_name
3501 a8083063 Iustin Pop
3502 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
3503 a8083063 Iustin Pop
    """Deactivate the disks
3504 a8083063 Iustin Pop

3505 a8083063 Iustin Pop
    """
3506 a8083063 Iustin Pop
    instance = self.instance
3507 b9bddb6b Iustin Pop
    _SafeShutdownInstanceDisks(self, instance)
3508 a8083063 Iustin Pop
3509 a8083063 Iustin Pop
3510 b9bddb6b Iustin Pop
def _SafeShutdownInstanceDisks(lu, instance):
3511 155d6c75 Guido Trotter
  """Shutdown block devices of an instance.
3512 155d6c75 Guido Trotter

3513 155d6c75 Guido Trotter
  This function checks if an instance is running, before calling
3514 155d6c75 Guido Trotter
  _ShutdownInstanceDisks.
3515 155d6c75 Guido Trotter

3516 155d6c75 Guido Trotter
  """
3517 aca13712 Iustin Pop
  pnode = instance.primary_node
3518 4c4e4e1e Iustin Pop
  ins_l = lu.rpc.call_instance_list([pnode], [instance.hypervisor])[pnode]
3519 4c4e4e1e Iustin Pop
  ins_l.Raise("Can't contact node %s" % pnode)
3520 aca13712 Iustin Pop
3521 aca13712 Iustin Pop
  if instance.name in ins_l.payload:
3522 155d6c75 Guido Trotter
    raise errors.OpExecError("Instance is running, can't shutdown"
3523 155d6c75 Guido Trotter
                             " block devices.")
3524 155d6c75 Guido Trotter
3525 b9bddb6b Iustin Pop
  _ShutdownInstanceDisks(lu, instance)
3526 a8083063 Iustin Pop
3527 a8083063 Iustin Pop
3528 b9bddb6b Iustin Pop
def _ShutdownInstanceDisks(lu, instance, ignore_primary=False):
3529 a8083063 Iustin Pop
  """Shutdown block devices of an instance.
3530 a8083063 Iustin Pop

3531 a8083063 Iustin Pop
  This does the shutdown on all nodes of the instance.
3532 a8083063 Iustin Pop

3533 a8083063 Iustin Pop
  If the ignore_primary is false, errors on the primary node are
3534 a8083063 Iustin Pop
  ignored.
3535 a8083063 Iustin Pop

3536 a8083063 Iustin Pop
  """
3537 cacfd1fd Iustin Pop
  all_result = True
3538 a8083063 Iustin Pop
  for disk in instance.disks:
3539 a8083063 Iustin Pop
    for node, top_disk in disk.ComputeNodeTree(instance.primary_node):
3540 b9bddb6b Iustin Pop
      lu.cfg.SetDiskID(top_disk, node)
3541 781de953 Iustin Pop
      result = lu.rpc.call_blockdev_shutdown(node, top_disk)
3542 4c4e4e1e Iustin Pop
      msg = result.fail_msg
3543 cacfd1fd Iustin Pop
      if msg:
3544 cacfd1fd Iustin Pop
        lu.LogWarning("Could not shutdown block device %s on node %s: %s",
3545 cacfd1fd Iustin Pop
                      disk.iv_name, node, msg)
3546 a8083063 Iustin Pop
        if not ignore_primary or node != instance.primary_node:
3547 cacfd1fd Iustin Pop
          all_result = False
3548 cacfd1fd Iustin Pop
  return all_result
3549 a8083063 Iustin Pop
3550 a8083063 Iustin Pop
3551 9ca87a96 Iustin Pop
def _CheckNodeFreeMemory(lu, node, reason, requested, hypervisor_name):
3552 d4f16fd9 Iustin Pop
  """Checks if a node has enough free memory.
3553 d4f16fd9 Iustin Pop

3554 d4f16fd9 Iustin Pop
  This function check if a given node has the needed amount of free
3555 d4f16fd9 Iustin Pop
  memory. In case the node has less memory or we cannot get the
3556 d4f16fd9 Iustin Pop
  information from the node, this function raise an OpPrereqError
3557 d4f16fd9 Iustin Pop
  exception.
3558 d4f16fd9 Iustin Pop

3559 b9bddb6b Iustin Pop
  @type lu: C{LogicalUnit}
3560 b9bddb6b Iustin Pop
  @param lu: a logical unit from which we get configuration data
3561 e69d05fd Iustin Pop
  @type node: C{str}
3562 e69d05fd Iustin Pop
  @param node: the node to check
3563 e69d05fd Iustin Pop
  @type reason: C{str}
3564 e69d05fd Iustin Pop
  @param reason: string to use in the error message
3565 e69d05fd Iustin Pop
  @type requested: C{int}
3566 e69d05fd Iustin Pop
  @param requested: the amount of memory in MiB to check for
3567 9ca87a96 Iustin Pop
  @type hypervisor_name: C{str}
3568 9ca87a96 Iustin Pop
  @param hypervisor_name: the hypervisor to ask for memory stats
3569 e69d05fd Iustin Pop
  @raise errors.OpPrereqError: if the node doesn't have enough memory, or
3570 e69d05fd Iustin Pop
      we cannot check the node
3571 d4f16fd9 Iustin Pop

3572 d4f16fd9 Iustin Pop
  """
3573 9ca87a96 Iustin Pop
  nodeinfo = lu.rpc.call_node_info([node], lu.cfg.GetVGName(), hypervisor_name)
3574 045dd6d9 Iustin Pop
  nodeinfo[node].Raise("Can't get data from node %s" % node,
3575 045dd6d9 Iustin Pop
                       prereq=True, ecode=errors.ECODE_ENVIRON)
3576 070e998b Iustin Pop
  free_mem = nodeinfo[node].payload.get('memory_free', None)
3577 d4f16fd9 Iustin Pop
  if not isinstance(free_mem, int):
3578 d4f16fd9 Iustin Pop
    raise errors.OpPrereqError("Can't compute free memory on node %s, result"
3579 5c983ee5 Iustin Pop
                               " was '%s'" % (node, free_mem),
3580 5c983ee5 Iustin Pop
                               errors.ECODE_ENVIRON)
3581 d4f16fd9 Iustin Pop
  if requested > free_mem:
3582 d4f16fd9 Iustin Pop
    raise errors.OpPrereqError("Not enough memory on node %s for %s:"
3583 070e998b Iustin Pop
                               " needed %s MiB, available %s MiB" %
3584 5c983ee5 Iustin Pop
                               (node, reason, requested, free_mem),
3585 5c983ee5 Iustin Pop
                               errors.ECODE_NORES)
3586 d4f16fd9 Iustin Pop
3587 d4f16fd9 Iustin Pop
3588 a8083063 Iustin Pop
class LUStartupInstance(LogicalUnit):
3589 a8083063 Iustin Pop
  """Starts an instance.
3590 a8083063 Iustin Pop

3591 a8083063 Iustin Pop
  """
3592 a8083063 Iustin Pop
  HPATH = "instance-start"
3593 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
3594 a8083063 Iustin Pop
  _OP_REQP = ["instance_name", "force"]
3595 e873317a Guido Trotter
  REQ_BGL = False
3596 e873317a Guido Trotter
3597 e873317a Guido Trotter
  def ExpandNames(self):
3598 e873317a Guido Trotter
    self._ExpandAndLockInstance()
3599 a8083063 Iustin Pop
3600 a8083063 Iustin Pop
  def BuildHooksEnv(self):
3601 a8083063 Iustin Pop
    """Build hooks env.
3602 a8083063 Iustin Pop

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

3605 a8083063 Iustin Pop
    """
3606 a8083063 Iustin Pop
    env = {
3607 a8083063 Iustin Pop
      "FORCE": self.op.force,
3608 a8083063 Iustin Pop
      }
3609 338e51e8 Iustin Pop
    env.update(_BuildInstanceHookEnvByObject(self, self.instance))
3610 6b12959c Iustin Pop
    nl = [self.cfg.GetMasterNode()] + list(self.instance.all_nodes)
3611 a8083063 Iustin Pop
    return env, nl, nl
3612 a8083063 Iustin Pop
3613 a8083063 Iustin Pop
  def CheckPrereq(self):
3614 a8083063 Iustin Pop
    """Check prerequisites.
3615 a8083063 Iustin Pop

3616 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
3617 a8083063 Iustin Pop

3618 a8083063 Iustin Pop
    """
3619 e873317a Guido Trotter
    self.instance = instance = self.cfg.GetInstanceInfo(self.op.instance_name)
3620 e873317a Guido Trotter
    assert self.instance is not None, \
3621 e873317a Guido Trotter
      "Cannot retrieve locked instance %s" % self.op.instance_name
3622 a8083063 Iustin Pop
3623 d04aaa2f Iustin Pop
    # extra beparams
3624 d04aaa2f Iustin Pop
    self.beparams = getattr(self.op, "beparams", {})
3625 d04aaa2f Iustin Pop
    if self.beparams:
3626 d04aaa2f Iustin Pop
      if not isinstance(self.beparams, dict):
3627 d04aaa2f Iustin Pop
        raise errors.OpPrereqError("Invalid beparams passed: %s, expected"
3628 5c983ee5 Iustin Pop
                                   " dict" % (type(self.beparams), ),
3629 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
3630 d04aaa2f Iustin Pop
      # fill the beparams dict
3631 d04aaa2f Iustin Pop
      utils.ForceDictType(self.beparams, constants.BES_PARAMETER_TYPES)
3632 d04aaa2f Iustin Pop
      self.op.beparams = self.beparams
3633 d04aaa2f Iustin Pop
3634 d04aaa2f Iustin Pop
    # extra hvparams
3635 d04aaa2f Iustin Pop
    self.hvparams = getattr(self.op, "hvparams", {})
3636 d04aaa2f Iustin Pop
    if self.hvparams:
3637 d04aaa2f Iustin Pop
      if not isinstance(self.hvparams, dict):
3638 d04aaa2f Iustin Pop
        raise errors.OpPrereqError("Invalid hvparams passed: %s, expected"
3639 5c983ee5 Iustin Pop
                                   " dict" % (type(self.hvparams), ),
3640 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
3641 d04aaa2f Iustin Pop
3642 d04aaa2f Iustin Pop
      # check hypervisor parameter syntax (locally)
3643 d04aaa2f Iustin Pop
      cluster = self.cfg.GetClusterInfo()
3644 d04aaa2f Iustin Pop
      utils.ForceDictType(self.hvparams, constants.HVS_PARAMETER_TYPES)
3645 abe609b2 Guido Trotter
      filled_hvp = objects.FillDict(cluster.hvparams[instance.hypervisor],
3646 d04aaa2f Iustin Pop
                                    instance.hvparams)
3647 d04aaa2f Iustin Pop
      filled_hvp.update(self.hvparams)
3648 d04aaa2f Iustin Pop
      hv_type = hypervisor.GetHypervisor(instance.hypervisor)
3649 d04aaa2f Iustin Pop
      hv_type.CheckParameterSyntax(filled_hvp)
3650 d04aaa2f Iustin Pop
      _CheckHVParams(self, instance.all_nodes, instance.hypervisor, filled_hvp)
3651 d04aaa2f Iustin Pop
      self.op.hvparams = self.hvparams
3652 d04aaa2f Iustin Pop
3653 7527a8a4 Iustin Pop
    _CheckNodeOnline(self, instance.primary_node)
3654 7527a8a4 Iustin Pop
3655 338e51e8 Iustin Pop
    bep = self.cfg.GetClusterInfo().FillBE(instance)
3656 5bbd3f7f Michael Hanselmann
    # check bridges existence
3657 b9bddb6b Iustin Pop
    _CheckInstanceBridgesExist(self, instance)
3658 a8083063 Iustin Pop
3659 f1926756 Guido Trotter
    remote_info = self.rpc.call_instance_info(instance.primary_node,
3660 f1926756 Guido Trotter
                                              instance.name,
3661 f1926756 Guido Trotter
                                              instance.hypervisor)
3662 4c4e4e1e Iustin Pop
    remote_info.Raise("Error checking node %s" % instance.primary_node,
3663 045dd6d9 Iustin Pop
                      prereq=True, ecode=errors.ECODE_ENVIRON)
3664 7ad1af4a Iustin Pop
    if not remote_info.payload: # not running already
3665 f1926756 Guido Trotter
      _CheckNodeFreeMemory(self, instance.primary_node,
3666 f1926756 Guido Trotter
                           "starting instance %s" % instance.name,
3667 f1926756 Guido Trotter
                           bep[constants.BE_MEMORY], instance.hypervisor)
3668 d4f16fd9 Iustin Pop
3669 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
3670 a8083063 Iustin Pop
    """Start the instance.
3671 a8083063 Iustin Pop

3672 a8083063 Iustin Pop
    """
3673 a8083063 Iustin Pop
    instance = self.instance
3674 a8083063 Iustin Pop
    force = self.op.force
3675 a8083063 Iustin Pop
3676 fe482621 Iustin Pop
    self.cfg.MarkInstanceUp(instance.name)
3677 fe482621 Iustin Pop
3678 a8083063 Iustin Pop
    node_current = instance.primary_node
3679 a8083063 Iustin Pop
3680 b9bddb6b Iustin Pop
    _StartInstanceDisks(self, instance, force)
3681 a8083063 Iustin Pop
3682 d04aaa2f Iustin Pop
    result = self.rpc.call_instance_start(node_current, instance,
3683 d04aaa2f Iustin Pop
                                          self.hvparams, self.beparams)
3684 4c4e4e1e Iustin Pop
    msg = result.fail_msg
3685 dd279568 Iustin Pop
    if msg:
3686 b9bddb6b Iustin Pop
      _ShutdownInstanceDisks(self, instance)
3687 dd279568 Iustin Pop
      raise errors.OpExecError("Could not start instance: %s" % msg)
3688 a8083063 Iustin Pop
3689 a8083063 Iustin Pop
3690 bf6929a2 Alexander Schreiber
class LURebootInstance(LogicalUnit):
3691 bf6929a2 Alexander Schreiber
  """Reboot an instance.
3692 bf6929a2 Alexander Schreiber

3693 bf6929a2 Alexander Schreiber
  """
3694 bf6929a2 Alexander Schreiber
  HPATH = "instance-reboot"
3695 bf6929a2 Alexander Schreiber
  HTYPE = constants.HTYPE_INSTANCE
3696 bf6929a2 Alexander Schreiber
  _OP_REQP = ["instance_name", "ignore_secondaries", "reboot_type"]
3697 e873317a Guido Trotter
  REQ_BGL = False
3698 e873317a Guido Trotter
3699 17c3f802 Guido Trotter
  def CheckArguments(self):
3700 17c3f802 Guido Trotter
    """Check the arguments.
3701 17c3f802 Guido Trotter

3702 17c3f802 Guido Trotter
    """
3703 17c3f802 Guido Trotter
    self.shutdown_timeout = getattr(self.op, "shutdown_timeout",
3704 17c3f802 Guido Trotter
                                    constants.DEFAULT_SHUTDOWN_TIMEOUT)
3705 17c3f802 Guido Trotter
3706 e873317a Guido Trotter
  def ExpandNames(self):
3707 0fcc5db3 Guido Trotter
    if self.op.reboot_type not in [constants.INSTANCE_REBOOT_SOFT,
3708 0fcc5db3 Guido Trotter
                                   constants.INSTANCE_REBOOT_HARD,
3709 0fcc5db3 Guido Trotter
                                   constants.INSTANCE_REBOOT_FULL]:
3710 0fcc5db3 Guido Trotter
      raise errors.ParameterError("reboot type not in [%s, %s, %s]" %
3711 0fcc5db3 Guido Trotter
                                  (constants.INSTANCE_REBOOT_SOFT,
3712 0fcc5db3 Guido Trotter
                                   constants.INSTANCE_REBOOT_HARD,
3713 0fcc5db3 Guido Trotter
                                   constants.INSTANCE_REBOOT_FULL))
3714 e873317a Guido Trotter
    self._ExpandAndLockInstance()
3715 bf6929a2 Alexander Schreiber
3716 bf6929a2 Alexander Schreiber
  def BuildHooksEnv(self):
3717 bf6929a2 Alexander Schreiber
    """Build hooks env.
3718 bf6929a2 Alexander Schreiber

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

3721 bf6929a2 Alexander Schreiber
    """
3722 bf6929a2 Alexander Schreiber
    env = {
3723 bf6929a2 Alexander Schreiber
      "IGNORE_SECONDARIES": self.op.ignore_secondaries,
3724 2c2690c9 Iustin Pop
      "REBOOT_TYPE": self.op.reboot_type,
3725 17c3f802 Guido Trotter
      "SHUTDOWN_TIMEOUT": self.shutdown_timeout,
3726 bf6929a2 Alexander Schreiber
      }
3727 338e51e8 Iustin Pop
    env.update(_BuildInstanceHookEnvByObject(self, self.instance))
3728 6b12959c Iustin Pop
    nl = [self.cfg.GetMasterNode()] + list(self.instance.all_nodes)
3729 bf6929a2 Alexander Schreiber
    return env, nl, nl
3730 bf6929a2 Alexander Schreiber
3731 bf6929a2 Alexander Schreiber
  def CheckPrereq(self):
3732 bf6929a2 Alexander Schreiber
    """Check prerequisites.
3733 bf6929a2 Alexander Schreiber

3734 bf6929a2 Alexander Schreiber
    This checks that the instance is in the cluster.
3735 bf6929a2 Alexander Schreiber

3736 bf6929a2 Alexander Schreiber
    """
3737 e873317a Guido Trotter
    self.instance = instance = self.cfg.GetInstanceInfo(self.op.instance_name)
3738 e873317a Guido Trotter
    assert self.instance is not None, \
3739 e873317a Guido Trotter
      "Cannot retrieve locked instance %s" % self.op.instance_name
3740 bf6929a2 Alexander Schreiber
3741 7527a8a4 Iustin Pop
    _CheckNodeOnline(self, instance.primary_node)
3742 7527a8a4 Iustin Pop
3743 5bbd3f7f Michael Hanselmann
    # check bridges existence
3744 b9bddb6b Iustin Pop
    _CheckInstanceBridgesExist(self, instance)
3745 bf6929a2 Alexander Schreiber
3746 bf6929a2 Alexander Schreiber
  def Exec(self, feedback_fn):
3747 bf6929a2 Alexander Schreiber
    """Reboot the instance.
3748 bf6929a2 Alexander Schreiber

3749 bf6929a2 Alexander Schreiber
    """
3750 bf6929a2 Alexander Schreiber
    instance = self.instance
3751 bf6929a2 Alexander Schreiber
    ignore_secondaries = self.op.ignore_secondaries
3752 bf6929a2 Alexander Schreiber
    reboot_type = self.op.reboot_type
3753 bf6929a2 Alexander Schreiber
3754 bf6929a2 Alexander Schreiber
    node_current = instance.primary_node
3755 bf6929a2 Alexander Schreiber
3756 bf6929a2 Alexander Schreiber
    if reboot_type in [constants.INSTANCE_REBOOT_SOFT,
3757 bf6929a2 Alexander Schreiber
                       constants.INSTANCE_REBOOT_HARD]:
3758 ae48ac32 Iustin Pop
      for disk in instance.disks:
3759 ae48ac32 Iustin Pop
        self.cfg.SetDiskID(disk, node_current)
3760 781de953 Iustin Pop
      result = self.rpc.call_instance_reboot(node_current, instance,
3761 17c3f802 Guido Trotter
                                             reboot_type,
3762 17c3f802 Guido Trotter
                                             self.shutdown_timeout)
3763 4c4e4e1e Iustin Pop
      result.Raise("Could not reboot instance")
3764 bf6929a2 Alexander Schreiber
    else:
3765 17c3f802 Guido Trotter
      result = self.rpc.call_instance_shutdown(node_current, instance,
3766 17c3f802 Guido Trotter
                                               self.shutdown_timeout)
3767 4c4e4e1e Iustin Pop
      result.Raise("Could not shutdown instance for full reboot")
3768 b9bddb6b Iustin Pop
      _ShutdownInstanceDisks(self, instance)
3769 b9bddb6b Iustin Pop
      _StartInstanceDisks(self, instance, ignore_secondaries)
3770 0eca8e0c Iustin Pop
      result = self.rpc.call_instance_start(node_current, instance, None, None)
3771 4c4e4e1e Iustin Pop
      msg = result.fail_msg
3772 dd279568 Iustin Pop
      if msg:
3773 b9bddb6b Iustin Pop
        _ShutdownInstanceDisks(self, instance)
3774 dd279568 Iustin Pop
        raise errors.OpExecError("Could not start instance for"
3775 dd279568 Iustin Pop
                                 " full reboot: %s" % msg)
3776 bf6929a2 Alexander Schreiber
3777 bf6929a2 Alexander Schreiber
    self.cfg.MarkInstanceUp(instance.name)
3778 bf6929a2 Alexander Schreiber
3779 bf6929a2 Alexander Schreiber
3780 a8083063 Iustin Pop
class LUShutdownInstance(LogicalUnit):
3781 a8083063 Iustin Pop
  """Shutdown an instance.
3782 a8083063 Iustin Pop

3783 a8083063 Iustin Pop
  """
3784 a8083063 Iustin Pop
  HPATH = "instance-stop"
3785 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
3786 a8083063 Iustin Pop
  _OP_REQP = ["instance_name"]
3787 e873317a Guido Trotter
  REQ_BGL = False
3788 e873317a Guido Trotter
3789 6263189c Guido Trotter
  def CheckArguments(self):
3790 6263189c Guido Trotter
    """Check the arguments.
3791 6263189c Guido Trotter

3792 6263189c Guido Trotter
    """
3793 6263189c Guido Trotter
    self.timeout = getattr(self.op, "timeout",
3794 6263189c Guido Trotter
                           constants.DEFAULT_SHUTDOWN_TIMEOUT)
3795 6263189c Guido Trotter
3796 e873317a Guido Trotter
  def ExpandNames(self):
3797 e873317a Guido Trotter
    self._ExpandAndLockInstance()
3798 a8083063 Iustin Pop
3799 a8083063 Iustin Pop
  def BuildHooksEnv(self):
3800 a8083063 Iustin Pop
    """Build hooks env.
3801 a8083063 Iustin Pop

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

3804 a8083063 Iustin Pop
    """
3805 338e51e8 Iustin Pop
    env = _BuildInstanceHookEnvByObject(self, self.instance)
3806 6263189c Guido Trotter
    env["TIMEOUT"] = self.timeout
3807 6b12959c Iustin Pop
    nl = [self.cfg.GetMasterNode()] + list(self.instance.all_nodes)
3808 a8083063 Iustin Pop
    return env, nl, nl
3809 a8083063 Iustin Pop
3810 a8083063 Iustin Pop
  def CheckPrereq(self):
3811 a8083063 Iustin Pop
    """Check prerequisites.
3812 a8083063 Iustin Pop

3813 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
3814 a8083063 Iustin Pop

3815 a8083063 Iustin Pop
    """
3816 e873317a Guido Trotter
    self.instance = self.cfg.GetInstanceInfo(self.op.instance_name)
3817 e873317a Guido Trotter
    assert self.instance is not None, \
3818 e873317a Guido Trotter
      "Cannot retrieve locked instance %s" % self.op.instance_name
3819 43017d26 Iustin Pop
    _CheckNodeOnline(self, self.instance.primary_node)
3820 a8083063 Iustin Pop
3821 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
3822 a8083063 Iustin Pop
    """Shutdown the instance.
3823 a8083063 Iustin Pop

3824 a8083063 Iustin Pop
    """
3825 a8083063 Iustin Pop
    instance = self.instance
3826 a8083063 Iustin Pop
    node_current = instance.primary_node
3827 6263189c Guido Trotter
    timeout = self.timeout
3828 fe482621 Iustin Pop
    self.cfg.MarkInstanceDown(instance.name)
3829 6263189c Guido Trotter
    result = self.rpc.call_instance_shutdown(node_current, instance, timeout)
3830 4c4e4e1e Iustin Pop
    msg = result.fail_msg
3831 1fae010f Iustin Pop
    if msg:
3832 1fae010f Iustin Pop
      self.proc.LogWarning("Could not shutdown instance: %s" % msg)
3833 a8083063 Iustin Pop
3834 b9bddb6b Iustin Pop
    _ShutdownInstanceDisks(self, instance)
3835 a8083063 Iustin Pop
3836 a8083063 Iustin Pop
3837 fe7b0351 Michael Hanselmann
class LUReinstallInstance(LogicalUnit):
3838 fe7b0351 Michael Hanselmann
  """Reinstall an instance.
3839 fe7b0351 Michael Hanselmann

3840 fe7b0351 Michael Hanselmann
  """
3841 fe7b0351 Michael Hanselmann
  HPATH = "instance-reinstall"
3842 fe7b0351 Michael Hanselmann
  HTYPE = constants.HTYPE_INSTANCE
3843 fe7b0351 Michael Hanselmann
  _OP_REQP = ["instance_name"]
3844 4e0b4d2d Guido Trotter
  REQ_BGL = False
3845 4e0b4d2d Guido Trotter
3846 4e0b4d2d Guido Trotter
  def ExpandNames(self):
3847 4e0b4d2d Guido Trotter
    self._ExpandAndLockInstance()
3848 fe7b0351 Michael Hanselmann
3849 fe7b0351 Michael Hanselmann
  def BuildHooksEnv(self):
3850 fe7b0351 Michael Hanselmann
    """Build hooks env.
3851 fe7b0351 Michael Hanselmann

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

3854 fe7b0351 Michael Hanselmann
    """
3855 338e51e8 Iustin Pop
    env = _BuildInstanceHookEnvByObject(self, self.instance)
3856 6b12959c Iustin Pop
    nl = [self.cfg.GetMasterNode()] + list(self.instance.all_nodes)
3857 fe7b0351 Michael Hanselmann
    return env, nl, nl
3858 fe7b0351 Michael Hanselmann
3859 fe7b0351 Michael Hanselmann
  def CheckPrereq(self):
3860 fe7b0351 Michael Hanselmann
    """Check prerequisites.
3861 fe7b0351 Michael Hanselmann

3862 fe7b0351 Michael Hanselmann
    This checks that the instance is in the cluster and is not running.
3863 fe7b0351 Michael Hanselmann

3864 fe7b0351 Michael Hanselmann
    """
3865 4e0b4d2d Guido Trotter
    instance = self.cfg.GetInstanceInfo(self.op.instance_name)
3866 4e0b4d2d Guido Trotter
    assert instance is not None, \
3867 4e0b4d2d Guido Trotter
      "Cannot retrieve locked instance %s" % self.op.instance_name
3868 7527a8a4 Iustin Pop
    _CheckNodeOnline(self, instance.primary_node)
3869 4e0b4d2d Guido Trotter
3870 fe7b0351 Michael Hanselmann
    if instance.disk_template == constants.DT_DISKLESS:
3871 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' has no disks" %
3872 5c983ee5 Iustin Pop
                                 self.op.instance_name,
3873 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
3874 0d68c45d Iustin Pop
    if instance.admin_up:
3875 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' is marked to be up" %
3876 5c983ee5 Iustin Pop
                                 self.op.instance_name,
3877 5c983ee5 Iustin Pop
                                 errors.ECODE_STATE)
3878 72737a7f Iustin Pop
    remote_info = self.rpc.call_instance_info(instance.primary_node,
3879 72737a7f Iustin Pop
                                              instance.name,
3880 72737a7f Iustin Pop
                                              instance.hypervisor)
3881 4c4e4e1e Iustin Pop
    remote_info.Raise("Error checking node %s" % instance.primary_node,
3882 045dd6d9 Iustin Pop
                      prereq=True, ecode=errors.ECODE_ENVIRON)
3883 7ad1af4a Iustin Pop
    if remote_info.payload:
3884 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' is running on the node %s" %
3885 3ecf6786 Iustin Pop
                                 (self.op.instance_name,
3886 5c983ee5 Iustin Pop
                                  instance.primary_node),
3887 5c983ee5 Iustin Pop
                                 errors.ECODE_STATE)
3888 d0834de3 Michael Hanselmann
3889 d0834de3 Michael Hanselmann
    self.op.os_type = getattr(self.op, "os_type", None)
3890 f2c05717 Guido Trotter
    self.op.force_variant = getattr(self.op, "force_variant", False)
3891 d0834de3 Michael Hanselmann
    if self.op.os_type is not None:
3892 d0834de3 Michael Hanselmann
      # OS verification
3893 d0834de3 Michael Hanselmann
      pnode = self.cfg.GetNodeInfo(
3894 d0834de3 Michael Hanselmann
        self.cfg.ExpandNodeName(instance.primary_node))
3895 d0834de3 Michael Hanselmann
      if pnode is None:
3896 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Primary node '%s' is unknown" %
3897 5c983ee5 Iustin Pop
                                   self.op.pnode, errors.ECODE_NOENT)
3898 781de953 Iustin Pop
      result = self.rpc.call_os_get(pnode.name, self.op.os_type)
3899 4c4e4e1e Iustin Pop
      result.Raise("OS '%s' not in supported OS list for primary node %s" %
3900 045dd6d9 Iustin Pop
                   (self.op.os_type, pnode.name),
3901 045dd6d9 Iustin Pop
                   prereq=True, ecode=errors.ECODE_INVAL)
3902 f2c05717 Guido Trotter
      if not self.op.force_variant:
3903 f2c05717 Guido Trotter
        _CheckOSVariant(result.payload, self.op.os_type)
3904 d0834de3 Michael Hanselmann
3905 fe7b0351 Michael Hanselmann
    self.instance = instance
3906 fe7b0351 Michael Hanselmann
3907 fe7b0351 Michael Hanselmann
  def Exec(self, feedback_fn):
3908 fe7b0351 Michael Hanselmann
    """Reinstall the instance.
3909 fe7b0351 Michael Hanselmann

3910 fe7b0351 Michael Hanselmann
    """
3911 fe7b0351 Michael Hanselmann
    inst = self.instance
3912 fe7b0351 Michael Hanselmann
3913 d0834de3 Michael Hanselmann
    if self.op.os_type is not None:
3914 d0834de3 Michael Hanselmann
      feedback_fn("Changing OS to '%s'..." % self.op.os_type)
3915 d0834de3 Michael Hanselmann
      inst.os = self.op.os_type
3916 a4eae71f Michael Hanselmann
      self.cfg.Update(inst, feedback_fn)
3917 d0834de3 Michael Hanselmann
3918 b9bddb6b Iustin Pop
    _StartInstanceDisks(self, inst, None)
3919 fe7b0351 Michael Hanselmann
    try:
3920 fe7b0351 Michael Hanselmann
      feedback_fn("Running the instance OS create scripts...")
3921 e557bae9 Guido Trotter
      result = self.rpc.call_instance_os_add(inst.primary_node, inst, True)
3922 4c4e4e1e Iustin Pop
      result.Raise("Could not install OS for instance %s on node %s" %
3923 4c4e4e1e Iustin Pop
                   (inst.name, inst.primary_node))
3924 fe7b0351 Michael Hanselmann
    finally:
3925 b9bddb6b Iustin Pop
      _ShutdownInstanceDisks(self, inst)
3926 fe7b0351 Michael Hanselmann
3927 fe7b0351 Michael Hanselmann
3928 bd315bfa Iustin Pop
class LURecreateInstanceDisks(LogicalUnit):
3929 bd315bfa Iustin Pop
  """Recreate an instance's missing disks.
3930 bd315bfa Iustin Pop

3931 bd315bfa Iustin Pop
  """
3932 bd315bfa Iustin Pop
  HPATH = "instance-recreate-disks"
3933 bd315bfa Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
3934 bd315bfa Iustin Pop
  _OP_REQP = ["instance_name", "disks"]
3935 bd315bfa Iustin Pop
  REQ_BGL = False
3936 bd315bfa Iustin Pop
3937 bd315bfa Iustin Pop
  def CheckArguments(self):
3938 bd315bfa Iustin Pop
    """Check the arguments.
3939 bd315bfa Iustin Pop

3940 bd315bfa Iustin Pop
    """
3941 bd315bfa Iustin Pop
    if not isinstance(self.op.disks, list):
3942 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Invalid disks parameter", errors.ECODE_INVAL)
3943 bd315bfa Iustin Pop
    for item in self.op.disks:
3944 bd315bfa Iustin Pop
      if (not isinstance(item, int) or
3945 bd315bfa Iustin Pop
          item < 0):
3946 bd315bfa Iustin Pop
        raise errors.OpPrereqError("Invalid disk specification '%s'" %
3947 5c983ee5 Iustin Pop
                                   str(item), errors.ECODE_INVAL)
3948 bd315bfa Iustin Pop
3949 bd315bfa Iustin Pop
  def ExpandNames(self):
3950 bd315bfa Iustin Pop
    self._ExpandAndLockInstance()
3951 bd315bfa Iustin Pop
3952 bd315bfa Iustin Pop
  def BuildHooksEnv(self):
3953 bd315bfa Iustin Pop
    """Build hooks env.
3954 bd315bfa Iustin Pop

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

3957 bd315bfa Iustin Pop
    """
3958 bd315bfa Iustin Pop
    env = _BuildInstanceHookEnvByObject(self, self.instance)
3959 bd315bfa Iustin Pop
    nl = [self.cfg.GetMasterNode()] + list(self.instance.all_nodes)
3960 bd315bfa Iustin Pop
    return env, nl, nl
3961 bd315bfa Iustin Pop
3962 bd315bfa Iustin Pop
  def CheckPrereq(self):
3963 bd315bfa Iustin Pop
    """Check prerequisites.
3964 bd315bfa Iustin Pop

3965 bd315bfa Iustin Pop
    This checks that the instance is in the cluster and is not running.
3966 bd315bfa Iustin Pop

3967 bd315bfa Iustin Pop
    """
3968 bd315bfa Iustin Pop
    instance = self.cfg.GetInstanceInfo(self.op.instance_name)
3969 bd315bfa Iustin Pop
    assert instance is not None, \
3970 bd315bfa Iustin Pop
      "Cannot retrieve locked instance %s" % self.op.instance_name
3971 bd315bfa Iustin Pop
    _CheckNodeOnline(self, instance.primary_node)
3972 bd315bfa Iustin Pop
3973 bd315bfa Iustin Pop
    if instance.disk_template == constants.DT_DISKLESS:
3974 bd315bfa Iustin Pop
      raise errors.OpPrereqError("Instance '%s' has no disks" %
3975 5c983ee5 Iustin Pop
                                 self.op.instance_name, errors.ECODE_INVAL)
3976 bd315bfa Iustin Pop
    if instance.admin_up:
3977 bd315bfa Iustin Pop
      raise errors.OpPrereqError("Instance '%s' is marked to be up" %
3978 5c983ee5 Iustin Pop
                                 self.op.instance_name, errors.ECODE_STATE)
3979 bd315bfa Iustin Pop
    remote_info = self.rpc.call_instance_info(instance.primary_node,
3980 bd315bfa Iustin Pop
                                              instance.name,
3981 bd315bfa Iustin Pop
                                              instance.hypervisor)
3982 bd315bfa Iustin Pop
    remote_info.Raise("Error checking node %s" % instance.primary_node,
3983 045dd6d9 Iustin Pop
                      prereq=True, ecode=errors.ECODE_ENVIRON)
3984 bd315bfa Iustin Pop
    if remote_info.payload:
3985 bd315bfa Iustin Pop
      raise errors.OpPrereqError("Instance '%s' is running on the node %s" %
3986 bd315bfa Iustin Pop
                                 (self.op.instance_name,
3987 5c983ee5 Iustin Pop
                                  instance.primary_node), errors.ECODE_STATE)
3988 bd315bfa Iustin Pop
3989 bd315bfa Iustin Pop
    if not self.op.disks:
3990 bd315bfa Iustin Pop
      self.op.disks = range(len(instance.disks))
3991 bd315bfa Iustin Pop
    else:
3992 bd315bfa Iustin Pop
      for idx in self.op.disks:
3993 bd315bfa Iustin Pop
        if idx >= len(instance.disks):
3994 5c983ee5 Iustin Pop
          raise errors.OpPrereqError("Invalid disk index passed '%s'" % idx,
3995 5c983ee5 Iustin Pop
                                     errors.ECODE_INVAL)
3996 bd315bfa Iustin Pop
3997 bd315bfa Iustin Pop
    self.instance = instance
3998 bd315bfa Iustin Pop
3999 bd315bfa Iustin Pop
  def Exec(self, feedback_fn):
4000 bd315bfa Iustin Pop
    """Recreate the disks.
4001 bd315bfa Iustin Pop

4002 bd315bfa Iustin Pop
    """
4003 bd315bfa Iustin Pop
    to_skip = []
4004 bd315bfa Iustin Pop
    for idx, disk in enumerate(self.instance.disks):
4005 bd315bfa Iustin Pop
      if idx not in self.op.disks: # disk idx has not been passed in
4006 bd315bfa Iustin Pop
        to_skip.append(idx)
4007 bd315bfa Iustin Pop
        continue
4008 bd315bfa Iustin Pop
4009 bd315bfa Iustin Pop
    _CreateDisks(self, self.instance, to_skip=to_skip)
4010 bd315bfa Iustin Pop
4011 bd315bfa Iustin Pop
4012 decd5f45 Iustin Pop
class LURenameInstance(LogicalUnit):
4013 decd5f45 Iustin Pop
  """Rename an instance.
4014 decd5f45 Iustin Pop

4015 decd5f45 Iustin Pop
  """
4016 decd5f45 Iustin Pop
  HPATH = "instance-rename"
4017 decd5f45 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
4018 decd5f45 Iustin Pop
  _OP_REQP = ["instance_name", "new_name"]
4019 decd5f45 Iustin Pop
4020 decd5f45 Iustin Pop
  def BuildHooksEnv(self):
4021 decd5f45 Iustin Pop
    """Build hooks env.
4022 decd5f45 Iustin Pop

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

4025 decd5f45 Iustin Pop
    """
4026 338e51e8 Iustin Pop
    env = _BuildInstanceHookEnvByObject(self, self.instance)
4027 decd5f45 Iustin Pop
    env["INSTANCE_NEW_NAME"] = self.op.new_name
4028 6b12959c Iustin Pop
    nl = [self.cfg.GetMasterNode()] + list(self.instance.all_nodes)
4029 decd5f45 Iustin Pop
    return env, nl, nl
4030 decd5f45 Iustin Pop
4031 decd5f45 Iustin Pop
  def CheckPrereq(self):
4032 decd5f45 Iustin Pop
    """Check prerequisites.
4033 decd5f45 Iustin Pop

4034 decd5f45 Iustin Pop
    This checks that the instance is in the cluster and is not running.
4035 decd5f45 Iustin Pop

4036 decd5f45 Iustin Pop
    """
4037 decd5f45 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
4038 decd5f45 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
4039 decd5f45 Iustin Pop
    if instance is None:
4040 decd5f45 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
4041 5c983ee5 Iustin Pop
                                 self.op.instance_name, errors.ECODE_NOENT)
4042 7527a8a4 Iustin Pop
    _CheckNodeOnline(self, instance.primary_node)
4043 7527a8a4 Iustin Pop
4044 0d68c45d Iustin Pop
    if instance.admin_up:
4045 decd5f45 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' is marked to be up" %
4046 5c983ee5 Iustin Pop
                                 self.op.instance_name, errors.ECODE_STATE)
4047 72737a7f Iustin Pop
    remote_info = self.rpc.call_instance_info(instance.primary_node,
4048 72737a7f Iustin Pop
                                              instance.name,
4049 72737a7f Iustin Pop
                                              instance.hypervisor)
4050 4c4e4e1e Iustin Pop
    remote_info.Raise("Error checking node %s" % instance.primary_node,
4051 045dd6d9 Iustin Pop
                      prereq=True, ecode=errors.ECODE_ENVIRON)
4052 7ad1af4a Iustin Pop
    if remote_info.payload:
4053 decd5f45 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' is running on the node %s" %
4054 decd5f45 Iustin Pop
                                 (self.op.instance_name,
4055 5c983ee5 Iustin Pop
                                  instance.primary_node), errors.ECODE_STATE)
4056 decd5f45 Iustin Pop
    self.instance = instance
4057 decd5f45 Iustin Pop
4058 decd5f45 Iustin Pop
    # new name verification
4059 104f4ca1 Iustin Pop
    name_info = utils.GetHostInfo(self.op.new_name)
4060 decd5f45 Iustin Pop
4061 89e1fc26 Iustin Pop
    self.op.new_name = new_name = name_info.name
4062 7bde3275 Guido Trotter
    instance_list = self.cfg.GetInstanceList()
4063 7bde3275 Guido Trotter
    if new_name in instance_list:
4064 7bde3275 Guido Trotter
      raise errors.OpPrereqError("Instance '%s' is already in the cluster" %
4065 5c983ee5 Iustin Pop
                                 new_name, errors.ECODE_EXISTS)
4066 7bde3275 Guido Trotter
4067 decd5f45 Iustin Pop
    if not getattr(self.op, "ignore_ip", False):
4068 937f983d Guido Trotter
      if utils.TcpPing(name_info.ip, constants.DEFAULT_NODED_PORT):
4069 decd5f45 Iustin Pop
        raise errors.OpPrereqError("IP %s of instance %s already in use" %
4070 5c983ee5 Iustin Pop
                                   (name_info.ip, new_name),
4071 5c983ee5 Iustin Pop
                                   errors.ECODE_NOTUNIQUE)
4072 decd5f45 Iustin Pop
4073 decd5f45 Iustin Pop
4074 decd5f45 Iustin Pop
  def Exec(self, feedback_fn):
4075 decd5f45 Iustin Pop
    """Reinstall the instance.
4076 decd5f45 Iustin Pop

4077 decd5f45 Iustin Pop
    """
4078 decd5f45 Iustin Pop
    inst = self.instance
4079 decd5f45 Iustin Pop
    old_name = inst.name
4080 decd5f45 Iustin Pop
4081 b23c4333 Manuel Franceschini
    if inst.disk_template == constants.DT_FILE:
4082 b23c4333 Manuel Franceschini
      old_file_storage_dir = os.path.dirname(inst.disks[0].logical_id[1])
4083 b23c4333 Manuel Franceschini
4084 decd5f45 Iustin Pop
    self.cfg.RenameInstance(inst.name, self.op.new_name)
4085 74b5913f Guido Trotter
    # Change the instance lock. This is definitely safe while we hold the BGL
4086 cb4e8387 Iustin Pop
    self.context.glm.remove(locking.LEVEL_INSTANCE, old_name)
4087 74b5913f Guido Trotter
    self.context.glm.add(locking.LEVEL_INSTANCE, self.op.new_name)
4088 decd5f45 Iustin Pop
4089 decd5f45 Iustin Pop
    # re-read the instance from the configuration after rename
4090 decd5f45 Iustin Pop
    inst = self.cfg.GetInstanceInfo(self.op.new_name)
4091 decd5f45 Iustin Pop
4092 b23c4333 Manuel Franceschini
    if inst.disk_template == constants.DT_FILE:
4093 b23c4333 Manuel Franceschini
      new_file_storage_dir = os.path.dirname(inst.disks[0].logical_id[1])
4094 72737a7f Iustin Pop
      result = self.rpc.call_file_storage_dir_rename(inst.primary_node,
4095 72737a7f Iustin Pop
                                                     old_file_storage_dir,
4096 72737a7f Iustin Pop
                                                     new_file_storage_dir)
4097 4c4e4e1e Iustin Pop
      result.Raise("Could not rename on node %s directory '%s' to '%s'"
4098 4c4e4e1e Iustin Pop
                   " (but the instance has been renamed in Ganeti)" %
4099 4c4e4e1e Iustin Pop
                   (inst.primary_node, old_file_storage_dir,
4100 4c4e4e1e Iustin Pop
                    new_file_storage_dir))
4101 b23c4333 Manuel Franceschini
4102 b9bddb6b Iustin Pop
    _StartInstanceDisks(self, inst, None)
4103 decd5f45 Iustin Pop
    try:
4104 781de953 Iustin Pop
      result = self.rpc.call_instance_run_rename(inst.primary_node, inst,
4105 781de953 Iustin Pop
                                                 old_name)
4106 4c4e4e1e Iustin Pop
      msg = result.fail_msg
4107 96841384 Iustin Pop
      if msg:
4108 6291574d Alexander Schreiber
        msg = ("Could not run OS rename script for instance %s on node %s"
4109 96841384 Iustin Pop
               " (but the instance has been renamed in Ganeti): %s" %
4110 96841384 Iustin Pop
               (inst.name, inst.primary_node, msg))
4111 86d9d3bb Iustin Pop
        self.proc.LogWarning(msg)
4112 decd5f45 Iustin Pop
    finally:
4113 b9bddb6b Iustin Pop
      _ShutdownInstanceDisks(self, inst)
4114 decd5f45 Iustin Pop
4115 decd5f45 Iustin Pop
4116 a8083063 Iustin Pop
class LURemoveInstance(LogicalUnit):
4117 a8083063 Iustin Pop
  """Remove an instance.
4118 a8083063 Iustin Pop

4119 a8083063 Iustin Pop
  """
4120 a8083063 Iustin Pop
  HPATH = "instance-remove"
4121 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
4122 5c54b832 Iustin Pop
  _OP_REQP = ["instance_name", "ignore_failures"]
4123 cf472233 Guido Trotter
  REQ_BGL = False
4124 cf472233 Guido Trotter
4125 17c3f802 Guido Trotter
  def CheckArguments(self):
4126 17c3f802 Guido Trotter
    """Check the arguments.
4127 17c3f802 Guido Trotter

4128 17c3f802 Guido Trotter
    """
4129 17c3f802 Guido Trotter
    self.shutdown_timeout = getattr(self.op, "shutdown_timeout",
4130 17c3f802 Guido Trotter
                                    constants.DEFAULT_SHUTDOWN_TIMEOUT)
4131 17c3f802 Guido Trotter
4132 cf472233 Guido Trotter
  def ExpandNames(self):
4133 cf472233 Guido Trotter
    self._ExpandAndLockInstance()
4134 cf472233 Guido Trotter
    self.needed_locks[locking.LEVEL_NODE] = []
4135 cf472233 Guido Trotter
    self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
4136 cf472233 Guido Trotter
4137 cf472233 Guido Trotter
  def DeclareLocks(self, level):
4138 cf472233 Guido Trotter
    if level == locking.LEVEL_NODE:
4139 cf472233 Guido Trotter
      self._LockInstancesNodes()
4140 a8083063 Iustin Pop
4141 a8083063 Iustin Pop
  def BuildHooksEnv(self):
4142 a8083063 Iustin Pop
    """Build hooks env.
4143 a8083063 Iustin Pop

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

4146 a8083063 Iustin Pop
    """
4147 338e51e8 Iustin Pop
    env = _BuildInstanceHookEnvByObject(self, self.instance)
4148 17c3f802 Guido Trotter
    env["SHUTDOWN_TIMEOUT"] = self.shutdown_timeout
4149 d6a02168 Michael Hanselmann
    nl = [self.cfg.GetMasterNode()]
4150 a8083063 Iustin Pop
    return env, nl, nl
4151 a8083063 Iustin Pop
4152 a8083063 Iustin Pop
  def CheckPrereq(self):
4153 a8083063 Iustin Pop
    """Check prerequisites.
4154 a8083063 Iustin Pop

4155 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
4156 a8083063 Iustin Pop

4157 a8083063 Iustin Pop
    """
4158 cf472233 Guido Trotter
    self.instance = self.cfg.GetInstanceInfo(self.op.instance_name)
4159 cf472233 Guido Trotter
    assert self.instance is not None, \
4160 cf472233 Guido Trotter
      "Cannot retrieve locked instance %s" % self.op.instance_name
4161 a8083063 Iustin Pop
4162 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
4163 a8083063 Iustin Pop
    """Remove the instance.
4164 a8083063 Iustin Pop

4165 a8083063 Iustin Pop
    """
4166 a8083063 Iustin Pop
    instance = self.instance
4167 9a4f63d1 Iustin Pop
    logging.info("Shutting down instance %s on node %s",
4168 9a4f63d1 Iustin Pop
                 instance.name, instance.primary_node)
4169 a8083063 Iustin Pop
4170 17c3f802 Guido Trotter
    result = self.rpc.call_instance_shutdown(instance.primary_node, instance,
4171 17c3f802 Guido Trotter
                                             self.shutdown_timeout)
4172 4c4e4e1e Iustin Pop
    msg = result.fail_msg
4173 1fae010f Iustin Pop
    if msg:
4174 1d67656e Iustin Pop
      if self.op.ignore_failures:
4175 1fae010f Iustin Pop
        feedback_fn("Warning: can't shutdown instance: %s" % msg)
4176 1d67656e Iustin Pop
      else:
4177 1fae010f Iustin Pop
        raise errors.OpExecError("Could not shutdown instance %s on"
4178 1fae010f Iustin Pop
                                 " node %s: %s" %
4179 1fae010f Iustin Pop
                                 (instance.name, instance.primary_node, msg))
4180 a8083063 Iustin Pop
4181 9a4f63d1 Iustin Pop
    logging.info("Removing block devices for instance %s", instance.name)
4182 a8083063 Iustin Pop
4183 b9bddb6b Iustin Pop
    if not _RemoveDisks(self, instance):
4184 1d67656e Iustin Pop
      if self.op.ignore_failures:
4185 1d67656e Iustin Pop
        feedback_fn("Warning: can't remove instance's disks")
4186 1d67656e Iustin Pop
      else:
4187 1d67656e Iustin Pop
        raise errors.OpExecError("Can't remove instance's disks")
4188 a8083063 Iustin Pop
4189 9a4f63d1 Iustin Pop
    logging.info("Removing instance %s out of cluster config", instance.name)
4190 a8083063 Iustin Pop
4191 a8083063 Iustin Pop
    self.cfg.RemoveInstance(instance.name)
4192 cf472233 Guido Trotter
    self.remove_locks[locking.LEVEL_INSTANCE] = instance.name
4193 a8083063 Iustin Pop
4194 a8083063 Iustin Pop
4195 a8083063 Iustin Pop
class LUQueryInstances(NoHooksLU):
4196 a8083063 Iustin Pop
  """Logical unit for querying instances.
4197 a8083063 Iustin Pop

4198 a8083063 Iustin Pop
  """
4199 ec79568d Iustin Pop
  _OP_REQP = ["output_fields", "names", "use_locking"]
4200 7eb9d8f7 Guido Trotter
  REQ_BGL = False
4201 19bed813 Iustin Pop
  _SIMPLE_FIELDS = ["name", "os", "network_port", "hypervisor",
4202 19bed813 Iustin Pop
                    "serial_no", "ctime", "mtime", "uuid"]
4203 a2d2e1a7 Iustin Pop
  _FIELDS_STATIC = utils.FieldSet(*["name", "os", "pnode", "snodes",
4204 5b460366 Iustin Pop
                                    "admin_state",
4205 a2d2e1a7 Iustin Pop
                                    "disk_template", "ip", "mac", "bridge",
4206 638c6349 Guido Trotter
                                    "nic_mode", "nic_link",
4207 a2d2e1a7 Iustin Pop
                                    "sda_size", "sdb_size", "vcpus", "tags",
4208 a2d2e1a7 Iustin Pop
                                    "network_port", "beparams",
4209 8aec325c Iustin Pop
                                    r"(disk)\.(size)/([0-9]+)",
4210 8aec325c Iustin Pop
                                    r"(disk)\.(sizes)", "disk_usage",
4211 638c6349 Guido Trotter
                                    r"(nic)\.(mac|ip|mode|link)/([0-9]+)",
4212 638c6349 Guido Trotter
                                    r"(nic)\.(bridge)/([0-9]+)",
4213 638c6349 Guido Trotter
                                    r"(nic)\.(macs|ips|modes|links|bridges)",
4214 8aec325c Iustin Pop
                                    r"(disk|nic)\.(count)",
4215 19bed813 Iustin Pop
                                    "hvparams",
4216 19bed813 Iustin Pop
                                    ] + _SIMPLE_FIELDS +
4217 a2d2e1a7 Iustin Pop
                                  ["hv/%s" % name
4218 7736a5f2 Iustin Pop
                                   for name in constants.HVS_PARAMETERS
4219 7736a5f2 Iustin Pop
                                   if name not in constants.HVC_GLOBALS] +
4220 a2d2e1a7 Iustin Pop
                                  ["be/%s" % name
4221 a2d2e1a7 Iustin Pop
                                   for name in constants.BES_PARAMETERS])
4222 a2d2e1a7 Iustin Pop
  _FIELDS_DYNAMIC = utils.FieldSet("oper_state", "oper_ram", "status")
4223 31bf511f Iustin Pop
4224 a8083063 Iustin Pop
4225 7eb9d8f7 Guido Trotter
  def ExpandNames(self):
4226 31bf511f Iustin Pop
    _CheckOutputFields(static=self._FIELDS_STATIC,
4227 31bf511f Iustin Pop
                       dynamic=self._FIELDS_DYNAMIC,
4228 dcb93971 Michael Hanselmann
                       selected=self.op.output_fields)
4229 a8083063 Iustin Pop
4230 7eb9d8f7 Guido Trotter
    self.needed_locks = {}
4231 7eb9d8f7 Guido Trotter
    self.share_locks[locking.LEVEL_INSTANCE] = 1
4232 7eb9d8f7 Guido Trotter
    self.share_locks[locking.LEVEL_NODE] = 1
4233 7eb9d8f7 Guido Trotter
4234 57a2fb91 Iustin Pop
    if self.op.names:
4235 57a2fb91 Iustin Pop
      self.wanted = _GetWantedInstances(self, self.op.names)
4236 7eb9d8f7 Guido Trotter
    else:
4237 57a2fb91 Iustin Pop
      self.wanted = locking.ALL_SET
4238 7eb9d8f7 Guido Trotter
4239 ec79568d Iustin Pop
    self.do_node_query = self._FIELDS_STATIC.NonMatching(self.op.output_fields)
4240 ec79568d Iustin Pop
    self.do_locking = self.do_node_query and self.op.use_locking
4241 57a2fb91 Iustin Pop
    if self.do_locking:
4242 57a2fb91 Iustin Pop
      self.needed_locks[locking.LEVEL_INSTANCE] = self.wanted
4243 57a2fb91 Iustin Pop
      self.needed_locks[locking.LEVEL_NODE] = []
4244 57a2fb91 Iustin Pop
      self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
4245 7eb9d8f7 Guido Trotter
4246 7eb9d8f7 Guido Trotter
  def DeclareLocks(self, level):
4247 57a2fb91 Iustin Pop
    if level == locking.LEVEL_NODE and self.do_locking:
4248 7eb9d8f7 Guido Trotter
      self._LockInstancesNodes()
4249 7eb9d8f7 Guido Trotter
4250 7eb9d8f7 Guido Trotter
  def CheckPrereq(self):
4251 7eb9d8f7 Guido Trotter
    """Check prerequisites.
4252 7eb9d8f7 Guido Trotter

4253 7eb9d8f7 Guido Trotter
    """
4254 57a2fb91 Iustin Pop
    pass
4255 069dcc86 Iustin Pop
4256 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
4257 a8083063 Iustin Pop
    """Computes the list of nodes and their attributes.
4258 a8083063 Iustin Pop

4259 a8083063 Iustin Pop
    """
4260 57a2fb91 Iustin Pop
    all_info = self.cfg.GetAllInstancesInfo()
4261 a7f5dc98 Iustin Pop
    if self.wanted == locking.ALL_SET:
4262 a7f5dc98 Iustin Pop
      # caller didn't specify instance names, so ordering is not important
4263 a7f5dc98 Iustin Pop
      if self.do_locking:
4264 a7f5dc98 Iustin Pop
        instance_names = self.acquired_locks[locking.LEVEL_INSTANCE]
4265 a7f5dc98 Iustin Pop
      else:
4266 a7f5dc98 Iustin Pop
        instance_names = all_info.keys()
4267 a7f5dc98 Iustin Pop
      instance_names = utils.NiceSort(instance_names)
4268 57a2fb91 Iustin Pop
    else:
4269 a7f5dc98 Iustin Pop
      # caller did specify names, so we must keep the ordering
4270 a7f5dc98 Iustin Pop
      if self.do_locking:
4271 a7f5dc98 Iustin Pop
        tgt_set = self.acquired_locks[locking.LEVEL_INSTANCE]
4272 a7f5dc98 Iustin Pop
      else:
4273 a7f5dc98 Iustin Pop
        tgt_set = all_info.keys()
4274 a7f5dc98 Iustin Pop
      missing = set(self.wanted).difference(tgt_set)
4275 a7f5dc98 Iustin Pop
      if missing:
4276 a7f5dc98 Iustin Pop
        raise errors.OpExecError("Some instances were removed before"
4277 a7f5dc98 Iustin Pop
                                 " retrieving their data: %s" % missing)
4278 a7f5dc98 Iustin Pop
      instance_names = self.wanted
4279 c1f1cbb2 Iustin Pop
4280 57a2fb91 Iustin Pop
    instance_list = [all_info[iname] for iname in instance_names]
4281 a8083063 Iustin Pop
4282 a8083063 Iustin Pop
    # begin data gathering
4283 a8083063 Iustin Pop
4284 a8083063 Iustin Pop
    nodes = frozenset([inst.primary_node for inst in instance_list])
4285 e69d05fd Iustin Pop
    hv_list = list(set([inst.hypervisor for inst in instance_list]))
4286 a8083063 Iustin Pop
4287 a8083063 Iustin Pop
    bad_nodes = []
4288 cbfc4681 Iustin Pop
    off_nodes = []
4289 ec79568d Iustin Pop
    if self.do_node_query:
4290 a8083063 Iustin Pop
      live_data = {}
4291 72737a7f Iustin Pop
      node_data = self.rpc.call_all_instances_info(nodes, hv_list)
4292 a8083063 Iustin Pop
      for name in nodes:
4293 a8083063 Iustin Pop
        result = node_data[name]
4294 cbfc4681 Iustin Pop
        if result.offline:
4295 cbfc4681 Iustin Pop
          # offline nodes will be in both lists
4296 cbfc4681 Iustin Pop
          off_nodes.append(name)
4297 3cebe102 Michael Hanselmann
        if result.fail_msg:
4298 a8083063 Iustin Pop
          bad_nodes.append(name)
4299 781de953 Iustin Pop
        else:
4300 2fa74ef4 Iustin Pop
          if result.payload:
4301 2fa74ef4 Iustin Pop
            live_data.update(result.payload)
4302 2fa74ef4 Iustin Pop
          # else no instance is alive
4303 a8083063 Iustin Pop
    else:
4304 a8083063 Iustin Pop
      live_data = dict([(name, {}) for name in instance_names])
4305 a8083063 Iustin Pop
4306 a8083063 Iustin Pop
    # end data gathering
4307 a8083063 Iustin Pop
4308 5018a335 Iustin Pop
    HVPREFIX = "hv/"
4309 338e51e8 Iustin Pop
    BEPREFIX = "be/"
4310 a8083063 Iustin Pop
    output = []
4311 638c6349 Guido Trotter
    cluster = self.cfg.GetClusterInfo()
4312 a8083063 Iustin Pop
    for instance in instance_list:
4313 a8083063 Iustin Pop
      iout = []
4314 7736a5f2 Iustin Pop
      i_hv = cluster.FillHV(instance, skip_globals=True)
4315 638c6349 Guido Trotter
      i_be = cluster.FillBE(instance)
4316 638c6349 Guido Trotter
      i_nicp = [objects.FillDict(cluster.nicparams[constants.PP_DEFAULT],
4317 638c6349 Guido Trotter
                                 nic.nicparams) for nic in instance.nics]
4318 a8083063 Iustin Pop
      for field in self.op.output_fields:
4319 71c1af58 Iustin Pop
        st_match = self._FIELDS_STATIC.Matches(field)
4320 19bed813 Iustin Pop
        if field in self._SIMPLE_FIELDS:
4321 19bed813 Iustin Pop
          val = getattr(instance, field)
4322 a8083063 Iustin Pop
        elif field == "pnode":
4323 a8083063 Iustin Pop
          val = instance.primary_node
4324 a8083063 Iustin Pop
        elif field == "snodes":
4325 8a23d2d3 Iustin Pop
          val = list(instance.secondary_nodes)
4326 a8083063 Iustin Pop
        elif field == "admin_state":
4327 0d68c45d Iustin Pop
          val = instance.admin_up
4328 a8083063 Iustin Pop
        elif field == "oper_state":
4329 a8083063 Iustin Pop
          if instance.primary_node in bad_nodes:
4330 8a23d2d3 Iustin Pop
            val = None
4331 a8083063 Iustin Pop
          else:
4332 8a23d2d3 Iustin Pop
            val = bool(live_data.get(instance.name))
4333 d8052456 Iustin Pop
        elif field == "status":
4334 cbfc4681 Iustin Pop
          if instance.primary_node in off_nodes:
4335 cbfc4681 Iustin Pop
            val = "ERROR_nodeoffline"
4336 cbfc4681 Iustin Pop
          elif instance.primary_node in bad_nodes:
4337 d8052456 Iustin Pop
            val = "ERROR_nodedown"
4338 d8052456 Iustin Pop
          else:
4339 d8052456 Iustin Pop
            running = bool(live_data.get(instance.name))
4340 d8052456 Iustin Pop
            if running:
4341 0d68c45d Iustin Pop
              if instance.admin_up:
4342 d8052456 Iustin Pop
                val = "running"
4343 d8052456 Iustin Pop
              else:
4344 d8052456 Iustin Pop
                val = "ERROR_up"
4345 d8052456 Iustin Pop
            else:
4346 0d68c45d Iustin Pop
              if instance.admin_up:
4347 d8052456 Iustin Pop
                val = "ERROR_down"
4348 d8052456 Iustin Pop
              else:
4349 d8052456 Iustin Pop
                val = "ADMIN_down"
4350 a8083063 Iustin Pop
        elif field == "oper_ram":
4351 a8083063 Iustin Pop
          if instance.primary_node in bad_nodes:
4352 8a23d2d3 Iustin Pop
            val = None
4353 a8083063 Iustin Pop
          elif instance.name in live_data:
4354 a8083063 Iustin Pop
            val = live_data[instance.name].get("memory", "?")
4355 a8083063 Iustin Pop
          else:
4356 a8083063 Iustin Pop
            val = "-"
4357 c1ce76bb Iustin Pop
        elif field == "vcpus":
4358 c1ce76bb Iustin Pop
          val = i_be[constants.BE_VCPUS]
4359 a8083063 Iustin Pop
        elif field == "disk_template":
4360 a8083063 Iustin Pop
          val = instance.disk_template
4361 a8083063 Iustin Pop
        elif field == "ip":
4362 39a02558 Guido Trotter
          if instance.nics:
4363 39a02558 Guido Trotter
            val = instance.nics[0].ip
4364 39a02558 Guido Trotter
          else:
4365 39a02558 Guido Trotter
            val = None
4366 638c6349 Guido Trotter
        elif field == "nic_mode":
4367 638c6349 Guido Trotter
          if instance.nics:
4368 638c6349 Guido Trotter
            val = i_nicp[0][constants.NIC_MODE]
4369 638c6349 Guido Trotter
          else:
4370 638c6349 Guido Trotter
            val = None
4371 638c6349 Guido Trotter
        elif field == "nic_link":
4372 39a02558 Guido Trotter
          if instance.nics:
4373 638c6349 Guido Trotter
            val = i_nicp[0][constants.NIC_LINK]
4374 638c6349 Guido Trotter
          else:
4375 638c6349 Guido Trotter
            val = None
4376 638c6349 Guido Trotter
        elif field == "bridge":
4377 638c6349 Guido Trotter
          if (instance.nics and
4378 638c6349 Guido Trotter
              i_nicp[0][constants.NIC_MODE] == constants.NIC_MODE_BRIDGED):
4379 638c6349 Guido Trotter
            val = i_nicp[0][constants.NIC_LINK]
4380 39a02558 Guido Trotter
          else:
4381 39a02558 Guido Trotter
            val = None
4382 a8083063 Iustin Pop
        elif field == "mac":
4383 39a02558 Guido Trotter
          if instance.nics:
4384 39a02558 Guido Trotter
            val = instance.nics[0].mac
4385 39a02558 Guido Trotter
          else:
4386 39a02558 Guido Trotter
            val = None
4387 644eeef9 Iustin Pop
        elif field == "sda_size" or field == "sdb_size":
4388 ad24e046 Iustin Pop
          idx = ord(field[2]) - ord('a')
4389 ad24e046 Iustin Pop
          try:
4390 ad24e046 Iustin Pop
            val = instance.FindDisk(idx).size
4391 ad24e046 Iustin Pop
          except errors.OpPrereqError:
4392 8a23d2d3 Iustin Pop
            val = None
4393 024e157f Iustin Pop
        elif field == "disk_usage": # total disk usage per node
4394 024e157f Iustin Pop
          disk_sizes = [{'size': disk.size} for disk in instance.disks]
4395 024e157f Iustin Pop
          val = _ComputeDiskSize(instance.disk_template, disk_sizes)
4396 130a6a6f Iustin Pop
        elif field == "tags":
4397 130a6a6f Iustin Pop
          val = list(instance.GetTags())
4398 338e51e8 Iustin Pop
        elif field == "hvparams":
4399 338e51e8 Iustin Pop
          val = i_hv
4400 5018a335 Iustin Pop
        elif (field.startswith(HVPREFIX) and
4401 7736a5f2 Iustin Pop
              field[len(HVPREFIX):] in constants.HVS_PARAMETERS and
4402 7736a5f2 Iustin Pop
              field[len(HVPREFIX):] not in constants.HVC_GLOBALS):
4403 5018a335 Iustin Pop
          val = i_hv.get(field[len(HVPREFIX):], None)
4404 338e51e8 Iustin Pop
        elif field == "beparams":
4405 338e51e8 Iustin Pop
          val = i_be
4406 338e51e8 Iustin Pop
        elif (field.startswith(BEPREFIX) and
4407 338e51e8 Iustin Pop
              field[len(BEPREFIX):] in constants.BES_PARAMETERS):
4408 338e51e8 Iustin Pop
          val = i_be.get(field[len(BEPREFIX):], None)
4409 71c1af58 Iustin Pop
        elif st_match and st_match.groups():
4410 71c1af58 Iustin Pop
          # matches a variable list
4411 71c1af58 Iustin Pop
          st_groups = st_match.groups()
4412 71c1af58 Iustin Pop
          if st_groups and st_groups[0] == "disk":
4413 71c1af58 Iustin Pop
            if st_groups[1] == "count":
4414 71c1af58 Iustin Pop
              val = len(instance.disks)
4415 41a776da Iustin Pop
            elif st_groups[1] == "sizes":
4416 41a776da Iustin Pop
              val = [disk.size for disk in instance.disks]
4417 71c1af58 Iustin Pop
            elif st_groups[1] == "size":
4418 3e0cea06 Iustin Pop
              try:
4419 3e0cea06 Iustin Pop
                val = instance.FindDisk(st_groups[2]).size
4420 3e0cea06 Iustin Pop
              except errors.OpPrereqError:
4421 71c1af58 Iustin Pop
                val = None
4422 71c1af58 Iustin Pop
            else:
4423 71c1af58 Iustin Pop
              assert False, "Unhandled disk parameter"
4424 71c1af58 Iustin Pop
          elif st_groups[0] == "nic":
4425 71c1af58 Iustin Pop
            if st_groups[1] == "count":
4426 71c1af58 Iustin Pop
              val = len(instance.nics)
4427 41a776da Iustin Pop
            elif st_groups[1] == "macs":
4428 41a776da Iustin Pop
              val = [nic.mac for nic in instance.nics]
4429 41a776da Iustin Pop
            elif st_groups[1] == "ips":
4430 41a776da Iustin Pop
              val = [nic.ip for nic in instance.nics]
4431 638c6349 Guido Trotter
            elif st_groups[1] == "modes":
4432 638c6349 Guido Trotter
              val = [nicp[constants.NIC_MODE] for nicp in i_nicp]
4433 638c6349 Guido Trotter
            elif st_groups[1] == "links":
4434 638c6349 Guido Trotter
              val = [nicp[constants.NIC_LINK] for nicp in i_nicp]
4435 41a776da Iustin Pop
            elif st_groups[1] == "bridges":
4436 638c6349 Guido Trotter
              val = []
4437 638c6349 Guido Trotter
              for nicp in i_nicp:
4438 638c6349 Guido Trotter
                if nicp[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
4439 638c6349 Guido Trotter
                  val.append(nicp[constants.NIC_LINK])
4440 638c6349 Guido Trotter
                else:
4441 638c6349 Guido Trotter
                  val.append(None)
4442 71c1af58 Iustin Pop
            else:
4443 71c1af58 Iustin Pop
              # index-based item
4444 71c1af58 Iustin Pop
              nic_idx = int(st_groups[2])
4445 71c1af58 Iustin Pop
              if nic_idx >= len(instance.nics):
4446 71c1af58 Iustin Pop
                val = None
4447 71c1af58 Iustin Pop
              else:
4448 71c1af58 Iustin Pop
                if st_groups[1] == "mac":
4449 71c1af58 Iustin Pop
                  val = instance.nics[nic_idx].mac
4450 71c1af58 Iustin Pop
                elif st_groups[1] == "ip":
4451 71c1af58 Iustin Pop
                  val = instance.nics[nic_idx].ip
4452 638c6349 Guido Trotter
                elif st_groups[1] == "mode":
4453 638c6349 Guido Trotter
                  val = i_nicp[nic_idx][constants.NIC_MODE]
4454 638c6349 Guido Trotter
                elif st_groups[1] == "link":
4455 638c6349 Guido Trotter
                  val = i_nicp[nic_idx][constants.NIC_LINK]
4456 71c1af58 Iustin Pop
                elif st_groups[1] == "bridge":
4457 638c6349 Guido Trotter
                  nic_mode = i_nicp[nic_idx][constants.NIC_MODE]
4458 638c6349 Guido Trotter
                  if nic_mode == constants.NIC_MODE_BRIDGED:
4459 638c6349 Guido Trotter
                    val = i_nicp[nic_idx][constants.NIC_LINK]
4460 638c6349 Guido Trotter
                  else:
4461 638c6349 Guido Trotter
                    val = None
4462 71c1af58 Iustin Pop
                else:
4463 71c1af58 Iustin Pop
                  assert False, "Unhandled NIC parameter"
4464 71c1af58 Iustin Pop
          else:
4465 c1ce76bb Iustin Pop
            assert False, ("Declared but unhandled variable parameter '%s'" %
4466 c1ce76bb Iustin Pop
                           field)
4467 a8083063 Iustin Pop
        else:
4468 c1ce76bb Iustin Pop
          assert False, "Declared but unhandled parameter '%s'" % field
4469 a8083063 Iustin Pop
        iout.append(val)
4470 a8083063 Iustin Pop
      output.append(iout)
4471 a8083063 Iustin Pop
4472 a8083063 Iustin Pop
    return output
4473 a8083063 Iustin Pop
4474 a8083063 Iustin Pop
4475 a8083063 Iustin Pop
class LUFailoverInstance(LogicalUnit):
4476 a8083063 Iustin Pop
  """Failover an instance.
4477 a8083063 Iustin Pop

4478 a8083063 Iustin Pop
  """
4479 a8083063 Iustin Pop
  HPATH = "instance-failover"
4480 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
4481 a8083063 Iustin Pop
  _OP_REQP = ["instance_name", "ignore_consistency"]
4482 c9e5c064 Guido Trotter
  REQ_BGL = False
4483 c9e5c064 Guido Trotter
4484 17c3f802 Guido Trotter
  def CheckArguments(self):
4485 17c3f802 Guido Trotter
    """Check the arguments.
4486 17c3f802 Guido Trotter

4487 17c3f802 Guido Trotter
    """
4488 17c3f802 Guido Trotter
    self.shutdown_timeout = getattr(self.op, "shutdown_timeout",
4489 17c3f802 Guido Trotter
                                    constants.DEFAULT_SHUTDOWN_TIMEOUT)
4490 17c3f802 Guido Trotter
4491 c9e5c064 Guido Trotter
  def ExpandNames(self):
4492 c9e5c064 Guido Trotter
    self._ExpandAndLockInstance()
4493 c9e5c064 Guido Trotter
    self.needed_locks[locking.LEVEL_NODE] = []
4494 f6d9a522 Guido Trotter
    self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
4495 c9e5c064 Guido Trotter
4496 c9e5c064 Guido Trotter
  def DeclareLocks(self, level):
4497 c9e5c064 Guido Trotter
    if level == locking.LEVEL_NODE:
4498 c9e5c064 Guido Trotter
      self._LockInstancesNodes()
4499 a8083063 Iustin Pop
4500 a8083063 Iustin Pop
  def BuildHooksEnv(self):
4501 a8083063 Iustin Pop
    """Build hooks env.
4502 a8083063 Iustin Pop

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

4505 a8083063 Iustin Pop
    """
4506 a8083063 Iustin Pop
    env = {
4507 a8083063 Iustin Pop
      "IGNORE_CONSISTENCY": self.op.ignore_consistency,
4508 17c3f802 Guido Trotter
      "SHUTDOWN_TIMEOUT": self.shutdown_timeout,
4509 a8083063 Iustin Pop
      }
4510 338e51e8 Iustin Pop
    env.update(_BuildInstanceHookEnvByObject(self, self.instance))
4511 d6a02168 Michael Hanselmann
    nl = [self.cfg.GetMasterNode()] + list(self.instance.secondary_nodes)
4512 a8083063 Iustin Pop
    return env, nl, nl
4513 a8083063 Iustin Pop
4514 a8083063 Iustin Pop
  def CheckPrereq(self):
4515 a8083063 Iustin Pop
    """Check prerequisites.
4516 a8083063 Iustin Pop

4517 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
4518 a8083063 Iustin Pop

4519 a8083063 Iustin Pop
    """
4520 c9e5c064 Guido Trotter
    self.instance = instance = self.cfg.GetInstanceInfo(self.op.instance_name)
4521 c9e5c064 Guido Trotter
    assert self.instance is not None, \
4522 c9e5c064 Guido Trotter
      "Cannot retrieve locked instance %s" % self.op.instance_name
4523 a8083063 Iustin Pop
4524 338e51e8 Iustin Pop
    bep = self.cfg.GetClusterInfo().FillBE(instance)
4525 a1f445d3 Iustin Pop
    if instance.disk_template not in constants.DTS_NET_MIRROR:
4526 2a710df1 Michael Hanselmann
      raise errors.OpPrereqError("Instance's disk layout is not"
4527 5c983ee5 Iustin Pop
                                 " network mirrored, cannot failover.",
4528 5c983ee5 Iustin Pop
                                 errors.ECODE_STATE)
4529 2a710df1 Michael Hanselmann
4530 2a710df1 Michael Hanselmann
    secondary_nodes = instance.secondary_nodes
4531 2a710df1 Michael Hanselmann
    if not secondary_nodes:
4532 2a710df1 Michael Hanselmann
      raise errors.ProgrammerError("no secondary node but using "
4533 abdf0113 Iustin Pop
                                   "a mirrored disk template")
4534 2a710df1 Michael Hanselmann
4535 2a710df1 Michael Hanselmann
    target_node = secondary_nodes[0]
4536 7527a8a4 Iustin Pop
    _CheckNodeOnline(self, target_node)
4537 733a2b6a Iustin Pop
    _CheckNodeNotDrained(self, target_node)
4538 d27776f0 Iustin Pop
    if instance.admin_up:
4539 d27776f0 Iustin Pop
      # check memory requirements on the secondary node
4540 d27776f0 Iustin Pop
      _CheckNodeFreeMemory(self, target_node, "failing over instance %s" %
4541 d27776f0 Iustin Pop
                           instance.name, bep[constants.BE_MEMORY],
4542 d27776f0 Iustin Pop
                           instance.hypervisor)
4543 d27776f0 Iustin Pop
    else:
4544 d27776f0 Iustin Pop
      self.LogInfo("Not checking memory on the secondary node as"
4545 d27776f0 Iustin Pop
                   " instance will not be started")
4546 3a7c308e Guido Trotter
4547 a8083063 Iustin Pop
    # check bridge existance
4548 b165e77e Guido Trotter
    _CheckInstanceBridgesExist(self, instance, node=target_node)
4549 a8083063 Iustin Pop
4550 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
4551 a8083063 Iustin Pop
    """Failover an instance.
4552 a8083063 Iustin Pop

4553 a8083063 Iustin Pop
    The failover is done by shutting it down on its present node and
4554 a8083063 Iustin Pop
    starting it on the secondary.
4555 a8083063 Iustin Pop

4556 a8083063 Iustin Pop
    """
4557 a8083063 Iustin Pop
    instance = self.instance
4558 a8083063 Iustin Pop
4559 a8083063 Iustin Pop
    source_node = instance.primary_node
4560 a8083063 Iustin Pop
    target_node = instance.secondary_nodes[0]
4561 a8083063 Iustin Pop
4562 1df79ce6 Michael Hanselmann
    if instance.admin_up:
4563 1df79ce6 Michael Hanselmann
      feedback_fn("* checking disk consistency between source and target")
4564 1df79ce6 Michael Hanselmann
      for dev in instance.disks:
4565 1df79ce6 Michael Hanselmann
        # for drbd, these are drbd over lvm
4566 1df79ce6 Michael Hanselmann
        if not _CheckDiskConsistency(self, dev, target_node, False):
4567 1df79ce6 Michael Hanselmann
          if not self.op.ignore_consistency:
4568 1df79ce6 Michael Hanselmann
            raise errors.OpExecError("Disk %s is degraded on target node,"
4569 1df79ce6 Michael Hanselmann
                                     " aborting failover." % dev.iv_name)
4570 1df79ce6 Michael Hanselmann
    else:
4571 1df79ce6 Michael Hanselmann
      feedback_fn("* not checking disk consistency as instance is not running")
4572 a8083063 Iustin Pop
4573 a8083063 Iustin Pop
    feedback_fn("* shutting down instance on source node")
4574 9a4f63d1 Iustin Pop
    logging.info("Shutting down instance %s on node %s",
4575 9a4f63d1 Iustin Pop
                 instance.name, source_node)
4576 a8083063 Iustin Pop
4577 17c3f802 Guido Trotter
    result = self.rpc.call_instance_shutdown(source_node, instance,
4578 17c3f802 Guido Trotter
                                             self.shutdown_timeout)
4579 4c4e4e1e Iustin Pop
    msg = result.fail_msg
4580 1fae010f Iustin Pop
    if msg:
4581 24a40d57 Iustin Pop
      if self.op.ignore_consistency:
4582 86d9d3bb Iustin Pop
        self.proc.LogWarning("Could not shutdown instance %s on node %s."
4583 1fae010f Iustin Pop
                             " Proceeding anyway. Please make sure node"
4584 1fae010f Iustin Pop
                             " %s is down. Error details: %s",
4585 1fae010f Iustin Pop
                             instance.name, source_node, source_node, msg)
4586 24a40d57 Iustin Pop
      else:
4587 1fae010f Iustin Pop
        raise errors.OpExecError("Could not shutdown instance %s on"
4588 1fae010f Iustin Pop
                                 " node %s: %s" %
4589 1fae010f Iustin Pop
                                 (instance.name, source_node, msg))
4590 a8083063 Iustin Pop
4591 a8083063 Iustin Pop
    feedback_fn("* deactivating the instance's disks on source node")
4592 b9bddb6b Iustin Pop
    if not _ShutdownInstanceDisks(self, instance, ignore_primary=True):
4593 3ecf6786 Iustin Pop
      raise errors.OpExecError("Can't shut down the instance's disks.")
4594 a8083063 Iustin Pop
4595 a8083063 Iustin Pop
    instance.primary_node = target_node
4596 a8083063 Iustin Pop
    # distribute new instance config to the other nodes
4597 a4eae71f Michael Hanselmann
    self.cfg.Update(instance, feedback_fn)
4598 a8083063 Iustin Pop
4599 12a0cfbe Guido Trotter
    # Only start the instance if it's marked as up
4600 0d68c45d Iustin Pop
    if instance.admin_up:
4601 12a0cfbe Guido Trotter
      feedback_fn("* activating the instance's disks on target node")
4602 9a4f63d1 Iustin Pop
      logging.info("Starting instance %s on node %s",
4603 9a4f63d1 Iustin Pop
                   instance.name, target_node)
4604 12a0cfbe Guido Trotter
4605 7c4d6c7b Michael Hanselmann
      disks_ok, _ = _AssembleInstanceDisks(self, instance,
4606 12a0cfbe Guido Trotter
                                               ignore_secondaries=True)
4607 12a0cfbe Guido Trotter
      if not disks_ok:
4608 b9bddb6b Iustin Pop
        _ShutdownInstanceDisks(self, instance)
4609 12a0cfbe Guido Trotter
        raise errors.OpExecError("Can't activate the instance's disks")
4610 a8083063 Iustin Pop
4611 12a0cfbe Guido Trotter
      feedback_fn("* starting the instance on the target node")
4612 0eca8e0c Iustin Pop
      result = self.rpc.call_instance_start(target_node, instance, None, None)
4613 4c4e4e1e Iustin Pop
      msg = result.fail_msg
4614 dd279568 Iustin Pop
      if msg:
4615 b9bddb6b Iustin Pop
        _ShutdownInstanceDisks(self, instance)
4616 dd279568 Iustin Pop
        raise errors.OpExecError("Could not start instance %s on node %s: %s" %
4617 dd279568 Iustin Pop
                                 (instance.name, target_node, msg))
4618 a8083063 Iustin Pop
4619 a8083063 Iustin Pop
4620 53c776b5 Iustin Pop
class LUMigrateInstance(LogicalUnit):
4621 53c776b5 Iustin Pop
  """Migrate an instance.
4622 53c776b5 Iustin Pop

4623 53c776b5 Iustin Pop
  This is migration without shutting down, compared to the failover,
4624 53c776b5 Iustin Pop
  which is done with shutdown.
4625 53c776b5 Iustin Pop

4626 53c776b5 Iustin Pop
  """
4627 53c776b5 Iustin Pop
  HPATH = "instance-migrate"
4628 53c776b5 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
4629 53c776b5 Iustin Pop
  _OP_REQP = ["instance_name", "live", "cleanup"]
4630 53c776b5 Iustin Pop
4631 53c776b5 Iustin Pop
  REQ_BGL = False
4632 53c776b5 Iustin Pop
4633 53c776b5 Iustin Pop
  def ExpandNames(self):
4634 53c776b5 Iustin Pop
    self._ExpandAndLockInstance()
4635 3e06e001 Michael Hanselmann
4636 53c776b5 Iustin Pop
    self.needed_locks[locking.LEVEL_NODE] = []
4637 53c776b5 Iustin Pop
    self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
4638 53c776b5 Iustin Pop
4639 3e06e001 Michael Hanselmann
    self._migrater = TLMigrateInstance(self, self.op.instance_name,
4640 3e06e001 Michael Hanselmann
                                       self.op.live, self.op.cleanup)
4641 3a012b41 Michael Hanselmann
    self.tasklets = [self._migrater]
4642 3e06e001 Michael Hanselmann
4643 53c776b5 Iustin Pop
  def DeclareLocks(self, level):
4644 53c776b5 Iustin Pop
    if level == locking.LEVEL_NODE:
4645 53c776b5 Iustin Pop
      self._LockInstancesNodes()
4646 53c776b5 Iustin Pop
4647 53c776b5 Iustin Pop
  def BuildHooksEnv(self):
4648 53c776b5 Iustin Pop
    """Build hooks env.
4649 53c776b5 Iustin Pop

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

4652 53c776b5 Iustin Pop
    """
4653 3e06e001 Michael Hanselmann
    instance = self._migrater.instance
4654 3e06e001 Michael Hanselmann
    env = _BuildInstanceHookEnvByObject(self, instance)
4655 2c2690c9 Iustin Pop
    env["MIGRATE_LIVE"] = self.op.live
4656 2c2690c9 Iustin Pop
    env["MIGRATE_CLEANUP"] = self.op.cleanup
4657 3e06e001 Michael Hanselmann
    nl = [self.cfg.GetMasterNode()] + list(instance.secondary_nodes)
4658 53c776b5 Iustin Pop
    return env, nl, nl
4659 53c776b5 Iustin Pop
4660 3e06e001 Michael Hanselmann
4661 313bcead Iustin Pop
class LUMoveInstance(LogicalUnit):
4662 313bcead Iustin Pop
  """Move an instance by data-copying.
4663 313bcead Iustin Pop

4664 313bcead Iustin Pop
  """
4665 313bcead Iustin Pop
  HPATH = "instance-move"
4666 313bcead Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
4667 313bcead Iustin Pop
  _OP_REQP = ["instance_name", "target_node"]
4668 313bcead Iustin Pop
  REQ_BGL = False
4669 313bcead Iustin Pop
4670 17c3f802 Guido Trotter
  def CheckArguments(self):
4671 17c3f802 Guido Trotter
    """Check the arguments.
4672 17c3f802 Guido Trotter

4673 17c3f802 Guido Trotter
    """
4674 17c3f802 Guido Trotter
    self.shutdown_timeout = getattr(self.op, "shutdown_timeout",
4675 17c3f802 Guido Trotter
                                    constants.DEFAULT_SHUTDOWN_TIMEOUT)
4676 17c3f802 Guido Trotter
4677 313bcead Iustin Pop
  def ExpandNames(self):
4678 313bcead Iustin Pop
    self._ExpandAndLockInstance()
4679 313bcead Iustin Pop
    target_node = self.cfg.ExpandNodeName(self.op.target_node)
4680 313bcead Iustin Pop
    if target_node is None:
4681 313bcead Iustin Pop
      raise errors.OpPrereqError("Node '%s' not known" %
4682 5c983ee5 Iustin Pop
                                  self.op.target_node, errors.ECODE_NOENT)
4683 313bcead Iustin Pop
    self.op.target_node = target_node
4684 313bcead Iustin Pop
    self.needed_locks[locking.LEVEL_NODE] = [target_node]
4685 313bcead Iustin Pop
    self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_APPEND
4686 313bcead Iustin Pop
4687 313bcead Iustin Pop
  def DeclareLocks(self, level):
4688 313bcead Iustin Pop
    if level == locking.LEVEL_NODE:
4689 313bcead Iustin Pop
      self._LockInstancesNodes(primary_only=True)
4690 313bcead Iustin Pop
4691 313bcead Iustin Pop
  def BuildHooksEnv(self):
4692 313bcead Iustin Pop
    """Build hooks env.
4693 313bcead Iustin Pop

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

4696 313bcead Iustin Pop
    """
4697 313bcead Iustin Pop
    env = {
4698 313bcead Iustin Pop
      "TARGET_NODE": self.op.target_node,
4699 17c3f802 Guido Trotter
      "SHUTDOWN_TIMEOUT": self.shutdown_timeout,
4700 313bcead Iustin Pop
      }
4701 313bcead Iustin Pop
    env.update(_BuildInstanceHookEnvByObject(self, self.instance))
4702 313bcead Iustin Pop
    nl = [self.cfg.GetMasterNode()] + [self.instance.primary_node,
4703 313bcead Iustin Pop
                                       self.op.target_node]
4704 313bcead Iustin Pop
    return env, nl, nl
4705 313bcead Iustin Pop
4706 313bcead Iustin Pop
  def CheckPrereq(self):
4707 313bcead Iustin Pop
    """Check prerequisites.
4708 313bcead Iustin Pop

4709 313bcead Iustin Pop
    This checks that the instance is in the cluster.
4710 313bcead Iustin Pop

4711 313bcead Iustin Pop
    """
4712 313bcead Iustin Pop
    self.instance = instance = self.cfg.GetInstanceInfo(self.op.instance_name)
4713 313bcead Iustin Pop
    assert self.instance is not None, \
4714 313bcead Iustin Pop
      "Cannot retrieve locked instance %s" % self.op.instance_name
4715 313bcead Iustin Pop
4716 313bcead Iustin Pop
    node = self.cfg.GetNodeInfo(self.op.target_node)
4717 313bcead Iustin Pop
    assert node is not None, \
4718 313bcead Iustin Pop
      "Cannot retrieve locked node %s" % self.op.target_node
4719 313bcead Iustin Pop
4720 313bcead Iustin Pop
    self.target_node = target_node = node.name
4721 313bcead Iustin Pop
4722 313bcead Iustin Pop
    if target_node == instance.primary_node:
4723 313bcead Iustin Pop
      raise errors.OpPrereqError("Instance %s is already on the node %s" %
4724 5c983ee5 Iustin Pop
                                 (instance.name, target_node),
4725 5c983ee5 Iustin Pop
                                 errors.ECODE_STATE)
4726 313bcead Iustin Pop
4727 313bcead Iustin Pop
    bep = self.cfg.GetClusterInfo().FillBE(instance)
4728 313bcead Iustin Pop
4729 313bcead Iustin Pop
    for idx, dsk in enumerate(instance.disks):
4730 313bcead Iustin Pop
      if dsk.dev_type not in (constants.LD_LV, constants.LD_FILE):
4731 313bcead Iustin Pop
        raise errors.OpPrereqError("Instance disk %d has a complex layout,"
4732 5c983ee5 Iustin Pop
                                   " cannot copy", errors.ECODE_STATE)
4733 313bcead Iustin Pop
4734 313bcead Iustin Pop
    _CheckNodeOnline(self, target_node)
4735 313bcead Iustin Pop
    _CheckNodeNotDrained(self, target_node)
4736 313bcead Iustin Pop
4737 313bcead Iustin Pop
    if instance.admin_up:
4738 313bcead Iustin Pop
      # check memory requirements on the secondary node
4739 313bcead Iustin Pop
      _CheckNodeFreeMemory(self, target_node, "failing over instance %s" %
4740 313bcead Iustin Pop
                           instance.name, bep[constants.BE_MEMORY],
4741 313bcead Iustin Pop
                           instance.hypervisor)
4742 313bcead Iustin Pop
    else:
4743 313bcead Iustin Pop
      self.LogInfo("Not checking memory on the secondary node as"
4744 313bcead Iustin Pop
                   " instance will not be started")
4745 313bcead Iustin Pop
4746 313bcead Iustin Pop
    # check bridge existance
4747 313bcead Iustin Pop
    _CheckInstanceBridgesExist(self, instance, node=target_node)
4748 313bcead Iustin Pop
4749 313bcead Iustin Pop
  def Exec(self, feedback_fn):
4750 313bcead Iustin Pop
    """Move an instance.
4751 313bcead Iustin Pop

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

4755 313bcead Iustin Pop
    """
4756 313bcead Iustin Pop
    instance = self.instance
4757 313bcead Iustin Pop
4758 313bcead Iustin Pop
    source_node = instance.primary_node
4759 313bcead Iustin Pop
    target_node = self.target_node
4760 313bcead Iustin Pop
4761 313bcead Iustin Pop
    self.LogInfo("Shutting down instance %s on source node %s",
4762 313bcead Iustin Pop
                 instance.name, source_node)
4763 313bcead Iustin Pop
4764 17c3f802 Guido Trotter
    result = self.rpc.call_instance_shutdown(source_node, instance,
4765 17c3f802 Guido Trotter
                                             self.shutdown_timeout)
4766 313bcead Iustin Pop
    msg = result.fail_msg
4767 313bcead Iustin Pop
    if msg:
4768 313bcead Iustin Pop
      if self.op.ignore_consistency:
4769 313bcead Iustin Pop
        self.proc.LogWarning("Could not shutdown instance %s on node %s."
4770 313bcead Iustin Pop
                             " Proceeding anyway. Please make sure node"
4771 313bcead Iustin Pop
                             " %s is down. Error details: %s",
4772 313bcead Iustin Pop
                             instance.name, source_node, source_node, msg)
4773 313bcead Iustin Pop
      else:
4774 313bcead Iustin Pop
        raise errors.OpExecError("Could not shutdown instance %s on"
4775 313bcead Iustin Pop
                                 " node %s: %s" %
4776 313bcead Iustin Pop
                                 (instance.name, source_node, msg))
4777 313bcead Iustin Pop
4778 313bcead Iustin Pop
    # create the target disks
4779 313bcead Iustin Pop
    try:
4780 313bcead Iustin Pop
      _CreateDisks(self, instance, target_node=target_node)
4781 313bcead Iustin Pop
    except errors.OpExecError:
4782 313bcead Iustin Pop
      self.LogWarning("Device creation failed, reverting...")
4783 313bcead Iustin Pop
      try:
4784 313bcead Iustin Pop
        _RemoveDisks(self, instance, target_node=target_node)
4785 313bcead Iustin Pop
      finally:
4786 313bcead Iustin Pop
        self.cfg.ReleaseDRBDMinors(instance.name)
4787 313bcead Iustin Pop
        raise
4788 313bcead Iustin Pop
4789 313bcead Iustin Pop
    cluster_name = self.cfg.GetClusterInfo().cluster_name
4790 313bcead Iustin Pop
4791 313bcead Iustin Pop
    errs = []
4792 313bcead Iustin Pop
    # activate, get path, copy the data over
4793 313bcead Iustin Pop
    for idx, disk in enumerate(instance.disks):
4794 313bcead Iustin Pop
      self.LogInfo("Copying data for disk %d", idx)
4795 313bcead Iustin Pop
      result = self.rpc.call_blockdev_assemble(target_node, disk,
4796 313bcead Iustin Pop
                                               instance.name, True)
4797 313bcead Iustin Pop
      if result.fail_msg:
4798 313bcead Iustin Pop
        self.LogWarning("Can't assemble newly created disk %d: %s",
4799 313bcead Iustin Pop
                        idx, result.fail_msg)
4800 313bcead Iustin Pop
        errs.append(result.fail_msg)
4801 313bcead Iustin Pop
        break
4802 313bcead Iustin Pop
      dev_path = result.payload
4803 313bcead Iustin Pop
      result = self.rpc.call_blockdev_export(source_node, disk,
4804 313bcead Iustin Pop
                                             target_node, dev_path,
4805 313bcead Iustin Pop
                                             cluster_name)
4806 313bcead Iustin Pop
      if result.fail_msg:
4807 313bcead Iustin Pop
        self.LogWarning("Can't copy data over for disk %d: %s",
4808 313bcead Iustin Pop
                        idx, result.fail_msg)
4809 313bcead Iustin Pop
        errs.append(result.fail_msg)
4810 313bcead Iustin Pop
        break
4811 313bcead Iustin Pop
4812 313bcead Iustin Pop
    if errs:
4813 313bcead Iustin Pop
      self.LogWarning("Some disks failed to copy, aborting")
4814 313bcead Iustin Pop
      try:
4815 313bcead Iustin Pop
        _RemoveDisks(self, instance, target_node=target_node)
4816 313bcead Iustin Pop
      finally:
4817 313bcead Iustin Pop
        self.cfg.ReleaseDRBDMinors(instance.name)
4818 313bcead Iustin Pop
        raise errors.OpExecError("Errors during disk copy: %s" %
4819 313bcead Iustin Pop
                                 (",".join(errs),))
4820 313bcead Iustin Pop
4821 313bcead Iustin Pop
    instance.primary_node = target_node
4822 a4eae71f Michael Hanselmann
    self.cfg.Update(instance, feedback_fn)
4823 313bcead Iustin Pop
4824 313bcead Iustin Pop
    self.LogInfo("Removing the disks on the original node")
4825 313bcead Iustin Pop
    _RemoveDisks(self, instance, target_node=source_node)
4826 313bcead Iustin Pop
4827 313bcead Iustin Pop
    # Only start the instance if it's marked as up
4828 313bcead Iustin Pop
    if instance.admin_up:
4829 313bcead Iustin Pop
      self.LogInfo("Starting instance %s on node %s",
4830 313bcead Iustin Pop
                   instance.name, target_node)
4831 313bcead Iustin Pop
4832 313bcead Iustin Pop
      disks_ok, _ = _AssembleInstanceDisks(self, instance,
4833 313bcead Iustin Pop
                                           ignore_secondaries=True)
4834 313bcead Iustin Pop
      if not disks_ok:
4835 313bcead Iustin Pop
        _ShutdownInstanceDisks(self, instance)
4836 313bcead Iustin Pop
        raise errors.OpExecError("Can't activate the instance's disks")
4837 313bcead Iustin Pop
4838 313bcead Iustin Pop
      result = self.rpc.call_instance_start(target_node, instance, None, None)
4839 313bcead Iustin Pop
      msg = result.fail_msg
4840 313bcead Iustin Pop
      if msg:
4841 313bcead Iustin Pop
        _ShutdownInstanceDisks(self, instance)
4842 313bcead Iustin Pop
        raise errors.OpExecError("Could not start instance %s on node %s: %s" %
4843 313bcead Iustin Pop
                                 (instance.name, target_node, msg))
4844 313bcead Iustin Pop
4845 313bcead Iustin Pop
4846 80cb875c Michael Hanselmann
class LUMigrateNode(LogicalUnit):
4847 80cb875c Michael Hanselmann
  """Migrate all instances from a node.
4848 80cb875c Michael Hanselmann

4849 80cb875c Michael Hanselmann
  """
4850 80cb875c Michael Hanselmann
  HPATH = "node-migrate"
4851 80cb875c Michael Hanselmann
  HTYPE = constants.HTYPE_NODE
4852 80cb875c Michael Hanselmann
  _OP_REQP = ["node_name", "live"]
4853 80cb875c Michael Hanselmann
  REQ_BGL = False
4854 80cb875c Michael Hanselmann
4855 80cb875c Michael Hanselmann
  def ExpandNames(self):
4856 80cb875c Michael Hanselmann
    self.op.node_name = self.cfg.ExpandNodeName(self.op.node_name)
4857 80cb875c Michael Hanselmann
    if self.op.node_name is None:
4858 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Node '%s' not known" % self.op.node_name,
4859 5c983ee5 Iustin Pop
                                 errors.ECODE_NOENT)
4860 80cb875c Michael Hanselmann
4861 80cb875c Michael Hanselmann
    self.needed_locks = {
4862 80cb875c Michael Hanselmann
      locking.LEVEL_NODE: [self.op.node_name],
4863 80cb875c Michael Hanselmann
      }
4864 80cb875c Michael Hanselmann
4865 80cb875c Michael Hanselmann
    self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_APPEND
4866 80cb875c Michael Hanselmann
4867 80cb875c Michael Hanselmann
    # Create tasklets for migrating instances for all instances on this node
4868 80cb875c Michael Hanselmann
    names = []
4869 80cb875c Michael Hanselmann
    tasklets = []
4870 80cb875c Michael Hanselmann
4871 80cb875c Michael Hanselmann
    for inst in _GetNodePrimaryInstances(self.cfg, self.op.node_name):
4872 80cb875c Michael Hanselmann
      logging.debug("Migrating instance %s", inst.name)
4873 80cb875c Michael Hanselmann
      names.append(inst.name)
4874 80cb875c Michael Hanselmann
4875 80cb875c Michael Hanselmann
      tasklets.append(TLMigrateInstance(self, inst.name, self.op.live, False))
4876 80cb875c Michael Hanselmann
4877 80cb875c Michael Hanselmann
    self.tasklets = tasklets
4878 80cb875c Michael Hanselmann
4879 80cb875c Michael Hanselmann
    # Declare instance locks
4880 80cb875c Michael Hanselmann
    self.needed_locks[locking.LEVEL_INSTANCE] = names
4881 80cb875c Michael Hanselmann
4882 80cb875c Michael Hanselmann
  def DeclareLocks(self, level):
4883 80cb875c Michael Hanselmann
    if level == locking.LEVEL_NODE:
4884 80cb875c Michael Hanselmann
      self._LockInstancesNodes()
4885 80cb875c Michael Hanselmann
4886 80cb875c Michael Hanselmann
  def BuildHooksEnv(self):
4887 80cb875c Michael Hanselmann
    """Build hooks env.
4888 80cb875c Michael Hanselmann

4889 80cb875c Michael Hanselmann
    This runs on the master, the primary and all the secondaries.
4890 80cb875c Michael Hanselmann

4891 80cb875c Michael Hanselmann
    """
4892 80cb875c Michael Hanselmann
    env = {
4893 80cb875c Michael Hanselmann
      "NODE_NAME": self.op.node_name,
4894 80cb875c Michael Hanselmann
      }
4895 80cb875c Michael Hanselmann
4896 80cb875c Michael Hanselmann
    nl = [self.cfg.GetMasterNode()]
4897 80cb875c Michael Hanselmann
4898 80cb875c Michael Hanselmann
    return (env, nl, nl)
4899 80cb875c Michael Hanselmann
4900 80cb875c Michael Hanselmann
4901 3e06e001 Michael Hanselmann
class TLMigrateInstance(Tasklet):
4902 3e06e001 Michael Hanselmann
  def __init__(self, lu, instance_name, live, cleanup):
4903 3e06e001 Michael Hanselmann
    """Initializes this class.
4904 3e06e001 Michael Hanselmann

4905 3e06e001 Michael Hanselmann
    """
4906 464243a7 Michael Hanselmann
    Tasklet.__init__(self, lu)
4907 464243a7 Michael Hanselmann
4908 3e06e001 Michael Hanselmann
    # Parameters
4909 3e06e001 Michael Hanselmann
    self.instance_name = instance_name
4910 3e06e001 Michael Hanselmann
    self.live = live
4911 3e06e001 Michael Hanselmann
    self.cleanup = cleanup
4912 3e06e001 Michael Hanselmann
4913 53c776b5 Iustin Pop
  def CheckPrereq(self):
4914 53c776b5 Iustin Pop
    """Check prerequisites.
4915 53c776b5 Iustin Pop

4916 53c776b5 Iustin Pop
    This checks that the instance is in the cluster.
4917 53c776b5 Iustin Pop

4918 53c776b5 Iustin Pop
    """
4919 53c776b5 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
4920 3e06e001 Michael Hanselmann
      self.cfg.ExpandInstanceName(self.instance_name))
4921 53c776b5 Iustin Pop
    if instance is None:
4922 53c776b5 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
4923 5c983ee5 Iustin Pop
                                 self.instance_name, errors.ECODE_NOENT)
4924 53c776b5 Iustin Pop
4925 53c776b5 Iustin Pop
    if instance.disk_template != constants.DT_DRBD8:
4926 53c776b5 Iustin Pop
      raise errors.OpPrereqError("Instance's disk layout is not"
4927 5c983ee5 Iustin Pop
                                 " drbd8, cannot migrate.", errors.ECODE_STATE)
4928 53c776b5 Iustin Pop
4929 53c776b5 Iustin Pop
    secondary_nodes = instance.secondary_nodes
4930 53c776b5 Iustin Pop
    if not secondary_nodes:
4931 733a2b6a Iustin Pop
      raise errors.ConfigurationError("No secondary node but using"
4932 733a2b6a Iustin Pop
                                      " drbd8 disk template")
4933 53c776b5 Iustin Pop
4934 53c776b5 Iustin Pop
    i_be = self.cfg.GetClusterInfo().FillBE(instance)
4935 53c776b5 Iustin Pop
4936 53c776b5 Iustin Pop
    target_node = secondary_nodes[0]
4937 53c776b5 Iustin Pop
    # check memory requirements on the secondary node
4938 53c776b5 Iustin Pop
    _CheckNodeFreeMemory(self, target_node, "migrating instance %s" %
4939 53c776b5 Iustin Pop
                         instance.name, i_be[constants.BE_MEMORY],
4940 53c776b5 Iustin Pop
                         instance.hypervisor)
4941 53c776b5 Iustin Pop
4942 53c776b5 Iustin Pop
    # check bridge existance
4943 b165e77e Guido Trotter
    _CheckInstanceBridgesExist(self, instance, node=target_node)
4944 53c776b5 Iustin Pop
4945 3e06e001 Michael Hanselmann
    if not self.cleanup:
4946 733a2b6a Iustin Pop
      _CheckNodeNotDrained(self, target_node)
4947 53c776b5 Iustin Pop
      result = self.rpc.call_instance_migratable(instance.primary_node,
4948 53c776b5 Iustin Pop
                                                 instance)
4949 045dd6d9 Iustin Pop
      result.Raise("Can't migrate, please use failover",
4950 045dd6d9 Iustin Pop
                   prereq=True, ecode=errors.ECODE_STATE)
4951 53c776b5 Iustin Pop
4952 53c776b5 Iustin Pop
    self.instance = instance
4953 53c776b5 Iustin Pop
4954 53c776b5 Iustin Pop
  def _WaitUntilSync(self):
4955 53c776b5 Iustin Pop
    """Poll with custom rpc for disk sync.
4956 53c776b5 Iustin Pop

4957 53c776b5 Iustin Pop
    This uses our own step-based rpc call.
4958 53c776b5 Iustin Pop

4959 53c776b5 Iustin Pop
    """
4960 53c776b5 Iustin Pop
    self.feedback_fn("* wait until resync is done")
4961 53c776b5 Iustin Pop
    all_done = False
4962 53c776b5 Iustin Pop
    while not all_done:
4963 53c776b5 Iustin Pop
      all_done = True
4964 53c776b5 Iustin Pop
      result = self.rpc.call_drbd_wait_sync(self.all_nodes,
4965 53c776b5 Iustin Pop
                                            self.nodes_ip,
4966 53c776b5 Iustin Pop
                                            self.instance.disks)
4967 53c776b5 Iustin Pop
      min_percent = 100
4968 53c776b5 Iustin Pop
      for node, nres in result.items():
4969 4c4e4e1e Iustin Pop
        nres.Raise("Cannot resync disks on node %s" % node)
4970 0959c824 Iustin Pop
        node_done, node_percent = nres.payload
4971 53c776b5 Iustin Pop
        all_done = all_done and node_done
4972 53c776b5 Iustin Pop
        if node_percent is not None:
4973 53c776b5 Iustin Pop
          min_percent = min(min_percent, node_percent)
4974 53c776b5 Iustin Pop
      if not all_done:
4975 53c776b5 Iustin Pop
        if min_percent < 100:
4976 53c776b5 Iustin Pop
          self.feedback_fn("   - progress: %.1f%%" % min_percent)
4977 53c776b5 Iustin Pop
        time.sleep(2)
4978 53c776b5 Iustin Pop
4979 53c776b5 Iustin Pop
  def _EnsureSecondary(self, node):
4980 53c776b5 Iustin Pop
    """Demote a node to secondary.
4981 53c776b5 Iustin Pop

4982 53c776b5 Iustin Pop
    """
4983 53c776b5 Iustin Pop
    self.feedback_fn("* switching node %s to secondary mode" % node)
4984 53c776b5 Iustin Pop
4985 53c776b5 Iustin Pop
    for dev in self.instance.disks:
4986 53c776b5 Iustin Pop
      self.cfg.SetDiskID(dev, node)
4987 53c776b5 Iustin Pop
4988 53c776b5 Iustin Pop
    result = self.rpc.call_blockdev_close(node, self.instance.name,
4989 53c776b5 Iustin Pop
                                          self.instance.disks)
4990 4c4e4e1e Iustin Pop
    result.Raise("Cannot change disk to secondary on node %s" % node)
4991 53c776b5 Iustin Pop
4992 53c776b5 Iustin Pop
  def _GoStandalone(self):
4993 53c776b5 Iustin Pop
    """Disconnect from the network.
4994 53c776b5 Iustin Pop

4995 53c776b5 Iustin Pop
    """
4996 53c776b5 Iustin Pop
    self.feedback_fn("* changing into standalone mode")
4997 53c776b5 Iustin Pop
    result = self.rpc.call_drbd_disconnect_net(self.all_nodes, self.nodes_ip,
4998 53c776b5 Iustin Pop
                                               self.instance.disks)
4999 53c776b5 Iustin Pop
    for node, nres in result.items():
5000 4c4e4e1e Iustin Pop
      nres.Raise("Cannot disconnect disks node %s" % node)
5001 53c776b5 Iustin Pop
5002 53c776b5 Iustin Pop
  def _GoReconnect(self, multimaster):
5003 53c776b5 Iustin Pop
    """Reconnect to the network.
5004 53c776b5 Iustin Pop

5005 53c776b5 Iustin Pop
    """
5006 53c776b5 Iustin Pop
    if multimaster:
5007 53c776b5 Iustin Pop
      msg = "dual-master"
5008 53c776b5 Iustin Pop
    else:
5009 53c776b5 Iustin Pop
      msg = "single-master"
5010 53c776b5 Iustin Pop
    self.feedback_fn("* changing disks into %s mode" % msg)
5011 53c776b5 Iustin Pop
    result = self.rpc.call_drbd_attach_net(self.all_nodes, self.nodes_ip,
5012 53c776b5 Iustin Pop
                                           self.instance.disks,
5013 53c776b5 Iustin Pop
                                           self.instance.name, multimaster)
5014 53c776b5 Iustin Pop
    for node, nres in result.items():
5015 4c4e4e1e Iustin Pop
      nres.Raise("Cannot change disks config on node %s" % node)
5016 53c776b5 Iustin Pop
5017 53c776b5 Iustin Pop
  def _ExecCleanup(self):
5018 53c776b5 Iustin Pop
    """Try to cleanup after a failed migration.
5019 53c776b5 Iustin Pop

5020 53c776b5 Iustin Pop
    The cleanup is done by:
5021 53c776b5 Iustin Pop
      - check that the instance is running only on one node
5022 53c776b5 Iustin Pop
        (and update the config if needed)
5023 53c776b5 Iustin Pop
      - change disks on its secondary node to secondary
5024 53c776b5 Iustin Pop
      - wait until disks are fully synchronized
5025 53c776b5 Iustin Pop
      - disconnect from the network
5026 53c776b5 Iustin Pop
      - change disks into single-master mode
5027 53c776b5 Iustin Pop
      - wait again until disks are fully synchronized
5028 53c776b5 Iustin Pop

5029 53c776b5 Iustin Pop
    """
5030 53c776b5 Iustin Pop
    instance = self.instance
5031 53c776b5 Iustin Pop
    target_node = self.target_node
5032 53c776b5 Iustin Pop
    source_node = self.source_node
5033 53c776b5 Iustin Pop
5034 53c776b5 Iustin Pop
    # check running on only one node
5035 53c776b5 Iustin Pop
    self.feedback_fn("* checking where the instance actually runs"
5036 53c776b5 Iustin Pop
                     " (if this hangs, the hypervisor might be in"
5037 53c776b5 Iustin Pop
                     " a bad state)")
5038 53c776b5 Iustin Pop
    ins_l = self.rpc.call_instance_list(self.all_nodes, [instance.hypervisor])
5039 53c776b5 Iustin Pop
    for node, result in ins_l.items():
5040 4c4e4e1e Iustin Pop
      result.Raise("Can't contact node %s" % node)
5041 53c776b5 Iustin Pop
5042 aca13712 Iustin Pop
    runningon_source = instance.name in ins_l[source_node].payload
5043 aca13712 Iustin Pop
    runningon_target = instance.name in ins_l[target_node].payload
5044 53c776b5 Iustin Pop
5045 53c776b5 Iustin Pop
    if runningon_source and runningon_target:
5046 53c776b5 Iustin Pop
      raise errors.OpExecError("Instance seems to be running on two nodes,"
5047 53c776b5 Iustin Pop
                               " or the hypervisor is confused. You will have"
5048 53c776b5 Iustin Pop
                               " to ensure manually that it runs only on one"
5049 53c776b5 Iustin Pop
                               " and restart this operation.")
5050 53c776b5 Iustin Pop
5051 53c776b5 Iustin Pop
    if not (runningon_source or runningon_target):
5052 53c776b5 Iustin Pop
      raise errors.OpExecError("Instance does not seem to be running at all."
5053 53c776b5 Iustin Pop
                               " In this case, it's safer to repair by"
5054 53c776b5 Iustin Pop
                               " running 'gnt-instance stop' to ensure disk"
5055 53c776b5 Iustin Pop
                               " shutdown, and then restarting it.")
5056 53c776b5 Iustin Pop
5057 53c776b5 Iustin Pop
    if runningon_target:
5058 53c776b5 Iustin Pop
      # the migration has actually succeeded, we need to update the config
5059 53c776b5 Iustin Pop
      self.feedback_fn("* instance running on secondary node (%s),"
5060 53c776b5 Iustin Pop
                       " updating config" % target_node)
5061 53c776b5 Iustin Pop
      instance.primary_node = target_node
5062 a4eae71f Michael Hanselmann
      self.cfg.Update(instance, self.feedback_fn)
5063 53c776b5 Iustin Pop
      demoted_node = source_node
5064 53c776b5 Iustin Pop
    else:
5065 53c776b5 Iustin Pop
      self.feedback_fn("* instance confirmed to be running on its"
5066 53c776b5 Iustin Pop
                       " primary node (%s)" % source_node)
5067 53c776b5 Iustin Pop
      demoted_node = target_node
5068 53c776b5 Iustin Pop
5069 53c776b5 Iustin Pop
    self._EnsureSecondary(demoted_node)
5070 53c776b5 Iustin Pop
    try:
5071 53c776b5 Iustin Pop
      self._WaitUntilSync()
5072 53c776b5 Iustin Pop
    except errors.OpExecError:
5073 53c776b5 Iustin Pop
      # we ignore here errors, since if the device is standalone, it
5074 53c776b5 Iustin Pop
      # won't be able to sync
5075 53c776b5 Iustin Pop
      pass
5076 53c776b5 Iustin Pop
    self._GoStandalone()
5077 53c776b5 Iustin Pop
    self._GoReconnect(False)
5078 53c776b5 Iustin Pop
    self._WaitUntilSync()
5079 53c776b5 Iustin Pop
5080 53c776b5 Iustin Pop
    self.feedback_fn("* done")
5081 53c776b5 Iustin Pop
5082 6906a9d8 Guido Trotter
  def _RevertDiskStatus(self):
5083 6906a9d8 Guido Trotter
    """Try to revert the disk status after a failed migration.
5084 6906a9d8 Guido Trotter

5085 6906a9d8 Guido Trotter
    """
5086 6906a9d8 Guido Trotter
    target_node = self.target_node
5087 6906a9d8 Guido Trotter
    try:
5088 6906a9d8 Guido Trotter
      self._EnsureSecondary(target_node)
5089 6906a9d8 Guido Trotter
      self._GoStandalone()
5090 6906a9d8 Guido Trotter
      self._GoReconnect(False)
5091 6906a9d8 Guido Trotter
      self._WaitUntilSync()
5092 6906a9d8 Guido Trotter
    except errors.OpExecError, err:
5093 3e06e001 Michael Hanselmann
      self.lu.LogWarning("Migration failed and I can't reconnect the"
5094 3e06e001 Michael Hanselmann
                         " drives: error '%s'\n"
5095 3e06e001 Michael Hanselmann
                         "Please look and recover the instance status" %
5096 3e06e001 Michael Hanselmann
                         str(err))
5097 6906a9d8 Guido Trotter
5098 6906a9d8 Guido Trotter
  def _AbortMigration(self):
5099 6906a9d8 Guido Trotter
    """Call the hypervisor code to abort a started migration.
5100 6906a9d8 Guido Trotter

5101 6906a9d8 Guido Trotter
    """
5102 6906a9d8 Guido Trotter
    instance = self.instance
5103 6906a9d8 Guido Trotter
    target_node = self.target_node
5104 6906a9d8 Guido Trotter
    migration_info = self.migration_info
5105 6906a9d8 Guido Trotter
5106 6906a9d8 Guido Trotter
    abort_result = self.rpc.call_finalize_migration(target_node,
5107 6906a9d8 Guido Trotter
                                                    instance,
5108 6906a9d8 Guido Trotter
                                                    migration_info,
5109 6906a9d8 Guido Trotter
                                                    False)
5110 4c4e4e1e Iustin Pop
    abort_msg = abort_result.fail_msg
5111 6906a9d8 Guido Trotter
    if abort_msg:
5112 099c52ad Iustin Pop
      logging.error("Aborting migration failed on target node %s: %s",
5113 099c52ad Iustin Pop
                    target_node, abort_msg)
5114 6906a9d8 Guido Trotter
      # Don't raise an exception here, as we stil have to try to revert the
5115 6906a9d8 Guido Trotter
      # disk status, even if this step failed.
5116 6906a9d8 Guido Trotter
5117 53c776b5 Iustin Pop
  def _ExecMigration(self):
5118 53c776b5 Iustin Pop
    """Migrate an instance.
5119 53c776b5 Iustin Pop

5120 53c776b5 Iustin Pop
    The migrate is done by:
5121 53c776b5 Iustin Pop
      - change the disks into dual-master mode
5122 53c776b5 Iustin Pop
      - wait until disks are fully synchronized again
5123 53c776b5 Iustin Pop
      - migrate the instance
5124 53c776b5 Iustin Pop
      - change disks on the new secondary node (the old primary) to secondary
5125 53c776b5 Iustin Pop
      - wait until disks are fully synchronized
5126 53c776b5 Iustin Pop
      - change disks into single-master mode
5127 53c776b5 Iustin Pop

5128 53c776b5 Iustin Pop
    """
5129 53c776b5 Iustin Pop
    instance = self.instance
5130 53c776b5 Iustin Pop
    target_node = self.target_node
5131 53c776b5 Iustin Pop
    source_node = self.source_node
5132 53c776b5 Iustin Pop
5133 53c776b5 Iustin Pop
    self.feedback_fn("* checking disk consistency between source and target")
5134 53c776b5 Iustin Pop
    for dev in instance.disks:
5135 53c776b5 Iustin Pop
      if not _CheckDiskConsistency(self, dev, target_node, False):
5136 53c776b5 Iustin Pop
        raise errors.OpExecError("Disk %s is degraded or not fully"
5137 53c776b5 Iustin Pop
                                 " synchronized on target node,"
5138 53c776b5 Iustin Pop
                                 " aborting migrate." % dev.iv_name)
5139 53c776b5 Iustin Pop
5140 6906a9d8 Guido Trotter
    # First get the migration information from the remote node
5141 6906a9d8 Guido Trotter
    result = self.rpc.call_migration_info(source_node, instance)
5142 4c4e4e1e Iustin Pop
    msg = result.fail_msg
5143 6906a9d8 Guido Trotter
    if msg:
5144 6906a9d8 Guido Trotter
      log_err = ("Failed fetching source migration information from %s: %s" %
5145 0959c824 Iustin Pop
                 (source_node, msg))
5146 6906a9d8 Guido Trotter
      logging.error(log_err)
5147 6906a9d8 Guido Trotter
      raise errors.OpExecError(log_err)
5148 6906a9d8 Guido Trotter
5149 0959c824 Iustin Pop
    self.migration_info = migration_info = result.payload
5150 6906a9d8 Guido Trotter
5151 6906a9d8 Guido Trotter
    # Then switch the disks to master/master mode
5152 53c776b5 Iustin Pop
    self._EnsureSecondary(target_node)
5153 53c776b5 Iustin Pop
    self._GoStandalone()
5154 53c776b5 Iustin Pop
    self._GoReconnect(True)
5155 53c776b5 Iustin Pop
    self._WaitUntilSync()
5156 53c776b5 Iustin Pop
5157 6906a9d8 Guido Trotter
    self.feedback_fn("* preparing %s to accept the instance" % target_node)
5158 6906a9d8 Guido Trotter
    result = self.rpc.call_accept_instance(target_node,
5159 6906a9d8 Guido Trotter
                                           instance,
5160 6906a9d8 Guido Trotter
                                           migration_info,
5161 6906a9d8 Guido Trotter
                                           self.nodes_ip[target_node])
5162 6906a9d8 Guido Trotter
5163 4c4e4e1e Iustin Pop
    msg = result.fail_msg
5164 6906a9d8 Guido Trotter
    if msg:
5165 6906a9d8 Guido Trotter
      logging.error("Instance pre-migration failed, trying to revert"
5166 6906a9d8 Guido Trotter
                    " disk status: %s", msg)
5167 78212a5d Iustin Pop
      self.feedback_fn("Pre-migration failed, aborting")
5168 6906a9d8 Guido Trotter
      self._AbortMigration()
5169 6906a9d8 Guido Trotter
      self._RevertDiskStatus()
5170 6906a9d8 Guido Trotter
      raise errors.OpExecError("Could not pre-migrate instance %s: %s" %
5171 6906a9d8 Guido Trotter
                               (instance.name, msg))
5172 6906a9d8 Guido Trotter
5173 53c776b5 Iustin Pop
    self.feedback_fn("* migrating instance to %s" % target_node)
5174 53c776b5 Iustin Pop
    time.sleep(10)
5175 53c776b5 Iustin Pop
    result = self.rpc.call_instance_migrate(source_node, instance,
5176 53c776b5 Iustin Pop
                                            self.nodes_ip[target_node],
5177 3e06e001 Michael Hanselmann
                                            self.live)
5178 4c4e4e1e Iustin Pop
    msg = result.fail_msg
5179 53c776b5 Iustin Pop
    if msg:
5180 53c776b5 Iustin Pop
      logging.error("Instance migration failed, trying to revert"
5181 53c776b5 Iustin Pop
                    " disk status: %s", msg)
5182 78212a5d Iustin Pop
      self.feedback_fn("Migration failed, aborting")
5183 6906a9d8 Guido Trotter
      self._AbortMigration()
5184 6906a9d8 Guido Trotter
      self._RevertDiskStatus()
5185 53c776b5 Iustin Pop
      raise errors.OpExecError("Could not migrate instance %s: %s" %
5186 53c776b5 Iustin Pop
                               (instance.name, msg))
5187 53c776b5 Iustin Pop
    time.sleep(10)
5188 53c776b5 Iustin Pop
5189 53c776b5 Iustin Pop
    instance.primary_node = target_node
5190 53c776b5 Iustin Pop
    # distribute new instance config to the other nodes
5191 a4eae71f Michael Hanselmann
    self.cfg.Update(instance, self.feedback_fn)
5192 53c776b5 Iustin Pop
5193 6906a9d8 Guido Trotter
    result = self.rpc.call_finalize_migration(target_node,
5194 6906a9d8 Guido Trotter
                                              instance,
5195 6906a9d8 Guido Trotter
                                              migration_info,
5196 6906a9d8 Guido Trotter
                                              True)
5197 4c4e4e1e Iustin Pop
    msg = result.fail_msg
5198 6906a9d8 Guido Trotter
    if msg:
5199 6906a9d8 Guido Trotter
      logging.error("Instance migration succeeded, but finalization failed:"
5200 099c52ad Iustin Pop
                    " %s", msg)
5201 6906a9d8 Guido Trotter
      raise errors.OpExecError("Could not finalize instance migration: %s" %
5202 6906a9d8 Guido Trotter
                               msg)
5203 6906a9d8 Guido Trotter
5204 53c776b5 Iustin Pop
    self._EnsureSecondary(source_node)
5205 53c776b5 Iustin Pop
    self._WaitUntilSync()
5206 53c776b5 Iustin Pop
    self._GoStandalone()
5207 53c776b5 Iustin Pop
    self._GoReconnect(False)
5208 53c776b5 Iustin Pop
    self._WaitUntilSync()
5209 53c776b5 Iustin Pop
5210 53c776b5 Iustin Pop
    self.feedback_fn("* done")
5211 53c776b5 Iustin Pop
5212 53c776b5 Iustin Pop
  def Exec(self, feedback_fn):
5213 53c776b5 Iustin Pop
    """Perform the migration.
5214 53c776b5 Iustin Pop

5215 53c776b5 Iustin Pop
    """
5216 80cb875c Michael Hanselmann
    feedback_fn("Migrating instance %s" % self.instance.name)
5217 80cb875c Michael Hanselmann
5218 53c776b5 Iustin Pop
    self.feedback_fn = feedback_fn
5219 53c776b5 Iustin Pop
5220 53c776b5 Iustin Pop
    self.source_node = self.instance.primary_node
5221 53c776b5 Iustin Pop
    self.target_node = self.instance.secondary_nodes[0]
5222 53c776b5 Iustin Pop
    self.all_nodes = [self.source_node, self.target_node]
5223 53c776b5 Iustin Pop
    self.nodes_ip = {
5224 53c776b5 Iustin Pop
      self.source_node: self.cfg.GetNodeInfo(self.source_node).secondary_ip,
5225 53c776b5 Iustin Pop
      self.target_node: self.cfg.GetNodeInfo(self.target_node).secondary_ip,
5226 53c776b5 Iustin Pop
      }
5227 3e06e001 Michael Hanselmann
5228 3e06e001 Michael Hanselmann
    if self.cleanup:
5229 53c776b5 Iustin Pop
      return self._ExecCleanup()
5230 53c776b5 Iustin Pop
    else:
5231 53c776b5 Iustin Pop
      return self._ExecMigration()
5232 53c776b5 Iustin Pop
5233 53c776b5 Iustin Pop
5234 428958aa Iustin Pop
def _CreateBlockDev(lu, node, instance, device, force_create,
5235 428958aa Iustin Pop
                    info, force_open):
5236 428958aa Iustin Pop
  """Create a tree of block devices on a given node.
5237 a8083063 Iustin Pop

5238 a8083063 Iustin Pop
  If this device type has to be created on secondaries, create it and
5239 a8083063 Iustin Pop
  all its children.
5240 a8083063 Iustin Pop

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

5243 428958aa Iustin Pop
  @param lu: the lu on whose behalf we execute
5244 428958aa Iustin Pop
  @param node: the node on which to create the device
5245 428958aa Iustin Pop
  @type instance: L{objects.Instance}
5246 428958aa Iustin Pop
  @param instance: the instance which owns the device
5247 428958aa Iustin Pop
  @type device: L{objects.Disk}
5248 428958aa Iustin Pop
  @param device: the device to create
5249 428958aa Iustin Pop
  @type force_create: boolean
5250 428958aa Iustin Pop
  @param force_create: whether to force creation of this device; this
5251 428958aa Iustin Pop
      will be change to True whenever we find a device which has
5252 428958aa Iustin Pop
      CreateOnSecondary() attribute
5253 428958aa Iustin Pop
  @param info: the extra 'metadata' we should attach to the device
5254 428958aa Iustin Pop
      (this will be represented as a LVM tag)
5255 428958aa Iustin Pop
  @type force_open: boolean
5256 428958aa Iustin Pop
  @param force_open: this parameter will be passes to the
5257 821d1bd1 Iustin Pop
      L{backend.BlockdevCreate} function where it specifies
5258 428958aa Iustin Pop
      whether we run on primary or not, and it affects both
5259 428958aa Iustin Pop
      the child assembly and the device own Open() execution
5260 428958aa Iustin Pop

5261 a8083063 Iustin Pop
  """
5262 a8083063 Iustin Pop
  if device.CreateOnSecondary():
5263 428958aa Iustin Pop
    force_create = True
5264 796cab27 Iustin Pop
5265 a8083063 Iustin Pop
  if device.children:
5266 a8083063 Iustin Pop
    for child in device.children:
5267 428958aa Iustin Pop
      _CreateBlockDev(lu, node, instance, child, force_create,
5268 428958aa Iustin Pop
                      info, force_open)
5269 a8083063 Iustin Pop
5270 428958aa Iustin Pop
  if not force_create:
5271 796cab27 Iustin Pop
    return
5272 796cab27 Iustin Pop
5273 de12473a Iustin Pop
  _CreateSingleBlockDev(lu, node, instance, device, info, force_open)
5274 de12473a Iustin Pop
5275 de12473a Iustin Pop
5276 de12473a Iustin Pop
def _CreateSingleBlockDev(lu, node, instance, device, info, force_open):
5277 de12473a Iustin Pop
  """Create a single block device on a given node.
5278 de12473a Iustin Pop

5279 de12473a Iustin Pop
  This will not recurse over children of the device, so they must be
5280 de12473a Iustin Pop
  created in advance.
5281 de12473a Iustin Pop

5282 de12473a Iustin Pop
  @param lu: the lu on whose behalf we execute
5283 de12473a Iustin Pop
  @param node: the node on which to create the device
5284 de12473a Iustin Pop
  @type instance: L{objects.Instance}
5285 de12473a Iustin Pop
  @param instance: the instance which owns the device
5286 de12473a Iustin Pop
  @type device: L{objects.Disk}
5287 de12473a Iustin Pop
  @param device: the device to create
5288 de12473a Iustin Pop
  @param info: the extra 'metadata' we should attach to the device
5289 de12473a Iustin Pop
      (this will be represented as a LVM tag)
5290 de12473a Iustin Pop
  @type force_open: boolean
5291 de12473a Iustin Pop
  @param force_open: this parameter will be passes to the
5292 821d1bd1 Iustin Pop
      L{backend.BlockdevCreate} function where it specifies
5293 de12473a Iustin Pop
      whether we run on primary or not, and it affects both
5294 de12473a Iustin Pop
      the child assembly and the device own Open() execution
5295 de12473a Iustin Pop

5296 de12473a Iustin Pop
  """
5297 b9bddb6b Iustin Pop
  lu.cfg.SetDiskID(device, node)
5298 7d81697f Iustin Pop
  result = lu.rpc.call_blockdev_create(node, device, device.size,
5299 428958aa Iustin Pop
                                       instance.name, force_open, info)
5300 4c4e4e1e Iustin Pop
  result.Raise("Can't create block device %s on"
5301 4c4e4e1e Iustin Pop
               " node %s for instance %s" % (device, node, instance.name))
5302 a8083063 Iustin Pop
  if device.physical_id is None:
5303 0959c824 Iustin Pop
    device.physical_id = result.payload
5304 a8083063 Iustin Pop
5305 a8083063 Iustin Pop
5306 b9bddb6b Iustin Pop
def _GenerateUniqueNames(lu, exts):
5307 923b1523 Iustin Pop
  """Generate a suitable LV name.
5308 923b1523 Iustin Pop

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

5311 923b1523 Iustin Pop
  """
5312 923b1523 Iustin Pop
  results = []
5313 923b1523 Iustin Pop
  for val in exts:
5314 4fae38c5 Guido Trotter
    new_id = lu.cfg.GenerateUniqueID(lu.proc.GetECId())
5315 923b1523 Iustin Pop
    results.append("%s%s" % (new_id, val))
5316 923b1523 Iustin Pop
  return results
5317 923b1523 Iustin Pop
5318 923b1523 Iustin Pop
5319 b9bddb6b Iustin Pop
def _GenerateDRBD8Branch(lu, primary, secondary, size, names, iv_name,
5320 ffa1c0dc Iustin Pop
                         p_minor, s_minor):
5321 a1f445d3 Iustin Pop
  """Generate a drbd8 device complete with its children.
5322 a1f445d3 Iustin Pop

5323 a1f445d3 Iustin Pop
  """
5324 b9bddb6b Iustin Pop
  port = lu.cfg.AllocatePort()
5325 b9bddb6b Iustin Pop
  vgname = lu.cfg.GetVGName()
5326 afa1386e Guido Trotter
  shared_secret = lu.cfg.GenerateDRBDSecret(lu.proc.GetECId())
5327 a1f445d3 Iustin Pop
  dev_data = objects.Disk(dev_type=constants.LD_LV, size=size,
5328 a1f445d3 Iustin Pop
                          logical_id=(vgname, names[0]))
5329 a1f445d3 Iustin Pop
  dev_meta = objects.Disk(dev_type=constants.LD_LV, size=128,
5330 a1f445d3 Iustin Pop
                          logical_id=(vgname, names[1]))
5331 a1f445d3 Iustin Pop
  drbd_dev = objects.Disk(dev_type=constants.LD_DRBD8, size=size,
5332 ffa1c0dc Iustin Pop
                          logical_id=(primary, secondary, port,
5333 f9518d38 Iustin Pop
                                      p_minor, s_minor,
5334 f9518d38 Iustin Pop
                                      shared_secret),
5335 ffa1c0dc Iustin Pop
                          children=[dev_data, dev_meta],
5336 a1f445d3 Iustin Pop
                          iv_name=iv_name)
5337 a1f445d3 Iustin Pop
  return drbd_dev
5338 a1f445d3 Iustin Pop
5339 7c0d6283 Michael Hanselmann
5340 b9bddb6b Iustin Pop
def _GenerateDiskTemplate(lu, template_name,
5341 a8083063 Iustin Pop
                          instance_name, primary_node,
5342 08db7c5c Iustin Pop
                          secondary_nodes, disk_info,
5343 e2a65344 Iustin Pop
                          file_storage_dir, file_driver,
5344 e2a65344 Iustin Pop
                          base_index):
5345 a8083063 Iustin Pop
  """Generate the entire disk layout for a given template type.
5346 a8083063 Iustin Pop

5347 a8083063 Iustin Pop
  """
5348 a8083063 Iustin Pop
  #TODO: compute space requirements
5349 a8083063 Iustin Pop
5350 b9bddb6b Iustin Pop
  vgname = lu.cfg.GetVGName()
5351 08db7c5c Iustin Pop
  disk_count = len(disk_info)
5352 08db7c5c Iustin Pop
  disks = []
5353 3517d9b9 Manuel Franceschini
  if template_name == constants.DT_DISKLESS:
5354 08db7c5c Iustin Pop
    pass
5355 3517d9b9 Manuel Franceschini
  elif template_name == constants.DT_PLAIN:
5356 a8083063 Iustin Pop
    if len(secondary_nodes) != 0:
5357 a8083063 Iustin Pop
      raise errors.ProgrammerError("Wrong template configuration")
5358 923b1523 Iustin Pop
5359 fb4b324b Guido Trotter
    names = _GenerateUniqueNames(lu, [".disk%d" % (base_index + i)
5360 08db7c5c Iustin Pop
                                      for i in range(disk_count)])
5361 08db7c5c Iustin Pop
    for idx, disk in enumerate(disk_info):
5362 e2a65344 Iustin Pop
      disk_index = idx + base_index
5363 08db7c5c Iustin Pop
      disk_dev = objects.Disk(dev_type=constants.LD_LV, size=disk["size"],
5364 08db7c5c Iustin Pop
                              logical_id=(vgname, names[idx]),
5365 6ec66eae Iustin Pop
                              iv_name="disk/%d" % disk_index,
5366 6ec66eae Iustin Pop
                              mode=disk["mode"])
5367 08db7c5c Iustin Pop
      disks.append(disk_dev)
5368 a1f445d3 Iustin Pop
  elif template_name == constants.DT_DRBD8:
5369 a1f445d3 Iustin Pop
    if len(secondary_nodes) != 1:
5370 a1f445d3 Iustin Pop
      raise errors.ProgrammerError("Wrong template configuration")
5371 a1f445d3 Iustin Pop
    remote_node = secondary_nodes[0]
5372 08db7c5c Iustin Pop
    minors = lu.cfg.AllocateDRBDMinor(
5373 08db7c5c Iustin Pop
      [primary_node, remote_node] * len(disk_info), instance_name)
5374 08db7c5c Iustin Pop
5375 e6c1ff2f Iustin Pop
    names = []
5376 fb4b324b Guido Trotter
    for lv_prefix in _GenerateUniqueNames(lu, [".disk%d" % (base_index + i)
5377 e6c1ff2f Iustin Pop
                                               for i in range(disk_count)]):
5378 e6c1ff2f Iustin Pop
      names.append(lv_prefix + "_data")
5379 e6c1ff2f Iustin Pop
      names.append(lv_prefix + "_meta")
5380 08db7c5c Iustin Pop
    for idx, disk in enumerate(disk_info):
5381 112050d9 Iustin Pop
      disk_index = idx + base_index
5382 08db7c5c Iustin Pop
      disk_dev = _GenerateDRBD8Branch(lu, primary_node, remote_node,
5383 08db7c5c Iustin Pop
                                      disk["size"], names[idx*2:idx*2+2],
5384 e2a65344 Iustin Pop
                                      "disk/%d" % disk_index,
5385 08db7c5c Iustin Pop
                                      minors[idx*2], minors[idx*2+1])
5386 6ec66eae Iustin Pop
      disk_dev.mode = disk["mode"]
5387 08db7c5c Iustin Pop
      disks.append(disk_dev)
5388 0f1a06e3 Manuel Franceschini
  elif template_name == constants.DT_FILE:
5389 0f1a06e3 Manuel Franceschini
    if len(secondary_nodes) != 0:
5390 0f1a06e3 Manuel Franceschini
      raise errors.ProgrammerError("Wrong template configuration")
5391 0f1a06e3 Manuel Franceschini
5392 08db7c5c Iustin Pop
    for idx, disk in enumerate(disk_info):
5393 112050d9 Iustin Pop
      disk_index = idx + base_index
5394 08db7c5c Iustin Pop
      disk_dev = objects.Disk(dev_type=constants.LD_FILE, size=disk["size"],
5395 e2a65344 Iustin Pop
                              iv_name="disk/%d" % disk_index,
5396 08db7c5c Iustin Pop
                              logical_id=(file_driver,
5397 08db7c5c Iustin Pop
                                          "%s/disk%d" % (file_storage_dir,
5398 43e99cff Guido Trotter
                                                         disk_index)),
5399 6ec66eae Iustin Pop
                              mode=disk["mode"])
5400 08db7c5c Iustin Pop
      disks.append(disk_dev)
5401 a8083063 Iustin Pop
  else:
5402 a8083063 Iustin Pop
    raise errors.ProgrammerError("Invalid disk template '%s'" % template_name)
5403 a8083063 Iustin Pop
  return disks
5404 a8083063 Iustin Pop
5405 a8083063 Iustin Pop
5406 a0c3fea1 Michael Hanselmann
def _GetInstanceInfoText(instance):
5407 3ecf6786 Iustin Pop
  """Compute that text that should be added to the disk's metadata.
5408 3ecf6786 Iustin Pop

5409 3ecf6786 Iustin Pop
  """
5410 a0c3fea1 Michael Hanselmann
  return "originstname+%s" % instance.name
5411 a0c3fea1 Michael Hanselmann
5412 a0c3fea1 Michael Hanselmann
5413 621b7678 Iustin Pop
def _CreateDisks(lu, instance, to_skip=None, target_node=None):
5414 a8083063 Iustin Pop
  """Create all disks for an instance.
5415 a8083063 Iustin Pop

5416 a8083063 Iustin Pop
  This abstracts away some work from AddInstance.
5417 a8083063 Iustin Pop

5418 e4376078 Iustin Pop
  @type lu: L{LogicalUnit}
5419 e4376078 Iustin Pop
  @param lu: the logical unit on whose behalf we execute
5420 e4376078 Iustin Pop
  @type instance: L{objects.Instance}
5421 e4376078 Iustin Pop
  @param instance: the instance whose disks we should create
5422 bd315bfa Iustin Pop
  @type to_skip: list
5423 bd315bfa Iustin Pop
  @param to_skip: list of indices to skip
5424 621b7678 Iustin Pop
  @type target_node: string
5425 621b7678 Iustin Pop
  @param target_node: if passed, overrides the target node for creation
5426 e4376078 Iustin Pop
  @rtype: boolean
5427 e4376078 Iustin Pop
  @return: the success of the creation
5428 a8083063 Iustin Pop

5429 a8083063 Iustin Pop
  """
5430 a0c3fea1 Michael Hanselmann
  info = _GetInstanceInfoText(instance)
5431 621b7678 Iustin Pop
  if target_node is None:
5432 621b7678 Iustin Pop
    pnode = instance.primary_node
5433 621b7678 Iustin Pop
    all_nodes = instance.all_nodes
5434 621b7678 Iustin Pop
  else:
5435 621b7678 Iustin Pop
    pnode = target_node
5436 621b7678 Iustin Pop
    all_nodes = [pnode]
5437 a0c3fea1 Michael Hanselmann
5438 0f1a06e3 Manuel Franceschini
  if instance.disk_template == constants.DT_FILE:
5439 0f1a06e3 Manuel Franceschini
    file_storage_dir = os.path.dirname(instance.disks[0].logical_id[1])
5440 428958aa Iustin Pop
    result = lu.rpc.call_file_storage_dir_create(pnode, file_storage_dir)
5441 0f1a06e3 Manuel Franceschini
5442 4c4e4e1e Iustin Pop
    result.Raise("Failed to create directory '%s' on"
5443 9b4127eb Guido Trotter
                 " node %s" % (file_storage_dir, pnode))
5444 0f1a06e3 Manuel Franceschini
5445 24991749 Iustin Pop
  # Note: this needs to be kept in sync with adding of disks in
5446 24991749 Iustin Pop
  # LUSetInstanceParams
5447 bd315bfa Iustin Pop
  for idx, device in enumerate(instance.disks):
5448 bd315bfa Iustin Pop
    if to_skip and idx in to_skip:
5449 bd315bfa Iustin Pop
      continue
5450 9a4f63d1 Iustin Pop
    logging.info("Creating volume %s for instance %s",
5451 9a4f63d1 Iustin Pop
                 device.iv_name, instance.name)
5452 a8083063 Iustin Pop
    #HARDCODE
5453 621b7678 Iustin Pop
    for node in all_nodes:
5454 428958aa Iustin Pop
      f_create = node == pnode
5455 428958aa Iustin Pop
      _CreateBlockDev(lu, node, instance, device, f_create, info, f_create)
5456 a8083063 Iustin Pop
5457 a8083063 Iustin Pop
5458 621b7678 Iustin Pop
def _RemoveDisks(lu, instance, target_node=None):
5459 a8083063 Iustin Pop
  """Remove all disks for an instance.
5460 a8083063 Iustin Pop

5461 a8083063 Iustin Pop
  This abstracts away some work from `AddInstance()` and
5462 a8083063 Iustin Pop
  `RemoveInstance()`. Note that in case some of the devices couldn't
5463 1d67656e Iustin Pop
  be removed, the removal will continue with the other ones (compare
5464 a8083063 Iustin Pop
  with `_CreateDisks()`).
5465 a8083063 Iustin Pop

5466 e4376078 Iustin Pop
  @type lu: L{LogicalUnit}
5467 e4376078 Iustin Pop
  @param lu: the logical unit on whose behalf we execute
5468 e4376078 Iustin Pop
  @type instance: L{objects.Instance}
5469 e4376078 Iustin Pop
  @param instance: the instance whose disks we should remove
5470 621b7678 Iustin Pop
  @type target_node: string
5471 621b7678 Iustin Pop
  @param target_node: used to override the node on which to remove the disks
5472 e4376078 Iustin Pop
  @rtype: boolean
5473 e4376078 Iustin Pop
  @return: the success of the removal
5474 a8083063 Iustin Pop

5475 a8083063 Iustin Pop
  """
5476 9a4f63d1 Iustin Pop
  logging.info("Removing block devices for instance %s", instance.name)
5477 a8083063 Iustin Pop
5478 e1bc0878 Iustin Pop
  all_result = True
5479 a8083063 Iustin Pop
  for device in instance.disks:
5480 621b7678 Iustin Pop
    if target_node:
5481 621b7678 Iustin Pop
      edata = [(target_node, device)]
5482 621b7678 Iustin Pop
    else:
5483 621b7678 Iustin Pop
      edata = device.ComputeNodeTree(instance.primary_node)
5484 621b7678 Iustin Pop
    for node, disk in edata:
5485 b9bddb6b Iustin Pop
      lu.cfg.SetDiskID(disk, node)
5486 4c4e4e1e Iustin Pop
      msg = lu.rpc.call_blockdev_remove(node, disk).fail_msg
5487 e1bc0878 Iustin Pop
      if msg:
5488 e1bc0878 Iustin Pop
        lu.LogWarning("Could not remove block device %s on node %s,"
5489 e1bc0878 Iustin Pop
                      " continuing anyway: %s", device.iv_name, node, msg)
5490 e1bc0878 Iustin Pop
        all_result = False
5491 0f1a06e3 Manuel Franceschini
5492 0f1a06e3 Manuel Franceschini
  if instance.disk_template == constants.DT_FILE:
5493 0f1a06e3 Manuel Franceschini
    file_storage_dir = os.path.dirname(instance.disks[0].logical_id[1])
5494 dfc2a24c Guido Trotter
    if target_node:
5495 dfc2a24c Guido Trotter
      tgt = target_node
5496 621b7678 Iustin Pop
    else:
5497 dfc2a24c Guido Trotter
      tgt = instance.primary_node
5498 621b7678 Iustin Pop
    result = lu.rpc.call_file_storage_dir_remove(tgt, file_storage_dir)
5499 621b7678 Iustin Pop
    if result.fail_msg:
5500 b2b8bcce Iustin Pop
      lu.LogWarning("Could not remove directory '%s' on node %s: %s",
5501 621b7678 Iustin Pop
                    file_storage_dir, instance.primary_node, result.fail_msg)
5502 e1bc0878 Iustin Pop
      all_result = False
5503 0f1a06e3 Manuel Franceschini
5504 e1bc0878 Iustin Pop
  return all_result
5505 a8083063 Iustin Pop
5506 a8083063 Iustin Pop
5507 08db7c5c Iustin Pop
def _ComputeDiskSize(disk_template, disks):
5508 e2fe6369 Iustin Pop
  """Compute disk size requirements in the volume group
5509 e2fe6369 Iustin Pop

5510 e2fe6369 Iustin Pop
  """
5511 e2fe6369 Iustin Pop
  # Required free disk space as a function of disk and swap space
5512 e2fe6369 Iustin Pop
  req_size_dict = {
5513 e2fe6369 Iustin Pop
    constants.DT_DISKLESS: None,
5514 08db7c5c Iustin Pop
    constants.DT_PLAIN: sum(d["size"] for d in disks),
5515 08db7c5c Iustin Pop
    # 128 MB are added for drbd metadata for each disk
5516 08db7c5c Iustin Pop
    constants.DT_DRBD8: sum(d["size"] + 128 for d in disks),
5517 e2fe6369 Iustin Pop
    constants.DT_FILE: None,
5518 e2fe6369 Iustin Pop
  }
5519 e2fe6369 Iustin Pop
5520 e2fe6369 Iustin Pop
  if disk_template not in req_size_dict:
5521 e2fe6369 Iustin Pop
    raise errors.ProgrammerError("Disk template '%s' size requirement"
5522 e2fe6369 Iustin Pop
                                 " is unknown" %  disk_template)
5523 e2fe6369 Iustin Pop
5524 e2fe6369 Iustin Pop
  return req_size_dict[disk_template]
5525 e2fe6369 Iustin Pop
5526 e2fe6369 Iustin Pop
5527 74409b12 Iustin Pop
def _CheckHVParams(lu, nodenames, hvname, hvparams):
5528 74409b12 Iustin Pop
  """Hypervisor parameter validation.
5529 74409b12 Iustin Pop

5530 74409b12 Iustin Pop
  This function abstract the hypervisor parameter validation to be
5531 74409b12 Iustin Pop
  used in both instance create and instance modify.
5532 74409b12 Iustin Pop

5533 74409b12 Iustin Pop
  @type lu: L{LogicalUnit}
5534 74409b12 Iustin Pop
  @param lu: the logical unit for which we check
5535 74409b12 Iustin Pop
  @type nodenames: list
5536 74409b12 Iustin Pop
  @param nodenames: the list of nodes on which we should check
5537 74409b12 Iustin Pop
  @type hvname: string
5538 74409b12 Iustin Pop
  @param hvname: the name of the hypervisor we should use
5539 74409b12 Iustin Pop
  @type hvparams: dict
5540 74409b12 Iustin Pop
  @param hvparams: the parameters which we need to check
5541 74409b12 Iustin Pop
  @raise errors.OpPrereqError: if the parameters are not valid
5542 74409b12 Iustin Pop

5543 74409b12 Iustin Pop
  """
5544 74409b12 Iustin Pop
  hvinfo = lu.rpc.call_hypervisor_validate_params(nodenames,
5545 74409b12 Iustin Pop
                                                  hvname,
5546 74409b12 Iustin Pop
                                                  hvparams)
5547 74409b12 Iustin Pop
  for node in nodenames:
5548 781de953 Iustin Pop
    info = hvinfo[node]
5549 68c6f21c Iustin Pop
    if info.offline:
5550 68c6f21c Iustin Pop
      continue
5551 4c4e4e1e Iustin Pop
    info.Raise("Hypervisor parameter validation failed on node %s" % node)
5552 74409b12 Iustin Pop
5553 74409b12 Iustin Pop
5554 a8083063 Iustin Pop
class LUCreateInstance(LogicalUnit):
5555 a8083063 Iustin Pop
  """Create an instance.
5556 a8083063 Iustin Pop

5557 a8083063 Iustin Pop
  """
5558 a8083063 Iustin Pop
  HPATH = "instance-add"
5559 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
5560 08db7c5c Iustin Pop
  _OP_REQP = ["instance_name", "disks", "disk_template",
5561 08db7c5c Iustin Pop
              "mode", "start",
5562 08db7c5c Iustin Pop
              "wait_for_sync", "ip_check", "nics",
5563 338e51e8 Iustin Pop
              "hvparams", "beparams"]
5564 7baf741d Guido Trotter
  REQ_BGL = False
5565 7baf741d Guido Trotter
5566 7baf741d Guido Trotter
  def _ExpandNode(self, node):
5567 7baf741d Guido Trotter
    """Expands and checks one node name.
5568 7baf741d Guido Trotter

5569 7baf741d Guido Trotter
    """
5570 7baf741d Guido Trotter
    node_full = self.cfg.ExpandNodeName(node)
5571 7baf741d Guido Trotter
    if node_full is None:
5572 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Unknown node %s" % node, errors.ECODE_NOENT)
5573 7baf741d Guido Trotter
    return node_full
5574 7baf741d Guido Trotter
5575 7baf741d Guido Trotter
  def ExpandNames(self):
5576 7baf741d Guido Trotter
    """ExpandNames for CreateInstance.
5577 7baf741d Guido Trotter

5578 7baf741d Guido Trotter
    Figure out the right locks for instance creation.
5579 7baf741d Guido Trotter

5580 7baf741d Guido Trotter
    """
5581 7baf741d Guido Trotter
    self.needed_locks = {}
5582 7baf741d Guido Trotter
5583 7baf741d Guido Trotter
    # set optional parameters to none if they don't exist
5584 6785674e Iustin Pop
    for attr in ["pnode", "snode", "iallocator", "hypervisor"]:
5585 7baf741d Guido Trotter
      if not hasattr(self.op, attr):
5586 7baf741d Guido Trotter
        setattr(self.op, attr, None)
5587 7baf741d Guido Trotter
5588 4b2f38dd Iustin Pop
    # cheap checks, mostly valid constants given
5589 4b2f38dd Iustin Pop
5590 7baf741d Guido Trotter
    # verify creation mode
5591 7baf741d Guido Trotter
    if self.op.mode not in (constants.INSTANCE_CREATE,
5592 7baf741d Guido Trotter
                            constants.INSTANCE_IMPORT):
5593 7baf741d Guido Trotter
      raise errors.OpPrereqError("Invalid instance creation mode '%s'" %
5594 5c983ee5 Iustin Pop
                                 self.op.mode, errors.ECODE_INVAL)
5595 4b2f38dd Iustin Pop
5596 7baf741d Guido Trotter
    # disk template and mirror node verification
5597 7baf741d Guido Trotter
    if self.op.disk_template not in constants.DISK_TEMPLATES:
5598 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Invalid disk template name",
5599 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
5600 7baf741d Guido Trotter
5601 4b2f38dd Iustin Pop
    if self.op.hypervisor is None:
5602 4b2f38dd Iustin Pop
      self.op.hypervisor = self.cfg.GetHypervisorType()
5603 4b2f38dd Iustin Pop
5604 8705eb96 Iustin Pop
    cluster = self.cfg.GetClusterInfo()
5605 8705eb96 Iustin Pop
    enabled_hvs = cluster.enabled_hypervisors
5606 4b2f38dd Iustin Pop
    if self.op.hypervisor not in enabled_hvs:
5607 4b2f38dd Iustin Pop
      raise errors.OpPrereqError("Selected hypervisor (%s) not enabled in the"
5608 4b2f38dd Iustin Pop
                                 " cluster (%s)" % (self.op.hypervisor,
5609 5c983ee5 Iustin Pop
                                  ",".join(enabled_hvs)),
5610 5c983ee5 Iustin Pop
                                 errors.ECODE_STATE)
5611 4b2f38dd Iustin Pop
5612 6785674e Iustin Pop
    # check hypervisor parameter syntax (locally)
5613 a5728081 Guido Trotter
    utils.ForceDictType(self.op.hvparams, constants.HVS_PARAMETER_TYPES)
5614 abe609b2 Guido Trotter
    filled_hvp = objects.FillDict(cluster.hvparams[self.op.hypervisor],
5615 8705eb96 Iustin Pop
                                  self.op.hvparams)
5616 6785674e Iustin Pop
    hv_type = hypervisor.GetHypervisor(self.op.hypervisor)
5617 8705eb96 Iustin Pop
    hv_type.CheckParameterSyntax(filled_hvp)
5618 67fc3042 Iustin Pop
    self.hv_full = filled_hvp
5619 7736a5f2 Iustin Pop
    # check that we don't specify global parameters on an instance
5620 7736a5f2 Iustin Pop
    _CheckGlobalHvParams(self.op.hvparams)
5621 6785674e Iustin Pop
5622 338e51e8 Iustin Pop
    # fill and remember the beparams dict
5623 a5728081 Guido Trotter
    utils.ForceDictType(self.op.beparams, constants.BES_PARAMETER_TYPES)
5624 4ef7f423 Guido Trotter
    self.be_full = objects.FillDict(cluster.beparams[constants.PP_DEFAULT],
5625 338e51e8 Iustin Pop
                                    self.op.beparams)
5626 338e51e8 Iustin Pop
5627 7baf741d Guido Trotter
    #### instance parameters check
5628 7baf741d Guido Trotter
5629 7baf741d Guido Trotter
    # instance name verification
5630 104f4ca1 Iustin Pop
    hostname1 = utils.GetHostInfo(self.op.instance_name)
5631 7baf741d Guido Trotter
    self.op.instance_name = instance_name = hostname1.name
5632 7baf741d Guido Trotter
5633 7baf741d Guido Trotter
    # this is just a preventive check, but someone might still add this
5634 7baf741d Guido Trotter
    # instance in the meantime, and creation will fail at lock-add time
5635 7baf741d Guido Trotter
    if instance_name in self.cfg.GetInstanceList():
5636 7baf741d Guido Trotter
      raise errors.OpPrereqError("Instance '%s' is already in the cluster" %
5637 5c983ee5 Iustin Pop
                                 instance_name, errors.ECODE_EXISTS)
5638 7baf741d Guido Trotter
5639 7baf741d Guido Trotter
    self.add_locks[locking.LEVEL_INSTANCE] = instance_name
5640 7baf741d Guido Trotter
5641 08db7c5c Iustin Pop
    # NIC buildup
5642 08db7c5c Iustin Pop
    self.nics = []
5643 9dce4771 Guido Trotter
    for idx, nic in enumerate(self.op.nics):
5644 9dce4771 Guido Trotter
      nic_mode_req = nic.get("mode", None)
5645 9dce4771 Guido Trotter
      nic_mode = nic_mode_req
5646 9dce4771 Guido Trotter
      if nic_mode is None:
5647 9dce4771 Guido Trotter
        nic_mode = cluster.nicparams[constants.PP_DEFAULT][constants.NIC_MODE]
5648 9dce4771 Guido Trotter
5649 9dce4771 Guido Trotter
      # in routed mode, for the first nic, the default ip is 'auto'
5650 9dce4771 Guido Trotter
      if nic_mode == constants.NIC_MODE_ROUTED and idx == 0:
5651 9dce4771 Guido Trotter
        default_ip_mode = constants.VALUE_AUTO
5652 9dce4771 Guido Trotter
      else:
5653 9dce4771 Guido Trotter
        default_ip_mode = constants.VALUE_NONE
5654 9dce4771 Guido Trotter
5655 08db7c5c Iustin Pop
      # ip validity checks
5656 9dce4771 Guido Trotter
      ip = nic.get("ip", default_ip_mode)
5657 9dce4771 Guido Trotter
      if ip is None or ip.lower() == constants.VALUE_NONE:
5658 08db7c5c Iustin Pop
        nic_ip = None
5659 08db7c5c Iustin Pop
      elif ip.lower() == constants.VALUE_AUTO:
5660 08db7c5c Iustin Pop
        nic_ip = hostname1.ip
5661 08db7c5c Iustin Pop
      else:
5662 08db7c5c Iustin Pop
        if not utils.IsValidIP(ip):
5663 08db7c5c Iustin Pop
          raise errors.OpPrereqError("Given IP address '%s' doesn't look"
5664 5c983ee5 Iustin Pop
                                     " like a valid IP" % ip,
5665 5c983ee5 Iustin Pop
                                     errors.ECODE_INVAL)
5666 08db7c5c Iustin Pop
        nic_ip = ip
5667 08db7c5c Iustin Pop
5668 9dce4771 Guido Trotter
      # TODO: check the ip for uniqueness !!
5669 9dce4771 Guido Trotter
      if nic_mode == constants.NIC_MODE_ROUTED and not nic_ip:
5670 5c983ee5 Iustin Pop
        raise errors.OpPrereqError("Routed nic mode requires an ip address",
5671 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
5672 9dce4771 Guido Trotter
5673 08db7c5c Iustin Pop
      # MAC address verification
5674 08db7c5c Iustin Pop
      mac = nic.get("mac", constants.VALUE_AUTO)
5675 08db7c5c Iustin Pop
      if mac not in (constants.VALUE_AUTO, constants.VALUE_GENERATE):
5676 08db7c5c Iustin Pop
        if not utils.IsValidMac(mac.lower()):
5677 08db7c5c Iustin Pop
          raise errors.OpPrereqError("Invalid MAC address specified: %s" %
5678 5c983ee5 Iustin Pop
                                     mac, errors.ECODE_INVAL)
5679 87e43988 Iustin Pop
        else:
5680 36b66e6e Guido Trotter
          try:
5681 36b66e6e Guido Trotter
            self.cfg.ReserveMAC(mac, self.proc.GetECId())
5682 36b66e6e Guido Trotter
          except errors.ReservationError:
5683 87e43988 Iustin Pop
            raise errors.OpPrereqError("MAC address %s already in use"
5684 5c983ee5 Iustin Pop
                                       " in cluster" % mac,
5685 5c983ee5 Iustin Pop
                                       errors.ECODE_NOTUNIQUE)
5686 87e43988 Iustin Pop
5687 08db7c5c Iustin Pop
      # bridge verification
5688 9939547b Iustin Pop
      bridge = nic.get("bridge", None)
5689 9dce4771 Guido Trotter
      link = nic.get("link", None)
5690 9dce4771 Guido Trotter
      if bridge and link:
5691 29921401 Iustin Pop
        raise errors.OpPrereqError("Cannot pass 'bridge' and 'link'"
5692 5c983ee5 Iustin Pop
                                   " at the same time", errors.ECODE_INVAL)
5693 9dce4771 Guido Trotter
      elif bridge and nic_mode == constants.NIC_MODE_ROUTED:
5694 5c983ee5 Iustin Pop
        raise errors.OpPrereqError("Cannot pass 'bridge' on a routed nic",
5695 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
5696 9dce4771 Guido Trotter
      elif bridge:
5697 9dce4771 Guido Trotter
        link = bridge
5698 9dce4771 Guido Trotter
5699 9dce4771 Guido Trotter
      nicparams = {}
5700 9dce4771 Guido Trotter
      if nic_mode_req:
5701 9dce4771 Guido Trotter
        nicparams[constants.NIC_MODE] = nic_mode_req
5702 9dce4771 Guido Trotter
      if link:
5703 9dce4771 Guido Trotter
        nicparams[constants.NIC_LINK] = link
5704 9dce4771 Guido Trotter
5705 9dce4771 Guido Trotter
      check_params = objects.FillDict(cluster.nicparams[constants.PP_DEFAULT],
5706 9dce4771 Guido Trotter
                                      nicparams)
5707 9dce4771 Guido Trotter
      objects.NIC.CheckParameterSyntax(check_params)
5708 9dce4771 Guido Trotter
      self.nics.append(objects.NIC(mac=mac, ip=nic_ip, nicparams=nicparams))
5709 08db7c5c Iustin Pop
5710 08db7c5c Iustin Pop
    # disk checks/pre-build
5711 08db7c5c Iustin Pop
    self.disks = []
5712 08db7c5c Iustin Pop
    for disk in self.op.disks:
5713 08db7c5c Iustin Pop
      mode = disk.get("mode", constants.DISK_RDWR)
5714 08db7c5c Iustin Pop
      if mode not in constants.DISK_ACCESS_SET:
5715 08db7c5c Iustin Pop
        raise errors.OpPrereqError("Invalid disk access mode '%s'" %
5716 5c983ee5 Iustin Pop
                                   mode, errors.ECODE_INVAL)
5717 08db7c5c Iustin Pop
      size = disk.get("size", None)
5718 08db7c5c Iustin Pop
      if size is None:
5719 5c983ee5 Iustin Pop
        raise errors.OpPrereqError("Missing disk size", errors.ECODE_INVAL)
5720 08db7c5c Iustin Pop
      try:
5721 08db7c5c Iustin Pop
        size = int(size)
5722 08db7c5c Iustin Pop
      except ValueError:
5723 5c983ee5 Iustin Pop
        raise errors.OpPrereqError("Invalid disk size '%s'" % size,
5724 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
5725 08db7c5c Iustin Pop
      self.disks.append({"size": size, "mode": mode})
5726 08db7c5c Iustin Pop
5727 7baf741d Guido Trotter
    # used in CheckPrereq for ip ping check
5728 7baf741d Guido Trotter
    self.check_ip = hostname1.ip
5729 7baf741d Guido Trotter
5730 7baf741d Guido Trotter
    # file storage checks
5731 7baf741d Guido Trotter
    if (self.op.file_driver and
5732 7baf741d Guido Trotter
        not self.op.file_driver in constants.FILE_DRIVER):
5733 7baf741d Guido Trotter
      raise errors.OpPrereqError("Invalid file driver name '%s'" %
5734 5c983ee5 Iustin Pop
                                 self.op.file_driver, errors.ECODE_INVAL)
5735 7baf741d Guido Trotter
5736 7baf741d Guido Trotter
    if self.op.file_storage_dir and os.path.isabs(self.op.file_storage_dir):
5737 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("File storage directory path not absolute",
5738 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
5739 7baf741d Guido Trotter
5740 7baf741d Guido Trotter
    ### Node/iallocator related checks
5741 7baf741d Guido Trotter
    if [self.op.iallocator, self.op.pnode].count(None) != 1:
5742 7baf741d Guido Trotter
      raise errors.OpPrereqError("One and only one of iallocator and primary"
5743 5c983ee5 Iustin Pop
                                 " node must be given",
5744 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
5745 7baf741d Guido Trotter
5746 7baf741d Guido Trotter
    if self.op.iallocator:
5747 7baf741d Guido Trotter
      self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
5748 7baf741d Guido Trotter
    else:
5749 7baf741d Guido Trotter
      self.op.pnode = self._ExpandNode(self.op.pnode)
5750 7baf741d Guido Trotter
      nodelist = [self.op.pnode]
5751 7baf741d Guido Trotter
      if self.op.snode is not None:
5752 7baf741d Guido Trotter
        self.op.snode = self._ExpandNode(self.op.snode)
5753 7baf741d Guido Trotter
        nodelist.append(self.op.snode)
5754 7baf741d Guido Trotter
      self.needed_locks[locking.LEVEL_NODE] = nodelist
5755 7baf741d Guido Trotter
5756 7baf741d Guido Trotter
    # in case of import lock the source node too
5757 7baf741d Guido Trotter
    if self.op.mode == constants.INSTANCE_IMPORT:
5758 7baf741d Guido Trotter
      src_node = getattr(self.op, "src_node", None)
5759 7baf741d Guido Trotter
      src_path = getattr(self.op, "src_path", None)
5760 7baf741d Guido Trotter
5761 b9322a9f Guido Trotter
      if src_path is None:
5762 b9322a9f Guido Trotter
        self.op.src_path = src_path = self.op.instance_name
5763 b9322a9f Guido Trotter
5764 b9322a9f Guido Trotter
      if src_node is None:
5765 b9322a9f Guido Trotter
        self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
5766 b9322a9f Guido Trotter
        self.op.src_node = None
5767 b9322a9f Guido Trotter
        if os.path.isabs(src_path):
5768 b9322a9f Guido Trotter
          raise errors.OpPrereqError("Importing an instance from an absolute"
5769 5c983ee5 Iustin Pop
                                     " path requires a source node option.",
5770 5c983ee5 Iustin Pop
                                     errors.ECODE_INVAL)
5771 b9322a9f Guido Trotter
      else:
5772 b9322a9f Guido Trotter
        self.op.src_node = src_node = self._ExpandNode(src_node)
5773 b9322a9f Guido Trotter
        if self.needed_locks[locking.LEVEL_NODE] is not locking.ALL_SET:
5774 b9322a9f Guido Trotter
          self.needed_locks[locking.LEVEL_NODE].append(src_node)
5775 b9322a9f Guido Trotter
        if not os.path.isabs(src_path):
5776 b9322a9f Guido Trotter
          self.op.src_path = src_path = \
5777 b9322a9f Guido Trotter
            os.path.join(constants.EXPORT_DIR, src_path)
5778 7baf741d Guido Trotter
5779 f2c05717 Guido Trotter
      # On import force_variant must be True, because if we forced it at
5780 f2c05717 Guido Trotter
      # initial install, our only chance when importing it back is that it
5781 f2c05717 Guido Trotter
      # works again!
5782 f2c05717 Guido Trotter
      self.op.force_variant = True
5783 f2c05717 Guido Trotter
5784 7baf741d Guido Trotter
    else: # INSTANCE_CREATE
5785 7baf741d Guido Trotter
      if getattr(self.op, "os_type", None) is None:
5786 5c983ee5 Iustin Pop
        raise errors.OpPrereqError("No guest OS specified",
5787 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
5788 f2c05717 Guido Trotter
      self.op.force_variant = getattr(self.op, "force_variant", False)
5789 a8083063 Iustin Pop
5790 538475ca Iustin Pop
  def _RunAllocator(self):
5791 538475ca Iustin Pop
    """Run the allocator based on input opcode.
5792 538475ca Iustin Pop

5793 538475ca Iustin Pop
    """
5794 08db7c5c Iustin Pop
    nics = [n.ToDict() for n in self.nics]
5795 923ddac0 Michael Hanselmann
    ial = IAllocator(self.cfg, self.rpc,
5796 29859cb7 Iustin Pop
                     mode=constants.IALLOCATOR_MODE_ALLOC,
5797 d1c2dd75 Iustin Pop
                     name=self.op.instance_name,
5798 d1c2dd75 Iustin Pop
                     disk_template=self.op.disk_template,
5799 d1c2dd75 Iustin Pop
                     tags=[],
5800 d1c2dd75 Iustin Pop
                     os=self.op.os_type,
5801 338e51e8 Iustin Pop
                     vcpus=self.be_full[constants.BE_VCPUS],
5802 338e51e8 Iustin Pop
                     mem_size=self.be_full[constants.BE_MEMORY],
5803 08db7c5c Iustin Pop
                     disks=self.disks,
5804 d1c2dd75 Iustin Pop
                     nics=nics,
5805 8cc7e742 Guido Trotter
                     hypervisor=self.op.hypervisor,
5806 29859cb7 Iustin Pop
                     )
5807 d1c2dd75 Iustin Pop
5808 d1c2dd75 Iustin Pop
    ial.Run(self.op.iallocator)
5809 d1c2dd75 Iustin Pop
5810 d1c2dd75 Iustin Pop
    if not ial.success:
5811 538475ca Iustin Pop
      raise errors.OpPrereqError("Can't compute nodes using"
5812 5c983ee5 Iustin Pop
                                 " iallocator '%s': %s" %
5813 5c983ee5 Iustin Pop
                                 (self.op.iallocator, ial.info),
5814 5c983ee5 Iustin Pop
                                 errors.ECODE_NORES)
5815 27579978 Iustin Pop
    if len(ial.nodes) != ial.required_nodes:
5816 538475ca Iustin Pop
      raise errors.OpPrereqError("iallocator '%s' returned invalid number"
5817 538475ca Iustin Pop
                                 " of nodes (%s), required %s" %
5818 97abc79f Iustin Pop
                                 (self.op.iallocator, len(ial.nodes),
5819 5c983ee5 Iustin Pop
                                  ial.required_nodes), errors.ECODE_FAULT)
5820 d1c2dd75 Iustin Pop
    self.op.pnode = ial.nodes[0]
5821 86d9d3bb Iustin Pop
    self.LogInfo("Selected nodes for instance %s via iallocator %s: %s",
5822 86d9d3bb Iustin Pop
                 self.op.instance_name, self.op.iallocator,
5823 86d9d3bb Iustin Pop
                 ", ".join(ial.nodes))
5824 27579978 Iustin Pop
    if ial.required_nodes == 2:
5825 d1c2dd75 Iustin Pop
      self.op.snode = ial.nodes[1]
5826 538475ca Iustin Pop
5827 a8083063 Iustin Pop
  def BuildHooksEnv(self):
5828 a8083063 Iustin Pop
    """Build hooks env.
5829 a8083063 Iustin Pop

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

5832 a8083063 Iustin Pop
    """
5833 a8083063 Iustin Pop
    env = {
5834 2c2690c9 Iustin Pop
      "ADD_MODE": self.op.mode,
5835 a8083063 Iustin Pop
      }
5836 a8083063 Iustin Pop
    if self.op.mode == constants.INSTANCE_IMPORT:
5837 2c2690c9 Iustin Pop
      env["SRC_NODE"] = self.op.src_node
5838 2c2690c9 Iustin Pop
      env["SRC_PATH"] = self.op.src_path
5839 2c2690c9 Iustin Pop
      env["SRC_IMAGES"] = self.src_images
5840 396e1b78 Michael Hanselmann
5841 2c2690c9 Iustin Pop
    env.update(_BuildInstanceHookEnv(
5842 2c2690c9 Iustin Pop
      name=self.op.instance_name,
5843 396e1b78 Michael Hanselmann
      primary_node=self.op.pnode,
5844 396e1b78 Michael Hanselmann
      secondary_nodes=self.secondaries,
5845 4978db17 Iustin Pop
      status=self.op.start,
5846 ecb215b5 Michael Hanselmann
      os_type=self.op.os_type,
5847 338e51e8 Iustin Pop
      memory=self.be_full[constants.BE_MEMORY],
5848 338e51e8 Iustin Pop
      vcpus=self.be_full[constants.BE_VCPUS],
5849 f9b10246 Guido Trotter
      nics=_NICListToTuple(self, self.nics),
5850 2c2690c9 Iustin Pop
      disk_template=self.op.disk_template,
5851 2c2690c9 Iustin Pop
      disks=[(d["size"], d["mode"]) for d in self.disks],
5852 67fc3042 Iustin Pop
      bep=self.be_full,
5853 67fc3042 Iustin Pop
      hvp=self.hv_full,
5854 3df6e710 Iustin Pop
      hypervisor_name=self.op.hypervisor,
5855 396e1b78 Michael Hanselmann
    ))
5856 a8083063 Iustin Pop
5857 d6a02168 Michael Hanselmann
    nl = ([self.cfg.GetMasterNode(), self.op.pnode] +
5858 a8083063 Iustin Pop
          self.secondaries)
5859 a8083063 Iustin Pop
    return env, nl, nl
5860 a8083063 Iustin Pop
5861 a8083063 Iustin Pop
5862 a8083063 Iustin Pop
  def CheckPrereq(self):
5863 a8083063 Iustin Pop
    """Check prerequisites.
5864 a8083063 Iustin Pop

5865 a8083063 Iustin Pop
    """
5866 eedc99de Manuel Franceschini
    if (not self.cfg.GetVGName() and
5867 eedc99de Manuel Franceschini
        self.op.disk_template not in constants.DTS_NOT_LVM):
5868 eedc99de Manuel Franceschini
      raise errors.OpPrereqError("Cluster does not support lvm-based"
5869 5c983ee5 Iustin Pop
                                 " instances", errors.ECODE_STATE)
5870 eedc99de Manuel Franceschini
5871 a8083063 Iustin Pop
    if self.op.mode == constants.INSTANCE_IMPORT:
5872 7baf741d Guido Trotter
      src_node = self.op.src_node
5873 7baf741d Guido Trotter
      src_path = self.op.src_path
5874 a8083063 Iustin Pop
5875 c0cbdc67 Guido Trotter
      if src_node is None:
5876 1b7bfbb7 Iustin Pop
        locked_nodes = self.acquired_locks[locking.LEVEL_NODE]
5877 1b7bfbb7 Iustin Pop
        exp_list = self.rpc.call_export_list(locked_nodes)
5878 c0cbdc67 Guido Trotter
        found = False
5879 c0cbdc67 Guido Trotter
        for node in exp_list:
5880 4c4e4e1e Iustin Pop
          if exp_list[node].fail_msg:
5881 1b7bfbb7 Iustin Pop
            continue
5882 1b7bfbb7 Iustin Pop
          if src_path in exp_list[node].payload:
5883 c0cbdc67 Guido Trotter
            found = True
5884 c0cbdc67 Guido Trotter
            self.op.src_node = src_node = node
5885 c0cbdc67 Guido Trotter
            self.op.src_path = src_path = os.path.join(constants.EXPORT_DIR,
5886 c0cbdc67 Guido Trotter
                                                       src_path)
5887 c0cbdc67 Guido Trotter
            break
5888 c0cbdc67 Guido Trotter
        if not found:
5889 c0cbdc67 Guido Trotter
          raise errors.OpPrereqError("No export found for relative path %s" %
5890 5c983ee5 Iustin Pop
                                      src_path, errors.ECODE_INVAL)
5891 c0cbdc67 Guido Trotter
5892 7527a8a4 Iustin Pop
      _CheckNodeOnline(self, src_node)
5893 781de953 Iustin Pop
      result = self.rpc.call_export_info(src_node, src_path)
5894 4c4e4e1e Iustin Pop
      result.Raise("No export or invalid export found in dir %s" % src_path)
5895 a8083063 Iustin Pop
5896 3eccac06 Iustin Pop
      export_info = objects.SerializableConfigParser.Loads(str(result.payload))
5897 a8083063 Iustin Pop
      if not export_info.has_section(constants.INISECT_EXP):
5898 5c983ee5 Iustin Pop
        raise errors.ProgrammerError("Corrupted export config",
5899 5c983ee5 Iustin Pop
                                     errors.ECODE_ENVIRON)
5900 a8083063 Iustin Pop
5901 a8083063 Iustin Pop
      ei_version = export_info.get(constants.INISECT_EXP, 'version')
5902 a8083063 Iustin Pop
      if (int(ei_version) != constants.EXPORT_VERSION):
5903 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Wrong export version %s (wanted %d)" %
5904 5c983ee5 Iustin Pop
                                   (ei_version, constants.EXPORT_VERSION),
5905 5c983ee5 Iustin Pop
                                   errors.ECODE_ENVIRON)
5906 a8083063 Iustin Pop
5907 09acf207 Guido Trotter
      # Check that the new instance doesn't have less disks than the export
5908 08db7c5c Iustin Pop
      instance_disks = len(self.disks)
5909 09acf207 Guido Trotter
      export_disks = export_info.getint(constants.INISECT_INS, 'disk_count')
5910 09acf207 Guido Trotter
      if instance_disks < export_disks:
5911 09acf207 Guido Trotter
        raise errors.OpPrereqError("Not enough disks to import."
5912 09acf207 Guido Trotter
                                   " (instance: %d, export: %d)" %
5913 5c983ee5 Iustin Pop
                                   (instance_disks, export_disks),
5914 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
5915 a8083063 Iustin Pop
5916 a8083063 Iustin Pop
      self.op.os_type = export_info.get(constants.INISECT_EXP, 'os')
5917 09acf207 Guido Trotter
      disk_images = []
5918 09acf207 Guido Trotter
      for idx in range(export_disks):
5919 09acf207 Guido Trotter
        option = 'disk%d_dump' % idx
5920 09acf207 Guido Trotter
        if export_info.has_option(constants.INISECT_INS, option):
5921 09acf207 Guido Trotter
          # FIXME: are the old os-es, disk sizes, etc. useful?
5922 09acf207 Guido Trotter
          export_name = export_info.get(constants.INISECT_INS, option)
5923 09acf207 Guido Trotter
          image = os.path.join(src_path, export_name)
5924 09acf207 Guido Trotter
          disk_images.append(image)
5925 09acf207 Guido Trotter
        else:
5926 09acf207 Guido Trotter
          disk_images.append(False)
5927 09acf207 Guido Trotter
5928 09acf207 Guido Trotter
      self.src_images = disk_images
5929 901a65c1 Iustin Pop
5930 b4364a6b Guido Trotter
      old_name = export_info.get(constants.INISECT_INS, 'name')
5931 b4364a6b Guido Trotter
      # FIXME: int() here could throw a ValueError on broken exports
5932 b4364a6b Guido Trotter
      exp_nic_count = int(export_info.get(constants.INISECT_INS, 'nic_count'))
5933 b4364a6b Guido Trotter
      if self.op.instance_name == old_name:
5934 b4364a6b Guido Trotter
        for idx, nic in enumerate(self.nics):
5935 b4364a6b Guido Trotter
          if nic.mac == constants.VALUE_AUTO and exp_nic_count >= idx:
5936 b4364a6b Guido Trotter
            nic_mac_ini = 'nic%d_mac' % idx
5937 b4364a6b Guido Trotter
            nic.mac = export_info.get(constants.INISECT_INS, nic_mac_ini)
5938 bc89efc3 Guido Trotter
5939 295728df Guido Trotter
    # ENDIF: self.op.mode == constants.INSTANCE_IMPORT
5940 7baf741d Guido Trotter
    # ip ping checks (we use the same ip that was resolved in ExpandNames)
5941 901a65c1 Iustin Pop
    if self.op.start and not self.op.ip_check:
5942 901a65c1 Iustin Pop
      raise errors.OpPrereqError("Cannot ignore IP address conflicts when"
5943 5c983ee5 Iustin Pop
                                 " adding an instance in start mode",
5944 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
5945 901a65c1 Iustin Pop
5946 901a65c1 Iustin Pop
    if self.op.ip_check:
5947 7baf741d Guido Trotter
      if utils.TcpPing(self.check_ip, constants.DEFAULT_NODED_PORT):
5948 901a65c1 Iustin Pop
        raise errors.OpPrereqError("IP %s of instance %s already in use" %
5949 5c983ee5 Iustin Pop
                                   (self.check_ip, self.op.instance_name),
5950 5c983ee5 Iustin Pop
                                   errors.ECODE_NOTUNIQUE)
5951 901a65c1 Iustin Pop
5952 295728df Guido Trotter
    #### mac address generation
5953 295728df Guido Trotter
    # By generating here the mac address both the allocator and the hooks get
5954 295728df Guido Trotter
    # the real final mac address rather than the 'auto' or 'generate' value.
5955 295728df Guido Trotter
    # There is a race condition between the generation and the instance object
5956 295728df Guido Trotter
    # creation, which means that we know the mac is valid now, but we're not
5957 295728df Guido Trotter
    # sure it will be when we actually add the instance. If things go bad
5958 295728df Guido Trotter
    # adding the instance will abort because of a duplicate mac, and the
5959 295728df Guido Trotter
    # creation job will fail.
5960 295728df Guido Trotter
    for nic in self.nics:
5961 295728df Guido Trotter
      if nic.mac in (constants.VALUE_AUTO, constants.VALUE_GENERATE):
5962 36b66e6e Guido Trotter
        nic.mac = self.cfg.GenerateMAC(self.proc.GetECId())
5963 295728df Guido Trotter
5964 538475ca Iustin Pop
    #### allocator run
5965 538475ca Iustin Pop
5966 538475ca Iustin Pop
    if self.op.iallocator is not None:
5967 538475ca Iustin Pop
      self._RunAllocator()
5968 0f1a06e3 Manuel Franceschini
5969 901a65c1 Iustin Pop
    #### node related checks
5970 901a65c1 Iustin Pop
5971 901a65c1 Iustin Pop
    # check primary node
5972 7baf741d Guido Trotter
    self.pnode = pnode = self.cfg.GetNodeInfo(self.op.pnode)
5973 7baf741d Guido Trotter
    assert self.pnode is not None, \
5974 7baf741d Guido Trotter
      "Cannot retrieve locked node %s" % self.op.pnode
5975 7527a8a4 Iustin Pop
    if pnode.offline:
5976 7527a8a4 Iustin Pop
      raise errors.OpPrereqError("Cannot use offline primary node '%s'" %
5977 5c983ee5 Iustin Pop
                                 pnode.name, errors.ECODE_STATE)
5978 733a2b6a Iustin Pop
    if pnode.drained:
5979 733a2b6a Iustin Pop
      raise errors.OpPrereqError("Cannot use drained primary node '%s'" %
5980 5c983ee5 Iustin Pop
                                 pnode.name, errors.ECODE_STATE)
5981 7527a8a4 Iustin Pop
5982 901a65c1 Iustin Pop
    self.secondaries = []
5983 901a65c1 Iustin Pop
5984 901a65c1 Iustin Pop
    # mirror node verification
5985 a1f445d3 Iustin Pop
    if self.op.disk_template in constants.DTS_NET_MIRROR:
5986 7baf741d Guido Trotter
      if self.op.snode is None:
5987 a1f445d3 Iustin Pop
        raise errors.OpPrereqError("The networked disk templates need"
5988 5c983ee5 Iustin Pop
                                   " a mirror node", errors.ECODE_INVAL)
5989 7baf741d Guido Trotter
      if self.op.snode == pnode.name:
5990 5c983ee5 Iustin Pop
        raise errors.OpPrereqError("The secondary node cannot be the"
5991 5c983ee5 Iustin Pop
                                   " primary node.", errors.ECODE_INVAL)
5992 7527a8a4 Iustin Pop
      _CheckNodeOnline(self, self.op.snode)
5993 733a2b6a Iustin Pop
      _CheckNodeNotDrained(self, self.op.snode)
5994 733a2b6a Iustin Pop
      self.secondaries.append(self.op.snode)
5995 a8083063 Iustin Pop
5996 6785674e Iustin Pop
    nodenames = [pnode.name] + self.secondaries
5997 6785674e Iustin Pop
5998 e2fe6369 Iustin Pop
    req_size = _ComputeDiskSize(self.op.disk_template,
5999 08db7c5c Iustin Pop
                                self.disks)
6000 ed1ebc60 Guido Trotter
6001 8d75db10 Iustin Pop
    # Check lv size requirements
6002 8d75db10 Iustin Pop
    if req_size is not None:
6003 72737a7f Iustin Pop
      nodeinfo = self.rpc.call_node_info(nodenames, self.cfg.GetVGName(),
6004 72737a7f Iustin Pop
                                         self.op.hypervisor)
6005 8d75db10 Iustin Pop
      for node in nodenames:
6006 781de953 Iustin Pop
        info = nodeinfo[node]
6007 4c4e4e1e Iustin Pop
        info.Raise("Cannot get current information from node %s" % node)
6008 070e998b Iustin Pop
        info = info.payload
6009 8d75db10 Iustin Pop
        vg_free = info.get('vg_free', None)
6010 8d75db10 Iustin Pop
        if not isinstance(vg_free, int):
6011 8d75db10 Iustin Pop
          raise errors.OpPrereqError("Can't compute free disk space on"
6012 5c983ee5 Iustin Pop
                                     " node %s" % node, errors.ECODE_ENVIRON)
6013 070e998b Iustin Pop
        if req_size > vg_free:
6014 8d75db10 Iustin Pop
          raise errors.OpPrereqError("Not enough disk space on target node %s."
6015 8d75db10 Iustin Pop
                                     " %d MB available, %d MB required" %
6016 5c983ee5 Iustin Pop
                                     (node, vg_free, req_size),
6017 5c983ee5 Iustin Pop
                                     errors.ECODE_NORES)
6018 ed1ebc60 Guido Trotter
6019 74409b12 Iustin Pop
    _CheckHVParams(self, nodenames, self.op.hypervisor, self.op.hvparams)
6020 6785674e Iustin Pop
6021 a8083063 Iustin Pop
    # os verification
6022 781de953 Iustin Pop
    result = self.rpc.call_os_get(pnode.name, self.op.os_type)
6023 4c4e4e1e Iustin Pop
    result.Raise("OS '%s' not in supported os list for primary node %s" %
6024 045dd6d9 Iustin Pop
                 (self.op.os_type, pnode.name),
6025 045dd6d9 Iustin Pop
                 prereq=True, ecode=errors.ECODE_INVAL)
6026 f2c05717 Guido Trotter
    if not self.op.force_variant:
6027 f2c05717 Guido Trotter
      _CheckOSVariant(result.payload, self.op.os_type)
6028 a8083063 Iustin Pop
6029 b165e77e Guido Trotter
    _CheckNicsBridgesExist(self, self.nics, self.pnode.name)
6030 a8083063 Iustin Pop
6031 49ce1563 Iustin Pop
    # memory check on primary node
6032 49ce1563 Iustin Pop
    if self.op.start:
6033 b9bddb6b Iustin Pop
      _CheckNodeFreeMemory(self, self.pnode.name,
6034 49ce1563 Iustin Pop
                           "creating instance %s" % self.op.instance_name,
6035 338e51e8 Iustin Pop
                           self.be_full[constants.BE_MEMORY],
6036 338e51e8 Iustin Pop
                           self.op.hypervisor)
6037 49ce1563 Iustin Pop
6038 08896026 Iustin Pop
    self.dry_run_result = list(nodenames)
6039 08896026 Iustin Pop
6040 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
6041 a8083063 Iustin Pop
    """Create and add the instance to the cluster.
6042 a8083063 Iustin Pop

6043 a8083063 Iustin Pop
    """
6044 a8083063 Iustin Pop
    instance = self.op.instance_name
6045 a8083063 Iustin Pop
    pnode_name = self.pnode.name
6046 a8083063 Iustin Pop
6047 e69d05fd Iustin Pop
    ht_kind = self.op.hypervisor
6048 2a6469d5 Alexander Schreiber
    if ht_kind in constants.HTS_REQ_PORT:
6049 2a6469d5 Alexander Schreiber
      network_port = self.cfg.AllocatePort()
6050 2a6469d5 Alexander Schreiber
    else:
6051 2a6469d5 Alexander Schreiber
      network_port = None
6052 58acb49d Alexander Schreiber
6053 6785674e Iustin Pop
    ##if self.op.vnc_bind_address is None:
6054 6785674e Iustin Pop
    ##  self.op.vnc_bind_address = constants.VNC_DEFAULT_BIND_ADDRESS
6055 31a853d2 Iustin Pop
6056 2c313123 Manuel Franceschini
    # this is needed because os.path.join does not accept None arguments
6057 2c313123 Manuel Franceschini
    if self.op.file_storage_dir is None:
6058 2c313123 Manuel Franceschini
      string_file_storage_dir = ""
6059 2c313123 Manuel Franceschini
    else:
6060 2c313123 Manuel Franceschini
      string_file_storage_dir = self.op.file_storage_dir
6061 2c313123 Manuel Franceschini
6062 0f1a06e3 Manuel Franceschini
    # build the full file storage dir path
6063 0f1a06e3 Manuel Franceschini
    file_storage_dir = os.path.normpath(os.path.join(
6064 d6a02168 Michael Hanselmann
                                        self.cfg.GetFileStorageDir(),
6065 2c313123 Manuel Franceschini
                                        string_file_storage_dir, instance))
6066 0f1a06e3 Manuel Franceschini
6067 0f1a06e3 Manuel Franceschini
6068 b9bddb6b Iustin Pop
    disks = _GenerateDiskTemplate(self,
6069 a8083063 Iustin Pop
                                  self.op.disk_template,
6070 a8083063 Iustin Pop
                                  instance, pnode_name,
6071 08db7c5c Iustin Pop
                                  self.secondaries,
6072 08db7c5c Iustin Pop
                                  self.disks,
6073 0f1a06e3 Manuel Franceschini
                                  file_storage_dir,
6074 e2a65344 Iustin Pop
                                  self.op.file_driver,
6075 e2a65344 Iustin Pop
                                  0)
6076 a8083063 Iustin Pop
6077 a8083063 Iustin Pop
    iobj = objects.Instance(name=instance, os=self.op.os_type,
6078 a8083063 Iustin Pop
                            primary_node=pnode_name,
6079 08db7c5c Iustin Pop
                            nics=self.nics, disks=disks,
6080 a8083063 Iustin Pop
                            disk_template=self.op.disk_template,
6081 4978db17 Iustin Pop
                            admin_up=False,
6082 58acb49d Alexander Schreiber
                            network_port=network_port,
6083 338e51e8 Iustin Pop
                            beparams=self.op.beparams,
6084 6785674e Iustin Pop
                            hvparams=self.op.hvparams,
6085 e69d05fd Iustin Pop
                            hypervisor=self.op.hypervisor,
6086 a8083063 Iustin Pop
                            )
6087 a8083063 Iustin Pop
6088 a8083063 Iustin Pop
    feedback_fn("* creating instance disks...")
6089 796cab27 Iustin Pop
    try:
6090 796cab27 Iustin Pop
      _CreateDisks(self, iobj)
6091 796cab27 Iustin Pop
    except errors.OpExecError:
6092 796cab27 Iustin Pop
      self.LogWarning("Device creation failed, reverting...")
6093 796cab27 Iustin Pop
      try:
6094 796cab27 Iustin Pop
        _RemoveDisks(self, iobj)
6095 796cab27 Iustin Pop
      finally:
6096 796cab27 Iustin Pop
        self.cfg.ReleaseDRBDMinors(instance)
6097 796cab27 Iustin Pop
        raise
6098 a8083063 Iustin Pop
6099 a8083063 Iustin Pop
    feedback_fn("adding instance %s to cluster config" % instance)
6100 a8083063 Iustin Pop
6101 0debfb35 Guido Trotter
    self.cfg.AddInstance(iobj, self.proc.GetECId())
6102 0debfb35 Guido Trotter
6103 7baf741d Guido Trotter
    # Declare that we don't want to remove the instance lock anymore, as we've
6104 7baf741d Guido Trotter
    # added the instance to the config
6105 7baf741d Guido Trotter
    del self.remove_locks[locking.LEVEL_INSTANCE]
6106 e36e96b4 Guido Trotter
    # Unlock all the nodes
6107 9c8971d7 Guido Trotter
    if self.op.mode == constants.INSTANCE_IMPORT:
6108 9c8971d7 Guido Trotter
      nodes_keep = [self.op.src_node]
6109 9c8971d7 Guido Trotter
      nodes_release = [node for node in self.acquired_locks[locking.LEVEL_NODE]
6110 9c8971d7 Guido Trotter
                       if node != self.op.src_node]
6111 9c8971d7 Guido Trotter
      self.context.glm.release(locking.LEVEL_NODE, nodes_release)
6112 9c8971d7 Guido Trotter
      self.acquired_locks[locking.LEVEL_NODE] = nodes_keep
6113 9c8971d7 Guido Trotter
    else:
6114 9c8971d7 Guido Trotter
      self.context.glm.release(locking.LEVEL_NODE)
6115 9c8971d7 Guido Trotter
      del self.acquired_locks[locking.LEVEL_NODE]
6116 a8083063 Iustin Pop
6117 a8083063 Iustin Pop
    if self.op.wait_for_sync:
6118 b9bddb6b Iustin Pop
      disk_abort = not _WaitForSync(self, iobj)
6119 a1f445d3 Iustin Pop
    elif iobj.disk_template in constants.DTS_NET_MIRROR:
6120 a8083063 Iustin Pop
      # make sure the disks are not degraded (still sync-ing is ok)
6121 a8083063 Iustin Pop
      time.sleep(15)
6122 a8083063 Iustin Pop
      feedback_fn("* checking mirrors status")
6123 b9bddb6b Iustin Pop
      disk_abort = not _WaitForSync(self, iobj, oneshot=True)
6124 a8083063 Iustin Pop
    else:
6125 a8083063 Iustin Pop
      disk_abort = False
6126 a8083063 Iustin Pop
6127 a8083063 Iustin Pop
    if disk_abort:
6128 b9bddb6b Iustin Pop
      _RemoveDisks(self, iobj)
6129 a8083063 Iustin Pop
      self.cfg.RemoveInstance(iobj.name)
6130 7baf741d Guido Trotter
      # Make sure the instance lock gets removed
6131 7baf741d Guido Trotter
      self.remove_locks[locking.LEVEL_INSTANCE] = iobj.name
6132 3ecf6786 Iustin Pop
      raise errors.OpExecError("There are some degraded disks for"
6133 3ecf6786 Iustin Pop
                               " this instance")
6134 a8083063 Iustin Pop
6135 a8083063 Iustin Pop
    feedback_fn("creating os for instance %s on node %s" %
6136 a8083063 Iustin Pop
                (instance, pnode_name))
6137 a8083063 Iustin Pop
6138 a8083063 Iustin Pop
    if iobj.disk_template != constants.DT_DISKLESS:
6139 a8083063 Iustin Pop
      if self.op.mode == constants.INSTANCE_CREATE:
6140 a8083063 Iustin Pop
        feedback_fn("* running the instance OS create scripts...")
6141 e557bae9 Guido Trotter
        result = self.rpc.call_instance_os_add(pnode_name, iobj, False)
6142 4c4e4e1e Iustin Pop
        result.Raise("Could not add os for instance %s"
6143 4c4e4e1e Iustin Pop
                     " on node %s" % (instance, pnode_name))
6144 a8083063 Iustin Pop
6145 a8083063 Iustin Pop
      elif self.op.mode == constants.INSTANCE_IMPORT:
6146 a8083063 Iustin Pop
        feedback_fn("* running the instance OS import scripts...")
6147 a8083063 Iustin Pop
        src_node = self.op.src_node
6148 09acf207 Guido Trotter
        src_images = self.src_images
6149 62c9ec92 Iustin Pop
        cluster_name = self.cfg.GetClusterName()
6150 6c0af70e Guido Trotter
        import_result = self.rpc.call_instance_os_import(pnode_name, iobj,
6151 09acf207 Guido Trotter
                                                         src_node, src_images,
6152 6c0af70e Guido Trotter
                                                         cluster_name)
6153 4c4e4e1e Iustin Pop
        msg = import_result.fail_msg
6154 944bf548 Iustin Pop
        if msg:
6155 944bf548 Iustin Pop
          self.LogWarning("Error while importing the disk images for instance"
6156 944bf548 Iustin Pop
                          " %s on node %s: %s" % (instance, pnode_name, msg))
6157 a8083063 Iustin Pop
      else:
6158 a8083063 Iustin Pop
        # also checked in the prereq part
6159 3ecf6786 Iustin Pop
        raise errors.ProgrammerError("Unknown OS initialization mode '%s'"
6160 3ecf6786 Iustin Pop
                                     % self.op.mode)
6161 a8083063 Iustin Pop
6162 a8083063 Iustin Pop
    if self.op.start:
6163 4978db17 Iustin Pop
      iobj.admin_up = True
6164 a4eae71f Michael Hanselmann
      self.cfg.Update(iobj, feedback_fn)
6165 9a4f63d1 Iustin Pop
      logging.info("Starting instance %s on node %s", instance, pnode_name)
6166 a8083063 Iustin Pop
      feedback_fn("* starting instance...")
6167 0eca8e0c Iustin Pop
      result = self.rpc.call_instance_start(pnode_name, iobj, None, None)
6168 4c4e4e1e Iustin Pop
      result.Raise("Could not start instance")
6169 a8083063 Iustin Pop
6170 08896026 Iustin Pop
    return list(iobj.all_nodes)
6171 08896026 Iustin Pop
6172 a8083063 Iustin Pop
6173 a8083063 Iustin Pop
class LUConnectConsole(NoHooksLU):
6174 a8083063 Iustin Pop
  """Connect to an instance's console.
6175 a8083063 Iustin Pop

6176 a8083063 Iustin Pop
  This is somewhat special in that it returns the command line that
6177 a8083063 Iustin Pop
  you need to run on the master node in order to connect to the
6178 a8083063 Iustin Pop
  console.
6179 a8083063 Iustin Pop

6180 a8083063 Iustin Pop
  """
6181 a8083063 Iustin Pop
  _OP_REQP = ["instance_name"]
6182 8659b73e Guido Trotter
  REQ_BGL = False
6183 8659b73e Guido Trotter
6184 8659b73e Guido Trotter
  def ExpandNames(self):
6185 8659b73e Guido Trotter
    self._ExpandAndLockInstance()
6186 a8083063 Iustin Pop
6187 a8083063 Iustin Pop
  def CheckPrereq(self):
6188 a8083063 Iustin Pop
    """Check prerequisites.
6189 a8083063 Iustin Pop

6190 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
6191 a8083063 Iustin Pop

6192 a8083063 Iustin Pop
    """
6193 8659b73e Guido Trotter
    self.instance = self.cfg.GetInstanceInfo(self.op.instance_name)
6194 8659b73e Guido Trotter
    assert self.instance is not None, \
6195 8659b73e Guido Trotter
      "Cannot retrieve locked instance %s" % self.op.instance_name
6196 513e896d Guido Trotter
    _CheckNodeOnline(self, self.instance.primary_node)
6197 a8083063 Iustin Pop
6198 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
6199 a8083063 Iustin Pop
    """Connect to the console of an instance
6200 a8083063 Iustin Pop

6201 a8083063 Iustin Pop
    """
6202 a8083063 Iustin Pop
    instance = self.instance
6203 a8083063 Iustin Pop
    node = instance.primary_node
6204 a8083063 Iustin Pop
6205 72737a7f Iustin Pop
    node_insts = self.rpc.call_instance_list([node],
6206 72737a7f Iustin Pop
                                             [instance.hypervisor])[node]
6207 4c4e4e1e Iustin Pop
    node_insts.Raise("Can't get node information from %s" % node)
6208 a8083063 Iustin Pop
6209 aca13712 Iustin Pop
    if instance.name not in node_insts.payload:
6210 3ecf6786 Iustin Pop
      raise errors.OpExecError("Instance %s is not running." % instance.name)
6211 a8083063 Iustin Pop
6212 9a4f63d1 Iustin Pop
    logging.debug("Connecting to console of %s on %s", instance.name, node)
6213 a8083063 Iustin Pop
6214 e69d05fd Iustin Pop
    hyper = hypervisor.GetHypervisor(instance.hypervisor)
6215 5431b2e4 Guido Trotter
    cluster = self.cfg.GetClusterInfo()
6216 5431b2e4 Guido Trotter
    # beparams and hvparams are passed separately, to avoid editing the
6217 5431b2e4 Guido Trotter
    # instance and then saving the defaults in the instance itself.
6218 5431b2e4 Guido Trotter
    hvparams = cluster.FillHV(instance)
6219 5431b2e4 Guido Trotter
    beparams = cluster.FillBE(instance)
6220 5431b2e4 Guido Trotter
    console_cmd = hyper.GetShellCommandForConsole(instance, hvparams, beparams)
6221 b047857b Michael Hanselmann
6222 82122173 Iustin Pop
    # build ssh cmdline
6223 0a80a26f Michael Hanselmann
    return self.ssh.BuildCmd(node, "root", console_cmd, batch=True, tty=True)
6224 a8083063 Iustin Pop
6225 a8083063 Iustin Pop
6226 a8083063 Iustin Pop
class LUReplaceDisks(LogicalUnit):
6227 a8083063 Iustin Pop
  """Replace the disks of an instance.
6228 a8083063 Iustin Pop

6229 a8083063 Iustin Pop
  """
6230 a8083063 Iustin Pop
  HPATH = "mirrors-replace"
6231 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
6232 a9e0c397 Iustin Pop
  _OP_REQP = ["instance_name", "mode", "disks"]
6233 efd990e4 Guido Trotter
  REQ_BGL = False
6234 efd990e4 Guido Trotter
6235 7e9366f7 Iustin Pop
  def CheckArguments(self):
6236 efd990e4 Guido Trotter
    if not hasattr(self.op, "remote_node"):
6237 efd990e4 Guido Trotter
      self.op.remote_node = None
6238 7e9366f7 Iustin Pop
    if not hasattr(self.op, "iallocator"):
6239 7e9366f7 Iustin Pop
      self.op.iallocator = None
6240 7e9366f7 Iustin Pop
6241 c68174b6 Michael Hanselmann
    TLReplaceDisks.CheckArguments(self.op.mode, self.op.remote_node,
6242 c68174b6 Michael Hanselmann
                                  self.op.iallocator)
6243 7e9366f7 Iustin Pop
6244 7e9366f7 Iustin Pop
  def ExpandNames(self):
6245 7e9366f7 Iustin Pop
    self._ExpandAndLockInstance()
6246 7e9366f7 Iustin Pop
6247 7e9366f7 Iustin Pop
    if self.op.iallocator is not None:
6248 efd990e4 Guido Trotter
      self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
6249 2bb5c911 Michael Hanselmann
6250 efd990e4 Guido Trotter
    elif self.op.remote_node is not None:
6251 efd990e4 Guido Trotter
      remote_node = self.cfg.ExpandNodeName(self.op.remote_node)
6252 efd990e4 Guido Trotter
      if remote_node is None:
6253 efd990e4 Guido Trotter
        raise errors.OpPrereqError("Node '%s' not known" %
6254 5c983ee5 Iustin Pop
                                   self.op.remote_node, errors.ECODE_NOENT)
6255 2bb5c911 Michael Hanselmann
6256 efd990e4 Guido Trotter
      self.op.remote_node = remote_node
6257 2bb5c911 Michael Hanselmann
6258 3b559640 Iustin Pop
      # Warning: do not remove the locking of the new secondary here
6259 3b559640 Iustin Pop
      # unless DRBD8.AddChildren is changed to work in parallel;
6260 3b559640 Iustin Pop
      # currently it doesn't since parallel invocations of
6261 3b559640 Iustin Pop
      # FindUnusedMinor will conflict
6262 efd990e4 Guido Trotter
      self.needed_locks[locking.LEVEL_NODE] = [remote_node]
6263 efd990e4 Guido Trotter
      self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_APPEND
6264 2bb5c911 Michael Hanselmann
6265 efd990e4 Guido Trotter
    else:
6266 efd990e4 Guido Trotter
      self.needed_locks[locking.LEVEL_NODE] = []
6267 efd990e4 Guido Trotter
      self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
6268 efd990e4 Guido Trotter
6269 c68174b6 Michael Hanselmann
    self.replacer = TLReplaceDisks(self, self.op.instance_name, self.op.mode,
6270 c68174b6 Michael Hanselmann
                                   self.op.iallocator, self.op.remote_node,
6271 c68174b6 Michael Hanselmann
                                   self.op.disks)
6272 c68174b6 Michael Hanselmann
6273 3a012b41 Michael Hanselmann
    self.tasklets = [self.replacer]
6274 2bb5c911 Michael Hanselmann
6275 efd990e4 Guido Trotter
  def DeclareLocks(self, level):
6276 efd990e4 Guido Trotter
    # If we're not already locking all nodes in the set we have to declare the
6277 efd990e4 Guido Trotter
    # instance's primary/secondary nodes.
6278 efd990e4 Guido Trotter
    if (level == locking.LEVEL_NODE and
6279 efd990e4 Guido Trotter
        self.needed_locks[locking.LEVEL_NODE] is not locking.ALL_SET):
6280 efd990e4 Guido Trotter
      self._LockInstancesNodes()
6281 a8083063 Iustin Pop
6282 a8083063 Iustin Pop
  def BuildHooksEnv(self):
6283 a8083063 Iustin Pop
    """Build hooks env.
6284 a8083063 Iustin Pop

6285 a8083063 Iustin Pop
    This runs on the master, the primary and all the secondaries.
6286 a8083063 Iustin Pop

6287 a8083063 Iustin Pop
    """
6288 2bb5c911 Michael Hanselmann
    instance = self.replacer.instance
6289 a8083063 Iustin Pop
    env = {
6290 a9e0c397 Iustin Pop
      "MODE": self.op.mode,
6291 a8083063 Iustin Pop
      "NEW_SECONDARY": self.op.remote_node,
6292 2bb5c911 Michael Hanselmann
      "OLD_SECONDARY": instance.secondary_nodes[0],
6293 a8083063 Iustin Pop
      }
6294 2bb5c911 Michael Hanselmann
    env.update(_BuildInstanceHookEnvByObject(self, instance))
6295 0834c866 Iustin Pop
    nl = [
6296 d6a02168 Michael Hanselmann
      self.cfg.GetMasterNode(),
6297 2bb5c911 Michael Hanselmann
      instance.primary_node,
6298 0834c866 Iustin Pop
      ]
6299 0834c866 Iustin Pop
    if self.op.remote_node is not None:
6300 0834c866 Iustin Pop
      nl.append(self.op.remote_node)
6301 a8083063 Iustin Pop
    return env, nl, nl
6302 a8083063 Iustin Pop
6303 2bb5c911 Michael Hanselmann
6304 7ffc5a86 Michael Hanselmann
class LUEvacuateNode(LogicalUnit):
6305 7ffc5a86 Michael Hanselmann
  """Relocate the secondary instances from a node.
6306 7ffc5a86 Michael Hanselmann

6307 7ffc5a86 Michael Hanselmann
  """
6308 7ffc5a86 Michael Hanselmann
  HPATH = "node-evacuate"
6309 7ffc5a86 Michael Hanselmann
  HTYPE = constants.HTYPE_NODE
6310 7ffc5a86 Michael Hanselmann
  _OP_REQP = ["node_name"]
6311 7ffc5a86 Michael Hanselmann
  REQ_BGL = False
6312 7ffc5a86 Michael Hanselmann
6313 7ffc5a86 Michael Hanselmann
  def CheckArguments(self):
6314 7ffc5a86 Michael Hanselmann
    if not hasattr(self.op, "remote_node"):
6315 7ffc5a86 Michael Hanselmann
      self.op.remote_node = None
6316 7ffc5a86 Michael Hanselmann
    if not hasattr(self.op, "iallocator"):
6317 7ffc5a86 Michael Hanselmann
      self.op.iallocator = None
6318 7ffc5a86 Michael Hanselmann
6319 7ffc5a86 Michael Hanselmann
    TLReplaceDisks.CheckArguments(constants.REPLACE_DISK_CHG,
6320 7ffc5a86 Michael Hanselmann
                                  self.op.remote_node,
6321 7ffc5a86 Michael Hanselmann
                                  self.op.iallocator)
6322 7ffc5a86 Michael Hanselmann
6323 7ffc5a86 Michael Hanselmann
  def ExpandNames(self):
6324 7ffc5a86 Michael Hanselmann
    self.op.node_name = self.cfg.ExpandNodeName(self.op.node_name)
6325 7ffc5a86 Michael Hanselmann
    if self.op.node_name is None:
6326 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Node '%s' not known" % self.op.node_name,
6327 5c983ee5 Iustin Pop
                                 errors.ECODE_NOENT)
6328 7ffc5a86 Michael Hanselmann
6329 7ffc5a86 Michael Hanselmann
    self.needed_locks = {}
6330 7ffc5a86 Michael Hanselmann
6331 7ffc5a86 Michael Hanselmann
    # Declare node locks
6332 7ffc5a86 Michael Hanselmann
    if self.op.iallocator is not None:
6333 7ffc5a86 Michael Hanselmann
      self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
6334 7ffc5a86 Michael Hanselmann
6335 7ffc5a86 Michael Hanselmann
    elif self.op.remote_node is not None:
6336 7ffc5a86 Michael Hanselmann
      remote_node = self.cfg.ExpandNodeName(self.op.remote_node)
6337 7ffc5a86 Michael Hanselmann
      if remote_node is None:
6338 7ffc5a86 Michael Hanselmann
        raise errors.OpPrereqError("Node '%s' not known" %
6339 5c983ee5 Iustin Pop
                                   self.op.remote_node, errors.ECODE_NOENT)
6340 7ffc5a86 Michael Hanselmann
6341 7ffc5a86 Michael Hanselmann
      self.op.remote_node = remote_node
6342 7ffc5a86 Michael Hanselmann
6343 7ffc5a86 Michael Hanselmann
      # Warning: do not remove the locking of the new secondary here
6344 7ffc5a86 Michael Hanselmann
      # unless DRBD8.AddChildren is changed to work in parallel;
6345 7ffc5a86 Michael Hanselmann
      # currently it doesn't since parallel invocations of
6346 7ffc5a86 Michael Hanselmann
      # FindUnusedMinor will conflict
6347 7ffc5a86 Michael Hanselmann
      self.needed_locks[locking.LEVEL_NODE] = [remote_node]
6348 7ffc5a86 Michael Hanselmann
      self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_APPEND
6349 7ffc5a86 Michael Hanselmann
6350 7ffc5a86 Michael Hanselmann
    else:
6351 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Invalid parameters", errors.ECODE_INVAL)
6352 7ffc5a86 Michael Hanselmann
6353 7ffc5a86 Michael Hanselmann
    # Create tasklets for replacing disks for all secondary instances on this
6354 7ffc5a86 Michael Hanselmann
    # node
6355 7ffc5a86 Michael Hanselmann
    names = []
6356 3a012b41 Michael Hanselmann
    tasklets = []
6357 7ffc5a86 Michael Hanselmann
6358 7ffc5a86 Michael Hanselmann
    for inst in _GetNodeSecondaryInstances(self.cfg, self.op.node_name):
6359 7ffc5a86 Michael Hanselmann
      logging.debug("Replacing disks for instance %s", inst.name)
6360 7ffc5a86 Michael Hanselmann
      names.append(inst.name)
6361 7ffc5a86 Michael Hanselmann
6362 7ffc5a86 Michael Hanselmann
      replacer = TLReplaceDisks(self, inst.name, constants.REPLACE_DISK_CHG,
6363 7ffc5a86 Michael Hanselmann
                                self.op.iallocator, self.op.remote_node, [])
6364 3a012b41 Michael Hanselmann
      tasklets.append(replacer)
6365 7ffc5a86 Michael Hanselmann
6366 3a012b41 Michael Hanselmann
    self.tasklets = tasklets
6367 7ffc5a86 Michael Hanselmann
    self.instance_names = names
6368 7ffc5a86 Michael Hanselmann
6369 7ffc5a86 Michael Hanselmann
    # Declare instance locks
6370 7ffc5a86 Michael Hanselmann
    self.needed_locks[locking.LEVEL_INSTANCE] = self.instance_names
6371 7ffc5a86 Michael Hanselmann
6372 7ffc5a86 Michael Hanselmann
  def DeclareLocks(self, level):
6373 7ffc5a86 Michael Hanselmann
    # If we're not already locking all nodes in the set we have to declare the
6374 7ffc5a86 Michael Hanselmann
    # instance's primary/secondary nodes.
6375 7ffc5a86 Michael Hanselmann
    if (level == locking.LEVEL_NODE and
6376 7ffc5a86 Michael Hanselmann
        self.needed_locks[locking.LEVEL_NODE] is not locking.ALL_SET):
6377 7ffc5a86 Michael Hanselmann
      self._LockInstancesNodes()
6378 7ffc5a86 Michael Hanselmann
6379 7ffc5a86 Michael Hanselmann
  def BuildHooksEnv(self):
6380 7ffc5a86 Michael Hanselmann
    """Build hooks env.
6381 7ffc5a86 Michael Hanselmann

6382 7ffc5a86 Michael Hanselmann
    This runs on the master, the primary and all the secondaries.
6383 7ffc5a86 Michael Hanselmann

6384 7ffc5a86 Michael Hanselmann
    """
6385 7ffc5a86 Michael Hanselmann
    env = {
6386 7ffc5a86 Michael Hanselmann
      "NODE_NAME": self.op.node_name,
6387 7ffc5a86 Michael Hanselmann
      }
6388 7ffc5a86 Michael Hanselmann
6389 7ffc5a86 Michael Hanselmann
    nl = [self.cfg.GetMasterNode()]
6390 7ffc5a86 Michael Hanselmann
6391 7ffc5a86 Michael Hanselmann
    if self.op.remote_node is not None:
6392 7ffc5a86 Michael Hanselmann
      env["NEW_SECONDARY"] = self.op.remote_node
6393 7ffc5a86 Michael Hanselmann
      nl.append(self.op.remote_node)
6394 7ffc5a86 Michael Hanselmann
6395 7ffc5a86 Michael Hanselmann
    return (env, nl, nl)
6396 7ffc5a86 Michael Hanselmann
6397 7ffc5a86 Michael Hanselmann
6398 c68174b6 Michael Hanselmann
class TLReplaceDisks(Tasklet):
6399 2bb5c911 Michael Hanselmann
  """Replaces disks for an instance.
6400 2bb5c911 Michael Hanselmann

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

6403 2bb5c911 Michael Hanselmann
  """
6404 2bb5c911 Michael Hanselmann
  def __init__(self, lu, instance_name, mode, iallocator_name, remote_node,
6405 2bb5c911 Michael Hanselmann
               disks):
6406 2bb5c911 Michael Hanselmann
    """Initializes this class.
6407 2bb5c911 Michael Hanselmann

6408 2bb5c911 Michael Hanselmann
    """
6409 464243a7 Michael Hanselmann
    Tasklet.__init__(self, lu)
6410 464243a7 Michael Hanselmann
6411 2bb5c911 Michael Hanselmann
    # Parameters
6412 2bb5c911 Michael Hanselmann
    self.instance_name = instance_name
6413 2bb5c911 Michael Hanselmann
    self.mode = mode
6414 2bb5c911 Michael Hanselmann
    self.iallocator_name = iallocator_name
6415 2bb5c911 Michael Hanselmann
    self.remote_node = remote_node
6416 2bb5c911 Michael Hanselmann
    self.disks = disks
6417 2bb5c911 Michael Hanselmann
6418 2bb5c911 Michael Hanselmann
    # Runtime data
6419 2bb5c911 Michael Hanselmann
    self.instance = None
6420 2bb5c911 Michael Hanselmann
    self.new_node = None
6421 2bb5c911 Michael Hanselmann
    self.target_node = None
6422 2bb5c911 Michael Hanselmann
    self.other_node = None
6423 2bb5c911 Michael Hanselmann
    self.remote_node_info = None
6424 2bb5c911 Michael Hanselmann
    self.node_secondary_ip = None
6425 2bb5c911 Michael Hanselmann
6426 2bb5c911 Michael Hanselmann
  @staticmethod
6427 2bb5c911 Michael Hanselmann
  def CheckArguments(mode, remote_node, iallocator):
6428 c68174b6 Michael Hanselmann
    """Helper function for users of this class.
6429 c68174b6 Michael Hanselmann

6430 c68174b6 Michael Hanselmann
    """
6431 2bb5c911 Michael Hanselmann
    # check for valid parameter combination
6432 2bb5c911 Michael Hanselmann
    if mode == constants.REPLACE_DISK_CHG:
6433 02a00186 Michael Hanselmann
      if remote_node is None and iallocator is None:
6434 2bb5c911 Michael Hanselmann
        raise errors.OpPrereqError("When changing the secondary either an"
6435 2bb5c911 Michael Hanselmann
                                   " iallocator script must be used or the"
6436 5c983ee5 Iustin Pop
                                   " new node given", errors.ECODE_INVAL)
6437 02a00186 Michael Hanselmann
6438 02a00186 Michael Hanselmann
      if remote_node is not None and iallocator is not None:
6439 2bb5c911 Michael Hanselmann
        raise errors.OpPrereqError("Give either the iallocator or the new"
6440 5c983ee5 Iustin Pop
                                   " secondary, not both", errors.ECODE_INVAL)
6441 02a00186 Michael Hanselmann
6442 02a00186 Michael Hanselmann
    elif remote_node is not None or iallocator is not None:
6443 02a00186 Michael Hanselmann
      # Not replacing the secondary
6444 02a00186 Michael Hanselmann
      raise errors.OpPrereqError("The iallocator and new node options can"
6445 02a00186 Michael Hanselmann
                                 " only be used when changing the"
6446 5c983ee5 Iustin Pop
                                 " secondary node", errors.ECODE_INVAL)
6447 2bb5c911 Michael Hanselmann
6448 2bb5c911 Michael Hanselmann
  @staticmethod
6449 2bb5c911 Michael Hanselmann
  def _RunAllocator(lu, iallocator_name, instance_name, relocate_from):
6450 2bb5c911 Michael Hanselmann
    """Compute a new secondary node using an IAllocator.
6451 2bb5c911 Michael Hanselmann

6452 2bb5c911 Michael Hanselmann
    """
6453 2bb5c911 Michael Hanselmann
    ial = IAllocator(lu.cfg, lu.rpc,
6454 2bb5c911 Michael Hanselmann
                     mode=constants.IALLOCATOR_MODE_RELOC,
6455 2bb5c911 Michael Hanselmann
                     name=instance_name,
6456 2bb5c911 Michael Hanselmann
                     relocate_from=relocate_from)
6457 2bb5c911 Michael Hanselmann
6458 2bb5c911 Michael Hanselmann
    ial.Run(iallocator_name)
6459 2bb5c911 Michael Hanselmann
6460 2bb5c911 Michael Hanselmann
    if not ial.success:
6461 2bb5c911 Michael Hanselmann
      raise errors.OpPrereqError("Can't compute nodes using iallocator '%s':"
6462 5c983ee5 Iustin Pop
                                 " %s" % (iallocator_name, ial.info),
6463 5c983ee5 Iustin Pop
                                 errors.ECODE_NORES)
6464 2bb5c911 Michael Hanselmann
6465 2bb5c911 Michael Hanselmann
    if len(ial.nodes) != ial.required_nodes:
6466 2bb5c911 Michael Hanselmann
      raise errors.OpPrereqError("iallocator '%s' returned invalid number"
6467 2bb5c911 Michael Hanselmann
                                 " of nodes (%s), required %s" %
6468 5c983ee5 Iustin Pop
                                 (len(ial.nodes), ial.required_nodes),
6469 5c983ee5 Iustin Pop
                                 errors.ECODE_FAULT)
6470 2bb5c911 Michael Hanselmann
6471 2bb5c911 Michael Hanselmann
    remote_node_name = ial.nodes[0]
6472 2bb5c911 Michael Hanselmann
6473 2bb5c911 Michael Hanselmann
    lu.LogInfo("Selected new secondary for instance '%s': %s",
6474 2bb5c911 Michael Hanselmann
               instance_name, remote_node_name)
6475 2bb5c911 Michael Hanselmann
6476 2bb5c911 Michael Hanselmann
    return remote_node_name
6477 2bb5c911 Michael Hanselmann
6478 942be002 Michael Hanselmann
  def _FindFaultyDisks(self, node_name):
6479 2d9005d8 Michael Hanselmann
    return _FindFaultyInstanceDisks(self.cfg, self.rpc, self.instance,
6480 2d9005d8 Michael Hanselmann
                                    node_name, True)
6481 942be002 Michael Hanselmann
6482 2bb5c911 Michael Hanselmann
  def CheckPrereq(self):
6483 2bb5c911 Michael Hanselmann
    """Check prerequisites.
6484 2bb5c911 Michael Hanselmann

6485 2bb5c911 Michael Hanselmann
    This checks that the instance is in the cluster.
6486 2bb5c911 Michael Hanselmann

6487 2bb5c911 Michael Hanselmann
    """
6488 e9022531 Iustin Pop
    self.instance = instance = self.cfg.GetInstanceInfo(self.instance_name)
6489 e9022531 Iustin Pop
    assert instance is not None, \
6490 20eca47d Iustin Pop
      "Cannot retrieve locked instance %s" % self.instance_name
6491 2bb5c911 Michael Hanselmann
6492 e9022531 Iustin Pop
    if instance.disk_template != constants.DT_DRBD8:
6493 7e9366f7 Iustin Pop
      raise errors.OpPrereqError("Can only run replace disks for DRBD8-based"
6494 5c983ee5 Iustin Pop
                                 " instances", errors.ECODE_INVAL)
6495 a8083063 Iustin Pop
6496 e9022531 Iustin Pop
    if len(instance.secondary_nodes) != 1:
6497 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("The instance has a strange layout,"
6498 3ecf6786 Iustin Pop
                                 " expected one secondary but found %d" %
6499 5c983ee5 Iustin Pop
                                 len(instance.secondary_nodes),
6500 5c983ee5 Iustin Pop
                                 errors.ECODE_FAULT)
6501 a8083063 Iustin Pop
6502 e9022531 Iustin Pop
    secondary_node = instance.secondary_nodes[0]
6503 a9e0c397 Iustin Pop
6504 2bb5c911 Michael Hanselmann
    if self.iallocator_name is None:
6505 2bb5c911 Michael Hanselmann
      remote_node = self.remote_node
6506 2bb5c911 Michael Hanselmann
    else:
6507 2bb5c911 Michael Hanselmann
      remote_node = self._RunAllocator(self.lu, self.iallocator_name,
6508 e9022531 Iustin Pop
                                       instance.name, instance.secondary_nodes)
6509 b6e82a65 Iustin Pop
6510 a9e0c397 Iustin Pop
    if remote_node is not None:
6511 a9e0c397 Iustin Pop
      self.remote_node_info = self.cfg.GetNodeInfo(remote_node)
6512 efd990e4 Guido Trotter
      assert self.remote_node_info is not None, \
6513 efd990e4 Guido Trotter
        "Cannot retrieve locked node %s" % remote_node
6514 a9e0c397 Iustin Pop
    else:
6515 a9e0c397 Iustin Pop
      self.remote_node_info = None
6516 2bb5c911 Michael Hanselmann
6517 2bb5c911 Michael Hanselmann
    if remote_node == self.instance.primary_node:
6518 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("The specified node is the primary node of"
6519 5c983ee5 Iustin Pop
                                 " the instance.", errors.ECODE_INVAL)
6520 2bb5c911 Michael Hanselmann
6521 2bb5c911 Michael Hanselmann
    if remote_node == secondary_node:
6522 7e9366f7 Iustin Pop
      raise errors.OpPrereqError("The specified node is already the"
6523 5c983ee5 Iustin Pop
                                 " secondary node of the instance.",
6524 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
6525 7e9366f7 Iustin Pop
6526 2945fd2d Michael Hanselmann
    if self.disks and self.mode in (constants.REPLACE_DISK_AUTO,
6527 2945fd2d Michael Hanselmann
                                    constants.REPLACE_DISK_CHG):
6528 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Cannot specify disks to be replaced",
6529 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
6530 942be002 Michael Hanselmann
6531 2945fd2d Michael Hanselmann
    if self.mode == constants.REPLACE_DISK_AUTO:
6532 e9022531 Iustin Pop
      faulty_primary = self._FindFaultyDisks(instance.primary_node)
6533 942be002 Michael Hanselmann
      faulty_secondary = self._FindFaultyDisks(secondary_node)
6534 942be002 Michael Hanselmann
6535 942be002 Michael Hanselmann
      if faulty_primary and faulty_secondary:
6536 942be002 Michael Hanselmann
        raise errors.OpPrereqError("Instance %s has faulty disks on more than"
6537 942be002 Michael Hanselmann
                                   " one node and can not be repaired"
6538 5c983ee5 Iustin Pop
                                   " automatically" % self.instance_name,
6539 5c983ee5 Iustin Pop
                                   errors.ECODE_STATE)
6540 942be002 Michael Hanselmann
6541 942be002 Michael Hanselmann
      if faulty_primary:
6542 942be002 Michael Hanselmann
        self.disks = faulty_primary
6543 e9022531 Iustin Pop
        self.target_node = instance.primary_node
6544 942be002 Michael Hanselmann
        self.other_node = secondary_node
6545 942be002 Michael Hanselmann
        check_nodes = [self.target_node, self.other_node]
6546 942be002 Michael Hanselmann
      elif faulty_secondary:
6547 942be002 Michael Hanselmann
        self.disks = faulty_secondary
6548 942be002 Michael Hanselmann
        self.target_node = secondary_node
6549 e9022531 Iustin Pop
        self.other_node = instance.primary_node
6550 942be002 Michael Hanselmann
        check_nodes = [self.target_node, self.other_node]
6551 942be002 Michael Hanselmann
      else:
6552 942be002 Michael Hanselmann
        self.disks = []
6553 942be002 Michael Hanselmann
        check_nodes = []
6554 942be002 Michael Hanselmann
6555 942be002 Michael Hanselmann
    else:
6556 942be002 Michael Hanselmann
      # Non-automatic modes
6557 942be002 Michael Hanselmann
      if self.mode == constants.REPLACE_DISK_PRI:
6558 e9022531 Iustin Pop
        self.target_node = instance.primary_node
6559 942be002 Michael Hanselmann
        self.other_node = secondary_node
6560 942be002 Michael Hanselmann
        check_nodes = [self.target_node, self.other_node]
6561 7e9366f7 Iustin Pop
6562 942be002 Michael Hanselmann
      elif self.mode == constants.REPLACE_DISK_SEC:
6563 942be002 Michael Hanselmann
        self.target_node = secondary_node
6564 e9022531 Iustin Pop
        self.other_node = instance.primary_node
6565 942be002 Michael Hanselmann
        check_nodes = [self.target_node, self.other_node]
6566 a9e0c397 Iustin Pop
6567 942be002 Michael Hanselmann
      elif self.mode == constants.REPLACE_DISK_CHG:
6568 942be002 Michael Hanselmann
        self.new_node = remote_node
6569 e9022531 Iustin Pop
        self.other_node = instance.primary_node
6570 942be002 Michael Hanselmann
        self.target_node = secondary_node
6571 942be002 Michael Hanselmann
        check_nodes = [self.new_node, self.other_node]
6572 54155f52 Iustin Pop
6573 942be002 Michael Hanselmann
        _CheckNodeNotDrained(self.lu, remote_node)
6574 a8083063 Iustin Pop
6575 942be002 Michael Hanselmann
      else:
6576 942be002 Michael Hanselmann
        raise errors.ProgrammerError("Unhandled disk replace mode (%s)" %
6577 942be002 Michael Hanselmann
                                     self.mode)
6578 942be002 Michael Hanselmann
6579 942be002 Michael Hanselmann
      # If not specified all disks should be replaced
6580 942be002 Michael Hanselmann
      if not self.disks:
6581 942be002 Michael Hanselmann
        self.disks = range(len(self.instance.disks))
6582 a9e0c397 Iustin Pop
6583 2bb5c911 Michael Hanselmann
    for node in check_nodes:
6584 2bb5c911 Michael Hanselmann
      _CheckNodeOnline(self.lu, node)
6585 e4376078 Iustin Pop
6586 2bb5c911 Michael Hanselmann
    # Check whether disks are valid
6587 2bb5c911 Michael Hanselmann
    for disk_idx in self.disks:
6588 e9022531 Iustin Pop
      instance.FindDisk(disk_idx)
6589 e4376078 Iustin Pop
6590 2bb5c911 Michael Hanselmann
    # Get secondary node IP addresses
6591 2bb5c911 Michael Hanselmann
    node_2nd_ip = {}
6592 e4376078 Iustin Pop
6593 2bb5c911 Michael Hanselmann
    for node_name in [self.target_node, self.other_node, self.new_node]:
6594 2bb5c911 Michael Hanselmann
      if node_name is not None:
6595 2bb5c911 Michael Hanselmann
        node_2nd_ip[node_name] = self.cfg.GetNodeInfo(node_name).secondary_ip
6596 e4376078 Iustin Pop
6597 2bb5c911 Michael Hanselmann
    self.node_secondary_ip = node_2nd_ip
6598 a9e0c397 Iustin Pop
6599 c68174b6 Michael Hanselmann
  def Exec(self, feedback_fn):
6600 2bb5c911 Michael Hanselmann
    """Execute disk replacement.
6601 2bb5c911 Michael Hanselmann

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

6604 a9e0c397 Iustin Pop
    """
6605 942be002 Michael Hanselmann
    if not self.disks:
6606 942be002 Michael Hanselmann
      feedback_fn("No disks need replacement")
6607 942be002 Michael Hanselmann
      return
6608 942be002 Michael Hanselmann
6609 942be002 Michael Hanselmann
    feedback_fn("Replacing disk(s) %s for %s" %
6610 942be002 Michael Hanselmann
                (", ".join([str(i) for i in self.disks]), self.instance.name))
6611 7ffc5a86 Michael Hanselmann
6612 2bb5c911 Michael Hanselmann
    activate_disks = (not self.instance.admin_up)
6613 2bb5c911 Michael Hanselmann
6614 2bb5c911 Michael Hanselmann
    # Activate the instance disks if we're replacing them on a down instance
6615 2bb5c911 Michael Hanselmann
    if activate_disks:
6616 2bb5c911 Michael Hanselmann
      _StartInstanceDisks(self.lu, self.instance, True)
6617 2bb5c911 Michael Hanselmann
6618 2bb5c911 Michael Hanselmann
    try:
6619 942be002 Michael Hanselmann
      # Should we replace the secondary node?
6620 942be002 Michael Hanselmann
      if self.new_node is not None:
6621 a4eae71f Michael Hanselmann
        fn = self._ExecDrbd8Secondary
6622 2bb5c911 Michael Hanselmann
      else:
6623 a4eae71f Michael Hanselmann
        fn = self._ExecDrbd8DiskOnly
6624 a4eae71f Michael Hanselmann
6625 a4eae71f Michael Hanselmann
      return fn(feedback_fn)
6626 2bb5c911 Michael Hanselmann
6627 2bb5c911 Michael Hanselmann
    finally:
6628 5c983ee5 Iustin Pop
      # Deactivate the instance disks if we're replacing them on a
6629 5c983ee5 Iustin Pop
      # down instance
6630 2bb5c911 Michael Hanselmann
      if activate_disks:
6631 2bb5c911 Michael Hanselmann
        _SafeShutdownInstanceDisks(self.lu, self.instance)
6632 2bb5c911 Michael Hanselmann
6633 2bb5c911 Michael Hanselmann
  def _CheckVolumeGroup(self, nodes):
6634 2bb5c911 Michael Hanselmann
    self.lu.LogInfo("Checking volume groups")
6635 2bb5c911 Michael Hanselmann
6636 a9e0c397 Iustin Pop
    vgname = self.cfg.GetVGName()
6637 cff90b79 Iustin Pop
6638 2bb5c911 Michael Hanselmann
    # Make sure volume group exists on all involved nodes
6639 2bb5c911 Michael Hanselmann
    results = self.rpc.call_vg_list(nodes)
6640 cff90b79 Iustin Pop
    if not results:
6641 cff90b79 Iustin Pop
      raise errors.OpExecError("Can't list volume groups on the nodes")
6642 2bb5c911 Michael Hanselmann
6643 2bb5c911 Michael Hanselmann
    for node in nodes:
6644 781de953 Iustin Pop
      res = results[node]
6645 4c4e4e1e Iustin Pop
      res.Raise("Error checking node %s" % node)
6646 2bb5c911 Michael Hanselmann
      if vgname not in res.payload:
6647 2bb5c911 Michael Hanselmann
        raise errors.OpExecError("Volume group '%s' not found on node %s" %
6648 2bb5c911 Michael Hanselmann
                                 (vgname, node))
6649 2bb5c911 Michael Hanselmann
6650 2bb5c911 Michael Hanselmann
  def _CheckDisksExistence(self, nodes):
6651 2bb5c911 Michael Hanselmann
    # Check disk existence
6652 2bb5c911 Michael Hanselmann
    for idx, dev in enumerate(self.instance.disks):
6653 2bb5c911 Michael Hanselmann
      if idx not in self.disks:
6654 cff90b79 Iustin Pop
        continue
6655 2bb5c911 Michael Hanselmann
6656 2bb5c911 Michael Hanselmann
      for node in nodes:
6657 2bb5c911 Michael Hanselmann
        self.lu.LogInfo("Checking disk/%d on %s" % (idx, node))
6658 2bb5c911 Michael Hanselmann
        self.cfg.SetDiskID(dev, node)
6659 2bb5c911 Michael Hanselmann
6660 23829f6f Iustin Pop
        result = self.rpc.call_blockdev_find(node, dev)
6661 2bb5c911 Michael Hanselmann
6662 4c4e4e1e Iustin Pop
        msg = result.fail_msg
6663 2bb5c911 Michael Hanselmann
        if msg or not result.payload:
6664 2bb5c911 Michael Hanselmann
          if not msg:
6665 2bb5c911 Michael Hanselmann
            msg = "disk not found"
6666 23829f6f Iustin Pop
          raise errors.OpExecError("Can't find disk/%d on node %s: %s" %
6667 23829f6f Iustin Pop
                                   (idx, node, msg))
6668 cff90b79 Iustin Pop
6669 2bb5c911 Michael Hanselmann
  def _CheckDisksConsistency(self, node_name, on_primary, ldisk):
6670 2bb5c911 Michael Hanselmann
    for idx, dev in enumerate(self.instance.disks):
6671 2bb5c911 Michael Hanselmann
      if idx not in self.disks:
6672 cff90b79 Iustin Pop
        continue
6673 cff90b79 Iustin Pop
6674 2bb5c911 Michael Hanselmann
      self.lu.LogInfo("Checking disk/%d consistency on node %s" %
6675 2bb5c911 Michael Hanselmann
                      (idx, node_name))
6676 2bb5c911 Michael Hanselmann
6677 2bb5c911 Michael Hanselmann
      if not _CheckDiskConsistency(self.lu, dev, node_name, on_primary,
6678 2bb5c911 Michael Hanselmann
                                   ldisk=ldisk):
6679 2bb5c911 Michael Hanselmann
        raise errors.OpExecError("Node %s has degraded storage, unsafe to"
6680 2bb5c911 Michael Hanselmann
                                 " replace disks for instance %s" %
6681 2bb5c911 Michael Hanselmann
                                 (node_name, self.instance.name))
6682 2bb5c911 Michael Hanselmann
6683 2bb5c911 Michael Hanselmann
  def _CreateNewStorage(self, node_name):
6684 2bb5c911 Michael Hanselmann
    vgname = self.cfg.GetVGName()
6685 2bb5c911 Michael Hanselmann
    iv_names = {}
6686 2bb5c911 Michael Hanselmann
6687 2bb5c911 Michael Hanselmann
    for idx, dev in enumerate(self.instance.disks):
6688 2bb5c911 Michael Hanselmann
      if idx not in self.disks:
6689 a9e0c397 Iustin Pop
        continue
6690 2bb5c911 Michael Hanselmann
6691 2bb5c911 Michael Hanselmann
      self.lu.LogInfo("Adding storage on %s for disk/%d" % (node_name, idx))
6692 2bb5c911 Michael Hanselmann
6693 2bb5c911 Michael Hanselmann
      self.cfg.SetDiskID(dev, node_name)
6694 2bb5c911 Michael Hanselmann
6695 2bb5c911 Michael Hanselmann
      lv_names = [".disk%d_%s" % (idx, suffix) for suffix in ["data", "meta"]]
6696 2bb5c911 Michael Hanselmann
      names = _GenerateUniqueNames(self.lu, lv_names)
6697 2bb5c911 Michael Hanselmann
6698 2bb5c911 Michael Hanselmann
      lv_data = objects.Disk(dev_type=constants.LD_LV, size=dev.size,
6699 a9e0c397 Iustin Pop
                             logical_id=(vgname, names[0]))
6700 a9e0c397 Iustin Pop
      lv_meta = objects.Disk(dev_type=constants.LD_LV, size=128,
6701 a9e0c397 Iustin Pop
                             logical_id=(vgname, names[1]))
6702 2bb5c911 Michael Hanselmann
6703 a9e0c397 Iustin Pop
      new_lvs = [lv_data, lv_meta]
6704 a9e0c397 Iustin Pop
      old_lvs = dev.children
6705 a9e0c397 Iustin Pop
      iv_names[dev.iv_name] = (dev, old_lvs, new_lvs)
6706 2bb5c911 Michael Hanselmann
6707 428958aa Iustin Pop
      # we pass force_create=True to force the LVM creation
6708 a9e0c397 Iustin Pop
      for new_lv in new_lvs:
6709 2bb5c911 Michael Hanselmann
        _CreateBlockDev(self.lu, node_name, self.instance, new_lv, True,
6710 2bb5c911 Michael Hanselmann
                        _GetInstanceInfoText(self.instance), False)
6711 2bb5c911 Michael Hanselmann
6712 2bb5c911 Michael Hanselmann
    return iv_names
6713 2bb5c911 Michael Hanselmann
6714 2bb5c911 Michael Hanselmann
  def _CheckDevices(self, node_name, iv_names):
6715 2bb5c911 Michael Hanselmann
    for name, (dev, old_lvs, new_lvs) in iv_names.iteritems():
6716 2bb5c911 Michael Hanselmann
      self.cfg.SetDiskID(dev, node_name)
6717 2bb5c911 Michael Hanselmann
6718 2bb5c911 Michael Hanselmann
      result = self.rpc.call_blockdev_find(node_name, dev)
6719 2bb5c911 Michael Hanselmann
6720 2bb5c911 Michael Hanselmann
      msg = result.fail_msg
6721 2bb5c911 Michael Hanselmann
      if msg or not result.payload:
6722 2bb5c911 Michael Hanselmann
        if not msg:
6723 2bb5c911 Michael Hanselmann
          msg = "disk not found"
6724 2bb5c911 Michael Hanselmann
        raise errors.OpExecError("Can't find DRBD device %s: %s" %
6725 2bb5c911 Michael Hanselmann
                                 (name, msg))
6726 2bb5c911 Michael Hanselmann
6727 96acbc09 Michael Hanselmann
      if result.payload.is_degraded:
6728 2bb5c911 Michael Hanselmann
        raise errors.OpExecError("DRBD device %s is degraded!" % name)
6729 2bb5c911 Michael Hanselmann
6730 2bb5c911 Michael Hanselmann
  def _RemoveOldStorage(self, node_name, iv_names):
6731 2bb5c911 Michael Hanselmann
    for name, (dev, old_lvs, _) in iv_names.iteritems():
6732 2bb5c911 Michael Hanselmann
      self.lu.LogInfo("Remove logical volumes for %s" % name)
6733 2bb5c911 Michael Hanselmann
6734 2bb5c911 Michael Hanselmann
      for lv in old_lvs:
6735 2bb5c911 Michael Hanselmann
        self.cfg.SetDiskID(lv, node_name)
6736 2bb5c911 Michael Hanselmann
6737 2bb5c911 Michael Hanselmann
        msg = self.rpc.call_blockdev_remove(node_name, lv).fail_msg
6738 2bb5c911 Michael Hanselmann
        if msg:
6739 2bb5c911 Michael Hanselmann
          self.lu.LogWarning("Can't remove old LV: %s" % msg,
6740 2bb5c911 Michael Hanselmann
                             hint="remove unused LVs manually")
6741 2bb5c911 Michael Hanselmann
6742 a4eae71f Michael Hanselmann
  def _ExecDrbd8DiskOnly(self, feedback_fn):
6743 2bb5c911 Michael Hanselmann
    """Replace a disk on the primary or secondary for DRBD 8.
6744 2bb5c911 Michael Hanselmann

6745 2bb5c911 Michael Hanselmann
    The algorithm for replace is quite complicated:
6746 2bb5c911 Michael Hanselmann

6747 2bb5c911 Michael Hanselmann
      1. for each disk to be replaced:
6748 2bb5c911 Michael Hanselmann

6749 2bb5c911 Michael Hanselmann
        1. create new LVs on the target node with unique names
6750 2bb5c911 Michael Hanselmann
        1. detach old LVs from the drbd device
6751 2bb5c911 Michael Hanselmann
        1. rename old LVs to name_replaced.<time_t>
6752 2bb5c911 Michael Hanselmann
        1. rename new LVs to old LVs
6753 2bb5c911 Michael Hanselmann
        1. attach the new LVs (with the old names now) to the drbd device
6754 2bb5c911 Michael Hanselmann

6755 2bb5c911 Michael Hanselmann
      1. wait for sync across all devices
6756 2bb5c911 Michael Hanselmann

6757 2bb5c911 Michael Hanselmann
      1. for each modified disk:
6758 2bb5c911 Michael Hanselmann

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

6761 2bb5c911 Michael Hanselmann
    Failures are not very well handled.
6762 2bb5c911 Michael Hanselmann

6763 2bb5c911 Michael Hanselmann
    """
6764 2bb5c911 Michael Hanselmann
    steps_total = 6
6765 2bb5c911 Michael Hanselmann
6766 2bb5c911 Michael Hanselmann
    # Step: check device activation
6767 2bb5c911 Michael Hanselmann
    self.lu.LogStep(1, steps_total, "Check device existence")
6768 2bb5c911 Michael Hanselmann
    self._CheckDisksExistence([self.other_node, self.target_node])
6769 2bb5c911 Michael Hanselmann
    self._CheckVolumeGroup([self.target_node, self.other_node])
6770 2bb5c911 Michael Hanselmann
6771 2bb5c911 Michael Hanselmann
    # Step: check other node consistency
6772 2bb5c911 Michael Hanselmann
    self.lu.LogStep(2, steps_total, "Check peer consistency")
6773 2bb5c911 Michael Hanselmann
    self._CheckDisksConsistency(self.other_node,
6774 2bb5c911 Michael Hanselmann
                                self.other_node == self.instance.primary_node,
6775 2bb5c911 Michael Hanselmann
                                False)
6776 2bb5c911 Michael Hanselmann
6777 2bb5c911 Michael Hanselmann
    # Step: create new storage
6778 2bb5c911 Michael Hanselmann
    self.lu.LogStep(3, steps_total, "Allocate new storage")
6779 2bb5c911 Michael Hanselmann
    iv_names = self._CreateNewStorage(self.target_node)
6780 a9e0c397 Iustin Pop
6781 cff90b79 Iustin Pop
    # Step: for each lv, detach+rename*2+attach
6782 2bb5c911 Michael Hanselmann
    self.lu.LogStep(4, steps_total, "Changing drbd configuration")
6783 cff90b79 Iustin Pop
    for dev, old_lvs, new_lvs in iv_names.itervalues():
6784 2bb5c911 Michael Hanselmann
      self.lu.LogInfo("Detaching %s drbd from local storage" % dev.iv_name)
6785 2bb5c911 Michael Hanselmann
6786 4d4a651d Michael Hanselmann
      result = self.rpc.call_blockdev_removechildren(self.target_node, dev,
6787 4d4a651d Michael Hanselmann
                                                     old_lvs)
6788 4c4e4e1e Iustin Pop
      result.Raise("Can't detach drbd from local storage on node"
6789 2bb5c911 Michael Hanselmann
                   " %s for device %s" % (self.target_node, dev.iv_name))
6790 cff90b79 Iustin Pop
      #dev.children = []
6791 cff90b79 Iustin Pop
      #cfg.Update(instance)
6792 a9e0c397 Iustin Pop
6793 a9e0c397 Iustin Pop
      # ok, we created the new LVs, so now we know we have the needed
6794 a9e0c397 Iustin Pop
      # storage; as such, we proceed on the target node to rename
6795 a9e0c397 Iustin Pop
      # old_lv to _old, and new_lv to old_lv; note that we rename LVs
6796 c99a3cc0 Manuel Franceschini
      # using the assumption that logical_id == physical_id (which in
6797 a9e0c397 Iustin Pop
      # turn is the unique_id on that node)
6798 cff90b79 Iustin Pop
6799 cff90b79 Iustin Pop
      # FIXME(iustin): use a better name for the replaced LVs
6800 a9e0c397 Iustin Pop
      temp_suffix = int(time.time())
6801 a9e0c397 Iustin Pop
      ren_fn = lambda d, suff: (d.physical_id[0],
6802 a9e0c397 Iustin Pop
                                d.physical_id[1] + "_replaced-%s" % suff)
6803 2bb5c911 Michael Hanselmann
6804 2bb5c911 Michael Hanselmann
      # Build the rename list based on what LVs exist on the node
6805 2bb5c911 Michael Hanselmann
      rename_old_to_new = []
6806 cff90b79 Iustin Pop
      for to_ren in old_lvs:
6807 2bb5c911 Michael Hanselmann
        result = self.rpc.call_blockdev_find(self.target_node, to_ren)
6808 4c4e4e1e Iustin Pop
        if not result.fail_msg and result.payload:
6809 23829f6f Iustin Pop
          # device exists
6810 2bb5c911 Michael Hanselmann
          rename_old_to_new.append((to_ren, ren_fn(to_ren, temp_suffix)))
6811 cff90b79 Iustin Pop
6812 2bb5c911 Michael Hanselmann
      self.lu.LogInfo("Renaming the old LVs on the target node")
6813 4d4a651d Michael Hanselmann
      result = self.rpc.call_blockdev_rename(self.target_node,
6814 4d4a651d Michael Hanselmann
                                             rename_old_to_new)
6815 2bb5c911 Michael Hanselmann
      result.Raise("Can't rename old LVs on node %s" % self.target_node)
6816 2bb5c911 Michael Hanselmann
6817 2bb5c911 Michael Hanselmann
      # Now we rename the new LVs to the old LVs
6818 2bb5c911 Michael Hanselmann
      self.lu.LogInfo("Renaming the new LVs on the target node")
6819 2bb5c911 Michael Hanselmann
      rename_new_to_old = [(new, old.physical_id)
6820 2bb5c911 Michael Hanselmann
                           for old, new in zip(old_lvs, new_lvs)]
6821 4d4a651d Michael Hanselmann
      result = self.rpc.call_blockdev_rename(self.target_node,
6822 4d4a651d Michael Hanselmann
                                             rename_new_to_old)
6823 2bb5c911 Michael Hanselmann
      result.Raise("Can't rename new LVs on node %s" % self.target_node)
6824 cff90b79 Iustin Pop
6825 cff90b79 Iustin Pop
      for old, new in zip(old_lvs, new_lvs):
6826 cff90b79 Iustin Pop
        new.logical_id = old.logical_id
6827 2bb5c911 Michael Hanselmann
        self.cfg.SetDiskID(new, self.target_node)
6828 a9e0c397 Iustin Pop
6829 cff90b79 Iustin Pop
      for disk in old_lvs:
6830 cff90b79 Iustin Pop
        disk.logical_id = ren_fn(disk, temp_suffix)
6831 2bb5c911 Michael Hanselmann
        self.cfg.SetDiskID(disk, self.target_node)
6832 a9e0c397 Iustin Pop
6833 2bb5c911 Michael Hanselmann
      # Now that the new lvs have the old name, we can add them to the device
6834 2bb5c911 Michael Hanselmann
      self.lu.LogInfo("Adding new mirror component on %s" % self.target_node)
6835 4d4a651d Michael Hanselmann
      result = self.rpc.call_blockdev_addchildren(self.target_node, dev,
6836 4d4a651d Michael Hanselmann
                                                  new_lvs)
6837 4c4e4e1e Iustin Pop
      msg = result.fail_msg
6838 2cc1da8b Iustin Pop
      if msg:
6839 a9e0c397 Iustin Pop
        for new_lv in new_lvs:
6840 4d4a651d Michael Hanselmann
          msg2 = self.rpc.call_blockdev_remove(self.target_node,
6841 4d4a651d Michael Hanselmann
                                               new_lv).fail_msg
6842 4c4e4e1e Iustin Pop
          if msg2:
6843 2bb5c911 Michael Hanselmann
            self.lu.LogWarning("Can't rollback device %s: %s", dev, msg2,
6844 2bb5c911 Michael Hanselmann
                               hint=("cleanup manually the unused logical"
6845 2bb5c911 Michael Hanselmann
                                     "volumes"))
6846 2cc1da8b Iustin Pop
        raise errors.OpExecError("Can't add local storage to drbd: %s" % msg)
6847 a9e0c397 Iustin Pop
6848 a9e0c397 Iustin Pop
      dev.children = new_lvs
6849 a9e0c397 Iustin Pop
6850 a4eae71f Michael Hanselmann
      self.cfg.Update(self.instance, feedback_fn)
6851 a9e0c397 Iustin Pop
6852 2bb5c911 Michael Hanselmann
    # Wait for sync
6853 2bb5c911 Michael Hanselmann
    # This can fail as the old devices are degraded and _WaitForSync
6854 2bb5c911 Michael Hanselmann
    # does a combined result over all disks, so we don't check its return value
6855 2bb5c911 Michael Hanselmann
    self.lu.LogStep(5, steps_total, "Sync devices")
6856 2bb5c911 Michael Hanselmann
    _WaitForSync(self.lu, self.instance, unlock=True)
6857 a9e0c397 Iustin Pop
6858 2bb5c911 Michael Hanselmann
    # Check all devices manually
6859 2bb5c911 Michael Hanselmann
    self._CheckDevices(self.instance.primary_node, iv_names)
6860 a9e0c397 Iustin Pop
6861 cff90b79 Iustin Pop
    # Step: remove old storage
6862 2bb5c911 Michael Hanselmann
    self.lu.LogStep(6, steps_total, "Removing old storage")
6863 2bb5c911 Michael Hanselmann
    self._RemoveOldStorage(self.target_node, iv_names)
6864 a9e0c397 Iustin Pop
6865 a4eae71f Michael Hanselmann
  def _ExecDrbd8Secondary(self, feedback_fn):
6866 2bb5c911 Michael Hanselmann
    """Replace the secondary node for DRBD 8.
6867 a9e0c397 Iustin Pop

6868 a9e0c397 Iustin Pop
    The algorithm for replace is quite complicated:
6869 a9e0c397 Iustin Pop
      - for all disks of the instance:
6870 a9e0c397 Iustin Pop
        - create new LVs on the new node with same names
6871 a9e0c397 Iustin Pop
        - shutdown the drbd device on the old secondary
6872 a9e0c397 Iustin Pop
        - disconnect the drbd network on the primary
6873 a9e0c397 Iustin Pop
        - create the drbd device on the new secondary
6874 a9e0c397 Iustin Pop
        - network attach the drbd on the primary, using an artifice:
6875 a9e0c397 Iustin Pop
          the drbd code for Attach() will connect to the network if it
6876 a9e0c397 Iustin Pop
          finds a device which is connected to the good local disks but
6877 a9e0c397 Iustin Pop
          not network enabled
6878 a9e0c397 Iustin Pop
      - wait for sync across all devices
6879 a9e0c397 Iustin Pop
      - remove all disks from the old secondary
6880 a9e0c397 Iustin Pop

6881 a9e0c397 Iustin Pop
    Failures are not very well handled.
6882 0834c866 Iustin Pop

6883 a9e0c397 Iustin Pop
    """
6884 0834c866 Iustin Pop
    steps_total = 6
6885 0834c866 Iustin Pop
6886 0834c866 Iustin Pop
    # Step: check device activation
6887 2bb5c911 Michael Hanselmann
    self.lu.LogStep(1, steps_total, "Check device existence")
6888 2bb5c911 Michael Hanselmann
    self._CheckDisksExistence([self.instance.primary_node])
6889 2bb5c911 Michael Hanselmann
    self._CheckVolumeGroup([self.instance.primary_node])
6890 0834c866 Iustin Pop
6891 0834c866 Iustin Pop
    # Step: check other node consistency
6892 2bb5c911 Michael Hanselmann
    self.lu.LogStep(2, steps_total, "Check peer consistency")
6893 2bb5c911 Michael Hanselmann
    self._CheckDisksConsistency(self.instance.primary_node, True, True)
6894 0834c866 Iustin Pop
6895 0834c866 Iustin Pop
    # Step: create new storage
6896 2bb5c911 Michael Hanselmann
    self.lu.LogStep(3, steps_total, "Allocate new storage")
6897 2bb5c911 Michael Hanselmann
    for idx, dev in enumerate(self.instance.disks):
6898 2bb5c911 Michael Hanselmann
      self.lu.LogInfo("Adding new local storage on %s for disk/%d" %
6899 2bb5c911 Michael Hanselmann
                      (self.new_node, idx))
6900 428958aa Iustin Pop
      # we pass force_create=True to force LVM creation
6901 a9e0c397 Iustin Pop
      for new_lv in dev.children:
6902 2bb5c911 Michael Hanselmann
        _CreateBlockDev(self.lu, self.new_node, self.instance, new_lv, True,
6903 2bb5c911 Michael Hanselmann
                        _GetInstanceInfoText(self.instance), False)
6904 a9e0c397 Iustin Pop
6905 468b46f9 Iustin Pop
    # Step 4: dbrd minors and drbd setups changes
6906 a1578d63 Iustin Pop
    # after this, we must manually remove the drbd minors on both the
6907 a1578d63 Iustin Pop
    # error and the success paths
6908 2bb5c911 Michael Hanselmann
    self.lu.LogStep(4, steps_total, "Changing drbd configuration")
6909 4d4a651d Michael Hanselmann
    minors = self.cfg.AllocateDRBDMinor([self.new_node
6910 4d4a651d Michael Hanselmann
                                         for dev in self.instance.disks],
6911 2bb5c911 Michael Hanselmann
                                        self.instance.name)
6912 099c52ad Iustin Pop
    logging.debug("Allocated minors %r", minors)
6913 2bb5c911 Michael Hanselmann
6914 2bb5c911 Michael Hanselmann
    iv_names = {}
6915 2bb5c911 Michael Hanselmann
    for idx, (dev, new_minor) in enumerate(zip(self.instance.disks, minors)):
6916 4d4a651d Michael Hanselmann
      self.lu.LogInfo("activating a new drbd on %s for disk/%d" %
6917 4d4a651d Michael Hanselmann
                      (self.new_node, idx))
6918 a2d59d8b Iustin Pop
      # create new devices on new_node; note that we create two IDs:
6919 a2d59d8b Iustin Pop
      # one without port, so the drbd will be activated without
6920 a2d59d8b Iustin Pop
      # networking information on the new node at this stage, and one
6921 a2d59d8b Iustin Pop
      # with network, for the latter activation in step 4
6922 a2d59d8b Iustin Pop
      (o_node1, o_node2, o_port, o_minor1, o_minor2, o_secret) = dev.logical_id
6923 2bb5c911 Michael Hanselmann
      if self.instance.primary_node == o_node1:
6924 a2d59d8b Iustin Pop
        p_minor = o_minor1
6925 ffa1c0dc Iustin Pop
      else:
6926 a2d59d8b Iustin Pop
        p_minor = o_minor2
6927 a2d59d8b Iustin Pop
6928 4d4a651d Michael Hanselmann
      new_alone_id = (self.instance.primary_node, self.new_node, None,
6929 4d4a651d Michael Hanselmann
                      p_minor, new_minor, o_secret)
6930 4d4a651d Michael Hanselmann
      new_net_id = (self.instance.primary_node, self.new_node, o_port,
6931 4d4a651d Michael Hanselmann
                    p_minor, new_minor, o_secret)
6932 a2d59d8b Iustin Pop
6933 a2d59d8b Iustin Pop
      iv_names[idx] = (dev, dev.children, new_net_id)
6934 a1578d63 Iustin Pop
      logging.debug("Allocated new_minor: %s, new_logical_id: %s", new_minor,
6935 a2d59d8b Iustin Pop
                    new_net_id)
6936 a9e0c397 Iustin Pop
      new_drbd = objects.Disk(dev_type=constants.LD_DRBD8,
6937 a2d59d8b Iustin Pop
                              logical_id=new_alone_id,
6938 8a6c7011 Iustin Pop
                              children=dev.children,
6939 8a6c7011 Iustin Pop
                              size=dev.size)
6940 796cab27 Iustin Pop
      try:
6941 2bb5c911 Michael Hanselmann
        _CreateSingleBlockDev(self.lu, self.new_node, self.instance, new_drbd,
6942 2bb5c911 Michael Hanselmann
                              _GetInstanceInfoText(self.instance), False)
6943 82759cb1 Iustin Pop
      except errors.GenericError:
6944 2bb5c911 Michael Hanselmann
        self.cfg.ReleaseDRBDMinors(self.instance.name)
6945 796cab27 Iustin Pop
        raise
6946 a9e0c397 Iustin Pop
6947 2bb5c911 Michael Hanselmann
    # We have new devices, shutdown the drbd on the old secondary
6948 2bb5c911 Michael Hanselmann
    for idx, dev in enumerate(self.instance.disks):
6949 2bb5c911 Michael Hanselmann
      self.lu.LogInfo("Shutting down drbd for disk/%d on old node" % idx)
6950 2bb5c911 Michael Hanselmann
      self.cfg.SetDiskID(dev, self.target_node)
6951 2bb5c911 Michael Hanselmann
      msg = self.rpc.call_blockdev_shutdown(self.target_node, dev).fail_msg
6952 cacfd1fd Iustin Pop
      if msg:
6953 2bb5c911 Michael Hanselmann
        self.lu.LogWarning("Failed to shutdown drbd for disk/%d on old"
6954 2bb5c911 Michael Hanselmann
                           "node: %s" % (idx, msg),
6955 2bb5c911 Michael Hanselmann
                           hint=("Please cleanup this device manually as"
6956 2bb5c911 Michael Hanselmann
                                 " soon as possible"))
6957 a9e0c397 Iustin Pop
6958 2bb5c911 Michael Hanselmann
    self.lu.LogInfo("Detaching primary drbds from the network (=> standalone)")
6959 4d4a651d Michael Hanselmann
    result = self.rpc.call_drbd_disconnect_net([self.instance.primary_node],
6960 4d4a651d Michael Hanselmann
                                               self.node_secondary_ip,
6961 4d4a651d Michael Hanselmann
                                               self.instance.disks)\
6962 4d4a651d Michael Hanselmann
                                              [self.instance.primary_node]
6963 642445d9 Iustin Pop
6964 4c4e4e1e Iustin Pop
    msg = result.fail_msg
6965 a2d59d8b Iustin Pop
    if msg:
6966 a2d59d8b Iustin Pop
      # detaches didn't succeed (unlikely)
6967 2bb5c911 Michael Hanselmann
      self.cfg.ReleaseDRBDMinors(self.instance.name)
6968 a2d59d8b Iustin Pop
      raise errors.OpExecError("Can't detach the disks from the network on"
6969 a2d59d8b Iustin Pop
                               " old node: %s" % (msg,))
6970 642445d9 Iustin Pop
6971 642445d9 Iustin Pop
    # if we managed to detach at least one, we update all the disks of
6972 642445d9 Iustin Pop
    # the instance to point to the new secondary
6973 2bb5c911 Michael Hanselmann
    self.lu.LogInfo("Updating instance configuration")
6974 468b46f9 Iustin Pop
    for dev, _, new_logical_id in iv_names.itervalues():
6975 468b46f9 Iustin Pop
      dev.logical_id = new_logical_id
6976 2bb5c911 Michael Hanselmann
      self.cfg.SetDiskID(dev, self.instance.primary_node)
6977 2bb5c911 Michael Hanselmann
6978 a4eae71f Michael Hanselmann
    self.cfg.Update(self.instance, feedback_fn)
6979 a9e0c397 Iustin Pop
6980 642445d9 Iustin Pop
    # and now perform the drbd attach
6981 2bb5c911 Michael Hanselmann
    self.lu.LogInfo("Attaching primary drbds to new secondary"
6982 2bb5c911 Michael Hanselmann
                    " (standalone => connected)")
6983 4d4a651d Michael Hanselmann
    result = self.rpc.call_drbd_attach_net([self.instance.primary_node,
6984 4d4a651d Michael Hanselmann
                                            self.new_node],
6985 4d4a651d Michael Hanselmann
                                           self.node_secondary_ip,
6986 4d4a651d Michael Hanselmann
                                           self.instance.disks,
6987 4d4a651d Michael Hanselmann
                                           self.instance.name,
6988 a2d59d8b Iustin Pop
                                           False)
6989 a2d59d8b Iustin Pop
    for to_node, to_result in result.items():
6990 4c4e4e1e Iustin Pop
      msg = to_result.fail_msg
6991 a2d59d8b Iustin Pop
      if msg:
6992 4d4a651d Michael Hanselmann
        self.lu.LogWarning("Can't attach drbd disks on node %s: %s",
6993 4d4a651d Michael Hanselmann
                           to_node, msg,
6994 2bb5c911 Michael Hanselmann
                           hint=("please do a gnt-instance info to see the"
6995 2bb5c911 Michael Hanselmann
                                 " status of disks"))
6996 a9e0c397 Iustin Pop
6997 2bb5c911 Michael Hanselmann
    # Wait for sync
6998 2bb5c911 Michael Hanselmann
    # This can fail as the old devices are degraded and _WaitForSync
6999 2bb5c911 Michael Hanselmann
    # does a combined result over all disks, so we don't check its return value
7000 2bb5c911 Michael Hanselmann
    self.lu.LogStep(5, steps_total, "Sync devices")
7001 2bb5c911 Michael Hanselmann
    _WaitForSync(self.lu, self.instance, unlock=True)
7002 a9e0c397 Iustin Pop
7003 2bb5c911 Michael Hanselmann
    # Check all devices manually
7004 2bb5c911 Michael Hanselmann
    self._CheckDevices(self.instance.primary_node, iv_names)
7005 22985314 Guido Trotter
7006 2bb5c911 Michael Hanselmann
    # Step: remove old storage
7007 2bb5c911 Michael Hanselmann
    self.lu.LogStep(6, steps_total, "Removing old storage")
7008 2bb5c911 Michael Hanselmann
    self._RemoveOldStorage(self.target_node, iv_names)
7009 a9e0c397 Iustin Pop
7010 a8083063 Iustin Pop
7011 76aef8fc Michael Hanselmann
class LURepairNodeStorage(NoHooksLU):
7012 76aef8fc Michael Hanselmann
  """Repairs the volume group on a node.
7013 76aef8fc Michael Hanselmann

7014 76aef8fc Michael Hanselmann
  """
7015 76aef8fc Michael Hanselmann
  _OP_REQP = ["node_name"]
7016 76aef8fc Michael Hanselmann
  REQ_BGL = False
7017 76aef8fc Michael Hanselmann
7018 76aef8fc Michael Hanselmann
  def CheckArguments(self):
7019 76aef8fc Michael Hanselmann
    node_name = self.cfg.ExpandNodeName(self.op.node_name)
7020 76aef8fc Michael Hanselmann
    if node_name is None:
7021 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Invalid node name '%s'" % self.op.node_name,
7022 5c983ee5 Iustin Pop
                                 errors.ECODE_NOENT)
7023 76aef8fc Michael Hanselmann
7024 76aef8fc Michael Hanselmann
    self.op.node_name = node_name
7025 76aef8fc Michael Hanselmann
7026 76aef8fc Michael Hanselmann
  def ExpandNames(self):
7027 76aef8fc Michael Hanselmann
    self.needed_locks = {
7028 76aef8fc Michael Hanselmann
      locking.LEVEL_NODE: [self.op.node_name],
7029 76aef8fc Michael Hanselmann
      }
7030 76aef8fc Michael Hanselmann
7031 76aef8fc Michael Hanselmann
  def _CheckFaultyDisks(self, instance, node_name):
7032 7e9c6a78 Iustin Pop
    """Ensure faulty disks abort the opcode or at least warn."""
7033 7e9c6a78 Iustin Pop
    try:
7034 7e9c6a78 Iustin Pop
      if _FindFaultyInstanceDisks(self.cfg, self.rpc, instance,
7035 7e9c6a78 Iustin Pop
                                  node_name, True):
7036 7e9c6a78 Iustin Pop
        raise errors.OpPrereqError("Instance '%s' has faulty disks on"
7037 7e9c6a78 Iustin Pop
                                   " node '%s'" % (instance.name, node_name),
7038 7e9c6a78 Iustin Pop
                                   errors.ECODE_STATE)
7039 7e9c6a78 Iustin Pop
    except errors.OpPrereqError, err:
7040 7e9c6a78 Iustin Pop
      if self.op.ignore_consistency:
7041 7e9c6a78 Iustin Pop
        self.proc.LogWarning(str(err.args[0]))
7042 7e9c6a78 Iustin Pop
      else:
7043 7e9c6a78 Iustin Pop
        raise
7044 76aef8fc Michael Hanselmann
7045 76aef8fc Michael Hanselmann
  def CheckPrereq(self):
7046 76aef8fc Michael Hanselmann
    """Check prerequisites.
7047 76aef8fc Michael Hanselmann

7048 76aef8fc Michael Hanselmann
    """
7049 76aef8fc Michael Hanselmann
    storage_type = self.op.storage_type
7050 76aef8fc Michael Hanselmann
7051 76aef8fc Michael Hanselmann
    if (constants.SO_FIX_CONSISTENCY not in
7052 76aef8fc Michael Hanselmann
        constants.VALID_STORAGE_OPERATIONS.get(storage_type, [])):
7053 76aef8fc Michael Hanselmann
      raise errors.OpPrereqError("Storage units of type '%s' can not be"
7054 5c983ee5 Iustin Pop
                                 " repaired" % storage_type,
7055 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
7056 76aef8fc Michael Hanselmann
7057 76aef8fc Michael Hanselmann
    # Check whether any instance on this node has faulty disks
7058 76aef8fc Michael Hanselmann
    for inst in _GetNodeInstances(self.cfg, self.op.node_name):
7059 7e9c6a78 Iustin Pop
      if not inst.admin_up:
7060 7e9c6a78 Iustin Pop
        continue
7061 76aef8fc Michael Hanselmann
      check_nodes = set(inst.all_nodes)
7062 76aef8fc Michael Hanselmann
      check_nodes.discard(self.op.node_name)
7063 76aef8fc Michael Hanselmann
      for inst_node_name in check_nodes:
7064 76aef8fc Michael Hanselmann
        self._CheckFaultyDisks(inst, inst_node_name)
7065 76aef8fc Michael Hanselmann
7066 76aef8fc Michael Hanselmann
  def Exec(self, feedback_fn):
7067 76aef8fc Michael Hanselmann
    feedback_fn("Repairing storage unit '%s' on %s ..." %
7068 76aef8fc Michael Hanselmann
                (self.op.name, self.op.node_name))
7069 76aef8fc Michael Hanselmann
7070 76aef8fc Michael Hanselmann
    st_args = _GetStorageTypeArgs(self.cfg, self.op.storage_type)
7071 76aef8fc Michael Hanselmann
    result = self.rpc.call_storage_execute(self.op.node_name,
7072 76aef8fc Michael Hanselmann
                                           self.op.storage_type, st_args,
7073 76aef8fc Michael Hanselmann
                                           self.op.name,
7074 76aef8fc Michael Hanselmann
                                           constants.SO_FIX_CONSISTENCY)
7075 76aef8fc Michael Hanselmann
    result.Raise("Failed to repair storage unit '%s' on %s" %
7076 76aef8fc Michael Hanselmann
                 (self.op.name, self.op.node_name))
7077 76aef8fc Michael Hanselmann
7078 76aef8fc Michael Hanselmann
7079 8729e0d7 Iustin Pop
class LUGrowDisk(LogicalUnit):
7080 8729e0d7 Iustin Pop
  """Grow a disk of an instance.
7081 8729e0d7 Iustin Pop

7082 8729e0d7 Iustin Pop
  """
7083 8729e0d7 Iustin Pop
  HPATH = "disk-grow"
7084 8729e0d7 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
7085 6605411d Iustin Pop
  _OP_REQP = ["instance_name", "disk", "amount", "wait_for_sync"]
7086 31e63dbf Guido Trotter
  REQ_BGL = False
7087 31e63dbf Guido Trotter
7088 31e63dbf Guido Trotter
  def ExpandNames(self):
7089 31e63dbf Guido Trotter
    self._ExpandAndLockInstance()
7090 31e63dbf Guido Trotter
    self.needed_locks[locking.LEVEL_NODE] = []
7091 f6d9a522 Guido Trotter
    self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
7092 31e63dbf Guido Trotter
7093 31e63dbf Guido Trotter
  def DeclareLocks(self, level):
7094 31e63dbf Guido Trotter
    if level == locking.LEVEL_NODE:
7095 31e63dbf Guido Trotter
      self._LockInstancesNodes()
7096 8729e0d7 Iustin Pop
7097 8729e0d7 Iustin Pop
  def BuildHooksEnv(self):
7098 8729e0d7 Iustin Pop
    """Build hooks env.
7099 8729e0d7 Iustin Pop

7100 8729e0d7 Iustin Pop
    This runs on the master, the primary and all the secondaries.
7101 8729e0d7 Iustin Pop

7102 8729e0d7 Iustin Pop
    """
7103 8729e0d7 Iustin Pop
    env = {
7104 8729e0d7 Iustin Pop
      "DISK": self.op.disk,
7105 8729e0d7 Iustin Pop
      "AMOUNT": self.op.amount,
7106 8729e0d7 Iustin Pop
      }
7107 338e51e8 Iustin Pop
    env.update(_BuildInstanceHookEnvByObject(self, self.instance))
7108 8729e0d7 Iustin Pop
    nl = [
7109 d6a02168 Michael Hanselmann
      self.cfg.GetMasterNode(),
7110 8729e0d7 Iustin Pop
      self.instance.primary_node,
7111 8729e0d7 Iustin Pop
      ]
7112 8729e0d7 Iustin Pop
    return env, nl, nl
7113 8729e0d7 Iustin Pop
7114 8729e0d7 Iustin Pop
  def CheckPrereq(self):
7115 8729e0d7 Iustin Pop
    """Check prerequisites.
7116 8729e0d7 Iustin Pop

7117 8729e0d7 Iustin Pop
    This checks that the instance is in the cluster.
7118 8729e0d7 Iustin Pop

7119 8729e0d7 Iustin Pop
    """
7120 31e63dbf Guido Trotter
    instance = self.cfg.GetInstanceInfo(self.op.instance_name)
7121 31e63dbf Guido Trotter
    assert instance is not None, \
7122 31e63dbf Guido Trotter
      "Cannot retrieve locked instance %s" % self.op.instance_name
7123 6b12959c Iustin Pop
    nodenames = list(instance.all_nodes)
7124 6b12959c Iustin Pop
    for node in nodenames:
7125 7527a8a4 Iustin Pop
      _CheckNodeOnline(self, node)
7126 7527a8a4 Iustin Pop
7127 31e63dbf Guido Trotter
7128 8729e0d7 Iustin Pop
    self.instance = instance
7129 8729e0d7 Iustin Pop
7130 8729e0d7 Iustin Pop
    if instance.disk_template not in (constants.DT_PLAIN, constants.DT_DRBD8):
7131 8729e0d7 Iustin Pop
      raise errors.OpPrereqError("Instance's disk layout does not support"
7132 5c983ee5 Iustin Pop
                                 " growing.", errors.ECODE_INVAL)
7133 8729e0d7 Iustin Pop
7134 ad24e046 Iustin Pop
    self.disk = instance.FindDisk(self.op.disk)
7135 8729e0d7 Iustin Pop
7136 72737a7f Iustin Pop
    nodeinfo = self.rpc.call_node_info(nodenames, self.cfg.GetVGName(),
7137 72737a7f Iustin Pop
                                       instance.hypervisor)
7138 8729e0d7 Iustin Pop
    for node in nodenames:
7139 781de953 Iustin Pop
      info = nodeinfo[node]
7140 4c4e4e1e Iustin Pop
      info.Raise("Cannot get current information from node %s" % node)
7141 070e998b Iustin Pop
      vg_free = info.payload.get('vg_free', None)
7142 8729e0d7 Iustin Pop
      if not isinstance(vg_free, int):
7143 8729e0d7 Iustin Pop
        raise errors.OpPrereqError("Can't compute free disk space on"
7144 5c983ee5 Iustin Pop
                                   " node %s" % node, errors.ECODE_ENVIRON)
7145 781de953 Iustin Pop
      if self.op.amount > vg_free:
7146 8729e0d7 Iustin Pop
        raise errors.OpPrereqError("Not enough disk space on target node %s:"
7147 8729e0d7 Iustin Pop
                                   " %d MiB available, %d MiB required" %
7148 5c983ee5 Iustin Pop
                                   (node, vg_free, self.op.amount),
7149 5c983ee5 Iustin Pop
                                   errors.ECODE_NORES)
7150 8729e0d7 Iustin Pop
7151 8729e0d7 Iustin Pop
  def Exec(self, feedback_fn):
7152 8729e0d7 Iustin Pop
    """Execute disk grow.
7153 8729e0d7 Iustin Pop

7154 8729e0d7 Iustin Pop
    """
7155 8729e0d7 Iustin Pop
    instance = self.instance
7156 ad24e046 Iustin Pop
    disk = self.disk
7157 6b12959c Iustin Pop
    for node in instance.all_nodes:
7158 8729e0d7 Iustin Pop
      self.cfg.SetDiskID(disk, node)
7159 72737a7f Iustin Pop
      result = self.rpc.call_blockdev_grow(node, disk, self.op.amount)
7160 4c4e4e1e Iustin Pop
      result.Raise("Grow request failed to node %s" % node)
7161 8729e0d7 Iustin Pop
    disk.RecordGrow(self.op.amount)
7162 a4eae71f Michael Hanselmann
    self.cfg.Update(instance, feedback_fn)
7163 6605411d Iustin Pop
    if self.op.wait_for_sync:
7164 cd4d138f Guido Trotter
      disk_abort = not _WaitForSync(self, instance)
7165 6605411d Iustin Pop
      if disk_abort:
7166 86d9d3bb Iustin Pop
        self.proc.LogWarning("Warning: disk sync-ing has not returned a good"
7167 86d9d3bb Iustin Pop
                             " status.\nPlease check the instance.")
7168 8729e0d7 Iustin Pop
7169 8729e0d7 Iustin Pop
7170 a8083063 Iustin Pop
class LUQueryInstanceData(NoHooksLU):
7171 a8083063 Iustin Pop
  """Query runtime instance data.
7172 a8083063 Iustin Pop

7173 a8083063 Iustin Pop
  """
7174 57821cac Iustin Pop
  _OP_REQP = ["instances", "static"]
7175 a987fa48 Guido Trotter
  REQ_BGL = False
7176 ae5849b5 Michael Hanselmann
7177 a987fa48 Guido Trotter
  def ExpandNames(self):
7178 a987fa48 Guido Trotter
    self.needed_locks = {}
7179 c772d142 Michael Hanselmann
    self.share_locks = dict.fromkeys(locking.LEVELS, 1)
7180 a987fa48 Guido Trotter
7181 a987fa48 Guido Trotter
    if not isinstance(self.op.instances, list):
7182 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Invalid argument type 'instances'",
7183 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
7184 a987fa48 Guido Trotter
7185 a987fa48 Guido Trotter
    if self.op.instances:
7186 a987fa48 Guido Trotter
      self.wanted_names = []
7187 a987fa48 Guido Trotter
      for name in self.op.instances:
7188 a987fa48 Guido Trotter
        full_name = self.cfg.ExpandInstanceName(name)
7189 a987fa48 Guido Trotter
        if full_name is None:
7190 5c983ee5 Iustin Pop
          raise errors.OpPrereqError("Instance '%s' not known" % name,
7191 5c983ee5 Iustin Pop
                                     errors.ECODE_NOENT)
7192 a987fa48 Guido Trotter
        self.wanted_names.append(full_name)
7193 a987fa48 Guido Trotter
      self.needed_locks[locking.LEVEL_INSTANCE] = self.wanted_names
7194 a987fa48 Guido Trotter
    else:
7195 a987fa48 Guido Trotter
      self.wanted_names = None
7196 a987fa48 Guido Trotter
      self.needed_locks[locking.LEVEL_INSTANCE] = locking.ALL_SET
7197 a987fa48 Guido Trotter
7198 a987fa48 Guido Trotter
    self.needed_locks[locking.LEVEL_NODE] = []
7199 a987fa48 Guido Trotter
    self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
7200 a987fa48 Guido Trotter
7201 a987fa48 Guido Trotter
  def DeclareLocks(self, level):
7202 a987fa48 Guido Trotter
    if level == locking.LEVEL_NODE:
7203 a987fa48 Guido Trotter
      self._LockInstancesNodes()
7204 a8083063 Iustin Pop
7205 a8083063 Iustin Pop
  def CheckPrereq(self):
7206 a8083063 Iustin Pop
    """Check prerequisites.
7207 a8083063 Iustin Pop

7208 a8083063 Iustin Pop
    This only checks the optional instance list against the existing names.
7209 a8083063 Iustin Pop

7210 a8083063 Iustin Pop
    """
7211 a987fa48 Guido Trotter
    if self.wanted_names is None:
7212 a987fa48 Guido Trotter
      self.wanted_names = self.acquired_locks[locking.LEVEL_INSTANCE]
7213 a8083063 Iustin Pop
7214 a987fa48 Guido Trotter
    self.wanted_instances = [self.cfg.GetInstanceInfo(name) for name
7215 a987fa48 Guido Trotter
                             in self.wanted_names]
7216 a987fa48 Guido Trotter
    return
7217 a8083063 Iustin Pop
7218 98825740 Michael Hanselmann
  def _ComputeBlockdevStatus(self, node, instance_name, dev):
7219 98825740 Michael Hanselmann
    """Returns the status of a block device
7220 98825740 Michael Hanselmann

7221 98825740 Michael Hanselmann
    """
7222 4dce1a83 Michael Hanselmann
    if self.op.static or not node:
7223 98825740 Michael Hanselmann
      return None
7224 98825740 Michael Hanselmann
7225 98825740 Michael Hanselmann
    self.cfg.SetDiskID(dev, node)
7226 98825740 Michael Hanselmann
7227 98825740 Michael Hanselmann
    result = self.rpc.call_blockdev_find(node, dev)
7228 98825740 Michael Hanselmann
    if result.offline:
7229 98825740 Michael Hanselmann
      return None
7230 98825740 Michael Hanselmann
7231 98825740 Michael Hanselmann
    result.Raise("Can't compute disk status for %s" % instance_name)
7232 98825740 Michael Hanselmann
7233 98825740 Michael Hanselmann
    status = result.payload
7234 ddfe2228 Michael Hanselmann
    if status is None:
7235 ddfe2228 Michael Hanselmann
      return None
7236 98825740 Michael Hanselmann
7237 98825740 Michael Hanselmann
    return (status.dev_path, status.major, status.minor,
7238 98825740 Michael Hanselmann
            status.sync_percent, status.estimated_time,
7239 f208978a Michael Hanselmann
            status.is_degraded, status.ldisk_status)
7240 98825740 Michael Hanselmann
7241 a8083063 Iustin Pop
  def _ComputeDiskStatus(self, instance, snode, dev):
7242 a8083063 Iustin Pop
    """Compute block device status.
7243 a8083063 Iustin Pop

7244 a8083063 Iustin Pop
    """
7245 a1f445d3 Iustin Pop
    if dev.dev_type in constants.LDS_DRBD:
7246 a8083063 Iustin Pop
      # we change the snode then (otherwise we use the one passed in)
7247 a8083063 Iustin Pop
      if dev.logical_id[0] == instance.primary_node:
7248 a8083063 Iustin Pop
        snode = dev.logical_id[1]
7249 a8083063 Iustin Pop
      else:
7250 a8083063 Iustin Pop
        snode = dev.logical_id[0]
7251 a8083063 Iustin Pop
7252 98825740 Michael Hanselmann
    dev_pstatus = self._ComputeBlockdevStatus(instance.primary_node,
7253 98825740 Michael Hanselmann
                                              instance.name, dev)
7254 98825740 Michael Hanselmann
    dev_sstatus = self._ComputeBlockdevStatus(snode, instance.name, dev)
7255 a8083063 Iustin Pop
7256 a8083063 Iustin Pop
    if dev.children:
7257 a8083063 Iustin Pop
      dev_children = [self._ComputeDiskStatus(instance, snode, child)
7258 a8083063 Iustin Pop
                      for child in dev.children]
7259 a8083063 Iustin Pop
    else:
7260 a8083063 Iustin Pop
      dev_children = []
7261 a8083063 Iustin Pop
7262 a8083063 Iustin Pop
    data = {
7263 a8083063 Iustin Pop
      "iv_name": dev.iv_name,
7264 a8083063 Iustin Pop
      "dev_type": dev.dev_type,
7265 a8083063 Iustin Pop
      "logical_id": dev.logical_id,
7266 a8083063 Iustin Pop
      "physical_id": dev.physical_id,
7267 a8083063 Iustin Pop
      "pstatus": dev_pstatus,
7268 a8083063 Iustin Pop
      "sstatus": dev_sstatus,
7269 a8083063 Iustin Pop
      "children": dev_children,
7270 b6fdf8b8 Iustin Pop
      "mode": dev.mode,
7271 c98162a7 Iustin Pop
      "size": dev.size,
7272 a8083063 Iustin Pop
      }
7273 a8083063 Iustin Pop
7274 a8083063 Iustin Pop
    return data
7275 a8083063 Iustin Pop
7276 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
7277 a8083063 Iustin Pop
    """Gather and return data"""
7278 a8083063 Iustin Pop
    result = {}
7279 338e51e8 Iustin Pop
7280 338e51e8 Iustin Pop
    cluster = self.cfg.GetClusterInfo()
7281 338e51e8 Iustin Pop
7282 a8083063 Iustin Pop
    for instance in self.wanted_instances:
7283 57821cac Iustin Pop
      if not self.op.static:
7284 57821cac Iustin Pop
        remote_info = self.rpc.call_instance_info(instance.primary_node,
7285 57821cac Iustin Pop
                                                  instance.name,
7286 57821cac Iustin Pop
                                                  instance.hypervisor)
7287 4c4e4e1e Iustin Pop
        remote_info.Raise("Error checking node %s" % instance.primary_node)
7288 7ad1af4a Iustin Pop
        remote_info = remote_info.payload
7289 57821cac Iustin Pop
        if remote_info and "state" in remote_info:
7290 57821cac Iustin Pop
          remote_state = "up"
7291 57821cac Iustin Pop
        else:
7292 57821cac Iustin Pop
          remote_state = "down"
7293 a8083063 Iustin Pop
      else:
7294 57821cac Iustin Pop
        remote_state = None
7295 0d68c45d Iustin Pop
      if instance.admin_up:
7296 a8083063 Iustin Pop
        config_state = "up"
7297 0d68c45d Iustin Pop
      else:
7298 0d68c45d Iustin Pop
        config_state = "down"
7299 a8083063 Iustin Pop
7300 a8083063 Iustin Pop
      disks = [self._ComputeDiskStatus(instance, None, device)
7301 a8083063 Iustin Pop
               for device in instance.disks]
7302 a8083063 Iustin Pop
7303 a8083063 Iustin Pop
      idict = {
7304 a8083063 Iustin Pop
        "name": instance.name,
7305 a8083063 Iustin Pop
        "config_state": config_state,
7306 a8083063 Iustin Pop
        "run_state": remote_state,
7307 a8083063 Iustin Pop
        "pnode": instance.primary_node,
7308 a8083063 Iustin Pop
        "snodes": instance.secondary_nodes,
7309 a8083063 Iustin Pop
        "os": instance.os,
7310 0b13832c Guido Trotter
        # this happens to be the same format used for hooks
7311 0b13832c Guido Trotter
        "nics": _NICListToTuple(self, instance.nics),
7312 a8083063 Iustin Pop
        "disks": disks,
7313 e69d05fd Iustin Pop
        "hypervisor": instance.hypervisor,
7314 24838135 Iustin Pop
        "network_port": instance.network_port,
7315 24838135 Iustin Pop
        "hv_instance": instance.hvparams,
7316 7736a5f2 Iustin Pop
        "hv_actual": cluster.FillHV(instance, skip_globals=True),
7317 338e51e8 Iustin Pop
        "be_instance": instance.beparams,
7318 338e51e8 Iustin Pop
        "be_actual": cluster.FillBE(instance),
7319 90f72445 Iustin Pop
        "serial_no": instance.serial_no,
7320 90f72445 Iustin Pop
        "mtime": instance.mtime,
7321 90f72445 Iustin Pop
        "ctime": instance.ctime,
7322 033d58b0 Iustin Pop
        "uuid": instance.uuid,
7323 a8083063 Iustin Pop
        }
7324 a8083063 Iustin Pop
7325 a8083063 Iustin Pop
      result[instance.name] = idict
7326 a8083063 Iustin Pop
7327 a8083063 Iustin Pop
    return result
7328 a8083063 Iustin Pop
7329 a8083063 Iustin Pop
7330 7767bbf5 Manuel Franceschini
class LUSetInstanceParams(LogicalUnit):
7331 a8083063 Iustin Pop
  """Modifies an instances's parameters.
7332 a8083063 Iustin Pop

7333 a8083063 Iustin Pop
  """
7334 a8083063 Iustin Pop
  HPATH = "instance-modify"
7335 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
7336 24991749 Iustin Pop
  _OP_REQP = ["instance_name"]
7337 1a5c7281 Guido Trotter
  REQ_BGL = False
7338 1a5c7281 Guido Trotter
7339 24991749 Iustin Pop
  def CheckArguments(self):
7340 24991749 Iustin Pop
    if not hasattr(self.op, 'nics'):
7341 24991749 Iustin Pop
      self.op.nics = []
7342 24991749 Iustin Pop
    if not hasattr(self.op, 'disks'):
7343 24991749 Iustin Pop
      self.op.disks = []
7344 24991749 Iustin Pop
    if not hasattr(self.op, 'beparams'):
7345 24991749 Iustin Pop
      self.op.beparams = {}
7346 24991749 Iustin Pop
    if not hasattr(self.op, 'hvparams'):
7347 24991749 Iustin Pop
      self.op.hvparams = {}
7348 24991749 Iustin Pop
    self.op.force = getattr(self.op, "force", False)
7349 24991749 Iustin Pop
    if not (self.op.nics or self.op.disks or
7350 24991749 Iustin Pop
            self.op.hvparams or self.op.beparams):
7351 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("No changes submitted", errors.ECODE_INVAL)
7352 24991749 Iustin Pop
7353 7736a5f2 Iustin Pop
    if self.op.hvparams:
7354 7736a5f2 Iustin Pop
      _CheckGlobalHvParams(self.op.hvparams)
7355 7736a5f2 Iustin Pop
7356 24991749 Iustin Pop
    # Disk validation
7357 24991749 Iustin Pop
    disk_addremove = 0
7358 24991749 Iustin Pop
    for disk_op, disk_dict in self.op.disks:
7359 24991749 Iustin Pop
      if disk_op == constants.DDM_REMOVE:
7360 24991749 Iustin Pop
        disk_addremove += 1
7361 24991749 Iustin Pop
        continue
7362 24991749 Iustin Pop
      elif disk_op == constants.DDM_ADD:
7363 24991749 Iustin Pop
        disk_addremove += 1
7364 24991749 Iustin Pop
      else:
7365 24991749 Iustin Pop
        if not isinstance(disk_op, int):
7366 5c983ee5 Iustin Pop
          raise errors.OpPrereqError("Invalid disk index", errors.ECODE_INVAL)
7367 8b46606c Guido Trotter
        if not isinstance(disk_dict, dict):
7368 8b46606c Guido Trotter
          msg = "Invalid disk value: expected dict, got '%s'" % disk_dict
7369 5c983ee5 Iustin Pop
          raise errors.OpPrereqError(msg, errors.ECODE_INVAL)
7370 8b46606c Guido Trotter
7371 24991749 Iustin Pop
      if disk_op == constants.DDM_ADD:
7372 24991749 Iustin Pop
        mode = disk_dict.setdefault('mode', constants.DISK_RDWR)
7373 6ec66eae Iustin Pop
        if mode not in constants.DISK_ACCESS_SET:
7374 5c983ee5 Iustin Pop
          raise errors.OpPrereqError("Invalid disk access mode '%s'" % mode,
7375 5c983ee5 Iustin Pop
                                     errors.ECODE_INVAL)
7376 24991749 Iustin Pop
        size = disk_dict.get('size', None)
7377 24991749 Iustin Pop
        if size is None:
7378 5c983ee5 Iustin Pop
          raise errors.OpPrereqError("Required disk parameter size missing",
7379 5c983ee5 Iustin Pop
                                     errors.ECODE_INVAL)
7380 24991749 Iustin Pop
        try:
7381 24991749 Iustin Pop
          size = int(size)
7382 24991749 Iustin Pop
        except ValueError, err:
7383 24991749 Iustin Pop
          raise errors.OpPrereqError("Invalid disk size parameter: %s" %
7384 5c983ee5 Iustin Pop
                                     str(err), errors.ECODE_INVAL)
7385 24991749 Iustin Pop
        disk_dict['size'] = size
7386 24991749 Iustin Pop
      else:
7387 24991749 Iustin Pop
        # modification of disk
7388 24991749 Iustin Pop
        if 'size' in disk_dict:
7389 24991749 Iustin Pop
          raise errors.OpPrereqError("Disk size change not possible, use"
7390 5c983ee5 Iustin Pop
                                     " grow-disk", errors.ECODE_INVAL)
7391 24991749 Iustin Pop
7392 24991749 Iustin Pop
    if disk_addremove > 1:
7393 24991749 Iustin Pop
      raise errors.OpPrereqError("Only one disk add or remove operation"
7394 5c983ee5 Iustin Pop
                                 " supported at a time", errors.ECODE_INVAL)
7395 24991749 Iustin Pop
7396 24991749 Iustin Pop
    # NIC validation
7397 24991749 Iustin Pop
    nic_addremove = 0
7398 24991749 Iustin Pop
    for nic_op, nic_dict in self.op.nics:
7399 24991749 Iustin Pop
      if nic_op == constants.DDM_REMOVE:
7400 24991749 Iustin Pop
        nic_addremove += 1
7401 24991749 Iustin Pop
        continue
7402 24991749 Iustin Pop
      elif nic_op == constants.DDM_ADD:
7403 24991749 Iustin Pop
        nic_addremove += 1
7404 24991749 Iustin Pop
      else:
7405 24991749 Iustin Pop
        if not isinstance(nic_op, int):
7406 5c983ee5 Iustin Pop
          raise errors.OpPrereqError("Invalid nic index", errors.ECODE_INVAL)
7407 8b46606c Guido Trotter
        if not isinstance(nic_dict, dict):
7408 8b46606c Guido Trotter
          msg = "Invalid nic value: expected dict, got '%s'" % nic_dict
7409 5c983ee5 Iustin Pop
          raise errors.OpPrereqError(msg, errors.ECODE_INVAL)
7410 24991749 Iustin Pop
7411 24991749 Iustin Pop
      # nic_dict should be a dict
7412 24991749 Iustin Pop
      nic_ip = nic_dict.get('ip', None)
7413 24991749 Iustin Pop
      if nic_ip is not None:
7414 5c44da6a Guido Trotter
        if nic_ip.lower() == constants.VALUE_NONE:
7415 24991749 Iustin Pop
          nic_dict['ip'] = None
7416 24991749 Iustin Pop
        else:
7417 24991749 Iustin Pop
          if not utils.IsValidIP(nic_ip):
7418 5c983ee5 Iustin Pop
            raise errors.OpPrereqError("Invalid IP address '%s'" % nic_ip,
7419 5c983ee5 Iustin Pop
                                       errors.ECODE_INVAL)
7420 5c44da6a Guido Trotter
7421 cd098c41 Guido Trotter
      nic_bridge = nic_dict.get('bridge', None)
7422 cd098c41 Guido Trotter
      nic_link = nic_dict.get('link', None)
7423 cd098c41 Guido Trotter
      if nic_bridge and nic_link:
7424 29921401 Iustin Pop
        raise errors.OpPrereqError("Cannot pass 'bridge' and 'link'"
7425 5c983ee5 Iustin Pop
                                   " at the same time", errors.ECODE_INVAL)
7426 cd098c41 Guido Trotter
      elif nic_bridge and nic_bridge.lower() == constants.VALUE_NONE:
7427 cd098c41 Guido Trotter
        nic_dict['bridge'] = None
7428 cd098c41 Guido Trotter
      elif nic_link and nic_link.lower() == constants.VALUE_NONE:
7429 cd098c41 Guido Trotter
        nic_dict['link'] = None
7430 cd098c41 Guido Trotter
7431 5c44da6a Guido Trotter
      if nic_op == constants.DDM_ADD:
7432 5c44da6a Guido Trotter
        nic_mac = nic_dict.get('mac', None)
7433 5c44da6a Guido Trotter
        if nic_mac is None:
7434 5c44da6a Guido Trotter
          nic_dict['mac'] = constants.VALUE_AUTO
7435 5c44da6a Guido Trotter
7436 5c44da6a Guido Trotter
      if 'mac' in nic_dict:
7437 5c44da6a Guido Trotter
        nic_mac = nic_dict['mac']
7438 24991749 Iustin Pop
        if nic_mac not in (constants.VALUE_AUTO, constants.VALUE_GENERATE):
7439 24991749 Iustin Pop
          if not utils.IsValidMac(nic_mac):
7440 5c983ee5 Iustin Pop
            raise errors.OpPrereqError("Invalid MAC address %s" % nic_mac,
7441 5c983ee5 Iustin Pop
                                       errors.ECODE_INVAL)
7442 5c44da6a Guido Trotter
        if nic_op != constants.DDM_ADD and nic_mac == constants.VALUE_AUTO:
7443 5c44da6a Guido Trotter
          raise errors.OpPrereqError("'auto' is not a valid MAC address when"
7444 5c983ee5 Iustin Pop
                                     " modifying an existing nic",
7445 5c983ee5 Iustin Pop
                                     errors.ECODE_INVAL)
7446 5c44da6a Guido Trotter
7447 24991749 Iustin Pop
    if nic_addremove > 1:
7448 24991749 Iustin Pop
      raise errors.OpPrereqError("Only one NIC add or remove operation"
7449 5c983ee5 Iustin Pop
                                 " supported at a time", errors.ECODE_INVAL)
7450 24991749 Iustin Pop
7451 1a5c7281 Guido Trotter
  def ExpandNames(self):
7452 1a5c7281 Guido Trotter
    self._ExpandAndLockInstance()
7453 74409b12 Iustin Pop
    self.needed_locks[locking.LEVEL_NODE] = []
7454 74409b12 Iustin Pop
    self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
7455 74409b12 Iustin Pop
7456 74409b12 Iustin Pop
  def DeclareLocks(self, level):
7457 74409b12 Iustin Pop
    if level == locking.LEVEL_NODE:
7458 74409b12 Iustin Pop
      self._LockInstancesNodes()
7459 a8083063 Iustin Pop
7460 a8083063 Iustin Pop
  def BuildHooksEnv(self):
7461 a8083063 Iustin Pop
    """Build hooks env.
7462 a8083063 Iustin Pop

7463 a8083063 Iustin Pop
    This runs on the master, primary and secondaries.
7464 a8083063 Iustin Pop

7465 a8083063 Iustin Pop
    """
7466 396e1b78 Michael Hanselmann
    args = dict()
7467 338e51e8 Iustin Pop
    if constants.BE_MEMORY in self.be_new:
7468 338e51e8 Iustin Pop
      args['memory'] = self.be_new[constants.BE_MEMORY]
7469 338e51e8 Iustin Pop
    if constants.BE_VCPUS in self.be_new:
7470 61be6ba4 Iustin Pop
      args['vcpus'] = self.be_new[constants.BE_VCPUS]
7471 d8dcf3c9 Guido Trotter
    # TODO: export disk changes. Note: _BuildInstanceHookEnv* don't export disk
7472 d8dcf3c9 Guido Trotter
    # information at all.
7473 d8dcf3c9 Guido Trotter
    if self.op.nics:
7474 d8dcf3c9 Guido Trotter
      args['nics'] = []
7475 d8dcf3c9 Guido Trotter
      nic_override = dict(self.op.nics)
7476 62f0dd02 Guido Trotter
      c_nicparams = self.cluster.nicparams[constants.PP_DEFAULT]
7477 d8dcf3c9 Guido Trotter
      for idx, nic in enumerate(self.instance.nics):
7478 d8dcf3c9 Guido Trotter
        if idx in nic_override:
7479 d8dcf3c9 Guido Trotter
          this_nic_override = nic_override[idx]
7480 d8dcf3c9 Guido Trotter
        else:
7481 d8dcf3c9 Guido Trotter
          this_nic_override = {}
7482 d8dcf3c9 Guido Trotter
        if 'ip' in this_nic_override:
7483 d8dcf3c9 Guido Trotter
          ip = this_nic_override['ip']
7484 d8dcf3c9 Guido Trotter
        else:
7485 d8dcf3c9 Guido Trotter
          ip = nic.ip
7486 d8dcf3c9 Guido Trotter
        if 'mac' in this_nic_override:
7487 d8dcf3c9 Guido Trotter
          mac = this_nic_override['mac']
7488 d8dcf3c9 Guido Trotter
        else:
7489 d8dcf3c9 Guido Trotter
          mac = nic.mac
7490 62f0dd02 Guido Trotter
        if idx in self.nic_pnew:
7491 62f0dd02 Guido Trotter
          nicparams = self.nic_pnew[idx]
7492 62f0dd02 Guido Trotter
        else:
7493 62f0dd02 Guido Trotter
          nicparams = objects.FillDict(c_nicparams, nic.nicparams)
7494 62f0dd02 Guido Trotter
        mode = nicparams[constants.NIC_MODE]
7495 62f0dd02 Guido Trotter
        link = nicparams[constants.NIC_LINK]
7496 62f0dd02 Guido Trotter
        args['nics'].append((ip, mac, mode, link))
7497 d8dcf3c9 Guido Trotter
      if constants.DDM_ADD in nic_override:
7498 d8dcf3c9 Guido Trotter
        ip = nic_override[constants.DDM_ADD].get('ip', None)
7499 d8dcf3c9 Guido Trotter
        mac = nic_override[constants.DDM_ADD]['mac']
7500 62f0dd02 Guido Trotter
        nicparams = self.nic_pnew[constants.DDM_ADD]
7501 62f0dd02 Guido Trotter
        mode = nicparams[constants.NIC_MODE]
7502 62f0dd02 Guido Trotter
        link = nicparams[constants.NIC_LINK]
7503 62f0dd02 Guido Trotter
        args['nics'].append((ip, mac, mode, link))
7504 d8dcf3c9 Guido Trotter
      elif constants.DDM_REMOVE in nic_override:
7505 d8dcf3c9 Guido Trotter
        del args['nics'][-1]
7506 d8dcf3c9 Guido Trotter
7507 338e51e8 Iustin Pop
    env = _BuildInstanceHookEnvByObject(self, self.instance, override=args)
7508 6b12959c Iustin Pop
    nl = [self.cfg.GetMasterNode()] + list(self.instance.all_nodes)
7509 a8083063 Iustin Pop
    return env, nl, nl
7510 a8083063 Iustin Pop
7511 0329617a Guido Trotter
  def _GetUpdatedParams(self, old_params, update_dict,
7512 0329617a Guido Trotter
                        default_values, parameter_types):
7513 0329617a Guido Trotter
    """Return the new params dict for the given params.
7514 0329617a Guido Trotter

7515 0329617a Guido Trotter
    @type old_params: dict
7516 f2fd87d7 Iustin Pop
    @param old_params: old parameters
7517 0329617a Guido Trotter
    @type update_dict: dict
7518 f2fd87d7 Iustin Pop
    @param update_dict: dict containing new parameter values,
7519 f2fd87d7 Iustin Pop
                        or constants.VALUE_DEFAULT to reset the
7520 f2fd87d7 Iustin Pop
                        parameter to its default value
7521 0329617a Guido Trotter
    @type default_values: dict
7522 0329617a Guido Trotter
    @param default_values: default values for the filled parameters
7523 0329617a Guido Trotter
    @type parameter_types: dict
7524 0329617a Guido Trotter
    @param parameter_types: dict mapping target dict keys to types
7525 0329617a Guido Trotter
                            in constants.ENFORCEABLE_TYPES
7526 0329617a Guido Trotter
    @rtype: (dict, dict)
7527 0329617a Guido Trotter
    @return: (new_parameters, filled_parameters)
7528 0329617a Guido Trotter

7529 0329617a Guido Trotter
    """
7530 0329617a Guido Trotter
    params_copy = copy.deepcopy(old_params)
7531 0329617a Guido Trotter
    for key, val in update_dict.iteritems():
7532 0329617a Guido Trotter
      if val == constants.VALUE_DEFAULT:
7533 0329617a Guido Trotter
        try:
7534 0329617a Guido Trotter
          del params_copy[key]
7535 0329617a Guido Trotter
        except KeyError:
7536 0329617a Guido Trotter
          pass
7537 0329617a Guido Trotter
      else:
7538 0329617a Guido Trotter
        params_copy[key] = val
7539 0329617a Guido Trotter
    utils.ForceDictType(params_copy, parameter_types)
7540 0329617a Guido Trotter
    params_filled = objects.FillDict(default_values, params_copy)
7541 0329617a Guido Trotter
    return (params_copy, params_filled)
7542 0329617a Guido Trotter
7543 a8083063 Iustin Pop
  def CheckPrereq(self):
7544 a8083063 Iustin Pop
    """Check prerequisites.
7545 a8083063 Iustin Pop

7546 a8083063 Iustin Pop
    This only checks the instance list against the existing names.
7547 a8083063 Iustin Pop

7548 a8083063 Iustin Pop
    """
7549 7c4d6c7b Michael Hanselmann
    self.force = self.op.force
7550 a8083063 Iustin Pop
7551 74409b12 Iustin Pop
    # checking the new params on the primary/secondary nodes
7552 31a853d2 Iustin Pop
7553 cfefe007 Guido Trotter
    instance = self.instance = self.cfg.GetInstanceInfo(self.op.instance_name)
7554 2ee88aeb Guido Trotter
    cluster = self.cluster = self.cfg.GetClusterInfo()
7555 1a5c7281 Guido Trotter
    assert self.instance is not None, \
7556 1a5c7281 Guido Trotter
      "Cannot retrieve locked instance %s" % self.op.instance_name
7557 6b12959c Iustin Pop
    pnode = instance.primary_node
7558 6b12959c Iustin Pop
    nodelist = list(instance.all_nodes)
7559 74409b12 Iustin Pop
7560 338e51e8 Iustin Pop
    # hvparams processing
7561 74409b12 Iustin Pop
    if self.op.hvparams:
7562 0329617a Guido Trotter
      i_hvdict, hv_new = self._GetUpdatedParams(
7563 0329617a Guido Trotter
                             instance.hvparams, self.op.hvparams,
7564 0329617a Guido Trotter
                             cluster.hvparams[instance.hypervisor],
7565 0329617a Guido Trotter
                             constants.HVS_PARAMETER_TYPES)
7566 74409b12 Iustin Pop
      # local check
7567 74409b12 Iustin Pop
      hypervisor.GetHypervisor(
7568 74409b12 Iustin Pop
        instance.hypervisor).CheckParameterSyntax(hv_new)
7569 74409b12 Iustin Pop
      _CheckHVParams(self, nodelist, instance.hypervisor, hv_new)
7570 338e51e8 Iustin Pop
      self.hv_new = hv_new # the new actual values
7571 338e51e8 Iustin Pop
      self.hv_inst = i_hvdict # the new dict (without defaults)
7572 338e51e8 Iustin Pop
    else:
7573 338e51e8 Iustin Pop
      self.hv_new = self.hv_inst = {}
7574 338e51e8 Iustin Pop
7575 338e51e8 Iustin Pop
    # beparams processing
7576 338e51e8 Iustin Pop
    if self.op.beparams:
7577 0329617a Guido Trotter
      i_bedict, be_new = self._GetUpdatedParams(
7578 0329617a Guido Trotter
                             instance.beparams, self.op.beparams,
7579 0329617a Guido Trotter
                             cluster.beparams[constants.PP_DEFAULT],
7580 0329617a Guido Trotter
                             constants.BES_PARAMETER_TYPES)
7581 338e51e8 Iustin Pop
      self.be_new = be_new # the new actual values
7582 338e51e8 Iustin Pop
      self.be_inst = i_bedict # the new dict (without defaults)
7583 338e51e8 Iustin Pop
    else:
7584 b637ae4d Iustin Pop
      self.be_new = self.be_inst = {}
7585 74409b12 Iustin Pop
7586 cfefe007 Guido Trotter
    self.warn = []
7587 647a5d80 Iustin Pop
7588 338e51e8 Iustin Pop
    if constants.BE_MEMORY in self.op.beparams and not self.force:
7589 647a5d80 Iustin Pop
      mem_check_list = [pnode]
7590 c0f2b229 Iustin Pop
      if be_new[constants.BE_AUTO_BALANCE]:
7591 c0f2b229 Iustin Pop
        # either we changed auto_balance to yes or it was from before
7592 647a5d80 Iustin Pop
        mem_check_list.extend(instance.secondary_nodes)
7593 72737a7f Iustin Pop
      instance_info = self.rpc.call_instance_info(pnode, instance.name,
7594 72737a7f Iustin Pop
                                                  instance.hypervisor)
7595 647a5d80 Iustin Pop
      nodeinfo = self.rpc.call_node_info(mem_check_list, self.cfg.GetVGName(),
7596 72737a7f Iustin Pop
                                         instance.hypervisor)
7597 070e998b Iustin Pop
      pninfo = nodeinfo[pnode]
7598 4c4e4e1e Iustin Pop
      msg = pninfo.fail_msg
7599 070e998b Iustin Pop
      if msg:
7600 cfefe007 Guido Trotter
        # Assume the primary node is unreachable and go ahead
7601 070e998b Iustin Pop
        self.warn.append("Can't get info from primary node %s: %s" %
7602 070e998b Iustin Pop
                         (pnode,  msg))
7603 070e998b Iustin Pop
      elif not isinstance(pninfo.payload.get('memory_free', None), int):
7604 070e998b Iustin Pop
        self.warn.append("Node data from primary node %s doesn't contain"
7605 070e998b Iustin Pop
                         " free memory information" % pnode)
7606 4c4e4e1e Iustin Pop
      elif instance_info.fail_msg:
7607 7ad1af4a Iustin Pop
        self.warn.append("Can't get instance runtime information: %s" %
7608 4c4e4e1e Iustin Pop
                        instance_info.fail_msg)
7609 cfefe007 Guido Trotter
      else:
7610 7ad1af4a Iustin Pop
        if instance_info.payload:
7611 7ad1af4a Iustin Pop
          current_mem = int(instance_info.payload['memory'])
7612 cfefe007 Guido Trotter
        else:
7613 cfefe007 Guido Trotter
          # Assume instance not running
7614 cfefe007 Guido Trotter
          # (there is a slight race condition here, but it's not very probable,
7615 cfefe007 Guido Trotter
          # and we have no other way to check)
7616 cfefe007 Guido Trotter
          current_mem = 0
7617 338e51e8 Iustin Pop
        miss_mem = (be_new[constants.BE_MEMORY] - current_mem -
7618 070e998b Iustin Pop
                    pninfo.payload['memory_free'])
7619 cfefe007 Guido Trotter
        if miss_mem > 0:
7620 cfefe007 Guido Trotter
          raise errors.OpPrereqError("This change will prevent the instance"
7621 cfefe007 Guido Trotter
                                     " from starting, due to %d MB of memory"
7622 5c983ee5 Iustin Pop
                                     " missing on its primary node" % miss_mem,
7623 5c983ee5 Iustin Pop
                                     errors.ECODE_NORES)
7624 cfefe007 Guido Trotter
7625 c0f2b229 Iustin Pop
      if be_new[constants.BE_AUTO_BALANCE]:
7626 070e998b Iustin Pop
        for node, nres in nodeinfo.items():
7627 ea33068f Iustin Pop
          if node not in instance.secondary_nodes:
7628 ea33068f Iustin Pop
            continue
7629 4c4e4e1e Iustin Pop
          msg = nres.fail_msg
7630 070e998b Iustin Pop
          if msg:
7631 070e998b Iustin Pop
            self.warn.append("Can't get info from secondary node %s: %s" %
7632 070e998b Iustin Pop
                             (node, msg))
7633 070e998b Iustin Pop
          elif not isinstance(nres.payload.get('memory_free', None), int):
7634 070e998b Iustin Pop
            self.warn.append("Secondary node %s didn't return free"
7635 070e998b Iustin Pop
                             " memory information" % node)
7636 070e998b Iustin Pop
          elif be_new[constants.BE_MEMORY] > nres.payload['memory_free']:
7637 647a5d80 Iustin Pop
            self.warn.append("Not enough memory to failover instance to"
7638 647a5d80 Iustin Pop
                             " secondary node %s" % node)
7639 5bc84f33 Alexander Schreiber
7640 24991749 Iustin Pop
    # NIC processing
7641 cd098c41 Guido Trotter
    self.nic_pnew = {}
7642 cd098c41 Guido Trotter
    self.nic_pinst = {}
7643 24991749 Iustin Pop
    for nic_op, nic_dict in self.op.nics:
7644 24991749 Iustin Pop
      if nic_op == constants.DDM_REMOVE:
7645 24991749 Iustin Pop
        if not instance.nics:
7646 5c983ee5 Iustin Pop
          raise errors.OpPrereqError("Instance has no NICs, cannot remove",
7647 5c983ee5 Iustin Pop
                                     errors.ECODE_INVAL)
7648 24991749 Iustin Pop
        continue
7649 24991749 Iustin Pop
      if nic_op != constants.DDM_ADD:
7650 24991749 Iustin Pop
        # an existing nic
7651 24991749 Iustin Pop
        if nic_op < 0 or nic_op >= len(instance.nics):
7652 24991749 Iustin Pop
          raise errors.OpPrereqError("Invalid NIC index %s, valid values"
7653 24991749 Iustin Pop
                                     " are 0 to %d" %
7654 5c983ee5 Iustin Pop
                                     (nic_op, len(instance.nics)),
7655 5c983ee5 Iustin Pop
                                     errors.ECODE_INVAL)
7656 cd098c41 Guido Trotter
        old_nic_params = instance.nics[nic_op].nicparams
7657 cd098c41 Guido Trotter
        old_nic_ip = instance.nics[nic_op].ip
7658 cd098c41 Guido Trotter
      else:
7659 cd098c41 Guido Trotter
        old_nic_params = {}
7660 cd098c41 Guido Trotter
        old_nic_ip = None
7661 cd098c41 Guido Trotter
7662 cd098c41 Guido Trotter
      update_params_dict = dict([(key, nic_dict[key])
7663 cd098c41 Guido Trotter
                                 for key in constants.NICS_PARAMETERS
7664 cd098c41 Guido Trotter
                                 if key in nic_dict])
7665 cd098c41 Guido Trotter
7666 5c44da6a Guido Trotter
      if 'bridge' in nic_dict:
7667 cd098c41 Guido Trotter
        update_params_dict[constants.NIC_LINK] = nic_dict['bridge']
7668 cd098c41 Guido Trotter
7669 cd098c41 Guido Trotter
      new_nic_params, new_filled_nic_params = \
7670 cd098c41 Guido Trotter
          self._GetUpdatedParams(old_nic_params, update_params_dict,
7671 cd098c41 Guido Trotter
                                 cluster.nicparams[constants.PP_DEFAULT],
7672 cd098c41 Guido Trotter
                                 constants.NICS_PARAMETER_TYPES)
7673 cd098c41 Guido Trotter
      objects.NIC.CheckParameterSyntax(new_filled_nic_params)
7674 cd098c41 Guido Trotter
      self.nic_pinst[nic_op] = new_nic_params
7675 cd098c41 Guido Trotter
      self.nic_pnew[nic_op] = new_filled_nic_params
7676 cd098c41 Guido Trotter
      new_nic_mode = new_filled_nic_params[constants.NIC_MODE]
7677 cd098c41 Guido Trotter
7678 cd098c41 Guido Trotter
      if new_nic_mode == constants.NIC_MODE_BRIDGED:
7679 cd098c41 Guido Trotter
        nic_bridge = new_filled_nic_params[constants.NIC_LINK]
7680 4c4e4e1e Iustin Pop
        msg = self.rpc.call_bridges_exist(pnode, [nic_bridge]).fail_msg
7681 35c0c8da Iustin Pop
        if msg:
7682 35c0c8da Iustin Pop
          msg = "Error checking bridges on node %s: %s" % (pnode, msg)
7683 24991749 Iustin Pop
          if self.force:
7684 24991749 Iustin Pop
            self.warn.append(msg)
7685 24991749 Iustin Pop
          else:
7686 5c983ee5 Iustin Pop
            raise errors.OpPrereqError(msg, errors.ECODE_ENVIRON)
7687 cd098c41 Guido Trotter
      if new_nic_mode == constants.NIC_MODE_ROUTED:
7688 cd098c41 Guido Trotter
        if 'ip' in nic_dict:
7689 cd098c41 Guido Trotter
          nic_ip = nic_dict['ip']
7690 cd098c41 Guido Trotter
        else:
7691 cd098c41 Guido Trotter
          nic_ip = old_nic_ip
7692 cd098c41 Guido Trotter
        if nic_ip is None:
7693 cd098c41 Guido Trotter
          raise errors.OpPrereqError('Cannot set the nic ip to None'
7694 5c983ee5 Iustin Pop
                                     ' on a routed nic', errors.ECODE_INVAL)
7695 5c44da6a Guido Trotter
      if 'mac' in nic_dict:
7696 5c44da6a Guido Trotter
        nic_mac = nic_dict['mac']
7697 5c44da6a Guido Trotter
        if nic_mac is None:
7698 5c983ee5 Iustin Pop
          raise errors.OpPrereqError('Cannot set the nic mac to None',
7699 5c983ee5 Iustin Pop
                                     errors.ECODE_INVAL)
7700 5c44da6a Guido Trotter
        elif nic_mac in (constants.VALUE_AUTO, constants.VALUE_GENERATE):
7701 5c44da6a Guido Trotter
          # otherwise generate the mac
7702 36b66e6e Guido Trotter
          nic_dict['mac'] = self.cfg.GenerateMAC(self.proc.GetECId())
7703 5c44da6a Guido Trotter
        else:
7704 5c44da6a Guido Trotter
          # or validate/reserve the current one
7705 36b66e6e Guido Trotter
          try:
7706 36b66e6e Guido Trotter
            self.cfg.ReserveMAC(nic_mac, self.proc.GetECId())
7707 36b66e6e Guido Trotter
          except errors.ReservationError:
7708 5c44da6a Guido Trotter
            raise errors.OpPrereqError("MAC address %s already in use"
7709 5c983ee5 Iustin Pop
                                       " in cluster" % nic_mac,
7710 5c983ee5 Iustin Pop
                                       errors.ECODE_NOTUNIQUE)
7711 24991749 Iustin Pop
7712 24991749 Iustin Pop
    # DISK processing
7713 24991749 Iustin Pop
    if self.op.disks and instance.disk_template == constants.DT_DISKLESS:
7714 24991749 Iustin Pop
      raise errors.OpPrereqError("Disk operations not supported for"
7715 5c983ee5 Iustin Pop
                                 " diskless instances",
7716 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
7717 24991749 Iustin Pop
    for disk_op, disk_dict in self.op.disks:
7718 24991749 Iustin Pop
      if disk_op == constants.DDM_REMOVE:
7719 24991749 Iustin Pop
        if len(instance.disks) == 1:
7720 24991749 Iustin Pop
          raise errors.OpPrereqError("Cannot remove the last disk of"
7721 5c983ee5 Iustin Pop
                                     " an instance",
7722 5c983ee5 Iustin Pop
                                     errors.ECODE_INVAL)
7723 24991749 Iustin Pop
        ins_l = self.rpc.call_instance_list([pnode], [instance.hypervisor])
7724 24991749 Iustin Pop
        ins_l = ins_l[pnode]
7725 4c4e4e1e Iustin Pop
        msg = ins_l.fail_msg
7726 aca13712 Iustin Pop
        if msg:
7727 aca13712 Iustin Pop
          raise errors.OpPrereqError("Can't contact node %s: %s" %
7728 5c983ee5 Iustin Pop
                                     (pnode, msg), errors.ECODE_ENVIRON)
7729 aca13712 Iustin Pop
        if instance.name in ins_l.payload:
7730 24991749 Iustin Pop
          raise errors.OpPrereqError("Instance is running, can't remove"
7731 5c983ee5 Iustin Pop
                                     " disks.", errors.ECODE_STATE)
7732 24991749 Iustin Pop
7733 24991749 Iustin Pop
      if (disk_op == constants.DDM_ADD and
7734 24991749 Iustin Pop
          len(instance.nics) >= constants.MAX_DISKS):
7735 24991749 Iustin Pop
        raise errors.OpPrereqError("Instance has too many disks (%d), cannot"
7736 5c983ee5 Iustin Pop
                                   " add more" % constants.MAX_DISKS,
7737 5c983ee5 Iustin Pop
                                   errors.ECODE_STATE)
7738 24991749 Iustin Pop
      if disk_op not in (constants.DDM_ADD, constants.DDM_REMOVE):
7739 24991749 Iustin Pop
        # an existing disk
7740 24991749 Iustin Pop
        if disk_op < 0 or disk_op >= len(instance.disks):
7741 24991749 Iustin Pop
          raise errors.OpPrereqError("Invalid disk index %s, valid values"
7742 24991749 Iustin Pop
                                     " are 0 to %d" %
7743 5c983ee5 Iustin Pop
                                     (disk_op, len(instance.disks)),
7744 5c983ee5 Iustin Pop
                                     errors.ECODE_INVAL)
7745 24991749 Iustin Pop
7746 a8083063 Iustin Pop
    return
7747 a8083063 Iustin Pop
7748 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
7749 a8083063 Iustin Pop
    """Modifies an instance.
7750 a8083063 Iustin Pop

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

7753 a8083063 Iustin Pop
    """
7754 cfefe007 Guido Trotter
    # Process here the warnings from CheckPrereq, as we don't have a
7755 cfefe007 Guido Trotter
    # feedback_fn there.
7756 cfefe007 Guido Trotter
    for warn in self.warn:
7757 cfefe007 Guido Trotter
      feedback_fn("WARNING: %s" % warn)
7758 cfefe007 Guido Trotter
7759 a8083063 Iustin Pop
    result = []
7760 a8083063 Iustin Pop
    instance = self.instance
7761 cd098c41 Guido Trotter
    cluster = self.cluster
7762 24991749 Iustin Pop
    # disk changes
7763 24991749 Iustin Pop
    for disk_op, disk_dict in self.op.disks:
7764 24991749 Iustin Pop
      if disk_op == constants.DDM_REMOVE:
7765 24991749 Iustin Pop
        # remove the last disk
7766 24991749 Iustin Pop
        device = instance.disks.pop()
7767 24991749 Iustin Pop
        device_idx = len(instance.disks)
7768 24991749 Iustin Pop
        for node, disk in device.ComputeNodeTree(instance.primary_node):
7769 24991749 Iustin Pop
          self.cfg.SetDiskID(disk, node)
7770 4c4e4e1e Iustin Pop
          msg = self.rpc.call_blockdev_remove(node, disk).fail_msg
7771 e1bc0878 Iustin Pop
          if msg:
7772 e1bc0878 Iustin Pop
            self.LogWarning("Could not remove disk/%d on node %s: %s,"
7773 e1bc0878 Iustin Pop
                            " continuing anyway", device_idx, node, msg)
7774 24991749 Iustin Pop
        result.append(("disk/%d" % device_idx, "remove"))
7775 24991749 Iustin Pop
      elif disk_op == constants.DDM_ADD:
7776 24991749 Iustin Pop
        # add a new disk
7777 24991749 Iustin Pop
        if instance.disk_template == constants.DT_FILE:
7778 24991749 Iustin Pop
          file_driver, file_path = instance.disks[0].logical_id
7779 24991749 Iustin Pop
          file_path = os.path.dirname(file_path)
7780 24991749 Iustin Pop
        else:
7781 24991749 Iustin Pop
          file_driver = file_path = None
7782 24991749 Iustin Pop
        disk_idx_base = len(instance.disks)
7783 24991749 Iustin Pop
        new_disk = _GenerateDiskTemplate(self,
7784 24991749 Iustin Pop
                                         instance.disk_template,
7785 32388e6d Iustin Pop
                                         instance.name, instance.primary_node,
7786 24991749 Iustin Pop
                                         instance.secondary_nodes,
7787 24991749 Iustin Pop
                                         [disk_dict],
7788 24991749 Iustin Pop
                                         file_path,
7789 24991749 Iustin Pop
                                         file_driver,
7790 24991749 Iustin Pop
                                         disk_idx_base)[0]
7791 24991749 Iustin Pop
        instance.disks.append(new_disk)
7792 24991749 Iustin Pop
        info = _GetInstanceInfoText(instance)
7793 24991749 Iustin Pop
7794 24991749 Iustin Pop
        logging.info("Creating volume %s for instance %s",
7795 24991749 Iustin Pop
                     new_disk.iv_name, instance.name)
7796 24991749 Iustin Pop
        # Note: this needs to be kept in sync with _CreateDisks
7797 24991749 Iustin Pop
        #HARDCODE
7798 428958aa Iustin Pop
        for node in instance.all_nodes:
7799 428958aa Iustin Pop
          f_create = node == instance.primary_node
7800 796cab27 Iustin Pop
          try:
7801 428958aa Iustin Pop
            _CreateBlockDev(self, node, instance, new_disk,
7802 428958aa Iustin Pop
                            f_create, info, f_create)
7803 1492cca7 Iustin Pop
          except errors.OpExecError, err:
7804 24991749 Iustin Pop
            self.LogWarning("Failed to create volume %s (%s) on"
7805 428958aa Iustin Pop
                            " node %s: %s",
7806 428958aa Iustin Pop
                            new_disk.iv_name, new_disk, node, err)
7807 24991749 Iustin Pop
        result.append(("disk/%d" % disk_idx_base, "add:size=%s,mode=%s" %
7808 24991749 Iustin Pop
                       (new_disk.size, new_disk.mode)))
7809 24991749 Iustin Pop
      else:
7810 24991749 Iustin Pop
        # change a given disk
7811 24991749 Iustin Pop
        instance.disks[disk_op].mode = disk_dict['mode']
7812 24991749 Iustin Pop
        result.append(("disk.mode/%d" % disk_op, disk_dict['mode']))
7813 24991749 Iustin Pop
    # NIC changes
7814 24991749 Iustin Pop
    for nic_op, nic_dict in self.op.nics:
7815 24991749 Iustin Pop
      if nic_op == constants.DDM_REMOVE:
7816 24991749 Iustin Pop
        # remove the last nic
7817 24991749 Iustin Pop
        del instance.nics[-1]
7818 24991749 Iustin Pop
        result.append(("nic.%d" % len(instance.nics), "remove"))
7819 24991749 Iustin Pop
      elif nic_op == constants.DDM_ADD:
7820 5c44da6a Guido Trotter
        # mac and bridge should be set, by now
7821 5c44da6a Guido Trotter
        mac = nic_dict['mac']
7822 cd098c41 Guido Trotter
        ip = nic_dict.get('ip', None)
7823 cd098c41 Guido Trotter
        nicparams = self.nic_pinst[constants.DDM_ADD]
7824 cd098c41 Guido Trotter
        new_nic = objects.NIC(mac=mac, ip=ip, nicparams=nicparams)
7825 24991749 Iustin Pop
        instance.nics.append(new_nic)
7826 24991749 Iustin Pop
        result.append(("nic.%d" % (len(instance.nics) - 1),
7827 cd098c41 Guido Trotter
                       "add:mac=%s,ip=%s,mode=%s,link=%s" %
7828 cd098c41 Guido Trotter
                       (new_nic.mac, new_nic.ip,
7829 cd098c41 Guido Trotter
                        self.nic_pnew[constants.DDM_ADD][constants.NIC_MODE],
7830 cd098c41 Guido Trotter
                        self.nic_pnew[constants.DDM_ADD][constants.NIC_LINK]
7831 cd098c41 Guido Trotter
                       )))
7832 24991749 Iustin Pop
      else:
7833 cd098c41 Guido Trotter
        for key in 'mac', 'ip':
7834 24991749 Iustin Pop
          if key in nic_dict:
7835 24991749 Iustin Pop
            setattr(instance.nics[nic_op], key, nic_dict[key])
7836 cd098c41 Guido Trotter
        if nic_op in self.nic_pnew:
7837 cd098c41 Guido Trotter
          instance.nics[nic_op].nicparams = self.nic_pnew[nic_op]
7838 cd098c41 Guido Trotter
        for key, val in nic_dict.iteritems():
7839 cd098c41 Guido Trotter
          result.append(("nic.%s/%d" % (key, nic_op), val))
7840 24991749 Iustin Pop
7841 24991749 Iustin Pop
    # hvparams changes
7842 74409b12 Iustin Pop
    if self.op.hvparams:
7843 12649e35 Guido Trotter
      instance.hvparams = self.hv_inst
7844 74409b12 Iustin Pop
      for key, val in self.op.hvparams.iteritems():
7845 74409b12 Iustin Pop
        result.append(("hv/%s" % key, val))
7846 24991749 Iustin Pop
7847 24991749 Iustin Pop
    # beparams changes
7848 338e51e8 Iustin Pop
    if self.op.beparams:
7849 338e51e8 Iustin Pop
      instance.beparams = self.be_inst
7850 338e51e8 Iustin Pop
      for key, val in self.op.beparams.iteritems():
7851 338e51e8 Iustin Pop
        result.append(("be/%s" % key, val))
7852 a8083063 Iustin Pop
7853 a4eae71f Michael Hanselmann
    self.cfg.Update(instance, feedback_fn)
7854 a8083063 Iustin Pop
7855 a8083063 Iustin Pop
    return result
7856 a8083063 Iustin Pop
7857 a8083063 Iustin Pop
7858 a8083063 Iustin Pop
class LUQueryExports(NoHooksLU):
7859 a8083063 Iustin Pop
  """Query the exports list
7860 a8083063 Iustin Pop

7861 a8083063 Iustin Pop
  """
7862 895ecd9c Guido Trotter
  _OP_REQP = ['nodes']
7863 21a15682 Guido Trotter
  REQ_BGL = False
7864 21a15682 Guido Trotter
7865 21a15682 Guido Trotter
  def ExpandNames(self):
7866 21a15682 Guido Trotter
    self.needed_locks = {}
7867 21a15682 Guido Trotter
    self.share_locks[locking.LEVEL_NODE] = 1
7868 21a15682 Guido Trotter
    if not self.op.nodes:
7869 e310b019 Guido Trotter
      self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
7870 21a15682 Guido Trotter
    else:
7871 21a15682 Guido Trotter
      self.needed_locks[locking.LEVEL_NODE] = \
7872 21a15682 Guido Trotter
        _GetWantedNodes(self, self.op.nodes)
7873 a8083063 Iustin Pop
7874 a8083063 Iustin Pop
  def CheckPrereq(self):
7875 21a15682 Guido Trotter
    """Check prerequisites.
7876 a8083063 Iustin Pop

7877 a8083063 Iustin Pop
    """
7878 21a15682 Guido Trotter
    self.nodes = self.acquired_locks[locking.LEVEL_NODE]
7879 a8083063 Iustin Pop
7880 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
7881 a8083063 Iustin Pop
    """Compute the list of all the exported system images.
7882 a8083063 Iustin Pop

7883 e4376078 Iustin Pop
    @rtype: dict
7884 e4376078 Iustin Pop
    @return: a dictionary with the structure node->(export-list)
7885 e4376078 Iustin Pop
        where export-list is a list of the instances exported on
7886 e4376078 Iustin Pop
        that node.
7887 a8083063 Iustin Pop

7888 a8083063 Iustin Pop
    """
7889 b04285f2 Guido Trotter
    rpcresult = self.rpc.call_export_list(self.nodes)
7890 b04285f2 Guido Trotter
    result = {}
7891 b04285f2 Guido Trotter
    for node in rpcresult:
7892 4c4e4e1e Iustin Pop
      if rpcresult[node].fail_msg:
7893 b04285f2 Guido Trotter
        result[node] = False
7894 b04285f2 Guido Trotter
      else:
7895 1b7bfbb7 Iustin Pop
        result[node] = rpcresult[node].payload
7896 b04285f2 Guido Trotter
7897 b04285f2 Guido Trotter
    return result
7898 a8083063 Iustin Pop
7899 a8083063 Iustin Pop
7900 a8083063 Iustin Pop
class LUExportInstance(LogicalUnit):
7901 a8083063 Iustin Pop
  """Export an instance to an image in the cluster.
7902 a8083063 Iustin Pop

7903 a8083063 Iustin Pop
  """
7904 a8083063 Iustin Pop
  HPATH = "instance-export"
7905 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
7906 a8083063 Iustin Pop
  _OP_REQP = ["instance_name", "target_node", "shutdown"]
7907 6657590e Guido Trotter
  REQ_BGL = False
7908 6657590e Guido Trotter
7909 17c3f802 Guido Trotter
  def CheckArguments(self):
7910 17c3f802 Guido Trotter
    """Check the arguments.
7911 17c3f802 Guido Trotter

7912 17c3f802 Guido Trotter
    """
7913 17c3f802 Guido Trotter
    self.shutdown_timeout = getattr(self.op, "shutdown_timeout",
7914 17c3f802 Guido Trotter
                                    constants.DEFAULT_SHUTDOWN_TIMEOUT)
7915 17c3f802 Guido Trotter
7916 6657590e Guido Trotter
  def ExpandNames(self):
7917 6657590e Guido Trotter
    self._ExpandAndLockInstance()
7918 6657590e Guido Trotter
    # FIXME: lock only instance primary and destination node
7919 6657590e Guido Trotter
    #
7920 6657590e Guido Trotter
    # Sad but true, for now we have do lock all nodes, as we don't know where
7921 6657590e Guido Trotter
    # the previous export might be, and and in this LU we search for it and
7922 6657590e Guido Trotter
    # remove it from its current node. In the future we could fix this by:
7923 6657590e Guido Trotter
    #  - making a tasklet to search (share-lock all), then create the new one,
7924 6657590e Guido Trotter
    #    then one to remove, after
7925 5bbd3f7f Michael Hanselmann
    #  - removing the removal operation altogether
7926 6657590e Guido Trotter
    self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
7927 6657590e Guido Trotter
7928 6657590e Guido Trotter
  def DeclareLocks(self, level):
7929 6657590e Guido Trotter
    """Last minute lock declaration."""
7930 6657590e Guido Trotter
    # All nodes are locked anyway, so nothing to do here.
7931 a8083063 Iustin Pop
7932 a8083063 Iustin Pop
  def BuildHooksEnv(self):
7933 a8083063 Iustin Pop
    """Build hooks env.
7934 a8083063 Iustin Pop

7935 a8083063 Iustin Pop
    This will run on the master, primary node and target node.
7936 a8083063 Iustin Pop

7937 a8083063 Iustin Pop
    """
7938 a8083063 Iustin Pop
    env = {
7939 a8083063 Iustin Pop
      "EXPORT_NODE": self.op.target_node,
7940 a8083063 Iustin Pop
      "EXPORT_DO_SHUTDOWN": self.op.shutdown,
7941 17c3f802 Guido Trotter
      "SHUTDOWN_TIMEOUT": self.shutdown_timeout,
7942 a8083063 Iustin Pop
      }
7943 338e51e8 Iustin Pop
    env.update(_BuildInstanceHookEnvByObject(self, self.instance))
7944 d6a02168 Michael Hanselmann
    nl = [self.cfg.GetMasterNode(), self.instance.primary_node,
7945 a8083063 Iustin Pop
          self.op.target_node]
7946 a8083063 Iustin Pop
    return env, nl, nl
7947 a8083063 Iustin Pop
7948 a8083063 Iustin Pop
  def CheckPrereq(self):
7949 a8083063 Iustin Pop
    """Check prerequisites.
7950 a8083063 Iustin Pop

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

7953 a8083063 Iustin Pop
    """
7954 6657590e Guido Trotter
    instance_name = self.op.instance_name
7955 a8083063 Iustin Pop
    self.instance = self.cfg.GetInstanceInfo(instance_name)
7956 6657590e Guido Trotter
    assert self.instance is not None, \
7957 6657590e Guido Trotter
          "Cannot retrieve locked instance %s" % self.op.instance_name
7958 43017d26 Iustin Pop
    _CheckNodeOnline(self, self.instance.primary_node)
7959 a8083063 Iustin Pop
7960 6657590e Guido Trotter
    self.dst_node = self.cfg.GetNodeInfo(
7961 6657590e Guido Trotter
      self.cfg.ExpandNodeName(self.op.target_node))
7962 a8083063 Iustin Pop
7963 268b8e42 Iustin Pop
    if self.dst_node is None:
7964 268b8e42 Iustin Pop
      # This is wrong node name, not a non-locked node
7965 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Wrong node name %s" % self.op.target_node,
7966 5c983ee5 Iustin Pop
                                 errors.ECODE_NOENT)
7967 aeb83a2b Iustin Pop
    _CheckNodeOnline(self, self.dst_node.name)
7968 733a2b6a Iustin Pop
    _CheckNodeNotDrained(self, self.dst_node.name)
7969 a8083063 Iustin Pop
7970 b6023d6c Manuel Franceschini
    # instance disk type verification
7971 b6023d6c Manuel Franceschini
    for disk in self.instance.disks:
7972 b6023d6c Manuel Franceschini
      if disk.dev_type == constants.LD_FILE:
7973 b6023d6c Manuel Franceschini
        raise errors.OpPrereqError("Export not supported for instances with"
7974 5c983ee5 Iustin Pop
                                   " file-based disks", errors.ECODE_INVAL)
7975 b6023d6c Manuel Franceschini
7976 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
7977 a8083063 Iustin Pop
    """Export an instance to an image in the cluster.
7978 a8083063 Iustin Pop

7979 a8083063 Iustin Pop
    """
7980 a8083063 Iustin Pop
    instance = self.instance
7981 a8083063 Iustin Pop
    dst_node = self.dst_node
7982 a8083063 Iustin Pop
    src_node = instance.primary_node
7983 37972df0 Michael Hanselmann
7984 a8083063 Iustin Pop
    if self.op.shutdown:
7985 fb300fb7 Guido Trotter
      # shutdown the instance, but not the disks
7986 37972df0 Michael Hanselmann
      feedback_fn("Shutting down instance %s" % instance.name)
7987 17c3f802 Guido Trotter
      result = self.rpc.call_instance_shutdown(src_node, instance,
7988 17c3f802 Guido Trotter
                                               self.shutdown_timeout)
7989 4c4e4e1e Iustin Pop
      result.Raise("Could not shutdown instance %s on"
7990 4c4e4e1e Iustin Pop
                   " node %s" % (instance.name, src_node))
7991 a8083063 Iustin Pop
7992 a8083063 Iustin Pop
    vgname = self.cfg.GetVGName()
7993 a8083063 Iustin Pop
7994 a8083063 Iustin Pop
    snap_disks = []
7995 a8083063 Iustin Pop
7996 998c712c Iustin Pop
    # set the disks ID correctly since call_instance_start needs the
7997 998c712c Iustin Pop
    # correct drbd minor to create the symlinks
7998 998c712c Iustin Pop
    for disk in instance.disks:
7999 998c712c Iustin Pop
      self.cfg.SetDiskID(disk, src_node)
8000 998c712c Iustin Pop
8001 3e53a60b Michael Hanselmann
    activate_disks = (not instance.admin_up)
8002 3e53a60b Michael Hanselmann
8003 3e53a60b Michael Hanselmann
    if activate_disks:
8004 3e53a60b Michael Hanselmann
      # Activate the instance disks if we'exporting a stopped instance
8005 3e53a60b Michael Hanselmann
      feedback_fn("Activating disks for %s" % instance.name)
8006 3e53a60b Michael Hanselmann
      _StartInstanceDisks(self, instance, None)
8007 3e53a60b Michael Hanselmann
8008 a8083063 Iustin Pop
    try:
8009 3e53a60b Michael Hanselmann
      # per-disk results
8010 3e53a60b Michael Hanselmann
      dresults = []
8011 3e53a60b Michael Hanselmann
      try:
8012 3e53a60b Michael Hanselmann
        for idx, disk in enumerate(instance.disks):
8013 3e53a60b Michael Hanselmann
          feedback_fn("Creating a snapshot of disk/%s on node %s" %
8014 3e53a60b Michael Hanselmann
                      (idx, src_node))
8015 3e53a60b Michael Hanselmann
8016 3e53a60b Michael Hanselmann
          # result.payload will be a snapshot of an lvm leaf of the one we
8017 3e53a60b Michael Hanselmann
          # passed
8018 3e53a60b Michael Hanselmann
          result = self.rpc.call_blockdev_snapshot(src_node, disk)
8019 3e53a60b Michael Hanselmann
          msg = result.fail_msg
8020 3e53a60b Michael Hanselmann
          if msg:
8021 3e53a60b Michael Hanselmann
            self.LogWarning("Could not snapshot disk/%s on node %s: %s",
8022 3e53a60b Michael Hanselmann
                            idx, src_node, msg)
8023 3e53a60b Michael Hanselmann
            snap_disks.append(False)
8024 3e53a60b Michael Hanselmann
          else:
8025 3e53a60b Michael Hanselmann
            disk_id = (vgname, result.payload)
8026 3e53a60b Michael Hanselmann
            new_dev = objects.Disk(dev_type=constants.LD_LV, size=disk.size,
8027 3e53a60b Michael Hanselmann
                                   logical_id=disk_id, physical_id=disk_id,
8028 3e53a60b Michael Hanselmann
                                   iv_name=disk.iv_name)
8029 3e53a60b Michael Hanselmann
            snap_disks.append(new_dev)
8030 37972df0 Michael Hanselmann
8031 3e53a60b Michael Hanselmann
      finally:
8032 3e53a60b Michael Hanselmann
        if self.op.shutdown and instance.admin_up:
8033 3e53a60b Michael Hanselmann
          feedback_fn("Starting instance %s" % instance.name)
8034 3e53a60b Michael Hanselmann
          result = self.rpc.call_instance_start(src_node, instance, None, None)
8035 3e53a60b Michael Hanselmann
          msg = result.fail_msg
8036 3e53a60b Michael Hanselmann
          if msg:
8037 3e53a60b Michael Hanselmann
            _ShutdownInstanceDisks(self, instance)
8038 3e53a60b Michael Hanselmann
            raise errors.OpExecError("Could not start instance: %s" % msg)
8039 3e53a60b Michael Hanselmann
8040 3e53a60b Michael Hanselmann
      # TODO: check for size
8041 3e53a60b Michael Hanselmann
8042 3e53a60b Michael Hanselmann
      cluster_name = self.cfg.GetClusterName()
8043 3e53a60b Michael Hanselmann
      for idx, dev in enumerate(snap_disks):
8044 3e53a60b Michael Hanselmann
        feedback_fn("Exporting snapshot %s from %s to %s" %
8045 3e53a60b Michael Hanselmann
                    (idx, src_node, dst_node.name))
8046 3e53a60b Michael Hanselmann
        if dev:
8047 3e53a60b Michael Hanselmann
          result = self.rpc.call_snapshot_export(src_node, dev, dst_node.name,
8048 3e53a60b Michael Hanselmann
                                                 instance, cluster_name, idx)
8049 3e53a60b Michael Hanselmann
          msg = result.fail_msg
8050 3e53a60b Michael Hanselmann
          if msg:
8051 3e53a60b Michael Hanselmann
            self.LogWarning("Could not export disk/%s from node %s to"
8052 3e53a60b Michael Hanselmann
                            " node %s: %s", idx, src_node, dst_node.name, msg)
8053 3e53a60b Michael Hanselmann
            dresults.append(False)
8054 3e53a60b Michael Hanselmann
          else:
8055 3e53a60b Michael Hanselmann
            dresults.append(True)
8056 3e53a60b Michael Hanselmann
          msg = self.rpc.call_blockdev_remove(src_node, dev).fail_msg
8057 3e53a60b Michael Hanselmann
          if msg:
8058 3e53a60b Michael Hanselmann
            self.LogWarning("Could not remove snapshot for disk/%d from node"
8059 3e53a60b Michael Hanselmann
                            " %s: %s", idx, src_node, msg)
8060 19d7f90a Guido Trotter
        else:
8061 084f05a5 Iustin Pop
          dresults.append(False)
8062 a8083063 Iustin Pop
8063 3e53a60b Michael Hanselmann
      feedback_fn("Finalizing export on %s" % dst_node.name)
8064 3e53a60b Michael Hanselmann
      result = self.rpc.call_finalize_export(dst_node.name, instance,
8065 3e53a60b Michael Hanselmann
                                             snap_disks)
8066 3e53a60b Michael Hanselmann
      fin_resu = True
8067 3e53a60b Michael Hanselmann
      msg = result.fail_msg
8068 3e53a60b Michael Hanselmann
      if msg:
8069 3e53a60b Michael Hanselmann
        self.LogWarning("Could not finalize export for instance %s"
8070 3e53a60b Michael Hanselmann
                        " on node %s: %s", instance.name, dst_node.name, msg)
8071 3e53a60b Michael Hanselmann
        fin_resu = False
8072 3e53a60b Michael Hanselmann
8073 3e53a60b Michael Hanselmann
    finally:
8074 3e53a60b Michael Hanselmann
      if activate_disks:
8075 3e53a60b Michael Hanselmann
        feedback_fn("Deactivating disks for %s" % instance.name)
8076 3e53a60b Michael Hanselmann
        _ShutdownInstanceDisks(self, instance)
8077 a8083063 Iustin Pop
8078 a8083063 Iustin Pop
    nodelist = self.cfg.GetNodeList()
8079 a8083063 Iustin Pop
    nodelist.remove(dst_node.name)
8080 a8083063 Iustin Pop
8081 a8083063 Iustin Pop
    # on one-node clusters nodelist will be empty after the removal
8082 a8083063 Iustin Pop
    # if we proceed the backup would be removed because OpQueryExports
8083 a8083063 Iustin Pop
    # substitutes an empty list with the full cluster node list.
8084 35fbcd11 Iustin Pop
    iname = instance.name
8085 a8083063 Iustin Pop
    if nodelist:
8086 37972df0 Michael Hanselmann
      feedback_fn("Removing old exports for instance %s" % iname)
8087 72737a7f Iustin Pop
      exportlist = self.rpc.call_export_list(nodelist)
8088 a8083063 Iustin Pop
      for node in exportlist:
8089 4c4e4e1e Iustin Pop
        if exportlist[node].fail_msg:
8090 781de953 Iustin Pop
          continue
8091 35fbcd11 Iustin Pop
        if iname in exportlist[node].payload:
8092 4c4e4e1e Iustin Pop
          msg = self.rpc.call_export_remove(node, iname).fail_msg
8093 35fbcd11 Iustin Pop
          if msg:
8094 19d7f90a Guido Trotter
            self.LogWarning("Could not remove older export for instance %s"
8095 35fbcd11 Iustin Pop
                            " on node %s: %s", iname, node, msg)
8096 084f05a5 Iustin Pop
    return fin_resu, dresults
8097 5c947f38 Iustin Pop
8098 5c947f38 Iustin Pop
8099 9ac99fda Guido Trotter
class LURemoveExport(NoHooksLU):
8100 9ac99fda Guido Trotter
  """Remove exports related to the named instance.
8101 9ac99fda Guido Trotter

8102 9ac99fda Guido Trotter
  """
8103 9ac99fda Guido Trotter
  _OP_REQP = ["instance_name"]
8104 3656b3af Guido Trotter
  REQ_BGL = False
8105 3656b3af Guido Trotter
8106 3656b3af Guido Trotter
  def ExpandNames(self):
8107 3656b3af Guido Trotter
    self.needed_locks = {}
8108 3656b3af Guido Trotter
    # We need all nodes to be locked in order for RemoveExport to work, but we
8109 3656b3af Guido Trotter
    # don't need to lock the instance itself, as nothing will happen to it (and
8110 3656b3af Guido Trotter
    # we can remove exports also for a removed instance)
8111 3656b3af Guido Trotter
    self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
8112 9ac99fda Guido Trotter
8113 9ac99fda Guido Trotter
  def CheckPrereq(self):
8114 9ac99fda Guido Trotter
    """Check prerequisites.
8115 9ac99fda Guido Trotter
    """
8116 9ac99fda Guido Trotter
    pass
8117 9ac99fda Guido Trotter
8118 9ac99fda Guido Trotter
  def Exec(self, feedback_fn):
8119 9ac99fda Guido Trotter
    """Remove any export.
8120 9ac99fda Guido Trotter

8121 9ac99fda Guido Trotter
    """
8122 9ac99fda Guido Trotter
    instance_name = self.cfg.ExpandInstanceName(self.op.instance_name)
8123 9ac99fda Guido Trotter
    # If the instance was not found we'll try with the name that was passed in.
8124 9ac99fda Guido Trotter
    # This will only work if it was an FQDN, though.
8125 9ac99fda Guido Trotter
    fqdn_warn = False
8126 9ac99fda Guido Trotter
    if not instance_name:
8127 9ac99fda Guido Trotter
      fqdn_warn = True
8128 9ac99fda Guido Trotter
      instance_name = self.op.instance_name
8129 9ac99fda Guido Trotter
8130 1b7bfbb7 Iustin Pop
    locked_nodes = self.acquired_locks[locking.LEVEL_NODE]
8131 1b7bfbb7 Iustin Pop
    exportlist = self.rpc.call_export_list(locked_nodes)
8132 9ac99fda Guido Trotter
    found = False
8133 9ac99fda Guido Trotter
    for node in exportlist:
8134 4c4e4e1e Iustin Pop
      msg = exportlist[node].fail_msg
8135 1b7bfbb7 Iustin Pop
      if msg:
8136 1b7bfbb7 Iustin Pop
        self.LogWarning("Failed to query node %s (continuing): %s", node, msg)
8137 781de953 Iustin Pop
        continue
8138 1b7bfbb7 Iustin Pop
      if instance_name in exportlist[node].payload:
8139 9ac99fda Guido Trotter
        found = True
8140 781de953 Iustin Pop
        result = self.rpc.call_export_remove(node, instance_name)
8141 4c4e4e1e Iustin Pop
        msg = result.fail_msg
8142 35fbcd11 Iustin Pop
        if msg:
8143 9a4f63d1 Iustin Pop
          logging.error("Could not remove export for instance %s"
8144 35fbcd11 Iustin Pop
                        " on node %s: %s", instance_name, node, msg)
8145 9ac99fda Guido Trotter
8146 9ac99fda Guido Trotter
    if fqdn_warn and not found:
8147 9ac99fda Guido Trotter
      feedback_fn("Export not found. If trying to remove an export belonging"
8148 9ac99fda Guido Trotter
                  " to a deleted instance please use its Fully Qualified"
8149 9ac99fda Guido Trotter
                  " Domain Name.")
8150 9ac99fda Guido Trotter
8151 9ac99fda Guido Trotter
8152 5c947f38 Iustin Pop
class TagsLU(NoHooksLU):
8153 5c947f38 Iustin Pop
  """Generic tags LU.
8154 5c947f38 Iustin Pop

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

8157 5c947f38 Iustin Pop
  """
8158 5c947f38 Iustin Pop
8159 8646adce Guido Trotter
  def ExpandNames(self):
8160 8646adce Guido Trotter
    self.needed_locks = {}
8161 8646adce Guido Trotter
    if self.op.kind == constants.TAG_NODE:
8162 5c947f38 Iustin Pop
      name = self.cfg.ExpandNodeName(self.op.name)
8163 5c947f38 Iustin Pop
      if name is None:
8164 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Invalid node name (%s)" %
8165 5c983ee5 Iustin Pop
                                   (self.op.name,), errors.ECODE_NOENT)
8166 5c947f38 Iustin Pop
      self.op.name = name
8167 8646adce Guido Trotter
      self.needed_locks[locking.LEVEL_NODE] = name
8168 5c947f38 Iustin Pop
    elif self.op.kind == constants.TAG_INSTANCE:
8169 8f684e16 Iustin Pop
      name = self.cfg.ExpandInstanceName(self.op.name)
8170 5c947f38 Iustin Pop
      if name is None:
8171 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Invalid instance name (%s)" %
8172 5c983ee5 Iustin Pop
                                   (self.op.name,), errors.ECODE_NOENT)
8173 5c947f38 Iustin Pop
      self.op.name = name
8174 8646adce Guido Trotter
      self.needed_locks[locking.LEVEL_INSTANCE] = name
8175 8646adce Guido Trotter
8176 8646adce Guido Trotter
  def CheckPrereq(self):
8177 8646adce Guido Trotter
    """Check prerequisites.
8178 8646adce Guido Trotter

8179 8646adce Guido Trotter
    """
8180 8646adce Guido Trotter
    if self.op.kind == constants.TAG_CLUSTER:
8181 8646adce Guido Trotter
      self.target = self.cfg.GetClusterInfo()
8182 8646adce Guido Trotter
    elif self.op.kind == constants.TAG_NODE:
8183 8646adce Guido Trotter
      self.target = self.cfg.GetNodeInfo(self.op.name)
8184 8646adce Guido Trotter
    elif self.op.kind == constants.TAG_INSTANCE:
8185 8646adce Guido Trotter
      self.target = self.cfg.GetInstanceInfo(self.op.name)
8186 5c947f38 Iustin Pop
    else:
8187 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Wrong tag type requested (%s)" %
8188 5c983ee5 Iustin Pop
                                 str(self.op.kind), errors.ECODE_INVAL)
8189 5c947f38 Iustin Pop
8190 5c947f38 Iustin Pop
8191 5c947f38 Iustin Pop
class LUGetTags(TagsLU):
8192 5c947f38 Iustin Pop
  """Returns the tags of a given object.
8193 5c947f38 Iustin Pop

8194 5c947f38 Iustin Pop
  """
8195 5c947f38 Iustin Pop
  _OP_REQP = ["kind", "name"]
8196 8646adce Guido Trotter
  REQ_BGL = False
8197 5c947f38 Iustin Pop
8198 5c947f38 Iustin Pop
  def Exec(self, feedback_fn):
8199 5c947f38 Iustin Pop
    """Returns the tag list.
8200 5c947f38 Iustin Pop

8201 5c947f38 Iustin Pop
    """
8202 5d414478 Oleksiy Mishchenko
    return list(self.target.GetTags())
8203 5c947f38 Iustin Pop
8204 5c947f38 Iustin Pop
8205 73415719 Iustin Pop
class LUSearchTags(NoHooksLU):
8206 73415719 Iustin Pop
  """Searches the tags for a given pattern.
8207 73415719 Iustin Pop

8208 73415719 Iustin Pop
  """
8209 73415719 Iustin Pop
  _OP_REQP = ["pattern"]
8210 8646adce Guido Trotter
  REQ_BGL = False
8211 8646adce Guido Trotter
8212 8646adce Guido Trotter
  def ExpandNames(self):
8213 8646adce Guido Trotter
    self.needed_locks = {}
8214 73415719 Iustin Pop
8215 73415719 Iustin Pop
  def CheckPrereq(self):
8216 73415719 Iustin Pop
    """Check prerequisites.
8217 73415719 Iustin Pop

8218 73415719 Iustin Pop
    This checks the pattern passed for validity by compiling it.
8219 73415719 Iustin Pop

8220 73415719 Iustin Pop
    """
8221 73415719 Iustin Pop
    try:
8222 73415719 Iustin Pop
      self.re = re.compile(self.op.pattern)
8223 73415719 Iustin Pop
    except re.error, err:
8224 73415719 Iustin Pop
      raise errors.OpPrereqError("Invalid search pattern '%s': %s" %
8225 5c983ee5 Iustin Pop
                                 (self.op.pattern, err), errors.ECODE_INVAL)
8226 73415719 Iustin Pop
8227 73415719 Iustin Pop
  def Exec(self, feedback_fn):
8228 73415719 Iustin Pop
    """Returns the tag list.
8229 73415719 Iustin Pop

8230 73415719 Iustin Pop
    """
8231 73415719 Iustin Pop
    cfg = self.cfg
8232 73415719 Iustin Pop
    tgts = [("/cluster", cfg.GetClusterInfo())]
8233 8646adce Guido Trotter
    ilist = cfg.GetAllInstancesInfo().values()
8234 73415719 Iustin Pop
    tgts.extend([("/instances/%s" % i.name, i) for i in ilist])
8235 8646adce Guido Trotter
    nlist = cfg.GetAllNodesInfo().values()
8236 73415719 Iustin Pop
    tgts.extend([("/nodes/%s" % n.name, n) for n in nlist])
8237 73415719 Iustin Pop
    results = []
8238 73415719 Iustin Pop
    for path, target in tgts:
8239 73415719 Iustin Pop
      for tag in target.GetTags():
8240 73415719 Iustin Pop
        if self.re.search(tag):
8241 73415719 Iustin Pop
          results.append((path, tag))
8242 73415719 Iustin Pop
    return results
8243 73415719 Iustin Pop
8244 73415719 Iustin Pop
8245 f27302fa Iustin Pop
class LUAddTags(TagsLU):
8246 5c947f38 Iustin Pop
  """Sets a tag on a given object.
8247 5c947f38 Iustin Pop

8248 5c947f38 Iustin Pop
  """
8249 f27302fa Iustin Pop
  _OP_REQP = ["kind", "name", "tags"]
8250 8646adce Guido Trotter
  REQ_BGL = False
8251 5c947f38 Iustin Pop
8252 5c947f38 Iustin Pop
  def CheckPrereq(self):
8253 5c947f38 Iustin Pop
    """Check prerequisites.
8254 5c947f38 Iustin Pop

8255 5c947f38 Iustin Pop
    This checks the type and length of the tag name and value.
8256 5c947f38 Iustin Pop

8257 5c947f38 Iustin Pop
    """
8258 5c947f38 Iustin Pop
    TagsLU.CheckPrereq(self)
8259 f27302fa Iustin Pop
    for tag in self.op.tags:
8260 f27302fa Iustin Pop
      objects.TaggableObject.ValidateTag(tag)
8261 5c947f38 Iustin Pop
8262 5c947f38 Iustin Pop
  def Exec(self, feedback_fn):
8263 5c947f38 Iustin Pop
    """Sets the tag.
8264 5c947f38 Iustin Pop

8265 5c947f38 Iustin Pop
    """
8266 5c947f38 Iustin Pop
    try:
8267 f27302fa Iustin Pop
      for tag in self.op.tags:
8268 f27302fa Iustin Pop
        self.target.AddTag(tag)
8269 5c947f38 Iustin Pop
    except errors.TagError, err:
8270 3ecf6786 Iustin Pop
      raise errors.OpExecError("Error while setting tag: %s" % str(err))
8271 159d4ec6 Iustin Pop
    self.cfg.Update(self.target, feedback_fn)
8272 5c947f38 Iustin Pop
8273 5c947f38 Iustin Pop
8274 f27302fa Iustin Pop
class LUDelTags(TagsLU):
8275 f27302fa Iustin Pop
  """Delete a list of tags from a given object.
8276 5c947f38 Iustin Pop

8277 5c947f38 Iustin Pop
  """
8278 f27302fa Iustin Pop
  _OP_REQP = ["kind", "name", "tags"]
8279 8646adce Guido Trotter
  REQ_BGL = False
8280 5c947f38 Iustin Pop
8281 5c947f38 Iustin Pop
  def CheckPrereq(self):
8282 5c947f38 Iustin Pop
    """Check prerequisites.
8283 5c947f38 Iustin Pop

8284 5c947f38 Iustin Pop
    This checks that we have the given tag.
8285 5c947f38 Iustin Pop

8286 5c947f38 Iustin Pop
    """
8287 5c947f38 Iustin Pop
    TagsLU.CheckPrereq(self)
8288 f27302fa Iustin Pop
    for tag in self.op.tags:
8289 f27302fa Iustin Pop
      objects.TaggableObject.ValidateTag(tag)
8290 f27302fa Iustin Pop
    del_tags = frozenset(self.op.tags)
8291 f27302fa Iustin Pop
    cur_tags = self.target.GetTags()
8292 f27302fa Iustin Pop
    if not del_tags <= cur_tags:
8293 f27302fa Iustin Pop
      diff_tags = del_tags - cur_tags
8294 f27302fa Iustin Pop
      diff_names = ["'%s'" % tag for tag in diff_tags]
8295 f27302fa Iustin Pop
      diff_names.sort()
8296 f27302fa Iustin Pop
      raise errors.OpPrereqError("Tag(s) %s not found" %
8297 5c983ee5 Iustin Pop
                                 (",".join(diff_names)), errors.ECODE_NOENT)
8298 5c947f38 Iustin Pop
8299 5c947f38 Iustin Pop
  def Exec(self, feedback_fn):
8300 5c947f38 Iustin Pop
    """Remove the tag from the object.
8301 5c947f38 Iustin Pop

8302 5c947f38 Iustin Pop
    """
8303 f27302fa Iustin Pop
    for tag in self.op.tags:
8304 f27302fa Iustin Pop
      self.target.RemoveTag(tag)
8305 159d4ec6 Iustin Pop
    self.cfg.Update(self.target, feedback_fn)
8306 06009e27 Iustin Pop
8307 0eed6e61 Guido Trotter
8308 06009e27 Iustin Pop
class LUTestDelay(NoHooksLU):
8309 06009e27 Iustin Pop
  """Sleep for a specified amount of time.
8310 06009e27 Iustin Pop

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

8314 06009e27 Iustin Pop
  """
8315 06009e27 Iustin Pop
  _OP_REQP = ["duration", "on_master", "on_nodes"]
8316 fbe9022f Guido Trotter
  REQ_BGL = False
8317 06009e27 Iustin Pop
8318 fbe9022f Guido Trotter
  def ExpandNames(self):
8319 fbe9022f Guido Trotter
    """Expand names and set required locks.
8320 06009e27 Iustin Pop

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

8323 06009e27 Iustin Pop
    """
8324 fbe9022f Guido Trotter
    self.needed_locks = {}
8325 06009e27 Iustin Pop
    if self.op.on_nodes:
8326 fbe9022f Guido Trotter
      # _GetWantedNodes can be used here, but is not always appropriate to use
8327 fbe9022f Guido Trotter
      # this way in ExpandNames. Check LogicalUnit.ExpandNames docstring for
8328 fbe9022f Guido Trotter
      # more information.
8329 06009e27 Iustin Pop
      self.op.on_nodes = _GetWantedNodes(self, self.op.on_nodes)
8330 fbe9022f Guido Trotter
      self.needed_locks[locking.LEVEL_NODE] = self.op.on_nodes
8331 fbe9022f Guido Trotter
8332 fbe9022f Guido Trotter
  def CheckPrereq(self):
8333 fbe9022f Guido Trotter
    """Check prerequisites.
8334 fbe9022f Guido Trotter

8335 fbe9022f Guido Trotter
    """
8336 06009e27 Iustin Pop
8337 06009e27 Iustin Pop
  def Exec(self, feedback_fn):
8338 06009e27 Iustin Pop
    """Do the actual sleep.
8339 06009e27 Iustin Pop

8340 06009e27 Iustin Pop
    """
8341 06009e27 Iustin Pop
    if self.op.on_master:
8342 06009e27 Iustin Pop
      if not utils.TestDelay(self.op.duration):
8343 06009e27 Iustin Pop
        raise errors.OpExecError("Error during master delay test")
8344 06009e27 Iustin Pop
    if self.op.on_nodes:
8345 72737a7f Iustin Pop
      result = self.rpc.call_test_delay(self.op.on_nodes, self.op.duration)
8346 06009e27 Iustin Pop
      for node, node_result in result.items():
8347 4c4e4e1e Iustin Pop
        node_result.Raise("Failure during rpc call to node %s" % node)
8348 d61df03e Iustin Pop
8349 d61df03e Iustin Pop
8350 d1c2dd75 Iustin Pop
class IAllocator(object):
8351 d1c2dd75 Iustin Pop
  """IAllocator framework.
8352 d61df03e Iustin Pop

8353 d1c2dd75 Iustin Pop
  An IAllocator instance has three sets of attributes:
8354 d6a02168 Michael Hanselmann
    - cfg that is needed to query the cluster
8355 d1c2dd75 Iustin Pop
    - input data (all members of the _KEYS class attribute are required)
8356 d1c2dd75 Iustin Pop
    - four buffer attributes (in|out_data|text), that represent the
8357 d1c2dd75 Iustin Pop
      input (to the external script) in text and data structure format,
8358 d1c2dd75 Iustin Pop
      and the output from it, again in two formats
8359 d1c2dd75 Iustin Pop
    - the result variables from the script (success, info, nodes) for
8360 d1c2dd75 Iustin Pop
      easy usage
8361 d61df03e Iustin Pop

8362 d61df03e Iustin Pop
  """
8363 29859cb7 Iustin Pop
  _ALLO_KEYS = [
8364 d1c2dd75 Iustin Pop
    "mem_size", "disks", "disk_template",
8365 8cc7e742 Guido Trotter
    "os", "tags", "nics", "vcpus", "hypervisor",
8366 d1c2dd75 Iustin Pop
    ]
8367 29859cb7 Iustin Pop
  _RELO_KEYS = [
8368 29859cb7 Iustin Pop
    "relocate_from",
8369 29859cb7 Iustin Pop
    ]
8370 d1c2dd75 Iustin Pop
8371 923ddac0 Michael Hanselmann
  def __init__(self, cfg, rpc, mode, name, **kwargs):
8372 923ddac0 Michael Hanselmann
    self.cfg = cfg
8373 923ddac0 Michael Hanselmann
    self.rpc = rpc
8374 d1c2dd75 Iustin Pop
    # init buffer variables
8375 d1c2dd75 Iustin Pop
    self.in_text = self.out_text = self.in_data = self.out_data = None
8376 d1c2dd75 Iustin Pop
    # init all input fields so that pylint is happy
8377 29859cb7 Iustin Pop
    self.mode = mode
8378 29859cb7 Iustin Pop
    self.name = name
8379 d1c2dd75 Iustin Pop
    self.mem_size = self.disks = self.disk_template = None
8380 d1c2dd75 Iustin Pop
    self.os = self.tags = self.nics = self.vcpus = None
8381 a0add446 Iustin Pop
    self.hypervisor = None
8382 29859cb7 Iustin Pop
    self.relocate_from = None
8383 27579978 Iustin Pop
    # computed fields
8384 27579978 Iustin Pop
    self.required_nodes = None
8385 d1c2dd75 Iustin Pop
    # init result fields
8386 d1c2dd75 Iustin Pop
    self.success = self.info = self.nodes = None
8387 29859cb7 Iustin Pop
    if self.mode == constants.IALLOCATOR_MODE_ALLOC:
8388 29859cb7 Iustin Pop
      keyset = self._ALLO_KEYS
8389 29859cb7 Iustin Pop
    elif self.mode == constants.IALLOCATOR_MODE_RELOC:
8390 29859cb7 Iustin Pop
      keyset = self._RELO_KEYS
8391 29859cb7 Iustin Pop
    else:
8392 29859cb7 Iustin Pop
      raise errors.ProgrammerError("Unknown mode '%s' passed to the"
8393 29859cb7 Iustin Pop
                                   " IAllocator" % self.mode)
8394 d1c2dd75 Iustin Pop
    for key in kwargs:
8395 29859cb7 Iustin Pop
      if key not in keyset:
8396 d1c2dd75 Iustin Pop
        raise errors.ProgrammerError("Invalid input parameter '%s' to"
8397 d1c2dd75 Iustin Pop
                                     " IAllocator" % key)
8398 d1c2dd75 Iustin Pop
      setattr(self, key, kwargs[key])
8399 29859cb7 Iustin Pop
    for key in keyset:
8400 d1c2dd75 Iustin Pop
      if key not in kwargs:
8401 d1c2dd75 Iustin Pop
        raise errors.ProgrammerError("Missing input parameter '%s' to"
8402 d1c2dd75 Iustin Pop
                                     " IAllocator" % key)
8403 d1c2dd75 Iustin Pop
    self._BuildInputData()
8404 d1c2dd75 Iustin Pop
8405 d1c2dd75 Iustin Pop
  def _ComputeClusterData(self):
8406 d1c2dd75 Iustin Pop
    """Compute the generic allocator input data.
8407 d1c2dd75 Iustin Pop

8408 d1c2dd75 Iustin Pop
    This is the data that is independent of the actual operation.
8409 d1c2dd75 Iustin Pop

8410 d1c2dd75 Iustin Pop
    """
8411 923ddac0 Michael Hanselmann
    cfg = self.cfg
8412 e69d05fd Iustin Pop
    cluster_info = cfg.GetClusterInfo()
8413 d1c2dd75 Iustin Pop
    # cluster data
8414 d1c2dd75 Iustin Pop
    data = {
8415 77031881 Iustin Pop
      "version": constants.IALLOCATOR_VERSION,
8416 72737a7f Iustin Pop
      "cluster_name": cfg.GetClusterName(),
8417 e69d05fd Iustin Pop
      "cluster_tags": list(cluster_info.GetTags()),
8418 1325da74 Iustin Pop
      "enabled_hypervisors": list(cluster_info.enabled_hypervisors),
8419 d1c2dd75 Iustin Pop
      # we don't have job IDs
8420 d61df03e Iustin Pop
      }
8421 b57e9819 Guido Trotter
    iinfo = cfg.GetAllInstancesInfo().values()
8422 b57e9819 Guido Trotter
    i_list = [(inst, cluster_info.FillBE(inst)) for inst in iinfo]
8423 6286519f Iustin Pop
8424 d1c2dd75 Iustin Pop
    # node data
8425 d1c2dd75 Iustin Pop
    node_results = {}
8426 d1c2dd75 Iustin Pop
    node_list = cfg.GetNodeList()
8427 8cc7e742 Guido Trotter
8428 8cc7e742 Guido Trotter
    if self.mode == constants.IALLOCATOR_MODE_ALLOC:
8429 a0add446 Iustin Pop
      hypervisor_name = self.hypervisor
8430 8cc7e742 Guido Trotter
    elif self.mode == constants.IALLOCATOR_MODE_RELOC:
8431 a0add446 Iustin Pop
      hypervisor_name = cfg.GetInstanceInfo(self.name).hypervisor
8432 8cc7e742 Guido Trotter
8433 923ddac0 Michael Hanselmann
    node_data = self.rpc.call_node_info(node_list, cfg.GetVGName(),
8434 923ddac0 Michael Hanselmann
                                        hypervisor_name)
8435 923ddac0 Michael Hanselmann
    node_iinfo = \
8436 923ddac0 Michael Hanselmann
      self.rpc.call_all_instances_info(node_list,
8437 923ddac0 Michael Hanselmann
                                       cluster_info.enabled_hypervisors)
8438 1325da74 Iustin Pop
    for nname, nresult in node_data.items():
8439 1325da74 Iustin Pop
      # first fill in static (config-based) values
8440 d1c2dd75 Iustin Pop
      ninfo = cfg.GetNodeInfo(nname)
8441 d1c2dd75 Iustin Pop
      pnr = {
8442 d1c2dd75 Iustin Pop
        "tags": list(ninfo.GetTags()),
8443 d1c2dd75 Iustin Pop
        "primary_ip": ninfo.primary_ip,
8444 d1c2dd75 Iustin Pop
        "secondary_ip": ninfo.secondary_ip,
8445 fc0fe88c Iustin Pop
        "offline": ninfo.offline,
8446 0b2454b9 Iustin Pop
        "drained": ninfo.drained,
8447 1325da74 Iustin Pop
        "master_candidate": ninfo.master_candidate,
8448 d1c2dd75 Iustin Pop
        }
8449 1325da74 Iustin Pop
8450 0d853843 Iustin Pop
      if not (ninfo.offline or ninfo.drained):
8451 4c4e4e1e Iustin Pop
        nresult.Raise("Can't get data for node %s" % nname)
8452 4c4e4e1e Iustin Pop
        node_iinfo[nname].Raise("Can't get node instance info from node %s" %
8453 4c4e4e1e Iustin Pop
                                nname)
8454 070e998b Iustin Pop
        remote_info = nresult.payload
8455 b142ef15 Iustin Pop
8456 1325da74 Iustin Pop
        for attr in ['memory_total', 'memory_free', 'memory_dom0',
8457 1325da74 Iustin Pop
                     'vg_size', 'vg_free', 'cpu_total']:
8458 1325da74 Iustin Pop
          if attr not in remote_info:
8459 1325da74 Iustin Pop
            raise errors.OpExecError("Node '%s' didn't return attribute"
8460 1325da74 Iustin Pop
                                     " '%s'" % (nname, attr))
8461 070e998b Iustin Pop
          if not isinstance(remote_info[attr], int):
8462 1325da74 Iustin Pop
            raise errors.OpExecError("Node '%s' returned invalid value"
8463 070e998b Iustin Pop
                                     " for '%s': %s" %
8464 070e998b Iustin Pop
                                     (nname, attr, remote_info[attr]))
8465 1325da74 Iustin Pop
        # compute memory used by primary instances
8466 1325da74 Iustin Pop
        i_p_mem = i_p_up_mem = 0
8467 1325da74 Iustin Pop
        for iinfo, beinfo in i_list:
8468 1325da74 Iustin Pop
          if iinfo.primary_node == nname:
8469 1325da74 Iustin Pop
            i_p_mem += beinfo[constants.BE_MEMORY]
8470 2fa74ef4 Iustin Pop
            if iinfo.name not in node_iinfo[nname].payload:
8471 1325da74 Iustin Pop
              i_used_mem = 0
8472 1325da74 Iustin Pop
            else:
8473 2fa74ef4 Iustin Pop
              i_used_mem = int(node_iinfo[nname].payload[iinfo.name]['memory'])
8474 1325da74 Iustin Pop
            i_mem_diff = beinfo[constants.BE_MEMORY] - i_used_mem
8475 1325da74 Iustin Pop
            remote_info['memory_free'] -= max(0, i_mem_diff)
8476 1325da74 Iustin Pop
8477 1325da74 Iustin Pop
            if iinfo.admin_up:
8478 1325da74 Iustin Pop
              i_p_up_mem += beinfo[constants.BE_MEMORY]
8479 1325da74 Iustin Pop
8480 1325da74 Iustin Pop
        # compute memory used by instances
8481 1325da74 Iustin Pop
        pnr_dyn = {
8482 1325da74 Iustin Pop
          "total_memory": remote_info['memory_total'],
8483 1325da74 Iustin Pop
          "reserved_memory": remote_info['memory_dom0'],
8484 1325da74 Iustin Pop
          "free_memory": remote_info['memory_free'],
8485 1325da74 Iustin Pop
          "total_disk": remote_info['vg_size'],
8486 1325da74 Iustin Pop
          "free_disk": remote_info['vg_free'],
8487 1325da74 Iustin Pop
          "total_cpus": remote_info['cpu_total'],
8488 1325da74 Iustin Pop
          "i_pri_memory": i_p_mem,
8489 1325da74 Iustin Pop
          "i_pri_up_memory": i_p_up_mem,
8490 1325da74 Iustin Pop
          }
8491 1325da74 Iustin Pop
        pnr.update(pnr_dyn)
8492 1325da74 Iustin Pop
8493 d1c2dd75 Iustin Pop
      node_results[nname] = pnr
8494 d1c2dd75 Iustin Pop
    data["nodes"] = node_results
8495 d1c2dd75 Iustin Pop
8496 d1c2dd75 Iustin Pop
    # instance data
8497 d1c2dd75 Iustin Pop
    instance_data = {}
8498 338e51e8 Iustin Pop
    for iinfo, beinfo in i_list:
8499 a9fe7e8f Guido Trotter
      nic_data = []
8500 a9fe7e8f Guido Trotter
      for nic in iinfo.nics:
8501 a9fe7e8f Guido Trotter
        filled_params = objects.FillDict(
8502 a9fe7e8f Guido Trotter
            cluster_info.nicparams[constants.PP_DEFAULT],
8503 a9fe7e8f Guido Trotter
            nic.nicparams)
8504 a9fe7e8f Guido Trotter
        nic_dict = {"mac": nic.mac,
8505 a9fe7e8f Guido Trotter
                    "ip": nic.ip,
8506 a9fe7e8f Guido Trotter
                    "mode": filled_params[constants.NIC_MODE],
8507 a9fe7e8f Guido Trotter
                    "link": filled_params[constants.NIC_LINK],
8508 a9fe7e8f Guido Trotter
                   }
8509 a9fe7e8f Guido Trotter
        if filled_params[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
8510 a9fe7e8f Guido Trotter
          nic_dict["bridge"] = filled_params[constants.NIC_LINK]
8511 a9fe7e8f Guido Trotter
        nic_data.append(nic_dict)
8512 d1c2dd75 Iustin Pop
      pir = {
8513 d1c2dd75 Iustin Pop
        "tags": list(iinfo.GetTags()),
8514 1325da74 Iustin Pop
        "admin_up": iinfo.admin_up,
8515 338e51e8 Iustin Pop
        "vcpus": beinfo[constants.BE_VCPUS],
8516 338e51e8 Iustin Pop
        "memory": beinfo[constants.BE_MEMORY],
8517 d1c2dd75 Iustin Pop
        "os": iinfo.os,
8518 1325da74 Iustin Pop
        "nodes": [iinfo.primary_node] + list(iinfo.secondary_nodes),
8519 d1c2dd75 Iustin Pop
        "nics": nic_data,
8520 1325da74 Iustin Pop
        "disks": [{"size": dsk.size, "mode": dsk.mode} for dsk in iinfo.disks],
8521 d1c2dd75 Iustin Pop
        "disk_template": iinfo.disk_template,
8522 e69d05fd Iustin Pop
        "hypervisor": iinfo.hypervisor,
8523 d1c2dd75 Iustin Pop
        }
8524 88ae4f85 Iustin Pop
      pir["disk_space_total"] = _ComputeDiskSize(iinfo.disk_template,
8525 88ae4f85 Iustin Pop
                                                 pir["disks"])
8526 768f0a80 Iustin Pop
      instance_data[iinfo.name] = pir
8527 d61df03e Iustin Pop
8528 d1c2dd75 Iustin Pop
    data["instances"] = instance_data
8529 d61df03e Iustin Pop
8530 d1c2dd75 Iustin Pop
    self.in_data = data
8531 d61df03e Iustin Pop
8532 d1c2dd75 Iustin Pop
  def _AddNewInstance(self):
8533 d1c2dd75 Iustin Pop
    """Add new instance data to allocator structure.
8534 d61df03e Iustin Pop

8535 d1c2dd75 Iustin Pop
    This in combination with _AllocatorGetClusterData will create the
8536 d1c2dd75 Iustin Pop
    correct structure needed as input for the allocator.
8537 d61df03e Iustin Pop

8538 d1c2dd75 Iustin Pop
    The checks for the completeness of the opcode must have already been
8539 d1c2dd75 Iustin Pop
    done.
8540 d61df03e Iustin Pop

8541 d1c2dd75 Iustin Pop
    """
8542 d1c2dd75 Iustin Pop
    data = self.in_data
8543 d1c2dd75 Iustin Pop
8544 dafc7302 Guido Trotter
    disk_space = _ComputeDiskSize(self.disk_template, self.disks)
8545 d1c2dd75 Iustin Pop
8546 27579978 Iustin Pop
    if self.disk_template in constants.DTS_NET_MIRROR:
8547 27579978 Iustin Pop
      self.required_nodes = 2
8548 27579978 Iustin Pop
    else:
8549 27579978 Iustin Pop
      self.required_nodes = 1
8550 d1c2dd75 Iustin Pop
    request = {
8551 d1c2dd75 Iustin Pop
      "type": "allocate",
8552 d1c2dd75 Iustin Pop
      "name": self.name,
8553 d1c2dd75 Iustin Pop
      "disk_template": self.disk_template,
8554 d1c2dd75 Iustin Pop
      "tags": self.tags,
8555 d1c2dd75 Iustin Pop
      "os": self.os,
8556 d1c2dd75 Iustin Pop
      "vcpus": self.vcpus,
8557 d1c2dd75 Iustin Pop
      "memory": self.mem_size,
8558 d1c2dd75 Iustin Pop
      "disks": self.disks,
8559 d1c2dd75 Iustin Pop
      "disk_space_total": disk_space,
8560 d1c2dd75 Iustin Pop
      "nics": self.nics,
8561 27579978 Iustin Pop
      "required_nodes": self.required_nodes,
8562 d1c2dd75 Iustin Pop
      }
8563 d1c2dd75 Iustin Pop
    data["request"] = request
8564 298fe380 Iustin Pop
8565 d1c2dd75 Iustin Pop
  def _AddRelocateInstance(self):
8566 d1c2dd75 Iustin Pop
    """Add relocate instance data to allocator structure.
8567 298fe380 Iustin Pop

8568 d1c2dd75 Iustin Pop
    This in combination with _IAllocatorGetClusterData will create the
8569 d1c2dd75 Iustin Pop
    correct structure needed as input for the allocator.
8570 d61df03e Iustin Pop

8571 d1c2dd75 Iustin Pop
    The checks for the completeness of the opcode must have already been
8572 d1c2dd75 Iustin Pop
    done.
8573 d61df03e Iustin Pop

8574 d1c2dd75 Iustin Pop
    """
8575 923ddac0 Michael Hanselmann
    instance = self.cfg.GetInstanceInfo(self.name)
8576 27579978 Iustin Pop
    if instance is None:
8577 27579978 Iustin Pop
      raise errors.ProgrammerError("Unknown instance '%s' passed to"
8578 27579978 Iustin Pop
                                   " IAllocator" % self.name)
8579 27579978 Iustin Pop
8580 27579978 Iustin Pop
    if instance.disk_template not in constants.DTS_NET_MIRROR:
8581 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Can't relocate non-mirrored instances",
8582 5c983ee5 Iustin Pop
                                 errors.ECODE_INVAL)
8583 27579978 Iustin Pop
8584 2a139bb0 Iustin Pop
    if len(instance.secondary_nodes) != 1:
8585 5c983ee5 Iustin Pop
      raise errors.OpPrereqError("Instance has not exactly one secondary node",
8586 5c983ee5 Iustin Pop
                                 errors.ECODE_STATE)
8587 2a139bb0 Iustin Pop
8588 27579978 Iustin Pop
    self.required_nodes = 1
8589 dafc7302 Guido Trotter
    disk_sizes = [{'size': disk.size} for disk in instance.disks]
8590 dafc7302 Guido Trotter
    disk_space = _ComputeDiskSize(instance.disk_template, disk_sizes)
8591 27579978 Iustin Pop
8592 d1c2dd75 Iustin Pop
    request = {
8593 2a139bb0 Iustin Pop
      "type": "relocate",
8594 d1c2dd75 Iustin Pop
      "name": self.name,
8595 27579978 Iustin Pop
      "disk_space_total": disk_space,
8596 27579978 Iustin Pop
      "required_nodes": self.required_nodes,
8597 29859cb7 Iustin Pop
      "relocate_from": self.relocate_from,
8598 d1c2dd75 Iustin Pop
      }
8599 27579978 Iustin Pop
    self.in_data["request"] = request
8600 d61df03e Iustin Pop
8601 d1c2dd75 Iustin Pop
  def _BuildInputData(self):
8602 d1c2dd75 Iustin Pop
    """Build input data structures.
8603 d61df03e Iustin Pop

8604 d1c2dd75 Iustin Pop
    """
8605 d1c2dd75 Iustin Pop
    self._ComputeClusterData()
8606 d61df03e Iustin Pop
8607 d1c2dd75 Iustin Pop
    if self.mode == constants.IALLOCATOR_MODE_ALLOC:
8608 d1c2dd75 Iustin Pop
      self._AddNewInstance()
8609 d1c2dd75 Iustin Pop
    else:
8610 d1c2dd75 Iustin Pop
      self._AddRelocateInstance()
8611 d61df03e Iustin Pop
8612 d1c2dd75 Iustin Pop
    self.in_text = serializer.Dump(self.in_data)
8613 d61df03e Iustin Pop
8614 72737a7f Iustin Pop
  def Run(self, name, validate=True, call_fn=None):
8615 d1c2dd75 Iustin Pop
    """Run an instance allocator and return the results.
8616 298fe380 Iustin Pop

8617 d1c2dd75 Iustin Pop
    """
8618 72737a7f Iustin Pop
    if call_fn is None:
8619 923ddac0 Michael Hanselmann
      call_fn = self.rpc.call_iallocator_runner
8620 298fe380 Iustin Pop
8621 923ddac0 Michael Hanselmann
    result = call_fn(self.cfg.GetMasterNode(), name, self.in_text)
8622 4c4e4e1e Iustin Pop
    result.Raise("Failure while running the iallocator script")
8623 8d528b7c Iustin Pop
8624 87f5c298 Iustin Pop
    self.out_text = result.payload
8625 d1c2dd75 Iustin Pop
    if validate:
8626 d1c2dd75 Iustin Pop
      self._ValidateResult()
8627 298fe380 Iustin Pop
8628 d1c2dd75 Iustin Pop
  def _ValidateResult(self):
8629 d1c2dd75 Iustin Pop
    """Process the allocator results.
8630 538475ca Iustin Pop

8631 d1c2dd75 Iustin Pop
    This will process and if successful save the result in
8632 d1c2dd75 Iustin Pop
    self.out_data and the other parameters.
8633 538475ca Iustin Pop

8634 d1c2dd75 Iustin Pop
    """
8635 d1c2dd75 Iustin Pop
    try:
8636 d1c2dd75 Iustin Pop
      rdict = serializer.Load(self.out_text)
8637 d1c2dd75 Iustin Pop
    except Exception, err:
8638 d1c2dd75 Iustin Pop
      raise errors.OpExecError("Can't parse iallocator results: %s" % str(err))
8639 d1c2dd75 Iustin Pop
8640 d1c2dd75 Iustin Pop
    if not isinstance(rdict, dict):
8641 d1c2dd75 Iustin Pop
      raise errors.OpExecError("Can't parse iallocator results: not a dict")
8642 538475ca Iustin Pop
8643 d1c2dd75 Iustin Pop
    for key in "success", "info", "nodes":
8644 d1c2dd75 Iustin Pop
      if key not in rdict:
8645 d1c2dd75 Iustin Pop
        raise errors.OpExecError("Can't parse iallocator results:"
8646 d1c2dd75 Iustin Pop
                                 " missing key '%s'" % key)
8647 d1c2dd75 Iustin Pop
      setattr(self, key, rdict[key])
8648 538475ca Iustin Pop
8649 d1c2dd75 Iustin Pop
    if not isinstance(rdict["nodes"], list):
8650 d1c2dd75 Iustin Pop
      raise errors.OpExecError("Can't parse iallocator results: 'nodes' key"
8651 d1c2dd75 Iustin Pop
                               " is not a list")
8652 d1c2dd75 Iustin Pop
    self.out_data = rdict
8653 538475ca Iustin Pop
8654 538475ca Iustin Pop
8655 d61df03e Iustin Pop
class LUTestAllocator(NoHooksLU):
8656 d61df03e Iustin Pop
  """Run allocator tests.
8657 d61df03e Iustin Pop

8658 d61df03e Iustin Pop
  This LU runs the allocator tests
8659 d61df03e Iustin Pop

8660 d61df03e Iustin Pop
  """
8661 d61df03e Iustin Pop
  _OP_REQP = ["direction", "mode", "name"]
8662 d61df03e Iustin Pop
8663 d61df03e Iustin Pop
  def CheckPrereq(self):
8664 d61df03e Iustin Pop
    """Check prerequisites.
8665 d61df03e Iustin Pop

8666 d61df03e Iustin Pop
    This checks the opcode parameters depending on the director and mode test.
8667 d61df03e Iustin Pop

8668 d61df03e Iustin Pop
    """
8669 298fe380 Iustin Pop
    if self.op.mode == constants.IALLOCATOR_MODE_ALLOC:
8670 d61df03e Iustin Pop
      for attr in ["name", "mem_size", "disks", "disk_template",
8671 d61df03e Iustin Pop
                   "os", "tags", "nics", "vcpus"]:
8672 d61df03e Iustin Pop
        if not hasattr(self.op, attr):
8673 d61df03e Iustin Pop
          raise errors.OpPrereqError("Missing attribute '%s' on opcode input" %
8674 5c983ee5 Iustin Pop
                                     attr, errors.ECODE_INVAL)
8675 d61df03e Iustin Pop
      iname = self.cfg.ExpandInstanceName(self.op.name)
8676 d61df03e Iustin Pop
      if iname is not None:
8677 d61df03e Iustin Pop
        raise errors.OpPrereqError("Instance '%s' already in the cluster" %
8678 5c983ee5 Iustin Pop
                                   iname, errors.ECODE_EXISTS)
8679 d61df03e Iustin Pop
      if not isinstance(self.op.nics, list):
8680 5c983ee5 Iustin Pop
        raise errors.OpPrereqError("Invalid parameter 'nics'",
8681 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
8682 d61df03e Iustin Pop
      for row in self.op.nics:
8683 d61df03e Iustin Pop
        if (not isinstance(row, dict) or
8684 d61df03e Iustin Pop
            "mac" not in row or
8685 d61df03e Iustin Pop
            "ip" not in row or
8686 d61df03e Iustin Pop
            "bridge" not in row):
8687 5c983ee5 Iustin Pop
          raise errors.OpPrereqError("Invalid contents of the 'nics'"
8688 5c983ee5 Iustin Pop
                                     " parameter", errors.ECODE_INVAL)
8689 d61df03e Iustin Pop
      if not isinstance(self.op.disks, list):
8690 5c983ee5 Iustin Pop
        raise errors.OpPrereqError("Invalid parameter 'disks'",
8691 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
8692 d61df03e Iustin Pop
      for row in self.op.disks:
8693 d61df03e Iustin Pop
        if (not isinstance(row, dict) or
8694 d61df03e Iustin Pop
            "size" not in row or
8695 d61df03e Iustin Pop
            not isinstance(row["size"], int) or
8696 d61df03e Iustin Pop
            "mode" not in row or
8697 d61df03e Iustin Pop
            row["mode"] not in ['r', 'w']):
8698 5c983ee5 Iustin Pop
          raise errors.OpPrereqError("Invalid contents of the 'disks'"
8699 5c983ee5 Iustin Pop
                                     " parameter", errors.ECODE_INVAL)
8700 8901997e Iustin Pop
      if not hasattr(self.op, "hypervisor") or self.op.hypervisor is None:
8701 8cc7e742 Guido Trotter
        self.op.hypervisor = self.cfg.GetHypervisorType()
8702 298fe380 Iustin Pop
    elif self.op.mode == constants.IALLOCATOR_MODE_RELOC:
8703 d61df03e Iustin Pop
      if not hasattr(self.op, "name"):
8704 5c983ee5 Iustin Pop
        raise errors.OpPrereqError("Missing attribute 'name' on opcode input",
8705 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
8706 d61df03e Iustin Pop
      fname = self.cfg.ExpandInstanceName(self.op.name)
8707 d61df03e Iustin Pop
      if fname is None:
8708 d61df03e Iustin Pop
        raise errors.OpPrereqError("Instance '%s' not found for relocation" %
8709 5c983ee5 Iustin Pop
                                   self.op.name, errors.ECODE_NOENT)
8710 d61df03e Iustin Pop
      self.op.name = fname
8711 29859cb7 Iustin Pop
      self.relocate_from = self.cfg.GetInstanceInfo(fname).secondary_nodes
8712 d61df03e Iustin Pop
    else:
8713 d61df03e Iustin Pop
      raise errors.OpPrereqError("Invalid test allocator mode '%s'" %
8714 5c983ee5 Iustin Pop
                                 self.op.mode, errors.ECODE_INVAL)
8715 d61df03e Iustin Pop
8716 298fe380 Iustin Pop
    if self.op.direction == constants.IALLOCATOR_DIR_OUT:
8717 298fe380 Iustin Pop
      if not hasattr(self.op, "allocator") or self.op.allocator is None:
8718 5c983ee5 Iustin Pop
        raise errors.OpPrereqError("Missing allocator name",
8719 5c983ee5 Iustin Pop
                                   errors.ECODE_INVAL)
8720 298fe380 Iustin Pop
    elif self.op.direction != constants.IALLOCATOR_DIR_IN:
8721 d61df03e Iustin Pop
      raise errors.OpPrereqError("Wrong allocator test '%s'" %
8722 5c983ee5 Iustin Pop
                                 self.op.direction, errors.ECODE_INVAL)
8723 d61df03e Iustin Pop
8724 d61df03e Iustin Pop
  def Exec(self, feedback_fn):
8725 d61df03e Iustin Pop
    """Run the allocator test.
8726 d61df03e Iustin Pop

8727 d61df03e Iustin Pop
    """
8728 29859cb7 Iustin Pop
    if self.op.mode == constants.IALLOCATOR_MODE_ALLOC:
8729 923ddac0 Michael Hanselmann
      ial = IAllocator(self.cfg, self.rpc,
8730 29859cb7 Iustin Pop
                       mode=self.op.mode,
8731 29859cb7 Iustin Pop
                       name=self.op.name,
8732 29859cb7 Iustin Pop
                       mem_size=self.op.mem_size,
8733 29859cb7 Iustin Pop
                       disks=self.op.disks,
8734 29859cb7 Iustin Pop
                       disk_template=self.op.disk_template,
8735 29859cb7 Iustin Pop
                       os=self.op.os,
8736 29859cb7 Iustin Pop
                       tags=self.op.tags,
8737 29859cb7 Iustin Pop
                       nics=self.op.nics,
8738 29859cb7 Iustin Pop
                       vcpus=self.op.vcpus,
8739 8cc7e742 Guido Trotter
                       hypervisor=self.op.hypervisor,
8740 29859cb7 Iustin Pop
                       )
8741 29859cb7 Iustin Pop
    else:
8742 923ddac0 Michael Hanselmann
      ial = IAllocator(self.cfg, self.rpc,
8743 29859cb7 Iustin Pop
                       mode=self.op.mode,
8744 29859cb7 Iustin Pop
                       name=self.op.name,
8745 29859cb7 Iustin Pop
                       relocate_from=list(self.relocate_from),
8746 29859cb7 Iustin Pop
                       )
8747 d61df03e Iustin Pop
8748 298fe380 Iustin Pop
    if self.op.direction == constants.IALLOCATOR_DIR_IN:
8749 d1c2dd75 Iustin Pop
      result = ial.in_text
8750 298fe380 Iustin Pop
    else:
8751 d1c2dd75 Iustin Pop
      ial.Run(self.op.allocator, validate=False)
8752 d1c2dd75 Iustin Pop
      result = ial.out_text
8753 298fe380 Iustin Pop
    return result