Statistics
| Branch: | Tag: | Revision:

root / lib / cmdlib.py @ 9ff7e35c

History | View | Annotate | Download (120.1 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 89e1fc26 Iustin Pop
        if master != utils.HostInfo().name:
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 a7ba5e53 Iustin Pop
  """Returns list of checked and expanded node names.
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 3312b702 Iustin Pop
  if 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 3312b702 Iustin Pop
    wanted = []
179 dcb93971 Michael Hanselmann
180 dcb93971 Michael Hanselmann
    for name in nodes:
181 a7ba5e53 Iustin Pop
      node = 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 3312b702 Iustin Pop
      wanted.append(node)
185 dcb93971 Michael Hanselmann
186 dcb93971 Michael Hanselmann
  else:
187 a7ba5e53 Iustin Pop
    wanted = lu.cfg.GetNodeList()
188 a7ba5e53 Iustin Pop
  return utils.NiceSort(wanted)
189 3312b702 Iustin Pop
190 3312b702 Iustin Pop
191 3312b702 Iustin Pop
def _GetWantedInstances(lu, instances):
192 a7ba5e53 Iustin Pop
  """Returns list of checked and expanded instance names.
193 3312b702 Iustin Pop

194 3312b702 Iustin Pop
  Args:
195 3312b702 Iustin Pop
    instances: List of instances (strings) or None for all
196 3312b702 Iustin Pop

197 3312b702 Iustin Pop
  """
198 3312b702 Iustin Pop
  if not isinstance(instances, list):
199 3312b702 Iustin Pop
    raise errors.OpPrereqError("Invalid argument type 'instances'")
200 3312b702 Iustin Pop
201 3312b702 Iustin Pop
  if instances:
202 3312b702 Iustin Pop
    wanted = []
203 3312b702 Iustin Pop
204 3312b702 Iustin Pop
    for name in instances:
205 a7ba5e53 Iustin Pop
      instance = lu.cfg.ExpandInstanceName(name)
206 3312b702 Iustin Pop
      if instance is None:
207 3312b702 Iustin Pop
        raise errors.OpPrereqError("No such instance name '%s'" % name)
208 3312b702 Iustin Pop
      wanted.append(instance)
209 3312b702 Iustin Pop
210 3312b702 Iustin Pop
  else:
211 a7ba5e53 Iustin Pop
    wanted = lu.cfg.GetInstanceList()
212 a7ba5e53 Iustin Pop
  return utils.NiceSort(wanted)
213 dcb93971 Michael Hanselmann
214 dcb93971 Michael Hanselmann
215 dcb93971 Michael Hanselmann
def _CheckOutputFields(static, dynamic, selected):
216 83120a01 Michael Hanselmann
  """Checks whether all selected fields are valid.
217 83120a01 Michael Hanselmann

218 83120a01 Michael Hanselmann
  Args:
219 83120a01 Michael Hanselmann
    static: Static fields
220 83120a01 Michael Hanselmann
    dynamic: Dynamic fields
221 83120a01 Michael Hanselmann

222 83120a01 Michael Hanselmann
  """
223 83120a01 Michael Hanselmann
  static_fields = frozenset(static)
224 83120a01 Michael Hanselmann
  dynamic_fields = frozenset(dynamic)
225 dcb93971 Michael Hanselmann
226 83120a01 Michael Hanselmann
  all_fields = static_fields | dynamic_fields
227 dcb93971 Michael Hanselmann
228 83120a01 Michael Hanselmann
  if not all_fields.issuperset(selected):
229 3ecf6786 Iustin Pop
    raise errors.OpPrereqError("Unknown output fields selected: %s"
230 3ecf6786 Iustin Pop
                               % ",".join(frozenset(selected).
231 3ecf6786 Iustin Pop
                                          difference(all_fields)))
232 dcb93971 Michael Hanselmann
233 dcb93971 Michael Hanselmann
234 ecb215b5 Michael Hanselmann
def _BuildInstanceHookEnv(name, primary_node, secondary_nodes, os_type, status,
235 396e1b78 Michael Hanselmann
                          memory, vcpus, nics):
236 ecb215b5 Michael Hanselmann
  """Builds instance related env variables for hooks from single variables.
237 ecb215b5 Michael Hanselmann

238 ecb215b5 Michael Hanselmann
  Args:
239 ecb215b5 Michael Hanselmann
    secondary_nodes: List of secondary nodes as strings
240 396e1b78 Michael Hanselmann
  """
241 396e1b78 Michael Hanselmann
  env = {
242 396e1b78 Michael Hanselmann
    "INSTANCE_NAME": name,
243 396e1b78 Michael Hanselmann
    "INSTANCE_PRIMARY": primary_node,
244 396e1b78 Michael Hanselmann
    "INSTANCE_SECONDARIES": " ".join(secondary_nodes),
245 ecb215b5 Michael Hanselmann
    "INSTANCE_OS_TYPE": os_type,
246 396e1b78 Michael Hanselmann
    "INSTANCE_STATUS": status,
247 396e1b78 Michael Hanselmann
    "INSTANCE_MEMORY": memory,
248 396e1b78 Michael Hanselmann
    "INSTANCE_VCPUS": vcpus,
249 396e1b78 Michael Hanselmann
  }
250 396e1b78 Michael Hanselmann
251 396e1b78 Michael Hanselmann
  if nics:
252 396e1b78 Michael Hanselmann
    nic_count = len(nics)
253 396e1b78 Michael Hanselmann
    for idx, (ip, bridge) in enumerate(nics):
254 396e1b78 Michael Hanselmann
      if ip is None:
255 396e1b78 Michael Hanselmann
        ip = ""
256 396e1b78 Michael Hanselmann
      env["INSTANCE_NIC%d_IP" % idx] = ip
257 396e1b78 Michael Hanselmann
      env["INSTANCE_NIC%d_BRIDGE" % idx] = bridge
258 396e1b78 Michael Hanselmann
  else:
259 396e1b78 Michael Hanselmann
    nic_count = 0
260 396e1b78 Michael Hanselmann
261 396e1b78 Michael Hanselmann
  env["INSTANCE_NIC_COUNT"] = nic_count
262 396e1b78 Michael Hanselmann
263 396e1b78 Michael Hanselmann
  return env
264 396e1b78 Michael Hanselmann
265 396e1b78 Michael Hanselmann
266 396e1b78 Michael Hanselmann
def _BuildInstanceHookEnvByObject(instance, override=None):
267 ecb215b5 Michael Hanselmann
  """Builds instance related env variables for hooks from an object.
268 ecb215b5 Michael Hanselmann

269 ecb215b5 Michael Hanselmann
  Args:
270 ecb215b5 Michael Hanselmann
    instance: objects.Instance object of instance
271 ecb215b5 Michael Hanselmann
    override: dict of values to override
272 ecb215b5 Michael Hanselmann
  """
273 396e1b78 Michael Hanselmann
  args = {
274 396e1b78 Michael Hanselmann
    'name': instance.name,
275 396e1b78 Michael Hanselmann
    'primary_node': instance.primary_node,
276 396e1b78 Michael Hanselmann
    'secondary_nodes': instance.secondary_nodes,
277 ecb215b5 Michael Hanselmann
    'os_type': instance.os,
278 396e1b78 Michael Hanselmann
    'status': instance.os,
279 396e1b78 Michael Hanselmann
    'memory': instance.memory,
280 396e1b78 Michael Hanselmann
    'vcpus': instance.vcpus,
281 396e1b78 Michael Hanselmann
    'nics': [(nic.ip, nic.bridge) for nic in instance.nics],
282 396e1b78 Michael Hanselmann
  }
283 396e1b78 Michael Hanselmann
  if override:
284 396e1b78 Michael Hanselmann
    args.update(override)
285 396e1b78 Michael Hanselmann
  return _BuildInstanceHookEnv(**args)
286 396e1b78 Michael Hanselmann
287 396e1b78 Michael Hanselmann
288 a8083063 Iustin Pop
def _UpdateEtcHosts(fullnode, ip):
289 a8083063 Iustin Pop
  """Ensure a node has a correct entry in /etc/hosts.
290 a8083063 Iustin Pop

291 a8083063 Iustin Pop
  Args:
292 a8083063 Iustin Pop
    fullnode - Fully qualified domain name of host. (str)
293 a8083063 Iustin Pop
    ip       - IPv4 address of host (str)
294 a8083063 Iustin Pop

295 a8083063 Iustin Pop
  """
296 a8083063 Iustin Pop
  node = fullnode.split(".", 1)[0]
297 a8083063 Iustin Pop
298 a8083063 Iustin Pop
  f = open('/etc/hosts', 'r+')
299 a8083063 Iustin Pop
300 a8083063 Iustin Pop
  inthere = False
301 a8083063 Iustin Pop
302 a8083063 Iustin Pop
  save_lines = []
303 a8083063 Iustin Pop
  add_lines = []
304 a8083063 Iustin Pop
  removed = False
305 a8083063 Iustin Pop
306 a8083063 Iustin Pop
  while True:
307 a8083063 Iustin Pop
    rawline = f.readline()
308 a8083063 Iustin Pop
309 a8083063 Iustin Pop
    if not rawline:
310 a8083063 Iustin Pop
      # End of file
311 a8083063 Iustin Pop
      break
312 a8083063 Iustin Pop
313 a8083063 Iustin Pop
    line = rawline.split('\n')[0]
314 a8083063 Iustin Pop
315 a8083063 Iustin Pop
    # Strip off comments
316 a8083063 Iustin Pop
    line = line.split('#')[0]
317 a8083063 Iustin Pop
318 a8083063 Iustin Pop
    if not line:
319 a8083063 Iustin Pop
      # Entire line was comment, skip
320 a8083063 Iustin Pop
      save_lines.append(rawline)
321 a8083063 Iustin Pop
      continue
322 a8083063 Iustin Pop
323 a8083063 Iustin Pop
    fields = line.split()
324 a8083063 Iustin Pop
325 a8083063 Iustin Pop
    haveall = True
326 a8083063 Iustin Pop
    havesome = False
327 a8083063 Iustin Pop
    for spec in [ ip, fullnode, node ]:
328 a8083063 Iustin Pop
      if spec not in fields:
329 a8083063 Iustin Pop
        haveall = False
330 a8083063 Iustin Pop
      if spec in fields:
331 a8083063 Iustin Pop
        havesome = True
332 a8083063 Iustin Pop
333 a8083063 Iustin Pop
    if haveall:
334 a8083063 Iustin Pop
      inthere = True
335 a8083063 Iustin Pop
      save_lines.append(rawline)
336 a8083063 Iustin Pop
      continue
337 a8083063 Iustin Pop
338 a8083063 Iustin Pop
    if havesome and not haveall:
339 a8083063 Iustin Pop
      # Line (old, or manual?) which is missing some.  Remove.
340 a8083063 Iustin Pop
      removed = True
341 a8083063 Iustin Pop
      continue
342 a8083063 Iustin Pop
343 a8083063 Iustin Pop
    save_lines.append(rawline)
344 a8083063 Iustin Pop
345 a8083063 Iustin Pop
  if not inthere:
346 a8083063 Iustin Pop
    add_lines.append('%s\t%s %s\n' % (ip, fullnode, node))
347 a8083063 Iustin Pop
348 a8083063 Iustin Pop
  if removed:
349 a8083063 Iustin Pop
    if add_lines:
350 a8083063 Iustin Pop
      save_lines = save_lines + add_lines
351 a8083063 Iustin Pop
352 a8083063 Iustin Pop
    # We removed a line, write a new file and replace old.
353 a8083063 Iustin Pop
    fd, tmpname = tempfile.mkstemp('tmp', 'hosts_', '/etc')
354 a8083063 Iustin Pop
    newfile = os.fdopen(fd, 'w')
355 a8083063 Iustin Pop
    newfile.write(''.join(save_lines))
356 a8083063 Iustin Pop
    newfile.close()
357 a8083063 Iustin Pop
    os.rename(tmpname, '/etc/hosts')
358 a8083063 Iustin Pop
359 a8083063 Iustin Pop
  elif add_lines:
360 a8083063 Iustin Pop
    # Simply appending a new line will do the trick.
361 a8083063 Iustin Pop
    f.seek(0, 2)
362 a8083063 Iustin Pop
    for add in add_lines:
363 a8083063 Iustin Pop
      f.write(add)
364 a8083063 Iustin Pop
365 a8083063 Iustin Pop
  f.close()
366 a8083063 Iustin Pop
367 a8083063 Iustin Pop
368 a8083063 Iustin Pop
def _UpdateKnownHosts(fullnode, ip, pubkey):
369 a8083063 Iustin Pop
  """Ensure a node has a correct known_hosts entry.
370 a8083063 Iustin Pop

371 a8083063 Iustin Pop
  Args:
372 a8083063 Iustin Pop
    fullnode - Fully qualified domain name of host. (str)
373 a8083063 Iustin Pop
    ip       - IPv4 address of host (str)
374 a8083063 Iustin Pop
    pubkey   - the public key of the cluster
375 a8083063 Iustin Pop

376 a8083063 Iustin Pop
  """
377 82122173 Iustin Pop
  if os.path.exists(constants.SSH_KNOWN_HOSTS_FILE):
378 82122173 Iustin Pop
    f = open(constants.SSH_KNOWN_HOSTS_FILE, 'r+')
379 a8083063 Iustin Pop
  else:
380 82122173 Iustin Pop
    f = open(constants.SSH_KNOWN_HOSTS_FILE, 'w+')
381 a8083063 Iustin Pop
382 a8083063 Iustin Pop
  inthere = False
383 a8083063 Iustin Pop
384 a8083063 Iustin Pop
  save_lines = []
385 a8083063 Iustin Pop
  add_lines = []
386 a8083063 Iustin Pop
  removed = False
387 a8083063 Iustin Pop
388 a8083063 Iustin Pop
  while True:
389 a8083063 Iustin Pop
    rawline = f.readline()
390 a8083063 Iustin Pop
    logger.Debug('read %s' % (repr(rawline),))
391 a8083063 Iustin Pop
392 a8083063 Iustin Pop
    if not rawline:
393 a8083063 Iustin Pop
      # End of file
394 a8083063 Iustin Pop
      break
395 a8083063 Iustin Pop
396 a8083063 Iustin Pop
    line = rawline.split('\n')[0]
397 a8083063 Iustin Pop
398 a8083063 Iustin Pop
    parts = line.split(' ')
399 a8083063 Iustin Pop
    fields = parts[0].split(',')
400 a8083063 Iustin Pop
    key = parts[2]
401 a8083063 Iustin Pop
402 a8083063 Iustin Pop
    haveall = True
403 a8083063 Iustin Pop
    havesome = False
404 a8083063 Iustin Pop
    for spec in [ ip, fullnode ]:
405 a8083063 Iustin Pop
      if spec not in fields:
406 a8083063 Iustin Pop
        haveall = False
407 a8083063 Iustin Pop
      if spec in fields:
408 a8083063 Iustin Pop
        havesome = True
409 a8083063 Iustin Pop
410 a8083063 Iustin Pop
    logger.Debug("key, pubkey = %s." % (repr((key, pubkey)),))
411 a8083063 Iustin Pop
    if haveall and key == pubkey:
412 a8083063 Iustin Pop
      inthere = True
413 a8083063 Iustin Pop
      save_lines.append(rawline)
414 a8083063 Iustin Pop
      logger.Debug("Keeping known_hosts '%s'." % (repr(rawline),))
415 a8083063 Iustin Pop
      continue
416 a8083063 Iustin Pop
417 a8083063 Iustin Pop
    if havesome and (not haveall or key != pubkey):
418 a8083063 Iustin Pop
      removed = True
419 a8083063 Iustin Pop
      logger.Debug("Discarding known_hosts '%s'." % (repr(rawline),))
420 a8083063 Iustin Pop
      continue
421 a8083063 Iustin Pop
422 a8083063 Iustin Pop
    save_lines.append(rawline)
423 a8083063 Iustin Pop
424 a8083063 Iustin Pop
  if not inthere:
425 a8083063 Iustin Pop
    add_lines.append('%s,%s ssh-rsa %s\n' % (fullnode, ip, pubkey))
426 a8083063 Iustin Pop
    logger.Debug("Adding known_hosts '%s'." % (repr(add_lines[-1]),))
427 a8083063 Iustin Pop
428 a8083063 Iustin Pop
  if removed:
429 a8083063 Iustin Pop
    save_lines = save_lines + add_lines
430 a8083063 Iustin Pop
431 a8083063 Iustin Pop
    # Write a new file and replace old.
432 82122173 Iustin Pop
    fd, tmpname = tempfile.mkstemp('.tmp', 'known_hosts.',
433 82122173 Iustin Pop
                                   constants.DATA_DIR)
434 a8083063 Iustin Pop
    newfile = os.fdopen(fd, 'w')
435 82122173 Iustin Pop
    try:
436 82122173 Iustin Pop
      newfile.write(''.join(save_lines))
437 82122173 Iustin Pop
    finally:
438 82122173 Iustin Pop
      newfile.close()
439 a8083063 Iustin Pop
    logger.Debug("Wrote new known_hosts.")
440 82122173 Iustin Pop
    os.rename(tmpname, constants.SSH_KNOWN_HOSTS_FILE)
441 a8083063 Iustin Pop
442 a8083063 Iustin Pop
  elif add_lines:
443 a8083063 Iustin Pop
    # Simply appending a new line will do the trick.
444 a8083063 Iustin Pop
    f.seek(0, 2)
445 a8083063 Iustin Pop
    for add in add_lines:
446 a8083063 Iustin Pop
      f.write(add)
447 a8083063 Iustin Pop
448 a8083063 Iustin Pop
  f.close()
449 a8083063 Iustin Pop
450 a8083063 Iustin Pop
451 a8083063 Iustin Pop
def _HasValidVG(vglist, vgname):
452 a8083063 Iustin Pop
  """Checks if the volume group list is valid.
453 a8083063 Iustin Pop

454 a8083063 Iustin Pop
  A non-None return value means there's an error, and the return value
455 a8083063 Iustin Pop
  is the error message.
456 a8083063 Iustin Pop

457 a8083063 Iustin Pop
  """
458 a8083063 Iustin Pop
  vgsize = vglist.get(vgname, None)
459 a8083063 Iustin Pop
  if vgsize is None:
460 a8083063 Iustin Pop
    return "volume group '%s' missing" % vgname
461 a8083063 Iustin Pop
  elif vgsize < 20480:
462 191a8385 Guido Trotter
    return ("volume group '%s' too small (20480MiB required, %dMib found)" %
463 191a8385 Guido Trotter
            (vgname, vgsize))
464 a8083063 Iustin Pop
  return None
465 a8083063 Iustin Pop
466 a8083063 Iustin Pop
467 a8083063 Iustin Pop
def _InitSSHSetup(node):
468 a8083063 Iustin Pop
  """Setup the SSH configuration for the cluster.
469 a8083063 Iustin Pop

470 a8083063 Iustin Pop

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

474 a8083063 Iustin Pop
  Args:
475 a8083063 Iustin Pop
    node: the name of this host as a fqdn
476 a8083063 Iustin Pop

477 a8083063 Iustin Pop
  """
478 a8083063 Iustin Pop
  if os.path.exists('/root/.ssh/id_dsa'):
479 a8083063 Iustin Pop
    utils.CreateBackup('/root/.ssh/id_dsa')
480 a8083063 Iustin Pop
  if os.path.exists('/root/.ssh/id_dsa.pub'):
481 a8083063 Iustin Pop
    utils.CreateBackup('/root/.ssh/id_dsa.pub')
482 a8083063 Iustin Pop
483 a8083063 Iustin Pop
  utils.RemoveFile('/root/.ssh/id_dsa')
484 a8083063 Iustin Pop
  utils.RemoveFile('/root/.ssh/id_dsa.pub')
485 a8083063 Iustin Pop
486 a8083063 Iustin Pop
  result = utils.RunCmd(["ssh-keygen", "-t", "dsa",
487 a8083063 Iustin Pop
                         "-f", "/root/.ssh/id_dsa",
488 a8083063 Iustin Pop
                         "-q", "-N", ""])
489 a8083063 Iustin Pop
  if result.failed:
490 3ecf6786 Iustin Pop
    raise errors.OpExecError("Could not generate ssh keypair, error %s" %
491 3ecf6786 Iustin Pop
                             result.output)
492 a8083063 Iustin Pop
493 a8083063 Iustin Pop
  f = open('/root/.ssh/id_dsa.pub', 'r')
494 a8083063 Iustin Pop
  try:
495 a8083063 Iustin Pop
    utils.AddAuthorizedKey('/root/.ssh/authorized_keys', f.read(8192))
496 a8083063 Iustin Pop
  finally:
497 a8083063 Iustin Pop
    f.close()
498 a8083063 Iustin Pop
499 a8083063 Iustin Pop
500 a8083063 Iustin Pop
def _InitGanetiServerSetup(ss):
501 a8083063 Iustin Pop
  """Setup the necessary configuration for the initial node daemon.
502 a8083063 Iustin Pop

503 a8083063 Iustin Pop
  This creates the nodepass file containing the shared password for
504 a8083063 Iustin Pop
  the cluster and also generates the SSL certificate.
505 a8083063 Iustin Pop

506 a8083063 Iustin Pop
  """
507 a8083063 Iustin Pop
  # Create pseudo random password
508 a8083063 Iustin Pop
  randpass = sha.new(os.urandom(64)).hexdigest()
509 a8083063 Iustin Pop
  # and write it into sstore
510 a8083063 Iustin Pop
  ss.SetKey(ss.SS_NODED_PASS, randpass)
511 a8083063 Iustin Pop
512 a8083063 Iustin Pop
  result = utils.RunCmd(["openssl", "req", "-new", "-newkey", "rsa:1024",
513 a8083063 Iustin Pop
                         "-days", str(365*5), "-nodes", "-x509",
514 a8083063 Iustin Pop
                         "-keyout", constants.SSL_CERT_FILE,
515 a8083063 Iustin Pop
                         "-out", constants.SSL_CERT_FILE, "-batch"])
516 a8083063 Iustin Pop
  if result.failed:
517 3ecf6786 Iustin Pop
    raise errors.OpExecError("could not generate server ssl cert, command"
518 3ecf6786 Iustin Pop
                             " %s had exitcode %s and error message %s" %
519 3ecf6786 Iustin Pop
                             (result.cmd, result.exit_code, result.output))
520 a8083063 Iustin Pop
521 a8083063 Iustin Pop
  os.chmod(constants.SSL_CERT_FILE, 0400)
522 a8083063 Iustin Pop
523 a8083063 Iustin Pop
  result = utils.RunCmd([constants.NODE_INITD_SCRIPT, "restart"])
524 a8083063 Iustin Pop
525 a8083063 Iustin Pop
  if result.failed:
526 3ecf6786 Iustin Pop
    raise errors.OpExecError("Could not start the node daemon, command %s"
527 3ecf6786 Iustin Pop
                             " had exitcode %s and error %s" %
528 3ecf6786 Iustin Pop
                             (result.cmd, result.exit_code, result.output))
529 a8083063 Iustin Pop
530 a8083063 Iustin Pop
531 a8083063 Iustin Pop
class LUInitCluster(LogicalUnit):
532 a8083063 Iustin Pop
  """Initialise the cluster.
533 a8083063 Iustin Pop

534 a8083063 Iustin Pop
  """
535 a8083063 Iustin Pop
  HPATH = "cluster-init"
536 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_CLUSTER
537 a8083063 Iustin Pop
  _OP_REQP = ["cluster_name", "hypervisor_type", "vg_name", "mac_prefix",
538 880478f8 Iustin Pop
              "def_bridge", "master_netdev"]
539 a8083063 Iustin Pop
  REQ_CLUSTER = False
540 a8083063 Iustin Pop
541 a8083063 Iustin Pop
  def BuildHooksEnv(self):
542 a8083063 Iustin Pop
    """Build hooks env.
543 a8083063 Iustin Pop

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

547 a8083063 Iustin Pop
    """
548 396e1b78 Michael Hanselmann
    env = {
549 396e1b78 Michael Hanselmann
      "CLUSTER": self.op.cluster_name,
550 bcf043c9 Iustin Pop
      "MASTER": self.hostname.name,
551 396e1b78 Michael Hanselmann
      }
552 bcf043c9 Iustin Pop
    return env, [], [self.hostname.name]
553 a8083063 Iustin Pop
554 a8083063 Iustin Pop
  def CheckPrereq(self):
555 a8083063 Iustin Pop
    """Verify that the passed name is a valid one.
556 a8083063 Iustin Pop

557 a8083063 Iustin Pop
    """
558 a8083063 Iustin Pop
    if config.ConfigWriter.IsCluster():
559 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Cluster is already initialised")
560 a8083063 Iustin Pop
561 89e1fc26 Iustin Pop
    self.hostname = hostname = utils.HostInfo()
562 ff98055b Iustin Pop
563 bcf043c9 Iustin Pop
    if hostname.ip.startswith("127."):
564 130e907e Iustin Pop
      raise errors.OpPrereqError("This host's IP resolves to the private"
565 130e907e Iustin Pop
                                 " range (%s). Please fix DNS or /etc/hosts." %
566 bcf043c9 Iustin Pop
                                 (hostname.ip,))
567 130e907e Iustin Pop
568 89e1fc26 Iustin Pop
    self.clustername = clustername = utils.HostInfo(self.op.cluster_name)
569 a8083063 Iustin Pop
570 bcf043c9 Iustin Pop
    result = utils.RunCmd(["fping", "-S127.0.0.1", "-q", hostname.ip])
571 a8083063 Iustin Pop
    if result.failed:
572 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Inconsistency: this host's name resolves"
573 3ecf6786 Iustin Pop
                                 " to %s,\nbut this ip address does not"
574 3ecf6786 Iustin Pop
                                 " belong to this host."
575 bcf043c9 Iustin Pop
                                 " Aborting." % hostname.ip)
576 a8083063 Iustin Pop
577 a8083063 Iustin Pop
    secondary_ip = getattr(self.op, "secondary_ip", None)
578 a8083063 Iustin Pop
    if secondary_ip and not utils.IsValidIP(secondary_ip):
579 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Invalid secondary ip given")
580 bcf043c9 Iustin Pop
    if secondary_ip and secondary_ip != hostname.ip:
581 a8083063 Iustin Pop
      result = utils.RunCmd(["fping", "-S127.0.0.1", "-q", secondary_ip])
582 a8083063 Iustin Pop
      if result.failed:
583 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("You gave %s as secondary IP,\n"
584 3ecf6786 Iustin Pop
                                   "but it does not belong to this host." %
585 3ecf6786 Iustin Pop
                                   secondary_ip)
586 a8083063 Iustin Pop
    self.secondary_ip = secondary_ip
587 a8083063 Iustin Pop
588 a8083063 Iustin Pop
    # checks presence of the volume group given
589 a8083063 Iustin Pop
    vgstatus = _HasValidVG(utils.ListVolumeGroups(), self.op.vg_name)
590 a8083063 Iustin Pop
591 a8083063 Iustin Pop
    if vgstatus:
592 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Error: %s" % vgstatus)
593 a8083063 Iustin Pop
594 a8083063 Iustin Pop
    if not re.match("^[0-9a-z]{2}:[0-9a-z]{2}:[0-9a-z]{2}$",
595 a8083063 Iustin Pop
                    self.op.mac_prefix):
596 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Invalid mac prefix given '%s'" %
597 3ecf6786 Iustin Pop
                                 self.op.mac_prefix)
598 a8083063 Iustin Pop
599 a8083063 Iustin Pop
    if self.op.hypervisor_type not in hypervisor.VALID_HTYPES:
600 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Invalid hypervisor type given '%s'" %
601 3ecf6786 Iustin Pop
                                 self.op.hypervisor_type)
602 a8083063 Iustin Pop
603 880478f8 Iustin Pop
    result = utils.RunCmd(["ip", "link", "show", "dev", self.op.master_netdev])
604 880478f8 Iustin Pop
    if result.failed:
605 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Invalid master netdev given (%s): '%s'" %
606 8925faaa Iustin Pop
                                 (self.op.master_netdev,
607 8925faaa Iustin Pop
                                  result.output.strip()))
608 880478f8 Iustin Pop
609 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
610 a8083063 Iustin Pop
    """Initialize the cluster.
611 a8083063 Iustin Pop

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

654 a8083063 Iustin Pop
  """
655 a8083063 Iustin Pop
  _OP_REQP = []
656 a8083063 Iustin Pop
657 a8083063 Iustin Pop
  def CheckPrereq(self):
658 a8083063 Iustin Pop
    """Check prerequisites.
659 a8083063 Iustin Pop

660 a8083063 Iustin Pop
    This checks whether the cluster is empty.
661 a8083063 Iustin Pop

662 a8083063 Iustin Pop
    Any errors are signalled by raising errors.OpPrereqError.
663 a8083063 Iustin Pop

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

679 a8083063 Iustin Pop
    """
680 a8083063 Iustin Pop
    utils.CreateBackup('/root/.ssh/id_dsa')
681 a8083063 Iustin Pop
    utils.CreateBackup('/root/.ssh/id_dsa.pub')
682 880478f8 Iustin Pop
    rpc.call_node_leave_cluster(self.sstore.GetMasterNode())
683 a8083063 Iustin Pop
684 a8083063 Iustin Pop
685 a8083063 Iustin Pop
class LUVerifyCluster(NoHooksLU):
686 a8083063 Iustin Pop
  """Verifies the cluster status.
687 a8083063 Iustin Pop

688 a8083063 Iustin Pop
  """
689 a8083063 Iustin Pop
  _OP_REQP = []
690 a8083063 Iustin Pop
691 a8083063 Iustin Pop
  def _VerifyNode(self, node, file_list, local_cksum, vglist, node_result,
692 a8083063 Iustin Pop
                  remote_version, feedback_fn):
693 a8083063 Iustin Pop
    """Run multiple tests against a node.
694 a8083063 Iustin Pop

695 a8083063 Iustin Pop
    Test list:
696 a8083063 Iustin Pop
      - compares ganeti version
697 a8083063 Iustin Pop
      - checks vg existance and size > 20G
698 a8083063 Iustin Pop
      - checks config file checksum
699 a8083063 Iustin Pop
      - checks ssh to other nodes
700 a8083063 Iustin Pop

701 a8083063 Iustin Pop
    Args:
702 a8083063 Iustin Pop
      node: name of the node to check
703 a8083063 Iustin Pop
      file_list: required list of files
704 a8083063 Iustin Pop
      local_cksum: dictionary of local files and their checksums
705 098c0958 Michael Hanselmann

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

764 a8083063 Iustin Pop
    This function checks to see if the required block devices are
765 a8083063 Iustin Pop
    available on the instance's node.
766 a8083063 Iustin Pop

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

807 a8083063 Iustin Pop
    The .os, .swap and backup volumes are ignored. All other volumes are
808 a8083063 Iustin Pop
    reported as unknown.
809 a8083063 Iustin Pop

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

824 a8083063 Iustin Pop
    This checks what instances are running but unknown to the cluster.
825 a8083063 Iustin Pop

826 a8083063 Iustin Pop
    """
827 a8083063 Iustin Pop
    bad = False
828 a8083063 Iustin Pop
    for node in node_instance:
829 a8083063 Iustin Pop
      for runninginstance in node_instance[node]:
830 a8083063 Iustin Pop
        if runninginstance not in instancelist:
831 a8083063 Iustin Pop
          feedback_fn("  - ERROR: instance %s on node %s should not exist" %
832 a8083063 Iustin Pop
                          (runninginstance, node))
833 a8083063 Iustin Pop
          bad = True
834 a8083063 Iustin Pop
    return bad
835 a8083063 Iustin Pop
836 a8083063 Iustin Pop
  def CheckPrereq(self):
837 a8083063 Iustin Pop
    """Check prerequisites.
838 a8083063 Iustin Pop

839 a8083063 Iustin Pop
    This has no prerequisites.
840 a8083063 Iustin Pop

841 a8083063 Iustin Pop
    """
842 a8083063 Iustin Pop
    pass
843 a8083063 Iustin Pop
844 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
845 a8083063 Iustin Pop
    """Verify integrity of cluster, performing various test on nodes.
846 a8083063 Iustin Pop

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

932 07bd8a51 Iustin Pop
  """
933 07bd8a51 Iustin Pop
  HPATH = "cluster-rename"
934 07bd8a51 Iustin Pop
  HTYPE = constants.HTYPE_CLUSTER
935 07bd8a51 Iustin Pop
  _OP_REQP = ["name"]
936 07bd8a51 Iustin Pop
937 07bd8a51 Iustin Pop
  def BuildHooksEnv(self):
938 07bd8a51 Iustin Pop
    """Build hooks env.
939 07bd8a51 Iustin Pop

940 07bd8a51 Iustin Pop
    """
941 07bd8a51 Iustin Pop
    env = {
942 07bd8a51 Iustin Pop
      "NEW_NAME": self.op.name,
943 07bd8a51 Iustin Pop
      }
944 07bd8a51 Iustin Pop
    mn = self.sstore.GetMasterNode()
945 07bd8a51 Iustin Pop
    return env, [mn], [mn]
946 07bd8a51 Iustin Pop
947 07bd8a51 Iustin Pop
  def CheckPrereq(self):
948 07bd8a51 Iustin Pop
    """Verify that the passed name is a valid one.
949 07bd8a51 Iustin Pop

950 07bd8a51 Iustin Pop
    """
951 89e1fc26 Iustin Pop
    hostname = utils.HostInfo(self.op.name)
952 07bd8a51 Iustin Pop
953 bcf043c9 Iustin Pop
    new_name = hostname.name
954 bcf043c9 Iustin Pop
    self.ip = new_ip = hostname.ip
955 07bd8a51 Iustin Pop
    old_name = self.sstore.GetClusterName()
956 07bd8a51 Iustin Pop
    old_ip = self.sstore.GetMasterIP()
957 07bd8a51 Iustin Pop
    if new_name == old_name and new_ip == old_ip:
958 07bd8a51 Iustin Pop
      raise errors.OpPrereqError("Neither the name nor the IP address of the"
959 07bd8a51 Iustin Pop
                                 " cluster has changed")
960 07bd8a51 Iustin Pop
    if new_ip != old_ip:
961 07bd8a51 Iustin Pop
      result = utils.RunCmd(["fping", "-q", new_ip])
962 07bd8a51 Iustin Pop
      if not result.failed:
963 07bd8a51 Iustin Pop
        raise errors.OpPrereqError("The given cluster IP address (%s) is"
964 07bd8a51 Iustin Pop
                                   " reachable on the network. Aborting." %
965 07bd8a51 Iustin Pop
                                   new_ip)
966 07bd8a51 Iustin Pop
967 07bd8a51 Iustin Pop
    self.op.name = new_name
968 07bd8a51 Iustin Pop
969 07bd8a51 Iustin Pop
  def Exec(self, feedback_fn):
970 07bd8a51 Iustin Pop
    """Rename the cluster.
971 07bd8a51 Iustin Pop

972 07bd8a51 Iustin Pop
    """
973 07bd8a51 Iustin Pop
    clustername = self.op.name
974 07bd8a51 Iustin Pop
    ip = self.ip
975 07bd8a51 Iustin Pop
    ss = self.sstore
976 07bd8a51 Iustin Pop
977 07bd8a51 Iustin Pop
    # shutdown the master IP
978 07bd8a51 Iustin Pop
    master = ss.GetMasterNode()
979 07bd8a51 Iustin Pop
    if not rpc.call_node_stop_master(master):
980 07bd8a51 Iustin Pop
      raise errors.OpExecError("Could not disable the master role")
981 07bd8a51 Iustin Pop
982 07bd8a51 Iustin Pop
    try:
983 07bd8a51 Iustin Pop
      # modify the sstore
984 07bd8a51 Iustin Pop
      ss.SetKey(ss.SS_MASTER_IP, ip)
985 07bd8a51 Iustin Pop
      ss.SetKey(ss.SS_CLUSTER_NAME, clustername)
986 07bd8a51 Iustin Pop
987 07bd8a51 Iustin Pop
      # Distribute updated ss config to all nodes
988 07bd8a51 Iustin Pop
      myself = self.cfg.GetNodeInfo(master)
989 07bd8a51 Iustin Pop
      dist_nodes = self.cfg.GetNodeList()
990 07bd8a51 Iustin Pop
      if myself.name in dist_nodes:
991 07bd8a51 Iustin Pop
        dist_nodes.remove(myself.name)
992 07bd8a51 Iustin Pop
993 07bd8a51 Iustin Pop
      logger.Debug("Copying updated ssconf data to all nodes")
994 07bd8a51 Iustin Pop
      for keyname in [ss.SS_CLUSTER_NAME, ss.SS_MASTER_IP]:
995 07bd8a51 Iustin Pop
        fname = ss.KeyToFilename(keyname)
996 07bd8a51 Iustin Pop
        result = rpc.call_upload_file(dist_nodes, fname)
997 07bd8a51 Iustin Pop
        for to_node in dist_nodes:
998 07bd8a51 Iustin Pop
          if not result[to_node]:
999 07bd8a51 Iustin Pop
            logger.Error("copy of file %s to node %s failed" %
1000 07bd8a51 Iustin Pop
                         (fname, to_node))
1001 07bd8a51 Iustin Pop
    finally:
1002 07bd8a51 Iustin Pop
      if not rpc.call_node_start_master(master):
1003 07bd8a51 Iustin Pop
        logger.Error("Could not re-enable the master role on the master,\n"
1004 07bd8a51 Iustin Pop
                     "please restart manually.")
1005 07bd8a51 Iustin Pop
1006 07bd8a51 Iustin Pop
1007 a8083063 Iustin Pop
def _WaitForSync(cfgw, instance, oneshot=False, unlock=False):
1008 a8083063 Iustin Pop
  """Sleep and poll for an instance's disk to sync.
1009 a8083063 Iustin Pop

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

1073 a8083063 Iustin Pop
  """
1074 a8083063 Iustin Pop
  cfgw.SetDiskID(dev, node)
1075 a8083063 Iustin Pop
1076 a8083063 Iustin Pop
  result = True
1077 a8083063 Iustin Pop
  if on_primary or dev.AssembleOnSecondary():
1078 a8083063 Iustin Pop
    rstats = rpc.call_blockdev_find(node, dev)
1079 a8083063 Iustin Pop
    if not rstats:
1080 a8083063 Iustin Pop
      logger.ToStderr("Can't get any data from node %s" % node)
1081 a8083063 Iustin Pop
      result = False
1082 a8083063 Iustin Pop
    else:
1083 a8083063 Iustin Pop
      result = result and (not rstats[5])
1084 a8083063 Iustin Pop
  if dev.children:
1085 a8083063 Iustin Pop
    for child in dev.children:
1086 a8083063 Iustin Pop
      result = result and _CheckDiskConsistency(cfgw, child, node, on_primary)
1087 a8083063 Iustin Pop
1088 a8083063 Iustin Pop
  return result
1089 a8083063 Iustin Pop
1090 a8083063 Iustin Pop
1091 a8083063 Iustin Pop
class LUDiagnoseOS(NoHooksLU):
1092 a8083063 Iustin Pop
  """Logical unit for OS diagnose/query.
1093 a8083063 Iustin Pop

1094 a8083063 Iustin Pop
  """
1095 a8083063 Iustin Pop
  _OP_REQP = []
1096 a8083063 Iustin Pop
1097 a8083063 Iustin Pop
  def CheckPrereq(self):
1098 a8083063 Iustin Pop
    """Check prerequisites.
1099 a8083063 Iustin Pop

1100 a8083063 Iustin Pop
    This always succeeds, since this is a pure query LU.
1101 a8083063 Iustin Pop

1102 a8083063 Iustin Pop
    """
1103 a8083063 Iustin Pop
    return
1104 a8083063 Iustin Pop
1105 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1106 a8083063 Iustin Pop
    """Compute the list of OSes.
1107 a8083063 Iustin Pop

1108 a8083063 Iustin Pop
    """
1109 a8083063 Iustin Pop
    node_list = self.cfg.GetNodeList()
1110 a8083063 Iustin Pop
    node_data = rpc.call_os_diagnose(node_list)
1111 a8083063 Iustin Pop
    if node_data == False:
1112 3ecf6786 Iustin Pop
      raise errors.OpExecError("Can't gather the list of OSes")
1113 a8083063 Iustin Pop
    return node_data
1114 a8083063 Iustin Pop
1115 a8083063 Iustin Pop
1116 a8083063 Iustin Pop
class LURemoveNode(LogicalUnit):
1117 a8083063 Iustin Pop
  """Logical unit for removing a node.
1118 a8083063 Iustin Pop

1119 a8083063 Iustin Pop
  """
1120 a8083063 Iustin Pop
  HPATH = "node-remove"
1121 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_NODE
1122 a8083063 Iustin Pop
  _OP_REQP = ["node_name"]
1123 a8083063 Iustin Pop
1124 a8083063 Iustin Pop
  def BuildHooksEnv(self):
1125 a8083063 Iustin Pop
    """Build hooks env.
1126 a8083063 Iustin Pop

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

1130 a8083063 Iustin Pop
    """
1131 396e1b78 Michael Hanselmann
    env = {
1132 396e1b78 Michael Hanselmann
      "NODE_NAME": self.op.node_name,
1133 396e1b78 Michael Hanselmann
      }
1134 a8083063 Iustin Pop
    all_nodes = self.cfg.GetNodeList()
1135 a8083063 Iustin Pop
    all_nodes.remove(self.op.node_name)
1136 396e1b78 Michael Hanselmann
    return env, all_nodes, all_nodes
1137 a8083063 Iustin Pop
1138 a8083063 Iustin Pop
  def CheckPrereq(self):
1139 a8083063 Iustin Pop
    """Check prerequisites.
1140 a8083063 Iustin Pop

1141 a8083063 Iustin Pop
    This checks:
1142 a8083063 Iustin Pop
     - the node exists in the configuration
1143 a8083063 Iustin Pop
     - it does not have primary or secondary instances
1144 a8083063 Iustin Pop
     - it's not the master
1145 a8083063 Iustin Pop

1146 a8083063 Iustin Pop
    Any errors are signalled by raising errors.OpPrereqError.
1147 a8083063 Iustin Pop

1148 a8083063 Iustin Pop
    """
1149 a8083063 Iustin Pop
    node = self.cfg.GetNodeInfo(self.cfg.ExpandNodeName(self.op.node_name))
1150 a8083063 Iustin Pop
    if node is None:
1151 a02bc76e Iustin Pop
      raise errors.OpPrereqError, ("Node '%s' is unknown." % self.op.node_name)
1152 a8083063 Iustin Pop
1153 a8083063 Iustin Pop
    instance_list = self.cfg.GetInstanceList()
1154 a8083063 Iustin Pop
1155 880478f8 Iustin Pop
    masternode = self.sstore.GetMasterNode()
1156 a8083063 Iustin Pop
    if node.name == masternode:
1157 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Node is the master node,"
1158 3ecf6786 Iustin Pop
                                 " you need to failover first.")
1159 a8083063 Iustin Pop
1160 a8083063 Iustin Pop
    for instance_name in instance_list:
1161 a8083063 Iustin Pop
      instance = self.cfg.GetInstanceInfo(instance_name)
1162 a8083063 Iustin Pop
      if node.name == instance.primary_node:
1163 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Instance %s still running on the node,"
1164 3ecf6786 Iustin Pop
                                   " please remove first." % instance_name)
1165 a8083063 Iustin Pop
      if node.name in instance.secondary_nodes:
1166 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Instance %s has node as a secondary,"
1167 3ecf6786 Iustin Pop
                                   " please remove first." % instance_name)
1168 a8083063 Iustin Pop
    self.op.node_name = node.name
1169 a8083063 Iustin Pop
    self.node = node
1170 a8083063 Iustin Pop
1171 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1172 a8083063 Iustin Pop
    """Removes the node from the cluster.
1173 a8083063 Iustin Pop

1174 a8083063 Iustin Pop
    """
1175 a8083063 Iustin Pop
    node = self.node
1176 a8083063 Iustin Pop
    logger.Info("stopping the node daemon and removing configs from node %s" %
1177 a8083063 Iustin Pop
                node.name)
1178 a8083063 Iustin Pop
1179 a8083063 Iustin Pop
    rpc.call_node_leave_cluster(node.name)
1180 a8083063 Iustin Pop
1181 a8083063 Iustin Pop
    ssh.SSHCall(node.name, 'root', "%s stop" % constants.NODE_INITD_SCRIPT)
1182 a8083063 Iustin Pop
1183 a8083063 Iustin Pop
    logger.Info("Removing node %s from config" % node.name)
1184 a8083063 Iustin Pop
1185 a8083063 Iustin Pop
    self.cfg.RemoveNode(node.name)
1186 a8083063 Iustin Pop
1187 a8083063 Iustin Pop
1188 a8083063 Iustin Pop
class LUQueryNodes(NoHooksLU):
1189 a8083063 Iustin Pop
  """Logical unit for querying nodes.
1190 a8083063 Iustin Pop

1191 a8083063 Iustin Pop
  """
1192 246e180a Iustin Pop
  _OP_REQP = ["output_fields", "names"]
1193 a8083063 Iustin Pop
1194 a8083063 Iustin Pop
  def CheckPrereq(self):
1195 a8083063 Iustin Pop
    """Check prerequisites.
1196 a8083063 Iustin Pop

1197 a8083063 Iustin Pop
    This checks that the fields required are valid output fields.
1198 a8083063 Iustin Pop

1199 a8083063 Iustin Pop
    """
1200 a8083063 Iustin Pop
    self.dynamic_fields = frozenset(["dtotal", "dfree",
1201 a8083063 Iustin Pop
                                     "mtotal", "mnode", "mfree"])
1202 a8083063 Iustin Pop
1203 ec223efb Iustin Pop
    _CheckOutputFields(static=["name", "pinst_cnt", "sinst_cnt",
1204 ec223efb Iustin Pop
                               "pinst_list", "sinst_list",
1205 ec223efb Iustin Pop
                               "pip", "sip"],
1206 dcb93971 Michael Hanselmann
                       dynamic=self.dynamic_fields,
1207 dcb93971 Michael Hanselmann
                       selected=self.op.output_fields)
1208 a8083063 Iustin Pop
1209 246e180a Iustin Pop
    self.wanted = _GetWantedNodes(self, self.op.names)
1210 a8083063 Iustin Pop
1211 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1212 a8083063 Iustin Pop
    """Computes the list of nodes and their attributes.
1213 a8083063 Iustin Pop

1214 a8083063 Iustin Pop
    """
1215 246e180a Iustin Pop
    nodenames = self.wanted
1216 a8083063 Iustin Pop
    nodelist = [self.cfg.GetNodeInfo(name) for name in nodenames]
1217 a8083063 Iustin Pop
1218 a8083063 Iustin Pop
    # begin data gathering
1219 a8083063 Iustin Pop
1220 a8083063 Iustin Pop
    if self.dynamic_fields.intersection(self.op.output_fields):
1221 a8083063 Iustin Pop
      live_data = {}
1222 a8083063 Iustin Pop
      node_data = rpc.call_node_info(nodenames, self.cfg.GetVGName())
1223 a8083063 Iustin Pop
      for name in nodenames:
1224 a8083063 Iustin Pop
        nodeinfo = node_data.get(name, None)
1225 a8083063 Iustin Pop
        if nodeinfo:
1226 a8083063 Iustin Pop
          live_data[name] = {
1227 a8083063 Iustin Pop
            "mtotal": utils.TryConvert(int, nodeinfo['memory_total']),
1228 a8083063 Iustin Pop
            "mnode": utils.TryConvert(int, nodeinfo['memory_dom0']),
1229 a8083063 Iustin Pop
            "mfree": utils.TryConvert(int, nodeinfo['memory_free']),
1230 a8083063 Iustin Pop
            "dtotal": utils.TryConvert(int, nodeinfo['vg_size']),
1231 a8083063 Iustin Pop
            "dfree": utils.TryConvert(int, nodeinfo['vg_free']),
1232 a8083063 Iustin Pop
            }
1233 a8083063 Iustin Pop
        else:
1234 a8083063 Iustin Pop
          live_data[name] = {}
1235 a8083063 Iustin Pop
    else:
1236 a8083063 Iustin Pop
      live_data = dict.fromkeys(nodenames, {})
1237 a8083063 Iustin Pop
1238 ec223efb Iustin Pop
    node_to_primary = dict([(name, set()) for name in nodenames])
1239 ec223efb Iustin Pop
    node_to_secondary = dict([(name, set()) for name in nodenames])
1240 a8083063 Iustin Pop
1241 ec223efb Iustin Pop
    inst_fields = frozenset(("pinst_cnt", "pinst_list",
1242 ec223efb Iustin Pop
                             "sinst_cnt", "sinst_list"))
1243 ec223efb Iustin Pop
    if inst_fields & frozenset(self.op.output_fields):
1244 a8083063 Iustin Pop
      instancelist = self.cfg.GetInstanceList()
1245 a8083063 Iustin Pop
1246 ec223efb Iustin Pop
      for instance_name in instancelist:
1247 ec223efb Iustin Pop
        inst = self.cfg.GetInstanceInfo(instance_name)
1248 ec223efb Iustin Pop
        if inst.primary_node in node_to_primary:
1249 ec223efb Iustin Pop
          node_to_primary[inst.primary_node].add(inst.name)
1250 ec223efb Iustin Pop
        for secnode in inst.secondary_nodes:
1251 ec223efb Iustin Pop
          if secnode in node_to_secondary:
1252 ec223efb Iustin Pop
            node_to_secondary[secnode].add(inst.name)
1253 a8083063 Iustin Pop
1254 a8083063 Iustin Pop
    # end data gathering
1255 a8083063 Iustin Pop
1256 a8083063 Iustin Pop
    output = []
1257 a8083063 Iustin Pop
    for node in nodelist:
1258 a8083063 Iustin Pop
      node_output = []
1259 a8083063 Iustin Pop
      for field in self.op.output_fields:
1260 a8083063 Iustin Pop
        if field == "name":
1261 a8083063 Iustin Pop
          val = node.name
1262 ec223efb Iustin Pop
        elif field == "pinst_list":
1263 ec223efb Iustin Pop
          val = list(node_to_primary[node.name])
1264 ec223efb Iustin Pop
        elif field == "sinst_list":
1265 ec223efb Iustin Pop
          val = list(node_to_secondary[node.name])
1266 ec223efb Iustin Pop
        elif field == "pinst_cnt":
1267 ec223efb Iustin Pop
          val = len(node_to_primary[node.name])
1268 ec223efb Iustin Pop
        elif field == "sinst_cnt":
1269 ec223efb Iustin Pop
          val = len(node_to_secondary[node.name])
1270 a8083063 Iustin Pop
        elif field == "pip":
1271 a8083063 Iustin Pop
          val = node.primary_ip
1272 a8083063 Iustin Pop
        elif field == "sip":
1273 a8083063 Iustin Pop
          val = node.secondary_ip
1274 a8083063 Iustin Pop
        elif field in self.dynamic_fields:
1275 ec223efb Iustin Pop
          val = live_data[node.name].get(field, None)
1276 a8083063 Iustin Pop
        else:
1277 3ecf6786 Iustin Pop
          raise errors.ParameterError(field)
1278 a8083063 Iustin Pop
        node_output.append(val)
1279 a8083063 Iustin Pop
      output.append(node_output)
1280 a8083063 Iustin Pop
1281 a8083063 Iustin Pop
    return output
1282 a8083063 Iustin Pop
1283 a8083063 Iustin Pop
1284 dcb93971 Michael Hanselmann
class LUQueryNodeVolumes(NoHooksLU):
1285 dcb93971 Michael Hanselmann
  """Logical unit for getting volumes on node(s).
1286 dcb93971 Michael Hanselmann

1287 dcb93971 Michael Hanselmann
  """
1288 dcb93971 Michael Hanselmann
  _OP_REQP = ["nodes", "output_fields"]
1289 dcb93971 Michael Hanselmann
1290 dcb93971 Michael Hanselmann
  def CheckPrereq(self):
1291 dcb93971 Michael Hanselmann
    """Check prerequisites.
1292 dcb93971 Michael Hanselmann

1293 dcb93971 Michael Hanselmann
    This checks that the fields required are valid output fields.
1294 dcb93971 Michael Hanselmann

1295 dcb93971 Michael Hanselmann
    """
1296 dcb93971 Michael Hanselmann
    self.nodes = _GetWantedNodes(self, self.op.nodes)
1297 dcb93971 Michael Hanselmann
1298 dcb93971 Michael Hanselmann
    _CheckOutputFields(static=["node"],
1299 dcb93971 Michael Hanselmann
                       dynamic=["phys", "vg", "name", "size", "instance"],
1300 dcb93971 Michael Hanselmann
                       selected=self.op.output_fields)
1301 dcb93971 Michael Hanselmann
1302 dcb93971 Michael Hanselmann
1303 dcb93971 Michael Hanselmann
  def Exec(self, feedback_fn):
1304 dcb93971 Michael Hanselmann
    """Computes the list of nodes and their attributes.
1305 dcb93971 Michael Hanselmann

1306 dcb93971 Michael Hanselmann
    """
1307 a7ba5e53 Iustin Pop
    nodenames = self.nodes
1308 dcb93971 Michael Hanselmann
    volumes = rpc.call_node_volumes(nodenames)
1309 dcb93971 Michael Hanselmann
1310 dcb93971 Michael Hanselmann
    ilist = [self.cfg.GetInstanceInfo(iname) for iname
1311 dcb93971 Michael Hanselmann
             in self.cfg.GetInstanceList()]
1312 dcb93971 Michael Hanselmann
1313 dcb93971 Michael Hanselmann
    lv_by_node = dict([(inst, inst.MapLVsByNode()) for inst in ilist])
1314 dcb93971 Michael Hanselmann
1315 dcb93971 Michael Hanselmann
    output = []
1316 dcb93971 Michael Hanselmann
    for node in nodenames:
1317 37d19eb2 Michael Hanselmann
      if node not in volumes or not volumes[node]:
1318 37d19eb2 Michael Hanselmann
        continue
1319 37d19eb2 Michael Hanselmann
1320 dcb93971 Michael Hanselmann
      node_vols = volumes[node][:]
1321 dcb93971 Michael Hanselmann
      node_vols.sort(key=lambda vol: vol['dev'])
1322 dcb93971 Michael Hanselmann
1323 dcb93971 Michael Hanselmann
      for vol in node_vols:
1324 dcb93971 Michael Hanselmann
        node_output = []
1325 dcb93971 Michael Hanselmann
        for field in self.op.output_fields:
1326 dcb93971 Michael Hanselmann
          if field == "node":
1327 dcb93971 Michael Hanselmann
            val = node
1328 dcb93971 Michael Hanselmann
          elif field == "phys":
1329 dcb93971 Michael Hanselmann
            val = vol['dev']
1330 dcb93971 Michael Hanselmann
          elif field == "vg":
1331 dcb93971 Michael Hanselmann
            val = vol['vg']
1332 dcb93971 Michael Hanselmann
          elif field == "name":
1333 dcb93971 Michael Hanselmann
            val = vol['name']
1334 dcb93971 Michael Hanselmann
          elif field == "size":
1335 dcb93971 Michael Hanselmann
            val = int(float(vol['size']))
1336 dcb93971 Michael Hanselmann
          elif field == "instance":
1337 dcb93971 Michael Hanselmann
            for inst in ilist:
1338 dcb93971 Michael Hanselmann
              if node not in lv_by_node[inst]:
1339 dcb93971 Michael Hanselmann
                continue
1340 dcb93971 Michael Hanselmann
              if vol['name'] in lv_by_node[inst][node]:
1341 dcb93971 Michael Hanselmann
                val = inst.name
1342 dcb93971 Michael Hanselmann
                break
1343 dcb93971 Michael Hanselmann
            else:
1344 dcb93971 Michael Hanselmann
              val = '-'
1345 dcb93971 Michael Hanselmann
          else:
1346 3ecf6786 Iustin Pop
            raise errors.ParameterError(field)
1347 dcb93971 Michael Hanselmann
          node_output.append(str(val))
1348 dcb93971 Michael Hanselmann
1349 dcb93971 Michael Hanselmann
        output.append(node_output)
1350 dcb93971 Michael Hanselmann
1351 dcb93971 Michael Hanselmann
    return output
1352 dcb93971 Michael Hanselmann
1353 dcb93971 Michael Hanselmann
1354 a8083063 Iustin Pop
class LUAddNode(LogicalUnit):
1355 a8083063 Iustin Pop
  """Logical unit for adding node to the cluster.
1356 a8083063 Iustin Pop

1357 a8083063 Iustin Pop
  """
1358 a8083063 Iustin Pop
  HPATH = "node-add"
1359 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_NODE
1360 a8083063 Iustin Pop
  _OP_REQP = ["node_name"]
1361 a8083063 Iustin Pop
1362 a8083063 Iustin Pop
  def BuildHooksEnv(self):
1363 a8083063 Iustin Pop
    """Build hooks env.
1364 a8083063 Iustin Pop

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

1367 a8083063 Iustin Pop
    """
1368 a8083063 Iustin Pop
    env = {
1369 a8083063 Iustin Pop
      "NODE_NAME": self.op.node_name,
1370 a8083063 Iustin Pop
      "NODE_PIP": self.op.primary_ip,
1371 a8083063 Iustin Pop
      "NODE_SIP": self.op.secondary_ip,
1372 a8083063 Iustin Pop
      }
1373 a8083063 Iustin Pop
    nodes_0 = self.cfg.GetNodeList()
1374 a8083063 Iustin Pop
    nodes_1 = nodes_0 + [self.op.node_name, ]
1375 a8083063 Iustin Pop
    return env, nodes_0, nodes_1
1376 a8083063 Iustin Pop
1377 a8083063 Iustin Pop
  def CheckPrereq(self):
1378 a8083063 Iustin Pop
    """Check prerequisites.
1379 a8083063 Iustin Pop

1380 a8083063 Iustin Pop
    This checks:
1381 a8083063 Iustin Pop
     - the new node is not already in the config
1382 a8083063 Iustin Pop
     - it is resolvable
1383 a8083063 Iustin Pop
     - its parameters (single/dual homed) matches the cluster
1384 a8083063 Iustin Pop

1385 a8083063 Iustin Pop
    Any errors are signalled by raising errors.OpPrereqError.
1386 a8083063 Iustin Pop

1387 a8083063 Iustin Pop
    """
1388 a8083063 Iustin Pop
    node_name = self.op.node_name
1389 a8083063 Iustin Pop
    cfg = self.cfg
1390 a8083063 Iustin Pop
1391 89e1fc26 Iustin Pop
    dns_data = utils.HostInfo(node_name)
1392 a8083063 Iustin Pop
1393 bcf043c9 Iustin Pop
    node = dns_data.name
1394 bcf043c9 Iustin Pop
    primary_ip = self.op.primary_ip = dns_data.ip
1395 a8083063 Iustin Pop
    secondary_ip = getattr(self.op, "secondary_ip", None)
1396 a8083063 Iustin Pop
    if secondary_ip is None:
1397 a8083063 Iustin Pop
      secondary_ip = primary_ip
1398 a8083063 Iustin Pop
    if not utils.IsValidIP(secondary_ip):
1399 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Invalid secondary IP given")
1400 a8083063 Iustin Pop
    self.op.secondary_ip = secondary_ip
1401 a8083063 Iustin Pop
    node_list = cfg.GetNodeList()
1402 a8083063 Iustin Pop
    if node in node_list:
1403 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Node %s is already in the configuration"
1404 3ecf6786 Iustin Pop
                                 % node)
1405 a8083063 Iustin Pop
1406 a8083063 Iustin Pop
    for existing_node_name in node_list:
1407 a8083063 Iustin Pop
      existing_node = cfg.GetNodeInfo(existing_node_name)
1408 a8083063 Iustin Pop
      if (existing_node.primary_ip == primary_ip or
1409 a8083063 Iustin Pop
          existing_node.secondary_ip == primary_ip or
1410 a8083063 Iustin Pop
          existing_node.primary_ip == secondary_ip or
1411 a8083063 Iustin Pop
          existing_node.secondary_ip == secondary_ip):
1412 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("New node ip address(es) conflict with"
1413 3ecf6786 Iustin Pop
                                   " existing node %s" % existing_node.name)
1414 a8083063 Iustin Pop
1415 a8083063 Iustin Pop
    # check that the type of the node (single versus dual homed) is the
1416 a8083063 Iustin Pop
    # same as for the master
1417 880478f8 Iustin Pop
    myself = cfg.GetNodeInfo(self.sstore.GetMasterNode())
1418 a8083063 Iustin Pop
    master_singlehomed = myself.secondary_ip == myself.primary_ip
1419 a8083063 Iustin Pop
    newbie_singlehomed = secondary_ip == primary_ip
1420 a8083063 Iustin Pop
    if master_singlehomed != newbie_singlehomed:
1421 a8083063 Iustin Pop
      if master_singlehomed:
1422 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("The master has no private ip but the"
1423 3ecf6786 Iustin Pop
                                   " new node has one")
1424 a8083063 Iustin Pop
      else:
1425 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("The master has a private ip but the"
1426 3ecf6786 Iustin Pop
                                   " new node doesn't have one")
1427 a8083063 Iustin Pop
1428 a8083063 Iustin Pop
    # checks reachablity
1429 a8083063 Iustin Pop
    command = ["fping", "-q", primary_ip]
1430 a8083063 Iustin Pop
    result = utils.RunCmd(command)
1431 a8083063 Iustin Pop
    if result.failed:
1432 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Node not reachable by ping")
1433 a8083063 Iustin Pop
1434 a8083063 Iustin Pop
    if not newbie_singlehomed:
1435 a8083063 Iustin Pop
      # check reachability from my secondary ip to newbie's secondary ip
1436 a8083063 Iustin Pop
      command = ["fping", "-S%s" % myself.secondary_ip, "-q", secondary_ip]
1437 a8083063 Iustin Pop
      result = utils.RunCmd(command)
1438 a8083063 Iustin Pop
      if result.failed:
1439 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Node secondary ip not reachable by ping")
1440 a8083063 Iustin Pop
1441 a8083063 Iustin Pop
    self.new_node = objects.Node(name=node,
1442 a8083063 Iustin Pop
                                 primary_ip=primary_ip,
1443 a8083063 Iustin Pop
                                 secondary_ip=secondary_ip)
1444 a8083063 Iustin Pop
1445 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1446 a8083063 Iustin Pop
    """Adds the new node to the cluster.
1447 a8083063 Iustin Pop

1448 a8083063 Iustin Pop
    """
1449 a8083063 Iustin Pop
    new_node = self.new_node
1450 a8083063 Iustin Pop
    node = new_node.name
1451 a8083063 Iustin Pop
1452 a8083063 Iustin Pop
    # set up inter-node password and certificate and restarts the node daemon
1453 a8083063 Iustin Pop
    gntpass = self.sstore.GetNodeDaemonPassword()
1454 a8083063 Iustin Pop
    if not re.match('^[a-zA-Z0-9.]{1,64}$', gntpass):
1455 3ecf6786 Iustin Pop
      raise errors.OpExecError("ganeti password corruption detected")
1456 a8083063 Iustin Pop
    f = open(constants.SSL_CERT_FILE)
1457 a8083063 Iustin Pop
    try:
1458 a8083063 Iustin Pop
      gntpem = f.read(8192)
1459 a8083063 Iustin Pop
    finally:
1460 a8083063 Iustin Pop
      f.close()
1461 a8083063 Iustin Pop
    # in the base64 pem encoding, neither '!' nor '.' are valid chars,
1462 a8083063 Iustin Pop
    # so we use this to detect an invalid certificate; as long as the
1463 a8083063 Iustin Pop
    # cert doesn't contain this, the here-document will be correctly
1464 a8083063 Iustin Pop
    # parsed by the shell sequence below
1465 a8083063 Iustin Pop
    if re.search('^!EOF\.', gntpem, re.MULTILINE):
1466 3ecf6786 Iustin Pop
      raise errors.OpExecError("invalid PEM encoding in the SSL certificate")
1467 a8083063 Iustin Pop
    if not gntpem.endswith("\n"):
1468 3ecf6786 Iustin Pop
      raise errors.OpExecError("PEM must end with newline")
1469 a8083063 Iustin Pop
    logger.Info("copy cluster pass to %s and starting the node daemon" % node)
1470 a8083063 Iustin Pop
1471 a8083063 Iustin Pop
    # and then connect with ssh to set password and start ganeti-noded
1472 a8083063 Iustin Pop
    # note that all the below variables are sanitized at this point,
1473 a8083063 Iustin Pop
    # either by being constants or by the checks above
1474 a8083063 Iustin Pop
    ss = self.sstore
1475 a8083063 Iustin Pop
    mycommand = ("umask 077 && "
1476 a8083063 Iustin Pop
                 "echo '%s' > '%s' && "
1477 a8083063 Iustin Pop
                 "cat > '%s' << '!EOF.' && \n"
1478 a8083063 Iustin Pop
                 "%s!EOF.\n%s restart" %
1479 a8083063 Iustin Pop
                 (gntpass, ss.KeyToFilename(ss.SS_NODED_PASS),
1480 a8083063 Iustin Pop
                  constants.SSL_CERT_FILE, gntpem,
1481 a8083063 Iustin Pop
                  constants.NODE_INITD_SCRIPT))
1482 a8083063 Iustin Pop
1483 a8083063 Iustin Pop
    result = ssh.SSHCall(node, 'root', mycommand, batch=False, ask_key=True)
1484 a8083063 Iustin Pop
    if result.failed:
1485 3ecf6786 Iustin Pop
      raise errors.OpExecError("Remote command on node %s, error: %s,"
1486 3ecf6786 Iustin Pop
                               " output: %s" %
1487 3ecf6786 Iustin Pop
                               (node, result.fail_reason, result.output))
1488 a8083063 Iustin Pop
1489 a8083063 Iustin Pop
    # check connectivity
1490 a8083063 Iustin Pop
    time.sleep(4)
1491 a8083063 Iustin Pop
1492 a8083063 Iustin Pop
    result = rpc.call_version([node])[node]
1493 a8083063 Iustin Pop
    if result:
1494 a8083063 Iustin Pop
      if constants.PROTOCOL_VERSION == result:
1495 a8083063 Iustin Pop
        logger.Info("communication to node %s fine, sw version %s match" %
1496 a8083063 Iustin Pop
                    (node, result))
1497 a8083063 Iustin Pop
      else:
1498 3ecf6786 Iustin Pop
        raise errors.OpExecError("Version mismatch master version %s,"
1499 3ecf6786 Iustin Pop
                                 " node version %s" %
1500 3ecf6786 Iustin Pop
                                 (constants.PROTOCOL_VERSION, result))
1501 a8083063 Iustin Pop
    else:
1502 3ecf6786 Iustin Pop
      raise errors.OpExecError("Cannot get version from the new node")
1503 a8083063 Iustin Pop
1504 a8083063 Iustin Pop
    # setup ssh on node
1505 a8083063 Iustin Pop
    logger.Info("copy ssh key to node %s" % node)
1506 a8083063 Iustin Pop
    keyarray = []
1507 a8083063 Iustin Pop
    keyfiles = ["/etc/ssh/ssh_host_dsa_key", "/etc/ssh/ssh_host_dsa_key.pub",
1508 a8083063 Iustin Pop
                "/etc/ssh/ssh_host_rsa_key", "/etc/ssh/ssh_host_rsa_key.pub",
1509 a8083063 Iustin Pop
                "/root/.ssh/id_dsa", "/root/.ssh/id_dsa.pub"]
1510 a8083063 Iustin Pop
1511 a8083063 Iustin Pop
    for i in keyfiles:
1512 a8083063 Iustin Pop
      f = open(i, 'r')
1513 a8083063 Iustin Pop
      try:
1514 a8083063 Iustin Pop
        keyarray.append(f.read())
1515 a8083063 Iustin Pop
      finally:
1516 a8083063 Iustin Pop
        f.close()
1517 a8083063 Iustin Pop
1518 a8083063 Iustin Pop
    result = rpc.call_node_add(node, keyarray[0], keyarray[1], keyarray[2],
1519 a8083063 Iustin Pop
                               keyarray[3], keyarray[4], keyarray[5])
1520 a8083063 Iustin Pop
1521 a8083063 Iustin Pop
    if not result:
1522 3ecf6786 Iustin Pop
      raise errors.OpExecError("Cannot transfer ssh keys to the new node")
1523 a8083063 Iustin Pop
1524 a8083063 Iustin Pop
    # Add node to our /etc/hosts, and add key to known_hosts
1525 a8083063 Iustin Pop
    _UpdateEtcHosts(new_node.name, new_node.primary_ip)
1526 a8083063 Iustin Pop
    _UpdateKnownHosts(new_node.name, new_node.primary_ip,
1527 a8083063 Iustin Pop
                      self.cfg.GetHostKey())
1528 a8083063 Iustin Pop
1529 a8083063 Iustin Pop
    if new_node.secondary_ip != new_node.primary_ip:
1530 a8083063 Iustin Pop
      result = ssh.SSHCall(node, "root",
1531 a8083063 Iustin Pop
                           "fping -S 127.0.0.1 -q %s" % new_node.secondary_ip)
1532 a8083063 Iustin Pop
      if result.failed:
1533 3ecf6786 Iustin Pop
        raise errors.OpExecError("Node claims it doesn't have the"
1534 3ecf6786 Iustin Pop
                                 " secondary ip you gave (%s).\n"
1535 3ecf6786 Iustin Pop
                                 "Please fix and re-run this command." %
1536 3ecf6786 Iustin Pop
                                 new_node.secondary_ip)
1537 a8083063 Iustin Pop
1538 ff98055b Iustin Pop
    success, msg = ssh.VerifyNodeHostname(node)
1539 ff98055b Iustin Pop
    if not success:
1540 ff98055b Iustin Pop
      raise errors.OpExecError("Node '%s' claims it has a different hostname"
1541 ff98055b Iustin Pop
                               " than the one the resolver gives: %s.\n"
1542 ff98055b Iustin Pop
                               "Please fix and re-run this command." %
1543 ff98055b Iustin Pop
                               (node, msg))
1544 ff98055b Iustin Pop
1545 a8083063 Iustin Pop
    # Distribute updated /etc/hosts and known_hosts to all nodes,
1546 a8083063 Iustin Pop
    # including the node just added
1547 880478f8 Iustin Pop
    myself = self.cfg.GetNodeInfo(self.sstore.GetMasterNode())
1548 a8083063 Iustin Pop
    dist_nodes = self.cfg.GetNodeList() + [node]
1549 a8083063 Iustin Pop
    if myself.name in dist_nodes:
1550 a8083063 Iustin Pop
      dist_nodes.remove(myself.name)
1551 a8083063 Iustin Pop
1552 a8083063 Iustin Pop
    logger.Debug("Copying hosts and known_hosts to all nodes")
1553 82122173 Iustin Pop
    for fname in ("/etc/hosts", constants.SSH_KNOWN_HOSTS_FILE):
1554 a8083063 Iustin Pop
      result = rpc.call_upload_file(dist_nodes, fname)
1555 a8083063 Iustin Pop
      for to_node in dist_nodes:
1556 a8083063 Iustin Pop
        if not result[to_node]:
1557 a8083063 Iustin Pop
          logger.Error("copy of file %s to node %s failed" %
1558 a8083063 Iustin Pop
                       (fname, to_node))
1559 a8083063 Iustin Pop
1560 cb91d46e Iustin Pop
    to_copy = ss.GetFileList()
1561 a8083063 Iustin Pop
    for fname in to_copy:
1562 a8083063 Iustin Pop
      if not ssh.CopyFileToNode(node, fname):
1563 a8083063 Iustin Pop
        logger.Error("could not copy file %s to node %s" % (fname, node))
1564 a8083063 Iustin Pop
1565 a8083063 Iustin Pop
    logger.Info("adding node %s to cluster.conf" % node)
1566 a8083063 Iustin Pop
    self.cfg.AddNode(new_node)
1567 a8083063 Iustin Pop
1568 a8083063 Iustin Pop
1569 a8083063 Iustin Pop
class LUMasterFailover(LogicalUnit):
1570 a8083063 Iustin Pop
  """Failover the master node to the current node.
1571 a8083063 Iustin Pop

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

1574 a8083063 Iustin Pop
  """
1575 a8083063 Iustin Pop
  HPATH = "master-failover"
1576 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_CLUSTER
1577 a8083063 Iustin Pop
  REQ_MASTER = False
1578 a8083063 Iustin Pop
  _OP_REQP = []
1579 a8083063 Iustin Pop
1580 a8083063 Iustin Pop
  def BuildHooksEnv(self):
1581 a8083063 Iustin Pop
    """Build hooks env.
1582 a8083063 Iustin Pop

1583 a8083063 Iustin Pop
    This will run on the new master only in the pre phase, and on all
1584 a8083063 Iustin Pop
    the nodes in the post phase.
1585 a8083063 Iustin Pop

1586 a8083063 Iustin Pop
    """
1587 a8083063 Iustin Pop
    env = {
1588 a8083063 Iustin Pop
      "NEW_MASTER": self.new_master,
1589 a8083063 Iustin Pop
      "OLD_MASTER": self.old_master,
1590 a8083063 Iustin Pop
      }
1591 a8083063 Iustin Pop
    return env, [self.new_master], self.cfg.GetNodeList()
1592 a8083063 Iustin Pop
1593 a8083063 Iustin Pop
  def CheckPrereq(self):
1594 a8083063 Iustin Pop
    """Check prerequisites.
1595 a8083063 Iustin Pop

1596 a8083063 Iustin Pop
    This checks that we are not already the master.
1597 a8083063 Iustin Pop

1598 a8083063 Iustin Pop
    """
1599 89e1fc26 Iustin Pop
    self.new_master = utils.HostInfo().name
1600 880478f8 Iustin Pop
    self.old_master = self.sstore.GetMasterNode()
1601 a8083063 Iustin Pop
1602 a8083063 Iustin Pop
    if self.old_master == self.new_master:
1603 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("This commands must be run on the node"
1604 3ecf6786 Iustin Pop
                                 " where you want the new master to be.\n"
1605 3ecf6786 Iustin Pop
                                 "%s is already the master" %
1606 3ecf6786 Iustin Pop
                                 self.old_master)
1607 a8083063 Iustin Pop
1608 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1609 a8083063 Iustin Pop
    """Failover the master node.
1610 a8083063 Iustin Pop

1611 a8083063 Iustin Pop
    This command, when run on a non-master node, will cause the current
1612 a8083063 Iustin Pop
    master to cease being master, and the non-master to become new
1613 a8083063 Iustin Pop
    master.
1614 a8083063 Iustin Pop

1615 a8083063 Iustin Pop
    """
1616 a8083063 Iustin Pop
    #TODO: do not rely on gethostname returning the FQDN
1617 a8083063 Iustin Pop
    logger.Info("setting master to %s, old master: %s" %
1618 a8083063 Iustin Pop
                (self.new_master, self.old_master))
1619 a8083063 Iustin Pop
1620 a8083063 Iustin Pop
    if not rpc.call_node_stop_master(self.old_master):
1621 a8083063 Iustin Pop
      logger.Error("could disable the master role on the old master"
1622 a8083063 Iustin Pop
                   " %s, please disable manually" % self.old_master)
1623 a8083063 Iustin Pop
1624 880478f8 Iustin Pop
    ss = self.sstore
1625 880478f8 Iustin Pop
    ss.SetKey(ss.SS_MASTER_NODE, self.new_master)
1626 880478f8 Iustin Pop
    if not rpc.call_upload_file(self.cfg.GetNodeList(),
1627 880478f8 Iustin Pop
                                ss.KeyToFilename(ss.SS_MASTER_NODE)):
1628 880478f8 Iustin Pop
      logger.Error("could not distribute the new simple store master file"
1629 880478f8 Iustin Pop
                   " to the other nodes, please check.")
1630 880478f8 Iustin Pop
1631 a8083063 Iustin Pop
    if not rpc.call_node_start_master(self.new_master):
1632 a8083063 Iustin Pop
      logger.Error("could not start the master role on the new master"
1633 a8083063 Iustin Pop
                   " %s, please check" % self.new_master)
1634 880478f8 Iustin Pop
      feedback_fn("Error in activating the master IP on the new master,\n"
1635 880478f8 Iustin Pop
                  "please fix manually.")
1636 a8083063 Iustin Pop
1637 a8083063 Iustin Pop
1638 a8083063 Iustin Pop
1639 a8083063 Iustin Pop
class LUQueryClusterInfo(NoHooksLU):
1640 a8083063 Iustin Pop
  """Query cluster configuration.
1641 a8083063 Iustin Pop

1642 a8083063 Iustin Pop
  """
1643 a8083063 Iustin Pop
  _OP_REQP = []
1644 59322403 Iustin Pop
  REQ_MASTER = False
1645 a8083063 Iustin Pop
1646 a8083063 Iustin Pop
  def CheckPrereq(self):
1647 a8083063 Iustin Pop
    """No prerequsites needed for this LU.
1648 a8083063 Iustin Pop

1649 a8083063 Iustin Pop
    """
1650 a8083063 Iustin Pop
    pass
1651 a8083063 Iustin Pop
1652 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1653 a8083063 Iustin Pop
    """Return cluster config.
1654 a8083063 Iustin Pop

1655 a8083063 Iustin Pop
    """
1656 a8083063 Iustin Pop
    result = {
1657 5fcdc80d Iustin Pop
      "name": self.sstore.GetClusterName(),
1658 a8083063 Iustin Pop
      "software_version": constants.RELEASE_VERSION,
1659 a8083063 Iustin Pop
      "protocol_version": constants.PROTOCOL_VERSION,
1660 a8083063 Iustin Pop
      "config_version": constants.CONFIG_VERSION,
1661 a8083063 Iustin Pop
      "os_api_version": constants.OS_API_VERSION,
1662 a8083063 Iustin Pop
      "export_version": constants.EXPORT_VERSION,
1663 880478f8 Iustin Pop
      "master": self.sstore.GetMasterNode(),
1664 a8083063 Iustin Pop
      "architecture": (platform.architecture()[0], platform.machine()),
1665 a8083063 Iustin Pop
      }
1666 a8083063 Iustin Pop
1667 a8083063 Iustin Pop
    return result
1668 a8083063 Iustin Pop
1669 a8083063 Iustin Pop
1670 a8083063 Iustin Pop
class LUClusterCopyFile(NoHooksLU):
1671 a8083063 Iustin Pop
  """Copy file to cluster.
1672 a8083063 Iustin Pop

1673 a8083063 Iustin Pop
  """
1674 a8083063 Iustin Pop
  _OP_REQP = ["nodes", "filename"]
1675 a8083063 Iustin Pop
1676 a8083063 Iustin Pop
  def CheckPrereq(self):
1677 a8083063 Iustin Pop
    """Check prerequisites.
1678 a8083063 Iustin Pop

1679 a8083063 Iustin Pop
    It should check that the named file exists and that the given list
1680 a8083063 Iustin Pop
    of nodes is valid.
1681 a8083063 Iustin Pop

1682 a8083063 Iustin Pop
    """
1683 a8083063 Iustin Pop
    if not os.path.exists(self.op.filename):
1684 a8083063 Iustin Pop
      raise errors.OpPrereqError("No such filename '%s'" % self.op.filename)
1685 dcb93971 Michael Hanselmann
1686 dcb93971 Michael Hanselmann
    self.nodes = _GetWantedNodes(self, self.op.nodes)
1687 a8083063 Iustin Pop
1688 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1689 a8083063 Iustin Pop
    """Copy a file from master to some nodes.
1690 a8083063 Iustin Pop

1691 a8083063 Iustin Pop
    Args:
1692 a8083063 Iustin Pop
      opts - class with options as members
1693 a8083063 Iustin Pop
      args - list containing a single element, the file name
1694 a8083063 Iustin Pop
    Opts used:
1695 a8083063 Iustin Pop
      nodes - list containing the name of target nodes; if empty, all nodes
1696 a8083063 Iustin Pop

1697 a8083063 Iustin Pop
    """
1698 a8083063 Iustin Pop
    filename = self.op.filename
1699 a8083063 Iustin Pop
1700 89e1fc26 Iustin Pop
    myname = utils.HostInfo().name
1701 a8083063 Iustin Pop
1702 a7ba5e53 Iustin Pop
    for node in self.nodes:
1703 a8083063 Iustin Pop
      if node == myname:
1704 a8083063 Iustin Pop
        continue
1705 a8083063 Iustin Pop
      if not ssh.CopyFileToNode(node, filename):
1706 a8083063 Iustin Pop
        logger.Error("Copy of file %s to node %s failed" % (filename, node))
1707 a8083063 Iustin Pop
1708 a8083063 Iustin Pop
1709 a8083063 Iustin Pop
class LUDumpClusterConfig(NoHooksLU):
1710 a8083063 Iustin Pop
  """Return a text-representation of the cluster-config.
1711 a8083063 Iustin Pop

1712 a8083063 Iustin Pop
  """
1713 a8083063 Iustin Pop
  _OP_REQP = []
1714 a8083063 Iustin Pop
1715 a8083063 Iustin Pop
  def CheckPrereq(self):
1716 a8083063 Iustin Pop
    """No prerequisites.
1717 a8083063 Iustin Pop

1718 a8083063 Iustin Pop
    """
1719 a8083063 Iustin Pop
    pass
1720 a8083063 Iustin Pop
1721 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1722 a8083063 Iustin Pop
    """Dump a representation of the cluster config to the standard output.
1723 a8083063 Iustin Pop

1724 a8083063 Iustin Pop
    """
1725 a8083063 Iustin Pop
    return self.cfg.DumpConfig()
1726 a8083063 Iustin Pop
1727 a8083063 Iustin Pop
1728 a8083063 Iustin Pop
class LURunClusterCommand(NoHooksLU):
1729 a8083063 Iustin Pop
  """Run a command on some nodes.
1730 a8083063 Iustin Pop

1731 a8083063 Iustin Pop
  """
1732 a8083063 Iustin Pop
  _OP_REQP = ["command", "nodes"]
1733 a8083063 Iustin Pop
1734 a8083063 Iustin Pop
  def CheckPrereq(self):
1735 a8083063 Iustin Pop
    """Check prerequisites.
1736 a8083063 Iustin Pop

1737 a8083063 Iustin Pop
    It checks that the given list of nodes is valid.
1738 a8083063 Iustin Pop

1739 a8083063 Iustin Pop
    """
1740 dcb93971 Michael Hanselmann
    self.nodes = _GetWantedNodes(self, self.op.nodes)
1741 a8083063 Iustin Pop
1742 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1743 a8083063 Iustin Pop
    """Run a command on some nodes.
1744 a8083063 Iustin Pop

1745 a8083063 Iustin Pop
    """
1746 a8083063 Iustin Pop
    data = []
1747 a8083063 Iustin Pop
    for node in self.nodes:
1748 a7ba5e53 Iustin Pop
      result = ssh.SSHCall(node, "root", self.op.command)
1749 a7ba5e53 Iustin Pop
      data.append((node, result.output, result.exit_code))
1750 a8083063 Iustin Pop
1751 a8083063 Iustin Pop
    return data
1752 a8083063 Iustin Pop
1753 a8083063 Iustin Pop
1754 a8083063 Iustin Pop
class LUActivateInstanceDisks(NoHooksLU):
1755 a8083063 Iustin Pop
  """Bring up an instance's disks.
1756 a8083063 Iustin Pop

1757 a8083063 Iustin Pop
  """
1758 a8083063 Iustin Pop
  _OP_REQP = ["instance_name"]
1759 a8083063 Iustin Pop
1760 a8083063 Iustin Pop
  def CheckPrereq(self):
1761 a8083063 Iustin Pop
    """Check prerequisites.
1762 a8083063 Iustin Pop

1763 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
1764 a8083063 Iustin Pop

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

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

1788 a8083063 Iustin Pop
  This sets up the block devices on all nodes.
1789 a8083063 Iustin Pop

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

1795 a8083063 Iustin Pop
  Returns:
1796 a8083063 Iustin Pop
    false if the operation failed
1797 a8083063 Iustin Pop
    list of (host, instance_visible_name, node_visible_name) if the operation
1798 a8083063 Iustin Pop
         suceeded with the mapping from node devices to instance devices
1799 a8083063 Iustin Pop
  """
1800 a8083063 Iustin Pop
  device_info = []
1801 a8083063 Iustin Pop
  disks_ok = True
1802 a8083063 Iustin Pop
  for inst_disk in instance.disks:
1803 a8083063 Iustin Pop
    master_result = None
1804 a8083063 Iustin Pop
    for node, node_disk in inst_disk.ComputeNodeTree(instance.primary_node):
1805 a8083063 Iustin Pop
      cfg.SetDiskID(node_disk, node)
1806 a8083063 Iustin Pop
      is_primary = node == instance.primary_node
1807 a8083063 Iustin Pop
      result = rpc.call_blockdev_assemble(node, node_disk, is_primary)
1808 a8083063 Iustin Pop
      if not result:
1809 a8083063 Iustin Pop
        logger.Error("could not prepare block device %s on node %s (is_pri"
1810 a8083063 Iustin Pop
                     "mary=%s)" % (inst_disk.iv_name, node, is_primary))
1811 a8083063 Iustin Pop
        if is_primary or not ignore_secondaries:
1812 a8083063 Iustin Pop
          disks_ok = False
1813 a8083063 Iustin Pop
      if is_primary:
1814 a8083063 Iustin Pop
        master_result = result
1815 a8083063 Iustin Pop
    device_info.append((instance.primary_node, inst_disk.iv_name,
1816 a8083063 Iustin Pop
                        master_result))
1817 a8083063 Iustin Pop
1818 a8083063 Iustin Pop
  return disks_ok, device_info
1819 a8083063 Iustin Pop
1820 a8083063 Iustin Pop
1821 fe7b0351 Michael Hanselmann
def _StartInstanceDisks(cfg, instance, force):
1822 3ecf6786 Iustin Pop
  """Start the disks of an instance.
1823 3ecf6786 Iustin Pop

1824 3ecf6786 Iustin Pop
  """
1825 fe7b0351 Michael Hanselmann
  disks_ok, dummy = _AssembleInstanceDisks(instance, cfg,
1826 fe7b0351 Michael Hanselmann
                                           ignore_secondaries=force)
1827 fe7b0351 Michael Hanselmann
  if not disks_ok:
1828 fe7b0351 Michael Hanselmann
    _ShutdownInstanceDisks(instance, cfg)
1829 fe7b0351 Michael Hanselmann
    if force is not None and not force:
1830 fe7b0351 Michael Hanselmann
      logger.Error("If the message above refers to a secondary node,"
1831 fe7b0351 Michael Hanselmann
                   " you can retry the operation using '--force'.")
1832 3ecf6786 Iustin Pop
    raise errors.OpExecError("Disk consistency error")
1833 fe7b0351 Michael Hanselmann
1834 fe7b0351 Michael Hanselmann
1835 a8083063 Iustin Pop
class LUDeactivateInstanceDisks(NoHooksLU):
1836 a8083063 Iustin Pop
  """Shutdown an instance's disks.
1837 a8083063 Iustin Pop

1838 a8083063 Iustin Pop
  """
1839 a8083063 Iustin Pop
  _OP_REQP = ["instance_name"]
1840 a8083063 Iustin Pop
1841 a8083063 Iustin Pop
  def CheckPrereq(self):
1842 a8083063 Iustin Pop
    """Check prerequisites.
1843 a8083063 Iustin Pop

1844 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
1845 a8083063 Iustin Pop

1846 a8083063 Iustin Pop
    """
1847 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
1848 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
1849 a8083063 Iustin Pop
    if instance is None:
1850 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
1851 3ecf6786 Iustin Pop
                                 self.op.instance_name)
1852 a8083063 Iustin Pop
    self.instance = instance
1853 a8083063 Iustin Pop
1854 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1855 a8083063 Iustin Pop
    """Deactivate the disks
1856 a8083063 Iustin Pop

1857 a8083063 Iustin Pop
    """
1858 a8083063 Iustin Pop
    instance = self.instance
1859 a8083063 Iustin Pop
    ins_l = rpc.call_instance_list([instance.primary_node])
1860 a8083063 Iustin Pop
    ins_l = ins_l[instance.primary_node]
1861 a8083063 Iustin Pop
    if not type(ins_l) is list:
1862 3ecf6786 Iustin Pop
      raise errors.OpExecError("Can't contact node '%s'" %
1863 3ecf6786 Iustin Pop
                               instance.primary_node)
1864 a8083063 Iustin Pop
1865 a8083063 Iustin Pop
    if self.instance.name in ins_l:
1866 3ecf6786 Iustin Pop
      raise errors.OpExecError("Instance is running, can't shutdown"
1867 3ecf6786 Iustin Pop
                               " block devices.")
1868 a8083063 Iustin Pop
1869 a8083063 Iustin Pop
    _ShutdownInstanceDisks(instance, self.cfg)
1870 a8083063 Iustin Pop
1871 a8083063 Iustin Pop
1872 a8083063 Iustin Pop
def _ShutdownInstanceDisks(instance, cfg, ignore_primary=False):
1873 a8083063 Iustin Pop
  """Shutdown block devices of an instance.
1874 a8083063 Iustin Pop

1875 a8083063 Iustin Pop
  This does the shutdown on all nodes of the instance.
1876 a8083063 Iustin Pop

1877 a8083063 Iustin Pop
  If the ignore_primary is false, errors on the primary node are
1878 a8083063 Iustin Pop
  ignored.
1879 a8083063 Iustin Pop

1880 a8083063 Iustin Pop
  """
1881 a8083063 Iustin Pop
  result = True
1882 a8083063 Iustin Pop
  for disk in instance.disks:
1883 a8083063 Iustin Pop
    for node, top_disk in disk.ComputeNodeTree(instance.primary_node):
1884 a8083063 Iustin Pop
      cfg.SetDiskID(top_disk, node)
1885 a8083063 Iustin Pop
      if not rpc.call_blockdev_shutdown(node, top_disk):
1886 a8083063 Iustin Pop
        logger.Error("could not shutdown block device %s on node %s" %
1887 a8083063 Iustin Pop
                     (disk.iv_name, node))
1888 a8083063 Iustin Pop
        if not ignore_primary or node != instance.primary_node:
1889 a8083063 Iustin Pop
          result = False
1890 a8083063 Iustin Pop
  return result
1891 a8083063 Iustin Pop
1892 a8083063 Iustin Pop
1893 a8083063 Iustin Pop
class LUStartupInstance(LogicalUnit):
1894 a8083063 Iustin Pop
  """Starts an instance.
1895 a8083063 Iustin Pop

1896 a8083063 Iustin Pop
  """
1897 a8083063 Iustin Pop
  HPATH = "instance-start"
1898 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
1899 a8083063 Iustin Pop
  _OP_REQP = ["instance_name", "force"]
1900 a8083063 Iustin Pop
1901 a8083063 Iustin Pop
  def BuildHooksEnv(self):
1902 a8083063 Iustin Pop
    """Build hooks env.
1903 a8083063 Iustin Pop

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

1906 a8083063 Iustin Pop
    """
1907 a8083063 Iustin Pop
    env = {
1908 a8083063 Iustin Pop
      "FORCE": self.op.force,
1909 a8083063 Iustin Pop
      }
1910 396e1b78 Michael Hanselmann
    env.update(_BuildInstanceHookEnvByObject(self.instance))
1911 880478f8 Iustin Pop
    nl = ([self.sstore.GetMasterNode(), self.instance.primary_node] +
1912 a8083063 Iustin Pop
          list(self.instance.secondary_nodes))
1913 a8083063 Iustin Pop
    return env, nl, nl
1914 a8083063 Iustin Pop
1915 a8083063 Iustin Pop
  def CheckPrereq(self):
1916 a8083063 Iustin Pop
    """Check prerequisites.
1917 a8083063 Iustin Pop

1918 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
1919 a8083063 Iustin Pop

1920 a8083063 Iustin Pop
    """
1921 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
1922 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
1923 a8083063 Iustin Pop
    if instance is None:
1924 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
1925 3ecf6786 Iustin Pop
                                 self.op.instance_name)
1926 a8083063 Iustin Pop
1927 a8083063 Iustin Pop
    # check bridges existance
1928 a8083063 Iustin Pop
    brlist = [nic.bridge for nic in instance.nics]
1929 a8083063 Iustin Pop
    if not rpc.call_bridges_exist(instance.primary_node, brlist):
1930 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("one or more target bridges %s does not"
1931 3ecf6786 Iustin Pop
                                 " exist on destination node '%s'" %
1932 3ecf6786 Iustin Pop
                                 (brlist, instance.primary_node))
1933 a8083063 Iustin Pop
1934 a8083063 Iustin Pop
    self.instance = instance
1935 a8083063 Iustin Pop
    self.op.instance_name = instance.name
1936 a8083063 Iustin Pop
1937 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1938 a8083063 Iustin Pop
    """Start the instance.
1939 a8083063 Iustin Pop

1940 a8083063 Iustin Pop
    """
1941 a8083063 Iustin Pop
    instance = self.instance
1942 a8083063 Iustin Pop
    force = self.op.force
1943 a8083063 Iustin Pop
    extra_args = getattr(self.op, "extra_args", "")
1944 a8083063 Iustin Pop
1945 a8083063 Iustin Pop
    node_current = instance.primary_node
1946 a8083063 Iustin Pop
1947 a8083063 Iustin Pop
    nodeinfo = rpc.call_node_info([node_current], self.cfg.GetVGName())
1948 a8083063 Iustin Pop
    if not nodeinfo:
1949 3ecf6786 Iustin Pop
      raise errors.OpExecError("Could not contact node %s for infos" %
1950 3ecf6786 Iustin Pop
                               (node_current))
1951 a8083063 Iustin Pop
1952 a8083063 Iustin Pop
    freememory = nodeinfo[node_current]['memory_free']
1953 a8083063 Iustin Pop
    memory = instance.memory
1954 a8083063 Iustin Pop
    if memory > freememory:
1955 3ecf6786 Iustin Pop
      raise errors.OpExecError("Not enough memory to start instance"
1956 3ecf6786 Iustin Pop
                               " %s on node %s"
1957 3ecf6786 Iustin Pop
                               " needed %s MiB, available %s MiB" %
1958 3ecf6786 Iustin Pop
                               (instance.name, node_current, memory,
1959 3ecf6786 Iustin Pop
                                freememory))
1960 a8083063 Iustin Pop
1961 fe7b0351 Michael Hanselmann
    _StartInstanceDisks(self.cfg, instance, force)
1962 a8083063 Iustin Pop
1963 a8083063 Iustin Pop
    if not rpc.call_instance_start(node_current, instance, extra_args):
1964 a8083063 Iustin Pop
      _ShutdownInstanceDisks(instance, self.cfg)
1965 3ecf6786 Iustin Pop
      raise errors.OpExecError("Could not start instance")
1966 a8083063 Iustin Pop
1967 a8083063 Iustin Pop
    self.cfg.MarkInstanceUp(instance.name)
1968 a8083063 Iustin Pop
1969 a8083063 Iustin Pop
1970 a8083063 Iustin Pop
class LUShutdownInstance(LogicalUnit):
1971 a8083063 Iustin Pop
  """Shutdown an instance.
1972 a8083063 Iustin Pop

1973 a8083063 Iustin Pop
  """
1974 a8083063 Iustin Pop
  HPATH = "instance-stop"
1975 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
1976 a8083063 Iustin Pop
  _OP_REQP = ["instance_name"]
1977 a8083063 Iustin Pop
1978 a8083063 Iustin Pop
  def BuildHooksEnv(self):
1979 a8083063 Iustin Pop
    """Build hooks env.
1980 a8083063 Iustin Pop

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

1983 a8083063 Iustin Pop
    """
1984 396e1b78 Michael Hanselmann
    env = _BuildInstanceHookEnvByObject(self.instance)
1985 880478f8 Iustin Pop
    nl = ([self.sstore.GetMasterNode(), self.instance.primary_node] +
1986 a8083063 Iustin Pop
          list(self.instance.secondary_nodes))
1987 a8083063 Iustin Pop
    return env, nl, nl
1988 a8083063 Iustin Pop
1989 a8083063 Iustin Pop
  def CheckPrereq(self):
1990 a8083063 Iustin Pop
    """Check prerequisites.
1991 a8083063 Iustin Pop

1992 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
1993 a8083063 Iustin Pop

1994 a8083063 Iustin Pop
    """
1995 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
1996 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
1997 a8083063 Iustin Pop
    if instance is None:
1998 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
1999 3ecf6786 Iustin Pop
                                 self.op.instance_name)
2000 a8083063 Iustin Pop
    self.instance = instance
2001 a8083063 Iustin Pop
2002 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
2003 a8083063 Iustin Pop
    """Shutdown the instance.
2004 a8083063 Iustin Pop

2005 a8083063 Iustin Pop
    """
2006 a8083063 Iustin Pop
    instance = self.instance
2007 a8083063 Iustin Pop
    node_current = instance.primary_node
2008 a8083063 Iustin Pop
    if not rpc.call_instance_shutdown(node_current, instance):
2009 a8083063 Iustin Pop
      logger.Error("could not shutdown instance")
2010 a8083063 Iustin Pop
2011 a8083063 Iustin Pop
    self.cfg.MarkInstanceDown(instance.name)
2012 a8083063 Iustin Pop
    _ShutdownInstanceDisks(instance, self.cfg)
2013 a8083063 Iustin Pop
2014 a8083063 Iustin Pop
2015 fe7b0351 Michael Hanselmann
class LUReinstallInstance(LogicalUnit):
2016 fe7b0351 Michael Hanselmann
  """Reinstall an instance.
2017 fe7b0351 Michael Hanselmann

2018 fe7b0351 Michael Hanselmann
  """
2019 fe7b0351 Michael Hanselmann
  HPATH = "instance-reinstall"
2020 fe7b0351 Michael Hanselmann
  HTYPE = constants.HTYPE_INSTANCE
2021 fe7b0351 Michael Hanselmann
  _OP_REQP = ["instance_name"]
2022 fe7b0351 Michael Hanselmann
2023 fe7b0351 Michael Hanselmann
  def BuildHooksEnv(self):
2024 fe7b0351 Michael Hanselmann
    """Build hooks env.
2025 fe7b0351 Michael Hanselmann

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

2028 fe7b0351 Michael Hanselmann
    """
2029 396e1b78 Michael Hanselmann
    env = _BuildInstanceHookEnvByObject(self.instance)
2030 fe7b0351 Michael Hanselmann
    nl = ([self.sstore.GetMasterNode(), self.instance.primary_node] +
2031 fe7b0351 Michael Hanselmann
          list(self.instance.secondary_nodes))
2032 fe7b0351 Michael Hanselmann
    return env, nl, nl
2033 fe7b0351 Michael Hanselmann
2034 fe7b0351 Michael Hanselmann
  def CheckPrereq(self):
2035 fe7b0351 Michael Hanselmann
    """Check prerequisites.
2036 fe7b0351 Michael Hanselmann

2037 fe7b0351 Michael Hanselmann
    This checks that the instance is in the cluster and is not running.
2038 fe7b0351 Michael Hanselmann

2039 fe7b0351 Michael Hanselmann
    """
2040 fe7b0351 Michael Hanselmann
    instance = self.cfg.GetInstanceInfo(
2041 fe7b0351 Michael Hanselmann
      self.cfg.ExpandInstanceName(self.op.instance_name))
2042 fe7b0351 Michael Hanselmann
    if instance is None:
2043 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
2044 3ecf6786 Iustin Pop
                                 self.op.instance_name)
2045 fe7b0351 Michael Hanselmann
    if instance.disk_template == constants.DT_DISKLESS:
2046 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' has no disks" %
2047 3ecf6786 Iustin Pop
                                 self.op.instance_name)
2048 fe7b0351 Michael Hanselmann
    if instance.status != "down":
2049 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' is marked to be up" %
2050 3ecf6786 Iustin Pop
                                 self.op.instance_name)
2051 fe7b0351 Michael Hanselmann
    remote_info = rpc.call_instance_info(instance.primary_node, instance.name)
2052 fe7b0351 Michael Hanselmann
    if remote_info:
2053 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' is running on the node %s" %
2054 3ecf6786 Iustin Pop
                                 (self.op.instance_name,
2055 3ecf6786 Iustin Pop
                                  instance.primary_node))
2056 d0834de3 Michael Hanselmann
2057 d0834de3 Michael Hanselmann
    self.op.os_type = getattr(self.op, "os_type", None)
2058 d0834de3 Michael Hanselmann
    if self.op.os_type is not None:
2059 d0834de3 Michael Hanselmann
      # OS verification
2060 d0834de3 Michael Hanselmann
      pnode = self.cfg.GetNodeInfo(
2061 d0834de3 Michael Hanselmann
        self.cfg.ExpandNodeName(instance.primary_node))
2062 d0834de3 Michael Hanselmann
      if pnode is None:
2063 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Primary node '%s' is unknown" %
2064 3ecf6786 Iustin Pop
                                   self.op.pnode)
2065 d0834de3 Michael Hanselmann
      os_obj = rpc.call_os_get([pnode.name], self.op.os_type)[pnode.name]
2066 d0834de3 Michael Hanselmann
      if not isinstance(os_obj, objects.OS):
2067 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("OS '%s' not in supported OS list for"
2068 3ecf6786 Iustin Pop
                                   " primary node"  % self.op.os_type)
2069 d0834de3 Michael Hanselmann
2070 fe7b0351 Michael Hanselmann
    self.instance = instance
2071 fe7b0351 Michael Hanselmann
2072 fe7b0351 Michael Hanselmann
  def Exec(self, feedback_fn):
2073 fe7b0351 Michael Hanselmann
    """Reinstall the instance.
2074 fe7b0351 Michael Hanselmann

2075 fe7b0351 Michael Hanselmann
    """
2076 fe7b0351 Michael Hanselmann
    inst = self.instance
2077 fe7b0351 Michael Hanselmann
2078 d0834de3 Michael Hanselmann
    if self.op.os_type is not None:
2079 d0834de3 Michael Hanselmann
      feedback_fn("Changing OS to '%s'..." % self.op.os_type)
2080 d0834de3 Michael Hanselmann
      inst.os = self.op.os_type
2081 d0834de3 Michael Hanselmann
      self.cfg.AddInstance(inst)
2082 d0834de3 Michael Hanselmann
2083 fe7b0351 Michael Hanselmann
    _StartInstanceDisks(self.cfg, inst, None)
2084 fe7b0351 Michael Hanselmann
    try:
2085 fe7b0351 Michael Hanselmann
      feedback_fn("Running the instance OS create scripts...")
2086 fe7b0351 Michael Hanselmann
      if not rpc.call_instance_os_add(inst.primary_node, inst, "sda", "sdb"):
2087 3ecf6786 Iustin Pop
        raise errors.OpExecError("Could not install OS for instance %s "
2088 3ecf6786 Iustin Pop
                                 "on node %s" %
2089 3ecf6786 Iustin Pop
                                 (inst.name, inst.primary_node))
2090 fe7b0351 Michael Hanselmann
    finally:
2091 fe7b0351 Michael Hanselmann
      _ShutdownInstanceDisks(inst, self.cfg)
2092 fe7b0351 Michael Hanselmann
2093 fe7b0351 Michael Hanselmann
2094 decd5f45 Iustin Pop
class LURenameInstance(LogicalUnit):
2095 decd5f45 Iustin Pop
  """Rename an instance.
2096 decd5f45 Iustin Pop

2097 decd5f45 Iustin Pop
  """
2098 decd5f45 Iustin Pop
  HPATH = "instance-rename"
2099 decd5f45 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
2100 decd5f45 Iustin Pop
  _OP_REQP = ["instance_name", "new_name"]
2101 decd5f45 Iustin Pop
2102 decd5f45 Iustin Pop
  def BuildHooksEnv(self):
2103 decd5f45 Iustin Pop
    """Build hooks env.
2104 decd5f45 Iustin Pop

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

2107 decd5f45 Iustin Pop
    """
2108 decd5f45 Iustin Pop
    env = _BuildInstanceHookEnvByObject(self.instance)
2109 decd5f45 Iustin Pop
    env["INSTANCE_NEW_NAME"] = self.op.new_name
2110 decd5f45 Iustin Pop
    nl = ([self.sstore.GetMasterNode(), self.instance.primary_node] +
2111 decd5f45 Iustin Pop
          list(self.instance.secondary_nodes))
2112 decd5f45 Iustin Pop
    return env, nl, nl
2113 decd5f45 Iustin Pop
2114 decd5f45 Iustin Pop
  def CheckPrereq(self):
2115 decd5f45 Iustin Pop
    """Check prerequisites.
2116 decd5f45 Iustin Pop

2117 decd5f45 Iustin Pop
    This checks that the instance is in the cluster and is not running.
2118 decd5f45 Iustin Pop

2119 decd5f45 Iustin Pop
    """
2120 decd5f45 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
2121 decd5f45 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
2122 decd5f45 Iustin Pop
    if instance is None:
2123 decd5f45 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
2124 decd5f45 Iustin Pop
                                 self.op.instance_name)
2125 decd5f45 Iustin Pop
    if instance.status != "down":
2126 decd5f45 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' is marked to be up" %
2127 decd5f45 Iustin Pop
                                 self.op.instance_name)
2128 decd5f45 Iustin Pop
    remote_info = rpc.call_instance_info(instance.primary_node, instance.name)
2129 decd5f45 Iustin Pop
    if remote_info:
2130 decd5f45 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' is running on the node %s" %
2131 decd5f45 Iustin Pop
                                 (self.op.instance_name,
2132 decd5f45 Iustin Pop
                                  instance.primary_node))
2133 decd5f45 Iustin Pop
    self.instance = instance
2134 decd5f45 Iustin Pop
2135 decd5f45 Iustin Pop
    # new name verification
2136 89e1fc26 Iustin Pop
    name_info = utils.HostInfo(self.op.new_name)
2137 decd5f45 Iustin Pop
2138 89e1fc26 Iustin Pop
    self.op.new_name = new_name = name_info.name
2139 decd5f45 Iustin Pop
    if not getattr(self.op, "ignore_ip", False):
2140 89e1fc26 Iustin Pop
      command = ["fping", "-q", name_info.ip]
2141 decd5f45 Iustin Pop
      result = utils.RunCmd(command)
2142 decd5f45 Iustin Pop
      if not result.failed:
2143 decd5f45 Iustin Pop
        raise errors.OpPrereqError("IP %s of instance %s already in use" %
2144 89e1fc26 Iustin Pop
                                   (name_info.ip, new_name))
2145 decd5f45 Iustin Pop
2146 decd5f45 Iustin Pop
2147 decd5f45 Iustin Pop
  def Exec(self, feedback_fn):
2148 decd5f45 Iustin Pop
    """Reinstall the instance.
2149 decd5f45 Iustin Pop

2150 decd5f45 Iustin Pop
    """
2151 decd5f45 Iustin Pop
    inst = self.instance
2152 decd5f45 Iustin Pop
    old_name = inst.name
2153 decd5f45 Iustin Pop
2154 decd5f45 Iustin Pop
    self.cfg.RenameInstance(inst.name, self.op.new_name)
2155 decd5f45 Iustin Pop
2156 decd5f45 Iustin Pop
    # re-read the instance from the configuration after rename
2157 decd5f45 Iustin Pop
    inst = self.cfg.GetInstanceInfo(self.op.new_name)
2158 decd5f45 Iustin Pop
2159 decd5f45 Iustin Pop
    _StartInstanceDisks(self.cfg, inst, None)
2160 decd5f45 Iustin Pop
    try:
2161 decd5f45 Iustin Pop
      if not rpc.call_instance_run_rename(inst.primary_node, inst, old_name,
2162 decd5f45 Iustin Pop
                                          "sda", "sdb"):
2163 decd5f45 Iustin Pop
        msg = ("Could run OS rename script for instance %s\n"
2164 decd5f45 Iustin Pop
               "on node %s\n"
2165 decd5f45 Iustin Pop
               "(but the instance has been renamed in Ganeti)" %
2166 decd5f45 Iustin Pop
               (inst.name, inst.primary_node))
2167 decd5f45 Iustin Pop
        logger.Error(msg)
2168 decd5f45 Iustin Pop
    finally:
2169 decd5f45 Iustin Pop
      _ShutdownInstanceDisks(inst, self.cfg)
2170 decd5f45 Iustin Pop
2171 decd5f45 Iustin Pop
2172 a8083063 Iustin Pop
class LURemoveInstance(LogicalUnit):
2173 a8083063 Iustin Pop
  """Remove an instance.
2174 a8083063 Iustin Pop

2175 a8083063 Iustin Pop
  """
2176 a8083063 Iustin Pop
  HPATH = "instance-remove"
2177 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
2178 a8083063 Iustin Pop
  _OP_REQP = ["instance_name"]
2179 a8083063 Iustin Pop
2180 a8083063 Iustin Pop
  def BuildHooksEnv(self):
2181 a8083063 Iustin Pop
    """Build hooks env.
2182 a8083063 Iustin Pop

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

2185 a8083063 Iustin Pop
    """
2186 396e1b78 Michael Hanselmann
    env = _BuildInstanceHookEnvByObject(self.instance)
2187 880478f8 Iustin Pop
    nl = ([self.sstore.GetMasterNode(), self.instance.primary_node] +
2188 a8083063 Iustin Pop
          list(self.instance.secondary_nodes))
2189 a8083063 Iustin Pop
    return env, nl, nl
2190 a8083063 Iustin Pop
2191 a8083063 Iustin Pop
  def CheckPrereq(self):
2192 a8083063 Iustin Pop
    """Check prerequisites.
2193 a8083063 Iustin Pop

2194 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
2195 a8083063 Iustin Pop

2196 a8083063 Iustin Pop
    """
2197 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
2198 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
2199 a8083063 Iustin Pop
    if instance is None:
2200 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
2201 3ecf6786 Iustin Pop
                                 self.op.instance_name)
2202 a8083063 Iustin Pop
    self.instance = instance
2203 a8083063 Iustin Pop
2204 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
2205 a8083063 Iustin Pop
    """Remove the instance.
2206 a8083063 Iustin Pop

2207 a8083063 Iustin Pop
    """
2208 a8083063 Iustin Pop
    instance = self.instance
2209 a8083063 Iustin Pop
    logger.Info("shutting down instance %s on node %s" %
2210 a8083063 Iustin Pop
                (instance.name, instance.primary_node))
2211 a8083063 Iustin Pop
2212 a8083063 Iustin Pop
    if not rpc.call_instance_shutdown(instance.primary_node, instance):
2213 3ecf6786 Iustin Pop
      raise errors.OpExecError("Could not shutdown instance %s on node %s" %
2214 3ecf6786 Iustin Pop
                               (instance.name, instance.primary_node))
2215 a8083063 Iustin Pop
2216 a8083063 Iustin Pop
    logger.Info("removing block devices for instance %s" % instance.name)
2217 a8083063 Iustin Pop
2218 a8083063 Iustin Pop
    _RemoveDisks(instance, self.cfg)
2219 a8083063 Iustin Pop
2220 a8083063 Iustin Pop
    logger.Info("removing instance %s out of cluster config" % instance.name)
2221 a8083063 Iustin Pop
2222 a8083063 Iustin Pop
    self.cfg.RemoveInstance(instance.name)
2223 a8083063 Iustin Pop
2224 a8083063 Iustin Pop
2225 a8083063 Iustin Pop
class LUQueryInstances(NoHooksLU):
2226 a8083063 Iustin Pop
  """Logical unit for querying instances.
2227 a8083063 Iustin Pop

2228 a8083063 Iustin Pop
  """
2229 069dcc86 Iustin Pop
  _OP_REQP = ["output_fields", "names"]
2230 a8083063 Iustin Pop
2231 a8083063 Iustin Pop
  def CheckPrereq(self):
2232 a8083063 Iustin Pop
    """Check prerequisites.
2233 a8083063 Iustin Pop

2234 a8083063 Iustin Pop
    This checks that the fields required are valid output fields.
2235 a8083063 Iustin Pop

2236 a8083063 Iustin Pop
    """
2237 a8083063 Iustin Pop
    self.dynamic_fields = frozenset(["oper_state", "oper_ram"])
2238 dcb93971 Michael Hanselmann
    _CheckOutputFields(static=["name", "os", "pnode", "snodes",
2239 dcb93971 Michael Hanselmann
                               "admin_state", "admin_ram",
2240 644eeef9 Iustin Pop
                               "disk_template", "ip", "mac", "bridge",
2241 644eeef9 Iustin Pop
                               "sda_size", "sdb_size"],
2242 dcb93971 Michael Hanselmann
                       dynamic=self.dynamic_fields,
2243 dcb93971 Michael Hanselmann
                       selected=self.op.output_fields)
2244 a8083063 Iustin Pop
2245 069dcc86 Iustin Pop
    self.wanted = _GetWantedInstances(self, self.op.names)
2246 069dcc86 Iustin Pop
2247 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
2248 a8083063 Iustin Pop
    """Computes the list of nodes and their attributes.
2249 a8083063 Iustin Pop

2250 a8083063 Iustin Pop
    """
2251 069dcc86 Iustin Pop
    instance_names = self.wanted
2252 a8083063 Iustin Pop
    instance_list = [self.cfg.GetInstanceInfo(iname) for iname
2253 a8083063 Iustin Pop
                     in instance_names]
2254 a8083063 Iustin Pop
2255 a8083063 Iustin Pop
    # begin data gathering
2256 a8083063 Iustin Pop
2257 a8083063 Iustin Pop
    nodes = frozenset([inst.primary_node for inst in instance_list])
2258 a8083063 Iustin Pop
2259 a8083063 Iustin Pop
    bad_nodes = []
2260 a8083063 Iustin Pop
    if self.dynamic_fields.intersection(self.op.output_fields):
2261 a8083063 Iustin Pop
      live_data = {}
2262 a8083063 Iustin Pop
      node_data = rpc.call_all_instances_info(nodes)
2263 a8083063 Iustin Pop
      for name in nodes:
2264 a8083063 Iustin Pop
        result = node_data[name]
2265 a8083063 Iustin Pop
        if result:
2266 a8083063 Iustin Pop
          live_data.update(result)
2267 a8083063 Iustin Pop
        elif result == False:
2268 a8083063 Iustin Pop
          bad_nodes.append(name)
2269 a8083063 Iustin Pop
        # else no instance is alive
2270 a8083063 Iustin Pop
    else:
2271 a8083063 Iustin Pop
      live_data = dict([(name, {}) for name in instance_names])
2272 a8083063 Iustin Pop
2273 a8083063 Iustin Pop
    # end data gathering
2274 a8083063 Iustin Pop
2275 a8083063 Iustin Pop
    output = []
2276 a8083063 Iustin Pop
    for instance in instance_list:
2277 a8083063 Iustin Pop
      iout = []
2278 a8083063 Iustin Pop
      for field in self.op.output_fields:
2279 a8083063 Iustin Pop
        if field == "name":
2280 a8083063 Iustin Pop
          val = instance.name
2281 a8083063 Iustin Pop
        elif field == "os":
2282 a8083063 Iustin Pop
          val = instance.os
2283 a8083063 Iustin Pop
        elif field == "pnode":
2284 a8083063 Iustin Pop
          val = instance.primary_node
2285 a8083063 Iustin Pop
        elif field == "snodes":
2286 8a23d2d3 Iustin Pop
          val = list(instance.secondary_nodes)
2287 a8083063 Iustin Pop
        elif field == "admin_state":
2288 8a23d2d3 Iustin Pop
          val = (instance.status != "down")
2289 a8083063 Iustin Pop
        elif field == "oper_state":
2290 a8083063 Iustin Pop
          if instance.primary_node in bad_nodes:
2291 8a23d2d3 Iustin Pop
            val = None
2292 a8083063 Iustin Pop
          else:
2293 8a23d2d3 Iustin Pop
            val = bool(live_data.get(instance.name))
2294 a8083063 Iustin Pop
        elif field == "admin_ram":
2295 a8083063 Iustin Pop
          val = instance.memory
2296 a8083063 Iustin Pop
        elif field == "oper_ram":
2297 a8083063 Iustin Pop
          if instance.primary_node in bad_nodes:
2298 8a23d2d3 Iustin Pop
            val = None
2299 a8083063 Iustin Pop
          elif instance.name in live_data:
2300 a8083063 Iustin Pop
            val = live_data[instance.name].get("memory", "?")
2301 a8083063 Iustin Pop
          else:
2302 a8083063 Iustin Pop
            val = "-"
2303 a8083063 Iustin Pop
        elif field == "disk_template":
2304 a8083063 Iustin Pop
          val = instance.disk_template
2305 a8083063 Iustin Pop
        elif field == "ip":
2306 a8083063 Iustin Pop
          val = instance.nics[0].ip
2307 a8083063 Iustin Pop
        elif field == "bridge":
2308 a8083063 Iustin Pop
          val = instance.nics[0].bridge
2309 a8083063 Iustin Pop
        elif field == "mac":
2310 a8083063 Iustin Pop
          val = instance.nics[0].mac
2311 644eeef9 Iustin Pop
        elif field == "sda_size" or field == "sdb_size":
2312 644eeef9 Iustin Pop
          disk = instance.FindDisk(field[:3])
2313 644eeef9 Iustin Pop
          if disk is None:
2314 8a23d2d3 Iustin Pop
            val = None
2315 644eeef9 Iustin Pop
          else:
2316 644eeef9 Iustin Pop
            val = disk.size
2317 a8083063 Iustin Pop
        else:
2318 3ecf6786 Iustin Pop
          raise errors.ParameterError(field)
2319 a8083063 Iustin Pop
        iout.append(val)
2320 a8083063 Iustin Pop
      output.append(iout)
2321 a8083063 Iustin Pop
2322 a8083063 Iustin Pop
    return output
2323 a8083063 Iustin Pop
2324 a8083063 Iustin Pop
2325 a8083063 Iustin Pop
class LUFailoverInstance(LogicalUnit):
2326 a8083063 Iustin Pop
  """Failover an instance.
2327 a8083063 Iustin Pop

2328 a8083063 Iustin Pop
  """
2329 a8083063 Iustin Pop
  HPATH = "instance-failover"
2330 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
2331 a8083063 Iustin Pop
  _OP_REQP = ["instance_name", "ignore_consistency"]
2332 a8083063 Iustin Pop
2333 a8083063 Iustin Pop
  def BuildHooksEnv(self):
2334 a8083063 Iustin Pop
    """Build hooks env.
2335 a8083063 Iustin Pop

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

2338 a8083063 Iustin Pop
    """
2339 a8083063 Iustin Pop
    env = {
2340 a8083063 Iustin Pop
      "IGNORE_CONSISTENCY": self.op.ignore_consistency,
2341 a8083063 Iustin Pop
      }
2342 396e1b78 Michael Hanselmann
    env.update(_BuildInstanceHookEnvByObject(self.instance))
2343 880478f8 Iustin Pop
    nl = [self.sstore.GetMasterNode()] + list(self.instance.secondary_nodes)
2344 a8083063 Iustin Pop
    return env, nl, nl
2345 a8083063 Iustin Pop
2346 a8083063 Iustin Pop
  def CheckPrereq(self):
2347 a8083063 Iustin Pop
    """Check prerequisites.
2348 a8083063 Iustin Pop

2349 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
2350 a8083063 Iustin Pop

2351 a8083063 Iustin Pop
    """
2352 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
2353 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
2354 a8083063 Iustin Pop
    if instance is None:
2355 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
2356 3ecf6786 Iustin Pop
                                 self.op.instance_name)
2357 a8083063 Iustin Pop
2358 2a710df1 Michael Hanselmann
    if instance.disk_template != constants.DT_REMOTE_RAID1:
2359 2a710df1 Michael Hanselmann
      raise errors.OpPrereqError("Instance's disk layout is not"
2360 2a710df1 Michael Hanselmann
                                 " remote_raid1.")
2361 2a710df1 Michael Hanselmann
2362 2a710df1 Michael Hanselmann
    secondary_nodes = instance.secondary_nodes
2363 2a710df1 Michael Hanselmann
    if not secondary_nodes:
2364 2a710df1 Michael Hanselmann
      raise errors.ProgrammerError("no secondary node but using "
2365 2a710df1 Michael Hanselmann
                                   "DT_REMOTE_RAID1 template")
2366 2a710df1 Michael Hanselmann
2367 3a7c308e Guido Trotter
    # check memory requirements on the secondary node
2368 2a710df1 Michael Hanselmann
    target_node = secondary_nodes[0]
2369 3a7c308e Guido Trotter
    nodeinfo = rpc.call_node_info([target_node], self.cfg.GetVGName())
2370 3a7c308e Guido Trotter
    info = nodeinfo.get(target_node, None)
2371 3a7c308e Guido Trotter
    if not info:
2372 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Cannot get current information"
2373 3ecf6786 Iustin Pop
                                 " from node '%s'" % nodeinfo)
2374 3a7c308e Guido Trotter
    if instance.memory > info['memory_free']:
2375 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Not enough memory on target node %s."
2376 3ecf6786 Iustin Pop
                                 " %d MB available, %d MB required" %
2377 3ecf6786 Iustin Pop
                                 (target_node, info['memory_free'],
2378 3ecf6786 Iustin Pop
                                  instance.memory))
2379 3a7c308e Guido Trotter
2380 a8083063 Iustin Pop
    # check bridge existance
2381 a8083063 Iustin Pop
    brlist = [nic.bridge for nic in instance.nics]
2382 a8083063 Iustin Pop
    if not rpc.call_bridges_exist(instance.primary_node, brlist):
2383 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("One or more target bridges %s does not"
2384 3ecf6786 Iustin Pop
                                 " exist on destination node '%s'" %
2385 3ecf6786 Iustin Pop
                                 (brlist, instance.primary_node))
2386 a8083063 Iustin Pop
2387 a8083063 Iustin Pop
    self.instance = instance
2388 a8083063 Iustin Pop
2389 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
2390 a8083063 Iustin Pop
    """Failover an instance.
2391 a8083063 Iustin Pop

2392 a8083063 Iustin Pop
    The failover is done by shutting it down on its present node and
2393 a8083063 Iustin Pop
    starting it on the secondary.
2394 a8083063 Iustin Pop

2395 a8083063 Iustin Pop
    """
2396 a8083063 Iustin Pop
    instance = self.instance
2397 a8083063 Iustin Pop
2398 a8083063 Iustin Pop
    source_node = instance.primary_node
2399 a8083063 Iustin Pop
    target_node = instance.secondary_nodes[0]
2400 a8083063 Iustin Pop
2401 a8083063 Iustin Pop
    feedback_fn("* checking disk consistency between source and target")
2402 a8083063 Iustin Pop
    for dev in instance.disks:
2403 a8083063 Iustin Pop
      # for remote_raid1, these are md over drbd
2404 a8083063 Iustin Pop
      if not _CheckDiskConsistency(self.cfg, dev, target_node, False):
2405 a8083063 Iustin Pop
        if not self.op.ignore_consistency:
2406 3ecf6786 Iustin Pop
          raise errors.OpExecError("Disk %s is degraded on target node,"
2407 3ecf6786 Iustin Pop
                                   " aborting failover." % dev.iv_name)
2408 a8083063 Iustin Pop
2409 a8083063 Iustin Pop
    feedback_fn("* checking target node resource availability")
2410 a8083063 Iustin Pop
    nodeinfo = rpc.call_node_info([target_node], self.cfg.GetVGName())
2411 a8083063 Iustin Pop
2412 a8083063 Iustin Pop
    if not nodeinfo:
2413 3ecf6786 Iustin Pop
      raise errors.OpExecError("Could not contact target node %s." %
2414 3ecf6786 Iustin Pop
                               target_node)
2415 a8083063 Iustin Pop
2416 a8083063 Iustin Pop
    free_memory = int(nodeinfo[target_node]['memory_free'])
2417 a8083063 Iustin Pop
    memory = instance.memory
2418 a8083063 Iustin Pop
    if memory > free_memory:
2419 3ecf6786 Iustin Pop
      raise errors.OpExecError("Not enough memory to create instance %s on"
2420 3ecf6786 Iustin Pop
                               " node %s. needed %s MiB, available %s MiB" %
2421 3ecf6786 Iustin Pop
                               (instance.name, target_node, memory,
2422 3ecf6786 Iustin Pop
                                free_memory))
2423 a8083063 Iustin Pop
2424 a8083063 Iustin Pop
    feedback_fn("* shutting down instance on source node")
2425 a8083063 Iustin Pop
    logger.Info("Shutting down instance %s on node %s" %
2426 a8083063 Iustin Pop
                (instance.name, source_node))
2427 a8083063 Iustin Pop
2428 a8083063 Iustin Pop
    if not rpc.call_instance_shutdown(source_node, instance):
2429 a8083063 Iustin Pop
      logger.Error("Could not shutdown instance %s on node %s. Proceeding"
2430 a8083063 Iustin Pop
                   " anyway. Please make sure node %s is down"  %
2431 a8083063 Iustin Pop
                   (instance.name, source_node, source_node))
2432 a8083063 Iustin Pop
2433 a8083063 Iustin Pop
    feedback_fn("* deactivating the instance's disks on source node")
2434 a8083063 Iustin Pop
    if not _ShutdownInstanceDisks(instance, self.cfg, ignore_primary=True):
2435 3ecf6786 Iustin Pop
      raise errors.OpExecError("Can't shut down the instance's disks.")
2436 a8083063 Iustin Pop
2437 a8083063 Iustin Pop
    instance.primary_node = target_node
2438 a8083063 Iustin Pop
    # distribute new instance config to the other nodes
2439 a8083063 Iustin Pop
    self.cfg.AddInstance(instance)
2440 a8083063 Iustin Pop
2441 a8083063 Iustin Pop
    feedback_fn("* activating the instance's disks on target node")
2442 a8083063 Iustin Pop
    logger.Info("Starting instance %s on node %s" %
2443 a8083063 Iustin Pop
                (instance.name, target_node))
2444 a8083063 Iustin Pop
2445 a8083063 Iustin Pop
    disks_ok, dummy = _AssembleInstanceDisks(instance, self.cfg,
2446 a8083063 Iustin Pop
                                             ignore_secondaries=True)
2447 a8083063 Iustin Pop
    if not disks_ok:
2448 a8083063 Iustin Pop
      _ShutdownInstanceDisks(instance, self.cfg)
2449 3ecf6786 Iustin Pop
      raise errors.OpExecError("Can't activate the instance's disks")
2450 a8083063 Iustin Pop
2451 a8083063 Iustin Pop
    feedback_fn("* starting the instance on the target node")
2452 a8083063 Iustin Pop
    if not rpc.call_instance_start(target_node, instance, None):
2453 a8083063 Iustin Pop
      _ShutdownInstanceDisks(instance, self.cfg)
2454 a8083063 Iustin Pop
      raise errors.OpExecError("Could not start instance %s on node %s." %
2455 d0b3526f Michael Hanselmann
                               (instance.name, target_node))
2456 a8083063 Iustin Pop
2457 a8083063 Iustin Pop
2458 a0c3fea1 Michael Hanselmann
def _CreateBlockDevOnPrimary(cfg, node, device, info):
2459 a8083063 Iustin Pop
  """Create a tree of block devices on the primary node.
2460 a8083063 Iustin Pop

2461 a8083063 Iustin Pop
  This always creates all devices.
2462 a8083063 Iustin Pop

2463 a8083063 Iustin Pop
  """
2464 a8083063 Iustin Pop
  if device.children:
2465 a8083063 Iustin Pop
    for child in device.children:
2466 a0c3fea1 Michael Hanselmann
      if not _CreateBlockDevOnPrimary(cfg, node, child, info):
2467 a8083063 Iustin Pop
        return False
2468 a8083063 Iustin Pop
2469 a8083063 Iustin Pop
  cfg.SetDiskID(device, node)
2470 a0c3fea1 Michael Hanselmann
  new_id = rpc.call_blockdev_create(node, device, device.size, True, info)
2471 a8083063 Iustin Pop
  if not new_id:
2472 a8083063 Iustin Pop
    return False
2473 a8083063 Iustin Pop
  if device.physical_id is None:
2474 a8083063 Iustin Pop
    device.physical_id = new_id
2475 a8083063 Iustin Pop
  return True
2476 a8083063 Iustin Pop
2477 a8083063 Iustin Pop
2478 a0c3fea1 Michael Hanselmann
def _CreateBlockDevOnSecondary(cfg, node, device, force, info):
2479 a8083063 Iustin Pop
  """Create a tree of block devices on a secondary node.
2480 a8083063 Iustin Pop

2481 a8083063 Iustin Pop
  If this device type has to be created on secondaries, create it and
2482 a8083063 Iustin Pop
  all its children.
2483 a8083063 Iustin Pop

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

2486 a8083063 Iustin Pop
  """
2487 a8083063 Iustin Pop
  if device.CreateOnSecondary():
2488 a8083063 Iustin Pop
    force = True
2489 a8083063 Iustin Pop
  if device.children:
2490 a8083063 Iustin Pop
    for child in device.children:
2491 a0c3fea1 Michael Hanselmann
      if not _CreateBlockDevOnSecondary(cfg, node, child, force, info):
2492 a8083063 Iustin Pop
        return False
2493 a8083063 Iustin Pop
2494 a8083063 Iustin Pop
  if not force:
2495 a8083063 Iustin Pop
    return True
2496 a8083063 Iustin Pop
  cfg.SetDiskID(device, node)
2497 a0c3fea1 Michael Hanselmann
  new_id = rpc.call_blockdev_create(node, device, device.size, False, info)
2498 a8083063 Iustin Pop
  if not new_id:
2499 a8083063 Iustin Pop
    return False
2500 a8083063 Iustin Pop
  if device.physical_id is None:
2501 a8083063 Iustin Pop
    device.physical_id = new_id
2502 a8083063 Iustin Pop
  return True
2503 a8083063 Iustin Pop
2504 a8083063 Iustin Pop
2505 923b1523 Iustin Pop
def _GenerateUniqueNames(cfg, exts):
2506 923b1523 Iustin Pop
  """Generate a suitable LV name.
2507 923b1523 Iustin Pop

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

2510 923b1523 Iustin Pop
  """
2511 923b1523 Iustin Pop
  results = []
2512 923b1523 Iustin Pop
  for val in exts:
2513 923b1523 Iustin Pop
    new_id = cfg.GenerateUniqueID()
2514 923b1523 Iustin Pop
    results.append("%s%s" % (new_id, val))
2515 923b1523 Iustin Pop
  return results
2516 923b1523 Iustin Pop
2517 923b1523 Iustin Pop
2518 923b1523 Iustin Pop
def _GenerateMDDRBDBranch(cfg, primary, secondary, size, names):
2519 a8083063 Iustin Pop
  """Generate a drbd device complete with its children.
2520 a8083063 Iustin Pop

2521 a8083063 Iustin Pop
  """
2522 a8083063 Iustin Pop
  port = cfg.AllocatePort()
2523 923b1523 Iustin Pop
  vgname = cfg.GetVGName()
2524 a8083063 Iustin Pop
  dev_data = objects.Disk(dev_type="lvm", size=size,
2525 923b1523 Iustin Pop
                          logical_id=(vgname, names[0]))
2526 a8083063 Iustin Pop
  dev_meta = objects.Disk(dev_type="lvm", size=128,
2527 923b1523 Iustin Pop
                          logical_id=(vgname, names[1]))
2528 a8083063 Iustin Pop
  drbd_dev = objects.Disk(dev_type="drbd", size=size,
2529 a8083063 Iustin Pop
                          logical_id = (primary, secondary, port),
2530 a8083063 Iustin Pop
                          children = [dev_data, dev_meta])
2531 a8083063 Iustin Pop
  return drbd_dev
2532 a8083063 Iustin Pop
2533 a8083063 Iustin Pop
2534 923b1523 Iustin Pop
def _GenerateDiskTemplate(cfg, template_name,
2535 a8083063 Iustin Pop
                          instance_name, primary_node,
2536 a8083063 Iustin Pop
                          secondary_nodes, disk_sz, swap_sz):
2537 a8083063 Iustin Pop
  """Generate the entire disk layout for a given template type.
2538 a8083063 Iustin Pop

2539 a8083063 Iustin Pop
  """
2540 a8083063 Iustin Pop
  #TODO: compute space requirements
2541 a8083063 Iustin Pop
2542 923b1523 Iustin Pop
  vgname = cfg.GetVGName()
2543 a8083063 Iustin Pop
  if template_name == "diskless":
2544 a8083063 Iustin Pop
    disks = []
2545 a8083063 Iustin Pop
  elif template_name == "plain":
2546 a8083063 Iustin Pop
    if len(secondary_nodes) != 0:
2547 a8083063 Iustin Pop
      raise errors.ProgrammerError("Wrong template configuration")
2548 923b1523 Iustin Pop
2549 923b1523 Iustin Pop
    names = _GenerateUniqueNames(cfg, [".sda", ".sdb"])
2550 a8083063 Iustin Pop
    sda_dev = objects.Disk(dev_type="lvm", size=disk_sz,
2551 923b1523 Iustin Pop
                           logical_id=(vgname, names[0]),
2552 a8083063 Iustin Pop
                           iv_name = "sda")
2553 a8083063 Iustin Pop
    sdb_dev = objects.Disk(dev_type="lvm", size=swap_sz,
2554 923b1523 Iustin Pop
                           logical_id=(vgname, names[1]),
2555 a8083063 Iustin Pop
                           iv_name = "sdb")
2556 a8083063 Iustin Pop
    disks = [sda_dev, sdb_dev]
2557 a8083063 Iustin Pop
  elif template_name == "local_raid1":
2558 a8083063 Iustin Pop
    if len(secondary_nodes) != 0:
2559 a8083063 Iustin Pop
      raise errors.ProgrammerError("Wrong template configuration")
2560 923b1523 Iustin Pop
2561 923b1523 Iustin Pop
2562 923b1523 Iustin Pop
    names = _GenerateUniqueNames(cfg, [".sda_m1", ".sda_m2",
2563 923b1523 Iustin Pop
                                       ".sdb_m1", ".sdb_m2"])
2564 a8083063 Iustin Pop
    sda_dev_m1 = objects.Disk(dev_type="lvm", size=disk_sz,
2565 923b1523 Iustin Pop
                              logical_id=(vgname, names[0]))
2566 a8083063 Iustin Pop
    sda_dev_m2 = objects.Disk(dev_type="lvm", size=disk_sz,
2567 923b1523 Iustin Pop
                              logical_id=(vgname, names[1]))
2568 a8083063 Iustin Pop
    md_sda_dev = objects.Disk(dev_type="md_raid1", iv_name = "sda",
2569 a8083063 Iustin Pop
                              size=disk_sz,
2570 a8083063 Iustin Pop
                              children = [sda_dev_m1, sda_dev_m2])
2571 a8083063 Iustin Pop
    sdb_dev_m1 = objects.Disk(dev_type="lvm", size=swap_sz,
2572 923b1523 Iustin Pop
                              logical_id=(vgname, names[2]))
2573 a8083063 Iustin Pop
    sdb_dev_m2 = objects.Disk(dev_type="lvm", size=swap_sz,
2574 923b1523 Iustin Pop
                              logical_id=(vgname, names[3]))
2575 a8083063 Iustin Pop
    md_sdb_dev = objects.Disk(dev_type="md_raid1", iv_name = "sdb",
2576 a8083063 Iustin Pop
                              size=swap_sz,
2577 a8083063 Iustin Pop
                              children = [sdb_dev_m1, sdb_dev_m2])
2578 a8083063 Iustin Pop
    disks = [md_sda_dev, md_sdb_dev]
2579 2a710df1 Michael Hanselmann
  elif template_name == constants.DT_REMOTE_RAID1:
2580 a8083063 Iustin Pop
    if len(secondary_nodes) != 1:
2581 a8083063 Iustin Pop
      raise errors.ProgrammerError("Wrong template configuration")
2582 a8083063 Iustin Pop
    remote_node = secondary_nodes[0]
2583 923b1523 Iustin Pop
    names = _GenerateUniqueNames(cfg, [".sda_data", ".sda_meta",
2584 923b1523 Iustin Pop
                                       ".sdb_data", ".sdb_meta"])
2585 923b1523 Iustin Pop
    drbd_sda_dev = _GenerateMDDRBDBranch(cfg, primary_node, remote_node,
2586 923b1523 Iustin Pop
                                         disk_sz, names[0:2])
2587 a8083063 Iustin Pop
    md_sda_dev = objects.Disk(dev_type="md_raid1", iv_name="sda",
2588 a8083063 Iustin Pop
                              children = [drbd_sda_dev], size=disk_sz)
2589 923b1523 Iustin Pop
    drbd_sdb_dev = _GenerateMDDRBDBranch(cfg, primary_node, remote_node,
2590 923b1523 Iustin Pop
                                         swap_sz, names[2:4])
2591 a8083063 Iustin Pop
    md_sdb_dev = objects.Disk(dev_type="md_raid1", iv_name="sdb",
2592 a8083063 Iustin Pop
                              children = [drbd_sdb_dev], size=swap_sz)
2593 a8083063 Iustin Pop
    disks = [md_sda_dev, md_sdb_dev]
2594 a8083063 Iustin Pop
  else:
2595 a8083063 Iustin Pop
    raise errors.ProgrammerError("Invalid disk template '%s'" % template_name)
2596 a8083063 Iustin Pop
  return disks
2597 a8083063 Iustin Pop
2598 a8083063 Iustin Pop
2599 a0c3fea1 Michael Hanselmann
def _GetInstanceInfoText(instance):
2600 3ecf6786 Iustin Pop
  """Compute that text that should be added to the disk's metadata.
2601 3ecf6786 Iustin Pop

2602 3ecf6786 Iustin Pop
  """
2603 a0c3fea1 Michael Hanselmann
  return "originstname+%s" % instance.name
2604 a0c3fea1 Michael Hanselmann
2605 a0c3fea1 Michael Hanselmann
2606 a8083063 Iustin Pop
def _CreateDisks(cfg, instance):
2607 a8083063 Iustin Pop
  """Create all disks for an instance.
2608 a8083063 Iustin Pop

2609 a8083063 Iustin Pop
  This abstracts away some work from AddInstance.
2610 a8083063 Iustin Pop

2611 a8083063 Iustin Pop
  Args:
2612 a8083063 Iustin Pop
    instance: the instance object
2613 a8083063 Iustin Pop

2614 a8083063 Iustin Pop
  Returns:
2615 a8083063 Iustin Pop
    True or False showing the success of the creation process
2616 a8083063 Iustin Pop

2617 a8083063 Iustin Pop
  """
2618 a0c3fea1 Michael Hanselmann
  info = _GetInstanceInfoText(instance)
2619 a0c3fea1 Michael Hanselmann
2620 a8083063 Iustin Pop
  for device in instance.disks:
2621 a8083063 Iustin Pop
    logger.Info("creating volume %s for instance %s" %
2622 a8083063 Iustin Pop
              (device.iv_name, instance.name))
2623 a8083063 Iustin Pop
    #HARDCODE
2624 a8083063 Iustin Pop
    for secondary_node in instance.secondary_nodes:
2625 a0c3fea1 Michael Hanselmann
      if not _CreateBlockDevOnSecondary(cfg, secondary_node, device, False,
2626 a0c3fea1 Michael Hanselmann
                                        info):
2627 a8083063 Iustin Pop
        logger.Error("failed to create volume %s (%s) on secondary node %s!" %
2628 a8083063 Iustin Pop
                     (device.iv_name, device, secondary_node))
2629 a8083063 Iustin Pop
        return False
2630 a8083063 Iustin Pop
    #HARDCODE
2631 a0c3fea1 Michael Hanselmann
    if not _CreateBlockDevOnPrimary(cfg, instance.primary_node, device, info):
2632 a8083063 Iustin Pop
      logger.Error("failed to create volume %s on primary!" %
2633 a8083063 Iustin Pop
                   device.iv_name)
2634 a8083063 Iustin Pop
      return False
2635 a8083063 Iustin Pop
  return True
2636 a8083063 Iustin Pop
2637 a8083063 Iustin Pop
2638 a8083063 Iustin Pop
def _RemoveDisks(instance, cfg):
2639 a8083063 Iustin Pop
  """Remove all disks for an instance.
2640 a8083063 Iustin Pop

2641 a8083063 Iustin Pop
  This abstracts away some work from `AddInstance()` and
2642 a8083063 Iustin Pop
  `RemoveInstance()`. Note that in case some of the devices couldn't
2643 a8083063 Iustin Pop
  be remove, the removal will continue with the other ones (compare
2644 a8083063 Iustin Pop
  with `_CreateDisks()`).
2645 a8083063 Iustin Pop

2646 a8083063 Iustin Pop
  Args:
2647 a8083063 Iustin Pop
    instance: the instance object
2648 a8083063 Iustin Pop

2649 a8083063 Iustin Pop
  Returns:
2650 a8083063 Iustin Pop
    True or False showing the success of the removal proces
2651 a8083063 Iustin Pop

2652 a8083063 Iustin Pop
  """
2653 a8083063 Iustin Pop
  logger.Info("removing block devices for instance %s" % instance.name)
2654 a8083063 Iustin Pop
2655 a8083063 Iustin Pop
  result = True
2656 a8083063 Iustin Pop
  for device in instance.disks:
2657 a8083063 Iustin Pop
    for node, disk in device.ComputeNodeTree(instance.primary_node):
2658 a8083063 Iustin Pop
      cfg.SetDiskID(disk, node)
2659 a8083063 Iustin Pop
      if not rpc.call_blockdev_remove(node, disk):
2660 a8083063 Iustin Pop
        logger.Error("could not remove block device %s on node %s,"
2661 a8083063 Iustin Pop
                     " continuing anyway" %
2662 a8083063 Iustin Pop
                     (device.iv_name, node))
2663 a8083063 Iustin Pop
        result = False
2664 a8083063 Iustin Pop
  return result
2665 a8083063 Iustin Pop
2666 a8083063 Iustin Pop
2667 a8083063 Iustin Pop
class LUCreateInstance(LogicalUnit):
2668 a8083063 Iustin Pop
  """Create an instance.
2669 a8083063 Iustin Pop

2670 a8083063 Iustin Pop
  """
2671 a8083063 Iustin Pop
  HPATH = "instance-add"
2672 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
2673 a8083063 Iustin Pop
  _OP_REQP = ["instance_name", "mem_size", "disk_size", "pnode",
2674 a8083063 Iustin Pop
              "disk_template", "swap_size", "mode", "start", "vcpus",
2675 bdd55f71 Iustin Pop
              "wait_for_sync", "ip_check"]
2676 a8083063 Iustin Pop
2677 a8083063 Iustin Pop
  def BuildHooksEnv(self):
2678 a8083063 Iustin Pop
    """Build hooks env.
2679 a8083063 Iustin Pop

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

2682 a8083063 Iustin Pop
    """
2683 a8083063 Iustin Pop
    env = {
2684 396e1b78 Michael Hanselmann
      "INSTANCE_DISK_TEMPLATE": self.op.disk_template,
2685 396e1b78 Michael Hanselmann
      "INSTANCE_DISK_SIZE": self.op.disk_size,
2686 396e1b78 Michael Hanselmann
      "INSTANCE_SWAP_SIZE": self.op.swap_size,
2687 a8083063 Iustin Pop
      "INSTANCE_ADD_MODE": self.op.mode,
2688 a8083063 Iustin Pop
      }
2689 a8083063 Iustin Pop
    if self.op.mode == constants.INSTANCE_IMPORT:
2690 396e1b78 Michael Hanselmann
      env["INSTANCE_SRC_NODE"] = self.op.src_node
2691 396e1b78 Michael Hanselmann
      env["INSTANCE_SRC_PATH"] = self.op.src_path
2692 396e1b78 Michael Hanselmann
      env["INSTANCE_SRC_IMAGE"] = self.src_image
2693 396e1b78 Michael Hanselmann
2694 396e1b78 Michael Hanselmann
    env.update(_BuildInstanceHookEnv(name=self.op.instance_name,
2695 396e1b78 Michael Hanselmann
      primary_node=self.op.pnode,
2696 396e1b78 Michael Hanselmann
      secondary_nodes=self.secondaries,
2697 396e1b78 Michael Hanselmann
      status=self.instance_status,
2698 ecb215b5 Michael Hanselmann
      os_type=self.op.os_type,
2699 396e1b78 Michael Hanselmann
      memory=self.op.mem_size,
2700 396e1b78 Michael Hanselmann
      vcpus=self.op.vcpus,
2701 396e1b78 Michael Hanselmann
      nics=[(self.inst_ip, self.op.bridge)],
2702 396e1b78 Michael Hanselmann
    ))
2703 a8083063 Iustin Pop
2704 880478f8 Iustin Pop
    nl = ([self.sstore.GetMasterNode(), self.op.pnode] +
2705 a8083063 Iustin Pop
          self.secondaries)
2706 a8083063 Iustin Pop
    return env, nl, nl
2707 a8083063 Iustin Pop
2708 a8083063 Iustin Pop
2709 a8083063 Iustin Pop
  def CheckPrereq(self):
2710 a8083063 Iustin Pop
    """Check prerequisites.
2711 a8083063 Iustin Pop

2712 a8083063 Iustin Pop
    """
2713 a8083063 Iustin Pop
    if self.op.mode not in (constants.INSTANCE_CREATE,
2714 a8083063 Iustin Pop
                            constants.INSTANCE_IMPORT):
2715 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Invalid instance creation mode '%s'" %
2716 3ecf6786 Iustin Pop
                                 self.op.mode)
2717 a8083063 Iustin Pop
2718 a8083063 Iustin Pop
    if self.op.mode == constants.INSTANCE_IMPORT:
2719 a8083063 Iustin Pop
      src_node = getattr(self.op, "src_node", None)
2720 a8083063 Iustin Pop
      src_path = getattr(self.op, "src_path", None)
2721 a8083063 Iustin Pop
      if src_node is None or src_path is None:
2722 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Importing an instance requires source"
2723 3ecf6786 Iustin Pop
                                   " node and path options")
2724 a8083063 Iustin Pop
      src_node_full = self.cfg.ExpandNodeName(src_node)
2725 a8083063 Iustin Pop
      if src_node_full is None:
2726 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Unknown source node '%s'" % src_node)
2727 a8083063 Iustin Pop
      self.op.src_node = src_node = src_node_full
2728 a8083063 Iustin Pop
2729 a8083063 Iustin Pop
      if not os.path.isabs(src_path):
2730 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("The source path must be absolute")
2731 a8083063 Iustin Pop
2732 a8083063 Iustin Pop
      export_info = rpc.call_export_info(src_node, src_path)
2733 a8083063 Iustin Pop
2734 a8083063 Iustin Pop
      if not export_info:
2735 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("No export found in dir %s" % src_path)
2736 a8083063 Iustin Pop
2737 a8083063 Iustin Pop
      if not export_info.has_section(constants.INISECT_EXP):
2738 3ecf6786 Iustin Pop
        raise errors.ProgrammerError("Corrupted export config")
2739 a8083063 Iustin Pop
2740 a8083063 Iustin Pop
      ei_version = export_info.get(constants.INISECT_EXP, 'version')
2741 a8083063 Iustin Pop
      if (int(ei_version) != constants.EXPORT_VERSION):
2742 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Wrong export version %s (wanted %d)" %
2743 3ecf6786 Iustin Pop
                                   (ei_version, constants.EXPORT_VERSION))
2744 a8083063 Iustin Pop
2745 a8083063 Iustin Pop
      if int(export_info.get(constants.INISECT_INS, 'disk_count')) > 1:
2746 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Can't import instance with more than"
2747 3ecf6786 Iustin Pop
                                   " one data disk")
2748 a8083063 Iustin Pop
2749 a8083063 Iustin Pop
      # FIXME: are the old os-es, disk sizes, etc. useful?
2750 a8083063 Iustin Pop
      self.op.os_type = export_info.get(constants.INISECT_EXP, 'os')
2751 a8083063 Iustin Pop
      diskimage = os.path.join(src_path, export_info.get(constants.INISECT_INS,
2752 a8083063 Iustin Pop
                                                         'disk0_dump'))
2753 a8083063 Iustin Pop
      self.src_image = diskimage
2754 a8083063 Iustin Pop
    else: # INSTANCE_CREATE
2755 a8083063 Iustin Pop
      if getattr(self.op, "os_type", None) is None:
2756 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("No guest OS specified")
2757 a8083063 Iustin Pop
2758 a8083063 Iustin Pop
    # check primary node
2759 a8083063 Iustin Pop
    pnode = self.cfg.GetNodeInfo(self.cfg.ExpandNodeName(self.op.pnode))
2760 a8083063 Iustin Pop
    if pnode is None:
2761 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Primary node '%s' is unknown" %
2762 3ecf6786 Iustin Pop
                                 self.op.pnode)
2763 a8083063 Iustin Pop
    self.op.pnode = pnode.name
2764 a8083063 Iustin Pop
    self.pnode = pnode
2765 a8083063 Iustin Pop
    self.secondaries = []
2766 a8083063 Iustin Pop
    # disk template and mirror node verification
2767 a8083063 Iustin Pop
    if self.op.disk_template not in constants.DISK_TEMPLATES:
2768 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Invalid disk template name")
2769 a8083063 Iustin Pop
2770 a8083063 Iustin Pop
    if self.op.disk_template == constants.DT_REMOTE_RAID1:
2771 a8083063 Iustin Pop
      if getattr(self.op, "snode", None) is None:
2772 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("The 'remote_raid1' disk template needs"
2773 3ecf6786 Iustin Pop
                                   " a mirror node")
2774 a8083063 Iustin Pop
2775 a8083063 Iustin Pop
      snode_name = self.cfg.ExpandNodeName(self.op.snode)
2776 a8083063 Iustin Pop
      if snode_name is None:
2777 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Unknown secondary node '%s'" %
2778 3ecf6786 Iustin Pop
                                   self.op.snode)
2779 a8083063 Iustin Pop
      elif snode_name == pnode.name:
2780 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("The secondary node cannot be"
2781 3ecf6786 Iustin Pop
                                   " the primary node.")
2782 a8083063 Iustin Pop
      self.secondaries.append(snode_name)
2783 a8083063 Iustin Pop
2784 ed1ebc60 Guido Trotter
    # Check lv size requirements
2785 ed1ebc60 Guido Trotter
    nodenames = [pnode.name] + self.secondaries
2786 ed1ebc60 Guido Trotter
    nodeinfo = rpc.call_node_info(nodenames, self.cfg.GetVGName())
2787 ed1ebc60 Guido Trotter
2788 ed1ebc60 Guido Trotter
    # Required free disk space as a function of disk and swap space
2789 ed1ebc60 Guido Trotter
    req_size_dict = {
2790 ed1ebc60 Guido Trotter
      constants.DT_DISKLESS: 0,
2791 ed1ebc60 Guido Trotter
      constants.DT_PLAIN: self.op.disk_size + self.op.swap_size,
2792 ed1ebc60 Guido Trotter
      constants.DT_LOCAL_RAID1: (self.op.disk_size + self.op.swap_size) * 2,
2793 ed1ebc60 Guido Trotter
      # 256 MB are added for drbd metadata, 128MB for each drbd device
2794 ed1ebc60 Guido Trotter
      constants.DT_REMOTE_RAID1: self.op.disk_size + self.op.swap_size + 256,
2795 ed1ebc60 Guido Trotter
    }
2796 ed1ebc60 Guido Trotter
2797 ed1ebc60 Guido Trotter
    if self.op.disk_template not in req_size_dict:
2798 3ecf6786 Iustin Pop
      raise errors.ProgrammerError("Disk template '%s' size requirement"
2799 3ecf6786 Iustin Pop
                                   " is unknown" %  self.op.disk_template)
2800 ed1ebc60 Guido Trotter
2801 ed1ebc60 Guido Trotter
    req_size = req_size_dict[self.op.disk_template]
2802 ed1ebc60 Guido Trotter
2803 ed1ebc60 Guido Trotter
    for node in nodenames:
2804 ed1ebc60 Guido Trotter
      info = nodeinfo.get(node, None)
2805 ed1ebc60 Guido Trotter
      if not info:
2806 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Cannot get current information"
2807 3ecf6786 Iustin Pop
                                   " from node '%s'" % nodeinfo)
2808 ed1ebc60 Guido Trotter
      if req_size > info['vg_free']:
2809 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Not enough disk space on target node %s."
2810 3ecf6786 Iustin Pop
                                   " %d MB available, %d MB required" %
2811 3ecf6786 Iustin Pop
                                   (node, info['vg_free'], req_size))
2812 ed1ebc60 Guido Trotter
2813 a8083063 Iustin Pop
    # os verification
2814 a8083063 Iustin Pop
    os_obj = rpc.call_os_get([pnode.name], self.op.os_type)[pnode.name]
2815 a8083063 Iustin Pop
    if not isinstance(os_obj, objects.OS):
2816 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("OS '%s' not in supported os list for"
2817 3ecf6786 Iustin Pop
                                 " primary node"  % self.op.os_type)
2818 a8083063 Iustin Pop
2819 a8083063 Iustin Pop
    # instance verification
2820 89e1fc26 Iustin Pop
    hostname1 = utils.HostInfo(self.op.instance_name)
2821 a8083063 Iustin Pop
2822 bcf043c9 Iustin Pop
    self.op.instance_name = instance_name = hostname1.name
2823 a8083063 Iustin Pop
    instance_list = self.cfg.GetInstanceList()
2824 a8083063 Iustin Pop
    if instance_name in instance_list:
2825 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' is already in the cluster" %
2826 3ecf6786 Iustin Pop
                                 instance_name)
2827 a8083063 Iustin Pop
2828 a8083063 Iustin Pop
    ip = getattr(self.op, "ip", None)
2829 a8083063 Iustin Pop
    if ip is None or ip.lower() == "none":
2830 a8083063 Iustin Pop
      inst_ip = None
2831 a8083063 Iustin Pop
    elif ip.lower() == "auto":
2832 bcf043c9 Iustin Pop
      inst_ip = hostname1.ip
2833 a8083063 Iustin Pop
    else:
2834 a8083063 Iustin Pop
      if not utils.IsValidIP(ip):
2835 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("given IP address '%s' doesn't look"
2836 3ecf6786 Iustin Pop
                                   " like a valid IP" % ip)
2837 a8083063 Iustin Pop
      inst_ip = ip
2838 a8083063 Iustin Pop
    self.inst_ip = inst_ip
2839 a8083063 Iustin Pop
2840 bdd55f71 Iustin Pop
    if self.op.start and not self.op.ip_check:
2841 bdd55f71 Iustin Pop
      raise errors.OpPrereqError("Cannot ignore IP address conflicts when"
2842 bdd55f71 Iustin Pop
                                 " adding an instance in start mode")
2843 bdd55f71 Iustin Pop
2844 bdd55f71 Iustin Pop
    if self.op.ip_check:
2845 bdd55f71 Iustin Pop
      command = ["fping", "-q", hostname1.ip]
2846 bdd55f71 Iustin Pop
      result = utils.RunCmd(command)
2847 bdd55f71 Iustin Pop
      if not result.failed:
2848 bdd55f71 Iustin Pop
        raise errors.OpPrereqError("IP address %s of instance %s already"
2849 bdd55f71 Iustin Pop
                                   " in use" % (hostname1.ip, instance_name))
2850 a8083063 Iustin Pop
2851 a8083063 Iustin Pop
    # bridge verification
2852 a8083063 Iustin Pop
    bridge = getattr(self.op, "bridge", None)
2853 a8083063 Iustin Pop
    if bridge is None:
2854 a8083063 Iustin Pop
      self.op.bridge = self.cfg.GetDefBridge()
2855 a8083063 Iustin Pop
    else:
2856 a8083063 Iustin Pop
      self.op.bridge = bridge
2857 a8083063 Iustin Pop
2858 a8083063 Iustin Pop
    if not rpc.call_bridges_exist(self.pnode.name, [self.op.bridge]):
2859 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("target bridge '%s' does not exist on"
2860 3ecf6786 Iustin Pop
                                 " destination node '%s'" %
2861 3ecf6786 Iustin Pop
                                 (self.op.bridge, pnode.name))
2862 a8083063 Iustin Pop
2863 a8083063 Iustin Pop
    if self.op.start:
2864 a8083063 Iustin Pop
      self.instance_status = 'up'
2865 a8083063 Iustin Pop
    else:
2866 a8083063 Iustin Pop
      self.instance_status = 'down'
2867 a8083063 Iustin Pop
2868 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
2869 a8083063 Iustin Pop
    """Create and add the instance to the cluster.
2870 a8083063 Iustin Pop

2871 a8083063 Iustin Pop
    """
2872 a8083063 Iustin Pop
    instance = self.op.instance_name
2873 a8083063 Iustin Pop
    pnode_name = self.pnode.name
2874 a8083063 Iustin Pop
2875 a8083063 Iustin Pop
    nic = objects.NIC(bridge=self.op.bridge, mac=self.cfg.GenerateMAC())
2876 a8083063 Iustin Pop
    if self.inst_ip is not None:
2877 a8083063 Iustin Pop
      nic.ip = self.inst_ip
2878 a8083063 Iustin Pop
2879 923b1523 Iustin Pop
    disks = _GenerateDiskTemplate(self.cfg,
2880 a8083063 Iustin Pop
                                  self.op.disk_template,
2881 a8083063 Iustin Pop
                                  instance, pnode_name,
2882 a8083063 Iustin Pop
                                  self.secondaries, self.op.disk_size,
2883 a8083063 Iustin Pop
                                  self.op.swap_size)
2884 a8083063 Iustin Pop
2885 a8083063 Iustin Pop
    iobj = objects.Instance(name=instance, os=self.op.os_type,
2886 a8083063 Iustin Pop
                            primary_node=pnode_name,
2887 a8083063 Iustin Pop
                            memory=self.op.mem_size,
2888 a8083063 Iustin Pop
                            vcpus=self.op.vcpus,
2889 a8083063 Iustin Pop
                            nics=[nic], disks=disks,
2890 a8083063 Iustin Pop
                            disk_template=self.op.disk_template,
2891 a8083063 Iustin Pop
                            status=self.instance_status,
2892 a8083063 Iustin Pop
                            )
2893 a8083063 Iustin Pop
2894 a8083063 Iustin Pop
    feedback_fn("* creating instance disks...")
2895 a8083063 Iustin Pop
    if not _CreateDisks(self.cfg, iobj):
2896 a8083063 Iustin Pop
      _RemoveDisks(iobj, self.cfg)
2897 3ecf6786 Iustin Pop
      raise errors.OpExecError("Device creation failed, reverting...")
2898 a8083063 Iustin Pop
2899 a8083063 Iustin Pop
    feedback_fn("adding instance %s to cluster config" % instance)
2900 a8083063 Iustin Pop
2901 a8083063 Iustin Pop
    self.cfg.AddInstance(iobj)
2902 a8083063 Iustin Pop
2903 a8083063 Iustin Pop
    if self.op.wait_for_sync:
2904 a8083063 Iustin Pop
      disk_abort = not _WaitForSync(self.cfg, iobj)
2905 2a710df1 Michael Hanselmann
    elif iobj.disk_template == constants.DT_REMOTE_RAID1:
2906 a8083063 Iustin Pop
      # make sure the disks are not degraded (still sync-ing is ok)
2907 a8083063 Iustin Pop
      time.sleep(15)
2908 a8083063 Iustin Pop
      feedback_fn("* checking mirrors status")
2909 a8083063 Iustin Pop
      disk_abort = not _WaitForSync(self.cfg, iobj, oneshot=True)
2910 a8083063 Iustin Pop
    else:
2911 a8083063 Iustin Pop
      disk_abort = False
2912 a8083063 Iustin Pop
2913 a8083063 Iustin Pop
    if disk_abort:
2914 a8083063 Iustin Pop
      _RemoveDisks(iobj, self.cfg)
2915 a8083063 Iustin Pop
      self.cfg.RemoveInstance(iobj.name)
2916 3ecf6786 Iustin Pop
      raise errors.OpExecError("There are some degraded disks for"
2917 3ecf6786 Iustin Pop
                               " this instance")
2918 a8083063 Iustin Pop
2919 a8083063 Iustin Pop
    feedback_fn("creating os for instance %s on node %s" %
2920 a8083063 Iustin Pop
                (instance, pnode_name))
2921 a8083063 Iustin Pop
2922 a8083063 Iustin Pop
    if iobj.disk_template != constants.DT_DISKLESS:
2923 a8083063 Iustin Pop
      if self.op.mode == constants.INSTANCE_CREATE:
2924 a8083063 Iustin Pop
        feedback_fn("* running the instance OS create scripts...")
2925 a8083063 Iustin Pop
        if not rpc.call_instance_os_add(pnode_name, iobj, "sda", "sdb"):
2926 3ecf6786 Iustin Pop
          raise errors.OpExecError("could not add os for instance %s"
2927 3ecf6786 Iustin Pop
                                   " on node %s" %
2928 3ecf6786 Iustin Pop
                                   (instance, pnode_name))
2929 a8083063 Iustin Pop
2930 a8083063 Iustin Pop
      elif self.op.mode == constants.INSTANCE_IMPORT:
2931 a8083063 Iustin Pop
        feedback_fn("* running the instance OS import scripts...")
2932 a8083063 Iustin Pop
        src_node = self.op.src_node
2933 a8083063 Iustin Pop
        src_image = self.src_image
2934 a8083063 Iustin Pop
        if not rpc.call_instance_os_import(pnode_name, iobj, "sda", "sdb",
2935 a8083063 Iustin Pop
                                                src_node, src_image):
2936 3ecf6786 Iustin Pop
          raise errors.OpExecError("Could not import os for instance"
2937 3ecf6786 Iustin Pop
                                   " %s on node %s" %
2938 3ecf6786 Iustin Pop
                                   (instance, pnode_name))
2939 a8083063 Iustin Pop
      else:
2940 a8083063 Iustin Pop
        # also checked in the prereq part
2941 3ecf6786 Iustin Pop
        raise errors.ProgrammerError("Unknown OS initialization mode '%s'"
2942 3ecf6786 Iustin Pop
                                     % self.op.mode)
2943 a8083063 Iustin Pop
2944 a8083063 Iustin Pop
    if self.op.start:
2945 a8083063 Iustin Pop
      logger.Info("starting instance %s on node %s" % (instance, pnode_name))
2946 a8083063 Iustin Pop
      feedback_fn("* starting instance...")
2947 a8083063 Iustin Pop
      if not rpc.call_instance_start(pnode_name, iobj, None):
2948 3ecf6786 Iustin Pop
        raise errors.OpExecError("Could not start instance")
2949 a8083063 Iustin Pop
2950 a8083063 Iustin Pop
2951 a8083063 Iustin Pop
class LUConnectConsole(NoHooksLU):
2952 a8083063 Iustin Pop
  """Connect to an instance's console.
2953 a8083063 Iustin Pop

2954 a8083063 Iustin Pop
  This is somewhat special in that it returns the command line that
2955 a8083063 Iustin Pop
  you need to run on the master node in order to connect to the
2956 a8083063 Iustin Pop
  console.
2957 a8083063 Iustin Pop

2958 a8083063 Iustin Pop
  """
2959 a8083063 Iustin Pop
  _OP_REQP = ["instance_name"]
2960 a8083063 Iustin Pop
2961 a8083063 Iustin Pop
  def CheckPrereq(self):
2962 a8083063 Iustin Pop
    """Check prerequisites.
2963 a8083063 Iustin Pop

2964 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
2965 a8083063 Iustin Pop

2966 a8083063 Iustin Pop
    """
2967 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
2968 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
2969 a8083063 Iustin Pop
    if instance is None:
2970 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
2971 3ecf6786 Iustin Pop
                                 self.op.instance_name)
2972 a8083063 Iustin Pop
    self.instance = instance
2973 a8083063 Iustin Pop
2974 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
2975 a8083063 Iustin Pop
    """Connect to the console of an instance
2976 a8083063 Iustin Pop

2977 a8083063 Iustin Pop
    """
2978 a8083063 Iustin Pop
    instance = self.instance
2979 a8083063 Iustin Pop
    node = instance.primary_node
2980 a8083063 Iustin Pop
2981 a8083063 Iustin Pop
    node_insts = rpc.call_instance_list([node])[node]
2982 a8083063 Iustin Pop
    if node_insts is False:
2983 3ecf6786 Iustin Pop
      raise errors.OpExecError("Can't connect to node %s." % node)
2984 a8083063 Iustin Pop
2985 a8083063 Iustin Pop
    if instance.name not in node_insts:
2986 3ecf6786 Iustin Pop
      raise errors.OpExecError("Instance %s is not running." % instance.name)
2987 a8083063 Iustin Pop
2988 a8083063 Iustin Pop
    logger.Debug("connecting to console of %s on %s" % (instance.name, node))
2989 a8083063 Iustin Pop
2990 a8083063 Iustin Pop
    hyper = hypervisor.GetHypervisor()
2991 a8083063 Iustin Pop
    console_cmd = hyper.GetShellCommandForConsole(instance.name)
2992 82122173 Iustin Pop
    # build ssh cmdline
2993 82122173 Iustin Pop
    argv = ["ssh", "-q", "-t"]
2994 82122173 Iustin Pop
    argv.extend(ssh.KNOWN_HOSTS_OPTS)
2995 82122173 Iustin Pop
    argv.extend(ssh.BATCH_MODE_OPTS)
2996 82122173 Iustin Pop
    argv.append(node)
2997 82122173 Iustin Pop
    argv.append(console_cmd)
2998 82122173 Iustin Pop
    return "ssh", argv
2999 a8083063 Iustin Pop
3000 a8083063 Iustin Pop
3001 a8083063 Iustin Pop
class LUAddMDDRBDComponent(LogicalUnit):
3002 a8083063 Iustin Pop
  """Adda new mirror member to an instance's disk.
3003 a8083063 Iustin Pop

3004 a8083063 Iustin Pop
  """
3005 a8083063 Iustin Pop
  HPATH = "mirror-add"
3006 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
3007 a8083063 Iustin Pop
  _OP_REQP = ["instance_name", "remote_node", "disk_name"]
3008 a8083063 Iustin Pop
3009 a8083063 Iustin Pop
  def BuildHooksEnv(self):
3010 a8083063 Iustin Pop
    """Build hooks env.
3011 a8083063 Iustin Pop

3012 a8083063 Iustin Pop
    This runs on the master, the primary and all the secondaries.
3013 a8083063 Iustin Pop

3014 a8083063 Iustin Pop
    """
3015 a8083063 Iustin Pop
    env = {
3016 a8083063 Iustin Pop
      "NEW_SECONDARY": self.op.remote_node,
3017 a8083063 Iustin Pop
      "DISK_NAME": self.op.disk_name,
3018 a8083063 Iustin Pop
      }
3019 396e1b78 Michael Hanselmann
    env.update(_BuildInstanceHookEnvByObject(self.instance))
3020 880478f8 Iustin Pop
    nl = [self.sstore.GetMasterNode(), self.instance.primary_node,
3021 a8083063 Iustin Pop
          self.op.remote_node,] + list(self.instance.secondary_nodes)
3022 a8083063 Iustin Pop
    return env, nl, nl
3023 a8083063 Iustin Pop
3024 a8083063 Iustin Pop
  def CheckPrereq(self):
3025 a8083063 Iustin Pop
    """Check prerequisites.
3026 a8083063 Iustin Pop

3027 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
3028 a8083063 Iustin Pop

3029 a8083063 Iustin Pop
    """
3030 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
3031 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
3032 a8083063 Iustin Pop
    if instance is None:
3033 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
3034 3ecf6786 Iustin Pop
                                 self.op.instance_name)
3035 a8083063 Iustin Pop
    self.instance = instance
3036 a8083063 Iustin Pop
3037 a8083063 Iustin Pop
    remote_node = self.cfg.ExpandNodeName(self.op.remote_node)
3038 a8083063 Iustin Pop
    if remote_node is None:
3039 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Node '%s' not known" % self.op.remote_node)
3040 a8083063 Iustin Pop
    self.remote_node = remote_node
3041 a8083063 Iustin Pop
3042 a8083063 Iustin Pop
    if remote_node == instance.primary_node:
3043 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("The specified node is the primary node of"
3044 3ecf6786 Iustin Pop
                                 " the instance.")
3045 a8083063 Iustin Pop
3046 a8083063 Iustin Pop
    if instance.disk_template != constants.DT_REMOTE_RAID1:
3047 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance's disk layout is not"
3048 3ecf6786 Iustin Pop
                                 " remote_raid1.")
3049 a8083063 Iustin Pop
    for disk in instance.disks:
3050 a8083063 Iustin Pop
      if disk.iv_name == self.op.disk_name:
3051 a8083063 Iustin Pop
        break
3052 a8083063 Iustin Pop
    else:
3053 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Can't find this device ('%s') in the"
3054 3ecf6786 Iustin Pop
                                 " instance." % self.op.disk_name)
3055 a8083063 Iustin Pop
    if len(disk.children) > 1:
3056 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("The device already has two slave"
3057 3ecf6786 Iustin Pop
                                 " devices.\n"
3058 3ecf6786 Iustin Pop
                                 "This would create a 3-disk raid1"
3059 3ecf6786 Iustin Pop
                                 " which we don't allow.")
3060 a8083063 Iustin Pop
    self.disk = disk
3061 a8083063 Iustin Pop
3062 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
3063 a8083063 Iustin Pop
    """Add the mirror component
3064 a8083063 Iustin Pop

3065 a8083063 Iustin Pop
    """
3066 a8083063 Iustin Pop
    disk = self.disk
3067 a8083063 Iustin Pop
    instance = self.instance
3068 a8083063 Iustin Pop
3069 a8083063 Iustin Pop
    remote_node = self.remote_node
3070 923b1523 Iustin Pop
    lv_names = [".%s_%s" % (disk.iv_name, suf) for suf in ["data", "meta"]]
3071 923b1523 Iustin Pop
    names = _GenerateUniqueNames(self.cfg, lv_names)
3072 923b1523 Iustin Pop
    new_drbd = _GenerateMDDRBDBranch(self.cfg, instance.primary_node,
3073 923b1523 Iustin Pop
                                     remote_node, disk.size, names)
3074 a8083063 Iustin Pop
3075 a8083063 Iustin Pop
    logger.Info("adding new mirror component on secondary")
3076 a8083063 Iustin Pop
    #HARDCODE
3077 a0c3fea1 Michael Hanselmann
    if not _CreateBlockDevOnSecondary(self.cfg, remote_node, new_drbd, False,
3078 a0c3fea1 Michael Hanselmann
                                      _GetInstanceInfoText(instance)):
3079 3ecf6786 Iustin Pop
      raise errors.OpExecError("Failed to create new component on secondary"
3080 3ecf6786 Iustin Pop
                               " node %s" % remote_node)
3081 a8083063 Iustin Pop
3082 a8083063 Iustin Pop
    logger.Info("adding new mirror component on primary")
3083 a8083063 Iustin Pop
    #HARDCODE
3084 a0c3fea1 Michael Hanselmann
    if not _CreateBlockDevOnPrimary(self.cfg, instance.primary_node, new_drbd,
3085 a0c3fea1 Michael Hanselmann
                                    _GetInstanceInfoText(instance)):
3086 a8083063 Iustin Pop
      # remove secondary dev
3087 a8083063 Iustin Pop
      self.cfg.SetDiskID(new_drbd, remote_node)
3088 a8083063 Iustin Pop
      rpc.call_blockdev_remove(remote_node, new_drbd)
3089 3ecf6786 Iustin Pop
      raise errors.OpExecError("Failed to create volume on primary")
3090 a8083063 Iustin Pop
3091 a8083063 Iustin Pop
    # the device exists now
3092 a8083063 Iustin Pop
    # call the primary node to add the mirror to md
3093 a8083063 Iustin Pop
    logger.Info("adding new mirror component to md")
3094 a8083063 Iustin Pop
    if not rpc.call_blockdev_addchild(instance.primary_node,
3095 a8083063 Iustin Pop
                                           disk, new_drbd):
3096 a8083063 Iustin Pop
      logger.Error("Can't add mirror compoment to md!")
3097 a8083063 Iustin Pop
      self.cfg.SetDiskID(new_drbd, remote_node)
3098 a8083063 Iustin Pop
      if not rpc.call_blockdev_remove(remote_node, new_drbd):
3099 a8083063 Iustin Pop
        logger.Error("Can't rollback on secondary")
3100 a8083063 Iustin Pop
      self.cfg.SetDiskID(new_drbd, instance.primary_node)
3101 a8083063 Iustin Pop
      if not rpc.call_blockdev_remove(instance.primary_node, new_drbd):
3102 a8083063 Iustin Pop
        logger.Error("Can't rollback on primary")
3103 3ecf6786 Iustin Pop
      raise errors.OpExecError("Can't add mirror component to md array")
3104 a8083063 Iustin Pop
3105 a8083063 Iustin Pop
    disk.children.append(new_drbd)
3106 a8083063 Iustin Pop
3107 a8083063 Iustin Pop
    self.cfg.AddInstance(instance)
3108 a8083063 Iustin Pop
3109 a8083063 Iustin Pop
    _WaitForSync(self.cfg, instance)
3110 a8083063 Iustin Pop
3111 a8083063 Iustin Pop
    return 0
3112 a8083063 Iustin Pop
3113 a8083063 Iustin Pop
3114 a8083063 Iustin Pop
class LURemoveMDDRBDComponent(LogicalUnit):
3115 a8083063 Iustin Pop
  """Remove a component from a remote_raid1 disk.
3116 a8083063 Iustin Pop

3117 a8083063 Iustin Pop
  """
3118 a8083063 Iustin Pop
  HPATH = "mirror-remove"
3119 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
3120 a8083063 Iustin Pop
  _OP_REQP = ["instance_name", "disk_name", "disk_id"]
3121 a8083063 Iustin Pop
3122 a8083063 Iustin Pop
  def BuildHooksEnv(self):
3123 a8083063 Iustin Pop
    """Build hooks env.
3124 a8083063 Iustin Pop

3125 a8083063 Iustin Pop
    This runs on the master, the primary and all the secondaries.
3126 a8083063 Iustin Pop

3127 a8083063 Iustin Pop
    """
3128 a8083063 Iustin Pop
    env = {
3129 a8083063 Iustin Pop
      "DISK_NAME": self.op.disk_name,
3130 a8083063 Iustin Pop
      "DISK_ID": self.op.disk_id,
3131 a8083063 Iustin Pop
      "OLD_SECONDARY": self.old_secondary,
3132 a8083063 Iustin Pop
      }
3133 396e1b78 Michael Hanselmann
    env.update(_BuildInstanceHookEnvByObject(self.instance))
3134 880478f8 Iustin Pop
    nl = [self.sstore.GetMasterNode(),
3135 a8083063 Iustin Pop
          self.instance.primary_node] + list(self.instance.secondary_nodes)
3136 a8083063 Iustin Pop
    return env, nl, nl
3137 a8083063 Iustin Pop
3138 a8083063 Iustin Pop
  def CheckPrereq(self):
3139 a8083063 Iustin Pop
    """Check prerequisites.
3140 a8083063 Iustin Pop

3141 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
3142 a8083063 Iustin Pop

3143 a8083063 Iustin Pop
    """
3144 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
3145 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
3146 a8083063 Iustin Pop
    if instance is None:
3147 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
3148 3ecf6786 Iustin Pop
                                 self.op.instance_name)
3149 a8083063 Iustin Pop
    self.instance = instance
3150 a8083063 Iustin Pop
3151 a8083063 Iustin Pop
    if instance.disk_template != constants.DT_REMOTE_RAID1:
3152 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance's disk layout is not"
3153 3ecf6786 Iustin Pop
                                 " remote_raid1.")
3154 a8083063 Iustin Pop
    for disk in instance.disks:
3155 a8083063 Iustin Pop
      if disk.iv_name == self.op.disk_name:
3156 a8083063 Iustin Pop
        break
3157 a8083063 Iustin Pop
    else:
3158 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Can't find this device ('%s') in the"
3159 3ecf6786 Iustin Pop
                                 " instance." % self.op.disk_name)
3160 a8083063 Iustin Pop
    for child in disk.children:
3161 a8083063 Iustin Pop
      if child.dev_type == "drbd" and child.logical_id[2] == self.op.disk_id:
3162 a8083063 Iustin Pop
        break
3163 a8083063 Iustin Pop
    else:
3164 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Can't find the device with this port.")
3165 a8083063 Iustin Pop
3166 a8083063 Iustin Pop
    if len(disk.children) < 2:
3167 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Cannot remove the last component from"
3168 3ecf6786 Iustin Pop
                                 " a mirror.")
3169 a8083063 Iustin Pop
    self.disk = disk
3170 a8083063 Iustin Pop
    self.child = child
3171 a8083063 Iustin Pop
    if self.child.logical_id[0] == instance.primary_node:
3172 a8083063 Iustin Pop
      oid = 1
3173 a8083063 Iustin Pop
    else:
3174 a8083063 Iustin Pop
      oid = 0
3175 a8083063 Iustin Pop
    self.old_secondary = self.child.logical_id[oid]
3176 a8083063 Iustin Pop
3177 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
3178 a8083063 Iustin Pop
    """Remove the mirror component
3179 a8083063 Iustin Pop

3180 a8083063 Iustin Pop
    """
3181 a8083063 Iustin Pop
    instance = self.instance
3182 a8083063 Iustin Pop
    disk = self.disk
3183 a8083063 Iustin Pop
    child = self.child
3184 a8083063 Iustin Pop
    logger.Info("remove mirror component")
3185 a8083063 Iustin Pop
    self.cfg.SetDiskID(disk, instance.primary_node)
3186 a8083063 Iustin Pop
    if not rpc.call_blockdev_removechild(instance.primary_node,
3187 a8083063 Iustin Pop
                                              disk, child):
3188 3ecf6786 Iustin Pop
      raise errors.OpExecError("Can't remove child from mirror.")
3189 a8083063 Iustin Pop
3190 a8083063 Iustin Pop
    for node in child.logical_id[:2]:
3191 a8083063 Iustin Pop
      self.cfg.SetDiskID(child, node)
3192 a8083063 Iustin Pop
      if not rpc.call_blockdev_remove(node, child):
3193 a8083063 Iustin Pop
        logger.Error("Warning: failed to remove device from node %s,"
3194 a8083063 Iustin Pop
                     " continuing operation." % node)
3195 a8083063 Iustin Pop
3196 a8083063 Iustin Pop
    disk.children.remove(child)
3197 a8083063 Iustin Pop
    self.cfg.AddInstance(instance)
3198 a8083063 Iustin Pop
3199 a8083063 Iustin Pop
3200 a8083063 Iustin Pop
class LUReplaceDisks(LogicalUnit):
3201 a8083063 Iustin Pop
  """Replace the disks of an instance.
3202 a8083063 Iustin Pop

3203 a8083063 Iustin Pop
  """
3204 a8083063 Iustin Pop
  HPATH = "mirrors-replace"
3205 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
3206 a8083063 Iustin Pop
  _OP_REQP = ["instance_name"]
3207 a8083063 Iustin Pop
3208 a8083063 Iustin Pop
  def BuildHooksEnv(self):
3209 a8083063 Iustin Pop
    """Build hooks env.
3210 a8083063 Iustin Pop

3211 a8083063 Iustin Pop
    This runs on the master, the primary and all the secondaries.
3212 a8083063 Iustin Pop

3213 a8083063 Iustin Pop
    """
3214 a8083063 Iustin Pop
    env = {
3215 a8083063 Iustin Pop
      "NEW_SECONDARY": self.op.remote_node,
3216 a8083063 Iustin Pop
      "OLD_SECONDARY": self.instance.secondary_nodes[0],
3217 a8083063 Iustin Pop
      }
3218 396e1b78 Michael Hanselmann
    env.update(_BuildInstanceHookEnvByObject(self.instance))
3219 880478f8 Iustin Pop
    nl = [self.sstore.GetMasterNode(),
3220 a8083063 Iustin Pop
          self.instance.primary_node] + list(self.instance.secondary_nodes)
3221 a8083063 Iustin Pop
    return env, nl, nl
3222 a8083063 Iustin Pop
3223 a8083063 Iustin Pop
  def CheckPrereq(self):
3224 a8083063 Iustin Pop
    """Check prerequisites.
3225 a8083063 Iustin Pop

3226 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
3227 a8083063 Iustin Pop

3228 a8083063 Iustin Pop
    """
3229 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
3230 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
3231 a8083063 Iustin Pop
    if instance is None:
3232 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
3233 3ecf6786 Iustin Pop
                                 self.op.instance_name)
3234 a8083063 Iustin Pop
    self.instance = instance
3235 a8083063 Iustin Pop
3236 a8083063 Iustin Pop
    if instance.disk_template != constants.DT_REMOTE_RAID1:
3237 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance's disk layout is not"
3238 3ecf6786 Iustin Pop
                                 " remote_raid1.")
3239 a8083063 Iustin Pop
3240 a8083063 Iustin Pop
    if len(instance.secondary_nodes) != 1:
3241 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("The instance has a strange layout,"
3242 3ecf6786 Iustin Pop
                                 " expected one secondary but found %d" %
3243 3ecf6786 Iustin Pop
                                 len(instance.secondary_nodes))
3244 a8083063 Iustin Pop
3245 a8083063 Iustin Pop
    remote_node = getattr(self.op, "remote_node", None)
3246 a8083063 Iustin Pop
    if remote_node is None:
3247 a8083063 Iustin Pop
      remote_node = instance.secondary_nodes[0]
3248 a8083063 Iustin Pop
    else:
3249 a8083063 Iustin Pop
      remote_node = self.cfg.ExpandNodeName(remote_node)
3250 a8083063 Iustin Pop
      if remote_node is None:
3251 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Node '%s' not known" %
3252 3ecf6786 Iustin Pop
                                   self.op.remote_node)
3253 a8083063 Iustin Pop
    if remote_node == instance.primary_node:
3254 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("The specified node is the primary node of"
3255 3ecf6786 Iustin Pop
                                 " the instance.")
3256 a8083063 Iustin Pop
    self.op.remote_node = remote_node
3257 a8083063 Iustin Pop
3258 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
3259 a8083063 Iustin Pop
    """Replace the disks of an instance.
3260 a8083063 Iustin Pop

3261 a8083063 Iustin Pop
    """
3262 a8083063 Iustin Pop
    instance = self.instance
3263 a8083063 Iustin Pop
    iv_names = {}
3264 a8083063 Iustin Pop
    # start of work
3265 a8083063 Iustin Pop
    remote_node = self.op.remote_node
3266 a8083063 Iustin Pop
    cfg = self.cfg
3267 a8083063 Iustin Pop
    for dev in instance.disks:
3268 a8083063 Iustin Pop
      size = dev.size
3269 923b1523 Iustin Pop
      lv_names = [".%s_%s" % (dev.iv_name, suf) for suf in ["data", "meta"]]
3270 923b1523 Iustin Pop
      names = _GenerateUniqueNames(cfg, lv_names)
3271 923b1523 Iustin Pop
      new_drbd = _GenerateMDDRBDBranch(cfg, instance.primary_node,
3272 923b1523 Iustin Pop
                                       remote_node, size, names)
3273 a8083063 Iustin Pop
      iv_names[dev.iv_name] = (dev, dev.children[0], new_drbd)
3274 a8083063 Iustin Pop
      logger.Info("adding new mirror component on secondary for %s" %
3275 a8083063 Iustin Pop
                  dev.iv_name)
3276 a8083063 Iustin Pop
      #HARDCODE
3277 a0c3fea1 Michael Hanselmann
      if not _CreateBlockDevOnSecondary(cfg, remote_node, new_drbd, False,
3278 a0c3fea1 Michael Hanselmann
                                        _GetInstanceInfoText(instance)):
3279 3ecf6786 Iustin Pop
        raise errors.OpExecError("Failed to create new component on"
3280 3ecf6786 Iustin Pop
                                 " secondary node %s\n"
3281 3ecf6786 Iustin Pop
                                 "Full abort, cleanup manually!" %
3282 3ecf6786 Iustin Pop
                                 remote_node)
3283 a8083063 Iustin Pop
3284 a8083063 Iustin Pop
      logger.Info("adding new mirror component on primary")
3285 a8083063 Iustin Pop
      #HARDCODE
3286 a0c3fea1 Michael Hanselmann
      if not _CreateBlockDevOnPrimary(cfg, instance.primary_node, new_drbd,
3287 a0c3fea1 Michael Hanselmann
                                      _GetInstanceInfoText(instance)):
3288 a8083063 Iustin Pop
        # remove secondary dev
3289 a8083063 Iustin Pop
        cfg.SetDiskID(new_drbd, remote_node)
3290 a8083063 Iustin Pop
        rpc.call_blockdev_remove(remote_node, new_drbd)
3291 a8083063 Iustin Pop
        raise errors.OpExecError("Failed to create volume on primary!\n"
3292 a8083063 Iustin Pop
                                 "Full abort, cleanup manually!!")
3293 a8083063 Iustin Pop
3294 a8083063 Iustin Pop
      # the device exists now
3295 a8083063 Iustin Pop
      # call the primary node to add the mirror to md
3296 a8083063 Iustin Pop
      logger.Info("adding new mirror component to md")
3297 a8083063 Iustin Pop
      if not rpc.call_blockdev_addchild(instance.primary_node, dev,
3298 880478f8 Iustin Pop
                                        new_drbd):
3299 a8083063 Iustin Pop
        logger.Error("Can't add mirror compoment to md!")
3300 a8083063 Iustin Pop
        cfg.SetDiskID(new_drbd, remote_node)
3301 a8083063 Iustin Pop
        if not rpc.call_blockdev_remove(remote_node, new_drbd):
3302 a8083063 Iustin Pop
          logger.Error("Can't rollback on secondary")
3303 a8083063 Iustin Pop
        cfg.SetDiskID(new_drbd, instance.primary_node)
3304 a8083063 Iustin Pop
        if not rpc.call_blockdev_remove(instance.primary_node, new_drbd):
3305 a8083063 Iustin Pop
          logger.Error("Can't rollback on primary")
3306 3ecf6786 Iustin Pop
        raise errors.OpExecError("Full abort, cleanup manually!!")
3307 a8083063 Iustin Pop
3308 a8083063 Iustin Pop
      dev.children.append(new_drbd)
3309 a8083063 Iustin Pop
      cfg.AddInstance(instance)
3310 a8083063 Iustin Pop
3311 a8083063 Iustin Pop
    # this can fail as the old devices are degraded and _WaitForSync
3312 a8083063 Iustin Pop
    # does a combined result over all disks, so we don't check its
3313 a8083063 Iustin Pop
    # return value
3314 a8083063 Iustin Pop
    _WaitForSync(cfg, instance, unlock=True)
3315 a8083063 Iustin Pop
3316 a8083063 Iustin Pop
    # so check manually all the devices
3317 a8083063 Iustin Pop
    for name in iv_names:
3318 a8083063 Iustin Pop
      dev, child, new_drbd = iv_names[name]
3319 a8083063 Iustin Pop
      cfg.SetDiskID(dev, instance.primary_node)
3320 a8083063 Iustin Pop
      is_degr = rpc.call_blockdev_find(instance.primary_node, dev)[5]
3321 a8083063 Iustin Pop
      if is_degr:
3322 3ecf6786 Iustin Pop
        raise errors.OpExecError("MD device %s is degraded!" % name)
3323 a8083063 Iustin Pop
      cfg.SetDiskID(new_drbd, instance.primary_node)
3324 a8083063 Iustin Pop
      is_degr = rpc.call_blockdev_find(instance.primary_node, new_drbd)[5]
3325 a8083063 Iustin Pop
      if is_degr:
3326 3ecf6786 Iustin Pop
        raise errors.OpExecError("New drbd device %s is degraded!" % name)
3327 a8083063 Iustin Pop
3328 a8083063 Iustin Pop
    for name in iv_names:
3329 a8083063 Iustin Pop
      dev, child, new_drbd = iv_names[name]
3330 a8083063 Iustin Pop
      logger.Info("remove mirror %s component" % name)
3331 a8083063 Iustin Pop
      cfg.SetDiskID(dev, instance.primary_node)
3332 a8083063 Iustin Pop
      if not rpc.call_blockdev_removechild(instance.primary_node,
3333 a8083063 Iustin Pop
                                                dev, child):
3334 a8083063 Iustin Pop
        logger.Error("Can't remove child from mirror, aborting"
3335 a8083063 Iustin Pop
                     " *this device cleanup*.\nYou need to cleanup manually!!")
3336 a8083063 Iustin Pop
        continue
3337 a8083063 Iustin Pop
3338 a8083063 Iustin Pop
      for node in child.logical_id[:2]:
3339 a8083063 Iustin Pop
        logger.Info("remove child device on %s" % node)
3340 a8083063 Iustin Pop
        cfg.SetDiskID(child, node)
3341 a8083063 Iustin Pop
        if not rpc.call_blockdev_remove(node, child):
3342 a8083063 Iustin Pop
          logger.Error("Warning: failed to remove device from node %s,"
3343 a8083063 Iustin Pop
                       " continuing operation." % node)
3344 a8083063 Iustin Pop
3345 a8083063 Iustin Pop
      dev.children.remove(child)
3346 a8083063 Iustin Pop
3347 a8083063 Iustin Pop
      cfg.AddInstance(instance)
3348 a8083063 Iustin Pop
3349 a8083063 Iustin Pop
3350 a8083063 Iustin Pop
class LUQueryInstanceData(NoHooksLU):
3351 a8083063 Iustin Pop
  """Query runtime instance data.
3352 a8083063 Iustin Pop

3353 a8083063 Iustin Pop
  """
3354 a8083063 Iustin Pop
  _OP_REQP = ["instances"]
3355 a8083063 Iustin Pop
3356 a8083063 Iustin Pop
  def CheckPrereq(self):
3357 a8083063 Iustin Pop
    """Check prerequisites.
3358 a8083063 Iustin Pop

3359 a8083063 Iustin Pop
    This only checks the optional instance list against the existing names.
3360 a8083063 Iustin Pop

3361 a8083063 Iustin Pop
    """
3362 a8083063 Iustin Pop
    if not isinstance(self.op.instances, list):
3363 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Invalid argument type 'instances'")
3364 a8083063 Iustin Pop
    if self.op.instances:
3365 a8083063 Iustin Pop
      self.wanted_instances = []
3366 a8083063 Iustin Pop
      names = self.op.instances
3367 a8083063 Iustin Pop
      for name in names:
3368 a8083063 Iustin Pop
        instance = self.cfg.GetInstanceInfo(self.cfg.ExpandInstanceName(name))
3369 a8083063 Iustin Pop
        if instance is None:
3370 3ecf6786 Iustin Pop
          raise errors.OpPrereqError("No such instance name '%s'" % name)
3371 a8083063 Iustin Pop
      self.wanted_instances.append(instance)
3372 a8083063 Iustin Pop
    else:
3373 a8083063 Iustin Pop
      self.wanted_instances = [self.cfg.GetInstanceInfo(name) for name
3374 a8083063 Iustin Pop
                               in self.cfg.GetInstanceList()]
3375 a8083063 Iustin Pop
    return
3376 a8083063 Iustin Pop
3377 a8083063 Iustin Pop
3378 a8083063 Iustin Pop
  def _ComputeDiskStatus(self, instance, snode, dev):
3379 a8083063 Iustin Pop
    """Compute block device status.
3380 a8083063 Iustin Pop

3381 a8083063 Iustin Pop
    """
3382 a8083063 Iustin Pop
    self.cfg.SetDiskID(dev, instance.primary_node)
3383 a8083063 Iustin Pop
    dev_pstatus = rpc.call_blockdev_find(instance.primary_node, dev)
3384 a8083063 Iustin Pop
    if dev.dev_type == "drbd":
3385 a8083063 Iustin Pop
      # we change the snode then (otherwise we use the one passed in)
3386 a8083063 Iustin Pop
      if dev.logical_id[0] == instance.primary_node:
3387 a8083063 Iustin Pop
        snode = dev.logical_id[1]
3388 a8083063 Iustin Pop
      else:
3389 a8083063 Iustin Pop
        snode = dev.logical_id[0]
3390 a8083063 Iustin Pop
3391 a8083063 Iustin Pop
    if snode:
3392 a8083063 Iustin Pop
      self.cfg.SetDiskID(dev, snode)
3393 a8083063 Iustin Pop
      dev_sstatus = rpc.call_blockdev_find(snode, dev)
3394 a8083063 Iustin Pop
    else:
3395 a8083063 Iustin Pop
      dev_sstatus = None
3396 a8083063 Iustin Pop
3397 a8083063 Iustin Pop
    if dev.children:
3398 a8083063 Iustin Pop
      dev_children = [self._ComputeDiskStatus(instance, snode, child)
3399 a8083063 Iustin Pop
                      for child in dev.children]
3400 a8083063 Iustin Pop
    else:
3401 a8083063 Iustin Pop
      dev_children = []
3402 a8083063 Iustin Pop
3403 a8083063 Iustin Pop
    data = {
3404 a8083063 Iustin Pop
      "iv_name": dev.iv_name,
3405 a8083063 Iustin Pop
      "dev_type": dev.dev_type,
3406 a8083063 Iustin Pop
      "logical_id": dev.logical_id,
3407 a8083063 Iustin Pop
      "physical_id": dev.physical_id,
3408 a8083063 Iustin Pop
      "pstatus": dev_pstatus,
3409 a8083063 Iustin Pop
      "sstatus": dev_sstatus,
3410 a8083063 Iustin Pop
      "children": dev_children,
3411 a8083063 Iustin Pop
      }
3412 a8083063 Iustin Pop
3413 a8083063 Iustin Pop
    return data
3414 a8083063 Iustin Pop
3415 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
3416 a8083063 Iustin Pop
    """Gather and return data"""
3417 a8083063 Iustin Pop
    result = {}
3418 a8083063 Iustin Pop
    for instance in self.wanted_instances:
3419 a8083063 Iustin Pop
      remote_info = rpc.call_instance_info(instance.primary_node,
3420 a8083063 Iustin Pop
                                                instance.name)
3421 a8083063 Iustin Pop
      if remote_info and "state" in remote_info:
3422 a8083063 Iustin Pop
        remote_state = "up"
3423 a8083063 Iustin Pop
      else:
3424 a8083063 Iustin Pop
        remote_state = "down"
3425 a8083063 Iustin Pop
      if instance.status == "down":
3426 a8083063 Iustin Pop
        config_state = "down"
3427 a8083063 Iustin Pop
      else:
3428 a8083063 Iustin Pop
        config_state = "up"
3429 a8083063 Iustin Pop
3430 a8083063 Iustin Pop
      disks = [self._ComputeDiskStatus(instance, None, device)
3431 a8083063 Iustin Pop
               for device in instance.disks]
3432 a8083063 Iustin Pop
3433 a8083063 Iustin Pop
      idict = {
3434 a8083063 Iustin Pop
        "name": instance.name,
3435 a8083063 Iustin Pop
        "config_state": config_state,
3436 a8083063 Iustin Pop
        "run_state": remote_state,
3437 a8083063 Iustin Pop
        "pnode": instance.primary_node,
3438 a8083063 Iustin Pop
        "snodes": instance.secondary_nodes,
3439 a8083063 Iustin Pop
        "os": instance.os,
3440 a8083063 Iustin Pop
        "memory": instance.memory,
3441 a8083063 Iustin Pop
        "nics": [(nic.mac, nic.ip, nic.bridge) for nic in instance.nics],
3442 a8083063 Iustin Pop
        "disks": disks,
3443 a8083063 Iustin Pop
        }
3444 a8083063 Iustin Pop
3445 a8083063 Iustin Pop
      result[instance.name] = idict
3446 a8083063 Iustin Pop
3447 a8083063 Iustin Pop
    return result
3448 a8083063 Iustin Pop
3449 a8083063 Iustin Pop
3450 a8083063 Iustin Pop
class LUSetInstanceParms(LogicalUnit):
3451 a8083063 Iustin Pop
  """Modifies an instances's parameters.
3452 a8083063 Iustin Pop

3453 a8083063 Iustin Pop
  """
3454 a8083063 Iustin Pop
  HPATH = "instance-modify"
3455 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
3456 a8083063 Iustin Pop
  _OP_REQP = ["instance_name"]
3457 a8083063 Iustin Pop
3458 a8083063 Iustin Pop
  def BuildHooksEnv(self):
3459 a8083063 Iustin Pop
    """Build hooks env.
3460 a8083063 Iustin Pop

3461 a8083063 Iustin Pop
    This runs on the master, primary and secondaries.
3462 a8083063 Iustin Pop

3463 a8083063 Iustin Pop
    """
3464 396e1b78 Michael Hanselmann
    args = dict()
3465 a8083063 Iustin Pop
    if self.mem:
3466 396e1b78 Michael Hanselmann
      args['memory'] = self.mem
3467 a8083063 Iustin Pop
    if self.vcpus:
3468 396e1b78 Michael Hanselmann
      args['vcpus'] = self.vcpus
3469 396e1b78 Michael Hanselmann
    if self.do_ip or self.do_bridge:
3470 396e1b78 Michael Hanselmann
      if self.do_ip:
3471 396e1b78 Michael Hanselmann
        ip = self.ip
3472 396e1b78 Michael Hanselmann
      else:
3473 396e1b78 Michael Hanselmann
        ip = self.instance.nics[0].ip
3474 396e1b78 Michael Hanselmann
      if self.bridge:
3475 396e1b78 Michael Hanselmann
        bridge = self.bridge
3476 396e1b78 Michael Hanselmann
      else:
3477 396e1b78 Michael Hanselmann
        bridge = self.instance.nics[0].bridge
3478 396e1b78 Michael Hanselmann
      args['nics'] = [(ip, bridge)]
3479 396e1b78 Michael Hanselmann
    env = _BuildInstanceHookEnvByObject(self.instance, override=args)
3480 880478f8 Iustin Pop
    nl = [self.sstore.GetMasterNode(),
3481 a8083063 Iustin Pop
          self.instance.primary_node] + list(self.instance.secondary_nodes)
3482 a8083063 Iustin Pop
    return env, nl, nl
3483 a8083063 Iustin Pop
3484 a8083063 Iustin Pop
  def CheckPrereq(self):
3485 a8083063 Iustin Pop
    """Check prerequisites.
3486 a8083063 Iustin Pop

3487 a8083063 Iustin Pop
    This only checks the instance list against the existing names.
3488 a8083063 Iustin Pop

3489 a8083063 Iustin Pop
    """
3490 a8083063 Iustin Pop
    self.mem = getattr(self.op, "mem", None)
3491 a8083063 Iustin Pop
    self.vcpus = getattr(self.op, "vcpus", None)
3492 a8083063 Iustin Pop
    self.ip = getattr(self.op, "ip", None)
3493 a8083063 Iustin Pop
    self.bridge = getattr(self.op, "bridge", None)
3494 a8083063 Iustin Pop
    if [self.mem, self.vcpus, self.ip, self.bridge].count(None) == 4:
3495 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("No changes submitted")
3496 a8083063 Iustin Pop
    if self.mem is not None:
3497 a8083063 Iustin Pop
      try:
3498 a8083063 Iustin Pop
        self.mem = int(self.mem)
3499 a8083063 Iustin Pop
      except ValueError, err:
3500 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Invalid memory size: %s" % str(err))
3501 a8083063 Iustin Pop
    if self.vcpus is not None:
3502 a8083063 Iustin Pop
      try:
3503 a8083063 Iustin Pop
        self.vcpus = int(self.vcpus)
3504 a8083063 Iustin Pop
      except ValueError, err:
3505 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Invalid vcpus number: %s" % str(err))
3506 a8083063 Iustin Pop
    if self.ip is not None:
3507 a8083063 Iustin Pop
      self.do_ip = True
3508 a8083063 Iustin Pop
      if self.ip.lower() == "none":
3509 a8083063 Iustin Pop
        self.ip = None
3510 a8083063 Iustin Pop
      else:
3511 a8083063 Iustin Pop
        if not utils.IsValidIP(self.ip):
3512 3ecf6786 Iustin Pop
          raise errors.OpPrereqError("Invalid IP address '%s'." % self.ip)
3513 a8083063 Iustin Pop
    else:
3514 a8083063 Iustin Pop
      self.do_ip = False
3515 ecb215b5 Michael Hanselmann
    self.do_bridge = (self.bridge is not None)
3516 a8083063 Iustin Pop
3517 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
3518 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
3519 a8083063 Iustin Pop
    if instance is None:
3520 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("No such instance name '%s'" %
3521 3ecf6786 Iustin Pop
                                 self.op.instance_name)
3522 a8083063 Iustin Pop
    self.op.instance_name = instance.name
3523 a8083063 Iustin Pop
    self.instance = instance
3524 a8083063 Iustin Pop
    return
3525 a8083063 Iustin Pop
3526 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
3527 a8083063 Iustin Pop
    """Modifies an instance.
3528 a8083063 Iustin Pop

3529 a8083063 Iustin Pop
    All parameters take effect only at the next restart of the instance.
3530 a8083063 Iustin Pop
    """
3531 a8083063 Iustin Pop
    result = []
3532 a8083063 Iustin Pop
    instance = self.instance
3533 a8083063 Iustin Pop
    if self.mem:
3534 a8083063 Iustin Pop
      instance.memory = self.mem
3535 a8083063 Iustin Pop
      result.append(("mem", self.mem))
3536 a8083063 Iustin Pop
    if self.vcpus:
3537 a8083063 Iustin Pop
      instance.vcpus = self.vcpus
3538 a8083063 Iustin Pop
      result.append(("vcpus",  self.vcpus))
3539 a8083063 Iustin Pop
    if self.do_ip:
3540 a8083063 Iustin Pop
      instance.nics[0].ip = self.ip
3541 a8083063 Iustin Pop
      result.append(("ip", self.ip))
3542 a8083063 Iustin Pop
    if self.bridge:
3543 a8083063 Iustin Pop
      instance.nics[0].bridge = self.bridge
3544 a8083063 Iustin Pop
      result.append(("bridge", self.bridge))
3545 a8083063 Iustin Pop
3546 a8083063 Iustin Pop
    self.cfg.AddInstance(instance)
3547 a8083063 Iustin Pop
3548 a8083063 Iustin Pop
    return result
3549 a8083063 Iustin Pop
3550 a8083063 Iustin Pop
3551 a8083063 Iustin Pop
class LUQueryExports(NoHooksLU):
3552 a8083063 Iustin Pop
  """Query the exports list
3553 a8083063 Iustin Pop

3554 a8083063 Iustin Pop
  """
3555 a8083063 Iustin Pop
  _OP_REQP = []
3556 a8083063 Iustin Pop
3557 a8083063 Iustin Pop
  def CheckPrereq(self):
3558 a8083063 Iustin Pop
    """Check that the nodelist contains only existing nodes.
3559 a8083063 Iustin Pop

3560 a8083063 Iustin Pop
    """
3561 dcb93971 Michael Hanselmann
    self.nodes = _GetWantedNodes(self, getattr(self.op, "nodes", None))
3562 a8083063 Iustin Pop
3563 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
3564 a8083063 Iustin Pop
    """Compute the list of all the exported system images.
3565 a8083063 Iustin Pop

3566 a8083063 Iustin Pop
    Returns:
3567 a8083063 Iustin Pop
      a dictionary with the structure node->(export-list)
3568 a8083063 Iustin Pop
      where export-list is a list of the instances exported on
3569 a8083063 Iustin Pop
      that node.
3570 a8083063 Iustin Pop

3571 a8083063 Iustin Pop
    """
3572 a7ba5e53 Iustin Pop
    return rpc.call_export_list(self.nodes)
3573 a8083063 Iustin Pop
3574 a8083063 Iustin Pop
3575 a8083063 Iustin Pop
class LUExportInstance(LogicalUnit):
3576 a8083063 Iustin Pop
  """Export an instance to an image in the cluster.
3577 a8083063 Iustin Pop

3578 a8083063 Iustin Pop
  """
3579 a8083063 Iustin Pop
  HPATH = "instance-export"
3580 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
3581 a8083063 Iustin Pop
  _OP_REQP = ["instance_name", "target_node", "shutdown"]
3582 a8083063 Iustin Pop
3583 a8083063 Iustin Pop
  def BuildHooksEnv(self):
3584 a8083063 Iustin Pop
    """Build hooks env.
3585 a8083063 Iustin Pop

3586 a8083063 Iustin Pop
    This will run on the master, primary node and target node.
3587 a8083063 Iustin Pop

3588 a8083063 Iustin Pop
    """
3589 a8083063 Iustin Pop
    env = {
3590 a8083063 Iustin Pop
      "EXPORT_NODE": self.op.target_node,
3591 a8083063 Iustin Pop
      "EXPORT_DO_SHUTDOWN": self.op.shutdown,
3592 a8083063 Iustin Pop
      }
3593 396e1b78 Michael Hanselmann
    env.update(_BuildInstanceHookEnvByObject(self.instance))
3594 880478f8 Iustin Pop
    nl = [self.sstore.GetMasterNode(), self.instance.primary_node,
3595 a8083063 Iustin Pop
          self.op.target_node]
3596 a8083063 Iustin Pop
    return env, nl, nl
3597 a8083063 Iustin Pop
3598 a8083063 Iustin Pop
  def CheckPrereq(self):
3599 a8083063 Iustin Pop
    """Check prerequisites.
3600 a8083063 Iustin Pop

3601 a8083063 Iustin Pop
    This checks that the instance name is a valid one.
3602 a8083063 Iustin Pop

3603 a8083063 Iustin Pop
    """
3604 a8083063 Iustin Pop
    instance_name = self.cfg.ExpandInstanceName(self.op.instance_name)
3605 a8083063 Iustin Pop
    self.instance = self.cfg.GetInstanceInfo(instance_name)
3606 a8083063 Iustin Pop
    if self.instance is None:
3607 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not found" %
3608 3ecf6786 Iustin Pop
                                 self.op.instance_name)
3609 a8083063 Iustin Pop
3610 a8083063 Iustin Pop
    # node verification
3611 a8083063 Iustin Pop
    dst_node_short = self.cfg.ExpandNodeName(self.op.target_node)
3612 a8083063 Iustin Pop
    self.dst_node = self.cfg.GetNodeInfo(dst_node_short)
3613 a8083063 Iustin Pop
3614 a8083063 Iustin Pop
    if self.dst_node is None:
3615 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Destination node '%s' is unknown." %
3616 3ecf6786 Iustin Pop
                                 self.op.target_node)
3617 a8083063 Iustin Pop
    self.op.target_node = self.dst_node.name
3618 a8083063 Iustin Pop
3619 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
3620 a8083063 Iustin Pop
    """Export an instance to an image in the cluster.
3621 a8083063 Iustin Pop

3622 a8083063 Iustin Pop
    """
3623 a8083063 Iustin Pop
    instance = self.instance
3624 a8083063 Iustin Pop
    dst_node = self.dst_node
3625 a8083063 Iustin Pop
    src_node = instance.primary_node
3626 a8083063 Iustin Pop
    # shutdown the instance, unless requested not to do so
3627 a8083063 Iustin Pop
    if self.op.shutdown:
3628 a8083063 Iustin Pop
      op = opcodes.OpShutdownInstance(instance_name=instance.name)
3629 a8083063 Iustin Pop
      self.processor.ChainOpCode(op, feedback_fn)
3630 a8083063 Iustin Pop
3631 a8083063 Iustin Pop
    vgname = self.cfg.GetVGName()
3632 a8083063 Iustin Pop
3633 a8083063 Iustin Pop
    snap_disks = []
3634 a8083063 Iustin Pop
3635 a8083063 Iustin Pop
    try:
3636 a8083063 Iustin Pop
      for disk in instance.disks:
3637 a8083063 Iustin Pop
        if disk.iv_name == "sda":
3638 a8083063 Iustin Pop
          # new_dev_name will be a snapshot of an lvm leaf of the one we passed
3639 a8083063 Iustin Pop
          new_dev_name = rpc.call_blockdev_snapshot(src_node, disk)
3640 a8083063 Iustin Pop
3641 a8083063 Iustin Pop
          if not new_dev_name:
3642 a8083063 Iustin Pop
            logger.Error("could not snapshot block device %s on node %s" %
3643 a8083063 Iustin Pop
                         (disk.logical_id[1], src_node))
3644 a8083063 Iustin Pop
          else:
3645 a8083063 Iustin Pop
            new_dev = objects.Disk(dev_type="lvm", size=disk.size,
3646 a8083063 Iustin Pop
                                      logical_id=(vgname, new_dev_name),
3647 a8083063 Iustin Pop
                                      physical_id=(vgname, new_dev_name),
3648 a8083063 Iustin Pop
                                      iv_name=disk.iv_name)
3649 a8083063 Iustin Pop
            snap_disks.append(new_dev)
3650 a8083063 Iustin Pop
3651 a8083063 Iustin Pop
    finally:
3652 a8083063 Iustin Pop
      if self.op.shutdown:
3653 a8083063 Iustin Pop
        op = opcodes.OpStartupInstance(instance_name=instance.name,
3654 a8083063 Iustin Pop
                                       force=False)
3655 a8083063 Iustin Pop
        self.processor.ChainOpCode(op, feedback_fn)
3656 a8083063 Iustin Pop
3657 a8083063 Iustin Pop
    # TODO: check for size
3658 a8083063 Iustin Pop
3659 a8083063 Iustin Pop
    for dev in snap_disks:
3660 a8083063 Iustin Pop
      if not rpc.call_snapshot_export(src_node, dev, dst_node.name,
3661 a8083063 Iustin Pop
                                           instance):
3662 a8083063 Iustin Pop
        logger.Error("could not export block device %s from node"
3663 a8083063 Iustin Pop
                     " %s to node %s" %
3664 a8083063 Iustin Pop
                     (dev.logical_id[1], src_node, dst_node.name))
3665 a8083063 Iustin Pop
      if not rpc.call_blockdev_remove(src_node, dev):
3666 a8083063 Iustin Pop
        logger.Error("could not remove snapshot block device %s from"
3667 a8083063 Iustin Pop
                     " node %s" % (dev.logical_id[1], src_node))
3668 a8083063 Iustin Pop
3669 a8083063 Iustin Pop
    if not rpc.call_finalize_export(dst_node.name, instance, snap_disks):
3670 a8083063 Iustin Pop
      logger.Error("could not finalize export for instance %s on node %s" %
3671 a8083063 Iustin Pop
                   (instance.name, dst_node.name))
3672 a8083063 Iustin Pop
3673 a8083063 Iustin Pop
    nodelist = self.cfg.GetNodeList()
3674 a8083063 Iustin Pop
    nodelist.remove(dst_node.name)
3675 a8083063 Iustin Pop
3676 a8083063 Iustin Pop
    # on one-node clusters nodelist will be empty after the removal
3677 a8083063 Iustin Pop
    # if we proceed the backup would be removed because OpQueryExports
3678 a8083063 Iustin Pop
    # substitutes an empty list with the full cluster node list.
3679 a8083063 Iustin Pop
    if nodelist:
3680 a8083063 Iustin Pop
      op = opcodes.OpQueryExports(nodes=nodelist)
3681 a8083063 Iustin Pop
      exportlist = self.processor.ChainOpCode(op, feedback_fn)
3682 a8083063 Iustin Pop
      for node in exportlist:
3683 a8083063 Iustin Pop
        if instance.name in exportlist[node]:
3684 a8083063 Iustin Pop
          if not rpc.call_export_remove(node, instance.name):
3685 a8083063 Iustin Pop
            logger.Error("could not remove older export for instance %s"
3686 a8083063 Iustin Pop
                         " on node %s" % (instance.name, node))
3687 5c947f38 Iustin Pop
3688 5c947f38 Iustin Pop
3689 5c947f38 Iustin Pop
class TagsLU(NoHooksLU):
3690 5c947f38 Iustin Pop
  """Generic tags LU.
3691 5c947f38 Iustin Pop

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

3694 5c947f38 Iustin Pop
  """
3695 5c947f38 Iustin Pop
  def CheckPrereq(self):
3696 5c947f38 Iustin Pop
    """Check prerequisites.
3697 5c947f38 Iustin Pop

3698 5c947f38 Iustin Pop
    """
3699 5c947f38 Iustin Pop
    if self.op.kind == constants.TAG_CLUSTER:
3700 5c947f38 Iustin Pop
      self.target = self.cfg.GetClusterInfo()
3701 5c947f38 Iustin Pop
    elif self.op.kind == constants.TAG_NODE:
3702 5c947f38 Iustin Pop
      name = self.cfg.ExpandNodeName(self.op.name)
3703 5c947f38 Iustin Pop
      if name is None:
3704 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Invalid node name (%s)" %
3705 3ecf6786 Iustin Pop
                                   (self.op.name,))
3706 5c947f38 Iustin Pop
      self.op.name = name
3707 5c947f38 Iustin Pop
      self.target = self.cfg.GetNodeInfo(name)
3708 5c947f38 Iustin Pop
    elif self.op.kind == constants.TAG_INSTANCE:
3709 5c947f38 Iustin Pop
      name = self.cfg.ExpandInstanceName(name)
3710 5c947f38 Iustin Pop
      if name is None:
3711 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Invalid instance name (%s)" %
3712 3ecf6786 Iustin Pop
                                   (self.op.name,))
3713 5c947f38 Iustin Pop
      self.op.name = name
3714 5c947f38 Iustin Pop
      self.target = self.cfg.GetInstanceInfo(name)
3715 5c947f38 Iustin Pop
    else:
3716 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Wrong tag type requested (%s)" %
3717 3ecf6786 Iustin Pop
                                 str(self.op.kind))
3718 5c947f38 Iustin Pop
3719 5c947f38 Iustin Pop
3720 5c947f38 Iustin Pop
class LUGetTags(TagsLU):
3721 5c947f38 Iustin Pop
  """Returns the tags of a given object.
3722 5c947f38 Iustin Pop

3723 5c947f38 Iustin Pop
  """
3724 5c947f38 Iustin Pop
  _OP_REQP = ["kind", "name"]
3725 5c947f38 Iustin Pop
3726 5c947f38 Iustin Pop
  def Exec(self, feedback_fn):
3727 5c947f38 Iustin Pop
    """Returns the tag list.
3728 5c947f38 Iustin Pop

3729 5c947f38 Iustin Pop
    """
3730 5c947f38 Iustin Pop
    return self.target.GetTags()
3731 5c947f38 Iustin Pop
3732 5c947f38 Iustin Pop
3733 5c947f38 Iustin Pop
class LUAddTag(TagsLU):
3734 5c947f38 Iustin Pop
  """Sets a tag on a given object.
3735 5c947f38 Iustin Pop

3736 5c947f38 Iustin Pop
  """
3737 5c947f38 Iustin Pop
  _OP_REQP = ["kind", "name", "tag"]
3738 5c947f38 Iustin Pop
3739 5c947f38 Iustin Pop
  def CheckPrereq(self):
3740 5c947f38 Iustin Pop
    """Check prerequisites.
3741 5c947f38 Iustin Pop

3742 5c947f38 Iustin Pop
    This checks the type and length of the tag name and value.
3743 5c947f38 Iustin Pop

3744 5c947f38 Iustin Pop
    """
3745 5c947f38 Iustin Pop
    TagsLU.CheckPrereq(self)
3746 5c947f38 Iustin Pop
    objects.TaggableObject.ValidateTag(self.op.tag)
3747 5c947f38 Iustin Pop
3748 5c947f38 Iustin Pop
  def Exec(self, feedback_fn):
3749 5c947f38 Iustin Pop
    """Sets the tag.
3750 5c947f38 Iustin Pop

3751 5c947f38 Iustin Pop
    """
3752 5c947f38 Iustin Pop
    try:
3753 5c947f38 Iustin Pop
      self.target.AddTag(self.op.tag)
3754 5c947f38 Iustin Pop
    except errors.TagError, err:
3755 3ecf6786 Iustin Pop
      raise errors.OpExecError("Error while setting tag: %s" % str(err))
3756 5c947f38 Iustin Pop
    try:
3757 5c947f38 Iustin Pop
      self.cfg.Update(self.target)
3758 5c947f38 Iustin Pop
    except errors.ConfigurationError:
3759 3ecf6786 Iustin Pop
      raise errors.OpRetryError("There has been a modification to the"
3760 3ecf6786 Iustin Pop
                                " config file and the operation has been"
3761 3ecf6786 Iustin Pop
                                " aborted. Please retry.")
3762 5c947f38 Iustin Pop
3763 5c947f38 Iustin Pop
3764 5c947f38 Iustin Pop
class LUDelTag(TagsLU):
3765 5c947f38 Iustin Pop
  """Delete a tag from a given object.
3766 5c947f38 Iustin Pop

3767 5c947f38 Iustin Pop
  """
3768 5c947f38 Iustin Pop
  _OP_REQP = ["kind", "name", "tag"]
3769 5c947f38 Iustin Pop
3770 5c947f38 Iustin Pop
  def CheckPrereq(self):
3771 5c947f38 Iustin Pop
    """Check prerequisites.
3772 5c947f38 Iustin Pop

3773 5c947f38 Iustin Pop
    This checks that we have the given tag.
3774 5c947f38 Iustin Pop

3775 5c947f38 Iustin Pop
    """
3776 5c947f38 Iustin Pop
    TagsLU.CheckPrereq(self)
3777 5c947f38 Iustin Pop
    objects.TaggableObject.ValidateTag(self.op.tag)
3778 5c947f38 Iustin Pop
    if self.op.tag not in self.target.GetTags():
3779 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Tag not found")
3780 5c947f38 Iustin Pop
3781 5c947f38 Iustin Pop
  def Exec(self, feedback_fn):
3782 5c947f38 Iustin Pop
    """Remove the tag from the object.
3783 5c947f38 Iustin Pop

3784 5c947f38 Iustin Pop
    """
3785 5c947f38 Iustin Pop
    self.target.RemoveTag(self.op.tag)
3786 5c947f38 Iustin Pop
    try:
3787 5c947f38 Iustin Pop
      self.cfg.Update(self.target)
3788 5c947f38 Iustin Pop
    except errors.ConfigurationError:
3789 3ecf6786 Iustin Pop
      raise errors.OpRetryError("There has been a modification to the"
3790 3ecf6786 Iustin Pop
                                " config file and the operation has been"
3791 3ecf6786 Iustin Pop
                                " aborted. Please retry.")