Statistics
| Branch: | Tag: | Revision:

root / lib / cmdlib.py @ c9673d92

History | View | Annotate | Download (176.9 kB)

1 2f31098c Iustin Pop
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 e7c6e02b Michael Hanselmann
# Copyright (C) 2006, 2007, 2008 Google Inc.
5 a8083063 Iustin Pop
#
6 a8083063 Iustin Pop
# This program is free software; you can redistribute it and/or modify
7 a8083063 Iustin Pop
# it under the terms of the GNU General Public License as published by
8 a8083063 Iustin Pop
# the Free Software Foundation; either version 2 of the License, or
9 a8083063 Iustin Pop
# (at your option) any later version.
10 a8083063 Iustin Pop
#
11 a8083063 Iustin Pop
# This program is distributed in the hope that it will be useful, but
12 a8083063 Iustin Pop
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 a8083063 Iustin Pop
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 a8083063 Iustin Pop
# General Public License for more details.
15 a8083063 Iustin Pop
#
16 a8083063 Iustin Pop
# You should have received a copy of the GNU General Public License
17 a8083063 Iustin Pop
# along with this program; if not, write to the Free Software
18 a8083063 Iustin Pop
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 a8083063 Iustin Pop
# 02110-1301, USA.
20 a8083063 Iustin Pop
21 a8083063 Iustin Pop
22 880478f8 Iustin Pop
"""Module implementing the master-side code."""
23 a8083063 Iustin Pop
24 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 a8083063 Iustin Pop
from ganeti import config
41 a8083063 Iustin Pop
from ganeti import constants
42 a8083063 Iustin Pop
from ganeti import objects
43 a8083063 Iustin Pop
from ganeti import opcodes
44 a8083063 Iustin Pop
from ganeti import ssconf
45 8d14b30d Iustin Pop
from ganeti import serializer
46 d61df03e Iustin Pop
47 d61df03e Iustin Pop
48 a8083063 Iustin Pop
class LogicalUnit(object):
49 396e1b78 Michael Hanselmann
  """Logical Unit base class.
50 a8083063 Iustin Pop

51 a8083063 Iustin Pop
  Subclasses must follow these rules:
52 a8083063 Iustin Pop
    - implement CheckPrereq which also fills in the opcode instance
53 a8083063 Iustin Pop
      with all the fields (even if as None)
54 a8083063 Iustin Pop
    - implement Exec
55 a8083063 Iustin Pop
    - implement BuildHooksEnv
56 a8083063 Iustin Pop
    - redefine HPATH and HTYPE
57 a8083063 Iustin Pop
    - optionally redefine their run requirements (REQ_CLUSTER,
58 a8083063 Iustin Pop
      REQ_MASTER); note that all commands require root permissions
59 a8083063 Iustin Pop

60 a8083063 Iustin Pop
  """
61 a8083063 Iustin Pop
  HPATH = None
62 a8083063 Iustin Pop
  HTYPE = None
63 a8083063 Iustin Pop
  _OP_REQP = []
64 a8083063 Iustin Pop
  REQ_CLUSTER = True
65 a8083063 Iustin Pop
  REQ_MASTER = True
66 a8083063 Iustin Pop
67 a8083063 Iustin Pop
  def __init__(self, processor, op, cfg, sstore):
68 a8083063 Iustin Pop
    """Constructor for LogicalUnit.
69 a8083063 Iustin Pop

70 a8083063 Iustin Pop
    This needs to be overriden in derived classes in order to check op
71 a8083063 Iustin Pop
    validity.
72 a8083063 Iustin Pop

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

98 c92b310a Michael Hanselmann
    """
99 c92b310a Michael Hanselmann
    if not self.__ssh:
100 1ff08570 Michael Hanselmann
      self.__ssh = ssh.SshRunner(self.sstore)
101 c92b310a Michael Hanselmann
    return self.__ssh
102 c92b310a Michael Hanselmann
103 c92b310a Michael Hanselmann
  ssh = property(fget=__GetSSH)
104 c92b310a Michael Hanselmann
105 a8083063 Iustin Pop
  def CheckPrereq(self):
106 a8083063 Iustin Pop
    """Check prerequisites for this LU.
107 a8083063 Iustin Pop

108 a8083063 Iustin Pop
    This method should check that the prerequisites for the execution
109 a8083063 Iustin Pop
    of this LU are fulfilled. It can do internode communication, but
110 a8083063 Iustin Pop
    it should be idempotent - no cluster or system changes are
111 a8083063 Iustin Pop
    allowed.
112 a8083063 Iustin Pop

113 a8083063 Iustin Pop
    The method should raise errors.OpPrereqError in case something is
114 a8083063 Iustin Pop
    not fulfilled. Its return value is ignored.
115 a8083063 Iustin Pop

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

121 a8083063 Iustin Pop
    """
122 a8083063 Iustin Pop
    raise NotImplementedError
123 a8083063 Iustin Pop
124 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
125 a8083063 Iustin Pop
    """Execute the LU.
126 a8083063 Iustin Pop

127 a8083063 Iustin Pop
    This method should implement the actual work. It should raise
128 a8083063 Iustin Pop
    errors.OpExecError for failures that are somewhat dealt with in
129 a8083063 Iustin Pop
    code, or expected.
130 a8083063 Iustin Pop

131 a8083063 Iustin Pop
    """
132 a8083063 Iustin Pop
    raise NotImplementedError
133 a8083063 Iustin Pop
134 a8083063 Iustin Pop
  def BuildHooksEnv(self):
135 a8083063 Iustin Pop
    """Build hooks environment for this LU.
136 a8083063 Iustin Pop

137 a8083063 Iustin Pop
    This method should return a three-node tuple consisting of: a dict
138 a8083063 Iustin Pop
    containing the environment that will be used for running the
139 a8083063 Iustin Pop
    specific hook for this LU, a list of node names on which the hook
140 a8083063 Iustin Pop
    should run before the execution, and a list of node names on which
141 a8083063 Iustin Pop
    the hook should run after the execution.
142 a8083063 Iustin Pop

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

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

150 a8083063 Iustin Pop
    Note that if the HPATH for a LU class is None, this function will
151 a8083063 Iustin Pop
    not be called.
152 a8083063 Iustin Pop

153 a8083063 Iustin Pop
    """
154 a8083063 Iustin Pop
    raise NotImplementedError
155 a8083063 Iustin Pop
156 1fce5219 Guido Trotter
  def HooksCallBack(self, phase, hook_results, feedback_fn, lu_result):
157 1fce5219 Guido Trotter
    """Notify the LU about the results of its hooks.
158 1fce5219 Guido Trotter

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

165 1fce5219 Guido Trotter
    Args:
166 1fce5219 Guido Trotter
      phase: the hooks phase that has just been run
167 1fce5219 Guido Trotter
      hooks_results: the results of the multi-node hooks rpc call
168 1fce5219 Guido Trotter
      feedback_fn: function to send feedback back to the caller
169 1fce5219 Guido Trotter
      lu_result: the previous result this LU had, or None in the PRE phase.
170 1fce5219 Guido Trotter

171 1fce5219 Guido Trotter
    """
172 1fce5219 Guido Trotter
    return lu_result
173 1fce5219 Guido Trotter
174 a8083063 Iustin Pop
175 a8083063 Iustin Pop
class NoHooksLU(LogicalUnit):
176 a8083063 Iustin Pop
  """Simple LU which runs no hooks.
177 a8083063 Iustin Pop

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

181 a8083063 Iustin Pop
  """
182 a8083063 Iustin Pop
  HPATH = None
183 a8083063 Iustin Pop
  HTYPE = None
184 a8083063 Iustin Pop
185 a8083063 Iustin Pop
186 9440aeab Michael Hanselmann
def _AddHostToEtcHosts(hostname):
187 9440aeab Michael Hanselmann
  """Wrapper around utils.SetEtcHostsEntry.
188 9440aeab Michael Hanselmann

189 9440aeab Michael Hanselmann
  """
190 9440aeab Michael Hanselmann
  hi = utils.HostInfo(name=hostname)
191 9440aeab Michael Hanselmann
  utils.SetEtcHostsEntry(constants.ETC_HOSTS, hi.ip, hi.name, [hi.ShortName()])
192 9440aeab Michael Hanselmann
193 9440aeab Michael Hanselmann
194 c8a0948f Michael Hanselmann
def _RemoveHostFromEtcHosts(hostname):
195 9440aeab Michael Hanselmann
  """Wrapper around utils.RemoveEtcHostsEntry.
196 c8a0948f Michael Hanselmann

197 c8a0948f Michael Hanselmann
  """
198 c8a0948f Michael Hanselmann
  hi = utils.HostInfo(name=hostname)
199 c8a0948f Michael Hanselmann
  utils.RemoveEtcHostsEntry(constants.ETC_HOSTS, hi.name)
200 c8a0948f Michael Hanselmann
  utils.RemoveEtcHostsEntry(constants.ETC_HOSTS, hi.ShortName())
201 c8a0948f Michael Hanselmann
202 c8a0948f Michael Hanselmann
203 dcb93971 Michael Hanselmann
def _GetWantedNodes(lu, nodes):
204 a7ba5e53 Iustin Pop
  """Returns list of checked and expanded node names.
205 83120a01 Michael Hanselmann

206 83120a01 Michael Hanselmann
  Args:
207 83120a01 Michael Hanselmann
    nodes: List of nodes (strings) or None for all
208 83120a01 Michael Hanselmann

209 83120a01 Michael Hanselmann
  """
210 3312b702 Iustin Pop
  if not isinstance(nodes, list):
211 3ecf6786 Iustin Pop
    raise errors.OpPrereqError("Invalid argument type 'nodes'")
212 dcb93971 Michael Hanselmann
213 dcb93971 Michael Hanselmann
  if nodes:
214 3312b702 Iustin Pop
    wanted = []
215 dcb93971 Michael Hanselmann
216 dcb93971 Michael Hanselmann
    for name in nodes:
217 a7ba5e53 Iustin Pop
      node = lu.cfg.ExpandNodeName(name)
218 dcb93971 Michael Hanselmann
      if node is None:
219 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("No such node name '%s'" % name)
220 3312b702 Iustin Pop
      wanted.append(node)
221 dcb93971 Michael Hanselmann
222 dcb93971 Michael Hanselmann
  else:
223 a7ba5e53 Iustin Pop
    wanted = lu.cfg.GetNodeList()
224 a7ba5e53 Iustin Pop
  return utils.NiceSort(wanted)
225 3312b702 Iustin Pop
226 3312b702 Iustin Pop
227 3312b702 Iustin Pop
def _GetWantedInstances(lu, instances):
228 a7ba5e53 Iustin Pop
  """Returns list of checked and expanded instance names.
229 3312b702 Iustin Pop

230 3312b702 Iustin Pop
  Args:
231 3312b702 Iustin Pop
    instances: List of instances (strings) or None for all
232 3312b702 Iustin Pop

233 3312b702 Iustin Pop
  """
234 3312b702 Iustin Pop
  if not isinstance(instances, list):
235 3312b702 Iustin Pop
    raise errors.OpPrereqError("Invalid argument type 'instances'")
236 3312b702 Iustin Pop
237 3312b702 Iustin Pop
  if instances:
238 3312b702 Iustin Pop
    wanted = []
239 3312b702 Iustin Pop
240 3312b702 Iustin Pop
    for name in instances:
241 a7ba5e53 Iustin Pop
      instance = lu.cfg.ExpandInstanceName(name)
242 3312b702 Iustin Pop
      if instance is None:
243 3312b702 Iustin Pop
        raise errors.OpPrereqError("No such instance name '%s'" % name)
244 3312b702 Iustin Pop
      wanted.append(instance)
245 3312b702 Iustin Pop
246 3312b702 Iustin Pop
  else:
247 a7ba5e53 Iustin Pop
    wanted = lu.cfg.GetInstanceList()
248 a7ba5e53 Iustin Pop
  return utils.NiceSort(wanted)
249 dcb93971 Michael Hanselmann
250 dcb93971 Michael Hanselmann
251 dcb93971 Michael Hanselmann
def _CheckOutputFields(static, dynamic, selected):
252 83120a01 Michael Hanselmann
  """Checks whether all selected fields are valid.
253 83120a01 Michael Hanselmann

254 83120a01 Michael Hanselmann
  Args:
255 83120a01 Michael Hanselmann
    static: Static fields
256 83120a01 Michael Hanselmann
    dynamic: Dynamic fields
257 83120a01 Michael Hanselmann

258 83120a01 Michael Hanselmann
  """
259 83120a01 Michael Hanselmann
  static_fields = frozenset(static)
260 83120a01 Michael Hanselmann
  dynamic_fields = frozenset(dynamic)
261 dcb93971 Michael Hanselmann
262 83120a01 Michael Hanselmann
  all_fields = static_fields | dynamic_fields
263 dcb93971 Michael Hanselmann
264 83120a01 Michael Hanselmann
  if not all_fields.issuperset(selected):
265 3ecf6786 Iustin Pop
    raise errors.OpPrereqError("Unknown output fields selected: %s"
266 3ecf6786 Iustin Pop
                               % ",".join(frozenset(selected).
267 3ecf6786 Iustin Pop
                                          difference(all_fields)))
268 dcb93971 Michael Hanselmann
269 dcb93971 Michael Hanselmann
270 ecb215b5 Michael Hanselmann
def _BuildInstanceHookEnv(name, primary_node, secondary_nodes, os_type, status,
271 396e1b78 Michael Hanselmann
                          memory, vcpus, nics):
272 ecb215b5 Michael Hanselmann
  """Builds instance related env variables for hooks from single variables.
273 ecb215b5 Michael Hanselmann

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

307 ecb215b5 Michael Hanselmann
  Args:
308 ecb215b5 Michael Hanselmann
    instance: objects.Instance object of instance
309 ecb215b5 Michael Hanselmann
    override: dict of values to override
310 ecb215b5 Michael Hanselmann
  """
311 396e1b78 Michael Hanselmann
  args = {
312 396e1b78 Michael Hanselmann
    'name': instance.name,
313 396e1b78 Michael Hanselmann
    'primary_node': instance.primary_node,
314 396e1b78 Michael Hanselmann
    'secondary_nodes': instance.secondary_nodes,
315 ecb215b5 Michael Hanselmann
    'os_type': instance.os,
316 396e1b78 Michael Hanselmann
    'status': instance.os,
317 396e1b78 Michael Hanselmann
    'memory': instance.memory,
318 396e1b78 Michael Hanselmann
    'vcpus': instance.vcpus,
319 53e4e875 Guido Trotter
    'nics': [(nic.ip, nic.bridge, nic.mac) for nic in instance.nics],
320 396e1b78 Michael Hanselmann
  }
321 396e1b78 Michael Hanselmann
  if override:
322 396e1b78 Michael Hanselmann
    args.update(override)
323 396e1b78 Michael Hanselmann
  return _BuildInstanceHookEnv(**args)
324 396e1b78 Michael Hanselmann
325 396e1b78 Michael Hanselmann
326 a8083063 Iustin Pop
def _HasValidVG(vglist, vgname):
327 a8083063 Iustin Pop
  """Checks if the volume group list is valid.
328 a8083063 Iustin Pop

329 a8083063 Iustin Pop
  A non-None return value means there's an error, and the return value
330 a8083063 Iustin Pop
  is the error message.
331 a8083063 Iustin Pop

332 a8083063 Iustin Pop
  """
333 a8083063 Iustin Pop
  vgsize = vglist.get(vgname, None)
334 a8083063 Iustin Pop
  if vgsize is None:
335 a8083063 Iustin Pop
    return "volume group '%s' missing" % vgname
336 a8083063 Iustin Pop
  elif vgsize < 20480:
337 191a8385 Guido Trotter
    return ("volume group '%s' too small (20480MiB required, %dMib found)" %
338 191a8385 Guido Trotter
            (vgname, vgsize))
339 a8083063 Iustin Pop
  return None
340 a8083063 Iustin Pop
341 a8083063 Iustin Pop
342 a8083063 Iustin Pop
def _InitSSHSetup(node):
343 a8083063 Iustin Pop
  """Setup the SSH configuration for the cluster.
344 a8083063 Iustin Pop

345 a8083063 Iustin Pop

346 a8083063 Iustin Pop
  This generates a dsa keypair for root, adds the pub key to the
347 a8083063 Iustin Pop
  permitted hosts and adds the hostkey to its own known hosts.
348 a8083063 Iustin Pop

349 a8083063 Iustin Pop
  Args:
350 a8083063 Iustin Pop
    node: the name of this host as a fqdn
351 a8083063 Iustin Pop

352 a8083063 Iustin Pop
  """
353 70d9e3d8 Iustin Pop
  priv_key, pub_key, auth_keys = ssh.GetUserFiles(constants.GANETI_RUNAS)
354 a8083063 Iustin Pop
355 70d9e3d8 Iustin Pop
  for name in priv_key, pub_key:
356 70d9e3d8 Iustin Pop
    if os.path.exists(name):
357 70d9e3d8 Iustin Pop
      utils.CreateBackup(name)
358 70d9e3d8 Iustin Pop
    utils.RemoveFile(name)
359 a8083063 Iustin Pop
360 a8083063 Iustin Pop
  result = utils.RunCmd(["ssh-keygen", "-t", "dsa",
361 70d9e3d8 Iustin Pop
                         "-f", priv_key,
362 a8083063 Iustin Pop
                         "-q", "-N", ""])
363 a8083063 Iustin Pop
  if result.failed:
364 3ecf6786 Iustin Pop
    raise errors.OpExecError("Could not generate ssh keypair, error %s" %
365 3ecf6786 Iustin Pop
                             result.output)
366 a8083063 Iustin Pop
367 70d9e3d8 Iustin Pop
  f = open(pub_key, 'r')
368 a8083063 Iustin Pop
  try:
369 70d9e3d8 Iustin Pop
    utils.AddAuthorizedKey(auth_keys, f.read(8192))
370 a8083063 Iustin Pop
  finally:
371 a8083063 Iustin Pop
    f.close()
372 a8083063 Iustin Pop
373 a8083063 Iustin Pop
374 a8083063 Iustin Pop
def _InitGanetiServerSetup(ss):
375 a8083063 Iustin Pop
  """Setup the necessary configuration for the initial node daemon.
376 a8083063 Iustin Pop

377 a8083063 Iustin Pop
  This creates the nodepass file containing the shared password for
378 a8083063 Iustin Pop
  the cluster and also generates the SSL certificate.
379 a8083063 Iustin Pop

380 a8083063 Iustin Pop
  """
381 a8083063 Iustin Pop
  # Create pseudo random password
382 a8083063 Iustin Pop
  randpass = sha.new(os.urandom(64)).hexdigest()
383 a8083063 Iustin Pop
  # and write it into sstore
384 a8083063 Iustin Pop
  ss.SetKey(ss.SS_NODED_PASS, randpass)
385 a8083063 Iustin Pop
386 a8083063 Iustin Pop
  result = utils.RunCmd(["openssl", "req", "-new", "-newkey", "rsa:1024",
387 a8083063 Iustin Pop
                         "-days", str(365*5), "-nodes", "-x509",
388 a8083063 Iustin Pop
                         "-keyout", constants.SSL_CERT_FILE,
389 a8083063 Iustin Pop
                         "-out", constants.SSL_CERT_FILE, "-batch"])
390 a8083063 Iustin Pop
  if result.failed:
391 3ecf6786 Iustin Pop
    raise errors.OpExecError("could not generate server ssl cert, command"
392 3ecf6786 Iustin Pop
                             " %s had exitcode %s and error message %s" %
393 3ecf6786 Iustin Pop
                             (result.cmd, result.exit_code, result.output))
394 a8083063 Iustin Pop
395 a8083063 Iustin Pop
  os.chmod(constants.SSL_CERT_FILE, 0400)
396 a8083063 Iustin Pop
397 a8083063 Iustin Pop
  result = utils.RunCmd([constants.NODE_INITD_SCRIPT, "restart"])
398 a8083063 Iustin Pop
399 a8083063 Iustin Pop
  if result.failed:
400 3ecf6786 Iustin Pop
    raise errors.OpExecError("Could not start the node daemon, command %s"
401 3ecf6786 Iustin Pop
                             " had exitcode %s and error %s" %
402 3ecf6786 Iustin Pop
                             (result.cmd, result.exit_code, result.output))
403 a8083063 Iustin Pop
404 a8083063 Iustin Pop
405 bf6929a2 Alexander Schreiber
def _CheckInstanceBridgesExist(instance):
406 bf6929a2 Alexander Schreiber
  """Check that the brigdes needed by an instance exist.
407 bf6929a2 Alexander Schreiber

408 bf6929a2 Alexander Schreiber
  """
409 bf6929a2 Alexander Schreiber
  # check bridges existance
410 bf6929a2 Alexander Schreiber
  brlist = [nic.bridge for nic in instance.nics]
411 bf6929a2 Alexander Schreiber
  if not rpc.call_bridges_exist(instance.primary_node, brlist):
412 bf6929a2 Alexander Schreiber
    raise errors.OpPrereqError("one or more target bridges %s does not"
413 bf6929a2 Alexander Schreiber
                               " exist on destination node '%s'" %
414 bf6929a2 Alexander Schreiber
                               (brlist, instance.primary_node))
415 bf6929a2 Alexander Schreiber
416 bf6929a2 Alexander Schreiber
417 a8083063 Iustin Pop
class LUInitCluster(LogicalUnit):
418 a8083063 Iustin Pop
  """Initialise the cluster.
419 a8083063 Iustin Pop

420 a8083063 Iustin Pop
  """
421 a8083063 Iustin Pop
  HPATH = "cluster-init"
422 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_CLUSTER
423 efa14262 Manuel Franceschini
  _OP_REQP = ["cluster_name", "hypervisor_type", "mac_prefix",
424 871705db Manuel Franceschini
              "def_bridge", "master_netdev", "file_storage_dir"]
425 a8083063 Iustin Pop
  REQ_CLUSTER = False
426 a8083063 Iustin Pop
427 a8083063 Iustin Pop
  def BuildHooksEnv(self):
428 a8083063 Iustin Pop
    """Build hooks env.
429 a8083063 Iustin Pop

430 a8083063 Iustin Pop
    Notes: Since we don't require a cluster, we must manually add
431 a8083063 Iustin Pop
    ourselves in the post-run node list.
432 a8083063 Iustin Pop

433 a8083063 Iustin Pop
    """
434 0e137c28 Iustin Pop
    env = {"OP_TARGET": self.op.cluster_name}
435 0e137c28 Iustin Pop
    return env, [], [self.hostname.name]
436 a8083063 Iustin Pop
437 a8083063 Iustin Pop
  def CheckPrereq(self):
438 a8083063 Iustin Pop
    """Verify that the passed name is a valid one.
439 a8083063 Iustin Pop

440 a8083063 Iustin Pop
    """
441 a8083063 Iustin Pop
    if config.ConfigWriter.IsCluster():
442 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Cluster is already initialised")
443 a8083063 Iustin Pop
444 2a6469d5 Alexander Schreiber
    if self.op.hypervisor_type == constants.HT_XEN_HVM31:
445 2a6469d5 Alexander Schreiber
      if not os.path.exists(constants.VNC_PASSWORD_FILE):
446 2a6469d5 Alexander Schreiber
        raise errors.OpPrereqError("Please prepare the cluster VNC"
447 2a6469d5 Alexander Schreiber
                                   "password file %s" %
448 2a6469d5 Alexander Schreiber
                                   constants.VNC_PASSWORD_FILE)
449 2a6469d5 Alexander Schreiber
450 89e1fc26 Iustin Pop
    self.hostname = hostname = utils.HostInfo()
451 ff98055b Iustin Pop
452 bcf043c9 Iustin Pop
    if hostname.ip.startswith("127."):
453 130e907e Iustin Pop
      raise errors.OpPrereqError("This host's IP resolves to the private"
454 107711b0 Michael Hanselmann
                                 " range (%s). Please fix DNS or %s." %
455 107711b0 Michael Hanselmann
                                 (hostname.ip, constants.ETC_HOSTS))
456 130e907e Iustin Pop
457 b15d625f Iustin Pop
    if not utils.TcpPing(hostname.ip, constants.DEFAULT_NODED_PORT,
458 b15d625f Iustin Pop
                         source=constants.LOCALHOST_IP_ADDRESS):
459 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Inconsistency: this host's name resolves"
460 3ecf6786 Iustin Pop
                                 " to %s,\nbut this ip address does not"
461 3ecf6786 Iustin Pop
                                 " belong to this host."
462 bcf043c9 Iustin Pop
                                 " Aborting." % hostname.ip)
463 a8083063 Iustin Pop
464 411f8ad0 Iustin Pop
    self.clustername = clustername = utils.HostInfo(self.op.cluster_name)
465 411f8ad0 Iustin Pop
466 411f8ad0 Iustin Pop
    if utils.TcpPing(clustername.ip, constants.DEFAULT_NODED_PORT,
467 411f8ad0 Iustin Pop
                     timeout=5):
468 411f8ad0 Iustin Pop
      raise errors.OpPrereqError("Cluster IP already active. Aborting.")
469 411f8ad0 Iustin Pop
470 a8083063 Iustin Pop
    secondary_ip = getattr(self.op, "secondary_ip", None)
471 a8083063 Iustin Pop
    if secondary_ip and not utils.IsValidIP(secondary_ip):
472 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Invalid secondary ip given")
473 16abfbc2 Alexander Schreiber
    if (secondary_ip and
474 16abfbc2 Alexander Schreiber
        secondary_ip != hostname.ip and
475 b15d625f Iustin Pop
        (not utils.TcpPing(secondary_ip, constants.DEFAULT_NODED_PORT,
476 b15d625f Iustin Pop
                           source=constants.LOCALHOST_IP_ADDRESS))):
477 f4bc1f2c Michael Hanselmann
      raise errors.OpPrereqError("You gave %s as secondary IP,"
478 f4bc1f2c Michael Hanselmann
                                 " but it does not belong to this host." %
479 16abfbc2 Alexander Schreiber
                                 secondary_ip)
480 a8083063 Iustin Pop
    self.secondary_ip = secondary_ip
481 a8083063 Iustin Pop
482 efa14262 Manuel Franceschini
    if not hasattr(self.op, "vg_name"):
483 efa14262 Manuel Franceschini
      self.op.vg_name = None
484 efa14262 Manuel Franceschini
    # if vg_name not None, checks if volume group is valid
485 efa14262 Manuel Franceschini
    if self.op.vg_name:
486 efa14262 Manuel Franceschini
      vgstatus = _HasValidVG(utils.ListVolumeGroups(), self.op.vg_name)
487 efa14262 Manuel Franceschini
      if vgstatus:
488 efa14262 Manuel Franceschini
        raise errors.OpPrereqError("Error: %s\nspecify --no-lvm-storage if"
489 efa14262 Manuel Franceschini
                                   " you are not using lvm" % vgstatus)
490 a8083063 Iustin Pop
491 2872a949 Manuel Franceschini
    self.op.file_storage_dir = os.path.normpath(self.op.file_storage_dir)
492 2872a949 Manuel Franceschini
493 871705db Manuel Franceschini
    if not os.path.isabs(self.op.file_storage_dir):
494 871705db Manuel Franceschini
      raise errors.OpPrereqError("The file storage directory you have is"
495 871705db Manuel Franceschini
                                 " not an absolute path.")
496 871705db Manuel Franceschini
497 871705db Manuel Franceschini
    if not os.path.exists(self.op.file_storage_dir):
498 2872a949 Manuel Franceschini
      try:
499 2872a949 Manuel Franceschini
        os.makedirs(self.op.file_storage_dir, 0750)
500 2872a949 Manuel Franceschini
      except OSError, err:
501 2872a949 Manuel Franceschini
        raise errors.OpPrereqError("Cannot create file storage directory"
502 2872a949 Manuel Franceschini
                                   " '%s': %s" %
503 2872a949 Manuel Franceschini
                                   (self.op.file_storage_dir, err))
504 2872a949 Manuel Franceschini
505 2872a949 Manuel Franceschini
    if not os.path.isdir(self.op.file_storage_dir):
506 2872a949 Manuel Franceschini
      raise errors.OpPrereqError("The file storage directory '%s' is not"
507 2872a949 Manuel Franceschini
                                 " a directory." % self.op.file_storage_dir)
508 871705db Manuel Franceschini
509 a8083063 Iustin Pop
    if not re.match("^[0-9a-z]{2}:[0-9a-z]{2}:[0-9a-z]{2}$",
510 a8083063 Iustin Pop
                    self.op.mac_prefix):
511 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Invalid mac prefix given '%s'" %
512 3ecf6786 Iustin Pop
                                 self.op.mac_prefix)
513 a8083063 Iustin Pop
514 2584d4a4 Alexander Schreiber
    if self.op.hypervisor_type not in constants.HYPER_TYPES:
515 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Invalid hypervisor type given '%s'" %
516 3ecf6786 Iustin Pop
                                 self.op.hypervisor_type)
517 a8083063 Iustin Pop
518 880478f8 Iustin Pop
    result = utils.RunCmd(["ip", "link", "show", "dev", self.op.master_netdev])
519 880478f8 Iustin Pop
    if result.failed:
520 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Invalid master netdev given (%s): '%s'" %
521 8925faaa Iustin Pop
                                 (self.op.master_netdev,
522 8925faaa Iustin Pop
                                  result.output.strip()))
523 880478f8 Iustin Pop
524 7dd30006 Michael Hanselmann
    if not (os.path.isfile(constants.NODE_INITD_SCRIPT) and
525 7dd30006 Michael Hanselmann
            os.access(constants.NODE_INITD_SCRIPT, os.X_OK)):
526 f4bc1f2c Michael Hanselmann
      raise errors.OpPrereqError("Init.d script '%s' missing or not"
527 f4bc1f2c Michael Hanselmann
                                 " executable." % constants.NODE_INITD_SCRIPT)
528 c7b46d59 Iustin Pop
529 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
530 a8083063 Iustin Pop
    """Initialize the cluster.
531 a8083063 Iustin Pop

532 a8083063 Iustin Pop
    """
533 a8083063 Iustin Pop
    clustername = self.clustername
534 a8083063 Iustin Pop
    hostname = self.hostname
535 a8083063 Iustin Pop
536 a8083063 Iustin Pop
    # set up the simple store
537 4167825b Iustin Pop
    self.sstore = ss = ssconf.SimpleStore()
538 a8083063 Iustin Pop
    ss.SetKey(ss.SS_HYPERVISOR, self.op.hypervisor_type)
539 bcf043c9 Iustin Pop
    ss.SetKey(ss.SS_MASTER_NODE, hostname.name)
540 bcf043c9 Iustin Pop
    ss.SetKey(ss.SS_MASTER_IP, clustername.ip)
541 880478f8 Iustin Pop
    ss.SetKey(ss.SS_MASTER_NETDEV, self.op.master_netdev)
542 bcf043c9 Iustin Pop
    ss.SetKey(ss.SS_CLUSTER_NAME, clustername.name)
543 871705db Manuel Franceschini
    ss.SetKey(ss.SS_FILE_STORAGE_DIR, self.op.file_storage_dir)
544 243cdbcc Michael Hanselmann
    ss.SetKey(ss.SS_CONFIG_VERSION, constants.CONFIG_VERSION)
545 a8083063 Iustin Pop
546 a8083063 Iustin Pop
    # set up the inter-node password and certificate
547 a8083063 Iustin Pop
    _InitGanetiServerSetup(ss)
548 a8083063 Iustin Pop
549 a8083063 Iustin Pop
    # start the master ip
550 bcf043c9 Iustin Pop
    rpc.call_node_start_master(hostname.name)
551 a8083063 Iustin Pop
552 a8083063 Iustin Pop
    # set up ssh config and /etc/hosts
553 70d9e3d8 Iustin Pop
    f = open(constants.SSH_HOST_RSA_PUB, 'r')
554 a8083063 Iustin Pop
    try:
555 a8083063 Iustin Pop
      sshline = f.read()
556 a8083063 Iustin Pop
    finally:
557 a8083063 Iustin Pop
      f.close()
558 a8083063 Iustin Pop
    sshkey = sshline.split(" ")[1]
559 a8083063 Iustin Pop
560 9440aeab Michael Hanselmann
    _AddHostToEtcHosts(hostname.name)
561 bcf043c9 Iustin Pop
    _InitSSHSetup(hostname.name)
562 a8083063 Iustin Pop
563 a8083063 Iustin Pop
    # init of cluster config file
564 4167825b Iustin Pop
    self.cfg = cfgw = config.ConfigWriter()
565 bcf043c9 Iustin Pop
    cfgw.InitConfig(hostname.name, hostname.ip, self.secondary_ip,
566 5fcdc80d Iustin Pop
                    sshkey, self.op.mac_prefix,
567 a8083063 Iustin Pop
                    self.op.vg_name, self.op.def_bridge)
568 a8083063 Iustin Pop
569 f408b346 Michael Hanselmann
    ssh.WriteKnownHostsFile(cfgw, ss, constants.SSH_KNOWN_HOSTS_FILE)
570 f408b346 Michael Hanselmann
571 a8083063 Iustin Pop
572 a8083063 Iustin Pop
class LUDestroyCluster(NoHooksLU):
573 a8083063 Iustin Pop
  """Logical unit for destroying the cluster.
574 a8083063 Iustin Pop

575 a8083063 Iustin Pop
  """
576 a8083063 Iustin Pop
  _OP_REQP = []
577 a8083063 Iustin Pop
578 a8083063 Iustin Pop
  def CheckPrereq(self):
579 a8083063 Iustin Pop
    """Check prerequisites.
580 a8083063 Iustin Pop

581 a8083063 Iustin Pop
    This checks whether the cluster is empty.
582 a8083063 Iustin Pop

583 a8083063 Iustin Pop
    Any errors are signalled by raising errors.OpPrereqError.
584 a8083063 Iustin Pop

585 a8083063 Iustin Pop
    """
586 880478f8 Iustin Pop
    master = self.sstore.GetMasterNode()
587 a8083063 Iustin Pop
588 a8083063 Iustin Pop
    nodelist = self.cfg.GetNodeList()
589 db915bd1 Michael Hanselmann
    if len(nodelist) != 1 or nodelist[0] != master:
590 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("There are still %d node(s) in"
591 3ecf6786 Iustin Pop
                                 " this cluster." % (len(nodelist) - 1))
592 db915bd1 Michael Hanselmann
    instancelist = self.cfg.GetInstanceList()
593 db915bd1 Michael Hanselmann
    if instancelist:
594 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("There are still %d instance(s) in"
595 3ecf6786 Iustin Pop
                                 " this cluster." % len(instancelist))
596 a8083063 Iustin Pop
597 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
598 a8083063 Iustin Pop
    """Destroys the cluster.
599 a8083063 Iustin Pop

600 a8083063 Iustin Pop
    """
601 c8a0948f Michael Hanselmann
    master = self.sstore.GetMasterNode()
602 c9064964 Iustin Pop
    if not rpc.call_node_stop_master(master):
603 c9064964 Iustin Pop
      raise errors.OpExecError("Could not disable the master role")
604 70d9e3d8 Iustin Pop
    priv_key, pub_key, _ = ssh.GetUserFiles(constants.GANETI_RUNAS)
605 70d9e3d8 Iustin Pop
    utils.CreateBackup(priv_key)
606 70d9e3d8 Iustin Pop
    utils.CreateBackup(pub_key)
607 c8a0948f Michael Hanselmann
    rpc.call_node_leave_cluster(master)
608 a8083063 Iustin Pop
609 a8083063 Iustin Pop
610 d8fff41c Guido Trotter
class LUVerifyCluster(LogicalUnit):
611 a8083063 Iustin Pop
  """Verifies the cluster status.
612 a8083063 Iustin Pop

613 a8083063 Iustin Pop
  """
614 d8fff41c Guido Trotter
  HPATH = "cluster-verify"
615 d8fff41c Guido Trotter
  HTYPE = constants.HTYPE_CLUSTER
616 e54c4c5e Guido Trotter
  _OP_REQP = ["skip_checks"]
617 a8083063 Iustin Pop
618 a8083063 Iustin Pop
  def _VerifyNode(self, node, file_list, local_cksum, vglist, node_result,
619 a8083063 Iustin Pop
                  remote_version, feedback_fn):
620 a8083063 Iustin Pop
    """Run multiple tests against a node.
621 a8083063 Iustin Pop

622 a8083063 Iustin Pop
    Test list:
623 a8083063 Iustin Pop
      - compares ganeti version
624 a8083063 Iustin Pop
      - checks vg existance and size > 20G
625 a8083063 Iustin Pop
      - checks config file checksum
626 a8083063 Iustin Pop
      - checks ssh to other nodes
627 a8083063 Iustin Pop

628 a8083063 Iustin Pop
    Args:
629 a8083063 Iustin Pop
      node: name of the node to check
630 a8083063 Iustin Pop
      file_list: required list of files
631 a8083063 Iustin Pop
      local_cksum: dictionary of local files and their checksums
632 098c0958 Michael Hanselmann

633 a8083063 Iustin Pop
    """
634 a8083063 Iustin Pop
    # compares ganeti version
635 a8083063 Iustin Pop
    local_version = constants.PROTOCOL_VERSION
636 a8083063 Iustin Pop
    if not remote_version:
637 c840ae6f Guido Trotter
      feedback_fn("  - ERROR: connection to %s failed" % (node))
638 a8083063 Iustin Pop
      return True
639 a8083063 Iustin Pop
640 a8083063 Iustin Pop
    if local_version != remote_version:
641 a8083063 Iustin Pop
      feedback_fn("  - ERROR: sw version mismatch: master %s, node(%s) %s" %
642 a8083063 Iustin Pop
                      (local_version, node, remote_version))
643 a8083063 Iustin Pop
      return True
644 a8083063 Iustin Pop
645 a8083063 Iustin Pop
    # checks vg existance and size > 20G
646 a8083063 Iustin Pop
647 a8083063 Iustin Pop
    bad = False
648 a8083063 Iustin Pop
    if not vglist:
649 a8083063 Iustin Pop
      feedback_fn("  - ERROR: unable to check volume groups on node %s." %
650 a8083063 Iustin Pop
                      (node,))
651 a8083063 Iustin Pop
      bad = True
652 a8083063 Iustin Pop
    else:
653 a8083063 Iustin Pop
      vgstatus = _HasValidVG(vglist, self.cfg.GetVGName())
654 a8083063 Iustin Pop
      if vgstatus:
655 a8083063 Iustin Pop
        feedback_fn("  - ERROR: %s on node %s" % (vgstatus, node))
656 a8083063 Iustin Pop
        bad = True
657 a8083063 Iustin Pop
658 a8083063 Iustin Pop
    # checks config file checksum
659 a8083063 Iustin Pop
    # checks ssh to any
660 a8083063 Iustin Pop
661 a8083063 Iustin Pop
    if 'filelist' not in node_result:
662 a8083063 Iustin Pop
      bad = True
663 a8083063 Iustin Pop
      feedback_fn("  - ERROR: node hasn't returned file checksum data")
664 a8083063 Iustin Pop
    else:
665 a8083063 Iustin Pop
      remote_cksum = node_result['filelist']
666 a8083063 Iustin Pop
      for file_name in file_list:
667 a8083063 Iustin Pop
        if file_name not in remote_cksum:
668 a8083063 Iustin Pop
          bad = True
669 a8083063 Iustin Pop
          feedback_fn("  - ERROR: file '%s' missing" % file_name)
670 a8083063 Iustin Pop
        elif remote_cksum[file_name] != local_cksum[file_name]:
671 a8083063 Iustin Pop
          bad = True
672 a8083063 Iustin Pop
          feedback_fn("  - ERROR: file '%s' has wrong checksum" % file_name)
673 a8083063 Iustin Pop
674 a8083063 Iustin Pop
    if 'nodelist' not in node_result:
675 a8083063 Iustin Pop
      bad = True
676 9d4bfc96 Iustin Pop
      feedback_fn("  - ERROR: node hasn't returned node ssh connectivity data")
677 a8083063 Iustin Pop
    else:
678 a8083063 Iustin Pop
      if node_result['nodelist']:
679 a8083063 Iustin Pop
        bad = True
680 a8083063 Iustin Pop
        for node in node_result['nodelist']:
681 9d4bfc96 Iustin Pop
          feedback_fn("  - ERROR: ssh communication with node '%s': %s" %
682 a8083063 Iustin Pop
                          (node, node_result['nodelist'][node]))
683 9d4bfc96 Iustin Pop
    if 'node-net-test' not in node_result:
684 9d4bfc96 Iustin Pop
      bad = True
685 9d4bfc96 Iustin Pop
      feedback_fn("  - ERROR: node hasn't returned node tcp connectivity data")
686 9d4bfc96 Iustin Pop
    else:
687 9d4bfc96 Iustin Pop
      if node_result['node-net-test']:
688 9d4bfc96 Iustin Pop
        bad = True
689 9d4bfc96 Iustin Pop
        nlist = utils.NiceSort(node_result['node-net-test'].keys())
690 9d4bfc96 Iustin Pop
        for node in nlist:
691 9d4bfc96 Iustin Pop
          feedback_fn("  - ERROR: tcp communication with node '%s': %s" %
692 9d4bfc96 Iustin Pop
                          (node, node_result['node-net-test'][node]))
693 9d4bfc96 Iustin Pop
694 a8083063 Iustin Pop
    hyp_result = node_result.get('hypervisor', None)
695 a8083063 Iustin Pop
    if hyp_result is not None:
696 a8083063 Iustin Pop
      feedback_fn("  - ERROR: hypervisor verify failure: '%s'" % hyp_result)
697 a8083063 Iustin Pop
    return bad
698 a8083063 Iustin Pop
699 c5705f58 Guido Trotter
  def _VerifyInstance(self, instance, instanceconfig, node_vol_is,
700 c5705f58 Guido Trotter
                      node_instance, feedback_fn):
701 a8083063 Iustin Pop
    """Verify an instance.
702 a8083063 Iustin Pop

703 a8083063 Iustin Pop
    This function checks to see if the required block devices are
704 a8083063 Iustin Pop
    available on the instance's node.
705 a8083063 Iustin Pop

706 a8083063 Iustin Pop
    """
707 a8083063 Iustin Pop
    bad = False
708 a8083063 Iustin Pop
709 a8083063 Iustin Pop
    node_current = instanceconfig.primary_node
710 a8083063 Iustin Pop
711 a8083063 Iustin Pop
    node_vol_should = {}
712 a8083063 Iustin Pop
    instanceconfig.MapLVsByNode(node_vol_should)
713 a8083063 Iustin Pop
714 a8083063 Iustin Pop
    for node in node_vol_should:
715 a8083063 Iustin Pop
      for volume in node_vol_should[node]:
716 a8083063 Iustin Pop
        if node not in node_vol_is or volume not in node_vol_is[node]:
717 a8083063 Iustin Pop
          feedback_fn("  - ERROR: volume %s missing on node %s" %
718 a8083063 Iustin Pop
                          (volume, node))
719 a8083063 Iustin Pop
          bad = True
720 a8083063 Iustin Pop
721 a8083063 Iustin Pop
    if not instanceconfig.status == 'down':
722 a872dae6 Guido Trotter
      if (node_current not in node_instance or
723 a872dae6 Guido Trotter
          not instance in node_instance[node_current]):
724 a8083063 Iustin Pop
        feedback_fn("  - ERROR: instance %s not running on node %s" %
725 a8083063 Iustin Pop
                        (instance, node_current))
726 a8083063 Iustin Pop
        bad = True
727 a8083063 Iustin Pop
728 a8083063 Iustin Pop
    for node in node_instance:
729 a8083063 Iustin Pop
      if (not node == node_current):
730 a8083063 Iustin Pop
        if instance in node_instance[node]:
731 a8083063 Iustin Pop
          feedback_fn("  - ERROR: instance %s should not run on node %s" %
732 a8083063 Iustin Pop
                          (instance, node))
733 a8083063 Iustin Pop
          bad = True
734 a8083063 Iustin Pop
735 6a438c98 Michael Hanselmann
    return bad
736 a8083063 Iustin Pop
737 a8083063 Iustin Pop
  def _VerifyOrphanVolumes(self, node_vol_should, node_vol_is, feedback_fn):
738 a8083063 Iustin Pop
    """Verify if there are any unknown volumes in the cluster.
739 a8083063 Iustin Pop

740 a8083063 Iustin Pop
    The .os, .swap and backup volumes are ignored. All other volumes are
741 a8083063 Iustin Pop
    reported as unknown.
742 a8083063 Iustin Pop

743 a8083063 Iustin Pop
    """
744 a8083063 Iustin Pop
    bad = False
745 a8083063 Iustin Pop
746 a8083063 Iustin Pop
    for node in node_vol_is:
747 a8083063 Iustin Pop
      for volume in node_vol_is[node]:
748 a8083063 Iustin Pop
        if node not in node_vol_should or volume not in node_vol_should[node]:
749 a8083063 Iustin Pop
          feedback_fn("  - ERROR: volume %s on node %s should not exist" %
750 a8083063 Iustin Pop
                      (volume, node))
751 a8083063 Iustin Pop
          bad = True
752 a8083063 Iustin Pop
    return bad
753 a8083063 Iustin Pop
754 a8083063 Iustin Pop
  def _VerifyOrphanInstances(self, instancelist, node_instance, feedback_fn):
755 a8083063 Iustin Pop
    """Verify the list of running instances.
756 a8083063 Iustin Pop

757 a8083063 Iustin Pop
    This checks what instances are running but unknown to the cluster.
758 a8083063 Iustin Pop

759 a8083063 Iustin Pop
    """
760 a8083063 Iustin Pop
    bad = False
761 a8083063 Iustin Pop
    for node in node_instance:
762 a8083063 Iustin Pop
      for runninginstance in node_instance[node]:
763 a8083063 Iustin Pop
        if runninginstance not in instancelist:
764 a8083063 Iustin Pop
          feedback_fn("  - ERROR: instance %s on node %s should not exist" %
765 a8083063 Iustin Pop
                          (runninginstance, node))
766 a8083063 Iustin Pop
          bad = True
767 a8083063 Iustin Pop
    return bad
768 a8083063 Iustin Pop
769 2b3b6ddd Guido Trotter
  def _VerifyNPlusOneMemory(self, node_info, instance_cfg, feedback_fn):
770 2b3b6ddd Guido Trotter
    """Verify N+1 Memory Resilience.
771 2b3b6ddd Guido Trotter

772 2b3b6ddd Guido Trotter
    Check that if one single node dies we can still start all the instances it
773 2b3b6ddd Guido Trotter
    was primary for.
774 2b3b6ddd Guido Trotter

775 2b3b6ddd Guido Trotter
    """
776 2b3b6ddd Guido Trotter
    bad = False
777 2b3b6ddd Guido Trotter
778 2b3b6ddd Guido Trotter
    for node, nodeinfo in node_info.iteritems():
779 2b3b6ddd Guido Trotter
      # This code checks that every node which is now listed as secondary has
780 2b3b6ddd Guido Trotter
      # enough memory to host all instances it is supposed to should a single
781 2b3b6ddd Guido Trotter
      # other node in the cluster fail.
782 2b3b6ddd Guido Trotter
      # FIXME: not ready for failover to an arbitrary node
783 2b3b6ddd Guido Trotter
      # FIXME: does not support file-backed instances
784 2b3b6ddd Guido Trotter
      # WARNING: we currently take into account down instances as well as up
785 2b3b6ddd Guido Trotter
      # ones, considering that even if they're down someone might want to start
786 2b3b6ddd Guido Trotter
      # them even in the event of a node failure.
787 2b3b6ddd Guido Trotter
      for prinode, instances in nodeinfo['sinst-by-pnode'].iteritems():
788 2b3b6ddd Guido Trotter
        needed_mem = 0
789 2b3b6ddd Guido Trotter
        for instance in instances:
790 2b3b6ddd Guido Trotter
          needed_mem += instance_cfg[instance].memory
791 2b3b6ddd Guido Trotter
        if nodeinfo['mfree'] < needed_mem:
792 2b3b6ddd Guido Trotter
          feedback_fn("  - ERROR: not enough memory on node %s to accomodate"
793 2b3b6ddd Guido Trotter
                      " failovers should node %s fail" % (node, prinode))
794 2b3b6ddd Guido Trotter
          bad = True
795 2b3b6ddd Guido Trotter
    return bad
796 2b3b6ddd Guido Trotter
797 a8083063 Iustin Pop
  def CheckPrereq(self):
798 a8083063 Iustin Pop
    """Check prerequisites.
799 a8083063 Iustin Pop

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

803 a8083063 Iustin Pop
    """
804 e54c4c5e Guido Trotter
    self.skip_set = frozenset(self.op.skip_checks)
805 e54c4c5e Guido Trotter
    if not constants.VERIFY_OPTIONAL_CHECKS.issuperset(self.skip_set):
806 e54c4c5e Guido Trotter
      raise errors.OpPrereqError("Invalid checks to be skipped specified")
807 a8083063 Iustin Pop
808 d8fff41c Guido Trotter
  def BuildHooksEnv(self):
809 d8fff41c Guido Trotter
    """Build hooks env.
810 d8fff41c Guido Trotter

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

814 d8fff41c Guido Trotter
    """
815 d8fff41c Guido Trotter
    all_nodes = self.cfg.GetNodeList()
816 d8fff41c Guido Trotter
    # TODO: populate the environment with useful information for verify hooks
817 d8fff41c Guido Trotter
    env = {}
818 d8fff41c Guido Trotter
    return env, [], all_nodes
819 d8fff41c Guido Trotter
820 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
821 a8083063 Iustin Pop
    """Verify integrity of cluster, performing various test on nodes.
822 a8083063 Iustin Pop

823 a8083063 Iustin Pop
    """
824 a8083063 Iustin Pop
    bad = False
825 a8083063 Iustin Pop
    feedback_fn("* Verifying global settings")
826 8522ceeb Iustin Pop
    for msg in self.cfg.VerifyConfig():
827 8522ceeb Iustin Pop
      feedback_fn("  - ERROR: %s" % msg)
828 a8083063 Iustin Pop
829 a8083063 Iustin Pop
    vg_name = self.cfg.GetVGName()
830 a8083063 Iustin Pop
    nodelist = utils.NiceSort(self.cfg.GetNodeList())
831 9d4bfc96 Iustin Pop
    nodeinfo = [self.cfg.GetNodeInfo(nname) for nname in nodelist]
832 a8083063 Iustin Pop
    instancelist = utils.NiceSort(self.cfg.GetInstanceList())
833 93e4c50b Guido Trotter
    i_non_redundant = [] # Non redundant instances
834 a8083063 Iustin Pop
    node_volume = {}
835 a8083063 Iustin Pop
    node_instance = {}
836 9c9c7d30 Guido Trotter
    node_info = {}
837 26b6af5e Guido Trotter
    instance_cfg = {}
838 a8083063 Iustin Pop
839 a8083063 Iustin Pop
    # FIXME: verify OS list
840 a8083063 Iustin Pop
    # do local checksums
841 cb91d46e Iustin Pop
    file_names = list(self.sstore.GetFileList())
842 cb91d46e Iustin Pop
    file_names.append(constants.SSL_CERT_FILE)
843 cb91d46e Iustin Pop
    file_names.append(constants.CLUSTER_CONF_FILE)
844 a8083063 Iustin Pop
    local_checksums = utils.FingerprintFiles(file_names)
845 a8083063 Iustin Pop
846 a8083063 Iustin Pop
    feedback_fn("* Gathering data (%d nodes)" % len(nodelist))
847 a8083063 Iustin Pop
    all_volumeinfo = rpc.call_volume_list(nodelist, vg_name)
848 a8083063 Iustin Pop
    all_instanceinfo = rpc.call_instance_list(nodelist)
849 a8083063 Iustin Pop
    all_vglist = rpc.call_vg_list(nodelist)
850 a8083063 Iustin Pop
    node_verify_param = {
851 a8083063 Iustin Pop
      'filelist': file_names,
852 a8083063 Iustin Pop
      'nodelist': nodelist,
853 a8083063 Iustin Pop
      'hypervisor': None,
854 9d4bfc96 Iustin Pop
      'node-net-test': [(node.name, node.primary_ip, node.secondary_ip)
855 9d4bfc96 Iustin Pop
                        for node in nodeinfo]
856 a8083063 Iustin Pop
      }
857 a8083063 Iustin Pop
    all_nvinfo = rpc.call_node_verify(nodelist, node_verify_param)
858 a8083063 Iustin Pop
    all_rversion = rpc.call_version(nodelist)
859 9c9c7d30 Guido Trotter
    all_ninfo = rpc.call_node_info(nodelist, self.cfg.GetVGName())
860 a8083063 Iustin Pop
861 a8083063 Iustin Pop
    for node in nodelist:
862 a8083063 Iustin Pop
      feedback_fn("* Verifying node %s" % node)
863 a8083063 Iustin Pop
      result = self._VerifyNode(node, file_names, local_checksums,
864 a8083063 Iustin Pop
                                all_vglist[node], all_nvinfo[node],
865 a8083063 Iustin Pop
                                all_rversion[node], feedback_fn)
866 a8083063 Iustin Pop
      bad = bad or result
867 a8083063 Iustin Pop
868 a8083063 Iustin Pop
      # node_volume
869 a8083063 Iustin Pop
      volumeinfo = all_volumeinfo[node]
870 a8083063 Iustin Pop
871 b63ed789 Iustin Pop
      if isinstance(volumeinfo, basestring):
872 b63ed789 Iustin Pop
        feedback_fn("  - ERROR: LVM problem on node %s: %s" %
873 b63ed789 Iustin Pop
                    (node, volumeinfo[-400:].encode('string_escape')))
874 b63ed789 Iustin Pop
        bad = True
875 b63ed789 Iustin Pop
        node_volume[node] = {}
876 b63ed789 Iustin Pop
      elif not isinstance(volumeinfo, dict):
877 a8083063 Iustin Pop
        feedback_fn("  - ERROR: connection to %s failed" % (node,))
878 a8083063 Iustin Pop
        bad = True
879 a8083063 Iustin Pop
        continue
880 b63ed789 Iustin Pop
      else:
881 b63ed789 Iustin Pop
        node_volume[node] = volumeinfo
882 a8083063 Iustin Pop
883 a8083063 Iustin Pop
      # node_instance
884 a8083063 Iustin Pop
      nodeinstance = all_instanceinfo[node]
885 a8083063 Iustin Pop
      if type(nodeinstance) != list:
886 a8083063 Iustin Pop
        feedback_fn("  - ERROR: connection to %s failed" % (node,))
887 a8083063 Iustin Pop
        bad = True
888 a8083063 Iustin Pop
        continue
889 a8083063 Iustin Pop
890 a8083063 Iustin Pop
      node_instance[node] = nodeinstance
891 a8083063 Iustin Pop
892 9c9c7d30 Guido Trotter
      # node_info
893 9c9c7d30 Guido Trotter
      nodeinfo = all_ninfo[node]
894 9c9c7d30 Guido Trotter
      if not isinstance(nodeinfo, dict):
895 9c9c7d30 Guido Trotter
        feedback_fn("  - ERROR: connection to %s failed" % (node,))
896 9c9c7d30 Guido Trotter
        bad = True
897 9c9c7d30 Guido Trotter
        continue
898 9c9c7d30 Guido Trotter
899 9c9c7d30 Guido Trotter
      try:
900 9c9c7d30 Guido Trotter
        node_info[node] = {
901 9c9c7d30 Guido Trotter
          "mfree": int(nodeinfo['memory_free']),
902 9c9c7d30 Guido Trotter
          "dfree": int(nodeinfo['vg_free']),
903 93e4c50b Guido Trotter
          "pinst": [],
904 93e4c50b Guido Trotter
          "sinst": [],
905 36e7da50 Guido Trotter
          # dictionary holding all instances this node is secondary for,
906 36e7da50 Guido Trotter
          # grouped by their primary node. Each key is a cluster node, and each
907 36e7da50 Guido Trotter
          # value is a list of instances which have the key as primary and the
908 36e7da50 Guido Trotter
          # current node as secondary.  this is handy to calculate N+1 memory
909 36e7da50 Guido Trotter
          # availability if you can only failover from a primary to its
910 36e7da50 Guido Trotter
          # secondary.
911 36e7da50 Guido Trotter
          "sinst-by-pnode": {},
912 9c9c7d30 Guido Trotter
        }
913 9c9c7d30 Guido Trotter
      except ValueError:
914 9c9c7d30 Guido Trotter
        feedback_fn("  - ERROR: invalid value returned from node %s" % (node,))
915 9c9c7d30 Guido Trotter
        bad = True
916 9c9c7d30 Guido Trotter
        continue
917 9c9c7d30 Guido Trotter
918 a8083063 Iustin Pop
    node_vol_should = {}
919 a8083063 Iustin Pop
920 a8083063 Iustin Pop
    for instance in instancelist:
921 a8083063 Iustin Pop
      feedback_fn("* Verifying instance %s" % instance)
922 a8083063 Iustin Pop
      inst_config = self.cfg.GetInstanceInfo(instance)
923 c5705f58 Guido Trotter
      result =  self._VerifyInstance(instance, inst_config, node_volume,
924 c5705f58 Guido Trotter
                                     node_instance, feedback_fn)
925 c5705f58 Guido Trotter
      bad = bad or result
926 a8083063 Iustin Pop
927 a8083063 Iustin Pop
      inst_config.MapLVsByNode(node_vol_should)
928 a8083063 Iustin Pop
929 26b6af5e Guido Trotter
      instance_cfg[instance] = inst_config
930 26b6af5e Guido Trotter
931 93e4c50b Guido Trotter
      pnode = inst_config.primary_node
932 93e4c50b Guido Trotter
      if pnode in node_info:
933 93e4c50b Guido Trotter
        node_info[pnode]['pinst'].append(instance)
934 93e4c50b Guido Trotter
      else:
935 93e4c50b Guido Trotter
        feedback_fn("  - ERROR: instance %s, connection to primary node"
936 93e4c50b Guido Trotter
                    " %s failed" % (instance, pnode))
937 93e4c50b Guido Trotter
        bad = True
938 93e4c50b Guido Trotter
939 93e4c50b Guido Trotter
      # If the instance is non-redundant we cannot survive losing its primary
940 93e4c50b Guido Trotter
      # node, so we are not N+1 compliant. On the other hand we have no disk
941 93e4c50b Guido Trotter
      # templates with more than one secondary so that situation is not well
942 93e4c50b Guido Trotter
      # supported either.
943 93e4c50b Guido Trotter
      # FIXME: does not support file-backed instances
944 93e4c50b Guido Trotter
      if len(inst_config.secondary_nodes) == 0:
945 93e4c50b Guido Trotter
        i_non_redundant.append(instance)
946 93e4c50b Guido Trotter
      elif len(inst_config.secondary_nodes) > 1:
947 93e4c50b Guido Trotter
        feedback_fn("  - WARNING: multiple secondaries for instance %s"
948 93e4c50b Guido Trotter
                    % instance)
949 93e4c50b Guido Trotter
950 93e4c50b Guido Trotter
      for snode in inst_config.secondary_nodes:
951 93e4c50b Guido Trotter
        if snode in node_info:
952 93e4c50b Guido Trotter
          node_info[snode]['sinst'].append(instance)
953 36e7da50 Guido Trotter
          if pnode not in node_info[snode]['sinst-by-pnode']:
954 36e7da50 Guido Trotter
            node_info[snode]['sinst-by-pnode'][pnode] = []
955 36e7da50 Guido Trotter
          node_info[snode]['sinst-by-pnode'][pnode].append(instance)
956 93e4c50b Guido Trotter
        else:
957 93e4c50b Guido Trotter
          feedback_fn("  - ERROR: instance %s, connection to secondary node"
958 93e4c50b Guido Trotter
                      " %s failed" % (instance, snode))
959 93e4c50b Guido Trotter
960 a8083063 Iustin Pop
    feedback_fn("* Verifying orphan volumes")
961 a8083063 Iustin Pop
    result = self._VerifyOrphanVolumes(node_vol_should, node_volume,
962 a8083063 Iustin Pop
                                       feedback_fn)
963 a8083063 Iustin Pop
    bad = bad or result
964 a8083063 Iustin Pop
965 a8083063 Iustin Pop
    feedback_fn("* Verifying remaining instances")
966 a8083063 Iustin Pop
    result = self._VerifyOrphanInstances(instancelist, node_instance,
967 a8083063 Iustin Pop
                                         feedback_fn)
968 a8083063 Iustin Pop
    bad = bad or result
969 a8083063 Iustin Pop
970 e54c4c5e Guido Trotter
    if constants.VERIFY_NPLUSONE_MEM not in self.skip_set:
971 e54c4c5e Guido Trotter
      feedback_fn("* Verifying N+1 Memory redundancy")
972 e54c4c5e Guido Trotter
      result = self._VerifyNPlusOneMemory(node_info, instance_cfg, feedback_fn)
973 e54c4c5e Guido Trotter
      bad = bad or result
974 2b3b6ddd Guido Trotter
975 2b3b6ddd Guido Trotter
    feedback_fn("* Other Notes")
976 2b3b6ddd Guido Trotter
    if i_non_redundant:
977 2b3b6ddd Guido Trotter
      feedback_fn("  - NOTICE: %d non-redundant instance(s) found."
978 2b3b6ddd Guido Trotter
                  % len(i_non_redundant))
979 2b3b6ddd Guido Trotter
980 a8083063 Iustin Pop
    return int(bad)
981 a8083063 Iustin Pop
982 d8fff41c Guido Trotter
  def HooksCallBack(self, phase, hooks_results, feedback_fn, lu_result):
983 d8fff41c Guido Trotter
    """Analize the post-hooks' result, handle it, and send some
984 d8fff41c Guido Trotter
    nicely-formatted feedback back to the user.
985 d8fff41c Guido Trotter

986 d8fff41c Guido Trotter
    Args:
987 d8fff41c Guido Trotter
      phase: the hooks phase that has just been run
988 d8fff41c Guido Trotter
      hooks_results: the results of the multi-node hooks rpc call
989 d8fff41c Guido Trotter
      feedback_fn: function to send feedback back to the caller
990 d8fff41c Guido Trotter
      lu_result: previous Exec result
991 d8fff41c Guido Trotter

992 d8fff41c Guido Trotter
    """
993 d8fff41c Guido Trotter
    # We only really run POST phase hooks, and are only interested in their results
994 d8fff41c Guido Trotter
    if phase == constants.HOOKS_PHASE_POST:
995 d8fff41c Guido Trotter
      # Used to change hooks' output to proper indentation
996 d8fff41c Guido Trotter
      indent_re = re.compile('^', re.M)
997 d8fff41c Guido Trotter
      feedback_fn("* Hooks Results")
998 d8fff41c Guido Trotter
      if not hooks_results:
999 d8fff41c Guido Trotter
        feedback_fn("  - ERROR: general communication failure")
1000 d8fff41c Guido Trotter
        lu_result = 1
1001 d8fff41c Guido Trotter
      else:
1002 d8fff41c Guido Trotter
        for node_name in hooks_results:
1003 d8fff41c Guido Trotter
          show_node_header = True
1004 d8fff41c Guido Trotter
          res = hooks_results[node_name]
1005 d8fff41c Guido Trotter
          if res is False or not isinstance(res, list):
1006 d8fff41c Guido Trotter
            feedback_fn("    Communication failure")
1007 d8fff41c Guido Trotter
            lu_result = 1
1008 d8fff41c Guido Trotter
            continue
1009 d8fff41c Guido Trotter
          for script, hkr, output in res:
1010 d8fff41c Guido Trotter
            if hkr == constants.HKR_FAIL:
1011 d8fff41c Guido Trotter
              # The node header is only shown once, if there are
1012 d8fff41c Guido Trotter
              # failing hooks on that node
1013 d8fff41c Guido Trotter
              if show_node_header:
1014 d8fff41c Guido Trotter
                feedback_fn("  Node %s:" % node_name)
1015 d8fff41c Guido Trotter
                show_node_header = False
1016 d8fff41c Guido Trotter
              feedback_fn("    ERROR: Script %s failed, output:" % script)
1017 d8fff41c Guido Trotter
              output = indent_re.sub('      ', output)
1018 d8fff41c Guido Trotter
              feedback_fn("%s" % output)
1019 d8fff41c Guido Trotter
              lu_result = 1
1020 d8fff41c Guido Trotter
1021 d8fff41c Guido Trotter
      return lu_result
1022 d8fff41c Guido Trotter
1023 a8083063 Iustin Pop
1024 2c95a8d4 Iustin Pop
class LUVerifyDisks(NoHooksLU):
1025 2c95a8d4 Iustin Pop
  """Verifies the cluster disks status.
1026 2c95a8d4 Iustin Pop

1027 2c95a8d4 Iustin Pop
  """
1028 2c95a8d4 Iustin Pop
  _OP_REQP = []
1029 2c95a8d4 Iustin Pop
1030 2c95a8d4 Iustin Pop
  def CheckPrereq(self):
1031 2c95a8d4 Iustin Pop
    """Check prerequisites.
1032 2c95a8d4 Iustin Pop

1033 2c95a8d4 Iustin Pop
    This has no prerequisites.
1034 2c95a8d4 Iustin Pop

1035 2c95a8d4 Iustin Pop
    """
1036 2c95a8d4 Iustin Pop
    pass
1037 2c95a8d4 Iustin Pop
1038 2c95a8d4 Iustin Pop
  def Exec(self, feedback_fn):
1039 2c95a8d4 Iustin Pop
    """Verify integrity of cluster disks.
1040 2c95a8d4 Iustin Pop

1041 2c95a8d4 Iustin Pop
    """
1042 b63ed789 Iustin Pop
    result = res_nodes, res_nlvm, res_instances, res_missing = [], {}, [], {}
1043 2c95a8d4 Iustin Pop
1044 2c95a8d4 Iustin Pop
    vg_name = self.cfg.GetVGName()
1045 2c95a8d4 Iustin Pop
    nodes = utils.NiceSort(self.cfg.GetNodeList())
1046 2c95a8d4 Iustin Pop
    instances = [self.cfg.GetInstanceInfo(name)
1047 2c95a8d4 Iustin Pop
                 for name in self.cfg.GetInstanceList()]
1048 2c95a8d4 Iustin Pop
1049 2c95a8d4 Iustin Pop
    nv_dict = {}
1050 2c95a8d4 Iustin Pop
    for inst in instances:
1051 2c95a8d4 Iustin Pop
      inst_lvs = {}
1052 2c95a8d4 Iustin Pop
      if (inst.status != "up" or
1053 2c95a8d4 Iustin Pop
          inst.disk_template not in constants.DTS_NET_MIRROR):
1054 2c95a8d4 Iustin Pop
        continue
1055 2c95a8d4 Iustin Pop
      inst.MapLVsByNode(inst_lvs)
1056 2c95a8d4 Iustin Pop
      # transform { iname: {node: [vol,],},} to {(node, vol): iname}
1057 2c95a8d4 Iustin Pop
      for node, vol_list in inst_lvs.iteritems():
1058 2c95a8d4 Iustin Pop
        for vol in vol_list:
1059 2c95a8d4 Iustin Pop
          nv_dict[(node, vol)] = inst
1060 2c95a8d4 Iustin Pop
1061 2c95a8d4 Iustin Pop
    if not nv_dict:
1062 2c95a8d4 Iustin Pop
      return result
1063 2c95a8d4 Iustin Pop
1064 2c95a8d4 Iustin Pop
    node_lvs = rpc.call_volume_list(nodes, vg_name)
1065 2c95a8d4 Iustin Pop
1066 2c95a8d4 Iustin Pop
    to_act = set()
1067 2c95a8d4 Iustin Pop
    for node in nodes:
1068 2c95a8d4 Iustin Pop
      # node_volume
1069 2c95a8d4 Iustin Pop
      lvs = node_lvs[node]
1070 2c95a8d4 Iustin Pop
1071 b63ed789 Iustin Pop
      if isinstance(lvs, basestring):
1072 b63ed789 Iustin Pop
        logger.Info("error enumerating LVs on node %s: %s" % (node, lvs))
1073 b63ed789 Iustin Pop
        res_nlvm[node] = lvs
1074 b63ed789 Iustin Pop
      elif not isinstance(lvs, dict):
1075 2c95a8d4 Iustin Pop
        logger.Info("connection to node %s failed or invalid data returned" %
1076 2c95a8d4 Iustin Pop
                    (node,))
1077 2c95a8d4 Iustin Pop
        res_nodes.append(node)
1078 2c95a8d4 Iustin Pop
        continue
1079 2c95a8d4 Iustin Pop
1080 2c95a8d4 Iustin Pop
      for lv_name, (_, lv_inactive, lv_online) in lvs.iteritems():
1081 b63ed789 Iustin Pop
        inst = nv_dict.pop((node, lv_name), None)
1082 b63ed789 Iustin Pop
        if (not lv_online and inst is not None
1083 b63ed789 Iustin Pop
            and inst.name not in res_instances):
1084 b08d5a87 Iustin Pop
          res_instances.append(inst.name)
1085 2c95a8d4 Iustin Pop
1086 b63ed789 Iustin Pop
    # any leftover items in nv_dict are missing LVs, let's arrange the
1087 b63ed789 Iustin Pop
    # data better
1088 b63ed789 Iustin Pop
    for key, inst in nv_dict.iteritems():
1089 b63ed789 Iustin Pop
      if inst.name not in res_missing:
1090 b63ed789 Iustin Pop
        res_missing[inst.name] = []
1091 b63ed789 Iustin Pop
      res_missing[inst.name].append(key)
1092 b63ed789 Iustin Pop
1093 2c95a8d4 Iustin Pop
    return result
1094 2c95a8d4 Iustin Pop
1095 2c95a8d4 Iustin Pop
1096 07bd8a51 Iustin Pop
class LURenameCluster(LogicalUnit):
1097 07bd8a51 Iustin Pop
  """Rename the cluster.
1098 07bd8a51 Iustin Pop

1099 07bd8a51 Iustin Pop
  """
1100 07bd8a51 Iustin Pop
  HPATH = "cluster-rename"
1101 07bd8a51 Iustin Pop
  HTYPE = constants.HTYPE_CLUSTER
1102 07bd8a51 Iustin Pop
  _OP_REQP = ["name"]
1103 07bd8a51 Iustin Pop
1104 07bd8a51 Iustin Pop
  def BuildHooksEnv(self):
1105 07bd8a51 Iustin Pop
    """Build hooks env.
1106 07bd8a51 Iustin Pop

1107 07bd8a51 Iustin Pop
    """
1108 07bd8a51 Iustin Pop
    env = {
1109 488b540d Iustin Pop
      "OP_TARGET": self.sstore.GetClusterName(),
1110 07bd8a51 Iustin Pop
      "NEW_NAME": self.op.name,
1111 07bd8a51 Iustin Pop
      }
1112 07bd8a51 Iustin Pop
    mn = self.sstore.GetMasterNode()
1113 07bd8a51 Iustin Pop
    return env, [mn], [mn]
1114 07bd8a51 Iustin Pop
1115 07bd8a51 Iustin Pop
  def CheckPrereq(self):
1116 07bd8a51 Iustin Pop
    """Verify that the passed name is a valid one.
1117 07bd8a51 Iustin Pop

1118 07bd8a51 Iustin Pop
    """
1119 89e1fc26 Iustin Pop
    hostname = utils.HostInfo(self.op.name)
1120 07bd8a51 Iustin Pop
1121 bcf043c9 Iustin Pop
    new_name = hostname.name
1122 bcf043c9 Iustin Pop
    self.ip = new_ip = hostname.ip
1123 07bd8a51 Iustin Pop
    old_name = self.sstore.GetClusterName()
1124 07bd8a51 Iustin Pop
    old_ip = self.sstore.GetMasterIP()
1125 07bd8a51 Iustin Pop
    if new_name == old_name and new_ip == old_ip:
1126 07bd8a51 Iustin Pop
      raise errors.OpPrereqError("Neither the name nor the IP address of the"
1127 07bd8a51 Iustin Pop
                                 " cluster has changed")
1128 07bd8a51 Iustin Pop
    if new_ip != old_ip:
1129 07bd8a51 Iustin Pop
      result = utils.RunCmd(["fping", "-q", new_ip])
1130 07bd8a51 Iustin Pop
      if not result.failed:
1131 07bd8a51 Iustin Pop
        raise errors.OpPrereqError("The given cluster IP address (%s) is"
1132 07bd8a51 Iustin Pop
                                   " reachable on the network. Aborting." %
1133 07bd8a51 Iustin Pop
                                   new_ip)
1134 07bd8a51 Iustin Pop
1135 07bd8a51 Iustin Pop
    self.op.name = new_name
1136 07bd8a51 Iustin Pop
1137 07bd8a51 Iustin Pop
  def Exec(self, feedback_fn):
1138 07bd8a51 Iustin Pop
    """Rename the cluster.
1139 07bd8a51 Iustin Pop

1140 07bd8a51 Iustin Pop
    """
1141 07bd8a51 Iustin Pop
    clustername = self.op.name
1142 07bd8a51 Iustin Pop
    ip = self.ip
1143 07bd8a51 Iustin Pop
    ss = self.sstore
1144 07bd8a51 Iustin Pop
1145 07bd8a51 Iustin Pop
    # shutdown the master IP
1146 07bd8a51 Iustin Pop
    master = ss.GetMasterNode()
1147 07bd8a51 Iustin Pop
    if not rpc.call_node_stop_master(master):
1148 07bd8a51 Iustin Pop
      raise errors.OpExecError("Could not disable the master role")
1149 07bd8a51 Iustin Pop
1150 07bd8a51 Iustin Pop
    try:
1151 07bd8a51 Iustin Pop
      # modify the sstore
1152 07bd8a51 Iustin Pop
      ss.SetKey(ss.SS_MASTER_IP, ip)
1153 07bd8a51 Iustin Pop
      ss.SetKey(ss.SS_CLUSTER_NAME, clustername)
1154 07bd8a51 Iustin Pop
1155 07bd8a51 Iustin Pop
      # Distribute updated ss config to all nodes
1156 07bd8a51 Iustin Pop
      myself = self.cfg.GetNodeInfo(master)
1157 07bd8a51 Iustin Pop
      dist_nodes = self.cfg.GetNodeList()
1158 07bd8a51 Iustin Pop
      if myself.name in dist_nodes:
1159 07bd8a51 Iustin Pop
        dist_nodes.remove(myself.name)
1160 07bd8a51 Iustin Pop
1161 07bd8a51 Iustin Pop
      logger.Debug("Copying updated ssconf data to all nodes")
1162 07bd8a51 Iustin Pop
      for keyname in [ss.SS_CLUSTER_NAME, ss.SS_MASTER_IP]:
1163 07bd8a51 Iustin Pop
        fname = ss.KeyToFilename(keyname)
1164 07bd8a51 Iustin Pop
        result = rpc.call_upload_file(dist_nodes, fname)
1165 07bd8a51 Iustin Pop
        for to_node in dist_nodes:
1166 07bd8a51 Iustin Pop
          if not result[to_node]:
1167 07bd8a51 Iustin Pop
            logger.Error("copy of file %s to node %s failed" %
1168 07bd8a51 Iustin Pop
                         (fname, to_node))
1169 07bd8a51 Iustin Pop
    finally:
1170 07bd8a51 Iustin Pop
      if not rpc.call_node_start_master(master):
1171 f4bc1f2c Michael Hanselmann
        logger.Error("Could not re-enable the master role on the master,"
1172 f4bc1f2c Michael Hanselmann
                     " please restart manually.")
1173 07bd8a51 Iustin Pop
1174 07bd8a51 Iustin Pop
1175 8084f9f6 Manuel Franceschini
def _RecursiveCheckIfLVMBased(disk):
1176 8084f9f6 Manuel Franceschini
  """Check if the given disk or its children are lvm-based.
1177 8084f9f6 Manuel Franceschini

1178 8084f9f6 Manuel Franceschini
  Args:
1179 8084f9f6 Manuel Franceschini
    disk: ganeti.objects.Disk object
1180 8084f9f6 Manuel Franceschini

1181 8084f9f6 Manuel Franceschini
  Returns:
1182 8084f9f6 Manuel Franceschini
    boolean indicating whether a LD_LV dev_type was found or not
1183 8084f9f6 Manuel Franceschini

1184 8084f9f6 Manuel Franceschini
  """
1185 8084f9f6 Manuel Franceschini
  if disk.children:
1186 8084f9f6 Manuel Franceschini
    for chdisk in disk.children:
1187 8084f9f6 Manuel Franceschini
      if _RecursiveCheckIfLVMBased(chdisk):
1188 8084f9f6 Manuel Franceschini
        return True
1189 8084f9f6 Manuel Franceschini
  return disk.dev_type == constants.LD_LV
1190 8084f9f6 Manuel Franceschini
1191 8084f9f6 Manuel Franceschini
1192 8084f9f6 Manuel Franceschini
class LUSetClusterParams(LogicalUnit):
1193 8084f9f6 Manuel Franceschini
  """Change the parameters of the cluster.
1194 8084f9f6 Manuel Franceschini

1195 8084f9f6 Manuel Franceschini
  """
1196 8084f9f6 Manuel Franceschini
  HPATH = "cluster-modify"
1197 8084f9f6 Manuel Franceschini
  HTYPE = constants.HTYPE_CLUSTER
1198 8084f9f6 Manuel Franceschini
  _OP_REQP = []
1199 8084f9f6 Manuel Franceschini
1200 8084f9f6 Manuel Franceschini
  def BuildHooksEnv(self):
1201 8084f9f6 Manuel Franceschini
    """Build hooks env.
1202 8084f9f6 Manuel Franceschini

1203 8084f9f6 Manuel Franceschini
    """
1204 8084f9f6 Manuel Franceschini
    env = {
1205 8084f9f6 Manuel Franceschini
      "OP_TARGET": self.sstore.GetClusterName(),
1206 8084f9f6 Manuel Franceschini
      "NEW_VG_NAME": self.op.vg_name,
1207 8084f9f6 Manuel Franceschini
      }
1208 8084f9f6 Manuel Franceschini
    mn = self.sstore.GetMasterNode()
1209 8084f9f6 Manuel Franceschini
    return env, [mn], [mn]
1210 8084f9f6 Manuel Franceschini
1211 8084f9f6 Manuel Franceschini
  def CheckPrereq(self):
1212 8084f9f6 Manuel Franceschini
    """Check prerequisites.
1213 8084f9f6 Manuel Franceschini

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

1217 8084f9f6 Manuel Franceschini
    """
1218 8084f9f6 Manuel Franceschini
    if not self.op.vg_name:
1219 8084f9f6 Manuel Franceschini
      instances = [self.cfg.GetInstanceInfo(name)
1220 8084f9f6 Manuel Franceschini
                   for name in self.cfg.GetInstanceList()]
1221 8084f9f6 Manuel Franceschini
      for inst in instances:
1222 8084f9f6 Manuel Franceschini
        for disk in inst.disks:
1223 8084f9f6 Manuel Franceschini
          if _RecursiveCheckIfLVMBased(disk):
1224 8084f9f6 Manuel Franceschini
            raise errors.OpPrereqError("Cannot disable lvm storage while"
1225 8084f9f6 Manuel Franceschini
                                       " lvm-based instances exist")
1226 8084f9f6 Manuel Franceschini
1227 8084f9f6 Manuel Franceschini
    # if vg_name not None, checks given volume group on all nodes
1228 8084f9f6 Manuel Franceschini
    if self.op.vg_name:
1229 8084f9f6 Manuel Franceschini
      node_list = self.cfg.GetNodeList()
1230 8084f9f6 Manuel Franceschini
      vglist = rpc.call_vg_list(node_list)
1231 8084f9f6 Manuel Franceschini
      for node in node_list:
1232 8084f9f6 Manuel Franceschini
        vgstatus = _HasValidVG(vglist[node], self.op.vg_name)
1233 8084f9f6 Manuel Franceschini
        if vgstatus:
1234 8084f9f6 Manuel Franceschini
          raise errors.OpPrereqError("Error on node '%s': %s" %
1235 8084f9f6 Manuel Franceschini
                                     (node, vgstatus))
1236 8084f9f6 Manuel Franceschini
1237 8084f9f6 Manuel Franceschini
  def Exec(self, feedback_fn):
1238 8084f9f6 Manuel Franceschini
    """Change the parameters of the cluster.
1239 8084f9f6 Manuel Franceschini

1240 8084f9f6 Manuel Franceschini
    """
1241 8084f9f6 Manuel Franceschini
    if self.op.vg_name != self.cfg.GetVGName():
1242 8084f9f6 Manuel Franceschini
      self.cfg.SetVGName(self.op.vg_name)
1243 8084f9f6 Manuel Franceschini
    else:
1244 8084f9f6 Manuel Franceschini
      feedback_fn("Cluster LVM configuration already in desired"
1245 8084f9f6 Manuel Franceschini
                  " state, not changing")
1246 8084f9f6 Manuel Franceschini
1247 8084f9f6 Manuel Franceschini
1248 5bfac263 Iustin Pop
def _WaitForSync(cfgw, instance, proc, oneshot=False, unlock=False):
1249 a8083063 Iustin Pop
  """Sleep and poll for an instance's disk to sync.
1250 a8083063 Iustin Pop

1251 a8083063 Iustin Pop
  """
1252 a8083063 Iustin Pop
  if not instance.disks:
1253 a8083063 Iustin Pop
    return True
1254 a8083063 Iustin Pop
1255 a8083063 Iustin Pop
  if not oneshot:
1256 5bfac263 Iustin Pop
    proc.LogInfo("Waiting for instance %s to sync disks." % instance.name)
1257 a8083063 Iustin Pop
1258 a8083063 Iustin Pop
  node = instance.primary_node
1259 a8083063 Iustin Pop
1260 a8083063 Iustin Pop
  for dev in instance.disks:
1261 a8083063 Iustin Pop
    cfgw.SetDiskID(dev, node)
1262 a8083063 Iustin Pop
1263 a8083063 Iustin Pop
  retries = 0
1264 a8083063 Iustin Pop
  while True:
1265 a8083063 Iustin Pop
    max_time = 0
1266 a8083063 Iustin Pop
    done = True
1267 a8083063 Iustin Pop
    cumul_degraded = False
1268 a8083063 Iustin Pop
    rstats = rpc.call_blockdev_getmirrorstatus(node, instance.disks)
1269 a8083063 Iustin Pop
    if not rstats:
1270 5bfac263 Iustin Pop
      proc.LogWarning("Can't get any data from node %s" % node)
1271 a8083063 Iustin Pop
      retries += 1
1272 a8083063 Iustin Pop
      if retries >= 10:
1273 3ecf6786 Iustin Pop
        raise errors.RemoteError("Can't contact node %s for mirror data,"
1274 3ecf6786 Iustin Pop
                                 " aborting." % node)
1275 a8083063 Iustin Pop
      time.sleep(6)
1276 a8083063 Iustin Pop
      continue
1277 a8083063 Iustin Pop
    retries = 0
1278 a8083063 Iustin Pop
    for i in range(len(rstats)):
1279 a8083063 Iustin Pop
      mstat = rstats[i]
1280 a8083063 Iustin Pop
      if mstat is None:
1281 5bfac263 Iustin Pop
        proc.LogWarning("Can't compute data for node %s/%s" %
1282 a8083063 Iustin Pop
                        (node, instance.disks[i].iv_name))
1283 a8083063 Iustin Pop
        continue
1284 0834c866 Iustin Pop
      # we ignore the ldisk parameter
1285 0834c866 Iustin Pop
      perc_done, est_time, is_degraded, _ = mstat
1286 a8083063 Iustin Pop
      cumul_degraded = cumul_degraded or (is_degraded and perc_done is None)
1287 a8083063 Iustin Pop
      if perc_done is not None:
1288 a8083063 Iustin Pop
        done = False
1289 a8083063 Iustin Pop
        if est_time is not None:
1290 a8083063 Iustin Pop
          rem_time = "%d estimated seconds remaining" % est_time
1291 a8083063 Iustin Pop
          max_time = est_time
1292 a8083063 Iustin Pop
        else:
1293 a8083063 Iustin Pop
          rem_time = "no time estimate"
1294 5bfac263 Iustin Pop
        proc.LogInfo("- device %s: %5.2f%% done, %s" %
1295 5bfac263 Iustin Pop
                     (instance.disks[i].iv_name, perc_done, rem_time))
1296 a8083063 Iustin Pop
    if done or oneshot:
1297 a8083063 Iustin Pop
      break
1298 a8083063 Iustin Pop
1299 a8083063 Iustin Pop
    if unlock:
1300 685ee993 Iustin Pop
      #utils.Unlock('cmd')
1301 685ee993 Iustin Pop
      pass
1302 a8083063 Iustin Pop
    try:
1303 a8083063 Iustin Pop
      time.sleep(min(60, max_time))
1304 a8083063 Iustin Pop
    finally:
1305 a8083063 Iustin Pop
      if unlock:
1306 685ee993 Iustin Pop
        #utils.Lock('cmd')
1307 685ee993 Iustin Pop
        pass
1308 a8083063 Iustin Pop
1309 a8083063 Iustin Pop
  if done:
1310 5bfac263 Iustin Pop
    proc.LogInfo("Instance %s's disks are in sync." % instance.name)
1311 a8083063 Iustin Pop
  return not cumul_degraded
1312 a8083063 Iustin Pop
1313 a8083063 Iustin Pop
1314 0834c866 Iustin Pop
def _CheckDiskConsistency(cfgw, dev, node, on_primary, ldisk=False):
1315 a8083063 Iustin Pop
  """Check that mirrors are not degraded.
1316 a8083063 Iustin Pop

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

1321 a8083063 Iustin Pop
  """
1322 a8083063 Iustin Pop
  cfgw.SetDiskID(dev, node)
1323 0834c866 Iustin Pop
  if ldisk:
1324 0834c866 Iustin Pop
    idx = 6
1325 0834c866 Iustin Pop
  else:
1326 0834c866 Iustin Pop
    idx = 5
1327 a8083063 Iustin Pop
1328 a8083063 Iustin Pop
  result = True
1329 a8083063 Iustin Pop
  if on_primary or dev.AssembleOnSecondary():
1330 a8083063 Iustin Pop
    rstats = rpc.call_blockdev_find(node, dev)
1331 a8083063 Iustin Pop
    if not rstats:
1332 aa9d0c32 Guido Trotter
      logger.ToStderr("Node %s: Disk degraded, not found or node down" % node)
1333 a8083063 Iustin Pop
      result = False
1334 a8083063 Iustin Pop
    else:
1335 0834c866 Iustin Pop
      result = result and (not rstats[idx])
1336 a8083063 Iustin Pop
  if dev.children:
1337 a8083063 Iustin Pop
    for child in dev.children:
1338 a8083063 Iustin Pop
      result = result and _CheckDiskConsistency(cfgw, child, node, on_primary)
1339 a8083063 Iustin Pop
1340 a8083063 Iustin Pop
  return result
1341 a8083063 Iustin Pop
1342 a8083063 Iustin Pop
1343 a8083063 Iustin Pop
class LUDiagnoseOS(NoHooksLU):
1344 a8083063 Iustin Pop
  """Logical unit for OS diagnose/query.
1345 a8083063 Iustin Pop

1346 a8083063 Iustin Pop
  """
1347 1f9430d6 Iustin Pop
  _OP_REQP = ["output_fields", "names"]
1348 a8083063 Iustin Pop
1349 a8083063 Iustin Pop
  def CheckPrereq(self):
1350 a8083063 Iustin Pop
    """Check prerequisites.
1351 a8083063 Iustin Pop

1352 a8083063 Iustin Pop
    This always succeeds, since this is a pure query LU.
1353 a8083063 Iustin Pop

1354 a8083063 Iustin Pop
    """
1355 1f9430d6 Iustin Pop
    if self.op.names:
1356 1f9430d6 Iustin Pop
      raise errors.OpPrereqError("Selective OS query not supported")
1357 1f9430d6 Iustin Pop
1358 1f9430d6 Iustin Pop
    self.dynamic_fields = frozenset(["name", "valid", "node_status"])
1359 1f9430d6 Iustin Pop
    _CheckOutputFields(static=[],
1360 1f9430d6 Iustin Pop
                       dynamic=self.dynamic_fields,
1361 1f9430d6 Iustin Pop
                       selected=self.op.output_fields)
1362 1f9430d6 Iustin Pop
1363 1f9430d6 Iustin Pop
  @staticmethod
1364 1f9430d6 Iustin Pop
  def _DiagnoseByOS(node_list, rlist):
1365 1f9430d6 Iustin Pop
    """Remaps a per-node return list into an a per-os per-node dictionary
1366 1f9430d6 Iustin Pop

1367 1f9430d6 Iustin Pop
      Args:
1368 1f9430d6 Iustin Pop
        node_list: a list with the names of all nodes
1369 1f9430d6 Iustin Pop
        rlist: a map with node names as keys and OS objects as values
1370 1f9430d6 Iustin Pop

1371 1f9430d6 Iustin Pop
      Returns:
1372 1f9430d6 Iustin Pop
        map: a map with osnames as keys and as value another map, with
1373 1f9430d6 Iustin Pop
             nodes as
1374 1f9430d6 Iustin Pop
             keys and list of OS objects as values
1375 1f9430d6 Iustin Pop
             e.g. {"debian-etch": {"node1": [<object>,...],
1376 1f9430d6 Iustin Pop
                                   "node2": [<object>,]}
1377 1f9430d6 Iustin Pop
                  }
1378 1f9430d6 Iustin Pop

1379 1f9430d6 Iustin Pop
    """
1380 1f9430d6 Iustin Pop
    all_os = {}
1381 1f9430d6 Iustin Pop
    for node_name, nr in rlist.iteritems():
1382 1f9430d6 Iustin Pop
      if not nr:
1383 1f9430d6 Iustin Pop
        continue
1384 b4de68a9 Iustin Pop
      for os_obj in nr:
1385 b4de68a9 Iustin Pop
        if os_obj.name not in all_os:
1386 1f9430d6 Iustin Pop
          # build a list of nodes for this os containing empty lists
1387 1f9430d6 Iustin Pop
          # for each node in node_list
1388 b4de68a9 Iustin Pop
          all_os[os_obj.name] = {}
1389 1f9430d6 Iustin Pop
          for nname in node_list:
1390 b4de68a9 Iustin Pop
            all_os[os_obj.name][nname] = []
1391 b4de68a9 Iustin Pop
        all_os[os_obj.name][node_name].append(os_obj)
1392 1f9430d6 Iustin Pop
    return all_os
1393 a8083063 Iustin Pop
1394 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1395 a8083063 Iustin Pop
    """Compute the list of OSes.
1396 a8083063 Iustin Pop

1397 a8083063 Iustin Pop
    """
1398 a8083063 Iustin Pop
    node_list = self.cfg.GetNodeList()
1399 a8083063 Iustin Pop
    node_data = rpc.call_os_diagnose(node_list)
1400 a8083063 Iustin Pop
    if node_data == False:
1401 3ecf6786 Iustin Pop
      raise errors.OpExecError("Can't gather the list of OSes")
1402 1f9430d6 Iustin Pop
    pol = self._DiagnoseByOS(node_list, node_data)
1403 1f9430d6 Iustin Pop
    output = []
1404 1f9430d6 Iustin Pop
    for os_name, os_data in pol.iteritems():
1405 1f9430d6 Iustin Pop
      row = []
1406 1f9430d6 Iustin Pop
      for field in self.op.output_fields:
1407 1f9430d6 Iustin Pop
        if field == "name":
1408 1f9430d6 Iustin Pop
          val = os_name
1409 1f9430d6 Iustin Pop
        elif field == "valid":
1410 1f9430d6 Iustin Pop
          val = utils.all([osl and osl[0] for osl in os_data.values()])
1411 1f9430d6 Iustin Pop
        elif field == "node_status":
1412 1f9430d6 Iustin Pop
          val = {}
1413 1f9430d6 Iustin Pop
          for node_name, nos_list in os_data.iteritems():
1414 1f9430d6 Iustin Pop
            val[node_name] = [(v.status, v.path) for v in nos_list]
1415 1f9430d6 Iustin Pop
        else:
1416 1f9430d6 Iustin Pop
          raise errors.ParameterError(field)
1417 1f9430d6 Iustin Pop
        row.append(val)
1418 1f9430d6 Iustin Pop
      output.append(row)
1419 1f9430d6 Iustin Pop
1420 1f9430d6 Iustin Pop
    return output
1421 a8083063 Iustin Pop
1422 a8083063 Iustin Pop
1423 a8083063 Iustin Pop
class LURemoveNode(LogicalUnit):
1424 a8083063 Iustin Pop
  """Logical unit for removing a node.
1425 a8083063 Iustin Pop

1426 a8083063 Iustin Pop
  """
1427 a8083063 Iustin Pop
  HPATH = "node-remove"
1428 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_NODE
1429 a8083063 Iustin Pop
  _OP_REQP = ["node_name"]
1430 a8083063 Iustin Pop
1431 a8083063 Iustin Pop
  def BuildHooksEnv(self):
1432 a8083063 Iustin Pop
    """Build hooks env.
1433 a8083063 Iustin Pop

1434 a8083063 Iustin Pop
    This doesn't run on the target node in the pre phase as a failed
1435 a8083063 Iustin Pop
    node would not allows itself to run.
1436 a8083063 Iustin Pop

1437 a8083063 Iustin Pop
    """
1438 396e1b78 Michael Hanselmann
    env = {
1439 0e137c28 Iustin Pop
      "OP_TARGET": self.op.node_name,
1440 396e1b78 Michael Hanselmann
      "NODE_NAME": self.op.node_name,
1441 396e1b78 Michael Hanselmann
      }
1442 a8083063 Iustin Pop
    all_nodes = self.cfg.GetNodeList()
1443 a8083063 Iustin Pop
    all_nodes.remove(self.op.node_name)
1444 396e1b78 Michael Hanselmann
    return env, all_nodes, all_nodes
1445 a8083063 Iustin Pop
1446 a8083063 Iustin Pop
  def CheckPrereq(self):
1447 a8083063 Iustin Pop
    """Check prerequisites.
1448 a8083063 Iustin Pop

1449 a8083063 Iustin Pop
    This checks:
1450 a8083063 Iustin Pop
     - the node exists in the configuration
1451 a8083063 Iustin Pop
     - it does not have primary or secondary instances
1452 a8083063 Iustin Pop
     - it's not the master
1453 a8083063 Iustin Pop

1454 a8083063 Iustin Pop
    Any errors are signalled by raising errors.OpPrereqError.
1455 a8083063 Iustin Pop

1456 a8083063 Iustin Pop
    """
1457 a8083063 Iustin Pop
    node = self.cfg.GetNodeInfo(self.cfg.ExpandNodeName(self.op.node_name))
1458 a8083063 Iustin Pop
    if node is None:
1459 a02bc76e Iustin Pop
      raise errors.OpPrereqError, ("Node '%s' is unknown." % self.op.node_name)
1460 a8083063 Iustin Pop
1461 a8083063 Iustin Pop
    instance_list = self.cfg.GetInstanceList()
1462 a8083063 Iustin Pop
1463 880478f8 Iustin Pop
    masternode = self.sstore.GetMasterNode()
1464 a8083063 Iustin Pop
    if node.name == masternode:
1465 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Node is the master node,"
1466 3ecf6786 Iustin Pop
                                 " you need to failover first.")
1467 a8083063 Iustin Pop
1468 a8083063 Iustin Pop
    for instance_name in instance_list:
1469 a8083063 Iustin Pop
      instance = self.cfg.GetInstanceInfo(instance_name)
1470 a8083063 Iustin Pop
      if node.name == instance.primary_node:
1471 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Instance %s still running on the node,"
1472 3ecf6786 Iustin Pop
                                   " please remove first." % instance_name)
1473 a8083063 Iustin Pop
      if node.name in instance.secondary_nodes:
1474 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Instance %s has node as a secondary,"
1475 3ecf6786 Iustin Pop
                                   " please remove first." % instance_name)
1476 a8083063 Iustin Pop
    self.op.node_name = node.name
1477 a8083063 Iustin Pop
    self.node = node
1478 a8083063 Iustin Pop
1479 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1480 a8083063 Iustin Pop
    """Removes the node from the cluster.
1481 a8083063 Iustin Pop

1482 a8083063 Iustin Pop
    """
1483 a8083063 Iustin Pop
    node = self.node
1484 a8083063 Iustin Pop
    logger.Info("stopping the node daemon and removing configs from node %s" %
1485 a8083063 Iustin Pop
                node.name)
1486 a8083063 Iustin Pop
1487 a8083063 Iustin Pop
    rpc.call_node_leave_cluster(node.name)
1488 a8083063 Iustin Pop
1489 c92b310a Michael Hanselmann
    self.ssh.Run(node.name, 'root', "%s stop" % constants.NODE_INITD_SCRIPT)
1490 a8083063 Iustin Pop
1491 a8083063 Iustin Pop
    logger.Info("Removing node %s from config" % node.name)
1492 a8083063 Iustin Pop
1493 a8083063 Iustin Pop
    self.cfg.RemoveNode(node.name)
1494 a8083063 Iustin Pop
1495 c8a0948f Michael Hanselmann
    _RemoveHostFromEtcHosts(node.name)
1496 c8a0948f Michael Hanselmann
1497 a8083063 Iustin Pop
1498 a8083063 Iustin Pop
class LUQueryNodes(NoHooksLU):
1499 a8083063 Iustin Pop
  """Logical unit for querying nodes.
1500 a8083063 Iustin Pop

1501 a8083063 Iustin Pop
  """
1502 246e180a Iustin Pop
  _OP_REQP = ["output_fields", "names"]
1503 a8083063 Iustin Pop
1504 a8083063 Iustin Pop
  def CheckPrereq(self):
1505 a8083063 Iustin Pop
    """Check prerequisites.
1506 a8083063 Iustin Pop

1507 a8083063 Iustin Pop
    This checks that the fields required are valid output fields.
1508 a8083063 Iustin Pop

1509 a8083063 Iustin Pop
    """
1510 e8a4c138 Iustin Pop
    self.dynamic_fields = frozenset([
1511 e8a4c138 Iustin Pop
      "dtotal", "dfree",
1512 e8a4c138 Iustin Pop
      "mtotal", "mnode", "mfree",
1513 e8a4c138 Iustin Pop
      "bootid",
1514 e8a4c138 Iustin Pop
      "ctotal",
1515 e8a4c138 Iustin Pop
      ])
1516 a8083063 Iustin Pop
1517 ec223efb Iustin Pop
    _CheckOutputFields(static=["name", "pinst_cnt", "sinst_cnt",
1518 ec223efb Iustin Pop
                               "pinst_list", "sinst_list",
1519 ec223efb Iustin Pop
                               "pip", "sip"],
1520 dcb93971 Michael Hanselmann
                       dynamic=self.dynamic_fields,
1521 dcb93971 Michael Hanselmann
                       selected=self.op.output_fields)
1522 a8083063 Iustin Pop
1523 246e180a Iustin Pop
    self.wanted = _GetWantedNodes(self, self.op.names)
1524 a8083063 Iustin Pop
1525 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1526 a8083063 Iustin Pop
    """Computes the list of nodes and their attributes.
1527 a8083063 Iustin Pop

1528 a8083063 Iustin Pop
    """
1529 246e180a Iustin Pop
    nodenames = self.wanted
1530 a8083063 Iustin Pop
    nodelist = [self.cfg.GetNodeInfo(name) for name in nodenames]
1531 a8083063 Iustin Pop
1532 a8083063 Iustin Pop
    # begin data gathering
1533 a8083063 Iustin Pop
1534 a8083063 Iustin Pop
    if self.dynamic_fields.intersection(self.op.output_fields):
1535 a8083063 Iustin Pop
      live_data = {}
1536 a8083063 Iustin Pop
      node_data = rpc.call_node_info(nodenames, self.cfg.GetVGName())
1537 a8083063 Iustin Pop
      for name in nodenames:
1538 a8083063 Iustin Pop
        nodeinfo = node_data.get(name, None)
1539 a8083063 Iustin Pop
        if nodeinfo:
1540 a8083063 Iustin Pop
          live_data[name] = {
1541 a8083063 Iustin Pop
            "mtotal": utils.TryConvert(int, nodeinfo['memory_total']),
1542 a8083063 Iustin Pop
            "mnode": utils.TryConvert(int, nodeinfo['memory_dom0']),
1543 a8083063 Iustin Pop
            "mfree": utils.TryConvert(int, nodeinfo['memory_free']),
1544 a8083063 Iustin Pop
            "dtotal": utils.TryConvert(int, nodeinfo['vg_size']),
1545 a8083063 Iustin Pop
            "dfree": utils.TryConvert(int, nodeinfo['vg_free']),
1546 e8a4c138 Iustin Pop
            "ctotal": utils.TryConvert(int, nodeinfo['cpu_total']),
1547 3ef10550 Michael Hanselmann
            "bootid": nodeinfo['bootid'],
1548 a8083063 Iustin Pop
            }
1549 a8083063 Iustin Pop
        else:
1550 a8083063 Iustin Pop
          live_data[name] = {}
1551 a8083063 Iustin Pop
    else:
1552 a8083063 Iustin Pop
      live_data = dict.fromkeys(nodenames, {})
1553 a8083063 Iustin Pop
1554 ec223efb Iustin Pop
    node_to_primary = dict([(name, set()) for name in nodenames])
1555 ec223efb Iustin Pop
    node_to_secondary = dict([(name, set()) for name in nodenames])
1556 a8083063 Iustin Pop
1557 ec223efb Iustin Pop
    inst_fields = frozenset(("pinst_cnt", "pinst_list",
1558 ec223efb Iustin Pop
                             "sinst_cnt", "sinst_list"))
1559 ec223efb Iustin Pop
    if inst_fields & frozenset(self.op.output_fields):
1560 a8083063 Iustin Pop
      instancelist = self.cfg.GetInstanceList()
1561 a8083063 Iustin Pop
1562 ec223efb Iustin Pop
      for instance_name in instancelist:
1563 ec223efb Iustin Pop
        inst = self.cfg.GetInstanceInfo(instance_name)
1564 ec223efb Iustin Pop
        if inst.primary_node in node_to_primary:
1565 ec223efb Iustin Pop
          node_to_primary[inst.primary_node].add(inst.name)
1566 ec223efb Iustin Pop
        for secnode in inst.secondary_nodes:
1567 ec223efb Iustin Pop
          if secnode in node_to_secondary:
1568 ec223efb Iustin Pop
            node_to_secondary[secnode].add(inst.name)
1569 a8083063 Iustin Pop
1570 a8083063 Iustin Pop
    # end data gathering
1571 a8083063 Iustin Pop
1572 a8083063 Iustin Pop
    output = []
1573 a8083063 Iustin Pop
    for node in nodelist:
1574 a8083063 Iustin Pop
      node_output = []
1575 a8083063 Iustin Pop
      for field in self.op.output_fields:
1576 a8083063 Iustin Pop
        if field == "name":
1577 a8083063 Iustin Pop
          val = node.name
1578 ec223efb Iustin Pop
        elif field == "pinst_list":
1579 ec223efb Iustin Pop
          val = list(node_to_primary[node.name])
1580 ec223efb Iustin Pop
        elif field == "sinst_list":
1581 ec223efb Iustin Pop
          val = list(node_to_secondary[node.name])
1582 ec223efb Iustin Pop
        elif field == "pinst_cnt":
1583 ec223efb Iustin Pop
          val = len(node_to_primary[node.name])
1584 ec223efb Iustin Pop
        elif field == "sinst_cnt":
1585 ec223efb Iustin Pop
          val = len(node_to_secondary[node.name])
1586 a8083063 Iustin Pop
        elif field == "pip":
1587 a8083063 Iustin Pop
          val = node.primary_ip
1588 a8083063 Iustin Pop
        elif field == "sip":
1589 a8083063 Iustin Pop
          val = node.secondary_ip
1590 a8083063 Iustin Pop
        elif field in self.dynamic_fields:
1591 ec223efb Iustin Pop
          val = live_data[node.name].get(field, None)
1592 a8083063 Iustin Pop
        else:
1593 3ecf6786 Iustin Pop
          raise errors.ParameterError(field)
1594 a8083063 Iustin Pop
        node_output.append(val)
1595 a8083063 Iustin Pop
      output.append(node_output)
1596 a8083063 Iustin Pop
1597 a8083063 Iustin Pop
    return output
1598 a8083063 Iustin Pop
1599 a8083063 Iustin Pop
1600 dcb93971 Michael Hanselmann
class LUQueryNodeVolumes(NoHooksLU):
1601 dcb93971 Michael Hanselmann
  """Logical unit for getting volumes on node(s).
1602 dcb93971 Michael Hanselmann

1603 dcb93971 Michael Hanselmann
  """
1604 dcb93971 Michael Hanselmann
  _OP_REQP = ["nodes", "output_fields"]
1605 dcb93971 Michael Hanselmann
1606 dcb93971 Michael Hanselmann
  def CheckPrereq(self):
1607 dcb93971 Michael Hanselmann
    """Check prerequisites.
1608 dcb93971 Michael Hanselmann

1609 dcb93971 Michael Hanselmann
    This checks that the fields required are valid output fields.
1610 dcb93971 Michael Hanselmann

1611 dcb93971 Michael Hanselmann
    """
1612 dcb93971 Michael Hanselmann
    self.nodes = _GetWantedNodes(self, self.op.nodes)
1613 dcb93971 Michael Hanselmann
1614 dcb93971 Michael Hanselmann
    _CheckOutputFields(static=["node"],
1615 dcb93971 Michael Hanselmann
                       dynamic=["phys", "vg", "name", "size", "instance"],
1616 dcb93971 Michael Hanselmann
                       selected=self.op.output_fields)
1617 dcb93971 Michael Hanselmann
1618 dcb93971 Michael Hanselmann
1619 dcb93971 Michael Hanselmann
  def Exec(self, feedback_fn):
1620 dcb93971 Michael Hanselmann
    """Computes the list of nodes and their attributes.
1621 dcb93971 Michael Hanselmann

1622 dcb93971 Michael Hanselmann
    """
1623 a7ba5e53 Iustin Pop
    nodenames = self.nodes
1624 dcb93971 Michael Hanselmann
    volumes = rpc.call_node_volumes(nodenames)
1625 dcb93971 Michael Hanselmann
1626 dcb93971 Michael Hanselmann
    ilist = [self.cfg.GetInstanceInfo(iname) for iname
1627 dcb93971 Michael Hanselmann
             in self.cfg.GetInstanceList()]
1628 dcb93971 Michael Hanselmann
1629 dcb93971 Michael Hanselmann
    lv_by_node = dict([(inst, inst.MapLVsByNode()) for inst in ilist])
1630 dcb93971 Michael Hanselmann
1631 dcb93971 Michael Hanselmann
    output = []
1632 dcb93971 Michael Hanselmann
    for node in nodenames:
1633 37d19eb2 Michael Hanselmann
      if node not in volumes or not volumes[node]:
1634 37d19eb2 Michael Hanselmann
        continue
1635 37d19eb2 Michael Hanselmann
1636 dcb93971 Michael Hanselmann
      node_vols = volumes[node][:]
1637 dcb93971 Michael Hanselmann
      node_vols.sort(key=lambda vol: vol['dev'])
1638 dcb93971 Michael Hanselmann
1639 dcb93971 Michael Hanselmann
      for vol in node_vols:
1640 dcb93971 Michael Hanselmann
        node_output = []
1641 dcb93971 Michael Hanselmann
        for field in self.op.output_fields:
1642 dcb93971 Michael Hanselmann
          if field == "node":
1643 dcb93971 Michael Hanselmann
            val = node
1644 dcb93971 Michael Hanselmann
          elif field == "phys":
1645 dcb93971 Michael Hanselmann
            val = vol['dev']
1646 dcb93971 Michael Hanselmann
          elif field == "vg":
1647 dcb93971 Michael Hanselmann
            val = vol['vg']
1648 dcb93971 Michael Hanselmann
          elif field == "name":
1649 dcb93971 Michael Hanselmann
            val = vol['name']
1650 dcb93971 Michael Hanselmann
          elif field == "size":
1651 dcb93971 Michael Hanselmann
            val = int(float(vol['size']))
1652 dcb93971 Michael Hanselmann
          elif field == "instance":
1653 dcb93971 Michael Hanselmann
            for inst in ilist:
1654 dcb93971 Michael Hanselmann
              if node not in lv_by_node[inst]:
1655 dcb93971 Michael Hanselmann
                continue
1656 dcb93971 Michael Hanselmann
              if vol['name'] in lv_by_node[inst][node]:
1657 dcb93971 Michael Hanselmann
                val = inst.name
1658 dcb93971 Michael Hanselmann
                break
1659 dcb93971 Michael Hanselmann
            else:
1660 dcb93971 Michael Hanselmann
              val = '-'
1661 dcb93971 Michael Hanselmann
          else:
1662 3ecf6786 Iustin Pop
            raise errors.ParameterError(field)
1663 dcb93971 Michael Hanselmann
          node_output.append(str(val))
1664 dcb93971 Michael Hanselmann
1665 dcb93971 Michael Hanselmann
        output.append(node_output)
1666 dcb93971 Michael Hanselmann
1667 dcb93971 Michael Hanselmann
    return output
1668 dcb93971 Michael Hanselmann
1669 dcb93971 Michael Hanselmann
1670 a8083063 Iustin Pop
class LUAddNode(LogicalUnit):
1671 a8083063 Iustin Pop
  """Logical unit for adding node to the cluster.
1672 a8083063 Iustin Pop

1673 a8083063 Iustin Pop
  """
1674 a8083063 Iustin Pop
  HPATH = "node-add"
1675 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_NODE
1676 a8083063 Iustin Pop
  _OP_REQP = ["node_name"]
1677 a8083063 Iustin Pop
1678 a8083063 Iustin Pop
  def BuildHooksEnv(self):
1679 a8083063 Iustin Pop
    """Build hooks env.
1680 a8083063 Iustin Pop

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

1683 a8083063 Iustin Pop
    """
1684 a8083063 Iustin Pop
    env = {
1685 0e137c28 Iustin Pop
      "OP_TARGET": self.op.node_name,
1686 a8083063 Iustin Pop
      "NODE_NAME": self.op.node_name,
1687 a8083063 Iustin Pop
      "NODE_PIP": self.op.primary_ip,
1688 a8083063 Iustin Pop
      "NODE_SIP": self.op.secondary_ip,
1689 a8083063 Iustin Pop
      }
1690 a8083063 Iustin Pop
    nodes_0 = self.cfg.GetNodeList()
1691 a8083063 Iustin Pop
    nodes_1 = nodes_0 + [self.op.node_name, ]
1692 a8083063 Iustin Pop
    return env, nodes_0, nodes_1
1693 a8083063 Iustin Pop
1694 a8083063 Iustin Pop
  def CheckPrereq(self):
1695 a8083063 Iustin Pop
    """Check prerequisites.
1696 a8083063 Iustin Pop

1697 a8083063 Iustin Pop
    This checks:
1698 a8083063 Iustin Pop
     - the new node is not already in the config
1699 a8083063 Iustin Pop
     - it is resolvable
1700 a8083063 Iustin Pop
     - its parameters (single/dual homed) matches the cluster
1701 a8083063 Iustin Pop

1702 a8083063 Iustin Pop
    Any errors are signalled by raising errors.OpPrereqError.
1703 a8083063 Iustin Pop

1704 a8083063 Iustin Pop
    """
1705 a8083063 Iustin Pop
    node_name = self.op.node_name
1706 a8083063 Iustin Pop
    cfg = self.cfg
1707 a8083063 Iustin Pop
1708 89e1fc26 Iustin Pop
    dns_data = utils.HostInfo(node_name)
1709 a8083063 Iustin Pop
1710 bcf043c9 Iustin Pop
    node = dns_data.name
1711 bcf043c9 Iustin Pop
    primary_ip = self.op.primary_ip = dns_data.ip
1712 a8083063 Iustin Pop
    secondary_ip = getattr(self.op, "secondary_ip", None)
1713 a8083063 Iustin Pop
    if secondary_ip is None:
1714 a8083063 Iustin Pop
      secondary_ip = primary_ip
1715 a8083063 Iustin Pop
    if not utils.IsValidIP(secondary_ip):
1716 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Invalid secondary IP given")
1717 a8083063 Iustin Pop
    self.op.secondary_ip = secondary_ip
1718 e7c6e02b Michael Hanselmann
1719 a8083063 Iustin Pop
    node_list = cfg.GetNodeList()
1720 e7c6e02b Michael Hanselmann
    if not self.op.readd and node in node_list:
1721 e7c6e02b Michael Hanselmann
      raise errors.OpPrereqError("Node %s is already in the configuration" %
1722 e7c6e02b Michael Hanselmann
                                 node)
1723 e7c6e02b Michael Hanselmann
    elif self.op.readd and node not in node_list:
1724 e7c6e02b Michael Hanselmann
      raise errors.OpPrereqError("Node %s is not in the configuration" % node)
1725 a8083063 Iustin Pop
1726 a8083063 Iustin Pop
    for existing_node_name in node_list:
1727 a8083063 Iustin Pop
      existing_node = cfg.GetNodeInfo(existing_node_name)
1728 e7c6e02b Michael Hanselmann
1729 e7c6e02b Michael Hanselmann
      if self.op.readd and node == existing_node_name:
1730 e7c6e02b Michael Hanselmann
        if (existing_node.primary_ip != primary_ip or
1731 e7c6e02b Michael Hanselmann
            existing_node.secondary_ip != secondary_ip):
1732 e7c6e02b Michael Hanselmann
          raise errors.OpPrereqError("Readded node doesn't have the same IP"
1733 e7c6e02b Michael Hanselmann
                                     " address configuration as before")
1734 e7c6e02b Michael Hanselmann
        continue
1735 e7c6e02b Michael Hanselmann
1736 a8083063 Iustin Pop
      if (existing_node.primary_ip == primary_ip or
1737 a8083063 Iustin Pop
          existing_node.secondary_ip == primary_ip or
1738 a8083063 Iustin Pop
          existing_node.primary_ip == secondary_ip or
1739 a8083063 Iustin Pop
          existing_node.secondary_ip == secondary_ip):
1740 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("New node ip address(es) conflict with"
1741 3ecf6786 Iustin Pop
                                   " existing node %s" % existing_node.name)
1742 a8083063 Iustin Pop
1743 a8083063 Iustin Pop
    # check that the type of the node (single versus dual homed) is the
1744 a8083063 Iustin Pop
    # same as for the master
1745 880478f8 Iustin Pop
    myself = cfg.GetNodeInfo(self.sstore.GetMasterNode())
1746 a8083063 Iustin Pop
    master_singlehomed = myself.secondary_ip == myself.primary_ip
1747 a8083063 Iustin Pop
    newbie_singlehomed = secondary_ip == primary_ip
1748 a8083063 Iustin Pop
    if master_singlehomed != newbie_singlehomed:
1749 a8083063 Iustin Pop
      if master_singlehomed:
1750 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("The master has no private ip but the"
1751 3ecf6786 Iustin Pop
                                   " new node has one")
1752 a8083063 Iustin Pop
      else:
1753 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("The master has a private ip but the"
1754 3ecf6786 Iustin Pop
                                   " new node doesn't have one")
1755 a8083063 Iustin Pop
1756 a8083063 Iustin Pop
    # checks reachablity
1757 b15d625f Iustin Pop
    if not utils.TcpPing(primary_ip, constants.DEFAULT_NODED_PORT):
1758 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Node not reachable by ping")
1759 a8083063 Iustin Pop
1760 a8083063 Iustin Pop
    if not newbie_singlehomed:
1761 a8083063 Iustin Pop
      # check reachability from my secondary ip to newbie's secondary ip
1762 b15d625f Iustin Pop
      if not utils.TcpPing(secondary_ip, constants.DEFAULT_NODED_PORT,
1763 b15d625f Iustin Pop
                           source=myself.secondary_ip):
1764 f4bc1f2c Michael Hanselmann
        raise errors.OpPrereqError("Node secondary ip not reachable by TCP"
1765 f4bc1f2c Michael Hanselmann
                                   " based ping to noded port")
1766 a8083063 Iustin Pop
1767 a8083063 Iustin Pop
    self.new_node = objects.Node(name=node,
1768 a8083063 Iustin Pop
                                 primary_ip=primary_ip,
1769 a8083063 Iustin Pop
                                 secondary_ip=secondary_ip)
1770 a8083063 Iustin Pop
1771 2a6469d5 Alexander Schreiber
    if self.sstore.GetHypervisorType() == constants.HT_XEN_HVM31:
1772 2a6469d5 Alexander Schreiber
      if not os.path.exists(constants.VNC_PASSWORD_FILE):
1773 2a6469d5 Alexander Schreiber
        raise errors.OpPrereqError("Cluster VNC password file %s missing" %
1774 2a6469d5 Alexander Schreiber
                                   constants.VNC_PASSWORD_FILE)
1775 2a6469d5 Alexander Schreiber
1776 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1777 a8083063 Iustin Pop
    """Adds the new node to the cluster.
1778 a8083063 Iustin Pop

1779 a8083063 Iustin Pop
    """
1780 a8083063 Iustin Pop
    new_node = self.new_node
1781 a8083063 Iustin Pop
    node = new_node.name
1782 a8083063 Iustin Pop
1783 a8083063 Iustin Pop
    # set up inter-node password and certificate and restarts the node daemon
1784 a8083063 Iustin Pop
    gntpass = self.sstore.GetNodeDaemonPassword()
1785 a8083063 Iustin Pop
    if not re.match('^[a-zA-Z0-9.]{1,64}$', gntpass):
1786 3ecf6786 Iustin Pop
      raise errors.OpExecError("ganeti password corruption detected")
1787 a8083063 Iustin Pop
    f = open(constants.SSL_CERT_FILE)
1788 a8083063 Iustin Pop
    try:
1789 a8083063 Iustin Pop
      gntpem = f.read(8192)
1790 a8083063 Iustin Pop
    finally:
1791 a8083063 Iustin Pop
      f.close()
1792 a8083063 Iustin Pop
    # in the base64 pem encoding, neither '!' nor '.' are valid chars,
1793 a8083063 Iustin Pop
    # so we use this to detect an invalid certificate; as long as the
1794 a8083063 Iustin Pop
    # cert doesn't contain this, the here-document will be correctly
1795 a8083063 Iustin Pop
    # parsed by the shell sequence below
1796 a8083063 Iustin Pop
    if re.search('^!EOF\.', gntpem, re.MULTILINE):
1797 3ecf6786 Iustin Pop
      raise errors.OpExecError("invalid PEM encoding in the SSL certificate")
1798 a8083063 Iustin Pop
    if not gntpem.endswith("\n"):
1799 3ecf6786 Iustin Pop
      raise errors.OpExecError("PEM must end with newline")
1800 a8083063 Iustin Pop
    logger.Info("copy cluster pass to %s and starting the node daemon" % node)
1801 a8083063 Iustin Pop
1802 a8083063 Iustin Pop
    # and then connect with ssh to set password and start ganeti-noded
1803 a8083063 Iustin Pop
    # note that all the below variables are sanitized at this point,
1804 a8083063 Iustin Pop
    # either by being constants or by the checks above
1805 a8083063 Iustin Pop
    ss = self.sstore
1806 a8083063 Iustin Pop
    mycommand = ("umask 077 && "
1807 a8083063 Iustin Pop
                 "echo '%s' > '%s' && "
1808 a8083063 Iustin Pop
                 "cat > '%s' << '!EOF.' && \n"
1809 a8083063 Iustin Pop
                 "%s!EOF.\n%s restart" %
1810 a8083063 Iustin Pop
                 (gntpass, ss.KeyToFilename(ss.SS_NODED_PASS),
1811 a8083063 Iustin Pop
                  constants.SSL_CERT_FILE, gntpem,
1812 a8083063 Iustin Pop
                  constants.NODE_INITD_SCRIPT))
1813 a8083063 Iustin Pop
1814 c92b310a Michael Hanselmann
    result = self.ssh.Run(node, 'root', mycommand, batch=False, ask_key=True)
1815 a8083063 Iustin Pop
    if result.failed:
1816 3ecf6786 Iustin Pop
      raise errors.OpExecError("Remote command on node %s, error: %s,"
1817 3ecf6786 Iustin Pop
                               " output: %s" %
1818 3ecf6786 Iustin Pop
                               (node, result.fail_reason, result.output))
1819 a8083063 Iustin Pop
1820 a8083063 Iustin Pop
    # check connectivity
1821 a8083063 Iustin Pop
    time.sleep(4)
1822 a8083063 Iustin Pop
1823 a8083063 Iustin Pop
    result = rpc.call_version([node])[node]
1824 a8083063 Iustin Pop
    if result:
1825 a8083063 Iustin Pop
      if constants.PROTOCOL_VERSION == result:
1826 a8083063 Iustin Pop
        logger.Info("communication to node %s fine, sw version %s match" %
1827 a8083063 Iustin Pop
                    (node, result))
1828 a8083063 Iustin Pop
      else:
1829 3ecf6786 Iustin Pop
        raise errors.OpExecError("Version mismatch master version %s,"
1830 3ecf6786 Iustin Pop
                                 " node version %s" %
1831 3ecf6786 Iustin Pop
                                 (constants.PROTOCOL_VERSION, result))
1832 a8083063 Iustin Pop
    else:
1833 3ecf6786 Iustin Pop
      raise errors.OpExecError("Cannot get version from the new node")
1834 a8083063 Iustin Pop
1835 a8083063 Iustin Pop
    # setup ssh on node
1836 a8083063 Iustin Pop
    logger.Info("copy ssh key to node %s" % node)
1837 70d9e3d8 Iustin Pop
    priv_key, pub_key, _ = ssh.GetUserFiles(constants.GANETI_RUNAS)
1838 a8083063 Iustin Pop
    keyarray = []
1839 70d9e3d8 Iustin Pop
    keyfiles = [constants.SSH_HOST_DSA_PRIV, constants.SSH_HOST_DSA_PUB,
1840 70d9e3d8 Iustin Pop
                constants.SSH_HOST_RSA_PRIV, constants.SSH_HOST_RSA_PUB,
1841 70d9e3d8 Iustin Pop
                priv_key, pub_key]
1842 a8083063 Iustin Pop
1843 a8083063 Iustin Pop
    for i in keyfiles:
1844 a8083063 Iustin Pop
      f = open(i, 'r')
1845 a8083063 Iustin Pop
      try:
1846 a8083063 Iustin Pop
        keyarray.append(f.read())
1847 a8083063 Iustin Pop
      finally:
1848 a8083063 Iustin Pop
        f.close()
1849 a8083063 Iustin Pop
1850 a8083063 Iustin Pop
    result = rpc.call_node_add(node, keyarray[0], keyarray[1], keyarray[2],
1851 a8083063 Iustin Pop
                               keyarray[3], keyarray[4], keyarray[5])
1852 a8083063 Iustin Pop
1853 a8083063 Iustin Pop
    if not result:
1854 3ecf6786 Iustin Pop
      raise errors.OpExecError("Cannot transfer ssh keys to the new node")
1855 a8083063 Iustin Pop
1856 a8083063 Iustin Pop
    # Add node to our /etc/hosts, and add key to known_hosts
1857 9440aeab Michael Hanselmann
    _AddHostToEtcHosts(new_node.name)
1858 c8a0948f Michael Hanselmann
1859 a8083063 Iustin Pop
    if new_node.secondary_ip != new_node.primary_ip:
1860 16abfbc2 Alexander Schreiber
      if not rpc.call_node_tcp_ping(new_node.name,
1861 16abfbc2 Alexander Schreiber
                                    constants.LOCALHOST_IP_ADDRESS,
1862 16abfbc2 Alexander Schreiber
                                    new_node.secondary_ip,
1863 16abfbc2 Alexander Schreiber
                                    constants.DEFAULT_NODED_PORT,
1864 16abfbc2 Alexander Schreiber
                                    10, False):
1865 f4bc1f2c Michael Hanselmann
        raise errors.OpExecError("Node claims it doesn't have the secondary ip"
1866 f4bc1f2c Michael Hanselmann
                                 " you gave (%s). Please fix and re-run this"
1867 f4bc1f2c Michael Hanselmann
                                 " command." % new_node.secondary_ip)
1868 a8083063 Iustin Pop
1869 c92b310a Michael Hanselmann
    success, msg = self.ssh.VerifyNodeHostname(node)
1870 ff98055b Iustin Pop
    if not success:
1871 ff98055b Iustin Pop
      raise errors.OpExecError("Node '%s' claims it has a different hostname"
1872 f4bc1f2c Michael Hanselmann
                               " than the one the resolver gives: %s."
1873 f4bc1f2c Michael Hanselmann
                               " Please fix and re-run this command." %
1874 ff98055b Iustin Pop
                               (node, msg))
1875 ff98055b Iustin Pop
1876 a8083063 Iustin Pop
    # Distribute updated /etc/hosts and known_hosts to all nodes,
1877 a8083063 Iustin Pop
    # including the node just added
1878 880478f8 Iustin Pop
    myself = self.cfg.GetNodeInfo(self.sstore.GetMasterNode())
1879 102b115b Michael Hanselmann
    dist_nodes = self.cfg.GetNodeList()
1880 102b115b Michael Hanselmann
    if not self.op.readd:
1881 102b115b Michael Hanselmann
      dist_nodes.append(node)
1882 a8083063 Iustin Pop
    if myself.name in dist_nodes:
1883 a8083063 Iustin Pop
      dist_nodes.remove(myself.name)
1884 a8083063 Iustin Pop
1885 a8083063 Iustin Pop
    logger.Debug("Copying hosts and known_hosts to all nodes")
1886 107711b0 Michael Hanselmann
    for fname in (constants.ETC_HOSTS, constants.SSH_KNOWN_HOSTS_FILE):
1887 a8083063 Iustin Pop
      result = rpc.call_upload_file(dist_nodes, fname)
1888 a8083063 Iustin Pop
      for to_node in dist_nodes:
1889 a8083063 Iustin Pop
        if not result[to_node]:
1890 a8083063 Iustin Pop
          logger.Error("copy of file %s to node %s failed" %
1891 a8083063 Iustin Pop
                       (fname, to_node))
1892 a8083063 Iustin Pop
1893 cb91d46e Iustin Pop
    to_copy = ss.GetFileList()
1894 2a6469d5 Alexander Schreiber
    if self.sstore.GetHypervisorType() == constants.HT_XEN_HVM31:
1895 2a6469d5 Alexander Schreiber
      to_copy.append(constants.VNC_PASSWORD_FILE)
1896 a8083063 Iustin Pop
    for fname in to_copy:
1897 c92b310a Michael Hanselmann
      if not self.ssh.CopyFileToNode(node, fname):
1898 a8083063 Iustin Pop
        logger.Error("could not copy file %s to node %s" % (fname, node))
1899 a8083063 Iustin Pop
1900 e7c6e02b Michael Hanselmann
    if not self.op.readd:
1901 e7c6e02b Michael Hanselmann
      logger.Info("adding node %s to cluster.conf" % node)
1902 e7c6e02b Michael Hanselmann
      self.cfg.AddNode(new_node)
1903 a8083063 Iustin Pop
1904 a8083063 Iustin Pop
1905 a8083063 Iustin Pop
class LUMasterFailover(LogicalUnit):
1906 a8083063 Iustin Pop
  """Failover the master node to the current node.
1907 a8083063 Iustin Pop

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

1910 a8083063 Iustin Pop
  """
1911 a8083063 Iustin Pop
  HPATH = "master-failover"
1912 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_CLUSTER
1913 a8083063 Iustin Pop
  REQ_MASTER = False
1914 a8083063 Iustin Pop
  _OP_REQP = []
1915 a8083063 Iustin Pop
1916 a8083063 Iustin Pop
  def BuildHooksEnv(self):
1917 a8083063 Iustin Pop
    """Build hooks env.
1918 a8083063 Iustin Pop

1919 a8083063 Iustin Pop
    This will run on the new master only in the pre phase, and on all
1920 a8083063 Iustin Pop
    the nodes in the post phase.
1921 a8083063 Iustin Pop

1922 a8083063 Iustin Pop
    """
1923 a8083063 Iustin Pop
    env = {
1924 0e137c28 Iustin Pop
      "OP_TARGET": self.new_master,
1925 a8083063 Iustin Pop
      "NEW_MASTER": self.new_master,
1926 a8083063 Iustin Pop
      "OLD_MASTER": self.old_master,
1927 a8083063 Iustin Pop
      }
1928 a8083063 Iustin Pop
    return env, [self.new_master], self.cfg.GetNodeList()
1929 a8083063 Iustin Pop
1930 a8083063 Iustin Pop
  def CheckPrereq(self):
1931 a8083063 Iustin Pop
    """Check prerequisites.
1932 a8083063 Iustin Pop

1933 a8083063 Iustin Pop
    This checks that we are not already the master.
1934 a8083063 Iustin Pop

1935 a8083063 Iustin Pop
    """
1936 89e1fc26 Iustin Pop
    self.new_master = utils.HostInfo().name
1937 880478f8 Iustin Pop
    self.old_master = self.sstore.GetMasterNode()
1938 a8083063 Iustin Pop
1939 a8083063 Iustin Pop
    if self.old_master == self.new_master:
1940 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("This commands must be run on the node"
1941 f4bc1f2c Michael Hanselmann
                                 " where you want the new master to be."
1942 f4bc1f2c Michael Hanselmann
                                 " %s is already the master" %
1943 3ecf6786 Iustin Pop
                                 self.old_master)
1944 a8083063 Iustin Pop
1945 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1946 a8083063 Iustin Pop
    """Failover the master node.
1947 a8083063 Iustin Pop

1948 a8083063 Iustin Pop
    This command, when run on a non-master node, will cause the current
1949 a8083063 Iustin Pop
    master to cease being master, and the non-master to become new
1950 a8083063 Iustin Pop
    master.
1951 a8083063 Iustin Pop

1952 a8083063 Iustin Pop
    """
1953 a8083063 Iustin Pop
    #TODO: do not rely on gethostname returning the FQDN
1954 a8083063 Iustin Pop
    logger.Info("setting master to %s, old master: %s" %
1955 a8083063 Iustin Pop
                (self.new_master, self.old_master))
1956 a8083063 Iustin Pop
1957 a8083063 Iustin Pop
    if not rpc.call_node_stop_master(self.old_master):
1958 a8083063 Iustin Pop
      logger.Error("could disable the master role on the old master"
1959 a8083063 Iustin Pop
                   " %s, please disable manually" % self.old_master)
1960 a8083063 Iustin Pop
1961 880478f8 Iustin Pop
    ss = self.sstore
1962 880478f8 Iustin Pop
    ss.SetKey(ss.SS_MASTER_NODE, self.new_master)
1963 880478f8 Iustin Pop
    if not rpc.call_upload_file(self.cfg.GetNodeList(),
1964 880478f8 Iustin Pop
                                ss.KeyToFilename(ss.SS_MASTER_NODE)):
1965 880478f8 Iustin Pop
      logger.Error("could not distribute the new simple store master file"
1966 880478f8 Iustin Pop
                   " to the other nodes, please check.")
1967 880478f8 Iustin Pop
1968 a8083063 Iustin Pop
    if not rpc.call_node_start_master(self.new_master):
1969 a8083063 Iustin Pop
      logger.Error("could not start the master role on the new master"
1970 a8083063 Iustin Pop
                   " %s, please check" % self.new_master)
1971 f4bc1f2c Michael Hanselmann
      feedback_fn("Error in activating the master IP on the new master,"
1972 f4bc1f2c Michael Hanselmann
                  " please fix manually.")
1973 a8083063 Iustin Pop
1974 a8083063 Iustin Pop
1975 a8083063 Iustin Pop
1976 a8083063 Iustin Pop
class LUQueryClusterInfo(NoHooksLU):
1977 a8083063 Iustin Pop
  """Query cluster configuration.
1978 a8083063 Iustin Pop

1979 a8083063 Iustin Pop
  """
1980 a8083063 Iustin Pop
  _OP_REQP = []
1981 59322403 Iustin Pop
  REQ_MASTER = False
1982 a8083063 Iustin Pop
1983 a8083063 Iustin Pop
  def CheckPrereq(self):
1984 a8083063 Iustin Pop
    """No prerequsites needed for this LU.
1985 a8083063 Iustin Pop

1986 a8083063 Iustin Pop
    """
1987 a8083063 Iustin Pop
    pass
1988 a8083063 Iustin Pop
1989 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1990 a8083063 Iustin Pop
    """Return cluster config.
1991 a8083063 Iustin Pop

1992 a8083063 Iustin Pop
    """
1993 a8083063 Iustin Pop
    result = {
1994 5fcdc80d Iustin Pop
      "name": self.sstore.GetClusterName(),
1995 a8083063 Iustin Pop
      "software_version": constants.RELEASE_VERSION,
1996 a8083063 Iustin Pop
      "protocol_version": constants.PROTOCOL_VERSION,
1997 a8083063 Iustin Pop
      "config_version": constants.CONFIG_VERSION,
1998 a8083063 Iustin Pop
      "os_api_version": constants.OS_API_VERSION,
1999 a8083063 Iustin Pop
      "export_version": constants.EXPORT_VERSION,
2000 880478f8 Iustin Pop
      "master": self.sstore.GetMasterNode(),
2001 a8083063 Iustin Pop
      "architecture": (platform.architecture()[0], platform.machine()),
2002 8a12ce45 Iustin Pop
      "hypervisor_type": self.sstore.GetHypervisorType(),
2003 a8083063 Iustin Pop
      }
2004 a8083063 Iustin Pop
2005 a8083063 Iustin Pop
    return result
2006 a8083063 Iustin Pop
2007 a8083063 Iustin Pop
2008 a8083063 Iustin Pop
class LUClusterCopyFile(NoHooksLU):
2009 a8083063 Iustin Pop
  """Copy file to cluster.
2010 a8083063 Iustin Pop

2011 a8083063 Iustin Pop
  """
2012 a8083063 Iustin Pop
  _OP_REQP = ["nodes", "filename"]
2013 a8083063 Iustin Pop
2014 a8083063 Iustin Pop
  def CheckPrereq(self):
2015 a8083063 Iustin Pop
    """Check prerequisites.
2016 a8083063 Iustin Pop

2017 a8083063 Iustin Pop
    It should check that the named file exists and that the given list
2018 a8083063 Iustin Pop
    of nodes is valid.
2019 a8083063 Iustin Pop

2020 a8083063 Iustin Pop
    """
2021 a8083063 Iustin Pop
    if not os.path.exists(self.op.filename):
2022 a8083063 Iustin Pop
      raise errors.OpPrereqError("No such filename '%s'" % self.op.filename)
2023 dcb93971 Michael Hanselmann
2024 dcb93971 Michael Hanselmann
    self.nodes = _GetWantedNodes(self, self.op.nodes)
2025 a8083063 Iustin Pop
2026 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
2027 a8083063 Iustin Pop
    """Copy a file from master to some nodes.
2028 a8083063 Iustin Pop

2029 a8083063 Iustin Pop
    Args:
2030 a8083063 Iustin Pop
      opts - class with options as members
2031 a8083063 Iustin Pop
      args - list containing a single element, the file name
2032 a8083063 Iustin Pop
    Opts used:
2033 a8083063 Iustin Pop
      nodes - list containing the name of target nodes; if empty, all nodes
2034 a8083063 Iustin Pop

2035 a8083063 Iustin Pop
    """
2036 a8083063 Iustin Pop
    filename = self.op.filename
2037 a8083063 Iustin Pop
2038 89e1fc26 Iustin Pop
    myname = utils.HostInfo().name
2039 a8083063 Iustin Pop
2040 a7ba5e53 Iustin Pop
    for node in self.nodes:
2041 a8083063 Iustin Pop
      if node == myname:
2042 a8083063 Iustin Pop
        continue
2043 c92b310a Michael Hanselmann
      if not self.ssh.CopyFileToNode(node, filename):
2044 a8083063 Iustin Pop
        logger.Error("Copy of file %s to node %s failed" % (filename, node))
2045 a8083063 Iustin Pop
2046 a8083063 Iustin Pop
2047 a8083063 Iustin Pop
class LUDumpClusterConfig(NoHooksLU):
2048 a8083063 Iustin Pop
  """Return a text-representation of the cluster-config.
2049 a8083063 Iustin Pop

2050 a8083063 Iustin Pop
  """
2051 a8083063 Iustin Pop
  _OP_REQP = []
2052 a8083063 Iustin Pop
2053 a8083063 Iustin Pop
  def CheckPrereq(self):
2054 a8083063 Iustin Pop
    """No prerequisites.
2055 a8083063 Iustin Pop

2056 a8083063 Iustin Pop
    """
2057 a8083063 Iustin Pop
    pass
2058 a8083063 Iustin Pop
2059 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
2060 a8083063 Iustin Pop
    """Dump a representation of the cluster config to the standard output.
2061 a8083063 Iustin Pop

2062 a8083063 Iustin Pop
    """
2063 a8083063 Iustin Pop
    return self.cfg.DumpConfig()
2064 a8083063 Iustin Pop
2065 a8083063 Iustin Pop
2066 a8083063 Iustin Pop
class LURunClusterCommand(NoHooksLU):
2067 a8083063 Iustin Pop
  """Run a command on some nodes.
2068 a8083063 Iustin Pop

2069 a8083063 Iustin Pop
  """
2070 a8083063 Iustin Pop
  _OP_REQP = ["command", "nodes"]
2071 a8083063 Iustin Pop
2072 a8083063 Iustin Pop
  def CheckPrereq(self):
2073 a8083063 Iustin Pop
    """Check prerequisites.
2074 a8083063 Iustin Pop

2075 a8083063 Iustin Pop
    It checks that the given list of nodes is valid.
2076 a8083063 Iustin Pop

2077 a8083063 Iustin Pop
    """
2078 dcb93971 Michael Hanselmann
    self.nodes = _GetWantedNodes(self, self.op.nodes)
2079 a8083063 Iustin Pop
2080 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
2081 a8083063 Iustin Pop
    """Run a command on some nodes.
2082 a8083063 Iustin Pop

2083 a8083063 Iustin Pop
    """
2084 5f83e263 Iustin Pop
    # put the master at the end of the nodes list
2085 5f83e263 Iustin Pop
    master_node = self.sstore.GetMasterNode()
2086 5f83e263 Iustin Pop
    if master_node in self.nodes:
2087 5f83e263 Iustin Pop
      self.nodes.remove(master_node)
2088 5f83e263 Iustin Pop
      self.nodes.append(master_node)
2089 5f83e263 Iustin Pop
2090 a8083063 Iustin Pop
    data = []
2091 a8083063 Iustin Pop
    for node in self.nodes:
2092 c92b310a Michael Hanselmann
      result = self.ssh.Run(node, "root", self.op.command)
2093 a7ba5e53 Iustin Pop
      data.append((node, result.output, result.exit_code))
2094 a8083063 Iustin Pop
2095 a8083063 Iustin Pop
    return data
2096 a8083063 Iustin Pop
2097 a8083063 Iustin Pop
2098 a8083063 Iustin Pop
class LUActivateInstanceDisks(NoHooksLU):
2099 a8083063 Iustin Pop
  """Bring up an instance's disks.
2100 a8083063 Iustin Pop

2101 a8083063 Iustin Pop
  """
2102 a8083063 Iustin Pop
  _OP_REQP = ["instance_name"]
2103 a8083063 Iustin Pop
2104 a8083063 Iustin Pop
  def CheckPrereq(self):
2105 a8083063 Iustin Pop
    """Check prerequisites.
2106 a8083063 Iustin Pop

2107 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
2108 a8083063 Iustin Pop

2109 a8083063 Iustin Pop
    """
2110 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
2111 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
2112 a8083063 Iustin Pop
    if instance is None:
2113 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
2114 3ecf6786 Iustin Pop
                                 self.op.instance_name)
2115 a8083063 Iustin Pop
    self.instance = instance
2116 a8083063 Iustin Pop
2117 a8083063 Iustin Pop
2118 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
2119 a8083063 Iustin Pop
    """Activate the disks.
2120 a8083063 Iustin Pop

2121 a8083063 Iustin Pop
    """
2122 a8083063 Iustin Pop
    disks_ok, disks_info = _AssembleInstanceDisks(self.instance, self.cfg)
2123 a8083063 Iustin Pop
    if not disks_ok:
2124 3ecf6786 Iustin Pop
      raise errors.OpExecError("Cannot activate block devices")
2125 a8083063 Iustin Pop
2126 a8083063 Iustin Pop
    return disks_info
2127 a8083063 Iustin Pop
2128 a8083063 Iustin Pop
2129 a8083063 Iustin Pop
def _AssembleInstanceDisks(instance, cfg, ignore_secondaries=False):
2130 a8083063 Iustin Pop
  """Prepare the block devices for an instance.
2131 a8083063 Iustin Pop

2132 a8083063 Iustin Pop
  This sets up the block devices on all nodes.
2133 a8083063 Iustin Pop

2134 a8083063 Iustin Pop
  Args:
2135 a8083063 Iustin Pop
    instance: a ganeti.objects.Instance object
2136 a8083063 Iustin Pop
    ignore_secondaries: if true, errors on secondary nodes won't result
2137 a8083063 Iustin Pop
                        in an error return from the function
2138 a8083063 Iustin Pop

2139 a8083063 Iustin Pop
  Returns:
2140 a8083063 Iustin Pop
    false if the operation failed
2141 a8083063 Iustin Pop
    list of (host, instance_visible_name, node_visible_name) if the operation
2142 a8083063 Iustin Pop
         suceeded with the mapping from node devices to instance devices
2143 a8083063 Iustin Pop
  """
2144 a8083063 Iustin Pop
  device_info = []
2145 a8083063 Iustin Pop
  disks_ok = True
2146 fdbd668d Iustin Pop
  iname = instance.name
2147 fdbd668d Iustin Pop
  # With the two passes mechanism we try to reduce the window of
2148 fdbd668d Iustin Pop
  # opportunity for the race condition of switching DRBD to primary
2149 fdbd668d Iustin Pop
  # before handshaking occured, but we do not eliminate it
2150 fdbd668d Iustin Pop
2151 fdbd668d Iustin Pop
  # The proper fix would be to wait (with some limits) until the
2152 fdbd668d Iustin Pop
  # connection has been made and drbd transitions from WFConnection
2153 fdbd668d Iustin Pop
  # into any other network-connected state (Connected, SyncTarget,
2154 fdbd668d Iustin Pop
  # SyncSource, etc.)
2155 fdbd668d Iustin Pop
2156 fdbd668d Iustin Pop
  # 1st pass, assemble on all nodes in secondary mode
2157 a8083063 Iustin Pop
  for inst_disk in instance.disks:
2158 a8083063 Iustin Pop
    for node, node_disk in inst_disk.ComputeNodeTree(instance.primary_node):
2159 a8083063 Iustin Pop
      cfg.SetDiskID(node_disk, node)
2160 fdbd668d Iustin Pop
      result = rpc.call_blockdev_assemble(node, node_disk, iname, False)
2161 a8083063 Iustin Pop
      if not result:
2162 f4bc1f2c Michael Hanselmann
        logger.Error("could not prepare block device %s on node %s"
2163 fdbd668d Iustin Pop
                     " (is_primary=False, pass=1)" % (inst_disk.iv_name, node))
2164 fdbd668d Iustin Pop
        if not ignore_secondaries:
2165 a8083063 Iustin Pop
          disks_ok = False
2166 fdbd668d Iustin Pop
2167 fdbd668d Iustin Pop
  # FIXME: race condition on drbd migration to primary
2168 fdbd668d Iustin Pop
2169 fdbd668d Iustin Pop
  # 2nd pass, do only the primary node
2170 fdbd668d Iustin Pop
  for inst_disk in instance.disks:
2171 fdbd668d Iustin Pop
    for node, node_disk in inst_disk.ComputeNodeTree(instance.primary_node):
2172 fdbd668d Iustin Pop
      if node != instance.primary_node:
2173 fdbd668d Iustin Pop
        continue
2174 fdbd668d Iustin Pop
      cfg.SetDiskID(node_disk, node)
2175 fdbd668d Iustin Pop
      result = rpc.call_blockdev_assemble(node, node_disk, iname, True)
2176 fdbd668d Iustin Pop
      if not result:
2177 fdbd668d Iustin Pop
        logger.Error("could not prepare block device %s on node %s"
2178 fdbd668d Iustin Pop
                     " (is_primary=True, pass=2)" % (inst_disk.iv_name, node))
2179 fdbd668d Iustin Pop
        disks_ok = False
2180 fdbd668d Iustin Pop
    device_info.append((instance.primary_node, inst_disk.iv_name, result))
2181 a8083063 Iustin Pop
2182 b352ab5b Iustin Pop
  # leave the disks configured for the primary node
2183 b352ab5b Iustin Pop
  # this is a workaround that would be fixed better by
2184 b352ab5b Iustin Pop
  # improving the logical/physical id handling
2185 b352ab5b Iustin Pop
  for disk in instance.disks:
2186 b352ab5b Iustin Pop
    cfg.SetDiskID(disk, instance.primary_node)
2187 b352ab5b Iustin Pop
2188 a8083063 Iustin Pop
  return disks_ok, device_info
2189 a8083063 Iustin Pop
2190 a8083063 Iustin Pop
2191 fe7b0351 Michael Hanselmann
def _StartInstanceDisks(cfg, instance, force):
2192 3ecf6786 Iustin Pop
  """Start the disks of an instance.
2193 3ecf6786 Iustin Pop

2194 3ecf6786 Iustin Pop
  """
2195 fe7b0351 Michael Hanselmann
  disks_ok, dummy = _AssembleInstanceDisks(instance, cfg,
2196 fe7b0351 Michael Hanselmann
                                           ignore_secondaries=force)
2197 fe7b0351 Michael Hanselmann
  if not disks_ok:
2198 fe7b0351 Michael Hanselmann
    _ShutdownInstanceDisks(instance, cfg)
2199 fe7b0351 Michael Hanselmann
    if force is not None and not force:
2200 fe7b0351 Michael Hanselmann
      logger.Error("If the message above refers to a secondary node,"
2201 fe7b0351 Michael Hanselmann
                   " you can retry the operation using '--force'.")
2202 3ecf6786 Iustin Pop
    raise errors.OpExecError("Disk consistency error")
2203 fe7b0351 Michael Hanselmann
2204 fe7b0351 Michael Hanselmann
2205 a8083063 Iustin Pop
class LUDeactivateInstanceDisks(NoHooksLU):
2206 a8083063 Iustin Pop
  """Shutdown an instance's disks.
2207 a8083063 Iustin Pop

2208 a8083063 Iustin Pop
  """
2209 a8083063 Iustin Pop
  _OP_REQP = ["instance_name"]
2210 a8083063 Iustin Pop
2211 a8083063 Iustin Pop
  def CheckPrereq(self):
2212 a8083063 Iustin Pop
    """Check prerequisites.
2213 a8083063 Iustin Pop

2214 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
2215 a8083063 Iustin Pop

2216 a8083063 Iustin Pop
    """
2217 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
2218 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
2219 a8083063 Iustin Pop
    if instance is None:
2220 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
2221 3ecf6786 Iustin Pop
                                 self.op.instance_name)
2222 a8083063 Iustin Pop
    self.instance = instance
2223 a8083063 Iustin Pop
2224 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
2225 a8083063 Iustin Pop
    """Deactivate the disks
2226 a8083063 Iustin Pop

2227 a8083063 Iustin Pop
    """
2228 a8083063 Iustin Pop
    instance = self.instance
2229 a8083063 Iustin Pop
    ins_l = rpc.call_instance_list([instance.primary_node])
2230 a8083063 Iustin Pop
    ins_l = ins_l[instance.primary_node]
2231 a8083063 Iustin Pop
    if not type(ins_l) is list:
2232 3ecf6786 Iustin Pop
      raise errors.OpExecError("Can't contact node '%s'" %
2233 3ecf6786 Iustin Pop
                               instance.primary_node)
2234 a8083063 Iustin Pop
2235 a8083063 Iustin Pop
    if self.instance.name in ins_l:
2236 3ecf6786 Iustin Pop
      raise errors.OpExecError("Instance is running, can't shutdown"
2237 3ecf6786 Iustin Pop
                               " block devices.")
2238 a8083063 Iustin Pop
2239 a8083063 Iustin Pop
    _ShutdownInstanceDisks(instance, self.cfg)
2240 a8083063 Iustin Pop
2241 a8083063 Iustin Pop
2242 a8083063 Iustin Pop
def _ShutdownInstanceDisks(instance, cfg, ignore_primary=False):
2243 a8083063 Iustin Pop
  """Shutdown block devices of an instance.
2244 a8083063 Iustin Pop

2245 a8083063 Iustin Pop
  This does the shutdown on all nodes of the instance.
2246 a8083063 Iustin Pop

2247 a8083063 Iustin Pop
  If the ignore_primary is false, errors on the primary node are
2248 a8083063 Iustin Pop
  ignored.
2249 a8083063 Iustin Pop

2250 a8083063 Iustin Pop
  """
2251 a8083063 Iustin Pop
  result = True
2252 a8083063 Iustin Pop
  for disk in instance.disks:
2253 a8083063 Iustin Pop
    for node, top_disk in disk.ComputeNodeTree(instance.primary_node):
2254 a8083063 Iustin Pop
      cfg.SetDiskID(top_disk, node)
2255 a8083063 Iustin Pop
      if not rpc.call_blockdev_shutdown(node, top_disk):
2256 a8083063 Iustin Pop
        logger.Error("could not shutdown block device %s on node %s" %
2257 a8083063 Iustin Pop
                     (disk.iv_name, node))
2258 a8083063 Iustin Pop
        if not ignore_primary or node != instance.primary_node:
2259 a8083063 Iustin Pop
          result = False
2260 a8083063 Iustin Pop
  return result
2261 a8083063 Iustin Pop
2262 a8083063 Iustin Pop
2263 d4f16fd9 Iustin Pop
def _CheckNodeFreeMemory(cfg, node, reason, requested):
2264 d4f16fd9 Iustin Pop
  """Checks if a node has enough free memory.
2265 d4f16fd9 Iustin Pop

2266 d4f16fd9 Iustin Pop
  This function check if a given node has the needed amount of free
2267 d4f16fd9 Iustin Pop
  memory. In case the node has less memory or we cannot get the
2268 d4f16fd9 Iustin Pop
  information from the node, this function raise an OpPrereqError
2269 d4f16fd9 Iustin Pop
  exception.
2270 d4f16fd9 Iustin Pop

2271 d4f16fd9 Iustin Pop
  Args:
2272 d4f16fd9 Iustin Pop
    - cfg: a ConfigWriter instance
2273 d4f16fd9 Iustin Pop
    - node: the node name
2274 d4f16fd9 Iustin Pop
    - reason: string to use in the error message
2275 d4f16fd9 Iustin Pop
    - requested: the amount of memory in MiB
2276 d4f16fd9 Iustin Pop

2277 d4f16fd9 Iustin Pop
  """
2278 d4f16fd9 Iustin Pop
  nodeinfo = rpc.call_node_info([node], cfg.GetVGName())
2279 d4f16fd9 Iustin Pop
  if not nodeinfo or not isinstance(nodeinfo, dict):
2280 d4f16fd9 Iustin Pop
    raise errors.OpPrereqError("Could not contact node %s for resource"
2281 d4f16fd9 Iustin Pop
                             " information" % (node,))
2282 d4f16fd9 Iustin Pop
2283 d4f16fd9 Iustin Pop
  free_mem = nodeinfo[node].get('memory_free')
2284 d4f16fd9 Iustin Pop
  if not isinstance(free_mem, int):
2285 d4f16fd9 Iustin Pop
    raise errors.OpPrereqError("Can't compute free memory on node %s, result"
2286 d4f16fd9 Iustin Pop
                             " was '%s'" % (node, free_mem))
2287 d4f16fd9 Iustin Pop
  if requested > free_mem:
2288 d4f16fd9 Iustin Pop
    raise errors.OpPrereqError("Not enough memory on node %s for %s:"
2289 d4f16fd9 Iustin Pop
                             " needed %s MiB, available %s MiB" %
2290 d4f16fd9 Iustin Pop
                             (node, reason, requested, free_mem))
2291 d4f16fd9 Iustin Pop
2292 d4f16fd9 Iustin Pop
2293 a8083063 Iustin Pop
class LUStartupInstance(LogicalUnit):
2294 a8083063 Iustin Pop
  """Starts an instance.
2295 a8083063 Iustin Pop

2296 a8083063 Iustin Pop
  """
2297 a8083063 Iustin Pop
  HPATH = "instance-start"
2298 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
2299 a8083063 Iustin Pop
  _OP_REQP = ["instance_name", "force"]
2300 a8083063 Iustin Pop
2301 a8083063 Iustin Pop
  def BuildHooksEnv(self):
2302 a8083063 Iustin Pop
    """Build hooks env.
2303 a8083063 Iustin Pop

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

2306 a8083063 Iustin Pop
    """
2307 a8083063 Iustin Pop
    env = {
2308 a8083063 Iustin Pop
      "FORCE": self.op.force,
2309 a8083063 Iustin Pop
      }
2310 396e1b78 Michael Hanselmann
    env.update(_BuildInstanceHookEnvByObject(self.instance))
2311 880478f8 Iustin Pop
    nl = ([self.sstore.GetMasterNode(), self.instance.primary_node] +
2312 a8083063 Iustin Pop
          list(self.instance.secondary_nodes))
2313 a8083063 Iustin Pop
    return env, nl, nl
2314 a8083063 Iustin Pop
2315 a8083063 Iustin Pop
  def CheckPrereq(self):
2316 a8083063 Iustin Pop
    """Check prerequisites.
2317 a8083063 Iustin Pop

2318 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
2319 a8083063 Iustin Pop

2320 a8083063 Iustin Pop
    """
2321 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
2322 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
2323 a8083063 Iustin Pop
    if instance is None:
2324 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
2325 3ecf6786 Iustin Pop
                                 self.op.instance_name)
2326 a8083063 Iustin Pop
2327 a8083063 Iustin Pop
    # check bridges existance
2328 bf6929a2 Alexander Schreiber
    _CheckInstanceBridgesExist(instance)
2329 a8083063 Iustin Pop
2330 d4f16fd9 Iustin Pop
    _CheckNodeFreeMemory(self.cfg, instance.primary_node,
2331 d4f16fd9 Iustin Pop
                         "starting instance %s" % instance.name,
2332 d4f16fd9 Iustin Pop
                         instance.memory)
2333 d4f16fd9 Iustin Pop
2334 a8083063 Iustin Pop
    self.instance = instance
2335 a8083063 Iustin Pop
    self.op.instance_name = instance.name
2336 a8083063 Iustin Pop
2337 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
2338 a8083063 Iustin Pop
    """Start the instance.
2339 a8083063 Iustin Pop

2340 a8083063 Iustin Pop
    """
2341 a8083063 Iustin Pop
    instance = self.instance
2342 a8083063 Iustin Pop
    force = self.op.force
2343 a8083063 Iustin Pop
    extra_args = getattr(self.op, "extra_args", "")
2344 a8083063 Iustin Pop
2345 fe482621 Iustin Pop
    self.cfg.MarkInstanceUp(instance.name)
2346 fe482621 Iustin Pop
2347 a8083063 Iustin Pop
    node_current = instance.primary_node
2348 a8083063 Iustin Pop
2349 fe7b0351 Michael Hanselmann
    _StartInstanceDisks(self.cfg, instance, force)
2350 a8083063 Iustin Pop
2351 a8083063 Iustin Pop
    if not rpc.call_instance_start(node_current, instance, extra_args):
2352 a8083063 Iustin Pop
      _ShutdownInstanceDisks(instance, self.cfg)
2353 3ecf6786 Iustin Pop
      raise errors.OpExecError("Could not start instance")
2354 a8083063 Iustin Pop
2355 a8083063 Iustin Pop
2356 bf6929a2 Alexander Schreiber
class LURebootInstance(LogicalUnit):
2357 bf6929a2 Alexander Schreiber
  """Reboot an instance.
2358 bf6929a2 Alexander Schreiber

2359 bf6929a2 Alexander Schreiber
  """
2360 bf6929a2 Alexander Schreiber
  HPATH = "instance-reboot"
2361 bf6929a2 Alexander Schreiber
  HTYPE = constants.HTYPE_INSTANCE
2362 bf6929a2 Alexander Schreiber
  _OP_REQP = ["instance_name", "ignore_secondaries", "reboot_type"]
2363 bf6929a2 Alexander Schreiber
2364 bf6929a2 Alexander Schreiber
  def BuildHooksEnv(self):
2365 bf6929a2 Alexander Schreiber
    """Build hooks env.
2366 bf6929a2 Alexander Schreiber

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

2369 bf6929a2 Alexander Schreiber
    """
2370 bf6929a2 Alexander Schreiber
    env = {
2371 bf6929a2 Alexander Schreiber
      "IGNORE_SECONDARIES": self.op.ignore_secondaries,
2372 bf6929a2 Alexander Schreiber
      }
2373 bf6929a2 Alexander Schreiber
    env.update(_BuildInstanceHookEnvByObject(self.instance))
2374 bf6929a2 Alexander Schreiber
    nl = ([self.sstore.GetMasterNode(), self.instance.primary_node] +
2375 bf6929a2 Alexander Schreiber
          list(self.instance.secondary_nodes))
2376 bf6929a2 Alexander Schreiber
    return env, nl, nl
2377 bf6929a2 Alexander Schreiber
2378 bf6929a2 Alexander Schreiber
  def CheckPrereq(self):
2379 bf6929a2 Alexander Schreiber
    """Check prerequisites.
2380 bf6929a2 Alexander Schreiber

2381 bf6929a2 Alexander Schreiber
    This checks that the instance is in the cluster.
2382 bf6929a2 Alexander Schreiber

2383 bf6929a2 Alexander Schreiber
    """
2384 bf6929a2 Alexander Schreiber
    instance = self.cfg.GetInstanceInfo(
2385 bf6929a2 Alexander Schreiber
      self.cfg.ExpandInstanceName(self.op.instance_name))
2386 bf6929a2 Alexander Schreiber
    if instance is None:
2387 bf6929a2 Alexander Schreiber
      raise errors.OpPrereqError("Instance '%s' not known" %
2388 bf6929a2 Alexander Schreiber
                                 self.op.instance_name)
2389 bf6929a2 Alexander Schreiber
2390 bf6929a2 Alexander Schreiber
    # check bridges existance
2391 bf6929a2 Alexander Schreiber
    _CheckInstanceBridgesExist(instance)
2392 bf6929a2 Alexander Schreiber
2393 bf6929a2 Alexander Schreiber
    self.instance = instance
2394 bf6929a2 Alexander Schreiber
    self.op.instance_name = instance.name
2395 bf6929a2 Alexander Schreiber
2396 bf6929a2 Alexander Schreiber
  def Exec(self, feedback_fn):
2397 bf6929a2 Alexander Schreiber
    """Reboot the instance.
2398 bf6929a2 Alexander Schreiber

2399 bf6929a2 Alexander Schreiber
    """
2400 bf6929a2 Alexander Schreiber
    instance = self.instance
2401 bf6929a2 Alexander Schreiber
    ignore_secondaries = self.op.ignore_secondaries
2402 bf6929a2 Alexander Schreiber
    reboot_type = self.op.reboot_type
2403 bf6929a2 Alexander Schreiber
    extra_args = getattr(self.op, "extra_args", "")
2404 bf6929a2 Alexander Schreiber
2405 bf6929a2 Alexander Schreiber
    node_current = instance.primary_node
2406 bf6929a2 Alexander Schreiber
2407 bf6929a2 Alexander Schreiber
    if reboot_type not in [constants.INSTANCE_REBOOT_SOFT,
2408 bf6929a2 Alexander Schreiber
                           constants.INSTANCE_REBOOT_HARD,
2409 bf6929a2 Alexander Schreiber
                           constants.INSTANCE_REBOOT_FULL]:
2410 bf6929a2 Alexander Schreiber
      raise errors.ParameterError("reboot type not in [%s, %s, %s]" %
2411 bf6929a2 Alexander Schreiber
                                  (constants.INSTANCE_REBOOT_SOFT,
2412 bf6929a2 Alexander Schreiber
                                   constants.INSTANCE_REBOOT_HARD,
2413 bf6929a2 Alexander Schreiber
                                   constants.INSTANCE_REBOOT_FULL))
2414 bf6929a2 Alexander Schreiber
2415 bf6929a2 Alexander Schreiber
    if reboot_type in [constants.INSTANCE_REBOOT_SOFT,
2416 bf6929a2 Alexander Schreiber
                       constants.INSTANCE_REBOOT_HARD]:
2417 bf6929a2 Alexander Schreiber
      if not rpc.call_instance_reboot(node_current, instance,
2418 bf6929a2 Alexander Schreiber
                                      reboot_type, extra_args):
2419 bf6929a2 Alexander Schreiber
        raise errors.OpExecError("Could not reboot instance")
2420 bf6929a2 Alexander Schreiber
    else:
2421 bf6929a2 Alexander Schreiber
      if not rpc.call_instance_shutdown(node_current, instance):
2422 bf6929a2 Alexander Schreiber
        raise errors.OpExecError("could not shutdown instance for full reboot")
2423 bf6929a2 Alexander Schreiber
      _ShutdownInstanceDisks(instance, self.cfg)
2424 bf6929a2 Alexander Schreiber
      _StartInstanceDisks(self.cfg, instance, ignore_secondaries)
2425 bf6929a2 Alexander Schreiber
      if not rpc.call_instance_start(node_current, instance, extra_args):
2426 bf6929a2 Alexander Schreiber
        _ShutdownInstanceDisks(instance, self.cfg)
2427 bf6929a2 Alexander Schreiber
        raise errors.OpExecError("Could not start instance for full reboot")
2428 bf6929a2 Alexander Schreiber
2429 bf6929a2 Alexander Schreiber
    self.cfg.MarkInstanceUp(instance.name)
2430 bf6929a2 Alexander Schreiber
2431 bf6929a2 Alexander Schreiber
2432 a8083063 Iustin Pop
class LUShutdownInstance(LogicalUnit):
2433 a8083063 Iustin Pop
  """Shutdown an instance.
2434 a8083063 Iustin Pop

2435 a8083063 Iustin Pop
  """
2436 a8083063 Iustin Pop
  HPATH = "instance-stop"
2437 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
2438 a8083063 Iustin Pop
  _OP_REQP = ["instance_name"]
2439 a8083063 Iustin Pop
2440 a8083063 Iustin Pop
  def BuildHooksEnv(self):
2441 a8083063 Iustin Pop
    """Build hooks env.
2442 a8083063 Iustin Pop

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

2445 a8083063 Iustin Pop
    """
2446 396e1b78 Michael Hanselmann
    env = _BuildInstanceHookEnvByObject(self.instance)
2447 880478f8 Iustin Pop
    nl = ([self.sstore.GetMasterNode(), self.instance.primary_node] +
2448 a8083063 Iustin Pop
          list(self.instance.secondary_nodes))
2449 a8083063 Iustin Pop
    return env, nl, nl
2450 a8083063 Iustin Pop
2451 a8083063 Iustin Pop
  def CheckPrereq(self):
2452 a8083063 Iustin Pop
    """Check prerequisites.
2453 a8083063 Iustin Pop

2454 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
2455 a8083063 Iustin Pop

2456 a8083063 Iustin Pop
    """
2457 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
2458 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
2459 a8083063 Iustin Pop
    if instance is None:
2460 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
2461 3ecf6786 Iustin Pop
                                 self.op.instance_name)
2462 a8083063 Iustin Pop
    self.instance = instance
2463 a8083063 Iustin Pop
2464 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
2465 a8083063 Iustin Pop
    """Shutdown the instance.
2466 a8083063 Iustin Pop

2467 a8083063 Iustin Pop
    """
2468 a8083063 Iustin Pop
    instance = self.instance
2469 a8083063 Iustin Pop
    node_current = instance.primary_node
2470 fe482621 Iustin Pop
    self.cfg.MarkInstanceDown(instance.name)
2471 a8083063 Iustin Pop
    if not rpc.call_instance_shutdown(node_current, instance):
2472 a8083063 Iustin Pop
      logger.Error("could not shutdown instance")
2473 a8083063 Iustin Pop
2474 a8083063 Iustin Pop
    _ShutdownInstanceDisks(instance, self.cfg)
2475 a8083063 Iustin Pop
2476 a8083063 Iustin Pop
2477 fe7b0351 Michael Hanselmann
class LUReinstallInstance(LogicalUnit):
2478 fe7b0351 Michael Hanselmann
  """Reinstall an instance.
2479 fe7b0351 Michael Hanselmann

2480 fe7b0351 Michael Hanselmann
  """
2481 fe7b0351 Michael Hanselmann
  HPATH = "instance-reinstall"
2482 fe7b0351 Michael Hanselmann
  HTYPE = constants.HTYPE_INSTANCE
2483 fe7b0351 Michael Hanselmann
  _OP_REQP = ["instance_name"]
2484 fe7b0351 Michael Hanselmann
2485 fe7b0351 Michael Hanselmann
  def BuildHooksEnv(self):
2486 fe7b0351 Michael Hanselmann
    """Build hooks env.
2487 fe7b0351 Michael Hanselmann

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

2490 fe7b0351 Michael Hanselmann
    """
2491 396e1b78 Michael Hanselmann
    env = _BuildInstanceHookEnvByObject(self.instance)
2492 fe7b0351 Michael Hanselmann
    nl = ([self.sstore.GetMasterNode(), self.instance.primary_node] +
2493 fe7b0351 Michael Hanselmann
          list(self.instance.secondary_nodes))
2494 fe7b0351 Michael Hanselmann
    return env, nl, nl
2495 fe7b0351 Michael Hanselmann
2496 fe7b0351 Michael Hanselmann
  def CheckPrereq(self):
2497 fe7b0351 Michael Hanselmann
    """Check prerequisites.
2498 fe7b0351 Michael Hanselmann

2499 fe7b0351 Michael Hanselmann
    This checks that the instance is in the cluster and is not running.
2500 fe7b0351 Michael Hanselmann

2501 fe7b0351 Michael Hanselmann
    """
2502 fe7b0351 Michael Hanselmann
    instance = self.cfg.GetInstanceInfo(
2503 fe7b0351 Michael Hanselmann
      self.cfg.ExpandInstanceName(self.op.instance_name))
2504 fe7b0351 Michael Hanselmann
    if instance is None:
2505 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
2506 3ecf6786 Iustin Pop
                                 self.op.instance_name)
2507 fe7b0351 Michael Hanselmann
    if instance.disk_template == constants.DT_DISKLESS:
2508 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' has no disks" %
2509 3ecf6786 Iustin Pop
                                 self.op.instance_name)
2510 fe7b0351 Michael Hanselmann
    if instance.status != "down":
2511 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' is marked to be up" %
2512 3ecf6786 Iustin Pop
                                 self.op.instance_name)
2513 fe7b0351 Michael Hanselmann
    remote_info = rpc.call_instance_info(instance.primary_node, instance.name)
2514 fe7b0351 Michael Hanselmann
    if remote_info:
2515 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' is running on the node %s" %
2516 3ecf6786 Iustin Pop
                                 (self.op.instance_name,
2517 3ecf6786 Iustin Pop
                                  instance.primary_node))
2518 d0834de3 Michael Hanselmann
2519 d0834de3 Michael Hanselmann
    self.op.os_type = getattr(self.op, "os_type", None)
2520 d0834de3 Michael Hanselmann
    if self.op.os_type is not None:
2521 d0834de3 Michael Hanselmann
      # OS verification
2522 d0834de3 Michael Hanselmann
      pnode = self.cfg.GetNodeInfo(
2523 d0834de3 Michael Hanselmann
        self.cfg.ExpandNodeName(instance.primary_node))
2524 d0834de3 Michael Hanselmann
      if pnode is None:
2525 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Primary node '%s' is unknown" %
2526 3ecf6786 Iustin Pop
                                   self.op.pnode)
2527 00fe9e38 Guido Trotter
      os_obj = rpc.call_os_get(pnode.name, self.op.os_type)
2528 dfa96ded Guido Trotter
      if not os_obj:
2529 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("OS '%s' not in supported OS list for"
2530 3ecf6786 Iustin Pop
                                   " primary node"  % self.op.os_type)
2531 d0834de3 Michael Hanselmann
2532 fe7b0351 Michael Hanselmann
    self.instance = instance
2533 fe7b0351 Michael Hanselmann
2534 fe7b0351 Michael Hanselmann
  def Exec(self, feedback_fn):
2535 fe7b0351 Michael Hanselmann
    """Reinstall the instance.
2536 fe7b0351 Michael Hanselmann

2537 fe7b0351 Michael Hanselmann
    """
2538 fe7b0351 Michael Hanselmann
    inst = self.instance
2539 fe7b0351 Michael Hanselmann
2540 d0834de3 Michael Hanselmann
    if self.op.os_type is not None:
2541 d0834de3 Michael Hanselmann
      feedback_fn("Changing OS to '%s'..." % self.op.os_type)
2542 d0834de3 Michael Hanselmann
      inst.os = self.op.os_type
2543 d0834de3 Michael Hanselmann
      self.cfg.AddInstance(inst)
2544 d0834de3 Michael Hanselmann
2545 fe7b0351 Michael Hanselmann
    _StartInstanceDisks(self.cfg, inst, None)
2546 fe7b0351 Michael Hanselmann
    try:
2547 fe7b0351 Michael Hanselmann
      feedback_fn("Running the instance OS create scripts...")
2548 fe7b0351 Michael Hanselmann
      if not rpc.call_instance_os_add(inst.primary_node, inst, "sda", "sdb"):
2549 f4bc1f2c Michael Hanselmann
        raise errors.OpExecError("Could not install OS for instance %s"
2550 f4bc1f2c Michael Hanselmann
                                 " on node %s" %
2551 3ecf6786 Iustin Pop
                                 (inst.name, inst.primary_node))
2552 fe7b0351 Michael Hanselmann
    finally:
2553 fe7b0351 Michael Hanselmann
      _ShutdownInstanceDisks(inst, self.cfg)
2554 fe7b0351 Michael Hanselmann
2555 fe7b0351 Michael Hanselmann
2556 decd5f45 Iustin Pop
class LURenameInstance(LogicalUnit):
2557 decd5f45 Iustin Pop
  """Rename an instance.
2558 decd5f45 Iustin Pop

2559 decd5f45 Iustin Pop
  """
2560 decd5f45 Iustin Pop
  HPATH = "instance-rename"
2561 decd5f45 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
2562 decd5f45 Iustin Pop
  _OP_REQP = ["instance_name", "new_name"]
2563 decd5f45 Iustin Pop
2564 decd5f45 Iustin Pop
  def BuildHooksEnv(self):
2565 decd5f45 Iustin Pop
    """Build hooks env.
2566 decd5f45 Iustin Pop

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

2569 decd5f45 Iustin Pop
    """
2570 decd5f45 Iustin Pop
    env = _BuildInstanceHookEnvByObject(self.instance)
2571 decd5f45 Iustin Pop
    env["INSTANCE_NEW_NAME"] = self.op.new_name
2572 decd5f45 Iustin Pop
    nl = ([self.sstore.GetMasterNode(), self.instance.primary_node] +
2573 decd5f45 Iustin Pop
          list(self.instance.secondary_nodes))
2574 decd5f45 Iustin Pop
    return env, nl, nl
2575 decd5f45 Iustin Pop
2576 decd5f45 Iustin Pop
  def CheckPrereq(self):
2577 decd5f45 Iustin Pop
    """Check prerequisites.
2578 decd5f45 Iustin Pop

2579 decd5f45 Iustin Pop
    This checks that the instance is in the cluster and is not running.
2580 decd5f45 Iustin Pop

2581 decd5f45 Iustin Pop
    """
2582 decd5f45 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
2583 decd5f45 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
2584 decd5f45 Iustin Pop
    if instance is None:
2585 decd5f45 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
2586 decd5f45 Iustin Pop
                                 self.op.instance_name)
2587 decd5f45 Iustin Pop
    if instance.status != "down":
2588 decd5f45 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' is marked to be up" %
2589 decd5f45 Iustin Pop
                                 self.op.instance_name)
2590 decd5f45 Iustin Pop
    remote_info = rpc.call_instance_info(instance.primary_node, instance.name)
2591 decd5f45 Iustin Pop
    if remote_info:
2592 decd5f45 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' is running on the node %s" %
2593 decd5f45 Iustin Pop
                                 (self.op.instance_name,
2594 decd5f45 Iustin Pop
                                  instance.primary_node))
2595 decd5f45 Iustin Pop
    self.instance = instance
2596 decd5f45 Iustin Pop
2597 decd5f45 Iustin Pop
    # new name verification
2598 89e1fc26 Iustin Pop
    name_info = utils.HostInfo(self.op.new_name)
2599 decd5f45 Iustin Pop
2600 89e1fc26 Iustin Pop
    self.op.new_name = new_name = name_info.name
2601 7bde3275 Guido Trotter
    instance_list = self.cfg.GetInstanceList()
2602 7bde3275 Guido Trotter
    if new_name in instance_list:
2603 7bde3275 Guido Trotter
      raise errors.OpPrereqError("Instance '%s' is already in the cluster" %
2604 c09f363f Manuel Franceschini
                                 new_name)
2605 7bde3275 Guido Trotter
2606 decd5f45 Iustin Pop
    if not getattr(self.op, "ignore_ip", False):
2607 89e1fc26 Iustin Pop
      command = ["fping", "-q", name_info.ip]
2608 decd5f45 Iustin Pop
      result = utils.RunCmd(command)
2609 decd5f45 Iustin Pop
      if not result.failed:
2610 decd5f45 Iustin Pop
        raise errors.OpPrereqError("IP %s of instance %s already in use" %
2611 89e1fc26 Iustin Pop
                                   (name_info.ip, new_name))
2612 decd5f45 Iustin Pop
2613 decd5f45 Iustin Pop
2614 decd5f45 Iustin Pop
  def Exec(self, feedback_fn):
2615 decd5f45 Iustin Pop
    """Reinstall the instance.
2616 decd5f45 Iustin Pop

2617 decd5f45 Iustin Pop
    """
2618 decd5f45 Iustin Pop
    inst = self.instance
2619 decd5f45 Iustin Pop
    old_name = inst.name
2620 decd5f45 Iustin Pop
2621 b23c4333 Manuel Franceschini
    if inst.disk_template == constants.DT_FILE:
2622 b23c4333 Manuel Franceschini
      old_file_storage_dir = os.path.dirname(inst.disks[0].logical_id[1])
2623 b23c4333 Manuel Franceschini
2624 decd5f45 Iustin Pop
    self.cfg.RenameInstance(inst.name, self.op.new_name)
2625 decd5f45 Iustin Pop
2626 decd5f45 Iustin Pop
    # re-read the instance from the configuration after rename
2627 decd5f45 Iustin Pop
    inst = self.cfg.GetInstanceInfo(self.op.new_name)
2628 decd5f45 Iustin Pop
2629 b23c4333 Manuel Franceschini
    if inst.disk_template == constants.DT_FILE:
2630 b23c4333 Manuel Franceschini
      new_file_storage_dir = os.path.dirname(inst.disks[0].logical_id[1])
2631 b23c4333 Manuel Franceschini
      result = rpc.call_file_storage_dir_rename(inst.primary_node,
2632 b23c4333 Manuel Franceschini
                                                old_file_storage_dir,
2633 b23c4333 Manuel Franceschini
                                                new_file_storage_dir)
2634 b23c4333 Manuel Franceschini
2635 b23c4333 Manuel Franceschini
      if not result:
2636 b23c4333 Manuel Franceschini
        raise errors.OpExecError("Could not connect to node '%s' to rename"
2637 b23c4333 Manuel Franceschini
                                 " directory '%s' to '%s' (but the instance"
2638 b23c4333 Manuel Franceschini
                                 " has been renamed in Ganeti)" % (
2639 b23c4333 Manuel Franceschini
                                 inst.primary_node, old_file_storage_dir,
2640 b23c4333 Manuel Franceschini
                                 new_file_storage_dir))
2641 b23c4333 Manuel Franceschini
2642 b23c4333 Manuel Franceschini
      if not result[0]:
2643 b23c4333 Manuel Franceschini
        raise errors.OpExecError("Could not rename directory '%s' to '%s'"
2644 b23c4333 Manuel Franceschini
                                 " (but the instance has been renamed in"
2645 b23c4333 Manuel Franceschini
                                 " Ganeti)" % (old_file_storage_dir,
2646 b23c4333 Manuel Franceschini
                                               new_file_storage_dir))
2647 b23c4333 Manuel Franceschini
2648 decd5f45 Iustin Pop
    _StartInstanceDisks(self.cfg, inst, None)
2649 decd5f45 Iustin Pop
    try:
2650 decd5f45 Iustin Pop
      if not rpc.call_instance_run_rename(inst.primary_node, inst, old_name,
2651 decd5f45 Iustin Pop
                                          "sda", "sdb"):
2652 f4bc1f2c Michael Hanselmann
        msg = ("Could run OS rename script for instance %s on node %s (but the"
2653 f4bc1f2c Michael Hanselmann
               " instance has been renamed in Ganeti)" %
2654 decd5f45 Iustin Pop
               (inst.name, inst.primary_node))
2655 decd5f45 Iustin Pop
        logger.Error(msg)
2656 decd5f45 Iustin Pop
    finally:
2657 decd5f45 Iustin Pop
      _ShutdownInstanceDisks(inst, self.cfg)
2658 decd5f45 Iustin Pop
2659 decd5f45 Iustin Pop
2660 a8083063 Iustin Pop
class LURemoveInstance(LogicalUnit):
2661 a8083063 Iustin Pop
  """Remove an instance.
2662 a8083063 Iustin Pop

2663 a8083063 Iustin Pop
  """
2664 a8083063 Iustin Pop
  HPATH = "instance-remove"
2665 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
2666 5c54b832 Iustin Pop
  _OP_REQP = ["instance_name", "ignore_failures"]
2667 a8083063 Iustin Pop
2668 a8083063 Iustin Pop
  def BuildHooksEnv(self):
2669 a8083063 Iustin Pop
    """Build hooks env.
2670 a8083063 Iustin Pop

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

2673 a8083063 Iustin Pop
    """
2674 396e1b78 Michael Hanselmann
    env = _BuildInstanceHookEnvByObject(self.instance)
2675 1d67656e Iustin Pop
    nl = [self.sstore.GetMasterNode()]
2676 a8083063 Iustin Pop
    return env, nl, nl
2677 a8083063 Iustin Pop
2678 a8083063 Iustin Pop
  def CheckPrereq(self):
2679 a8083063 Iustin Pop
    """Check prerequisites.
2680 a8083063 Iustin Pop

2681 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
2682 a8083063 Iustin Pop

2683 a8083063 Iustin Pop
    """
2684 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
2685 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
2686 a8083063 Iustin Pop
    if instance is None:
2687 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
2688 3ecf6786 Iustin Pop
                                 self.op.instance_name)
2689 a8083063 Iustin Pop
    self.instance = instance
2690 a8083063 Iustin Pop
2691 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
2692 a8083063 Iustin Pop
    """Remove the instance.
2693 a8083063 Iustin Pop

2694 a8083063 Iustin Pop
    """
2695 a8083063 Iustin Pop
    instance = self.instance
2696 a8083063 Iustin Pop
    logger.Info("shutting down instance %s on node %s" %
2697 a8083063 Iustin Pop
                (instance.name, instance.primary_node))
2698 a8083063 Iustin Pop
2699 a8083063 Iustin Pop
    if not rpc.call_instance_shutdown(instance.primary_node, instance):
2700 1d67656e Iustin Pop
      if self.op.ignore_failures:
2701 1d67656e Iustin Pop
        feedback_fn("Warning: can't shutdown instance")
2702 1d67656e Iustin Pop
      else:
2703 1d67656e Iustin Pop
        raise errors.OpExecError("Could not shutdown instance %s on node %s" %
2704 1d67656e Iustin Pop
                                 (instance.name, instance.primary_node))
2705 a8083063 Iustin Pop
2706 a8083063 Iustin Pop
    logger.Info("removing block devices for instance %s" % instance.name)
2707 a8083063 Iustin Pop
2708 1d67656e Iustin Pop
    if not _RemoveDisks(instance, self.cfg):
2709 1d67656e Iustin Pop
      if self.op.ignore_failures:
2710 1d67656e Iustin Pop
        feedback_fn("Warning: can't remove instance's disks")
2711 1d67656e Iustin Pop
      else:
2712 1d67656e Iustin Pop
        raise errors.OpExecError("Can't remove instance's disks")
2713 a8083063 Iustin Pop
2714 a8083063 Iustin Pop
    logger.Info("removing instance %s out of cluster config" % instance.name)
2715 a8083063 Iustin Pop
2716 a8083063 Iustin Pop
    self.cfg.RemoveInstance(instance.name)
2717 a8083063 Iustin Pop
2718 a8083063 Iustin Pop
2719 a8083063 Iustin Pop
class LUQueryInstances(NoHooksLU):
2720 a8083063 Iustin Pop
  """Logical unit for querying instances.
2721 a8083063 Iustin Pop

2722 a8083063 Iustin Pop
  """
2723 069dcc86 Iustin Pop
  _OP_REQP = ["output_fields", "names"]
2724 a8083063 Iustin Pop
2725 a8083063 Iustin Pop
  def CheckPrereq(self):
2726 a8083063 Iustin Pop
    """Check prerequisites.
2727 a8083063 Iustin Pop

2728 a8083063 Iustin Pop
    This checks that the fields required are valid output fields.
2729 a8083063 Iustin Pop

2730 a8083063 Iustin Pop
    """
2731 d8052456 Iustin Pop
    self.dynamic_fields = frozenset(["oper_state", "oper_ram", "status"])
2732 dcb93971 Michael Hanselmann
    _CheckOutputFields(static=["name", "os", "pnode", "snodes",
2733 dcb93971 Michael Hanselmann
                               "admin_state", "admin_ram",
2734 644eeef9 Iustin Pop
                               "disk_template", "ip", "mac", "bridge",
2735 d6d415e8 Iustin Pop
                               "sda_size", "sdb_size", "vcpus"],
2736 dcb93971 Michael Hanselmann
                       dynamic=self.dynamic_fields,
2737 dcb93971 Michael Hanselmann
                       selected=self.op.output_fields)
2738 a8083063 Iustin Pop
2739 069dcc86 Iustin Pop
    self.wanted = _GetWantedInstances(self, self.op.names)
2740 069dcc86 Iustin Pop
2741 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
2742 a8083063 Iustin Pop
    """Computes the list of nodes and their attributes.
2743 a8083063 Iustin Pop

2744 a8083063 Iustin Pop
    """
2745 069dcc86 Iustin Pop
    instance_names = self.wanted
2746 a8083063 Iustin Pop
    instance_list = [self.cfg.GetInstanceInfo(iname) for iname
2747 a8083063 Iustin Pop
                     in instance_names]
2748 a8083063 Iustin Pop
2749 a8083063 Iustin Pop
    # begin data gathering
2750 a8083063 Iustin Pop
2751 a8083063 Iustin Pop
    nodes = frozenset([inst.primary_node for inst in instance_list])
2752 a8083063 Iustin Pop
2753 a8083063 Iustin Pop
    bad_nodes = []
2754 a8083063 Iustin Pop
    if self.dynamic_fields.intersection(self.op.output_fields):
2755 a8083063 Iustin Pop
      live_data = {}
2756 a8083063 Iustin Pop
      node_data = rpc.call_all_instances_info(nodes)
2757 a8083063 Iustin Pop
      for name in nodes:
2758 a8083063 Iustin Pop
        result = node_data[name]
2759 a8083063 Iustin Pop
        if result:
2760 a8083063 Iustin Pop
          live_data.update(result)
2761 a8083063 Iustin Pop
        elif result == False:
2762 a8083063 Iustin Pop
          bad_nodes.append(name)
2763 a8083063 Iustin Pop
        # else no instance is alive
2764 a8083063 Iustin Pop
    else:
2765 a8083063 Iustin Pop
      live_data = dict([(name, {}) for name in instance_names])
2766 a8083063 Iustin Pop
2767 a8083063 Iustin Pop
    # end data gathering
2768 a8083063 Iustin Pop
2769 a8083063 Iustin Pop
    output = []
2770 a8083063 Iustin Pop
    for instance in instance_list:
2771 a8083063 Iustin Pop
      iout = []
2772 a8083063 Iustin Pop
      for field in self.op.output_fields:
2773 a8083063 Iustin Pop
        if field == "name":
2774 a8083063 Iustin Pop
          val = instance.name
2775 a8083063 Iustin Pop
        elif field == "os":
2776 a8083063 Iustin Pop
          val = instance.os
2777 a8083063 Iustin Pop
        elif field == "pnode":
2778 a8083063 Iustin Pop
          val = instance.primary_node
2779 a8083063 Iustin Pop
        elif field == "snodes":
2780 8a23d2d3 Iustin Pop
          val = list(instance.secondary_nodes)
2781 a8083063 Iustin Pop
        elif field == "admin_state":
2782 8a23d2d3 Iustin Pop
          val = (instance.status != "down")
2783 a8083063 Iustin Pop
        elif field == "oper_state":
2784 a8083063 Iustin Pop
          if instance.primary_node in bad_nodes:
2785 8a23d2d3 Iustin Pop
            val = None
2786 a8083063 Iustin Pop
          else:
2787 8a23d2d3 Iustin Pop
            val = bool(live_data.get(instance.name))
2788 d8052456 Iustin Pop
        elif field == "status":
2789 d8052456 Iustin Pop
          if instance.primary_node in bad_nodes:
2790 d8052456 Iustin Pop
            val = "ERROR_nodedown"
2791 d8052456 Iustin Pop
          else:
2792 d8052456 Iustin Pop
            running = bool(live_data.get(instance.name))
2793 d8052456 Iustin Pop
            if running:
2794 d8052456 Iustin Pop
              if instance.status != "down":
2795 d8052456 Iustin Pop
                val = "running"
2796 d8052456 Iustin Pop
              else:
2797 d8052456 Iustin Pop
                val = "ERROR_up"
2798 d8052456 Iustin Pop
            else:
2799 d8052456 Iustin Pop
              if instance.status != "down":
2800 d8052456 Iustin Pop
                val = "ERROR_down"
2801 d8052456 Iustin Pop
              else:
2802 d8052456 Iustin Pop
                val = "ADMIN_down"
2803 a8083063 Iustin Pop
        elif field == "admin_ram":
2804 a8083063 Iustin Pop
          val = instance.memory
2805 a8083063 Iustin Pop
        elif field == "oper_ram":
2806 a8083063 Iustin Pop
          if instance.primary_node in bad_nodes:
2807 8a23d2d3 Iustin Pop
            val = None
2808 a8083063 Iustin Pop
          elif instance.name in live_data:
2809 a8083063 Iustin Pop
            val = live_data[instance.name].get("memory", "?")
2810 a8083063 Iustin Pop
          else:
2811 a8083063 Iustin Pop
            val = "-"
2812 a8083063 Iustin Pop
        elif field == "disk_template":
2813 a8083063 Iustin Pop
          val = instance.disk_template
2814 a8083063 Iustin Pop
        elif field == "ip":
2815 a8083063 Iustin Pop
          val = instance.nics[0].ip
2816 a8083063 Iustin Pop
        elif field == "bridge":
2817 a8083063 Iustin Pop
          val = instance.nics[0].bridge
2818 a8083063 Iustin Pop
        elif field == "mac":
2819 a8083063 Iustin Pop
          val = instance.nics[0].mac
2820 644eeef9 Iustin Pop
        elif field == "sda_size" or field == "sdb_size":
2821 644eeef9 Iustin Pop
          disk = instance.FindDisk(field[:3])
2822 644eeef9 Iustin Pop
          if disk is None:
2823 8a23d2d3 Iustin Pop
            val = None
2824 644eeef9 Iustin Pop
          else:
2825 644eeef9 Iustin Pop
            val = disk.size
2826 d6d415e8 Iustin Pop
        elif field == "vcpus":
2827 d6d415e8 Iustin Pop
          val = instance.vcpus
2828 a8083063 Iustin Pop
        else:
2829 3ecf6786 Iustin Pop
          raise errors.ParameterError(field)
2830 a8083063 Iustin Pop
        iout.append(val)
2831 a8083063 Iustin Pop
      output.append(iout)
2832 a8083063 Iustin Pop
2833 a8083063 Iustin Pop
    return output
2834 a8083063 Iustin Pop
2835 a8083063 Iustin Pop
2836 a8083063 Iustin Pop
class LUFailoverInstance(LogicalUnit):
2837 a8083063 Iustin Pop
  """Failover an instance.
2838 a8083063 Iustin Pop

2839 a8083063 Iustin Pop
  """
2840 a8083063 Iustin Pop
  HPATH = "instance-failover"
2841 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
2842 a8083063 Iustin Pop
  _OP_REQP = ["instance_name", "ignore_consistency"]
2843 a8083063 Iustin Pop
2844 a8083063 Iustin Pop
  def BuildHooksEnv(self):
2845 a8083063 Iustin Pop
    """Build hooks env.
2846 a8083063 Iustin Pop

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

2849 a8083063 Iustin Pop
    """
2850 a8083063 Iustin Pop
    env = {
2851 a8083063 Iustin Pop
      "IGNORE_CONSISTENCY": self.op.ignore_consistency,
2852 a8083063 Iustin Pop
      }
2853 396e1b78 Michael Hanselmann
    env.update(_BuildInstanceHookEnvByObject(self.instance))
2854 880478f8 Iustin Pop
    nl = [self.sstore.GetMasterNode()] + list(self.instance.secondary_nodes)
2855 a8083063 Iustin Pop
    return env, nl, nl
2856 a8083063 Iustin Pop
2857 a8083063 Iustin Pop
  def CheckPrereq(self):
2858 a8083063 Iustin Pop
    """Check prerequisites.
2859 a8083063 Iustin Pop

2860 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
2861 a8083063 Iustin Pop

2862 a8083063 Iustin Pop
    """
2863 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
2864 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
2865 a8083063 Iustin Pop
    if instance is None:
2866 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
2867 3ecf6786 Iustin Pop
                                 self.op.instance_name)
2868 a8083063 Iustin Pop
2869 a1f445d3 Iustin Pop
    if instance.disk_template not in constants.DTS_NET_MIRROR:
2870 2a710df1 Michael Hanselmann
      raise errors.OpPrereqError("Instance's disk layout is not"
2871 a1f445d3 Iustin Pop
                                 " network mirrored, cannot failover.")
2872 2a710df1 Michael Hanselmann
2873 2a710df1 Michael Hanselmann
    secondary_nodes = instance.secondary_nodes
2874 2a710df1 Michael Hanselmann
    if not secondary_nodes:
2875 2a710df1 Michael Hanselmann
      raise errors.ProgrammerError("no secondary node but using "
2876 abdf0113 Iustin Pop
                                   "a mirrored disk template")
2877 2a710df1 Michael Hanselmann
2878 2a710df1 Michael Hanselmann
    target_node = secondary_nodes[0]
2879 d4f16fd9 Iustin Pop
    # check memory requirements on the secondary node
2880 d4f16fd9 Iustin Pop
    _CheckNodeFreeMemory(self.cfg, target_node, "failing over instance %s" %
2881 d4f16fd9 Iustin Pop
                         instance.name, instance.memory)
2882 3a7c308e Guido Trotter
2883 a8083063 Iustin Pop
    # check bridge existance
2884 a8083063 Iustin Pop
    brlist = [nic.bridge for nic in instance.nics]
2885 50ff9a7a Iustin Pop
    if not rpc.call_bridges_exist(target_node, brlist):
2886 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("One or more target bridges %s does not"
2887 3ecf6786 Iustin Pop
                                 " exist on destination node '%s'" %
2888 50ff9a7a Iustin Pop
                                 (brlist, target_node))
2889 a8083063 Iustin Pop
2890 a8083063 Iustin Pop
    self.instance = instance
2891 a8083063 Iustin Pop
2892 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
2893 a8083063 Iustin Pop
    """Failover an instance.
2894 a8083063 Iustin Pop

2895 a8083063 Iustin Pop
    The failover is done by shutting it down on its present node and
2896 a8083063 Iustin Pop
    starting it on the secondary.
2897 a8083063 Iustin Pop

2898 a8083063 Iustin Pop
    """
2899 a8083063 Iustin Pop
    instance = self.instance
2900 a8083063 Iustin Pop
2901 a8083063 Iustin Pop
    source_node = instance.primary_node
2902 a8083063 Iustin Pop
    target_node = instance.secondary_nodes[0]
2903 a8083063 Iustin Pop
2904 a8083063 Iustin Pop
    feedback_fn("* checking disk consistency between source and target")
2905 a8083063 Iustin Pop
    for dev in instance.disks:
2906 abdf0113 Iustin Pop
      # for drbd, these are drbd over lvm
2907 a8083063 Iustin Pop
      if not _CheckDiskConsistency(self.cfg, dev, target_node, False):
2908 a0aaa0d0 Guido Trotter
        if instance.status == "up" and not self.op.ignore_consistency:
2909 3ecf6786 Iustin Pop
          raise errors.OpExecError("Disk %s is degraded on target node,"
2910 3ecf6786 Iustin Pop
                                   " aborting failover." % dev.iv_name)
2911 a8083063 Iustin Pop
2912 a8083063 Iustin Pop
    feedback_fn("* shutting down instance on source node")
2913 a8083063 Iustin Pop
    logger.Info("Shutting down instance %s on node %s" %
2914 a8083063 Iustin Pop
                (instance.name, source_node))
2915 a8083063 Iustin Pop
2916 a8083063 Iustin Pop
    if not rpc.call_instance_shutdown(source_node, instance):
2917 24a40d57 Iustin Pop
      if self.op.ignore_consistency:
2918 24a40d57 Iustin Pop
        logger.Error("Could not shutdown instance %s on node %s. Proceeding"
2919 24a40d57 Iustin Pop
                     " anyway. Please make sure node %s is down"  %
2920 24a40d57 Iustin Pop
                     (instance.name, source_node, source_node))
2921 24a40d57 Iustin Pop
      else:
2922 24a40d57 Iustin Pop
        raise errors.OpExecError("Could not shutdown instance %s on node %s" %
2923 24a40d57 Iustin Pop
                                 (instance.name, source_node))
2924 a8083063 Iustin Pop
2925 a8083063 Iustin Pop
    feedback_fn("* deactivating the instance's disks on source node")
2926 a8083063 Iustin Pop
    if not _ShutdownInstanceDisks(instance, self.cfg, ignore_primary=True):
2927 3ecf6786 Iustin Pop
      raise errors.OpExecError("Can't shut down the instance's disks.")
2928 a8083063 Iustin Pop
2929 a8083063 Iustin Pop
    instance.primary_node = target_node
2930 a8083063 Iustin Pop
    # distribute new instance config to the other nodes
2931 a8083063 Iustin Pop
    self.cfg.AddInstance(instance)
2932 a8083063 Iustin Pop
2933 12a0cfbe Guido Trotter
    # Only start the instance if it's marked as up
2934 12a0cfbe Guido Trotter
    if instance.status == "up":
2935 12a0cfbe Guido Trotter
      feedback_fn("* activating the instance's disks on target node")
2936 12a0cfbe Guido Trotter
      logger.Info("Starting instance %s on node %s" %
2937 12a0cfbe Guido Trotter
                  (instance.name, target_node))
2938 12a0cfbe Guido Trotter
2939 12a0cfbe Guido Trotter
      disks_ok, dummy = _AssembleInstanceDisks(instance, self.cfg,
2940 12a0cfbe Guido Trotter
                                               ignore_secondaries=True)
2941 12a0cfbe Guido Trotter
      if not disks_ok:
2942 12a0cfbe Guido Trotter
        _ShutdownInstanceDisks(instance, self.cfg)
2943 12a0cfbe Guido Trotter
        raise errors.OpExecError("Can't activate the instance's disks")
2944 a8083063 Iustin Pop
2945 12a0cfbe Guido Trotter
      feedback_fn("* starting the instance on the target node")
2946 12a0cfbe Guido Trotter
      if not rpc.call_instance_start(target_node, instance, None):
2947 12a0cfbe Guido Trotter
        _ShutdownInstanceDisks(instance, self.cfg)
2948 12a0cfbe Guido Trotter
        raise errors.OpExecError("Could not start instance %s on node %s." %
2949 12a0cfbe Guido Trotter
                                 (instance.name, target_node))
2950 a8083063 Iustin Pop
2951 a8083063 Iustin Pop
2952 3f78eef2 Iustin Pop
def _CreateBlockDevOnPrimary(cfg, node, instance, device, info):
2953 a8083063 Iustin Pop
  """Create a tree of block devices on the primary node.
2954 a8083063 Iustin Pop

2955 a8083063 Iustin Pop
  This always creates all devices.
2956 a8083063 Iustin Pop

2957 a8083063 Iustin Pop
  """
2958 a8083063 Iustin Pop
  if device.children:
2959 a8083063 Iustin Pop
    for child in device.children:
2960 3f78eef2 Iustin Pop
      if not _CreateBlockDevOnPrimary(cfg, node, instance, child, info):
2961 a8083063 Iustin Pop
        return False
2962 a8083063 Iustin Pop
2963 a8083063 Iustin Pop
  cfg.SetDiskID(device, node)
2964 3f78eef2 Iustin Pop
  new_id = rpc.call_blockdev_create(node, device, device.size,
2965 3f78eef2 Iustin Pop
                                    instance.name, True, info)
2966 a8083063 Iustin Pop
  if not new_id:
2967 a8083063 Iustin Pop
    return False
2968 a8083063 Iustin Pop
  if device.physical_id is None:
2969 a8083063 Iustin Pop
    device.physical_id = new_id
2970 a8083063 Iustin Pop
  return True
2971 a8083063 Iustin Pop
2972 a8083063 Iustin Pop
2973 3f78eef2 Iustin Pop
def _CreateBlockDevOnSecondary(cfg, node, instance, device, force, info):
2974 a8083063 Iustin Pop
  """Create a tree of block devices on a secondary node.
2975 a8083063 Iustin Pop

2976 a8083063 Iustin Pop
  If this device type has to be created on secondaries, create it and
2977 a8083063 Iustin Pop
  all its children.
2978 a8083063 Iustin Pop

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

2981 a8083063 Iustin Pop
  """
2982 a8083063 Iustin Pop
  if device.CreateOnSecondary():
2983 a8083063 Iustin Pop
    force = True
2984 a8083063 Iustin Pop
  if device.children:
2985 a8083063 Iustin Pop
    for child in device.children:
2986 3f78eef2 Iustin Pop
      if not _CreateBlockDevOnSecondary(cfg, node, instance,
2987 3f78eef2 Iustin Pop
                                        child, force, info):
2988 a8083063 Iustin Pop
        return False
2989 a8083063 Iustin Pop
2990 a8083063 Iustin Pop
  if not force:
2991 a8083063 Iustin Pop
    return True
2992 a8083063 Iustin Pop
  cfg.SetDiskID(device, node)
2993 3f78eef2 Iustin Pop
  new_id = rpc.call_blockdev_create(node, device, device.size,
2994 3f78eef2 Iustin Pop
                                    instance.name, False, info)
2995 a8083063 Iustin Pop
  if not new_id:
2996 a8083063 Iustin Pop
    return False
2997 a8083063 Iustin Pop
  if device.physical_id is None:
2998 a8083063 Iustin Pop
    device.physical_id = new_id
2999 a8083063 Iustin Pop
  return True
3000 a8083063 Iustin Pop
3001 a8083063 Iustin Pop
3002 923b1523 Iustin Pop
def _GenerateUniqueNames(cfg, exts):
3003 923b1523 Iustin Pop
  """Generate a suitable LV name.
3004 923b1523 Iustin Pop

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

3007 923b1523 Iustin Pop
  """
3008 923b1523 Iustin Pop
  results = []
3009 923b1523 Iustin Pop
  for val in exts:
3010 923b1523 Iustin Pop
    new_id = cfg.GenerateUniqueID()
3011 923b1523 Iustin Pop
    results.append("%s%s" % (new_id, val))
3012 923b1523 Iustin Pop
  return results
3013 923b1523 Iustin Pop
3014 923b1523 Iustin Pop
3015 923b1523 Iustin Pop
def _GenerateMDDRBDBranch(cfg, primary, secondary, size, names):
3016 a8083063 Iustin Pop
  """Generate a drbd device complete with its children.
3017 a8083063 Iustin Pop

3018 a8083063 Iustin Pop
  """
3019 a8083063 Iustin Pop
  port = cfg.AllocatePort()
3020 923b1523 Iustin Pop
  vgname = cfg.GetVGName()
3021 fe96220b Iustin Pop
  dev_data = objects.Disk(dev_type=constants.LD_LV, size=size,
3022 923b1523 Iustin Pop
                          logical_id=(vgname, names[0]))
3023 fe96220b Iustin Pop
  dev_meta = objects.Disk(dev_type=constants.LD_LV, size=128,
3024 923b1523 Iustin Pop
                          logical_id=(vgname, names[1]))
3025 fe96220b Iustin Pop
  drbd_dev = objects.Disk(dev_type=constants.LD_DRBD7, size=size,
3026 a8083063 Iustin Pop
                          logical_id = (primary, secondary, port),
3027 a8083063 Iustin Pop
                          children = [dev_data, dev_meta])
3028 a8083063 Iustin Pop
  return drbd_dev
3029 a8083063 Iustin Pop
3030 a8083063 Iustin Pop
3031 a1f445d3 Iustin Pop
def _GenerateDRBD8Branch(cfg, primary, secondary, size, names, iv_name):
3032 a1f445d3 Iustin Pop
  """Generate a drbd8 device complete with its children.
3033 a1f445d3 Iustin Pop

3034 a1f445d3 Iustin Pop
  """
3035 a1f445d3 Iustin Pop
  port = cfg.AllocatePort()
3036 a1f445d3 Iustin Pop
  vgname = cfg.GetVGName()
3037 a1f445d3 Iustin Pop
  dev_data = objects.Disk(dev_type=constants.LD_LV, size=size,
3038 a1f445d3 Iustin Pop
                          logical_id=(vgname, names[0]))
3039 a1f445d3 Iustin Pop
  dev_meta = objects.Disk(dev_type=constants.LD_LV, size=128,
3040 a1f445d3 Iustin Pop
                          logical_id=(vgname, names[1]))
3041 a1f445d3 Iustin Pop
  drbd_dev = objects.Disk(dev_type=constants.LD_DRBD8, size=size,
3042 a1f445d3 Iustin Pop
                          logical_id = (primary, secondary, port),
3043 a1f445d3 Iustin Pop
                          children = [dev_data, dev_meta],
3044 a1f445d3 Iustin Pop
                          iv_name=iv_name)
3045 a1f445d3 Iustin Pop
  return drbd_dev
3046 a1f445d3 Iustin Pop
3047 7c0d6283 Michael Hanselmann
3048 923b1523 Iustin Pop
def _GenerateDiskTemplate(cfg, template_name,
3049 a8083063 Iustin Pop
                          instance_name, primary_node,
3050 0f1a06e3 Manuel Franceschini
                          secondary_nodes, disk_sz, swap_sz,
3051 0f1a06e3 Manuel Franceschini
                          file_storage_dir, file_driver):
3052 a8083063 Iustin Pop
  """Generate the entire disk layout for a given template type.
3053 a8083063 Iustin Pop

3054 a8083063 Iustin Pop
  """
3055 a8083063 Iustin Pop
  #TODO: compute space requirements
3056 a8083063 Iustin Pop
3057 923b1523 Iustin Pop
  vgname = cfg.GetVGName()
3058 3517d9b9 Manuel Franceschini
  if template_name == constants.DT_DISKLESS:
3059 a8083063 Iustin Pop
    disks = []
3060 3517d9b9 Manuel Franceschini
  elif template_name == constants.DT_PLAIN:
3061 a8083063 Iustin Pop
    if len(secondary_nodes) != 0:
3062 a8083063 Iustin Pop
      raise errors.ProgrammerError("Wrong template configuration")
3063 923b1523 Iustin Pop
3064 923b1523 Iustin Pop
    names = _GenerateUniqueNames(cfg, [".sda", ".sdb"])
3065 fe96220b Iustin Pop
    sda_dev = objects.Disk(dev_type=constants.LD_LV, size=disk_sz,
3066 923b1523 Iustin Pop
                           logical_id=(vgname, names[0]),
3067 a8083063 Iustin Pop
                           iv_name = "sda")
3068 fe96220b Iustin Pop
    sdb_dev = objects.Disk(dev_type=constants.LD_LV, size=swap_sz,
3069 923b1523 Iustin Pop
                           logical_id=(vgname, names[1]),
3070 a8083063 Iustin Pop
                           iv_name = "sdb")
3071 a8083063 Iustin Pop
    disks = [sda_dev, sdb_dev]
3072 a1f445d3 Iustin Pop
  elif template_name == constants.DT_DRBD8:
3073 a1f445d3 Iustin Pop
    if len(secondary_nodes) != 1:
3074 a1f445d3 Iustin Pop
      raise errors.ProgrammerError("Wrong template configuration")
3075 a1f445d3 Iustin Pop
    remote_node = secondary_nodes[0]
3076 a1f445d3 Iustin Pop
    names = _GenerateUniqueNames(cfg, [".sda_data", ".sda_meta",
3077 a1f445d3 Iustin Pop
                                       ".sdb_data", ".sdb_meta"])
3078 a1f445d3 Iustin Pop
    drbd_sda_dev = _GenerateDRBD8Branch(cfg, primary_node, remote_node,
3079 a1f445d3 Iustin Pop
                                         disk_sz, names[0:2], "sda")
3080 a1f445d3 Iustin Pop
    drbd_sdb_dev = _GenerateDRBD8Branch(cfg, primary_node, remote_node,
3081 a1f445d3 Iustin Pop
                                         swap_sz, names[2:4], "sdb")
3082 a1f445d3 Iustin Pop
    disks = [drbd_sda_dev, drbd_sdb_dev]
3083 0f1a06e3 Manuel Franceschini
  elif template_name == constants.DT_FILE:
3084 0f1a06e3 Manuel Franceschini
    if len(secondary_nodes) != 0:
3085 0f1a06e3 Manuel Franceschini
      raise errors.ProgrammerError("Wrong template configuration")
3086 0f1a06e3 Manuel Franceschini
3087 0f1a06e3 Manuel Franceschini
    file_sda_dev = objects.Disk(dev_type=constants.LD_FILE, size=disk_sz,
3088 0f1a06e3 Manuel Franceschini
                                iv_name="sda", logical_id=(file_driver,
3089 0f1a06e3 Manuel Franceschini
                                "%s/sda" % file_storage_dir))
3090 0f1a06e3 Manuel Franceschini
    file_sdb_dev = objects.Disk(dev_type=constants.LD_FILE, size=swap_sz,
3091 0f1a06e3 Manuel Franceschini
                                iv_name="sdb", logical_id=(file_driver,
3092 0f1a06e3 Manuel Franceschini
                                "%s/sdb" % file_storage_dir))
3093 0f1a06e3 Manuel Franceschini
    disks = [file_sda_dev, file_sdb_dev]
3094 a8083063 Iustin Pop
  else:
3095 a8083063 Iustin Pop
    raise errors.ProgrammerError("Invalid disk template '%s'" % template_name)
3096 a8083063 Iustin Pop
  return disks
3097 a8083063 Iustin Pop
3098 a8083063 Iustin Pop
3099 a0c3fea1 Michael Hanselmann
def _GetInstanceInfoText(instance):
3100 3ecf6786 Iustin Pop
  """Compute that text that should be added to the disk's metadata.
3101 3ecf6786 Iustin Pop

3102 3ecf6786 Iustin Pop
  """
3103 a0c3fea1 Michael Hanselmann
  return "originstname+%s" % instance.name
3104 a0c3fea1 Michael Hanselmann
3105 a0c3fea1 Michael Hanselmann
3106 a8083063 Iustin Pop
def _CreateDisks(cfg, instance):
3107 a8083063 Iustin Pop
  """Create all disks for an instance.
3108 a8083063 Iustin Pop

3109 a8083063 Iustin Pop
  This abstracts away some work from AddInstance.
3110 a8083063 Iustin Pop

3111 a8083063 Iustin Pop
  Args:
3112 a8083063 Iustin Pop
    instance: the instance object
3113 a8083063 Iustin Pop

3114 a8083063 Iustin Pop
  Returns:
3115 a8083063 Iustin Pop
    True or False showing the success of the creation process
3116 a8083063 Iustin Pop

3117 a8083063 Iustin Pop
  """
3118 a0c3fea1 Michael Hanselmann
  info = _GetInstanceInfoText(instance)
3119 a0c3fea1 Michael Hanselmann
3120 0f1a06e3 Manuel Franceschini
  if instance.disk_template == constants.DT_FILE:
3121 0f1a06e3 Manuel Franceschini
    file_storage_dir = os.path.dirname(instance.disks[0].logical_id[1])
3122 0f1a06e3 Manuel Franceschini
    result = rpc.call_file_storage_dir_create(instance.primary_node,
3123 0f1a06e3 Manuel Franceschini
                                              file_storage_dir)
3124 0f1a06e3 Manuel Franceschini
3125 0f1a06e3 Manuel Franceschini
    if not result:
3126 b62ddbe5 Guido Trotter
      logger.Error("Could not connect to node '%s'" % instance.primary_node)
3127 0f1a06e3 Manuel Franceschini
      return False
3128 0f1a06e3 Manuel Franceschini
3129 0f1a06e3 Manuel Franceschini
    if not result[0]:
3130 0f1a06e3 Manuel Franceschini
      logger.Error("failed to create directory '%s'" % file_storage_dir)
3131 0f1a06e3 Manuel Franceschini
      return False
3132 0f1a06e3 Manuel Franceschini
3133 a8083063 Iustin Pop
  for device in instance.disks:
3134 a8083063 Iustin Pop
    logger.Info("creating volume %s for instance %s" %
3135 1c6e3627 Manuel Franceschini
                (device.iv_name, instance.name))
3136 a8083063 Iustin Pop
    #HARDCODE
3137 a8083063 Iustin Pop
    for secondary_node in instance.secondary_nodes:
3138 3f78eef2 Iustin Pop
      if not _CreateBlockDevOnSecondary(cfg, secondary_node, instance,
3139 3f78eef2 Iustin Pop
                                        device, False, info):
3140 a8083063 Iustin Pop
        logger.Error("failed to create volume %s (%s) on secondary node %s!" %
3141 a8083063 Iustin Pop
                     (device.iv_name, device, secondary_node))
3142 a8083063 Iustin Pop
        return False
3143 a8083063 Iustin Pop
    #HARDCODE
3144 3f78eef2 Iustin Pop
    if not _CreateBlockDevOnPrimary(cfg, instance.primary_node,
3145 3f78eef2 Iustin Pop
                                    instance, device, info):
3146 a8083063 Iustin Pop
      logger.Error("failed to create volume %s on primary!" %
3147 a8083063 Iustin Pop
                   device.iv_name)
3148 a8083063 Iustin Pop
      return False
3149 1c6e3627 Manuel Franceschini
3150 a8083063 Iustin Pop
  return True
3151 a8083063 Iustin Pop
3152 a8083063 Iustin Pop
3153 a8083063 Iustin Pop
def _RemoveDisks(instance, cfg):
3154 a8083063 Iustin Pop
  """Remove all disks for an instance.
3155 a8083063 Iustin Pop

3156 a8083063 Iustin Pop
  This abstracts away some work from `AddInstance()` and
3157 a8083063 Iustin Pop
  `RemoveInstance()`. Note that in case some of the devices couldn't
3158 1d67656e Iustin Pop
  be removed, the removal will continue with the other ones (compare
3159 a8083063 Iustin Pop
  with `_CreateDisks()`).
3160 a8083063 Iustin Pop

3161 a8083063 Iustin Pop
  Args:
3162 a8083063 Iustin Pop
    instance: the instance object
3163 a8083063 Iustin Pop

3164 a8083063 Iustin Pop
  Returns:
3165 a8083063 Iustin Pop
    True or False showing the success of the removal proces
3166 a8083063 Iustin Pop

3167 a8083063 Iustin Pop
  """
3168 a8083063 Iustin Pop
  logger.Info("removing block devices for instance %s" % instance.name)
3169 a8083063 Iustin Pop
3170 a8083063 Iustin Pop
  result = True
3171 a8083063 Iustin Pop
  for device in instance.disks:
3172 a8083063 Iustin Pop
    for node, disk in device.ComputeNodeTree(instance.primary_node):
3173 a8083063 Iustin Pop
      cfg.SetDiskID(disk, node)
3174 a8083063 Iustin Pop
      if not rpc.call_blockdev_remove(node, disk):
3175 a8083063 Iustin Pop
        logger.Error("could not remove block device %s on node %s,"
3176 a8083063 Iustin Pop
                     " continuing anyway" %
3177 a8083063 Iustin Pop
                     (device.iv_name, node))
3178 a8083063 Iustin Pop
        result = False
3179 0f1a06e3 Manuel Franceschini
3180 0f1a06e3 Manuel Franceschini
  if instance.disk_template == constants.DT_FILE:
3181 0f1a06e3 Manuel Franceschini
    file_storage_dir = os.path.dirname(instance.disks[0].logical_id[1])
3182 0f1a06e3 Manuel Franceschini
    if not rpc.call_file_storage_dir_remove(instance.primary_node,
3183 0f1a06e3 Manuel Franceschini
                                            file_storage_dir):
3184 0f1a06e3 Manuel Franceschini
      logger.Error("could not remove directory '%s'" % file_storage_dir)
3185 0f1a06e3 Manuel Franceschini
      result = False
3186 0f1a06e3 Manuel Franceschini
3187 a8083063 Iustin Pop
  return result
3188 a8083063 Iustin Pop
3189 a8083063 Iustin Pop
3190 e2fe6369 Iustin Pop
def _ComputeDiskSize(disk_template, disk_size, swap_size):
3191 e2fe6369 Iustin Pop
  """Compute disk size requirements in the volume group
3192 e2fe6369 Iustin Pop

3193 e2fe6369 Iustin Pop
  This is currently hard-coded for the two-drive layout.
3194 e2fe6369 Iustin Pop

3195 e2fe6369 Iustin Pop
  """
3196 e2fe6369 Iustin Pop
  # Required free disk space as a function of disk and swap space
3197 e2fe6369 Iustin Pop
  req_size_dict = {
3198 e2fe6369 Iustin Pop
    constants.DT_DISKLESS: None,
3199 e2fe6369 Iustin Pop
    constants.DT_PLAIN: disk_size + swap_size,
3200 e2fe6369 Iustin Pop
    # 256 MB are added for drbd metadata, 128MB for each drbd device
3201 e2fe6369 Iustin Pop
    constants.DT_DRBD8: disk_size + swap_size + 256,
3202 e2fe6369 Iustin Pop
    constants.DT_FILE: None,
3203 e2fe6369 Iustin Pop
  }
3204 e2fe6369 Iustin Pop
3205 e2fe6369 Iustin Pop
  if disk_template not in req_size_dict:
3206 e2fe6369 Iustin Pop
    raise errors.ProgrammerError("Disk template '%s' size requirement"
3207 e2fe6369 Iustin Pop
                                 " is unknown" %  disk_template)
3208 e2fe6369 Iustin Pop
3209 e2fe6369 Iustin Pop
  return req_size_dict[disk_template]
3210 e2fe6369 Iustin Pop
3211 e2fe6369 Iustin Pop
3212 a8083063 Iustin Pop
class LUCreateInstance(LogicalUnit):
3213 a8083063 Iustin Pop
  """Create an instance.
3214 a8083063 Iustin Pop

3215 a8083063 Iustin Pop
  """
3216 a8083063 Iustin Pop
  HPATH = "instance-add"
3217 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
3218 538475ca Iustin Pop
  _OP_REQP = ["instance_name", "mem_size", "disk_size",
3219 a8083063 Iustin Pop
              "disk_template", "swap_size", "mode", "start", "vcpus",
3220 1862d460 Alexander Schreiber
              "wait_for_sync", "ip_check", "mac"]
3221 a8083063 Iustin Pop
3222 538475ca Iustin Pop
  def _RunAllocator(self):
3223 538475ca Iustin Pop
    """Run the allocator based on input opcode.
3224 538475ca Iustin Pop

3225 538475ca Iustin Pop
    """
3226 538475ca Iustin Pop
    disks = [{"size": self.op.disk_size, "mode": "w"},
3227 538475ca Iustin Pop
             {"size": self.op.swap_size, "mode": "w"}]
3228 538475ca Iustin Pop
    nics = [{"mac": self.op.mac, "ip": getattr(self.op, "ip", None),
3229 538475ca Iustin Pop
             "bridge": self.op.bridge}]
3230 d1c2dd75 Iustin Pop
    ial = IAllocator(self.cfg, self.sstore,
3231 29859cb7 Iustin Pop
                     mode=constants.IALLOCATOR_MODE_ALLOC,
3232 d1c2dd75 Iustin Pop
                     name=self.op.instance_name,
3233 d1c2dd75 Iustin Pop
                     disk_template=self.op.disk_template,
3234 d1c2dd75 Iustin Pop
                     tags=[],
3235 d1c2dd75 Iustin Pop
                     os=self.op.os_type,
3236 d1c2dd75 Iustin Pop
                     vcpus=self.op.vcpus,
3237 d1c2dd75 Iustin Pop
                     mem_size=self.op.mem_size,
3238 d1c2dd75 Iustin Pop
                     disks=disks,
3239 d1c2dd75 Iustin Pop
                     nics=nics,
3240 29859cb7 Iustin Pop
                     )
3241 d1c2dd75 Iustin Pop
3242 d1c2dd75 Iustin Pop
    ial.Run(self.op.iallocator)
3243 d1c2dd75 Iustin Pop
3244 d1c2dd75 Iustin Pop
    if not ial.success:
3245 538475ca Iustin Pop
      raise errors.OpPrereqError("Can't compute nodes using"
3246 538475ca Iustin Pop
                                 " iallocator '%s': %s" % (self.op.iallocator,
3247 d1c2dd75 Iustin Pop
                                                           ial.info))
3248 27579978 Iustin Pop
    if len(ial.nodes) != ial.required_nodes:
3249 538475ca Iustin Pop
      raise errors.OpPrereqError("iallocator '%s' returned invalid number"
3250 538475ca Iustin Pop
                                 " of nodes (%s), required %s" %
3251 27579978 Iustin Pop
                                 (len(ial.nodes), ial.required_nodes))
3252 d1c2dd75 Iustin Pop
    self.op.pnode = ial.nodes[0]
3253 538475ca Iustin Pop
    logger.ToStdout("Selected nodes for the instance: %s" %
3254 d1c2dd75 Iustin Pop
                    (", ".join(ial.nodes),))
3255 538475ca Iustin Pop
    logger.Info("Selected nodes for instance %s via iallocator %s: %s" %
3256 d1c2dd75 Iustin Pop
                (self.op.instance_name, self.op.iallocator, ial.nodes))
3257 27579978 Iustin Pop
    if ial.required_nodes == 2:
3258 d1c2dd75 Iustin Pop
      self.op.snode = ial.nodes[1]
3259 538475ca Iustin Pop
3260 a8083063 Iustin Pop
  def BuildHooksEnv(self):
3261 a8083063 Iustin Pop
    """Build hooks env.
3262 a8083063 Iustin Pop

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

3265 a8083063 Iustin Pop
    """
3266 a8083063 Iustin Pop
    env = {
3267 396e1b78 Michael Hanselmann
      "INSTANCE_DISK_TEMPLATE": self.op.disk_template,
3268 396e1b78 Michael Hanselmann
      "INSTANCE_DISK_SIZE": self.op.disk_size,
3269 396e1b78 Michael Hanselmann
      "INSTANCE_SWAP_SIZE": self.op.swap_size,
3270 a8083063 Iustin Pop
      "INSTANCE_ADD_MODE": self.op.mode,
3271 a8083063 Iustin Pop
      }
3272 a8083063 Iustin Pop
    if self.op.mode == constants.INSTANCE_IMPORT:
3273 396e1b78 Michael Hanselmann
      env["INSTANCE_SRC_NODE"] = self.op.src_node
3274 396e1b78 Michael Hanselmann
      env["INSTANCE_SRC_PATH"] = self.op.src_path
3275 396e1b78 Michael Hanselmann
      env["INSTANCE_SRC_IMAGE"] = self.src_image
3276 396e1b78 Michael Hanselmann
3277 396e1b78 Michael Hanselmann
    env.update(_BuildInstanceHookEnv(name=self.op.instance_name,
3278 396e1b78 Michael Hanselmann
      primary_node=self.op.pnode,
3279 396e1b78 Michael Hanselmann
      secondary_nodes=self.secondaries,
3280 396e1b78 Michael Hanselmann
      status=self.instance_status,
3281 ecb215b5 Michael Hanselmann
      os_type=self.op.os_type,
3282 396e1b78 Michael Hanselmann
      memory=self.op.mem_size,
3283 396e1b78 Michael Hanselmann
      vcpus=self.op.vcpus,
3284 c7b27e9e Iustin Pop
      nics=[(self.inst_ip, self.op.bridge, self.op.mac)],
3285 396e1b78 Michael Hanselmann
    ))
3286 a8083063 Iustin Pop
3287 880478f8 Iustin Pop
    nl = ([self.sstore.GetMasterNode(), self.op.pnode] +
3288 a8083063 Iustin Pop
          self.secondaries)
3289 a8083063 Iustin Pop
    return env, nl, nl
3290 a8083063 Iustin Pop
3291 a8083063 Iustin Pop
3292 a8083063 Iustin Pop
  def CheckPrereq(self):
3293 a8083063 Iustin Pop
    """Check prerequisites.
3294 a8083063 Iustin Pop

3295 a8083063 Iustin Pop
    """
3296 538475ca Iustin Pop
    # set optional parameters to none if they don't exist
3297 538475ca Iustin Pop
    for attr in ["kernel_path", "initrd_path", "hvm_boot_order", "pnode",
3298 31a853d2 Iustin Pop
                 "iallocator", "hvm_acpi", "hvm_pae", "hvm_cdrom_image_path",
3299 31a853d2 Iustin Pop
                 "vnc_bind_address"]:
3300 40ed12dd Guido Trotter
      if not hasattr(self.op, attr):
3301 40ed12dd Guido Trotter
        setattr(self.op, attr, None)
3302 40ed12dd Guido Trotter
3303 a8083063 Iustin Pop
    if self.op.mode not in (constants.INSTANCE_CREATE,
3304 a8083063 Iustin Pop
                            constants.INSTANCE_IMPORT):
3305 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Invalid instance creation mode '%s'" %
3306 3ecf6786 Iustin Pop
                                 self.op.mode)
3307 a8083063 Iustin Pop
3308 eedc99de Manuel Franceschini
    if (not self.cfg.GetVGName() and
3309 eedc99de Manuel Franceschini
        self.op.disk_template not in constants.DTS_NOT_LVM):
3310 eedc99de Manuel Franceschini
      raise errors.OpPrereqError("Cluster does not support lvm-based"
3311 eedc99de Manuel Franceschini
                                 " instances")
3312 eedc99de Manuel Franceschini
3313 a8083063 Iustin Pop
    if self.op.mode == constants.INSTANCE_IMPORT:
3314 a8083063 Iustin Pop
      src_node = getattr(self.op, "src_node", None)
3315 a8083063 Iustin Pop
      src_path = getattr(self.op, "src_path", None)
3316 a8083063 Iustin Pop
      if src_node is None or src_path is None:
3317 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Importing an instance requires source"
3318 3ecf6786 Iustin Pop
                                   " node and path options")
3319 a8083063 Iustin Pop
      src_node_full = self.cfg.ExpandNodeName(src_node)
3320 a8083063 Iustin Pop
      if src_node_full is None:
3321 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Unknown source node '%s'" % src_node)
3322 a8083063 Iustin Pop
      self.op.src_node = src_node = src_node_full
3323 a8083063 Iustin Pop
3324 a8083063 Iustin Pop
      if not os.path.isabs(src_path):
3325 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("The source path must be absolute")
3326 a8083063 Iustin Pop
3327 a8083063 Iustin Pop
      export_info = rpc.call_export_info(src_node, src_path)
3328 a8083063 Iustin Pop
3329 a8083063 Iustin Pop
      if not export_info:
3330 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("No export found in dir %s" % src_path)
3331 a8083063 Iustin Pop
3332 a8083063 Iustin Pop
      if not export_info.has_section(constants.INISECT_EXP):
3333 3ecf6786 Iustin Pop
        raise errors.ProgrammerError("Corrupted export config")
3334 a8083063 Iustin Pop
3335 a8083063 Iustin Pop
      ei_version = export_info.get(constants.INISECT_EXP, 'version')
3336 a8083063 Iustin Pop
      if (int(ei_version) != constants.EXPORT_VERSION):
3337 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Wrong export version %s (wanted %d)" %
3338 3ecf6786 Iustin Pop
                                   (ei_version, constants.EXPORT_VERSION))
3339 a8083063 Iustin Pop
3340 a8083063 Iustin Pop
      if int(export_info.get(constants.INISECT_INS, 'disk_count')) > 1:
3341 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Can't import instance with more than"
3342 3ecf6786 Iustin Pop
                                   " one data disk")
3343 a8083063 Iustin Pop
3344 a8083063 Iustin Pop
      # FIXME: are the old os-es, disk sizes, etc. useful?
3345 a8083063 Iustin Pop
      self.op.os_type = export_info.get(constants.INISECT_EXP, 'os')
3346 a8083063 Iustin Pop
      diskimage = os.path.join(src_path, export_info.get(constants.INISECT_INS,
3347 a8083063 Iustin Pop
                                                         'disk0_dump'))
3348 a8083063 Iustin Pop
      self.src_image = diskimage
3349 a8083063 Iustin Pop
    else: # INSTANCE_CREATE
3350 a8083063 Iustin Pop
      if getattr(self.op, "os_type", None) is None:
3351 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("No guest OS specified")
3352 a8083063 Iustin Pop
3353 901a65c1 Iustin Pop
    #### instance parameters check
3354 901a65c1 Iustin Pop
3355 a8083063 Iustin Pop
    # disk template and mirror node verification
3356 a8083063 Iustin Pop
    if self.op.disk_template not in constants.DISK_TEMPLATES:
3357 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Invalid disk template name")
3358 a8083063 Iustin Pop
3359 901a65c1 Iustin Pop
    # instance name verification
3360 901a65c1 Iustin Pop
    hostname1 = utils.HostInfo(self.op.instance_name)
3361 901a65c1 Iustin Pop
3362 901a65c1 Iustin Pop
    self.op.instance_name = instance_name = hostname1.name
3363 901a65c1 Iustin Pop
    instance_list = self.cfg.GetInstanceList()
3364 901a65c1 Iustin Pop
    if instance_name in instance_list:
3365 901a65c1 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' is already in the cluster" %
3366 901a65c1 Iustin Pop
                                 instance_name)
3367 901a65c1 Iustin Pop
3368 901a65c1 Iustin Pop
    # ip validity checks
3369 901a65c1 Iustin Pop
    ip = getattr(self.op, "ip", None)
3370 901a65c1 Iustin Pop
    if ip is None or ip.lower() == "none":
3371 901a65c1 Iustin Pop
      inst_ip = None
3372 901a65c1 Iustin Pop
    elif ip.lower() == "auto":
3373 901a65c1 Iustin Pop
      inst_ip = hostname1.ip
3374 901a65c1 Iustin Pop
    else:
3375 901a65c1 Iustin Pop
      if not utils.IsValidIP(ip):
3376 901a65c1 Iustin Pop
        raise errors.OpPrereqError("given IP address '%s' doesn't look"
3377 901a65c1 Iustin Pop
                                   " like a valid IP" % ip)
3378 901a65c1 Iustin Pop
      inst_ip = ip
3379 901a65c1 Iustin Pop
    self.inst_ip = self.op.ip = inst_ip
3380 901a65c1 Iustin Pop
3381 901a65c1 Iustin Pop
    if self.op.start and not self.op.ip_check:
3382 901a65c1 Iustin Pop
      raise errors.OpPrereqError("Cannot ignore IP address conflicts when"
3383 901a65c1 Iustin Pop
                                 " adding an instance in start mode")
3384 901a65c1 Iustin Pop
3385 901a65c1 Iustin Pop
    if self.op.ip_check:
3386 901a65c1 Iustin Pop
      if utils.TcpPing(hostname1.ip, constants.DEFAULT_NODED_PORT):
3387 901a65c1 Iustin Pop
        raise errors.OpPrereqError("IP %s of instance %s already in use" %
3388 901a65c1 Iustin Pop
                                   (hostname1.ip, instance_name))
3389 901a65c1 Iustin Pop
3390 901a65c1 Iustin Pop
    # MAC address verification
3391 901a65c1 Iustin Pop
    if self.op.mac != "auto":
3392 901a65c1 Iustin Pop
      if not utils.IsValidMac(self.op.mac.lower()):
3393 901a65c1 Iustin Pop
        raise errors.OpPrereqError("invalid MAC address specified: %s" %
3394 901a65c1 Iustin Pop
                                   self.op.mac)
3395 901a65c1 Iustin Pop
3396 901a65c1 Iustin Pop
    # bridge verification
3397 901a65c1 Iustin Pop
    bridge = getattr(self.op, "bridge", None)
3398 901a65c1 Iustin Pop
    if bridge is None:
3399 901a65c1 Iustin Pop
      self.op.bridge = self.cfg.GetDefBridge()
3400 901a65c1 Iustin Pop
    else:
3401 901a65c1 Iustin Pop
      self.op.bridge = bridge
3402 901a65c1 Iustin Pop
3403 901a65c1 Iustin Pop
    # boot order verification
3404 901a65c1 Iustin Pop
    if self.op.hvm_boot_order is not None:
3405 901a65c1 Iustin Pop
      if len(self.op.hvm_boot_order.strip("acdn")) != 0:
3406 901a65c1 Iustin Pop
        raise errors.OpPrereqError("invalid boot order specified,"
3407 901a65c1 Iustin Pop
                                   " must be one or more of [acdn]")
3408 901a65c1 Iustin Pop
    # file storage checks
3409 0f1a06e3 Manuel Franceschini
    if (self.op.file_driver and
3410 0f1a06e3 Manuel Franceschini
        not self.op.file_driver in constants.FILE_DRIVER):
3411 0f1a06e3 Manuel Franceschini
      raise errors.OpPrereqError("Invalid file driver name '%s'" %
3412 0f1a06e3 Manuel Franceschini
                                 self.op.file_driver)
3413 0f1a06e3 Manuel Franceschini
3414 0f1a06e3 Manuel Franceschini
    if self.op.file_storage_dir and os.path.isabs(self.op.file_storage_dir):
3415 b4de68a9 Iustin Pop
      raise errors.OpPrereqError("File storage directory not a relative"
3416 b4de68a9 Iustin Pop
                                 " path")
3417 538475ca Iustin Pop
    #### allocator run
3418 538475ca Iustin Pop
3419 538475ca Iustin Pop
    if [self.op.iallocator, self.op.pnode].count(None) != 1:
3420 538475ca Iustin Pop
      raise errors.OpPrereqError("One and only one of iallocator and primary"
3421 538475ca Iustin Pop
                                 " node must be given")
3422 538475ca Iustin Pop
3423 538475ca Iustin Pop
    if self.op.iallocator is not None:
3424 538475ca Iustin Pop
      self._RunAllocator()
3425 0f1a06e3 Manuel Franceschini
3426 901a65c1 Iustin Pop
    #### node related checks
3427 901a65c1 Iustin Pop
3428 901a65c1 Iustin Pop
    # check primary node
3429 901a65c1 Iustin Pop
    pnode = self.cfg.GetNodeInfo(self.cfg.ExpandNodeName(self.op.pnode))
3430 901a65c1 Iustin Pop
    if pnode is None:
3431 901a65c1 Iustin Pop
      raise errors.OpPrereqError("Primary node '%s' is unknown" %
3432 901a65c1 Iustin Pop
                                 self.op.pnode)
3433 901a65c1 Iustin Pop
    self.op.pnode = pnode.name
3434 901a65c1 Iustin Pop
    self.pnode = pnode
3435 901a65c1 Iustin Pop
    self.secondaries = []
3436 901a65c1 Iustin Pop
3437 901a65c1 Iustin Pop
    # mirror node verification
3438 a1f445d3 Iustin Pop
    if self.op.disk_template in constants.DTS_NET_MIRROR:
3439 a8083063 Iustin Pop
      if getattr(self.op, "snode", None) is None:
3440 a1f445d3 Iustin Pop
        raise errors.OpPrereqError("The networked disk templates need"
3441 3ecf6786 Iustin Pop
                                   " a mirror node")
3442 a8083063 Iustin Pop
3443 a8083063 Iustin Pop
      snode_name = self.cfg.ExpandNodeName(self.op.snode)
3444 a8083063 Iustin Pop
      if snode_name is None:
3445 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Unknown secondary node '%s'" %
3446 3ecf6786 Iustin Pop
                                   self.op.snode)
3447 a8083063 Iustin Pop
      elif snode_name == pnode.name:
3448 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("The secondary node cannot be"
3449 3ecf6786 Iustin Pop
                                   " the primary node.")
3450 a8083063 Iustin Pop
      self.secondaries.append(snode_name)
3451 a8083063 Iustin Pop
3452 e2fe6369 Iustin Pop
    req_size = _ComputeDiskSize(self.op.disk_template,
3453 e2fe6369 Iustin Pop
                                self.op.disk_size, self.op.swap_size)
3454 ed1ebc60 Guido Trotter
3455 8d75db10 Iustin Pop
    # Check lv size requirements
3456 8d75db10 Iustin Pop
    if req_size is not None:
3457 8d75db10 Iustin Pop
      nodenames = [pnode.name] + self.secondaries
3458 8d75db10 Iustin Pop
      nodeinfo = rpc.call_node_info(nodenames, self.cfg.GetVGName())
3459 8d75db10 Iustin Pop
      for node in nodenames:
3460 8d75db10 Iustin Pop
        info = nodeinfo.get(node, None)
3461 8d75db10 Iustin Pop
        if not info:
3462 8d75db10 Iustin Pop
          raise errors.OpPrereqError("Cannot get current information"
3463 8d75db10 Iustin Pop
                                     " from node '%s'" % nodeinfo)
3464 8d75db10 Iustin Pop
        vg_free = info.get('vg_free', None)
3465 8d75db10 Iustin Pop
        if not isinstance(vg_free, int):
3466 8d75db10 Iustin Pop
          raise errors.OpPrereqError("Can't compute free disk space on"
3467 8d75db10 Iustin Pop
                                     " node %s" % node)
3468 8d75db10 Iustin Pop
        if req_size > info['vg_free']:
3469 8d75db10 Iustin Pop
          raise errors.OpPrereqError("Not enough disk space on target node %s."
3470 8d75db10 Iustin Pop
                                     " %d MB available, %d MB required" %
3471 8d75db10 Iustin Pop
                                     (node, info['vg_free'], req_size))
3472 ed1ebc60 Guido Trotter
3473 a8083063 Iustin Pop
    # os verification
3474 00fe9e38 Guido Trotter
    os_obj = rpc.call_os_get(pnode.name, self.op.os_type)
3475 dfa96ded Guido Trotter
    if not os_obj:
3476 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("OS '%s' not in supported os list for"
3477 3ecf6786 Iustin Pop
                                 " primary node"  % self.op.os_type)
3478 a8083063 Iustin Pop
3479 3b6d8c9b Iustin Pop
    if self.op.kernel_path == constants.VALUE_NONE:
3480 3b6d8c9b Iustin Pop
      raise errors.OpPrereqError("Can't set instance kernel to none")
3481 3b6d8c9b Iustin Pop
3482 a8083063 Iustin Pop
3483 901a65c1 Iustin Pop
    # bridge check on primary node
3484 a8083063 Iustin Pop
    if not rpc.call_bridges_exist(self.pnode.name, [self.op.bridge]):
3485 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("target bridge '%s' does not exist on"
3486 3ecf6786 Iustin Pop
                                 " destination node '%s'" %
3487 3ecf6786 Iustin Pop
                                 (self.op.bridge, pnode.name))
3488 a8083063 Iustin Pop
3489 49ce1563 Iustin Pop
    # memory check on primary node
3490 49ce1563 Iustin Pop
    if self.op.start:
3491 49ce1563 Iustin Pop
      _CheckNodeFreeMemory(self.cfg, self.pnode.name,
3492 49ce1563 Iustin Pop
                           "creating instance %s" % self.op.instance_name,
3493 49ce1563 Iustin Pop
                           self.op.mem_size)
3494 49ce1563 Iustin Pop
3495 31a853d2 Iustin Pop
    # hvm_cdrom_image_path verification
3496 31a853d2 Iustin Pop
    if self.op.hvm_cdrom_image_path is not None:
3497 31a853d2 Iustin Pop
      if not os.path.isabs(self.op.hvm_cdrom_image_path):
3498 31a853d2 Iustin Pop
        raise errors.OpPrereqError("The path to the HVM CDROM image must"
3499 31a853d2 Iustin Pop
                                   " be an absolute path or None, not %s" %
3500 31a853d2 Iustin Pop
                                   self.op.hvm_cdrom_image_path)
3501 31a853d2 Iustin Pop
      if not os.path.isfile(self.op.hvm_cdrom_image_path):
3502 31a853d2 Iustin Pop
        raise errors.OpPrereqError("The HVM CDROM image must either be a"
3503 31a853d2 Iustin Pop
                                   " regular file or a symlink pointing to"
3504 31a853d2 Iustin Pop
                                   " an existing regular file, not %s" %
3505 31a853d2 Iustin Pop
                                   self.op.hvm_cdrom_image_path)
3506 31a853d2 Iustin Pop
3507 31a853d2 Iustin Pop
    # vnc_bind_address verification
3508 31a853d2 Iustin Pop
    if self.op.vnc_bind_address is not None:
3509 31a853d2 Iustin Pop
      if not utils.IsValidIP(self.op.vnc_bind_address):
3510 31a853d2 Iustin Pop
        raise errors.OpPrereqError("given VNC bind address '%s' doesn't look"
3511 31a853d2 Iustin Pop
                                   " like a valid IP address" %
3512 31a853d2 Iustin Pop
                                   self.op.vnc_bind_address)
3513 31a853d2 Iustin Pop
3514 a8083063 Iustin Pop
    if self.op.start:
3515 a8083063 Iustin Pop
      self.instance_status = 'up'
3516 a8083063 Iustin Pop
    else:
3517 a8083063 Iustin Pop
      self.instance_status = 'down'
3518 a8083063 Iustin Pop
3519 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
3520 a8083063 Iustin Pop
    """Create and add the instance to the cluster.
3521 a8083063 Iustin Pop

3522 a8083063 Iustin Pop
    """
3523 a8083063 Iustin Pop
    instance = self.op.instance_name
3524 a8083063 Iustin Pop
    pnode_name = self.pnode.name
3525 a8083063 Iustin Pop
3526 1862d460 Alexander Schreiber
    if self.op.mac == "auto":
3527 ba4b62cf Iustin Pop
      mac_address = self.cfg.GenerateMAC()
3528 1862d460 Alexander Schreiber
    else:
3529 ba4b62cf Iustin Pop
      mac_address = self.op.mac
3530 1862d460 Alexander Schreiber
3531 1862d460 Alexander Schreiber
    nic = objects.NIC(bridge=self.op.bridge, mac=mac_address)
3532 a8083063 Iustin Pop
    if self.inst_ip is not None:
3533 a8083063 Iustin Pop
      nic.ip = self.inst_ip
3534 a8083063 Iustin Pop
3535 2a6469d5 Alexander Schreiber
    ht_kind = self.sstore.GetHypervisorType()
3536 2a6469d5 Alexander Schreiber
    if ht_kind in constants.HTS_REQ_PORT:
3537 2a6469d5 Alexander Schreiber
      network_port = self.cfg.AllocatePort()
3538 2a6469d5 Alexander Schreiber
    else:
3539 2a6469d5 Alexander Schreiber
      network_port = None
3540 58acb49d Alexander Schreiber
3541 31a853d2 Iustin Pop
    if self.op.vnc_bind_address is None:
3542 31a853d2 Iustin Pop
      self.op.vnc_bind_address = constants.VNC_DEFAULT_BIND_ADDRESS
3543 31a853d2 Iustin Pop
3544 2c313123 Manuel Franceschini
    # this is needed because os.path.join does not accept None arguments
3545 2c313123 Manuel Franceschini
    if self.op.file_storage_dir is None:
3546 2c313123 Manuel Franceschini
      string_file_storage_dir = ""
3547 2c313123 Manuel Franceschini
    else:
3548 2c313123 Manuel Franceschini
      string_file_storage_dir = self.op.file_storage_dir
3549 2c313123 Manuel Franceschini
3550 0f1a06e3 Manuel Franceschini
    # build the full file storage dir path
3551 0f1a06e3 Manuel Franceschini
    file_storage_dir = os.path.normpath(os.path.join(
3552 0f1a06e3 Manuel Franceschini
                                        self.sstore.GetFileStorageDir(),
3553 2c313123 Manuel Franceschini
                                        string_file_storage_dir, instance))
3554 0f1a06e3 Manuel Franceschini
3555 0f1a06e3 Manuel Franceschini
3556 923b1523 Iustin Pop
    disks = _GenerateDiskTemplate(self.cfg,
3557 a8083063 Iustin Pop
                                  self.op.disk_template,
3558 a8083063 Iustin Pop
                                  instance, pnode_name,
3559 a8083063 Iustin Pop
                                  self.secondaries, self.op.disk_size,
3560 0f1a06e3 Manuel Franceschini
                                  self.op.swap_size,
3561 0f1a06e3 Manuel Franceschini
                                  file_storage_dir,
3562 0f1a06e3 Manuel Franceschini
                                  self.op.file_driver)
3563 a8083063 Iustin Pop
3564 a8083063 Iustin Pop
    iobj = objects.Instance(name=instance, os=self.op.os_type,
3565 a8083063 Iustin Pop
                            primary_node=pnode_name,
3566 a8083063 Iustin Pop
                            memory=self.op.mem_size,
3567 a8083063 Iustin Pop
                            vcpus=self.op.vcpus,
3568 a8083063 Iustin Pop
                            nics=[nic], disks=disks,
3569 a8083063 Iustin Pop
                            disk_template=self.op.disk_template,
3570 a8083063 Iustin Pop
                            status=self.instance_status,
3571 58acb49d Alexander Schreiber
                            network_port=network_port,
3572 3b6d8c9b Iustin Pop
                            kernel_path=self.op.kernel_path,
3573 3b6d8c9b Iustin Pop
                            initrd_path=self.op.initrd_path,
3574 25c5878d Alexander Schreiber
                            hvm_boot_order=self.op.hvm_boot_order,
3575 31a853d2 Iustin Pop
                            hvm_acpi=self.op.hvm_acpi,
3576 31a853d2 Iustin Pop
                            hvm_pae=self.op.hvm_pae,
3577 31a853d2 Iustin Pop
                            hvm_cdrom_image_path=self.op.hvm_cdrom_image_path,
3578 31a853d2 Iustin Pop
                            vnc_bind_address=self.op.vnc_bind_address,
3579 a8083063 Iustin Pop
                            )
3580 a8083063 Iustin Pop
3581 a8083063 Iustin Pop
    feedback_fn("* creating instance disks...")
3582 a8083063 Iustin Pop
    if not _CreateDisks(self.cfg, iobj):
3583 a8083063 Iustin Pop
      _RemoveDisks(iobj, self.cfg)
3584 3ecf6786 Iustin Pop
      raise errors.OpExecError("Device creation failed, reverting...")
3585 a8083063 Iustin Pop
3586 a8083063 Iustin Pop
    feedback_fn("adding instance %s to cluster config" % instance)
3587 a8083063 Iustin Pop
3588 a8083063 Iustin Pop
    self.cfg.AddInstance(iobj)
3589 a8083063 Iustin Pop
3590 a8083063 Iustin Pop
    if self.op.wait_for_sync:
3591 5bfac263 Iustin Pop
      disk_abort = not _WaitForSync(self.cfg, iobj, self.proc)
3592 a1f445d3 Iustin Pop
    elif iobj.disk_template in constants.DTS_NET_MIRROR:
3593 a8083063 Iustin Pop
      # make sure the disks are not degraded (still sync-ing is ok)
3594 a8083063 Iustin Pop
      time.sleep(15)
3595 a8083063 Iustin Pop
      feedback_fn("* checking mirrors status")
3596 5bfac263 Iustin Pop
      disk_abort = not _WaitForSync(self.cfg, iobj, self.proc, oneshot=True)
3597 a8083063 Iustin Pop
    else:
3598 a8083063 Iustin Pop
      disk_abort = False
3599 a8083063 Iustin Pop
3600 a8083063 Iustin Pop
    if disk_abort:
3601 a8083063 Iustin Pop
      _RemoveDisks(iobj, self.cfg)
3602 a8083063 Iustin Pop
      self.cfg.RemoveInstance(iobj.name)
3603 3ecf6786 Iustin Pop
      raise errors.OpExecError("There are some degraded disks for"
3604 3ecf6786 Iustin Pop
                               " this instance")
3605 a8083063 Iustin Pop
3606 a8083063 Iustin Pop
    feedback_fn("creating os for instance %s on node %s" %
3607 a8083063 Iustin Pop
                (instance, pnode_name))
3608 a8083063 Iustin Pop
3609 a8083063 Iustin Pop
    if iobj.disk_template != constants.DT_DISKLESS:
3610 a8083063 Iustin Pop
      if self.op.mode == constants.INSTANCE_CREATE:
3611 a8083063 Iustin Pop
        feedback_fn("* running the instance OS create scripts...")
3612 a8083063 Iustin Pop
        if not rpc.call_instance_os_add(pnode_name, iobj, "sda", "sdb"):
3613 3ecf6786 Iustin Pop
          raise errors.OpExecError("could not add os for instance %s"
3614 3ecf6786 Iustin Pop
                                   " on node %s" %
3615 3ecf6786 Iustin Pop
                                   (instance, pnode_name))
3616 a8083063 Iustin Pop
3617 a8083063 Iustin Pop
      elif self.op.mode == constants.INSTANCE_IMPORT:
3618 a8083063 Iustin Pop
        feedback_fn("* running the instance OS import scripts...")
3619 a8083063 Iustin Pop
        src_node = self.op.src_node
3620 a8083063 Iustin Pop
        src_image = self.src_image
3621 a8083063 Iustin Pop
        if not rpc.call_instance_os_import(pnode_name, iobj, "sda", "sdb",
3622 a8083063 Iustin Pop
                                                src_node, src_image):
3623 3ecf6786 Iustin Pop
          raise errors.OpExecError("Could not import os for instance"
3624 3ecf6786 Iustin Pop
                                   " %s on node %s" %
3625 3ecf6786 Iustin Pop
                                   (instance, pnode_name))
3626 a8083063 Iustin Pop
      else:
3627 a8083063 Iustin Pop
        # also checked in the prereq part
3628 3ecf6786 Iustin Pop
        raise errors.ProgrammerError("Unknown OS initialization mode '%s'"
3629 3ecf6786 Iustin Pop
                                     % self.op.mode)
3630 a8083063 Iustin Pop
3631 a8083063 Iustin Pop
    if self.op.start:
3632 a8083063 Iustin Pop
      logger.Info("starting instance %s on node %s" % (instance, pnode_name))
3633 a8083063 Iustin Pop
      feedback_fn("* starting instance...")
3634 a8083063 Iustin Pop
      if not rpc.call_instance_start(pnode_name, iobj, None):
3635 3ecf6786 Iustin Pop
        raise errors.OpExecError("Could not start instance")
3636 a8083063 Iustin Pop
3637 a8083063 Iustin Pop
3638 a8083063 Iustin Pop
class LUConnectConsole(NoHooksLU):
3639 a8083063 Iustin Pop
  """Connect to an instance's console.
3640 a8083063 Iustin Pop

3641 a8083063 Iustin Pop
  This is somewhat special in that it returns the command line that
3642 a8083063 Iustin Pop
  you need to run on the master node in order to connect to the
3643 a8083063 Iustin Pop
  console.
3644 a8083063 Iustin Pop

3645 a8083063 Iustin Pop
  """
3646 a8083063 Iustin Pop
  _OP_REQP = ["instance_name"]
3647 a8083063 Iustin Pop
3648 a8083063 Iustin Pop
  def CheckPrereq(self):
3649 a8083063 Iustin Pop
    """Check prerequisites.
3650 a8083063 Iustin Pop

3651 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
3652 a8083063 Iustin Pop

3653 a8083063 Iustin Pop
    """
3654 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
3655 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
3656 a8083063 Iustin Pop
    if instance is None:
3657 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
3658 3ecf6786 Iustin Pop
                                 self.op.instance_name)
3659 a8083063 Iustin Pop
    self.instance = instance
3660 a8083063 Iustin Pop
3661 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
3662 a8083063 Iustin Pop
    """Connect to the console of an instance
3663 a8083063 Iustin Pop

3664 a8083063 Iustin Pop
    """
3665 a8083063 Iustin Pop
    instance = self.instance
3666 a8083063 Iustin Pop
    node = instance.primary_node
3667 a8083063 Iustin Pop
3668 a8083063 Iustin Pop
    node_insts = rpc.call_instance_list([node])[node]
3669 a8083063 Iustin Pop
    if node_insts is False:
3670 3ecf6786 Iustin Pop
      raise errors.OpExecError("Can't connect to node %s." % node)
3671 a8083063 Iustin Pop
3672 a8083063 Iustin Pop
    if instance.name not in node_insts:
3673 3ecf6786 Iustin Pop
      raise errors.OpExecError("Instance %s is not running." % instance.name)
3674 a8083063 Iustin Pop
3675 a8083063 Iustin Pop
    logger.Debug("connecting to console of %s on %s" % (instance.name, node))
3676 a8083063 Iustin Pop
3677 a8083063 Iustin Pop
    hyper = hypervisor.GetHypervisor()
3678 30989e69 Alexander Schreiber
    console_cmd = hyper.GetShellCommandForConsole(instance)
3679 b047857b Michael Hanselmann
3680 82122173 Iustin Pop
    # build ssh cmdline
3681 0a80a26f Michael Hanselmann
    return self.ssh.BuildCmd(node, "root", console_cmd, batch=True, tty=True)
3682 a8083063 Iustin Pop
3683 a8083063 Iustin Pop
3684 a8083063 Iustin Pop
class LUReplaceDisks(LogicalUnit):
3685 a8083063 Iustin Pop
  """Replace the disks of an instance.
3686 a8083063 Iustin Pop

3687 a8083063 Iustin Pop
  """
3688 a8083063 Iustin Pop
  HPATH = "mirrors-replace"
3689 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
3690 a9e0c397 Iustin Pop
  _OP_REQP = ["instance_name", "mode", "disks"]
3691 a8083063 Iustin Pop
3692 b6e82a65 Iustin Pop
  def _RunAllocator(self):
3693 b6e82a65 Iustin Pop
    """Compute a new secondary node using an IAllocator.
3694 b6e82a65 Iustin Pop

3695 b6e82a65 Iustin Pop
    """
3696 b6e82a65 Iustin Pop
    ial = IAllocator(self.cfg, self.sstore,
3697 b6e82a65 Iustin Pop
                     mode=constants.IALLOCATOR_MODE_RELOC,
3698 b6e82a65 Iustin Pop
                     name=self.op.instance_name,
3699 b6e82a65 Iustin Pop
                     relocate_from=[self.sec_node])
3700 b6e82a65 Iustin Pop
3701 b6e82a65 Iustin Pop
    ial.Run(self.op.iallocator)
3702 b6e82a65 Iustin Pop
3703 b6e82a65 Iustin Pop
    if not ial.success:
3704 b6e82a65 Iustin Pop
      raise errors.OpPrereqError("Can't compute nodes using"
3705 b6e82a65 Iustin Pop
                                 " iallocator '%s': %s" % (self.op.iallocator,
3706 b6e82a65 Iustin Pop
                                                           ial.info))
3707 b6e82a65 Iustin Pop
    if len(ial.nodes) != ial.required_nodes:
3708 b6e82a65 Iustin Pop
      raise errors.OpPrereqError("iallocator '%s' returned invalid number"
3709 b6e82a65 Iustin Pop
                                 " of nodes (%s), required %s" %
3710 b6e82a65 Iustin Pop
                                 (len(ial.nodes), ial.required_nodes))
3711 b6e82a65 Iustin Pop
    self.op.remote_node = ial.nodes[0]
3712 b6e82a65 Iustin Pop
    logger.ToStdout("Selected new secondary for the instance: %s" %
3713 b6e82a65 Iustin Pop
                    self.op.remote_node)
3714 b6e82a65 Iustin Pop
3715 a8083063 Iustin Pop
  def BuildHooksEnv(self):
3716 a8083063 Iustin Pop
    """Build hooks env.
3717 a8083063 Iustin Pop

3718 a8083063 Iustin Pop
    This runs on the master, the primary and all the secondaries.
3719 a8083063 Iustin Pop

3720 a8083063 Iustin Pop
    """
3721 a8083063 Iustin Pop
    env = {
3722 a9e0c397 Iustin Pop
      "MODE": self.op.mode,
3723 a8083063 Iustin Pop
      "NEW_SECONDARY": self.op.remote_node,
3724 a8083063 Iustin Pop
      "OLD_SECONDARY": self.instance.secondary_nodes[0],
3725 a8083063 Iustin Pop
      }
3726 396e1b78 Michael Hanselmann
    env.update(_BuildInstanceHookEnvByObject(self.instance))
3727 0834c866 Iustin Pop
    nl = [
3728 0834c866 Iustin Pop
      self.sstore.GetMasterNode(),
3729 0834c866 Iustin Pop
      self.instance.primary_node,
3730 0834c866 Iustin Pop
      ]
3731 0834c866 Iustin Pop
    if self.op.remote_node is not None:
3732 0834c866 Iustin Pop
      nl.append(self.op.remote_node)
3733 a8083063 Iustin Pop
    return env, nl, nl
3734 a8083063 Iustin Pop
3735 a8083063 Iustin Pop
  def CheckPrereq(self):
3736 a8083063 Iustin Pop
    """Check prerequisites.
3737 a8083063 Iustin Pop

3738 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
3739 a8083063 Iustin Pop

3740 a8083063 Iustin Pop
    """
3741 b6e82a65 Iustin Pop
    if not hasattr(self.op, "remote_node"):
3742 b6e82a65 Iustin Pop
      self.op.remote_node = None
3743 b6e82a65 Iustin Pop
3744 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
3745 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
3746 a8083063 Iustin Pop
    if instance is None:
3747 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
3748 3ecf6786 Iustin Pop
                                 self.op.instance_name)
3749 a8083063 Iustin Pop
    self.instance = instance
3750 7df43a76 Iustin Pop
    self.op.instance_name = instance.name
3751 a8083063 Iustin Pop
3752 a9e0c397 Iustin Pop
    if instance.disk_template not in constants.DTS_NET_MIRROR:
3753 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance's disk layout is not"
3754 a9e0c397 Iustin Pop
                                 " network mirrored.")
3755 a8083063 Iustin Pop
3756 a8083063 Iustin Pop
    if len(instance.secondary_nodes) != 1:
3757 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("The instance has a strange layout,"
3758 3ecf6786 Iustin Pop
                                 " expected one secondary but found %d" %
3759 3ecf6786 Iustin Pop
                                 len(instance.secondary_nodes))
3760 a8083063 Iustin Pop
3761 a9e0c397 Iustin Pop
    self.sec_node = instance.secondary_nodes[0]
3762 a9e0c397 Iustin Pop
3763 b6e82a65 Iustin Pop
    ia_name = getattr(self.op, "iallocator", None)
3764 b6e82a65 Iustin Pop
    if ia_name is not None:
3765 b6e82a65 Iustin Pop
      if self.op.remote_node is not None:
3766 b6e82a65 Iustin Pop
        raise errors.OpPrereqError("Give either the iallocator or the new"
3767 b6e82a65 Iustin Pop
                                   " secondary, not both")
3768 b6e82a65 Iustin Pop
      self.op.remote_node = self._RunAllocator()
3769 b6e82a65 Iustin Pop
3770 b6e82a65 Iustin Pop
    remote_node = self.op.remote_node
3771 a9e0c397 Iustin Pop
    if remote_node is not None:
3772 a8083063 Iustin Pop
      remote_node = self.cfg.ExpandNodeName(remote_node)
3773 a8083063 Iustin Pop
      if remote_node is None:
3774 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Node '%s' not known" %
3775 3ecf6786 Iustin Pop
                                   self.op.remote_node)
3776 a9e0c397 Iustin Pop
      self.remote_node_info = self.cfg.GetNodeInfo(remote_node)
3777 a9e0c397 Iustin Pop
    else:
3778 a9e0c397 Iustin Pop
      self.remote_node_info = None
3779 a8083063 Iustin Pop
    if remote_node == instance.primary_node:
3780 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("The specified node is the primary node of"
3781 3ecf6786 Iustin Pop
                                 " the instance.")
3782 a9e0c397 Iustin Pop
    elif remote_node == self.sec_node:
3783 0834c866 Iustin Pop
      if self.op.mode == constants.REPLACE_DISK_SEC:
3784 0834c866 Iustin Pop
        # this is for DRBD8, where we can't execute the same mode of
3785 0834c866 Iustin Pop
        # replacement as for drbd7 (no different port allocated)
3786 0834c866 Iustin Pop
        raise errors.OpPrereqError("Same secondary given, cannot execute"
3787 0834c866 Iustin Pop
                                   " replacement")
3788 a9e0c397 Iustin Pop
    if instance.disk_template == constants.DT_DRBD8:
3789 7df43a76 Iustin Pop
      if (self.op.mode == constants.REPLACE_DISK_ALL and
3790 7df43a76 Iustin Pop
          remote_node is not None):
3791 7df43a76 Iustin Pop
        # switch to replace secondary mode
3792 7df43a76 Iustin Pop
        self.op.mode = constants.REPLACE_DISK_SEC
3793 7df43a76 Iustin Pop
3794 a9e0c397 Iustin Pop
      if self.op.mode == constants.REPLACE_DISK_ALL:
3795 12c3449a Michael Hanselmann
        raise errors.OpPrereqError("Template 'drbd' only allows primary or"
3796 a9e0c397 Iustin Pop
                                   " secondary disk replacement, not"
3797 a9e0c397 Iustin Pop
                                   " both at once")
3798 a9e0c397 Iustin Pop
      elif self.op.mode == constants.REPLACE_DISK_PRI:
3799 a9e0c397 Iustin Pop
        if remote_node is not None:
3800 12c3449a Michael Hanselmann
          raise errors.OpPrereqError("Template 'drbd' does not allow changing"
3801 a9e0c397 Iustin Pop
                                     " the secondary while doing a primary"
3802 a9e0c397 Iustin Pop
                                     " node disk replacement")
3803 a9e0c397 Iustin Pop
        self.tgt_node = instance.primary_node
3804 cff90b79 Iustin Pop
        self.oth_node = instance.secondary_nodes[0]
3805 a9e0c397 Iustin Pop
      elif self.op.mode == constants.REPLACE_DISK_SEC:
3806 a9e0c397 Iustin Pop
        self.new_node = remote_node # this can be None, in which case
3807 a9e0c397 Iustin Pop
                                    # we don't change the secondary
3808 a9e0c397 Iustin Pop
        self.tgt_node = instance.secondary_nodes[0]
3809 cff90b79 Iustin Pop
        self.oth_node = instance.primary_node
3810 a9e0c397 Iustin Pop
      else:
3811 a9e0c397 Iustin Pop
        raise errors.ProgrammerError("Unhandled disk replace mode")
3812 a9e0c397 Iustin Pop
3813 a9e0c397 Iustin Pop
    for name in self.op.disks:
3814 a9e0c397 Iustin Pop
      if instance.FindDisk(name) is None:
3815 a9e0c397 Iustin Pop
        raise errors.OpPrereqError("Disk '%s' not found for instance '%s'" %
3816 a9e0c397 Iustin Pop
                                   (name, instance.name))
3817 a8083063 Iustin Pop
    self.op.remote_node = remote_node
3818 a8083063 Iustin Pop
3819 a9e0c397 Iustin Pop
  def _ExecD8DiskOnly(self, feedback_fn):
3820 a9e0c397 Iustin Pop
    """Replace a disk on the primary or secondary for dbrd8.
3821 a9e0c397 Iustin Pop

3822 a9e0c397 Iustin Pop
    The algorithm for replace is quite complicated:
3823 a9e0c397 Iustin Pop
      - for each disk to be replaced:
3824 a9e0c397 Iustin Pop
        - create new LVs on the target node with unique names
3825 a9e0c397 Iustin Pop
        - detach old LVs from the drbd device
3826 a9e0c397 Iustin Pop
        - rename old LVs to name_replaced.<time_t>
3827 a9e0c397 Iustin Pop
        - rename new LVs to old LVs
3828 a9e0c397 Iustin Pop
        - attach the new LVs (with the old names now) to the drbd device
3829 a9e0c397 Iustin Pop
      - wait for sync across all devices
3830 a9e0c397 Iustin Pop
      - for each modified disk:
3831 a9e0c397 Iustin Pop
        - remove old LVs (which have the name name_replaces.<time_t>)
3832 a9e0c397 Iustin Pop

3833 a9e0c397 Iustin Pop
    Failures are not very well handled.
3834 cff90b79 Iustin Pop

3835 a9e0c397 Iustin Pop
    """
3836 cff90b79 Iustin Pop
    steps_total = 6
3837 5bfac263 Iustin Pop
    warning, info = (self.proc.LogWarning, self.proc.LogInfo)
3838 a9e0c397 Iustin Pop
    instance = self.instance
3839 a9e0c397 Iustin Pop
    iv_names = {}
3840 a9e0c397 Iustin Pop
    vgname = self.cfg.GetVGName()
3841 a9e0c397 Iustin Pop
    # start of work
3842 a9e0c397 Iustin Pop
    cfg = self.cfg
3843 a9e0c397 Iustin Pop
    tgt_node = self.tgt_node
3844 cff90b79 Iustin Pop
    oth_node = self.oth_node
3845 cff90b79 Iustin Pop
3846 cff90b79 Iustin Pop
    # Step: check device activation
3847 5bfac263 Iustin Pop
    self.proc.LogStep(1, steps_total, "check device existence")
3848 cff90b79 Iustin Pop
    info("checking volume groups")
3849 cff90b79 Iustin Pop
    my_vg = cfg.GetVGName()
3850 cff90b79 Iustin Pop
    results = rpc.call_vg_list([oth_node, tgt_node])
3851 cff90b79 Iustin Pop
    if not results:
3852 cff90b79 Iustin Pop
      raise errors.OpExecError("Can't list volume groups on the nodes")
3853 cff90b79 Iustin Pop
    for node in oth_node, tgt_node:
3854 cff90b79 Iustin Pop
      res = results.get(node, False)
3855 cff90b79 Iustin Pop
      if not res or my_vg not in res:
3856 cff90b79 Iustin Pop
        raise errors.OpExecError("Volume group '%s' not found on %s" %
3857 cff90b79 Iustin Pop
                                 (my_vg, node))
3858 cff90b79 Iustin Pop
    for dev in instance.disks:
3859 cff90b79 Iustin Pop
      if not dev.iv_name in self.op.disks:
3860 cff90b79 Iustin Pop
        continue
3861 cff90b79 Iustin Pop
      for node in tgt_node, oth_node:
3862 cff90b79 Iustin Pop
        info("checking %s on %s" % (dev.iv_name, node))
3863 cff90b79 Iustin Pop
        cfg.SetDiskID(dev, node)
3864 cff90b79 Iustin Pop
        if not rpc.call_blockdev_find(node, dev):
3865 cff90b79 Iustin Pop
          raise errors.OpExecError("Can't find device %s on node %s" %
3866 cff90b79 Iustin Pop
                                   (dev.iv_name, node))
3867 cff90b79 Iustin Pop
3868 cff90b79 Iustin Pop
    # Step: check other node consistency
3869 5bfac263 Iustin Pop
    self.proc.LogStep(2, steps_total, "check peer consistency")
3870 cff90b79 Iustin Pop
    for dev in instance.disks:
3871 cff90b79 Iustin Pop
      if not dev.iv_name in self.op.disks:
3872 cff90b79 Iustin Pop
        continue
3873 cff90b79 Iustin Pop
      info("checking %s consistency on %s" % (dev.iv_name, oth_node))
3874 cff90b79 Iustin Pop
      if not _CheckDiskConsistency(self.cfg, dev, oth_node,
3875 cff90b79 Iustin Pop
                                   oth_node==instance.primary_node):
3876 cff90b79 Iustin Pop
        raise errors.OpExecError("Peer node (%s) has degraded storage, unsafe"
3877 cff90b79 Iustin Pop
                                 " to replace disks on this node (%s)" %
3878 cff90b79 Iustin Pop
                                 (oth_node, tgt_node))
3879 cff90b79 Iustin Pop
3880 cff90b79 Iustin Pop
    # Step: create new storage
3881 5bfac263 Iustin Pop
    self.proc.LogStep(3, steps_total, "allocate new storage")
3882 a9e0c397 Iustin Pop
    for dev in instance.disks:
3883 a9e0c397 Iustin Pop
      if not dev.iv_name in self.op.disks:
3884 a9e0c397 Iustin Pop
        continue
3885 a9e0c397 Iustin Pop
      size = dev.size
3886 a9e0c397 Iustin Pop
      cfg.SetDiskID(dev, tgt_node)
3887 a9e0c397 Iustin Pop
      lv_names = [".%s_%s" % (dev.iv_name, suf) for suf in ["data", "meta"]]
3888 a9e0c397 Iustin Pop
      names = _GenerateUniqueNames(cfg, lv_names)
3889 a9e0c397 Iustin Pop
      lv_data = objects.Disk(dev_type=constants.LD_LV, size=size,
3890 a9e0c397 Iustin Pop
                             logical_id=(vgname, names[0]))
3891 a9e0c397 Iustin Pop
      lv_meta = objects.Disk(dev_type=constants.LD_LV, size=128,
3892 a9e0c397 Iustin Pop
                             logical_id=(vgname, names[1]))
3893 a9e0c397 Iustin Pop
      new_lvs = [lv_data, lv_meta]
3894 a9e0c397 Iustin Pop
      old_lvs = dev.children
3895 a9e0c397 Iustin Pop
      iv_names[dev.iv_name] = (dev, old_lvs, new_lvs)
3896 cff90b79 Iustin Pop
      info("creating new local storage on %s for %s" %
3897 cff90b79 Iustin Pop
           (tgt_node, dev.iv_name))
3898 a9e0c397 Iustin Pop
      # since we *always* want to create this LV, we use the
3899 a9e0c397 Iustin Pop
      # _Create...OnPrimary (which forces the creation), even if we
3900 a9e0c397 Iustin Pop
      # are talking about the secondary node
3901 a9e0c397 Iustin Pop
      for new_lv in new_lvs:
3902 3f78eef2 Iustin Pop
        if not _CreateBlockDevOnPrimary(cfg, tgt_node, instance, new_lv,
3903 a9e0c397 Iustin Pop
                                        _GetInstanceInfoText(instance)):
3904 a9e0c397 Iustin Pop
          raise errors.OpExecError("Failed to create new LV named '%s' on"
3905 a9e0c397 Iustin Pop
                                   " node '%s'" %
3906 a9e0c397 Iustin Pop
                                   (new_lv.logical_id[1], tgt_node))
3907 a9e0c397 Iustin Pop
3908 cff90b79 Iustin Pop
    # Step: for each lv, detach+rename*2+attach
3909 5bfac263 Iustin Pop
    self.proc.LogStep(4, steps_total, "change drbd configuration")
3910 cff90b79 Iustin Pop
    for dev, old_lvs, new_lvs in iv_names.itervalues():
3911 cff90b79 Iustin Pop
      info("detaching %s drbd from local storage" % dev.iv_name)
3912 a9e0c397 Iustin Pop
      if not rpc.call_blockdev_removechildren(tgt_node, dev, old_lvs):
3913 a9e0c397 Iustin Pop
        raise errors.OpExecError("Can't detach drbd from local storage on node"
3914 a9e0c397 Iustin Pop
                                 " %s for device %s" % (tgt_node, dev.iv_name))
3915 cff90b79 Iustin Pop
      #dev.children = []
3916 cff90b79 Iustin Pop
      #cfg.Update(instance)
3917 a9e0c397 Iustin Pop
3918 a9e0c397 Iustin Pop
      # ok, we created the new LVs, so now we know we have the needed
3919 a9e0c397 Iustin Pop
      # storage; as such, we proceed on the target node to rename
3920 a9e0c397 Iustin Pop
      # old_lv to _old, and new_lv to old_lv; note that we rename LVs
3921 c99a3cc0 Manuel Franceschini
      # using the assumption that logical_id == physical_id (which in
3922 a9e0c397 Iustin Pop
      # turn is the unique_id on that node)
3923 cff90b79 Iustin Pop
3924 cff90b79 Iustin Pop
      # FIXME(iustin): use a better name for the replaced LVs
3925 a9e0c397 Iustin Pop
      temp_suffix = int(time.time())
3926 a9e0c397 Iustin Pop
      ren_fn = lambda d, suff: (d.physical_id[0],
3927 a9e0c397 Iustin Pop
                                d.physical_id[1] + "_replaced-%s" % suff)
3928 cff90b79 Iustin Pop
      # build the rename list based on what LVs exist on the node
3929 cff90b79 Iustin Pop
      rlist = []
3930 cff90b79 Iustin Pop
      for to_ren in old_lvs:
3931 cff90b79 Iustin Pop
        find_res = rpc.call_blockdev_find(tgt_node, to_ren)
3932 cff90b79 Iustin Pop
        if find_res is not None: # device exists
3933 cff90b79 Iustin Pop
          rlist.append((to_ren, ren_fn(to_ren, temp_suffix)))
3934 cff90b79 Iustin Pop
3935 cff90b79 Iustin Pop
      info("renaming the old LVs on the target node")
3936 a9e0c397 Iustin Pop
      if not rpc.call_blockdev_rename(tgt_node, rlist):
3937 cff90b79 Iustin Pop
        raise errors.OpExecError("Can't rename old LVs on node %s" % tgt_node)
3938 a9e0c397 Iustin Pop
      # now we rename the new LVs to the old LVs
3939 cff90b79 Iustin Pop
      info("renaming the new LVs on the target node")
3940 a9e0c397 Iustin Pop
      rlist = [(new, old.physical_id) for old, new in zip(old_lvs, new_lvs)]
3941 a9e0c397 Iustin Pop
      if not rpc.call_blockdev_rename(tgt_node, rlist):
3942 cff90b79 Iustin Pop
        raise errors.OpExecError("Can't rename new LVs on node %s" % tgt_node)
3943 cff90b79 Iustin Pop
3944 cff90b79 Iustin Pop
      for old, new in zip(old_lvs, new_lvs):
3945 cff90b79 Iustin Pop
        new.logical_id = old.logical_id
3946 cff90b79 Iustin Pop
        cfg.SetDiskID(new, tgt_node)
3947 a9e0c397 Iustin Pop
3948 cff90b79 Iustin Pop
      for disk in old_lvs:
3949 cff90b79 Iustin Pop
        disk.logical_id = ren_fn(disk, temp_suffix)
3950 cff90b79 Iustin Pop
        cfg.SetDiskID(disk, tgt_node)
3951 a9e0c397 Iustin Pop
3952 a9e0c397 Iustin Pop
      # now that the new lvs have the old name, we can add them to the device
3953 cff90b79 Iustin Pop
      info("adding new mirror component on %s" % tgt_node)
3954 a9e0c397 Iustin Pop
      if not rpc.call_blockdev_addchildren(tgt_node, dev, new_lvs):
3955 a9e0c397 Iustin Pop
        for new_lv in new_lvs:
3956 a9e0c397 Iustin Pop
          if not rpc.call_blockdev_remove(tgt_node, new_lv):
3957 79caa9ed Guido Trotter
            warning("Can't rollback device %s", hint="manually cleanup unused"
3958 cff90b79 Iustin Pop
                    " logical volumes")
3959 cff90b79 Iustin Pop
        raise errors.OpExecError("Can't add local storage to drbd")
3960 a9e0c397 Iustin Pop
3961 a9e0c397 Iustin Pop
      dev.children = new_lvs
3962 a9e0c397 Iustin Pop
      cfg.Update(instance)
3963 a9e0c397 Iustin Pop
3964 cff90b79 Iustin Pop
    # Step: wait for sync
3965 a9e0c397 Iustin Pop
3966 a9e0c397 Iustin Pop
    # this can fail as the old devices are degraded and _WaitForSync
3967 a9e0c397 Iustin Pop
    # does a combined result over all disks, so we don't check its
3968 a9e0c397 Iustin Pop
    # return value
3969 5bfac263 Iustin Pop
    self.proc.LogStep(5, steps_total, "sync devices")
3970 5bfac263 Iustin Pop
    _WaitForSync(cfg, instance, self.proc, unlock=True)
3971 a9e0c397 Iustin Pop
3972 a9e0c397 Iustin Pop
    # so check manually all the devices
3973 a9e0c397 Iustin Pop
    for name, (dev, old_lvs, new_lvs) in iv_names.iteritems():
3974 a9e0c397 Iustin Pop
      cfg.SetDiskID(dev, instance.primary_node)
3975 a9e0c397 Iustin Pop
      is_degr = rpc.call_blockdev_find(instance.primary_node, dev)[5]
3976 a9e0c397 Iustin Pop
      if is_degr:
3977 a9e0c397 Iustin Pop
        raise errors.OpExecError("DRBD device %s is degraded!" % name)
3978 a9e0c397 Iustin Pop
3979 cff90b79 Iustin Pop
    # Step: remove old storage
3980 5bfac263 Iustin Pop
    self.proc.LogStep(6, steps_total, "removing old storage")
3981 a9e0c397 Iustin Pop
    for name, (dev, old_lvs, new_lvs) in iv_names.iteritems():
3982 cff90b79 Iustin Pop
      info("remove logical volumes for %s" % name)
3983 a9e0c397 Iustin Pop
      for lv in old_lvs:
3984 a9e0c397 Iustin Pop
        cfg.SetDiskID(lv, tgt_node)
3985 a9e0c397 Iustin Pop
        if not rpc.call_blockdev_remove(tgt_node, lv):
3986 79caa9ed Guido Trotter
          warning("Can't remove old LV", hint="manually remove unused LVs")
3987 a9e0c397 Iustin Pop
          continue
3988 a9e0c397 Iustin Pop
3989 a9e0c397 Iustin Pop
  def _ExecD8Secondary(self, feedback_fn):
3990 a9e0c397 Iustin Pop
    """Replace the secondary node for drbd8.
3991 a9e0c397 Iustin Pop

3992 a9e0c397 Iustin Pop
    The algorithm for replace is quite complicated:
3993 a9e0c397 Iustin Pop
      - for all disks of the instance:
3994 a9e0c397 Iustin Pop
        - create new LVs on the new node with same names
3995 a9e0c397 Iustin Pop
        - shutdown the drbd device on the old secondary
3996 a9e0c397 Iustin Pop
        - disconnect the drbd network on the primary
3997 a9e0c397 Iustin Pop
        - create the drbd device on the new secondary
3998 a9e0c397 Iustin Pop
        - network attach the drbd on the primary, using an artifice:
3999 a9e0c397 Iustin Pop
          the drbd code for Attach() will connect to the network if it
4000 a9e0c397 Iustin Pop
          finds a device which is connected to the good local disks but
4001 a9e0c397 Iustin Pop
          not network enabled
4002 a9e0c397 Iustin Pop
      - wait for sync across all devices
4003 a9e0c397 Iustin Pop
      - remove all disks from the old secondary
4004 a9e0c397 Iustin Pop

4005 a9e0c397 Iustin Pop
    Failures are not very well handled.
4006 0834c866 Iustin Pop

4007 a9e0c397 Iustin Pop
    """
4008 0834c866 Iustin Pop
    steps_total = 6
4009 5bfac263 Iustin Pop
    warning, info = (self.proc.LogWarning, self.proc.LogInfo)
4010 a9e0c397 Iustin Pop
    instance = self.instance
4011 a9e0c397 Iustin Pop
    iv_names = {}
4012 a9e0c397 Iustin Pop
    vgname = self.cfg.GetVGName()
4013 a9e0c397 Iustin Pop
    # start of work
4014 a9e0c397 Iustin Pop
    cfg = self.cfg
4015 a9e0c397 Iustin Pop
    old_node = self.tgt_node
4016 a9e0c397 Iustin Pop
    new_node = self.new_node
4017 a9e0c397 Iustin Pop
    pri_node = instance.primary_node
4018 0834c866 Iustin Pop
4019 0834c866 Iustin Pop
    # Step: check device activation
4020 5bfac263 Iustin Pop
    self.proc.LogStep(1, steps_total, "check device existence")
4021 0834c866 Iustin Pop
    info("checking volume groups")
4022 0834c866 Iustin Pop
    my_vg = cfg.GetVGName()
4023 0834c866 Iustin Pop
    results = rpc.call_vg_list([pri_node, new_node])
4024 0834c866 Iustin Pop
    if not results:
4025 0834c866 Iustin Pop
      raise errors.OpExecError("Can't list volume groups on the nodes")
4026 0834c866 Iustin Pop
    for node in pri_node, new_node:
4027 0834c866 Iustin Pop
      res = results.get(node, False)
4028 0834c866 Iustin Pop
      if not res or my_vg not in res:
4029 0834c866 Iustin Pop
        raise errors.OpExecError("Volume group '%s' not found on %s" %
4030 0834c866 Iustin Pop
                                 (my_vg, node))
4031 0834c866 Iustin Pop
    for dev in instance.disks:
4032 0834c866 Iustin Pop
      if not dev.iv_name in self.op.disks:
4033 0834c866 Iustin Pop
        continue
4034 0834c866 Iustin Pop
      info("checking %s on %s" % (dev.iv_name, pri_node))
4035 0834c866 Iustin Pop
      cfg.SetDiskID(dev, pri_node)
4036 0834c866 Iustin Pop
      if not rpc.call_blockdev_find(pri_node, dev):
4037 0834c866 Iustin Pop
        raise errors.OpExecError("Can't find device %s on node %s" %
4038 0834c866 Iustin Pop
                                 (dev.iv_name, pri_node))
4039 0834c866 Iustin Pop
4040 0834c866 Iustin Pop
    # Step: check other node consistency
4041 5bfac263 Iustin Pop
    self.proc.LogStep(2, steps_total, "check peer consistency")
4042 0834c866 Iustin Pop
    for dev in instance.disks:
4043 0834c866 Iustin Pop
      if not dev.iv_name in self.op.disks:
4044 0834c866 Iustin Pop
        continue
4045 0834c866 Iustin Pop
      info("checking %s consistency on %s" % (dev.iv_name, pri_node))
4046 0834c866 Iustin Pop
      if not _CheckDiskConsistency(self.cfg, dev, pri_node, True, ldisk=True):
4047 0834c866 Iustin Pop
        raise errors.OpExecError("Primary node (%s) has degraded storage,"
4048 0834c866 Iustin Pop
                                 " unsafe to replace the secondary" %
4049 0834c866 Iustin Pop
                                 pri_node)
4050 0834c866 Iustin Pop
4051 0834c866 Iustin Pop
    # Step: create new storage
4052 5bfac263 Iustin Pop
    self.proc.LogStep(3, steps_total, "allocate new storage")
4053 a9e0c397 Iustin Pop
    for dev in instance.disks:
4054 a9e0c397 Iustin Pop
      size = dev.size
4055 0834c866 Iustin Pop
      info("adding new local storage on %s for %s" % (new_node, dev.iv_name))
4056 a9e0c397 Iustin Pop
      # since we *always* want to create this LV, we use the
4057 a9e0c397 Iustin Pop
      # _Create...OnPrimary (which forces the creation), even if we
4058 a9e0c397 Iustin Pop
      # are talking about the secondary node
4059 a9e0c397 Iustin Pop
      for new_lv in dev.children:
4060 3f78eef2 Iustin Pop
        if not _CreateBlockDevOnPrimary(cfg, new_node, instance, new_lv,
4061 a9e0c397 Iustin Pop
                                        _GetInstanceInfoText(instance)):
4062 a9e0c397 Iustin Pop
          raise errors.OpExecError("Failed to create new LV named '%s' on"
4063 a9e0c397 Iustin Pop
                                   " node '%s'" %
4064 a9e0c397 Iustin Pop
                                   (new_lv.logical_id[1], new_node))
4065 a9e0c397 Iustin Pop
4066 0834c866 Iustin Pop
      iv_names[dev.iv_name] = (dev, dev.children)
4067 0834c866 Iustin Pop
4068 5bfac263 Iustin Pop
    self.proc.LogStep(4, steps_total, "changing drbd configuration")
4069 0834c866 Iustin Pop
    for dev in instance.disks:
4070 0834c866 Iustin Pop
      size = dev.size
4071 0834c866 Iustin Pop
      info("activating a new drbd on %s for %s" % (new_node, dev.iv_name))
4072 a9e0c397 Iustin Pop
      # create new devices on new_node
4073 a9e0c397 Iustin Pop
      new_drbd = objects.Disk(dev_type=constants.LD_DRBD8,
4074 a9e0c397 Iustin Pop
                              logical_id=(pri_node, new_node,
4075 a9e0c397 Iustin Pop
                                          dev.logical_id[2]),
4076 a9e0c397 Iustin Pop
                              children=dev.children)
4077 3f78eef2 Iustin Pop
      if not _CreateBlockDevOnSecondary(cfg, new_node, instance,
4078 3f78eef2 Iustin Pop
                                        new_drbd, False,
4079 a9e0c397 Iustin Pop
                                      _GetInstanceInfoText(instance)):
4080 a9e0c397 Iustin Pop
        raise errors.OpExecError("Failed to create new DRBD on"
4081 a9e0c397 Iustin Pop
                                 " node '%s'" % new_node)
4082 a9e0c397 Iustin Pop
4083 0834c866 Iustin Pop
    for dev in instance.disks:
4084 a9e0c397 Iustin Pop
      # we have new devices, shutdown the drbd on the old secondary
4085 0834c866 Iustin Pop
      info("shutting down drbd for %s on old node" % dev.iv_name)
4086 a9e0c397 Iustin Pop
      cfg.SetDiskID(dev, old_node)
4087 a9e0c397 Iustin Pop
      if not rpc.call_blockdev_shutdown(old_node, dev):
4088 0834c866 Iustin Pop
        warning("Failed to shutdown drbd for %s on old node" % dev.iv_name,
4089 79caa9ed Guido Trotter
                hint="Please cleanup this device manually as soon as possible")
4090 a9e0c397 Iustin Pop
4091 642445d9 Iustin Pop
    info("detaching primary drbds from the network (=> standalone)")
4092 642445d9 Iustin Pop
    done = 0
4093 642445d9 Iustin Pop
    for dev in instance.disks:
4094 a9e0c397 Iustin Pop
      cfg.SetDiskID(dev, pri_node)
4095 642445d9 Iustin Pop
      # set the physical (unique in bdev terms) id to None, meaning
4096 642445d9 Iustin Pop
      # detach from network
4097 642445d9 Iustin Pop
      dev.physical_id = (None,) * len(dev.physical_id)
4098 642445d9 Iustin Pop
      # and 'find' the device, which will 'fix' it to match the
4099 642445d9 Iustin Pop
      # standalone state
4100 642445d9 Iustin Pop
      if rpc.call_blockdev_find(pri_node, dev):
4101 642445d9 Iustin Pop
        done += 1
4102 642445d9 Iustin Pop
      else:
4103 642445d9 Iustin Pop
        warning("Failed to detach drbd %s from network, unusual case" %
4104 642445d9 Iustin Pop
                dev.iv_name)
4105 642445d9 Iustin Pop
4106 642445d9 Iustin Pop
    if not done:
4107 642445d9 Iustin Pop
      # no detaches succeeded (very unlikely)
4108 642445d9 Iustin Pop
      raise errors.OpExecError("Can't detach at least one DRBD from old node")
4109 642445d9 Iustin Pop
4110 642445d9 Iustin Pop
    # if we managed to detach at least one, we update all the disks of
4111 642445d9 Iustin Pop
    # the instance to point to the new secondary
4112 642445d9 Iustin Pop
    info("updating instance configuration")
4113 642445d9 Iustin Pop
    for dev in instance.disks:
4114 642445d9 Iustin Pop
      dev.logical_id = (pri_node, new_node) + dev.logical_id[2:]
4115 a9e0c397 Iustin Pop
      cfg.SetDiskID(dev, pri_node)
4116 642445d9 Iustin Pop
    cfg.Update(instance)
4117 a9e0c397 Iustin Pop
4118 642445d9 Iustin Pop
    # and now perform the drbd attach
4119 642445d9 Iustin Pop
    info("attaching primary drbds to new secondary (standalone => connected)")
4120 642445d9 Iustin Pop
    failures = []
4121 642445d9 Iustin Pop
    for dev in instance.disks:
4122 642445d9 Iustin Pop
      info("attaching primary drbd for %s to new secondary node" % dev.iv_name)
4123 642445d9 Iustin Pop
      # since the attach is smart, it's enough to 'find' the device,
4124 642445d9 Iustin Pop
      # it will automatically activate the network, if the physical_id
4125 642445d9 Iustin Pop
      # is correct
4126 642445d9 Iustin Pop
      cfg.SetDiskID(dev, pri_node)
4127 642445d9 Iustin Pop
      if not rpc.call_blockdev_find(pri_node, dev):
4128 642445d9 Iustin Pop
        warning("can't attach drbd %s to new secondary!" % dev.iv_name,
4129 642445d9 Iustin Pop
                "please do a gnt-instance info to see the status of disks")
4130 a9e0c397 Iustin Pop
4131 a9e0c397 Iustin Pop
    # this can fail as the old devices are degraded and _WaitForSync
4132 a9e0c397 Iustin Pop
    # does a combined result over all disks, so we don't check its
4133 a9e0c397 Iustin Pop
    # return value
4134 5bfac263 Iustin Pop
    self.proc.LogStep(5, steps_total, "sync devices")
4135 5bfac263 Iustin Pop
    _WaitForSync(cfg, instance, self.proc, unlock=True)
4136 a9e0c397 Iustin Pop
4137 a9e0c397 Iustin Pop
    # so check manually all the devices
4138 a9e0c397 Iustin Pop
    for name, (dev, old_lvs) in iv_names.iteritems():
4139 a9e0c397 Iustin Pop
      cfg.SetDiskID(dev, pri_node)
4140 a9e0c397 Iustin Pop
      is_degr = rpc.call_blockdev_find(pri_node, dev)[5]
4141 a9e0c397 Iustin Pop
      if is_degr:
4142 a9e0c397 Iustin Pop
        raise errors.OpExecError("DRBD device %s is degraded!" % name)
4143 a9e0c397 Iustin Pop
4144 5bfac263 Iustin Pop
    self.proc.LogStep(6, steps_total, "removing old storage")
4145 a9e0c397 Iustin Pop
    for name, (dev, old_lvs) in iv_names.iteritems():
4146 0834c866 Iustin Pop
      info("remove logical volumes for %s" % name)
4147 a9e0c397 Iustin Pop
      for lv in old_lvs:
4148 a9e0c397 Iustin Pop
        cfg.SetDiskID(lv, old_node)
4149 a9e0c397 Iustin Pop
        if not rpc.call_blockdev_remove(old_node, lv):
4150 0834c866 Iustin Pop
          warning("Can't remove LV on old secondary",
4151 79caa9ed Guido Trotter
                  hint="Cleanup stale volumes by hand")
4152 a9e0c397 Iustin Pop
4153 a9e0c397 Iustin Pop
  def Exec(self, feedback_fn):
4154 a9e0c397 Iustin Pop
    """Execute disk replacement.
4155 a9e0c397 Iustin Pop

4156 a9e0c397 Iustin Pop
    This dispatches the disk replacement to the appropriate handler.
4157 a9e0c397 Iustin Pop

4158 a9e0c397 Iustin Pop
    """
4159 a9e0c397 Iustin Pop
    instance = self.instance
4160 abdf0113 Iustin Pop
    if instance.disk_template == constants.DT_DRBD8:
4161 a9e0c397 Iustin Pop
      if self.op.remote_node is None:
4162 a9e0c397 Iustin Pop
        fn = self._ExecD8DiskOnly
4163 a9e0c397 Iustin Pop
      else:
4164 a9e0c397 Iustin Pop
        fn = self._ExecD8Secondary
4165 a9e0c397 Iustin Pop
    else:
4166 a9e0c397 Iustin Pop
      raise errors.ProgrammerError("Unhandled disk replacement case")
4167 a9e0c397 Iustin Pop
    return fn(feedback_fn)
4168 a9e0c397 Iustin Pop
4169 a8083063 Iustin Pop
4170 a8083063 Iustin Pop
class LUQueryInstanceData(NoHooksLU):
4171 a8083063 Iustin Pop
  """Query runtime instance data.
4172 a8083063 Iustin Pop

4173 a8083063 Iustin Pop
  """
4174 a8083063 Iustin Pop
  _OP_REQP = ["instances"]
4175 a8083063 Iustin Pop
4176 a8083063 Iustin Pop
  def CheckPrereq(self):
4177 a8083063 Iustin Pop
    """Check prerequisites.
4178 a8083063 Iustin Pop

4179 a8083063 Iustin Pop
    This only checks the optional instance list against the existing names.
4180 a8083063 Iustin Pop

4181 a8083063 Iustin Pop
    """
4182 a8083063 Iustin Pop
    if not isinstance(self.op.instances, list):
4183 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Invalid argument type 'instances'")
4184 a8083063 Iustin Pop
    if self.op.instances:
4185 a8083063 Iustin Pop
      self.wanted_instances = []
4186 a8083063 Iustin Pop
      names = self.op.instances
4187 a8083063 Iustin Pop
      for name in names:
4188 a8083063 Iustin Pop
        instance = self.cfg.GetInstanceInfo(self.cfg.ExpandInstanceName(name))
4189 a8083063 Iustin Pop
        if instance is None:
4190 3ecf6786 Iustin Pop
          raise errors.OpPrereqError("No such instance name '%s'" % name)
4191 515207af Guido Trotter
        self.wanted_instances.append(instance)
4192 a8083063 Iustin Pop
    else:
4193 a8083063 Iustin Pop
      self.wanted_instances = [self.cfg.GetInstanceInfo(name) for name
4194 a8083063 Iustin Pop
                               in self.cfg.GetInstanceList()]
4195 a8083063 Iustin Pop
    return
4196 a8083063 Iustin Pop
4197 a8083063 Iustin Pop
4198 a8083063 Iustin Pop
  def _ComputeDiskStatus(self, instance, snode, dev):
4199 a8083063 Iustin Pop
    """Compute block device status.
4200 a8083063 Iustin Pop

4201 a8083063 Iustin Pop
    """
4202 a8083063 Iustin Pop
    self.cfg.SetDiskID(dev, instance.primary_node)
4203 a8083063 Iustin Pop
    dev_pstatus = rpc.call_blockdev_find(instance.primary_node, dev)
4204 a1f445d3 Iustin Pop
    if dev.dev_type in constants.LDS_DRBD:
4205 a8083063 Iustin Pop
      # we change the snode then (otherwise we use the one passed in)
4206 a8083063 Iustin Pop
      if dev.logical_id[0] == instance.primary_node:
4207 a8083063 Iustin Pop
        snode = dev.logical_id[1]
4208 a8083063 Iustin Pop
      else:
4209 a8083063 Iustin Pop
        snode = dev.logical_id[0]
4210 a8083063 Iustin Pop
4211 a8083063 Iustin Pop
    if snode:
4212 a8083063 Iustin Pop
      self.cfg.SetDiskID(dev, snode)
4213 a8083063 Iustin Pop
      dev_sstatus = rpc.call_blockdev_find(snode, dev)
4214 a8083063 Iustin Pop
    else:
4215 a8083063 Iustin Pop
      dev_sstatus = None
4216 a8083063 Iustin Pop
4217 a8083063 Iustin Pop
    if dev.children:
4218 a8083063 Iustin Pop
      dev_children = [self._ComputeDiskStatus(instance, snode, child)
4219 a8083063 Iustin Pop
                      for child in dev.children]
4220 a8083063 Iustin Pop
    else:
4221 a8083063 Iustin Pop
      dev_children = []
4222 a8083063 Iustin Pop
4223 a8083063 Iustin Pop
    data = {
4224 a8083063 Iustin Pop
      "iv_name": dev.iv_name,
4225 a8083063 Iustin Pop
      "dev_type": dev.dev_type,
4226 a8083063 Iustin Pop
      "logical_id": dev.logical_id,
4227 a8083063 Iustin Pop
      "physical_id": dev.physical_id,
4228 a8083063 Iustin Pop
      "pstatus": dev_pstatus,
4229 a8083063 Iustin Pop
      "sstatus": dev_sstatus,
4230 a8083063 Iustin Pop
      "children": dev_children,
4231 a8083063 Iustin Pop
      }
4232 a8083063 Iustin Pop
4233 a8083063 Iustin Pop
    return data
4234 a8083063 Iustin Pop
4235 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
4236 a8083063 Iustin Pop
    """Gather and return data"""
4237 a8083063 Iustin Pop
    result = {}
4238 a8083063 Iustin Pop
    for instance in self.wanted_instances:
4239 a8083063 Iustin Pop
      remote_info = rpc.call_instance_info(instance.primary_node,
4240 a8083063 Iustin Pop
                                                instance.name)
4241 a8083063 Iustin Pop
      if remote_info and "state" in remote_info:
4242 a8083063 Iustin Pop
        remote_state = "up"
4243 a8083063 Iustin Pop
      else:
4244 a8083063 Iustin Pop
        remote_state = "down"
4245 a8083063 Iustin Pop
      if instance.status == "down":
4246 a8083063 Iustin Pop
        config_state = "down"
4247 a8083063 Iustin Pop
      else:
4248 a8083063 Iustin Pop
        config_state = "up"
4249 a8083063 Iustin Pop
4250 a8083063 Iustin Pop
      disks = [self._ComputeDiskStatus(instance, None, device)
4251 a8083063 Iustin Pop
               for device in instance.disks]
4252 a8083063 Iustin Pop
4253 a8083063 Iustin Pop
      idict = {
4254 a8083063 Iustin Pop
        "name": instance.name,
4255 a8083063 Iustin Pop
        "config_state": config_state,
4256 a8083063 Iustin Pop
        "run_state": remote_state,
4257 a8083063 Iustin Pop
        "pnode": instance.primary_node,
4258 a8083063 Iustin Pop
        "snodes": instance.secondary_nodes,
4259 a8083063 Iustin Pop
        "os": instance.os,
4260 a8083063 Iustin Pop
        "memory": instance.memory,
4261 a8083063 Iustin Pop
        "nics": [(nic.mac, nic.ip, nic.bridge) for nic in instance.nics],
4262 a8083063 Iustin Pop
        "disks": disks,
4263 f55ff7ec Iustin Pop
        "vcpus": instance.vcpus,
4264 a8083063 Iustin Pop
        }
4265 a8083063 Iustin Pop
4266 a8340917 Iustin Pop
      htkind = self.sstore.GetHypervisorType()
4267 a8340917 Iustin Pop
      if htkind == constants.HT_XEN_PVM30:
4268 a8340917 Iustin Pop
        idict["kernel_path"] = instance.kernel_path
4269 a8340917 Iustin Pop
        idict["initrd_path"] = instance.initrd_path
4270 a8340917 Iustin Pop
4271 a8340917 Iustin Pop
      if htkind == constants.HT_XEN_HVM31:
4272 a8340917 Iustin Pop
        idict["hvm_boot_order"] = instance.hvm_boot_order
4273 a8340917 Iustin Pop
        idict["hvm_acpi"] = instance.hvm_acpi
4274 a8340917 Iustin Pop
        idict["hvm_pae"] = instance.hvm_pae
4275 a8340917 Iustin Pop
        idict["hvm_cdrom_image_path"] = instance.hvm_cdrom_image_path
4276 a8340917 Iustin Pop
4277 a8340917 Iustin Pop
      if htkind in constants.HTS_REQ_PORT:
4278 a8340917 Iustin Pop
        idict["vnc_bind_address"] = instance.vnc_bind_address
4279 a8340917 Iustin Pop
        idict["network_port"] = instance.network_port
4280 a8340917 Iustin Pop
4281 a8083063 Iustin Pop
      result[instance.name] = idict
4282 a8083063 Iustin Pop
4283 a8083063 Iustin Pop
    return result
4284 a8083063 Iustin Pop
4285 a8083063 Iustin Pop
4286 7767bbf5 Manuel Franceschini
class LUSetInstanceParams(LogicalUnit):
4287 a8083063 Iustin Pop
  """Modifies an instances's parameters.
4288 a8083063 Iustin Pop

4289 a8083063 Iustin Pop
  """
4290 a8083063 Iustin Pop
  HPATH = "instance-modify"
4291 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
4292 a8083063 Iustin Pop
  _OP_REQP = ["instance_name"]
4293 a8083063 Iustin Pop
4294 a8083063 Iustin Pop
  def BuildHooksEnv(self):
4295 a8083063 Iustin Pop
    """Build hooks env.
4296 a8083063 Iustin Pop

4297 a8083063 Iustin Pop
    This runs on the master, primary and secondaries.
4298 a8083063 Iustin Pop

4299 a8083063 Iustin Pop
    """
4300 396e1b78 Michael Hanselmann
    args = dict()
4301 a8083063 Iustin Pop
    if self.mem:
4302 396e1b78 Michael Hanselmann
      args['memory'] = self.mem
4303 a8083063 Iustin Pop
    if self.vcpus:
4304 396e1b78 Michael Hanselmann
      args['vcpus'] = self.vcpus
4305 ef756965 Iustin Pop
    if self.do_ip or self.do_bridge or self.mac:
4306 396e1b78 Michael Hanselmann
      if self.do_ip:
4307 396e1b78 Michael Hanselmann
        ip = self.ip
4308 396e1b78 Michael Hanselmann
      else:
4309 396e1b78 Michael Hanselmann
        ip = self.instance.nics[0].ip
4310 396e1b78 Michael Hanselmann
      if self.bridge:
4311 396e1b78 Michael Hanselmann
        bridge = self.bridge
4312 396e1b78 Michael Hanselmann
      else:
4313 396e1b78 Michael Hanselmann
        bridge = self.instance.nics[0].bridge
4314 ef756965 Iustin Pop
      if self.mac:
4315 ef756965 Iustin Pop
        mac = self.mac
4316 ef756965 Iustin Pop
      else:
4317 ef756965 Iustin Pop
        mac = self.instance.nics[0].mac
4318 ef756965 Iustin Pop
      args['nics'] = [(ip, bridge, mac)]
4319 396e1b78 Michael Hanselmann
    env = _BuildInstanceHookEnvByObject(self.instance, override=args)
4320 880478f8 Iustin Pop
    nl = [self.sstore.GetMasterNode(),
4321 a8083063 Iustin Pop
          self.instance.primary_node] + list(self.instance.secondary_nodes)
4322 a8083063 Iustin Pop
    return env, nl, nl
4323 a8083063 Iustin Pop
4324 a8083063 Iustin Pop
  def CheckPrereq(self):
4325 a8083063 Iustin Pop
    """Check prerequisites.
4326 a8083063 Iustin Pop

4327 a8083063 Iustin Pop
    This only checks the instance list against the existing names.
4328 a8083063 Iustin Pop

4329 a8083063 Iustin Pop
    """
4330 a8083063 Iustin Pop
    self.mem = getattr(self.op, "mem", None)
4331 a8083063 Iustin Pop
    self.vcpus = getattr(self.op, "vcpus", None)
4332 a8083063 Iustin Pop
    self.ip = getattr(self.op, "ip", None)
4333 1862d460 Alexander Schreiber
    self.mac = getattr(self.op, "mac", None)
4334 a8083063 Iustin Pop
    self.bridge = getattr(self.op, "bridge", None)
4335 973d7867 Iustin Pop
    self.kernel_path = getattr(self.op, "kernel_path", None)
4336 973d7867 Iustin Pop
    self.initrd_path = getattr(self.op, "initrd_path", None)
4337 25c5878d Alexander Schreiber
    self.hvm_boot_order = getattr(self.op, "hvm_boot_order", None)
4338 31a853d2 Iustin Pop
    self.hvm_acpi = getattr(self.op, "hvm_acpi", None)
4339 31a853d2 Iustin Pop
    self.hvm_pae = getattr(self.op, "hvm_pae", None)
4340 31a853d2 Iustin Pop
    self.hvm_cdrom_image_path = getattr(self.op, "hvm_cdrom_image_path", None)
4341 31a853d2 Iustin Pop
    self.vnc_bind_address = getattr(self.op, "vnc_bind_address", None)
4342 31a853d2 Iustin Pop
    all_parms = [self.mem, self.vcpus, self.ip, self.bridge, self.mac,
4343 31a853d2 Iustin Pop
                 self.kernel_path, self.initrd_path, self.hvm_boot_order,
4344 31a853d2 Iustin Pop
                 self.hvm_acpi, self.hvm_pae, self.hvm_cdrom_image_path,
4345 31a853d2 Iustin Pop
                 self.vnc_bind_address]
4346 31a853d2 Iustin Pop
    if all_parms.count(None) == len(all_parms):
4347 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("No changes submitted")
4348 a8083063 Iustin Pop
    if self.mem is not None:
4349 a8083063 Iustin Pop
      try:
4350 a8083063 Iustin Pop
        self.mem = int(self.mem)
4351 a8083063 Iustin Pop
      except ValueError, err:
4352 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Invalid memory size: %s" % str(err))
4353 a8083063 Iustin Pop
    if self.vcpus is not None:
4354 a8083063 Iustin Pop
      try:
4355 a8083063 Iustin Pop
        self.vcpus = int(self.vcpus)
4356 a8083063 Iustin Pop
      except ValueError, err:
4357 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Invalid vcpus number: %s" % str(err))
4358 a8083063 Iustin Pop
    if self.ip is not None:
4359 a8083063 Iustin Pop
      self.do_ip = True
4360 a8083063 Iustin Pop
      if self.ip.lower() == "none":
4361 a8083063 Iustin Pop
        self.ip = None
4362 a8083063 Iustin Pop
      else:
4363 a8083063 Iustin Pop
        if not utils.IsValidIP(self.ip):
4364 3ecf6786 Iustin Pop
          raise errors.OpPrereqError("Invalid IP address '%s'." % self.ip)
4365 a8083063 Iustin Pop
    else:
4366 a8083063 Iustin Pop
      self.do_ip = False
4367 ecb215b5 Michael Hanselmann
    self.do_bridge = (self.bridge is not None)
4368 1862d460 Alexander Schreiber
    if self.mac is not None:
4369 1862d460 Alexander Schreiber
      if self.cfg.IsMacInUse(self.mac):
4370 1862d460 Alexander Schreiber
        raise errors.OpPrereqError('MAC address %s already in use in cluster' %
4371 1862d460 Alexander Schreiber
                                   self.mac)
4372 1862d460 Alexander Schreiber
      if not utils.IsValidMac(self.mac):
4373 1862d460 Alexander Schreiber
        raise errors.OpPrereqError('Invalid MAC address %s' % self.mac)
4374 a8083063 Iustin Pop
4375 973d7867 Iustin Pop
    if self.kernel_path is not None:
4376 973d7867 Iustin Pop
      self.do_kernel_path = True
4377 973d7867 Iustin Pop
      if self.kernel_path == constants.VALUE_NONE:
4378 973d7867 Iustin Pop
        raise errors.OpPrereqError("Can't set instance to no kernel")
4379 973d7867 Iustin Pop
4380 973d7867 Iustin Pop
      if self.kernel_path != constants.VALUE_DEFAULT:
4381 973d7867 Iustin Pop
        if not os.path.isabs(self.kernel_path):
4382 ba4b62cf Iustin Pop
          raise errors.OpPrereqError("The kernel path must be an absolute"
4383 973d7867 Iustin Pop
                                    " filename")
4384 8cafeb26 Iustin Pop
    else:
4385 8cafeb26 Iustin Pop
      self.do_kernel_path = False
4386 973d7867 Iustin Pop
4387 973d7867 Iustin Pop
    if self.initrd_path is not None:
4388 973d7867 Iustin Pop
      self.do_initrd_path = True
4389 973d7867 Iustin Pop
      if self.initrd_path not in (constants.VALUE_NONE,
4390 973d7867 Iustin Pop
                                  constants.VALUE_DEFAULT):
4391 2bc22872 Iustin Pop
        if not os.path.isabs(self.initrd_path):
4392 ba4b62cf Iustin Pop
          raise errors.OpPrereqError("The initrd path must be an absolute"
4393 973d7867 Iustin Pop
                                    " filename")
4394 8cafeb26 Iustin Pop
    else:
4395 8cafeb26 Iustin Pop
      self.do_initrd_path = False
4396 973d7867 Iustin Pop
4397 25c5878d Alexander Schreiber
    # boot order verification
4398 25c5878d Alexander Schreiber
    if self.hvm_boot_order is not None:
4399 25c5878d Alexander Schreiber
      if self.hvm_boot_order != constants.VALUE_DEFAULT:
4400 25c5878d Alexander Schreiber
        if len(self.hvm_boot_order.strip("acdn")) != 0:
4401 25c5878d Alexander Schreiber
          raise errors.OpPrereqError("invalid boot order specified,"
4402 25c5878d Alexander Schreiber
                                     " must be one or more of [acdn]"
4403 25c5878d Alexander Schreiber
                                     " or 'default'")
4404 25c5878d Alexander Schreiber
4405 31a853d2 Iustin Pop
    # hvm_cdrom_image_path verification
4406 31a853d2 Iustin Pop
    if self.op.hvm_cdrom_image_path is not None:
4407 31a853d2 Iustin Pop
      if not os.path.isabs(self.op.hvm_cdrom_image_path):
4408 31a853d2 Iustin Pop
        raise errors.OpPrereqError("The path to the HVM CDROM image must"
4409 31a853d2 Iustin Pop
                                   " be an absolute path or None, not %s" %
4410 31a853d2 Iustin Pop
                                   self.op.hvm_cdrom_image_path)
4411 31a853d2 Iustin Pop
      if not os.path.isfile(self.op.hvm_cdrom_image_path):
4412 31a853d2 Iustin Pop
        raise errors.OpPrereqError("The HVM CDROM image must either be a"
4413 31a853d2 Iustin Pop
                                   " regular file or a symlink pointing to"
4414 31a853d2 Iustin Pop
                                   " an existing regular file, not %s" %
4415 31a853d2 Iustin Pop
                                   self.op.hvm_cdrom_image_path)
4416 31a853d2 Iustin Pop
4417 31a853d2 Iustin Pop
    # vnc_bind_address verification
4418 31a853d2 Iustin Pop
    if self.op.vnc_bind_address is not None:
4419 31a853d2 Iustin Pop
      if not utils.IsValidIP(self.op.vnc_bind_address):
4420 31a853d2 Iustin Pop
        raise errors.OpPrereqError("given VNC bind address '%s' doesn't look"
4421 31a853d2 Iustin Pop
                                   " like a valid IP address" %
4422 31a853d2 Iustin Pop
                                   self.op.vnc_bind_address)
4423 31a853d2 Iustin Pop
4424 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
4425 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
4426 a8083063 Iustin Pop
    if instance is None:
4427 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("No such instance name '%s'" %
4428 3ecf6786 Iustin Pop
                                 self.op.instance_name)
4429 a8083063 Iustin Pop
    self.op.instance_name = instance.name
4430 a8083063 Iustin Pop
    self.instance = instance
4431 a8083063 Iustin Pop
    return
4432 a8083063 Iustin Pop
4433 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
4434 a8083063 Iustin Pop
    """Modifies an instance.
4435 a8083063 Iustin Pop

4436 a8083063 Iustin Pop
    All parameters take effect only at the next restart of the instance.
4437 a8083063 Iustin Pop
    """
4438 a8083063 Iustin Pop
    result = []
4439 a8083063 Iustin Pop
    instance = self.instance
4440 a8083063 Iustin Pop
    if self.mem:
4441 a8083063 Iustin Pop
      instance.memory = self.mem
4442 a8083063 Iustin Pop
      result.append(("mem", self.mem))
4443 a8083063 Iustin Pop
    if self.vcpus:
4444 a8083063 Iustin Pop
      instance.vcpus = self.vcpus
4445 a8083063 Iustin Pop
      result.append(("vcpus",  self.vcpus))
4446 a8083063 Iustin Pop
    if self.do_ip:
4447 a8083063 Iustin Pop
      instance.nics[0].ip = self.ip
4448 a8083063 Iustin Pop
      result.append(("ip", self.ip))
4449 a8083063 Iustin Pop
    if self.bridge:
4450 a8083063 Iustin Pop
      instance.nics[0].bridge = self.bridge
4451 a8083063 Iustin Pop
      result.append(("bridge", self.bridge))
4452 1862d460 Alexander Schreiber
    if self.mac:
4453 1862d460 Alexander Schreiber
      instance.nics[0].mac = self.mac
4454 1862d460 Alexander Schreiber
      result.append(("mac", self.mac))
4455 973d7867 Iustin Pop
    if self.do_kernel_path:
4456 973d7867 Iustin Pop
      instance.kernel_path = self.kernel_path
4457 973d7867 Iustin Pop
      result.append(("kernel_path", self.kernel_path))
4458 973d7867 Iustin Pop
    if self.do_initrd_path:
4459 973d7867 Iustin Pop
      instance.initrd_path = self.initrd_path
4460 973d7867 Iustin Pop
      result.append(("initrd_path", self.initrd_path))
4461 25c5878d Alexander Schreiber
    if self.hvm_boot_order:
4462 25c5878d Alexander Schreiber
      if self.hvm_boot_order == constants.VALUE_DEFAULT:
4463 25c5878d Alexander Schreiber
        instance.hvm_boot_order = None
4464 25c5878d Alexander Schreiber
      else:
4465 25c5878d Alexander Schreiber
        instance.hvm_boot_order = self.hvm_boot_order
4466 25c5878d Alexander Schreiber
      result.append(("hvm_boot_order", self.hvm_boot_order))
4467 31a853d2 Iustin Pop
    if self.hvm_acpi:
4468 ec1ba002 Iustin Pop
      instance.hvm_acpi = self.hvm_acpi
4469 31a853d2 Iustin Pop
      result.append(("hvm_acpi", self.hvm_acpi))
4470 31a853d2 Iustin Pop
    if self.hvm_pae:
4471 ec1ba002 Iustin Pop
      instance.hvm_pae = self.hvm_pae
4472 31a853d2 Iustin Pop
      result.append(("hvm_pae", self.hvm_pae))
4473 31a853d2 Iustin Pop
    if self.hvm_cdrom_image_path:
4474 ec1ba002 Iustin Pop
      instance.hvm_cdrom_image_path = self.hvm_cdrom_image_path
4475 31a853d2 Iustin Pop
      result.append(("hvm_cdrom_image_path", self.hvm_cdrom_image_path))
4476 31a853d2 Iustin Pop
    if self.vnc_bind_address:
4477 31a853d2 Iustin Pop
      instance.vnc_bind_address = self.vnc_bind_address
4478 31a853d2 Iustin Pop
      result.append(("vnc_bind_address", self.vnc_bind_address))
4479 a8083063 Iustin Pop
4480 a8083063 Iustin Pop
    self.cfg.AddInstance(instance)
4481 a8083063 Iustin Pop
4482 a8083063 Iustin Pop
    return result
4483 a8083063 Iustin Pop
4484 a8083063 Iustin Pop
4485 a8083063 Iustin Pop
class LUQueryExports(NoHooksLU):
4486 a8083063 Iustin Pop
  """Query the exports list
4487 a8083063 Iustin Pop

4488 a8083063 Iustin Pop
  """
4489 a8083063 Iustin Pop
  _OP_REQP = []
4490 a8083063 Iustin Pop
4491 a8083063 Iustin Pop
  def CheckPrereq(self):
4492 a8083063 Iustin Pop
    """Check that the nodelist contains only existing nodes.
4493 a8083063 Iustin Pop

4494 a8083063 Iustin Pop
    """
4495 dcb93971 Michael Hanselmann
    self.nodes = _GetWantedNodes(self, getattr(self.op, "nodes", None))
4496 a8083063 Iustin Pop
4497 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
4498 a8083063 Iustin Pop
    """Compute the list of all the exported system images.
4499 a8083063 Iustin Pop

4500 a8083063 Iustin Pop
    Returns:
4501 a8083063 Iustin Pop
      a dictionary with the structure node->(export-list)
4502 a8083063 Iustin Pop
      where export-list is a list of the instances exported on
4503 a8083063 Iustin Pop
      that node.
4504 a8083063 Iustin Pop

4505 a8083063 Iustin Pop
    """
4506 a7ba5e53 Iustin Pop
    return rpc.call_export_list(self.nodes)
4507 a8083063 Iustin Pop
4508 a8083063 Iustin Pop
4509 a8083063 Iustin Pop
class LUExportInstance(LogicalUnit):
4510 a8083063 Iustin Pop
  """Export an instance to an image in the cluster.
4511 a8083063 Iustin Pop

4512 a8083063 Iustin Pop
  """
4513 a8083063 Iustin Pop
  HPATH = "instance-export"
4514 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
4515 a8083063 Iustin Pop
  _OP_REQP = ["instance_name", "target_node", "shutdown"]
4516 a8083063 Iustin Pop
4517 a8083063 Iustin Pop
  def BuildHooksEnv(self):
4518 a8083063 Iustin Pop
    """Build hooks env.
4519 a8083063 Iustin Pop

4520 a8083063 Iustin Pop
    This will run on the master, primary node and target node.
4521 a8083063 Iustin Pop

4522 a8083063 Iustin Pop
    """
4523 a8083063 Iustin Pop
    env = {
4524 a8083063 Iustin Pop
      "EXPORT_NODE": self.op.target_node,
4525 a8083063 Iustin Pop
      "EXPORT_DO_SHUTDOWN": self.op.shutdown,
4526 a8083063 Iustin Pop
      }
4527 396e1b78 Michael Hanselmann
    env.update(_BuildInstanceHookEnvByObject(self.instance))
4528 880478f8 Iustin Pop
    nl = [self.sstore.GetMasterNode(), self.instance.primary_node,
4529 a8083063 Iustin Pop
          self.op.target_node]
4530 a8083063 Iustin Pop
    return env, nl, nl
4531 a8083063 Iustin Pop
4532 a8083063 Iustin Pop
  def CheckPrereq(self):
4533 a8083063 Iustin Pop
    """Check prerequisites.
4534 a8083063 Iustin Pop

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

4537 a8083063 Iustin Pop
    """
4538 a8083063 Iustin Pop
    instance_name = self.cfg.ExpandInstanceName(self.op.instance_name)
4539 a8083063 Iustin Pop
    self.instance = self.cfg.GetInstanceInfo(instance_name)
4540 a8083063 Iustin Pop
    if self.instance is None:
4541 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not found" %
4542 3ecf6786 Iustin Pop
                                 self.op.instance_name)
4543 a8083063 Iustin Pop
4544 a8083063 Iustin Pop
    # node verification
4545 a8083063 Iustin Pop
    dst_node_short = self.cfg.ExpandNodeName(self.op.target_node)
4546 a8083063 Iustin Pop
    self.dst_node = self.cfg.GetNodeInfo(dst_node_short)
4547 a8083063 Iustin Pop
4548 a8083063 Iustin Pop
    if self.dst_node is None:
4549 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Destination node '%s' is unknown." %
4550 3ecf6786 Iustin Pop
                                 self.op.target_node)
4551 a8083063 Iustin Pop
    self.op.target_node = self.dst_node.name
4552 a8083063 Iustin Pop
4553 b6023d6c Manuel Franceschini
    # instance disk type verification
4554 b6023d6c Manuel Franceschini
    for disk in self.instance.disks:
4555 b6023d6c Manuel Franceschini
      if disk.dev_type == constants.LD_FILE:
4556 b6023d6c Manuel Franceschini
        raise errors.OpPrereqError("Export not supported for instances with"
4557 b6023d6c Manuel Franceschini
                                   " file-based disks")
4558 b6023d6c Manuel Franceschini
4559 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
4560 a8083063 Iustin Pop
    """Export an instance to an image in the cluster.
4561 a8083063 Iustin Pop

4562 a8083063 Iustin Pop
    """
4563 a8083063 Iustin Pop
    instance = self.instance
4564 a8083063 Iustin Pop
    dst_node = self.dst_node
4565 a8083063 Iustin Pop
    src_node = instance.primary_node
4566 a8083063 Iustin Pop
    if self.op.shutdown:
4567 fb300fb7 Guido Trotter
      # shutdown the instance, but not the disks
4568 fb300fb7 Guido Trotter
      if not rpc.call_instance_shutdown(src_node, instance):
4569 fb300fb7 Guido Trotter
         raise errors.OpExecError("Could not shutdown instance %s on node %s" %
4570 b4de68a9 Iustin Pop
                                  (instance.name, src_node))
4571 a8083063 Iustin Pop
4572 a8083063 Iustin Pop
    vgname = self.cfg.GetVGName()
4573 a8083063 Iustin Pop
4574 a8083063 Iustin Pop
    snap_disks = []
4575 a8083063 Iustin Pop
4576 a8083063 Iustin Pop
    try:
4577 a8083063 Iustin Pop
      for disk in instance.disks:
4578 a8083063 Iustin Pop
        if disk.iv_name == "sda":
4579 a8083063 Iustin Pop
          # new_dev_name will be a snapshot of an lvm leaf of the one we passed
4580 a8083063 Iustin Pop
          new_dev_name = rpc.call_blockdev_snapshot(src_node, disk)
4581 a8083063 Iustin Pop
4582 a8083063 Iustin Pop
          if not new_dev_name:
4583 a8083063 Iustin Pop
            logger.Error("could not snapshot block device %s on node %s" %
4584 a8083063 Iustin Pop
                         (disk.logical_id[1], src_node))
4585 a8083063 Iustin Pop
          else:
4586 fe96220b Iustin Pop
            new_dev = objects.Disk(dev_type=constants.LD_LV, size=disk.size,
4587 a8083063 Iustin Pop
                                      logical_id=(vgname, new_dev_name),
4588 a8083063 Iustin Pop
                                      physical_id=(vgname, new_dev_name),
4589 a8083063 Iustin Pop
                                      iv_name=disk.iv_name)
4590 a8083063 Iustin Pop
            snap_disks.append(new_dev)
4591 a8083063 Iustin Pop
4592 a8083063 Iustin Pop
    finally:
4593 fb300fb7 Guido Trotter
      if self.op.shutdown and instance.status == "up":
4594 fb300fb7 Guido Trotter
        if not rpc.call_instance_start(src_node, instance, None):
4595 fb300fb7 Guido Trotter
          _ShutdownInstanceDisks(instance, self.cfg)
4596 fb300fb7 Guido Trotter
          raise errors.OpExecError("Could not start instance")
4597 a8083063 Iustin Pop
4598 a8083063 Iustin Pop
    # TODO: check for size
4599 a8083063 Iustin Pop
4600 a8083063 Iustin Pop
    for dev in snap_disks:
4601 16687b98 Manuel Franceschini
      if not rpc.call_snapshot_export(src_node, dev, dst_node.name, instance):
4602 16687b98 Manuel Franceschini
        logger.Error("could not export block device %s from node %s to node %s"
4603 16687b98 Manuel Franceschini
                     % (dev.logical_id[1], src_node, dst_node.name))
4604 a8083063 Iustin Pop
      if not rpc.call_blockdev_remove(src_node, dev):
4605 16687b98 Manuel Franceschini
        logger.Error("could not remove snapshot block device %s from node %s" %
4606 16687b98 Manuel Franceschini
                     (dev.logical_id[1], src_node))
4607 a8083063 Iustin Pop
4608 a8083063 Iustin Pop
    if not rpc.call_finalize_export(dst_node.name, instance, snap_disks):
4609 a8083063 Iustin Pop
      logger.Error("could not finalize export for instance %s on node %s" %
4610 a8083063 Iustin Pop
                   (instance.name, dst_node.name))
4611 a8083063 Iustin Pop
4612 a8083063 Iustin Pop
    nodelist = self.cfg.GetNodeList()
4613 a8083063 Iustin Pop
    nodelist.remove(dst_node.name)
4614 a8083063 Iustin Pop
4615 a8083063 Iustin Pop
    # on one-node clusters nodelist will be empty after the removal
4616 a8083063 Iustin Pop
    # if we proceed the backup would be removed because OpQueryExports
4617 a8083063 Iustin Pop
    # substitutes an empty list with the full cluster node list.
4618 a8083063 Iustin Pop
    if nodelist:
4619 a8083063 Iustin Pop
      op = opcodes.OpQueryExports(nodes=nodelist)
4620 5bfac263 Iustin Pop
      exportlist = self.proc.ChainOpCode(op)
4621 a8083063 Iustin Pop
      for node in exportlist:
4622 a8083063 Iustin Pop
        if instance.name in exportlist[node]:
4623 a8083063 Iustin Pop
          if not rpc.call_export_remove(node, instance.name):
4624 a8083063 Iustin Pop
            logger.Error("could not remove older export for instance %s"
4625 a8083063 Iustin Pop
                         " on node %s" % (instance.name, node))
4626 5c947f38 Iustin Pop
4627 5c947f38 Iustin Pop
4628 9ac99fda Guido Trotter
class LURemoveExport(NoHooksLU):
4629 9ac99fda Guido Trotter
  """Remove exports related to the named instance.
4630 9ac99fda Guido Trotter

4631 9ac99fda Guido Trotter
  """
4632 9ac99fda Guido Trotter
  _OP_REQP = ["instance_name"]
4633 9ac99fda Guido Trotter
4634 9ac99fda Guido Trotter
  def CheckPrereq(self):
4635 9ac99fda Guido Trotter
    """Check prerequisites.
4636 9ac99fda Guido Trotter
    """
4637 9ac99fda Guido Trotter
    pass
4638 9ac99fda Guido Trotter
4639 9ac99fda Guido Trotter
  def Exec(self, feedback_fn):
4640 9ac99fda Guido Trotter
    """Remove any export.
4641 9ac99fda Guido Trotter

4642 9ac99fda Guido Trotter
    """
4643 9ac99fda Guido Trotter
    instance_name = self.cfg.ExpandInstanceName(self.op.instance_name)
4644 9ac99fda Guido Trotter
    # If the instance was not found we'll try with the name that was passed in.
4645 9ac99fda Guido Trotter
    # This will only work if it was an FQDN, though.
4646 9ac99fda Guido Trotter
    fqdn_warn = False
4647 9ac99fda Guido Trotter
    if not instance_name:
4648 9ac99fda Guido Trotter
      fqdn_warn = True
4649 9ac99fda Guido Trotter
      instance_name = self.op.instance_name
4650 9ac99fda Guido Trotter
4651 9ac99fda Guido Trotter
    op = opcodes.OpQueryExports(nodes=[])
4652 9ac99fda Guido Trotter
    exportlist = self.proc.ChainOpCode(op)
4653 9ac99fda Guido Trotter
    found = False
4654 9ac99fda Guido Trotter
    for node in exportlist:
4655 9ac99fda Guido Trotter
      if instance_name in exportlist[node]:
4656 9ac99fda Guido Trotter
        found = True
4657 9ac99fda Guido Trotter
        if not rpc.call_export_remove(node, instance_name):
4658 9ac99fda Guido Trotter
          logger.Error("could not remove export for instance %s"
4659 9ac99fda Guido Trotter
                       " on node %s" % (instance_name, node))
4660 9ac99fda Guido Trotter
4661 9ac99fda Guido Trotter
    if fqdn_warn and not found:
4662 9ac99fda Guido Trotter
      feedback_fn("Export not found. If trying to remove an export belonging"
4663 9ac99fda Guido Trotter
                  " to a deleted instance please use its Fully Qualified"
4664 9ac99fda Guido Trotter
                  " Domain Name.")
4665 9ac99fda Guido Trotter
4666 9ac99fda Guido Trotter
4667 5c947f38 Iustin Pop
class TagsLU(NoHooksLU):
4668 5c947f38 Iustin Pop
  """Generic tags LU.
4669 5c947f38 Iustin Pop

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

4672 5c947f38 Iustin Pop
  """
4673 5c947f38 Iustin Pop
  def CheckPrereq(self):
4674 5c947f38 Iustin Pop
    """Check prerequisites.
4675 5c947f38 Iustin Pop

4676 5c947f38 Iustin Pop
    """
4677 5c947f38 Iustin Pop
    if self.op.kind == constants.TAG_CLUSTER:
4678 5c947f38 Iustin Pop
      self.target = self.cfg.GetClusterInfo()
4679 5c947f38 Iustin Pop
    elif self.op.kind == constants.TAG_NODE:
4680 5c947f38 Iustin Pop
      name = self.cfg.ExpandNodeName(self.op.name)
4681 5c947f38 Iustin Pop
      if name is None:
4682 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Invalid node name (%s)" %
4683 3ecf6786 Iustin Pop
                                   (self.op.name,))
4684 5c947f38 Iustin Pop
      self.op.name = name
4685 5c947f38 Iustin Pop
      self.target = self.cfg.GetNodeInfo(name)
4686 5c947f38 Iustin Pop
    elif self.op.kind == constants.TAG_INSTANCE:
4687 8f684e16 Iustin Pop
      name = self.cfg.ExpandInstanceName(self.op.name)
4688 5c947f38 Iustin Pop
      if name is None:
4689 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Invalid instance name (%s)" %
4690 3ecf6786 Iustin Pop
                                   (self.op.name,))
4691 5c947f38 Iustin Pop
      self.op.name = name
4692 5c947f38 Iustin Pop
      self.target = self.cfg.GetInstanceInfo(name)
4693 5c947f38 Iustin Pop
    else:
4694 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Wrong tag type requested (%s)" %
4695 3ecf6786 Iustin Pop
                                 str(self.op.kind))
4696 5c947f38 Iustin Pop
4697 5c947f38 Iustin Pop
4698 5c947f38 Iustin Pop
class LUGetTags(TagsLU):
4699 5c947f38 Iustin Pop
  """Returns the tags of a given object.
4700 5c947f38 Iustin Pop

4701 5c947f38 Iustin Pop
  """
4702 5c947f38 Iustin Pop
  _OP_REQP = ["kind", "name"]
4703 5c947f38 Iustin Pop
4704 5c947f38 Iustin Pop
  def Exec(self, feedback_fn):
4705 5c947f38 Iustin Pop
    """Returns the tag list.
4706 5c947f38 Iustin Pop

4707 5c947f38 Iustin Pop
    """
4708 5c947f38 Iustin Pop
    return self.target.GetTags()
4709 5c947f38 Iustin Pop
4710 5c947f38 Iustin Pop
4711 73415719 Iustin Pop
class LUSearchTags(NoHooksLU):
4712 73415719 Iustin Pop
  """Searches the tags for a given pattern.
4713 73415719 Iustin Pop

4714 73415719 Iustin Pop
  """
4715 73415719 Iustin Pop
  _OP_REQP = ["pattern"]
4716 73415719 Iustin Pop
4717 73415719 Iustin Pop
  def CheckPrereq(self):
4718 73415719 Iustin Pop
    """Check prerequisites.
4719 73415719 Iustin Pop

4720 73415719 Iustin Pop
    This checks the pattern passed for validity by compiling it.
4721 73415719 Iustin Pop

4722 73415719 Iustin Pop
    """
4723 73415719 Iustin Pop
    try:
4724 73415719 Iustin Pop
      self.re = re.compile(self.op.pattern)
4725 73415719 Iustin Pop
    except re.error, err:
4726 73415719 Iustin Pop
      raise errors.OpPrereqError("Invalid search pattern '%s': %s" %
4727 73415719 Iustin Pop
                                 (self.op.pattern, err))
4728 73415719 Iustin Pop
4729 73415719 Iustin Pop
  def Exec(self, feedback_fn):
4730 73415719 Iustin Pop
    """Returns the tag list.
4731 73415719 Iustin Pop

4732 73415719 Iustin Pop
    """
4733 73415719 Iustin Pop
    cfg = self.cfg
4734 73415719 Iustin Pop
    tgts = [("/cluster", cfg.GetClusterInfo())]
4735 73415719 Iustin Pop
    ilist = [cfg.GetInstanceInfo(name) for name in cfg.GetInstanceList()]
4736 73415719 Iustin Pop
    tgts.extend([("/instances/%s" % i.name, i) for i in ilist])
4737 73415719 Iustin Pop
    nlist = [cfg.GetNodeInfo(name) for name in cfg.GetNodeList()]
4738 73415719 Iustin Pop
    tgts.extend([("/nodes/%s" % n.name, n) for n in nlist])
4739 73415719 Iustin Pop
    results = []
4740 73415719 Iustin Pop
    for path, target in tgts:
4741 73415719 Iustin Pop
      for tag in target.GetTags():
4742 73415719 Iustin Pop
        if self.re.search(tag):
4743 73415719 Iustin Pop
          results.append((path, tag))
4744 73415719 Iustin Pop
    return results
4745 73415719 Iustin Pop
4746 73415719 Iustin Pop
4747 f27302fa Iustin Pop
class LUAddTags(TagsLU):
4748 5c947f38 Iustin Pop
  """Sets a tag on a given object.
4749 5c947f38 Iustin Pop

4750 5c947f38 Iustin Pop
  """
4751 f27302fa Iustin Pop
  _OP_REQP = ["kind", "name", "tags"]
4752 5c947f38 Iustin Pop
4753 5c947f38 Iustin Pop
  def CheckPrereq(self):
4754 5c947f38 Iustin Pop
    """Check prerequisites.
4755 5c947f38 Iustin Pop

4756 5c947f38 Iustin Pop
    This checks the type and length of the tag name and value.
4757 5c947f38 Iustin Pop

4758 5c947f38 Iustin Pop
    """
4759 5c947f38 Iustin Pop
    TagsLU.CheckPrereq(self)
4760 f27302fa Iustin Pop
    for tag in self.op.tags:
4761 f27302fa Iustin Pop
      objects.TaggableObject.ValidateTag(tag)
4762 5c947f38 Iustin Pop
4763 5c947f38 Iustin Pop
  def Exec(self, feedback_fn):
4764 5c947f38 Iustin Pop
    """Sets the tag.
4765 5c947f38 Iustin Pop

4766 5c947f38 Iustin Pop
    """
4767 5c947f38 Iustin Pop
    try:
4768 f27302fa Iustin Pop
      for tag in self.op.tags:
4769 f27302fa Iustin Pop
        self.target.AddTag(tag)
4770 5c947f38 Iustin Pop
    except errors.TagError, err:
4771 3ecf6786 Iustin Pop
      raise errors.OpExecError("Error while setting tag: %s" % str(err))
4772 5c947f38 Iustin Pop
    try:
4773 5c947f38 Iustin Pop
      self.cfg.Update(self.target)
4774 5c947f38 Iustin Pop
    except errors.ConfigurationError:
4775 3ecf6786 Iustin Pop
      raise errors.OpRetryError("There has been a modification to the"
4776 3ecf6786 Iustin Pop
                                " config file and the operation has been"
4777 3ecf6786 Iustin Pop
                                " aborted. Please retry.")
4778 5c947f38 Iustin Pop
4779 5c947f38 Iustin Pop
4780 f27302fa Iustin Pop
class LUDelTags(TagsLU):
4781 f27302fa Iustin Pop
  """Delete a list of tags from a given object.
4782 5c947f38 Iustin Pop

4783 5c947f38 Iustin Pop
  """
4784 f27302fa Iustin Pop
  _OP_REQP = ["kind", "name", "tags"]
4785 5c947f38 Iustin Pop
4786 5c947f38 Iustin Pop
  def CheckPrereq(self):
4787 5c947f38 Iustin Pop
    """Check prerequisites.
4788 5c947f38 Iustin Pop

4789 5c947f38 Iustin Pop
    This checks that we have the given tag.
4790 5c947f38 Iustin Pop

4791 5c947f38 Iustin Pop
    """
4792 5c947f38 Iustin Pop
    TagsLU.CheckPrereq(self)
4793 f27302fa Iustin Pop
    for tag in self.op.tags:
4794 f27302fa Iustin Pop
      objects.TaggableObject.ValidateTag(tag)
4795 f27302fa Iustin Pop
    del_tags = frozenset(self.op.tags)
4796 f27302fa Iustin Pop
    cur_tags = self.target.GetTags()
4797 f27302fa Iustin Pop
    if not del_tags <= cur_tags:
4798 f27302fa Iustin Pop
      diff_tags = del_tags - cur_tags
4799 f27302fa Iustin Pop
      diff_names = ["'%s'" % tag for tag in diff_tags]
4800 f27302fa Iustin Pop
      diff_names.sort()
4801 f27302fa Iustin Pop
      raise errors.OpPrereqError("Tag(s) %s not found" %
4802 f27302fa Iustin Pop
                                 (",".join(diff_names)))
4803 5c947f38 Iustin Pop
4804 5c947f38 Iustin Pop
  def Exec(self, feedback_fn):
4805 5c947f38 Iustin Pop
    """Remove the tag from the object.
4806 5c947f38 Iustin Pop

4807 5c947f38 Iustin Pop
    """
4808 f27302fa Iustin Pop
    for tag in self.op.tags:
4809 f27302fa Iustin Pop
      self.target.RemoveTag(tag)
4810 5c947f38 Iustin Pop
    try:
4811 5c947f38 Iustin Pop
      self.cfg.Update(self.target)
4812 5c947f38 Iustin Pop
    except errors.ConfigurationError:
4813 3ecf6786 Iustin Pop
      raise errors.OpRetryError("There has been a modification to the"
4814 3ecf6786 Iustin Pop
                                " config file and the operation has been"
4815 3ecf6786 Iustin Pop
                                " aborted. Please retry.")
4816 06009e27 Iustin Pop
4817 06009e27 Iustin Pop
class LUTestDelay(NoHooksLU):
4818 06009e27 Iustin Pop
  """Sleep for a specified amount of time.
4819 06009e27 Iustin Pop

4820 06009e27 Iustin Pop
  This LU sleeps on the master and/or nodes for a specified amoutn of
4821 06009e27 Iustin Pop
  time.
4822 06009e27 Iustin Pop

4823 06009e27 Iustin Pop
  """
4824 06009e27 Iustin Pop
  _OP_REQP = ["duration", "on_master", "on_nodes"]
4825 06009e27 Iustin Pop
4826 06009e27 Iustin Pop
  def CheckPrereq(self):
4827 06009e27 Iustin Pop
    """Check prerequisites.
4828 06009e27 Iustin Pop

4829 06009e27 Iustin Pop
    This checks that we have a good list of nodes and/or the duration
4830 06009e27 Iustin Pop
    is valid.
4831 06009e27 Iustin Pop

4832 06009e27 Iustin Pop
    """
4833 06009e27 Iustin Pop
4834 06009e27 Iustin Pop
    if self.op.on_nodes:
4835 06009e27 Iustin Pop
      self.op.on_nodes = _GetWantedNodes(self, self.op.on_nodes)
4836 06009e27 Iustin Pop
4837 06009e27 Iustin Pop
  def Exec(self, feedback_fn):
4838 06009e27 Iustin Pop
    """Do the actual sleep.
4839 06009e27 Iustin Pop

4840 06009e27 Iustin Pop
    """
4841 06009e27 Iustin Pop
    if self.op.on_master:
4842 06009e27 Iustin Pop
      if not utils.TestDelay(self.op.duration):
4843 06009e27 Iustin Pop
        raise errors.OpExecError("Error during master delay test")
4844 06009e27 Iustin Pop
    if self.op.on_nodes:
4845 06009e27 Iustin Pop
      result = rpc.call_test_delay(self.op.on_nodes, self.op.duration)
4846 06009e27 Iustin Pop
      if not result:
4847 06009e27 Iustin Pop
        raise errors.OpExecError("Complete failure from rpc call")
4848 06009e27 Iustin Pop
      for node, node_result in result.items():
4849 06009e27 Iustin Pop
        if not node_result:
4850 06009e27 Iustin Pop
          raise errors.OpExecError("Failure during rpc call to node %s,"
4851 06009e27 Iustin Pop
                                   " result: %s" % (node, node_result))
4852 d61df03e Iustin Pop
4853 d61df03e Iustin Pop
4854 d1c2dd75 Iustin Pop
class IAllocator(object):
4855 d1c2dd75 Iustin Pop
  """IAllocator framework.
4856 d61df03e Iustin Pop

4857 d1c2dd75 Iustin Pop
  An IAllocator instance has three sets of attributes:
4858 d1c2dd75 Iustin Pop
    - cfg/sstore that are needed to query the cluster
4859 d1c2dd75 Iustin Pop
    - input data (all members of the _KEYS class attribute are required)
4860 d1c2dd75 Iustin Pop
    - four buffer attributes (in|out_data|text), that represent the
4861 d1c2dd75 Iustin Pop
      input (to the external script) in text and data structure format,
4862 d1c2dd75 Iustin Pop
      and the output from it, again in two formats
4863 d1c2dd75 Iustin Pop
    - the result variables from the script (success, info, nodes) for
4864 d1c2dd75 Iustin Pop
      easy usage
4865 d61df03e Iustin Pop

4866 d61df03e Iustin Pop
  """
4867 29859cb7 Iustin Pop
  _ALLO_KEYS = [
4868 d1c2dd75 Iustin Pop
    "mem_size", "disks", "disk_template",
4869 d1c2dd75 Iustin Pop
    "os", "tags", "nics", "vcpus",
4870 d1c2dd75 Iustin Pop
    ]
4871 29859cb7 Iustin Pop
  _RELO_KEYS = [
4872 29859cb7 Iustin Pop
    "relocate_from",
4873 29859cb7 Iustin Pop
    ]
4874 d1c2dd75 Iustin Pop
4875 29859cb7 Iustin Pop
  def __init__(self, cfg, sstore, mode, name, **kwargs):
4876 d1c2dd75 Iustin Pop
    self.cfg = cfg
4877 d1c2dd75 Iustin Pop
    self.sstore = sstore
4878 d1c2dd75 Iustin Pop
    # init buffer variables
4879 d1c2dd75 Iustin Pop
    self.in_text = self.out_text = self.in_data = self.out_data = None
4880 d1c2dd75 Iustin Pop
    # init all input fields so that pylint is happy
4881 29859cb7 Iustin Pop
    self.mode = mode
4882 29859cb7 Iustin Pop
    self.name = name
4883 d1c2dd75 Iustin Pop
    self.mem_size = self.disks = self.disk_template = None
4884 d1c2dd75 Iustin Pop
    self.os = self.tags = self.nics = self.vcpus = None
4885 29859cb7 Iustin Pop
    self.relocate_from = None
4886 27579978 Iustin Pop
    # computed fields
4887 27579978 Iustin Pop
    self.required_nodes = None
4888 d1c2dd75 Iustin Pop
    # init result fields
4889 d1c2dd75 Iustin Pop
    self.success = self.info = self.nodes = None
4890 29859cb7 Iustin Pop
    if self.mode == constants.IALLOCATOR_MODE_ALLOC:
4891 29859cb7 Iustin Pop
      keyset = self._ALLO_KEYS
4892 29859cb7 Iustin Pop
    elif self.mode == constants.IALLOCATOR_MODE_RELOC:
4893 29859cb7 Iustin Pop
      keyset = self._RELO_KEYS
4894 29859cb7 Iustin Pop
    else:
4895 29859cb7 Iustin Pop
      raise errors.ProgrammerError("Unknown mode '%s' passed to the"
4896 29859cb7 Iustin Pop
                                   " IAllocator" % self.mode)
4897 d1c2dd75 Iustin Pop
    for key in kwargs:
4898 29859cb7 Iustin Pop
      if key not in keyset:
4899 d1c2dd75 Iustin Pop
        raise errors.ProgrammerError("Invalid input parameter '%s' to"
4900 d1c2dd75 Iustin Pop
                                     " IAllocator" % key)
4901 d1c2dd75 Iustin Pop
      setattr(self, key, kwargs[key])
4902 29859cb7 Iustin Pop
    for key in keyset:
4903 d1c2dd75 Iustin Pop
      if key not in kwargs:
4904 d1c2dd75 Iustin Pop
        raise errors.ProgrammerError("Missing input parameter '%s' to"
4905 d1c2dd75 Iustin Pop
                                     " IAllocator" % key)
4906 d1c2dd75 Iustin Pop
    self._BuildInputData()
4907 d1c2dd75 Iustin Pop
4908 d1c2dd75 Iustin Pop
  def _ComputeClusterData(self):
4909 d1c2dd75 Iustin Pop
    """Compute the generic allocator input data.
4910 d1c2dd75 Iustin Pop

4911 d1c2dd75 Iustin Pop
    This is the data that is independent of the actual operation.
4912 d1c2dd75 Iustin Pop

4913 d1c2dd75 Iustin Pop
    """
4914 d1c2dd75 Iustin Pop
    cfg = self.cfg
4915 d1c2dd75 Iustin Pop
    # cluster data
4916 d1c2dd75 Iustin Pop
    data = {
4917 d1c2dd75 Iustin Pop
      "version": 1,
4918 d1c2dd75 Iustin Pop
      "cluster_name": self.sstore.GetClusterName(),
4919 d1c2dd75 Iustin Pop
      "cluster_tags": list(cfg.GetClusterInfo().GetTags()),
4920 6286519f Iustin Pop
      "hypervisor_type": self.sstore.GetHypervisorType(),
4921 d1c2dd75 Iustin Pop
      # we don't have job IDs
4922 d61df03e Iustin Pop
      }
4923 d61df03e Iustin Pop
4924 6286519f Iustin Pop
    i_list = [cfg.GetInstanceInfo(iname) for iname in cfg.GetInstanceList()]
4925 6286519f Iustin Pop
4926 d1c2dd75 Iustin Pop
    # node data
4927 d1c2dd75 Iustin Pop
    node_results = {}
4928 d1c2dd75 Iustin Pop
    node_list = cfg.GetNodeList()
4929 d1c2dd75 Iustin Pop
    node_data = rpc.call_node_info(node_list, cfg.GetVGName())
4930 d1c2dd75 Iustin Pop
    for nname in node_list:
4931 d1c2dd75 Iustin Pop
      ninfo = cfg.GetNodeInfo(nname)
4932 d1c2dd75 Iustin Pop
      if nname not in node_data or not isinstance(node_data[nname], dict):
4933 d1c2dd75 Iustin Pop
        raise errors.OpExecError("Can't get data for node %s" % nname)
4934 d1c2dd75 Iustin Pop
      remote_info = node_data[nname]
4935 b2662e7f Iustin Pop
      for attr in ['memory_total', 'memory_free', 'memory_dom0',
4936 4337cf1b Iustin Pop
                   'vg_size', 'vg_free', 'cpu_total']:
4937 d1c2dd75 Iustin Pop
        if attr not in remote_info:
4938 d1c2dd75 Iustin Pop
          raise errors.OpExecError("Node '%s' didn't return attribute '%s'" %
4939 d1c2dd75 Iustin Pop
                                   (nname, attr))
4940 d1c2dd75 Iustin Pop
        try:
4941 b2662e7f Iustin Pop
          remote_info[attr] = int(remote_info[attr])
4942 d1c2dd75 Iustin Pop
        except ValueError, err:
4943 d1c2dd75 Iustin Pop
          raise errors.OpExecError("Node '%s' returned invalid value for '%s':"
4944 d1c2dd75 Iustin Pop
                                   " %s" % (nname, attr, str(err)))
4945 6286519f Iustin Pop
      # compute memory used by primary instances
4946 6286519f Iustin Pop
      i_p_mem = i_p_up_mem = 0
4947 6286519f Iustin Pop
      for iinfo in i_list:
4948 6286519f Iustin Pop
        if iinfo.primary_node == nname:
4949 6286519f Iustin Pop
          i_p_mem += iinfo.memory
4950 6286519f Iustin Pop
          if iinfo.status == "up":
4951 6286519f Iustin Pop
            i_p_up_mem += iinfo.memory
4952 6286519f Iustin Pop
4953 b2662e7f Iustin Pop
      # compute memory used by instances
4954 d1c2dd75 Iustin Pop
      pnr = {
4955 d1c2dd75 Iustin Pop
        "tags": list(ninfo.GetTags()),
4956 b2662e7f Iustin Pop
        "total_memory": remote_info['memory_total'],
4957 b2662e7f Iustin Pop
        "reserved_memory": remote_info['memory_dom0'],
4958 b2662e7f Iustin Pop
        "free_memory": remote_info['memory_free'],
4959 6286519f Iustin Pop
        "i_pri_memory": i_p_mem,
4960 6286519f Iustin Pop
        "i_pri_up_memory": i_p_up_mem,
4961 b2662e7f Iustin Pop
        "total_disk": remote_info['vg_size'],
4962 b2662e7f Iustin Pop
        "free_disk": remote_info['vg_free'],
4963 d1c2dd75 Iustin Pop
        "primary_ip": ninfo.primary_ip,
4964 d1c2dd75 Iustin Pop
        "secondary_ip": ninfo.secondary_ip,
4965 4337cf1b Iustin Pop
        "total_cpus": remote_info['cpu_total'],
4966 d1c2dd75 Iustin Pop
        }
4967 d1c2dd75 Iustin Pop
      node_results[nname] = pnr
4968 d1c2dd75 Iustin Pop
    data["nodes"] = node_results
4969 d1c2dd75 Iustin Pop
4970 d1c2dd75 Iustin Pop
    # instance data
4971 d1c2dd75 Iustin Pop
    instance_data = {}
4972 6286519f Iustin Pop
    for iinfo in i_list:
4973 d1c2dd75 Iustin Pop
      nic_data = [{"mac": n.mac, "ip": n.ip, "bridge": n.bridge}
4974 d1c2dd75 Iustin Pop
                  for n in iinfo.nics]
4975 d1c2dd75 Iustin Pop
      pir = {
4976 d1c2dd75 Iustin Pop
        "tags": list(iinfo.GetTags()),
4977 d1c2dd75 Iustin Pop
        "should_run": iinfo.status == "up",
4978 d1c2dd75 Iustin Pop
        "vcpus": iinfo.vcpus,
4979 d1c2dd75 Iustin Pop
        "memory": iinfo.memory,
4980 d1c2dd75 Iustin Pop
        "os": iinfo.os,
4981 d1c2dd75 Iustin Pop
        "nodes": [iinfo.primary_node] + list(iinfo.secondary_nodes),
4982 d1c2dd75 Iustin Pop
        "nics": nic_data,
4983 d1c2dd75 Iustin Pop
        "disks": [{"size": dsk.size, "mode": "w"} for dsk in iinfo.disks],
4984 d1c2dd75 Iustin Pop
        "disk_template": iinfo.disk_template,
4985 d1c2dd75 Iustin Pop
        }
4986 768f0a80 Iustin Pop
      instance_data[iinfo.name] = pir
4987 d61df03e Iustin Pop
4988 d1c2dd75 Iustin Pop
    data["instances"] = instance_data
4989 d61df03e Iustin Pop
4990 d1c2dd75 Iustin Pop
    self.in_data = data
4991 d61df03e Iustin Pop
4992 d1c2dd75 Iustin Pop
  def _AddNewInstance(self):
4993 d1c2dd75 Iustin Pop
    """Add new instance data to allocator structure.
4994 d61df03e Iustin Pop

4995 d1c2dd75 Iustin Pop
    This in combination with _AllocatorGetClusterData will create the
4996 d1c2dd75 Iustin Pop
    correct structure needed as input for the allocator.
4997 d61df03e Iustin Pop

4998 d1c2dd75 Iustin Pop
    The checks for the completeness of the opcode must have already been
4999 d1c2dd75 Iustin Pop
    done.
5000 d61df03e Iustin Pop

5001 d1c2dd75 Iustin Pop
    """
5002 d1c2dd75 Iustin Pop
    data = self.in_data
5003 d1c2dd75 Iustin Pop
    if len(self.disks) != 2:
5004 d1c2dd75 Iustin Pop
      raise errors.OpExecError("Only two-disk configurations supported")
5005 d1c2dd75 Iustin Pop
5006 d1c2dd75 Iustin Pop
    disk_space = _ComputeDiskSize(self.disk_template,
5007 d1c2dd75 Iustin Pop
                                  self.disks[0]["size"], self.disks[1]["size"])
5008 d1c2dd75 Iustin Pop
5009 27579978 Iustin Pop
    if self.disk_template in constants.DTS_NET_MIRROR:
5010 27579978 Iustin Pop
      self.required_nodes = 2
5011 27579978 Iustin Pop
    else:
5012 27579978 Iustin Pop
      self.required_nodes = 1
5013 d1c2dd75 Iustin Pop
    request = {
5014 d1c2dd75 Iustin Pop
      "type": "allocate",
5015 d1c2dd75 Iustin Pop
      "name": self.name,
5016 d1c2dd75 Iustin Pop
      "disk_template": self.disk_template,
5017 d1c2dd75 Iustin Pop
      "tags": self.tags,
5018 d1c2dd75 Iustin Pop
      "os": self.os,
5019 d1c2dd75 Iustin Pop
      "vcpus": self.vcpus,
5020 d1c2dd75 Iustin Pop
      "memory": self.mem_size,
5021 d1c2dd75 Iustin Pop
      "disks": self.disks,
5022 d1c2dd75 Iustin Pop
      "disk_space_total": disk_space,
5023 d1c2dd75 Iustin Pop
      "nics": self.nics,
5024 27579978 Iustin Pop
      "required_nodes": self.required_nodes,
5025 d1c2dd75 Iustin Pop
      }
5026 d1c2dd75 Iustin Pop
    data["request"] = request
5027 298fe380 Iustin Pop
5028 d1c2dd75 Iustin Pop
  def _AddRelocateInstance(self):
5029 d1c2dd75 Iustin Pop
    """Add relocate instance data to allocator structure.
5030 298fe380 Iustin Pop

5031 d1c2dd75 Iustin Pop
    This in combination with _IAllocatorGetClusterData will create the
5032 d1c2dd75 Iustin Pop
    correct structure needed as input for the allocator.
5033 d61df03e Iustin Pop

5034 d1c2dd75 Iustin Pop
    The checks for the completeness of the opcode must have already been
5035 d1c2dd75 Iustin Pop
    done.
5036 d61df03e Iustin Pop

5037 d1c2dd75 Iustin Pop
    """
5038 27579978 Iustin Pop
    instance = self.cfg.GetInstanceInfo(self.name)
5039 27579978 Iustin Pop
    if instance is None:
5040 27579978 Iustin Pop
      raise errors.ProgrammerError("Unknown instance '%s' passed to"
5041 27579978 Iustin Pop
                                   " IAllocator" % self.name)
5042 27579978 Iustin Pop
5043 27579978 Iustin Pop
    if instance.disk_template not in constants.DTS_NET_MIRROR:
5044 27579978 Iustin Pop
      raise errors.OpPrereqError("Can't relocate non-mirrored instances")
5045 27579978 Iustin Pop
5046 2a139bb0 Iustin Pop
    if len(instance.secondary_nodes) != 1:
5047 2a139bb0 Iustin Pop
      raise errors.OpPrereqError("Instance has not exactly one secondary node")
5048 2a139bb0 Iustin Pop
5049 27579978 Iustin Pop
    self.required_nodes = 1
5050 27579978 Iustin Pop
5051 27579978 Iustin Pop
    disk_space = _ComputeDiskSize(instance.disk_template,
5052 27579978 Iustin Pop
                                  instance.disks[0].size,
5053 27579978 Iustin Pop
                                  instance.disks[1].size)
5054 27579978 Iustin Pop
5055 d1c2dd75 Iustin Pop
    request = {
5056 2a139bb0 Iustin Pop
      "type": "relocate",
5057 d1c2dd75 Iustin Pop
      "name": self.name,
5058 27579978 Iustin Pop
      "disk_space_total": disk_space,
5059 27579978 Iustin Pop
      "required_nodes": self.required_nodes,
5060 29859cb7 Iustin Pop
      "relocate_from": self.relocate_from,
5061 d1c2dd75 Iustin Pop
      }
5062 27579978 Iustin Pop
    self.in_data["request"] = request
5063 d61df03e Iustin Pop
5064 d1c2dd75 Iustin Pop
  def _BuildInputData(self):
5065 d1c2dd75 Iustin Pop
    """Build input data structures.
5066 d61df03e Iustin Pop

5067 d1c2dd75 Iustin Pop
    """
5068 d1c2dd75 Iustin Pop
    self._ComputeClusterData()
5069 d61df03e Iustin Pop
5070 d1c2dd75 Iustin Pop
    if self.mode == constants.IALLOCATOR_MODE_ALLOC:
5071 d1c2dd75 Iustin Pop
      self._AddNewInstance()
5072 d1c2dd75 Iustin Pop
    else:
5073 d1c2dd75 Iustin Pop
      self._AddRelocateInstance()
5074 d61df03e Iustin Pop
5075 d1c2dd75 Iustin Pop
    self.in_text = serializer.Dump(self.in_data)
5076 d61df03e Iustin Pop
5077 8d528b7c Iustin Pop
  def Run(self, name, validate=True, call_fn=rpc.call_iallocator_runner):
5078 d1c2dd75 Iustin Pop
    """Run an instance allocator and return the results.
5079 298fe380 Iustin Pop

5080 d1c2dd75 Iustin Pop
    """
5081 d1c2dd75 Iustin Pop
    data = self.in_text
5082 298fe380 Iustin Pop
5083 8d528b7c Iustin Pop
    result = call_fn(self.sstore.GetMasterNode(), name, self.in_text)
5084 298fe380 Iustin Pop
5085 8d528b7c Iustin Pop
    if not isinstance(result, tuple) or len(result) != 4:
5086 8d528b7c Iustin Pop
      raise errors.OpExecError("Invalid result from master iallocator runner")
5087 8d528b7c Iustin Pop
5088 8d528b7c Iustin Pop
    rcode, stdout, stderr, fail = result
5089 8d528b7c Iustin Pop
5090 8d528b7c Iustin Pop
    if rcode == constants.IARUN_NOTFOUND:
5091 8d528b7c Iustin Pop
      raise errors.OpExecError("Can't find allocator '%s'" % name)
5092 8d528b7c Iustin Pop
    elif rcode == constants.IARUN_FAILURE:
5093 d1c2dd75 Iustin Pop
        raise errors.OpExecError("Instance allocator call failed: %s,"
5094 d1c2dd75 Iustin Pop
                                 " output: %s" %
5095 8d528b7c Iustin Pop
                                 (fail, stdout+stderr))
5096 8d528b7c Iustin Pop
    self.out_text = stdout
5097 d1c2dd75 Iustin Pop
    if validate:
5098 d1c2dd75 Iustin Pop
      self._ValidateResult()
5099 298fe380 Iustin Pop
5100 d1c2dd75 Iustin Pop
  def _ValidateResult(self):
5101 d1c2dd75 Iustin Pop
    """Process the allocator results.
5102 538475ca Iustin Pop

5103 d1c2dd75 Iustin Pop
    This will process and if successful save the result in
5104 d1c2dd75 Iustin Pop
    self.out_data and the other parameters.
5105 538475ca Iustin Pop

5106 d1c2dd75 Iustin Pop
    """
5107 d1c2dd75 Iustin Pop
    try:
5108 d1c2dd75 Iustin Pop
      rdict = serializer.Load(self.out_text)
5109 d1c2dd75 Iustin Pop
    except Exception, err:
5110 d1c2dd75 Iustin Pop
      raise errors.OpExecError("Can't parse iallocator results: %s" % str(err))
5111 d1c2dd75 Iustin Pop
5112 d1c2dd75 Iustin Pop
    if not isinstance(rdict, dict):
5113 d1c2dd75 Iustin Pop
      raise errors.OpExecError("Can't parse iallocator results: not a dict")
5114 538475ca Iustin Pop
5115 d1c2dd75 Iustin Pop
    for key in "success", "info", "nodes":
5116 d1c2dd75 Iustin Pop
      if key not in rdict:
5117 d1c2dd75 Iustin Pop
        raise errors.OpExecError("Can't parse iallocator results:"
5118 d1c2dd75 Iustin Pop
                                 " missing key '%s'" % key)
5119 d1c2dd75 Iustin Pop
      setattr(self, key, rdict[key])
5120 538475ca Iustin Pop
5121 d1c2dd75 Iustin Pop
    if not isinstance(rdict["nodes"], list):
5122 d1c2dd75 Iustin Pop
      raise errors.OpExecError("Can't parse iallocator results: 'nodes' key"
5123 d1c2dd75 Iustin Pop
                               " is not a list")
5124 d1c2dd75 Iustin Pop
    self.out_data = rdict
5125 538475ca Iustin Pop
5126 538475ca Iustin Pop
5127 d61df03e Iustin Pop
class LUTestAllocator(NoHooksLU):
5128 d61df03e Iustin Pop
  """Run allocator tests.
5129 d61df03e Iustin Pop

5130 d61df03e Iustin Pop
  This LU runs the allocator tests
5131 d61df03e Iustin Pop

5132 d61df03e Iustin Pop
  """
5133 d61df03e Iustin Pop
  _OP_REQP = ["direction", "mode", "name"]
5134 d61df03e Iustin Pop
5135 d61df03e Iustin Pop
  def CheckPrereq(self):
5136 d61df03e Iustin Pop
    """Check prerequisites.
5137 d61df03e Iustin Pop

5138 d61df03e Iustin Pop
    This checks the opcode parameters depending on the director and mode test.
5139 d61df03e Iustin Pop

5140 d61df03e Iustin Pop
    """
5141 298fe380 Iustin Pop
    if self.op.mode == constants.IALLOCATOR_MODE_ALLOC:
5142 d61df03e Iustin Pop
      for attr in ["name", "mem_size", "disks", "disk_template",
5143 d61df03e Iustin Pop
                   "os", "tags", "nics", "vcpus"]:
5144 d61df03e Iustin Pop
        if not hasattr(self.op, attr):
5145 d61df03e Iustin Pop
          raise errors.OpPrereqError("Missing attribute '%s' on opcode input" %
5146 d61df03e Iustin Pop
                                     attr)
5147 d61df03e Iustin Pop
      iname = self.cfg.ExpandInstanceName(self.op.name)
5148 d61df03e Iustin Pop
      if iname is not None:
5149 d61df03e Iustin Pop
        raise errors.OpPrereqError("Instance '%s' already in the cluster" %
5150 d61df03e Iustin Pop
                                   iname)
5151 d61df03e Iustin Pop
      if not isinstance(self.op.nics, list):
5152 d61df03e Iustin Pop
        raise errors.OpPrereqError("Invalid parameter 'nics'")
5153 d61df03e Iustin Pop
      for row in self.op.nics:
5154 d61df03e Iustin Pop
        if (not isinstance(row, dict) or
5155 d61df03e Iustin Pop
            "mac" not in row or
5156 d61df03e Iustin Pop
            "ip" not in row or
5157 d61df03e Iustin Pop
            "bridge" not in row):
5158 d61df03e Iustin Pop
          raise errors.OpPrereqError("Invalid contents of the"
5159 d61df03e Iustin Pop
                                     " 'nics' parameter")
5160 d61df03e Iustin Pop
      if not isinstance(self.op.disks, list):
5161 d61df03e Iustin Pop
        raise errors.OpPrereqError("Invalid parameter 'disks'")
5162 298fe380 Iustin Pop
      if len(self.op.disks) != 2:
5163 298fe380 Iustin Pop
        raise errors.OpPrereqError("Only two-disk configurations supported")
5164 d61df03e Iustin Pop
      for row in self.op.disks:
5165 d61df03e Iustin Pop
        if (not isinstance(row, dict) or
5166 d61df03e Iustin Pop
            "size" not in row or
5167 d61df03e Iustin Pop
            not isinstance(row["size"], int) or
5168 d61df03e Iustin Pop
            "mode" not in row or
5169 d61df03e Iustin Pop
            row["mode"] not in ['r', 'w']):
5170 d61df03e Iustin Pop
          raise errors.OpPrereqError("Invalid contents of the"
5171 d61df03e Iustin Pop
                                     " 'disks' parameter")
5172 298fe380 Iustin Pop
    elif self.op.mode == constants.IALLOCATOR_MODE_RELOC:
5173 d61df03e Iustin Pop
      if not hasattr(self.op, "name"):
5174 d61df03e Iustin Pop
        raise errors.OpPrereqError("Missing attribute 'name' on opcode input")
5175 d61df03e Iustin Pop
      fname = self.cfg.ExpandInstanceName(self.op.name)
5176 d61df03e Iustin Pop
      if fname is None:
5177 d61df03e Iustin Pop
        raise errors.OpPrereqError("Instance '%s' not found for relocation" %
5178 d61df03e Iustin Pop
                                   self.op.name)
5179 d61df03e Iustin Pop
      self.op.name = fname
5180 29859cb7 Iustin Pop
      self.relocate_from = self.cfg.GetInstanceInfo(fname).secondary_nodes
5181 d61df03e Iustin Pop
    else:
5182 d61df03e Iustin Pop
      raise errors.OpPrereqError("Invalid test allocator mode '%s'" %
5183 d61df03e Iustin Pop
                                 self.op.mode)
5184 d61df03e Iustin Pop
5185 298fe380 Iustin Pop
    if self.op.direction == constants.IALLOCATOR_DIR_OUT:
5186 298fe380 Iustin Pop
      if not hasattr(self.op, "allocator") or self.op.allocator is None:
5187 d61df03e Iustin Pop
        raise errors.OpPrereqError("Missing allocator name")
5188 298fe380 Iustin Pop
    elif self.op.direction != constants.IALLOCATOR_DIR_IN:
5189 d61df03e Iustin Pop
      raise errors.OpPrereqError("Wrong allocator test '%s'" %
5190 d61df03e Iustin Pop
                                 self.op.direction)
5191 d61df03e Iustin Pop
5192 d61df03e Iustin Pop
  def Exec(self, feedback_fn):
5193 d61df03e Iustin Pop
    """Run the allocator test.
5194 d61df03e Iustin Pop

5195 d61df03e Iustin Pop
    """
5196 29859cb7 Iustin Pop
    if self.op.mode == constants.IALLOCATOR_MODE_ALLOC:
5197 29859cb7 Iustin Pop
      ial = IAllocator(self.cfg, self.sstore,
5198 29859cb7 Iustin Pop
                       mode=self.op.mode,
5199 29859cb7 Iustin Pop
                       name=self.op.name,
5200 29859cb7 Iustin Pop
                       mem_size=self.op.mem_size,
5201 29859cb7 Iustin Pop
                       disks=self.op.disks,
5202 29859cb7 Iustin Pop
                       disk_template=self.op.disk_template,
5203 29859cb7 Iustin Pop
                       os=self.op.os,
5204 29859cb7 Iustin Pop
                       tags=self.op.tags,
5205 29859cb7 Iustin Pop
                       nics=self.op.nics,
5206 29859cb7 Iustin Pop
                       vcpus=self.op.vcpus,
5207 29859cb7 Iustin Pop
                       )
5208 29859cb7 Iustin Pop
    else:
5209 29859cb7 Iustin Pop
      ial = IAllocator(self.cfg, self.sstore,
5210 29859cb7 Iustin Pop
                       mode=self.op.mode,
5211 29859cb7 Iustin Pop
                       name=self.op.name,
5212 29859cb7 Iustin Pop
                       relocate_from=list(self.relocate_from),
5213 29859cb7 Iustin Pop
                       )
5214 d61df03e Iustin Pop
5215 298fe380 Iustin Pop
    if self.op.direction == constants.IALLOCATOR_DIR_IN:
5216 d1c2dd75 Iustin Pop
      result = ial.in_text
5217 298fe380 Iustin Pop
    else:
5218 d1c2dd75 Iustin Pop
      ial.Run(self.op.allocator, validate=False)
5219 d1c2dd75 Iustin Pop
      result = ial.out_text
5220 298fe380 Iustin Pop
    return result