Statistics
| Branch: | Tag: | Revision:

root / lib / cmdlib.py @ f6441c7c

History | View | Annotate | Download (116.2 kB)

1 a8083063 Iustin Pop
#!/usr/bin/python
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 a8083063 Iustin Pop
# Copyright (C) 2006, 2007 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 socket
30 a8083063 Iustin Pop
import time
31 a8083063 Iustin Pop
import tempfile
32 a8083063 Iustin Pop
import re
33 a8083063 Iustin Pop
import platform
34 a8083063 Iustin Pop
35 a8083063 Iustin Pop
from ganeti import rpc
36 a8083063 Iustin Pop
from ganeti import ssh
37 a8083063 Iustin Pop
from ganeti import logger
38 a8083063 Iustin Pop
from ganeti import utils
39 a8083063 Iustin Pop
from ganeti import errors
40 a8083063 Iustin Pop
from ganeti import hypervisor
41 a8083063 Iustin Pop
from ganeti import config
42 a8083063 Iustin Pop
from ganeti import constants
43 a8083063 Iustin Pop
from ganeti import objects
44 a8083063 Iustin Pop
from ganeti import opcodes
45 a8083063 Iustin Pop
from ganeti import ssconf
46 a8083063 Iustin Pop
47 a8083063 Iustin Pop
class LogicalUnit(object):
48 396e1b78 Michael Hanselmann
  """Logical Unit base class.
49 a8083063 Iustin Pop

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

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

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

72 a8083063 Iustin Pop
    """
73 a8083063 Iustin Pop
    self.processor = processor
74 a8083063 Iustin Pop
    self.op = op
75 a8083063 Iustin Pop
    self.cfg = cfg
76 a8083063 Iustin Pop
    self.sstore = sstore
77 a8083063 Iustin Pop
    for attr_name in self._OP_REQP:
78 a8083063 Iustin Pop
      attr_val = getattr(op, attr_name, None)
79 a8083063 Iustin Pop
      if attr_val is None:
80 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Required parameter '%s' missing" %
81 3ecf6786 Iustin Pop
                                   attr_name)
82 a8083063 Iustin Pop
    if self.REQ_CLUSTER:
83 a8083063 Iustin Pop
      if not cfg.IsCluster():
84 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Cluster not initialized yet,"
85 3ecf6786 Iustin Pop
                                   " use 'gnt-cluster init' first.")
86 a8083063 Iustin Pop
      if self.REQ_MASTER:
87 880478f8 Iustin Pop
        master = sstore.GetMasterNode()
88 a8083063 Iustin Pop
        if master != socket.gethostname():
89 3ecf6786 Iustin Pop
          raise errors.OpPrereqError("Commands must be run on the master"
90 3ecf6786 Iustin Pop
                                     " node %s" % master)
91 a8083063 Iustin Pop
92 a8083063 Iustin Pop
  def CheckPrereq(self):
93 a8083063 Iustin Pop
    """Check prerequisites for this LU.
94 a8083063 Iustin Pop

95 a8083063 Iustin Pop
    This method should check that the prerequisites for the execution
96 a8083063 Iustin Pop
    of this LU are fulfilled. It can do internode communication, but
97 a8083063 Iustin Pop
    it should be idempotent - no cluster or system changes are
98 a8083063 Iustin Pop
    allowed.
99 a8083063 Iustin Pop

100 a8083063 Iustin Pop
    The method should raise errors.OpPrereqError in case something is
101 a8083063 Iustin Pop
    not fulfilled. Its return value is ignored.
102 a8083063 Iustin Pop

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

108 a8083063 Iustin Pop
    """
109 a8083063 Iustin Pop
    raise NotImplementedError
110 a8083063 Iustin Pop
111 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
112 a8083063 Iustin Pop
    """Execute the LU.
113 a8083063 Iustin Pop

114 a8083063 Iustin Pop
    This method should implement the actual work. It should raise
115 a8083063 Iustin Pop
    errors.OpExecError for failures that are somewhat dealt with in
116 a8083063 Iustin Pop
    code, or expected.
117 a8083063 Iustin Pop

118 a8083063 Iustin Pop
    """
119 a8083063 Iustin Pop
    raise NotImplementedError
120 a8083063 Iustin Pop
121 a8083063 Iustin Pop
  def BuildHooksEnv(self):
122 a8083063 Iustin Pop
    """Build hooks environment for this LU.
123 a8083063 Iustin Pop

124 a8083063 Iustin Pop
    This method should return a three-node tuple consisting of: a dict
125 a8083063 Iustin Pop
    containing the environment that will be used for running the
126 a8083063 Iustin Pop
    specific hook for this LU, a list of node names on which the hook
127 a8083063 Iustin Pop
    should run before the execution, and a list of node names on which
128 a8083063 Iustin Pop
    the hook should run after the execution.
129 a8083063 Iustin Pop

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

135 a8083063 Iustin Pop
    As for the node lists, the master should not be included in the
136 a8083063 Iustin Pop
    them, as it will be added by the hooks runner in case this LU
137 a8083063 Iustin Pop
    requires a cluster to run on (otherwise we don't have a node
138 a8083063 Iustin Pop
    list). No nodes should be returned as an empty list (and not
139 a8083063 Iustin Pop
    None).
140 a8083063 Iustin Pop

141 a8083063 Iustin Pop
    Note that if the HPATH for a LU class is None, this function will
142 a8083063 Iustin Pop
    not be called.
143 a8083063 Iustin Pop

144 a8083063 Iustin Pop
    """
145 a8083063 Iustin Pop
    raise NotImplementedError
146 a8083063 Iustin Pop
147 a8083063 Iustin Pop
148 a8083063 Iustin Pop
class NoHooksLU(LogicalUnit):
149 a8083063 Iustin Pop
  """Simple LU which runs no hooks.
150 a8083063 Iustin Pop

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

154 a8083063 Iustin Pop
  """
155 a8083063 Iustin Pop
  HPATH = None
156 a8083063 Iustin Pop
  HTYPE = None
157 a8083063 Iustin Pop
158 a8083063 Iustin Pop
  def BuildHooksEnv(self):
159 a8083063 Iustin Pop
    """Build hooks env.
160 a8083063 Iustin Pop

161 a8083063 Iustin Pop
    This is a no-op, since we don't run hooks.
162 a8083063 Iustin Pop

163 a8083063 Iustin Pop
    """
164 a8083063 Iustin Pop
    return
165 a8083063 Iustin Pop
166 a8083063 Iustin Pop
167 dcb93971 Michael Hanselmann
def _GetWantedNodes(lu, nodes):
168 83120a01 Michael Hanselmann
  """Returns list of checked and expanded nodes.
169 83120a01 Michael Hanselmann

170 83120a01 Michael Hanselmann
  Args:
171 83120a01 Michael Hanselmann
    nodes: List of nodes (strings) or None for all
172 83120a01 Michael Hanselmann

173 83120a01 Michael Hanselmann
  """
174 dcb93971 Michael Hanselmann
  if nodes is not None and not isinstance(nodes, list):
175 3ecf6786 Iustin Pop
    raise errors.OpPrereqError("Invalid argument type 'nodes'")
176 dcb93971 Michael Hanselmann
177 dcb93971 Michael Hanselmann
  if nodes:
178 dcb93971 Michael Hanselmann
    wanted_nodes = []
179 dcb93971 Michael Hanselmann
180 dcb93971 Michael Hanselmann
    for name in nodes:
181 dcb93971 Michael Hanselmann
      node = lu.cfg.GetNodeInfo(lu.cfg.ExpandNodeName(name))
182 dcb93971 Michael Hanselmann
      if node is None:
183 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("No such node name '%s'" % name)
184 dcb93971 Michael Hanselmann
    wanted_nodes.append(node)
185 dcb93971 Michael Hanselmann
186 dcb93971 Michael Hanselmann
    return wanted_nodes
187 dcb93971 Michael Hanselmann
  else:
188 dcb93971 Michael Hanselmann
    return [lu.cfg.GetNodeInfo(name) for name in lu.cfg.GetNodeList()]
189 dcb93971 Michael Hanselmann
190 dcb93971 Michael Hanselmann
191 dcb93971 Michael Hanselmann
def _CheckOutputFields(static, dynamic, selected):
192 83120a01 Michael Hanselmann
  """Checks whether all selected fields are valid.
193 83120a01 Michael Hanselmann

194 83120a01 Michael Hanselmann
  Args:
195 83120a01 Michael Hanselmann
    static: Static fields
196 83120a01 Michael Hanselmann
    dynamic: Dynamic fields
197 83120a01 Michael Hanselmann

198 83120a01 Michael Hanselmann
  """
199 83120a01 Michael Hanselmann
  static_fields = frozenset(static)
200 83120a01 Michael Hanselmann
  dynamic_fields = frozenset(dynamic)
201 dcb93971 Michael Hanselmann
202 83120a01 Michael Hanselmann
  all_fields = static_fields | dynamic_fields
203 dcb93971 Michael Hanselmann
204 83120a01 Michael Hanselmann
  if not all_fields.issuperset(selected):
205 3ecf6786 Iustin Pop
    raise errors.OpPrereqError("Unknown output fields selected: %s"
206 3ecf6786 Iustin Pop
                               % ",".join(frozenset(selected).
207 3ecf6786 Iustin Pop
                                          difference(all_fields)))
208 dcb93971 Michael Hanselmann
209 dcb93971 Michael Hanselmann
210 ecb215b5 Michael Hanselmann
def _BuildInstanceHookEnv(name, primary_node, secondary_nodes, os_type, status,
211 396e1b78 Michael Hanselmann
                          memory, vcpus, nics):
212 ecb215b5 Michael Hanselmann
  """Builds instance related env variables for hooks from single variables.
213 ecb215b5 Michael Hanselmann

214 ecb215b5 Michael Hanselmann
  Args:
215 ecb215b5 Michael Hanselmann
    secondary_nodes: List of secondary nodes as strings
216 396e1b78 Michael Hanselmann
  """
217 396e1b78 Michael Hanselmann
  env = {
218 396e1b78 Michael Hanselmann
    "INSTANCE_NAME": name,
219 396e1b78 Michael Hanselmann
    "INSTANCE_PRIMARY": primary_node,
220 396e1b78 Michael Hanselmann
    "INSTANCE_SECONDARIES": " ".join(secondary_nodes),
221 ecb215b5 Michael Hanselmann
    "INSTANCE_OS_TYPE": os_type,
222 396e1b78 Michael Hanselmann
    "INSTANCE_STATUS": status,
223 396e1b78 Michael Hanselmann
    "INSTANCE_MEMORY": memory,
224 396e1b78 Michael Hanselmann
    "INSTANCE_VCPUS": vcpus,
225 396e1b78 Michael Hanselmann
  }
226 396e1b78 Michael Hanselmann
227 396e1b78 Michael Hanselmann
  if nics:
228 396e1b78 Michael Hanselmann
    nic_count = len(nics)
229 396e1b78 Michael Hanselmann
    for idx, (ip, bridge) in enumerate(nics):
230 396e1b78 Michael Hanselmann
      if ip is None:
231 396e1b78 Michael Hanselmann
        ip = ""
232 396e1b78 Michael Hanselmann
      env["INSTANCE_NIC%d_IP" % idx] = ip
233 396e1b78 Michael Hanselmann
      env["INSTANCE_NIC%d_BRIDGE" % idx] = bridge
234 396e1b78 Michael Hanselmann
  else:
235 396e1b78 Michael Hanselmann
    nic_count = 0
236 396e1b78 Michael Hanselmann
237 396e1b78 Michael Hanselmann
  env["INSTANCE_NIC_COUNT"] = nic_count
238 396e1b78 Michael Hanselmann
239 396e1b78 Michael Hanselmann
  return env
240 396e1b78 Michael Hanselmann
241 396e1b78 Michael Hanselmann
242 396e1b78 Michael Hanselmann
def _BuildInstanceHookEnvByObject(instance, override=None):
243 ecb215b5 Michael Hanselmann
  """Builds instance related env variables for hooks from an object.
244 ecb215b5 Michael Hanselmann

245 ecb215b5 Michael Hanselmann
  Args:
246 ecb215b5 Michael Hanselmann
    instance: objects.Instance object of instance
247 ecb215b5 Michael Hanselmann
    override: dict of values to override
248 ecb215b5 Michael Hanselmann
  """
249 396e1b78 Michael Hanselmann
  args = {
250 396e1b78 Michael Hanselmann
    'name': instance.name,
251 396e1b78 Michael Hanselmann
    'primary_node': instance.primary_node,
252 396e1b78 Michael Hanselmann
    'secondary_nodes': instance.secondary_nodes,
253 ecb215b5 Michael Hanselmann
    'os_type': instance.os,
254 396e1b78 Michael Hanselmann
    'status': instance.os,
255 396e1b78 Michael Hanselmann
    'memory': instance.memory,
256 396e1b78 Michael Hanselmann
    'vcpus': instance.vcpus,
257 396e1b78 Michael Hanselmann
    'nics': [(nic.ip, nic.bridge) for nic in instance.nics],
258 396e1b78 Michael Hanselmann
  }
259 396e1b78 Michael Hanselmann
  if override:
260 396e1b78 Michael Hanselmann
    args.update(override)
261 396e1b78 Michael Hanselmann
  return _BuildInstanceHookEnv(**args)
262 396e1b78 Michael Hanselmann
263 396e1b78 Michael Hanselmann
264 a8083063 Iustin Pop
def _UpdateEtcHosts(fullnode, ip):
265 a8083063 Iustin Pop
  """Ensure a node has a correct entry in /etc/hosts.
266 a8083063 Iustin Pop

267 a8083063 Iustin Pop
  Args:
268 a8083063 Iustin Pop
    fullnode - Fully qualified domain name of host. (str)
269 a8083063 Iustin Pop
    ip       - IPv4 address of host (str)
270 a8083063 Iustin Pop

271 a8083063 Iustin Pop
  """
272 a8083063 Iustin Pop
  node = fullnode.split(".", 1)[0]
273 a8083063 Iustin Pop
274 a8083063 Iustin Pop
  f = open('/etc/hosts', 'r+')
275 a8083063 Iustin Pop
276 a8083063 Iustin Pop
  inthere = False
277 a8083063 Iustin Pop
278 a8083063 Iustin Pop
  save_lines = []
279 a8083063 Iustin Pop
  add_lines = []
280 a8083063 Iustin Pop
  removed = False
281 a8083063 Iustin Pop
282 a8083063 Iustin Pop
  while True:
283 a8083063 Iustin Pop
    rawline = f.readline()
284 a8083063 Iustin Pop
285 a8083063 Iustin Pop
    if not rawline:
286 a8083063 Iustin Pop
      # End of file
287 a8083063 Iustin Pop
      break
288 a8083063 Iustin Pop
289 a8083063 Iustin Pop
    line = rawline.split('\n')[0]
290 a8083063 Iustin Pop
291 a8083063 Iustin Pop
    # Strip off comments
292 a8083063 Iustin Pop
    line = line.split('#')[0]
293 a8083063 Iustin Pop
294 a8083063 Iustin Pop
    if not line:
295 a8083063 Iustin Pop
      # Entire line was comment, skip
296 a8083063 Iustin Pop
      save_lines.append(rawline)
297 a8083063 Iustin Pop
      continue
298 a8083063 Iustin Pop
299 a8083063 Iustin Pop
    fields = line.split()
300 a8083063 Iustin Pop
301 a8083063 Iustin Pop
    haveall = True
302 a8083063 Iustin Pop
    havesome = False
303 a8083063 Iustin Pop
    for spec in [ ip, fullnode, node ]:
304 a8083063 Iustin Pop
      if spec not in fields:
305 a8083063 Iustin Pop
        haveall = False
306 a8083063 Iustin Pop
      if spec in fields:
307 a8083063 Iustin Pop
        havesome = True
308 a8083063 Iustin Pop
309 a8083063 Iustin Pop
    if haveall:
310 a8083063 Iustin Pop
      inthere = True
311 a8083063 Iustin Pop
      save_lines.append(rawline)
312 a8083063 Iustin Pop
      continue
313 a8083063 Iustin Pop
314 a8083063 Iustin Pop
    if havesome and not haveall:
315 a8083063 Iustin Pop
      # Line (old, or manual?) which is missing some.  Remove.
316 a8083063 Iustin Pop
      removed = True
317 a8083063 Iustin Pop
      continue
318 a8083063 Iustin Pop
319 a8083063 Iustin Pop
    save_lines.append(rawline)
320 a8083063 Iustin Pop
321 a8083063 Iustin Pop
  if not inthere:
322 a8083063 Iustin Pop
    add_lines.append('%s\t%s %s\n' % (ip, fullnode, node))
323 a8083063 Iustin Pop
324 a8083063 Iustin Pop
  if removed:
325 a8083063 Iustin Pop
    if add_lines:
326 a8083063 Iustin Pop
      save_lines = save_lines + add_lines
327 a8083063 Iustin Pop
328 a8083063 Iustin Pop
    # We removed a line, write a new file and replace old.
329 a8083063 Iustin Pop
    fd, tmpname = tempfile.mkstemp('tmp', 'hosts_', '/etc')
330 a8083063 Iustin Pop
    newfile = os.fdopen(fd, 'w')
331 a8083063 Iustin Pop
    newfile.write(''.join(save_lines))
332 a8083063 Iustin Pop
    newfile.close()
333 a8083063 Iustin Pop
    os.rename(tmpname, '/etc/hosts')
334 a8083063 Iustin Pop
335 a8083063 Iustin Pop
  elif add_lines:
336 a8083063 Iustin Pop
    # Simply appending a new line will do the trick.
337 a8083063 Iustin Pop
    f.seek(0, 2)
338 a8083063 Iustin Pop
    for add in add_lines:
339 a8083063 Iustin Pop
      f.write(add)
340 a8083063 Iustin Pop
341 a8083063 Iustin Pop
  f.close()
342 a8083063 Iustin Pop
343 a8083063 Iustin Pop
344 a8083063 Iustin Pop
def _UpdateKnownHosts(fullnode, ip, pubkey):
345 a8083063 Iustin Pop
  """Ensure a node has a correct known_hosts entry.
346 a8083063 Iustin Pop

347 a8083063 Iustin Pop
  Args:
348 a8083063 Iustin Pop
    fullnode - Fully qualified domain name of host. (str)
349 a8083063 Iustin Pop
    ip       - IPv4 address of host (str)
350 a8083063 Iustin Pop
    pubkey   - the public key of the cluster
351 a8083063 Iustin Pop

352 a8083063 Iustin Pop
  """
353 82122173 Iustin Pop
  if os.path.exists(constants.SSH_KNOWN_HOSTS_FILE):
354 82122173 Iustin Pop
    f = open(constants.SSH_KNOWN_HOSTS_FILE, 'r+')
355 a8083063 Iustin Pop
  else:
356 82122173 Iustin Pop
    f = open(constants.SSH_KNOWN_HOSTS_FILE, 'w+')
357 a8083063 Iustin Pop
358 a8083063 Iustin Pop
  inthere = False
359 a8083063 Iustin Pop
360 a8083063 Iustin Pop
  save_lines = []
361 a8083063 Iustin Pop
  add_lines = []
362 a8083063 Iustin Pop
  removed = False
363 a8083063 Iustin Pop
364 a8083063 Iustin Pop
  while True:
365 a8083063 Iustin Pop
    rawline = f.readline()
366 a8083063 Iustin Pop
    logger.Debug('read %s' % (repr(rawline),))
367 a8083063 Iustin Pop
368 a8083063 Iustin Pop
    if not rawline:
369 a8083063 Iustin Pop
      # End of file
370 a8083063 Iustin Pop
      break
371 a8083063 Iustin Pop
372 a8083063 Iustin Pop
    line = rawline.split('\n')[0]
373 a8083063 Iustin Pop
374 a8083063 Iustin Pop
    parts = line.split(' ')
375 a8083063 Iustin Pop
    fields = parts[0].split(',')
376 a8083063 Iustin Pop
    key = parts[2]
377 a8083063 Iustin Pop
378 a8083063 Iustin Pop
    haveall = True
379 a8083063 Iustin Pop
    havesome = False
380 a8083063 Iustin Pop
    for spec in [ ip, fullnode ]:
381 a8083063 Iustin Pop
      if spec not in fields:
382 a8083063 Iustin Pop
        haveall = False
383 a8083063 Iustin Pop
      if spec in fields:
384 a8083063 Iustin Pop
        havesome = True
385 a8083063 Iustin Pop
386 a8083063 Iustin Pop
    logger.Debug("key, pubkey = %s." % (repr((key, pubkey)),))
387 a8083063 Iustin Pop
    if haveall and key == pubkey:
388 a8083063 Iustin Pop
      inthere = True
389 a8083063 Iustin Pop
      save_lines.append(rawline)
390 a8083063 Iustin Pop
      logger.Debug("Keeping known_hosts '%s'." % (repr(rawline),))
391 a8083063 Iustin Pop
      continue
392 a8083063 Iustin Pop
393 a8083063 Iustin Pop
    if havesome and (not haveall or key != pubkey):
394 a8083063 Iustin Pop
      removed = True
395 a8083063 Iustin Pop
      logger.Debug("Discarding known_hosts '%s'." % (repr(rawline),))
396 a8083063 Iustin Pop
      continue
397 a8083063 Iustin Pop
398 a8083063 Iustin Pop
    save_lines.append(rawline)
399 a8083063 Iustin Pop
400 a8083063 Iustin Pop
  if not inthere:
401 a8083063 Iustin Pop
    add_lines.append('%s,%s ssh-rsa %s\n' % (fullnode, ip, pubkey))
402 a8083063 Iustin Pop
    logger.Debug("Adding known_hosts '%s'." % (repr(add_lines[-1]),))
403 a8083063 Iustin Pop
404 a8083063 Iustin Pop
  if removed:
405 a8083063 Iustin Pop
    save_lines = save_lines + add_lines
406 a8083063 Iustin Pop
407 a8083063 Iustin Pop
    # Write a new file and replace old.
408 82122173 Iustin Pop
    fd, tmpname = tempfile.mkstemp('.tmp', 'known_hosts.',
409 82122173 Iustin Pop
                                   constants.DATA_DIR)
410 a8083063 Iustin Pop
    newfile = os.fdopen(fd, 'w')
411 82122173 Iustin Pop
    try:
412 82122173 Iustin Pop
      newfile.write(''.join(save_lines))
413 82122173 Iustin Pop
    finally:
414 82122173 Iustin Pop
      newfile.close()
415 a8083063 Iustin Pop
    logger.Debug("Wrote new known_hosts.")
416 82122173 Iustin Pop
    os.rename(tmpname, constants.SSH_KNOWN_HOSTS_FILE)
417 a8083063 Iustin Pop
418 a8083063 Iustin Pop
  elif add_lines:
419 a8083063 Iustin Pop
    # Simply appending a new line will do the trick.
420 a8083063 Iustin Pop
    f.seek(0, 2)
421 a8083063 Iustin Pop
    for add in add_lines:
422 a8083063 Iustin Pop
      f.write(add)
423 a8083063 Iustin Pop
424 a8083063 Iustin Pop
  f.close()
425 a8083063 Iustin Pop
426 a8083063 Iustin Pop
427 a8083063 Iustin Pop
def _HasValidVG(vglist, vgname):
428 a8083063 Iustin Pop
  """Checks if the volume group list is valid.
429 a8083063 Iustin Pop

430 a8083063 Iustin Pop
  A non-None return value means there's an error, and the return value
431 a8083063 Iustin Pop
  is the error message.
432 a8083063 Iustin Pop

433 a8083063 Iustin Pop
  """
434 a8083063 Iustin Pop
  vgsize = vglist.get(vgname, None)
435 a8083063 Iustin Pop
  if vgsize is None:
436 a8083063 Iustin Pop
    return "volume group '%s' missing" % vgname
437 a8083063 Iustin Pop
  elif vgsize < 20480:
438 191a8385 Guido Trotter
    return ("volume group '%s' too small (20480MiB required, %dMib found)" %
439 191a8385 Guido Trotter
            (vgname, vgsize))
440 a8083063 Iustin Pop
  return None
441 a8083063 Iustin Pop
442 a8083063 Iustin Pop
443 a8083063 Iustin Pop
def _InitSSHSetup(node):
444 a8083063 Iustin Pop
  """Setup the SSH configuration for the cluster.
445 a8083063 Iustin Pop

446 a8083063 Iustin Pop

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

450 a8083063 Iustin Pop
  Args:
451 a8083063 Iustin Pop
    node: the name of this host as a fqdn
452 a8083063 Iustin Pop

453 a8083063 Iustin Pop
  """
454 a8083063 Iustin Pop
  if os.path.exists('/root/.ssh/id_dsa'):
455 a8083063 Iustin Pop
    utils.CreateBackup('/root/.ssh/id_dsa')
456 a8083063 Iustin Pop
  if os.path.exists('/root/.ssh/id_dsa.pub'):
457 a8083063 Iustin Pop
    utils.CreateBackup('/root/.ssh/id_dsa.pub')
458 a8083063 Iustin Pop
459 a8083063 Iustin Pop
  utils.RemoveFile('/root/.ssh/id_dsa')
460 a8083063 Iustin Pop
  utils.RemoveFile('/root/.ssh/id_dsa.pub')
461 a8083063 Iustin Pop
462 a8083063 Iustin Pop
  result = utils.RunCmd(["ssh-keygen", "-t", "dsa",
463 a8083063 Iustin Pop
                         "-f", "/root/.ssh/id_dsa",
464 a8083063 Iustin Pop
                         "-q", "-N", ""])
465 a8083063 Iustin Pop
  if result.failed:
466 3ecf6786 Iustin Pop
    raise errors.OpExecError("Could not generate ssh keypair, error %s" %
467 3ecf6786 Iustin Pop
                             result.output)
468 a8083063 Iustin Pop
469 a8083063 Iustin Pop
  f = open('/root/.ssh/id_dsa.pub', 'r')
470 a8083063 Iustin Pop
  try:
471 a8083063 Iustin Pop
    utils.AddAuthorizedKey('/root/.ssh/authorized_keys', f.read(8192))
472 a8083063 Iustin Pop
  finally:
473 a8083063 Iustin Pop
    f.close()
474 a8083063 Iustin Pop
475 a8083063 Iustin Pop
476 a8083063 Iustin Pop
def _InitGanetiServerSetup(ss):
477 a8083063 Iustin Pop
  """Setup the necessary configuration for the initial node daemon.
478 a8083063 Iustin Pop

479 a8083063 Iustin Pop
  This creates the nodepass file containing the shared password for
480 a8083063 Iustin Pop
  the cluster and also generates the SSL certificate.
481 a8083063 Iustin Pop

482 a8083063 Iustin Pop
  """
483 a8083063 Iustin Pop
  # Create pseudo random password
484 a8083063 Iustin Pop
  randpass = sha.new(os.urandom(64)).hexdigest()
485 a8083063 Iustin Pop
  # and write it into sstore
486 a8083063 Iustin Pop
  ss.SetKey(ss.SS_NODED_PASS, randpass)
487 a8083063 Iustin Pop
488 a8083063 Iustin Pop
  result = utils.RunCmd(["openssl", "req", "-new", "-newkey", "rsa:1024",
489 a8083063 Iustin Pop
                         "-days", str(365*5), "-nodes", "-x509",
490 a8083063 Iustin Pop
                         "-keyout", constants.SSL_CERT_FILE,
491 a8083063 Iustin Pop
                         "-out", constants.SSL_CERT_FILE, "-batch"])
492 a8083063 Iustin Pop
  if result.failed:
493 3ecf6786 Iustin Pop
    raise errors.OpExecError("could not generate server ssl cert, command"
494 3ecf6786 Iustin Pop
                             " %s had exitcode %s and error message %s" %
495 3ecf6786 Iustin Pop
                             (result.cmd, result.exit_code, result.output))
496 a8083063 Iustin Pop
497 a8083063 Iustin Pop
  os.chmod(constants.SSL_CERT_FILE, 0400)
498 a8083063 Iustin Pop
499 a8083063 Iustin Pop
  result = utils.RunCmd([constants.NODE_INITD_SCRIPT, "restart"])
500 a8083063 Iustin Pop
501 a8083063 Iustin Pop
  if result.failed:
502 3ecf6786 Iustin Pop
    raise errors.OpExecError("Could not start the node daemon, command %s"
503 3ecf6786 Iustin Pop
                             " had exitcode %s and error %s" %
504 3ecf6786 Iustin Pop
                             (result.cmd, result.exit_code, result.output))
505 a8083063 Iustin Pop
506 a8083063 Iustin Pop
507 a8083063 Iustin Pop
class LUInitCluster(LogicalUnit):
508 a8083063 Iustin Pop
  """Initialise the cluster.
509 a8083063 Iustin Pop

510 a8083063 Iustin Pop
  """
511 a8083063 Iustin Pop
  HPATH = "cluster-init"
512 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_CLUSTER
513 a8083063 Iustin Pop
  _OP_REQP = ["cluster_name", "hypervisor_type", "vg_name", "mac_prefix",
514 880478f8 Iustin Pop
              "def_bridge", "master_netdev"]
515 a8083063 Iustin Pop
  REQ_CLUSTER = False
516 a8083063 Iustin Pop
517 a8083063 Iustin Pop
  def BuildHooksEnv(self):
518 a8083063 Iustin Pop
    """Build hooks env.
519 a8083063 Iustin Pop

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

523 a8083063 Iustin Pop
    """
524 396e1b78 Michael Hanselmann
    env = {
525 396e1b78 Michael Hanselmann
      "CLUSTER": self.op.cluster_name,
526 396e1b78 Michael Hanselmann
      "MASTER": self.hostname['hostname_full'],
527 396e1b78 Michael Hanselmann
      }
528 a8083063 Iustin Pop
    return env, [], [self.hostname['hostname_full']]
529 a8083063 Iustin Pop
530 a8083063 Iustin Pop
  def CheckPrereq(self):
531 a8083063 Iustin Pop
    """Verify that the passed name is a valid one.
532 a8083063 Iustin Pop

533 a8083063 Iustin Pop
    """
534 a8083063 Iustin Pop
    if config.ConfigWriter.IsCluster():
535 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Cluster is already initialised")
536 a8083063 Iustin Pop
537 a8083063 Iustin Pop
    hostname_local = socket.gethostname()
538 a8083063 Iustin Pop
    self.hostname = hostname = utils.LookupHostname(hostname_local)
539 a8083063 Iustin Pop
    if not hostname:
540 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Cannot resolve my own hostname ('%s')" %
541 3ecf6786 Iustin Pop
                                 hostname_local)
542 a8083063 Iustin Pop
543 ff98055b Iustin Pop
    if hostname["hostname_full"] != hostname_local:
544 ff98055b Iustin Pop
      raise errors.OpPrereqError("My own hostname (%s) does not match the"
545 ff98055b Iustin Pop
                                 " resolver (%s): probably not using FQDN"
546 ff98055b Iustin Pop
                                 " for hostname." %
547 ff98055b Iustin Pop
                                 (hostname_local, hostname["hostname_full"]))
548 ff98055b Iustin Pop
549 130e907e Iustin Pop
    if hostname["ip"].startswith("127."):
550 130e907e Iustin Pop
      raise errors.OpPrereqError("This host's IP resolves to the private"
551 130e907e Iustin Pop
                                 " range (%s). Please fix DNS or /etc/hosts." %
552 130e907e Iustin Pop
                                 (hostname["ip"],))
553 130e907e Iustin Pop
554 a8083063 Iustin Pop
    self.clustername = clustername = utils.LookupHostname(self.op.cluster_name)
555 a8083063 Iustin Pop
    if not clustername:
556 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Cannot resolve given cluster name ('%s')"
557 3ecf6786 Iustin Pop
                                 % self.op.cluster_name)
558 a8083063 Iustin Pop
559 a8083063 Iustin Pop
    result = utils.RunCmd(["fping", "-S127.0.0.1", "-q", hostname['ip']])
560 a8083063 Iustin Pop
    if result.failed:
561 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Inconsistency: this host's name resolves"
562 3ecf6786 Iustin Pop
                                 " to %s,\nbut this ip address does not"
563 3ecf6786 Iustin Pop
                                 " belong to this host."
564 3ecf6786 Iustin Pop
                                 " Aborting." % hostname['ip'])
565 a8083063 Iustin Pop
566 a8083063 Iustin Pop
    secondary_ip = getattr(self.op, "secondary_ip", None)
567 a8083063 Iustin Pop
    if secondary_ip and not utils.IsValidIP(secondary_ip):
568 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Invalid secondary ip given")
569 a8083063 Iustin Pop
    if secondary_ip and secondary_ip != hostname['ip']:
570 a8083063 Iustin Pop
      result = utils.RunCmd(["fping", "-S127.0.0.1", "-q", secondary_ip])
571 a8083063 Iustin Pop
      if result.failed:
572 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("You gave %s as secondary IP,\n"
573 3ecf6786 Iustin Pop
                                   "but it does not belong to this host." %
574 3ecf6786 Iustin Pop
                                   secondary_ip)
575 a8083063 Iustin Pop
    self.secondary_ip = secondary_ip
576 a8083063 Iustin Pop
577 a8083063 Iustin Pop
    # checks presence of the volume group given
578 a8083063 Iustin Pop
    vgstatus = _HasValidVG(utils.ListVolumeGroups(), self.op.vg_name)
579 a8083063 Iustin Pop
580 a8083063 Iustin Pop
    if vgstatus:
581 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Error: %s" % vgstatus)
582 a8083063 Iustin Pop
583 a8083063 Iustin Pop
    if not re.match("^[0-9a-z]{2}:[0-9a-z]{2}:[0-9a-z]{2}$",
584 a8083063 Iustin Pop
                    self.op.mac_prefix):
585 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Invalid mac prefix given '%s'" %
586 3ecf6786 Iustin Pop
                                 self.op.mac_prefix)
587 a8083063 Iustin Pop
588 a8083063 Iustin Pop
    if self.op.hypervisor_type not in hypervisor.VALID_HTYPES:
589 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Invalid hypervisor type given '%s'" %
590 3ecf6786 Iustin Pop
                                 self.op.hypervisor_type)
591 a8083063 Iustin Pop
592 880478f8 Iustin Pop
    result = utils.RunCmd(["ip", "link", "show", "dev", self.op.master_netdev])
593 880478f8 Iustin Pop
    if result.failed:
594 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Invalid master netdev given (%s): '%s'" %
595 8925faaa Iustin Pop
                                 (self.op.master_netdev,
596 8925faaa Iustin Pop
                                  result.output.strip()))
597 880478f8 Iustin Pop
598 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
599 a8083063 Iustin Pop
    """Initialize the cluster.
600 a8083063 Iustin Pop

601 a8083063 Iustin Pop
    """
602 a8083063 Iustin Pop
    clustername = self.clustername
603 a8083063 Iustin Pop
    hostname = self.hostname
604 a8083063 Iustin Pop
605 a8083063 Iustin Pop
    # set up the simple store
606 a8083063 Iustin Pop
    ss = ssconf.SimpleStore()
607 a8083063 Iustin Pop
    ss.SetKey(ss.SS_HYPERVISOR, self.op.hypervisor_type)
608 880478f8 Iustin Pop
    ss.SetKey(ss.SS_MASTER_NODE, hostname['hostname_full'])
609 880478f8 Iustin Pop
    ss.SetKey(ss.SS_MASTER_IP, clustername['ip'])
610 880478f8 Iustin Pop
    ss.SetKey(ss.SS_MASTER_NETDEV, self.op.master_netdev)
611 5fcdc80d Iustin Pop
    ss.SetKey(ss.SS_CLUSTER_NAME, clustername['hostname'])
612 a8083063 Iustin Pop
613 a8083063 Iustin Pop
    # set up the inter-node password and certificate
614 a8083063 Iustin Pop
    _InitGanetiServerSetup(ss)
615 a8083063 Iustin Pop
616 a8083063 Iustin Pop
    # start the master ip
617 a8083063 Iustin Pop
    rpc.call_node_start_master(hostname['hostname_full'])
618 a8083063 Iustin Pop
619 a8083063 Iustin Pop
    # set up ssh config and /etc/hosts
620 a8083063 Iustin Pop
    f = open('/etc/ssh/ssh_host_rsa_key.pub', 'r')
621 a8083063 Iustin Pop
    try:
622 a8083063 Iustin Pop
      sshline = f.read()
623 a8083063 Iustin Pop
    finally:
624 a8083063 Iustin Pop
      f.close()
625 a8083063 Iustin Pop
    sshkey = sshline.split(" ")[1]
626 a8083063 Iustin Pop
627 a8083063 Iustin Pop
    _UpdateEtcHosts(hostname['hostname_full'],
628 a8083063 Iustin Pop
                    hostname['ip'],
629 a8083063 Iustin Pop
                    )
630 a8083063 Iustin Pop
631 a8083063 Iustin Pop
    _UpdateKnownHosts(hostname['hostname_full'],
632 a8083063 Iustin Pop
                      hostname['ip'],
633 a8083063 Iustin Pop
                      sshkey,
634 a8083063 Iustin Pop
                      )
635 a8083063 Iustin Pop
636 a8083063 Iustin Pop
    _InitSSHSetup(hostname['hostname'])
637 a8083063 Iustin Pop
638 a8083063 Iustin Pop
    # init of cluster config file
639 a8083063 Iustin Pop
    cfgw = config.ConfigWriter()
640 a8083063 Iustin Pop
    cfgw.InitConfig(hostname['hostname'], hostname['ip'], self.secondary_ip,
641 5fcdc80d Iustin Pop
                    sshkey, self.op.mac_prefix,
642 a8083063 Iustin Pop
                    self.op.vg_name, self.op.def_bridge)
643 a8083063 Iustin Pop
644 a8083063 Iustin Pop
645 a8083063 Iustin Pop
class LUDestroyCluster(NoHooksLU):
646 a8083063 Iustin Pop
  """Logical unit for destroying the cluster.
647 a8083063 Iustin Pop

648 a8083063 Iustin Pop
  """
649 a8083063 Iustin Pop
  _OP_REQP = []
650 a8083063 Iustin Pop
651 a8083063 Iustin Pop
  def CheckPrereq(self):
652 a8083063 Iustin Pop
    """Check prerequisites.
653 a8083063 Iustin Pop

654 a8083063 Iustin Pop
    This checks whether the cluster is empty.
655 a8083063 Iustin Pop

656 a8083063 Iustin Pop
    Any errors are signalled by raising errors.OpPrereqError.
657 a8083063 Iustin Pop

658 a8083063 Iustin Pop
    """
659 880478f8 Iustin Pop
    master = self.sstore.GetMasterNode()
660 a8083063 Iustin Pop
661 a8083063 Iustin Pop
    nodelist = self.cfg.GetNodeList()
662 db915bd1 Michael Hanselmann
    if len(nodelist) != 1 or nodelist[0] != master:
663 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("There are still %d node(s) in"
664 3ecf6786 Iustin Pop
                                 " this cluster." % (len(nodelist) - 1))
665 db915bd1 Michael Hanselmann
    instancelist = self.cfg.GetInstanceList()
666 db915bd1 Michael Hanselmann
    if instancelist:
667 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("There are still %d instance(s) in"
668 3ecf6786 Iustin Pop
                                 " this cluster." % len(instancelist))
669 a8083063 Iustin Pop
670 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
671 a8083063 Iustin Pop
    """Destroys the cluster.
672 a8083063 Iustin Pop

673 a8083063 Iustin Pop
    """
674 a8083063 Iustin Pop
    utils.CreateBackup('/root/.ssh/id_dsa')
675 a8083063 Iustin Pop
    utils.CreateBackup('/root/.ssh/id_dsa.pub')
676 880478f8 Iustin Pop
    rpc.call_node_leave_cluster(self.sstore.GetMasterNode())
677 a8083063 Iustin Pop
678 a8083063 Iustin Pop
679 a8083063 Iustin Pop
class LUVerifyCluster(NoHooksLU):
680 a8083063 Iustin Pop
  """Verifies the cluster status.
681 a8083063 Iustin Pop

682 a8083063 Iustin Pop
  """
683 a8083063 Iustin Pop
  _OP_REQP = []
684 a8083063 Iustin Pop
685 a8083063 Iustin Pop
  def _VerifyNode(self, node, file_list, local_cksum, vglist, node_result,
686 a8083063 Iustin Pop
                  remote_version, feedback_fn):
687 a8083063 Iustin Pop
    """Run multiple tests against a node.
688 a8083063 Iustin Pop

689 a8083063 Iustin Pop
    Test list:
690 a8083063 Iustin Pop
      - compares ganeti version
691 a8083063 Iustin Pop
      - checks vg existance and size > 20G
692 a8083063 Iustin Pop
      - checks config file checksum
693 a8083063 Iustin Pop
      - checks ssh to other nodes
694 a8083063 Iustin Pop

695 a8083063 Iustin Pop
    Args:
696 a8083063 Iustin Pop
      node: name of the node to check
697 a8083063 Iustin Pop
      file_list: required list of files
698 a8083063 Iustin Pop
      local_cksum: dictionary of local files and their checksums
699 098c0958 Michael Hanselmann

700 a8083063 Iustin Pop
    """
701 a8083063 Iustin Pop
    # compares ganeti version
702 a8083063 Iustin Pop
    local_version = constants.PROTOCOL_VERSION
703 a8083063 Iustin Pop
    if not remote_version:
704 a8083063 Iustin Pop
      feedback_fn(" - ERROR: connection to %s failed" % (node))
705 a8083063 Iustin Pop
      return True
706 a8083063 Iustin Pop
707 a8083063 Iustin Pop
    if local_version != remote_version:
708 a8083063 Iustin Pop
      feedback_fn("  - ERROR: sw version mismatch: master %s, node(%s) %s" %
709 a8083063 Iustin Pop
                      (local_version, node, remote_version))
710 a8083063 Iustin Pop
      return True
711 a8083063 Iustin Pop
712 a8083063 Iustin Pop
    # checks vg existance and size > 20G
713 a8083063 Iustin Pop
714 a8083063 Iustin Pop
    bad = False
715 a8083063 Iustin Pop
    if not vglist:
716 a8083063 Iustin Pop
      feedback_fn("  - ERROR: unable to check volume groups on node %s." %
717 a8083063 Iustin Pop
                      (node,))
718 a8083063 Iustin Pop
      bad = True
719 a8083063 Iustin Pop
    else:
720 a8083063 Iustin Pop
      vgstatus = _HasValidVG(vglist, self.cfg.GetVGName())
721 a8083063 Iustin Pop
      if vgstatus:
722 a8083063 Iustin Pop
        feedback_fn("  - ERROR: %s on node %s" % (vgstatus, node))
723 a8083063 Iustin Pop
        bad = True
724 a8083063 Iustin Pop
725 a8083063 Iustin Pop
    # checks config file checksum
726 a8083063 Iustin Pop
    # checks ssh to any
727 a8083063 Iustin Pop
728 a8083063 Iustin Pop
    if 'filelist' not in node_result:
729 a8083063 Iustin Pop
      bad = True
730 a8083063 Iustin Pop
      feedback_fn("  - ERROR: node hasn't returned file checksum data")
731 a8083063 Iustin Pop
    else:
732 a8083063 Iustin Pop
      remote_cksum = node_result['filelist']
733 a8083063 Iustin Pop
      for file_name in file_list:
734 a8083063 Iustin Pop
        if file_name not in remote_cksum:
735 a8083063 Iustin Pop
          bad = True
736 a8083063 Iustin Pop
          feedback_fn("  - ERROR: file '%s' missing" % file_name)
737 a8083063 Iustin Pop
        elif remote_cksum[file_name] != local_cksum[file_name]:
738 a8083063 Iustin Pop
          bad = True
739 a8083063 Iustin Pop
          feedback_fn("  - ERROR: file '%s' has wrong checksum" % file_name)
740 a8083063 Iustin Pop
741 a8083063 Iustin Pop
    if 'nodelist' not in node_result:
742 a8083063 Iustin Pop
      bad = True
743 a8083063 Iustin Pop
      feedback_fn("  - ERROR: node hasn't returned node connectivity data")
744 a8083063 Iustin Pop
    else:
745 a8083063 Iustin Pop
      if node_result['nodelist']:
746 a8083063 Iustin Pop
        bad = True
747 a8083063 Iustin Pop
        for node in node_result['nodelist']:
748 a8083063 Iustin Pop
          feedback_fn("  - ERROR: communication with node '%s': %s" %
749 a8083063 Iustin Pop
                          (node, node_result['nodelist'][node]))
750 a8083063 Iustin Pop
    hyp_result = node_result.get('hypervisor', None)
751 a8083063 Iustin Pop
    if hyp_result is not None:
752 a8083063 Iustin Pop
      feedback_fn("  - ERROR: hypervisor verify failure: '%s'" % hyp_result)
753 a8083063 Iustin Pop
    return bad
754 a8083063 Iustin Pop
755 a8083063 Iustin Pop
  def _VerifyInstance(self, instance, node_vol_is, node_instance, feedback_fn):
756 a8083063 Iustin Pop
    """Verify an instance.
757 a8083063 Iustin Pop

758 a8083063 Iustin Pop
    This function checks to see if the required block devices are
759 a8083063 Iustin Pop
    available on the instance's node.
760 a8083063 Iustin Pop

761 a8083063 Iustin Pop
    """
762 a8083063 Iustin Pop
    bad = False
763 a8083063 Iustin Pop
764 a8083063 Iustin Pop
    instancelist = self.cfg.GetInstanceList()
765 a8083063 Iustin Pop
    if not instance in instancelist:
766 a8083063 Iustin Pop
      feedback_fn("  - ERROR: instance %s not in instance list %s" %
767 a8083063 Iustin Pop
                      (instance, instancelist))
768 a8083063 Iustin Pop
      bad = True
769 a8083063 Iustin Pop
770 a8083063 Iustin Pop
    instanceconfig = self.cfg.GetInstanceInfo(instance)
771 a8083063 Iustin Pop
    node_current = instanceconfig.primary_node
772 a8083063 Iustin Pop
773 a8083063 Iustin Pop
    node_vol_should = {}
774 a8083063 Iustin Pop
    instanceconfig.MapLVsByNode(node_vol_should)
775 a8083063 Iustin Pop
776 a8083063 Iustin Pop
    for node in node_vol_should:
777 a8083063 Iustin Pop
      for volume in node_vol_should[node]:
778 a8083063 Iustin Pop
        if node not in node_vol_is or volume not in node_vol_is[node]:
779 a8083063 Iustin Pop
          feedback_fn("  - ERROR: volume %s missing on node %s" %
780 a8083063 Iustin Pop
                          (volume, node))
781 a8083063 Iustin Pop
          bad = True
782 a8083063 Iustin Pop
783 a8083063 Iustin Pop
    if not instanceconfig.status == 'down':
784 a8083063 Iustin Pop
      if not instance in node_instance[node_current]:
785 a8083063 Iustin Pop
        feedback_fn("  - ERROR: instance %s not running on node %s" %
786 a8083063 Iustin Pop
                        (instance, node_current))
787 a8083063 Iustin Pop
        bad = True
788 a8083063 Iustin Pop
789 a8083063 Iustin Pop
    for node in node_instance:
790 a8083063 Iustin Pop
      if (not node == node_current):
791 a8083063 Iustin Pop
        if instance in node_instance[node]:
792 a8083063 Iustin Pop
          feedback_fn("  - ERROR: instance %s should not run on node %s" %
793 a8083063 Iustin Pop
                          (instance, node))
794 a8083063 Iustin Pop
          bad = True
795 a8083063 Iustin Pop
796 a8083063 Iustin Pop
    return not bad
797 a8083063 Iustin Pop
798 a8083063 Iustin Pop
  def _VerifyOrphanVolumes(self, node_vol_should, node_vol_is, feedback_fn):
799 a8083063 Iustin Pop
    """Verify if there are any unknown volumes in the cluster.
800 a8083063 Iustin Pop

801 a8083063 Iustin Pop
    The .os, .swap and backup volumes are ignored. All other volumes are
802 a8083063 Iustin Pop
    reported as unknown.
803 a8083063 Iustin Pop

804 a8083063 Iustin Pop
    """
805 a8083063 Iustin Pop
    bad = False
806 a8083063 Iustin Pop
807 a8083063 Iustin Pop
    for node in node_vol_is:
808 a8083063 Iustin Pop
      for volume in node_vol_is[node]:
809 a8083063 Iustin Pop
        if node not in node_vol_should or volume not in node_vol_should[node]:
810 a8083063 Iustin Pop
          feedback_fn("  - ERROR: volume %s on node %s should not exist" %
811 a8083063 Iustin Pop
                      (volume, node))
812 a8083063 Iustin Pop
          bad = True
813 a8083063 Iustin Pop
    return bad
814 a8083063 Iustin Pop
815 a8083063 Iustin Pop
  def _VerifyOrphanInstances(self, instancelist, node_instance, feedback_fn):
816 a8083063 Iustin Pop
    """Verify the list of running instances.
817 a8083063 Iustin Pop

818 a8083063 Iustin Pop
    This checks what instances are running but unknown to the cluster.
819 a8083063 Iustin Pop

820 a8083063 Iustin Pop
    """
821 a8083063 Iustin Pop
    bad = False
822 a8083063 Iustin Pop
    for node in node_instance:
823 a8083063 Iustin Pop
      for runninginstance in node_instance[node]:
824 a8083063 Iustin Pop
        if runninginstance not in instancelist:
825 a8083063 Iustin Pop
          feedback_fn("  - ERROR: instance %s on node %s should not exist" %
826 a8083063 Iustin Pop
                          (runninginstance, node))
827 a8083063 Iustin Pop
          bad = True
828 a8083063 Iustin Pop
    return bad
829 a8083063 Iustin Pop
830 a8083063 Iustin Pop
  def CheckPrereq(self):
831 a8083063 Iustin Pop
    """Check prerequisites.
832 a8083063 Iustin Pop

833 a8083063 Iustin Pop
    This has no prerequisites.
834 a8083063 Iustin Pop

835 a8083063 Iustin Pop
    """
836 a8083063 Iustin Pop
    pass
837 a8083063 Iustin Pop
838 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
839 a8083063 Iustin Pop
    """Verify integrity of cluster, performing various test on nodes.
840 a8083063 Iustin Pop

841 a8083063 Iustin Pop
    """
842 a8083063 Iustin Pop
    bad = False
843 a8083063 Iustin Pop
    feedback_fn("* Verifying global settings")
844 a8083063 Iustin Pop
    self.cfg.VerifyConfig()
845 a8083063 Iustin Pop
846 880478f8 Iustin Pop
    master = self.sstore.GetMasterNode()
847 a8083063 Iustin Pop
    vg_name = self.cfg.GetVGName()
848 a8083063 Iustin Pop
    nodelist = utils.NiceSort(self.cfg.GetNodeList())
849 a8083063 Iustin Pop
    instancelist = utils.NiceSort(self.cfg.GetInstanceList())
850 a8083063 Iustin Pop
    node_volume = {}
851 a8083063 Iustin Pop
    node_instance = {}
852 a8083063 Iustin Pop
853 a8083063 Iustin Pop
    # FIXME: verify OS list
854 a8083063 Iustin Pop
    # do local checksums
855 cb91d46e Iustin Pop
    file_names = list(self.sstore.GetFileList())
856 cb91d46e Iustin Pop
    file_names.append(constants.SSL_CERT_FILE)
857 cb91d46e Iustin Pop
    file_names.append(constants.CLUSTER_CONF_FILE)
858 a8083063 Iustin Pop
    local_checksums = utils.FingerprintFiles(file_names)
859 a8083063 Iustin Pop
860 a8083063 Iustin Pop
    feedback_fn("* Gathering data (%d nodes)" % len(nodelist))
861 a8083063 Iustin Pop
    all_volumeinfo = rpc.call_volume_list(nodelist, vg_name)
862 a8083063 Iustin Pop
    all_instanceinfo = rpc.call_instance_list(nodelist)
863 a8083063 Iustin Pop
    all_vglist = rpc.call_vg_list(nodelist)
864 a8083063 Iustin Pop
    node_verify_param = {
865 a8083063 Iustin Pop
      'filelist': file_names,
866 a8083063 Iustin Pop
      'nodelist': nodelist,
867 a8083063 Iustin Pop
      'hypervisor': None,
868 a8083063 Iustin Pop
      }
869 a8083063 Iustin Pop
    all_nvinfo = rpc.call_node_verify(nodelist, node_verify_param)
870 a8083063 Iustin Pop
    all_rversion = rpc.call_version(nodelist)
871 a8083063 Iustin Pop
872 a8083063 Iustin Pop
    for node in nodelist:
873 a8083063 Iustin Pop
      feedback_fn("* Verifying node %s" % node)
874 a8083063 Iustin Pop
      result = self._VerifyNode(node, file_names, local_checksums,
875 a8083063 Iustin Pop
                                all_vglist[node], all_nvinfo[node],
876 a8083063 Iustin Pop
                                all_rversion[node], feedback_fn)
877 a8083063 Iustin Pop
      bad = bad or result
878 a8083063 Iustin Pop
879 a8083063 Iustin Pop
      # node_volume
880 a8083063 Iustin Pop
      volumeinfo = all_volumeinfo[node]
881 a8083063 Iustin Pop
882 a8083063 Iustin Pop
      if type(volumeinfo) != dict:
883 a8083063 Iustin Pop
        feedback_fn("  - ERROR: connection to %s failed" % (node,))
884 a8083063 Iustin Pop
        bad = True
885 a8083063 Iustin Pop
        continue
886 a8083063 Iustin Pop
887 a8083063 Iustin Pop
      node_volume[node] = volumeinfo
888 a8083063 Iustin Pop
889 a8083063 Iustin Pop
      # node_instance
890 a8083063 Iustin Pop
      nodeinstance = all_instanceinfo[node]
891 a8083063 Iustin Pop
      if type(nodeinstance) != list:
892 a8083063 Iustin Pop
        feedback_fn("  - ERROR: connection to %s failed" % (node,))
893 a8083063 Iustin Pop
        bad = True
894 a8083063 Iustin Pop
        continue
895 a8083063 Iustin Pop
896 a8083063 Iustin Pop
      node_instance[node] = nodeinstance
897 a8083063 Iustin Pop
898 a8083063 Iustin Pop
    node_vol_should = {}
899 a8083063 Iustin Pop
900 a8083063 Iustin Pop
    for instance in instancelist:
901 a8083063 Iustin Pop
      feedback_fn("* Verifying instance %s" % instance)
902 a8083063 Iustin Pop
      result =  self._VerifyInstance(instance, node_volume, node_instance,
903 a8083063 Iustin Pop
                                     feedback_fn)
904 a8083063 Iustin Pop
      bad = bad or result
905 a8083063 Iustin Pop
906 a8083063 Iustin Pop
      inst_config = self.cfg.GetInstanceInfo(instance)
907 a8083063 Iustin Pop
908 a8083063 Iustin Pop
      inst_config.MapLVsByNode(node_vol_should)
909 a8083063 Iustin Pop
910 a8083063 Iustin Pop
    feedback_fn("* Verifying orphan volumes")
911 a8083063 Iustin Pop
    result = self._VerifyOrphanVolumes(node_vol_should, node_volume,
912 a8083063 Iustin Pop
                                       feedback_fn)
913 a8083063 Iustin Pop
    bad = bad or result
914 a8083063 Iustin Pop
915 a8083063 Iustin Pop
    feedback_fn("* Verifying remaining instances")
916 a8083063 Iustin Pop
    result = self._VerifyOrphanInstances(instancelist, node_instance,
917 a8083063 Iustin Pop
                                         feedback_fn)
918 a8083063 Iustin Pop
    bad = bad or result
919 a8083063 Iustin Pop
920 a8083063 Iustin Pop
    return int(bad)
921 a8083063 Iustin Pop
922 a8083063 Iustin Pop
923 a8083063 Iustin Pop
def _WaitForSync(cfgw, instance, oneshot=False, unlock=False):
924 a8083063 Iustin Pop
  """Sleep and poll for an instance's disk to sync.
925 a8083063 Iustin Pop

926 a8083063 Iustin Pop
  """
927 a8083063 Iustin Pop
  if not instance.disks:
928 a8083063 Iustin Pop
    return True
929 a8083063 Iustin Pop
930 a8083063 Iustin Pop
  if not oneshot:
931 a8083063 Iustin Pop
    logger.ToStdout("Waiting for instance %s to sync disks." % instance.name)
932 a8083063 Iustin Pop
933 a8083063 Iustin Pop
  node = instance.primary_node
934 a8083063 Iustin Pop
935 a8083063 Iustin Pop
  for dev in instance.disks:
936 a8083063 Iustin Pop
    cfgw.SetDiskID(dev, node)
937 a8083063 Iustin Pop
938 a8083063 Iustin Pop
  retries = 0
939 a8083063 Iustin Pop
  while True:
940 a8083063 Iustin Pop
    max_time = 0
941 a8083063 Iustin Pop
    done = True
942 a8083063 Iustin Pop
    cumul_degraded = False
943 a8083063 Iustin Pop
    rstats = rpc.call_blockdev_getmirrorstatus(node, instance.disks)
944 a8083063 Iustin Pop
    if not rstats:
945 a8083063 Iustin Pop
      logger.ToStderr("Can't get any data from node %s" % node)
946 a8083063 Iustin Pop
      retries += 1
947 a8083063 Iustin Pop
      if retries >= 10:
948 3ecf6786 Iustin Pop
        raise errors.RemoteError("Can't contact node %s for mirror data,"
949 3ecf6786 Iustin Pop
                                 " aborting." % node)
950 a8083063 Iustin Pop
      time.sleep(6)
951 a8083063 Iustin Pop
      continue
952 a8083063 Iustin Pop
    retries = 0
953 a8083063 Iustin Pop
    for i in range(len(rstats)):
954 a8083063 Iustin Pop
      mstat = rstats[i]
955 a8083063 Iustin Pop
      if mstat is None:
956 a8083063 Iustin Pop
        logger.ToStderr("Can't compute data for node %s/%s" %
957 a8083063 Iustin Pop
                        (node, instance.disks[i].iv_name))
958 a8083063 Iustin Pop
        continue
959 a8083063 Iustin Pop
      perc_done, est_time, is_degraded = mstat
960 a8083063 Iustin Pop
      cumul_degraded = cumul_degraded or (is_degraded and perc_done is None)
961 a8083063 Iustin Pop
      if perc_done is not None:
962 a8083063 Iustin Pop
        done = False
963 a8083063 Iustin Pop
        if est_time is not None:
964 a8083063 Iustin Pop
          rem_time = "%d estimated seconds remaining" % est_time
965 a8083063 Iustin Pop
          max_time = est_time
966 a8083063 Iustin Pop
        else:
967 a8083063 Iustin Pop
          rem_time = "no time estimate"
968 a8083063 Iustin Pop
        logger.ToStdout("- device %s: %5.2f%% done, %s" %
969 a8083063 Iustin Pop
                        (instance.disks[i].iv_name, perc_done, rem_time))
970 a8083063 Iustin Pop
    if done or oneshot:
971 a8083063 Iustin Pop
      break
972 a8083063 Iustin Pop
973 a8083063 Iustin Pop
    if unlock:
974 a8083063 Iustin Pop
      utils.Unlock('cmd')
975 a8083063 Iustin Pop
    try:
976 a8083063 Iustin Pop
      time.sleep(min(60, max_time))
977 a8083063 Iustin Pop
    finally:
978 a8083063 Iustin Pop
      if unlock:
979 a8083063 Iustin Pop
        utils.Lock('cmd')
980 a8083063 Iustin Pop
981 a8083063 Iustin Pop
  if done:
982 a8083063 Iustin Pop
    logger.ToStdout("Instance %s's disks are in sync." % instance.name)
983 a8083063 Iustin Pop
  return not cumul_degraded
984 a8083063 Iustin Pop
985 a8083063 Iustin Pop
986 a8083063 Iustin Pop
def _CheckDiskConsistency(cfgw, dev, node, on_primary):
987 a8083063 Iustin Pop
  """Check that mirrors are not degraded.
988 a8083063 Iustin Pop

989 a8083063 Iustin Pop
  """
990 a8083063 Iustin Pop
  cfgw.SetDiskID(dev, node)
991 a8083063 Iustin Pop
992 a8083063 Iustin Pop
  result = True
993 a8083063 Iustin Pop
  if on_primary or dev.AssembleOnSecondary():
994 a8083063 Iustin Pop
    rstats = rpc.call_blockdev_find(node, dev)
995 a8083063 Iustin Pop
    if not rstats:
996 a8083063 Iustin Pop
      logger.ToStderr("Can't get any data from node %s" % node)
997 a8083063 Iustin Pop
      result = False
998 a8083063 Iustin Pop
    else:
999 a8083063 Iustin Pop
      result = result and (not rstats[5])
1000 a8083063 Iustin Pop
  if dev.children:
1001 a8083063 Iustin Pop
    for child in dev.children:
1002 a8083063 Iustin Pop
      result = result and _CheckDiskConsistency(cfgw, child, node, on_primary)
1003 a8083063 Iustin Pop
1004 a8083063 Iustin Pop
  return result
1005 a8083063 Iustin Pop
1006 a8083063 Iustin Pop
1007 a8083063 Iustin Pop
class LUDiagnoseOS(NoHooksLU):
1008 a8083063 Iustin Pop
  """Logical unit for OS diagnose/query.
1009 a8083063 Iustin Pop

1010 a8083063 Iustin Pop
  """
1011 a8083063 Iustin Pop
  _OP_REQP = []
1012 a8083063 Iustin Pop
1013 a8083063 Iustin Pop
  def CheckPrereq(self):
1014 a8083063 Iustin Pop
    """Check prerequisites.
1015 a8083063 Iustin Pop

1016 a8083063 Iustin Pop
    This always succeeds, since this is a pure query LU.
1017 a8083063 Iustin Pop

1018 a8083063 Iustin Pop
    """
1019 a8083063 Iustin Pop
    return
1020 a8083063 Iustin Pop
1021 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1022 a8083063 Iustin Pop
    """Compute the list of OSes.
1023 a8083063 Iustin Pop

1024 a8083063 Iustin Pop
    """
1025 a8083063 Iustin Pop
    node_list = self.cfg.GetNodeList()
1026 a8083063 Iustin Pop
    node_data = rpc.call_os_diagnose(node_list)
1027 a8083063 Iustin Pop
    if node_data == False:
1028 3ecf6786 Iustin Pop
      raise errors.OpExecError("Can't gather the list of OSes")
1029 a8083063 Iustin Pop
    return node_data
1030 a8083063 Iustin Pop
1031 a8083063 Iustin Pop
1032 a8083063 Iustin Pop
class LURemoveNode(LogicalUnit):
1033 a8083063 Iustin Pop
  """Logical unit for removing a node.
1034 a8083063 Iustin Pop

1035 a8083063 Iustin Pop
  """
1036 a8083063 Iustin Pop
  HPATH = "node-remove"
1037 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_NODE
1038 a8083063 Iustin Pop
  _OP_REQP = ["node_name"]
1039 a8083063 Iustin Pop
1040 a8083063 Iustin Pop
  def BuildHooksEnv(self):
1041 a8083063 Iustin Pop
    """Build hooks env.
1042 a8083063 Iustin Pop

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

1046 a8083063 Iustin Pop
    """
1047 396e1b78 Michael Hanselmann
    env = {
1048 396e1b78 Michael Hanselmann
      "NODE_NAME": self.op.node_name,
1049 396e1b78 Michael Hanselmann
      }
1050 a8083063 Iustin Pop
    all_nodes = self.cfg.GetNodeList()
1051 a8083063 Iustin Pop
    all_nodes.remove(self.op.node_name)
1052 396e1b78 Michael Hanselmann
    return env, all_nodes, all_nodes
1053 a8083063 Iustin Pop
1054 a8083063 Iustin Pop
  def CheckPrereq(self):
1055 a8083063 Iustin Pop
    """Check prerequisites.
1056 a8083063 Iustin Pop

1057 a8083063 Iustin Pop
    This checks:
1058 a8083063 Iustin Pop
     - the node exists in the configuration
1059 a8083063 Iustin Pop
     - it does not have primary or secondary instances
1060 a8083063 Iustin Pop
     - it's not the master
1061 a8083063 Iustin Pop

1062 a8083063 Iustin Pop
    Any errors are signalled by raising errors.OpPrereqError.
1063 a8083063 Iustin Pop

1064 a8083063 Iustin Pop
    """
1065 a8083063 Iustin Pop
    node = self.cfg.GetNodeInfo(self.cfg.ExpandNodeName(self.op.node_name))
1066 a8083063 Iustin Pop
    if node is None:
1067 a02bc76e Iustin Pop
      raise errors.OpPrereqError, ("Node '%s' is unknown." % self.op.node_name)
1068 a8083063 Iustin Pop
1069 a8083063 Iustin Pop
    instance_list = self.cfg.GetInstanceList()
1070 a8083063 Iustin Pop
1071 880478f8 Iustin Pop
    masternode = self.sstore.GetMasterNode()
1072 a8083063 Iustin Pop
    if node.name == masternode:
1073 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Node is the master node,"
1074 3ecf6786 Iustin Pop
                                 " you need to failover first.")
1075 a8083063 Iustin Pop
1076 a8083063 Iustin Pop
    for instance_name in instance_list:
1077 a8083063 Iustin Pop
      instance = self.cfg.GetInstanceInfo(instance_name)
1078 a8083063 Iustin Pop
      if node.name == instance.primary_node:
1079 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Instance %s still running on the node,"
1080 3ecf6786 Iustin Pop
                                   " please remove first." % instance_name)
1081 a8083063 Iustin Pop
      if node.name in instance.secondary_nodes:
1082 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Instance %s has node as a secondary,"
1083 3ecf6786 Iustin Pop
                                   " please remove first." % instance_name)
1084 a8083063 Iustin Pop
    self.op.node_name = node.name
1085 a8083063 Iustin Pop
    self.node = node
1086 a8083063 Iustin Pop
1087 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1088 a8083063 Iustin Pop
    """Removes the node from the cluster.
1089 a8083063 Iustin Pop

1090 a8083063 Iustin Pop
    """
1091 a8083063 Iustin Pop
    node = self.node
1092 a8083063 Iustin Pop
    logger.Info("stopping the node daemon and removing configs from node %s" %
1093 a8083063 Iustin Pop
                node.name)
1094 a8083063 Iustin Pop
1095 a8083063 Iustin Pop
    rpc.call_node_leave_cluster(node.name)
1096 a8083063 Iustin Pop
1097 a8083063 Iustin Pop
    ssh.SSHCall(node.name, 'root', "%s stop" % constants.NODE_INITD_SCRIPT)
1098 a8083063 Iustin Pop
1099 a8083063 Iustin Pop
    logger.Info("Removing node %s from config" % node.name)
1100 a8083063 Iustin Pop
1101 a8083063 Iustin Pop
    self.cfg.RemoveNode(node.name)
1102 a8083063 Iustin Pop
1103 a8083063 Iustin Pop
1104 a8083063 Iustin Pop
class LUQueryNodes(NoHooksLU):
1105 a8083063 Iustin Pop
  """Logical unit for querying nodes.
1106 a8083063 Iustin Pop

1107 a8083063 Iustin Pop
  """
1108 a8083063 Iustin Pop
  _OP_REQP = ["output_fields"]
1109 a8083063 Iustin Pop
1110 a8083063 Iustin Pop
  def CheckPrereq(self):
1111 a8083063 Iustin Pop
    """Check prerequisites.
1112 a8083063 Iustin Pop

1113 a8083063 Iustin Pop
    This checks that the fields required are valid output fields.
1114 a8083063 Iustin Pop

1115 a8083063 Iustin Pop
    """
1116 a8083063 Iustin Pop
    self.dynamic_fields = frozenset(["dtotal", "dfree",
1117 a8083063 Iustin Pop
                                     "mtotal", "mnode", "mfree"])
1118 a8083063 Iustin Pop
1119 dcb93971 Michael Hanselmann
    _CheckOutputFields(static=["name", "pinst", "sinst", "pip", "sip"],
1120 dcb93971 Michael Hanselmann
                       dynamic=self.dynamic_fields,
1121 dcb93971 Michael Hanselmann
                       selected=self.op.output_fields)
1122 a8083063 Iustin Pop
1123 a8083063 Iustin Pop
1124 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1125 a8083063 Iustin Pop
    """Computes the list of nodes and their attributes.
1126 a8083063 Iustin Pop

1127 a8083063 Iustin Pop
    """
1128 a8083063 Iustin Pop
    nodenames = utils.NiceSort(self.cfg.GetNodeList())
1129 a8083063 Iustin Pop
    nodelist = [self.cfg.GetNodeInfo(name) for name in nodenames]
1130 a8083063 Iustin Pop
1131 a8083063 Iustin Pop
1132 a8083063 Iustin Pop
    # begin data gathering
1133 a8083063 Iustin Pop
1134 a8083063 Iustin Pop
    if self.dynamic_fields.intersection(self.op.output_fields):
1135 a8083063 Iustin Pop
      live_data = {}
1136 a8083063 Iustin Pop
      node_data = rpc.call_node_info(nodenames, self.cfg.GetVGName())
1137 a8083063 Iustin Pop
      for name in nodenames:
1138 a8083063 Iustin Pop
        nodeinfo = node_data.get(name, None)
1139 a8083063 Iustin Pop
        if nodeinfo:
1140 a8083063 Iustin Pop
          live_data[name] = {
1141 a8083063 Iustin Pop
            "mtotal": utils.TryConvert(int, nodeinfo['memory_total']),
1142 a8083063 Iustin Pop
            "mnode": utils.TryConvert(int, nodeinfo['memory_dom0']),
1143 a8083063 Iustin Pop
            "mfree": utils.TryConvert(int, nodeinfo['memory_free']),
1144 a8083063 Iustin Pop
            "dtotal": utils.TryConvert(int, nodeinfo['vg_size']),
1145 a8083063 Iustin Pop
            "dfree": utils.TryConvert(int, nodeinfo['vg_free']),
1146 a8083063 Iustin Pop
            }
1147 a8083063 Iustin Pop
        else:
1148 a8083063 Iustin Pop
          live_data[name] = {}
1149 a8083063 Iustin Pop
    else:
1150 a8083063 Iustin Pop
      live_data = dict.fromkeys(nodenames, {})
1151 a8083063 Iustin Pop
1152 a8083063 Iustin Pop
    node_to_primary = dict.fromkeys(nodenames, 0)
1153 a8083063 Iustin Pop
    node_to_secondary = dict.fromkeys(nodenames, 0)
1154 a8083063 Iustin Pop
1155 a8083063 Iustin Pop
    if "pinst" in self.op.output_fields or "sinst" in self.op.output_fields:
1156 a8083063 Iustin Pop
      instancelist = self.cfg.GetInstanceList()
1157 a8083063 Iustin Pop
1158 a8083063 Iustin Pop
      for instance in instancelist:
1159 a8083063 Iustin Pop
        instanceinfo = self.cfg.GetInstanceInfo(instance)
1160 a8083063 Iustin Pop
        node_to_primary[instanceinfo.primary_node] += 1
1161 a8083063 Iustin Pop
        for secnode in instanceinfo.secondary_nodes:
1162 a8083063 Iustin Pop
          node_to_secondary[secnode] += 1
1163 a8083063 Iustin Pop
1164 a8083063 Iustin Pop
    # end data gathering
1165 a8083063 Iustin Pop
1166 a8083063 Iustin Pop
    output = []
1167 a8083063 Iustin Pop
    for node in nodelist:
1168 a8083063 Iustin Pop
      node_output = []
1169 a8083063 Iustin Pop
      for field in self.op.output_fields:
1170 a8083063 Iustin Pop
        if field == "name":
1171 a8083063 Iustin Pop
          val = node.name
1172 a8083063 Iustin Pop
        elif field == "pinst":
1173 a8083063 Iustin Pop
          val = node_to_primary[node.name]
1174 a8083063 Iustin Pop
        elif field == "sinst":
1175 a8083063 Iustin Pop
          val = node_to_secondary[node.name]
1176 a8083063 Iustin Pop
        elif field == "pip":
1177 a8083063 Iustin Pop
          val = node.primary_ip
1178 a8083063 Iustin Pop
        elif field == "sip":
1179 a8083063 Iustin Pop
          val = node.secondary_ip
1180 a8083063 Iustin Pop
        elif field in self.dynamic_fields:
1181 a8083063 Iustin Pop
          val = live_data[node.name].get(field, "?")
1182 a8083063 Iustin Pop
        else:
1183 3ecf6786 Iustin Pop
          raise errors.ParameterError(field)
1184 a8083063 Iustin Pop
        val = str(val)
1185 a8083063 Iustin Pop
        node_output.append(val)
1186 a8083063 Iustin Pop
      output.append(node_output)
1187 a8083063 Iustin Pop
1188 a8083063 Iustin Pop
    return output
1189 a8083063 Iustin Pop
1190 a8083063 Iustin Pop
1191 dcb93971 Michael Hanselmann
class LUQueryNodeVolumes(NoHooksLU):
1192 dcb93971 Michael Hanselmann
  """Logical unit for getting volumes on node(s).
1193 dcb93971 Michael Hanselmann

1194 dcb93971 Michael Hanselmann
  """
1195 dcb93971 Michael Hanselmann
  _OP_REQP = ["nodes", "output_fields"]
1196 dcb93971 Michael Hanselmann
1197 dcb93971 Michael Hanselmann
  def CheckPrereq(self):
1198 dcb93971 Michael Hanselmann
    """Check prerequisites.
1199 dcb93971 Michael Hanselmann

1200 dcb93971 Michael Hanselmann
    This checks that the fields required are valid output fields.
1201 dcb93971 Michael Hanselmann

1202 dcb93971 Michael Hanselmann
    """
1203 dcb93971 Michael Hanselmann
    self.nodes = _GetWantedNodes(self, self.op.nodes)
1204 dcb93971 Michael Hanselmann
1205 dcb93971 Michael Hanselmann
    _CheckOutputFields(static=["node"],
1206 dcb93971 Michael Hanselmann
                       dynamic=["phys", "vg", "name", "size", "instance"],
1207 dcb93971 Michael Hanselmann
                       selected=self.op.output_fields)
1208 dcb93971 Michael Hanselmann
1209 dcb93971 Michael Hanselmann
1210 dcb93971 Michael Hanselmann
  def Exec(self, feedback_fn):
1211 dcb93971 Michael Hanselmann
    """Computes the list of nodes and their attributes.
1212 dcb93971 Michael Hanselmann

1213 dcb93971 Michael Hanselmann
    """
1214 dcb93971 Michael Hanselmann
    nodenames = utils.NiceSort([node.name for node in self.nodes])
1215 dcb93971 Michael Hanselmann
    volumes = rpc.call_node_volumes(nodenames)
1216 dcb93971 Michael Hanselmann
1217 dcb93971 Michael Hanselmann
    ilist = [self.cfg.GetInstanceInfo(iname) for iname
1218 dcb93971 Michael Hanselmann
             in self.cfg.GetInstanceList()]
1219 dcb93971 Michael Hanselmann
1220 dcb93971 Michael Hanselmann
    lv_by_node = dict([(inst, inst.MapLVsByNode()) for inst in ilist])
1221 dcb93971 Michael Hanselmann
1222 dcb93971 Michael Hanselmann
    output = []
1223 dcb93971 Michael Hanselmann
    for node in nodenames:
1224 37d19eb2 Michael Hanselmann
      if node not in volumes or not volumes[node]:
1225 37d19eb2 Michael Hanselmann
        continue
1226 37d19eb2 Michael Hanselmann
1227 dcb93971 Michael Hanselmann
      node_vols = volumes[node][:]
1228 dcb93971 Michael Hanselmann
      node_vols.sort(key=lambda vol: vol['dev'])
1229 dcb93971 Michael Hanselmann
1230 dcb93971 Michael Hanselmann
      for vol in node_vols:
1231 dcb93971 Michael Hanselmann
        node_output = []
1232 dcb93971 Michael Hanselmann
        for field in self.op.output_fields:
1233 dcb93971 Michael Hanselmann
          if field == "node":
1234 dcb93971 Michael Hanselmann
            val = node
1235 dcb93971 Michael Hanselmann
          elif field == "phys":
1236 dcb93971 Michael Hanselmann
            val = vol['dev']
1237 dcb93971 Michael Hanselmann
          elif field == "vg":
1238 dcb93971 Michael Hanselmann
            val = vol['vg']
1239 dcb93971 Michael Hanselmann
          elif field == "name":
1240 dcb93971 Michael Hanselmann
            val = vol['name']
1241 dcb93971 Michael Hanselmann
          elif field == "size":
1242 dcb93971 Michael Hanselmann
            val = int(float(vol['size']))
1243 dcb93971 Michael Hanselmann
          elif field == "instance":
1244 dcb93971 Michael Hanselmann
            for inst in ilist:
1245 dcb93971 Michael Hanselmann
              if node not in lv_by_node[inst]:
1246 dcb93971 Michael Hanselmann
                continue
1247 dcb93971 Michael Hanselmann
              if vol['name'] in lv_by_node[inst][node]:
1248 dcb93971 Michael Hanselmann
                val = inst.name
1249 dcb93971 Michael Hanselmann
                break
1250 dcb93971 Michael Hanselmann
            else:
1251 dcb93971 Michael Hanselmann
              val = '-'
1252 dcb93971 Michael Hanselmann
          else:
1253 3ecf6786 Iustin Pop
            raise errors.ParameterError(field)
1254 dcb93971 Michael Hanselmann
          node_output.append(str(val))
1255 dcb93971 Michael Hanselmann
1256 dcb93971 Michael Hanselmann
        output.append(node_output)
1257 dcb93971 Michael Hanselmann
1258 dcb93971 Michael Hanselmann
    return output
1259 dcb93971 Michael Hanselmann
1260 dcb93971 Michael Hanselmann
1261 a8083063 Iustin Pop
class LUAddNode(LogicalUnit):
1262 a8083063 Iustin Pop
  """Logical unit for adding node to the cluster.
1263 a8083063 Iustin Pop

1264 a8083063 Iustin Pop
  """
1265 a8083063 Iustin Pop
  HPATH = "node-add"
1266 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_NODE
1267 a8083063 Iustin Pop
  _OP_REQP = ["node_name"]
1268 a8083063 Iustin Pop
1269 a8083063 Iustin Pop
  def BuildHooksEnv(self):
1270 a8083063 Iustin Pop
    """Build hooks env.
1271 a8083063 Iustin Pop

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

1274 a8083063 Iustin Pop
    """
1275 a8083063 Iustin Pop
    env = {
1276 a8083063 Iustin Pop
      "NODE_NAME": self.op.node_name,
1277 a8083063 Iustin Pop
      "NODE_PIP": self.op.primary_ip,
1278 a8083063 Iustin Pop
      "NODE_SIP": self.op.secondary_ip,
1279 a8083063 Iustin Pop
      }
1280 a8083063 Iustin Pop
    nodes_0 = self.cfg.GetNodeList()
1281 a8083063 Iustin Pop
    nodes_1 = nodes_0 + [self.op.node_name, ]
1282 a8083063 Iustin Pop
    return env, nodes_0, nodes_1
1283 a8083063 Iustin Pop
1284 a8083063 Iustin Pop
  def CheckPrereq(self):
1285 a8083063 Iustin Pop
    """Check prerequisites.
1286 a8083063 Iustin Pop

1287 a8083063 Iustin Pop
    This checks:
1288 a8083063 Iustin Pop
     - the new node is not already in the config
1289 a8083063 Iustin Pop
     - it is resolvable
1290 a8083063 Iustin Pop
     - its parameters (single/dual homed) matches the cluster
1291 a8083063 Iustin Pop

1292 a8083063 Iustin Pop
    Any errors are signalled by raising errors.OpPrereqError.
1293 a8083063 Iustin Pop

1294 a8083063 Iustin Pop
    """
1295 a8083063 Iustin Pop
    node_name = self.op.node_name
1296 a8083063 Iustin Pop
    cfg = self.cfg
1297 a8083063 Iustin Pop
1298 a8083063 Iustin Pop
    dns_data = utils.LookupHostname(node_name)
1299 a8083063 Iustin Pop
    if not dns_data:
1300 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Node %s is not resolvable" % node_name)
1301 a8083063 Iustin Pop
1302 a8083063 Iustin Pop
    node = dns_data['hostname']
1303 a8083063 Iustin Pop
    primary_ip = self.op.primary_ip = dns_data['ip']
1304 a8083063 Iustin Pop
    secondary_ip = getattr(self.op, "secondary_ip", None)
1305 a8083063 Iustin Pop
    if secondary_ip is None:
1306 a8083063 Iustin Pop
      secondary_ip = primary_ip
1307 a8083063 Iustin Pop
    if not utils.IsValidIP(secondary_ip):
1308 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Invalid secondary IP given")
1309 a8083063 Iustin Pop
    self.op.secondary_ip = secondary_ip
1310 a8083063 Iustin Pop
    node_list = cfg.GetNodeList()
1311 a8083063 Iustin Pop
    if node in node_list:
1312 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Node %s is already in the configuration"
1313 3ecf6786 Iustin Pop
                                 % node)
1314 a8083063 Iustin Pop
1315 a8083063 Iustin Pop
    for existing_node_name in node_list:
1316 a8083063 Iustin Pop
      existing_node = cfg.GetNodeInfo(existing_node_name)
1317 a8083063 Iustin Pop
      if (existing_node.primary_ip == primary_ip or
1318 a8083063 Iustin Pop
          existing_node.secondary_ip == primary_ip or
1319 a8083063 Iustin Pop
          existing_node.primary_ip == secondary_ip or
1320 a8083063 Iustin Pop
          existing_node.secondary_ip == secondary_ip):
1321 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("New node ip address(es) conflict with"
1322 3ecf6786 Iustin Pop
                                   " existing node %s" % existing_node.name)
1323 a8083063 Iustin Pop
1324 a8083063 Iustin Pop
    # check that the type of the node (single versus dual homed) is the
1325 a8083063 Iustin Pop
    # same as for the master
1326 880478f8 Iustin Pop
    myself = cfg.GetNodeInfo(self.sstore.GetMasterNode())
1327 a8083063 Iustin Pop
    master_singlehomed = myself.secondary_ip == myself.primary_ip
1328 a8083063 Iustin Pop
    newbie_singlehomed = secondary_ip == primary_ip
1329 a8083063 Iustin Pop
    if master_singlehomed != newbie_singlehomed:
1330 a8083063 Iustin Pop
      if master_singlehomed:
1331 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("The master has no private ip but the"
1332 3ecf6786 Iustin Pop
                                   " new node has one")
1333 a8083063 Iustin Pop
      else:
1334 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("The master has a private ip but the"
1335 3ecf6786 Iustin Pop
                                   " new node doesn't have one")
1336 a8083063 Iustin Pop
1337 a8083063 Iustin Pop
    # checks reachablity
1338 a8083063 Iustin Pop
    command = ["fping", "-q", primary_ip]
1339 a8083063 Iustin Pop
    result = utils.RunCmd(command)
1340 a8083063 Iustin Pop
    if result.failed:
1341 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Node not reachable by ping")
1342 a8083063 Iustin Pop
1343 a8083063 Iustin Pop
    if not newbie_singlehomed:
1344 a8083063 Iustin Pop
      # check reachability from my secondary ip to newbie's secondary ip
1345 a8083063 Iustin Pop
      command = ["fping", "-S%s" % myself.secondary_ip, "-q", secondary_ip]
1346 a8083063 Iustin Pop
      result = utils.RunCmd(command)
1347 a8083063 Iustin Pop
      if result.failed:
1348 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Node secondary ip not reachable by ping")
1349 a8083063 Iustin Pop
1350 a8083063 Iustin Pop
    self.new_node = objects.Node(name=node,
1351 a8083063 Iustin Pop
                                 primary_ip=primary_ip,
1352 a8083063 Iustin Pop
                                 secondary_ip=secondary_ip)
1353 a8083063 Iustin Pop
1354 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1355 a8083063 Iustin Pop
    """Adds the new node to the cluster.
1356 a8083063 Iustin Pop

1357 a8083063 Iustin Pop
    """
1358 a8083063 Iustin Pop
    new_node = self.new_node
1359 a8083063 Iustin Pop
    node = new_node.name
1360 a8083063 Iustin Pop
1361 a8083063 Iustin Pop
    # set up inter-node password and certificate and restarts the node daemon
1362 a8083063 Iustin Pop
    gntpass = self.sstore.GetNodeDaemonPassword()
1363 a8083063 Iustin Pop
    if not re.match('^[a-zA-Z0-9.]{1,64}$', gntpass):
1364 3ecf6786 Iustin Pop
      raise errors.OpExecError("ganeti password corruption detected")
1365 a8083063 Iustin Pop
    f = open(constants.SSL_CERT_FILE)
1366 a8083063 Iustin Pop
    try:
1367 a8083063 Iustin Pop
      gntpem = f.read(8192)
1368 a8083063 Iustin Pop
    finally:
1369 a8083063 Iustin Pop
      f.close()
1370 a8083063 Iustin Pop
    # in the base64 pem encoding, neither '!' nor '.' are valid chars,
1371 a8083063 Iustin Pop
    # so we use this to detect an invalid certificate; as long as the
1372 a8083063 Iustin Pop
    # cert doesn't contain this, the here-document will be correctly
1373 a8083063 Iustin Pop
    # parsed by the shell sequence below
1374 a8083063 Iustin Pop
    if re.search('^!EOF\.', gntpem, re.MULTILINE):
1375 3ecf6786 Iustin Pop
      raise errors.OpExecError("invalid PEM encoding in the SSL certificate")
1376 a8083063 Iustin Pop
    if not gntpem.endswith("\n"):
1377 3ecf6786 Iustin Pop
      raise errors.OpExecError("PEM must end with newline")
1378 a8083063 Iustin Pop
    logger.Info("copy cluster pass to %s and starting the node daemon" % node)
1379 a8083063 Iustin Pop
1380 a8083063 Iustin Pop
    # and then connect with ssh to set password and start ganeti-noded
1381 a8083063 Iustin Pop
    # note that all the below variables are sanitized at this point,
1382 a8083063 Iustin Pop
    # either by being constants or by the checks above
1383 a8083063 Iustin Pop
    ss = self.sstore
1384 a8083063 Iustin Pop
    mycommand = ("umask 077 && "
1385 a8083063 Iustin Pop
                 "echo '%s' > '%s' && "
1386 a8083063 Iustin Pop
                 "cat > '%s' << '!EOF.' && \n"
1387 a8083063 Iustin Pop
                 "%s!EOF.\n%s restart" %
1388 a8083063 Iustin Pop
                 (gntpass, ss.KeyToFilename(ss.SS_NODED_PASS),
1389 a8083063 Iustin Pop
                  constants.SSL_CERT_FILE, gntpem,
1390 a8083063 Iustin Pop
                  constants.NODE_INITD_SCRIPT))
1391 a8083063 Iustin Pop
1392 a8083063 Iustin Pop
    result = ssh.SSHCall(node, 'root', mycommand, batch=False, ask_key=True)
1393 a8083063 Iustin Pop
    if result.failed:
1394 3ecf6786 Iustin Pop
      raise errors.OpExecError("Remote command on node %s, error: %s,"
1395 3ecf6786 Iustin Pop
                               " output: %s" %
1396 3ecf6786 Iustin Pop
                               (node, result.fail_reason, result.output))
1397 a8083063 Iustin Pop
1398 a8083063 Iustin Pop
    # check connectivity
1399 a8083063 Iustin Pop
    time.sleep(4)
1400 a8083063 Iustin Pop
1401 a8083063 Iustin Pop
    result = rpc.call_version([node])[node]
1402 a8083063 Iustin Pop
    if result:
1403 a8083063 Iustin Pop
      if constants.PROTOCOL_VERSION == result:
1404 a8083063 Iustin Pop
        logger.Info("communication to node %s fine, sw version %s match" %
1405 a8083063 Iustin Pop
                    (node, result))
1406 a8083063 Iustin Pop
      else:
1407 3ecf6786 Iustin Pop
        raise errors.OpExecError("Version mismatch master version %s,"
1408 3ecf6786 Iustin Pop
                                 " node version %s" %
1409 3ecf6786 Iustin Pop
                                 (constants.PROTOCOL_VERSION, result))
1410 a8083063 Iustin Pop
    else:
1411 3ecf6786 Iustin Pop
      raise errors.OpExecError("Cannot get version from the new node")
1412 a8083063 Iustin Pop
1413 a8083063 Iustin Pop
    # setup ssh on node
1414 a8083063 Iustin Pop
    logger.Info("copy ssh key to node %s" % node)
1415 a8083063 Iustin Pop
    keyarray = []
1416 a8083063 Iustin Pop
    keyfiles = ["/etc/ssh/ssh_host_dsa_key", "/etc/ssh/ssh_host_dsa_key.pub",
1417 a8083063 Iustin Pop
                "/etc/ssh/ssh_host_rsa_key", "/etc/ssh/ssh_host_rsa_key.pub",
1418 a8083063 Iustin Pop
                "/root/.ssh/id_dsa", "/root/.ssh/id_dsa.pub"]
1419 a8083063 Iustin Pop
1420 a8083063 Iustin Pop
    for i in keyfiles:
1421 a8083063 Iustin Pop
      f = open(i, 'r')
1422 a8083063 Iustin Pop
      try:
1423 a8083063 Iustin Pop
        keyarray.append(f.read())
1424 a8083063 Iustin Pop
      finally:
1425 a8083063 Iustin Pop
        f.close()
1426 a8083063 Iustin Pop
1427 a8083063 Iustin Pop
    result = rpc.call_node_add(node, keyarray[0], keyarray[1], keyarray[2],
1428 a8083063 Iustin Pop
                               keyarray[3], keyarray[4], keyarray[5])
1429 a8083063 Iustin Pop
1430 a8083063 Iustin Pop
    if not result:
1431 3ecf6786 Iustin Pop
      raise errors.OpExecError("Cannot transfer ssh keys to the new node")
1432 a8083063 Iustin Pop
1433 a8083063 Iustin Pop
    # Add node to our /etc/hosts, and add key to known_hosts
1434 a8083063 Iustin Pop
    _UpdateEtcHosts(new_node.name, new_node.primary_ip)
1435 a8083063 Iustin Pop
    _UpdateKnownHosts(new_node.name, new_node.primary_ip,
1436 a8083063 Iustin Pop
                      self.cfg.GetHostKey())
1437 a8083063 Iustin Pop
1438 a8083063 Iustin Pop
    if new_node.secondary_ip != new_node.primary_ip:
1439 a8083063 Iustin Pop
      result = ssh.SSHCall(node, "root",
1440 a8083063 Iustin Pop
                           "fping -S 127.0.0.1 -q %s" % new_node.secondary_ip)
1441 a8083063 Iustin Pop
      if result.failed:
1442 3ecf6786 Iustin Pop
        raise errors.OpExecError("Node claims it doesn't have the"
1443 3ecf6786 Iustin Pop
                                 " secondary ip you gave (%s).\n"
1444 3ecf6786 Iustin Pop
                                 "Please fix and re-run this command." %
1445 3ecf6786 Iustin Pop
                                 new_node.secondary_ip)
1446 a8083063 Iustin Pop
1447 ff98055b Iustin Pop
    success, msg = ssh.VerifyNodeHostname(node)
1448 ff98055b Iustin Pop
    if not success:
1449 ff98055b Iustin Pop
      raise errors.OpExecError("Node '%s' claims it has a different hostname"
1450 ff98055b Iustin Pop
                               " than the one the resolver gives: %s.\n"
1451 ff98055b Iustin Pop
                               "Please fix and re-run this command." %
1452 ff98055b Iustin Pop
                               (node, msg))
1453 ff98055b Iustin Pop
1454 a8083063 Iustin Pop
    # Distribute updated /etc/hosts and known_hosts to all nodes,
1455 a8083063 Iustin Pop
    # including the node just added
1456 880478f8 Iustin Pop
    myself = self.cfg.GetNodeInfo(self.sstore.GetMasterNode())
1457 a8083063 Iustin Pop
    dist_nodes = self.cfg.GetNodeList() + [node]
1458 a8083063 Iustin Pop
    if myself.name in dist_nodes:
1459 a8083063 Iustin Pop
      dist_nodes.remove(myself.name)
1460 a8083063 Iustin Pop
1461 a8083063 Iustin Pop
    logger.Debug("Copying hosts and known_hosts to all nodes")
1462 82122173 Iustin Pop
    for fname in ("/etc/hosts", constants.SSH_KNOWN_HOSTS_FILE):
1463 a8083063 Iustin Pop
      result = rpc.call_upload_file(dist_nodes, fname)
1464 a8083063 Iustin Pop
      for to_node in dist_nodes:
1465 a8083063 Iustin Pop
        if not result[to_node]:
1466 a8083063 Iustin Pop
          logger.Error("copy of file %s to node %s failed" %
1467 a8083063 Iustin Pop
                       (fname, to_node))
1468 a8083063 Iustin Pop
1469 cb91d46e Iustin Pop
    to_copy = ss.GetFileList()
1470 a8083063 Iustin Pop
    for fname in to_copy:
1471 a8083063 Iustin Pop
      if not ssh.CopyFileToNode(node, fname):
1472 a8083063 Iustin Pop
        logger.Error("could not copy file %s to node %s" % (fname, node))
1473 a8083063 Iustin Pop
1474 a8083063 Iustin Pop
    logger.Info("adding node %s to cluster.conf" % node)
1475 a8083063 Iustin Pop
    self.cfg.AddNode(new_node)
1476 a8083063 Iustin Pop
1477 a8083063 Iustin Pop
1478 a8083063 Iustin Pop
class LUMasterFailover(LogicalUnit):
1479 a8083063 Iustin Pop
  """Failover the master node to the current node.
1480 a8083063 Iustin Pop

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

1483 a8083063 Iustin Pop
  """
1484 a8083063 Iustin Pop
  HPATH = "master-failover"
1485 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_CLUSTER
1486 a8083063 Iustin Pop
  REQ_MASTER = False
1487 a8083063 Iustin Pop
  _OP_REQP = []
1488 a8083063 Iustin Pop
1489 a8083063 Iustin Pop
  def BuildHooksEnv(self):
1490 a8083063 Iustin Pop
    """Build hooks env.
1491 a8083063 Iustin Pop

1492 a8083063 Iustin Pop
    This will run on the new master only in the pre phase, and on all
1493 a8083063 Iustin Pop
    the nodes in the post phase.
1494 a8083063 Iustin Pop

1495 a8083063 Iustin Pop
    """
1496 a8083063 Iustin Pop
    env = {
1497 a8083063 Iustin Pop
      "NEW_MASTER": self.new_master,
1498 a8083063 Iustin Pop
      "OLD_MASTER": self.old_master,
1499 a8083063 Iustin Pop
      }
1500 a8083063 Iustin Pop
    return env, [self.new_master], self.cfg.GetNodeList()
1501 a8083063 Iustin Pop
1502 a8083063 Iustin Pop
  def CheckPrereq(self):
1503 a8083063 Iustin Pop
    """Check prerequisites.
1504 a8083063 Iustin Pop

1505 a8083063 Iustin Pop
    This checks that we are not already the master.
1506 a8083063 Iustin Pop

1507 a8083063 Iustin Pop
    """
1508 a8083063 Iustin Pop
    self.new_master = socket.gethostname()
1509 a8083063 Iustin Pop
1510 880478f8 Iustin Pop
    self.old_master = self.sstore.GetMasterNode()
1511 a8083063 Iustin Pop
1512 a8083063 Iustin Pop
    if self.old_master == self.new_master:
1513 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("This commands must be run on the node"
1514 3ecf6786 Iustin Pop
                                 " where you want the new master to be.\n"
1515 3ecf6786 Iustin Pop
                                 "%s is already the master" %
1516 3ecf6786 Iustin Pop
                                 self.old_master)
1517 a8083063 Iustin Pop
1518 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1519 a8083063 Iustin Pop
    """Failover the master node.
1520 a8083063 Iustin Pop

1521 a8083063 Iustin Pop
    This command, when run on a non-master node, will cause the current
1522 a8083063 Iustin Pop
    master to cease being master, and the non-master to become new
1523 a8083063 Iustin Pop
    master.
1524 a8083063 Iustin Pop

1525 a8083063 Iustin Pop
    """
1526 a8083063 Iustin Pop
    #TODO: do not rely on gethostname returning the FQDN
1527 a8083063 Iustin Pop
    logger.Info("setting master to %s, old master: %s" %
1528 a8083063 Iustin Pop
                (self.new_master, self.old_master))
1529 a8083063 Iustin Pop
1530 a8083063 Iustin Pop
    if not rpc.call_node_stop_master(self.old_master):
1531 a8083063 Iustin Pop
      logger.Error("could disable the master role on the old master"
1532 a8083063 Iustin Pop
                   " %s, please disable manually" % self.old_master)
1533 a8083063 Iustin Pop
1534 880478f8 Iustin Pop
    ss = self.sstore
1535 880478f8 Iustin Pop
    ss.SetKey(ss.SS_MASTER_NODE, self.new_master)
1536 880478f8 Iustin Pop
    if not rpc.call_upload_file(self.cfg.GetNodeList(),
1537 880478f8 Iustin Pop
                                ss.KeyToFilename(ss.SS_MASTER_NODE)):
1538 880478f8 Iustin Pop
      logger.Error("could not distribute the new simple store master file"
1539 880478f8 Iustin Pop
                   " to the other nodes, please check.")
1540 880478f8 Iustin Pop
1541 a8083063 Iustin Pop
    if not rpc.call_node_start_master(self.new_master):
1542 a8083063 Iustin Pop
      logger.Error("could not start the master role on the new master"
1543 a8083063 Iustin Pop
                   " %s, please check" % self.new_master)
1544 880478f8 Iustin Pop
      feedback_fn("Error in activating the master IP on the new master,\n"
1545 880478f8 Iustin Pop
                  "please fix manually.")
1546 a8083063 Iustin Pop
1547 a8083063 Iustin Pop
1548 a8083063 Iustin Pop
1549 a8083063 Iustin Pop
class LUQueryClusterInfo(NoHooksLU):
1550 a8083063 Iustin Pop
  """Query cluster configuration.
1551 a8083063 Iustin Pop

1552 a8083063 Iustin Pop
  """
1553 a8083063 Iustin Pop
  _OP_REQP = []
1554 59322403 Iustin Pop
  REQ_MASTER = False
1555 a8083063 Iustin Pop
1556 a8083063 Iustin Pop
  def CheckPrereq(self):
1557 a8083063 Iustin Pop
    """No prerequsites needed for this LU.
1558 a8083063 Iustin Pop

1559 a8083063 Iustin Pop
    """
1560 a8083063 Iustin Pop
    pass
1561 a8083063 Iustin Pop
1562 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1563 a8083063 Iustin Pop
    """Return cluster config.
1564 a8083063 Iustin Pop

1565 a8083063 Iustin Pop
    """
1566 a8083063 Iustin Pop
    result = {
1567 5fcdc80d Iustin Pop
      "name": self.sstore.GetClusterName(),
1568 a8083063 Iustin Pop
      "software_version": constants.RELEASE_VERSION,
1569 a8083063 Iustin Pop
      "protocol_version": constants.PROTOCOL_VERSION,
1570 a8083063 Iustin Pop
      "config_version": constants.CONFIG_VERSION,
1571 a8083063 Iustin Pop
      "os_api_version": constants.OS_API_VERSION,
1572 a8083063 Iustin Pop
      "export_version": constants.EXPORT_VERSION,
1573 880478f8 Iustin Pop
      "master": self.sstore.GetMasterNode(),
1574 a8083063 Iustin Pop
      "architecture": (platform.architecture()[0], platform.machine()),
1575 a8083063 Iustin Pop
      }
1576 a8083063 Iustin Pop
1577 a8083063 Iustin Pop
    return result
1578 a8083063 Iustin Pop
1579 a8083063 Iustin Pop
1580 a8083063 Iustin Pop
class LUClusterCopyFile(NoHooksLU):
1581 a8083063 Iustin Pop
  """Copy file to cluster.
1582 a8083063 Iustin Pop

1583 a8083063 Iustin Pop
  """
1584 a8083063 Iustin Pop
  _OP_REQP = ["nodes", "filename"]
1585 a8083063 Iustin Pop
1586 a8083063 Iustin Pop
  def CheckPrereq(self):
1587 a8083063 Iustin Pop
    """Check prerequisites.
1588 a8083063 Iustin Pop

1589 a8083063 Iustin Pop
    It should check that the named file exists and that the given list
1590 a8083063 Iustin Pop
    of nodes is valid.
1591 a8083063 Iustin Pop

1592 a8083063 Iustin Pop
    """
1593 a8083063 Iustin Pop
    if not os.path.exists(self.op.filename):
1594 a8083063 Iustin Pop
      raise errors.OpPrereqError("No such filename '%s'" % self.op.filename)
1595 dcb93971 Michael Hanselmann
1596 dcb93971 Michael Hanselmann
    self.nodes = _GetWantedNodes(self, self.op.nodes)
1597 a8083063 Iustin Pop
1598 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1599 a8083063 Iustin Pop
    """Copy a file from master to some nodes.
1600 a8083063 Iustin Pop

1601 a8083063 Iustin Pop
    Args:
1602 a8083063 Iustin Pop
      opts - class with options as members
1603 a8083063 Iustin Pop
      args - list containing a single element, the file name
1604 a8083063 Iustin Pop
    Opts used:
1605 a8083063 Iustin Pop
      nodes - list containing the name of target nodes; if empty, all nodes
1606 a8083063 Iustin Pop

1607 a8083063 Iustin Pop
    """
1608 a8083063 Iustin Pop
    filename = self.op.filename
1609 a8083063 Iustin Pop
1610 a8083063 Iustin Pop
    myname = socket.gethostname()
1611 a8083063 Iustin Pop
1612 8bd562f5 Iustin Pop
    for node in [node.name for node in self.nodes]:
1613 a8083063 Iustin Pop
      if node == myname:
1614 a8083063 Iustin Pop
        continue
1615 a8083063 Iustin Pop
      if not ssh.CopyFileToNode(node, filename):
1616 a8083063 Iustin Pop
        logger.Error("Copy of file %s to node %s failed" % (filename, node))
1617 a8083063 Iustin Pop
1618 a8083063 Iustin Pop
1619 a8083063 Iustin Pop
class LUDumpClusterConfig(NoHooksLU):
1620 a8083063 Iustin Pop
  """Return a text-representation of the cluster-config.
1621 a8083063 Iustin Pop

1622 a8083063 Iustin Pop
  """
1623 a8083063 Iustin Pop
  _OP_REQP = []
1624 a8083063 Iustin Pop
1625 a8083063 Iustin Pop
  def CheckPrereq(self):
1626 a8083063 Iustin Pop
    """No prerequisites.
1627 a8083063 Iustin Pop

1628 a8083063 Iustin Pop
    """
1629 a8083063 Iustin Pop
    pass
1630 a8083063 Iustin Pop
1631 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1632 a8083063 Iustin Pop
    """Dump a representation of the cluster config to the standard output.
1633 a8083063 Iustin Pop

1634 a8083063 Iustin Pop
    """
1635 a8083063 Iustin Pop
    return self.cfg.DumpConfig()
1636 a8083063 Iustin Pop
1637 a8083063 Iustin Pop
1638 a8083063 Iustin Pop
class LURunClusterCommand(NoHooksLU):
1639 a8083063 Iustin Pop
  """Run a command on some nodes.
1640 a8083063 Iustin Pop

1641 a8083063 Iustin Pop
  """
1642 a8083063 Iustin Pop
  _OP_REQP = ["command", "nodes"]
1643 a8083063 Iustin Pop
1644 a8083063 Iustin Pop
  def CheckPrereq(self):
1645 a8083063 Iustin Pop
    """Check prerequisites.
1646 a8083063 Iustin Pop

1647 a8083063 Iustin Pop
    It checks that the given list of nodes is valid.
1648 a8083063 Iustin Pop

1649 a8083063 Iustin Pop
    """
1650 dcb93971 Michael Hanselmann
    self.nodes = _GetWantedNodes(self, self.op.nodes)
1651 a8083063 Iustin Pop
1652 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1653 a8083063 Iustin Pop
    """Run a command on some nodes.
1654 a8083063 Iustin Pop

1655 a8083063 Iustin Pop
    """
1656 a8083063 Iustin Pop
    data = []
1657 a8083063 Iustin Pop
    for node in self.nodes:
1658 02715459 Iustin Pop
      result = ssh.SSHCall(node.name, "root", self.op.command)
1659 02715459 Iustin Pop
      data.append((node.name, result.output, result.exit_code))
1660 a8083063 Iustin Pop
1661 a8083063 Iustin Pop
    return data
1662 a8083063 Iustin Pop
1663 a8083063 Iustin Pop
1664 a8083063 Iustin Pop
class LUActivateInstanceDisks(NoHooksLU):
1665 a8083063 Iustin Pop
  """Bring up an instance's disks.
1666 a8083063 Iustin Pop

1667 a8083063 Iustin Pop
  """
1668 a8083063 Iustin Pop
  _OP_REQP = ["instance_name"]
1669 a8083063 Iustin Pop
1670 a8083063 Iustin Pop
  def CheckPrereq(self):
1671 a8083063 Iustin Pop
    """Check prerequisites.
1672 a8083063 Iustin Pop

1673 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
1674 a8083063 Iustin Pop

1675 a8083063 Iustin Pop
    """
1676 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
1677 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
1678 a8083063 Iustin Pop
    if instance is None:
1679 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
1680 3ecf6786 Iustin Pop
                                 self.op.instance_name)
1681 a8083063 Iustin Pop
    self.instance = instance
1682 a8083063 Iustin Pop
1683 a8083063 Iustin Pop
1684 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1685 a8083063 Iustin Pop
    """Activate the disks.
1686 a8083063 Iustin Pop

1687 a8083063 Iustin Pop
    """
1688 a8083063 Iustin Pop
    disks_ok, disks_info = _AssembleInstanceDisks(self.instance, self.cfg)
1689 a8083063 Iustin Pop
    if not disks_ok:
1690 3ecf6786 Iustin Pop
      raise errors.OpExecError("Cannot activate block devices")
1691 a8083063 Iustin Pop
1692 a8083063 Iustin Pop
    return disks_info
1693 a8083063 Iustin Pop
1694 a8083063 Iustin Pop
1695 a8083063 Iustin Pop
def _AssembleInstanceDisks(instance, cfg, ignore_secondaries=False):
1696 a8083063 Iustin Pop
  """Prepare the block devices for an instance.
1697 a8083063 Iustin Pop

1698 a8083063 Iustin Pop
  This sets up the block devices on all nodes.
1699 a8083063 Iustin Pop

1700 a8083063 Iustin Pop
  Args:
1701 a8083063 Iustin Pop
    instance: a ganeti.objects.Instance object
1702 a8083063 Iustin Pop
    ignore_secondaries: if true, errors on secondary nodes won't result
1703 a8083063 Iustin Pop
                        in an error return from the function
1704 a8083063 Iustin Pop

1705 a8083063 Iustin Pop
  Returns:
1706 a8083063 Iustin Pop
    false if the operation failed
1707 a8083063 Iustin Pop
    list of (host, instance_visible_name, node_visible_name) if the operation
1708 a8083063 Iustin Pop
         suceeded with the mapping from node devices to instance devices
1709 a8083063 Iustin Pop
  """
1710 a8083063 Iustin Pop
  device_info = []
1711 a8083063 Iustin Pop
  disks_ok = True
1712 a8083063 Iustin Pop
  for inst_disk in instance.disks:
1713 a8083063 Iustin Pop
    master_result = None
1714 a8083063 Iustin Pop
    for node, node_disk in inst_disk.ComputeNodeTree(instance.primary_node):
1715 a8083063 Iustin Pop
      cfg.SetDiskID(node_disk, node)
1716 a8083063 Iustin Pop
      is_primary = node == instance.primary_node
1717 a8083063 Iustin Pop
      result = rpc.call_blockdev_assemble(node, node_disk, is_primary)
1718 a8083063 Iustin Pop
      if not result:
1719 a8083063 Iustin Pop
        logger.Error("could not prepare block device %s on node %s (is_pri"
1720 a8083063 Iustin Pop
                     "mary=%s)" % (inst_disk.iv_name, node, is_primary))
1721 a8083063 Iustin Pop
        if is_primary or not ignore_secondaries:
1722 a8083063 Iustin Pop
          disks_ok = False
1723 a8083063 Iustin Pop
      if is_primary:
1724 a8083063 Iustin Pop
        master_result = result
1725 a8083063 Iustin Pop
    device_info.append((instance.primary_node, inst_disk.iv_name,
1726 a8083063 Iustin Pop
                        master_result))
1727 a8083063 Iustin Pop
1728 a8083063 Iustin Pop
  return disks_ok, device_info
1729 a8083063 Iustin Pop
1730 a8083063 Iustin Pop
1731 fe7b0351 Michael Hanselmann
def _StartInstanceDisks(cfg, instance, force):
1732 3ecf6786 Iustin Pop
  """Start the disks of an instance.
1733 3ecf6786 Iustin Pop

1734 3ecf6786 Iustin Pop
  """
1735 fe7b0351 Michael Hanselmann
  disks_ok, dummy = _AssembleInstanceDisks(instance, cfg,
1736 fe7b0351 Michael Hanselmann
                                           ignore_secondaries=force)
1737 fe7b0351 Michael Hanselmann
  if not disks_ok:
1738 fe7b0351 Michael Hanselmann
    _ShutdownInstanceDisks(instance, cfg)
1739 fe7b0351 Michael Hanselmann
    if force is not None and not force:
1740 fe7b0351 Michael Hanselmann
      logger.Error("If the message above refers to a secondary node,"
1741 fe7b0351 Michael Hanselmann
                   " you can retry the operation using '--force'.")
1742 3ecf6786 Iustin Pop
    raise errors.OpExecError("Disk consistency error")
1743 fe7b0351 Michael Hanselmann
1744 fe7b0351 Michael Hanselmann
1745 a8083063 Iustin Pop
class LUDeactivateInstanceDisks(NoHooksLU):
1746 a8083063 Iustin Pop
  """Shutdown an instance's disks.
1747 a8083063 Iustin Pop

1748 a8083063 Iustin Pop
  """
1749 a8083063 Iustin Pop
  _OP_REQP = ["instance_name"]
1750 a8083063 Iustin Pop
1751 a8083063 Iustin Pop
  def CheckPrereq(self):
1752 a8083063 Iustin Pop
    """Check prerequisites.
1753 a8083063 Iustin Pop

1754 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
1755 a8083063 Iustin Pop

1756 a8083063 Iustin Pop
    """
1757 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
1758 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
1759 a8083063 Iustin Pop
    if instance is None:
1760 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
1761 3ecf6786 Iustin Pop
                                 self.op.instance_name)
1762 a8083063 Iustin Pop
    self.instance = instance
1763 a8083063 Iustin Pop
1764 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1765 a8083063 Iustin Pop
    """Deactivate the disks
1766 a8083063 Iustin Pop

1767 a8083063 Iustin Pop
    """
1768 a8083063 Iustin Pop
    instance = self.instance
1769 a8083063 Iustin Pop
    ins_l = rpc.call_instance_list([instance.primary_node])
1770 a8083063 Iustin Pop
    ins_l = ins_l[instance.primary_node]
1771 a8083063 Iustin Pop
    if not type(ins_l) is list:
1772 3ecf6786 Iustin Pop
      raise errors.OpExecError("Can't contact node '%s'" %
1773 3ecf6786 Iustin Pop
                               instance.primary_node)
1774 a8083063 Iustin Pop
1775 a8083063 Iustin Pop
    if self.instance.name in ins_l:
1776 3ecf6786 Iustin Pop
      raise errors.OpExecError("Instance is running, can't shutdown"
1777 3ecf6786 Iustin Pop
                               " block devices.")
1778 a8083063 Iustin Pop
1779 a8083063 Iustin Pop
    _ShutdownInstanceDisks(instance, self.cfg)
1780 a8083063 Iustin Pop
1781 a8083063 Iustin Pop
1782 a8083063 Iustin Pop
def _ShutdownInstanceDisks(instance, cfg, ignore_primary=False):
1783 a8083063 Iustin Pop
  """Shutdown block devices of an instance.
1784 a8083063 Iustin Pop

1785 a8083063 Iustin Pop
  This does the shutdown on all nodes of the instance.
1786 a8083063 Iustin Pop

1787 a8083063 Iustin Pop
  If the ignore_primary is false, errors on the primary node are
1788 a8083063 Iustin Pop
  ignored.
1789 a8083063 Iustin Pop

1790 a8083063 Iustin Pop
  """
1791 a8083063 Iustin Pop
  result = True
1792 a8083063 Iustin Pop
  for disk in instance.disks:
1793 a8083063 Iustin Pop
    for node, top_disk in disk.ComputeNodeTree(instance.primary_node):
1794 a8083063 Iustin Pop
      cfg.SetDiskID(top_disk, node)
1795 a8083063 Iustin Pop
      if not rpc.call_blockdev_shutdown(node, top_disk):
1796 a8083063 Iustin Pop
        logger.Error("could not shutdown block device %s on node %s" %
1797 a8083063 Iustin Pop
                     (disk.iv_name, node))
1798 a8083063 Iustin Pop
        if not ignore_primary or node != instance.primary_node:
1799 a8083063 Iustin Pop
          result = False
1800 a8083063 Iustin Pop
  return result
1801 a8083063 Iustin Pop
1802 a8083063 Iustin Pop
1803 a8083063 Iustin Pop
class LUStartupInstance(LogicalUnit):
1804 a8083063 Iustin Pop
  """Starts an instance.
1805 a8083063 Iustin Pop

1806 a8083063 Iustin Pop
  """
1807 a8083063 Iustin Pop
  HPATH = "instance-start"
1808 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
1809 a8083063 Iustin Pop
  _OP_REQP = ["instance_name", "force"]
1810 a8083063 Iustin Pop
1811 a8083063 Iustin Pop
  def BuildHooksEnv(self):
1812 a8083063 Iustin Pop
    """Build hooks env.
1813 a8083063 Iustin Pop

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

1816 a8083063 Iustin Pop
    """
1817 a8083063 Iustin Pop
    env = {
1818 a8083063 Iustin Pop
      "FORCE": self.op.force,
1819 a8083063 Iustin Pop
      }
1820 396e1b78 Michael Hanselmann
    env.update(_BuildInstanceHookEnvByObject(self.instance))
1821 880478f8 Iustin Pop
    nl = ([self.sstore.GetMasterNode(), self.instance.primary_node] +
1822 a8083063 Iustin Pop
          list(self.instance.secondary_nodes))
1823 a8083063 Iustin Pop
    return env, nl, nl
1824 a8083063 Iustin Pop
1825 a8083063 Iustin Pop
  def CheckPrereq(self):
1826 a8083063 Iustin Pop
    """Check prerequisites.
1827 a8083063 Iustin Pop

1828 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
1829 a8083063 Iustin Pop

1830 a8083063 Iustin Pop
    """
1831 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
1832 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
1833 a8083063 Iustin Pop
    if instance is None:
1834 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
1835 3ecf6786 Iustin Pop
                                 self.op.instance_name)
1836 a8083063 Iustin Pop
1837 a8083063 Iustin Pop
    # check bridges existance
1838 a8083063 Iustin Pop
    brlist = [nic.bridge for nic in instance.nics]
1839 a8083063 Iustin Pop
    if not rpc.call_bridges_exist(instance.primary_node, brlist):
1840 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("one or more target bridges %s does not"
1841 3ecf6786 Iustin Pop
                                 " exist on destination node '%s'" %
1842 3ecf6786 Iustin Pop
                                 (brlist, instance.primary_node))
1843 a8083063 Iustin Pop
1844 a8083063 Iustin Pop
    self.instance = instance
1845 a8083063 Iustin Pop
    self.op.instance_name = instance.name
1846 a8083063 Iustin Pop
1847 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1848 a8083063 Iustin Pop
    """Start the instance.
1849 a8083063 Iustin Pop

1850 a8083063 Iustin Pop
    """
1851 a8083063 Iustin Pop
    instance = self.instance
1852 a8083063 Iustin Pop
    force = self.op.force
1853 a8083063 Iustin Pop
    extra_args = getattr(self.op, "extra_args", "")
1854 a8083063 Iustin Pop
1855 a8083063 Iustin Pop
    node_current = instance.primary_node
1856 a8083063 Iustin Pop
1857 a8083063 Iustin Pop
    nodeinfo = rpc.call_node_info([node_current], self.cfg.GetVGName())
1858 a8083063 Iustin Pop
    if not nodeinfo:
1859 3ecf6786 Iustin Pop
      raise errors.OpExecError("Could not contact node %s for infos" %
1860 3ecf6786 Iustin Pop
                               (node_current))
1861 a8083063 Iustin Pop
1862 a8083063 Iustin Pop
    freememory = nodeinfo[node_current]['memory_free']
1863 a8083063 Iustin Pop
    memory = instance.memory
1864 a8083063 Iustin Pop
    if memory > freememory:
1865 3ecf6786 Iustin Pop
      raise errors.OpExecError("Not enough memory to start instance"
1866 3ecf6786 Iustin Pop
                               " %s on node %s"
1867 3ecf6786 Iustin Pop
                               " needed %s MiB, available %s MiB" %
1868 3ecf6786 Iustin Pop
                               (instance.name, node_current, memory,
1869 3ecf6786 Iustin Pop
                                freememory))
1870 a8083063 Iustin Pop
1871 fe7b0351 Michael Hanselmann
    _StartInstanceDisks(self.cfg, instance, force)
1872 a8083063 Iustin Pop
1873 a8083063 Iustin Pop
    if not rpc.call_instance_start(node_current, instance, extra_args):
1874 a8083063 Iustin Pop
      _ShutdownInstanceDisks(instance, self.cfg)
1875 3ecf6786 Iustin Pop
      raise errors.OpExecError("Could not start instance")
1876 a8083063 Iustin Pop
1877 a8083063 Iustin Pop
    self.cfg.MarkInstanceUp(instance.name)
1878 a8083063 Iustin Pop
1879 a8083063 Iustin Pop
1880 a8083063 Iustin Pop
class LUShutdownInstance(LogicalUnit):
1881 a8083063 Iustin Pop
  """Shutdown an instance.
1882 a8083063 Iustin Pop

1883 a8083063 Iustin Pop
  """
1884 a8083063 Iustin Pop
  HPATH = "instance-stop"
1885 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
1886 a8083063 Iustin Pop
  _OP_REQP = ["instance_name"]
1887 a8083063 Iustin Pop
1888 a8083063 Iustin Pop
  def BuildHooksEnv(self):
1889 a8083063 Iustin Pop
    """Build hooks env.
1890 a8083063 Iustin Pop

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

1893 a8083063 Iustin Pop
    """
1894 396e1b78 Michael Hanselmann
    env = _BuildInstanceHookEnvByObject(self.instance)
1895 880478f8 Iustin Pop
    nl = ([self.sstore.GetMasterNode(), self.instance.primary_node] +
1896 a8083063 Iustin Pop
          list(self.instance.secondary_nodes))
1897 a8083063 Iustin Pop
    return env, nl, nl
1898 a8083063 Iustin Pop
1899 a8083063 Iustin Pop
  def CheckPrereq(self):
1900 a8083063 Iustin Pop
    """Check prerequisites.
1901 a8083063 Iustin Pop

1902 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
1903 a8083063 Iustin Pop

1904 a8083063 Iustin Pop
    """
1905 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
1906 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
1907 a8083063 Iustin Pop
    if instance is None:
1908 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
1909 3ecf6786 Iustin Pop
                                 self.op.instance_name)
1910 a8083063 Iustin Pop
    self.instance = instance
1911 a8083063 Iustin Pop
1912 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1913 a8083063 Iustin Pop
    """Shutdown the instance.
1914 a8083063 Iustin Pop

1915 a8083063 Iustin Pop
    """
1916 a8083063 Iustin Pop
    instance = self.instance
1917 a8083063 Iustin Pop
    node_current = instance.primary_node
1918 a8083063 Iustin Pop
    if not rpc.call_instance_shutdown(node_current, instance):
1919 a8083063 Iustin Pop
      logger.Error("could not shutdown instance")
1920 a8083063 Iustin Pop
1921 a8083063 Iustin Pop
    self.cfg.MarkInstanceDown(instance.name)
1922 a8083063 Iustin Pop
    _ShutdownInstanceDisks(instance, self.cfg)
1923 a8083063 Iustin Pop
1924 a8083063 Iustin Pop
1925 fe7b0351 Michael Hanselmann
class LUReinstallInstance(LogicalUnit):
1926 fe7b0351 Michael Hanselmann
  """Reinstall an instance.
1927 fe7b0351 Michael Hanselmann

1928 fe7b0351 Michael Hanselmann
  """
1929 fe7b0351 Michael Hanselmann
  HPATH = "instance-reinstall"
1930 fe7b0351 Michael Hanselmann
  HTYPE = constants.HTYPE_INSTANCE
1931 fe7b0351 Michael Hanselmann
  _OP_REQP = ["instance_name"]
1932 fe7b0351 Michael Hanselmann
1933 fe7b0351 Michael Hanselmann
  def BuildHooksEnv(self):
1934 fe7b0351 Michael Hanselmann
    """Build hooks env.
1935 fe7b0351 Michael Hanselmann

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

1938 fe7b0351 Michael Hanselmann
    """
1939 396e1b78 Michael Hanselmann
    env = _BuildInstanceHookEnvByObject(self.instance)
1940 fe7b0351 Michael Hanselmann
    nl = ([self.sstore.GetMasterNode(), self.instance.primary_node] +
1941 fe7b0351 Michael Hanselmann
          list(self.instance.secondary_nodes))
1942 fe7b0351 Michael Hanselmann
    return env, nl, nl
1943 fe7b0351 Michael Hanselmann
1944 fe7b0351 Michael Hanselmann
  def CheckPrereq(self):
1945 fe7b0351 Michael Hanselmann
    """Check prerequisites.
1946 fe7b0351 Michael Hanselmann

1947 fe7b0351 Michael Hanselmann
    This checks that the instance is in the cluster and is not running.
1948 fe7b0351 Michael Hanselmann

1949 fe7b0351 Michael Hanselmann
    """
1950 fe7b0351 Michael Hanselmann
    instance = self.cfg.GetInstanceInfo(
1951 fe7b0351 Michael Hanselmann
      self.cfg.ExpandInstanceName(self.op.instance_name))
1952 fe7b0351 Michael Hanselmann
    if instance is None:
1953 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
1954 3ecf6786 Iustin Pop
                                 self.op.instance_name)
1955 fe7b0351 Michael Hanselmann
    if instance.disk_template == constants.DT_DISKLESS:
1956 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' has no disks" %
1957 3ecf6786 Iustin Pop
                                 self.op.instance_name)
1958 fe7b0351 Michael Hanselmann
    if instance.status != "down":
1959 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' is marked to be up" %
1960 3ecf6786 Iustin Pop
                                 self.op.instance_name)
1961 fe7b0351 Michael Hanselmann
    remote_info = rpc.call_instance_info(instance.primary_node, instance.name)
1962 fe7b0351 Michael Hanselmann
    if remote_info:
1963 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' is running on the node %s" %
1964 3ecf6786 Iustin Pop
                                 (self.op.instance_name,
1965 3ecf6786 Iustin Pop
                                  instance.primary_node))
1966 d0834de3 Michael Hanselmann
1967 d0834de3 Michael Hanselmann
    self.op.os_type = getattr(self.op, "os_type", None)
1968 d0834de3 Michael Hanselmann
    if self.op.os_type is not None:
1969 d0834de3 Michael Hanselmann
      # OS verification
1970 d0834de3 Michael Hanselmann
      pnode = self.cfg.GetNodeInfo(
1971 d0834de3 Michael Hanselmann
        self.cfg.ExpandNodeName(instance.primary_node))
1972 d0834de3 Michael Hanselmann
      if pnode is None:
1973 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Primary node '%s' is unknown" %
1974 3ecf6786 Iustin Pop
                                   self.op.pnode)
1975 d0834de3 Michael Hanselmann
      os_obj = rpc.call_os_get([pnode.name], self.op.os_type)[pnode.name]
1976 d0834de3 Michael Hanselmann
      if not isinstance(os_obj, objects.OS):
1977 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("OS '%s' not in supported OS list for"
1978 3ecf6786 Iustin Pop
                                   " primary node"  % self.op.os_type)
1979 d0834de3 Michael Hanselmann
1980 fe7b0351 Michael Hanselmann
    self.instance = instance
1981 fe7b0351 Michael Hanselmann
1982 fe7b0351 Michael Hanselmann
  def Exec(self, feedback_fn):
1983 fe7b0351 Michael Hanselmann
    """Reinstall the instance.
1984 fe7b0351 Michael Hanselmann

1985 fe7b0351 Michael Hanselmann
    """
1986 fe7b0351 Michael Hanselmann
    inst = self.instance
1987 fe7b0351 Michael Hanselmann
1988 d0834de3 Michael Hanselmann
    if self.op.os_type is not None:
1989 d0834de3 Michael Hanselmann
      feedback_fn("Changing OS to '%s'..." % self.op.os_type)
1990 d0834de3 Michael Hanselmann
      inst.os = self.op.os_type
1991 d0834de3 Michael Hanselmann
      self.cfg.AddInstance(inst)
1992 d0834de3 Michael Hanselmann
1993 fe7b0351 Michael Hanselmann
    _StartInstanceDisks(self.cfg, inst, None)
1994 fe7b0351 Michael Hanselmann
    try:
1995 fe7b0351 Michael Hanselmann
      feedback_fn("Running the instance OS create scripts...")
1996 fe7b0351 Michael Hanselmann
      if not rpc.call_instance_os_add(inst.primary_node, inst, "sda", "sdb"):
1997 3ecf6786 Iustin Pop
        raise errors.OpExecError("Could not install OS for instance %s "
1998 3ecf6786 Iustin Pop
                                 "on node %s" %
1999 3ecf6786 Iustin Pop
                                 (inst.name, inst.primary_node))
2000 fe7b0351 Michael Hanselmann
    finally:
2001 fe7b0351 Michael Hanselmann
      _ShutdownInstanceDisks(inst, self.cfg)
2002 fe7b0351 Michael Hanselmann
2003 fe7b0351 Michael Hanselmann
2004 a8083063 Iustin Pop
class LURemoveInstance(LogicalUnit):
2005 a8083063 Iustin Pop
  """Remove an instance.
2006 a8083063 Iustin Pop

2007 a8083063 Iustin Pop
  """
2008 a8083063 Iustin Pop
  HPATH = "instance-remove"
2009 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
2010 a8083063 Iustin Pop
  _OP_REQP = ["instance_name"]
2011 a8083063 Iustin Pop
2012 a8083063 Iustin Pop
  def BuildHooksEnv(self):
2013 a8083063 Iustin Pop
    """Build hooks env.
2014 a8083063 Iustin Pop

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

2017 a8083063 Iustin Pop
    """
2018 396e1b78 Michael Hanselmann
    env = _BuildInstanceHookEnvByObject(self.instance)
2019 880478f8 Iustin Pop
    nl = ([self.sstore.GetMasterNode(), self.instance.primary_node] +
2020 a8083063 Iustin Pop
          list(self.instance.secondary_nodes))
2021 a8083063 Iustin Pop
    return env, nl, nl
2022 a8083063 Iustin Pop
2023 a8083063 Iustin Pop
  def CheckPrereq(self):
2024 a8083063 Iustin Pop
    """Check prerequisites.
2025 a8083063 Iustin Pop

2026 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
2027 a8083063 Iustin Pop

2028 a8083063 Iustin Pop
    """
2029 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
2030 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
2031 a8083063 Iustin Pop
    if instance is None:
2032 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
2033 3ecf6786 Iustin Pop
                                 self.op.instance_name)
2034 a8083063 Iustin Pop
    self.instance = instance
2035 a8083063 Iustin Pop
2036 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
2037 a8083063 Iustin Pop
    """Remove the instance.
2038 a8083063 Iustin Pop

2039 a8083063 Iustin Pop
    """
2040 a8083063 Iustin Pop
    instance = self.instance
2041 a8083063 Iustin Pop
    logger.Info("shutting down instance %s on node %s" %
2042 a8083063 Iustin Pop
                (instance.name, instance.primary_node))
2043 a8083063 Iustin Pop
2044 a8083063 Iustin Pop
    if not rpc.call_instance_shutdown(instance.primary_node, instance):
2045 3ecf6786 Iustin Pop
      raise errors.OpExecError("Could not shutdown instance %s on node %s" %
2046 3ecf6786 Iustin Pop
                               (instance.name, instance.primary_node))
2047 a8083063 Iustin Pop
2048 a8083063 Iustin Pop
    logger.Info("removing block devices for instance %s" % instance.name)
2049 a8083063 Iustin Pop
2050 a8083063 Iustin Pop
    _RemoveDisks(instance, self.cfg)
2051 a8083063 Iustin Pop
2052 a8083063 Iustin Pop
    logger.Info("removing instance %s out of cluster config" % instance.name)
2053 a8083063 Iustin Pop
2054 a8083063 Iustin Pop
    self.cfg.RemoveInstance(instance.name)
2055 a8083063 Iustin Pop
2056 a8083063 Iustin Pop
2057 a8083063 Iustin Pop
class LUQueryInstances(NoHooksLU):
2058 a8083063 Iustin Pop
  """Logical unit for querying instances.
2059 a8083063 Iustin Pop

2060 a8083063 Iustin Pop
  """
2061 dcb93971 Michael Hanselmann
  _OP_REQP = ["output_fields"]
2062 a8083063 Iustin Pop
2063 a8083063 Iustin Pop
  def CheckPrereq(self):
2064 a8083063 Iustin Pop
    """Check prerequisites.
2065 a8083063 Iustin Pop

2066 a8083063 Iustin Pop
    This checks that the fields required are valid output fields.
2067 a8083063 Iustin Pop

2068 a8083063 Iustin Pop
    """
2069 a8083063 Iustin Pop
    self.dynamic_fields = frozenset(["oper_state", "oper_ram"])
2070 dcb93971 Michael Hanselmann
    _CheckOutputFields(static=["name", "os", "pnode", "snodes",
2071 dcb93971 Michael Hanselmann
                               "admin_state", "admin_ram",
2072 644eeef9 Iustin Pop
                               "disk_template", "ip", "mac", "bridge",
2073 644eeef9 Iustin Pop
                               "sda_size", "sdb_size"],
2074 dcb93971 Michael Hanselmann
                       dynamic=self.dynamic_fields,
2075 dcb93971 Michael Hanselmann
                       selected=self.op.output_fields)
2076 a8083063 Iustin Pop
2077 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
2078 a8083063 Iustin Pop
    """Computes the list of nodes and their attributes.
2079 a8083063 Iustin Pop

2080 a8083063 Iustin Pop
    """
2081 a8083063 Iustin Pop
    instance_names = utils.NiceSort(self.cfg.GetInstanceList())
2082 a8083063 Iustin Pop
    instance_list = [self.cfg.GetInstanceInfo(iname) for iname
2083 a8083063 Iustin Pop
                     in instance_names]
2084 a8083063 Iustin Pop
2085 a8083063 Iustin Pop
    # begin data gathering
2086 a8083063 Iustin Pop
2087 a8083063 Iustin Pop
    nodes = frozenset([inst.primary_node for inst in instance_list])
2088 a8083063 Iustin Pop
2089 a8083063 Iustin Pop
    bad_nodes = []
2090 a8083063 Iustin Pop
    if self.dynamic_fields.intersection(self.op.output_fields):
2091 a8083063 Iustin Pop
      live_data = {}
2092 a8083063 Iustin Pop
      node_data = rpc.call_all_instances_info(nodes)
2093 a8083063 Iustin Pop
      for name in nodes:
2094 a8083063 Iustin Pop
        result = node_data[name]
2095 a8083063 Iustin Pop
        if result:
2096 a8083063 Iustin Pop
          live_data.update(result)
2097 a8083063 Iustin Pop
        elif result == False:
2098 a8083063 Iustin Pop
          bad_nodes.append(name)
2099 a8083063 Iustin Pop
        # else no instance is alive
2100 a8083063 Iustin Pop
    else:
2101 a8083063 Iustin Pop
      live_data = dict([(name, {}) for name in instance_names])
2102 a8083063 Iustin Pop
2103 a8083063 Iustin Pop
    # end data gathering
2104 a8083063 Iustin Pop
2105 a8083063 Iustin Pop
    output = []
2106 a8083063 Iustin Pop
    for instance in instance_list:
2107 a8083063 Iustin Pop
      iout = []
2108 a8083063 Iustin Pop
      for field in self.op.output_fields:
2109 a8083063 Iustin Pop
        if field == "name":
2110 a8083063 Iustin Pop
          val = instance.name
2111 a8083063 Iustin Pop
        elif field == "os":
2112 a8083063 Iustin Pop
          val = instance.os
2113 a8083063 Iustin Pop
        elif field == "pnode":
2114 a8083063 Iustin Pop
          val = instance.primary_node
2115 a8083063 Iustin Pop
        elif field == "snodes":
2116 a8083063 Iustin Pop
          val = ",".join(instance.secondary_nodes) or "-"
2117 a8083063 Iustin Pop
        elif field == "admin_state":
2118 a8083063 Iustin Pop
          if instance.status == "down":
2119 a8083063 Iustin Pop
            val = "no"
2120 a8083063 Iustin Pop
          else:
2121 a8083063 Iustin Pop
            val = "yes"
2122 a8083063 Iustin Pop
        elif field == "oper_state":
2123 a8083063 Iustin Pop
          if instance.primary_node in bad_nodes:
2124 a8083063 Iustin Pop
            val = "(node down)"
2125 a8083063 Iustin Pop
          else:
2126 a8083063 Iustin Pop
            if live_data.get(instance.name):
2127 a8083063 Iustin Pop
              val = "running"
2128 a8083063 Iustin Pop
            else:
2129 a8083063 Iustin Pop
              val = "stopped"
2130 a8083063 Iustin Pop
        elif field == "admin_ram":
2131 a8083063 Iustin Pop
          val = instance.memory
2132 a8083063 Iustin Pop
        elif field == "oper_ram":
2133 a8083063 Iustin Pop
          if instance.primary_node in bad_nodes:
2134 a8083063 Iustin Pop
            val = "(node down)"
2135 a8083063 Iustin Pop
          elif instance.name in live_data:
2136 a8083063 Iustin Pop
            val = live_data[instance.name].get("memory", "?")
2137 a8083063 Iustin Pop
          else:
2138 a8083063 Iustin Pop
            val = "-"
2139 a8083063 Iustin Pop
        elif field == "disk_template":
2140 a8083063 Iustin Pop
          val = instance.disk_template
2141 a8083063 Iustin Pop
        elif field == "ip":
2142 a8083063 Iustin Pop
          val = instance.nics[0].ip
2143 a8083063 Iustin Pop
        elif field == "bridge":
2144 a8083063 Iustin Pop
          val = instance.nics[0].bridge
2145 a8083063 Iustin Pop
        elif field == "mac":
2146 a8083063 Iustin Pop
          val = instance.nics[0].mac
2147 644eeef9 Iustin Pop
        elif field == "sda_size" or field == "sdb_size":
2148 644eeef9 Iustin Pop
          disk = instance.FindDisk(field[:3])
2149 644eeef9 Iustin Pop
          if disk is None:
2150 644eeef9 Iustin Pop
            val = "N/A"
2151 644eeef9 Iustin Pop
          else:
2152 644eeef9 Iustin Pop
            val = disk.size
2153 a8083063 Iustin Pop
        else:
2154 3ecf6786 Iustin Pop
          raise errors.ParameterError(field)
2155 a8083063 Iustin Pop
        val = str(val)
2156 a8083063 Iustin Pop
        iout.append(val)
2157 a8083063 Iustin Pop
      output.append(iout)
2158 a8083063 Iustin Pop
2159 a8083063 Iustin Pop
    return output
2160 a8083063 Iustin Pop
2161 a8083063 Iustin Pop
2162 a8083063 Iustin Pop
class LUFailoverInstance(LogicalUnit):
2163 a8083063 Iustin Pop
  """Failover an instance.
2164 a8083063 Iustin Pop

2165 a8083063 Iustin Pop
  """
2166 a8083063 Iustin Pop
  HPATH = "instance-failover"
2167 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
2168 a8083063 Iustin Pop
  _OP_REQP = ["instance_name", "ignore_consistency"]
2169 a8083063 Iustin Pop
2170 a8083063 Iustin Pop
  def BuildHooksEnv(self):
2171 a8083063 Iustin Pop
    """Build hooks env.
2172 a8083063 Iustin Pop

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

2175 a8083063 Iustin Pop
    """
2176 a8083063 Iustin Pop
    env = {
2177 a8083063 Iustin Pop
      "IGNORE_CONSISTENCY": self.op.ignore_consistency,
2178 a8083063 Iustin Pop
      }
2179 396e1b78 Michael Hanselmann
    env.update(_BuildInstanceHookEnvByObject(self.instance))
2180 880478f8 Iustin Pop
    nl = [self.sstore.GetMasterNode()] + list(self.instance.secondary_nodes)
2181 a8083063 Iustin Pop
    return env, nl, nl
2182 a8083063 Iustin Pop
2183 a8083063 Iustin Pop
  def CheckPrereq(self):
2184 a8083063 Iustin Pop
    """Check prerequisites.
2185 a8083063 Iustin Pop

2186 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
2187 a8083063 Iustin Pop

2188 a8083063 Iustin Pop
    """
2189 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
2190 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
2191 a8083063 Iustin Pop
    if instance is None:
2192 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
2193 3ecf6786 Iustin Pop
                                 self.op.instance_name)
2194 a8083063 Iustin Pop
2195 2a710df1 Michael Hanselmann
    if instance.disk_template != constants.DT_REMOTE_RAID1:
2196 2a710df1 Michael Hanselmann
      raise errors.OpPrereqError("Instance's disk layout is not"
2197 2a710df1 Michael Hanselmann
                                 " remote_raid1.")
2198 2a710df1 Michael Hanselmann
2199 2a710df1 Michael Hanselmann
    secondary_nodes = instance.secondary_nodes
2200 2a710df1 Michael Hanselmann
    if not secondary_nodes:
2201 2a710df1 Michael Hanselmann
      raise errors.ProgrammerError("no secondary node but using "
2202 2a710df1 Michael Hanselmann
                                   "DT_REMOTE_RAID1 template")
2203 2a710df1 Michael Hanselmann
2204 3a7c308e Guido Trotter
    # check memory requirements on the secondary node
2205 2a710df1 Michael Hanselmann
    target_node = secondary_nodes[0]
2206 3a7c308e Guido Trotter
    nodeinfo = rpc.call_node_info([target_node], self.cfg.GetVGName())
2207 3a7c308e Guido Trotter
    info = nodeinfo.get(target_node, None)
2208 3a7c308e Guido Trotter
    if not info:
2209 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Cannot get current information"
2210 3ecf6786 Iustin Pop
                                 " from node '%s'" % nodeinfo)
2211 3a7c308e Guido Trotter
    if instance.memory > info['memory_free']:
2212 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Not enough memory on target node %s."
2213 3ecf6786 Iustin Pop
                                 " %d MB available, %d MB required" %
2214 3ecf6786 Iustin Pop
                                 (target_node, info['memory_free'],
2215 3ecf6786 Iustin Pop
                                  instance.memory))
2216 3a7c308e Guido Trotter
2217 a8083063 Iustin Pop
    # check bridge existance
2218 a8083063 Iustin Pop
    brlist = [nic.bridge for nic in instance.nics]
2219 a8083063 Iustin Pop
    if not rpc.call_bridges_exist(instance.primary_node, brlist):
2220 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("One or more target bridges %s does not"
2221 3ecf6786 Iustin Pop
                                 " exist on destination node '%s'" %
2222 3ecf6786 Iustin Pop
                                 (brlist, instance.primary_node))
2223 a8083063 Iustin Pop
2224 a8083063 Iustin Pop
    self.instance = instance
2225 a8083063 Iustin Pop
2226 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
2227 a8083063 Iustin Pop
    """Failover an instance.
2228 a8083063 Iustin Pop

2229 a8083063 Iustin Pop
    The failover is done by shutting it down on its present node and
2230 a8083063 Iustin Pop
    starting it on the secondary.
2231 a8083063 Iustin Pop

2232 a8083063 Iustin Pop
    """
2233 a8083063 Iustin Pop
    instance = self.instance
2234 a8083063 Iustin Pop
2235 a8083063 Iustin Pop
    source_node = instance.primary_node
2236 a8083063 Iustin Pop
    target_node = instance.secondary_nodes[0]
2237 a8083063 Iustin Pop
2238 a8083063 Iustin Pop
    feedback_fn("* checking disk consistency between source and target")
2239 a8083063 Iustin Pop
    for dev in instance.disks:
2240 a8083063 Iustin Pop
      # for remote_raid1, these are md over drbd
2241 a8083063 Iustin Pop
      if not _CheckDiskConsistency(self.cfg, dev, target_node, False):
2242 a8083063 Iustin Pop
        if not self.op.ignore_consistency:
2243 3ecf6786 Iustin Pop
          raise errors.OpExecError("Disk %s is degraded on target node,"
2244 3ecf6786 Iustin Pop
                                   " aborting failover." % dev.iv_name)
2245 a8083063 Iustin Pop
2246 a8083063 Iustin Pop
    feedback_fn("* checking target node resource availability")
2247 a8083063 Iustin Pop
    nodeinfo = rpc.call_node_info([target_node], self.cfg.GetVGName())
2248 a8083063 Iustin Pop
2249 a8083063 Iustin Pop
    if not nodeinfo:
2250 3ecf6786 Iustin Pop
      raise errors.OpExecError("Could not contact target node %s." %
2251 3ecf6786 Iustin Pop
                               target_node)
2252 a8083063 Iustin Pop
2253 a8083063 Iustin Pop
    free_memory = int(nodeinfo[target_node]['memory_free'])
2254 a8083063 Iustin Pop
    memory = instance.memory
2255 a8083063 Iustin Pop
    if memory > free_memory:
2256 3ecf6786 Iustin Pop
      raise errors.OpExecError("Not enough memory to create instance %s on"
2257 3ecf6786 Iustin Pop
                               " node %s. needed %s MiB, available %s MiB" %
2258 3ecf6786 Iustin Pop
                               (instance.name, target_node, memory,
2259 3ecf6786 Iustin Pop
                                free_memory))
2260 a8083063 Iustin Pop
2261 a8083063 Iustin Pop
    feedback_fn("* shutting down instance on source node")
2262 a8083063 Iustin Pop
    logger.Info("Shutting down instance %s on node %s" %
2263 a8083063 Iustin Pop
                (instance.name, source_node))
2264 a8083063 Iustin Pop
2265 a8083063 Iustin Pop
    if not rpc.call_instance_shutdown(source_node, instance):
2266 a8083063 Iustin Pop
      logger.Error("Could not shutdown instance %s on node %s. Proceeding"
2267 a8083063 Iustin Pop
                   " anyway. Please make sure node %s is down"  %
2268 a8083063 Iustin Pop
                   (instance.name, source_node, source_node))
2269 a8083063 Iustin Pop
2270 a8083063 Iustin Pop
    feedback_fn("* deactivating the instance's disks on source node")
2271 a8083063 Iustin Pop
    if not _ShutdownInstanceDisks(instance, self.cfg, ignore_primary=True):
2272 3ecf6786 Iustin Pop
      raise errors.OpExecError("Can't shut down the instance's disks.")
2273 a8083063 Iustin Pop
2274 a8083063 Iustin Pop
    instance.primary_node = target_node
2275 a8083063 Iustin Pop
    # distribute new instance config to the other nodes
2276 a8083063 Iustin Pop
    self.cfg.AddInstance(instance)
2277 a8083063 Iustin Pop
2278 a8083063 Iustin Pop
    feedback_fn("* activating the instance's disks on target node")
2279 a8083063 Iustin Pop
    logger.Info("Starting instance %s on node %s" %
2280 a8083063 Iustin Pop
                (instance.name, target_node))
2281 a8083063 Iustin Pop
2282 a8083063 Iustin Pop
    disks_ok, dummy = _AssembleInstanceDisks(instance, self.cfg,
2283 a8083063 Iustin Pop
                                             ignore_secondaries=True)
2284 a8083063 Iustin Pop
    if not disks_ok:
2285 a8083063 Iustin Pop
      _ShutdownInstanceDisks(instance, self.cfg)
2286 3ecf6786 Iustin Pop
      raise errors.OpExecError("Can't activate the instance's disks")
2287 a8083063 Iustin Pop
2288 a8083063 Iustin Pop
    feedback_fn("* starting the instance on the target node")
2289 a8083063 Iustin Pop
    if not rpc.call_instance_start(target_node, instance, None):
2290 a8083063 Iustin Pop
      _ShutdownInstanceDisks(instance, self.cfg)
2291 a8083063 Iustin Pop
      raise errors.OpExecError("Could not start instance %s on node %s." %
2292 d0b3526f Michael Hanselmann
                               (instance.name, target_node))
2293 a8083063 Iustin Pop
2294 a8083063 Iustin Pop
2295 a0c3fea1 Michael Hanselmann
def _CreateBlockDevOnPrimary(cfg, node, device, info):
2296 a8083063 Iustin Pop
  """Create a tree of block devices on the primary node.
2297 a8083063 Iustin Pop

2298 a8083063 Iustin Pop
  This always creates all devices.
2299 a8083063 Iustin Pop

2300 a8083063 Iustin Pop
  """
2301 a8083063 Iustin Pop
  if device.children:
2302 a8083063 Iustin Pop
    for child in device.children:
2303 a0c3fea1 Michael Hanselmann
      if not _CreateBlockDevOnPrimary(cfg, node, child, info):
2304 a8083063 Iustin Pop
        return False
2305 a8083063 Iustin Pop
2306 a8083063 Iustin Pop
  cfg.SetDiskID(device, node)
2307 a0c3fea1 Michael Hanselmann
  new_id = rpc.call_blockdev_create(node, device, device.size, True, info)
2308 a8083063 Iustin Pop
  if not new_id:
2309 a8083063 Iustin Pop
    return False
2310 a8083063 Iustin Pop
  if device.physical_id is None:
2311 a8083063 Iustin Pop
    device.physical_id = new_id
2312 a8083063 Iustin Pop
  return True
2313 a8083063 Iustin Pop
2314 a8083063 Iustin Pop
2315 a0c3fea1 Michael Hanselmann
def _CreateBlockDevOnSecondary(cfg, node, device, force, info):
2316 a8083063 Iustin Pop
  """Create a tree of block devices on a secondary node.
2317 a8083063 Iustin Pop

2318 a8083063 Iustin Pop
  If this device type has to be created on secondaries, create it and
2319 a8083063 Iustin Pop
  all its children.
2320 a8083063 Iustin Pop

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

2323 a8083063 Iustin Pop
  """
2324 a8083063 Iustin Pop
  if device.CreateOnSecondary():
2325 a8083063 Iustin Pop
    force = True
2326 a8083063 Iustin Pop
  if device.children:
2327 a8083063 Iustin Pop
    for child in device.children:
2328 a0c3fea1 Michael Hanselmann
      if not _CreateBlockDevOnSecondary(cfg, node, child, force, info):
2329 a8083063 Iustin Pop
        return False
2330 a8083063 Iustin Pop
2331 a8083063 Iustin Pop
  if not force:
2332 a8083063 Iustin Pop
    return True
2333 a8083063 Iustin Pop
  cfg.SetDiskID(device, node)
2334 a0c3fea1 Michael Hanselmann
  new_id = rpc.call_blockdev_create(node, device, device.size, False, info)
2335 a8083063 Iustin Pop
  if not new_id:
2336 a8083063 Iustin Pop
    return False
2337 a8083063 Iustin Pop
  if device.physical_id is None:
2338 a8083063 Iustin Pop
    device.physical_id = new_id
2339 a8083063 Iustin Pop
  return True
2340 a8083063 Iustin Pop
2341 a8083063 Iustin Pop
2342 923b1523 Iustin Pop
def _GenerateUniqueNames(cfg, exts):
2343 923b1523 Iustin Pop
  """Generate a suitable LV name.
2344 923b1523 Iustin Pop

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

2347 923b1523 Iustin Pop
  """
2348 923b1523 Iustin Pop
  results = []
2349 923b1523 Iustin Pop
  for val in exts:
2350 923b1523 Iustin Pop
    new_id = cfg.GenerateUniqueID()
2351 923b1523 Iustin Pop
    results.append("%s%s" % (new_id, val))
2352 923b1523 Iustin Pop
  return results
2353 923b1523 Iustin Pop
2354 923b1523 Iustin Pop
2355 923b1523 Iustin Pop
def _GenerateMDDRBDBranch(cfg, primary, secondary, size, names):
2356 a8083063 Iustin Pop
  """Generate a drbd device complete with its children.
2357 a8083063 Iustin Pop

2358 a8083063 Iustin Pop
  """
2359 a8083063 Iustin Pop
  port = cfg.AllocatePort()
2360 923b1523 Iustin Pop
  vgname = cfg.GetVGName()
2361 a8083063 Iustin Pop
  dev_data = objects.Disk(dev_type="lvm", size=size,
2362 923b1523 Iustin Pop
                          logical_id=(vgname, names[0]))
2363 a8083063 Iustin Pop
  dev_meta = objects.Disk(dev_type="lvm", size=128,
2364 923b1523 Iustin Pop
                          logical_id=(vgname, names[1]))
2365 a8083063 Iustin Pop
  drbd_dev = objects.Disk(dev_type="drbd", size=size,
2366 a8083063 Iustin Pop
                          logical_id = (primary, secondary, port),
2367 a8083063 Iustin Pop
                          children = [dev_data, dev_meta])
2368 a8083063 Iustin Pop
  return drbd_dev
2369 a8083063 Iustin Pop
2370 a8083063 Iustin Pop
2371 923b1523 Iustin Pop
def _GenerateDiskTemplate(cfg, template_name,
2372 a8083063 Iustin Pop
                          instance_name, primary_node,
2373 a8083063 Iustin Pop
                          secondary_nodes, disk_sz, swap_sz):
2374 a8083063 Iustin Pop
  """Generate the entire disk layout for a given template type.
2375 a8083063 Iustin Pop

2376 a8083063 Iustin Pop
  """
2377 a8083063 Iustin Pop
  #TODO: compute space requirements
2378 a8083063 Iustin Pop
2379 923b1523 Iustin Pop
  vgname = cfg.GetVGName()
2380 a8083063 Iustin Pop
  if template_name == "diskless":
2381 a8083063 Iustin Pop
    disks = []
2382 a8083063 Iustin Pop
  elif template_name == "plain":
2383 a8083063 Iustin Pop
    if len(secondary_nodes) != 0:
2384 a8083063 Iustin Pop
      raise errors.ProgrammerError("Wrong template configuration")
2385 923b1523 Iustin Pop
2386 923b1523 Iustin Pop
    names = _GenerateUniqueNames(cfg, [".sda", ".sdb"])
2387 a8083063 Iustin Pop
    sda_dev = objects.Disk(dev_type="lvm", size=disk_sz,
2388 923b1523 Iustin Pop
                           logical_id=(vgname, names[0]),
2389 a8083063 Iustin Pop
                           iv_name = "sda")
2390 a8083063 Iustin Pop
    sdb_dev = objects.Disk(dev_type="lvm", size=swap_sz,
2391 923b1523 Iustin Pop
                           logical_id=(vgname, names[1]),
2392 a8083063 Iustin Pop
                           iv_name = "sdb")
2393 a8083063 Iustin Pop
    disks = [sda_dev, sdb_dev]
2394 a8083063 Iustin Pop
  elif template_name == "local_raid1":
2395 a8083063 Iustin Pop
    if len(secondary_nodes) != 0:
2396 a8083063 Iustin Pop
      raise errors.ProgrammerError("Wrong template configuration")
2397 923b1523 Iustin Pop
2398 923b1523 Iustin Pop
2399 923b1523 Iustin Pop
    names = _GenerateUniqueNames(cfg, [".sda_m1", ".sda_m2",
2400 923b1523 Iustin Pop
                                       ".sdb_m1", ".sdb_m2"])
2401 a8083063 Iustin Pop
    sda_dev_m1 = objects.Disk(dev_type="lvm", size=disk_sz,
2402 923b1523 Iustin Pop
                              logical_id=(vgname, names[0]))
2403 a8083063 Iustin Pop
    sda_dev_m2 = objects.Disk(dev_type="lvm", size=disk_sz,
2404 923b1523 Iustin Pop
                              logical_id=(vgname, names[1]))
2405 a8083063 Iustin Pop
    md_sda_dev = objects.Disk(dev_type="md_raid1", iv_name = "sda",
2406 a8083063 Iustin Pop
                              size=disk_sz,
2407 a8083063 Iustin Pop
                              children = [sda_dev_m1, sda_dev_m2])
2408 a8083063 Iustin Pop
    sdb_dev_m1 = objects.Disk(dev_type="lvm", size=swap_sz,
2409 923b1523 Iustin Pop
                              logical_id=(vgname, names[2]))
2410 a8083063 Iustin Pop
    sdb_dev_m2 = objects.Disk(dev_type="lvm", size=swap_sz,
2411 923b1523 Iustin Pop
                              logical_id=(vgname, names[3]))
2412 a8083063 Iustin Pop
    md_sdb_dev = objects.Disk(dev_type="md_raid1", iv_name = "sdb",
2413 a8083063 Iustin Pop
                              size=swap_sz,
2414 a8083063 Iustin Pop
                              children = [sdb_dev_m1, sdb_dev_m2])
2415 a8083063 Iustin Pop
    disks = [md_sda_dev, md_sdb_dev]
2416 2a710df1 Michael Hanselmann
  elif template_name == constants.DT_REMOTE_RAID1:
2417 a8083063 Iustin Pop
    if len(secondary_nodes) != 1:
2418 a8083063 Iustin Pop
      raise errors.ProgrammerError("Wrong template configuration")
2419 a8083063 Iustin Pop
    remote_node = secondary_nodes[0]
2420 923b1523 Iustin Pop
    names = _GenerateUniqueNames(cfg, [".sda_data", ".sda_meta",
2421 923b1523 Iustin Pop
                                       ".sdb_data", ".sdb_meta"])
2422 923b1523 Iustin Pop
    drbd_sda_dev = _GenerateMDDRBDBranch(cfg, primary_node, remote_node,
2423 923b1523 Iustin Pop
                                         disk_sz, names[0:2])
2424 a8083063 Iustin Pop
    md_sda_dev = objects.Disk(dev_type="md_raid1", iv_name="sda",
2425 a8083063 Iustin Pop
                              children = [drbd_sda_dev], size=disk_sz)
2426 923b1523 Iustin Pop
    drbd_sdb_dev = _GenerateMDDRBDBranch(cfg, primary_node, remote_node,
2427 923b1523 Iustin Pop
                                         swap_sz, names[2:4])
2428 a8083063 Iustin Pop
    md_sdb_dev = objects.Disk(dev_type="md_raid1", iv_name="sdb",
2429 a8083063 Iustin Pop
                              children = [drbd_sdb_dev], size=swap_sz)
2430 a8083063 Iustin Pop
    disks = [md_sda_dev, md_sdb_dev]
2431 a8083063 Iustin Pop
  else:
2432 a8083063 Iustin Pop
    raise errors.ProgrammerError("Invalid disk template '%s'" % template_name)
2433 a8083063 Iustin Pop
  return disks
2434 a8083063 Iustin Pop
2435 a8083063 Iustin Pop
2436 a0c3fea1 Michael Hanselmann
def _GetInstanceInfoText(instance):
2437 3ecf6786 Iustin Pop
  """Compute that text that should be added to the disk's metadata.
2438 3ecf6786 Iustin Pop

2439 3ecf6786 Iustin Pop
  """
2440 a0c3fea1 Michael Hanselmann
  return "originstname+%s" % instance.name
2441 a0c3fea1 Michael Hanselmann
2442 a0c3fea1 Michael Hanselmann
2443 a8083063 Iustin Pop
def _CreateDisks(cfg, instance):
2444 a8083063 Iustin Pop
  """Create all disks for an instance.
2445 a8083063 Iustin Pop

2446 a8083063 Iustin Pop
  This abstracts away some work from AddInstance.
2447 a8083063 Iustin Pop

2448 a8083063 Iustin Pop
  Args:
2449 a8083063 Iustin Pop
    instance: the instance object
2450 a8083063 Iustin Pop

2451 a8083063 Iustin Pop
  Returns:
2452 a8083063 Iustin Pop
    True or False showing the success of the creation process
2453 a8083063 Iustin Pop

2454 a8083063 Iustin Pop
  """
2455 a0c3fea1 Michael Hanselmann
  info = _GetInstanceInfoText(instance)
2456 a0c3fea1 Michael Hanselmann
2457 a8083063 Iustin Pop
  for device in instance.disks:
2458 a8083063 Iustin Pop
    logger.Info("creating volume %s for instance %s" %
2459 a8083063 Iustin Pop
              (device.iv_name, instance.name))
2460 a8083063 Iustin Pop
    #HARDCODE
2461 a8083063 Iustin Pop
    for secondary_node in instance.secondary_nodes:
2462 a0c3fea1 Michael Hanselmann
      if not _CreateBlockDevOnSecondary(cfg, secondary_node, device, False,
2463 a0c3fea1 Michael Hanselmann
                                        info):
2464 a8083063 Iustin Pop
        logger.Error("failed to create volume %s (%s) on secondary node %s!" %
2465 a8083063 Iustin Pop
                     (device.iv_name, device, secondary_node))
2466 a8083063 Iustin Pop
        return False
2467 a8083063 Iustin Pop
    #HARDCODE
2468 a0c3fea1 Michael Hanselmann
    if not _CreateBlockDevOnPrimary(cfg, instance.primary_node, device, info):
2469 a8083063 Iustin Pop
      logger.Error("failed to create volume %s on primary!" %
2470 a8083063 Iustin Pop
                   device.iv_name)
2471 a8083063 Iustin Pop
      return False
2472 a8083063 Iustin Pop
  return True
2473 a8083063 Iustin Pop
2474 a8083063 Iustin Pop
2475 a8083063 Iustin Pop
def _RemoveDisks(instance, cfg):
2476 a8083063 Iustin Pop
  """Remove all disks for an instance.
2477 a8083063 Iustin Pop

2478 a8083063 Iustin Pop
  This abstracts away some work from `AddInstance()` and
2479 a8083063 Iustin Pop
  `RemoveInstance()`. Note that in case some of the devices couldn't
2480 a8083063 Iustin Pop
  be remove, the removal will continue with the other ones (compare
2481 a8083063 Iustin Pop
  with `_CreateDisks()`).
2482 a8083063 Iustin Pop

2483 a8083063 Iustin Pop
  Args:
2484 a8083063 Iustin Pop
    instance: the instance object
2485 a8083063 Iustin Pop

2486 a8083063 Iustin Pop
  Returns:
2487 a8083063 Iustin Pop
    True or False showing the success of the removal proces
2488 a8083063 Iustin Pop

2489 a8083063 Iustin Pop
  """
2490 a8083063 Iustin Pop
  logger.Info("removing block devices for instance %s" % instance.name)
2491 a8083063 Iustin Pop
2492 a8083063 Iustin Pop
  result = True
2493 a8083063 Iustin Pop
  for device in instance.disks:
2494 a8083063 Iustin Pop
    for node, disk in device.ComputeNodeTree(instance.primary_node):
2495 a8083063 Iustin Pop
      cfg.SetDiskID(disk, node)
2496 a8083063 Iustin Pop
      if not rpc.call_blockdev_remove(node, disk):
2497 a8083063 Iustin Pop
        logger.Error("could not remove block device %s on node %s,"
2498 a8083063 Iustin Pop
                     " continuing anyway" %
2499 a8083063 Iustin Pop
                     (device.iv_name, node))
2500 a8083063 Iustin Pop
        result = False
2501 a8083063 Iustin Pop
  return result
2502 a8083063 Iustin Pop
2503 a8083063 Iustin Pop
2504 a8083063 Iustin Pop
class LUCreateInstance(LogicalUnit):
2505 a8083063 Iustin Pop
  """Create an instance.
2506 a8083063 Iustin Pop

2507 a8083063 Iustin Pop
  """
2508 a8083063 Iustin Pop
  HPATH = "instance-add"
2509 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
2510 a8083063 Iustin Pop
  _OP_REQP = ["instance_name", "mem_size", "disk_size", "pnode",
2511 a8083063 Iustin Pop
              "disk_template", "swap_size", "mode", "start", "vcpus",
2512 a8083063 Iustin Pop
              "wait_for_sync"]
2513 a8083063 Iustin Pop
2514 a8083063 Iustin Pop
  def BuildHooksEnv(self):
2515 a8083063 Iustin Pop
    """Build hooks env.
2516 a8083063 Iustin Pop

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

2519 a8083063 Iustin Pop
    """
2520 a8083063 Iustin Pop
    env = {
2521 396e1b78 Michael Hanselmann
      "INSTANCE_DISK_TEMPLATE": self.op.disk_template,
2522 396e1b78 Michael Hanselmann
      "INSTANCE_DISK_SIZE": self.op.disk_size,
2523 396e1b78 Michael Hanselmann
      "INSTANCE_SWAP_SIZE": self.op.swap_size,
2524 a8083063 Iustin Pop
      "INSTANCE_ADD_MODE": self.op.mode,
2525 a8083063 Iustin Pop
      }
2526 a8083063 Iustin Pop
    if self.op.mode == constants.INSTANCE_IMPORT:
2527 396e1b78 Michael Hanselmann
      env["INSTANCE_SRC_NODE"] = self.op.src_node
2528 396e1b78 Michael Hanselmann
      env["INSTANCE_SRC_PATH"] = self.op.src_path
2529 396e1b78 Michael Hanselmann
      env["INSTANCE_SRC_IMAGE"] = self.src_image
2530 396e1b78 Michael Hanselmann
2531 396e1b78 Michael Hanselmann
    env.update(_BuildInstanceHookEnv(name=self.op.instance_name,
2532 396e1b78 Michael Hanselmann
      primary_node=self.op.pnode,
2533 396e1b78 Michael Hanselmann
      secondary_nodes=self.secondaries,
2534 396e1b78 Michael Hanselmann
      status=self.instance_status,
2535 ecb215b5 Michael Hanselmann
      os_type=self.op.os_type,
2536 396e1b78 Michael Hanselmann
      memory=self.op.mem_size,
2537 396e1b78 Michael Hanselmann
      vcpus=self.op.vcpus,
2538 396e1b78 Michael Hanselmann
      nics=[(self.inst_ip, self.op.bridge)],
2539 396e1b78 Michael Hanselmann
    ))
2540 a8083063 Iustin Pop
2541 880478f8 Iustin Pop
    nl = ([self.sstore.GetMasterNode(), self.op.pnode] +
2542 a8083063 Iustin Pop
          self.secondaries)
2543 a8083063 Iustin Pop
    return env, nl, nl
2544 a8083063 Iustin Pop
2545 a8083063 Iustin Pop
2546 a8083063 Iustin Pop
  def CheckPrereq(self):
2547 a8083063 Iustin Pop
    """Check prerequisites.
2548 a8083063 Iustin Pop

2549 a8083063 Iustin Pop
    """
2550 a8083063 Iustin Pop
    if self.op.mode not in (constants.INSTANCE_CREATE,
2551 a8083063 Iustin Pop
                            constants.INSTANCE_IMPORT):
2552 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Invalid instance creation mode '%s'" %
2553 3ecf6786 Iustin Pop
                                 self.op.mode)
2554 a8083063 Iustin Pop
2555 a8083063 Iustin Pop
    if self.op.mode == constants.INSTANCE_IMPORT:
2556 a8083063 Iustin Pop
      src_node = getattr(self.op, "src_node", None)
2557 a8083063 Iustin Pop
      src_path = getattr(self.op, "src_path", None)
2558 a8083063 Iustin Pop
      if src_node is None or src_path is None:
2559 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Importing an instance requires source"
2560 3ecf6786 Iustin Pop
                                   " node and path options")
2561 a8083063 Iustin Pop
      src_node_full = self.cfg.ExpandNodeName(src_node)
2562 a8083063 Iustin Pop
      if src_node_full is None:
2563 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Unknown source node '%s'" % src_node)
2564 a8083063 Iustin Pop
      self.op.src_node = src_node = src_node_full
2565 a8083063 Iustin Pop
2566 a8083063 Iustin Pop
      if not os.path.isabs(src_path):
2567 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("The source path must be absolute")
2568 a8083063 Iustin Pop
2569 a8083063 Iustin Pop
      export_info = rpc.call_export_info(src_node, src_path)
2570 a8083063 Iustin Pop
2571 a8083063 Iustin Pop
      if not export_info:
2572 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("No export found in dir %s" % src_path)
2573 a8083063 Iustin Pop
2574 a8083063 Iustin Pop
      if not export_info.has_section(constants.INISECT_EXP):
2575 3ecf6786 Iustin Pop
        raise errors.ProgrammerError("Corrupted export config")
2576 a8083063 Iustin Pop
2577 a8083063 Iustin Pop
      ei_version = export_info.get(constants.INISECT_EXP, 'version')
2578 a8083063 Iustin Pop
      if (int(ei_version) != constants.EXPORT_VERSION):
2579 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Wrong export version %s (wanted %d)" %
2580 3ecf6786 Iustin Pop
                                   (ei_version, constants.EXPORT_VERSION))
2581 a8083063 Iustin Pop
2582 a8083063 Iustin Pop
      if int(export_info.get(constants.INISECT_INS, 'disk_count')) > 1:
2583 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Can't import instance with more than"
2584 3ecf6786 Iustin Pop
                                   " one data disk")
2585 a8083063 Iustin Pop
2586 a8083063 Iustin Pop
      # FIXME: are the old os-es, disk sizes, etc. useful?
2587 a8083063 Iustin Pop
      self.op.os_type = export_info.get(constants.INISECT_EXP, 'os')
2588 a8083063 Iustin Pop
      diskimage = os.path.join(src_path, export_info.get(constants.INISECT_INS,
2589 a8083063 Iustin Pop
                                                         'disk0_dump'))
2590 a8083063 Iustin Pop
      self.src_image = diskimage
2591 a8083063 Iustin Pop
    else: # INSTANCE_CREATE
2592 a8083063 Iustin Pop
      if getattr(self.op, "os_type", None) is None:
2593 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("No guest OS specified")
2594 a8083063 Iustin Pop
2595 a8083063 Iustin Pop
    # check primary node
2596 a8083063 Iustin Pop
    pnode = self.cfg.GetNodeInfo(self.cfg.ExpandNodeName(self.op.pnode))
2597 a8083063 Iustin Pop
    if pnode is None:
2598 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Primary node '%s' is unknown" %
2599 3ecf6786 Iustin Pop
                                 self.op.pnode)
2600 a8083063 Iustin Pop
    self.op.pnode = pnode.name
2601 a8083063 Iustin Pop
    self.pnode = pnode
2602 a8083063 Iustin Pop
    self.secondaries = []
2603 a8083063 Iustin Pop
    # disk template and mirror node verification
2604 a8083063 Iustin Pop
    if self.op.disk_template not in constants.DISK_TEMPLATES:
2605 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Invalid disk template name")
2606 a8083063 Iustin Pop
2607 a8083063 Iustin Pop
    if self.op.disk_template == constants.DT_REMOTE_RAID1:
2608 a8083063 Iustin Pop
      if getattr(self.op, "snode", None) is None:
2609 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("The 'remote_raid1' disk template needs"
2610 3ecf6786 Iustin Pop
                                   " a mirror node")
2611 a8083063 Iustin Pop
2612 a8083063 Iustin Pop
      snode_name = self.cfg.ExpandNodeName(self.op.snode)
2613 a8083063 Iustin Pop
      if snode_name is None:
2614 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Unknown secondary node '%s'" %
2615 3ecf6786 Iustin Pop
                                   self.op.snode)
2616 a8083063 Iustin Pop
      elif snode_name == pnode.name:
2617 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("The secondary node cannot be"
2618 3ecf6786 Iustin Pop
                                   " the primary node.")
2619 a8083063 Iustin Pop
      self.secondaries.append(snode_name)
2620 a8083063 Iustin Pop
2621 ed1ebc60 Guido Trotter
    # Check lv size requirements
2622 ed1ebc60 Guido Trotter
    nodenames = [pnode.name] + self.secondaries
2623 ed1ebc60 Guido Trotter
    nodeinfo = rpc.call_node_info(nodenames, self.cfg.GetVGName())
2624 ed1ebc60 Guido Trotter
2625 ed1ebc60 Guido Trotter
    # Required free disk space as a function of disk and swap space
2626 ed1ebc60 Guido Trotter
    req_size_dict = {
2627 ed1ebc60 Guido Trotter
      constants.DT_DISKLESS: 0,
2628 ed1ebc60 Guido Trotter
      constants.DT_PLAIN: self.op.disk_size + self.op.swap_size,
2629 ed1ebc60 Guido Trotter
      constants.DT_LOCAL_RAID1: (self.op.disk_size + self.op.swap_size) * 2,
2630 ed1ebc60 Guido Trotter
      # 256 MB are added for drbd metadata, 128MB for each drbd device
2631 ed1ebc60 Guido Trotter
      constants.DT_REMOTE_RAID1: self.op.disk_size + self.op.swap_size + 256,
2632 ed1ebc60 Guido Trotter
    }
2633 ed1ebc60 Guido Trotter
2634 ed1ebc60 Guido Trotter
    if self.op.disk_template not in req_size_dict:
2635 3ecf6786 Iustin Pop
      raise errors.ProgrammerError("Disk template '%s' size requirement"
2636 3ecf6786 Iustin Pop
                                   " is unknown" %  self.op.disk_template)
2637 ed1ebc60 Guido Trotter
2638 ed1ebc60 Guido Trotter
    req_size = req_size_dict[self.op.disk_template]
2639 ed1ebc60 Guido Trotter
2640 ed1ebc60 Guido Trotter
    for node in nodenames:
2641 ed1ebc60 Guido Trotter
      info = nodeinfo.get(node, None)
2642 ed1ebc60 Guido Trotter
      if not info:
2643 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Cannot get current information"
2644 3ecf6786 Iustin Pop
                                   " from node '%s'" % nodeinfo)
2645 ed1ebc60 Guido Trotter
      if req_size > info['vg_free']:
2646 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Not enough disk space on target node %s."
2647 3ecf6786 Iustin Pop
                                   " %d MB available, %d MB required" %
2648 3ecf6786 Iustin Pop
                                   (node, info['vg_free'], req_size))
2649 ed1ebc60 Guido Trotter
2650 a8083063 Iustin Pop
    # os verification
2651 a8083063 Iustin Pop
    os_obj = rpc.call_os_get([pnode.name], self.op.os_type)[pnode.name]
2652 a8083063 Iustin Pop
    if not isinstance(os_obj, objects.OS):
2653 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("OS '%s' not in supported os list for"
2654 3ecf6786 Iustin Pop
                                 " primary node"  % self.op.os_type)
2655 a8083063 Iustin Pop
2656 a8083063 Iustin Pop
    # instance verification
2657 a8083063 Iustin Pop
    hostname1 = utils.LookupHostname(self.op.instance_name)
2658 a8083063 Iustin Pop
    if not hostname1:
2659 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance name '%s' not found in dns" %
2660 3ecf6786 Iustin Pop
                                 self.op.instance_name)
2661 a8083063 Iustin Pop
2662 a8083063 Iustin Pop
    self.op.instance_name = instance_name = hostname1['hostname']
2663 a8083063 Iustin Pop
    instance_list = self.cfg.GetInstanceList()
2664 a8083063 Iustin Pop
    if instance_name in instance_list:
2665 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' is already in the cluster" %
2666 3ecf6786 Iustin Pop
                                 instance_name)
2667 a8083063 Iustin Pop
2668 a8083063 Iustin Pop
    ip = getattr(self.op, "ip", None)
2669 a8083063 Iustin Pop
    if ip is None or ip.lower() == "none":
2670 a8083063 Iustin Pop
      inst_ip = None
2671 a8083063 Iustin Pop
    elif ip.lower() == "auto":
2672 a8083063 Iustin Pop
      inst_ip = hostname1['ip']
2673 a8083063 Iustin Pop
    else:
2674 a8083063 Iustin Pop
      if not utils.IsValidIP(ip):
2675 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("given IP address '%s' doesn't look"
2676 3ecf6786 Iustin Pop
                                   " like a valid IP" % ip)
2677 a8083063 Iustin Pop
      inst_ip = ip
2678 a8083063 Iustin Pop
    self.inst_ip = inst_ip
2679 a8083063 Iustin Pop
2680 a8083063 Iustin Pop
    command = ["fping", "-q", hostname1['ip']]
2681 a8083063 Iustin Pop
    result = utils.RunCmd(command)
2682 a8083063 Iustin Pop
    if not result.failed:
2683 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("IP %s of instance %s already in use" %
2684 3ecf6786 Iustin Pop
                                 (hostname1['ip'], instance_name))
2685 a8083063 Iustin Pop
2686 a8083063 Iustin Pop
    # bridge verification
2687 a8083063 Iustin Pop
    bridge = getattr(self.op, "bridge", None)
2688 a8083063 Iustin Pop
    if bridge is None:
2689 a8083063 Iustin Pop
      self.op.bridge = self.cfg.GetDefBridge()
2690 a8083063 Iustin Pop
    else:
2691 a8083063 Iustin Pop
      self.op.bridge = bridge
2692 a8083063 Iustin Pop
2693 a8083063 Iustin Pop
    if not rpc.call_bridges_exist(self.pnode.name, [self.op.bridge]):
2694 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("target bridge '%s' does not exist on"
2695 3ecf6786 Iustin Pop
                                 " destination node '%s'" %
2696 3ecf6786 Iustin Pop
                                 (self.op.bridge, pnode.name))
2697 a8083063 Iustin Pop
2698 a8083063 Iustin Pop
    if self.op.start:
2699 a8083063 Iustin Pop
      self.instance_status = 'up'
2700 a8083063 Iustin Pop
    else:
2701 a8083063 Iustin Pop
      self.instance_status = 'down'
2702 a8083063 Iustin Pop
2703 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
2704 a8083063 Iustin Pop
    """Create and add the instance to the cluster.
2705 a8083063 Iustin Pop

2706 a8083063 Iustin Pop
    """
2707 a8083063 Iustin Pop
    instance = self.op.instance_name
2708 a8083063 Iustin Pop
    pnode_name = self.pnode.name
2709 a8083063 Iustin Pop
2710 a8083063 Iustin Pop
    nic = objects.NIC(bridge=self.op.bridge, mac=self.cfg.GenerateMAC())
2711 a8083063 Iustin Pop
    if self.inst_ip is not None:
2712 a8083063 Iustin Pop
      nic.ip = self.inst_ip
2713 a8083063 Iustin Pop
2714 923b1523 Iustin Pop
    disks = _GenerateDiskTemplate(self.cfg,
2715 a8083063 Iustin Pop
                                  self.op.disk_template,
2716 a8083063 Iustin Pop
                                  instance, pnode_name,
2717 a8083063 Iustin Pop
                                  self.secondaries, self.op.disk_size,
2718 a8083063 Iustin Pop
                                  self.op.swap_size)
2719 a8083063 Iustin Pop
2720 a8083063 Iustin Pop
    iobj = objects.Instance(name=instance, os=self.op.os_type,
2721 a8083063 Iustin Pop
                            primary_node=pnode_name,
2722 a8083063 Iustin Pop
                            memory=self.op.mem_size,
2723 a8083063 Iustin Pop
                            vcpus=self.op.vcpus,
2724 a8083063 Iustin Pop
                            nics=[nic], disks=disks,
2725 a8083063 Iustin Pop
                            disk_template=self.op.disk_template,
2726 a8083063 Iustin Pop
                            status=self.instance_status,
2727 a8083063 Iustin Pop
                            )
2728 a8083063 Iustin Pop
2729 a8083063 Iustin Pop
    feedback_fn("* creating instance disks...")
2730 a8083063 Iustin Pop
    if not _CreateDisks(self.cfg, iobj):
2731 a8083063 Iustin Pop
      _RemoveDisks(iobj, self.cfg)
2732 3ecf6786 Iustin Pop
      raise errors.OpExecError("Device creation failed, reverting...")
2733 a8083063 Iustin Pop
2734 a8083063 Iustin Pop
    feedback_fn("adding instance %s to cluster config" % instance)
2735 a8083063 Iustin Pop
2736 a8083063 Iustin Pop
    self.cfg.AddInstance(iobj)
2737 a8083063 Iustin Pop
2738 a8083063 Iustin Pop
    if self.op.wait_for_sync:
2739 a8083063 Iustin Pop
      disk_abort = not _WaitForSync(self.cfg, iobj)
2740 2a710df1 Michael Hanselmann
    elif iobj.disk_template == constants.DT_REMOTE_RAID1:
2741 a8083063 Iustin Pop
      # make sure the disks are not degraded (still sync-ing is ok)
2742 a8083063 Iustin Pop
      time.sleep(15)
2743 a8083063 Iustin Pop
      feedback_fn("* checking mirrors status")
2744 a8083063 Iustin Pop
      disk_abort = not _WaitForSync(self.cfg, iobj, oneshot=True)
2745 a8083063 Iustin Pop
    else:
2746 a8083063 Iustin Pop
      disk_abort = False
2747 a8083063 Iustin Pop
2748 a8083063 Iustin Pop
    if disk_abort:
2749 a8083063 Iustin Pop
      _RemoveDisks(iobj, self.cfg)
2750 a8083063 Iustin Pop
      self.cfg.RemoveInstance(iobj.name)
2751 3ecf6786 Iustin Pop
      raise errors.OpExecError("There are some degraded disks for"
2752 3ecf6786 Iustin Pop
                               " this instance")
2753 a8083063 Iustin Pop
2754 a8083063 Iustin Pop
    feedback_fn("creating os for instance %s on node %s" %
2755 a8083063 Iustin Pop
                (instance, pnode_name))
2756 a8083063 Iustin Pop
2757 a8083063 Iustin Pop
    if iobj.disk_template != constants.DT_DISKLESS:
2758 a8083063 Iustin Pop
      if self.op.mode == constants.INSTANCE_CREATE:
2759 a8083063 Iustin Pop
        feedback_fn("* running the instance OS create scripts...")
2760 a8083063 Iustin Pop
        if not rpc.call_instance_os_add(pnode_name, iobj, "sda", "sdb"):
2761 3ecf6786 Iustin Pop
          raise errors.OpExecError("could not add os for instance %s"
2762 3ecf6786 Iustin Pop
                                   " on node %s" %
2763 3ecf6786 Iustin Pop
                                   (instance, pnode_name))
2764 a8083063 Iustin Pop
2765 a8083063 Iustin Pop
      elif self.op.mode == constants.INSTANCE_IMPORT:
2766 a8083063 Iustin Pop
        feedback_fn("* running the instance OS import scripts...")
2767 a8083063 Iustin Pop
        src_node = self.op.src_node
2768 a8083063 Iustin Pop
        src_image = self.src_image
2769 a8083063 Iustin Pop
        if not rpc.call_instance_os_import(pnode_name, iobj, "sda", "sdb",
2770 a8083063 Iustin Pop
                                                src_node, src_image):
2771 3ecf6786 Iustin Pop
          raise errors.OpExecError("Could not import os for instance"
2772 3ecf6786 Iustin Pop
                                   " %s on node %s" %
2773 3ecf6786 Iustin Pop
                                   (instance, pnode_name))
2774 a8083063 Iustin Pop
      else:
2775 a8083063 Iustin Pop
        # also checked in the prereq part
2776 3ecf6786 Iustin Pop
        raise errors.ProgrammerError("Unknown OS initialization mode '%s'"
2777 3ecf6786 Iustin Pop
                                     % self.op.mode)
2778 a8083063 Iustin Pop
2779 a8083063 Iustin Pop
    if self.op.start:
2780 a8083063 Iustin Pop
      logger.Info("starting instance %s on node %s" % (instance, pnode_name))
2781 a8083063 Iustin Pop
      feedback_fn("* starting instance...")
2782 a8083063 Iustin Pop
      if not rpc.call_instance_start(pnode_name, iobj, None):
2783 3ecf6786 Iustin Pop
        raise errors.OpExecError("Could not start instance")
2784 a8083063 Iustin Pop
2785 a8083063 Iustin Pop
2786 a8083063 Iustin Pop
class LUConnectConsole(NoHooksLU):
2787 a8083063 Iustin Pop
  """Connect to an instance's console.
2788 a8083063 Iustin Pop

2789 a8083063 Iustin Pop
  This is somewhat special in that it returns the command line that
2790 a8083063 Iustin Pop
  you need to run on the master node in order to connect to the
2791 a8083063 Iustin Pop
  console.
2792 a8083063 Iustin Pop

2793 a8083063 Iustin Pop
  """
2794 a8083063 Iustin Pop
  _OP_REQP = ["instance_name"]
2795 a8083063 Iustin Pop
2796 a8083063 Iustin Pop
  def CheckPrereq(self):
2797 a8083063 Iustin Pop
    """Check prerequisites.
2798 a8083063 Iustin Pop

2799 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
2800 a8083063 Iustin Pop

2801 a8083063 Iustin Pop
    """
2802 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
2803 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
2804 a8083063 Iustin Pop
    if instance is None:
2805 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
2806 3ecf6786 Iustin Pop
                                 self.op.instance_name)
2807 a8083063 Iustin Pop
    self.instance = instance
2808 a8083063 Iustin Pop
2809 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
2810 a8083063 Iustin Pop
    """Connect to the console of an instance
2811 a8083063 Iustin Pop

2812 a8083063 Iustin Pop
    """
2813 a8083063 Iustin Pop
    instance = self.instance
2814 a8083063 Iustin Pop
    node = instance.primary_node
2815 a8083063 Iustin Pop
2816 a8083063 Iustin Pop
    node_insts = rpc.call_instance_list([node])[node]
2817 a8083063 Iustin Pop
    if node_insts is False:
2818 3ecf6786 Iustin Pop
      raise errors.OpExecError("Can't connect to node %s." % node)
2819 a8083063 Iustin Pop
2820 a8083063 Iustin Pop
    if instance.name not in node_insts:
2821 3ecf6786 Iustin Pop
      raise errors.OpExecError("Instance %s is not running." % instance.name)
2822 a8083063 Iustin Pop
2823 a8083063 Iustin Pop
    logger.Debug("connecting to console of %s on %s" % (instance.name, node))
2824 a8083063 Iustin Pop
2825 a8083063 Iustin Pop
    hyper = hypervisor.GetHypervisor()
2826 a8083063 Iustin Pop
    console_cmd = hyper.GetShellCommandForConsole(instance.name)
2827 82122173 Iustin Pop
    # build ssh cmdline
2828 82122173 Iustin Pop
    argv = ["ssh", "-q", "-t"]
2829 82122173 Iustin Pop
    argv.extend(ssh.KNOWN_HOSTS_OPTS)
2830 82122173 Iustin Pop
    argv.extend(ssh.BATCH_MODE_OPTS)
2831 82122173 Iustin Pop
    argv.append(node)
2832 82122173 Iustin Pop
    argv.append(console_cmd)
2833 82122173 Iustin Pop
    return "ssh", argv
2834 a8083063 Iustin Pop
2835 a8083063 Iustin Pop
2836 a8083063 Iustin Pop
class LUAddMDDRBDComponent(LogicalUnit):
2837 a8083063 Iustin Pop
  """Adda new mirror member to an instance's disk.
2838 a8083063 Iustin Pop

2839 a8083063 Iustin Pop
  """
2840 a8083063 Iustin Pop
  HPATH = "mirror-add"
2841 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
2842 a8083063 Iustin Pop
  _OP_REQP = ["instance_name", "remote_node", "disk_name"]
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 the master, the primary and all the secondaries.
2848 a8083063 Iustin Pop

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

2862 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
2863 a8083063 Iustin Pop

2864 a8083063 Iustin Pop
    """
2865 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
2866 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
2867 a8083063 Iustin Pop
    if instance is None:
2868 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
2869 3ecf6786 Iustin Pop
                                 self.op.instance_name)
2870 a8083063 Iustin Pop
    self.instance = instance
2871 a8083063 Iustin Pop
2872 a8083063 Iustin Pop
    remote_node = self.cfg.ExpandNodeName(self.op.remote_node)
2873 a8083063 Iustin Pop
    if remote_node is None:
2874 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Node '%s' not known" % self.op.remote_node)
2875 a8083063 Iustin Pop
    self.remote_node = remote_node
2876 a8083063 Iustin Pop
2877 a8083063 Iustin Pop
    if remote_node == instance.primary_node:
2878 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("The specified node is the primary node of"
2879 3ecf6786 Iustin Pop
                                 " the instance.")
2880 a8083063 Iustin Pop
2881 a8083063 Iustin Pop
    if instance.disk_template != constants.DT_REMOTE_RAID1:
2882 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance's disk layout is not"
2883 3ecf6786 Iustin Pop
                                 " remote_raid1.")
2884 a8083063 Iustin Pop
    for disk in instance.disks:
2885 a8083063 Iustin Pop
      if disk.iv_name == self.op.disk_name:
2886 a8083063 Iustin Pop
        break
2887 a8083063 Iustin Pop
    else:
2888 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Can't find this device ('%s') in the"
2889 3ecf6786 Iustin Pop
                                 " instance." % self.op.disk_name)
2890 a8083063 Iustin Pop
    if len(disk.children) > 1:
2891 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("The device already has two slave"
2892 3ecf6786 Iustin Pop
                                 " devices.\n"
2893 3ecf6786 Iustin Pop
                                 "This would create a 3-disk raid1"
2894 3ecf6786 Iustin Pop
                                 " which we don't allow.")
2895 a8083063 Iustin Pop
    self.disk = disk
2896 a8083063 Iustin Pop
2897 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
2898 a8083063 Iustin Pop
    """Add the mirror component
2899 a8083063 Iustin Pop

2900 a8083063 Iustin Pop
    """
2901 a8083063 Iustin Pop
    disk = self.disk
2902 a8083063 Iustin Pop
    instance = self.instance
2903 a8083063 Iustin Pop
2904 a8083063 Iustin Pop
    remote_node = self.remote_node
2905 923b1523 Iustin Pop
    lv_names = [".%s_%s" % (disk.iv_name, suf) for suf in ["data", "meta"]]
2906 923b1523 Iustin Pop
    names = _GenerateUniqueNames(self.cfg, lv_names)
2907 923b1523 Iustin Pop
    new_drbd = _GenerateMDDRBDBranch(self.cfg, instance.primary_node,
2908 923b1523 Iustin Pop
                                     remote_node, disk.size, names)
2909 a8083063 Iustin Pop
2910 a8083063 Iustin Pop
    logger.Info("adding new mirror component on secondary")
2911 a8083063 Iustin Pop
    #HARDCODE
2912 a0c3fea1 Michael Hanselmann
    if not _CreateBlockDevOnSecondary(self.cfg, remote_node, new_drbd, False,
2913 a0c3fea1 Michael Hanselmann
                                      _GetInstanceInfoText(instance)):
2914 3ecf6786 Iustin Pop
      raise errors.OpExecError("Failed to create new component on secondary"
2915 3ecf6786 Iustin Pop
                               " node %s" % remote_node)
2916 a8083063 Iustin Pop
2917 a8083063 Iustin Pop
    logger.Info("adding new mirror component on primary")
2918 a8083063 Iustin Pop
    #HARDCODE
2919 a0c3fea1 Michael Hanselmann
    if not _CreateBlockDevOnPrimary(self.cfg, instance.primary_node, new_drbd,
2920 a0c3fea1 Michael Hanselmann
                                    _GetInstanceInfoText(instance)):
2921 a8083063 Iustin Pop
      # remove secondary dev
2922 a8083063 Iustin Pop
      self.cfg.SetDiskID(new_drbd, remote_node)
2923 a8083063 Iustin Pop
      rpc.call_blockdev_remove(remote_node, new_drbd)
2924 3ecf6786 Iustin Pop
      raise errors.OpExecError("Failed to create volume on primary")
2925 a8083063 Iustin Pop
2926 a8083063 Iustin Pop
    # the device exists now
2927 a8083063 Iustin Pop
    # call the primary node to add the mirror to md
2928 a8083063 Iustin Pop
    logger.Info("adding new mirror component to md")
2929 a8083063 Iustin Pop
    if not rpc.call_blockdev_addchild(instance.primary_node,
2930 a8083063 Iustin Pop
                                           disk, new_drbd):
2931 a8083063 Iustin Pop
      logger.Error("Can't add mirror compoment to md!")
2932 a8083063 Iustin Pop
      self.cfg.SetDiskID(new_drbd, remote_node)
2933 a8083063 Iustin Pop
      if not rpc.call_blockdev_remove(remote_node, new_drbd):
2934 a8083063 Iustin Pop
        logger.Error("Can't rollback on secondary")
2935 a8083063 Iustin Pop
      self.cfg.SetDiskID(new_drbd, instance.primary_node)
2936 a8083063 Iustin Pop
      if not rpc.call_blockdev_remove(instance.primary_node, new_drbd):
2937 a8083063 Iustin Pop
        logger.Error("Can't rollback on primary")
2938 3ecf6786 Iustin Pop
      raise errors.OpExecError("Can't add mirror component to md array")
2939 a8083063 Iustin Pop
2940 a8083063 Iustin Pop
    disk.children.append(new_drbd)
2941 a8083063 Iustin Pop
2942 a8083063 Iustin Pop
    self.cfg.AddInstance(instance)
2943 a8083063 Iustin Pop
2944 a8083063 Iustin Pop
    _WaitForSync(self.cfg, instance)
2945 a8083063 Iustin Pop
2946 a8083063 Iustin Pop
    return 0
2947 a8083063 Iustin Pop
2948 a8083063 Iustin Pop
2949 a8083063 Iustin Pop
class LURemoveMDDRBDComponent(LogicalUnit):
2950 a8083063 Iustin Pop
  """Remove a component from a remote_raid1 disk.
2951 a8083063 Iustin Pop

2952 a8083063 Iustin Pop
  """
2953 a8083063 Iustin Pop
  HPATH = "mirror-remove"
2954 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
2955 a8083063 Iustin Pop
  _OP_REQP = ["instance_name", "disk_name", "disk_id"]
2956 a8083063 Iustin Pop
2957 a8083063 Iustin Pop
  def BuildHooksEnv(self):
2958 a8083063 Iustin Pop
    """Build hooks env.
2959 a8083063 Iustin Pop

2960 a8083063 Iustin Pop
    This runs on the master, the primary and all the secondaries.
2961 a8083063 Iustin Pop

2962 a8083063 Iustin Pop
    """
2963 a8083063 Iustin Pop
    env = {
2964 a8083063 Iustin Pop
      "DISK_NAME": self.op.disk_name,
2965 a8083063 Iustin Pop
      "DISK_ID": self.op.disk_id,
2966 a8083063 Iustin Pop
      "OLD_SECONDARY": self.old_secondary,
2967 a8083063 Iustin Pop
      }
2968 396e1b78 Michael Hanselmann
    env.update(_BuildInstanceHookEnvByObject(self.instance))
2969 880478f8 Iustin Pop
    nl = [self.sstore.GetMasterNode(),
2970 a8083063 Iustin Pop
          self.instance.primary_node] + list(self.instance.secondary_nodes)
2971 a8083063 Iustin Pop
    return env, nl, nl
2972 a8083063 Iustin Pop
2973 a8083063 Iustin Pop
  def CheckPrereq(self):
2974 a8083063 Iustin Pop
    """Check prerequisites.
2975 a8083063 Iustin Pop

2976 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
2977 a8083063 Iustin Pop

2978 a8083063 Iustin Pop
    """
2979 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
2980 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
2981 a8083063 Iustin Pop
    if instance is None:
2982 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
2983 3ecf6786 Iustin Pop
                                 self.op.instance_name)
2984 a8083063 Iustin Pop
    self.instance = instance
2985 a8083063 Iustin Pop
2986 a8083063 Iustin Pop
    if instance.disk_template != constants.DT_REMOTE_RAID1:
2987 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance's disk layout is not"
2988 3ecf6786 Iustin Pop
                                 " remote_raid1.")
2989 a8083063 Iustin Pop
    for disk in instance.disks:
2990 a8083063 Iustin Pop
      if disk.iv_name == self.op.disk_name:
2991 a8083063 Iustin Pop
        break
2992 a8083063 Iustin Pop
    else:
2993 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Can't find this device ('%s') in the"
2994 3ecf6786 Iustin Pop
                                 " instance." % self.op.disk_name)
2995 a8083063 Iustin Pop
    for child in disk.children:
2996 a8083063 Iustin Pop
      if child.dev_type == "drbd" and child.logical_id[2] == self.op.disk_id:
2997 a8083063 Iustin Pop
        break
2998 a8083063 Iustin Pop
    else:
2999 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Can't find the device with this port.")
3000 a8083063 Iustin Pop
3001 a8083063 Iustin Pop
    if len(disk.children) < 2:
3002 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Cannot remove the last component from"
3003 3ecf6786 Iustin Pop
                                 " a mirror.")
3004 a8083063 Iustin Pop
    self.disk = disk
3005 a8083063 Iustin Pop
    self.child = child
3006 a8083063 Iustin Pop
    if self.child.logical_id[0] == instance.primary_node:
3007 a8083063 Iustin Pop
      oid = 1
3008 a8083063 Iustin Pop
    else:
3009 a8083063 Iustin Pop
      oid = 0
3010 a8083063 Iustin Pop
    self.old_secondary = self.child.logical_id[oid]
3011 a8083063 Iustin Pop
3012 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
3013 a8083063 Iustin Pop
    """Remove the mirror component
3014 a8083063 Iustin Pop

3015 a8083063 Iustin Pop
    """
3016 a8083063 Iustin Pop
    instance = self.instance
3017 a8083063 Iustin Pop
    disk = self.disk
3018 a8083063 Iustin Pop
    child = self.child
3019 a8083063 Iustin Pop
    logger.Info("remove mirror component")
3020 a8083063 Iustin Pop
    self.cfg.SetDiskID(disk, instance.primary_node)
3021 a8083063 Iustin Pop
    if not rpc.call_blockdev_removechild(instance.primary_node,
3022 a8083063 Iustin Pop
                                              disk, child):
3023 3ecf6786 Iustin Pop
      raise errors.OpExecError("Can't remove child from mirror.")
3024 a8083063 Iustin Pop
3025 a8083063 Iustin Pop
    for node in child.logical_id[:2]:
3026 a8083063 Iustin Pop
      self.cfg.SetDiskID(child, node)
3027 a8083063 Iustin Pop
      if not rpc.call_blockdev_remove(node, child):
3028 a8083063 Iustin Pop
        logger.Error("Warning: failed to remove device from node %s,"
3029 a8083063 Iustin Pop
                     " continuing operation." % node)
3030 a8083063 Iustin Pop
3031 a8083063 Iustin Pop
    disk.children.remove(child)
3032 a8083063 Iustin Pop
    self.cfg.AddInstance(instance)
3033 a8083063 Iustin Pop
3034 a8083063 Iustin Pop
3035 a8083063 Iustin Pop
class LUReplaceDisks(LogicalUnit):
3036 a8083063 Iustin Pop
  """Replace the disks of an instance.
3037 a8083063 Iustin Pop

3038 a8083063 Iustin Pop
  """
3039 a8083063 Iustin Pop
  HPATH = "mirrors-replace"
3040 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
3041 a8083063 Iustin Pop
  _OP_REQP = ["instance_name"]
3042 a8083063 Iustin Pop
3043 a8083063 Iustin Pop
  def BuildHooksEnv(self):
3044 a8083063 Iustin Pop
    """Build hooks env.
3045 a8083063 Iustin Pop

3046 a8083063 Iustin Pop
    This runs on the master, the primary and all the secondaries.
3047 a8083063 Iustin Pop

3048 a8083063 Iustin Pop
    """
3049 a8083063 Iustin Pop
    env = {
3050 a8083063 Iustin Pop
      "NEW_SECONDARY": self.op.remote_node,
3051 a8083063 Iustin Pop
      "OLD_SECONDARY": self.instance.secondary_nodes[0],
3052 a8083063 Iustin Pop
      }
3053 396e1b78 Michael Hanselmann
    env.update(_BuildInstanceHookEnvByObject(self.instance))
3054 880478f8 Iustin Pop
    nl = [self.sstore.GetMasterNode(),
3055 a8083063 Iustin Pop
          self.instance.primary_node] + list(self.instance.secondary_nodes)
3056 a8083063 Iustin Pop
    return env, nl, nl
3057 a8083063 Iustin Pop
3058 a8083063 Iustin Pop
  def CheckPrereq(self):
3059 a8083063 Iustin Pop
    """Check prerequisites.
3060 a8083063 Iustin Pop

3061 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
3062 a8083063 Iustin Pop

3063 a8083063 Iustin Pop
    """
3064 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
3065 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
3066 a8083063 Iustin Pop
    if instance is None:
3067 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
3068 3ecf6786 Iustin Pop
                                 self.op.instance_name)
3069 a8083063 Iustin Pop
    self.instance = instance
3070 a8083063 Iustin Pop
3071 a8083063 Iustin Pop
    if instance.disk_template != constants.DT_REMOTE_RAID1:
3072 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance's disk layout is not"
3073 3ecf6786 Iustin Pop
                                 " remote_raid1.")
3074 a8083063 Iustin Pop
3075 a8083063 Iustin Pop
    if len(instance.secondary_nodes) != 1:
3076 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("The instance has a strange layout,"
3077 3ecf6786 Iustin Pop
                                 " expected one secondary but found %d" %
3078 3ecf6786 Iustin Pop
                                 len(instance.secondary_nodes))
3079 a8083063 Iustin Pop
3080 a8083063 Iustin Pop
    remote_node = getattr(self.op, "remote_node", None)
3081 a8083063 Iustin Pop
    if remote_node is None:
3082 a8083063 Iustin Pop
      remote_node = instance.secondary_nodes[0]
3083 a8083063 Iustin Pop
    else:
3084 a8083063 Iustin Pop
      remote_node = self.cfg.ExpandNodeName(remote_node)
3085 a8083063 Iustin Pop
      if remote_node is None:
3086 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Node '%s' not known" %
3087 3ecf6786 Iustin Pop
                                   self.op.remote_node)
3088 a8083063 Iustin Pop
    if remote_node == instance.primary_node:
3089 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("The specified node is the primary node of"
3090 3ecf6786 Iustin Pop
                                 " the instance.")
3091 a8083063 Iustin Pop
    self.op.remote_node = remote_node
3092 a8083063 Iustin Pop
3093 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
3094 a8083063 Iustin Pop
    """Replace the disks of an instance.
3095 a8083063 Iustin Pop

3096 a8083063 Iustin Pop
    """
3097 a8083063 Iustin Pop
    instance = self.instance
3098 a8083063 Iustin Pop
    iv_names = {}
3099 a8083063 Iustin Pop
    # start of work
3100 a8083063 Iustin Pop
    remote_node = self.op.remote_node
3101 a8083063 Iustin Pop
    cfg = self.cfg
3102 a8083063 Iustin Pop
    for dev in instance.disks:
3103 a8083063 Iustin Pop
      size = dev.size
3104 923b1523 Iustin Pop
      lv_names = [".%s_%s" % (dev.iv_name, suf) for suf in ["data", "meta"]]
3105 923b1523 Iustin Pop
      names = _GenerateUniqueNames(cfg, lv_names)
3106 923b1523 Iustin Pop
      new_drbd = _GenerateMDDRBDBranch(cfg, instance.primary_node,
3107 923b1523 Iustin Pop
                                       remote_node, size, names)
3108 a8083063 Iustin Pop
      iv_names[dev.iv_name] = (dev, dev.children[0], new_drbd)
3109 a8083063 Iustin Pop
      logger.Info("adding new mirror component on secondary for %s" %
3110 a8083063 Iustin Pop
                  dev.iv_name)
3111 a8083063 Iustin Pop
      #HARDCODE
3112 a0c3fea1 Michael Hanselmann
      if not _CreateBlockDevOnSecondary(cfg, remote_node, new_drbd, False,
3113 a0c3fea1 Michael Hanselmann
                                        _GetInstanceInfoText(instance)):
3114 3ecf6786 Iustin Pop
        raise errors.OpExecError("Failed to create new component on"
3115 3ecf6786 Iustin Pop
                                 " secondary node %s\n"
3116 3ecf6786 Iustin Pop
                                 "Full abort, cleanup manually!" %
3117 3ecf6786 Iustin Pop
                                 remote_node)
3118 a8083063 Iustin Pop
3119 a8083063 Iustin Pop
      logger.Info("adding new mirror component on primary")
3120 a8083063 Iustin Pop
      #HARDCODE
3121 a0c3fea1 Michael Hanselmann
      if not _CreateBlockDevOnPrimary(cfg, instance.primary_node, new_drbd,
3122 a0c3fea1 Michael Hanselmann
                                      _GetInstanceInfoText(instance)):
3123 a8083063 Iustin Pop
        # remove secondary dev
3124 a8083063 Iustin Pop
        cfg.SetDiskID(new_drbd, remote_node)
3125 a8083063 Iustin Pop
        rpc.call_blockdev_remove(remote_node, new_drbd)
3126 a8083063 Iustin Pop
        raise errors.OpExecError("Failed to create volume on primary!\n"
3127 a8083063 Iustin Pop
                                 "Full abort, cleanup manually!!")
3128 a8083063 Iustin Pop
3129 a8083063 Iustin Pop
      # the device exists now
3130 a8083063 Iustin Pop
      # call the primary node to add the mirror to md
3131 a8083063 Iustin Pop
      logger.Info("adding new mirror component to md")
3132 a8083063 Iustin Pop
      if not rpc.call_blockdev_addchild(instance.primary_node, dev,
3133 880478f8 Iustin Pop
                                        new_drbd):
3134 a8083063 Iustin Pop
        logger.Error("Can't add mirror compoment to md!")
3135 a8083063 Iustin Pop
        cfg.SetDiskID(new_drbd, remote_node)
3136 a8083063 Iustin Pop
        if not rpc.call_blockdev_remove(remote_node, new_drbd):
3137 a8083063 Iustin Pop
          logger.Error("Can't rollback on secondary")
3138 a8083063 Iustin Pop
        cfg.SetDiskID(new_drbd, instance.primary_node)
3139 a8083063 Iustin Pop
        if not rpc.call_blockdev_remove(instance.primary_node, new_drbd):
3140 a8083063 Iustin Pop
          logger.Error("Can't rollback on primary")
3141 3ecf6786 Iustin Pop
        raise errors.OpExecError("Full abort, cleanup manually!!")
3142 a8083063 Iustin Pop
3143 a8083063 Iustin Pop
      dev.children.append(new_drbd)
3144 a8083063 Iustin Pop
      cfg.AddInstance(instance)
3145 a8083063 Iustin Pop
3146 a8083063 Iustin Pop
    # this can fail as the old devices are degraded and _WaitForSync
3147 a8083063 Iustin Pop
    # does a combined result over all disks, so we don't check its
3148 a8083063 Iustin Pop
    # return value
3149 a8083063 Iustin Pop
    _WaitForSync(cfg, instance, unlock=True)
3150 a8083063 Iustin Pop
3151 a8083063 Iustin Pop
    # so check manually all the devices
3152 a8083063 Iustin Pop
    for name in iv_names:
3153 a8083063 Iustin Pop
      dev, child, new_drbd = iv_names[name]
3154 a8083063 Iustin Pop
      cfg.SetDiskID(dev, instance.primary_node)
3155 a8083063 Iustin Pop
      is_degr = rpc.call_blockdev_find(instance.primary_node, dev)[5]
3156 a8083063 Iustin Pop
      if is_degr:
3157 3ecf6786 Iustin Pop
        raise errors.OpExecError("MD device %s is degraded!" % name)
3158 a8083063 Iustin Pop
      cfg.SetDiskID(new_drbd, instance.primary_node)
3159 a8083063 Iustin Pop
      is_degr = rpc.call_blockdev_find(instance.primary_node, new_drbd)[5]
3160 a8083063 Iustin Pop
      if is_degr:
3161 3ecf6786 Iustin Pop
        raise errors.OpExecError("New drbd device %s is degraded!" % name)
3162 a8083063 Iustin Pop
3163 a8083063 Iustin Pop
    for name in iv_names:
3164 a8083063 Iustin Pop
      dev, child, new_drbd = iv_names[name]
3165 a8083063 Iustin Pop
      logger.Info("remove mirror %s component" % name)
3166 a8083063 Iustin Pop
      cfg.SetDiskID(dev, instance.primary_node)
3167 a8083063 Iustin Pop
      if not rpc.call_blockdev_removechild(instance.primary_node,
3168 a8083063 Iustin Pop
                                                dev, child):
3169 a8083063 Iustin Pop
        logger.Error("Can't remove child from mirror, aborting"
3170 a8083063 Iustin Pop
                     " *this device cleanup*.\nYou need to cleanup manually!!")
3171 a8083063 Iustin Pop
        continue
3172 a8083063 Iustin Pop
3173 a8083063 Iustin Pop
      for node in child.logical_id[:2]:
3174 a8083063 Iustin Pop
        logger.Info("remove child device on %s" % node)
3175 a8083063 Iustin Pop
        cfg.SetDiskID(child, node)
3176 a8083063 Iustin Pop
        if not rpc.call_blockdev_remove(node, child):
3177 a8083063 Iustin Pop
          logger.Error("Warning: failed to remove device from node %s,"
3178 a8083063 Iustin Pop
                       " continuing operation." % node)
3179 a8083063 Iustin Pop
3180 a8083063 Iustin Pop
      dev.children.remove(child)
3181 a8083063 Iustin Pop
3182 a8083063 Iustin Pop
      cfg.AddInstance(instance)
3183 a8083063 Iustin Pop
3184 a8083063 Iustin Pop
3185 a8083063 Iustin Pop
class LUQueryInstanceData(NoHooksLU):
3186 a8083063 Iustin Pop
  """Query runtime instance data.
3187 a8083063 Iustin Pop

3188 a8083063 Iustin Pop
  """
3189 a8083063 Iustin Pop
  _OP_REQP = ["instances"]
3190 a8083063 Iustin Pop
3191 a8083063 Iustin Pop
  def CheckPrereq(self):
3192 a8083063 Iustin Pop
    """Check prerequisites.
3193 a8083063 Iustin Pop

3194 a8083063 Iustin Pop
    This only checks the optional instance list against the existing names.
3195 a8083063 Iustin Pop

3196 a8083063 Iustin Pop
    """
3197 a8083063 Iustin Pop
    if not isinstance(self.op.instances, list):
3198 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Invalid argument type 'instances'")
3199 a8083063 Iustin Pop
    if self.op.instances:
3200 a8083063 Iustin Pop
      self.wanted_instances = []
3201 a8083063 Iustin Pop
      names = self.op.instances
3202 a8083063 Iustin Pop
      for name in names:
3203 a8083063 Iustin Pop
        instance = self.cfg.GetInstanceInfo(self.cfg.ExpandInstanceName(name))
3204 a8083063 Iustin Pop
        if instance is None:
3205 3ecf6786 Iustin Pop
          raise errors.OpPrereqError("No such instance name '%s'" % name)
3206 a8083063 Iustin Pop
      self.wanted_instances.append(instance)
3207 a8083063 Iustin Pop
    else:
3208 a8083063 Iustin Pop
      self.wanted_instances = [self.cfg.GetInstanceInfo(name) for name
3209 a8083063 Iustin Pop
                               in self.cfg.GetInstanceList()]
3210 a8083063 Iustin Pop
    return
3211 a8083063 Iustin Pop
3212 a8083063 Iustin Pop
3213 a8083063 Iustin Pop
  def _ComputeDiskStatus(self, instance, snode, dev):
3214 a8083063 Iustin Pop
    """Compute block device status.
3215 a8083063 Iustin Pop

3216 a8083063 Iustin Pop
    """
3217 a8083063 Iustin Pop
    self.cfg.SetDiskID(dev, instance.primary_node)
3218 a8083063 Iustin Pop
    dev_pstatus = rpc.call_blockdev_find(instance.primary_node, dev)
3219 a8083063 Iustin Pop
    if dev.dev_type == "drbd":
3220 a8083063 Iustin Pop
      # we change the snode then (otherwise we use the one passed in)
3221 a8083063 Iustin Pop
      if dev.logical_id[0] == instance.primary_node:
3222 a8083063 Iustin Pop
        snode = dev.logical_id[1]
3223 a8083063 Iustin Pop
      else:
3224 a8083063 Iustin Pop
        snode = dev.logical_id[0]
3225 a8083063 Iustin Pop
3226 a8083063 Iustin Pop
    if snode:
3227 a8083063 Iustin Pop
      self.cfg.SetDiskID(dev, snode)
3228 a8083063 Iustin Pop
      dev_sstatus = rpc.call_blockdev_find(snode, dev)
3229 a8083063 Iustin Pop
    else:
3230 a8083063 Iustin Pop
      dev_sstatus = None
3231 a8083063 Iustin Pop
3232 a8083063 Iustin Pop
    if dev.children:
3233 a8083063 Iustin Pop
      dev_children = [self._ComputeDiskStatus(instance, snode, child)
3234 a8083063 Iustin Pop
                      for child in dev.children]
3235 a8083063 Iustin Pop
    else:
3236 a8083063 Iustin Pop
      dev_children = []
3237 a8083063 Iustin Pop
3238 a8083063 Iustin Pop
    data = {
3239 a8083063 Iustin Pop
      "iv_name": dev.iv_name,
3240 a8083063 Iustin Pop
      "dev_type": dev.dev_type,
3241 a8083063 Iustin Pop
      "logical_id": dev.logical_id,
3242 a8083063 Iustin Pop
      "physical_id": dev.physical_id,
3243 a8083063 Iustin Pop
      "pstatus": dev_pstatus,
3244 a8083063 Iustin Pop
      "sstatus": dev_sstatus,
3245 a8083063 Iustin Pop
      "children": dev_children,
3246 a8083063 Iustin Pop
      }
3247 a8083063 Iustin Pop
3248 a8083063 Iustin Pop
    return data
3249 a8083063 Iustin Pop
3250 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
3251 a8083063 Iustin Pop
    """Gather and return data"""
3252 a8083063 Iustin Pop
    result = {}
3253 a8083063 Iustin Pop
    for instance in self.wanted_instances:
3254 a8083063 Iustin Pop
      remote_info = rpc.call_instance_info(instance.primary_node,
3255 a8083063 Iustin Pop
                                                instance.name)
3256 a8083063 Iustin Pop
      if remote_info and "state" in remote_info:
3257 a8083063 Iustin Pop
        remote_state = "up"
3258 a8083063 Iustin Pop
      else:
3259 a8083063 Iustin Pop
        remote_state = "down"
3260 a8083063 Iustin Pop
      if instance.status == "down":
3261 a8083063 Iustin Pop
        config_state = "down"
3262 a8083063 Iustin Pop
      else:
3263 a8083063 Iustin Pop
        config_state = "up"
3264 a8083063 Iustin Pop
3265 a8083063 Iustin Pop
      disks = [self._ComputeDiskStatus(instance, None, device)
3266 a8083063 Iustin Pop
               for device in instance.disks]
3267 a8083063 Iustin Pop
3268 a8083063 Iustin Pop
      idict = {
3269 a8083063 Iustin Pop
        "name": instance.name,
3270 a8083063 Iustin Pop
        "config_state": config_state,
3271 a8083063 Iustin Pop
        "run_state": remote_state,
3272 a8083063 Iustin Pop
        "pnode": instance.primary_node,
3273 a8083063 Iustin Pop
        "snodes": instance.secondary_nodes,
3274 a8083063 Iustin Pop
        "os": instance.os,
3275 a8083063 Iustin Pop
        "memory": instance.memory,
3276 a8083063 Iustin Pop
        "nics": [(nic.mac, nic.ip, nic.bridge) for nic in instance.nics],
3277 a8083063 Iustin Pop
        "disks": disks,
3278 a8083063 Iustin Pop
        }
3279 a8083063 Iustin Pop
3280 a8083063 Iustin Pop
      result[instance.name] = idict
3281 a8083063 Iustin Pop
3282 a8083063 Iustin Pop
    return result
3283 a8083063 Iustin Pop
3284 a8083063 Iustin Pop
3285 a8083063 Iustin Pop
class LUQueryNodeData(NoHooksLU):
3286 a8083063 Iustin Pop
  """Logical unit for querying node data.
3287 a8083063 Iustin Pop

3288 a8083063 Iustin Pop
  """
3289 a8083063 Iustin Pop
  _OP_REQP = ["nodes"]
3290 a8083063 Iustin Pop
3291 a8083063 Iustin Pop
  def CheckPrereq(self):
3292 a8083063 Iustin Pop
    """Check prerequisites.
3293 a8083063 Iustin Pop

3294 a8083063 Iustin Pop
    This only checks the optional node list against the existing names.
3295 a8083063 Iustin Pop

3296 a8083063 Iustin Pop
    """
3297 dcb93971 Michael Hanselmann
    self.wanted_nodes = _GetWantedNodes(self, self.op.nodes)
3298 a8083063 Iustin Pop
3299 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
3300 a8083063 Iustin Pop
    """Compute and return the list of nodes.
3301 a8083063 Iustin Pop

3302 a8083063 Iustin Pop
    """
3303 a8083063 Iustin Pop
    ilist = [self.cfg.GetInstanceInfo(iname) for iname
3304 a8083063 Iustin Pop
             in self.cfg.GetInstanceList()]
3305 a8083063 Iustin Pop
    result = []
3306 a8083063 Iustin Pop
    for node in self.wanted_nodes:
3307 a8083063 Iustin Pop
      result.append((node.name, node.primary_ip, node.secondary_ip,
3308 a8083063 Iustin Pop
                     [inst.name for inst in ilist
3309 a8083063 Iustin Pop
                      if inst.primary_node == node.name],
3310 a8083063 Iustin Pop
                     [inst.name for inst in ilist
3311 a8083063 Iustin Pop
                      if node.name in inst.secondary_nodes],
3312 a8083063 Iustin Pop
                     ))
3313 a8083063 Iustin Pop
    return result
3314 a8083063 Iustin Pop
3315 a8083063 Iustin Pop
3316 a8083063 Iustin Pop
class LUSetInstanceParms(LogicalUnit):
3317 a8083063 Iustin Pop
  """Modifies an instances's parameters.
3318 a8083063 Iustin Pop

3319 a8083063 Iustin Pop
  """
3320 a8083063 Iustin Pop
  HPATH = "instance-modify"
3321 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
3322 a8083063 Iustin Pop
  _OP_REQP = ["instance_name"]
3323 a8083063 Iustin Pop
3324 a8083063 Iustin Pop
  def BuildHooksEnv(self):
3325 a8083063 Iustin Pop
    """Build hooks env.
3326 a8083063 Iustin Pop

3327 a8083063 Iustin Pop
    This runs on the master, primary and secondaries.
3328 a8083063 Iustin Pop

3329 a8083063 Iustin Pop
    """
3330 396e1b78 Michael Hanselmann
    args = dict()
3331 a8083063 Iustin Pop
    if self.mem:
3332 396e1b78 Michael Hanselmann
      args['memory'] = self.mem
3333 a8083063 Iustin Pop
    if self.vcpus:
3334 396e1b78 Michael Hanselmann
      args['vcpus'] = self.vcpus
3335 396e1b78 Michael Hanselmann
    if self.do_ip or self.do_bridge:
3336 396e1b78 Michael Hanselmann
      if self.do_ip:
3337 396e1b78 Michael Hanselmann
        ip = self.ip
3338 396e1b78 Michael Hanselmann
      else:
3339 396e1b78 Michael Hanselmann
        ip = self.instance.nics[0].ip
3340 396e1b78 Michael Hanselmann
      if self.bridge:
3341 396e1b78 Michael Hanselmann
        bridge = self.bridge
3342 396e1b78 Michael Hanselmann
      else:
3343 396e1b78 Michael Hanselmann
        bridge = self.instance.nics[0].bridge
3344 396e1b78 Michael Hanselmann
      args['nics'] = [(ip, bridge)]
3345 396e1b78 Michael Hanselmann
    env = _BuildInstanceHookEnvByObject(self.instance, override=args)
3346 880478f8 Iustin Pop
    nl = [self.sstore.GetMasterNode(),
3347 a8083063 Iustin Pop
          self.instance.primary_node] + list(self.instance.secondary_nodes)
3348 a8083063 Iustin Pop
    return env, nl, nl
3349 a8083063 Iustin Pop
3350 a8083063 Iustin Pop
  def CheckPrereq(self):
3351 a8083063 Iustin Pop
    """Check prerequisites.
3352 a8083063 Iustin Pop

3353 a8083063 Iustin Pop
    This only checks the instance list against the existing names.
3354 a8083063 Iustin Pop

3355 a8083063 Iustin Pop
    """
3356 a8083063 Iustin Pop
    self.mem = getattr(self.op, "mem", None)
3357 a8083063 Iustin Pop
    self.vcpus = getattr(self.op, "vcpus", None)
3358 a8083063 Iustin Pop
    self.ip = getattr(self.op, "ip", None)
3359 a8083063 Iustin Pop
    self.bridge = getattr(self.op, "bridge", None)
3360 a8083063 Iustin Pop
    if [self.mem, self.vcpus, self.ip, self.bridge].count(None) == 4:
3361 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("No changes submitted")
3362 a8083063 Iustin Pop
    if self.mem is not None:
3363 a8083063 Iustin Pop
      try:
3364 a8083063 Iustin Pop
        self.mem = int(self.mem)
3365 a8083063 Iustin Pop
      except ValueError, err:
3366 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Invalid memory size: %s" % str(err))
3367 a8083063 Iustin Pop
    if self.vcpus is not None:
3368 a8083063 Iustin Pop
      try:
3369 a8083063 Iustin Pop
        self.vcpus = int(self.vcpus)
3370 a8083063 Iustin Pop
      except ValueError, err:
3371 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Invalid vcpus number: %s" % str(err))
3372 a8083063 Iustin Pop
    if self.ip is not None:
3373 a8083063 Iustin Pop
      self.do_ip = True
3374 a8083063 Iustin Pop
      if self.ip.lower() == "none":
3375 a8083063 Iustin Pop
        self.ip = None
3376 a8083063 Iustin Pop
      else:
3377 a8083063 Iustin Pop
        if not utils.IsValidIP(self.ip):
3378 3ecf6786 Iustin Pop
          raise errors.OpPrereqError("Invalid IP address '%s'." % self.ip)
3379 a8083063 Iustin Pop
    else:
3380 a8083063 Iustin Pop
      self.do_ip = False
3381 ecb215b5 Michael Hanselmann
    self.do_bridge = (self.bridge is not None)
3382 a8083063 Iustin Pop
3383 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
3384 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
3385 a8083063 Iustin Pop
    if instance is None:
3386 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("No such instance name '%s'" %
3387 3ecf6786 Iustin Pop
                                 self.op.instance_name)
3388 a8083063 Iustin Pop
    self.op.instance_name = instance.name
3389 a8083063 Iustin Pop
    self.instance = instance
3390 a8083063 Iustin Pop
    return
3391 a8083063 Iustin Pop
3392 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
3393 a8083063 Iustin Pop
    """Modifies an instance.
3394 a8083063 Iustin Pop

3395 a8083063 Iustin Pop
    All parameters take effect only at the next restart of the instance.
3396 a8083063 Iustin Pop
    """
3397 a8083063 Iustin Pop
    result = []
3398 a8083063 Iustin Pop
    instance = self.instance
3399 a8083063 Iustin Pop
    if self.mem:
3400 a8083063 Iustin Pop
      instance.memory = self.mem
3401 a8083063 Iustin Pop
      result.append(("mem", self.mem))
3402 a8083063 Iustin Pop
    if self.vcpus:
3403 a8083063 Iustin Pop
      instance.vcpus = self.vcpus
3404 a8083063 Iustin Pop
      result.append(("vcpus",  self.vcpus))
3405 a8083063 Iustin Pop
    if self.do_ip:
3406 a8083063 Iustin Pop
      instance.nics[0].ip = self.ip
3407 a8083063 Iustin Pop
      result.append(("ip", self.ip))
3408 a8083063 Iustin Pop
    if self.bridge:
3409 a8083063 Iustin Pop
      instance.nics[0].bridge = self.bridge
3410 a8083063 Iustin Pop
      result.append(("bridge", self.bridge))
3411 a8083063 Iustin Pop
3412 a8083063 Iustin Pop
    self.cfg.AddInstance(instance)
3413 a8083063 Iustin Pop
3414 a8083063 Iustin Pop
    return result
3415 a8083063 Iustin Pop
3416 a8083063 Iustin Pop
3417 a8083063 Iustin Pop
class LUQueryExports(NoHooksLU):
3418 a8083063 Iustin Pop
  """Query the exports list
3419 a8083063 Iustin Pop

3420 a8083063 Iustin Pop
  """
3421 a8083063 Iustin Pop
  _OP_REQP = []
3422 a8083063 Iustin Pop
3423 a8083063 Iustin Pop
  def CheckPrereq(self):
3424 a8083063 Iustin Pop
    """Check that the nodelist contains only existing nodes.
3425 a8083063 Iustin Pop

3426 a8083063 Iustin Pop
    """
3427 dcb93971 Michael Hanselmann
    self.nodes = _GetWantedNodes(self, getattr(self.op, "nodes", None))
3428 a8083063 Iustin Pop
3429 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
3430 a8083063 Iustin Pop
    """Compute the list of all the exported system images.
3431 a8083063 Iustin Pop

3432 a8083063 Iustin Pop
    Returns:
3433 a8083063 Iustin Pop
      a dictionary with the structure node->(export-list)
3434 a8083063 Iustin Pop
      where export-list is a list of the instances exported on
3435 a8083063 Iustin Pop
      that node.
3436 a8083063 Iustin Pop

3437 a8083063 Iustin Pop
    """
3438 dcb93971 Michael Hanselmann
    return rpc.call_export_list([node.name for node in self.nodes])
3439 a8083063 Iustin Pop
3440 a8083063 Iustin Pop
3441 a8083063 Iustin Pop
class LUExportInstance(LogicalUnit):
3442 a8083063 Iustin Pop
  """Export an instance to an image in the cluster.
3443 a8083063 Iustin Pop

3444 a8083063 Iustin Pop
  """
3445 a8083063 Iustin Pop
  HPATH = "instance-export"
3446 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
3447 a8083063 Iustin Pop
  _OP_REQP = ["instance_name", "target_node", "shutdown"]
3448 a8083063 Iustin Pop
3449 a8083063 Iustin Pop
  def BuildHooksEnv(self):
3450 a8083063 Iustin Pop
    """Build hooks env.
3451 a8083063 Iustin Pop

3452 a8083063 Iustin Pop
    This will run on the master, primary node and target node.
3453 a8083063 Iustin Pop

3454 a8083063 Iustin Pop
    """
3455 a8083063 Iustin Pop
    env = {
3456 a8083063 Iustin Pop
      "EXPORT_NODE": self.op.target_node,
3457 a8083063 Iustin Pop
      "EXPORT_DO_SHUTDOWN": self.op.shutdown,
3458 a8083063 Iustin Pop
      }
3459 396e1b78 Michael Hanselmann
    env.update(_BuildInstanceHookEnvByObject(self.instance))
3460 880478f8 Iustin Pop
    nl = [self.sstore.GetMasterNode(), self.instance.primary_node,
3461 a8083063 Iustin Pop
          self.op.target_node]
3462 a8083063 Iustin Pop
    return env, nl, nl
3463 a8083063 Iustin Pop
3464 a8083063 Iustin Pop
  def CheckPrereq(self):
3465 a8083063 Iustin Pop
    """Check prerequisites.
3466 a8083063 Iustin Pop

3467 a8083063 Iustin Pop
    This checks that the instance name is a valid one.
3468 a8083063 Iustin Pop

3469 a8083063 Iustin Pop
    """
3470 a8083063 Iustin Pop
    instance_name = self.cfg.ExpandInstanceName(self.op.instance_name)
3471 a8083063 Iustin Pop
    self.instance = self.cfg.GetInstanceInfo(instance_name)
3472 a8083063 Iustin Pop
    if self.instance is None:
3473 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not found" %
3474 3ecf6786 Iustin Pop
                                 self.op.instance_name)
3475 a8083063 Iustin Pop
3476 a8083063 Iustin Pop
    # node verification
3477 a8083063 Iustin Pop
    dst_node_short = self.cfg.ExpandNodeName(self.op.target_node)
3478 a8083063 Iustin Pop
    self.dst_node = self.cfg.GetNodeInfo(dst_node_short)
3479 a8083063 Iustin Pop
3480 a8083063 Iustin Pop
    if self.dst_node is None:
3481 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Destination node '%s' is unknown." %
3482 3ecf6786 Iustin Pop
                                 self.op.target_node)
3483 a8083063 Iustin Pop
    self.op.target_node = self.dst_node.name
3484 a8083063 Iustin Pop
3485 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
3486 a8083063 Iustin Pop
    """Export an instance to an image in the cluster.
3487 a8083063 Iustin Pop

3488 a8083063 Iustin Pop
    """
3489 a8083063 Iustin Pop
    instance = self.instance
3490 a8083063 Iustin Pop
    dst_node = self.dst_node
3491 a8083063 Iustin Pop
    src_node = instance.primary_node
3492 a8083063 Iustin Pop
    # shutdown the instance, unless requested not to do so
3493 a8083063 Iustin Pop
    if self.op.shutdown:
3494 a8083063 Iustin Pop
      op = opcodes.OpShutdownInstance(instance_name=instance.name)
3495 a8083063 Iustin Pop
      self.processor.ChainOpCode(op, feedback_fn)
3496 a8083063 Iustin Pop
3497 a8083063 Iustin Pop
    vgname = self.cfg.GetVGName()
3498 a8083063 Iustin Pop
3499 a8083063 Iustin Pop
    snap_disks = []
3500 a8083063 Iustin Pop
3501 a8083063 Iustin Pop
    try:
3502 a8083063 Iustin Pop
      for disk in instance.disks:
3503 a8083063 Iustin Pop
        if disk.iv_name == "sda":
3504 a8083063 Iustin Pop
          # new_dev_name will be a snapshot of an lvm leaf of the one we passed
3505 a8083063 Iustin Pop
          new_dev_name = rpc.call_blockdev_snapshot(src_node, disk)
3506 a8083063 Iustin Pop
3507 a8083063 Iustin Pop
          if not new_dev_name:
3508 a8083063 Iustin Pop
            logger.Error("could not snapshot block device %s on node %s" %
3509 a8083063 Iustin Pop
                         (disk.logical_id[1], src_node))
3510 a8083063 Iustin Pop
          else:
3511 a8083063 Iustin Pop
            new_dev = objects.Disk(dev_type="lvm", size=disk.size,
3512 a8083063 Iustin Pop
                                      logical_id=(vgname, new_dev_name),
3513 a8083063 Iustin Pop
                                      physical_id=(vgname, new_dev_name),
3514 a8083063 Iustin Pop
                                      iv_name=disk.iv_name)
3515 a8083063 Iustin Pop
            snap_disks.append(new_dev)
3516 a8083063 Iustin Pop
3517 a8083063 Iustin Pop
    finally:
3518 a8083063 Iustin Pop
      if self.op.shutdown:
3519 a8083063 Iustin Pop
        op = opcodes.OpStartupInstance(instance_name=instance.name,
3520 a8083063 Iustin Pop
                                       force=False)
3521 a8083063 Iustin Pop
        self.processor.ChainOpCode(op, feedback_fn)
3522 a8083063 Iustin Pop
3523 a8083063 Iustin Pop
    # TODO: check for size
3524 a8083063 Iustin Pop
3525 a8083063 Iustin Pop
    for dev in snap_disks:
3526 a8083063 Iustin Pop
      if not rpc.call_snapshot_export(src_node, dev, dst_node.name,
3527 a8083063 Iustin Pop
                                           instance):
3528 a8083063 Iustin Pop
        logger.Error("could not export block device %s from node"
3529 a8083063 Iustin Pop
                     " %s to node %s" %
3530 a8083063 Iustin Pop
                     (dev.logical_id[1], src_node, dst_node.name))
3531 a8083063 Iustin Pop
      if not rpc.call_blockdev_remove(src_node, dev):
3532 a8083063 Iustin Pop
        logger.Error("could not remove snapshot block device %s from"
3533 a8083063 Iustin Pop
                     " node %s" % (dev.logical_id[1], src_node))
3534 a8083063 Iustin Pop
3535 a8083063 Iustin Pop
    if not rpc.call_finalize_export(dst_node.name, instance, snap_disks):
3536 a8083063 Iustin Pop
      logger.Error("could not finalize export for instance %s on node %s" %
3537 a8083063 Iustin Pop
                   (instance.name, dst_node.name))
3538 a8083063 Iustin Pop
3539 a8083063 Iustin Pop
    nodelist = self.cfg.GetNodeList()
3540 a8083063 Iustin Pop
    nodelist.remove(dst_node.name)
3541 a8083063 Iustin Pop
3542 a8083063 Iustin Pop
    # on one-node clusters nodelist will be empty after the removal
3543 a8083063 Iustin Pop
    # if we proceed the backup would be removed because OpQueryExports
3544 a8083063 Iustin Pop
    # substitutes an empty list with the full cluster node list.
3545 a8083063 Iustin Pop
    if nodelist:
3546 a8083063 Iustin Pop
      op = opcodes.OpQueryExports(nodes=nodelist)
3547 a8083063 Iustin Pop
      exportlist = self.processor.ChainOpCode(op, feedback_fn)
3548 a8083063 Iustin Pop
      for node in exportlist:
3549 a8083063 Iustin Pop
        if instance.name in exportlist[node]:
3550 a8083063 Iustin Pop
          if not rpc.call_export_remove(node, instance.name):
3551 a8083063 Iustin Pop
            logger.Error("could not remove older export for instance %s"
3552 a8083063 Iustin Pop
                         " on node %s" % (instance.name, node))
3553 5c947f38 Iustin Pop
3554 5c947f38 Iustin Pop
3555 5c947f38 Iustin Pop
class TagsLU(NoHooksLU):
3556 5c947f38 Iustin Pop
  """Generic tags LU.
3557 5c947f38 Iustin Pop

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

3560 5c947f38 Iustin Pop
  """
3561 5c947f38 Iustin Pop
  def CheckPrereq(self):
3562 5c947f38 Iustin Pop
    """Check prerequisites.
3563 5c947f38 Iustin Pop

3564 5c947f38 Iustin Pop
    """
3565 5c947f38 Iustin Pop
    if self.op.kind == constants.TAG_CLUSTER:
3566 5c947f38 Iustin Pop
      self.target = self.cfg.GetClusterInfo()
3567 5c947f38 Iustin Pop
    elif self.op.kind == constants.TAG_NODE:
3568 5c947f38 Iustin Pop
      name = self.cfg.ExpandNodeName(self.op.name)
3569 5c947f38 Iustin Pop
      if name is None:
3570 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Invalid node name (%s)" %
3571 3ecf6786 Iustin Pop
                                   (self.op.name,))
3572 5c947f38 Iustin Pop
      self.op.name = name
3573 5c947f38 Iustin Pop
      self.target = self.cfg.GetNodeInfo(name)
3574 5c947f38 Iustin Pop
    elif self.op.kind == constants.TAG_INSTANCE:
3575 5c947f38 Iustin Pop
      name = self.cfg.ExpandInstanceName(name)
3576 5c947f38 Iustin Pop
      if name is None:
3577 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Invalid instance name (%s)" %
3578 3ecf6786 Iustin Pop
                                   (self.op.name,))
3579 5c947f38 Iustin Pop
      self.op.name = name
3580 5c947f38 Iustin Pop
      self.target = self.cfg.GetInstanceInfo(name)
3581 5c947f38 Iustin Pop
    else:
3582 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Wrong tag type requested (%s)" %
3583 3ecf6786 Iustin Pop
                                 str(self.op.kind))
3584 5c947f38 Iustin Pop
3585 5c947f38 Iustin Pop
3586 5c947f38 Iustin Pop
class LUGetTags(TagsLU):
3587 5c947f38 Iustin Pop
  """Returns the tags of a given object.
3588 5c947f38 Iustin Pop

3589 5c947f38 Iustin Pop
  """
3590 5c947f38 Iustin Pop
  _OP_REQP = ["kind", "name"]
3591 5c947f38 Iustin Pop
3592 5c947f38 Iustin Pop
  def Exec(self, feedback_fn):
3593 5c947f38 Iustin Pop
    """Returns the tag list.
3594 5c947f38 Iustin Pop

3595 5c947f38 Iustin Pop
    """
3596 5c947f38 Iustin Pop
    return self.target.GetTags()
3597 5c947f38 Iustin Pop
3598 5c947f38 Iustin Pop
3599 5c947f38 Iustin Pop
class LUAddTag(TagsLU):
3600 5c947f38 Iustin Pop
  """Sets a tag on a given object.
3601 5c947f38 Iustin Pop

3602 5c947f38 Iustin Pop
  """
3603 5c947f38 Iustin Pop
  _OP_REQP = ["kind", "name", "tag"]
3604 5c947f38 Iustin Pop
3605 5c947f38 Iustin Pop
  def CheckPrereq(self):
3606 5c947f38 Iustin Pop
    """Check prerequisites.
3607 5c947f38 Iustin Pop

3608 5c947f38 Iustin Pop
    This checks the type and length of the tag name and value.
3609 5c947f38 Iustin Pop

3610 5c947f38 Iustin Pop
    """
3611 5c947f38 Iustin Pop
    TagsLU.CheckPrereq(self)
3612 5c947f38 Iustin Pop
    objects.TaggableObject.ValidateTag(self.op.tag)
3613 5c947f38 Iustin Pop
3614 5c947f38 Iustin Pop
  def Exec(self, feedback_fn):
3615 5c947f38 Iustin Pop
    """Sets the tag.
3616 5c947f38 Iustin Pop

3617 5c947f38 Iustin Pop
    """
3618 5c947f38 Iustin Pop
    try:
3619 5c947f38 Iustin Pop
      self.target.AddTag(self.op.tag)
3620 5c947f38 Iustin Pop
    except errors.TagError, err:
3621 3ecf6786 Iustin Pop
      raise errors.OpExecError("Error while setting tag: %s" % str(err))
3622 5c947f38 Iustin Pop
    try:
3623 5c947f38 Iustin Pop
      self.cfg.Update(self.target)
3624 5c947f38 Iustin Pop
    except errors.ConfigurationError:
3625 3ecf6786 Iustin Pop
      raise errors.OpRetryError("There has been a modification to the"
3626 3ecf6786 Iustin Pop
                                " config file and the operation has been"
3627 3ecf6786 Iustin Pop
                                " aborted. Please retry.")
3628 5c947f38 Iustin Pop
3629 5c947f38 Iustin Pop
3630 5c947f38 Iustin Pop
class LUDelTag(TagsLU):
3631 5c947f38 Iustin Pop
  """Delete a tag from a given object.
3632 5c947f38 Iustin Pop

3633 5c947f38 Iustin Pop
  """
3634 5c947f38 Iustin Pop
  _OP_REQP = ["kind", "name", "tag"]
3635 5c947f38 Iustin Pop
3636 5c947f38 Iustin Pop
  def CheckPrereq(self):
3637 5c947f38 Iustin Pop
    """Check prerequisites.
3638 5c947f38 Iustin Pop

3639 5c947f38 Iustin Pop
    This checks that we have the given tag.
3640 5c947f38 Iustin Pop

3641 5c947f38 Iustin Pop
    """
3642 5c947f38 Iustin Pop
    TagsLU.CheckPrereq(self)
3643 5c947f38 Iustin Pop
    objects.TaggableObject.ValidateTag(self.op.tag)
3644 5c947f38 Iustin Pop
    if self.op.tag not in self.target.GetTags():
3645 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Tag not found")
3646 5c947f38 Iustin Pop
3647 5c947f38 Iustin Pop
  def Exec(self, feedback_fn):
3648 5c947f38 Iustin Pop
    """Remove the tag from the object.
3649 5c947f38 Iustin Pop

3650 5c947f38 Iustin Pop
    """
3651 5c947f38 Iustin Pop
    self.target.RemoveTag(self.op.tag)
3652 5c947f38 Iustin Pop
    try:
3653 5c947f38 Iustin Pop
      self.cfg.Update(self.target)
3654 5c947f38 Iustin Pop
    except errors.ConfigurationError:
3655 3ecf6786 Iustin Pop
      raise errors.OpRetryError("There has been a modification to the"
3656 3ecf6786 Iustin Pop
                                " config file and the operation has been"
3657 3ecf6786 Iustin Pop
                                " aborted. Please retry.")