Statistics
| Branch: | Tag: | Revision:

root / lib / cmdlib.py @ 6048c986

History | View | Annotate | Download (168.4 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 sha
29 a8083063 Iustin Pop
import time
30 a8083063 Iustin Pop
import tempfile
31 a8083063 Iustin Pop
import re
32 a8083063 Iustin Pop
import platform
33 a8083063 Iustin Pop
34 a8083063 Iustin Pop
from ganeti import rpc
35 a8083063 Iustin Pop
from ganeti import ssh
36 a8083063 Iustin Pop
from ganeti import logger
37 a8083063 Iustin Pop
from ganeti import utils
38 a8083063 Iustin Pop
from ganeti import errors
39 a8083063 Iustin Pop
from ganeti import hypervisor
40 6048c986 Guido Trotter
from ganeti import locking
41 a8083063 Iustin Pop
from ganeti import config
42 a8083063 Iustin Pop
from ganeti import constants
43 a8083063 Iustin Pop
from ganeti import objects
44 a8083063 Iustin Pop
from ganeti import opcodes
45 a8083063 Iustin Pop
from ganeti import ssconf
46 8d14b30d Iustin Pop
from ganeti import serializer
47 d61df03e Iustin Pop
48 d61df03e Iustin Pop
49 a8083063 Iustin Pop
class LogicalUnit(object):
50 396e1b78 Michael Hanselmann
  """Logical Unit base class.
51 a8083063 Iustin Pop

52 a8083063 Iustin Pop
  Subclasses must follow these rules:
53 a8083063 Iustin Pop
    - implement CheckPrereq which also fills in the opcode instance
54 a8083063 Iustin Pop
      with all the fields (even if as None)
55 a8083063 Iustin Pop
    - implement Exec
56 a8083063 Iustin Pop
    - implement BuildHooksEnv
57 a8083063 Iustin Pop
    - redefine HPATH and HTYPE
58 05f86716 Guido Trotter
    - optionally redefine their run requirements:
59 05f86716 Guido Trotter
        REQ_MASTER: the LU needs to run on the master node
60 05f86716 Guido Trotter
        REQ_WSSTORE: the LU needs a writable SimpleStore
61 7e55040e Guido Trotter
        REQ_BGL: the LU needs to hold the Big Ganeti Lock exclusively
62 05f86716 Guido Trotter

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

65 a8083063 Iustin Pop
  """
66 a8083063 Iustin Pop
  HPATH = None
67 a8083063 Iustin Pop
  HTYPE = None
68 a8083063 Iustin Pop
  _OP_REQP = []
69 a8083063 Iustin Pop
  REQ_MASTER = True
70 05f86716 Guido Trotter
  REQ_WSSTORE = False
71 7e55040e Guido Trotter
  REQ_BGL = True
72 a8083063 Iustin Pop
73 77b657a3 Guido Trotter
  def __init__(self, processor, op, context, sstore):
74 a8083063 Iustin Pop
    """Constructor for LogicalUnit.
75 a8083063 Iustin Pop

76 a8083063 Iustin Pop
    This needs to be overriden in derived classes in order to check op
77 a8083063 Iustin Pop
    validity.
78 a8083063 Iustin Pop

79 a8083063 Iustin Pop
    """
80 5bfac263 Iustin Pop
    self.proc = processor
81 a8083063 Iustin Pop
    self.op = op
82 77b657a3 Guido Trotter
    self.cfg = context.cfg
83 a8083063 Iustin Pop
    self.sstore = sstore
84 77b657a3 Guido Trotter
    self.context = context
85 c92b310a Michael Hanselmann
    self.__ssh = None
86 c92b310a Michael Hanselmann
87 a8083063 Iustin Pop
    for attr_name in self._OP_REQP:
88 a8083063 Iustin Pop
      attr_val = getattr(op, attr_name, None)
89 a8083063 Iustin Pop
      if attr_val is None:
90 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Required parameter '%s' missing" %
91 3ecf6786 Iustin Pop
                                   attr_name)
92 c6d58a2b Michael Hanselmann
93 f64c9de6 Guido Trotter
    if not self.cfg.IsCluster():
94 c6d58a2b Michael Hanselmann
      raise errors.OpPrereqError("Cluster not initialized yet,"
95 c6d58a2b Michael Hanselmann
                                 " use 'gnt-cluster init' first.")
96 c6d58a2b Michael Hanselmann
    if self.REQ_MASTER:
97 c6d58a2b Michael Hanselmann
      master = sstore.GetMasterNode()
98 c6d58a2b Michael Hanselmann
      if master != utils.HostInfo().name:
99 c6d58a2b Michael Hanselmann
        raise errors.OpPrereqError("Commands must be run on the master"
100 c6d58a2b Michael Hanselmann
                                   " node %s" % master)
101 a8083063 Iustin Pop
102 c92b310a Michael Hanselmann
  def __GetSSH(self):
103 c92b310a Michael Hanselmann
    """Returns the SshRunner object
104 c92b310a Michael Hanselmann

105 c92b310a Michael Hanselmann
    """
106 c92b310a Michael Hanselmann
    if not self.__ssh:
107 1ff08570 Michael Hanselmann
      self.__ssh = ssh.SshRunner(self.sstore)
108 c92b310a Michael Hanselmann
    return self.__ssh
109 c92b310a Michael Hanselmann
110 c92b310a Michael Hanselmann
  ssh = property(fget=__GetSSH)
111 c92b310a Michael Hanselmann
112 a8083063 Iustin Pop
  def CheckPrereq(self):
113 a8083063 Iustin Pop
    """Check prerequisites for this LU.
114 a8083063 Iustin Pop

115 a8083063 Iustin Pop
    This method should check that the prerequisites for the execution
116 a8083063 Iustin Pop
    of this LU are fulfilled. It can do internode communication, but
117 a8083063 Iustin Pop
    it should be idempotent - no cluster or system changes are
118 a8083063 Iustin Pop
    allowed.
119 a8083063 Iustin Pop

120 a8083063 Iustin Pop
    The method should raise errors.OpPrereqError in case something is
121 a8083063 Iustin Pop
    not fulfilled. Its return value is ignored.
122 a8083063 Iustin Pop

123 a8083063 Iustin Pop
    This method should also update all the parameters of the opcode to
124 a8083063 Iustin Pop
    their canonical form; e.g. a short node name must be fully
125 a8083063 Iustin Pop
    expanded after this method has successfully completed (so that
126 a8083063 Iustin Pop
    hooks, logging, etc. work correctly).
127 a8083063 Iustin Pop

128 a8083063 Iustin Pop
    """
129 a8083063 Iustin Pop
    raise NotImplementedError
130 a8083063 Iustin Pop
131 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
132 a8083063 Iustin Pop
    """Execute the LU.
133 a8083063 Iustin Pop

134 a8083063 Iustin Pop
    This method should implement the actual work. It should raise
135 a8083063 Iustin Pop
    errors.OpExecError for failures that are somewhat dealt with in
136 a8083063 Iustin Pop
    code, or expected.
137 a8083063 Iustin Pop

138 a8083063 Iustin Pop
    """
139 a8083063 Iustin Pop
    raise NotImplementedError
140 a8083063 Iustin Pop
141 a8083063 Iustin Pop
  def BuildHooksEnv(self):
142 a8083063 Iustin Pop
    """Build hooks environment for this LU.
143 a8083063 Iustin Pop

144 a8083063 Iustin Pop
    This method should return a three-node tuple consisting of: a dict
145 a8083063 Iustin Pop
    containing the environment that will be used for running the
146 a8083063 Iustin Pop
    specific hook for this LU, a list of node names on which the hook
147 a8083063 Iustin Pop
    should run before the execution, and a list of node names on which
148 a8083063 Iustin Pop
    the hook should run after the execution.
149 a8083063 Iustin Pop

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

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

157 a8083063 Iustin Pop
    Note that if the HPATH for a LU class is None, this function will
158 a8083063 Iustin Pop
    not be called.
159 a8083063 Iustin Pop

160 a8083063 Iustin Pop
    """
161 a8083063 Iustin Pop
    raise NotImplementedError
162 a8083063 Iustin Pop
163 1fce5219 Guido Trotter
  def HooksCallBack(self, phase, hook_results, feedback_fn, lu_result):
164 1fce5219 Guido Trotter
    """Notify the LU about the results of its hooks.
165 1fce5219 Guido Trotter

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

172 1fce5219 Guido Trotter
    Args:
173 1fce5219 Guido Trotter
      phase: the hooks phase that has just been run
174 1fce5219 Guido Trotter
      hooks_results: the results of the multi-node hooks rpc call
175 1fce5219 Guido Trotter
      feedback_fn: function to send feedback back to the caller
176 1fce5219 Guido Trotter
      lu_result: the previous result this LU had, or None in the PRE phase.
177 1fce5219 Guido Trotter

178 1fce5219 Guido Trotter
    """
179 1fce5219 Guido Trotter
    return lu_result
180 1fce5219 Guido Trotter
181 a8083063 Iustin Pop
182 a8083063 Iustin Pop
class NoHooksLU(LogicalUnit):
183 a8083063 Iustin Pop
  """Simple LU which runs no hooks.
184 a8083063 Iustin Pop

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

188 a8083063 Iustin Pop
  """
189 a8083063 Iustin Pop
  HPATH = None
190 a8083063 Iustin Pop
  HTYPE = None
191 a8083063 Iustin Pop
192 a8083063 Iustin Pop
193 dcb93971 Michael Hanselmann
def _GetWantedNodes(lu, nodes):
194 a7ba5e53 Iustin Pop
  """Returns list of checked and expanded node names.
195 83120a01 Michael Hanselmann

196 83120a01 Michael Hanselmann
  Args:
197 83120a01 Michael Hanselmann
    nodes: List of nodes (strings) or None for all
198 83120a01 Michael Hanselmann

199 83120a01 Michael Hanselmann
  """
200 3312b702 Iustin Pop
  if not isinstance(nodes, list):
201 3ecf6786 Iustin Pop
    raise errors.OpPrereqError("Invalid argument type 'nodes'")
202 dcb93971 Michael Hanselmann
203 dcb93971 Michael Hanselmann
  if nodes:
204 3312b702 Iustin Pop
    wanted = []
205 dcb93971 Michael Hanselmann
206 dcb93971 Michael Hanselmann
    for name in nodes:
207 a7ba5e53 Iustin Pop
      node = lu.cfg.ExpandNodeName(name)
208 dcb93971 Michael Hanselmann
      if node is None:
209 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("No such node name '%s'" % name)
210 3312b702 Iustin Pop
      wanted.append(node)
211 dcb93971 Michael Hanselmann
212 dcb93971 Michael Hanselmann
  else:
213 a7ba5e53 Iustin Pop
    wanted = lu.cfg.GetNodeList()
214 a7ba5e53 Iustin Pop
  return utils.NiceSort(wanted)
215 3312b702 Iustin Pop
216 3312b702 Iustin Pop
217 3312b702 Iustin Pop
def _GetWantedInstances(lu, instances):
218 a7ba5e53 Iustin Pop
  """Returns list of checked and expanded instance names.
219 3312b702 Iustin Pop

220 3312b702 Iustin Pop
  Args:
221 3312b702 Iustin Pop
    instances: List of instances (strings) or None for all
222 3312b702 Iustin Pop

223 3312b702 Iustin Pop
  """
224 3312b702 Iustin Pop
  if not isinstance(instances, list):
225 3312b702 Iustin Pop
    raise errors.OpPrereqError("Invalid argument type 'instances'")
226 3312b702 Iustin Pop
227 3312b702 Iustin Pop
  if instances:
228 3312b702 Iustin Pop
    wanted = []
229 3312b702 Iustin Pop
230 3312b702 Iustin Pop
    for name in instances:
231 a7ba5e53 Iustin Pop
      instance = lu.cfg.ExpandInstanceName(name)
232 3312b702 Iustin Pop
      if instance is None:
233 3312b702 Iustin Pop
        raise errors.OpPrereqError("No such instance name '%s'" % name)
234 3312b702 Iustin Pop
      wanted.append(instance)
235 3312b702 Iustin Pop
236 3312b702 Iustin Pop
  else:
237 a7ba5e53 Iustin Pop
    wanted = lu.cfg.GetInstanceList()
238 a7ba5e53 Iustin Pop
  return utils.NiceSort(wanted)
239 dcb93971 Michael Hanselmann
240 dcb93971 Michael Hanselmann
241 dcb93971 Michael Hanselmann
def _CheckOutputFields(static, dynamic, selected):
242 83120a01 Michael Hanselmann
  """Checks whether all selected fields are valid.
243 83120a01 Michael Hanselmann

244 83120a01 Michael Hanselmann
  Args:
245 83120a01 Michael Hanselmann
    static: Static fields
246 83120a01 Michael Hanselmann
    dynamic: Dynamic fields
247 83120a01 Michael Hanselmann

248 83120a01 Michael Hanselmann
  """
249 83120a01 Michael Hanselmann
  static_fields = frozenset(static)
250 83120a01 Michael Hanselmann
  dynamic_fields = frozenset(dynamic)
251 dcb93971 Michael Hanselmann
252 83120a01 Michael Hanselmann
  all_fields = static_fields | dynamic_fields
253 dcb93971 Michael Hanselmann
254 83120a01 Michael Hanselmann
  if not all_fields.issuperset(selected):
255 3ecf6786 Iustin Pop
    raise errors.OpPrereqError("Unknown output fields selected: %s"
256 3ecf6786 Iustin Pop
                               % ",".join(frozenset(selected).
257 3ecf6786 Iustin Pop
                                          difference(all_fields)))
258 dcb93971 Michael Hanselmann
259 dcb93971 Michael Hanselmann
260 ecb215b5 Michael Hanselmann
def _BuildInstanceHookEnv(name, primary_node, secondary_nodes, os_type, status,
261 396e1b78 Michael Hanselmann
                          memory, vcpus, nics):
262 ecb215b5 Michael Hanselmann
  """Builds instance related env variables for hooks from single variables.
263 ecb215b5 Michael Hanselmann

264 ecb215b5 Michael Hanselmann
  Args:
265 ecb215b5 Michael Hanselmann
    secondary_nodes: List of secondary nodes as strings
266 396e1b78 Michael Hanselmann
  """
267 396e1b78 Michael Hanselmann
  env = {
268 0e137c28 Iustin Pop
    "OP_TARGET": name,
269 396e1b78 Michael Hanselmann
    "INSTANCE_NAME": name,
270 396e1b78 Michael Hanselmann
    "INSTANCE_PRIMARY": primary_node,
271 396e1b78 Michael Hanselmann
    "INSTANCE_SECONDARIES": " ".join(secondary_nodes),
272 ecb215b5 Michael Hanselmann
    "INSTANCE_OS_TYPE": os_type,
273 396e1b78 Michael Hanselmann
    "INSTANCE_STATUS": status,
274 396e1b78 Michael Hanselmann
    "INSTANCE_MEMORY": memory,
275 396e1b78 Michael Hanselmann
    "INSTANCE_VCPUS": vcpus,
276 396e1b78 Michael Hanselmann
  }
277 396e1b78 Michael Hanselmann
278 396e1b78 Michael Hanselmann
  if nics:
279 396e1b78 Michael Hanselmann
    nic_count = len(nics)
280 53e4e875 Guido Trotter
    for idx, (ip, bridge, mac) in enumerate(nics):
281 396e1b78 Michael Hanselmann
      if ip is None:
282 396e1b78 Michael Hanselmann
        ip = ""
283 396e1b78 Michael Hanselmann
      env["INSTANCE_NIC%d_IP" % idx] = ip
284 396e1b78 Michael Hanselmann
      env["INSTANCE_NIC%d_BRIDGE" % idx] = bridge
285 53e4e875 Guido Trotter
      env["INSTANCE_NIC%d_HWADDR" % idx] = mac
286 396e1b78 Michael Hanselmann
  else:
287 396e1b78 Michael Hanselmann
    nic_count = 0
288 396e1b78 Michael Hanselmann
289 396e1b78 Michael Hanselmann
  env["INSTANCE_NIC_COUNT"] = nic_count
290 396e1b78 Michael Hanselmann
291 396e1b78 Michael Hanselmann
  return env
292 396e1b78 Michael Hanselmann
293 396e1b78 Michael Hanselmann
294 396e1b78 Michael Hanselmann
def _BuildInstanceHookEnvByObject(instance, override=None):
295 ecb215b5 Michael Hanselmann
  """Builds instance related env variables for hooks from an object.
296 ecb215b5 Michael Hanselmann

297 ecb215b5 Michael Hanselmann
  Args:
298 ecb215b5 Michael Hanselmann
    instance: objects.Instance object of instance
299 ecb215b5 Michael Hanselmann
    override: dict of values to override
300 ecb215b5 Michael Hanselmann
  """
301 396e1b78 Michael Hanselmann
  args = {
302 396e1b78 Michael Hanselmann
    'name': instance.name,
303 396e1b78 Michael Hanselmann
    'primary_node': instance.primary_node,
304 396e1b78 Michael Hanselmann
    'secondary_nodes': instance.secondary_nodes,
305 ecb215b5 Michael Hanselmann
    'os_type': instance.os,
306 396e1b78 Michael Hanselmann
    'status': instance.os,
307 396e1b78 Michael Hanselmann
    'memory': instance.memory,
308 396e1b78 Michael Hanselmann
    'vcpus': instance.vcpus,
309 53e4e875 Guido Trotter
    'nics': [(nic.ip, nic.bridge, nic.mac) for nic in instance.nics],
310 396e1b78 Michael Hanselmann
  }
311 396e1b78 Michael Hanselmann
  if override:
312 396e1b78 Michael Hanselmann
    args.update(override)
313 396e1b78 Michael Hanselmann
  return _BuildInstanceHookEnv(**args)
314 396e1b78 Michael Hanselmann
315 396e1b78 Michael Hanselmann
316 bf6929a2 Alexander Schreiber
def _CheckInstanceBridgesExist(instance):
317 bf6929a2 Alexander Schreiber
  """Check that the brigdes needed by an instance exist.
318 bf6929a2 Alexander Schreiber

319 bf6929a2 Alexander Schreiber
  """
320 bf6929a2 Alexander Schreiber
  # check bridges existance
321 bf6929a2 Alexander Schreiber
  brlist = [nic.bridge for nic in instance.nics]
322 bf6929a2 Alexander Schreiber
  if not rpc.call_bridges_exist(instance.primary_node, brlist):
323 bf6929a2 Alexander Schreiber
    raise errors.OpPrereqError("one or more target bridges %s does not"
324 bf6929a2 Alexander Schreiber
                               " exist on destination node '%s'" %
325 bf6929a2 Alexander Schreiber
                               (brlist, instance.primary_node))
326 bf6929a2 Alexander Schreiber
327 bf6929a2 Alexander Schreiber
328 a8083063 Iustin Pop
class LUDestroyCluster(NoHooksLU):
329 a8083063 Iustin Pop
  """Logical unit for destroying the cluster.
330 a8083063 Iustin Pop

331 a8083063 Iustin Pop
  """
332 a8083063 Iustin Pop
  _OP_REQP = []
333 a8083063 Iustin Pop
334 a8083063 Iustin Pop
  def CheckPrereq(self):
335 a8083063 Iustin Pop
    """Check prerequisites.
336 a8083063 Iustin Pop

337 a8083063 Iustin Pop
    This checks whether the cluster is empty.
338 a8083063 Iustin Pop

339 a8083063 Iustin Pop
    Any errors are signalled by raising errors.OpPrereqError.
340 a8083063 Iustin Pop

341 a8083063 Iustin Pop
    """
342 880478f8 Iustin Pop
    master = self.sstore.GetMasterNode()
343 a8083063 Iustin Pop
344 a8083063 Iustin Pop
    nodelist = self.cfg.GetNodeList()
345 db915bd1 Michael Hanselmann
    if len(nodelist) != 1 or nodelist[0] != master:
346 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("There are still %d node(s) in"
347 3ecf6786 Iustin Pop
                                 " this cluster." % (len(nodelist) - 1))
348 db915bd1 Michael Hanselmann
    instancelist = self.cfg.GetInstanceList()
349 db915bd1 Michael Hanselmann
    if instancelist:
350 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("There are still %d instance(s) in"
351 3ecf6786 Iustin Pop
                                 " this cluster." % len(instancelist))
352 a8083063 Iustin Pop
353 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
354 a8083063 Iustin Pop
    """Destroys the cluster.
355 a8083063 Iustin Pop

356 a8083063 Iustin Pop
    """
357 c8a0948f Michael Hanselmann
    master = self.sstore.GetMasterNode()
358 c9064964 Iustin Pop
    if not rpc.call_node_stop_master(master):
359 c9064964 Iustin Pop
      raise errors.OpExecError("Could not disable the master role")
360 70d9e3d8 Iustin Pop
    priv_key, pub_key, _ = ssh.GetUserFiles(constants.GANETI_RUNAS)
361 70d9e3d8 Iustin Pop
    utils.CreateBackup(priv_key)
362 70d9e3d8 Iustin Pop
    utils.CreateBackup(pub_key)
363 c8a0948f Michael Hanselmann
    rpc.call_node_leave_cluster(master)
364 a8083063 Iustin Pop
365 a8083063 Iustin Pop
366 d8fff41c Guido Trotter
class LUVerifyCluster(LogicalUnit):
367 a8083063 Iustin Pop
  """Verifies the cluster status.
368 a8083063 Iustin Pop

369 a8083063 Iustin Pop
  """
370 d8fff41c Guido Trotter
  HPATH = "cluster-verify"
371 d8fff41c Guido Trotter
  HTYPE = constants.HTYPE_CLUSTER
372 e54c4c5e Guido Trotter
  _OP_REQP = ["skip_checks"]
373 a8083063 Iustin Pop
374 a8083063 Iustin Pop
  def _VerifyNode(self, node, file_list, local_cksum, vglist, node_result,
375 a8083063 Iustin Pop
                  remote_version, feedback_fn):
376 a8083063 Iustin Pop
    """Run multiple tests against a node.
377 a8083063 Iustin Pop

378 a8083063 Iustin Pop
    Test list:
379 a8083063 Iustin Pop
      - compares ganeti version
380 a8083063 Iustin Pop
      - checks vg existance and size > 20G
381 a8083063 Iustin Pop
      - checks config file checksum
382 a8083063 Iustin Pop
      - checks ssh to other nodes
383 a8083063 Iustin Pop

384 a8083063 Iustin Pop
    Args:
385 a8083063 Iustin Pop
      node: name of the node to check
386 a8083063 Iustin Pop
      file_list: required list of files
387 a8083063 Iustin Pop
      local_cksum: dictionary of local files and their checksums
388 098c0958 Michael Hanselmann

389 a8083063 Iustin Pop
    """
390 a8083063 Iustin Pop
    # compares ganeti version
391 a8083063 Iustin Pop
    local_version = constants.PROTOCOL_VERSION
392 a8083063 Iustin Pop
    if not remote_version:
393 c840ae6f Guido Trotter
      feedback_fn("  - ERROR: connection to %s failed" % (node))
394 a8083063 Iustin Pop
      return True
395 a8083063 Iustin Pop
396 a8083063 Iustin Pop
    if local_version != remote_version:
397 a8083063 Iustin Pop
      feedback_fn("  - ERROR: sw version mismatch: master %s, node(%s) %s" %
398 a8083063 Iustin Pop
                      (local_version, node, remote_version))
399 a8083063 Iustin Pop
      return True
400 a8083063 Iustin Pop
401 a8083063 Iustin Pop
    # checks vg existance and size > 20G
402 a8083063 Iustin Pop
403 a8083063 Iustin Pop
    bad = False
404 a8083063 Iustin Pop
    if not vglist:
405 a8083063 Iustin Pop
      feedback_fn("  - ERROR: unable to check volume groups on node %s." %
406 a8083063 Iustin Pop
                      (node,))
407 a8083063 Iustin Pop
      bad = True
408 a8083063 Iustin Pop
    else:
409 8d1a2a64 Michael Hanselmann
      vgstatus = utils.CheckVolumeGroupSize(vglist, self.cfg.GetVGName(),
410 8d1a2a64 Michael Hanselmann
                                            constants.MIN_VG_SIZE)
411 a8083063 Iustin Pop
      if vgstatus:
412 a8083063 Iustin Pop
        feedback_fn("  - ERROR: %s on node %s" % (vgstatus, node))
413 a8083063 Iustin Pop
        bad = True
414 a8083063 Iustin Pop
415 a8083063 Iustin Pop
    # checks config file checksum
416 a8083063 Iustin Pop
    # checks ssh to any
417 a8083063 Iustin Pop
418 a8083063 Iustin Pop
    if 'filelist' not in node_result:
419 a8083063 Iustin Pop
      bad = True
420 a8083063 Iustin Pop
      feedback_fn("  - ERROR: node hasn't returned file checksum data")
421 a8083063 Iustin Pop
    else:
422 a8083063 Iustin Pop
      remote_cksum = node_result['filelist']
423 a8083063 Iustin Pop
      for file_name in file_list:
424 a8083063 Iustin Pop
        if file_name not in remote_cksum:
425 a8083063 Iustin Pop
          bad = True
426 a8083063 Iustin Pop
          feedback_fn("  - ERROR: file '%s' missing" % file_name)
427 a8083063 Iustin Pop
        elif remote_cksum[file_name] != local_cksum[file_name]:
428 a8083063 Iustin Pop
          bad = True
429 a8083063 Iustin Pop
          feedback_fn("  - ERROR: file '%s' has wrong checksum" % file_name)
430 a8083063 Iustin Pop
431 a8083063 Iustin Pop
    if 'nodelist' not in node_result:
432 a8083063 Iustin Pop
      bad = True
433 9d4bfc96 Iustin Pop
      feedback_fn("  - ERROR: node hasn't returned node ssh connectivity data")
434 a8083063 Iustin Pop
    else:
435 a8083063 Iustin Pop
      if node_result['nodelist']:
436 a8083063 Iustin Pop
        bad = True
437 a8083063 Iustin Pop
        for node in node_result['nodelist']:
438 9d4bfc96 Iustin Pop
          feedback_fn("  - ERROR: ssh communication with node '%s': %s" %
439 a8083063 Iustin Pop
                          (node, node_result['nodelist'][node]))
440 9d4bfc96 Iustin Pop
    if 'node-net-test' not in node_result:
441 9d4bfc96 Iustin Pop
      bad = True
442 9d4bfc96 Iustin Pop
      feedback_fn("  - ERROR: node hasn't returned node tcp connectivity data")
443 9d4bfc96 Iustin Pop
    else:
444 9d4bfc96 Iustin Pop
      if node_result['node-net-test']:
445 9d4bfc96 Iustin Pop
        bad = True
446 9d4bfc96 Iustin Pop
        nlist = utils.NiceSort(node_result['node-net-test'].keys())
447 9d4bfc96 Iustin Pop
        for node in nlist:
448 9d4bfc96 Iustin Pop
          feedback_fn("  - ERROR: tcp communication with node '%s': %s" %
449 9d4bfc96 Iustin Pop
                          (node, node_result['node-net-test'][node]))
450 9d4bfc96 Iustin Pop
451 a8083063 Iustin Pop
    hyp_result = node_result.get('hypervisor', None)
452 a8083063 Iustin Pop
    if hyp_result is not None:
453 a8083063 Iustin Pop
      feedback_fn("  - ERROR: hypervisor verify failure: '%s'" % hyp_result)
454 a8083063 Iustin Pop
    return bad
455 a8083063 Iustin Pop
456 c5705f58 Guido Trotter
  def _VerifyInstance(self, instance, instanceconfig, node_vol_is,
457 c5705f58 Guido Trotter
                      node_instance, feedback_fn):
458 a8083063 Iustin Pop
    """Verify an instance.
459 a8083063 Iustin Pop

460 a8083063 Iustin Pop
    This function checks to see if the required block devices are
461 a8083063 Iustin Pop
    available on the instance's node.
462 a8083063 Iustin Pop

463 a8083063 Iustin Pop
    """
464 a8083063 Iustin Pop
    bad = False
465 a8083063 Iustin Pop
466 a8083063 Iustin Pop
    node_current = instanceconfig.primary_node
467 a8083063 Iustin Pop
468 a8083063 Iustin Pop
    node_vol_should = {}
469 a8083063 Iustin Pop
    instanceconfig.MapLVsByNode(node_vol_should)
470 a8083063 Iustin Pop
471 a8083063 Iustin Pop
    for node in node_vol_should:
472 a8083063 Iustin Pop
      for volume in node_vol_should[node]:
473 a8083063 Iustin Pop
        if node not in node_vol_is or volume not in node_vol_is[node]:
474 a8083063 Iustin Pop
          feedback_fn("  - ERROR: volume %s missing on node %s" %
475 a8083063 Iustin Pop
                          (volume, node))
476 a8083063 Iustin Pop
          bad = True
477 a8083063 Iustin Pop
478 a8083063 Iustin Pop
    if not instanceconfig.status == 'down':
479 a872dae6 Guido Trotter
      if (node_current not in node_instance or
480 a872dae6 Guido Trotter
          not instance in node_instance[node_current]):
481 a8083063 Iustin Pop
        feedback_fn("  - ERROR: instance %s not running on node %s" %
482 a8083063 Iustin Pop
                        (instance, node_current))
483 a8083063 Iustin Pop
        bad = True
484 a8083063 Iustin Pop
485 a8083063 Iustin Pop
    for node in node_instance:
486 a8083063 Iustin Pop
      if (not node == node_current):
487 a8083063 Iustin Pop
        if instance in node_instance[node]:
488 a8083063 Iustin Pop
          feedback_fn("  - ERROR: instance %s should not run on node %s" %
489 a8083063 Iustin Pop
                          (instance, node))
490 a8083063 Iustin Pop
          bad = True
491 a8083063 Iustin Pop
492 6a438c98 Michael Hanselmann
    return bad
493 a8083063 Iustin Pop
494 a8083063 Iustin Pop
  def _VerifyOrphanVolumes(self, node_vol_should, node_vol_is, feedback_fn):
495 a8083063 Iustin Pop
    """Verify if there are any unknown volumes in the cluster.
496 a8083063 Iustin Pop

497 a8083063 Iustin Pop
    The .os, .swap and backup volumes are ignored. All other volumes are
498 a8083063 Iustin Pop
    reported as unknown.
499 a8083063 Iustin Pop

500 a8083063 Iustin Pop
    """
501 a8083063 Iustin Pop
    bad = False
502 a8083063 Iustin Pop
503 a8083063 Iustin Pop
    for node in node_vol_is:
504 a8083063 Iustin Pop
      for volume in node_vol_is[node]:
505 a8083063 Iustin Pop
        if node not in node_vol_should or volume not in node_vol_should[node]:
506 a8083063 Iustin Pop
          feedback_fn("  - ERROR: volume %s on node %s should not exist" %
507 a8083063 Iustin Pop
                      (volume, node))
508 a8083063 Iustin Pop
          bad = True
509 a8083063 Iustin Pop
    return bad
510 a8083063 Iustin Pop
511 a8083063 Iustin Pop
  def _VerifyOrphanInstances(self, instancelist, node_instance, feedback_fn):
512 a8083063 Iustin Pop
    """Verify the list of running instances.
513 a8083063 Iustin Pop

514 a8083063 Iustin Pop
    This checks what instances are running but unknown to the cluster.
515 a8083063 Iustin Pop

516 a8083063 Iustin Pop
    """
517 a8083063 Iustin Pop
    bad = False
518 a8083063 Iustin Pop
    for node in node_instance:
519 a8083063 Iustin Pop
      for runninginstance in node_instance[node]:
520 a8083063 Iustin Pop
        if runninginstance not in instancelist:
521 a8083063 Iustin Pop
          feedback_fn("  - ERROR: instance %s on node %s should not exist" %
522 a8083063 Iustin Pop
                          (runninginstance, node))
523 a8083063 Iustin Pop
          bad = True
524 a8083063 Iustin Pop
    return bad
525 a8083063 Iustin Pop
526 2b3b6ddd Guido Trotter
  def _VerifyNPlusOneMemory(self, node_info, instance_cfg, feedback_fn):
527 2b3b6ddd Guido Trotter
    """Verify N+1 Memory Resilience.
528 2b3b6ddd Guido Trotter

529 2b3b6ddd Guido Trotter
    Check that if one single node dies we can still start all the instances it
530 2b3b6ddd Guido Trotter
    was primary for.
531 2b3b6ddd Guido Trotter

532 2b3b6ddd Guido Trotter
    """
533 2b3b6ddd Guido Trotter
    bad = False
534 2b3b6ddd Guido Trotter
535 2b3b6ddd Guido Trotter
    for node, nodeinfo in node_info.iteritems():
536 2b3b6ddd Guido Trotter
      # This code checks that every node which is now listed as secondary has
537 2b3b6ddd Guido Trotter
      # enough memory to host all instances it is supposed to should a single
538 2b3b6ddd Guido Trotter
      # other node in the cluster fail.
539 2b3b6ddd Guido Trotter
      # FIXME: not ready for failover to an arbitrary node
540 2b3b6ddd Guido Trotter
      # FIXME: does not support file-backed instances
541 2b3b6ddd Guido Trotter
      # WARNING: we currently take into account down instances as well as up
542 2b3b6ddd Guido Trotter
      # ones, considering that even if they're down someone might want to start
543 2b3b6ddd Guido Trotter
      # them even in the event of a node failure.
544 2b3b6ddd Guido Trotter
      for prinode, instances in nodeinfo['sinst-by-pnode'].iteritems():
545 2b3b6ddd Guido Trotter
        needed_mem = 0
546 2b3b6ddd Guido Trotter
        for instance in instances:
547 2b3b6ddd Guido Trotter
          needed_mem += instance_cfg[instance].memory
548 2b3b6ddd Guido Trotter
        if nodeinfo['mfree'] < needed_mem:
549 2b3b6ddd Guido Trotter
          feedback_fn("  - ERROR: not enough memory on node %s to accomodate"
550 2b3b6ddd Guido Trotter
                      " failovers should node %s fail" % (node, prinode))
551 2b3b6ddd Guido Trotter
          bad = True
552 2b3b6ddd Guido Trotter
    return bad
553 2b3b6ddd Guido Trotter
554 a8083063 Iustin Pop
  def CheckPrereq(self):
555 a8083063 Iustin Pop
    """Check prerequisites.
556 a8083063 Iustin Pop

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

560 a8083063 Iustin Pop
    """
561 e54c4c5e Guido Trotter
    self.skip_set = frozenset(self.op.skip_checks)
562 e54c4c5e Guido Trotter
    if not constants.VERIFY_OPTIONAL_CHECKS.issuperset(self.skip_set):
563 e54c4c5e Guido Trotter
      raise errors.OpPrereqError("Invalid checks to be skipped specified")
564 a8083063 Iustin Pop
565 d8fff41c Guido Trotter
  def BuildHooksEnv(self):
566 d8fff41c Guido Trotter
    """Build hooks env.
567 d8fff41c Guido Trotter

568 d8fff41c Guido Trotter
    Cluster-Verify hooks just rone in the post phase and their failure makes
569 d8fff41c Guido Trotter
    the output be logged in the verify output and the verification to fail.
570 d8fff41c Guido Trotter

571 d8fff41c Guido Trotter
    """
572 d8fff41c Guido Trotter
    all_nodes = self.cfg.GetNodeList()
573 d8fff41c Guido Trotter
    # TODO: populate the environment with useful information for verify hooks
574 d8fff41c Guido Trotter
    env = {}
575 d8fff41c Guido Trotter
    return env, [], all_nodes
576 d8fff41c Guido Trotter
577 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
578 a8083063 Iustin Pop
    """Verify integrity of cluster, performing various test on nodes.
579 a8083063 Iustin Pop

580 a8083063 Iustin Pop
    """
581 a8083063 Iustin Pop
    bad = False
582 a8083063 Iustin Pop
    feedback_fn("* Verifying global settings")
583 8522ceeb Iustin Pop
    for msg in self.cfg.VerifyConfig():
584 8522ceeb Iustin Pop
      feedback_fn("  - ERROR: %s" % msg)
585 a8083063 Iustin Pop
586 a8083063 Iustin Pop
    vg_name = self.cfg.GetVGName()
587 a8083063 Iustin Pop
    nodelist = utils.NiceSort(self.cfg.GetNodeList())
588 9d4bfc96 Iustin Pop
    nodeinfo = [self.cfg.GetNodeInfo(nname) for nname in nodelist]
589 a8083063 Iustin Pop
    instancelist = utils.NiceSort(self.cfg.GetInstanceList())
590 93e4c50b Guido Trotter
    i_non_redundant = [] # Non redundant instances
591 a8083063 Iustin Pop
    node_volume = {}
592 a8083063 Iustin Pop
    node_instance = {}
593 9c9c7d30 Guido Trotter
    node_info = {}
594 26b6af5e Guido Trotter
    instance_cfg = {}
595 a8083063 Iustin Pop
596 a8083063 Iustin Pop
    # FIXME: verify OS list
597 a8083063 Iustin Pop
    # do local checksums
598 cb91d46e Iustin Pop
    file_names = list(self.sstore.GetFileList())
599 cb91d46e Iustin Pop
    file_names.append(constants.SSL_CERT_FILE)
600 cb91d46e Iustin Pop
    file_names.append(constants.CLUSTER_CONF_FILE)
601 a8083063 Iustin Pop
    local_checksums = utils.FingerprintFiles(file_names)
602 a8083063 Iustin Pop
603 a8083063 Iustin Pop
    feedback_fn("* Gathering data (%d nodes)" % len(nodelist))
604 a8083063 Iustin Pop
    all_volumeinfo = rpc.call_volume_list(nodelist, vg_name)
605 a8083063 Iustin Pop
    all_instanceinfo = rpc.call_instance_list(nodelist)
606 a8083063 Iustin Pop
    all_vglist = rpc.call_vg_list(nodelist)
607 a8083063 Iustin Pop
    node_verify_param = {
608 a8083063 Iustin Pop
      'filelist': file_names,
609 a8083063 Iustin Pop
      'nodelist': nodelist,
610 a8083063 Iustin Pop
      'hypervisor': None,
611 9d4bfc96 Iustin Pop
      'node-net-test': [(node.name, node.primary_ip, node.secondary_ip)
612 9d4bfc96 Iustin Pop
                        for node in nodeinfo]
613 a8083063 Iustin Pop
      }
614 a8083063 Iustin Pop
    all_nvinfo = rpc.call_node_verify(nodelist, node_verify_param)
615 a8083063 Iustin Pop
    all_rversion = rpc.call_version(nodelist)
616 9c9c7d30 Guido Trotter
    all_ninfo = rpc.call_node_info(nodelist, self.cfg.GetVGName())
617 a8083063 Iustin Pop
618 a8083063 Iustin Pop
    for node in nodelist:
619 a8083063 Iustin Pop
      feedback_fn("* Verifying node %s" % node)
620 a8083063 Iustin Pop
      result = self._VerifyNode(node, file_names, local_checksums,
621 a8083063 Iustin Pop
                                all_vglist[node], all_nvinfo[node],
622 a8083063 Iustin Pop
                                all_rversion[node], feedback_fn)
623 a8083063 Iustin Pop
      bad = bad or result
624 a8083063 Iustin Pop
625 a8083063 Iustin Pop
      # node_volume
626 a8083063 Iustin Pop
      volumeinfo = all_volumeinfo[node]
627 a8083063 Iustin Pop
628 b63ed789 Iustin Pop
      if isinstance(volumeinfo, basestring):
629 b63ed789 Iustin Pop
        feedback_fn("  - ERROR: LVM problem on node %s: %s" %
630 b63ed789 Iustin Pop
                    (node, volumeinfo[-400:].encode('string_escape')))
631 b63ed789 Iustin Pop
        bad = True
632 b63ed789 Iustin Pop
        node_volume[node] = {}
633 b63ed789 Iustin Pop
      elif not isinstance(volumeinfo, dict):
634 a8083063 Iustin Pop
        feedback_fn("  - ERROR: connection to %s failed" % (node,))
635 a8083063 Iustin Pop
        bad = True
636 a8083063 Iustin Pop
        continue
637 b63ed789 Iustin Pop
      else:
638 b63ed789 Iustin Pop
        node_volume[node] = volumeinfo
639 a8083063 Iustin Pop
640 a8083063 Iustin Pop
      # node_instance
641 a8083063 Iustin Pop
      nodeinstance = all_instanceinfo[node]
642 a8083063 Iustin Pop
      if type(nodeinstance) != list:
643 a8083063 Iustin Pop
        feedback_fn("  - ERROR: connection to %s failed" % (node,))
644 a8083063 Iustin Pop
        bad = True
645 a8083063 Iustin Pop
        continue
646 a8083063 Iustin Pop
647 a8083063 Iustin Pop
      node_instance[node] = nodeinstance
648 a8083063 Iustin Pop
649 9c9c7d30 Guido Trotter
      # node_info
650 9c9c7d30 Guido Trotter
      nodeinfo = all_ninfo[node]
651 9c9c7d30 Guido Trotter
      if not isinstance(nodeinfo, dict):
652 9c9c7d30 Guido Trotter
        feedback_fn("  - ERROR: connection to %s failed" % (node,))
653 9c9c7d30 Guido Trotter
        bad = True
654 9c9c7d30 Guido Trotter
        continue
655 9c9c7d30 Guido Trotter
656 9c9c7d30 Guido Trotter
      try:
657 9c9c7d30 Guido Trotter
        node_info[node] = {
658 9c9c7d30 Guido Trotter
          "mfree": int(nodeinfo['memory_free']),
659 9c9c7d30 Guido Trotter
          "dfree": int(nodeinfo['vg_free']),
660 93e4c50b Guido Trotter
          "pinst": [],
661 93e4c50b Guido Trotter
          "sinst": [],
662 36e7da50 Guido Trotter
          # dictionary holding all instances this node is secondary for,
663 36e7da50 Guido Trotter
          # grouped by their primary node. Each key is a cluster node, and each
664 36e7da50 Guido Trotter
          # value is a list of instances which have the key as primary and the
665 36e7da50 Guido Trotter
          # current node as secondary.  this is handy to calculate N+1 memory
666 36e7da50 Guido Trotter
          # availability if you can only failover from a primary to its
667 36e7da50 Guido Trotter
          # secondary.
668 36e7da50 Guido Trotter
          "sinst-by-pnode": {},
669 9c9c7d30 Guido Trotter
        }
670 9c9c7d30 Guido Trotter
      except ValueError:
671 9c9c7d30 Guido Trotter
        feedback_fn("  - ERROR: invalid value returned from node %s" % (node,))
672 9c9c7d30 Guido Trotter
        bad = True
673 9c9c7d30 Guido Trotter
        continue
674 9c9c7d30 Guido Trotter
675 a8083063 Iustin Pop
    node_vol_should = {}
676 a8083063 Iustin Pop
677 a8083063 Iustin Pop
    for instance in instancelist:
678 a8083063 Iustin Pop
      feedback_fn("* Verifying instance %s" % instance)
679 a8083063 Iustin Pop
      inst_config = self.cfg.GetInstanceInfo(instance)
680 c5705f58 Guido Trotter
      result =  self._VerifyInstance(instance, inst_config, node_volume,
681 c5705f58 Guido Trotter
                                     node_instance, feedback_fn)
682 c5705f58 Guido Trotter
      bad = bad or result
683 a8083063 Iustin Pop
684 a8083063 Iustin Pop
      inst_config.MapLVsByNode(node_vol_should)
685 a8083063 Iustin Pop
686 26b6af5e Guido Trotter
      instance_cfg[instance] = inst_config
687 26b6af5e Guido Trotter
688 93e4c50b Guido Trotter
      pnode = inst_config.primary_node
689 93e4c50b Guido Trotter
      if pnode in node_info:
690 93e4c50b Guido Trotter
        node_info[pnode]['pinst'].append(instance)
691 93e4c50b Guido Trotter
      else:
692 93e4c50b Guido Trotter
        feedback_fn("  - ERROR: instance %s, connection to primary node"
693 93e4c50b Guido Trotter
                    " %s failed" % (instance, pnode))
694 93e4c50b Guido Trotter
        bad = True
695 93e4c50b Guido Trotter
696 93e4c50b Guido Trotter
      # If the instance is non-redundant we cannot survive losing its primary
697 93e4c50b Guido Trotter
      # node, so we are not N+1 compliant. On the other hand we have no disk
698 93e4c50b Guido Trotter
      # templates with more than one secondary so that situation is not well
699 93e4c50b Guido Trotter
      # supported either.
700 93e4c50b Guido Trotter
      # FIXME: does not support file-backed instances
701 93e4c50b Guido Trotter
      if len(inst_config.secondary_nodes) == 0:
702 93e4c50b Guido Trotter
        i_non_redundant.append(instance)
703 93e4c50b Guido Trotter
      elif len(inst_config.secondary_nodes) > 1:
704 93e4c50b Guido Trotter
        feedback_fn("  - WARNING: multiple secondaries for instance %s"
705 93e4c50b Guido Trotter
                    % instance)
706 93e4c50b Guido Trotter
707 93e4c50b Guido Trotter
      for snode in inst_config.secondary_nodes:
708 93e4c50b Guido Trotter
        if snode in node_info:
709 93e4c50b Guido Trotter
          node_info[snode]['sinst'].append(instance)
710 36e7da50 Guido Trotter
          if pnode not in node_info[snode]['sinst-by-pnode']:
711 36e7da50 Guido Trotter
            node_info[snode]['sinst-by-pnode'][pnode] = []
712 36e7da50 Guido Trotter
          node_info[snode]['sinst-by-pnode'][pnode].append(instance)
713 93e4c50b Guido Trotter
        else:
714 93e4c50b Guido Trotter
          feedback_fn("  - ERROR: instance %s, connection to secondary node"
715 93e4c50b Guido Trotter
                      " %s failed" % (instance, snode))
716 93e4c50b Guido Trotter
717 a8083063 Iustin Pop
    feedback_fn("* Verifying orphan volumes")
718 a8083063 Iustin Pop
    result = self._VerifyOrphanVolumes(node_vol_should, node_volume,
719 a8083063 Iustin Pop
                                       feedback_fn)
720 a8083063 Iustin Pop
    bad = bad or result
721 a8083063 Iustin Pop
722 a8083063 Iustin Pop
    feedback_fn("* Verifying remaining instances")
723 a8083063 Iustin Pop
    result = self._VerifyOrphanInstances(instancelist, node_instance,
724 a8083063 Iustin Pop
                                         feedback_fn)
725 a8083063 Iustin Pop
    bad = bad or result
726 a8083063 Iustin Pop
727 e54c4c5e Guido Trotter
    if constants.VERIFY_NPLUSONE_MEM not in self.skip_set:
728 e54c4c5e Guido Trotter
      feedback_fn("* Verifying N+1 Memory redundancy")
729 e54c4c5e Guido Trotter
      result = self._VerifyNPlusOneMemory(node_info, instance_cfg, feedback_fn)
730 e54c4c5e Guido Trotter
      bad = bad or result
731 2b3b6ddd Guido Trotter
732 2b3b6ddd Guido Trotter
    feedback_fn("* Other Notes")
733 2b3b6ddd Guido Trotter
    if i_non_redundant:
734 2b3b6ddd Guido Trotter
      feedback_fn("  - NOTICE: %d non-redundant instance(s) found."
735 2b3b6ddd Guido Trotter
                  % len(i_non_redundant))
736 2b3b6ddd Guido Trotter
737 a8083063 Iustin Pop
    return int(bad)
738 a8083063 Iustin Pop
739 d8fff41c Guido Trotter
  def HooksCallBack(self, phase, hooks_results, feedback_fn, lu_result):
740 d8fff41c Guido Trotter
    """Analize the post-hooks' result, handle it, and send some
741 d8fff41c Guido Trotter
    nicely-formatted feedback back to the user.
742 d8fff41c Guido Trotter

743 d8fff41c Guido Trotter
    Args:
744 d8fff41c Guido Trotter
      phase: the hooks phase that has just been run
745 d8fff41c Guido Trotter
      hooks_results: the results of the multi-node hooks rpc call
746 d8fff41c Guido Trotter
      feedback_fn: function to send feedback back to the caller
747 d8fff41c Guido Trotter
      lu_result: previous Exec result
748 d8fff41c Guido Trotter

749 d8fff41c Guido Trotter
    """
750 d8fff41c Guido Trotter
    # We only really run POST phase hooks, and are only interested in their results
751 d8fff41c Guido Trotter
    if phase == constants.HOOKS_PHASE_POST:
752 d8fff41c Guido Trotter
      # Used to change hooks' output to proper indentation
753 d8fff41c Guido Trotter
      indent_re = re.compile('^', re.M)
754 d8fff41c Guido Trotter
      feedback_fn("* Hooks Results")
755 d8fff41c Guido Trotter
      if not hooks_results:
756 d8fff41c Guido Trotter
        feedback_fn("  - ERROR: general communication failure")
757 d8fff41c Guido Trotter
        lu_result = 1
758 d8fff41c Guido Trotter
      else:
759 d8fff41c Guido Trotter
        for node_name in hooks_results:
760 d8fff41c Guido Trotter
          show_node_header = True
761 d8fff41c Guido Trotter
          res = hooks_results[node_name]
762 d8fff41c Guido Trotter
          if res is False or not isinstance(res, list):
763 d8fff41c Guido Trotter
            feedback_fn("    Communication failure")
764 d8fff41c Guido Trotter
            lu_result = 1
765 d8fff41c Guido Trotter
            continue
766 d8fff41c Guido Trotter
          for script, hkr, output in res:
767 d8fff41c Guido Trotter
            if hkr == constants.HKR_FAIL:
768 d8fff41c Guido Trotter
              # The node header is only shown once, if there are
769 d8fff41c Guido Trotter
              # failing hooks on that node
770 d8fff41c Guido Trotter
              if show_node_header:
771 d8fff41c Guido Trotter
                feedback_fn("  Node %s:" % node_name)
772 d8fff41c Guido Trotter
                show_node_header = False
773 d8fff41c Guido Trotter
              feedback_fn("    ERROR: Script %s failed, output:" % script)
774 d8fff41c Guido Trotter
              output = indent_re.sub('      ', output)
775 d8fff41c Guido Trotter
              feedback_fn("%s" % output)
776 d8fff41c Guido Trotter
              lu_result = 1
777 d8fff41c Guido Trotter
778 d8fff41c Guido Trotter
      return lu_result
779 d8fff41c Guido Trotter
780 a8083063 Iustin Pop
781 2c95a8d4 Iustin Pop
class LUVerifyDisks(NoHooksLU):
782 2c95a8d4 Iustin Pop
  """Verifies the cluster disks status.
783 2c95a8d4 Iustin Pop

784 2c95a8d4 Iustin Pop
  """
785 2c95a8d4 Iustin Pop
  _OP_REQP = []
786 2c95a8d4 Iustin Pop
787 2c95a8d4 Iustin Pop
  def CheckPrereq(self):
788 2c95a8d4 Iustin Pop
    """Check prerequisites.
789 2c95a8d4 Iustin Pop

790 2c95a8d4 Iustin Pop
    This has no prerequisites.
791 2c95a8d4 Iustin Pop

792 2c95a8d4 Iustin Pop
    """
793 2c95a8d4 Iustin Pop
    pass
794 2c95a8d4 Iustin Pop
795 2c95a8d4 Iustin Pop
  def Exec(self, feedback_fn):
796 2c95a8d4 Iustin Pop
    """Verify integrity of cluster disks.
797 2c95a8d4 Iustin Pop

798 2c95a8d4 Iustin Pop
    """
799 b63ed789 Iustin Pop
    result = res_nodes, res_nlvm, res_instances, res_missing = [], {}, [], {}
800 2c95a8d4 Iustin Pop
801 2c95a8d4 Iustin Pop
    vg_name = self.cfg.GetVGName()
802 2c95a8d4 Iustin Pop
    nodes = utils.NiceSort(self.cfg.GetNodeList())
803 2c95a8d4 Iustin Pop
    instances = [self.cfg.GetInstanceInfo(name)
804 2c95a8d4 Iustin Pop
                 for name in self.cfg.GetInstanceList()]
805 2c95a8d4 Iustin Pop
806 2c95a8d4 Iustin Pop
    nv_dict = {}
807 2c95a8d4 Iustin Pop
    for inst in instances:
808 2c95a8d4 Iustin Pop
      inst_lvs = {}
809 2c95a8d4 Iustin Pop
      if (inst.status != "up" or
810 2c95a8d4 Iustin Pop
          inst.disk_template not in constants.DTS_NET_MIRROR):
811 2c95a8d4 Iustin Pop
        continue
812 2c95a8d4 Iustin Pop
      inst.MapLVsByNode(inst_lvs)
813 2c95a8d4 Iustin Pop
      # transform { iname: {node: [vol,],},} to {(node, vol): iname}
814 2c95a8d4 Iustin Pop
      for node, vol_list in inst_lvs.iteritems():
815 2c95a8d4 Iustin Pop
        for vol in vol_list:
816 2c95a8d4 Iustin Pop
          nv_dict[(node, vol)] = inst
817 2c95a8d4 Iustin Pop
818 2c95a8d4 Iustin Pop
    if not nv_dict:
819 2c95a8d4 Iustin Pop
      return result
820 2c95a8d4 Iustin Pop
821 2c95a8d4 Iustin Pop
    node_lvs = rpc.call_volume_list(nodes, vg_name)
822 2c95a8d4 Iustin Pop
823 2c95a8d4 Iustin Pop
    to_act = set()
824 2c95a8d4 Iustin Pop
    for node in nodes:
825 2c95a8d4 Iustin Pop
      # node_volume
826 2c95a8d4 Iustin Pop
      lvs = node_lvs[node]
827 2c95a8d4 Iustin Pop
828 b63ed789 Iustin Pop
      if isinstance(lvs, basestring):
829 b63ed789 Iustin Pop
        logger.Info("error enumerating LVs on node %s: %s" % (node, lvs))
830 b63ed789 Iustin Pop
        res_nlvm[node] = lvs
831 b63ed789 Iustin Pop
      elif not isinstance(lvs, dict):
832 2c95a8d4 Iustin Pop
        logger.Info("connection to node %s failed or invalid data returned" %
833 2c95a8d4 Iustin Pop
                    (node,))
834 2c95a8d4 Iustin Pop
        res_nodes.append(node)
835 2c95a8d4 Iustin Pop
        continue
836 2c95a8d4 Iustin Pop
837 2c95a8d4 Iustin Pop
      for lv_name, (_, lv_inactive, lv_online) in lvs.iteritems():
838 b63ed789 Iustin Pop
        inst = nv_dict.pop((node, lv_name), None)
839 b63ed789 Iustin Pop
        if (not lv_online and inst is not None
840 b63ed789 Iustin Pop
            and inst.name not in res_instances):
841 b08d5a87 Iustin Pop
          res_instances.append(inst.name)
842 2c95a8d4 Iustin Pop
843 b63ed789 Iustin Pop
    # any leftover items in nv_dict are missing LVs, let's arrange the
844 b63ed789 Iustin Pop
    # data better
845 b63ed789 Iustin Pop
    for key, inst in nv_dict.iteritems():
846 b63ed789 Iustin Pop
      if inst.name not in res_missing:
847 b63ed789 Iustin Pop
        res_missing[inst.name] = []
848 b63ed789 Iustin Pop
      res_missing[inst.name].append(key)
849 b63ed789 Iustin Pop
850 2c95a8d4 Iustin Pop
    return result
851 2c95a8d4 Iustin Pop
852 2c95a8d4 Iustin Pop
853 07bd8a51 Iustin Pop
class LURenameCluster(LogicalUnit):
854 07bd8a51 Iustin Pop
  """Rename the cluster.
855 07bd8a51 Iustin Pop

856 07bd8a51 Iustin Pop
  """
857 07bd8a51 Iustin Pop
  HPATH = "cluster-rename"
858 07bd8a51 Iustin Pop
  HTYPE = constants.HTYPE_CLUSTER
859 07bd8a51 Iustin Pop
  _OP_REQP = ["name"]
860 05f86716 Guido Trotter
  REQ_WSSTORE = True
861 07bd8a51 Iustin Pop
862 07bd8a51 Iustin Pop
  def BuildHooksEnv(self):
863 07bd8a51 Iustin Pop
    """Build hooks env.
864 07bd8a51 Iustin Pop

865 07bd8a51 Iustin Pop
    """
866 07bd8a51 Iustin Pop
    env = {
867 488b540d Iustin Pop
      "OP_TARGET": self.sstore.GetClusterName(),
868 07bd8a51 Iustin Pop
      "NEW_NAME": self.op.name,
869 07bd8a51 Iustin Pop
      }
870 07bd8a51 Iustin Pop
    mn = self.sstore.GetMasterNode()
871 07bd8a51 Iustin Pop
    return env, [mn], [mn]
872 07bd8a51 Iustin Pop
873 07bd8a51 Iustin Pop
  def CheckPrereq(self):
874 07bd8a51 Iustin Pop
    """Verify that the passed name is a valid one.
875 07bd8a51 Iustin Pop

876 07bd8a51 Iustin Pop
    """
877 89e1fc26 Iustin Pop
    hostname = utils.HostInfo(self.op.name)
878 07bd8a51 Iustin Pop
879 bcf043c9 Iustin Pop
    new_name = hostname.name
880 bcf043c9 Iustin Pop
    self.ip = new_ip = hostname.ip
881 07bd8a51 Iustin Pop
    old_name = self.sstore.GetClusterName()
882 07bd8a51 Iustin Pop
    old_ip = self.sstore.GetMasterIP()
883 07bd8a51 Iustin Pop
    if new_name == old_name and new_ip == old_ip:
884 07bd8a51 Iustin Pop
      raise errors.OpPrereqError("Neither the name nor the IP address of the"
885 07bd8a51 Iustin Pop
                                 " cluster has changed")
886 07bd8a51 Iustin Pop
    if new_ip != old_ip:
887 937f983d Guido Trotter
      if utils.TcpPing(new_ip, constants.DEFAULT_NODED_PORT):
888 07bd8a51 Iustin Pop
        raise errors.OpPrereqError("The given cluster IP address (%s) is"
889 07bd8a51 Iustin Pop
                                   " reachable on the network. Aborting." %
890 07bd8a51 Iustin Pop
                                   new_ip)
891 07bd8a51 Iustin Pop
892 07bd8a51 Iustin Pop
    self.op.name = new_name
893 07bd8a51 Iustin Pop
894 07bd8a51 Iustin Pop
  def Exec(self, feedback_fn):
895 07bd8a51 Iustin Pop
    """Rename the cluster.
896 07bd8a51 Iustin Pop

897 07bd8a51 Iustin Pop
    """
898 07bd8a51 Iustin Pop
    clustername = self.op.name
899 07bd8a51 Iustin Pop
    ip = self.ip
900 07bd8a51 Iustin Pop
    ss = self.sstore
901 07bd8a51 Iustin Pop
902 07bd8a51 Iustin Pop
    # shutdown the master IP
903 07bd8a51 Iustin Pop
    master = ss.GetMasterNode()
904 07bd8a51 Iustin Pop
    if not rpc.call_node_stop_master(master):
905 07bd8a51 Iustin Pop
      raise errors.OpExecError("Could not disable the master role")
906 07bd8a51 Iustin Pop
907 07bd8a51 Iustin Pop
    try:
908 07bd8a51 Iustin Pop
      # modify the sstore
909 07bd8a51 Iustin Pop
      ss.SetKey(ss.SS_MASTER_IP, ip)
910 07bd8a51 Iustin Pop
      ss.SetKey(ss.SS_CLUSTER_NAME, clustername)
911 07bd8a51 Iustin Pop
912 07bd8a51 Iustin Pop
      # Distribute updated ss config to all nodes
913 07bd8a51 Iustin Pop
      myself = self.cfg.GetNodeInfo(master)
914 07bd8a51 Iustin Pop
      dist_nodes = self.cfg.GetNodeList()
915 07bd8a51 Iustin Pop
      if myself.name in dist_nodes:
916 07bd8a51 Iustin Pop
        dist_nodes.remove(myself.name)
917 07bd8a51 Iustin Pop
918 07bd8a51 Iustin Pop
      logger.Debug("Copying updated ssconf data to all nodes")
919 07bd8a51 Iustin Pop
      for keyname in [ss.SS_CLUSTER_NAME, ss.SS_MASTER_IP]:
920 07bd8a51 Iustin Pop
        fname = ss.KeyToFilename(keyname)
921 07bd8a51 Iustin Pop
        result = rpc.call_upload_file(dist_nodes, fname)
922 07bd8a51 Iustin Pop
        for to_node in dist_nodes:
923 07bd8a51 Iustin Pop
          if not result[to_node]:
924 07bd8a51 Iustin Pop
            logger.Error("copy of file %s to node %s failed" %
925 07bd8a51 Iustin Pop
                         (fname, to_node))
926 07bd8a51 Iustin Pop
    finally:
927 07bd8a51 Iustin Pop
      if not rpc.call_node_start_master(master):
928 f4bc1f2c Michael Hanselmann
        logger.Error("Could not re-enable the master role on the master,"
929 f4bc1f2c Michael Hanselmann
                     " please restart manually.")
930 07bd8a51 Iustin Pop
931 07bd8a51 Iustin Pop
932 8084f9f6 Manuel Franceschini
def _RecursiveCheckIfLVMBased(disk):
933 8084f9f6 Manuel Franceschini
  """Check if the given disk or its children are lvm-based.
934 8084f9f6 Manuel Franceschini

935 8084f9f6 Manuel Franceschini
  Args:
936 8084f9f6 Manuel Franceschini
    disk: ganeti.objects.Disk object
937 8084f9f6 Manuel Franceschini

938 8084f9f6 Manuel Franceschini
  Returns:
939 8084f9f6 Manuel Franceschini
    boolean indicating whether a LD_LV dev_type was found or not
940 8084f9f6 Manuel Franceschini

941 8084f9f6 Manuel Franceschini
  """
942 8084f9f6 Manuel Franceschini
  if disk.children:
943 8084f9f6 Manuel Franceschini
    for chdisk in disk.children:
944 8084f9f6 Manuel Franceschini
      if _RecursiveCheckIfLVMBased(chdisk):
945 8084f9f6 Manuel Franceschini
        return True
946 8084f9f6 Manuel Franceschini
  return disk.dev_type == constants.LD_LV
947 8084f9f6 Manuel Franceschini
948 8084f9f6 Manuel Franceschini
949 8084f9f6 Manuel Franceschini
class LUSetClusterParams(LogicalUnit):
950 8084f9f6 Manuel Franceschini
  """Change the parameters of the cluster.
951 8084f9f6 Manuel Franceschini

952 8084f9f6 Manuel Franceschini
  """
953 8084f9f6 Manuel Franceschini
  HPATH = "cluster-modify"
954 8084f9f6 Manuel Franceschini
  HTYPE = constants.HTYPE_CLUSTER
955 8084f9f6 Manuel Franceschini
  _OP_REQP = []
956 8084f9f6 Manuel Franceschini
957 8084f9f6 Manuel Franceschini
  def BuildHooksEnv(self):
958 8084f9f6 Manuel Franceschini
    """Build hooks env.
959 8084f9f6 Manuel Franceschini

960 8084f9f6 Manuel Franceschini
    """
961 8084f9f6 Manuel Franceschini
    env = {
962 8084f9f6 Manuel Franceschini
      "OP_TARGET": self.sstore.GetClusterName(),
963 8084f9f6 Manuel Franceschini
      "NEW_VG_NAME": self.op.vg_name,
964 8084f9f6 Manuel Franceschini
      }
965 8084f9f6 Manuel Franceschini
    mn = self.sstore.GetMasterNode()
966 8084f9f6 Manuel Franceschini
    return env, [mn], [mn]
967 8084f9f6 Manuel Franceschini
968 8084f9f6 Manuel Franceschini
  def CheckPrereq(self):
969 8084f9f6 Manuel Franceschini
    """Check prerequisites.
970 8084f9f6 Manuel Franceschini

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

974 8084f9f6 Manuel Franceschini
    """
975 8084f9f6 Manuel Franceschini
    if not self.op.vg_name:
976 8084f9f6 Manuel Franceschini
      instances = [self.cfg.GetInstanceInfo(name)
977 8084f9f6 Manuel Franceschini
                   for name in self.cfg.GetInstanceList()]
978 8084f9f6 Manuel Franceschini
      for inst in instances:
979 8084f9f6 Manuel Franceschini
        for disk in inst.disks:
980 8084f9f6 Manuel Franceschini
          if _RecursiveCheckIfLVMBased(disk):
981 8084f9f6 Manuel Franceschini
            raise errors.OpPrereqError("Cannot disable lvm storage while"
982 8084f9f6 Manuel Franceschini
                                       " lvm-based instances exist")
983 8084f9f6 Manuel Franceschini
984 8084f9f6 Manuel Franceschini
    # if vg_name not None, checks given volume group on all nodes
985 8084f9f6 Manuel Franceschini
    if self.op.vg_name:
986 8084f9f6 Manuel Franceschini
      node_list = self.cfg.GetNodeList()
987 8084f9f6 Manuel Franceschini
      vglist = rpc.call_vg_list(node_list)
988 8084f9f6 Manuel Franceschini
      for node in node_list:
989 8d1a2a64 Michael Hanselmann
        vgstatus = utils.CheckVolumeGroupSize(vglist[node], self.op.vg_name,
990 8d1a2a64 Michael Hanselmann
                                              constants.MIN_VG_SIZE)
991 8084f9f6 Manuel Franceschini
        if vgstatus:
992 8084f9f6 Manuel Franceschini
          raise errors.OpPrereqError("Error on node '%s': %s" %
993 8084f9f6 Manuel Franceschini
                                     (node, vgstatus))
994 8084f9f6 Manuel Franceschini
995 8084f9f6 Manuel Franceschini
  def Exec(self, feedback_fn):
996 8084f9f6 Manuel Franceschini
    """Change the parameters of the cluster.
997 8084f9f6 Manuel Franceschini

998 8084f9f6 Manuel Franceschini
    """
999 8084f9f6 Manuel Franceschini
    if self.op.vg_name != self.cfg.GetVGName():
1000 8084f9f6 Manuel Franceschini
      self.cfg.SetVGName(self.op.vg_name)
1001 8084f9f6 Manuel Franceschini
    else:
1002 8084f9f6 Manuel Franceschini
      feedback_fn("Cluster LVM configuration already in desired"
1003 8084f9f6 Manuel Franceschini
                  " state, not changing")
1004 8084f9f6 Manuel Franceschini
1005 8084f9f6 Manuel Franceschini
1006 5bfac263 Iustin Pop
def _WaitForSync(cfgw, instance, proc, oneshot=False, unlock=False):
1007 a8083063 Iustin Pop
  """Sleep and poll for an instance's disk to sync.
1008 a8083063 Iustin Pop

1009 a8083063 Iustin Pop
  """
1010 a8083063 Iustin Pop
  if not instance.disks:
1011 a8083063 Iustin Pop
    return True
1012 a8083063 Iustin Pop
1013 a8083063 Iustin Pop
  if not oneshot:
1014 5bfac263 Iustin Pop
    proc.LogInfo("Waiting for instance %s to sync disks." % instance.name)
1015 a8083063 Iustin Pop
1016 a8083063 Iustin Pop
  node = instance.primary_node
1017 a8083063 Iustin Pop
1018 a8083063 Iustin Pop
  for dev in instance.disks:
1019 a8083063 Iustin Pop
    cfgw.SetDiskID(dev, node)
1020 a8083063 Iustin Pop
1021 a8083063 Iustin Pop
  retries = 0
1022 a8083063 Iustin Pop
  while True:
1023 a8083063 Iustin Pop
    max_time = 0
1024 a8083063 Iustin Pop
    done = True
1025 a8083063 Iustin Pop
    cumul_degraded = False
1026 a8083063 Iustin Pop
    rstats = rpc.call_blockdev_getmirrorstatus(node, instance.disks)
1027 a8083063 Iustin Pop
    if not rstats:
1028 5bfac263 Iustin Pop
      proc.LogWarning("Can't get any data from node %s" % node)
1029 a8083063 Iustin Pop
      retries += 1
1030 a8083063 Iustin Pop
      if retries >= 10:
1031 3ecf6786 Iustin Pop
        raise errors.RemoteError("Can't contact node %s for mirror data,"
1032 3ecf6786 Iustin Pop
                                 " aborting." % node)
1033 a8083063 Iustin Pop
      time.sleep(6)
1034 a8083063 Iustin Pop
      continue
1035 a8083063 Iustin Pop
    retries = 0
1036 a8083063 Iustin Pop
    for i in range(len(rstats)):
1037 a8083063 Iustin Pop
      mstat = rstats[i]
1038 a8083063 Iustin Pop
      if mstat is None:
1039 5bfac263 Iustin Pop
        proc.LogWarning("Can't compute data for node %s/%s" %
1040 a8083063 Iustin Pop
                        (node, instance.disks[i].iv_name))
1041 a8083063 Iustin Pop
        continue
1042 0834c866 Iustin Pop
      # we ignore the ldisk parameter
1043 0834c866 Iustin Pop
      perc_done, est_time, is_degraded, _ = mstat
1044 a8083063 Iustin Pop
      cumul_degraded = cumul_degraded or (is_degraded and perc_done is None)
1045 a8083063 Iustin Pop
      if perc_done is not None:
1046 a8083063 Iustin Pop
        done = False
1047 a8083063 Iustin Pop
        if est_time is not None:
1048 a8083063 Iustin Pop
          rem_time = "%d estimated seconds remaining" % est_time
1049 a8083063 Iustin Pop
          max_time = est_time
1050 a8083063 Iustin Pop
        else:
1051 a8083063 Iustin Pop
          rem_time = "no time estimate"
1052 5bfac263 Iustin Pop
        proc.LogInfo("- device %s: %5.2f%% done, %s" %
1053 5bfac263 Iustin Pop
                     (instance.disks[i].iv_name, perc_done, rem_time))
1054 a8083063 Iustin Pop
    if done or oneshot:
1055 a8083063 Iustin Pop
      break
1056 a8083063 Iustin Pop
1057 a8083063 Iustin Pop
    if unlock:
1058 685ee993 Iustin Pop
      #utils.Unlock('cmd')
1059 685ee993 Iustin Pop
      pass
1060 a8083063 Iustin Pop
    try:
1061 a8083063 Iustin Pop
      time.sleep(min(60, max_time))
1062 a8083063 Iustin Pop
    finally:
1063 a8083063 Iustin Pop
      if unlock:
1064 685ee993 Iustin Pop
        #utils.Lock('cmd')
1065 685ee993 Iustin Pop
        pass
1066 a8083063 Iustin Pop
1067 a8083063 Iustin Pop
  if done:
1068 5bfac263 Iustin Pop
    proc.LogInfo("Instance %s's disks are in sync." % instance.name)
1069 a8083063 Iustin Pop
  return not cumul_degraded
1070 a8083063 Iustin Pop
1071 a8083063 Iustin Pop
1072 0834c866 Iustin Pop
def _CheckDiskConsistency(cfgw, dev, node, on_primary, ldisk=False):
1073 a8083063 Iustin Pop
  """Check that mirrors are not degraded.
1074 a8083063 Iustin Pop

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

1079 a8083063 Iustin Pop
  """
1080 a8083063 Iustin Pop
  cfgw.SetDiskID(dev, node)
1081 0834c866 Iustin Pop
  if ldisk:
1082 0834c866 Iustin Pop
    idx = 6
1083 0834c866 Iustin Pop
  else:
1084 0834c866 Iustin Pop
    idx = 5
1085 a8083063 Iustin Pop
1086 a8083063 Iustin Pop
  result = True
1087 a8083063 Iustin Pop
  if on_primary or dev.AssembleOnSecondary():
1088 a8083063 Iustin Pop
    rstats = rpc.call_blockdev_find(node, dev)
1089 a8083063 Iustin Pop
    if not rstats:
1090 aa9d0c32 Guido Trotter
      logger.ToStderr("Node %s: Disk degraded, not found or node down" % node)
1091 a8083063 Iustin Pop
      result = False
1092 a8083063 Iustin Pop
    else:
1093 0834c866 Iustin Pop
      result = result and (not rstats[idx])
1094 a8083063 Iustin Pop
  if dev.children:
1095 a8083063 Iustin Pop
    for child in dev.children:
1096 a8083063 Iustin Pop
      result = result and _CheckDiskConsistency(cfgw, child, node, on_primary)
1097 a8083063 Iustin Pop
1098 a8083063 Iustin Pop
  return result
1099 a8083063 Iustin Pop
1100 a8083063 Iustin Pop
1101 a8083063 Iustin Pop
class LUDiagnoseOS(NoHooksLU):
1102 a8083063 Iustin Pop
  """Logical unit for OS diagnose/query.
1103 a8083063 Iustin Pop

1104 a8083063 Iustin Pop
  """
1105 1f9430d6 Iustin Pop
  _OP_REQP = ["output_fields", "names"]
1106 a8083063 Iustin Pop
1107 a8083063 Iustin Pop
  def CheckPrereq(self):
1108 a8083063 Iustin Pop
    """Check prerequisites.
1109 a8083063 Iustin Pop

1110 a8083063 Iustin Pop
    This always succeeds, since this is a pure query LU.
1111 a8083063 Iustin Pop

1112 a8083063 Iustin Pop
    """
1113 1f9430d6 Iustin Pop
    if self.op.names:
1114 1f9430d6 Iustin Pop
      raise errors.OpPrereqError("Selective OS query not supported")
1115 1f9430d6 Iustin Pop
1116 1f9430d6 Iustin Pop
    self.dynamic_fields = frozenset(["name", "valid", "node_status"])
1117 1f9430d6 Iustin Pop
    _CheckOutputFields(static=[],
1118 1f9430d6 Iustin Pop
                       dynamic=self.dynamic_fields,
1119 1f9430d6 Iustin Pop
                       selected=self.op.output_fields)
1120 1f9430d6 Iustin Pop
1121 1f9430d6 Iustin Pop
  @staticmethod
1122 1f9430d6 Iustin Pop
  def _DiagnoseByOS(node_list, rlist):
1123 1f9430d6 Iustin Pop
    """Remaps a per-node return list into an a per-os per-node dictionary
1124 1f9430d6 Iustin Pop

1125 1f9430d6 Iustin Pop
      Args:
1126 1f9430d6 Iustin Pop
        node_list: a list with the names of all nodes
1127 1f9430d6 Iustin Pop
        rlist: a map with node names as keys and OS objects as values
1128 1f9430d6 Iustin Pop

1129 1f9430d6 Iustin Pop
      Returns:
1130 1f9430d6 Iustin Pop
        map: a map with osnames as keys and as value another map, with
1131 1f9430d6 Iustin Pop
             nodes as
1132 1f9430d6 Iustin Pop
             keys and list of OS objects as values
1133 1f9430d6 Iustin Pop
             e.g. {"debian-etch": {"node1": [<object>,...],
1134 1f9430d6 Iustin Pop
                                   "node2": [<object>,]}
1135 1f9430d6 Iustin Pop
                  }
1136 1f9430d6 Iustin Pop

1137 1f9430d6 Iustin Pop
    """
1138 1f9430d6 Iustin Pop
    all_os = {}
1139 1f9430d6 Iustin Pop
    for node_name, nr in rlist.iteritems():
1140 1f9430d6 Iustin Pop
      if not nr:
1141 1f9430d6 Iustin Pop
        continue
1142 b4de68a9 Iustin Pop
      for os_obj in nr:
1143 b4de68a9 Iustin Pop
        if os_obj.name not in all_os:
1144 1f9430d6 Iustin Pop
          # build a list of nodes for this os containing empty lists
1145 1f9430d6 Iustin Pop
          # for each node in node_list
1146 b4de68a9 Iustin Pop
          all_os[os_obj.name] = {}
1147 1f9430d6 Iustin Pop
          for nname in node_list:
1148 b4de68a9 Iustin Pop
            all_os[os_obj.name][nname] = []
1149 b4de68a9 Iustin Pop
        all_os[os_obj.name][node_name].append(os_obj)
1150 1f9430d6 Iustin Pop
    return all_os
1151 a8083063 Iustin Pop
1152 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1153 a8083063 Iustin Pop
    """Compute the list of OSes.
1154 a8083063 Iustin Pop

1155 a8083063 Iustin Pop
    """
1156 a8083063 Iustin Pop
    node_list = self.cfg.GetNodeList()
1157 a8083063 Iustin Pop
    node_data = rpc.call_os_diagnose(node_list)
1158 a8083063 Iustin Pop
    if node_data == False:
1159 3ecf6786 Iustin Pop
      raise errors.OpExecError("Can't gather the list of OSes")
1160 1f9430d6 Iustin Pop
    pol = self._DiagnoseByOS(node_list, node_data)
1161 1f9430d6 Iustin Pop
    output = []
1162 1f9430d6 Iustin Pop
    for os_name, os_data in pol.iteritems():
1163 1f9430d6 Iustin Pop
      row = []
1164 1f9430d6 Iustin Pop
      for field in self.op.output_fields:
1165 1f9430d6 Iustin Pop
        if field == "name":
1166 1f9430d6 Iustin Pop
          val = os_name
1167 1f9430d6 Iustin Pop
        elif field == "valid":
1168 1f9430d6 Iustin Pop
          val = utils.all([osl and osl[0] for osl in os_data.values()])
1169 1f9430d6 Iustin Pop
        elif field == "node_status":
1170 1f9430d6 Iustin Pop
          val = {}
1171 1f9430d6 Iustin Pop
          for node_name, nos_list in os_data.iteritems():
1172 1f9430d6 Iustin Pop
            val[node_name] = [(v.status, v.path) for v in nos_list]
1173 1f9430d6 Iustin Pop
        else:
1174 1f9430d6 Iustin Pop
          raise errors.ParameterError(field)
1175 1f9430d6 Iustin Pop
        row.append(val)
1176 1f9430d6 Iustin Pop
      output.append(row)
1177 1f9430d6 Iustin Pop
1178 1f9430d6 Iustin Pop
    return output
1179 a8083063 Iustin Pop
1180 a8083063 Iustin Pop
1181 a8083063 Iustin Pop
class LURemoveNode(LogicalUnit):
1182 a8083063 Iustin Pop
  """Logical unit for removing a node.
1183 a8083063 Iustin Pop

1184 a8083063 Iustin Pop
  """
1185 a8083063 Iustin Pop
  HPATH = "node-remove"
1186 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_NODE
1187 a8083063 Iustin Pop
  _OP_REQP = ["node_name"]
1188 a8083063 Iustin Pop
1189 a8083063 Iustin Pop
  def BuildHooksEnv(self):
1190 a8083063 Iustin Pop
    """Build hooks env.
1191 a8083063 Iustin Pop

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

1195 a8083063 Iustin Pop
    """
1196 396e1b78 Michael Hanselmann
    env = {
1197 0e137c28 Iustin Pop
      "OP_TARGET": self.op.node_name,
1198 396e1b78 Michael Hanselmann
      "NODE_NAME": self.op.node_name,
1199 396e1b78 Michael Hanselmann
      }
1200 a8083063 Iustin Pop
    all_nodes = self.cfg.GetNodeList()
1201 a8083063 Iustin Pop
    all_nodes.remove(self.op.node_name)
1202 396e1b78 Michael Hanselmann
    return env, all_nodes, all_nodes
1203 a8083063 Iustin Pop
1204 a8083063 Iustin Pop
  def CheckPrereq(self):
1205 a8083063 Iustin Pop
    """Check prerequisites.
1206 a8083063 Iustin Pop

1207 a8083063 Iustin Pop
    This checks:
1208 a8083063 Iustin Pop
     - the node exists in the configuration
1209 a8083063 Iustin Pop
     - it does not have primary or secondary instances
1210 a8083063 Iustin Pop
     - it's not the master
1211 a8083063 Iustin Pop

1212 a8083063 Iustin Pop
    Any errors are signalled by raising errors.OpPrereqError.
1213 a8083063 Iustin Pop

1214 a8083063 Iustin Pop
    """
1215 a8083063 Iustin Pop
    node = self.cfg.GetNodeInfo(self.cfg.ExpandNodeName(self.op.node_name))
1216 a8083063 Iustin Pop
    if node is None:
1217 a02bc76e Iustin Pop
      raise errors.OpPrereqError, ("Node '%s' is unknown." % self.op.node_name)
1218 a8083063 Iustin Pop
1219 a8083063 Iustin Pop
    instance_list = self.cfg.GetInstanceList()
1220 a8083063 Iustin Pop
1221 880478f8 Iustin Pop
    masternode = self.sstore.GetMasterNode()
1222 a8083063 Iustin Pop
    if node.name == masternode:
1223 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Node is the master node,"
1224 3ecf6786 Iustin Pop
                                 " you need to failover first.")
1225 a8083063 Iustin Pop
1226 a8083063 Iustin Pop
    for instance_name in instance_list:
1227 a8083063 Iustin Pop
      instance = self.cfg.GetInstanceInfo(instance_name)
1228 a8083063 Iustin Pop
      if node.name == instance.primary_node:
1229 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Instance %s still running on the node,"
1230 3ecf6786 Iustin Pop
                                   " please remove first." % instance_name)
1231 a8083063 Iustin Pop
      if node.name in instance.secondary_nodes:
1232 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Instance %s has node as a secondary,"
1233 3ecf6786 Iustin Pop
                                   " please remove first." % instance_name)
1234 a8083063 Iustin Pop
    self.op.node_name = node.name
1235 a8083063 Iustin Pop
    self.node = node
1236 a8083063 Iustin Pop
1237 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1238 a8083063 Iustin Pop
    """Removes the node from the cluster.
1239 a8083063 Iustin Pop

1240 a8083063 Iustin Pop
    """
1241 a8083063 Iustin Pop
    node = self.node
1242 a8083063 Iustin Pop
    logger.Info("stopping the node daemon and removing configs from node %s" %
1243 a8083063 Iustin Pop
                node.name)
1244 a8083063 Iustin Pop
1245 a8083063 Iustin Pop
    rpc.call_node_leave_cluster(node.name)
1246 a8083063 Iustin Pop
1247 a8083063 Iustin Pop
    logger.Info("Removing node %s from config" % node.name)
1248 a8083063 Iustin Pop
1249 a8083063 Iustin Pop
    self.cfg.RemoveNode(node.name)
1250 a2fd9afc Guido Trotter
    # Remove the node from the Ganeti Lock Manager
1251 a2fd9afc Guido Trotter
    self.context.glm.remove(locking.LEVEL_NODE, node.name)
1252 a8083063 Iustin Pop
1253 d9c02ca6 Michael Hanselmann
    utils.RemoveHostFromEtcHosts(node.name)
1254 c8a0948f Michael Hanselmann
1255 a8083063 Iustin Pop
1256 a8083063 Iustin Pop
class LUQueryNodes(NoHooksLU):
1257 a8083063 Iustin Pop
  """Logical unit for querying nodes.
1258 a8083063 Iustin Pop

1259 a8083063 Iustin Pop
  """
1260 246e180a Iustin Pop
  _OP_REQP = ["output_fields", "names"]
1261 a8083063 Iustin Pop
1262 a8083063 Iustin Pop
  def CheckPrereq(self):
1263 a8083063 Iustin Pop
    """Check prerequisites.
1264 a8083063 Iustin Pop

1265 a8083063 Iustin Pop
    This checks that the fields required are valid output fields.
1266 a8083063 Iustin Pop

1267 a8083063 Iustin Pop
    """
1268 e8a4c138 Iustin Pop
    self.dynamic_fields = frozenset([
1269 e8a4c138 Iustin Pop
      "dtotal", "dfree",
1270 e8a4c138 Iustin Pop
      "mtotal", "mnode", "mfree",
1271 e8a4c138 Iustin Pop
      "bootid",
1272 e8a4c138 Iustin Pop
      "ctotal",
1273 e8a4c138 Iustin Pop
      ])
1274 a8083063 Iustin Pop
1275 ec223efb Iustin Pop
    _CheckOutputFields(static=["name", "pinst_cnt", "sinst_cnt",
1276 ec223efb Iustin Pop
                               "pinst_list", "sinst_list",
1277 130a6a6f Iustin Pop
                               "pip", "sip", "tags"],
1278 dcb93971 Michael Hanselmann
                       dynamic=self.dynamic_fields,
1279 dcb93971 Michael Hanselmann
                       selected=self.op.output_fields)
1280 a8083063 Iustin Pop
1281 246e180a Iustin Pop
    self.wanted = _GetWantedNodes(self, self.op.names)
1282 a8083063 Iustin Pop
1283 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1284 a8083063 Iustin Pop
    """Computes the list of nodes and their attributes.
1285 a8083063 Iustin Pop

1286 a8083063 Iustin Pop
    """
1287 246e180a Iustin Pop
    nodenames = self.wanted
1288 a8083063 Iustin Pop
    nodelist = [self.cfg.GetNodeInfo(name) for name in nodenames]
1289 a8083063 Iustin Pop
1290 a8083063 Iustin Pop
    # begin data gathering
1291 a8083063 Iustin Pop
1292 a8083063 Iustin Pop
    if self.dynamic_fields.intersection(self.op.output_fields):
1293 a8083063 Iustin Pop
      live_data = {}
1294 a8083063 Iustin Pop
      node_data = rpc.call_node_info(nodenames, self.cfg.GetVGName())
1295 a8083063 Iustin Pop
      for name in nodenames:
1296 a8083063 Iustin Pop
        nodeinfo = node_data.get(name, None)
1297 a8083063 Iustin Pop
        if nodeinfo:
1298 a8083063 Iustin Pop
          live_data[name] = {
1299 a8083063 Iustin Pop
            "mtotal": utils.TryConvert(int, nodeinfo['memory_total']),
1300 a8083063 Iustin Pop
            "mnode": utils.TryConvert(int, nodeinfo['memory_dom0']),
1301 a8083063 Iustin Pop
            "mfree": utils.TryConvert(int, nodeinfo['memory_free']),
1302 a8083063 Iustin Pop
            "dtotal": utils.TryConvert(int, nodeinfo['vg_size']),
1303 a8083063 Iustin Pop
            "dfree": utils.TryConvert(int, nodeinfo['vg_free']),
1304 e8a4c138 Iustin Pop
            "ctotal": utils.TryConvert(int, nodeinfo['cpu_total']),
1305 3ef10550 Michael Hanselmann
            "bootid": nodeinfo['bootid'],
1306 a8083063 Iustin Pop
            }
1307 a8083063 Iustin Pop
        else:
1308 a8083063 Iustin Pop
          live_data[name] = {}
1309 a8083063 Iustin Pop
    else:
1310 a8083063 Iustin Pop
      live_data = dict.fromkeys(nodenames, {})
1311 a8083063 Iustin Pop
1312 ec223efb Iustin Pop
    node_to_primary = dict([(name, set()) for name in nodenames])
1313 ec223efb Iustin Pop
    node_to_secondary = dict([(name, set()) for name in nodenames])
1314 a8083063 Iustin Pop
1315 ec223efb Iustin Pop
    inst_fields = frozenset(("pinst_cnt", "pinst_list",
1316 ec223efb Iustin Pop
                             "sinst_cnt", "sinst_list"))
1317 ec223efb Iustin Pop
    if inst_fields & frozenset(self.op.output_fields):
1318 a8083063 Iustin Pop
      instancelist = self.cfg.GetInstanceList()
1319 a8083063 Iustin Pop
1320 ec223efb Iustin Pop
      for instance_name in instancelist:
1321 ec223efb Iustin Pop
        inst = self.cfg.GetInstanceInfo(instance_name)
1322 ec223efb Iustin Pop
        if inst.primary_node in node_to_primary:
1323 ec223efb Iustin Pop
          node_to_primary[inst.primary_node].add(inst.name)
1324 ec223efb Iustin Pop
        for secnode in inst.secondary_nodes:
1325 ec223efb Iustin Pop
          if secnode in node_to_secondary:
1326 ec223efb Iustin Pop
            node_to_secondary[secnode].add(inst.name)
1327 a8083063 Iustin Pop
1328 a8083063 Iustin Pop
    # end data gathering
1329 a8083063 Iustin Pop
1330 a8083063 Iustin Pop
    output = []
1331 a8083063 Iustin Pop
    for node in nodelist:
1332 a8083063 Iustin Pop
      node_output = []
1333 a8083063 Iustin Pop
      for field in self.op.output_fields:
1334 a8083063 Iustin Pop
        if field == "name":
1335 a8083063 Iustin Pop
          val = node.name
1336 ec223efb Iustin Pop
        elif field == "pinst_list":
1337 ec223efb Iustin Pop
          val = list(node_to_primary[node.name])
1338 ec223efb Iustin Pop
        elif field == "sinst_list":
1339 ec223efb Iustin Pop
          val = list(node_to_secondary[node.name])
1340 ec223efb Iustin Pop
        elif field == "pinst_cnt":
1341 ec223efb Iustin Pop
          val = len(node_to_primary[node.name])
1342 ec223efb Iustin Pop
        elif field == "sinst_cnt":
1343 ec223efb Iustin Pop
          val = len(node_to_secondary[node.name])
1344 a8083063 Iustin Pop
        elif field == "pip":
1345 a8083063 Iustin Pop
          val = node.primary_ip
1346 a8083063 Iustin Pop
        elif field == "sip":
1347 a8083063 Iustin Pop
          val = node.secondary_ip
1348 130a6a6f Iustin Pop
        elif field == "tags":
1349 130a6a6f Iustin Pop
          val = list(node.GetTags())
1350 a8083063 Iustin Pop
        elif field in self.dynamic_fields:
1351 ec223efb Iustin Pop
          val = live_data[node.name].get(field, None)
1352 a8083063 Iustin Pop
        else:
1353 3ecf6786 Iustin Pop
          raise errors.ParameterError(field)
1354 a8083063 Iustin Pop
        node_output.append(val)
1355 a8083063 Iustin Pop
      output.append(node_output)
1356 a8083063 Iustin Pop
1357 a8083063 Iustin Pop
    return output
1358 a8083063 Iustin Pop
1359 a8083063 Iustin Pop
1360 dcb93971 Michael Hanselmann
class LUQueryNodeVolumes(NoHooksLU):
1361 dcb93971 Michael Hanselmann
  """Logical unit for getting volumes on node(s).
1362 dcb93971 Michael Hanselmann

1363 dcb93971 Michael Hanselmann
  """
1364 dcb93971 Michael Hanselmann
  _OP_REQP = ["nodes", "output_fields"]
1365 dcb93971 Michael Hanselmann
1366 dcb93971 Michael Hanselmann
  def CheckPrereq(self):
1367 dcb93971 Michael Hanselmann
    """Check prerequisites.
1368 dcb93971 Michael Hanselmann

1369 dcb93971 Michael Hanselmann
    This checks that the fields required are valid output fields.
1370 dcb93971 Michael Hanselmann

1371 dcb93971 Michael Hanselmann
    """
1372 dcb93971 Michael Hanselmann
    self.nodes = _GetWantedNodes(self, self.op.nodes)
1373 dcb93971 Michael Hanselmann
1374 dcb93971 Michael Hanselmann
    _CheckOutputFields(static=["node"],
1375 dcb93971 Michael Hanselmann
                       dynamic=["phys", "vg", "name", "size", "instance"],
1376 dcb93971 Michael Hanselmann
                       selected=self.op.output_fields)
1377 dcb93971 Michael Hanselmann
1378 dcb93971 Michael Hanselmann
1379 dcb93971 Michael Hanselmann
  def Exec(self, feedback_fn):
1380 dcb93971 Michael Hanselmann
    """Computes the list of nodes and their attributes.
1381 dcb93971 Michael Hanselmann

1382 dcb93971 Michael Hanselmann
    """
1383 a7ba5e53 Iustin Pop
    nodenames = self.nodes
1384 dcb93971 Michael Hanselmann
    volumes = rpc.call_node_volumes(nodenames)
1385 dcb93971 Michael Hanselmann
1386 dcb93971 Michael Hanselmann
    ilist = [self.cfg.GetInstanceInfo(iname) for iname
1387 dcb93971 Michael Hanselmann
             in self.cfg.GetInstanceList()]
1388 dcb93971 Michael Hanselmann
1389 dcb93971 Michael Hanselmann
    lv_by_node = dict([(inst, inst.MapLVsByNode()) for inst in ilist])
1390 dcb93971 Michael Hanselmann
1391 dcb93971 Michael Hanselmann
    output = []
1392 dcb93971 Michael Hanselmann
    for node in nodenames:
1393 37d19eb2 Michael Hanselmann
      if node not in volumes or not volumes[node]:
1394 37d19eb2 Michael Hanselmann
        continue
1395 37d19eb2 Michael Hanselmann
1396 dcb93971 Michael Hanselmann
      node_vols = volumes[node][:]
1397 dcb93971 Michael Hanselmann
      node_vols.sort(key=lambda vol: vol['dev'])
1398 dcb93971 Michael Hanselmann
1399 dcb93971 Michael Hanselmann
      for vol in node_vols:
1400 dcb93971 Michael Hanselmann
        node_output = []
1401 dcb93971 Michael Hanselmann
        for field in self.op.output_fields:
1402 dcb93971 Michael Hanselmann
          if field == "node":
1403 dcb93971 Michael Hanselmann
            val = node
1404 dcb93971 Michael Hanselmann
          elif field == "phys":
1405 dcb93971 Michael Hanselmann
            val = vol['dev']
1406 dcb93971 Michael Hanselmann
          elif field == "vg":
1407 dcb93971 Michael Hanselmann
            val = vol['vg']
1408 dcb93971 Michael Hanselmann
          elif field == "name":
1409 dcb93971 Michael Hanselmann
            val = vol['name']
1410 dcb93971 Michael Hanselmann
          elif field == "size":
1411 dcb93971 Michael Hanselmann
            val = int(float(vol['size']))
1412 dcb93971 Michael Hanselmann
          elif field == "instance":
1413 dcb93971 Michael Hanselmann
            for inst in ilist:
1414 dcb93971 Michael Hanselmann
              if node not in lv_by_node[inst]:
1415 dcb93971 Michael Hanselmann
                continue
1416 dcb93971 Michael Hanselmann
              if vol['name'] in lv_by_node[inst][node]:
1417 dcb93971 Michael Hanselmann
                val = inst.name
1418 dcb93971 Michael Hanselmann
                break
1419 dcb93971 Michael Hanselmann
            else:
1420 dcb93971 Michael Hanselmann
              val = '-'
1421 dcb93971 Michael Hanselmann
          else:
1422 3ecf6786 Iustin Pop
            raise errors.ParameterError(field)
1423 dcb93971 Michael Hanselmann
          node_output.append(str(val))
1424 dcb93971 Michael Hanselmann
1425 dcb93971 Michael Hanselmann
        output.append(node_output)
1426 dcb93971 Michael Hanselmann
1427 dcb93971 Michael Hanselmann
    return output
1428 dcb93971 Michael Hanselmann
1429 dcb93971 Michael Hanselmann
1430 a8083063 Iustin Pop
class LUAddNode(LogicalUnit):
1431 a8083063 Iustin Pop
  """Logical unit for adding node to the cluster.
1432 a8083063 Iustin Pop

1433 a8083063 Iustin Pop
  """
1434 a8083063 Iustin Pop
  HPATH = "node-add"
1435 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_NODE
1436 a8083063 Iustin Pop
  _OP_REQP = ["node_name"]
1437 a8083063 Iustin Pop
1438 a8083063 Iustin Pop
  def BuildHooksEnv(self):
1439 a8083063 Iustin Pop
    """Build hooks env.
1440 a8083063 Iustin Pop

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

1443 a8083063 Iustin Pop
    """
1444 a8083063 Iustin Pop
    env = {
1445 0e137c28 Iustin Pop
      "OP_TARGET": self.op.node_name,
1446 a8083063 Iustin Pop
      "NODE_NAME": self.op.node_name,
1447 a8083063 Iustin Pop
      "NODE_PIP": self.op.primary_ip,
1448 a8083063 Iustin Pop
      "NODE_SIP": self.op.secondary_ip,
1449 a8083063 Iustin Pop
      }
1450 a8083063 Iustin Pop
    nodes_0 = self.cfg.GetNodeList()
1451 a8083063 Iustin Pop
    nodes_1 = nodes_0 + [self.op.node_name, ]
1452 a8083063 Iustin Pop
    return env, nodes_0, nodes_1
1453 a8083063 Iustin Pop
1454 a8083063 Iustin Pop
  def CheckPrereq(self):
1455 a8083063 Iustin Pop
    """Check prerequisites.
1456 a8083063 Iustin Pop

1457 a8083063 Iustin Pop
    This checks:
1458 a8083063 Iustin Pop
     - the new node is not already in the config
1459 a8083063 Iustin Pop
     - it is resolvable
1460 a8083063 Iustin Pop
     - its parameters (single/dual homed) matches the cluster
1461 a8083063 Iustin Pop

1462 a8083063 Iustin Pop
    Any errors are signalled by raising errors.OpPrereqError.
1463 a8083063 Iustin Pop

1464 a8083063 Iustin Pop
    """
1465 a8083063 Iustin Pop
    node_name = self.op.node_name
1466 a8083063 Iustin Pop
    cfg = self.cfg
1467 a8083063 Iustin Pop
1468 89e1fc26 Iustin Pop
    dns_data = utils.HostInfo(node_name)
1469 a8083063 Iustin Pop
1470 bcf043c9 Iustin Pop
    node = dns_data.name
1471 bcf043c9 Iustin Pop
    primary_ip = self.op.primary_ip = dns_data.ip
1472 a8083063 Iustin Pop
    secondary_ip = getattr(self.op, "secondary_ip", None)
1473 a8083063 Iustin Pop
    if secondary_ip is None:
1474 a8083063 Iustin Pop
      secondary_ip = primary_ip
1475 a8083063 Iustin Pop
    if not utils.IsValidIP(secondary_ip):
1476 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Invalid secondary IP given")
1477 a8083063 Iustin Pop
    self.op.secondary_ip = secondary_ip
1478 e7c6e02b Michael Hanselmann
1479 a8083063 Iustin Pop
    node_list = cfg.GetNodeList()
1480 e7c6e02b Michael Hanselmann
    if not self.op.readd and node in node_list:
1481 e7c6e02b Michael Hanselmann
      raise errors.OpPrereqError("Node %s is already in the configuration" %
1482 e7c6e02b Michael Hanselmann
                                 node)
1483 e7c6e02b Michael Hanselmann
    elif self.op.readd and node not in node_list:
1484 e7c6e02b Michael Hanselmann
      raise errors.OpPrereqError("Node %s is not in the configuration" % node)
1485 a8083063 Iustin Pop
1486 a8083063 Iustin Pop
    for existing_node_name in node_list:
1487 a8083063 Iustin Pop
      existing_node = cfg.GetNodeInfo(existing_node_name)
1488 e7c6e02b Michael Hanselmann
1489 e7c6e02b Michael Hanselmann
      if self.op.readd and node == existing_node_name:
1490 e7c6e02b Michael Hanselmann
        if (existing_node.primary_ip != primary_ip or
1491 e7c6e02b Michael Hanselmann
            existing_node.secondary_ip != secondary_ip):
1492 e7c6e02b Michael Hanselmann
          raise errors.OpPrereqError("Readded node doesn't have the same IP"
1493 e7c6e02b Michael Hanselmann
                                     " address configuration as before")
1494 e7c6e02b Michael Hanselmann
        continue
1495 e7c6e02b Michael Hanselmann
1496 a8083063 Iustin Pop
      if (existing_node.primary_ip == primary_ip or
1497 a8083063 Iustin Pop
          existing_node.secondary_ip == primary_ip or
1498 a8083063 Iustin Pop
          existing_node.primary_ip == secondary_ip or
1499 a8083063 Iustin Pop
          existing_node.secondary_ip == secondary_ip):
1500 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("New node ip address(es) conflict with"
1501 3ecf6786 Iustin Pop
                                   " existing node %s" % existing_node.name)
1502 a8083063 Iustin Pop
1503 a8083063 Iustin Pop
    # check that the type of the node (single versus dual homed) is the
1504 a8083063 Iustin Pop
    # same as for the master
1505 880478f8 Iustin Pop
    myself = cfg.GetNodeInfo(self.sstore.GetMasterNode())
1506 a8083063 Iustin Pop
    master_singlehomed = myself.secondary_ip == myself.primary_ip
1507 a8083063 Iustin Pop
    newbie_singlehomed = secondary_ip == primary_ip
1508 a8083063 Iustin Pop
    if master_singlehomed != newbie_singlehomed:
1509 a8083063 Iustin Pop
      if master_singlehomed:
1510 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("The master has no private ip but the"
1511 3ecf6786 Iustin Pop
                                   " new node has one")
1512 a8083063 Iustin Pop
      else:
1513 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("The master has a private ip but the"
1514 3ecf6786 Iustin Pop
                                   " new node doesn't have one")
1515 a8083063 Iustin Pop
1516 a8083063 Iustin Pop
    # checks reachablity
1517 b15d625f Iustin Pop
    if not utils.TcpPing(primary_ip, constants.DEFAULT_NODED_PORT):
1518 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Node not reachable by ping")
1519 a8083063 Iustin Pop
1520 a8083063 Iustin Pop
    if not newbie_singlehomed:
1521 a8083063 Iustin Pop
      # check reachability from my secondary ip to newbie's secondary ip
1522 b15d625f Iustin Pop
      if not utils.TcpPing(secondary_ip, constants.DEFAULT_NODED_PORT,
1523 b15d625f Iustin Pop
                           source=myself.secondary_ip):
1524 f4bc1f2c Michael Hanselmann
        raise errors.OpPrereqError("Node secondary ip not reachable by TCP"
1525 f4bc1f2c Michael Hanselmann
                                   " based ping to noded port")
1526 a8083063 Iustin Pop
1527 a8083063 Iustin Pop
    self.new_node = objects.Node(name=node,
1528 a8083063 Iustin Pop
                                 primary_ip=primary_ip,
1529 a8083063 Iustin Pop
                                 secondary_ip=secondary_ip)
1530 a8083063 Iustin Pop
1531 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1532 a8083063 Iustin Pop
    """Adds the new node to the cluster.
1533 a8083063 Iustin Pop

1534 a8083063 Iustin Pop
    """
1535 a8083063 Iustin Pop
    new_node = self.new_node
1536 a8083063 Iustin Pop
    node = new_node.name
1537 a8083063 Iustin Pop
1538 a8083063 Iustin Pop
    # check connectivity
1539 a8083063 Iustin Pop
    result = rpc.call_version([node])[node]
1540 a8083063 Iustin Pop
    if result:
1541 a8083063 Iustin Pop
      if constants.PROTOCOL_VERSION == result:
1542 a8083063 Iustin Pop
        logger.Info("communication to node %s fine, sw version %s match" %
1543 a8083063 Iustin Pop
                    (node, result))
1544 a8083063 Iustin Pop
      else:
1545 3ecf6786 Iustin Pop
        raise errors.OpExecError("Version mismatch master version %s,"
1546 3ecf6786 Iustin Pop
                                 " node version %s" %
1547 3ecf6786 Iustin Pop
                                 (constants.PROTOCOL_VERSION, result))
1548 a8083063 Iustin Pop
    else:
1549 3ecf6786 Iustin Pop
      raise errors.OpExecError("Cannot get version from the new node")
1550 a8083063 Iustin Pop
1551 a8083063 Iustin Pop
    # setup ssh on node
1552 a8083063 Iustin Pop
    logger.Info("copy ssh key to node %s" % node)
1553 70d9e3d8 Iustin Pop
    priv_key, pub_key, _ = ssh.GetUserFiles(constants.GANETI_RUNAS)
1554 a8083063 Iustin Pop
    keyarray = []
1555 70d9e3d8 Iustin Pop
    keyfiles = [constants.SSH_HOST_DSA_PRIV, constants.SSH_HOST_DSA_PUB,
1556 70d9e3d8 Iustin Pop
                constants.SSH_HOST_RSA_PRIV, constants.SSH_HOST_RSA_PUB,
1557 70d9e3d8 Iustin Pop
                priv_key, pub_key]
1558 a8083063 Iustin Pop
1559 a8083063 Iustin Pop
    for i in keyfiles:
1560 a8083063 Iustin Pop
      f = open(i, 'r')
1561 a8083063 Iustin Pop
      try:
1562 a8083063 Iustin Pop
        keyarray.append(f.read())
1563 a8083063 Iustin Pop
      finally:
1564 a8083063 Iustin Pop
        f.close()
1565 a8083063 Iustin Pop
1566 a8083063 Iustin Pop
    result = rpc.call_node_add(node, keyarray[0], keyarray[1], keyarray[2],
1567 a8083063 Iustin Pop
                               keyarray[3], keyarray[4], keyarray[5])
1568 a8083063 Iustin Pop
1569 a8083063 Iustin Pop
    if not result:
1570 3ecf6786 Iustin Pop
      raise errors.OpExecError("Cannot transfer ssh keys to the new node")
1571 a8083063 Iustin Pop
1572 a8083063 Iustin Pop
    # Add node to our /etc/hosts, and add key to known_hosts
1573 d9c02ca6 Michael Hanselmann
    utils.AddHostToEtcHosts(new_node.name)
1574 c8a0948f Michael Hanselmann
1575 a8083063 Iustin Pop
    if new_node.secondary_ip != new_node.primary_ip:
1576 16abfbc2 Alexander Schreiber
      if not rpc.call_node_tcp_ping(new_node.name,
1577 16abfbc2 Alexander Schreiber
                                    constants.LOCALHOST_IP_ADDRESS,
1578 16abfbc2 Alexander Schreiber
                                    new_node.secondary_ip,
1579 16abfbc2 Alexander Schreiber
                                    constants.DEFAULT_NODED_PORT,
1580 16abfbc2 Alexander Schreiber
                                    10, False):
1581 f4bc1f2c Michael Hanselmann
        raise errors.OpExecError("Node claims it doesn't have the secondary ip"
1582 f4bc1f2c Michael Hanselmann
                                 " you gave (%s). Please fix and re-run this"
1583 f4bc1f2c Michael Hanselmann
                                 " command." % new_node.secondary_ip)
1584 a8083063 Iustin Pop
1585 5c0527ed Guido Trotter
    node_verify_list = [self.sstore.GetMasterNode()]
1586 5c0527ed Guido Trotter
    node_verify_param = {
1587 5c0527ed Guido Trotter
      'nodelist': [node],
1588 5c0527ed Guido Trotter
      # TODO: do a node-net-test as well?
1589 5c0527ed Guido Trotter
    }
1590 5c0527ed Guido Trotter
1591 5c0527ed Guido Trotter
    result = rpc.call_node_verify(node_verify_list, node_verify_param)
1592 5c0527ed Guido Trotter
    for verifier in node_verify_list:
1593 5c0527ed Guido Trotter
      if not result[verifier]:
1594 5c0527ed Guido Trotter
        raise errors.OpExecError("Cannot communicate with %s's node daemon"
1595 5c0527ed Guido Trotter
                                 " for remote verification" % verifier)
1596 5c0527ed Guido Trotter
      if result[verifier]['nodelist']:
1597 5c0527ed Guido Trotter
        for failed in result[verifier]['nodelist']:
1598 5c0527ed Guido Trotter
          feedback_fn("ssh/hostname verification failed %s -> %s" %
1599 5c0527ed Guido Trotter
                      (verifier, result[verifier]['nodelist'][failed]))
1600 5c0527ed Guido Trotter
        raise errors.OpExecError("ssh/hostname verification failed.")
1601 ff98055b Iustin Pop
1602 a8083063 Iustin Pop
    # Distribute updated /etc/hosts and known_hosts to all nodes,
1603 a8083063 Iustin Pop
    # including the node just added
1604 880478f8 Iustin Pop
    myself = self.cfg.GetNodeInfo(self.sstore.GetMasterNode())
1605 102b115b Michael Hanselmann
    dist_nodes = self.cfg.GetNodeList()
1606 102b115b Michael Hanselmann
    if not self.op.readd:
1607 102b115b Michael Hanselmann
      dist_nodes.append(node)
1608 a8083063 Iustin Pop
    if myself.name in dist_nodes:
1609 a8083063 Iustin Pop
      dist_nodes.remove(myself.name)
1610 a8083063 Iustin Pop
1611 a8083063 Iustin Pop
    logger.Debug("Copying hosts and known_hosts to all nodes")
1612 107711b0 Michael Hanselmann
    for fname in (constants.ETC_HOSTS, constants.SSH_KNOWN_HOSTS_FILE):
1613 a8083063 Iustin Pop
      result = rpc.call_upload_file(dist_nodes, fname)
1614 a8083063 Iustin Pop
      for to_node in dist_nodes:
1615 a8083063 Iustin Pop
        if not result[to_node]:
1616 a8083063 Iustin Pop
          logger.Error("copy of file %s to node %s failed" %
1617 a8083063 Iustin Pop
                       (fname, to_node))
1618 a8083063 Iustin Pop
1619 3d1e7706 Guido Trotter
    to_copy = self.sstore.GetFileList()
1620 2a6469d5 Alexander Schreiber
    if self.sstore.GetHypervisorType() == constants.HT_XEN_HVM31:
1621 2a6469d5 Alexander Schreiber
      to_copy.append(constants.VNC_PASSWORD_FILE)
1622 a8083063 Iustin Pop
    for fname in to_copy:
1623 b5602d15 Guido Trotter
      result = rpc.call_upload_file([node], fname)
1624 b5602d15 Guido Trotter
      if not result[node]:
1625 a8083063 Iustin Pop
        logger.Error("could not copy file %s to node %s" % (fname, node))
1626 a8083063 Iustin Pop
1627 e7c6e02b Michael Hanselmann
    if not self.op.readd:
1628 e7c6e02b Michael Hanselmann
      logger.Info("adding node %s to cluster.conf" % node)
1629 e7c6e02b Michael Hanselmann
      self.cfg.AddNode(new_node)
1630 a2fd9afc Guido Trotter
      # Add the new node to the Ganeti Lock Manager
1631 a2fd9afc Guido Trotter
      self.context.glm.add(locking.LEVEL_NODE, node)
1632 a8083063 Iustin Pop
1633 a8083063 Iustin Pop
1634 a8083063 Iustin Pop
class LUMasterFailover(LogicalUnit):
1635 a8083063 Iustin Pop
  """Failover the master node to the current node.
1636 a8083063 Iustin Pop

1637 a8083063 Iustin Pop
  This is a special LU in that it must run on a non-master node.
1638 a8083063 Iustin Pop

1639 a8083063 Iustin Pop
  """
1640 a8083063 Iustin Pop
  HPATH = "master-failover"
1641 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_CLUSTER
1642 a8083063 Iustin Pop
  REQ_MASTER = False
1643 05f86716 Guido Trotter
  REQ_WSSTORE = True
1644 a8083063 Iustin Pop
  _OP_REQP = []
1645 a8083063 Iustin Pop
1646 a8083063 Iustin Pop
  def BuildHooksEnv(self):
1647 a8083063 Iustin Pop
    """Build hooks env.
1648 a8083063 Iustin Pop

1649 a8083063 Iustin Pop
    This will run on the new master only in the pre phase, and on all
1650 a8083063 Iustin Pop
    the nodes in the post phase.
1651 a8083063 Iustin Pop

1652 a8083063 Iustin Pop
    """
1653 a8083063 Iustin Pop
    env = {
1654 0e137c28 Iustin Pop
      "OP_TARGET": self.new_master,
1655 a8083063 Iustin Pop
      "NEW_MASTER": self.new_master,
1656 a8083063 Iustin Pop
      "OLD_MASTER": self.old_master,
1657 a8083063 Iustin Pop
      }
1658 a8083063 Iustin Pop
    return env, [self.new_master], self.cfg.GetNodeList()
1659 a8083063 Iustin Pop
1660 a8083063 Iustin Pop
  def CheckPrereq(self):
1661 a8083063 Iustin Pop
    """Check prerequisites.
1662 a8083063 Iustin Pop

1663 a8083063 Iustin Pop
    This checks that we are not already the master.
1664 a8083063 Iustin Pop

1665 a8083063 Iustin Pop
    """
1666 89e1fc26 Iustin Pop
    self.new_master = utils.HostInfo().name
1667 880478f8 Iustin Pop
    self.old_master = self.sstore.GetMasterNode()
1668 a8083063 Iustin Pop
1669 a8083063 Iustin Pop
    if self.old_master == self.new_master:
1670 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("This commands must be run on the node"
1671 f4bc1f2c Michael Hanselmann
                                 " where you want the new master to be."
1672 f4bc1f2c Michael Hanselmann
                                 " %s is already the master" %
1673 3ecf6786 Iustin Pop
                                 self.old_master)
1674 a8083063 Iustin Pop
1675 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1676 a8083063 Iustin Pop
    """Failover the master node.
1677 a8083063 Iustin Pop

1678 a8083063 Iustin Pop
    This command, when run on a non-master node, will cause the current
1679 a8083063 Iustin Pop
    master to cease being master, and the non-master to become new
1680 a8083063 Iustin Pop
    master.
1681 a8083063 Iustin Pop

1682 a8083063 Iustin Pop
    """
1683 a8083063 Iustin Pop
    #TODO: do not rely on gethostname returning the FQDN
1684 a8083063 Iustin Pop
    logger.Info("setting master to %s, old master: %s" %
1685 a8083063 Iustin Pop
                (self.new_master, self.old_master))
1686 a8083063 Iustin Pop
1687 a8083063 Iustin Pop
    if not rpc.call_node_stop_master(self.old_master):
1688 a8083063 Iustin Pop
      logger.Error("could disable the master role on the old master"
1689 a8083063 Iustin Pop
                   " %s, please disable manually" % self.old_master)
1690 a8083063 Iustin Pop
1691 880478f8 Iustin Pop
    ss = self.sstore
1692 880478f8 Iustin Pop
    ss.SetKey(ss.SS_MASTER_NODE, self.new_master)
1693 880478f8 Iustin Pop
    if not rpc.call_upload_file(self.cfg.GetNodeList(),
1694 880478f8 Iustin Pop
                                ss.KeyToFilename(ss.SS_MASTER_NODE)):
1695 880478f8 Iustin Pop
      logger.Error("could not distribute the new simple store master file"
1696 880478f8 Iustin Pop
                   " to the other nodes, please check.")
1697 880478f8 Iustin Pop
1698 a8083063 Iustin Pop
    if not rpc.call_node_start_master(self.new_master):
1699 a8083063 Iustin Pop
      logger.Error("could not start the master role on the new master"
1700 a8083063 Iustin Pop
                   " %s, please check" % self.new_master)
1701 f4bc1f2c Michael Hanselmann
      feedback_fn("Error in activating the master IP on the new master,"
1702 f4bc1f2c Michael Hanselmann
                  " please fix manually.")
1703 a8083063 Iustin Pop
1704 a8083063 Iustin Pop
1705 a8083063 Iustin Pop
1706 a8083063 Iustin Pop
class LUQueryClusterInfo(NoHooksLU):
1707 a8083063 Iustin Pop
  """Query cluster configuration.
1708 a8083063 Iustin Pop

1709 a8083063 Iustin Pop
  """
1710 a8083063 Iustin Pop
  _OP_REQP = []
1711 59322403 Iustin Pop
  REQ_MASTER = False
1712 a8083063 Iustin Pop
1713 a8083063 Iustin Pop
  def CheckPrereq(self):
1714 a8083063 Iustin Pop
    """No prerequsites needed for this LU.
1715 a8083063 Iustin Pop

1716 a8083063 Iustin Pop
    """
1717 a8083063 Iustin Pop
    pass
1718 a8083063 Iustin Pop
1719 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1720 a8083063 Iustin Pop
    """Return cluster config.
1721 a8083063 Iustin Pop

1722 a8083063 Iustin Pop
    """
1723 a8083063 Iustin Pop
    result = {
1724 5fcdc80d Iustin Pop
      "name": self.sstore.GetClusterName(),
1725 a8083063 Iustin Pop
      "software_version": constants.RELEASE_VERSION,
1726 a8083063 Iustin Pop
      "protocol_version": constants.PROTOCOL_VERSION,
1727 a8083063 Iustin Pop
      "config_version": constants.CONFIG_VERSION,
1728 a8083063 Iustin Pop
      "os_api_version": constants.OS_API_VERSION,
1729 a8083063 Iustin Pop
      "export_version": constants.EXPORT_VERSION,
1730 880478f8 Iustin Pop
      "master": self.sstore.GetMasterNode(),
1731 a8083063 Iustin Pop
      "architecture": (platform.architecture()[0], platform.machine()),
1732 8a12ce45 Iustin Pop
      "hypervisor_type": self.sstore.GetHypervisorType(),
1733 a8083063 Iustin Pop
      }
1734 a8083063 Iustin Pop
1735 a8083063 Iustin Pop
    return result
1736 a8083063 Iustin Pop
1737 a8083063 Iustin Pop
1738 a8083063 Iustin Pop
class LUDumpClusterConfig(NoHooksLU):
1739 a8083063 Iustin Pop
  """Return a text-representation of the cluster-config.
1740 a8083063 Iustin Pop

1741 a8083063 Iustin Pop
  """
1742 a8083063 Iustin Pop
  _OP_REQP = []
1743 a8083063 Iustin Pop
1744 a8083063 Iustin Pop
  def CheckPrereq(self):
1745 a8083063 Iustin Pop
    """No prerequisites.
1746 a8083063 Iustin Pop

1747 a8083063 Iustin Pop
    """
1748 a8083063 Iustin Pop
    pass
1749 a8083063 Iustin Pop
1750 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1751 a8083063 Iustin Pop
    """Dump a representation of the cluster config to the standard output.
1752 a8083063 Iustin Pop

1753 a8083063 Iustin Pop
    """
1754 a8083063 Iustin Pop
    return self.cfg.DumpConfig()
1755 a8083063 Iustin Pop
1756 a8083063 Iustin Pop
1757 a8083063 Iustin Pop
class LUActivateInstanceDisks(NoHooksLU):
1758 a8083063 Iustin Pop
  """Bring up an instance's disks.
1759 a8083063 Iustin Pop

1760 a8083063 Iustin Pop
  """
1761 a8083063 Iustin Pop
  _OP_REQP = ["instance_name"]
1762 a8083063 Iustin Pop
1763 a8083063 Iustin Pop
  def CheckPrereq(self):
1764 a8083063 Iustin Pop
    """Check prerequisites.
1765 a8083063 Iustin Pop

1766 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
1767 a8083063 Iustin Pop

1768 a8083063 Iustin Pop
    """
1769 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
1770 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
1771 a8083063 Iustin Pop
    if instance is None:
1772 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
1773 3ecf6786 Iustin Pop
                                 self.op.instance_name)
1774 a8083063 Iustin Pop
    self.instance = instance
1775 a8083063 Iustin Pop
1776 a8083063 Iustin Pop
1777 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1778 a8083063 Iustin Pop
    """Activate the disks.
1779 a8083063 Iustin Pop

1780 a8083063 Iustin Pop
    """
1781 a8083063 Iustin Pop
    disks_ok, disks_info = _AssembleInstanceDisks(self.instance, self.cfg)
1782 a8083063 Iustin Pop
    if not disks_ok:
1783 3ecf6786 Iustin Pop
      raise errors.OpExecError("Cannot activate block devices")
1784 a8083063 Iustin Pop
1785 a8083063 Iustin Pop
    return disks_info
1786 a8083063 Iustin Pop
1787 a8083063 Iustin Pop
1788 a8083063 Iustin Pop
def _AssembleInstanceDisks(instance, cfg, ignore_secondaries=False):
1789 a8083063 Iustin Pop
  """Prepare the block devices for an instance.
1790 a8083063 Iustin Pop

1791 a8083063 Iustin Pop
  This sets up the block devices on all nodes.
1792 a8083063 Iustin Pop

1793 a8083063 Iustin Pop
  Args:
1794 a8083063 Iustin Pop
    instance: a ganeti.objects.Instance object
1795 a8083063 Iustin Pop
    ignore_secondaries: if true, errors on secondary nodes won't result
1796 a8083063 Iustin Pop
                        in an error return from the function
1797 a8083063 Iustin Pop

1798 a8083063 Iustin Pop
  Returns:
1799 a8083063 Iustin Pop
    false if the operation failed
1800 a8083063 Iustin Pop
    list of (host, instance_visible_name, node_visible_name) if the operation
1801 a8083063 Iustin Pop
         suceeded with the mapping from node devices to instance devices
1802 a8083063 Iustin Pop
  """
1803 a8083063 Iustin Pop
  device_info = []
1804 a8083063 Iustin Pop
  disks_ok = True
1805 fdbd668d Iustin Pop
  iname = instance.name
1806 fdbd668d Iustin Pop
  # With the two passes mechanism we try to reduce the window of
1807 fdbd668d Iustin Pop
  # opportunity for the race condition of switching DRBD to primary
1808 fdbd668d Iustin Pop
  # before handshaking occured, but we do not eliminate it
1809 fdbd668d Iustin Pop
1810 fdbd668d Iustin Pop
  # The proper fix would be to wait (with some limits) until the
1811 fdbd668d Iustin Pop
  # connection has been made and drbd transitions from WFConnection
1812 fdbd668d Iustin Pop
  # into any other network-connected state (Connected, SyncTarget,
1813 fdbd668d Iustin Pop
  # SyncSource, etc.)
1814 fdbd668d Iustin Pop
1815 fdbd668d Iustin Pop
  # 1st pass, assemble on all nodes in secondary mode
1816 a8083063 Iustin Pop
  for inst_disk in instance.disks:
1817 a8083063 Iustin Pop
    for node, node_disk in inst_disk.ComputeNodeTree(instance.primary_node):
1818 a8083063 Iustin Pop
      cfg.SetDiskID(node_disk, node)
1819 fdbd668d Iustin Pop
      result = rpc.call_blockdev_assemble(node, node_disk, iname, False)
1820 a8083063 Iustin Pop
      if not result:
1821 f4bc1f2c Michael Hanselmann
        logger.Error("could not prepare block device %s on node %s"
1822 fdbd668d Iustin Pop
                     " (is_primary=False, pass=1)" % (inst_disk.iv_name, node))
1823 fdbd668d Iustin Pop
        if not ignore_secondaries:
1824 a8083063 Iustin Pop
          disks_ok = False
1825 fdbd668d Iustin Pop
1826 fdbd668d Iustin Pop
  # FIXME: race condition on drbd migration to primary
1827 fdbd668d Iustin Pop
1828 fdbd668d Iustin Pop
  # 2nd pass, do only the primary node
1829 fdbd668d Iustin Pop
  for inst_disk in instance.disks:
1830 fdbd668d Iustin Pop
    for node, node_disk in inst_disk.ComputeNodeTree(instance.primary_node):
1831 fdbd668d Iustin Pop
      if node != instance.primary_node:
1832 fdbd668d Iustin Pop
        continue
1833 fdbd668d Iustin Pop
      cfg.SetDiskID(node_disk, node)
1834 fdbd668d Iustin Pop
      result = rpc.call_blockdev_assemble(node, node_disk, iname, True)
1835 fdbd668d Iustin Pop
      if not result:
1836 fdbd668d Iustin Pop
        logger.Error("could not prepare block device %s on node %s"
1837 fdbd668d Iustin Pop
                     " (is_primary=True, pass=2)" % (inst_disk.iv_name, node))
1838 fdbd668d Iustin Pop
        disks_ok = False
1839 fdbd668d Iustin Pop
    device_info.append((instance.primary_node, inst_disk.iv_name, result))
1840 a8083063 Iustin Pop
1841 b352ab5b Iustin Pop
  # leave the disks configured for the primary node
1842 b352ab5b Iustin Pop
  # this is a workaround that would be fixed better by
1843 b352ab5b Iustin Pop
  # improving the logical/physical id handling
1844 b352ab5b Iustin Pop
  for disk in instance.disks:
1845 b352ab5b Iustin Pop
    cfg.SetDiskID(disk, instance.primary_node)
1846 b352ab5b Iustin Pop
1847 a8083063 Iustin Pop
  return disks_ok, device_info
1848 a8083063 Iustin Pop
1849 a8083063 Iustin Pop
1850 fe7b0351 Michael Hanselmann
def _StartInstanceDisks(cfg, instance, force):
1851 3ecf6786 Iustin Pop
  """Start the disks of an instance.
1852 3ecf6786 Iustin Pop

1853 3ecf6786 Iustin Pop
  """
1854 fe7b0351 Michael Hanselmann
  disks_ok, dummy = _AssembleInstanceDisks(instance, cfg,
1855 fe7b0351 Michael Hanselmann
                                           ignore_secondaries=force)
1856 fe7b0351 Michael Hanselmann
  if not disks_ok:
1857 fe7b0351 Michael Hanselmann
    _ShutdownInstanceDisks(instance, cfg)
1858 fe7b0351 Michael Hanselmann
    if force is not None and not force:
1859 fe7b0351 Michael Hanselmann
      logger.Error("If the message above refers to a secondary node,"
1860 fe7b0351 Michael Hanselmann
                   " you can retry the operation using '--force'.")
1861 3ecf6786 Iustin Pop
    raise errors.OpExecError("Disk consistency error")
1862 fe7b0351 Michael Hanselmann
1863 fe7b0351 Michael Hanselmann
1864 a8083063 Iustin Pop
class LUDeactivateInstanceDisks(NoHooksLU):
1865 a8083063 Iustin Pop
  """Shutdown an instance's disks.
1866 a8083063 Iustin Pop

1867 a8083063 Iustin Pop
  """
1868 a8083063 Iustin Pop
  _OP_REQP = ["instance_name"]
1869 a8083063 Iustin Pop
1870 a8083063 Iustin Pop
  def CheckPrereq(self):
1871 a8083063 Iustin Pop
    """Check prerequisites.
1872 a8083063 Iustin Pop

1873 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
1874 a8083063 Iustin Pop

1875 a8083063 Iustin Pop
    """
1876 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
1877 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
1878 a8083063 Iustin Pop
    if instance is None:
1879 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
1880 3ecf6786 Iustin Pop
                                 self.op.instance_name)
1881 a8083063 Iustin Pop
    self.instance = instance
1882 a8083063 Iustin Pop
1883 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1884 a8083063 Iustin Pop
    """Deactivate the disks
1885 a8083063 Iustin Pop

1886 a8083063 Iustin Pop
    """
1887 a8083063 Iustin Pop
    instance = self.instance
1888 a8083063 Iustin Pop
    ins_l = rpc.call_instance_list([instance.primary_node])
1889 a8083063 Iustin Pop
    ins_l = ins_l[instance.primary_node]
1890 a8083063 Iustin Pop
    if not type(ins_l) is list:
1891 3ecf6786 Iustin Pop
      raise errors.OpExecError("Can't contact node '%s'" %
1892 3ecf6786 Iustin Pop
                               instance.primary_node)
1893 a8083063 Iustin Pop
1894 a8083063 Iustin Pop
    if self.instance.name in ins_l:
1895 3ecf6786 Iustin Pop
      raise errors.OpExecError("Instance is running, can't shutdown"
1896 3ecf6786 Iustin Pop
                               " block devices.")
1897 a8083063 Iustin Pop
1898 a8083063 Iustin Pop
    _ShutdownInstanceDisks(instance, self.cfg)
1899 a8083063 Iustin Pop
1900 a8083063 Iustin Pop
1901 a8083063 Iustin Pop
def _ShutdownInstanceDisks(instance, cfg, ignore_primary=False):
1902 a8083063 Iustin Pop
  """Shutdown block devices of an instance.
1903 a8083063 Iustin Pop

1904 a8083063 Iustin Pop
  This does the shutdown on all nodes of the instance.
1905 a8083063 Iustin Pop

1906 a8083063 Iustin Pop
  If the ignore_primary is false, errors on the primary node are
1907 a8083063 Iustin Pop
  ignored.
1908 a8083063 Iustin Pop

1909 a8083063 Iustin Pop
  """
1910 a8083063 Iustin Pop
  result = True
1911 a8083063 Iustin Pop
  for disk in instance.disks:
1912 a8083063 Iustin Pop
    for node, top_disk in disk.ComputeNodeTree(instance.primary_node):
1913 a8083063 Iustin Pop
      cfg.SetDiskID(top_disk, node)
1914 a8083063 Iustin Pop
      if not rpc.call_blockdev_shutdown(node, top_disk):
1915 a8083063 Iustin Pop
        logger.Error("could not shutdown block device %s on node %s" %
1916 a8083063 Iustin Pop
                     (disk.iv_name, node))
1917 a8083063 Iustin Pop
        if not ignore_primary or node != instance.primary_node:
1918 a8083063 Iustin Pop
          result = False
1919 a8083063 Iustin Pop
  return result
1920 a8083063 Iustin Pop
1921 a8083063 Iustin Pop
1922 d4f16fd9 Iustin Pop
def _CheckNodeFreeMemory(cfg, node, reason, requested):
1923 d4f16fd9 Iustin Pop
  """Checks if a node has enough free memory.
1924 d4f16fd9 Iustin Pop

1925 d4f16fd9 Iustin Pop
  This function check if a given node has the needed amount of free
1926 d4f16fd9 Iustin Pop
  memory. In case the node has less memory or we cannot get the
1927 d4f16fd9 Iustin Pop
  information from the node, this function raise an OpPrereqError
1928 d4f16fd9 Iustin Pop
  exception.
1929 d4f16fd9 Iustin Pop

1930 d4f16fd9 Iustin Pop
  Args:
1931 d4f16fd9 Iustin Pop
    - cfg: a ConfigWriter instance
1932 d4f16fd9 Iustin Pop
    - node: the node name
1933 d4f16fd9 Iustin Pop
    - reason: string to use in the error message
1934 d4f16fd9 Iustin Pop
    - requested: the amount of memory in MiB
1935 d4f16fd9 Iustin Pop

1936 d4f16fd9 Iustin Pop
  """
1937 d4f16fd9 Iustin Pop
  nodeinfo = rpc.call_node_info([node], cfg.GetVGName())
1938 d4f16fd9 Iustin Pop
  if not nodeinfo or not isinstance(nodeinfo, dict):
1939 d4f16fd9 Iustin Pop
    raise errors.OpPrereqError("Could not contact node %s for resource"
1940 d4f16fd9 Iustin Pop
                             " information" % (node,))
1941 d4f16fd9 Iustin Pop
1942 d4f16fd9 Iustin Pop
  free_mem = nodeinfo[node].get('memory_free')
1943 d4f16fd9 Iustin Pop
  if not isinstance(free_mem, int):
1944 d4f16fd9 Iustin Pop
    raise errors.OpPrereqError("Can't compute free memory on node %s, result"
1945 d4f16fd9 Iustin Pop
                             " was '%s'" % (node, free_mem))
1946 d4f16fd9 Iustin Pop
  if requested > free_mem:
1947 d4f16fd9 Iustin Pop
    raise errors.OpPrereqError("Not enough memory on node %s for %s:"
1948 d4f16fd9 Iustin Pop
                             " needed %s MiB, available %s MiB" %
1949 d4f16fd9 Iustin Pop
                             (node, reason, requested, free_mem))
1950 d4f16fd9 Iustin Pop
1951 d4f16fd9 Iustin Pop
1952 a8083063 Iustin Pop
class LUStartupInstance(LogicalUnit):
1953 a8083063 Iustin Pop
  """Starts an instance.
1954 a8083063 Iustin Pop

1955 a8083063 Iustin Pop
  """
1956 a8083063 Iustin Pop
  HPATH = "instance-start"
1957 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
1958 a8083063 Iustin Pop
  _OP_REQP = ["instance_name", "force"]
1959 a8083063 Iustin Pop
1960 a8083063 Iustin Pop
  def BuildHooksEnv(self):
1961 a8083063 Iustin Pop
    """Build hooks env.
1962 a8083063 Iustin Pop

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

1965 a8083063 Iustin Pop
    """
1966 a8083063 Iustin Pop
    env = {
1967 a8083063 Iustin Pop
      "FORCE": self.op.force,
1968 a8083063 Iustin Pop
      }
1969 396e1b78 Michael Hanselmann
    env.update(_BuildInstanceHookEnvByObject(self.instance))
1970 880478f8 Iustin Pop
    nl = ([self.sstore.GetMasterNode(), self.instance.primary_node] +
1971 a8083063 Iustin Pop
          list(self.instance.secondary_nodes))
1972 a8083063 Iustin Pop
    return env, nl, nl
1973 a8083063 Iustin Pop
1974 a8083063 Iustin Pop
  def CheckPrereq(self):
1975 a8083063 Iustin Pop
    """Check prerequisites.
1976 a8083063 Iustin Pop

1977 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
1978 a8083063 Iustin Pop

1979 a8083063 Iustin Pop
    """
1980 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
1981 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
1982 a8083063 Iustin Pop
    if instance is None:
1983 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
1984 3ecf6786 Iustin Pop
                                 self.op.instance_name)
1985 a8083063 Iustin Pop
1986 a8083063 Iustin Pop
    # check bridges existance
1987 bf6929a2 Alexander Schreiber
    _CheckInstanceBridgesExist(instance)
1988 a8083063 Iustin Pop
1989 d4f16fd9 Iustin Pop
    _CheckNodeFreeMemory(self.cfg, instance.primary_node,
1990 d4f16fd9 Iustin Pop
                         "starting instance %s" % instance.name,
1991 d4f16fd9 Iustin Pop
                         instance.memory)
1992 d4f16fd9 Iustin Pop
1993 a8083063 Iustin Pop
    self.instance = instance
1994 a8083063 Iustin Pop
    self.op.instance_name = instance.name
1995 a8083063 Iustin Pop
1996 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1997 a8083063 Iustin Pop
    """Start the instance.
1998 a8083063 Iustin Pop

1999 a8083063 Iustin Pop
    """
2000 a8083063 Iustin Pop
    instance = self.instance
2001 a8083063 Iustin Pop
    force = self.op.force
2002 a8083063 Iustin Pop
    extra_args = getattr(self.op, "extra_args", "")
2003 a8083063 Iustin Pop
2004 fe482621 Iustin Pop
    self.cfg.MarkInstanceUp(instance.name)
2005 fe482621 Iustin Pop
2006 a8083063 Iustin Pop
    node_current = instance.primary_node
2007 a8083063 Iustin Pop
2008 fe7b0351 Michael Hanselmann
    _StartInstanceDisks(self.cfg, instance, force)
2009 a8083063 Iustin Pop
2010 a8083063 Iustin Pop
    if not rpc.call_instance_start(node_current, instance, extra_args):
2011 a8083063 Iustin Pop
      _ShutdownInstanceDisks(instance, self.cfg)
2012 3ecf6786 Iustin Pop
      raise errors.OpExecError("Could not start instance")
2013 a8083063 Iustin Pop
2014 a8083063 Iustin Pop
2015 bf6929a2 Alexander Schreiber
class LURebootInstance(LogicalUnit):
2016 bf6929a2 Alexander Schreiber
  """Reboot an instance.
2017 bf6929a2 Alexander Schreiber

2018 bf6929a2 Alexander Schreiber
  """
2019 bf6929a2 Alexander Schreiber
  HPATH = "instance-reboot"
2020 bf6929a2 Alexander Schreiber
  HTYPE = constants.HTYPE_INSTANCE
2021 bf6929a2 Alexander Schreiber
  _OP_REQP = ["instance_name", "ignore_secondaries", "reboot_type"]
2022 bf6929a2 Alexander Schreiber
2023 bf6929a2 Alexander Schreiber
  def BuildHooksEnv(self):
2024 bf6929a2 Alexander Schreiber
    """Build hooks env.
2025 bf6929a2 Alexander Schreiber

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

2028 bf6929a2 Alexander Schreiber
    """
2029 bf6929a2 Alexander Schreiber
    env = {
2030 bf6929a2 Alexander Schreiber
      "IGNORE_SECONDARIES": self.op.ignore_secondaries,
2031 bf6929a2 Alexander Schreiber
      }
2032 bf6929a2 Alexander Schreiber
    env.update(_BuildInstanceHookEnvByObject(self.instance))
2033 bf6929a2 Alexander Schreiber
    nl = ([self.sstore.GetMasterNode(), self.instance.primary_node] +
2034 bf6929a2 Alexander Schreiber
          list(self.instance.secondary_nodes))
2035 bf6929a2 Alexander Schreiber
    return env, nl, nl
2036 bf6929a2 Alexander Schreiber
2037 bf6929a2 Alexander Schreiber
  def CheckPrereq(self):
2038 bf6929a2 Alexander Schreiber
    """Check prerequisites.
2039 bf6929a2 Alexander Schreiber

2040 bf6929a2 Alexander Schreiber
    This checks that the instance is in the cluster.
2041 bf6929a2 Alexander Schreiber

2042 bf6929a2 Alexander Schreiber
    """
2043 bf6929a2 Alexander Schreiber
    instance = self.cfg.GetInstanceInfo(
2044 bf6929a2 Alexander Schreiber
      self.cfg.ExpandInstanceName(self.op.instance_name))
2045 bf6929a2 Alexander Schreiber
    if instance is None:
2046 bf6929a2 Alexander Schreiber
      raise errors.OpPrereqError("Instance '%s' not known" %
2047 bf6929a2 Alexander Schreiber
                                 self.op.instance_name)
2048 bf6929a2 Alexander Schreiber
2049 bf6929a2 Alexander Schreiber
    # check bridges existance
2050 bf6929a2 Alexander Schreiber
    _CheckInstanceBridgesExist(instance)
2051 bf6929a2 Alexander Schreiber
2052 bf6929a2 Alexander Schreiber
    self.instance = instance
2053 bf6929a2 Alexander Schreiber
    self.op.instance_name = instance.name
2054 bf6929a2 Alexander Schreiber
2055 bf6929a2 Alexander Schreiber
  def Exec(self, feedback_fn):
2056 bf6929a2 Alexander Schreiber
    """Reboot the instance.
2057 bf6929a2 Alexander Schreiber

2058 bf6929a2 Alexander Schreiber
    """
2059 bf6929a2 Alexander Schreiber
    instance = self.instance
2060 bf6929a2 Alexander Schreiber
    ignore_secondaries = self.op.ignore_secondaries
2061 bf6929a2 Alexander Schreiber
    reboot_type = self.op.reboot_type
2062 bf6929a2 Alexander Schreiber
    extra_args = getattr(self.op, "extra_args", "")
2063 bf6929a2 Alexander Schreiber
2064 bf6929a2 Alexander Schreiber
    node_current = instance.primary_node
2065 bf6929a2 Alexander Schreiber
2066 bf6929a2 Alexander Schreiber
    if reboot_type not in [constants.INSTANCE_REBOOT_SOFT,
2067 bf6929a2 Alexander Schreiber
                           constants.INSTANCE_REBOOT_HARD,
2068 bf6929a2 Alexander Schreiber
                           constants.INSTANCE_REBOOT_FULL]:
2069 bf6929a2 Alexander Schreiber
      raise errors.ParameterError("reboot type not in [%s, %s, %s]" %
2070 bf6929a2 Alexander Schreiber
                                  (constants.INSTANCE_REBOOT_SOFT,
2071 bf6929a2 Alexander Schreiber
                                   constants.INSTANCE_REBOOT_HARD,
2072 bf6929a2 Alexander Schreiber
                                   constants.INSTANCE_REBOOT_FULL))
2073 bf6929a2 Alexander Schreiber
2074 bf6929a2 Alexander Schreiber
    if reboot_type in [constants.INSTANCE_REBOOT_SOFT,
2075 bf6929a2 Alexander Schreiber
                       constants.INSTANCE_REBOOT_HARD]:
2076 bf6929a2 Alexander Schreiber
      if not rpc.call_instance_reboot(node_current, instance,
2077 bf6929a2 Alexander Schreiber
                                      reboot_type, extra_args):
2078 bf6929a2 Alexander Schreiber
        raise errors.OpExecError("Could not reboot instance")
2079 bf6929a2 Alexander Schreiber
    else:
2080 bf6929a2 Alexander Schreiber
      if not rpc.call_instance_shutdown(node_current, instance):
2081 bf6929a2 Alexander Schreiber
        raise errors.OpExecError("could not shutdown instance for full reboot")
2082 bf6929a2 Alexander Schreiber
      _ShutdownInstanceDisks(instance, self.cfg)
2083 bf6929a2 Alexander Schreiber
      _StartInstanceDisks(self.cfg, instance, ignore_secondaries)
2084 bf6929a2 Alexander Schreiber
      if not rpc.call_instance_start(node_current, instance, extra_args):
2085 bf6929a2 Alexander Schreiber
        _ShutdownInstanceDisks(instance, self.cfg)
2086 bf6929a2 Alexander Schreiber
        raise errors.OpExecError("Could not start instance for full reboot")
2087 bf6929a2 Alexander Schreiber
2088 bf6929a2 Alexander Schreiber
    self.cfg.MarkInstanceUp(instance.name)
2089 bf6929a2 Alexander Schreiber
2090 bf6929a2 Alexander Schreiber
2091 a8083063 Iustin Pop
class LUShutdownInstance(LogicalUnit):
2092 a8083063 Iustin Pop
  """Shutdown an instance.
2093 a8083063 Iustin Pop

2094 a8083063 Iustin Pop
  """
2095 a8083063 Iustin Pop
  HPATH = "instance-stop"
2096 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
2097 a8083063 Iustin Pop
  _OP_REQP = ["instance_name"]
2098 a8083063 Iustin Pop
2099 a8083063 Iustin Pop
  def BuildHooksEnv(self):
2100 a8083063 Iustin Pop
    """Build hooks env.
2101 a8083063 Iustin Pop

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

2104 a8083063 Iustin Pop
    """
2105 396e1b78 Michael Hanselmann
    env = _BuildInstanceHookEnvByObject(self.instance)
2106 880478f8 Iustin Pop
    nl = ([self.sstore.GetMasterNode(), self.instance.primary_node] +
2107 a8083063 Iustin Pop
          list(self.instance.secondary_nodes))
2108 a8083063 Iustin Pop
    return env, nl, nl
2109 a8083063 Iustin Pop
2110 a8083063 Iustin Pop
  def CheckPrereq(self):
2111 a8083063 Iustin Pop
    """Check prerequisites.
2112 a8083063 Iustin Pop

2113 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
2114 a8083063 Iustin Pop

2115 a8083063 Iustin Pop
    """
2116 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
2117 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
2118 a8083063 Iustin Pop
    if instance is None:
2119 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
2120 3ecf6786 Iustin Pop
                                 self.op.instance_name)
2121 a8083063 Iustin Pop
    self.instance = instance
2122 a8083063 Iustin Pop
2123 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
2124 a8083063 Iustin Pop
    """Shutdown the instance.
2125 a8083063 Iustin Pop

2126 a8083063 Iustin Pop
    """
2127 a8083063 Iustin Pop
    instance = self.instance
2128 a8083063 Iustin Pop
    node_current = instance.primary_node
2129 fe482621 Iustin Pop
    self.cfg.MarkInstanceDown(instance.name)
2130 a8083063 Iustin Pop
    if not rpc.call_instance_shutdown(node_current, instance):
2131 a8083063 Iustin Pop
      logger.Error("could not shutdown instance")
2132 a8083063 Iustin Pop
2133 a8083063 Iustin Pop
    _ShutdownInstanceDisks(instance, self.cfg)
2134 a8083063 Iustin Pop
2135 a8083063 Iustin Pop
2136 fe7b0351 Michael Hanselmann
class LUReinstallInstance(LogicalUnit):
2137 fe7b0351 Michael Hanselmann
  """Reinstall an instance.
2138 fe7b0351 Michael Hanselmann

2139 fe7b0351 Michael Hanselmann
  """
2140 fe7b0351 Michael Hanselmann
  HPATH = "instance-reinstall"
2141 fe7b0351 Michael Hanselmann
  HTYPE = constants.HTYPE_INSTANCE
2142 fe7b0351 Michael Hanselmann
  _OP_REQP = ["instance_name"]
2143 fe7b0351 Michael Hanselmann
2144 fe7b0351 Michael Hanselmann
  def BuildHooksEnv(self):
2145 fe7b0351 Michael Hanselmann
    """Build hooks env.
2146 fe7b0351 Michael Hanselmann

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

2149 fe7b0351 Michael Hanselmann
    """
2150 396e1b78 Michael Hanselmann
    env = _BuildInstanceHookEnvByObject(self.instance)
2151 fe7b0351 Michael Hanselmann
    nl = ([self.sstore.GetMasterNode(), self.instance.primary_node] +
2152 fe7b0351 Michael Hanselmann
          list(self.instance.secondary_nodes))
2153 fe7b0351 Michael Hanselmann
    return env, nl, nl
2154 fe7b0351 Michael Hanselmann
2155 fe7b0351 Michael Hanselmann
  def CheckPrereq(self):
2156 fe7b0351 Michael Hanselmann
    """Check prerequisites.
2157 fe7b0351 Michael Hanselmann

2158 fe7b0351 Michael Hanselmann
    This checks that the instance is in the cluster and is not running.
2159 fe7b0351 Michael Hanselmann

2160 fe7b0351 Michael Hanselmann
    """
2161 fe7b0351 Michael Hanselmann
    instance = self.cfg.GetInstanceInfo(
2162 fe7b0351 Michael Hanselmann
      self.cfg.ExpandInstanceName(self.op.instance_name))
2163 fe7b0351 Michael Hanselmann
    if instance is None:
2164 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
2165 3ecf6786 Iustin Pop
                                 self.op.instance_name)
2166 fe7b0351 Michael Hanselmann
    if instance.disk_template == constants.DT_DISKLESS:
2167 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' has no disks" %
2168 3ecf6786 Iustin Pop
                                 self.op.instance_name)
2169 fe7b0351 Michael Hanselmann
    if instance.status != "down":
2170 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' is marked to be up" %
2171 3ecf6786 Iustin Pop
                                 self.op.instance_name)
2172 fe7b0351 Michael Hanselmann
    remote_info = rpc.call_instance_info(instance.primary_node, instance.name)
2173 fe7b0351 Michael Hanselmann
    if remote_info:
2174 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' is running on the node %s" %
2175 3ecf6786 Iustin Pop
                                 (self.op.instance_name,
2176 3ecf6786 Iustin Pop
                                  instance.primary_node))
2177 d0834de3 Michael Hanselmann
2178 d0834de3 Michael Hanselmann
    self.op.os_type = getattr(self.op, "os_type", None)
2179 d0834de3 Michael Hanselmann
    if self.op.os_type is not None:
2180 d0834de3 Michael Hanselmann
      # OS verification
2181 d0834de3 Michael Hanselmann
      pnode = self.cfg.GetNodeInfo(
2182 d0834de3 Michael Hanselmann
        self.cfg.ExpandNodeName(instance.primary_node))
2183 d0834de3 Michael Hanselmann
      if pnode is None:
2184 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Primary node '%s' is unknown" %
2185 3ecf6786 Iustin Pop
                                   self.op.pnode)
2186 00fe9e38 Guido Trotter
      os_obj = rpc.call_os_get(pnode.name, self.op.os_type)
2187 dfa96ded Guido Trotter
      if not os_obj:
2188 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("OS '%s' not in supported OS list for"
2189 3ecf6786 Iustin Pop
                                   " primary node"  % self.op.os_type)
2190 d0834de3 Michael Hanselmann
2191 fe7b0351 Michael Hanselmann
    self.instance = instance
2192 fe7b0351 Michael Hanselmann
2193 fe7b0351 Michael Hanselmann
  def Exec(self, feedback_fn):
2194 fe7b0351 Michael Hanselmann
    """Reinstall the instance.
2195 fe7b0351 Michael Hanselmann

2196 fe7b0351 Michael Hanselmann
    """
2197 fe7b0351 Michael Hanselmann
    inst = self.instance
2198 fe7b0351 Michael Hanselmann
2199 d0834de3 Michael Hanselmann
    if self.op.os_type is not None:
2200 d0834de3 Michael Hanselmann
      feedback_fn("Changing OS to '%s'..." % self.op.os_type)
2201 d0834de3 Michael Hanselmann
      inst.os = self.op.os_type
2202 d0834de3 Michael Hanselmann
      self.cfg.AddInstance(inst)
2203 d0834de3 Michael Hanselmann
2204 fe7b0351 Michael Hanselmann
    _StartInstanceDisks(self.cfg, inst, None)
2205 fe7b0351 Michael Hanselmann
    try:
2206 fe7b0351 Michael Hanselmann
      feedback_fn("Running the instance OS create scripts...")
2207 fe7b0351 Michael Hanselmann
      if not rpc.call_instance_os_add(inst.primary_node, inst, "sda", "sdb"):
2208 f4bc1f2c Michael Hanselmann
        raise errors.OpExecError("Could not install OS for instance %s"
2209 f4bc1f2c Michael Hanselmann
                                 " on node %s" %
2210 3ecf6786 Iustin Pop
                                 (inst.name, inst.primary_node))
2211 fe7b0351 Michael Hanselmann
    finally:
2212 fe7b0351 Michael Hanselmann
      _ShutdownInstanceDisks(inst, self.cfg)
2213 fe7b0351 Michael Hanselmann
2214 fe7b0351 Michael Hanselmann
2215 decd5f45 Iustin Pop
class LURenameInstance(LogicalUnit):
2216 decd5f45 Iustin Pop
  """Rename an instance.
2217 decd5f45 Iustin Pop

2218 decd5f45 Iustin Pop
  """
2219 decd5f45 Iustin Pop
  HPATH = "instance-rename"
2220 decd5f45 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
2221 decd5f45 Iustin Pop
  _OP_REQP = ["instance_name", "new_name"]
2222 decd5f45 Iustin Pop
2223 decd5f45 Iustin Pop
  def BuildHooksEnv(self):
2224 decd5f45 Iustin Pop
    """Build hooks env.
2225 decd5f45 Iustin Pop

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

2228 decd5f45 Iustin Pop
    """
2229 decd5f45 Iustin Pop
    env = _BuildInstanceHookEnvByObject(self.instance)
2230 decd5f45 Iustin Pop
    env["INSTANCE_NEW_NAME"] = self.op.new_name
2231 decd5f45 Iustin Pop
    nl = ([self.sstore.GetMasterNode(), self.instance.primary_node] +
2232 decd5f45 Iustin Pop
          list(self.instance.secondary_nodes))
2233 decd5f45 Iustin Pop
    return env, nl, nl
2234 decd5f45 Iustin Pop
2235 decd5f45 Iustin Pop
  def CheckPrereq(self):
2236 decd5f45 Iustin Pop
    """Check prerequisites.
2237 decd5f45 Iustin Pop

2238 decd5f45 Iustin Pop
    This checks that the instance is in the cluster and is not running.
2239 decd5f45 Iustin Pop

2240 decd5f45 Iustin Pop
    """
2241 decd5f45 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
2242 decd5f45 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
2243 decd5f45 Iustin Pop
    if instance is None:
2244 decd5f45 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
2245 decd5f45 Iustin Pop
                                 self.op.instance_name)
2246 decd5f45 Iustin Pop
    if instance.status != "down":
2247 decd5f45 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' is marked to be up" %
2248 decd5f45 Iustin Pop
                                 self.op.instance_name)
2249 decd5f45 Iustin Pop
    remote_info = rpc.call_instance_info(instance.primary_node, instance.name)
2250 decd5f45 Iustin Pop
    if remote_info:
2251 decd5f45 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' is running on the node %s" %
2252 decd5f45 Iustin Pop
                                 (self.op.instance_name,
2253 decd5f45 Iustin Pop
                                  instance.primary_node))
2254 decd5f45 Iustin Pop
    self.instance = instance
2255 decd5f45 Iustin Pop
2256 decd5f45 Iustin Pop
    # new name verification
2257 89e1fc26 Iustin Pop
    name_info = utils.HostInfo(self.op.new_name)
2258 decd5f45 Iustin Pop
2259 89e1fc26 Iustin Pop
    self.op.new_name = new_name = name_info.name
2260 7bde3275 Guido Trotter
    instance_list = self.cfg.GetInstanceList()
2261 7bde3275 Guido Trotter
    if new_name in instance_list:
2262 7bde3275 Guido Trotter
      raise errors.OpPrereqError("Instance '%s' is already in the cluster" %
2263 c09f363f Manuel Franceschini
                                 new_name)
2264 7bde3275 Guido Trotter
2265 decd5f45 Iustin Pop
    if not getattr(self.op, "ignore_ip", False):
2266 937f983d Guido Trotter
      if utils.TcpPing(name_info.ip, constants.DEFAULT_NODED_PORT):
2267 decd5f45 Iustin Pop
        raise errors.OpPrereqError("IP %s of instance %s already in use" %
2268 89e1fc26 Iustin Pop
                                   (name_info.ip, new_name))
2269 decd5f45 Iustin Pop
2270 decd5f45 Iustin Pop
2271 decd5f45 Iustin Pop
  def Exec(self, feedback_fn):
2272 decd5f45 Iustin Pop
    """Reinstall the instance.
2273 decd5f45 Iustin Pop

2274 decd5f45 Iustin Pop
    """
2275 decd5f45 Iustin Pop
    inst = self.instance
2276 decd5f45 Iustin Pop
    old_name = inst.name
2277 decd5f45 Iustin Pop
2278 b23c4333 Manuel Franceschini
    if inst.disk_template == constants.DT_FILE:
2279 b23c4333 Manuel Franceschini
      old_file_storage_dir = os.path.dirname(inst.disks[0].logical_id[1])
2280 b23c4333 Manuel Franceschini
2281 decd5f45 Iustin Pop
    self.cfg.RenameInstance(inst.name, self.op.new_name)
2282 decd5f45 Iustin Pop
2283 decd5f45 Iustin Pop
    # re-read the instance from the configuration after rename
2284 decd5f45 Iustin Pop
    inst = self.cfg.GetInstanceInfo(self.op.new_name)
2285 decd5f45 Iustin Pop
2286 b23c4333 Manuel Franceschini
    if inst.disk_template == constants.DT_FILE:
2287 b23c4333 Manuel Franceschini
      new_file_storage_dir = os.path.dirname(inst.disks[0].logical_id[1])
2288 b23c4333 Manuel Franceschini
      result = rpc.call_file_storage_dir_rename(inst.primary_node,
2289 b23c4333 Manuel Franceschini
                                                old_file_storage_dir,
2290 b23c4333 Manuel Franceschini
                                                new_file_storage_dir)
2291 b23c4333 Manuel Franceschini
2292 b23c4333 Manuel Franceschini
      if not result:
2293 b23c4333 Manuel Franceschini
        raise errors.OpExecError("Could not connect to node '%s' to rename"
2294 b23c4333 Manuel Franceschini
                                 " directory '%s' to '%s' (but the instance"
2295 b23c4333 Manuel Franceschini
                                 " has been renamed in Ganeti)" % (
2296 b23c4333 Manuel Franceschini
                                 inst.primary_node, old_file_storage_dir,
2297 b23c4333 Manuel Franceschini
                                 new_file_storage_dir))
2298 b23c4333 Manuel Franceschini
2299 b23c4333 Manuel Franceschini
      if not result[0]:
2300 b23c4333 Manuel Franceschini
        raise errors.OpExecError("Could not rename directory '%s' to '%s'"
2301 b23c4333 Manuel Franceschini
                                 " (but the instance has been renamed in"
2302 b23c4333 Manuel Franceschini
                                 " Ganeti)" % (old_file_storage_dir,
2303 b23c4333 Manuel Franceschini
                                               new_file_storage_dir))
2304 b23c4333 Manuel Franceschini
2305 decd5f45 Iustin Pop
    _StartInstanceDisks(self.cfg, inst, None)
2306 decd5f45 Iustin Pop
    try:
2307 decd5f45 Iustin Pop
      if not rpc.call_instance_run_rename(inst.primary_node, inst, old_name,
2308 decd5f45 Iustin Pop
                                          "sda", "sdb"):
2309 f4bc1f2c Michael Hanselmann
        msg = ("Could run OS rename script for instance %s on node %s (but the"
2310 f4bc1f2c Michael Hanselmann
               " instance has been renamed in Ganeti)" %
2311 decd5f45 Iustin Pop
               (inst.name, inst.primary_node))
2312 decd5f45 Iustin Pop
        logger.Error(msg)
2313 decd5f45 Iustin Pop
    finally:
2314 decd5f45 Iustin Pop
      _ShutdownInstanceDisks(inst, self.cfg)
2315 decd5f45 Iustin Pop
2316 decd5f45 Iustin Pop
2317 a8083063 Iustin Pop
class LURemoveInstance(LogicalUnit):
2318 a8083063 Iustin Pop
  """Remove an instance.
2319 a8083063 Iustin Pop

2320 a8083063 Iustin Pop
  """
2321 a8083063 Iustin Pop
  HPATH = "instance-remove"
2322 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
2323 5c54b832 Iustin Pop
  _OP_REQP = ["instance_name", "ignore_failures"]
2324 a8083063 Iustin Pop
2325 a8083063 Iustin Pop
  def BuildHooksEnv(self):
2326 a8083063 Iustin Pop
    """Build hooks env.
2327 a8083063 Iustin Pop

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

2330 a8083063 Iustin Pop
    """
2331 396e1b78 Michael Hanselmann
    env = _BuildInstanceHookEnvByObject(self.instance)
2332 1d67656e Iustin Pop
    nl = [self.sstore.GetMasterNode()]
2333 a8083063 Iustin Pop
    return env, nl, nl
2334 a8083063 Iustin Pop
2335 a8083063 Iustin Pop
  def CheckPrereq(self):
2336 a8083063 Iustin Pop
    """Check prerequisites.
2337 a8083063 Iustin Pop

2338 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
2339 a8083063 Iustin Pop

2340 a8083063 Iustin Pop
    """
2341 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
2342 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
2343 a8083063 Iustin Pop
    if instance is None:
2344 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
2345 3ecf6786 Iustin Pop
                                 self.op.instance_name)
2346 a8083063 Iustin Pop
    self.instance = instance
2347 a8083063 Iustin Pop
2348 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
2349 a8083063 Iustin Pop
    """Remove the instance.
2350 a8083063 Iustin Pop

2351 a8083063 Iustin Pop
    """
2352 a8083063 Iustin Pop
    instance = self.instance
2353 a8083063 Iustin Pop
    logger.Info("shutting down instance %s on node %s" %
2354 a8083063 Iustin Pop
                (instance.name, instance.primary_node))
2355 a8083063 Iustin Pop
2356 a8083063 Iustin Pop
    if not rpc.call_instance_shutdown(instance.primary_node, instance):
2357 1d67656e Iustin Pop
      if self.op.ignore_failures:
2358 1d67656e Iustin Pop
        feedback_fn("Warning: can't shutdown instance")
2359 1d67656e Iustin Pop
      else:
2360 1d67656e Iustin Pop
        raise errors.OpExecError("Could not shutdown instance %s on node %s" %
2361 1d67656e Iustin Pop
                                 (instance.name, instance.primary_node))
2362 a8083063 Iustin Pop
2363 a8083063 Iustin Pop
    logger.Info("removing block devices for instance %s" % instance.name)
2364 a8083063 Iustin Pop
2365 1d67656e Iustin Pop
    if not _RemoveDisks(instance, self.cfg):
2366 1d67656e Iustin Pop
      if self.op.ignore_failures:
2367 1d67656e Iustin Pop
        feedback_fn("Warning: can't remove instance's disks")
2368 1d67656e Iustin Pop
      else:
2369 1d67656e Iustin Pop
        raise errors.OpExecError("Can't remove instance's disks")
2370 a8083063 Iustin Pop
2371 a8083063 Iustin Pop
    logger.Info("removing instance %s out of cluster config" % instance.name)
2372 a8083063 Iustin Pop
2373 a8083063 Iustin Pop
    self.cfg.RemoveInstance(instance.name)
2374 a2fd9afc Guido Trotter
    # Remove the new instance from the Ganeti Lock Manager
2375 a2fd9afc Guido Trotter
    self.context.glm.remove(locking.LEVEL_INSTANCE, instance.name)
2376 a8083063 Iustin Pop
2377 a8083063 Iustin Pop
2378 a8083063 Iustin Pop
class LUQueryInstances(NoHooksLU):
2379 a8083063 Iustin Pop
  """Logical unit for querying instances.
2380 a8083063 Iustin Pop

2381 a8083063 Iustin Pop
  """
2382 069dcc86 Iustin Pop
  _OP_REQP = ["output_fields", "names"]
2383 a8083063 Iustin Pop
2384 a8083063 Iustin Pop
  def CheckPrereq(self):
2385 a8083063 Iustin Pop
    """Check prerequisites.
2386 a8083063 Iustin Pop

2387 a8083063 Iustin Pop
    This checks that the fields required are valid output fields.
2388 a8083063 Iustin Pop

2389 a8083063 Iustin Pop
    """
2390 d8052456 Iustin Pop
    self.dynamic_fields = frozenset(["oper_state", "oper_ram", "status"])
2391 dcb93971 Michael Hanselmann
    _CheckOutputFields(static=["name", "os", "pnode", "snodes",
2392 dcb93971 Michael Hanselmann
                               "admin_state", "admin_ram",
2393 644eeef9 Iustin Pop
                               "disk_template", "ip", "mac", "bridge",
2394 130a6a6f Iustin Pop
                               "sda_size", "sdb_size", "vcpus", "tags"],
2395 dcb93971 Michael Hanselmann
                       dynamic=self.dynamic_fields,
2396 dcb93971 Michael Hanselmann
                       selected=self.op.output_fields)
2397 a8083063 Iustin Pop
2398 069dcc86 Iustin Pop
    self.wanted = _GetWantedInstances(self, self.op.names)
2399 069dcc86 Iustin Pop
2400 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
2401 a8083063 Iustin Pop
    """Computes the list of nodes and their attributes.
2402 a8083063 Iustin Pop

2403 a8083063 Iustin Pop
    """
2404 069dcc86 Iustin Pop
    instance_names = self.wanted
2405 a8083063 Iustin Pop
    instance_list = [self.cfg.GetInstanceInfo(iname) for iname
2406 a8083063 Iustin Pop
                     in instance_names]
2407 a8083063 Iustin Pop
2408 a8083063 Iustin Pop
    # begin data gathering
2409 a8083063 Iustin Pop
2410 a8083063 Iustin Pop
    nodes = frozenset([inst.primary_node for inst in instance_list])
2411 a8083063 Iustin Pop
2412 a8083063 Iustin Pop
    bad_nodes = []
2413 a8083063 Iustin Pop
    if self.dynamic_fields.intersection(self.op.output_fields):
2414 a8083063 Iustin Pop
      live_data = {}
2415 a8083063 Iustin Pop
      node_data = rpc.call_all_instances_info(nodes)
2416 a8083063 Iustin Pop
      for name in nodes:
2417 a8083063 Iustin Pop
        result = node_data[name]
2418 a8083063 Iustin Pop
        if result:
2419 a8083063 Iustin Pop
          live_data.update(result)
2420 a8083063 Iustin Pop
        elif result == False:
2421 a8083063 Iustin Pop
          bad_nodes.append(name)
2422 a8083063 Iustin Pop
        # else no instance is alive
2423 a8083063 Iustin Pop
    else:
2424 a8083063 Iustin Pop
      live_data = dict([(name, {}) for name in instance_names])
2425 a8083063 Iustin Pop
2426 a8083063 Iustin Pop
    # end data gathering
2427 a8083063 Iustin Pop
2428 a8083063 Iustin Pop
    output = []
2429 a8083063 Iustin Pop
    for instance in instance_list:
2430 a8083063 Iustin Pop
      iout = []
2431 a8083063 Iustin Pop
      for field in self.op.output_fields:
2432 a8083063 Iustin Pop
        if field == "name":
2433 a8083063 Iustin Pop
          val = instance.name
2434 a8083063 Iustin Pop
        elif field == "os":
2435 a8083063 Iustin Pop
          val = instance.os
2436 a8083063 Iustin Pop
        elif field == "pnode":
2437 a8083063 Iustin Pop
          val = instance.primary_node
2438 a8083063 Iustin Pop
        elif field == "snodes":
2439 8a23d2d3 Iustin Pop
          val = list(instance.secondary_nodes)
2440 a8083063 Iustin Pop
        elif field == "admin_state":
2441 8a23d2d3 Iustin Pop
          val = (instance.status != "down")
2442 a8083063 Iustin Pop
        elif field == "oper_state":
2443 a8083063 Iustin Pop
          if instance.primary_node in bad_nodes:
2444 8a23d2d3 Iustin Pop
            val = None
2445 a8083063 Iustin Pop
          else:
2446 8a23d2d3 Iustin Pop
            val = bool(live_data.get(instance.name))
2447 d8052456 Iustin Pop
        elif field == "status":
2448 d8052456 Iustin Pop
          if instance.primary_node in bad_nodes:
2449 d8052456 Iustin Pop
            val = "ERROR_nodedown"
2450 d8052456 Iustin Pop
          else:
2451 d8052456 Iustin Pop
            running = bool(live_data.get(instance.name))
2452 d8052456 Iustin Pop
            if running:
2453 d8052456 Iustin Pop
              if instance.status != "down":
2454 d8052456 Iustin Pop
                val = "running"
2455 d8052456 Iustin Pop
              else:
2456 d8052456 Iustin Pop
                val = "ERROR_up"
2457 d8052456 Iustin Pop
            else:
2458 d8052456 Iustin Pop
              if instance.status != "down":
2459 d8052456 Iustin Pop
                val = "ERROR_down"
2460 d8052456 Iustin Pop
              else:
2461 d8052456 Iustin Pop
                val = "ADMIN_down"
2462 a8083063 Iustin Pop
        elif field == "admin_ram":
2463 a8083063 Iustin Pop
          val = instance.memory
2464 a8083063 Iustin Pop
        elif field == "oper_ram":
2465 a8083063 Iustin Pop
          if instance.primary_node in bad_nodes:
2466 8a23d2d3 Iustin Pop
            val = None
2467 a8083063 Iustin Pop
          elif instance.name in live_data:
2468 a8083063 Iustin Pop
            val = live_data[instance.name].get("memory", "?")
2469 a8083063 Iustin Pop
          else:
2470 a8083063 Iustin Pop
            val = "-"
2471 a8083063 Iustin Pop
        elif field == "disk_template":
2472 a8083063 Iustin Pop
          val = instance.disk_template
2473 a8083063 Iustin Pop
        elif field == "ip":
2474 a8083063 Iustin Pop
          val = instance.nics[0].ip
2475 a8083063 Iustin Pop
        elif field == "bridge":
2476 a8083063 Iustin Pop
          val = instance.nics[0].bridge
2477 a8083063 Iustin Pop
        elif field == "mac":
2478 a8083063 Iustin Pop
          val = instance.nics[0].mac
2479 644eeef9 Iustin Pop
        elif field == "sda_size" or field == "sdb_size":
2480 644eeef9 Iustin Pop
          disk = instance.FindDisk(field[:3])
2481 644eeef9 Iustin Pop
          if disk is None:
2482 8a23d2d3 Iustin Pop
            val = None
2483 644eeef9 Iustin Pop
          else:
2484 644eeef9 Iustin Pop
            val = disk.size
2485 d6d415e8 Iustin Pop
        elif field == "vcpus":
2486 d6d415e8 Iustin Pop
          val = instance.vcpus
2487 130a6a6f Iustin Pop
        elif field == "tags":
2488 130a6a6f Iustin Pop
          val = list(instance.GetTags())
2489 a8083063 Iustin Pop
        else:
2490 3ecf6786 Iustin Pop
          raise errors.ParameterError(field)
2491 a8083063 Iustin Pop
        iout.append(val)
2492 a8083063 Iustin Pop
      output.append(iout)
2493 a8083063 Iustin Pop
2494 a8083063 Iustin Pop
    return output
2495 a8083063 Iustin Pop
2496 a8083063 Iustin Pop
2497 a8083063 Iustin Pop
class LUFailoverInstance(LogicalUnit):
2498 a8083063 Iustin Pop
  """Failover an instance.
2499 a8083063 Iustin Pop

2500 a8083063 Iustin Pop
  """
2501 a8083063 Iustin Pop
  HPATH = "instance-failover"
2502 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
2503 a8083063 Iustin Pop
  _OP_REQP = ["instance_name", "ignore_consistency"]
2504 a8083063 Iustin Pop
2505 a8083063 Iustin Pop
  def BuildHooksEnv(self):
2506 a8083063 Iustin Pop
    """Build hooks env.
2507 a8083063 Iustin Pop

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

2510 a8083063 Iustin Pop
    """
2511 a8083063 Iustin Pop
    env = {
2512 a8083063 Iustin Pop
      "IGNORE_CONSISTENCY": self.op.ignore_consistency,
2513 a8083063 Iustin Pop
      }
2514 396e1b78 Michael Hanselmann
    env.update(_BuildInstanceHookEnvByObject(self.instance))
2515 880478f8 Iustin Pop
    nl = [self.sstore.GetMasterNode()] + list(self.instance.secondary_nodes)
2516 a8083063 Iustin Pop
    return env, nl, nl
2517 a8083063 Iustin Pop
2518 a8083063 Iustin Pop
  def CheckPrereq(self):
2519 a8083063 Iustin Pop
    """Check prerequisites.
2520 a8083063 Iustin Pop

2521 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
2522 a8083063 Iustin Pop

2523 a8083063 Iustin Pop
    """
2524 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
2525 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
2526 a8083063 Iustin Pop
    if instance is None:
2527 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
2528 3ecf6786 Iustin Pop
                                 self.op.instance_name)
2529 a8083063 Iustin Pop
2530 a1f445d3 Iustin Pop
    if instance.disk_template not in constants.DTS_NET_MIRROR:
2531 2a710df1 Michael Hanselmann
      raise errors.OpPrereqError("Instance's disk layout is not"
2532 a1f445d3 Iustin Pop
                                 " network mirrored, cannot failover.")
2533 2a710df1 Michael Hanselmann
2534 2a710df1 Michael Hanselmann
    secondary_nodes = instance.secondary_nodes
2535 2a710df1 Michael Hanselmann
    if not secondary_nodes:
2536 2a710df1 Michael Hanselmann
      raise errors.ProgrammerError("no secondary node but using "
2537 abdf0113 Iustin Pop
                                   "a mirrored disk template")
2538 2a710df1 Michael Hanselmann
2539 2a710df1 Michael Hanselmann
    target_node = secondary_nodes[0]
2540 d4f16fd9 Iustin Pop
    # check memory requirements on the secondary node
2541 d4f16fd9 Iustin Pop
    _CheckNodeFreeMemory(self.cfg, target_node, "failing over instance %s" %
2542 d4f16fd9 Iustin Pop
                         instance.name, instance.memory)
2543 3a7c308e Guido Trotter
2544 a8083063 Iustin Pop
    # check bridge existance
2545 a8083063 Iustin Pop
    brlist = [nic.bridge for nic in instance.nics]
2546 50ff9a7a Iustin Pop
    if not rpc.call_bridges_exist(target_node, brlist):
2547 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("One or more target bridges %s does not"
2548 3ecf6786 Iustin Pop
                                 " exist on destination node '%s'" %
2549 50ff9a7a Iustin Pop
                                 (brlist, target_node))
2550 a8083063 Iustin Pop
2551 a8083063 Iustin Pop
    self.instance = instance
2552 a8083063 Iustin Pop
2553 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
2554 a8083063 Iustin Pop
    """Failover an instance.
2555 a8083063 Iustin Pop

2556 a8083063 Iustin Pop
    The failover is done by shutting it down on its present node and
2557 a8083063 Iustin Pop
    starting it on the secondary.
2558 a8083063 Iustin Pop

2559 a8083063 Iustin Pop
    """
2560 a8083063 Iustin Pop
    instance = self.instance
2561 a8083063 Iustin Pop
2562 a8083063 Iustin Pop
    source_node = instance.primary_node
2563 a8083063 Iustin Pop
    target_node = instance.secondary_nodes[0]
2564 a8083063 Iustin Pop
2565 a8083063 Iustin Pop
    feedback_fn("* checking disk consistency between source and target")
2566 a8083063 Iustin Pop
    for dev in instance.disks:
2567 abdf0113 Iustin Pop
      # for drbd, these are drbd over lvm
2568 a8083063 Iustin Pop
      if not _CheckDiskConsistency(self.cfg, dev, target_node, False):
2569 a0aaa0d0 Guido Trotter
        if instance.status == "up" and not self.op.ignore_consistency:
2570 3ecf6786 Iustin Pop
          raise errors.OpExecError("Disk %s is degraded on target node,"
2571 3ecf6786 Iustin Pop
                                   " aborting failover." % dev.iv_name)
2572 a8083063 Iustin Pop
2573 a8083063 Iustin Pop
    feedback_fn("* shutting down instance on source node")
2574 a8083063 Iustin Pop
    logger.Info("Shutting down instance %s on node %s" %
2575 a8083063 Iustin Pop
                (instance.name, source_node))
2576 a8083063 Iustin Pop
2577 a8083063 Iustin Pop
    if not rpc.call_instance_shutdown(source_node, instance):
2578 24a40d57 Iustin Pop
      if self.op.ignore_consistency:
2579 24a40d57 Iustin Pop
        logger.Error("Could not shutdown instance %s on node %s. Proceeding"
2580 24a40d57 Iustin Pop
                     " anyway. Please make sure node %s is down"  %
2581 24a40d57 Iustin Pop
                     (instance.name, source_node, source_node))
2582 24a40d57 Iustin Pop
      else:
2583 24a40d57 Iustin Pop
        raise errors.OpExecError("Could not shutdown instance %s on node %s" %
2584 24a40d57 Iustin Pop
                                 (instance.name, source_node))
2585 a8083063 Iustin Pop
2586 a8083063 Iustin Pop
    feedback_fn("* deactivating the instance's disks on source node")
2587 a8083063 Iustin Pop
    if not _ShutdownInstanceDisks(instance, self.cfg, ignore_primary=True):
2588 3ecf6786 Iustin Pop
      raise errors.OpExecError("Can't shut down the instance's disks.")
2589 a8083063 Iustin Pop
2590 a8083063 Iustin Pop
    instance.primary_node = target_node
2591 a8083063 Iustin Pop
    # distribute new instance config to the other nodes
2592 b6102dab Guido Trotter
    self.cfg.Update(instance)
2593 a8083063 Iustin Pop
2594 12a0cfbe Guido Trotter
    # Only start the instance if it's marked as up
2595 12a0cfbe Guido Trotter
    if instance.status == "up":
2596 12a0cfbe Guido Trotter
      feedback_fn("* activating the instance's disks on target node")
2597 12a0cfbe Guido Trotter
      logger.Info("Starting instance %s on node %s" %
2598 12a0cfbe Guido Trotter
                  (instance.name, target_node))
2599 12a0cfbe Guido Trotter
2600 12a0cfbe Guido Trotter
      disks_ok, dummy = _AssembleInstanceDisks(instance, self.cfg,
2601 12a0cfbe Guido Trotter
                                               ignore_secondaries=True)
2602 12a0cfbe Guido Trotter
      if not disks_ok:
2603 12a0cfbe Guido Trotter
        _ShutdownInstanceDisks(instance, self.cfg)
2604 12a0cfbe Guido Trotter
        raise errors.OpExecError("Can't activate the instance's disks")
2605 a8083063 Iustin Pop
2606 12a0cfbe Guido Trotter
      feedback_fn("* starting the instance on the target node")
2607 12a0cfbe Guido Trotter
      if not rpc.call_instance_start(target_node, instance, None):
2608 12a0cfbe Guido Trotter
        _ShutdownInstanceDisks(instance, self.cfg)
2609 12a0cfbe Guido Trotter
        raise errors.OpExecError("Could not start instance %s on node %s." %
2610 12a0cfbe Guido Trotter
                                 (instance.name, target_node))
2611 a8083063 Iustin Pop
2612 a8083063 Iustin Pop
2613 3f78eef2 Iustin Pop
def _CreateBlockDevOnPrimary(cfg, node, instance, device, info):
2614 a8083063 Iustin Pop
  """Create a tree of block devices on the primary node.
2615 a8083063 Iustin Pop

2616 a8083063 Iustin Pop
  This always creates all devices.
2617 a8083063 Iustin Pop

2618 a8083063 Iustin Pop
  """
2619 a8083063 Iustin Pop
  if device.children:
2620 a8083063 Iustin Pop
    for child in device.children:
2621 3f78eef2 Iustin Pop
      if not _CreateBlockDevOnPrimary(cfg, node, instance, child, info):
2622 a8083063 Iustin Pop
        return False
2623 a8083063 Iustin Pop
2624 a8083063 Iustin Pop
  cfg.SetDiskID(device, node)
2625 3f78eef2 Iustin Pop
  new_id = rpc.call_blockdev_create(node, device, device.size,
2626 3f78eef2 Iustin Pop
                                    instance.name, True, info)
2627 a8083063 Iustin Pop
  if not new_id:
2628 a8083063 Iustin Pop
    return False
2629 a8083063 Iustin Pop
  if device.physical_id is None:
2630 a8083063 Iustin Pop
    device.physical_id = new_id
2631 a8083063 Iustin Pop
  return True
2632 a8083063 Iustin Pop
2633 a8083063 Iustin Pop
2634 3f78eef2 Iustin Pop
def _CreateBlockDevOnSecondary(cfg, node, instance, device, force, info):
2635 a8083063 Iustin Pop
  """Create a tree of block devices on a secondary node.
2636 a8083063 Iustin Pop

2637 a8083063 Iustin Pop
  If this device type has to be created on secondaries, create it and
2638 a8083063 Iustin Pop
  all its children.
2639 a8083063 Iustin Pop

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

2642 a8083063 Iustin Pop
  """
2643 a8083063 Iustin Pop
  if device.CreateOnSecondary():
2644 a8083063 Iustin Pop
    force = True
2645 a8083063 Iustin Pop
  if device.children:
2646 a8083063 Iustin Pop
    for child in device.children:
2647 3f78eef2 Iustin Pop
      if not _CreateBlockDevOnSecondary(cfg, node, instance,
2648 3f78eef2 Iustin Pop
                                        child, force, info):
2649 a8083063 Iustin Pop
        return False
2650 a8083063 Iustin Pop
2651 a8083063 Iustin Pop
  if not force:
2652 a8083063 Iustin Pop
    return True
2653 a8083063 Iustin Pop
  cfg.SetDiskID(device, node)
2654 3f78eef2 Iustin Pop
  new_id = rpc.call_blockdev_create(node, device, device.size,
2655 3f78eef2 Iustin Pop
                                    instance.name, False, info)
2656 a8083063 Iustin Pop
  if not new_id:
2657 a8083063 Iustin Pop
    return False
2658 a8083063 Iustin Pop
  if device.physical_id is None:
2659 a8083063 Iustin Pop
    device.physical_id = new_id
2660 a8083063 Iustin Pop
  return True
2661 a8083063 Iustin Pop
2662 a8083063 Iustin Pop
2663 923b1523 Iustin Pop
def _GenerateUniqueNames(cfg, exts):
2664 923b1523 Iustin Pop
  """Generate a suitable LV name.
2665 923b1523 Iustin Pop

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

2668 923b1523 Iustin Pop
  """
2669 923b1523 Iustin Pop
  results = []
2670 923b1523 Iustin Pop
  for val in exts:
2671 923b1523 Iustin Pop
    new_id = cfg.GenerateUniqueID()
2672 923b1523 Iustin Pop
    results.append("%s%s" % (new_id, val))
2673 923b1523 Iustin Pop
  return results
2674 923b1523 Iustin Pop
2675 923b1523 Iustin Pop
2676 a1f445d3 Iustin Pop
def _GenerateDRBD8Branch(cfg, primary, secondary, size, names, iv_name):
2677 a1f445d3 Iustin Pop
  """Generate a drbd8 device complete with its children.
2678 a1f445d3 Iustin Pop

2679 a1f445d3 Iustin Pop
  """
2680 a1f445d3 Iustin Pop
  port = cfg.AllocatePort()
2681 a1f445d3 Iustin Pop
  vgname = cfg.GetVGName()
2682 a1f445d3 Iustin Pop
  dev_data = objects.Disk(dev_type=constants.LD_LV, size=size,
2683 a1f445d3 Iustin Pop
                          logical_id=(vgname, names[0]))
2684 a1f445d3 Iustin Pop
  dev_meta = objects.Disk(dev_type=constants.LD_LV, size=128,
2685 a1f445d3 Iustin Pop
                          logical_id=(vgname, names[1]))
2686 a1f445d3 Iustin Pop
  drbd_dev = objects.Disk(dev_type=constants.LD_DRBD8, size=size,
2687 a1f445d3 Iustin Pop
                          logical_id = (primary, secondary, port),
2688 a1f445d3 Iustin Pop
                          children = [dev_data, dev_meta],
2689 a1f445d3 Iustin Pop
                          iv_name=iv_name)
2690 a1f445d3 Iustin Pop
  return drbd_dev
2691 a1f445d3 Iustin Pop
2692 7c0d6283 Michael Hanselmann
2693 923b1523 Iustin Pop
def _GenerateDiskTemplate(cfg, template_name,
2694 a8083063 Iustin Pop
                          instance_name, primary_node,
2695 0f1a06e3 Manuel Franceschini
                          secondary_nodes, disk_sz, swap_sz,
2696 0f1a06e3 Manuel Franceschini
                          file_storage_dir, file_driver):
2697 a8083063 Iustin Pop
  """Generate the entire disk layout for a given template type.
2698 a8083063 Iustin Pop

2699 a8083063 Iustin Pop
  """
2700 a8083063 Iustin Pop
  #TODO: compute space requirements
2701 a8083063 Iustin Pop
2702 923b1523 Iustin Pop
  vgname = cfg.GetVGName()
2703 3517d9b9 Manuel Franceschini
  if template_name == constants.DT_DISKLESS:
2704 a8083063 Iustin Pop
    disks = []
2705 3517d9b9 Manuel Franceschini
  elif template_name == constants.DT_PLAIN:
2706 a8083063 Iustin Pop
    if len(secondary_nodes) != 0:
2707 a8083063 Iustin Pop
      raise errors.ProgrammerError("Wrong template configuration")
2708 923b1523 Iustin Pop
2709 923b1523 Iustin Pop
    names = _GenerateUniqueNames(cfg, [".sda", ".sdb"])
2710 fe96220b Iustin Pop
    sda_dev = objects.Disk(dev_type=constants.LD_LV, size=disk_sz,
2711 923b1523 Iustin Pop
                           logical_id=(vgname, names[0]),
2712 a8083063 Iustin Pop
                           iv_name = "sda")
2713 fe96220b Iustin Pop
    sdb_dev = objects.Disk(dev_type=constants.LD_LV, size=swap_sz,
2714 923b1523 Iustin Pop
                           logical_id=(vgname, names[1]),
2715 a8083063 Iustin Pop
                           iv_name = "sdb")
2716 a8083063 Iustin Pop
    disks = [sda_dev, sdb_dev]
2717 a1f445d3 Iustin Pop
  elif template_name == constants.DT_DRBD8:
2718 a1f445d3 Iustin Pop
    if len(secondary_nodes) != 1:
2719 a1f445d3 Iustin Pop
      raise errors.ProgrammerError("Wrong template configuration")
2720 a1f445d3 Iustin Pop
    remote_node = secondary_nodes[0]
2721 a1f445d3 Iustin Pop
    names = _GenerateUniqueNames(cfg, [".sda_data", ".sda_meta",
2722 a1f445d3 Iustin Pop
                                       ".sdb_data", ".sdb_meta"])
2723 a1f445d3 Iustin Pop
    drbd_sda_dev = _GenerateDRBD8Branch(cfg, primary_node, remote_node,
2724 a1f445d3 Iustin Pop
                                         disk_sz, names[0:2], "sda")
2725 a1f445d3 Iustin Pop
    drbd_sdb_dev = _GenerateDRBD8Branch(cfg, primary_node, remote_node,
2726 a1f445d3 Iustin Pop
                                         swap_sz, names[2:4], "sdb")
2727 a1f445d3 Iustin Pop
    disks = [drbd_sda_dev, drbd_sdb_dev]
2728 0f1a06e3 Manuel Franceschini
  elif template_name == constants.DT_FILE:
2729 0f1a06e3 Manuel Franceschini
    if len(secondary_nodes) != 0:
2730 0f1a06e3 Manuel Franceschini
      raise errors.ProgrammerError("Wrong template configuration")
2731 0f1a06e3 Manuel Franceschini
2732 0f1a06e3 Manuel Franceschini
    file_sda_dev = objects.Disk(dev_type=constants.LD_FILE, size=disk_sz,
2733 0f1a06e3 Manuel Franceschini
                                iv_name="sda", logical_id=(file_driver,
2734 0f1a06e3 Manuel Franceschini
                                "%s/sda" % file_storage_dir))
2735 0f1a06e3 Manuel Franceschini
    file_sdb_dev = objects.Disk(dev_type=constants.LD_FILE, size=swap_sz,
2736 0f1a06e3 Manuel Franceschini
                                iv_name="sdb", logical_id=(file_driver,
2737 0f1a06e3 Manuel Franceschini
                                "%s/sdb" % file_storage_dir))
2738 0f1a06e3 Manuel Franceschini
    disks = [file_sda_dev, file_sdb_dev]
2739 a8083063 Iustin Pop
  else:
2740 a8083063 Iustin Pop
    raise errors.ProgrammerError("Invalid disk template '%s'" % template_name)
2741 a8083063 Iustin Pop
  return disks
2742 a8083063 Iustin Pop
2743 a8083063 Iustin Pop
2744 a0c3fea1 Michael Hanselmann
def _GetInstanceInfoText(instance):
2745 3ecf6786 Iustin Pop
  """Compute that text that should be added to the disk's metadata.
2746 3ecf6786 Iustin Pop

2747 3ecf6786 Iustin Pop
  """
2748 a0c3fea1 Michael Hanselmann
  return "originstname+%s" % instance.name
2749 a0c3fea1 Michael Hanselmann
2750 a0c3fea1 Michael Hanselmann
2751 a8083063 Iustin Pop
def _CreateDisks(cfg, instance):
2752 a8083063 Iustin Pop
  """Create all disks for an instance.
2753 a8083063 Iustin Pop

2754 a8083063 Iustin Pop
  This abstracts away some work from AddInstance.
2755 a8083063 Iustin Pop

2756 a8083063 Iustin Pop
  Args:
2757 a8083063 Iustin Pop
    instance: the instance object
2758 a8083063 Iustin Pop

2759 a8083063 Iustin Pop
  Returns:
2760 a8083063 Iustin Pop
    True or False showing the success of the creation process
2761 a8083063 Iustin Pop

2762 a8083063 Iustin Pop
  """
2763 a0c3fea1 Michael Hanselmann
  info = _GetInstanceInfoText(instance)
2764 a0c3fea1 Michael Hanselmann
2765 0f1a06e3 Manuel Franceschini
  if instance.disk_template == constants.DT_FILE:
2766 0f1a06e3 Manuel Franceschini
    file_storage_dir = os.path.dirname(instance.disks[0].logical_id[1])
2767 0f1a06e3 Manuel Franceschini
    result = rpc.call_file_storage_dir_create(instance.primary_node,
2768 0f1a06e3 Manuel Franceschini
                                              file_storage_dir)
2769 0f1a06e3 Manuel Franceschini
2770 0f1a06e3 Manuel Franceschini
    if not result:
2771 b62ddbe5 Guido Trotter
      logger.Error("Could not connect to node '%s'" % instance.primary_node)
2772 0f1a06e3 Manuel Franceschini
      return False
2773 0f1a06e3 Manuel Franceschini
2774 0f1a06e3 Manuel Franceschini
    if not result[0]:
2775 0f1a06e3 Manuel Franceschini
      logger.Error("failed to create directory '%s'" % file_storage_dir)
2776 0f1a06e3 Manuel Franceschini
      return False
2777 0f1a06e3 Manuel Franceschini
2778 a8083063 Iustin Pop
  for device in instance.disks:
2779 a8083063 Iustin Pop
    logger.Info("creating volume %s for instance %s" %
2780 1c6e3627 Manuel Franceschini
                (device.iv_name, instance.name))
2781 a8083063 Iustin Pop
    #HARDCODE
2782 a8083063 Iustin Pop
    for secondary_node in instance.secondary_nodes:
2783 3f78eef2 Iustin Pop
      if not _CreateBlockDevOnSecondary(cfg, secondary_node, instance,
2784 3f78eef2 Iustin Pop
                                        device, False, info):
2785 a8083063 Iustin Pop
        logger.Error("failed to create volume %s (%s) on secondary node %s!" %
2786 a8083063 Iustin Pop
                     (device.iv_name, device, secondary_node))
2787 a8083063 Iustin Pop
        return False
2788 a8083063 Iustin Pop
    #HARDCODE
2789 3f78eef2 Iustin Pop
    if not _CreateBlockDevOnPrimary(cfg, instance.primary_node,
2790 3f78eef2 Iustin Pop
                                    instance, device, info):
2791 a8083063 Iustin Pop
      logger.Error("failed to create volume %s on primary!" %
2792 a8083063 Iustin Pop
                   device.iv_name)
2793 a8083063 Iustin Pop
      return False
2794 1c6e3627 Manuel Franceschini
2795 a8083063 Iustin Pop
  return True
2796 a8083063 Iustin Pop
2797 a8083063 Iustin Pop
2798 a8083063 Iustin Pop
def _RemoveDisks(instance, cfg):
2799 a8083063 Iustin Pop
  """Remove all disks for an instance.
2800 a8083063 Iustin Pop

2801 a8083063 Iustin Pop
  This abstracts away some work from `AddInstance()` and
2802 a8083063 Iustin Pop
  `RemoveInstance()`. Note that in case some of the devices couldn't
2803 1d67656e Iustin Pop
  be removed, the removal will continue with the other ones (compare
2804 a8083063 Iustin Pop
  with `_CreateDisks()`).
2805 a8083063 Iustin Pop

2806 a8083063 Iustin Pop
  Args:
2807 a8083063 Iustin Pop
    instance: the instance object
2808 a8083063 Iustin Pop

2809 a8083063 Iustin Pop
  Returns:
2810 a8083063 Iustin Pop
    True or False showing the success of the removal proces
2811 a8083063 Iustin Pop

2812 a8083063 Iustin Pop
  """
2813 a8083063 Iustin Pop
  logger.Info("removing block devices for instance %s" % instance.name)
2814 a8083063 Iustin Pop
2815 a8083063 Iustin Pop
  result = True
2816 a8083063 Iustin Pop
  for device in instance.disks:
2817 a8083063 Iustin Pop
    for node, disk in device.ComputeNodeTree(instance.primary_node):
2818 a8083063 Iustin Pop
      cfg.SetDiskID(disk, node)
2819 a8083063 Iustin Pop
      if not rpc.call_blockdev_remove(node, disk):
2820 a8083063 Iustin Pop
        logger.Error("could not remove block device %s on node %s,"
2821 a8083063 Iustin Pop
                     " continuing anyway" %
2822 a8083063 Iustin Pop
                     (device.iv_name, node))
2823 a8083063 Iustin Pop
        result = False
2824 0f1a06e3 Manuel Franceschini
2825 0f1a06e3 Manuel Franceschini
  if instance.disk_template == constants.DT_FILE:
2826 0f1a06e3 Manuel Franceschini
    file_storage_dir = os.path.dirname(instance.disks[0].logical_id[1])
2827 0f1a06e3 Manuel Franceschini
    if not rpc.call_file_storage_dir_remove(instance.primary_node,
2828 0f1a06e3 Manuel Franceschini
                                            file_storage_dir):
2829 0f1a06e3 Manuel Franceschini
      logger.Error("could not remove directory '%s'" % file_storage_dir)
2830 0f1a06e3 Manuel Franceschini
      result = False
2831 0f1a06e3 Manuel Franceschini
2832 a8083063 Iustin Pop
  return result
2833 a8083063 Iustin Pop
2834 a8083063 Iustin Pop
2835 e2fe6369 Iustin Pop
def _ComputeDiskSize(disk_template, disk_size, swap_size):
2836 e2fe6369 Iustin Pop
  """Compute disk size requirements in the volume group
2837 e2fe6369 Iustin Pop

2838 e2fe6369 Iustin Pop
  This is currently hard-coded for the two-drive layout.
2839 e2fe6369 Iustin Pop

2840 e2fe6369 Iustin Pop
  """
2841 e2fe6369 Iustin Pop
  # Required free disk space as a function of disk and swap space
2842 e2fe6369 Iustin Pop
  req_size_dict = {
2843 e2fe6369 Iustin Pop
    constants.DT_DISKLESS: None,
2844 e2fe6369 Iustin Pop
    constants.DT_PLAIN: disk_size + swap_size,
2845 e2fe6369 Iustin Pop
    # 256 MB are added for drbd metadata, 128MB for each drbd device
2846 e2fe6369 Iustin Pop
    constants.DT_DRBD8: disk_size + swap_size + 256,
2847 e2fe6369 Iustin Pop
    constants.DT_FILE: None,
2848 e2fe6369 Iustin Pop
  }
2849 e2fe6369 Iustin Pop
2850 e2fe6369 Iustin Pop
  if disk_template not in req_size_dict:
2851 e2fe6369 Iustin Pop
    raise errors.ProgrammerError("Disk template '%s' size requirement"
2852 e2fe6369 Iustin Pop
                                 " is unknown" %  disk_template)
2853 e2fe6369 Iustin Pop
2854 e2fe6369 Iustin Pop
  return req_size_dict[disk_template]
2855 e2fe6369 Iustin Pop
2856 e2fe6369 Iustin Pop
2857 a8083063 Iustin Pop
class LUCreateInstance(LogicalUnit):
2858 a8083063 Iustin Pop
  """Create an instance.
2859 a8083063 Iustin Pop

2860 a8083063 Iustin Pop
  """
2861 a8083063 Iustin Pop
  HPATH = "instance-add"
2862 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
2863 538475ca Iustin Pop
  _OP_REQP = ["instance_name", "mem_size", "disk_size",
2864 a8083063 Iustin Pop
              "disk_template", "swap_size", "mode", "start", "vcpus",
2865 1862d460 Alexander Schreiber
              "wait_for_sync", "ip_check", "mac"]
2866 a8083063 Iustin Pop
2867 538475ca Iustin Pop
  def _RunAllocator(self):
2868 538475ca Iustin Pop
    """Run the allocator based on input opcode.
2869 538475ca Iustin Pop

2870 538475ca Iustin Pop
    """
2871 538475ca Iustin Pop
    disks = [{"size": self.op.disk_size, "mode": "w"},
2872 538475ca Iustin Pop
             {"size": self.op.swap_size, "mode": "w"}]
2873 538475ca Iustin Pop
    nics = [{"mac": self.op.mac, "ip": getattr(self.op, "ip", None),
2874 538475ca Iustin Pop
             "bridge": self.op.bridge}]
2875 d1c2dd75 Iustin Pop
    ial = IAllocator(self.cfg, self.sstore,
2876 29859cb7 Iustin Pop
                     mode=constants.IALLOCATOR_MODE_ALLOC,
2877 d1c2dd75 Iustin Pop
                     name=self.op.instance_name,
2878 d1c2dd75 Iustin Pop
                     disk_template=self.op.disk_template,
2879 d1c2dd75 Iustin Pop
                     tags=[],
2880 d1c2dd75 Iustin Pop
                     os=self.op.os_type,
2881 d1c2dd75 Iustin Pop
                     vcpus=self.op.vcpus,
2882 d1c2dd75 Iustin Pop
                     mem_size=self.op.mem_size,
2883 d1c2dd75 Iustin Pop
                     disks=disks,
2884 d1c2dd75 Iustin Pop
                     nics=nics,
2885 29859cb7 Iustin Pop
                     )
2886 d1c2dd75 Iustin Pop
2887 d1c2dd75 Iustin Pop
    ial.Run(self.op.iallocator)
2888 d1c2dd75 Iustin Pop
2889 d1c2dd75 Iustin Pop
    if not ial.success:
2890 538475ca Iustin Pop
      raise errors.OpPrereqError("Can't compute nodes using"
2891 538475ca Iustin Pop
                                 " iallocator '%s': %s" % (self.op.iallocator,
2892 d1c2dd75 Iustin Pop
                                                           ial.info))
2893 27579978 Iustin Pop
    if len(ial.nodes) != ial.required_nodes:
2894 538475ca Iustin Pop
      raise errors.OpPrereqError("iallocator '%s' returned invalid number"
2895 538475ca Iustin Pop
                                 " of nodes (%s), required %s" %
2896 27579978 Iustin Pop
                                 (len(ial.nodes), ial.required_nodes))
2897 d1c2dd75 Iustin Pop
    self.op.pnode = ial.nodes[0]
2898 538475ca Iustin Pop
    logger.ToStdout("Selected nodes for the instance: %s" %
2899 d1c2dd75 Iustin Pop
                    (", ".join(ial.nodes),))
2900 538475ca Iustin Pop
    logger.Info("Selected nodes for instance %s via iallocator %s: %s" %
2901 d1c2dd75 Iustin Pop
                (self.op.instance_name, self.op.iallocator, ial.nodes))
2902 27579978 Iustin Pop
    if ial.required_nodes == 2:
2903 d1c2dd75 Iustin Pop
      self.op.snode = ial.nodes[1]
2904 538475ca Iustin Pop
2905 a8083063 Iustin Pop
  def BuildHooksEnv(self):
2906 a8083063 Iustin Pop
    """Build hooks env.
2907 a8083063 Iustin Pop

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

2910 a8083063 Iustin Pop
    """
2911 a8083063 Iustin Pop
    env = {
2912 396e1b78 Michael Hanselmann
      "INSTANCE_DISK_TEMPLATE": self.op.disk_template,
2913 396e1b78 Michael Hanselmann
      "INSTANCE_DISK_SIZE": self.op.disk_size,
2914 396e1b78 Michael Hanselmann
      "INSTANCE_SWAP_SIZE": self.op.swap_size,
2915 a8083063 Iustin Pop
      "INSTANCE_ADD_MODE": self.op.mode,
2916 a8083063 Iustin Pop
      }
2917 a8083063 Iustin Pop
    if self.op.mode == constants.INSTANCE_IMPORT:
2918 396e1b78 Michael Hanselmann
      env["INSTANCE_SRC_NODE"] = self.op.src_node
2919 396e1b78 Michael Hanselmann
      env["INSTANCE_SRC_PATH"] = self.op.src_path
2920 396e1b78 Michael Hanselmann
      env["INSTANCE_SRC_IMAGE"] = self.src_image
2921 396e1b78 Michael Hanselmann
2922 396e1b78 Michael Hanselmann
    env.update(_BuildInstanceHookEnv(name=self.op.instance_name,
2923 396e1b78 Michael Hanselmann
      primary_node=self.op.pnode,
2924 396e1b78 Michael Hanselmann
      secondary_nodes=self.secondaries,
2925 396e1b78 Michael Hanselmann
      status=self.instance_status,
2926 ecb215b5 Michael Hanselmann
      os_type=self.op.os_type,
2927 396e1b78 Michael Hanselmann
      memory=self.op.mem_size,
2928 396e1b78 Michael Hanselmann
      vcpus=self.op.vcpus,
2929 c7b27e9e Iustin Pop
      nics=[(self.inst_ip, self.op.bridge, self.op.mac)],
2930 396e1b78 Michael Hanselmann
    ))
2931 a8083063 Iustin Pop
2932 880478f8 Iustin Pop
    nl = ([self.sstore.GetMasterNode(), self.op.pnode] +
2933 a8083063 Iustin Pop
          self.secondaries)
2934 a8083063 Iustin Pop
    return env, nl, nl
2935 a8083063 Iustin Pop
2936 a8083063 Iustin Pop
2937 a8083063 Iustin Pop
  def CheckPrereq(self):
2938 a8083063 Iustin Pop
    """Check prerequisites.
2939 a8083063 Iustin Pop

2940 a8083063 Iustin Pop
    """
2941 538475ca Iustin Pop
    # set optional parameters to none if they don't exist
2942 538475ca Iustin Pop
    for attr in ["kernel_path", "initrd_path", "hvm_boot_order", "pnode",
2943 31a853d2 Iustin Pop
                 "iallocator", "hvm_acpi", "hvm_pae", "hvm_cdrom_image_path",
2944 31a853d2 Iustin Pop
                 "vnc_bind_address"]:
2945 40ed12dd Guido Trotter
      if not hasattr(self.op, attr):
2946 40ed12dd Guido Trotter
        setattr(self.op, attr, None)
2947 40ed12dd Guido Trotter
2948 a8083063 Iustin Pop
    if self.op.mode not in (constants.INSTANCE_CREATE,
2949 a8083063 Iustin Pop
                            constants.INSTANCE_IMPORT):
2950 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Invalid instance creation mode '%s'" %
2951 3ecf6786 Iustin Pop
                                 self.op.mode)
2952 a8083063 Iustin Pop
2953 eedc99de Manuel Franceschini
    if (not self.cfg.GetVGName() and
2954 eedc99de Manuel Franceschini
        self.op.disk_template not in constants.DTS_NOT_LVM):
2955 eedc99de Manuel Franceschini
      raise errors.OpPrereqError("Cluster does not support lvm-based"
2956 eedc99de Manuel Franceschini
                                 " instances")
2957 eedc99de Manuel Franceschini
2958 a8083063 Iustin Pop
    if self.op.mode == constants.INSTANCE_IMPORT:
2959 a8083063 Iustin Pop
      src_node = getattr(self.op, "src_node", None)
2960 a8083063 Iustin Pop
      src_path = getattr(self.op, "src_path", None)
2961 a8083063 Iustin Pop
      if src_node is None or src_path is None:
2962 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Importing an instance requires source"
2963 3ecf6786 Iustin Pop
                                   " node and path options")
2964 a8083063 Iustin Pop
      src_node_full = self.cfg.ExpandNodeName(src_node)
2965 a8083063 Iustin Pop
      if src_node_full is None:
2966 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Unknown source node '%s'" % src_node)
2967 a8083063 Iustin Pop
      self.op.src_node = src_node = src_node_full
2968 a8083063 Iustin Pop
2969 a8083063 Iustin Pop
      if not os.path.isabs(src_path):
2970 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("The source path must be absolute")
2971 a8083063 Iustin Pop
2972 a8083063 Iustin Pop
      export_info = rpc.call_export_info(src_node, src_path)
2973 a8083063 Iustin Pop
2974 a8083063 Iustin Pop
      if not export_info:
2975 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("No export found in dir %s" % src_path)
2976 a8083063 Iustin Pop
2977 a8083063 Iustin Pop
      if not export_info.has_section(constants.INISECT_EXP):
2978 3ecf6786 Iustin Pop
        raise errors.ProgrammerError("Corrupted export config")
2979 a8083063 Iustin Pop
2980 a8083063 Iustin Pop
      ei_version = export_info.get(constants.INISECT_EXP, 'version')
2981 a8083063 Iustin Pop
      if (int(ei_version) != constants.EXPORT_VERSION):
2982 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Wrong export version %s (wanted %d)" %
2983 3ecf6786 Iustin Pop
                                   (ei_version, constants.EXPORT_VERSION))
2984 a8083063 Iustin Pop
2985 a8083063 Iustin Pop
      if int(export_info.get(constants.INISECT_INS, 'disk_count')) > 1:
2986 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Can't import instance with more than"
2987 3ecf6786 Iustin Pop
                                   " one data disk")
2988 a8083063 Iustin Pop
2989 a8083063 Iustin Pop
      # FIXME: are the old os-es, disk sizes, etc. useful?
2990 a8083063 Iustin Pop
      self.op.os_type = export_info.get(constants.INISECT_EXP, 'os')
2991 a8083063 Iustin Pop
      diskimage = os.path.join(src_path, export_info.get(constants.INISECT_INS,
2992 a8083063 Iustin Pop
                                                         'disk0_dump'))
2993 a8083063 Iustin Pop
      self.src_image = diskimage
2994 a8083063 Iustin Pop
    else: # INSTANCE_CREATE
2995 a8083063 Iustin Pop
      if getattr(self.op, "os_type", None) is None:
2996 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("No guest OS specified")
2997 a8083063 Iustin Pop
2998 901a65c1 Iustin Pop
    #### instance parameters check
2999 901a65c1 Iustin Pop
3000 a8083063 Iustin Pop
    # disk template and mirror node verification
3001 a8083063 Iustin Pop
    if self.op.disk_template not in constants.DISK_TEMPLATES:
3002 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Invalid disk template name")
3003 a8083063 Iustin Pop
3004 901a65c1 Iustin Pop
    # instance name verification
3005 901a65c1 Iustin Pop
    hostname1 = utils.HostInfo(self.op.instance_name)
3006 901a65c1 Iustin Pop
3007 901a65c1 Iustin Pop
    self.op.instance_name = instance_name = hostname1.name
3008 901a65c1 Iustin Pop
    instance_list = self.cfg.GetInstanceList()
3009 901a65c1 Iustin Pop
    if instance_name in instance_list:
3010 901a65c1 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' is already in the cluster" %
3011 901a65c1 Iustin Pop
                                 instance_name)
3012 901a65c1 Iustin Pop
3013 901a65c1 Iustin Pop
    # ip validity checks
3014 901a65c1 Iustin Pop
    ip = getattr(self.op, "ip", None)
3015 901a65c1 Iustin Pop
    if ip is None or ip.lower() == "none":
3016 901a65c1 Iustin Pop
      inst_ip = None
3017 901a65c1 Iustin Pop
    elif ip.lower() == "auto":
3018 901a65c1 Iustin Pop
      inst_ip = hostname1.ip
3019 901a65c1 Iustin Pop
    else:
3020 901a65c1 Iustin Pop
      if not utils.IsValidIP(ip):
3021 901a65c1 Iustin Pop
        raise errors.OpPrereqError("given IP address '%s' doesn't look"
3022 901a65c1 Iustin Pop
                                   " like a valid IP" % ip)
3023 901a65c1 Iustin Pop
      inst_ip = ip
3024 901a65c1 Iustin Pop
    self.inst_ip = self.op.ip = inst_ip
3025 901a65c1 Iustin Pop
3026 901a65c1 Iustin Pop
    if self.op.start and not self.op.ip_check:
3027 901a65c1 Iustin Pop
      raise errors.OpPrereqError("Cannot ignore IP address conflicts when"
3028 901a65c1 Iustin Pop
                                 " adding an instance in start mode")
3029 901a65c1 Iustin Pop
3030 901a65c1 Iustin Pop
    if self.op.ip_check:
3031 901a65c1 Iustin Pop
      if utils.TcpPing(hostname1.ip, constants.DEFAULT_NODED_PORT):
3032 901a65c1 Iustin Pop
        raise errors.OpPrereqError("IP %s of instance %s already in use" %
3033 901a65c1 Iustin Pop
                                   (hostname1.ip, instance_name))
3034 901a65c1 Iustin Pop
3035 901a65c1 Iustin Pop
    # MAC address verification
3036 901a65c1 Iustin Pop
    if self.op.mac != "auto":
3037 901a65c1 Iustin Pop
      if not utils.IsValidMac(self.op.mac.lower()):
3038 901a65c1 Iustin Pop
        raise errors.OpPrereqError("invalid MAC address specified: %s" %
3039 901a65c1 Iustin Pop
                                   self.op.mac)
3040 901a65c1 Iustin Pop
3041 901a65c1 Iustin Pop
    # bridge verification
3042 901a65c1 Iustin Pop
    bridge = getattr(self.op, "bridge", None)
3043 901a65c1 Iustin Pop
    if bridge is None:
3044 901a65c1 Iustin Pop
      self.op.bridge = self.cfg.GetDefBridge()
3045 901a65c1 Iustin Pop
    else:
3046 901a65c1 Iustin Pop
      self.op.bridge = bridge
3047 901a65c1 Iustin Pop
3048 901a65c1 Iustin Pop
    # boot order verification
3049 901a65c1 Iustin Pop
    if self.op.hvm_boot_order is not None:
3050 901a65c1 Iustin Pop
      if len(self.op.hvm_boot_order.strip("acdn")) != 0:
3051 901a65c1 Iustin Pop
        raise errors.OpPrereqError("invalid boot order specified,"
3052 901a65c1 Iustin Pop
                                   " must be one or more of [acdn]")
3053 901a65c1 Iustin Pop
    # file storage checks
3054 0f1a06e3 Manuel Franceschini
    if (self.op.file_driver and
3055 0f1a06e3 Manuel Franceschini
        not self.op.file_driver in constants.FILE_DRIVER):
3056 0f1a06e3 Manuel Franceschini
      raise errors.OpPrereqError("Invalid file driver name '%s'" %
3057 0f1a06e3 Manuel Franceschini
                                 self.op.file_driver)
3058 0f1a06e3 Manuel Franceschini
3059 0f1a06e3 Manuel Franceschini
    if self.op.file_storage_dir and os.path.isabs(self.op.file_storage_dir):
3060 b4de68a9 Iustin Pop
      raise errors.OpPrereqError("File storage directory not a relative"
3061 b4de68a9 Iustin Pop
                                 " path")
3062 538475ca Iustin Pop
    #### allocator run
3063 538475ca Iustin Pop
3064 538475ca Iustin Pop
    if [self.op.iallocator, self.op.pnode].count(None) != 1:
3065 538475ca Iustin Pop
      raise errors.OpPrereqError("One and only one of iallocator and primary"
3066 538475ca Iustin Pop
                                 " node must be given")
3067 538475ca Iustin Pop
3068 538475ca Iustin Pop
    if self.op.iallocator is not None:
3069 538475ca Iustin Pop
      self._RunAllocator()
3070 0f1a06e3 Manuel Franceschini
3071 901a65c1 Iustin Pop
    #### node related checks
3072 901a65c1 Iustin Pop
3073 901a65c1 Iustin Pop
    # check primary node
3074 901a65c1 Iustin Pop
    pnode = self.cfg.GetNodeInfo(self.cfg.ExpandNodeName(self.op.pnode))
3075 901a65c1 Iustin Pop
    if pnode is None:
3076 901a65c1 Iustin Pop
      raise errors.OpPrereqError("Primary node '%s' is unknown" %
3077 901a65c1 Iustin Pop
                                 self.op.pnode)
3078 901a65c1 Iustin Pop
    self.op.pnode = pnode.name
3079 901a65c1 Iustin Pop
    self.pnode = pnode
3080 901a65c1 Iustin Pop
    self.secondaries = []
3081 901a65c1 Iustin Pop
3082 901a65c1 Iustin Pop
    # mirror node verification
3083 a1f445d3 Iustin Pop
    if self.op.disk_template in constants.DTS_NET_MIRROR:
3084 a8083063 Iustin Pop
      if getattr(self.op, "snode", None) is None:
3085 a1f445d3 Iustin Pop
        raise errors.OpPrereqError("The networked disk templates need"
3086 3ecf6786 Iustin Pop
                                   " a mirror node")
3087 a8083063 Iustin Pop
3088 a8083063 Iustin Pop
      snode_name = self.cfg.ExpandNodeName(self.op.snode)
3089 a8083063 Iustin Pop
      if snode_name is None:
3090 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Unknown secondary node '%s'" %
3091 3ecf6786 Iustin Pop
                                   self.op.snode)
3092 a8083063 Iustin Pop
      elif snode_name == pnode.name:
3093 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("The secondary node cannot be"
3094 3ecf6786 Iustin Pop
                                   " the primary node.")
3095 a8083063 Iustin Pop
      self.secondaries.append(snode_name)
3096 a8083063 Iustin Pop
3097 e2fe6369 Iustin Pop
    req_size = _ComputeDiskSize(self.op.disk_template,
3098 e2fe6369 Iustin Pop
                                self.op.disk_size, self.op.swap_size)
3099 ed1ebc60 Guido Trotter
3100 8d75db10 Iustin Pop
    # Check lv size requirements
3101 8d75db10 Iustin Pop
    if req_size is not None:
3102 8d75db10 Iustin Pop
      nodenames = [pnode.name] + self.secondaries
3103 8d75db10 Iustin Pop
      nodeinfo = rpc.call_node_info(nodenames, self.cfg.GetVGName())
3104 8d75db10 Iustin Pop
      for node in nodenames:
3105 8d75db10 Iustin Pop
        info = nodeinfo.get(node, None)
3106 8d75db10 Iustin Pop
        if not info:
3107 8d75db10 Iustin Pop
          raise errors.OpPrereqError("Cannot get current information"
3108 3e91897b Iustin Pop
                                     " from node '%s'" % node)
3109 8d75db10 Iustin Pop
        vg_free = info.get('vg_free', None)
3110 8d75db10 Iustin Pop
        if not isinstance(vg_free, int):
3111 8d75db10 Iustin Pop
          raise errors.OpPrereqError("Can't compute free disk space on"
3112 8d75db10 Iustin Pop
                                     " node %s" % node)
3113 8d75db10 Iustin Pop
        if req_size > info['vg_free']:
3114 8d75db10 Iustin Pop
          raise errors.OpPrereqError("Not enough disk space on target node %s."
3115 8d75db10 Iustin Pop
                                     " %d MB available, %d MB required" %
3116 8d75db10 Iustin Pop
                                     (node, info['vg_free'], req_size))
3117 ed1ebc60 Guido Trotter
3118 a8083063 Iustin Pop
    # os verification
3119 00fe9e38 Guido Trotter
    os_obj = rpc.call_os_get(pnode.name, self.op.os_type)
3120 dfa96ded Guido Trotter
    if not os_obj:
3121 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("OS '%s' not in supported os list for"
3122 3ecf6786 Iustin Pop
                                 " primary node"  % self.op.os_type)
3123 a8083063 Iustin Pop
3124 3b6d8c9b Iustin Pop
    if self.op.kernel_path == constants.VALUE_NONE:
3125 3b6d8c9b Iustin Pop
      raise errors.OpPrereqError("Can't set instance kernel to none")
3126 3b6d8c9b Iustin Pop
3127 a8083063 Iustin Pop
3128 901a65c1 Iustin Pop
    # bridge check on primary node
3129 a8083063 Iustin Pop
    if not rpc.call_bridges_exist(self.pnode.name, [self.op.bridge]):
3130 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("target bridge '%s' does not exist on"
3131 3ecf6786 Iustin Pop
                                 " destination node '%s'" %
3132 3ecf6786 Iustin Pop
                                 (self.op.bridge, pnode.name))
3133 a8083063 Iustin Pop
3134 49ce1563 Iustin Pop
    # memory check on primary node
3135 49ce1563 Iustin Pop
    if self.op.start:
3136 49ce1563 Iustin Pop
      _CheckNodeFreeMemory(self.cfg, self.pnode.name,
3137 49ce1563 Iustin Pop
                           "creating instance %s" % self.op.instance_name,
3138 49ce1563 Iustin Pop
                           self.op.mem_size)
3139 49ce1563 Iustin Pop
3140 31a853d2 Iustin Pop
    # hvm_cdrom_image_path verification
3141 31a853d2 Iustin Pop
    if self.op.hvm_cdrom_image_path is not None:
3142 31a853d2 Iustin Pop
      if not os.path.isabs(self.op.hvm_cdrom_image_path):
3143 31a853d2 Iustin Pop
        raise errors.OpPrereqError("The path to the HVM CDROM image must"
3144 31a853d2 Iustin Pop
                                   " be an absolute path or None, not %s" %
3145 31a853d2 Iustin Pop
                                   self.op.hvm_cdrom_image_path)
3146 31a853d2 Iustin Pop
      if not os.path.isfile(self.op.hvm_cdrom_image_path):
3147 31a853d2 Iustin Pop
        raise errors.OpPrereqError("The HVM CDROM image must either be a"
3148 31a853d2 Iustin Pop
                                   " regular file or a symlink pointing to"
3149 31a853d2 Iustin Pop
                                   " an existing regular file, not %s" %
3150 31a853d2 Iustin Pop
                                   self.op.hvm_cdrom_image_path)
3151 31a853d2 Iustin Pop
3152 31a853d2 Iustin Pop
    # vnc_bind_address verification
3153 31a853d2 Iustin Pop
    if self.op.vnc_bind_address is not None:
3154 31a853d2 Iustin Pop
      if not utils.IsValidIP(self.op.vnc_bind_address):
3155 31a853d2 Iustin Pop
        raise errors.OpPrereqError("given VNC bind address '%s' doesn't look"
3156 31a853d2 Iustin Pop
                                   " like a valid IP address" %
3157 31a853d2 Iustin Pop
                                   self.op.vnc_bind_address)
3158 31a853d2 Iustin Pop
3159 a8083063 Iustin Pop
    if self.op.start:
3160 a8083063 Iustin Pop
      self.instance_status = 'up'
3161 a8083063 Iustin Pop
    else:
3162 a8083063 Iustin Pop
      self.instance_status = 'down'
3163 a8083063 Iustin Pop
3164 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
3165 a8083063 Iustin Pop
    """Create and add the instance to the cluster.
3166 a8083063 Iustin Pop

3167 a8083063 Iustin Pop
    """
3168 a8083063 Iustin Pop
    instance = self.op.instance_name
3169 a8083063 Iustin Pop
    pnode_name = self.pnode.name
3170 a8083063 Iustin Pop
3171 1862d460 Alexander Schreiber
    if self.op.mac == "auto":
3172 ba4b62cf Iustin Pop
      mac_address = self.cfg.GenerateMAC()
3173 1862d460 Alexander Schreiber
    else:
3174 ba4b62cf Iustin Pop
      mac_address = self.op.mac
3175 1862d460 Alexander Schreiber
3176 1862d460 Alexander Schreiber
    nic = objects.NIC(bridge=self.op.bridge, mac=mac_address)
3177 a8083063 Iustin Pop
    if self.inst_ip is not None:
3178 a8083063 Iustin Pop
      nic.ip = self.inst_ip
3179 a8083063 Iustin Pop
3180 2a6469d5 Alexander Schreiber
    ht_kind = self.sstore.GetHypervisorType()
3181 2a6469d5 Alexander Schreiber
    if ht_kind in constants.HTS_REQ_PORT:
3182 2a6469d5 Alexander Schreiber
      network_port = self.cfg.AllocatePort()
3183 2a6469d5 Alexander Schreiber
    else:
3184 2a6469d5 Alexander Schreiber
      network_port = None
3185 58acb49d Alexander Schreiber
3186 31a853d2 Iustin Pop
    if self.op.vnc_bind_address is None:
3187 31a853d2 Iustin Pop
      self.op.vnc_bind_address = constants.VNC_DEFAULT_BIND_ADDRESS
3188 31a853d2 Iustin Pop
3189 2c313123 Manuel Franceschini
    # this is needed because os.path.join does not accept None arguments
3190 2c313123 Manuel Franceschini
    if self.op.file_storage_dir is None:
3191 2c313123 Manuel Franceschini
      string_file_storage_dir = ""
3192 2c313123 Manuel Franceschini
    else:
3193 2c313123 Manuel Franceschini
      string_file_storage_dir = self.op.file_storage_dir
3194 2c313123 Manuel Franceschini
3195 0f1a06e3 Manuel Franceschini
    # build the full file storage dir path
3196 0f1a06e3 Manuel Franceschini
    file_storage_dir = os.path.normpath(os.path.join(
3197 0f1a06e3 Manuel Franceschini
                                        self.sstore.GetFileStorageDir(),
3198 2c313123 Manuel Franceschini
                                        string_file_storage_dir, instance))
3199 0f1a06e3 Manuel Franceschini
3200 0f1a06e3 Manuel Franceschini
3201 923b1523 Iustin Pop
    disks = _GenerateDiskTemplate(self.cfg,
3202 a8083063 Iustin Pop
                                  self.op.disk_template,
3203 a8083063 Iustin Pop
                                  instance, pnode_name,
3204 a8083063 Iustin Pop
                                  self.secondaries, self.op.disk_size,
3205 0f1a06e3 Manuel Franceschini
                                  self.op.swap_size,
3206 0f1a06e3 Manuel Franceschini
                                  file_storage_dir,
3207 0f1a06e3 Manuel Franceschini
                                  self.op.file_driver)
3208 a8083063 Iustin Pop
3209 a8083063 Iustin Pop
    iobj = objects.Instance(name=instance, os=self.op.os_type,
3210 a8083063 Iustin Pop
                            primary_node=pnode_name,
3211 a8083063 Iustin Pop
                            memory=self.op.mem_size,
3212 a8083063 Iustin Pop
                            vcpus=self.op.vcpus,
3213 a8083063 Iustin Pop
                            nics=[nic], disks=disks,
3214 a8083063 Iustin Pop
                            disk_template=self.op.disk_template,
3215 a8083063 Iustin Pop
                            status=self.instance_status,
3216 58acb49d Alexander Schreiber
                            network_port=network_port,
3217 3b6d8c9b Iustin Pop
                            kernel_path=self.op.kernel_path,
3218 3b6d8c9b Iustin Pop
                            initrd_path=self.op.initrd_path,
3219 25c5878d Alexander Schreiber
                            hvm_boot_order=self.op.hvm_boot_order,
3220 31a853d2 Iustin Pop
                            hvm_acpi=self.op.hvm_acpi,
3221 31a853d2 Iustin Pop
                            hvm_pae=self.op.hvm_pae,
3222 31a853d2 Iustin Pop
                            hvm_cdrom_image_path=self.op.hvm_cdrom_image_path,
3223 31a853d2 Iustin Pop
                            vnc_bind_address=self.op.vnc_bind_address,
3224 a8083063 Iustin Pop
                            )
3225 a8083063 Iustin Pop
3226 a8083063 Iustin Pop
    feedback_fn("* creating instance disks...")
3227 a8083063 Iustin Pop
    if not _CreateDisks(self.cfg, iobj):
3228 a8083063 Iustin Pop
      _RemoveDisks(iobj, self.cfg)
3229 3ecf6786 Iustin Pop
      raise errors.OpExecError("Device creation failed, reverting...")
3230 a8083063 Iustin Pop
3231 a8083063 Iustin Pop
    feedback_fn("adding instance %s to cluster config" % instance)
3232 a8083063 Iustin Pop
3233 a8083063 Iustin Pop
    self.cfg.AddInstance(iobj)
3234 a2fd9afc Guido Trotter
    # Add the new instance to the Ganeti Lock Manager
3235 a2fd9afc Guido Trotter
    self.context.glm.add(locking.LEVEL_INSTANCE, instance)
3236 a8083063 Iustin Pop
3237 a8083063 Iustin Pop
    if self.op.wait_for_sync:
3238 5bfac263 Iustin Pop
      disk_abort = not _WaitForSync(self.cfg, iobj, self.proc)
3239 a1f445d3 Iustin Pop
    elif iobj.disk_template in constants.DTS_NET_MIRROR:
3240 a8083063 Iustin Pop
      # make sure the disks are not degraded (still sync-ing is ok)
3241 a8083063 Iustin Pop
      time.sleep(15)
3242 a8083063 Iustin Pop
      feedback_fn("* checking mirrors status")
3243 5bfac263 Iustin Pop
      disk_abort = not _WaitForSync(self.cfg, iobj, self.proc, oneshot=True)
3244 a8083063 Iustin Pop
    else:
3245 a8083063 Iustin Pop
      disk_abort = False
3246 a8083063 Iustin Pop
3247 a8083063 Iustin Pop
    if disk_abort:
3248 a8083063 Iustin Pop
      _RemoveDisks(iobj, self.cfg)
3249 a8083063 Iustin Pop
      self.cfg.RemoveInstance(iobj.name)
3250 a2fd9afc Guido Trotter
      # Remove the new instance from the Ganeti Lock Manager
3251 a2fd9afc Guido Trotter
      self.context.glm.remove(locking.LEVEL_INSTANCE, iobj.name)
3252 3ecf6786 Iustin Pop
      raise errors.OpExecError("There are some degraded disks for"
3253 3ecf6786 Iustin Pop
                               " this instance")
3254 a8083063 Iustin Pop
3255 a8083063 Iustin Pop
    feedback_fn("creating os for instance %s on node %s" %
3256 a8083063 Iustin Pop
                (instance, pnode_name))
3257 a8083063 Iustin Pop
3258 a8083063 Iustin Pop
    if iobj.disk_template != constants.DT_DISKLESS:
3259 a8083063 Iustin Pop
      if self.op.mode == constants.INSTANCE_CREATE:
3260 a8083063 Iustin Pop
        feedback_fn("* running the instance OS create scripts...")
3261 a8083063 Iustin Pop
        if not rpc.call_instance_os_add(pnode_name, iobj, "sda", "sdb"):
3262 3ecf6786 Iustin Pop
          raise errors.OpExecError("could not add os for instance %s"
3263 3ecf6786 Iustin Pop
                                   " on node %s" %
3264 3ecf6786 Iustin Pop
                                   (instance, pnode_name))
3265 a8083063 Iustin Pop
3266 a8083063 Iustin Pop
      elif self.op.mode == constants.INSTANCE_IMPORT:
3267 a8083063 Iustin Pop
        feedback_fn("* running the instance OS import scripts...")
3268 a8083063 Iustin Pop
        src_node = self.op.src_node
3269 a8083063 Iustin Pop
        src_image = self.src_image
3270 a8083063 Iustin Pop
        if not rpc.call_instance_os_import(pnode_name, iobj, "sda", "sdb",
3271 a8083063 Iustin Pop
                                                src_node, src_image):
3272 3ecf6786 Iustin Pop
          raise errors.OpExecError("Could not import os for instance"
3273 3ecf6786 Iustin Pop
                                   " %s on node %s" %
3274 3ecf6786 Iustin Pop
                                   (instance, pnode_name))
3275 a8083063 Iustin Pop
      else:
3276 a8083063 Iustin Pop
        # also checked in the prereq part
3277 3ecf6786 Iustin Pop
        raise errors.ProgrammerError("Unknown OS initialization mode '%s'"
3278 3ecf6786 Iustin Pop
                                     % self.op.mode)
3279 a8083063 Iustin Pop
3280 a8083063 Iustin Pop
    if self.op.start:
3281 a8083063 Iustin Pop
      logger.Info("starting instance %s on node %s" % (instance, pnode_name))
3282 a8083063 Iustin Pop
      feedback_fn("* starting instance...")
3283 a8083063 Iustin Pop
      if not rpc.call_instance_start(pnode_name, iobj, None):
3284 3ecf6786 Iustin Pop
        raise errors.OpExecError("Could not start instance")
3285 a8083063 Iustin Pop
3286 a8083063 Iustin Pop
3287 a8083063 Iustin Pop
class LUConnectConsole(NoHooksLU):
3288 a8083063 Iustin Pop
  """Connect to an instance's console.
3289 a8083063 Iustin Pop

3290 a8083063 Iustin Pop
  This is somewhat special in that it returns the command line that
3291 a8083063 Iustin Pop
  you need to run on the master node in order to connect to the
3292 a8083063 Iustin Pop
  console.
3293 a8083063 Iustin Pop

3294 a8083063 Iustin Pop
  """
3295 a8083063 Iustin Pop
  _OP_REQP = ["instance_name"]
3296 a8083063 Iustin Pop
3297 a8083063 Iustin Pop
  def CheckPrereq(self):
3298 a8083063 Iustin Pop
    """Check prerequisites.
3299 a8083063 Iustin Pop

3300 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
3301 a8083063 Iustin Pop

3302 a8083063 Iustin Pop
    """
3303 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
3304 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
3305 a8083063 Iustin Pop
    if instance is None:
3306 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
3307 3ecf6786 Iustin Pop
                                 self.op.instance_name)
3308 a8083063 Iustin Pop
    self.instance = instance
3309 a8083063 Iustin Pop
3310 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
3311 a8083063 Iustin Pop
    """Connect to the console of an instance
3312 a8083063 Iustin Pop

3313 a8083063 Iustin Pop
    """
3314 a8083063 Iustin Pop
    instance = self.instance
3315 a8083063 Iustin Pop
    node = instance.primary_node
3316 a8083063 Iustin Pop
3317 a8083063 Iustin Pop
    node_insts = rpc.call_instance_list([node])[node]
3318 a8083063 Iustin Pop
    if node_insts is False:
3319 3ecf6786 Iustin Pop
      raise errors.OpExecError("Can't connect to node %s." % node)
3320 a8083063 Iustin Pop
3321 a8083063 Iustin Pop
    if instance.name not in node_insts:
3322 3ecf6786 Iustin Pop
      raise errors.OpExecError("Instance %s is not running." % instance.name)
3323 a8083063 Iustin Pop
3324 a8083063 Iustin Pop
    logger.Debug("connecting to console of %s on %s" % (instance.name, node))
3325 a8083063 Iustin Pop
3326 a8083063 Iustin Pop
    hyper = hypervisor.GetHypervisor()
3327 30989e69 Alexander Schreiber
    console_cmd = hyper.GetShellCommandForConsole(instance)
3328 b047857b Michael Hanselmann
3329 82122173 Iustin Pop
    # build ssh cmdline
3330 0a80a26f Michael Hanselmann
    return self.ssh.BuildCmd(node, "root", console_cmd, batch=True, tty=True)
3331 a8083063 Iustin Pop
3332 a8083063 Iustin Pop
3333 a8083063 Iustin Pop
class LUReplaceDisks(LogicalUnit):
3334 a8083063 Iustin Pop
  """Replace the disks of an instance.
3335 a8083063 Iustin Pop

3336 a8083063 Iustin Pop
  """
3337 a8083063 Iustin Pop
  HPATH = "mirrors-replace"
3338 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
3339 a9e0c397 Iustin Pop
  _OP_REQP = ["instance_name", "mode", "disks"]
3340 a8083063 Iustin Pop
3341 b6e82a65 Iustin Pop
  def _RunAllocator(self):
3342 b6e82a65 Iustin Pop
    """Compute a new secondary node using an IAllocator.
3343 b6e82a65 Iustin Pop

3344 b6e82a65 Iustin Pop
    """
3345 b6e82a65 Iustin Pop
    ial = IAllocator(self.cfg, self.sstore,
3346 b6e82a65 Iustin Pop
                     mode=constants.IALLOCATOR_MODE_RELOC,
3347 b6e82a65 Iustin Pop
                     name=self.op.instance_name,
3348 b6e82a65 Iustin Pop
                     relocate_from=[self.sec_node])
3349 b6e82a65 Iustin Pop
3350 b6e82a65 Iustin Pop
    ial.Run(self.op.iallocator)
3351 b6e82a65 Iustin Pop
3352 b6e82a65 Iustin Pop
    if not ial.success:
3353 b6e82a65 Iustin Pop
      raise errors.OpPrereqError("Can't compute nodes using"
3354 b6e82a65 Iustin Pop
                                 " iallocator '%s': %s" % (self.op.iallocator,
3355 b6e82a65 Iustin Pop
                                                           ial.info))
3356 b6e82a65 Iustin Pop
    if len(ial.nodes) != ial.required_nodes:
3357 b6e82a65 Iustin Pop
      raise errors.OpPrereqError("iallocator '%s' returned invalid number"
3358 b6e82a65 Iustin Pop
                                 " of nodes (%s), required %s" %
3359 b6e82a65 Iustin Pop
                                 (len(ial.nodes), ial.required_nodes))
3360 b6e82a65 Iustin Pop
    self.op.remote_node = ial.nodes[0]
3361 b6e82a65 Iustin Pop
    logger.ToStdout("Selected new secondary for the instance: %s" %
3362 b6e82a65 Iustin Pop
                    self.op.remote_node)
3363 b6e82a65 Iustin Pop
3364 a8083063 Iustin Pop
  def BuildHooksEnv(self):
3365 a8083063 Iustin Pop
    """Build hooks env.
3366 a8083063 Iustin Pop

3367 a8083063 Iustin Pop
    This runs on the master, the primary and all the secondaries.
3368 a8083063 Iustin Pop

3369 a8083063 Iustin Pop
    """
3370 a8083063 Iustin Pop
    env = {
3371 a9e0c397 Iustin Pop
      "MODE": self.op.mode,
3372 a8083063 Iustin Pop
      "NEW_SECONDARY": self.op.remote_node,
3373 a8083063 Iustin Pop
      "OLD_SECONDARY": self.instance.secondary_nodes[0],
3374 a8083063 Iustin Pop
      }
3375 396e1b78 Michael Hanselmann
    env.update(_BuildInstanceHookEnvByObject(self.instance))
3376 0834c866 Iustin Pop
    nl = [
3377 0834c866 Iustin Pop
      self.sstore.GetMasterNode(),
3378 0834c866 Iustin Pop
      self.instance.primary_node,
3379 0834c866 Iustin Pop
      ]
3380 0834c866 Iustin Pop
    if self.op.remote_node is not None:
3381 0834c866 Iustin Pop
      nl.append(self.op.remote_node)
3382 a8083063 Iustin Pop
    return env, nl, nl
3383 a8083063 Iustin Pop
3384 a8083063 Iustin Pop
  def CheckPrereq(self):
3385 a8083063 Iustin Pop
    """Check prerequisites.
3386 a8083063 Iustin Pop

3387 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
3388 a8083063 Iustin Pop

3389 a8083063 Iustin Pop
    """
3390 b6e82a65 Iustin Pop
    if not hasattr(self.op, "remote_node"):
3391 b6e82a65 Iustin Pop
      self.op.remote_node = None
3392 b6e82a65 Iustin Pop
3393 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
3394 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
3395 a8083063 Iustin Pop
    if instance is None:
3396 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
3397 3ecf6786 Iustin Pop
                                 self.op.instance_name)
3398 a8083063 Iustin Pop
    self.instance = instance
3399 7df43a76 Iustin Pop
    self.op.instance_name = instance.name
3400 a8083063 Iustin Pop
3401 a9e0c397 Iustin Pop
    if instance.disk_template not in constants.DTS_NET_MIRROR:
3402 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance's disk layout is not"
3403 a9e0c397 Iustin Pop
                                 " network mirrored.")
3404 a8083063 Iustin Pop
3405 a8083063 Iustin Pop
    if len(instance.secondary_nodes) != 1:
3406 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("The instance has a strange layout,"
3407 3ecf6786 Iustin Pop
                                 " expected one secondary but found %d" %
3408 3ecf6786 Iustin Pop
                                 len(instance.secondary_nodes))
3409 a8083063 Iustin Pop
3410 a9e0c397 Iustin Pop
    self.sec_node = instance.secondary_nodes[0]
3411 a9e0c397 Iustin Pop
3412 b6e82a65 Iustin Pop
    ia_name = getattr(self.op, "iallocator", None)
3413 b6e82a65 Iustin Pop
    if ia_name is not None:
3414 b6e82a65 Iustin Pop
      if self.op.remote_node is not None:
3415 b6e82a65 Iustin Pop
        raise errors.OpPrereqError("Give either the iallocator or the new"
3416 b6e82a65 Iustin Pop
                                   " secondary, not both")
3417 b6e82a65 Iustin Pop
      self.op.remote_node = self._RunAllocator()
3418 b6e82a65 Iustin Pop
3419 b6e82a65 Iustin Pop
    remote_node = self.op.remote_node
3420 a9e0c397 Iustin Pop
    if remote_node is not None:
3421 a8083063 Iustin Pop
      remote_node = self.cfg.ExpandNodeName(remote_node)
3422 a8083063 Iustin Pop
      if remote_node is None:
3423 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Node '%s' not known" %
3424 3ecf6786 Iustin Pop
                                   self.op.remote_node)
3425 a9e0c397 Iustin Pop
      self.remote_node_info = self.cfg.GetNodeInfo(remote_node)
3426 a9e0c397 Iustin Pop
    else:
3427 a9e0c397 Iustin Pop
      self.remote_node_info = None
3428 a8083063 Iustin Pop
    if remote_node == instance.primary_node:
3429 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("The specified node is the primary node of"
3430 3ecf6786 Iustin Pop
                                 " the instance.")
3431 a9e0c397 Iustin Pop
    elif remote_node == self.sec_node:
3432 0834c866 Iustin Pop
      if self.op.mode == constants.REPLACE_DISK_SEC:
3433 0834c866 Iustin Pop
        # this is for DRBD8, where we can't execute the same mode of
3434 0834c866 Iustin Pop
        # replacement as for drbd7 (no different port allocated)
3435 0834c866 Iustin Pop
        raise errors.OpPrereqError("Same secondary given, cannot execute"
3436 0834c866 Iustin Pop
                                   " replacement")
3437 a9e0c397 Iustin Pop
    if instance.disk_template == constants.DT_DRBD8:
3438 7df43a76 Iustin Pop
      if (self.op.mode == constants.REPLACE_DISK_ALL and
3439 7df43a76 Iustin Pop
          remote_node is not None):
3440 7df43a76 Iustin Pop
        # switch to replace secondary mode
3441 7df43a76 Iustin Pop
        self.op.mode = constants.REPLACE_DISK_SEC
3442 7df43a76 Iustin Pop
3443 a9e0c397 Iustin Pop
      if self.op.mode == constants.REPLACE_DISK_ALL:
3444 12c3449a Michael Hanselmann
        raise errors.OpPrereqError("Template 'drbd' only allows primary or"
3445 a9e0c397 Iustin Pop
                                   " secondary disk replacement, not"
3446 a9e0c397 Iustin Pop
                                   " both at once")
3447 a9e0c397 Iustin Pop
      elif self.op.mode == constants.REPLACE_DISK_PRI:
3448 a9e0c397 Iustin Pop
        if remote_node is not None:
3449 12c3449a Michael Hanselmann
          raise errors.OpPrereqError("Template 'drbd' does not allow changing"
3450 a9e0c397 Iustin Pop
                                     " the secondary while doing a primary"
3451 a9e0c397 Iustin Pop
                                     " node disk replacement")
3452 a9e0c397 Iustin Pop
        self.tgt_node = instance.primary_node
3453 cff90b79 Iustin Pop
        self.oth_node = instance.secondary_nodes[0]
3454 a9e0c397 Iustin Pop
      elif self.op.mode == constants.REPLACE_DISK_SEC:
3455 a9e0c397 Iustin Pop
        self.new_node = remote_node # this can be None, in which case
3456 a9e0c397 Iustin Pop
                                    # we don't change the secondary
3457 a9e0c397 Iustin Pop
        self.tgt_node = instance.secondary_nodes[0]
3458 cff90b79 Iustin Pop
        self.oth_node = instance.primary_node
3459 a9e0c397 Iustin Pop
      else:
3460 a9e0c397 Iustin Pop
        raise errors.ProgrammerError("Unhandled disk replace mode")
3461 a9e0c397 Iustin Pop
3462 a9e0c397 Iustin Pop
    for name in self.op.disks:
3463 a9e0c397 Iustin Pop
      if instance.FindDisk(name) is None:
3464 a9e0c397 Iustin Pop
        raise errors.OpPrereqError("Disk '%s' not found for instance '%s'" %
3465 a9e0c397 Iustin Pop
                                   (name, instance.name))
3466 a8083063 Iustin Pop
    self.op.remote_node = remote_node
3467 a8083063 Iustin Pop
3468 a9e0c397 Iustin Pop
  def _ExecD8DiskOnly(self, feedback_fn):
3469 a9e0c397 Iustin Pop
    """Replace a disk on the primary or secondary for dbrd8.
3470 a9e0c397 Iustin Pop

3471 a9e0c397 Iustin Pop
    The algorithm for replace is quite complicated:
3472 a9e0c397 Iustin Pop
      - for each disk to be replaced:
3473 a9e0c397 Iustin Pop
        - create new LVs on the target node with unique names
3474 a9e0c397 Iustin Pop
        - detach old LVs from the drbd device
3475 a9e0c397 Iustin Pop
        - rename old LVs to name_replaced.<time_t>
3476 a9e0c397 Iustin Pop
        - rename new LVs to old LVs
3477 a9e0c397 Iustin Pop
        - attach the new LVs (with the old names now) to the drbd device
3478 a9e0c397 Iustin Pop
      - wait for sync across all devices
3479 a9e0c397 Iustin Pop
      - for each modified disk:
3480 a9e0c397 Iustin Pop
        - remove old LVs (which have the name name_replaces.<time_t>)
3481 a9e0c397 Iustin Pop

3482 a9e0c397 Iustin Pop
    Failures are not very well handled.
3483 cff90b79 Iustin Pop

3484 a9e0c397 Iustin Pop
    """
3485 cff90b79 Iustin Pop
    steps_total = 6
3486 5bfac263 Iustin Pop
    warning, info = (self.proc.LogWarning, self.proc.LogInfo)
3487 a9e0c397 Iustin Pop
    instance = self.instance
3488 a9e0c397 Iustin Pop
    iv_names = {}
3489 a9e0c397 Iustin Pop
    vgname = self.cfg.GetVGName()
3490 a9e0c397 Iustin Pop
    # start of work
3491 a9e0c397 Iustin Pop
    cfg = self.cfg
3492 a9e0c397 Iustin Pop
    tgt_node = self.tgt_node
3493 cff90b79 Iustin Pop
    oth_node = self.oth_node
3494 cff90b79 Iustin Pop
3495 cff90b79 Iustin Pop
    # Step: check device activation
3496 5bfac263 Iustin Pop
    self.proc.LogStep(1, steps_total, "check device existence")
3497 cff90b79 Iustin Pop
    info("checking volume groups")
3498 cff90b79 Iustin Pop
    my_vg = cfg.GetVGName()
3499 cff90b79 Iustin Pop
    results = rpc.call_vg_list([oth_node, tgt_node])
3500 cff90b79 Iustin Pop
    if not results:
3501 cff90b79 Iustin Pop
      raise errors.OpExecError("Can't list volume groups on the nodes")
3502 cff90b79 Iustin Pop
    for node in oth_node, tgt_node:
3503 cff90b79 Iustin Pop
      res = results.get(node, False)
3504 cff90b79 Iustin Pop
      if not res or my_vg not in res:
3505 cff90b79 Iustin Pop
        raise errors.OpExecError("Volume group '%s' not found on %s" %
3506 cff90b79 Iustin Pop
                                 (my_vg, node))
3507 cff90b79 Iustin Pop
    for dev in instance.disks:
3508 cff90b79 Iustin Pop
      if not dev.iv_name in self.op.disks:
3509 cff90b79 Iustin Pop
        continue
3510 cff90b79 Iustin Pop
      for node in tgt_node, oth_node:
3511 cff90b79 Iustin Pop
        info("checking %s on %s" % (dev.iv_name, node))
3512 cff90b79 Iustin Pop
        cfg.SetDiskID(dev, node)
3513 cff90b79 Iustin Pop
        if not rpc.call_blockdev_find(node, dev):
3514 cff90b79 Iustin Pop
          raise errors.OpExecError("Can't find device %s on node %s" %
3515 cff90b79 Iustin Pop
                                   (dev.iv_name, node))
3516 cff90b79 Iustin Pop
3517 cff90b79 Iustin Pop
    # Step: check other node consistency
3518 5bfac263 Iustin Pop
    self.proc.LogStep(2, steps_total, "check peer consistency")
3519 cff90b79 Iustin Pop
    for dev in instance.disks:
3520 cff90b79 Iustin Pop
      if not dev.iv_name in self.op.disks:
3521 cff90b79 Iustin Pop
        continue
3522 cff90b79 Iustin Pop
      info("checking %s consistency on %s" % (dev.iv_name, oth_node))
3523 cff90b79 Iustin Pop
      if not _CheckDiskConsistency(self.cfg, dev, oth_node,
3524 cff90b79 Iustin Pop
                                   oth_node==instance.primary_node):
3525 cff90b79 Iustin Pop
        raise errors.OpExecError("Peer node (%s) has degraded storage, unsafe"
3526 cff90b79 Iustin Pop
                                 " to replace disks on this node (%s)" %
3527 cff90b79 Iustin Pop
                                 (oth_node, tgt_node))
3528 cff90b79 Iustin Pop
3529 cff90b79 Iustin Pop
    # Step: create new storage
3530 5bfac263 Iustin Pop
    self.proc.LogStep(3, steps_total, "allocate new storage")
3531 a9e0c397 Iustin Pop
    for dev in instance.disks:
3532 a9e0c397 Iustin Pop
      if not dev.iv_name in self.op.disks:
3533 a9e0c397 Iustin Pop
        continue
3534 a9e0c397 Iustin Pop
      size = dev.size
3535 a9e0c397 Iustin Pop
      cfg.SetDiskID(dev, tgt_node)
3536 a9e0c397 Iustin Pop
      lv_names = [".%s_%s" % (dev.iv_name, suf) for suf in ["data", "meta"]]
3537 a9e0c397 Iustin Pop
      names = _GenerateUniqueNames(cfg, lv_names)
3538 a9e0c397 Iustin Pop
      lv_data = objects.Disk(dev_type=constants.LD_LV, size=size,
3539 a9e0c397 Iustin Pop
                             logical_id=(vgname, names[0]))
3540 a9e0c397 Iustin Pop
      lv_meta = objects.Disk(dev_type=constants.LD_LV, size=128,
3541 a9e0c397 Iustin Pop
                             logical_id=(vgname, names[1]))
3542 a9e0c397 Iustin Pop
      new_lvs = [lv_data, lv_meta]
3543 a9e0c397 Iustin Pop
      old_lvs = dev.children
3544 a9e0c397 Iustin Pop
      iv_names[dev.iv_name] = (dev, old_lvs, new_lvs)
3545 cff90b79 Iustin Pop
      info("creating new local storage on %s for %s" %
3546 cff90b79 Iustin Pop
           (tgt_node, dev.iv_name))
3547 a9e0c397 Iustin Pop
      # since we *always* want to create this LV, we use the
3548 a9e0c397 Iustin Pop
      # _Create...OnPrimary (which forces the creation), even if we
3549 a9e0c397 Iustin Pop
      # are talking about the secondary node
3550 a9e0c397 Iustin Pop
      for new_lv in new_lvs:
3551 3f78eef2 Iustin Pop
        if not _CreateBlockDevOnPrimary(cfg, tgt_node, instance, new_lv,
3552 a9e0c397 Iustin Pop
                                        _GetInstanceInfoText(instance)):
3553 a9e0c397 Iustin Pop
          raise errors.OpExecError("Failed to create new LV named '%s' on"
3554 a9e0c397 Iustin Pop
                                   " node '%s'" %
3555 a9e0c397 Iustin Pop
                                   (new_lv.logical_id[1], tgt_node))
3556 a9e0c397 Iustin Pop
3557 cff90b79 Iustin Pop
    # Step: for each lv, detach+rename*2+attach
3558 5bfac263 Iustin Pop
    self.proc.LogStep(4, steps_total, "change drbd configuration")
3559 cff90b79 Iustin Pop
    for dev, old_lvs, new_lvs in iv_names.itervalues():
3560 cff90b79 Iustin Pop
      info("detaching %s drbd from local storage" % dev.iv_name)
3561 a9e0c397 Iustin Pop
      if not rpc.call_blockdev_removechildren(tgt_node, dev, old_lvs):
3562 a9e0c397 Iustin Pop
        raise errors.OpExecError("Can't detach drbd from local storage on node"
3563 a9e0c397 Iustin Pop
                                 " %s for device %s" % (tgt_node, dev.iv_name))
3564 cff90b79 Iustin Pop
      #dev.children = []
3565 cff90b79 Iustin Pop
      #cfg.Update(instance)
3566 a9e0c397 Iustin Pop
3567 a9e0c397 Iustin Pop
      # ok, we created the new LVs, so now we know we have the needed
3568 a9e0c397 Iustin Pop
      # storage; as such, we proceed on the target node to rename
3569 a9e0c397 Iustin Pop
      # old_lv to _old, and new_lv to old_lv; note that we rename LVs
3570 c99a3cc0 Manuel Franceschini
      # using the assumption that logical_id == physical_id (which in
3571 a9e0c397 Iustin Pop
      # turn is the unique_id on that node)
3572 cff90b79 Iustin Pop
3573 cff90b79 Iustin Pop
      # FIXME(iustin): use a better name for the replaced LVs
3574 a9e0c397 Iustin Pop
      temp_suffix = int(time.time())
3575 a9e0c397 Iustin Pop
      ren_fn = lambda d, suff: (d.physical_id[0],
3576 a9e0c397 Iustin Pop
                                d.physical_id[1] + "_replaced-%s" % suff)
3577 cff90b79 Iustin Pop
      # build the rename list based on what LVs exist on the node
3578 cff90b79 Iustin Pop
      rlist = []
3579 cff90b79 Iustin Pop
      for to_ren in old_lvs:
3580 cff90b79 Iustin Pop
        find_res = rpc.call_blockdev_find(tgt_node, to_ren)
3581 cff90b79 Iustin Pop
        if find_res is not None: # device exists
3582 cff90b79 Iustin Pop
          rlist.append((to_ren, ren_fn(to_ren, temp_suffix)))
3583 cff90b79 Iustin Pop
3584 cff90b79 Iustin Pop
      info("renaming the old LVs on the target node")
3585 a9e0c397 Iustin Pop
      if not rpc.call_blockdev_rename(tgt_node, rlist):
3586 cff90b79 Iustin Pop
        raise errors.OpExecError("Can't rename old LVs on node %s" % tgt_node)
3587 a9e0c397 Iustin Pop
      # now we rename the new LVs to the old LVs
3588 cff90b79 Iustin Pop
      info("renaming the new LVs on the target node")
3589 a9e0c397 Iustin Pop
      rlist = [(new, old.physical_id) for old, new in zip(old_lvs, new_lvs)]
3590 a9e0c397 Iustin Pop
      if not rpc.call_blockdev_rename(tgt_node, rlist):
3591 cff90b79 Iustin Pop
        raise errors.OpExecError("Can't rename new LVs on node %s" % tgt_node)
3592 cff90b79 Iustin Pop
3593 cff90b79 Iustin Pop
      for old, new in zip(old_lvs, new_lvs):
3594 cff90b79 Iustin Pop
        new.logical_id = old.logical_id
3595 cff90b79 Iustin Pop
        cfg.SetDiskID(new, tgt_node)
3596 a9e0c397 Iustin Pop
3597 cff90b79 Iustin Pop
      for disk in old_lvs:
3598 cff90b79 Iustin Pop
        disk.logical_id = ren_fn(disk, temp_suffix)
3599 cff90b79 Iustin Pop
        cfg.SetDiskID(disk, tgt_node)
3600 a9e0c397 Iustin Pop
3601 a9e0c397 Iustin Pop
      # now that the new lvs have the old name, we can add them to the device
3602 cff90b79 Iustin Pop
      info("adding new mirror component on %s" % tgt_node)
3603 a9e0c397 Iustin Pop
      if not rpc.call_blockdev_addchildren(tgt_node, dev, new_lvs):
3604 a9e0c397 Iustin Pop
        for new_lv in new_lvs:
3605 a9e0c397 Iustin Pop
          if not rpc.call_blockdev_remove(tgt_node, new_lv):
3606 79caa9ed Guido Trotter
            warning("Can't rollback device %s", hint="manually cleanup unused"
3607 cff90b79 Iustin Pop
                    " logical volumes")
3608 cff90b79 Iustin Pop
        raise errors.OpExecError("Can't add local storage to drbd")
3609 a9e0c397 Iustin Pop
3610 a9e0c397 Iustin Pop
      dev.children = new_lvs
3611 a9e0c397 Iustin Pop
      cfg.Update(instance)
3612 a9e0c397 Iustin Pop
3613 cff90b79 Iustin Pop
    # Step: wait for sync
3614 a9e0c397 Iustin Pop
3615 a9e0c397 Iustin Pop
    # this can fail as the old devices are degraded and _WaitForSync
3616 a9e0c397 Iustin Pop
    # does a combined result over all disks, so we don't check its
3617 a9e0c397 Iustin Pop
    # return value
3618 5bfac263 Iustin Pop
    self.proc.LogStep(5, steps_total, "sync devices")
3619 5bfac263 Iustin Pop
    _WaitForSync(cfg, instance, self.proc, unlock=True)
3620 a9e0c397 Iustin Pop
3621 a9e0c397 Iustin Pop
    # so check manually all the devices
3622 a9e0c397 Iustin Pop
    for name, (dev, old_lvs, new_lvs) in iv_names.iteritems():
3623 a9e0c397 Iustin Pop
      cfg.SetDiskID(dev, instance.primary_node)
3624 a9e0c397 Iustin Pop
      is_degr = rpc.call_blockdev_find(instance.primary_node, dev)[5]
3625 a9e0c397 Iustin Pop
      if is_degr:
3626 a9e0c397 Iustin Pop
        raise errors.OpExecError("DRBD device %s is degraded!" % name)
3627 a9e0c397 Iustin Pop
3628 cff90b79 Iustin Pop
    # Step: remove old storage
3629 5bfac263 Iustin Pop
    self.proc.LogStep(6, steps_total, "removing old storage")
3630 a9e0c397 Iustin Pop
    for name, (dev, old_lvs, new_lvs) in iv_names.iteritems():
3631 cff90b79 Iustin Pop
      info("remove logical volumes for %s" % name)
3632 a9e0c397 Iustin Pop
      for lv in old_lvs:
3633 a9e0c397 Iustin Pop
        cfg.SetDiskID(lv, tgt_node)
3634 a9e0c397 Iustin Pop
        if not rpc.call_blockdev_remove(tgt_node, lv):
3635 79caa9ed Guido Trotter
          warning("Can't remove old LV", hint="manually remove unused LVs")
3636 a9e0c397 Iustin Pop
          continue
3637 a9e0c397 Iustin Pop
3638 a9e0c397 Iustin Pop
  def _ExecD8Secondary(self, feedback_fn):
3639 a9e0c397 Iustin Pop
    """Replace the secondary node for drbd8.
3640 a9e0c397 Iustin Pop

3641 a9e0c397 Iustin Pop
    The algorithm for replace is quite complicated:
3642 a9e0c397 Iustin Pop
      - for all disks of the instance:
3643 a9e0c397 Iustin Pop
        - create new LVs on the new node with same names
3644 a9e0c397 Iustin Pop
        - shutdown the drbd device on the old secondary
3645 a9e0c397 Iustin Pop
        - disconnect the drbd network on the primary
3646 a9e0c397 Iustin Pop
        - create the drbd device on the new secondary
3647 a9e0c397 Iustin Pop
        - network attach the drbd on the primary, using an artifice:
3648 a9e0c397 Iustin Pop
          the drbd code for Attach() will connect to the network if it
3649 a9e0c397 Iustin Pop
          finds a device which is connected to the good local disks but
3650 a9e0c397 Iustin Pop
          not network enabled
3651 a9e0c397 Iustin Pop
      - wait for sync across all devices
3652 a9e0c397 Iustin Pop
      - remove all disks from the old secondary
3653 a9e0c397 Iustin Pop

3654 a9e0c397 Iustin Pop
    Failures are not very well handled.
3655 0834c866 Iustin Pop

3656 a9e0c397 Iustin Pop
    """
3657 0834c866 Iustin Pop
    steps_total = 6
3658 5bfac263 Iustin Pop
    warning, info = (self.proc.LogWarning, self.proc.LogInfo)
3659 a9e0c397 Iustin Pop
    instance = self.instance
3660 a9e0c397 Iustin Pop
    iv_names = {}
3661 a9e0c397 Iustin Pop
    vgname = self.cfg.GetVGName()
3662 a9e0c397 Iustin Pop
    # start of work
3663 a9e0c397 Iustin Pop
    cfg = self.cfg
3664 a9e0c397 Iustin Pop
    old_node = self.tgt_node
3665 a9e0c397 Iustin Pop
    new_node = self.new_node
3666 a9e0c397 Iustin Pop
    pri_node = instance.primary_node
3667 0834c866 Iustin Pop
3668 0834c866 Iustin Pop
    # Step: check device activation
3669 5bfac263 Iustin Pop
    self.proc.LogStep(1, steps_total, "check device existence")
3670 0834c866 Iustin Pop
    info("checking volume groups")
3671 0834c866 Iustin Pop
    my_vg = cfg.GetVGName()
3672 0834c866 Iustin Pop
    results = rpc.call_vg_list([pri_node, new_node])
3673 0834c866 Iustin Pop
    if not results:
3674 0834c866 Iustin Pop
      raise errors.OpExecError("Can't list volume groups on the nodes")
3675 0834c866 Iustin Pop
    for node in pri_node, new_node:
3676 0834c866 Iustin Pop
      res = results.get(node, False)
3677 0834c866 Iustin Pop
      if not res or my_vg not in res:
3678 0834c866 Iustin Pop
        raise errors.OpExecError("Volume group '%s' not found on %s" %
3679 0834c866 Iustin Pop
                                 (my_vg, node))
3680 0834c866 Iustin Pop
    for dev in instance.disks:
3681 0834c866 Iustin Pop
      if not dev.iv_name in self.op.disks:
3682 0834c866 Iustin Pop
        continue
3683 0834c866 Iustin Pop
      info("checking %s on %s" % (dev.iv_name, pri_node))
3684 0834c866 Iustin Pop
      cfg.SetDiskID(dev, pri_node)
3685 0834c866 Iustin Pop
      if not rpc.call_blockdev_find(pri_node, dev):
3686 0834c866 Iustin Pop
        raise errors.OpExecError("Can't find device %s on node %s" %
3687 0834c866 Iustin Pop
                                 (dev.iv_name, pri_node))
3688 0834c866 Iustin Pop
3689 0834c866 Iustin Pop
    # Step: check other node consistency
3690 5bfac263 Iustin Pop
    self.proc.LogStep(2, steps_total, "check peer consistency")
3691 0834c866 Iustin Pop
    for dev in instance.disks:
3692 0834c866 Iustin Pop
      if not dev.iv_name in self.op.disks:
3693 0834c866 Iustin Pop
        continue
3694 0834c866 Iustin Pop
      info("checking %s consistency on %s" % (dev.iv_name, pri_node))
3695 0834c866 Iustin Pop
      if not _CheckDiskConsistency(self.cfg, dev, pri_node, True, ldisk=True):
3696 0834c866 Iustin Pop
        raise errors.OpExecError("Primary node (%s) has degraded storage,"
3697 0834c866 Iustin Pop
                                 " unsafe to replace the secondary" %
3698 0834c866 Iustin Pop
                                 pri_node)
3699 0834c866 Iustin Pop
3700 0834c866 Iustin Pop
    # Step: create new storage
3701 5bfac263 Iustin Pop
    self.proc.LogStep(3, steps_total, "allocate new storage")
3702 a9e0c397 Iustin Pop
    for dev in instance.disks:
3703 a9e0c397 Iustin Pop
      size = dev.size
3704 0834c866 Iustin Pop
      info("adding new local storage on %s for %s" % (new_node, dev.iv_name))
3705 a9e0c397 Iustin Pop
      # since we *always* want to create this LV, we use the
3706 a9e0c397 Iustin Pop
      # _Create...OnPrimary (which forces the creation), even if we
3707 a9e0c397 Iustin Pop
      # are talking about the secondary node
3708 a9e0c397 Iustin Pop
      for new_lv in dev.children:
3709 3f78eef2 Iustin Pop
        if not _CreateBlockDevOnPrimary(cfg, new_node, instance, new_lv,
3710 a9e0c397 Iustin Pop
                                        _GetInstanceInfoText(instance)):
3711 a9e0c397 Iustin Pop
          raise errors.OpExecError("Failed to create new LV named '%s' on"
3712 a9e0c397 Iustin Pop
                                   " node '%s'" %
3713 a9e0c397 Iustin Pop
                                   (new_lv.logical_id[1], new_node))
3714 a9e0c397 Iustin Pop
3715 0834c866 Iustin Pop
      iv_names[dev.iv_name] = (dev, dev.children)
3716 0834c866 Iustin Pop
3717 5bfac263 Iustin Pop
    self.proc.LogStep(4, steps_total, "changing drbd configuration")
3718 0834c866 Iustin Pop
    for dev in instance.disks:
3719 0834c866 Iustin Pop
      size = dev.size
3720 0834c866 Iustin Pop
      info("activating a new drbd on %s for %s" % (new_node, dev.iv_name))
3721 a9e0c397 Iustin Pop
      # create new devices on new_node
3722 a9e0c397 Iustin Pop
      new_drbd = objects.Disk(dev_type=constants.LD_DRBD8,
3723 a9e0c397 Iustin Pop
                              logical_id=(pri_node, new_node,
3724 a9e0c397 Iustin Pop
                                          dev.logical_id[2]),
3725 a9e0c397 Iustin Pop
                              children=dev.children)
3726 3f78eef2 Iustin Pop
      if not _CreateBlockDevOnSecondary(cfg, new_node, instance,
3727 3f78eef2 Iustin Pop
                                        new_drbd, False,
3728 a9e0c397 Iustin Pop
                                      _GetInstanceInfoText(instance)):
3729 a9e0c397 Iustin Pop
        raise errors.OpExecError("Failed to create new DRBD on"
3730 a9e0c397 Iustin Pop
                                 " node '%s'" % new_node)
3731 a9e0c397 Iustin Pop
3732 0834c866 Iustin Pop
    for dev in instance.disks:
3733 a9e0c397 Iustin Pop
      # we have new devices, shutdown the drbd on the old secondary
3734 0834c866 Iustin Pop
      info("shutting down drbd for %s on old node" % dev.iv_name)
3735 a9e0c397 Iustin Pop
      cfg.SetDiskID(dev, old_node)
3736 a9e0c397 Iustin Pop
      if not rpc.call_blockdev_shutdown(old_node, dev):
3737 0834c866 Iustin Pop
        warning("Failed to shutdown drbd for %s on old node" % dev.iv_name,
3738 79caa9ed Guido Trotter
                hint="Please cleanup this device manually as soon as possible")
3739 a9e0c397 Iustin Pop
3740 642445d9 Iustin Pop
    info("detaching primary drbds from the network (=> standalone)")
3741 642445d9 Iustin Pop
    done = 0
3742 642445d9 Iustin Pop
    for dev in instance.disks:
3743 a9e0c397 Iustin Pop
      cfg.SetDiskID(dev, pri_node)
3744 642445d9 Iustin Pop
      # set the physical (unique in bdev terms) id to None, meaning
3745 642445d9 Iustin Pop
      # detach from network
3746 642445d9 Iustin Pop
      dev.physical_id = (None,) * len(dev.physical_id)
3747 642445d9 Iustin Pop
      # and 'find' the device, which will 'fix' it to match the
3748 642445d9 Iustin Pop
      # standalone state
3749 642445d9 Iustin Pop
      if rpc.call_blockdev_find(pri_node, dev):
3750 642445d9 Iustin Pop
        done += 1
3751 642445d9 Iustin Pop
      else:
3752 642445d9 Iustin Pop
        warning("Failed to detach drbd %s from network, unusual case" %
3753 642445d9 Iustin Pop
                dev.iv_name)
3754 642445d9 Iustin Pop
3755 642445d9 Iustin Pop
    if not done:
3756 642445d9 Iustin Pop
      # no detaches succeeded (very unlikely)
3757 642445d9 Iustin Pop
      raise errors.OpExecError("Can't detach at least one DRBD from old node")
3758 642445d9 Iustin Pop
3759 642445d9 Iustin Pop
    # if we managed to detach at least one, we update all the disks of
3760 642445d9 Iustin Pop
    # the instance to point to the new secondary
3761 642445d9 Iustin Pop
    info("updating instance configuration")
3762 642445d9 Iustin Pop
    for dev in instance.disks:
3763 642445d9 Iustin Pop
      dev.logical_id = (pri_node, new_node) + dev.logical_id[2:]
3764 a9e0c397 Iustin Pop
      cfg.SetDiskID(dev, pri_node)
3765 642445d9 Iustin Pop
    cfg.Update(instance)
3766 a9e0c397 Iustin Pop
3767 642445d9 Iustin Pop
    # and now perform the drbd attach
3768 642445d9 Iustin Pop
    info("attaching primary drbds to new secondary (standalone => connected)")
3769 642445d9 Iustin Pop
    failures = []
3770 642445d9 Iustin Pop
    for dev in instance.disks:
3771 642445d9 Iustin Pop
      info("attaching primary drbd for %s to new secondary node" % dev.iv_name)
3772 642445d9 Iustin Pop
      # since the attach is smart, it's enough to 'find' the device,
3773 642445d9 Iustin Pop
      # it will automatically activate the network, if the physical_id
3774 642445d9 Iustin Pop
      # is correct
3775 642445d9 Iustin Pop
      cfg.SetDiskID(dev, pri_node)
3776 642445d9 Iustin Pop
      if not rpc.call_blockdev_find(pri_node, dev):
3777 642445d9 Iustin Pop
        warning("can't attach drbd %s to new secondary!" % dev.iv_name,
3778 642445d9 Iustin Pop
                "please do a gnt-instance info to see the status of disks")
3779 a9e0c397 Iustin Pop
3780 a9e0c397 Iustin Pop
    # this can fail as the old devices are degraded and _WaitForSync
3781 a9e0c397 Iustin Pop
    # does a combined result over all disks, so we don't check its
3782 a9e0c397 Iustin Pop
    # return value
3783 5bfac263 Iustin Pop
    self.proc.LogStep(5, steps_total, "sync devices")
3784 5bfac263 Iustin Pop
    _WaitForSync(cfg, instance, self.proc, unlock=True)
3785 a9e0c397 Iustin Pop
3786 a9e0c397 Iustin Pop
    # so check manually all the devices
3787 a9e0c397 Iustin Pop
    for name, (dev, old_lvs) in iv_names.iteritems():
3788 a9e0c397 Iustin Pop
      cfg.SetDiskID(dev, pri_node)
3789 a9e0c397 Iustin Pop
      is_degr = rpc.call_blockdev_find(pri_node, dev)[5]
3790 a9e0c397 Iustin Pop
      if is_degr:
3791 a9e0c397 Iustin Pop
        raise errors.OpExecError("DRBD device %s is degraded!" % name)
3792 a9e0c397 Iustin Pop
3793 5bfac263 Iustin Pop
    self.proc.LogStep(6, steps_total, "removing old storage")
3794 a9e0c397 Iustin Pop
    for name, (dev, old_lvs) in iv_names.iteritems():
3795 0834c866 Iustin Pop
      info("remove logical volumes for %s" % name)
3796 a9e0c397 Iustin Pop
      for lv in old_lvs:
3797 a9e0c397 Iustin Pop
        cfg.SetDiskID(lv, old_node)
3798 a9e0c397 Iustin Pop
        if not rpc.call_blockdev_remove(old_node, lv):
3799 0834c866 Iustin Pop
          warning("Can't remove LV on old secondary",
3800 79caa9ed Guido Trotter
                  hint="Cleanup stale volumes by hand")
3801 a9e0c397 Iustin Pop
3802 a9e0c397 Iustin Pop
  def Exec(self, feedback_fn):
3803 a9e0c397 Iustin Pop
    """Execute disk replacement.
3804 a9e0c397 Iustin Pop

3805 a9e0c397 Iustin Pop
    This dispatches the disk replacement to the appropriate handler.
3806 a9e0c397 Iustin Pop

3807 a9e0c397 Iustin Pop
    """
3808 a9e0c397 Iustin Pop
    instance = self.instance
3809 22985314 Guido Trotter
3810 22985314 Guido Trotter
    # Activate the instance disks if we're replacing them on a down instance
3811 22985314 Guido Trotter
    if instance.status == "down":
3812 22985314 Guido Trotter
      op = opcodes.OpActivateInstanceDisks(instance_name=instance.name)
3813 22985314 Guido Trotter
      self.proc.ChainOpCode(op)
3814 22985314 Guido Trotter
3815 abdf0113 Iustin Pop
    if instance.disk_template == constants.DT_DRBD8:
3816 a9e0c397 Iustin Pop
      if self.op.remote_node is None:
3817 a9e0c397 Iustin Pop
        fn = self._ExecD8DiskOnly
3818 a9e0c397 Iustin Pop
      else:
3819 a9e0c397 Iustin Pop
        fn = self._ExecD8Secondary
3820 a9e0c397 Iustin Pop
    else:
3821 a9e0c397 Iustin Pop
      raise errors.ProgrammerError("Unhandled disk replacement case")
3822 22985314 Guido Trotter
3823 22985314 Guido Trotter
    ret = fn(feedback_fn)
3824 22985314 Guido Trotter
3825 22985314 Guido Trotter
    # Deactivate the instance disks if we're replacing them on a down instance
3826 22985314 Guido Trotter
    if instance.status == "down":
3827 22985314 Guido Trotter
      op = opcodes.OpDeactivateInstanceDisks(instance_name=instance.name)
3828 22985314 Guido Trotter
      self.proc.ChainOpCode(op)
3829 22985314 Guido Trotter
3830 22985314 Guido Trotter
    return ret
3831 a9e0c397 Iustin Pop
3832 a8083063 Iustin Pop
3833 8729e0d7 Iustin Pop
class LUGrowDisk(LogicalUnit):
3834 8729e0d7 Iustin Pop
  """Grow a disk of an instance.
3835 8729e0d7 Iustin Pop

3836 8729e0d7 Iustin Pop
  """
3837 8729e0d7 Iustin Pop
  HPATH = "disk-grow"
3838 8729e0d7 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
3839 8729e0d7 Iustin Pop
  _OP_REQP = ["instance_name", "disk", "amount"]
3840 8729e0d7 Iustin Pop
3841 8729e0d7 Iustin Pop
  def BuildHooksEnv(self):
3842 8729e0d7 Iustin Pop
    """Build hooks env.
3843 8729e0d7 Iustin Pop

3844 8729e0d7 Iustin Pop
    This runs on the master, the primary and all the secondaries.
3845 8729e0d7 Iustin Pop

3846 8729e0d7 Iustin Pop
    """
3847 8729e0d7 Iustin Pop
    env = {
3848 8729e0d7 Iustin Pop
      "DISK": self.op.disk,
3849 8729e0d7 Iustin Pop
      "AMOUNT": self.op.amount,
3850 8729e0d7 Iustin Pop
      }
3851 8729e0d7 Iustin Pop
    env.update(_BuildInstanceHookEnvByObject(self.instance))
3852 8729e0d7 Iustin Pop
    nl = [
3853 8729e0d7 Iustin Pop
      self.sstore.GetMasterNode(),
3854 8729e0d7 Iustin Pop
      self.instance.primary_node,
3855 8729e0d7 Iustin Pop
      ]
3856 8729e0d7 Iustin Pop
    return env, nl, nl
3857 8729e0d7 Iustin Pop
3858 8729e0d7 Iustin Pop
  def CheckPrereq(self):
3859 8729e0d7 Iustin Pop
    """Check prerequisites.
3860 8729e0d7 Iustin Pop

3861 8729e0d7 Iustin Pop
    This checks that the instance is in the cluster.
3862 8729e0d7 Iustin Pop

3863 8729e0d7 Iustin Pop
    """
3864 8729e0d7 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
3865 8729e0d7 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
3866 8729e0d7 Iustin Pop
    if instance is None:
3867 8729e0d7 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
3868 8729e0d7 Iustin Pop
                                 self.op.instance_name)
3869 8729e0d7 Iustin Pop
    self.instance = instance
3870 8729e0d7 Iustin Pop
    self.op.instance_name = instance.name
3871 8729e0d7 Iustin Pop
3872 8729e0d7 Iustin Pop
    if instance.disk_template not in (constants.DT_PLAIN, constants.DT_DRBD8):
3873 8729e0d7 Iustin Pop
      raise errors.OpPrereqError("Instance's disk layout does not support"
3874 8729e0d7 Iustin Pop
                                 " growing.")
3875 8729e0d7 Iustin Pop
3876 8729e0d7 Iustin Pop
    if instance.FindDisk(self.op.disk) is None:
3877 8729e0d7 Iustin Pop
      raise errors.OpPrereqError("Disk '%s' not found for instance '%s'" %
3878 c7cdfc90 Iustin Pop
                                 (self.op.disk, instance.name))
3879 8729e0d7 Iustin Pop
3880 8729e0d7 Iustin Pop
    nodenames = [instance.primary_node] + list(instance.secondary_nodes)
3881 8729e0d7 Iustin Pop
    nodeinfo = rpc.call_node_info(nodenames, self.cfg.GetVGName())
3882 8729e0d7 Iustin Pop
    for node in nodenames:
3883 8729e0d7 Iustin Pop
      info = nodeinfo.get(node, None)
3884 8729e0d7 Iustin Pop
      if not info:
3885 8729e0d7 Iustin Pop
        raise errors.OpPrereqError("Cannot get current information"
3886 8729e0d7 Iustin Pop
                                   " from node '%s'" % node)
3887 8729e0d7 Iustin Pop
      vg_free = info.get('vg_free', None)
3888 8729e0d7 Iustin Pop
      if not isinstance(vg_free, int):
3889 8729e0d7 Iustin Pop
        raise errors.OpPrereqError("Can't compute free disk space on"
3890 8729e0d7 Iustin Pop
                                   " node %s" % node)
3891 8729e0d7 Iustin Pop
      if self.op.amount > info['vg_free']:
3892 8729e0d7 Iustin Pop
        raise errors.OpPrereqError("Not enough disk space on target node %s:"
3893 8729e0d7 Iustin Pop
                                   " %d MiB available, %d MiB required" %
3894 8729e0d7 Iustin Pop
                                   (node, info['vg_free'], self.op.amount))
3895 8729e0d7 Iustin Pop
3896 8729e0d7 Iustin Pop
  def Exec(self, feedback_fn):
3897 8729e0d7 Iustin Pop
    """Execute disk grow.
3898 8729e0d7 Iustin Pop

3899 8729e0d7 Iustin Pop
    """
3900 8729e0d7 Iustin Pop
    instance = self.instance
3901 8729e0d7 Iustin Pop
    disk = instance.FindDisk(self.op.disk)
3902 8729e0d7 Iustin Pop
    for node in (instance.secondary_nodes + (instance.primary_node,)):
3903 8729e0d7 Iustin Pop
      self.cfg.SetDiskID(disk, node)
3904 8729e0d7 Iustin Pop
      result = rpc.call_blockdev_grow(node, disk, self.op.amount)
3905 8729e0d7 Iustin Pop
      if not result or not isinstance(result, tuple) or len(result) != 2:
3906 8729e0d7 Iustin Pop
        raise errors.OpExecError("grow request failed to node %s" % node)
3907 8729e0d7 Iustin Pop
      elif not result[0]:
3908 8729e0d7 Iustin Pop
        raise errors.OpExecError("grow request failed to node %s: %s" %
3909 8729e0d7 Iustin Pop
                                 (node, result[1]))
3910 8729e0d7 Iustin Pop
    disk.RecordGrow(self.op.amount)
3911 8729e0d7 Iustin Pop
    self.cfg.Update(instance)
3912 8729e0d7 Iustin Pop
    return
3913 8729e0d7 Iustin Pop
3914 8729e0d7 Iustin Pop
3915 a8083063 Iustin Pop
class LUQueryInstanceData(NoHooksLU):
3916 a8083063 Iustin Pop
  """Query runtime instance data.
3917 a8083063 Iustin Pop

3918 a8083063 Iustin Pop
  """
3919 a8083063 Iustin Pop
  _OP_REQP = ["instances"]
3920 a8083063 Iustin Pop
3921 a8083063 Iustin Pop
  def CheckPrereq(self):
3922 a8083063 Iustin Pop
    """Check prerequisites.
3923 a8083063 Iustin Pop

3924 a8083063 Iustin Pop
    This only checks the optional instance list against the existing names.
3925 a8083063 Iustin Pop

3926 a8083063 Iustin Pop
    """
3927 a8083063 Iustin Pop
    if not isinstance(self.op.instances, list):
3928 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Invalid argument type 'instances'")
3929 a8083063 Iustin Pop
    if self.op.instances:
3930 a8083063 Iustin Pop
      self.wanted_instances = []
3931 a8083063 Iustin Pop
      names = self.op.instances
3932 a8083063 Iustin Pop
      for name in names:
3933 a8083063 Iustin Pop
        instance = self.cfg.GetInstanceInfo(self.cfg.ExpandInstanceName(name))
3934 a8083063 Iustin Pop
        if instance is None:
3935 3ecf6786 Iustin Pop
          raise errors.OpPrereqError("No such instance name '%s'" % name)
3936 515207af Guido Trotter
        self.wanted_instances.append(instance)
3937 a8083063 Iustin Pop
    else:
3938 a8083063 Iustin Pop
      self.wanted_instances = [self.cfg.GetInstanceInfo(name) for name
3939 a8083063 Iustin Pop
                               in self.cfg.GetInstanceList()]
3940 a8083063 Iustin Pop
    return
3941 a8083063 Iustin Pop
3942 a8083063 Iustin Pop
3943 a8083063 Iustin Pop
  def _ComputeDiskStatus(self, instance, snode, dev):
3944 a8083063 Iustin Pop
    """Compute block device status.
3945 a8083063 Iustin Pop

3946 a8083063 Iustin Pop
    """
3947 a8083063 Iustin Pop
    self.cfg.SetDiskID(dev, instance.primary_node)
3948 a8083063 Iustin Pop
    dev_pstatus = rpc.call_blockdev_find(instance.primary_node, dev)
3949 a1f445d3 Iustin Pop
    if dev.dev_type in constants.LDS_DRBD:
3950 a8083063 Iustin Pop
      # we change the snode then (otherwise we use the one passed in)
3951 a8083063 Iustin Pop
      if dev.logical_id[0] == instance.primary_node:
3952 a8083063 Iustin Pop
        snode = dev.logical_id[1]
3953 a8083063 Iustin Pop
      else:
3954 a8083063 Iustin Pop
        snode = dev.logical_id[0]
3955 a8083063 Iustin Pop
3956 a8083063 Iustin Pop
    if snode:
3957 a8083063 Iustin Pop
      self.cfg.SetDiskID(dev, snode)
3958 a8083063 Iustin Pop
      dev_sstatus = rpc.call_blockdev_find(snode, dev)
3959 a8083063 Iustin Pop
    else:
3960 a8083063 Iustin Pop
      dev_sstatus = None
3961 a8083063 Iustin Pop
3962 a8083063 Iustin Pop
    if dev.children:
3963 a8083063 Iustin Pop
      dev_children = [self._ComputeDiskStatus(instance, snode, child)
3964 a8083063 Iustin Pop
                      for child in dev.children]
3965 a8083063 Iustin Pop
    else:
3966 a8083063 Iustin Pop
      dev_children = []
3967 a8083063 Iustin Pop
3968 a8083063 Iustin Pop
    data = {
3969 a8083063 Iustin Pop
      "iv_name": dev.iv_name,
3970 a8083063 Iustin Pop
      "dev_type": dev.dev_type,
3971 a8083063 Iustin Pop
      "logical_id": dev.logical_id,
3972 a8083063 Iustin Pop
      "physical_id": dev.physical_id,
3973 a8083063 Iustin Pop
      "pstatus": dev_pstatus,
3974 a8083063 Iustin Pop
      "sstatus": dev_sstatus,
3975 a8083063 Iustin Pop
      "children": dev_children,
3976 a8083063 Iustin Pop
      }
3977 a8083063 Iustin Pop
3978 a8083063 Iustin Pop
    return data
3979 a8083063 Iustin Pop
3980 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
3981 a8083063 Iustin Pop
    """Gather and return data"""
3982 a8083063 Iustin Pop
    result = {}
3983 a8083063 Iustin Pop
    for instance in self.wanted_instances:
3984 a8083063 Iustin Pop
      remote_info = rpc.call_instance_info(instance.primary_node,
3985 a8083063 Iustin Pop
                                                instance.name)
3986 a8083063 Iustin Pop
      if remote_info and "state" in remote_info:
3987 a8083063 Iustin Pop
        remote_state = "up"
3988 a8083063 Iustin Pop
      else:
3989 a8083063 Iustin Pop
        remote_state = "down"
3990 a8083063 Iustin Pop
      if instance.status == "down":
3991 a8083063 Iustin Pop
        config_state = "down"
3992 a8083063 Iustin Pop
      else:
3993 a8083063 Iustin Pop
        config_state = "up"
3994 a8083063 Iustin Pop
3995 a8083063 Iustin Pop
      disks = [self._ComputeDiskStatus(instance, None, device)
3996 a8083063 Iustin Pop
               for device in instance.disks]
3997 a8083063 Iustin Pop
3998 a8083063 Iustin Pop
      idict = {
3999 a8083063 Iustin Pop
        "name": instance.name,
4000 a8083063 Iustin Pop
        "config_state": config_state,
4001 a8083063 Iustin Pop
        "run_state": remote_state,
4002 a8083063 Iustin Pop
        "pnode": instance.primary_node,
4003 a8083063 Iustin Pop
        "snodes": instance.secondary_nodes,
4004 a8083063 Iustin Pop
        "os": instance.os,
4005 a8083063 Iustin Pop
        "memory": instance.memory,
4006 a8083063 Iustin Pop
        "nics": [(nic.mac, nic.ip, nic.bridge) for nic in instance.nics],
4007 a8083063 Iustin Pop
        "disks": disks,
4008 f55ff7ec Iustin Pop
        "vcpus": instance.vcpus,
4009 a8083063 Iustin Pop
        }
4010 a8083063 Iustin Pop
4011 a8340917 Iustin Pop
      htkind = self.sstore.GetHypervisorType()
4012 a8340917 Iustin Pop
      if htkind == constants.HT_XEN_PVM30:
4013 a8340917 Iustin Pop
        idict["kernel_path"] = instance.kernel_path
4014 a8340917 Iustin Pop
        idict["initrd_path"] = instance.initrd_path
4015 a8340917 Iustin Pop
4016 a8340917 Iustin Pop
      if htkind == constants.HT_XEN_HVM31:
4017 a8340917 Iustin Pop
        idict["hvm_boot_order"] = instance.hvm_boot_order
4018 a8340917 Iustin Pop
        idict["hvm_acpi"] = instance.hvm_acpi
4019 a8340917 Iustin Pop
        idict["hvm_pae"] = instance.hvm_pae
4020 a8340917 Iustin Pop
        idict["hvm_cdrom_image_path"] = instance.hvm_cdrom_image_path
4021 a8340917 Iustin Pop
4022 a8340917 Iustin Pop
      if htkind in constants.HTS_REQ_PORT:
4023 a8340917 Iustin Pop
        idict["vnc_bind_address"] = instance.vnc_bind_address
4024 a8340917 Iustin Pop
        idict["network_port"] = instance.network_port
4025 a8340917 Iustin Pop
4026 a8083063 Iustin Pop
      result[instance.name] = idict
4027 a8083063 Iustin Pop
4028 a8083063 Iustin Pop
    return result
4029 a8083063 Iustin Pop
4030 a8083063 Iustin Pop
4031 7767bbf5 Manuel Franceschini
class LUSetInstanceParams(LogicalUnit):
4032 a8083063 Iustin Pop
  """Modifies an instances's parameters.
4033 a8083063 Iustin Pop

4034 a8083063 Iustin Pop
  """
4035 a8083063 Iustin Pop
  HPATH = "instance-modify"
4036 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
4037 a8083063 Iustin Pop
  _OP_REQP = ["instance_name"]
4038 a8083063 Iustin Pop
4039 a8083063 Iustin Pop
  def BuildHooksEnv(self):
4040 a8083063 Iustin Pop
    """Build hooks env.
4041 a8083063 Iustin Pop

4042 a8083063 Iustin Pop
    This runs on the master, primary and secondaries.
4043 a8083063 Iustin Pop

4044 a8083063 Iustin Pop
    """
4045 396e1b78 Michael Hanselmann
    args = dict()
4046 a8083063 Iustin Pop
    if self.mem:
4047 396e1b78 Michael Hanselmann
      args['memory'] = self.mem
4048 a8083063 Iustin Pop
    if self.vcpus:
4049 396e1b78 Michael Hanselmann
      args['vcpus'] = self.vcpus
4050 ef756965 Iustin Pop
    if self.do_ip or self.do_bridge or self.mac:
4051 396e1b78 Michael Hanselmann
      if self.do_ip:
4052 396e1b78 Michael Hanselmann
        ip = self.ip
4053 396e1b78 Michael Hanselmann
      else:
4054 396e1b78 Michael Hanselmann
        ip = self.instance.nics[0].ip
4055 396e1b78 Michael Hanselmann
      if self.bridge:
4056 396e1b78 Michael Hanselmann
        bridge = self.bridge
4057 396e1b78 Michael Hanselmann
      else:
4058 396e1b78 Michael Hanselmann
        bridge = self.instance.nics[0].bridge
4059 ef756965 Iustin Pop
      if self.mac:
4060 ef756965 Iustin Pop
        mac = self.mac
4061 ef756965 Iustin Pop
      else:
4062 ef756965 Iustin Pop
        mac = self.instance.nics[0].mac
4063 ef756965 Iustin Pop
      args['nics'] = [(ip, bridge, mac)]
4064 396e1b78 Michael Hanselmann
    env = _BuildInstanceHookEnvByObject(self.instance, override=args)
4065 880478f8 Iustin Pop
    nl = [self.sstore.GetMasterNode(),
4066 a8083063 Iustin Pop
          self.instance.primary_node] + list(self.instance.secondary_nodes)
4067 a8083063 Iustin Pop
    return env, nl, nl
4068 a8083063 Iustin Pop
4069 a8083063 Iustin Pop
  def CheckPrereq(self):
4070 a8083063 Iustin Pop
    """Check prerequisites.
4071 a8083063 Iustin Pop

4072 a8083063 Iustin Pop
    This only checks the instance list against the existing names.
4073 a8083063 Iustin Pop

4074 a8083063 Iustin Pop
    """
4075 a8083063 Iustin Pop
    self.mem = getattr(self.op, "mem", None)
4076 a8083063 Iustin Pop
    self.vcpus = getattr(self.op, "vcpus", None)
4077 a8083063 Iustin Pop
    self.ip = getattr(self.op, "ip", None)
4078 1862d460 Alexander Schreiber
    self.mac = getattr(self.op, "mac", None)
4079 a8083063 Iustin Pop
    self.bridge = getattr(self.op, "bridge", None)
4080 973d7867 Iustin Pop
    self.kernel_path = getattr(self.op, "kernel_path", None)
4081 973d7867 Iustin Pop
    self.initrd_path = getattr(self.op, "initrd_path", None)
4082 25c5878d Alexander Schreiber
    self.hvm_boot_order = getattr(self.op, "hvm_boot_order", None)
4083 31a853d2 Iustin Pop
    self.hvm_acpi = getattr(self.op, "hvm_acpi", None)
4084 31a853d2 Iustin Pop
    self.hvm_pae = getattr(self.op, "hvm_pae", None)
4085 31a853d2 Iustin Pop
    self.hvm_cdrom_image_path = getattr(self.op, "hvm_cdrom_image_path", None)
4086 31a853d2 Iustin Pop
    self.vnc_bind_address = getattr(self.op, "vnc_bind_address", None)
4087 31a853d2 Iustin Pop
    all_parms = [self.mem, self.vcpus, self.ip, self.bridge, self.mac,
4088 31a853d2 Iustin Pop
                 self.kernel_path, self.initrd_path, self.hvm_boot_order,
4089 31a853d2 Iustin Pop
                 self.hvm_acpi, self.hvm_pae, self.hvm_cdrom_image_path,
4090 31a853d2 Iustin Pop
                 self.vnc_bind_address]
4091 31a853d2 Iustin Pop
    if all_parms.count(None) == len(all_parms):
4092 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("No changes submitted")
4093 a8083063 Iustin Pop
    if self.mem is not None:
4094 a8083063 Iustin Pop
      try:
4095 a8083063 Iustin Pop
        self.mem = int(self.mem)
4096 a8083063 Iustin Pop
      except ValueError, err:
4097 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Invalid memory size: %s" % str(err))
4098 a8083063 Iustin Pop
    if self.vcpus is not None:
4099 a8083063 Iustin Pop
      try:
4100 a8083063 Iustin Pop
        self.vcpus = int(self.vcpus)
4101 a8083063 Iustin Pop
      except ValueError, err:
4102 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Invalid vcpus number: %s" % str(err))
4103 a8083063 Iustin Pop
    if self.ip is not None:
4104 a8083063 Iustin Pop
      self.do_ip = True
4105 a8083063 Iustin Pop
      if self.ip.lower() == "none":
4106 a8083063 Iustin Pop
        self.ip = None
4107 a8083063 Iustin Pop
      else:
4108 a8083063 Iustin Pop
        if not utils.IsValidIP(self.ip):
4109 3ecf6786 Iustin Pop
          raise errors.OpPrereqError("Invalid IP address '%s'." % self.ip)
4110 a8083063 Iustin Pop
    else:
4111 a8083063 Iustin Pop
      self.do_ip = False
4112 ecb215b5 Michael Hanselmann
    self.do_bridge = (self.bridge is not None)
4113 1862d460 Alexander Schreiber
    if self.mac is not None:
4114 1862d460 Alexander Schreiber
      if self.cfg.IsMacInUse(self.mac):
4115 1862d460 Alexander Schreiber
        raise errors.OpPrereqError('MAC address %s already in use in cluster' %
4116 1862d460 Alexander Schreiber
                                   self.mac)
4117 1862d460 Alexander Schreiber
      if not utils.IsValidMac(self.mac):
4118 1862d460 Alexander Schreiber
        raise errors.OpPrereqError('Invalid MAC address %s' % self.mac)
4119 a8083063 Iustin Pop
4120 973d7867 Iustin Pop
    if self.kernel_path is not None:
4121 973d7867 Iustin Pop
      self.do_kernel_path = True
4122 973d7867 Iustin Pop
      if self.kernel_path == constants.VALUE_NONE:
4123 973d7867 Iustin Pop
        raise errors.OpPrereqError("Can't set instance to no kernel")
4124 973d7867 Iustin Pop
4125 973d7867 Iustin Pop
      if self.kernel_path != constants.VALUE_DEFAULT:
4126 973d7867 Iustin Pop
        if not os.path.isabs(self.kernel_path):
4127 ba4b62cf Iustin Pop
          raise errors.OpPrereqError("The kernel path must be an absolute"
4128 973d7867 Iustin Pop
                                    " filename")
4129 8cafeb26 Iustin Pop
    else:
4130 8cafeb26 Iustin Pop
      self.do_kernel_path = False
4131 973d7867 Iustin Pop
4132 973d7867 Iustin Pop
    if self.initrd_path is not None:
4133 973d7867 Iustin Pop
      self.do_initrd_path = True
4134 973d7867 Iustin Pop
      if self.initrd_path not in (constants.VALUE_NONE,
4135 973d7867 Iustin Pop
                                  constants.VALUE_DEFAULT):
4136 2bc22872 Iustin Pop
        if not os.path.isabs(self.initrd_path):
4137 ba4b62cf Iustin Pop
          raise errors.OpPrereqError("The initrd path must be an absolute"
4138 973d7867 Iustin Pop
                                    " filename")
4139 8cafeb26 Iustin Pop
    else:
4140 8cafeb26 Iustin Pop
      self.do_initrd_path = False
4141 973d7867 Iustin Pop
4142 25c5878d Alexander Schreiber
    # boot order verification
4143 25c5878d Alexander Schreiber
    if self.hvm_boot_order is not None:
4144 25c5878d Alexander Schreiber
      if self.hvm_boot_order != constants.VALUE_DEFAULT:
4145 25c5878d Alexander Schreiber
        if len(self.hvm_boot_order.strip("acdn")) != 0:
4146 25c5878d Alexander Schreiber
          raise errors.OpPrereqError("invalid boot order specified,"
4147 25c5878d Alexander Schreiber
                                     " must be one or more of [acdn]"
4148 25c5878d Alexander Schreiber
                                     " or 'default'")
4149 25c5878d Alexander Schreiber
4150 31a853d2 Iustin Pop
    # hvm_cdrom_image_path verification
4151 31a853d2 Iustin Pop
    if self.op.hvm_cdrom_image_path is not None:
4152 31a853d2 Iustin Pop
      if not os.path.isabs(self.op.hvm_cdrom_image_path):
4153 31a853d2 Iustin Pop
        raise errors.OpPrereqError("The path to the HVM CDROM image must"
4154 31a853d2 Iustin Pop
                                   " be an absolute path or None, not %s" %
4155 31a853d2 Iustin Pop
                                   self.op.hvm_cdrom_image_path)
4156 31a853d2 Iustin Pop
      if not os.path.isfile(self.op.hvm_cdrom_image_path):
4157 31a853d2 Iustin Pop
        raise errors.OpPrereqError("The HVM CDROM image must either be a"
4158 31a853d2 Iustin Pop
                                   " regular file or a symlink pointing to"
4159 31a853d2 Iustin Pop
                                   " an existing regular file, not %s" %
4160 31a853d2 Iustin Pop
                                   self.op.hvm_cdrom_image_path)
4161 31a853d2 Iustin Pop
4162 31a853d2 Iustin Pop
    # vnc_bind_address verification
4163 31a853d2 Iustin Pop
    if self.op.vnc_bind_address is not None:
4164 31a853d2 Iustin Pop
      if not utils.IsValidIP(self.op.vnc_bind_address):
4165 31a853d2 Iustin Pop
        raise errors.OpPrereqError("given VNC bind address '%s' doesn't look"
4166 31a853d2 Iustin Pop
                                   " like a valid IP address" %
4167 31a853d2 Iustin Pop
                                   self.op.vnc_bind_address)
4168 31a853d2 Iustin Pop
4169 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
4170 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
4171 a8083063 Iustin Pop
    if instance is None:
4172 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("No such instance name '%s'" %
4173 3ecf6786 Iustin Pop
                                 self.op.instance_name)
4174 a8083063 Iustin Pop
    self.op.instance_name = instance.name
4175 a8083063 Iustin Pop
    self.instance = instance
4176 a8083063 Iustin Pop
    return
4177 a8083063 Iustin Pop
4178 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
4179 a8083063 Iustin Pop
    """Modifies an instance.
4180 a8083063 Iustin Pop

4181 a8083063 Iustin Pop
    All parameters take effect only at the next restart of the instance.
4182 a8083063 Iustin Pop
    """
4183 a8083063 Iustin Pop
    result = []
4184 a8083063 Iustin Pop
    instance = self.instance
4185 a8083063 Iustin Pop
    if self.mem:
4186 a8083063 Iustin Pop
      instance.memory = self.mem
4187 a8083063 Iustin Pop
      result.append(("mem", self.mem))
4188 a8083063 Iustin Pop
    if self.vcpus:
4189 a8083063 Iustin Pop
      instance.vcpus = self.vcpus
4190 a8083063 Iustin Pop
      result.append(("vcpus",  self.vcpus))
4191 a8083063 Iustin Pop
    if self.do_ip:
4192 a8083063 Iustin Pop
      instance.nics[0].ip = self.ip
4193 a8083063 Iustin Pop
      result.append(("ip", self.ip))
4194 a8083063 Iustin Pop
    if self.bridge:
4195 a8083063 Iustin Pop
      instance.nics[0].bridge = self.bridge
4196 a8083063 Iustin Pop
      result.append(("bridge", self.bridge))
4197 1862d460 Alexander Schreiber
    if self.mac:
4198 1862d460 Alexander Schreiber
      instance.nics[0].mac = self.mac
4199 1862d460 Alexander Schreiber
      result.append(("mac", self.mac))
4200 973d7867 Iustin Pop
    if self.do_kernel_path:
4201 973d7867 Iustin Pop
      instance.kernel_path = self.kernel_path
4202 973d7867 Iustin Pop
      result.append(("kernel_path", self.kernel_path))
4203 973d7867 Iustin Pop
    if self.do_initrd_path:
4204 973d7867 Iustin Pop
      instance.initrd_path = self.initrd_path
4205 973d7867 Iustin Pop
      result.append(("initrd_path", self.initrd_path))
4206 25c5878d Alexander Schreiber
    if self.hvm_boot_order:
4207 25c5878d Alexander Schreiber
      if self.hvm_boot_order == constants.VALUE_DEFAULT:
4208 25c5878d Alexander Schreiber
        instance.hvm_boot_order = None
4209 25c5878d Alexander Schreiber
      else:
4210 25c5878d Alexander Schreiber
        instance.hvm_boot_order = self.hvm_boot_order
4211 25c5878d Alexander Schreiber
      result.append(("hvm_boot_order", self.hvm_boot_order))
4212 31a853d2 Iustin Pop
    if self.hvm_acpi:
4213 ec1ba002 Iustin Pop
      instance.hvm_acpi = self.hvm_acpi
4214 31a853d2 Iustin Pop
      result.append(("hvm_acpi", self.hvm_acpi))
4215 31a853d2 Iustin Pop
    if self.hvm_pae:
4216 ec1ba002 Iustin Pop
      instance.hvm_pae = self.hvm_pae
4217 31a853d2 Iustin Pop
      result.append(("hvm_pae", self.hvm_pae))
4218 31a853d2 Iustin Pop
    if self.hvm_cdrom_image_path:
4219 ec1ba002 Iustin Pop
      instance.hvm_cdrom_image_path = self.hvm_cdrom_image_path
4220 31a853d2 Iustin Pop
      result.append(("hvm_cdrom_image_path", self.hvm_cdrom_image_path))
4221 31a853d2 Iustin Pop
    if self.vnc_bind_address:
4222 31a853d2 Iustin Pop
      instance.vnc_bind_address = self.vnc_bind_address
4223 31a853d2 Iustin Pop
      result.append(("vnc_bind_address", self.vnc_bind_address))
4224 a8083063 Iustin Pop
4225 a8083063 Iustin Pop
    self.cfg.AddInstance(instance)
4226 a8083063 Iustin Pop
4227 a8083063 Iustin Pop
    return result
4228 a8083063 Iustin Pop
4229 a8083063 Iustin Pop
4230 a8083063 Iustin Pop
class LUQueryExports(NoHooksLU):
4231 a8083063 Iustin Pop
  """Query the exports list
4232 a8083063 Iustin Pop

4233 a8083063 Iustin Pop
  """
4234 a8083063 Iustin Pop
  _OP_REQP = []
4235 a8083063 Iustin Pop
4236 a8083063 Iustin Pop
  def CheckPrereq(self):
4237 a8083063 Iustin Pop
    """Check that the nodelist contains only existing nodes.
4238 a8083063 Iustin Pop

4239 a8083063 Iustin Pop
    """
4240 dcb93971 Michael Hanselmann
    self.nodes = _GetWantedNodes(self, getattr(self.op, "nodes", None))
4241 a8083063 Iustin Pop
4242 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
4243 a8083063 Iustin Pop
    """Compute the list of all the exported system images.
4244 a8083063 Iustin Pop

4245 a8083063 Iustin Pop
    Returns:
4246 a8083063 Iustin Pop
      a dictionary with the structure node->(export-list)
4247 a8083063 Iustin Pop
      where export-list is a list of the instances exported on
4248 a8083063 Iustin Pop
      that node.
4249 a8083063 Iustin Pop

4250 a8083063 Iustin Pop
    """
4251 a7ba5e53 Iustin Pop
    return rpc.call_export_list(self.nodes)
4252 a8083063 Iustin Pop
4253 a8083063 Iustin Pop
4254 a8083063 Iustin Pop
class LUExportInstance(LogicalUnit):
4255 a8083063 Iustin Pop
  """Export an instance to an image in the cluster.
4256 a8083063 Iustin Pop

4257 a8083063 Iustin Pop
  """
4258 a8083063 Iustin Pop
  HPATH = "instance-export"
4259 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
4260 a8083063 Iustin Pop
  _OP_REQP = ["instance_name", "target_node", "shutdown"]
4261 a8083063 Iustin Pop
4262 a8083063 Iustin Pop
  def BuildHooksEnv(self):
4263 a8083063 Iustin Pop
    """Build hooks env.
4264 a8083063 Iustin Pop

4265 a8083063 Iustin Pop
    This will run on the master, primary node and target node.
4266 a8083063 Iustin Pop

4267 a8083063 Iustin Pop
    """
4268 a8083063 Iustin Pop
    env = {
4269 a8083063 Iustin Pop
      "EXPORT_NODE": self.op.target_node,
4270 a8083063 Iustin Pop
      "EXPORT_DO_SHUTDOWN": self.op.shutdown,
4271 a8083063 Iustin Pop
      }
4272 396e1b78 Michael Hanselmann
    env.update(_BuildInstanceHookEnvByObject(self.instance))
4273 880478f8 Iustin Pop
    nl = [self.sstore.GetMasterNode(), self.instance.primary_node,
4274 a8083063 Iustin Pop
          self.op.target_node]
4275 a8083063 Iustin Pop
    return env, nl, nl
4276 a8083063 Iustin Pop
4277 a8083063 Iustin Pop
  def CheckPrereq(self):
4278 a8083063 Iustin Pop
    """Check prerequisites.
4279 a8083063 Iustin Pop

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

4282 a8083063 Iustin Pop
    """
4283 a8083063 Iustin Pop
    instance_name = self.cfg.ExpandInstanceName(self.op.instance_name)
4284 a8083063 Iustin Pop
    self.instance = self.cfg.GetInstanceInfo(instance_name)
4285 a8083063 Iustin Pop
    if self.instance is None:
4286 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not found" %
4287 3ecf6786 Iustin Pop
                                 self.op.instance_name)
4288 a8083063 Iustin Pop
4289 a8083063 Iustin Pop
    # node verification
4290 a8083063 Iustin Pop
    dst_node_short = self.cfg.ExpandNodeName(self.op.target_node)
4291 a8083063 Iustin Pop
    self.dst_node = self.cfg.GetNodeInfo(dst_node_short)
4292 a8083063 Iustin Pop
4293 a8083063 Iustin Pop
    if self.dst_node is None:
4294 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Destination node '%s' is unknown." %
4295 3ecf6786 Iustin Pop
                                 self.op.target_node)
4296 a8083063 Iustin Pop
    self.op.target_node = self.dst_node.name
4297 a8083063 Iustin Pop
4298 b6023d6c Manuel Franceschini
    # instance disk type verification
4299 b6023d6c Manuel Franceschini
    for disk in self.instance.disks:
4300 b6023d6c Manuel Franceschini
      if disk.dev_type == constants.LD_FILE:
4301 b6023d6c Manuel Franceschini
        raise errors.OpPrereqError("Export not supported for instances with"
4302 b6023d6c Manuel Franceschini
                                   " file-based disks")
4303 b6023d6c Manuel Franceschini
4304 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
4305 a8083063 Iustin Pop
    """Export an instance to an image in the cluster.
4306 a8083063 Iustin Pop

4307 a8083063 Iustin Pop
    """
4308 a8083063 Iustin Pop
    instance = self.instance
4309 a8083063 Iustin Pop
    dst_node = self.dst_node
4310 a8083063 Iustin Pop
    src_node = instance.primary_node
4311 a8083063 Iustin Pop
    if self.op.shutdown:
4312 fb300fb7 Guido Trotter
      # shutdown the instance, but not the disks
4313 fb300fb7 Guido Trotter
      if not rpc.call_instance_shutdown(src_node, instance):
4314 fb300fb7 Guido Trotter
         raise errors.OpExecError("Could not shutdown instance %s on node %s" %
4315 b4de68a9 Iustin Pop
                                  (instance.name, src_node))
4316 a8083063 Iustin Pop
4317 a8083063 Iustin Pop
    vgname = self.cfg.GetVGName()
4318 a8083063 Iustin Pop
4319 a8083063 Iustin Pop
    snap_disks = []
4320 a8083063 Iustin Pop
4321 a8083063 Iustin Pop
    try:
4322 a8083063 Iustin Pop
      for disk in instance.disks:
4323 a8083063 Iustin Pop
        if disk.iv_name == "sda":
4324 a8083063 Iustin Pop
          # new_dev_name will be a snapshot of an lvm leaf of the one we passed
4325 a8083063 Iustin Pop
          new_dev_name = rpc.call_blockdev_snapshot(src_node, disk)
4326 a8083063 Iustin Pop
4327 a8083063 Iustin Pop
          if not new_dev_name:
4328 a8083063 Iustin Pop
            logger.Error("could not snapshot block device %s on node %s" %
4329 a8083063 Iustin Pop
                         (disk.logical_id[1], src_node))
4330 a8083063 Iustin Pop
          else:
4331 fe96220b Iustin Pop
            new_dev = objects.Disk(dev_type=constants.LD_LV, size=disk.size,
4332 a8083063 Iustin Pop
                                      logical_id=(vgname, new_dev_name),
4333 a8083063 Iustin Pop
                                      physical_id=(vgname, new_dev_name),
4334 a8083063 Iustin Pop
                                      iv_name=disk.iv_name)
4335 a8083063 Iustin Pop
            snap_disks.append(new_dev)
4336 a8083063 Iustin Pop
4337 a8083063 Iustin Pop
    finally:
4338 fb300fb7 Guido Trotter
      if self.op.shutdown and instance.status == "up":
4339 fb300fb7 Guido Trotter
        if not rpc.call_instance_start(src_node, instance, None):
4340 fb300fb7 Guido Trotter
          _ShutdownInstanceDisks(instance, self.cfg)
4341 fb300fb7 Guido Trotter
          raise errors.OpExecError("Could not start instance")
4342 a8083063 Iustin Pop
4343 a8083063 Iustin Pop
    # TODO: check for size
4344 a8083063 Iustin Pop
4345 a8083063 Iustin Pop
    for dev in snap_disks:
4346 16687b98 Manuel Franceschini
      if not rpc.call_snapshot_export(src_node, dev, dst_node.name, instance):
4347 16687b98 Manuel Franceschini
        logger.Error("could not export block device %s from node %s to node %s"
4348 16687b98 Manuel Franceschini
                     % (dev.logical_id[1], src_node, dst_node.name))
4349 a8083063 Iustin Pop
      if not rpc.call_blockdev_remove(src_node, dev):
4350 16687b98 Manuel Franceschini
        logger.Error("could not remove snapshot block device %s from node %s" %
4351 16687b98 Manuel Franceschini
                     (dev.logical_id[1], src_node))
4352 a8083063 Iustin Pop
4353 a8083063 Iustin Pop
    if not rpc.call_finalize_export(dst_node.name, instance, snap_disks):
4354 a8083063 Iustin Pop
      logger.Error("could not finalize export for instance %s on node %s" %
4355 a8083063 Iustin Pop
                   (instance.name, dst_node.name))
4356 a8083063 Iustin Pop
4357 a8083063 Iustin Pop
    nodelist = self.cfg.GetNodeList()
4358 a8083063 Iustin Pop
    nodelist.remove(dst_node.name)
4359 a8083063 Iustin Pop
4360 a8083063 Iustin Pop
    # on one-node clusters nodelist will be empty after the removal
4361 a8083063 Iustin Pop
    # if we proceed the backup would be removed because OpQueryExports
4362 a8083063 Iustin Pop
    # substitutes an empty list with the full cluster node list.
4363 a8083063 Iustin Pop
    if nodelist:
4364 a8083063 Iustin Pop
      op = opcodes.OpQueryExports(nodes=nodelist)
4365 5bfac263 Iustin Pop
      exportlist = self.proc.ChainOpCode(op)
4366 a8083063 Iustin Pop
      for node in exportlist:
4367 a8083063 Iustin Pop
        if instance.name in exportlist[node]:
4368 a8083063 Iustin Pop
          if not rpc.call_export_remove(node, instance.name):
4369 a8083063 Iustin Pop
            logger.Error("could not remove older export for instance %s"
4370 a8083063 Iustin Pop
                         " on node %s" % (instance.name, node))
4371 5c947f38 Iustin Pop
4372 5c947f38 Iustin Pop
4373 9ac99fda Guido Trotter
class LURemoveExport(NoHooksLU):
4374 9ac99fda Guido Trotter
  """Remove exports related to the named instance.
4375 9ac99fda Guido Trotter

4376 9ac99fda Guido Trotter
  """
4377 9ac99fda Guido Trotter
  _OP_REQP = ["instance_name"]
4378 9ac99fda Guido Trotter
4379 9ac99fda Guido Trotter
  def CheckPrereq(self):
4380 9ac99fda Guido Trotter
    """Check prerequisites.
4381 9ac99fda Guido Trotter
    """
4382 9ac99fda Guido Trotter
    pass
4383 9ac99fda Guido Trotter
4384 9ac99fda Guido Trotter
  def Exec(self, feedback_fn):
4385 9ac99fda Guido Trotter
    """Remove any export.
4386 9ac99fda Guido Trotter

4387 9ac99fda Guido Trotter
    """
4388 9ac99fda Guido Trotter
    instance_name = self.cfg.ExpandInstanceName(self.op.instance_name)
4389 9ac99fda Guido Trotter
    # If the instance was not found we'll try with the name that was passed in.
4390 9ac99fda Guido Trotter
    # This will only work if it was an FQDN, though.
4391 9ac99fda Guido Trotter
    fqdn_warn = False
4392 9ac99fda Guido Trotter
    if not instance_name:
4393 9ac99fda Guido Trotter
      fqdn_warn = True
4394 9ac99fda Guido Trotter
      instance_name = self.op.instance_name
4395 9ac99fda Guido Trotter
4396 9ac99fda Guido Trotter
    op = opcodes.OpQueryExports(nodes=[])
4397 9ac99fda Guido Trotter
    exportlist = self.proc.ChainOpCode(op)
4398 9ac99fda Guido Trotter
    found = False
4399 9ac99fda Guido Trotter
    for node in exportlist:
4400 9ac99fda Guido Trotter
      if instance_name in exportlist[node]:
4401 9ac99fda Guido Trotter
        found = True
4402 9ac99fda Guido Trotter
        if not rpc.call_export_remove(node, instance_name):
4403 9ac99fda Guido Trotter
          logger.Error("could not remove export for instance %s"
4404 9ac99fda Guido Trotter
                       " on node %s" % (instance_name, node))
4405 9ac99fda Guido Trotter
4406 9ac99fda Guido Trotter
    if fqdn_warn and not found:
4407 9ac99fda Guido Trotter
      feedback_fn("Export not found. If trying to remove an export belonging"
4408 9ac99fda Guido Trotter
                  " to a deleted instance please use its Fully Qualified"
4409 9ac99fda Guido Trotter
                  " Domain Name.")
4410 9ac99fda Guido Trotter
4411 9ac99fda Guido Trotter
4412 5c947f38 Iustin Pop
class TagsLU(NoHooksLU):
4413 5c947f38 Iustin Pop
  """Generic tags LU.
4414 5c947f38 Iustin Pop

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

4417 5c947f38 Iustin Pop
  """
4418 5c947f38 Iustin Pop
  def CheckPrereq(self):
4419 5c947f38 Iustin Pop
    """Check prerequisites.
4420 5c947f38 Iustin Pop

4421 5c947f38 Iustin Pop
    """
4422 5c947f38 Iustin Pop
    if self.op.kind == constants.TAG_CLUSTER:
4423 5c947f38 Iustin Pop
      self.target = self.cfg.GetClusterInfo()
4424 5c947f38 Iustin Pop
    elif self.op.kind == constants.TAG_NODE:
4425 5c947f38 Iustin Pop
      name = self.cfg.ExpandNodeName(self.op.name)
4426 5c947f38 Iustin Pop
      if name is None:
4427 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Invalid node name (%s)" %
4428 3ecf6786 Iustin Pop
                                   (self.op.name,))
4429 5c947f38 Iustin Pop
      self.op.name = name
4430 5c947f38 Iustin Pop
      self.target = self.cfg.GetNodeInfo(name)
4431 5c947f38 Iustin Pop
    elif self.op.kind == constants.TAG_INSTANCE:
4432 8f684e16 Iustin Pop
      name = self.cfg.ExpandInstanceName(self.op.name)
4433 5c947f38 Iustin Pop
      if name is None:
4434 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Invalid instance name (%s)" %
4435 3ecf6786 Iustin Pop
                                   (self.op.name,))
4436 5c947f38 Iustin Pop
      self.op.name = name
4437 5c947f38 Iustin Pop
      self.target = self.cfg.GetInstanceInfo(name)
4438 5c947f38 Iustin Pop
    else:
4439 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Wrong tag type requested (%s)" %
4440 3ecf6786 Iustin Pop
                                 str(self.op.kind))
4441 5c947f38 Iustin Pop
4442 5c947f38 Iustin Pop
4443 5c947f38 Iustin Pop
class LUGetTags(TagsLU):
4444 5c947f38 Iustin Pop
  """Returns the tags of a given object.
4445 5c947f38 Iustin Pop

4446 5c947f38 Iustin Pop
  """
4447 5c947f38 Iustin Pop
  _OP_REQP = ["kind", "name"]
4448 5c947f38 Iustin Pop
4449 5c947f38 Iustin Pop
  def Exec(self, feedback_fn):
4450 5c947f38 Iustin Pop
    """Returns the tag list.
4451 5c947f38 Iustin Pop

4452 5c947f38 Iustin Pop
    """
4453 5c947f38 Iustin Pop
    return self.target.GetTags()
4454 5c947f38 Iustin Pop
4455 5c947f38 Iustin Pop
4456 73415719 Iustin Pop
class LUSearchTags(NoHooksLU):
4457 73415719 Iustin Pop
  """Searches the tags for a given pattern.
4458 73415719 Iustin Pop

4459 73415719 Iustin Pop
  """
4460 73415719 Iustin Pop
  _OP_REQP = ["pattern"]
4461 73415719 Iustin Pop
4462 73415719 Iustin Pop
  def CheckPrereq(self):
4463 73415719 Iustin Pop
    """Check prerequisites.
4464 73415719 Iustin Pop

4465 73415719 Iustin Pop
    This checks the pattern passed for validity by compiling it.
4466 73415719 Iustin Pop

4467 73415719 Iustin Pop
    """
4468 73415719 Iustin Pop
    try:
4469 73415719 Iustin Pop
      self.re = re.compile(self.op.pattern)
4470 73415719 Iustin Pop
    except re.error, err:
4471 73415719 Iustin Pop
      raise errors.OpPrereqError("Invalid search pattern '%s': %s" %
4472 73415719 Iustin Pop
                                 (self.op.pattern, err))
4473 73415719 Iustin Pop
4474 73415719 Iustin Pop
  def Exec(self, feedback_fn):
4475 73415719 Iustin Pop
    """Returns the tag list.
4476 73415719 Iustin Pop

4477 73415719 Iustin Pop
    """
4478 73415719 Iustin Pop
    cfg = self.cfg
4479 73415719 Iustin Pop
    tgts = [("/cluster", cfg.GetClusterInfo())]
4480 73415719 Iustin Pop
    ilist = [cfg.GetInstanceInfo(name) for name in cfg.GetInstanceList()]
4481 73415719 Iustin Pop
    tgts.extend([("/instances/%s" % i.name, i) for i in ilist])
4482 73415719 Iustin Pop
    nlist = [cfg.GetNodeInfo(name) for name in cfg.GetNodeList()]
4483 73415719 Iustin Pop
    tgts.extend([("/nodes/%s" % n.name, n) for n in nlist])
4484 73415719 Iustin Pop
    results = []
4485 73415719 Iustin Pop
    for path, target in tgts:
4486 73415719 Iustin Pop
      for tag in target.GetTags():
4487 73415719 Iustin Pop
        if self.re.search(tag):
4488 73415719 Iustin Pop
          results.append((path, tag))
4489 73415719 Iustin Pop
    return results
4490 73415719 Iustin Pop
4491 73415719 Iustin Pop
4492 f27302fa Iustin Pop
class LUAddTags(TagsLU):
4493 5c947f38 Iustin Pop
  """Sets a tag on a given object.
4494 5c947f38 Iustin Pop

4495 5c947f38 Iustin Pop
  """
4496 f27302fa Iustin Pop
  _OP_REQP = ["kind", "name", "tags"]
4497 5c947f38 Iustin Pop
4498 5c947f38 Iustin Pop
  def CheckPrereq(self):
4499 5c947f38 Iustin Pop
    """Check prerequisites.
4500 5c947f38 Iustin Pop

4501 5c947f38 Iustin Pop
    This checks the type and length of the tag name and value.
4502 5c947f38 Iustin Pop

4503 5c947f38 Iustin Pop
    """
4504 5c947f38 Iustin Pop
    TagsLU.CheckPrereq(self)
4505 f27302fa Iustin Pop
    for tag in self.op.tags:
4506 f27302fa Iustin Pop
      objects.TaggableObject.ValidateTag(tag)
4507 5c947f38 Iustin Pop
4508 5c947f38 Iustin Pop
  def Exec(self, feedback_fn):
4509 5c947f38 Iustin Pop
    """Sets the tag.
4510 5c947f38 Iustin Pop

4511 5c947f38 Iustin Pop
    """
4512 5c947f38 Iustin Pop
    try:
4513 f27302fa Iustin Pop
      for tag in self.op.tags:
4514 f27302fa Iustin Pop
        self.target.AddTag(tag)
4515 5c947f38 Iustin Pop
    except errors.TagError, err:
4516 3ecf6786 Iustin Pop
      raise errors.OpExecError("Error while setting tag: %s" % str(err))
4517 5c947f38 Iustin Pop
    try:
4518 5c947f38 Iustin Pop
      self.cfg.Update(self.target)
4519 5c947f38 Iustin Pop
    except errors.ConfigurationError:
4520 3ecf6786 Iustin Pop
      raise errors.OpRetryError("There has been a modification to the"
4521 3ecf6786 Iustin Pop
                                " config file and the operation has been"
4522 3ecf6786 Iustin Pop
                                " aborted. Please retry.")
4523 5c947f38 Iustin Pop
4524 5c947f38 Iustin Pop
4525 f27302fa Iustin Pop
class LUDelTags(TagsLU):
4526 f27302fa Iustin Pop
  """Delete a list of tags from a given object.
4527 5c947f38 Iustin Pop

4528 5c947f38 Iustin Pop
  """
4529 f27302fa Iustin Pop
  _OP_REQP = ["kind", "name", "tags"]
4530 5c947f38 Iustin Pop
4531 5c947f38 Iustin Pop
  def CheckPrereq(self):
4532 5c947f38 Iustin Pop
    """Check prerequisites.
4533 5c947f38 Iustin Pop

4534 5c947f38 Iustin Pop
    This checks that we have the given tag.
4535 5c947f38 Iustin Pop

4536 5c947f38 Iustin Pop
    """
4537 5c947f38 Iustin Pop
    TagsLU.CheckPrereq(self)
4538 f27302fa Iustin Pop
    for tag in self.op.tags:
4539 f27302fa Iustin Pop
      objects.TaggableObject.ValidateTag(tag)
4540 f27302fa Iustin Pop
    del_tags = frozenset(self.op.tags)
4541 f27302fa Iustin Pop
    cur_tags = self.target.GetTags()
4542 f27302fa Iustin Pop
    if not del_tags <= cur_tags:
4543 f27302fa Iustin Pop
      diff_tags = del_tags - cur_tags
4544 f27302fa Iustin Pop
      diff_names = ["'%s'" % tag for tag in diff_tags]
4545 f27302fa Iustin Pop
      diff_names.sort()
4546 f27302fa Iustin Pop
      raise errors.OpPrereqError("Tag(s) %s not found" %
4547 f27302fa Iustin Pop
                                 (",".join(diff_names)))
4548 5c947f38 Iustin Pop
4549 5c947f38 Iustin Pop
  def Exec(self, feedback_fn):
4550 5c947f38 Iustin Pop
    """Remove the tag from the object.
4551 5c947f38 Iustin Pop

4552 5c947f38 Iustin Pop
    """
4553 f27302fa Iustin Pop
    for tag in self.op.tags:
4554 f27302fa Iustin Pop
      self.target.RemoveTag(tag)
4555 5c947f38 Iustin Pop
    try:
4556 5c947f38 Iustin Pop
      self.cfg.Update(self.target)
4557 5c947f38 Iustin Pop
    except errors.ConfigurationError:
4558 3ecf6786 Iustin Pop
      raise errors.OpRetryError("There has been a modification to the"
4559 3ecf6786 Iustin Pop
                                " config file and the operation has been"
4560 3ecf6786 Iustin Pop
                                " aborted. Please retry.")
4561 06009e27 Iustin Pop
4562 06009e27 Iustin Pop
class LUTestDelay(NoHooksLU):
4563 06009e27 Iustin Pop
  """Sleep for a specified amount of time.
4564 06009e27 Iustin Pop

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

4568 06009e27 Iustin Pop
  """
4569 06009e27 Iustin Pop
  _OP_REQP = ["duration", "on_master", "on_nodes"]
4570 06009e27 Iustin Pop
4571 06009e27 Iustin Pop
  def CheckPrereq(self):
4572 06009e27 Iustin Pop
    """Check prerequisites.
4573 06009e27 Iustin Pop

4574 06009e27 Iustin Pop
    This checks that we have a good list of nodes and/or the duration
4575 06009e27 Iustin Pop
    is valid.
4576 06009e27 Iustin Pop

4577 06009e27 Iustin Pop
    """
4578 06009e27 Iustin Pop
4579 06009e27 Iustin Pop
    if self.op.on_nodes:
4580 06009e27 Iustin Pop
      self.op.on_nodes = _GetWantedNodes(self, self.op.on_nodes)
4581 06009e27 Iustin Pop
4582 06009e27 Iustin Pop
  def Exec(self, feedback_fn):
4583 06009e27 Iustin Pop
    """Do the actual sleep.
4584 06009e27 Iustin Pop

4585 06009e27 Iustin Pop
    """
4586 06009e27 Iustin Pop
    if self.op.on_master:
4587 06009e27 Iustin Pop
      if not utils.TestDelay(self.op.duration):
4588 06009e27 Iustin Pop
        raise errors.OpExecError("Error during master delay test")
4589 06009e27 Iustin Pop
    if self.op.on_nodes:
4590 06009e27 Iustin Pop
      result = rpc.call_test_delay(self.op.on_nodes, self.op.duration)
4591 06009e27 Iustin Pop
      if not result:
4592 06009e27 Iustin Pop
        raise errors.OpExecError("Complete failure from rpc call")
4593 06009e27 Iustin Pop
      for node, node_result in result.items():
4594 06009e27 Iustin Pop
        if not node_result:
4595 06009e27 Iustin Pop
          raise errors.OpExecError("Failure during rpc call to node %s,"
4596 06009e27 Iustin Pop
                                   " result: %s" % (node, node_result))
4597 d61df03e Iustin Pop
4598 d61df03e Iustin Pop
4599 d1c2dd75 Iustin Pop
class IAllocator(object):
4600 d1c2dd75 Iustin Pop
  """IAllocator framework.
4601 d61df03e Iustin Pop

4602 d1c2dd75 Iustin Pop
  An IAllocator instance has three sets of attributes:
4603 d1c2dd75 Iustin Pop
    - cfg/sstore that are needed to query the cluster
4604 d1c2dd75 Iustin Pop
    - input data (all members of the _KEYS class attribute are required)
4605 d1c2dd75 Iustin Pop
    - four buffer attributes (in|out_data|text), that represent the
4606 d1c2dd75 Iustin Pop
      input (to the external script) in text and data structure format,
4607 d1c2dd75 Iustin Pop
      and the output from it, again in two formats
4608 d1c2dd75 Iustin Pop
    - the result variables from the script (success, info, nodes) for
4609 d1c2dd75 Iustin Pop
      easy usage
4610 d61df03e Iustin Pop

4611 d61df03e Iustin Pop
  """
4612 29859cb7 Iustin Pop
  _ALLO_KEYS = [
4613 d1c2dd75 Iustin Pop
    "mem_size", "disks", "disk_template",
4614 d1c2dd75 Iustin Pop
    "os", "tags", "nics", "vcpus",
4615 d1c2dd75 Iustin Pop
    ]
4616 29859cb7 Iustin Pop
  _RELO_KEYS = [
4617 29859cb7 Iustin Pop
    "relocate_from",
4618 29859cb7 Iustin Pop
    ]
4619 d1c2dd75 Iustin Pop
4620 29859cb7 Iustin Pop
  def __init__(self, cfg, sstore, mode, name, **kwargs):
4621 d1c2dd75 Iustin Pop
    self.cfg = cfg
4622 d1c2dd75 Iustin Pop
    self.sstore = sstore
4623 d1c2dd75 Iustin Pop
    # init buffer variables
4624 d1c2dd75 Iustin Pop
    self.in_text = self.out_text = self.in_data = self.out_data = None
4625 d1c2dd75 Iustin Pop
    # init all input fields so that pylint is happy
4626 29859cb7 Iustin Pop
    self.mode = mode
4627 29859cb7 Iustin Pop
    self.name = name
4628 d1c2dd75 Iustin Pop
    self.mem_size = self.disks = self.disk_template = None
4629 d1c2dd75 Iustin Pop
    self.os = self.tags = self.nics = self.vcpus = None
4630 29859cb7 Iustin Pop
    self.relocate_from = None
4631 27579978 Iustin Pop
    # computed fields
4632 27579978 Iustin Pop
    self.required_nodes = None
4633 d1c2dd75 Iustin Pop
    # init result fields
4634 d1c2dd75 Iustin Pop
    self.success = self.info = self.nodes = None
4635 29859cb7 Iustin Pop
    if self.mode == constants.IALLOCATOR_MODE_ALLOC:
4636 29859cb7 Iustin Pop
      keyset = self._ALLO_KEYS
4637 29859cb7 Iustin Pop
    elif self.mode == constants.IALLOCATOR_MODE_RELOC:
4638 29859cb7 Iustin Pop
      keyset = self._RELO_KEYS
4639 29859cb7 Iustin Pop
    else:
4640 29859cb7 Iustin Pop
      raise errors.ProgrammerError("Unknown mode '%s' passed to the"
4641 29859cb7 Iustin Pop
                                   " IAllocator" % self.mode)
4642 d1c2dd75 Iustin Pop
    for key in kwargs:
4643 29859cb7 Iustin Pop
      if key not in keyset:
4644 d1c2dd75 Iustin Pop
        raise errors.ProgrammerError("Invalid input parameter '%s' to"
4645 d1c2dd75 Iustin Pop
                                     " IAllocator" % key)
4646 d1c2dd75 Iustin Pop
      setattr(self, key, kwargs[key])
4647 29859cb7 Iustin Pop
    for key in keyset:
4648 d1c2dd75 Iustin Pop
      if key not in kwargs:
4649 d1c2dd75 Iustin Pop
        raise errors.ProgrammerError("Missing input parameter '%s' to"
4650 d1c2dd75 Iustin Pop
                                     " IAllocator" % key)
4651 d1c2dd75 Iustin Pop
    self._BuildInputData()
4652 d1c2dd75 Iustin Pop
4653 d1c2dd75 Iustin Pop
  def _ComputeClusterData(self):
4654 d1c2dd75 Iustin Pop
    """Compute the generic allocator input data.
4655 d1c2dd75 Iustin Pop

4656 d1c2dd75 Iustin Pop
    This is the data that is independent of the actual operation.
4657 d1c2dd75 Iustin Pop

4658 d1c2dd75 Iustin Pop
    """
4659 d1c2dd75 Iustin Pop
    cfg = self.cfg
4660 d1c2dd75 Iustin Pop
    # cluster data
4661 d1c2dd75 Iustin Pop
    data = {
4662 d1c2dd75 Iustin Pop
      "version": 1,
4663 d1c2dd75 Iustin Pop
      "cluster_name": self.sstore.GetClusterName(),
4664 d1c2dd75 Iustin Pop
      "cluster_tags": list(cfg.GetClusterInfo().GetTags()),
4665 6286519f Iustin Pop
      "hypervisor_type": self.sstore.GetHypervisorType(),
4666 d1c2dd75 Iustin Pop
      # we don't have job IDs
4667 d61df03e Iustin Pop
      }
4668 d61df03e Iustin Pop
4669 6286519f Iustin Pop
    i_list = [cfg.GetInstanceInfo(iname) for iname in cfg.GetInstanceList()]
4670 6286519f Iustin Pop
4671 d1c2dd75 Iustin Pop
    # node data
4672 d1c2dd75 Iustin Pop
    node_results = {}
4673 d1c2dd75 Iustin Pop
    node_list = cfg.GetNodeList()
4674 d1c2dd75 Iustin Pop
    node_data = rpc.call_node_info(node_list, cfg.GetVGName())
4675 d1c2dd75 Iustin Pop
    for nname in node_list:
4676 d1c2dd75 Iustin Pop
      ninfo = cfg.GetNodeInfo(nname)
4677 d1c2dd75 Iustin Pop
      if nname not in node_data or not isinstance(node_data[nname], dict):
4678 d1c2dd75 Iustin Pop
        raise errors.OpExecError("Can't get data for node %s" % nname)
4679 d1c2dd75 Iustin Pop
      remote_info = node_data[nname]
4680 b2662e7f Iustin Pop
      for attr in ['memory_total', 'memory_free', 'memory_dom0',
4681 4337cf1b Iustin Pop
                   'vg_size', 'vg_free', 'cpu_total']:
4682 d1c2dd75 Iustin Pop
        if attr not in remote_info:
4683 d1c2dd75 Iustin Pop
          raise errors.OpExecError("Node '%s' didn't return attribute '%s'" %
4684 d1c2dd75 Iustin Pop
                                   (nname, attr))
4685 d1c2dd75 Iustin Pop
        try:
4686 b2662e7f Iustin Pop
          remote_info[attr] = int(remote_info[attr])
4687 d1c2dd75 Iustin Pop
        except ValueError, err:
4688 d1c2dd75 Iustin Pop
          raise errors.OpExecError("Node '%s' returned invalid value for '%s':"
4689 d1c2dd75 Iustin Pop
                                   " %s" % (nname, attr, str(err)))
4690 6286519f Iustin Pop
      # compute memory used by primary instances
4691 6286519f Iustin Pop
      i_p_mem = i_p_up_mem = 0
4692 6286519f Iustin Pop
      for iinfo in i_list:
4693 6286519f Iustin Pop
        if iinfo.primary_node == nname:
4694 6286519f Iustin Pop
          i_p_mem += iinfo.memory
4695 6286519f Iustin Pop
          if iinfo.status == "up":
4696 6286519f Iustin Pop
            i_p_up_mem += iinfo.memory
4697 6286519f Iustin Pop
4698 b2662e7f Iustin Pop
      # compute memory used by instances
4699 d1c2dd75 Iustin Pop
      pnr = {
4700 d1c2dd75 Iustin Pop
        "tags": list(ninfo.GetTags()),
4701 b2662e7f Iustin Pop
        "total_memory": remote_info['memory_total'],
4702 b2662e7f Iustin Pop
        "reserved_memory": remote_info['memory_dom0'],
4703 b2662e7f Iustin Pop
        "free_memory": remote_info['memory_free'],
4704 6286519f Iustin Pop
        "i_pri_memory": i_p_mem,
4705 6286519f Iustin Pop
        "i_pri_up_memory": i_p_up_mem,
4706 b2662e7f Iustin Pop
        "total_disk": remote_info['vg_size'],
4707 b2662e7f Iustin Pop
        "free_disk": remote_info['vg_free'],
4708 d1c2dd75 Iustin Pop
        "primary_ip": ninfo.primary_ip,
4709 d1c2dd75 Iustin Pop
        "secondary_ip": ninfo.secondary_ip,
4710 4337cf1b Iustin Pop
        "total_cpus": remote_info['cpu_total'],
4711 d1c2dd75 Iustin Pop
        }
4712 d1c2dd75 Iustin Pop
      node_results[nname] = pnr
4713 d1c2dd75 Iustin Pop
    data["nodes"] = node_results
4714 d1c2dd75 Iustin Pop
4715 d1c2dd75 Iustin Pop
    # instance data
4716 d1c2dd75 Iustin Pop
    instance_data = {}
4717 6286519f Iustin Pop
    for iinfo in i_list:
4718 d1c2dd75 Iustin Pop
      nic_data = [{"mac": n.mac, "ip": n.ip, "bridge": n.bridge}
4719 d1c2dd75 Iustin Pop
                  for n in iinfo.nics]
4720 d1c2dd75 Iustin Pop
      pir = {
4721 d1c2dd75 Iustin Pop
        "tags": list(iinfo.GetTags()),
4722 d1c2dd75 Iustin Pop
        "should_run": iinfo.status == "up",
4723 d1c2dd75 Iustin Pop
        "vcpus": iinfo.vcpus,
4724 d1c2dd75 Iustin Pop
        "memory": iinfo.memory,
4725 d1c2dd75 Iustin Pop
        "os": iinfo.os,
4726 d1c2dd75 Iustin Pop
        "nodes": [iinfo.primary_node] + list(iinfo.secondary_nodes),
4727 d1c2dd75 Iustin Pop
        "nics": nic_data,
4728 d1c2dd75 Iustin Pop
        "disks": [{"size": dsk.size, "mode": "w"} for dsk in iinfo.disks],
4729 d1c2dd75 Iustin Pop
        "disk_template": iinfo.disk_template,
4730 d1c2dd75 Iustin Pop
        }
4731 768f0a80 Iustin Pop
      instance_data[iinfo.name] = pir
4732 d61df03e Iustin Pop
4733 d1c2dd75 Iustin Pop
    data["instances"] = instance_data
4734 d61df03e Iustin Pop
4735 d1c2dd75 Iustin Pop
    self.in_data = data
4736 d61df03e Iustin Pop
4737 d1c2dd75 Iustin Pop
  def _AddNewInstance(self):
4738 d1c2dd75 Iustin Pop
    """Add new instance data to allocator structure.
4739 d61df03e Iustin Pop

4740 d1c2dd75 Iustin Pop
    This in combination with _AllocatorGetClusterData will create the
4741 d1c2dd75 Iustin Pop
    correct structure needed as input for the allocator.
4742 d61df03e Iustin Pop

4743 d1c2dd75 Iustin Pop
    The checks for the completeness of the opcode must have already been
4744 d1c2dd75 Iustin Pop
    done.
4745 d61df03e Iustin Pop

4746 d1c2dd75 Iustin Pop
    """
4747 d1c2dd75 Iustin Pop
    data = self.in_data
4748 d1c2dd75 Iustin Pop
    if len(self.disks) != 2:
4749 d1c2dd75 Iustin Pop
      raise errors.OpExecError("Only two-disk configurations supported")
4750 d1c2dd75 Iustin Pop
4751 d1c2dd75 Iustin Pop
    disk_space = _ComputeDiskSize(self.disk_template,
4752 d1c2dd75 Iustin Pop
                                  self.disks[0]["size"], self.disks[1]["size"])
4753 d1c2dd75 Iustin Pop
4754 27579978 Iustin Pop
    if self.disk_template in constants.DTS_NET_MIRROR:
4755 27579978 Iustin Pop
      self.required_nodes = 2
4756 27579978 Iustin Pop
    else:
4757 27579978 Iustin Pop
      self.required_nodes = 1
4758 d1c2dd75 Iustin Pop
    request = {
4759 d1c2dd75 Iustin Pop
      "type": "allocate",
4760 d1c2dd75 Iustin Pop
      "name": self.name,
4761 d1c2dd75 Iustin Pop
      "disk_template": self.disk_template,
4762 d1c2dd75 Iustin Pop
      "tags": self.tags,
4763 d1c2dd75 Iustin Pop
      "os": self.os,
4764 d1c2dd75 Iustin Pop
      "vcpus": self.vcpus,
4765 d1c2dd75 Iustin Pop
      "memory": self.mem_size,
4766 d1c2dd75 Iustin Pop
      "disks": self.disks,
4767 d1c2dd75 Iustin Pop
      "disk_space_total": disk_space,
4768 d1c2dd75 Iustin Pop
      "nics": self.nics,
4769 27579978 Iustin Pop
      "required_nodes": self.required_nodes,
4770 d1c2dd75 Iustin Pop
      }
4771 d1c2dd75 Iustin Pop
    data["request"] = request
4772 298fe380 Iustin Pop
4773 d1c2dd75 Iustin Pop
  def _AddRelocateInstance(self):
4774 d1c2dd75 Iustin Pop
    """Add relocate instance data to allocator structure.
4775 298fe380 Iustin Pop

4776 d1c2dd75 Iustin Pop
    This in combination with _IAllocatorGetClusterData will create the
4777 d1c2dd75 Iustin Pop
    correct structure needed as input for the allocator.
4778 d61df03e Iustin Pop

4779 d1c2dd75 Iustin Pop
    The checks for the completeness of the opcode must have already been
4780 d1c2dd75 Iustin Pop
    done.
4781 d61df03e Iustin Pop

4782 d1c2dd75 Iustin Pop
    """
4783 27579978 Iustin Pop
    instance = self.cfg.GetInstanceInfo(self.name)
4784 27579978 Iustin Pop
    if instance is None:
4785 27579978 Iustin Pop
      raise errors.ProgrammerError("Unknown instance '%s' passed to"
4786 27579978 Iustin Pop
                                   " IAllocator" % self.name)
4787 27579978 Iustin Pop
4788 27579978 Iustin Pop
    if instance.disk_template not in constants.DTS_NET_MIRROR:
4789 27579978 Iustin Pop
      raise errors.OpPrereqError("Can't relocate non-mirrored instances")
4790 27579978 Iustin Pop
4791 2a139bb0 Iustin Pop
    if len(instance.secondary_nodes) != 1:
4792 2a139bb0 Iustin Pop
      raise errors.OpPrereqError("Instance has not exactly one secondary node")
4793 2a139bb0 Iustin Pop
4794 27579978 Iustin Pop
    self.required_nodes = 1
4795 27579978 Iustin Pop
4796 27579978 Iustin Pop
    disk_space = _ComputeDiskSize(instance.disk_template,
4797 27579978 Iustin Pop
                                  instance.disks[0].size,
4798 27579978 Iustin Pop
                                  instance.disks[1].size)
4799 27579978 Iustin Pop
4800 d1c2dd75 Iustin Pop
    request = {
4801 2a139bb0 Iustin Pop
      "type": "relocate",
4802 d1c2dd75 Iustin Pop
      "name": self.name,
4803 27579978 Iustin Pop
      "disk_space_total": disk_space,
4804 27579978 Iustin Pop
      "required_nodes": self.required_nodes,
4805 29859cb7 Iustin Pop
      "relocate_from": self.relocate_from,
4806 d1c2dd75 Iustin Pop
      }
4807 27579978 Iustin Pop
    self.in_data["request"] = request
4808 d61df03e Iustin Pop
4809 d1c2dd75 Iustin Pop
  def _BuildInputData(self):
4810 d1c2dd75 Iustin Pop
    """Build input data structures.
4811 d61df03e Iustin Pop

4812 d1c2dd75 Iustin Pop
    """
4813 d1c2dd75 Iustin Pop
    self._ComputeClusterData()
4814 d61df03e Iustin Pop
4815 d1c2dd75 Iustin Pop
    if self.mode == constants.IALLOCATOR_MODE_ALLOC:
4816 d1c2dd75 Iustin Pop
      self._AddNewInstance()
4817 d1c2dd75 Iustin Pop
    else:
4818 d1c2dd75 Iustin Pop
      self._AddRelocateInstance()
4819 d61df03e Iustin Pop
4820 d1c2dd75 Iustin Pop
    self.in_text = serializer.Dump(self.in_data)
4821 d61df03e Iustin Pop
4822 8d528b7c Iustin Pop
  def Run(self, name, validate=True, call_fn=rpc.call_iallocator_runner):
4823 d1c2dd75 Iustin Pop
    """Run an instance allocator and return the results.
4824 298fe380 Iustin Pop

4825 d1c2dd75 Iustin Pop
    """
4826 d1c2dd75 Iustin Pop
    data = self.in_text
4827 298fe380 Iustin Pop
4828 8d528b7c Iustin Pop
    result = call_fn(self.sstore.GetMasterNode(), name, self.in_text)
4829 298fe380 Iustin Pop
4830 8d528b7c Iustin Pop
    if not isinstance(result, tuple) or len(result) != 4:
4831 8d528b7c Iustin Pop
      raise errors.OpExecError("Invalid result from master iallocator runner")
4832 8d528b7c Iustin Pop
4833 8d528b7c Iustin Pop
    rcode, stdout, stderr, fail = result
4834 8d528b7c Iustin Pop
4835 8d528b7c Iustin Pop
    if rcode == constants.IARUN_NOTFOUND:
4836 8d528b7c Iustin Pop
      raise errors.OpExecError("Can't find allocator '%s'" % name)
4837 8d528b7c Iustin Pop
    elif rcode == constants.IARUN_FAILURE:
4838 d1c2dd75 Iustin Pop
        raise errors.OpExecError("Instance allocator call failed: %s,"
4839 d1c2dd75 Iustin Pop
                                 " output: %s" %
4840 8d528b7c Iustin Pop
                                 (fail, stdout+stderr))
4841 8d528b7c Iustin Pop
    self.out_text = stdout
4842 d1c2dd75 Iustin Pop
    if validate:
4843 d1c2dd75 Iustin Pop
      self._ValidateResult()
4844 298fe380 Iustin Pop
4845 d1c2dd75 Iustin Pop
  def _ValidateResult(self):
4846 d1c2dd75 Iustin Pop
    """Process the allocator results.
4847 538475ca Iustin Pop

4848 d1c2dd75 Iustin Pop
    This will process and if successful save the result in
4849 d1c2dd75 Iustin Pop
    self.out_data and the other parameters.
4850 538475ca Iustin Pop

4851 d1c2dd75 Iustin Pop
    """
4852 d1c2dd75 Iustin Pop
    try:
4853 d1c2dd75 Iustin Pop
      rdict = serializer.Load(self.out_text)
4854 d1c2dd75 Iustin Pop
    except Exception, err:
4855 d1c2dd75 Iustin Pop
      raise errors.OpExecError("Can't parse iallocator results: %s" % str(err))
4856 d1c2dd75 Iustin Pop
4857 d1c2dd75 Iustin Pop
    if not isinstance(rdict, dict):
4858 d1c2dd75 Iustin Pop
      raise errors.OpExecError("Can't parse iallocator results: not a dict")
4859 538475ca Iustin Pop
4860 d1c2dd75 Iustin Pop
    for key in "success", "info", "nodes":
4861 d1c2dd75 Iustin Pop
      if key not in rdict:
4862 d1c2dd75 Iustin Pop
        raise errors.OpExecError("Can't parse iallocator results:"
4863 d1c2dd75 Iustin Pop
                                 " missing key '%s'" % key)
4864 d1c2dd75 Iustin Pop
      setattr(self, key, rdict[key])
4865 538475ca Iustin Pop
4866 d1c2dd75 Iustin Pop
    if not isinstance(rdict["nodes"], list):
4867 d1c2dd75 Iustin Pop
      raise errors.OpExecError("Can't parse iallocator results: 'nodes' key"
4868 d1c2dd75 Iustin Pop
                               " is not a list")
4869 d1c2dd75 Iustin Pop
    self.out_data = rdict
4870 538475ca Iustin Pop
4871 538475ca Iustin Pop
4872 d61df03e Iustin Pop
class LUTestAllocator(NoHooksLU):
4873 d61df03e Iustin Pop
  """Run allocator tests.
4874 d61df03e Iustin Pop

4875 d61df03e Iustin Pop
  This LU runs the allocator tests
4876 d61df03e Iustin Pop

4877 d61df03e Iustin Pop
  """
4878 d61df03e Iustin Pop
  _OP_REQP = ["direction", "mode", "name"]
4879 d61df03e Iustin Pop
4880 d61df03e Iustin Pop
  def CheckPrereq(self):
4881 d61df03e Iustin Pop
    """Check prerequisites.
4882 d61df03e Iustin Pop

4883 d61df03e Iustin Pop
    This checks the opcode parameters depending on the director and mode test.
4884 d61df03e Iustin Pop

4885 d61df03e Iustin Pop
    """
4886 298fe380 Iustin Pop
    if self.op.mode == constants.IALLOCATOR_MODE_ALLOC:
4887 d61df03e Iustin Pop
      for attr in ["name", "mem_size", "disks", "disk_template",
4888 d61df03e Iustin Pop
                   "os", "tags", "nics", "vcpus"]:
4889 d61df03e Iustin Pop
        if not hasattr(self.op, attr):
4890 d61df03e Iustin Pop
          raise errors.OpPrereqError("Missing attribute '%s' on opcode input" %
4891 d61df03e Iustin Pop
                                     attr)
4892 d61df03e Iustin Pop
      iname = self.cfg.ExpandInstanceName(self.op.name)
4893 d61df03e Iustin Pop
      if iname is not None:
4894 d61df03e Iustin Pop
        raise errors.OpPrereqError("Instance '%s' already in the cluster" %
4895 d61df03e Iustin Pop
                                   iname)
4896 d61df03e Iustin Pop
      if not isinstance(self.op.nics, list):
4897 d61df03e Iustin Pop
        raise errors.OpPrereqError("Invalid parameter 'nics'")
4898 d61df03e Iustin Pop
      for row in self.op.nics:
4899 d61df03e Iustin Pop
        if (not isinstance(row, dict) or
4900 d61df03e Iustin Pop
            "mac" not in row or
4901 d61df03e Iustin Pop
            "ip" not in row or
4902 d61df03e Iustin Pop
            "bridge" not in row):
4903 d61df03e Iustin Pop
          raise errors.OpPrereqError("Invalid contents of the"
4904 d61df03e Iustin Pop
                                     " 'nics' parameter")
4905 d61df03e Iustin Pop
      if not isinstance(self.op.disks, list):
4906 d61df03e Iustin Pop
        raise errors.OpPrereqError("Invalid parameter 'disks'")
4907 298fe380 Iustin Pop
      if len(self.op.disks) != 2:
4908 298fe380 Iustin Pop
        raise errors.OpPrereqError("Only two-disk configurations supported")
4909 d61df03e Iustin Pop
      for row in self.op.disks:
4910 d61df03e Iustin Pop
        if (not isinstance(row, dict) or
4911 d61df03e Iustin Pop
            "size" not in row or
4912 d61df03e Iustin Pop
            not isinstance(row["size"], int) or
4913 d61df03e Iustin Pop
            "mode" not in row or
4914 d61df03e Iustin Pop
            row["mode"] not in ['r', 'w']):
4915 d61df03e Iustin Pop
          raise errors.OpPrereqError("Invalid contents of the"
4916 d61df03e Iustin Pop
                                     " 'disks' parameter")
4917 298fe380 Iustin Pop
    elif self.op.mode == constants.IALLOCATOR_MODE_RELOC:
4918 d61df03e Iustin Pop
      if not hasattr(self.op, "name"):
4919 d61df03e Iustin Pop
        raise errors.OpPrereqError("Missing attribute 'name' on opcode input")
4920 d61df03e Iustin Pop
      fname = self.cfg.ExpandInstanceName(self.op.name)
4921 d61df03e Iustin Pop
      if fname is None:
4922 d61df03e Iustin Pop
        raise errors.OpPrereqError("Instance '%s' not found for relocation" %
4923 d61df03e Iustin Pop
                                   self.op.name)
4924 d61df03e Iustin Pop
      self.op.name = fname
4925 29859cb7 Iustin Pop
      self.relocate_from = self.cfg.GetInstanceInfo(fname).secondary_nodes
4926 d61df03e Iustin Pop
    else:
4927 d61df03e Iustin Pop
      raise errors.OpPrereqError("Invalid test allocator mode '%s'" %
4928 d61df03e Iustin Pop
                                 self.op.mode)
4929 d61df03e Iustin Pop
4930 298fe380 Iustin Pop
    if self.op.direction == constants.IALLOCATOR_DIR_OUT:
4931 298fe380 Iustin Pop
      if not hasattr(self.op, "allocator") or self.op.allocator is None:
4932 d61df03e Iustin Pop
        raise errors.OpPrereqError("Missing allocator name")
4933 298fe380 Iustin Pop
    elif self.op.direction != constants.IALLOCATOR_DIR_IN:
4934 d61df03e Iustin Pop
      raise errors.OpPrereqError("Wrong allocator test '%s'" %
4935 d61df03e Iustin Pop
                                 self.op.direction)
4936 d61df03e Iustin Pop
4937 d61df03e Iustin Pop
  def Exec(self, feedback_fn):
4938 d61df03e Iustin Pop
    """Run the allocator test.
4939 d61df03e Iustin Pop

4940 d61df03e Iustin Pop
    """
4941 29859cb7 Iustin Pop
    if self.op.mode == constants.IALLOCATOR_MODE_ALLOC:
4942 29859cb7 Iustin Pop
      ial = IAllocator(self.cfg, self.sstore,
4943 29859cb7 Iustin Pop
                       mode=self.op.mode,
4944 29859cb7 Iustin Pop
                       name=self.op.name,
4945 29859cb7 Iustin Pop
                       mem_size=self.op.mem_size,
4946 29859cb7 Iustin Pop
                       disks=self.op.disks,
4947 29859cb7 Iustin Pop
                       disk_template=self.op.disk_template,
4948 29859cb7 Iustin Pop
                       os=self.op.os,
4949 29859cb7 Iustin Pop
                       tags=self.op.tags,
4950 29859cb7 Iustin Pop
                       nics=self.op.nics,
4951 29859cb7 Iustin Pop
                       vcpus=self.op.vcpus,
4952 29859cb7 Iustin Pop
                       )
4953 29859cb7 Iustin Pop
    else:
4954 29859cb7 Iustin Pop
      ial = IAllocator(self.cfg, self.sstore,
4955 29859cb7 Iustin Pop
                       mode=self.op.mode,
4956 29859cb7 Iustin Pop
                       name=self.op.name,
4957 29859cb7 Iustin Pop
                       relocate_from=list(self.relocate_from),
4958 29859cb7 Iustin Pop
                       )
4959 d61df03e Iustin Pop
4960 298fe380 Iustin Pop
    if self.op.direction == constants.IALLOCATOR_DIR_IN:
4961 d1c2dd75 Iustin Pop
      result = ial.in_text
4962 298fe380 Iustin Pop
    else:
4963 d1c2dd75 Iustin Pop
      ial.Run(self.op.allocator, validate=False)
4964 d1c2dd75 Iustin Pop
      result = ial.out_text
4965 298fe380 Iustin Pop
    return result