Statistics
| Branch: | Tag: | Revision:

root / lib / cmdlib.py @ f362096f

History | View | Annotate | Download (144 kB)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

162 a8083063 Iustin Pop
    """
163 0e137c28 Iustin Pop
    return {}, [], []
164 a8083063 Iustin Pop
165 a8083063 Iustin Pop
166 9440aeab Michael Hanselmann
def _AddHostToEtcHosts(hostname):
167 9440aeab Michael Hanselmann
  """Wrapper around utils.SetEtcHostsEntry.
168 9440aeab Michael Hanselmann

169 9440aeab Michael Hanselmann
  """
170 9440aeab Michael Hanselmann
  hi = utils.HostInfo(name=hostname)
171 9440aeab Michael Hanselmann
  utils.SetEtcHostsEntry(constants.ETC_HOSTS, hi.ip, hi.name, [hi.ShortName()])
172 9440aeab Michael Hanselmann
173 9440aeab Michael Hanselmann
174 c8a0948f Michael Hanselmann
def _RemoveHostFromEtcHosts(hostname):
175 9440aeab Michael Hanselmann
  """Wrapper around utils.RemoveEtcHostsEntry.
176 c8a0948f Michael Hanselmann

177 c8a0948f Michael Hanselmann
  """
178 c8a0948f Michael Hanselmann
  hi = utils.HostInfo(name=hostname)
179 c8a0948f Michael Hanselmann
  utils.RemoveEtcHostsEntry(constants.ETC_HOSTS, hi.name)
180 c8a0948f Michael Hanselmann
  utils.RemoveEtcHostsEntry(constants.ETC_HOSTS, hi.ShortName())
181 c8a0948f Michael Hanselmann
182 c8a0948f Michael Hanselmann
183 dcb93971 Michael Hanselmann
def _GetWantedNodes(lu, nodes):
184 a7ba5e53 Iustin Pop
  """Returns list of checked and expanded node names.
185 83120a01 Michael Hanselmann

186 83120a01 Michael Hanselmann
  Args:
187 83120a01 Michael Hanselmann
    nodes: List of nodes (strings) or None for all
188 83120a01 Michael Hanselmann

189 83120a01 Michael Hanselmann
  """
190 3312b702 Iustin Pop
  if not isinstance(nodes, list):
191 3ecf6786 Iustin Pop
    raise errors.OpPrereqError("Invalid argument type 'nodes'")
192 dcb93971 Michael Hanselmann
193 dcb93971 Michael Hanselmann
  if nodes:
194 3312b702 Iustin Pop
    wanted = []
195 dcb93971 Michael Hanselmann
196 dcb93971 Michael Hanselmann
    for name in nodes:
197 a7ba5e53 Iustin Pop
      node = lu.cfg.ExpandNodeName(name)
198 dcb93971 Michael Hanselmann
      if node is None:
199 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("No such node name '%s'" % name)
200 3312b702 Iustin Pop
      wanted.append(node)
201 dcb93971 Michael Hanselmann
202 dcb93971 Michael Hanselmann
  else:
203 a7ba5e53 Iustin Pop
    wanted = lu.cfg.GetNodeList()
204 a7ba5e53 Iustin Pop
  return utils.NiceSort(wanted)
205 3312b702 Iustin Pop
206 3312b702 Iustin Pop
207 3312b702 Iustin Pop
def _GetWantedInstances(lu, instances):
208 a7ba5e53 Iustin Pop
  """Returns list of checked and expanded instance names.
209 3312b702 Iustin Pop

210 3312b702 Iustin Pop
  Args:
211 3312b702 Iustin Pop
    instances: List of instances (strings) or None for all
212 3312b702 Iustin Pop

213 3312b702 Iustin Pop
  """
214 3312b702 Iustin Pop
  if not isinstance(instances, list):
215 3312b702 Iustin Pop
    raise errors.OpPrereqError("Invalid argument type 'instances'")
216 3312b702 Iustin Pop
217 3312b702 Iustin Pop
  if instances:
218 3312b702 Iustin Pop
    wanted = []
219 3312b702 Iustin Pop
220 3312b702 Iustin Pop
    for name in instances:
221 a7ba5e53 Iustin Pop
      instance = lu.cfg.ExpandInstanceName(name)
222 3312b702 Iustin Pop
      if instance is None:
223 3312b702 Iustin Pop
        raise errors.OpPrereqError("No such instance name '%s'" % name)
224 3312b702 Iustin Pop
      wanted.append(instance)
225 3312b702 Iustin Pop
226 3312b702 Iustin Pop
  else:
227 a7ba5e53 Iustin Pop
    wanted = lu.cfg.GetInstanceList()
228 a7ba5e53 Iustin Pop
  return utils.NiceSort(wanted)
229 dcb93971 Michael Hanselmann
230 dcb93971 Michael Hanselmann
231 dcb93971 Michael Hanselmann
def _CheckOutputFields(static, dynamic, selected):
232 83120a01 Michael Hanselmann
  """Checks whether all selected fields are valid.
233 83120a01 Michael Hanselmann

234 83120a01 Michael Hanselmann
  Args:
235 83120a01 Michael Hanselmann
    static: Static fields
236 83120a01 Michael Hanselmann
    dynamic: Dynamic fields
237 83120a01 Michael Hanselmann

238 83120a01 Michael Hanselmann
  """
239 83120a01 Michael Hanselmann
  static_fields = frozenset(static)
240 83120a01 Michael Hanselmann
  dynamic_fields = frozenset(dynamic)
241 dcb93971 Michael Hanselmann
242 83120a01 Michael Hanselmann
  all_fields = static_fields | dynamic_fields
243 dcb93971 Michael Hanselmann
244 83120a01 Michael Hanselmann
  if not all_fields.issuperset(selected):
245 3ecf6786 Iustin Pop
    raise errors.OpPrereqError("Unknown output fields selected: %s"
246 3ecf6786 Iustin Pop
                               % ",".join(frozenset(selected).
247 3ecf6786 Iustin Pop
                                          difference(all_fields)))
248 dcb93971 Michael Hanselmann
249 dcb93971 Michael Hanselmann
250 ecb215b5 Michael Hanselmann
def _BuildInstanceHookEnv(name, primary_node, secondary_nodes, os_type, status,
251 396e1b78 Michael Hanselmann
                          memory, vcpus, nics):
252 ecb215b5 Michael Hanselmann
  """Builds instance related env variables for hooks from single variables.
253 ecb215b5 Michael Hanselmann

254 ecb215b5 Michael Hanselmann
  Args:
255 ecb215b5 Michael Hanselmann
    secondary_nodes: List of secondary nodes as strings
256 396e1b78 Michael Hanselmann
  """
257 396e1b78 Michael Hanselmann
  env = {
258 0e137c28 Iustin Pop
    "OP_TARGET": name,
259 396e1b78 Michael Hanselmann
    "INSTANCE_NAME": name,
260 396e1b78 Michael Hanselmann
    "INSTANCE_PRIMARY": primary_node,
261 396e1b78 Michael Hanselmann
    "INSTANCE_SECONDARIES": " ".join(secondary_nodes),
262 ecb215b5 Michael Hanselmann
    "INSTANCE_OS_TYPE": os_type,
263 396e1b78 Michael Hanselmann
    "INSTANCE_STATUS": status,
264 396e1b78 Michael Hanselmann
    "INSTANCE_MEMORY": memory,
265 396e1b78 Michael Hanselmann
    "INSTANCE_VCPUS": vcpus,
266 396e1b78 Michael Hanselmann
  }
267 396e1b78 Michael Hanselmann
268 396e1b78 Michael Hanselmann
  if nics:
269 396e1b78 Michael Hanselmann
    nic_count = len(nics)
270 396e1b78 Michael Hanselmann
    for idx, (ip, bridge) in enumerate(nics):
271 396e1b78 Michael Hanselmann
      if ip is None:
272 396e1b78 Michael Hanselmann
        ip = ""
273 396e1b78 Michael Hanselmann
      env["INSTANCE_NIC%d_IP" % idx] = ip
274 396e1b78 Michael Hanselmann
      env["INSTANCE_NIC%d_BRIDGE" % idx] = bridge
275 396e1b78 Michael Hanselmann
  else:
276 396e1b78 Michael Hanselmann
    nic_count = 0
277 396e1b78 Michael Hanselmann
278 396e1b78 Michael Hanselmann
  env["INSTANCE_NIC_COUNT"] = nic_count
279 396e1b78 Michael Hanselmann
280 396e1b78 Michael Hanselmann
  return env
281 396e1b78 Michael Hanselmann
282 396e1b78 Michael Hanselmann
283 396e1b78 Michael Hanselmann
def _BuildInstanceHookEnvByObject(instance, override=None):
284 ecb215b5 Michael Hanselmann
  """Builds instance related env variables for hooks from an object.
285 ecb215b5 Michael Hanselmann

286 ecb215b5 Michael Hanselmann
  Args:
287 ecb215b5 Michael Hanselmann
    instance: objects.Instance object of instance
288 ecb215b5 Michael Hanselmann
    override: dict of values to override
289 ecb215b5 Michael Hanselmann
  """
290 396e1b78 Michael Hanselmann
  args = {
291 396e1b78 Michael Hanselmann
    'name': instance.name,
292 396e1b78 Michael Hanselmann
    'primary_node': instance.primary_node,
293 396e1b78 Michael Hanselmann
    'secondary_nodes': instance.secondary_nodes,
294 ecb215b5 Michael Hanselmann
    'os_type': instance.os,
295 396e1b78 Michael Hanselmann
    'status': instance.os,
296 396e1b78 Michael Hanselmann
    'memory': instance.memory,
297 396e1b78 Michael Hanselmann
    'vcpus': instance.vcpus,
298 396e1b78 Michael Hanselmann
    'nics': [(nic.ip, nic.bridge) for nic in instance.nics],
299 396e1b78 Michael Hanselmann
  }
300 396e1b78 Michael Hanselmann
  if override:
301 396e1b78 Michael Hanselmann
    args.update(override)
302 396e1b78 Michael Hanselmann
  return _BuildInstanceHookEnv(**args)
303 396e1b78 Michael Hanselmann
304 396e1b78 Michael Hanselmann
305 a8083063 Iustin Pop
def _UpdateKnownHosts(fullnode, ip, pubkey):
306 a8083063 Iustin Pop
  """Ensure a node has a correct known_hosts entry.
307 a8083063 Iustin Pop

308 a8083063 Iustin Pop
  Args:
309 a8083063 Iustin Pop
    fullnode - Fully qualified domain name of host. (str)
310 a8083063 Iustin Pop
    ip       - IPv4 address of host (str)
311 a8083063 Iustin Pop
    pubkey   - the public key of the cluster
312 a8083063 Iustin Pop

313 a8083063 Iustin Pop
  """
314 82122173 Iustin Pop
  if os.path.exists(constants.SSH_KNOWN_HOSTS_FILE):
315 82122173 Iustin Pop
    f = open(constants.SSH_KNOWN_HOSTS_FILE, 'r+')
316 a8083063 Iustin Pop
  else:
317 82122173 Iustin Pop
    f = open(constants.SSH_KNOWN_HOSTS_FILE, 'w+')
318 a8083063 Iustin Pop
319 a8083063 Iustin Pop
  inthere = False
320 a8083063 Iustin Pop
321 a8083063 Iustin Pop
  save_lines = []
322 a8083063 Iustin Pop
  add_lines = []
323 a8083063 Iustin Pop
  removed = False
324 a8083063 Iustin Pop
325 4cc2a728 Michael Hanselmann
  for rawline in f:
326 a8083063 Iustin Pop
    logger.Debug('read %s' % (repr(rawline),))
327 a8083063 Iustin Pop
328 4cc2a728 Michael Hanselmann
    parts = rawline.rstrip('\r\n').split()
329 4cc2a728 Michael Hanselmann
330 4cc2a728 Michael Hanselmann
    # Ignore unwanted lines
331 4cc2a728 Michael Hanselmann
    if len(parts) >= 3 and not rawline.lstrip()[0] == '#':
332 4cc2a728 Michael Hanselmann
      fields = parts[0].split(',')
333 4cc2a728 Michael Hanselmann
      key = parts[2]
334 4cc2a728 Michael Hanselmann
335 4cc2a728 Michael Hanselmann
      haveall = True
336 4cc2a728 Michael Hanselmann
      havesome = False
337 4cc2a728 Michael Hanselmann
      for spec in [ ip, fullnode ]:
338 4cc2a728 Michael Hanselmann
        if spec not in fields:
339 4cc2a728 Michael Hanselmann
          haveall = False
340 4cc2a728 Michael Hanselmann
        if spec in fields:
341 4cc2a728 Michael Hanselmann
          havesome = True
342 4cc2a728 Michael Hanselmann
343 4cc2a728 Michael Hanselmann
      logger.Debug("key, pubkey = %s." % (repr((key, pubkey)),))
344 4cc2a728 Michael Hanselmann
      if haveall and key == pubkey:
345 4cc2a728 Michael Hanselmann
        inthere = True
346 4cc2a728 Michael Hanselmann
        save_lines.append(rawline)
347 4cc2a728 Michael Hanselmann
        logger.Debug("Keeping known_hosts '%s'." % (repr(rawline),))
348 4cc2a728 Michael Hanselmann
        continue
349 4cc2a728 Michael Hanselmann
350 4cc2a728 Michael Hanselmann
      if havesome and (not haveall or key != pubkey):
351 4cc2a728 Michael Hanselmann
        removed = True
352 4cc2a728 Michael Hanselmann
        logger.Debug("Discarding known_hosts '%s'." % (repr(rawline),))
353 4cc2a728 Michael Hanselmann
        continue
354 a8083063 Iustin Pop
355 a8083063 Iustin Pop
    save_lines.append(rawline)
356 a8083063 Iustin Pop
357 a8083063 Iustin Pop
  if not inthere:
358 a8083063 Iustin Pop
    add_lines.append('%s,%s ssh-rsa %s\n' % (fullnode, ip, pubkey))
359 a8083063 Iustin Pop
    logger.Debug("Adding known_hosts '%s'." % (repr(add_lines[-1]),))
360 a8083063 Iustin Pop
361 a8083063 Iustin Pop
  if removed:
362 a8083063 Iustin Pop
    save_lines = save_lines + add_lines
363 a8083063 Iustin Pop
364 a8083063 Iustin Pop
    # Write a new file and replace old.
365 82122173 Iustin Pop
    fd, tmpname = tempfile.mkstemp('.tmp', 'known_hosts.',
366 82122173 Iustin Pop
                                   constants.DATA_DIR)
367 a8083063 Iustin Pop
    newfile = os.fdopen(fd, 'w')
368 82122173 Iustin Pop
    try:
369 82122173 Iustin Pop
      newfile.write(''.join(save_lines))
370 82122173 Iustin Pop
    finally:
371 82122173 Iustin Pop
      newfile.close()
372 a8083063 Iustin Pop
    logger.Debug("Wrote new known_hosts.")
373 82122173 Iustin Pop
    os.rename(tmpname, constants.SSH_KNOWN_HOSTS_FILE)
374 a8083063 Iustin Pop
375 a8083063 Iustin Pop
  elif add_lines:
376 a8083063 Iustin Pop
    # Simply appending a new line will do the trick.
377 a8083063 Iustin Pop
    f.seek(0, 2)
378 a8083063 Iustin Pop
    for add in add_lines:
379 a8083063 Iustin Pop
      f.write(add)
380 a8083063 Iustin Pop
381 a8083063 Iustin Pop
  f.close()
382 a8083063 Iustin Pop
383 a8083063 Iustin Pop
384 a8083063 Iustin Pop
def _HasValidVG(vglist, vgname):
385 a8083063 Iustin Pop
  """Checks if the volume group list is valid.
386 a8083063 Iustin Pop

387 a8083063 Iustin Pop
  A non-None return value means there's an error, and the return value
388 a8083063 Iustin Pop
  is the error message.
389 a8083063 Iustin Pop

390 a8083063 Iustin Pop
  """
391 a8083063 Iustin Pop
  vgsize = vglist.get(vgname, None)
392 a8083063 Iustin Pop
  if vgsize is None:
393 a8083063 Iustin Pop
    return "volume group '%s' missing" % vgname
394 a8083063 Iustin Pop
  elif vgsize < 20480:
395 191a8385 Guido Trotter
    return ("volume group '%s' too small (20480MiB required, %dMib found)" %
396 191a8385 Guido Trotter
            (vgname, vgsize))
397 a8083063 Iustin Pop
  return None
398 a8083063 Iustin Pop
399 a8083063 Iustin Pop
400 a8083063 Iustin Pop
def _InitSSHSetup(node):
401 a8083063 Iustin Pop
  """Setup the SSH configuration for the cluster.
402 a8083063 Iustin Pop

403 a8083063 Iustin Pop

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

407 a8083063 Iustin Pop
  Args:
408 a8083063 Iustin Pop
    node: the name of this host as a fqdn
409 a8083063 Iustin Pop

410 a8083063 Iustin Pop
  """
411 70d9e3d8 Iustin Pop
  priv_key, pub_key, auth_keys = ssh.GetUserFiles(constants.GANETI_RUNAS)
412 a8083063 Iustin Pop
413 70d9e3d8 Iustin Pop
  for name in priv_key, pub_key:
414 70d9e3d8 Iustin Pop
    if os.path.exists(name):
415 70d9e3d8 Iustin Pop
      utils.CreateBackup(name)
416 70d9e3d8 Iustin Pop
    utils.RemoveFile(name)
417 a8083063 Iustin Pop
418 a8083063 Iustin Pop
  result = utils.RunCmd(["ssh-keygen", "-t", "dsa",
419 70d9e3d8 Iustin Pop
                         "-f", priv_key,
420 a8083063 Iustin Pop
                         "-q", "-N", ""])
421 a8083063 Iustin Pop
  if result.failed:
422 3ecf6786 Iustin Pop
    raise errors.OpExecError("Could not generate ssh keypair, error %s" %
423 3ecf6786 Iustin Pop
                             result.output)
424 a8083063 Iustin Pop
425 70d9e3d8 Iustin Pop
  f = open(pub_key, 'r')
426 a8083063 Iustin Pop
  try:
427 70d9e3d8 Iustin Pop
    utils.AddAuthorizedKey(auth_keys, f.read(8192))
428 a8083063 Iustin Pop
  finally:
429 a8083063 Iustin Pop
    f.close()
430 a8083063 Iustin Pop
431 a8083063 Iustin Pop
432 a8083063 Iustin Pop
def _InitGanetiServerSetup(ss):
433 a8083063 Iustin Pop
  """Setup the necessary configuration for the initial node daemon.
434 a8083063 Iustin Pop

435 a8083063 Iustin Pop
  This creates the nodepass file containing the shared password for
436 a8083063 Iustin Pop
  the cluster and also generates the SSL certificate.
437 a8083063 Iustin Pop

438 a8083063 Iustin Pop
  """
439 a8083063 Iustin Pop
  # Create pseudo random password
440 a8083063 Iustin Pop
  randpass = sha.new(os.urandom(64)).hexdigest()
441 a8083063 Iustin Pop
  # and write it into sstore
442 a8083063 Iustin Pop
  ss.SetKey(ss.SS_NODED_PASS, randpass)
443 a8083063 Iustin Pop
444 a8083063 Iustin Pop
  result = utils.RunCmd(["openssl", "req", "-new", "-newkey", "rsa:1024",
445 a8083063 Iustin Pop
                         "-days", str(365*5), "-nodes", "-x509",
446 a8083063 Iustin Pop
                         "-keyout", constants.SSL_CERT_FILE,
447 a8083063 Iustin Pop
                         "-out", constants.SSL_CERT_FILE, "-batch"])
448 a8083063 Iustin Pop
  if result.failed:
449 3ecf6786 Iustin Pop
    raise errors.OpExecError("could not generate server ssl cert, command"
450 3ecf6786 Iustin Pop
                             " %s had exitcode %s and error message %s" %
451 3ecf6786 Iustin Pop
                             (result.cmd, result.exit_code, result.output))
452 a8083063 Iustin Pop
453 a8083063 Iustin Pop
  os.chmod(constants.SSL_CERT_FILE, 0400)
454 a8083063 Iustin Pop
455 a8083063 Iustin Pop
  result = utils.RunCmd([constants.NODE_INITD_SCRIPT, "restart"])
456 a8083063 Iustin Pop
457 a8083063 Iustin Pop
  if result.failed:
458 3ecf6786 Iustin Pop
    raise errors.OpExecError("Could not start the node daemon, command %s"
459 3ecf6786 Iustin Pop
                             " had exitcode %s and error %s" %
460 3ecf6786 Iustin Pop
                             (result.cmd, result.exit_code, result.output))
461 a8083063 Iustin Pop
462 a8083063 Iustin Pop
463 bf6929a2 Alexander Schreiber
def _CheckInstanceBridgesExist(instance):
464 bf6929a2 Alexander Schreiber
  """Check that the brigdes needed by an instance exist.
465 bf6929a2 Alexander Schreiber

466 bf6929a2 Alexander Schreiber
  """
467 bf6929a2 Alexander Schreiber
  # check bridges existance
468 bf6929a2 Alexander Schreiber
  brlist = [nic.bridge for nic in instance.nics]
469 bf6929a2 Alexander Schreiber
  if not rpc.call_bridges_exist(instance.primary_node, brlist):
470 bf6929a2 Alexander Schreiber
    raise errors.OpPrereqError("one or more target bridges %s does not"
471 bf6929a2 Alexander Schreiber
                               " exist on destination node '%s'" %
472 bf6929a2 Alexander Schreiber
                               (brlist, instance.primary_node))
473 bf6929a2 Alexander Schreiber
474 bf6929a2 Alexander Schreiber
475 a8083063 Iustin Pop
class LUInitCluster(LogicalUnit):
476 a8083063 Iustin Pop
  """Initialise the cluster.
477 a8083063 Iustin Pop

478 a8083063 Iustin Pop
  """
479 a8083063 Iustin Pop
  HPATH = "cluster-init"
480 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_CLUSTER
481 a8083063 Iustin Pop
  _OP_REQP = ["cluster_name", "hypervisor_type", "vg_name", "mac_prefix",
482 880478f8 Iustin Pop
              "def_bridge", "master_netdev"]
483 a8083063 Iustin Pop
  REQ_CLUSTER = False
484 a8083063 Iustin Pop
485 a8083063 Iustin Pop
  def BuildHooksEnv(self):
486 a8083063 Iustin Pop
    """Build hooks env.
487 a8083063 Iustin Pop

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

491 a8083063 Iustin Pop
    """
492 0e137c28 Iustin Pop
    env = {"OP_TARGET": self.op.cluster_name}
493 0e137c28 Iustin Pop
    return env, [], [self.hostname.name]
494 a8083063 Iustin Pop
495 a8083063 Iustin Pop
  def CheckPrereq(self):
496 a8083063 Iustin Pop
    """Verify that the passed name is a valid one.
497 a8083063 Iustin Pop

498 a8083063 Iustin Pop
    """
499 a8083063 Iustin Pop
    if config.ConfigWriter.IsCluster():
500 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Cluster is already initialised")
501 a8083063 Iustin Pop
502 89e1fc26 Iustin Pop
    self.hostname = hostname = utils.HostInfo()
503 ff98055b Iustin Pop
504 bcf043c9 Iustin Pop
    if hostname.ip.startswith("127."):
505 130e907e Iustin Pop
      raise errors.OpPrereqError("This host's IP resolves to the private"
506 130e907e Iustin Pop
                                 " range (%s). Please fix DNS or /etc/hosts." %
507 bcf043c9 Iustin Pop
                                 (hostname.ip,))
508 130e907e Iustin Pop
509 89e1fc26 Iustin Pop
    self.clustername = clustername = utils.HostInfo(self.op.cluster_name)
510 a8083063 Iustin Pop
511 16abfbc2 Alexander Schreiber
    if not utils.TcpPing(constants.LOCALHOST_IP_ADDRESS, hostname.ip,
512 16abfbc2 Alexander Schreiber
                         constants.DEFAULT_NODED_PORT):
513 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Inconsistency: this host's name resolves"
514 3ecf6786 Iustin Pop
                                 " to %s,\nbut this ip address does not"
515 3ecf6786 Iustin Pop
                                 " belong to this host."
516 bcf043c9 Iustin Pop
                                 " Aborting." % hostname.ip)
517 a8083063 Iustin Pop
518 a8083063 Iustin Pop
    secondary_ip = getattr(self.op, "secondary_ip", None)
519 a8083063 Iustin Pop
    if secondary_ip and not utils.IsValidIP(secondary_ip):
520 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Invalid secondary ip given")
521 16abfbc2 Alexander Schreiber
    if (secondary_ip and
522 16abfbc2 Alexander Schreiber
        secondary_ip != hostname.ip and
523 16abfbc2 Alexander Schreiber
        (not utils.TcpPing(constants.LOCALHOST_IP_ADDRESS, secondary_ip,
524 16abfbc2 Alexander Schreiber
                           constants.DEFAULT_NODED_PORT))):
525 16abfbc2 Alexander Schreiber
      raise errors.OpPrereqError("You gave %s as secondary IP,\n"
526 16abfbc2 Alexander Schreiber
                                 "but it does not belong to this host." %
527 16abfbc2 Alexander Schreiber
                                 secondary_ip)
528 a8083063 Iustin Pop
    self.secondary_ip = secondary_ip
529 a8083063 Iustin Pop
530 a8083063 Iustin Pop
    # checks presence of the volume group given
531 a8083063 Iustin Pop
    vgstatus = _HasValidVG(utils.ListVolumeGroups(), self.op.vg_name)
532 a8083063 Iustin Pop
533 a8083063 Iustin Pop
    if vgstatus:
534 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Error: %s" % vgstatus)
535 a8083063 Iustin Pop
536 a8083063 Iustin Pop
    if not re.match("^[0-9a-z]{2}:[0-9a-z]{2}:[0-9a-z]{2}$",
537 a8083063 Iustin Pop
                    self.op.mac_prefix):
538 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Invalid mac prefix given '%s'" %
539 3ecf6786 Iustin Pop
                                 self.op.mac_prefix)
540 a8083063 Iustin Pop
541 a8083063 Iustin Pop
    if self.op.hypervisor_type not in hypervisor.VALID_HTYPES:
542 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Invalid hypervisor type given '%s'" %
543 3ecf6786 Iustin Pop
                                 self.op.hypervisor_type)
544 a8083063 Iustin Pop
545 880478f8 Iustin Pop
    result = utils.RunCmd(["ip", "link", "show", "dev", self.op.master_netdev])
546 880478f8 Iustin Pop
    if result.failed:
547 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Invalid master netdev given (%s): '%s'" %
548 8925faaa Iustin Pop
                                 (self.op.master_netdev,
549 8925faaa Iustin Pop
                                  result.output.strip()))
550 880478f8 Iustin Pop
551 7dd30006 Michael Hanselmann
    if not (os.path.isfile(constants.NODE_INITD_SCRIPT) and
552 7dd30006 Michael Hanselmann
            os.access(constants.NODE_INITD_SCRIPT, os.X_OK)):
553 7dd30006 Michael Hanselmann
      raise errors.OpPrereqError("Init.d script '%s' missing or not "
554 7dd30006 Michael Hanselmann
                                 "executable." % constants.NODE_INITD_SCRIPT)
555 c7b46d59 Iustin Pop
556 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
557 a8083063 Iustin Pop
    """Initialize the cluster.
558 a8083063 Iustin Pop

559 a8083063 Iustin Pop
    """
560 a8083063 Iustin Pop
    clustername = self.clustername
561 a8083063 Iustin Pop
    hostname = self.hostname
562 a8083063 Iustin Pop
563 a8083063 Iustin Pop
    # set up the simple store
564 4167825b Iustin Pop
    self.sstore = ss = ssconf.SimpleStore()
565 a8083063 Iustin Pop
    ss.SetKey(ss.SS_HYPERVISOR, self.op.hypervisor_type)
566 bcf043c9 Iustin Pop
    ss.SetKey(ss.SS_MASTER_NODE, hostname.name)
567 bcf043c9 Iustin Pop
    ss.SetKey(ss.SS_MASTER_IP, clustername.ip)
568 880478f8 Iustin Pop
    ss.SetKey(ss.SS_MASTER_NETDEV, self.op.master_netdev)
569 bcf043c9 Iustin Pop
    ss.SetKey(ss.SS_CLUSTER_NAME, clustername.name)
570 a8083063 Iustin Pop
571 a8083063 Iustin Pop
    # set up the inter-node password and certificate
572 a8083063 Iustin Pop
    _InitGanetiServerSetup(ss)
573 a8083063 Iustin Pop
574 a8083063 Iustin Pop
    # start the master ip
575 bcf043c9 Iustin Pop
    rpc.call_node_start_master(hostname.name)
576 a8083063 Iustin Pop
577 a8083063 Iustin Pop
    # set up ssh config and /etc/hosts
578 70d9e3d8 Iustin Pop
    f = open(constants.SSH_HOST_RSA_PUB, 'r')
579 a8083063 Iustin Pop
    try:
580 a8083063 Iustin Pop
      sshline = f.read()
581 a8083063 Iustin Pop
    finally:
582 a8083063 Iustin Pop
      f.close()
583 a8083063 Iustin Pop
    sshkey = sshline.split(" ")[1]
584 a8083063 Iustin Pop
585 9440aeab Michael Hanselmann
    _AddHostToEtcHosts(hostname.name)
586 a8083063 Iustin Pop
587 bcf043c9 Iustin Pop
    _UpdateKnownHosts(hostname.name, hostname.ip, sshkey)
588 a8083063 Iustin Pop
589 bcf043c9 Iustin Pop
    _InitSSHSetup(hostname.name)
590 a8083063 Iustin Pop
591 a8083063 Iustin Pop
    # init of cluster config file
592 4167825b Iustin Pop
    self.cfg = cfgw = config.ConfigWriter()
593 bcf043c9 Iustin Pop
    cfgw.InitConfig(hostname.name, hostname.ip, self.secondary_ip,
594 5fcdc80d Iustin Pop
                    sshkey, self.op.mac_prefix,
595 a8083063 Iustin Pop
                    self.op.vg_name, self.op.def_bridge)
596 a8083063 Iustin Pop
597 a8083063 Iustin Pop
598 a8083063 Iustin Pop
class LUDestroyCluster(NoHooksLU):
599 a8083063 Iustin Pop
  """Logical unit for destroying the cluster.
600 a8083063 Iustin Pop

601 a8083063 Iustin Pop
  """
602 a8083063 Iustin Pop
  _OP_REQP = []
603 a8083063 Iustin Pop
604 a8083063 Iustin Pop
  def CheckPrereq(self):
605 a8083063 Iustin Pop
    """Check prerequisites.
606 a8083063 Iustin Pop

607 a8083063 Iustin Pop
    This checks whether the cluster is empty.
608 a8083063 Iustin Pop

609 a8083063 Iustin Pop
    Any errors are signalled by raising errors.OpPrereqError.
610 a8083063 Iustin Pop

611 a8083063 Iustin Pop
    """
612 880478f8 Iustin Pop
    master = self.sstore.GetMasterNode()
613 a8083063 Iustin Pop
614 a8083063 Iustin Pop
    nodelist = self.cfg.GetNodeList()
615 db915bd1 Michael Hanselmann
    if len(nodelist) != 1 or nodelist[0] != master:
616 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("There are still %d node(s) in"
617 3ecf6786 Iustin Pop
                                 " this cluster." % (len(nodelist) - 1))
618 db915bd1 Michael Hanselmann
    instancelist = self.cfg.GetInstanceList()
619 db915bd1 Michael Hanselmann
    if instancelist:
620 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("There are still %d instance(s) in"
621 3ecf6786 Iustin Pop
                                 " this cluster." % len(instancelist))
622 a8083063 Iustin Pop
623 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
624 a8083063 Iustin Pop
    """Destroys the cluster.
625 a8083063 Iustin Pop

626 a8083063 Iustin Pop
    """
627 c8a0948f Michael Hanselmann
    master = self.sstore.GetMasterNode()
628 70d9e3d8 Iustin Pop
    priv_key, pub_key, _ = ssh.GetUserFiles(constants.GANETI_RUNAS)
629 70d9e3d8 Iustin Pop
    utils.CreateBackup(priv_key)
630 70d9e3d8 Iustin Pop
    utils.CreateBackup(pub_key)
631 c8a0948f Michael Hanselmann
    rpc.call_node_leave_cluster(master)
632 a8083063 Iustin Pop
633 a8083063 Iustin Pop
634 a8083063 Iustin Pop
class LUVerifyCluster(NoHooksLU):
635 a8083063 Iustin Pop
  """Verifies the cluster status.
636 a8083063 Iustin Pop

637 a8083063 Iustin Pop
  """
638 a8083063 Iustin Pop
  _OP_REQP = []
639 a8083063 Iustin Pop
640 a8083063 Iustin Pop
  def _VerifyNode(self, node, file_list, local_cksum, vglist, node_result,
641 a8083063 Iustin Pop
                  remote_version, feedback_fn):
642 a8083063 Iustin Pop
    """Run multiple tests against a node.
643 a8083063 Iustin Pop

644 a8083063 Iustin Pop
    Test list:
645 a8083063 Iustin Pop
      - compares ganeti version
646 a8083063 Iustin Pop
      - checks vg existance and size > 20G
647 a8083063 Iustin Pop
      - checks config file checksum
648 a8083063 Iustin Pop
      - checks ssh to other nodes
649 a8083063 Iustin Pop

650 a8083063 Iustin Pop
    Args:
651 a8083063 Iustin Pop
      node: name of the node to check
652 a8083063 Iustin Pop
      file_list: required list of files
653 a8083063 Iustin Pop
      local_cksum: dictionary of local files and their checksums
654 098c0958 Michael Hanselmann

655 a8083063 Iustin Pop
    """
656 a8083063 Iustin Pop
    # compares ganeti version
657 a8083063 Iustin Pop
    local_version = constants.PROTOCOL_VERSION
658 a8083063 Iustin Pop
    if not remote_version:
659 a8083063 Iustin Pop
      feedback_fn(" - ERROR: connection to %s failed" % (node))
660 a8083063 Iustin Pop
      return True
661 a8083063 Iustin Pop
662 a8083063 Iustin Pop
    if local_version != remote_version:
663 a8083063 Iustin Pop
      feedback_fn("  - ERROR: sw version mismatch: master %s, node(%s) %s" %
664 a8083063 Iustin Pop
                      (local_version, node, remote_version))
665 a8083063 Iustin Pop
      return True
666 a8083063 Iustin Pop
667 a8083063 Iustin Pop
    # checks vg existance and size > 20G
668 a8083063 Iustin Pop
669 a8083063 Iustin Pop
    bad = False
670 a8083063 Iustin Pop
    if not vglist:
671 a8083063 Iustin Pop
      feedback_fn("  - ERROR: unable to check volume groups on node %s." %
672 a8083063 Iustin Pop
                      (node,))
673 a8083063 Iustin Pop
      bad = True
674 a8083063 Iustin Pop
    else:
675 a8083063 Iustin Pop
      vgstatus = _HasValidVG(vglist, self.cfg.GetVGName())
676 a8083063 Iustin Pop
      if vgstatus:
677 a8083063 Iustin Pop
        feedback_fn("  - ERROR: %s on node %s" % (vgstatus, node))
678 a8083063 Iustin Pop
        bad = True
679 a8083063 Iustin Pop
680 a8083063 Iustin Pop
    # checks config file checksum
681 a8083063 Iustin Pop
    # checks ssh to any
682 a8083063 Iustin Pop
683 a8083063 Iustin Pop
    if 'filelist' not in node_result:
684 a8083063 Iustin Pop
      bad = True
685 a8083063 Iustin Pop
      feedback_fn("  - ERROR: node hasn't returned file checksum data")
686 a8083063 Iustin Pop
    else:
687 a8083063 Iustin Pop
      remote_cksum = node_result['filelist']
688 a8083063 Iustin Pop
      for file_name in file_list:
689 a8083063 Iustin Pop
        if file_name not in remote_cksum:
690 a8083063 Iustin Pop
          bad = True
691 a8083063 Iustin Pop
          feedback_fn("  - ERROR: file '%s' missing" % file_name)
692 a8083063 Iustin Pop
        elif remote_cksum[file_name] != local_cksum[file_name]:
693 a8083063 Iustin Pop
          bad = True
694 a8083063 Iustin Pop
          feedback_fn("  - ERROR: file '%s' has wrong checksum" % file_name)
695 a8083063 Iustin Pop
696 a8083063 Iustin Pop
    if 'nodelist' not in node_result:
697 a8083063 Iustin Pop
      bad = True
698 a8083063 Iustin Pop
      feedback_fn("  - ERROR: node hasn't returned node connectivity data")
699 a8083063 Iustin Pop
    else:
700 a8083063 Iustin Pop
      if node_result['nodelist']:
701 a8083063 Iustin Pop
        bad = True
702 a8083063 Iustin Pop
        for node in node_result['nodelist']:
703 a8083063 Iustin Pop
          feedback_fn("  - ERROR: communication with node '%s': %s" %
704 a8083063 Iustin Pop
                          (node, node_result['nodelist'][node]))
705 a8083063 Iustin Pop
    hyp_result = node_result.get('hypervisor', None)
706 a8083063 Iustin Pop
    if hyp_result is not None:
707 a8083063 Iustin Pop
      feedback_fn("  - ERROR: hypervisor verify failure: '%s'" % hyp_result)
708 a8083063 Iustin Pop
    return bad
709 a8083063 Iustin Pop
710 a8083063 Iustin Pop
  def _VerifyInstance(self, instance, node_vol_is, node_instance, feedback_fn):
711 a8083063 Iustin Pop
    """Verify an instance.
712 a8083063 Iustin Pop

713 a8083063 Iustin Pop
    This function checks to see if the required block devices are
714 a8083063 Iustin Pop
    available on the instance's node.
715 a8083063 Iustin Pop

716 a8083063 Iustin Pop
    """
717 a8083063 Iustin Pop
    bad = False
718 a8083063 Iustin Pop
719 a8083063 Iustin Pop
    instancelist = self.cfg.GetInstanceList()
720 a8083063 Iustin Pop
    if not instance in instancelist:
721 a8083063 Iustin Pop
      feedback_fn("  - ERROR: instance %s not in instance list %s" %
722 a8083063 Iustin Pop
                      (instance, instancelist))
723 a8083063 Iustin Pop
      bad = True
724 a8083063 Iustin Pop
725 a8083063 Iustin Pop
    instanceconfig = self.cfg.GetInstanceInfo(instance)
726 a8083063 Iustin Pop
    node_current = instanceconfig.primary_node
727 a8083063 Iustin Pop
728 a8083063 Iustin Pop
    node_vol_should = {}
729 a8083063 Iustin Pop
    instanceconfig.MapLVsByNode(node_vol_should)
730 a8083063 Iustin Pop
731 a8083063 Iustin Pop
    for node in node_vol_should:
732 a8083063 Iustin Pop
      for volume in node_vol_should[node]:
733 a8083063 Iustin Pop
        if node not in node_vol_is or volume not in node_vol_is[node]:
734 a8083063 Iustin Pop
          feedback_fn("  - ERROR: volume %s missing on node %s" %
735 a8083063 Iustin Pop
                          (volume, node))
736 a8083063 Iustin Pop
          bad = True
737 a8083063 Iustin Pop
738 a8083063 Iustin Pop
    if not instanceconfig.status == 'down':
739 a8083063 Iustin Pop
      if not instance in node_instance[node_current]:
740 a8083063 Iustin Pop
        feedback_fn("  - ERROR: instance %s not running on node %s" %
741 a8083063 Iustin Pop
                        (instance, node_current))
742 a8083063 Iustin Pop
        bad = True
743 a8083063 Iustin Pop
744 a8083063 Iustin Pop
    for node in node_instance:
745 a8083063 Iustin Pop
      if (not node == node_current):
746 a8083063 Iustin Pop
        if instance in node_instance[node]:
747 a8083063 Iustin Pop
          feedback_fn("  - ERROR: instance %s should not run on node %s" %
748 a8083063 Iustin Pop
                          (instance, node))
749 a8083063 Iustin Pop
          bad = True
750 a8083063 Iustin Pop
751 6a438c98 Michael Hanselmann
    return bad
752 a8083063 Iustin Pop
753 a8083063 Iustin Pop
  def _VerifyOrphanVolumes(self, node_vol_should, node_vol_is, feedback_fn):
754 a8083063 Iustin Pop
    """Verify if there are any unknown volumes in the cluster.
755 a8083063 Iustin Pop

756 a8083063 Iustin Pop
    The .os, .swap and backup volumes are ignored. All other volumes are
757 a8083063 Iustin Pop
    reported as unknown.
758 a8083063 Iustin Pop

759 a8083063 Iustin Pop
    """
760 a8083063 Iustin Pop
    bad = False
761 a8083063 Iustin Pop
762 a8083063 Iustin Pop
    for node in node_vol_is:
763 a8083063 Iustin Pop
      for volume in node_vol_is[node]:
764 a8083063 Iustin Pop
        if node not in node_vol_should or volume not in node_vol_should[node]:
765 a8083063 Iustin Pop
          feedback_fn("  - ERROR: volume %s on node %s should not exist" %
766 a8083063 Iustin Pop
                      (volume, node))
767 a8083063 Iustin Pop
          bad = True
768 a8083063 Iustin Pop
    return bad
769 a8083063 Iustin Pop
770 a8083063 Iustin Pop
  def _VerifyOrphanInstances(self, instancelist, node_instance, feedback_fn):
771 a8083063 Iustin Pop
    """Verify the list of running instances.
772 a8083063 Iustin Pop

773 a8083063 Iustin Pop
    This checks what instances are running but unknown to the cluster.
774 a8083063 Iustin Pop

775 a8083063 Iustin Pop
    """
776 a8083063 Iustin Pop
    bad = False
777 a8083063 Iustin Pop
    for node in node_instance:
778 a8083063 Iustin Pop
      for runninginstance in node_instance[node]:
779 a8083063 Iustin Pop
        if runninginstance not in instancelist:
780 a8083063 Iustin Pop
          feedback_fn("  - ERROR: instance %s on node %s should not exist" %
781 a8083063 Iustin Pop
                          (runninginstance, node))
782 a8083063 Iustin Pop
          bad = True
783 a8083063 Iustin Pop
    return bad
784 a8083063 Iustin Pop
785 a8083063 Iustin Pop
  def CheckPrereq(self):
786 a8083063 Iustin Pop
    """Check prerequisites.
787 a8083063 Iustin Pop

788 a8083063 Iustin Pop
    This has no prerequisites.
789 a8083063 Iustin Pop

790 a8083063 Iustin Pop
    """
791 a8083063 Iustin Pop
    pass
792 a8083063 Iustin Pop
793 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
794 a8083063 Iustin Pop
    """Verify integrity of cluster, performing various test on nodes.
795 a8083063 Iustin Pop

796 a8083063 Iustin Pop
    """
797 a8083063 Iustin Pop
    bad = False
798 a8083063 Iustin Pop
    feedback_fn("* Verifying global settings")
799 8522ceeb Iustin Pop
    for msg in self.cfg.VerifyConfig():
800 8522ceeb Iustin Pop
      feedback_fn("  - ERROR: %s" % msg)
801 a8083063 Iustin Pop
802 a8083063 Iustin Pop
    vg_name = self.cfg.GetVGName()
803 a8083063 Iustin Pop
    nodelist = utils.NiceSort(self.cfg.GetNodeList())
804 a8083063 Iustin Pop
    instancelist = utils.NiceSort(self.cfg.GetInstanceList())
805 a8083063 Iustin Pop
    node_volume = {}
806 a8083063 Iustin Pop
    node_instance = {}
807 a8083063 Iustin Pop
808 a8083063 Iustin Pop
    # FIXME: verify OS list
809 a8083063 Iustin Pop
    # do local checksums
810 cb91d46e Iustin Pop
    file_names = list(self.sstore.GetFileList())
811 cb91d46e Iustin Pop
    file_names.append(constants.SSL_CERT_FILE)
812 cb91d46e Iustin Pop
    file_names.append(constants.CLUSTER_CONF_FILE)
813 a8083063 Iustin Pop
    local_checksums = utils.FingerprintFiles(file_names)
814 a8083063 Iustin Pop
815 a8083063 Iustin Pop
    feedback_fn("* Gathering data (%d nodes)" % len(nodelist))
816 a8083063 Iustin Pop
    all_volumeinfo = rpc.call_volume_list(nodelist, vg_name)
817 a8083063 Iustin Pop
    all_instanceinfo = rpc.call_instance_list(nodelist)
818 a8083063 Iustin Pop
    all_vglist = rpc.call_vg_list(nodelist)
819 a8083063 Iustin Pop
    node_verify_param = {
820 a8083063 Iustin Pop
      'filelist': file_names,
821 a8083063 Iustin Pop
      'nodelist': nodelist,
822 a8083063 Iustin Pop
      'hypervisor': None,
823 a8083063 Iustin Pop
      }
824 a8083063 Iustin Pop
    all_nvinfo = rpc.call_node_verify(nodelist, node_verify_param)
825 a8083063 Iustin Pop
    all_rversion = rpc.call_version(nodelist)
826 a8083063 Iustin Pop
827 a8083063 Iustin Pop
    for node in nodelist:
828 a8083063 Iustin Pop
      feedback_fn("* Verifying node %s" % node)
829 a8083063 Iustin Pop
      result = self._VerifyNode(node, file_names, local_checksums,
830 a8083063 Iustin Pop
                                all_vglist[node], all_nvinfo[node],
831 a8083063 Iustin Pop
                                all_rversion[node], feedback_fn)
832 a8083063 Iustin Pop
      bad = bad or result
833 a8083063 Iustin Pop
834 a8083063 Iustin Pop
      # node_volume
835 a8083063 Iustin Pop
      volumeinfo = all_volumeinfo[node]
836 a8083063 Iustin Pop
837 a8083063 Iustin Pop
      if type(volumeinfo) != dict:
838 a8083063 Iustin Pop
        feedback_fn("  - ERROR: connection to %s failed" % (node,))
839 a8083063 Iustin Pop
        bad = True
840 a8083063 Iustin Pop
        continue
841 a8083063 Iustin Pop
842 a8083063 Iustin Pop
      node_volume[node] = volumeinfo
843 a8083063 Iustin Pop
844 a8083063 Iustin Pop
      # node_instance
845 a8083063 Iustin Pop
      nodeinstance = all_instanceinfo[node]
846 a8083063 Iustin Pop
      if type(nodeinstance) != list:
847 a8083063 Iustin Pop
        feedback_fn("  - ERROR: connection to %s failed" % (node,))
848 a8083063 Iustin Pop
        bad = True
849 a8083063 Iustin Pop
        continue
850 a8083063 Iustin Pop
851 a8083063 Iustin Pop
      node_instance[node] = nodeinstance
852 a8083063 Iustin Pop
853 a8083063 Iustin Pop
    node_vol_should = {}
854 a8083063 Iustin Pop
855 a8083063 Iustin Pop
    for instance in instancelist:
856 a8083063 Iustin Pop
      feedback_fn("* Verifying instance %s" % instance)
857 a8083063 Iustin Pop
      result =  self._VerifyInstance(instance, node_volume, node_instance,
858 a8083063 Iustin Pop
                                     feedback_fn)
859 a8083063 Iustin Pop
      bad = bad or result
860 a8083063 Iustin Pop
861 a8083063 Iustin Pop
      inst_config = self.cfg.GetInstanceInfo(instance)
862 a8083063 Iustin Pop
863 a8083063 Iustin Pop
      inst_config.MapLVsByNode(node_vol_should)
864 a8083063 Iustin Pop
865 a8083063 Iustin Pop
    feedback_fn("* Verifying orphan volumes")
866 a8083063 Iustin Pop
    result = self._VerifyOrphanVolumes(node_vol_should, node_volume,
867 a8083063 Iustin Pop
                                       feedback_fn)
868 a8083063 Iustin Pop
    bad = bad or result
869 a8083063 Iustin Pop
870 a8083063 Iustin Pop
    feedback_fn("* Verifying remaining instances")
871 a8083063 Iustin Pop
    result = self._VerifyOrphanInstances(instancelist, node_instance,
872 a8083063 Iustin Pop
                                         feedback_fn)
873 a8083063 Iustin Pop
    bad = bad or result
874 a8083063 Iustin Pop
875 a8083063 Iustin Pop
    return int(bad)
876 a8083063 Iustin Pop
877 a8083063 Iustin Pop
878 07bd8a51 Iustin Pop
class LURenameCluster(LogicalUnit):
879 07bd8a51 Iustin Pop
  """Rename the cluster.
880 07bd8a51 Iustin Pop

881 07bd8a51 Iustin Pop
  """
882 07bd8a51 Iustin Pop
  HPATH = "cluster-rename"
883 07bd8a51 Iustin Pop
  HTYPE = constants.HTYPE_CLUSTER
884 07bd8a51 Iustin Pop
  _OP_REQP = ["name"]
885 07bd8a51 Iustin Pop
886 07bd8a51 Iustin Pop
  def BuildHooksEnv(self):
887 07bd8a51 Iustin Pop
    """Build hooks env.
888 07bd8a51 Iustin Pop

889 07bd8a51 Iustin Pop
    """
890 07bd8a51 Iustin Pop
    env = {
891 0e137c28 Iustin Pop
      "OP_TARGET": self.op.sstore.GetClusterName(),
892 07bd8a51 Iustin Pop
      "NEW_NAME": self.op.name,
893 07bd8a51 Iustin Pop
      }
894 07bd8a51 Iustin Pop
    mn = self.sstore.GetMasterNode()
895 07bd8a51 Iustin Pop
    return env, [mn], [mn]
896 07bd8a51 Iustin Pop
897 07bd8a51 Iustin Pop
  def CheckPrereq(self):
898 07bd8a51 Iustin Pop
    """Verify that the passed name is a valid one.
899 07bd8a51 Iustin Pop

900 07bd8a51 Iustin Pop
    """
901 89e1fc26 Iustin Pop
    hostname = utils.HostInfo(self.op.name)
902 07bd8a51 Iustin Pop
903 bcf043c9 Iustin Pop
    new_name = hostname.name
904 bcf043c9 Iustin Pop
    self.ip = new_ip = hostname.ip
905 07bd8a51 Iustin Pop
    old_name = self.sstore.GetClusterName()
906 07bd8a51 Iustin Pop
    old_ip = self.sstore.GetMasterIP()
907 07bd8a51 Iustin Pop
    if new_name == old_name and new_ip == old_ip:
908 07bd8a51 Iustin Pop
      raise errors.OpPrereqError("Neither the name nor the IP address of the"
909 07bd8a51 Iustin Pop
                                 " cluster has changed")
910 07bd8a51 Iustin Pop
    if new_ip != old_ip:
911 07bd8a51 Iustin Pop
      result = utils.RunCmd(["fping", "-q", new_ip])
912 07bd8a51 Iustin Pop
      if not result.failed:
913 07bd8a51 Iustin Pop
        raise errors.OpPrereqError("The given cluster IP address (%s) is"
914 07bd8a51 Iustin Pop
                                   " reachable on the network. Aborting." %
915 07bd8a51 Iustin Pop
                                   new_ip)
916 07bd8a51 Iustin Pop
917 07bd8a51 Iustin Pop
    self.op.name = new_name
918 07bd8a51 Iustin Pop
919 07bd8a51 Iustin Pop
  def Exec(self, feedback_fn):
920 07bd8a51 Iustin Pop
    """Rename the cluster.
921 07bd8a51 Iustin Pop

922 07bd8a51 Iustin Pop
    """
923 07bd8a51 Iustin Pop
    clustername = self.op.name
924 07bd8a51 Iustin Pop
    ip = self.ip
925 07bd8a51 Iustin Pop
    ss = self.sstore
926 07bd8a51 Iustin Pop
927 07bd8a51 Iustin Pop
    # shutdown the master IP
928 07bd8a51 Iustin Pop
    master = ss.GetMasterNode()
929 07bd8a51 Iustin Pop
    if not rpc.call_node_stop_master(master):
930 07bd8a51 Iustin Pop
      raise errors.OpExecError("Could not disable the master role")
931 07bd8a51 Iustin Pop
932 07bd8a51 Iustin Pop
    try:
933 07bd8a51 Iustin Pop
      # modify the sstore
934 07bd8a51 Iustin Pop
      ss.SetKey(ss.SS_MASTER_IP, ip)
935 07bd8a51 Iustin Pop
      ss.SetKey(ss.SS_CLUSTER_NAME, clustername)
936 07bd8a51 Iustin Pop
937 07bd8a51 Iustin Pop
      # Distribute updated ss config to all nodes
938 07bd8a51 Iustin Pop
      myself = self.cfg.GetNodeInfo(master)
939 07bd8a51 Iustin Pop
      dist_nodes = self.cfg.GetNodeList()
940 07bd8a51 Iustin Pop
      if myself.name in dist_nodes:
941 07bd8a51 Iustin Pop
        dist_nodes.remove(myself.name)
942 07bd8a51 Iustin Pop
943 07bd8a51 Iustin Pop
      logger.Debug("Copying updated ssconf data to all nodes")
944 07bd8a51 Iustin Pop
      for keyname in [ss.SS_CLUSTER_NAME, ss.SS_MASTER_IP]:
945 07bd8a51 Iustin Pop
        fname = ss.KeyToFilename(keyname)
946 07bd8a51 Iustin Pop
        result = rpc.call_upload_file(dist_nodes, fname)
947 07bd8a51 Iustin Pop
        for to_node in dist_nodes:
948 07bd8a51 Iustin Pop
          if not result[to_node]:
949 07bd8a51 Iustin Pop
            logger.Error("copy of file %s to node %s failed" %
950 07bd8a51 Iustin Pop
                         (fname, to_node))
951 07bd8a51 Iustin Pop
    finally:
952 07bd8a51 Iustin Pop
      if not rpc.call_node_start_master(master):
953 07bd8a51 Iustin Pop
        logger.Error("Could not re-enable the master role on the master,\n"
954 07bd8a51 Iustin Pop
                     "please restart manually.")
955 07bd8a51 Iustin Pop
956 07bd8a51 Iustin Pop
957 5bfac263 Iustin Pop
def _WaitForSync(cfgw, instance, proc, oneshot=False, unlock=False):
958 a8083063 Iustin Pop
  """Sleep and poll for an instance's disk to sync.
959 a8083063 Iustin Pop

960 a8083063 Iustin Pop
  """
961 a8083063 Iustin Pop
  if not instance.disks:
962 a8083063 Iustin Pop
    return True
963 a8083063 Iustin Pop
964 a8083063 Iustin Pop
  if not oneshot:
965 5bfac263 Iustin Pop
    proc.LogInfo("Waiting for instance %s to sync disks." % instance.name)
966 a8083063 Iustin Pop
967 a8083063 Iustin Pop
  node = instance.primary_node
968 a8083063 Iustin Pop
969 a8083063 Iustin Pop
  for dev in instance.disks:
970 a8083063 Iustin Pop
    cfgw.SetDiskID(dev, node)
971 a8083063 Iustin Pop
972 a8083063 Iustin Pop
  retries = 0
973 a8083063 Iustin Pop
  while True:
974 a8083063 Iustin Pop
    max_time = 0
975 a8083063 Iustin Pop
    done = True
976 a8083063 Iustin Pop
    cumul_degraded = False
977 a8083063 Iustin Pop
    rstats = rpc.call_blockdev_getmirrorstatus(node, instance.disks)
978 a8083063 Iustin Pop
    if not rstats:
979 5bfac263 Iustin Pop
      proc.LogWarning("Can't get any data from node %s" % node)
980 a8083063 Iustin Pop
      retries += 1
981 a8083063 Iustin Pop
      if retries >= 10:
982 3ecf6786 Iustin Pop
        raise errors.RemoteError("Can't contact node %s for mirror data,"
983 3ecf6786 Iustin Pop
                                 " aborting." % node)
984 a8083063 Iustin Pop
      time.sleep(6)
985 a8083063 Iustin Pop
      continue
986 a8083063 Iustin Pop
    retries = 0
987 a8083063 Iustin Pop
    for i in range(len(rstats)):
988 a8083063 Iustin Pop
      mstat = rstats[i]
989 a8083063 Iustin Pop
      if mstat is None:
990 5bfac263 Iustin Pop
        proc.LogWarning("Can't compute data for node %s/%s" %
991 a8083063 Iustin Pop
                        (node, instance.disks[i].iv_name))
992 a8083063 Iustin Pop
        continue
993 0834c866 Iustin Pop
      # we ignore the ldisk parameter
994 0834c866 Iustin Pop
      perc_done, est_time, is_degraded, _ = mstat
995 a8083063 Iustin Pop
      cumul_degraded = cumul_degraded or (is_degraded and perc_done is None)
996 a8083063 Iustin Pop
      if perc_done is not None:
997 a8083063 Iustin Pop
        done = False
998 a8083063 Iustin Pop
        if est_time is not None:
999 a8083063 Iustin Pop
          rem_time = "%d estimated seconds remaining" % est_time
1000 a8083063 Iustin Pop
          max_time = est_time
1001 a8083063 Iustin Pop
        else:
1002 a8083063 Iustin Pop
          rem_time = "no time estimate"
1003 5bfac263 Iustin Pop
        proc.LogInfo("- device %s: %5.2f%% done, %s" %
1004 5bfac263 Iustin Pop
                     (instance.disks[i].iv_name, perc_done, rem_time))
1005 a8083063 Iustin Pop
    if done or oneshot:
1006 a8083063 Iustin Pop
      break
1007 a8083063 Iustin Pop
1008 a8083063 Iustin Pop
    if unlock:
1009 a8083063 Iustin Pop
      utils.Unlock('cmd')
1010 a8083063 Iustin Pop
    try:
1011 a8083063 Iustin Pop
      time.sleep(min(60, max_time))
1012 a8083063 Iustin Pop
    finally:
1013 a8083063 Iustin Pop
      if unlock:
1014 a8083063 Iustin Pop
        utils.Lock('cmd')
1015 a8083063 Iustin Pop
1016 a8083063 Iustin Pop
  if done:
1017 5bfac263 Iustin Pop
    proc.LogInfo("Instance %s's disks are in sync." % instance.name)
1018 a8083063 Iustin Pop
  return not cumul_degraded
1019 a8083063 Iustin Pop
1020 a8083063 Iustin Pop
1021 0834c866 Iustin Pop
def _CheckDiskConsistency(cfgw, dev, node, on_primary, ldisk=False):
1022 a8083063 Iustin Pop
  """Check that mirrors are not degraded.
1023 a8083063 Iustin Pop

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

1028 a8083063 Iustin Pop
  """
1029 a8083063 Iustin Pop
  cfgw.SetDiskID(dev, node)
1030 0834c866 Iustin Pop
  if ldisk:
1031 0834c866 Iustin Pop
    idx = 6
1032 0834c866 Iustin Pop
  else:
1033 0834c866 Iustin Pop
    idx = 5
1034 a8083063 Iustin Pop
1035 a8083063 Iustin Pop
  result = True
1036 a8083063 Iustin Pop
  if on_primary or dev.AssembleOnSecondary():
1037 a8083063 Iustin Pop
    rstats = rpc.call_blockdev_find(node, dev)
1038 a8083063 Iustin Pop
    if not rstats:
1039 a8083063 Iustin Pop
      logger.ToStderr("Can't get any data from node %s" % node)
1040 a8083063 Iustin Pop
      result = False
1041 a8083063 Iustin Pop
    else:
1042 0834c866 Iustin Pop
      result = result and (not rstats[idx])
1043 a8083063 Iustin Pop
  if dev.children:
1044 a8083063 Iustin Pop
    for child in dev.children:
1045 a8083063 Iustin Pop
      result = result and _CheckDiskConsistency(cfgw, child, node, on_primary)
1046 a8083063 Iustin Pop
1047 a8083063 Iustin Pop
  return result
1048 a8083063 Iustin Pop
1049 a8083063 Iustin Pop
1050 a8083063 Iustin Pop
class LUDiagnoseOS(NoHooksLU):
1051 a8083063 Iustin Pop
  """Logical unit for OS diagnose/query.
1052 a8083063 Iustin Pop

1053 a8083063 Iustin Pop
  """
1054 a8083063 Iustin Pop
  _OP_REQP = []
1055 a8083063 Iustin Pop
1056 a8083063 Iustin Pop
  def CheckPrereq(self):
1057 a8083063 Iustin Pop
    """Check prerequisites.
1058 a8083063 Iustin Pop

1059 a8083063 Iustin Pop
    This always succeeds, since this is a pure query LU.
1060 a8083063 Iustin Pop

1061 a8083063 Iustin Pop
    """
1062 a8083063 Iustin Pop
    return
1063 a8083063 Iustin Pop
1064 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1065 a8083063 Iustin Pop
    """Compute the list of OSes.
1066 a8083063 Iustin Pop

1067 a8083063 Iustin Pop
    """
1068 a8083063 Iustin Pop
    node_list = self.cfg.GetNodeList()
1069 a8083063 Iustin Pop
    node_data = rpc.call_os_diagnose(node_list)
1070 a8083063 Iustin Pop
    if node_data == False:
1071 3ecf6786 Iustin Pop
      raise errors.OpExecError("Can't gather the list of OSes")
1072 a8083063 Iustin Pop
    return node_data
1073 a8083063 Iustin Pop
1074 a8083063 Iustin Pop
1075 a8083063 Iustin Pop
class LURemoveNode(LogicalUnit):
1076 a8083063 Iustin Pop
  """Logical unit for removing a node.
1077 a8083063 Iustin Pop

1078 a8083063 Iustin Pop
  """
1079 a8083063 Iustin Pop
  HPATH = "node-remove"
1080 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_NODE
1081 a8083063 Iustin Pop
  _OP_REQP = ["node_name"]
1082 a8083063 Iustin Pop
1083 a8083063 Iustin Pop
  def BuildHooksEnv(self):
1084 a8083063 Iustin Pop
    """Build hooks env.
1085 a8083063 Iustin Pop

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

1089 a8083063 Iustin Pop
    """
1090 396e1b78 Michael Hanselmann
    env = {
1091 0e137c28 Iustin Pop
      "OP_TARGET": self.op.node_name,
1092 396e1b78 Michael Hanselmann
      "NODE_NAME": self.op.node_name,
1093 396e1b78 Michael Hanselmann
      }
1094 a8083063 Iustin Pop
    all_nodes = self.cfg.GetNodeList()
1095 a8083063 Iustin Pop
    all_nodes.remove(self.op.node_name)
1096 396e1b78 Michael Hanselmann
    return env, all_nodes, all_nodes
1097 a8083063 Iustin Pop
1098 a8083063 Iustin Pop
  def CheckPrereq(self):
1099 a8083063 Iustin Pop
    """Check prerequisites.
1100 a8083063 Iustin Pop

1101 a8083063 Iustin Pop
    This checks:
1102 a8083063 Iustin Pop
     - the node exists in the configuration
1103 a8083063 Iustin Pop
     - it does not have primary or secondary instances
1104 a8083063 Iustin Pop
     - it's not the master
1105 a8083063 Iustin Pop

1106 a8083063 Iustin Pop
    Any errors are signalled by raising errors.OpPrereqError.
1107 a8083063 Iustin Pop

1108 a8083063 Iustin Pop
    """
1109 a8083063 Iustin Pop
    node = self.cfg.GetNodeInfo(self.cfg.ExpandNodeName(self.op.node_name))
1110 a8083063 Iustin Pop
    if node is None:
1111 a02bc76e Iustin Pop
      raise errors.OpPrereqError, ("Node '%s' is unknown." % self.op.node_name)
1112 a8083063 Iustin Pop
1113 a8083063 Iustin Pop
    instance_list = self.cfg.GetInstanceList()
1114 a8083063 Iustin Pop
1115 880478f8 Iustin Pop
    masternode = self.sstore.GetMasterNode()
1116 a8083063 Iustin Pop
    if node.name == masternode:
1117 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Node is the master node,"
1118 3ecf6786 Iustin Pop
                                 " you need to failover first.")
1119 a8083063 Iustin Pop
1120 a8083063 Iustin Pop
    for instance_name in instance_list:
1121 a8083063 Iustin Pop
      instance = self.cfg.GetInstanceInfo(instance_name)
1122 a8083063 Iustin Pop
      if node.name == instance.primary_node:
1123 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Instance %s still running on the node,"
1124 3ecf6786 Iustin Pop
                                   " please remove first." % instance_name)
1125 a8083063 Iustin Pop
      if node.name in instance.secondary_nodes:
1126 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("Instance %s has node as a secondary,"
1127 3ecf6786 Iustin Pop
                                   " please remove first." % instance_name)
1128 a8083063 Iustin Pop
    self.op.node_name = node.name
1129 a8083063 Iustin Pop
    self.node = node
1130 a8083063 Iustin Pop
1131 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1132 a8083063 Iustin Pop
    """Removes the node from the cluster.
1133 a8083063 Iustin Pop

1134 a8083063 Iustin Pop
    """
1135 a8083063 Iustin Pop
    node = self.node
1136 a8083063 Iustin Pop
    logger.Info("stopping the node daemon and removing configs from node %s" %
1137 a8083063 Iustin Pop
                node.name)
1138 a8083063 Iustin Pop
1139 a8083063 Iustin Pop
    rpc.call_node_leave_cluster(node.name)
1140 a8083063 Iustin Pop
1141 a8083063 Iustin Pop
    ssh.SSHCall(node.name, 'root', "%s stop" % constants.NODE_INITD_SCRIPT)
1142 a8083063 Iustin Pop
1143 a8083063 Iustin Pop
    logger.Info("Removing node %s from config" % node.name)
1144 a8083063 Iustin Pop
1145 a8083063 Iustin Pop
    self.cfg.RemoveNode(node.name)
1146 a8083063 Iustin Pop
1147 c8a0948f Michael Hanselmann
    _RemoveHostFromEtcHosts(node.name)
1148 c8a0948f Michael Hanselmann
1149 a8083063 Iustin Pop
1150 a8083063 Iustin Pop
class LUQueryNodes(NoHooksLU):
1151 a8083063 Iustin Pop
  """Logical unit for querying nodes.
1152 a8083063 Iustin Pop

1153 a8083063 Iustin Pop
  """
1154 246e180a Iustin Pop
  _OP_REQP = ["output_fields", "names"]
1155 a8083063 Iustin Pop
1156 a8083063 Iustin Pop
  def CheckPrereq(self):
1157 a8083063 Iustin Pop
    """Check prerequisites.
1158 a8083063 Iustin Pop

1159 a8083063 Iustin Pop
    This checks that the fields required are valid output fields.
1160 a8083063 Iustin Pop

1161 a8083063 Iustin Pop
    """
1162 a8083063 Iustin Pop
    self.dynamic_fields = frozenset(["dtotal", "dfree",
1163 3ef10550 Michael Hanselmann
                                     "mtotal", "mnode", "mfree",
1164 3ef10550 Michael Hanselmann
                                     "bootid"])
1165 a8083063 Iustin Pop
1166 ec223efb Iustin Pop
    _CheckOutputFields(static=["name", "pinst_cnt", "sinst_cnt",
1167 ec223efb Iustin Pop
                               "pinst_list", "sinst_list",
1168 ec223efb Iustin Pop
                               "pip", "sip"],
1169 dcb93971 Michael Hanselmann
                       dynamic=self.dynamic_fields,
1170 dcb93971 Michael Hanselmann
                       selected=self.op.output_fields)
1171 a8083063 Iustin Pop
1172 246e180a Iustin Pop
    self.wanted = _GetWantedNodes(self, self.op.names)
1173 a8083063 Iustin Pop
1174 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1175 a8083063 Iustin Pop
    """Computes the list of nodes and their attributes.
1176 a8083063 Iustin Pop

1177 a8083063 Iustin Pop
    """
1178 246e180a Iustin Pop
    nodenames = self.wanted
1179 a8083063 Iustin Pop
    nodelist = [self.cfg.GetNodeInfo(name) for name in nodenames]
1180 a8083063 Iustin Pop
1181 a8083063 Iustin Pop
    # begin data gathering
1182 a8083063 Iustin Pop
1183 a8083063 Iustin Pop
    if self.dynamic_fields.intersection(self.op.output_fields):
1184 a8083063 Iustin Pop
      live_data = {}
1185 a8083063 Iustin Pop
      node_data = rpc.call_node_info(nodenames, self.cfg.GetVGName())
1186 a8083063 Iustin Pop
      for name in nodenames:
1187 a8083063 Iustin Pop
        nodeinfo = node_data.get(name, None)
1188 a8083063 Iustin Pop
        if nodeinfo:
1189 a8083063 Iustin Pop
          live_data[name] = {
1190 a8083063 Iustin Pop
            "mtotal": utils.TryConvert(int, nodeinfo['memory_total']),
1191 a8083063 Iustin Pop
            "mnode": utils.TryConvert(int, nodeinfo['memory_dom0']),
1192 a8083063 Iustin Pop
            "mfree": utils.TryConvert(int, nodeinfo['memory_free']),
1193 a8083063 Iustin Pop
            "dtotal": utils.TryConvert(int, nodeinfo['vg_size']),
1194 a8083063 Iustin Pop
            "dfree": utils.TryConvert(int, nodeinfo['vg_free']),
1195 3ef10550 Michael Hanselmann
            "bootid": nodeinfo['bootid'],
1196 a8083063 Iustin Pop
            }
1197 a8083063 Iustin Pop
        else:
1198 a8083063 Iustin Pop
          live_data[name] = {}
1199 a8083063 Iustin Pop
    else:
1200 a8083063 Iustin Pop
      live_data = dict.fromkeys(nodenames, {})
1201 a8083063 Iustin Pop
1202 ec223efb Iustin Pop
    node_to_primary = dict([(name, set()) for name in nodenames])
1203 ec223efb Iustin Pop
    node_to_secondary = dict([(name, set()) for name in nodenames])
1204 a8083063 Iustin Pop
1205 ec223efb Iustin Pop
    inst_fields = frozenset(("pinst_cnt", "pinst_list",
1206 ec223efb Iustin Pop
                             "sinst_cnt", "sinst_list"))
1207 ec223efb Iustin Pop
    if inst_fields & frozenset(self.op.output_fields):
1208 a8083063 Iustin Pop
      instancelist = self.cfg.GetInstanceList()
1209 a8083063 Iustin Pop
1210 ec223efb Iustin Pop
      for instance_name in instancelist:
1211 ec223efb Iustin Pop
        inst = self.cfg.GetInstanceInfo(instance_name)
1212 ec223efb Iustin Pop
        if inst.primary_node in node_to_primary:
1213 ec223efb Iustin Pop
          node_to_primary[inst.primary_node].add(inst.name)
1214 ec223efb Iustin Pop
        for secnode in inst.secondary_nodes:
1215 ec223efb Iustin Pop
          if secnode in node_to_secondary:
1216 ec223efb Iustin Pop
            node_to_secondary[secnode].add(inst.name)
1217 a8083063 Iustin Pop
1218 a8083063 Iustin Pop
    # end data gathering
1219 a8083063 Iustin Pop
1220 a8083063 Iustin Pop
    output = []
1221 a8083063 Iustin Pop
    for node in nodelist:
1222 a8083063 Iustin Pop
      node_output = []
1223 a8083063 Iustin Pop
      for field in self.op.output_fields:
1224 a8083063 Iustin Pop
        if field == "name":
1225 a8083063 Iustin Pop
          val = node.name
1226 ec223efb Iustin Pop
        elif field == "pinst_list":
1227 ec223efb Iustin Pop
          val = list(node_to_primary[node.name])
1228 ec223efb Iustin Pop
        elif field == "sinst_list":
1229 ec223efb Iustin Pop
          val = list(node_to_secondary[node.name])
1230 ec223efb Iustin Pop
        elif field == "pinst_cnt":
1231 ec223efb Iustin Pop
          val = len(node_to_primary[node.name])
1232 ec223efb Iustin Pop
        elif field == "sinst_cnt":
1233 ec223efb Iustin Pop
          val = len(node_to_secondary[node.name])
1234 a8083063 Iustin Pop
        elif field == "pip":
1235 a8083063 Iustin Pop
          val = node.primary_ip
1236 a8083063 Iustin Pop
        elif field == "sip":
1237 a8083063 Iustin Pop
          val = node.secondary_ip
1238 a8083063 Iustin Pop
        elif field in self.dynamic_fields:
1239 ec223efb Iustin Pop
          val = live_data[node.name].get(field, None)
1240 a8083063 Iustin Pop
        else:
1241 3ecf6786 Iustin Pop
          raise errors.ParameterError(field)
1242 a8083063 Iustin Pop
        node_output.append(val)
1243 a8083063 Iustin Pop
      output.append(node_output)
1244 a8083063 Iustin Pop
1245 a8083063 Iustin Pop
    return output
1246 a8083063 Iustin Pop
1247 a8083063 Iustin Pop
1248 dcb93971 Michael Hanselmann
class LUQueryNodeVolumes(NoHooksLU):
1249 dcb93971 Michael Hanselmann
  """Logical unit for getting volumes on node(s).
1250 dcb93971 Michael Hanselmann

1251 dcb93971 Michael Hanselmann
  """
1252 dcb93971 Michael Hanselmann
  _OP_REQP = ["nodes", "output_fields"]
1253 dcb93971 Michael Hanselmann
1254 dcb93971 Michael Hanselmann
  def CheckPrereq(self):
1255 dcb93971 Michael Hanselmann
    """Check prerequisites.
1256 dcb93971 Michael Hanselmann

1257 dcb93971 Michael Hanselmann
    This checks that the fields required are valid output fields.
1258 dcb93971 Michael Hanselmann

1259 dcb93971 Michael Hanselmann
    """
1260 dcb93971 Michael Hanselmann
    self.nodes = _GetWantedNodes(self, self.op.nodes)
1261 dcb93971 Michael Hanselmann
1262 dcb93971 Michael Hanselmann
    _CheckOutputFields(static=["node"],
1263 dcb93971 Michael Hanselmann
                       dynamic=["phys", "vg", "name", "size", "instance"],
1264 dcb93971 Michael Hanselmann
                       selected=self.op.output_fields)
1265 dcb93971 Michael Hanselmann
1266 dcb93971 Michael Hanselmann
1267 dcb93971 Michael Hanselmann
  def Exec(self, feedback_fn):
1268 dcb93971 Michael Hanselmann
    """Computes the list of nodes and their attributes.
1269 dcb93971 Michael Hanselmann

1270 dcb93971 Michael Hanselmann
    """
1271 a7ba5e53 Iustin Pop
    nodenames = self.nodes
1272 dcb93971 Michael Hanselmann
    volumes = rpc.call_node_volumes(nodenames)
1273 dcb93971 Michael Hanselmann
1274 dcb93971 Michael Hanselmann
    ilist = [self.cfg.GetInstanceInfo(iname) for iname
1275 dcb93971 Michael Hanselmann
             in self.cfg.GetInstanceList()]
1276 dcb93971 Michael Hanselmann
1277 dcb93971 Michael Hanselmann
    lv_by_node = dict([(inst, inst.MapLVsByNode()) for inst in ilist])
1278 dcb93971 Michael Hanselmann
1279 dcb93971 Michael Hanselmann
    output = []
1280 dcb93971 Michael Hanselmann
    for node in nodenames:
1281 37d19eb2 Michael Hanselmann
      if node not in volumes or not volumes[node]:
1282 37d19eb2 Michael Hanselmann
        continue
1283 37d19eb2 Michael Hanselmann
1284 dcb93971 Michael Hanselmann
      node_vols = volumes[node][:]
1285 dcb93971 Michael Hanselmann
      node_vols.sort(key=lambda vol: vol['dev'])
1286 dcb93971 Michael Hanselmann
1287 dcb93971 Michael Hanselmann
      for vol in node_vols:
1288 dcb93971 Michael Hanselmann
        node_output = []
1289 dcb93971 Michael Hanselmann
        for field in self.op.output_fields:
1290 dcb93971 Michael Hanselmann
          if field == "node":
1291 dcb93971 Michael Hanselmann
            val = node
1292 dcb93971 Michael Hanselmann
          elif field == "phys":
1293 dcb93971 Michael Hanselmann
            val = vol['dev']
1294 dcb93971 Michael Hanselmann
          elif field == "vg":
1295 dcb93971 Michael Hanselmann
            val = vol['vg']
1296 dcb93971 Michael Hanselmann
          elif field == "name":
1297 dcb93971 Michael Hanselmann
            val = vol['name']
1298 dcb93971 Michael Hanselmann
          elif field == "size":
1299 dcb93971 Michael Hanselmann
            val = int(float(vol['size']))
1300 dcb93971 Michael Hanselmann
          elif field == "instance":
1301 dcb93971 Michael Hanselmann
            for inst in ilist:
1302 dcb93971 Michael Hanselmann
              if node not in lv_by_node[inst]:
1303 dcb93971 Michael Hanselmann
                continue
1304 dcb93971 Michael Hanselmann
              if vol['name'] in lv_by_node[inst][node]:
1305 dcb93971 Michael Hanselmann
                val = inst.name
1306 dcb93971 Michael Hanselmann
                break
1307 dcb93971 Michael Hanselmann
            else:
1308 dcb93971 Michael Hanselmann
              val = '-'
1309 dcb93971 Michael Hanselmann
          else:
1310 3ecf6786 Iustin Pop
            raise errors.ParameterError(field)
1311 dcb93971 Michael Hanselmann
          node_output.append(str(val))
1312 dcb93971 Michael Hanselmann
1313 dcb93971 Michael Hanselmann
        output.append(node_output)
1314 dcb93971 Michael Hanselmann
1315 dcb93971 Michael Hanselmann
    return output
1316 dcb93971 Michael Hanselmann
1317 dcb93971 Michael Hanselmann
1318 a8083063 Iustin Pop
class LUAddNode(LogicalUnit):
1319 a8083063 Iustin Pop
  """Logical unit for adding node to the cluster.
1320 a8083063 Iustin Pop

1321 a8083063 Iustin Pop
  """
1322 a8083063 Iustin Pop
  HPATH = "node-add"
1323 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_NODE
1324 a8083063 Iustin Pop
  _OP_REQP = ["node_name"]
1325 a8083063 Iustin Pop
1326 a8083063 Iustin Pop
  def BuildHooksEnv(self):
1327 a8083063 Iustin Pop
    """Build hooks env.
1328 a8083063 Iustin Pop

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

1331 a8083063 Iustin Pop
    """
1332 a8083063 Iustin Pop
    env = {
1333 0e137c28 Iustin Pop
      "OP_TARGET": self.op.node_name,
1334 a8083063 Iustin Pop
      "NODE_NAME": self.op.node_name,
1335 a8083063 Iustin Pop
      "NODE_PIP": self.op.primary_ip,
1336 a8083063 Iustin Pop
      "NODE_SIP": self.op.secondary_ip,
1337 a8083063 Iustin Pop
      }
1338 a8083063 Iustin Pop
    nodes_0 = self.cfg.GetNodeList()
1339 a8083063 Iustin Pop
    nodes_1 = nodes_0 + [self.op.node_name, ]
1340 a8083063 Iustin Pop
    return env, nodes_0, nodes_1
1341 a8083063 Iustin Pop
1342 a8083063 Iustin Pop
  def CheckPrereq(self):
1343 a8083063 Iustin Pop
    """Check prerequisites.
1344 a8083063 Iustin Pop

1345 a8083063 Iustin Pop
    This checks:
1346 a8083063 Iustin Pop
     - the new node is not already in the config
1347 a8083063 Iustin Pop
     - it is resolvable
1348 a8083063 Iustin Pop
     - its parameters (single/dual homed) matches the cluster
1349 a8083063 Iustin Pop

1350 a8083063 Iustin Pop
    Any errors are signalled by raising errors.OpPrereqError.
1351 a8083063 Iustin Pop

1352 a8083063 Iustin Pop
    """
1353 a8083063 Iustin Pop
    node_name = self.op.node_name
1354 a8083063 Iustin Pop
    cfg = self.cfg
1355 a8083063 Iustin Pop
1356 89e1fc26 Iustin Pop
    dns_data = utils.HostInfo(node_name)
1357 a8083063 Iustin Pop
1358 bcf043c9 Iustin Pop
    node = dns_data.name
1359 bcf043c9 Iustin Pop
    primary_ip = self.op.primary_ip = dns_data.ip
1360 a8083063 Iustin Pop
    secondary_ip = getattr(self.op, "secondary_ip", None)
1361 a8083063 Iustin Pop
    if secondary_ip is None:
1362 a8083063 Iustin Pop
      secondary_ip = primary_ip
1363 a8083063 Iustin Pop
    if not utils.IsValidIP(secondary_ip):
1364 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Invalid secondary IP given")
1365 a8083063 Iustin Pop
    self.op.secondary_ip = secondary_ip
1366 a8083063 Iustin Pop
    node_list = cfg.GetNodeList()
1367 a8083063 Iustin Pop
    if node in node_list:
1368 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Node %s is already in the configuration"
1369 3ecf6786 Iustin Pop
                                 % node)
1370 a8083063 Iustin Pop
1371 a8083063 Iustin Pop
    for existing_node_name in node_list:
1372 a8083063 Iustin Pop
      existing_node = cfg.GetNodeInfo(existing_node_name)
1373 a8083063 Iustin Pop
      if (existing_node.primary_ip == primary_ip or
1374 a8083063 Iustin Pop
          existing_node.secondary_ip == primary_ip or
1375 a8083063 Iustin Pop
          existing_node.primary_ip == secondary_ip or
1376 a8083063 Iustin Pop
          existing_node.secondary_ip == secondary_ip):
1377 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("New node ip address(es) conflict with"
1378 3ecf6786 Iustin Pop
                                   " existing node %s" % existing_node.name)
1379 a8083063 Iustin Pop
1380 a8083063 Iustin Pop
    # check that the type of the node (single versus dual homed) is the
1381 a8083063 Iustin Pop
    # same as for the master
1382 880478f8 Iustin Pop
    myself = cfg.GetNodeInfo(self.sstore.GetMasterNode())
1383 a8083063 Iustin Pop
    master_singlehomed = myself.secondary_ip == myself.primary_ip
1384 a8083063 Iustin Pop
    newbie_singlehomed = secondary_ip == primary_ip
1385 a8083063 Iustin Pop
    if master_singlehomed != newbie_singlehomed:
1386 a8083063 Iustin Pop
      if master_singlehomed:
1387 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("The master has no private ip but the"
1388 3ecf6786 Iustin Pop
                                   " new node has one")
1389 a8083063 Iustin Pop
      else:
1390 3ecf6786 Iustin Pop
        raise errors.OpPrereqError("The master has a private ip but the"
1391 3ecf6786 Iustin Pop
                                   " new node doesn't have one")
1392 a8083063 Iustin Pop
1393 a8083063 Iustin Pop
    # checks reachablity
1394 16abfbc2 Alexander Schreiber
    if not utils.TcpPing(utils.HostInfo().name,
1395 16abfbc2 Alexander Schreiber
                         primary_ip,
1396 16abfbc2 Alexander Schreiber
                         constants.DEFAULT_NODED_PORT):
1397 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Node not reachable by ping")
1398 a8083063 Iustin Pop
1399 a8083063 Iustin Pop
    if not newbie_singlehomed:
1400 a8083063 Iustin Pop
      # check reachability from my secondary ip to newbie's secondary ip
1401 16abfbc2 Alexander Schreiber
      if not utils.TcpPing(myself.secondary_ip,
1402 16abfbc2 Alexander Schreiber
                           secondary_ip,
1403 16abfbc2 Alexander Schreiber
                           constants.DEFAULT_NODED_PORT):
1404 16abfbc2 Alexander Schreiber
        raise errors.OpPrereqError(
1405 16abfbc2 Alexander Schreiber
          "Node secondary ip not reachable by TCP based ping to noded port")
1406 a8083063 Iustin Pop
1407 a8083063 Iustin Pop
    self.new_node = objects.Node(name=node,
1408 a8083063 Iustin Pop
                                 primary_ip=primary_ip,
1409 a8083063 Iustin Pop
                                 secondary_ip=secondary_ip)
1410 a8083063 Iustin Pop
1411 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1412 a8083063 Iustin Pop
    """Adds the new node to the cluster.
1413 a8083063 Iustin Pop

1414 a8083063 Iustin Pop
    """
1415 a8083063 Iustin Pop
    new_node = self.new_node
1416 a8083063 Iustin Pop
    node = new_node.name
1417 a8083063 Iustin Pop
1418 a8083063 Iustin Pop
    # set up inter-node password and certificate and restarts the node daemon
1419 a8083063 Iustin Pop
    gntpass = self.sstore.GetNodeDaemonPassword()
1420 a8083063 Iustin Pop
    if not re.match('^[a-zA-Z0-9.]{1,64}$', gntpass):
1421 3ecf6786 Iustin Pop
      raise errors.OpExecError("ganeti password corruption detected")
1422 a8083063 Iustin Pop
    f = open(constants.SSL_CERT_FILE)
1423 a8083063 Iustin Pop
    try:
1424 a8083063 Iustin Pop
      gntpem = f.read(8192)
1425 a8083063 Iustin Pop
    finally:
1426 a8083063 Iustin Pop
      f.close()
1427 a8083063 Iustin Pop
    # in the base64 pem encoding, neither '!' nor '.' are valid chars,
1428 a8083063 Iustin Pop
    # so we use this to detect an invalid certificate; as long as the
1429 a8083063 Iustin Pop
    # cert doesn't contain this, the here-document will be correctly
1430 a8083063 Iustin Pop
    # parsed by the shell sequence below
1431 a8083063 Iustin Pop
    if re.search('^!EOF\.', gntpem, re.MULTILINE):
1432 3ecf6786 Iustin Pop
      raise errors.OpExecError("invalid PEM encoding in the SSL certificate")
1433 a8083063 Iustin Pop
    if not gntpem.endswith("\n"):
1434 3ecf6786 Iustin Pop
      raise errors.OpExecError("PEM must end with newline")
1435 a8083063 Iustin Pop
    logger.Info("copy cluster pass to %s and starting the node daemon" % node)
1436 a8083063 Iustin Pop
1437 a8083063 Iustin Pop
    # and then connect with ssh to set password and start ganeti-noded
1438 a8083063 Iustin Pop
    # note that all the below variables are sanitized at this point,
1439 a8083063 Iustin Pop
    # either by being constants or by the checks above
1440 a8083063 Iustin Pop
    ss = self.sstore
1441 a8083063 Iustin Pop
    mycommand = ("umask 077 && "
1442 a8083063 Iustin Pop
                 "echo '%s' > '%s' && "
1443 a8083063 Iustin Pop
                 "cat > '%s' << '!EOF.' && \n"
1444 a8083063 Iustin Pop
                 "%s!EOF.\n%s restart" %
1445 a8083063 Iustin Pop
                 (gntpass, ss.KeyToFilename(ss.SS_NODED_PASS),
1446 a8083063 Iustin Pop
                  constants.SSL_CERT_FILE, gntpem,
1447 a8083063 Iustin Pop
                  constants.NODE_INITD_SCRIPT))
1448 a8083063 Iustin Pop
1449 a8083063 Iustin Pop
    result = ssh.SSHCall(node, 'root', mycommand, batch=False, ask_key=True)
1450 a8083063 Iustin Pop
    if result.failed:
1451 3ecf6786 Iustin Pop
      raise errors.OpExecError("Remote command on node %s, error: %s,"
1452 3ecf6786 Iustin Pop
                               " output: %s" %
1453 3ecf6786 Iustin Pop
                               (node, result.fail_reason, result.output))
1454 a8083063 Iustin Pop
1455 a8083063 Iustin Pop
    # check connectivity
1456 a8083063 Iustin Pop
    time.sleep(4)
1457 a8083063 Iustin Pop
1458 a8083063 Iustin Pop
    result = rpc.call_version([node])[node]
1459 a8083063 Iustin Pop
    if result:
1460 a8083063 Iustin Pop
      if constants.PROTOCOL_VERSION == result:
1461 a8083063 Iustin Pop
        logger.Info("communication to node %s fine, sw version %s match" %
1462 a8083063 Iustin Pop
                    (node, result))
1463 a8083063 Iustin Pop
      else:
1464 3ecf6786 Iustin Pop
        raise errors.OpExecError("Version mismatch master version %s,"
1465 3ecf6786 Iustin Pop
                                 " node version %s" %
1466 3ecf6786 Iustin Pop
                                 (constants.PROTOCOL_VERSION, result))
1467 a8083063 Iustin Pop
    else:
1468 3ecf6786 Iustin Pop
      raise errors.OpExecError("Cannot get version from the new node")
1469 a8083063 Iustin Pop
1470 a8083063 Iustin Pop
    # setup ssh on node
1471 a8083063 Iustin Pop
    logger.Info("copy ssh key to node %s" % node)
1472 70d9e3d8 Iustin Pop
    priv_key, pub_key, _ = ssh.GetUserFiles(constants.GANETI_RUNAS)
1473 a8083063 Iustin Pop
    keyarray = []
1474 70d9e3d8 Iustin Pop
    keyfiles = [constants.SSH_HOST_DSA_PRIV, constants.SSH_HOST_DSA_PUB,
1475 70d9e3d8 Iustin Pop
                constants.SSH_HOST_RSA_PRIV, constants.SSH_HOST_RSA_PUB,
1476 70d9e3d8 Iustin Pop
                priv_key, pub_key]
1477 a8083063 Iustin Pop
1478 a8083063 Iustin Pop
    for i in keyfiles:
1479 a8083063 Iustin Pop
      f = open(i, 'r')
1480 a8083063 Iustin Pop
      try:
1481 a8083063 Iustin Pop
        keyarray.append(f.read())
1482 a8083063 Iustin Pop
      finally:
1483 a8083063 Iustin Pop
        f.close()
1484 a8083063 Iustin Pop
1485 a8083063 Iustin Pop
    result = rpc.call_node_add(node, keyarray[0], keyarray[1], keyarray[2],
1486 a8083063 Iustin Pop
                               keyarray[3], keyarray[4], keyarray[5])
1487 a8083063 Iustin Pop
1488 a8083063 Iustin Pop
    if not result:
1489 3ecf6786 Iustin Pop
      raise errors.OpExecError("Cannot transfer ssh keys to the new node")
1490 a8083063 Iustin Pop
1491 a8083063 Iustin Pop
    # Add node to our /etc/hosts, and add key to known_hosts
1492 9440aeab Michael Hanselmann
    _AddHostToEtcHosts(new_node.name)
1493 c8a0948f Michael Hanselmann
1494 a8083063 Iustin Pop
    _UpdateKnownHosts(new_node.name, new_node.primary_ip,
1495 a8083063 Iustin Pop
                      self.cfg.GetHostKey())
1496 a8083063 Iustin Pop
1497 a8083063 Iustin Pop
    if new_node.secondary_ip != new_node.primary_ip:
1498 16abfbc2 Alexander Schreiber
      if not rpc.call_node_tcp_ping(new_node.name,
1499 16abfbc2 Alexander Schreiber
                                    constants.LOCALHOST_IP_ADDRESS,
1500 16abfbc2 Alexander Schreiber
                                    new_node.secondary_ip,
1501 16abfbc2 Alexander Schreiber
                                    constants.DEFAULT_NODED_PORT,
1502 16abfbc2 Alexander Schreiber
                                    10, False):
1503 3ecf6786 Iustin Pop
        raise errors.OpExecError("Node claims it doesn't have the"
1504 3ecf6786 Iustin Pop
                                 " secondary ip you gave (%s).\n"
1505 3ecf6786 Iustin Pop
                                 "Please fix and re-run this command." %
1506 3ecf6786 Iustin Pop
                                 new_node.secondary_ip)
1507 a8083063 Iustin Pop
1508 ff98055b Iustin Pop
    success, msg = ssh.VerifyNodeHostname(node)
1509 ff98055b Iustin Pop
    if not success:
1510 ff98055b Iustin Pop
      raise errors.OpExecError("Node '%s' claims it has a different hostname"
1511 ff98055b Iustin Pop
                               " than the one the resolver gives: %s.\n"
1512 ff98055b Iustin Pop
                               "Please fix and re-run this command." %
1513 ff98055b Iustin Pop
                               (node, msg))
1514 ff98055b Iustin Pop
1515 a8083063 Iustin Pop
    # Distribute updated /etc/hosts and known_hosts to all nodes,
1516 a8083063 Iustin Pop
    # including the node just added
1517 880478f8 Iustin Pop
    myself = self.cfg.GetNodeInfo(self.sstore.GetMasterNode())
1518 a8083063 Iustin Pop
    dist_nodes = self.cfg.GetNodeList() + [node]
1519 a8083063 Iustin Pop
    if myself.name in dist_nodes:
1520 a8083063 Iustin Pop
      dist_nodes.remove(myself.name)
1521 a8083063 Iustin Pop
1522 a8083063 Iustin Pop
    logger.Debug("Copying hosts and known_hosts to all nodes")
1523 82122173 Iustin Pop
    for fname in ("/etc/hosts", constants.SSH_KNOWN_HOSTS_FILE):
1524 a8083063 Iustin Pop
      result = rpc.call_upload_file(dist_nodes, fname)
1525 a8083063 Iustin Pop
      for to_node in dist_nodes:
1526 a8083063 Iustin Pop
        if not result[to_node]:
1527 a8083063 Iustin Pop
          logger.Error("copy of file %s to node %s failed" %
1528 a8083063 Iustin Pop
                       (fname, to_node))
1529 a8083063 Iustin Pop
1530 cb91d46e Iustin Pop
    to_copy = ss.GetFileList()
1531 a8083063 Iustin Pop
    for fname in to_copy:
1532 a8083063 Iustin Pop
      if not ssh.CopyFileToNode(node, fname):
1533 a8083063 Iustin Pop
        logger.Error("could not copy file %s to node %s" % (fname, node))
1534 a8083063 Iustin Pop
1535 a8083063 Iustin Pop
    logger.Info("adding node %s to cluster.conf" % node)
1536 a8083063 Iustin Pop
    self.cfg.AddNode(new_node)
1537 a8083063 Iustin Pop
1538 a8083063 Iustin Pop
1539 a8083063 Iustin Pop
class LUMasterFailover(LogicalUnit):
1540 a8083063 Iustin Pop
  """Failover the master node to the current node.
1541 a8083063 Iustin Pop

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

1544 a8083063 Iustin Pop
  """
1545 a8083063 Iustin Pop
  HPATH = "master-failover"
1546 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_CLUSTER
1547 a8083063 Iustin Pop
  REQ_MASTER = False
1548 a8083063 Iustin Pop
  _OP_REQP = []
1549 a8083063 Iustin Pop
1550 a8083063 Iustin Pop
  def BuildHooksEnv(self):
1551 a8083063 Iustin Pop
    """Build hooks env.
1552 a8083063 Iustin Pop

1553 a8083063 Iustin Pop
    This will run on the new master only in the pre phase, and on all
1554 a8083063 Iustin Pop
    the nodes in the post phase.
1555 a8083063 Iustin Pop

1556 a8083063 Iustin Pop
    """
1557 a8083063 Iustin Pop
    env = {
1558 0e137c28 Iustin Pop
      "OP_TARGET": self.new_master,
1559 a8083063 Iustin Pop
      "NEW_MASTER": self.new_master,
1560 a8083063 Iustin Pop
      "OLD_MASTER": self.old_master,
1561 a8083063 Iustin Pop
      }
1562 a8083063 Iustin Pop
    return env, [self.new_master], self.cfg.GetNodeList()
1563 a8083063 Iustin Pop
1564 a8083063 Iustin Pop
  def CheckPrereq(self):
1565 a8083063 Iustin Pop
    """Check prerequisites.
1566 a8083063 Iustin Pop

1567 a8083063 Iustin Pop
    This checks that we are not already the master.
1568 a8083063 Iustin Pop

1569 a8083063 Iustin Pop
    """
1570 89e1fc26 Iustin Pop
    self.new_master = utils.HostInfo().name
1571 880478f8 Iustin Pop
    self.old_master = self.sstore.GetMasterNode()
1572 a8083063 Iustin Pop
1573 a8083063 Iustin Pop
    if self.old_master == self.new_master:
1574 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("This commands must be run on the node"
1575 3ecf6786 Iustin Pop
                                 " where you want the new master to be.\n"
1576 3ecf6786 Iustin Pop
                                 "%s is already the master" %
1577 3ecf6786 Iustin Pop
                                 self.old_master)
1578 a8083063 Iustin Pop
1579 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1580 a8083063 Iustin Pop
    """Failover the master node.
1581 a8083063 Iustin Pop

1582 a8083063 Iustin Pop
    This command, when run on a non-master node, will cause the current
1583 a8083063 Iustin Pop
    master to cease being master, and the non-master to become new
1584 a8083063 Iustin Pop
    master.
1585 a8083063 Iustin Pop

1586 a8083063 Iustin Pop
    """
1587 a8083063 Iustin Pop
    #TODO: do not rely on gethostname returning the FQDN
1588 a8083063 Iustin Pop
    logger.Info("setting master to %s, old master: %s" %
1589 a8083063 Iustin Pop
                (self.new_master, self.old_master))
1590 a8083063 Iustin Pop
1591 a8083063 Iustin Pop
    if not rpc.call_node_stop_master(self.old_master):
1592 a8083063 Iustin Pop
      logger.Error("could disable the master role on the old master"
1593 a8083063 Iustin Pop
                   " %s, please disable manually" % self.old_master)
1594 a8083063 Iustin Pop
1595 880478f8 Iustin Pop
    ss = self.sstore
1596 880478f8 Iustin Pop
    ss.SetKey(ss.SS_MASTER_NODE, self.new_master)
1597 880478f8 Iustin Pop
    if not rpc.call_upload_file(self.cfg.GetNodeList(),
1598 880478f8 Iustin Pop
                                ss.KeyToFilename(ss.SS_MASTER_NODE)):
1599 880478f8 Iustin Pop
      logger.Error("could not distribute the new simple store master file"
1600 880478f8 Iustin Pop
                   " to the other nodes, please check.")
1601 880478f8 Iustin Pop
1602 a8083063 Iustin Pop
    if not rpc.call_node_start_master(self.new_master):
1603 a8083063 Iustin Pop
      logger.Error("could not start the master role on the new master"
1604 a8083063 Iustin Pop
                   " %s, please check" % self.new_master)
1605 880478f8 Iustin Pop
      feedback_fn("Error in activating the master IP on the new master,\n"
1606 880478f8 Iustin Pop
                  "please fix manually.")
1607 a8083063 Iustin Pop
1608 a8083063 Iustin Pop
1609 a8083063 Iustin Pop
1610 a8083063 Iustin Pop
class LUQueryClusterInfo(NoHooksLU):
1611 a8083063 Iustin Pop
  """Query cluster configuration.
1612 a8083063 Iustin Pop

1613 a8083063 Iustin Pop
  """
1614 a8083063 Iustin Pop
  _OP_REQP = []
1615 59322403 Iustin Pop
  REQ_MASTER = False
1616 a8083063 Iustin Pop
1617 a8083063 Iustin Pop
  def CheckPrereq(self):
1618 a8083063 Iustin Pop
    """No prerequsites needed for this LU.
1619 a8083063 Iustin Pop

1620 a8083063 Iustin Pop
    """
1621 a8083063 Iustin Pop
    pass
1622 a8083063 Iustin Pop
1623 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1624 a8083063 Iustin Pop
    """Return cluster config.
1625 a8083063 Iustin Pop

1626 a8083063 Iustin Pop
    """
1627 a8083063 Iustin Pop
    result = {
1628 5fcdc80d Iustin Pop
      "name": self.sstore.GetClusterName(),
1629 a8083063 Iustin Pop
      "software_version": constants.RELEASE_VERSION,
1630 a8083063 Iustin Pop
      "protocol_version": constants.PROTOCOL_VERSION,
1631 a8083063 Iustin Pop
      "config_version": constants.CONFIG_VERSION,
1632 a8083063 Iustin Pop
      "os_api_version": constants.OS_API_VERSION,
1633 a8083063 Iustin Pop
      "export_version": constants.EXPORT_VERSION,
1634 880478f8 Iustin Pop
      "master": self.sstore.GetMasterNode(),
1635 a8083063 Iustin Pop
      "architecture": (platform.architecture()[0], platform.machine()),
1636 a8083063 Iustin Pop
      }
1637 a8083063 Iustin Pop
1638 a8083063 Iustin Pop
    return result
1639 a8083063 Iustin Pop
1640 a8083063 Iustin Pop
1641 a8083063 Iustin Pop
class LUClusterCopyFile(NoHooksLU):
1642 a8083063 Iustin Pop
  """Copy file to cluster.
1643 a8083063 Iustin Pop

1644 a8083063 Iustin Pop
  """
1645 a8083063 Iustin Pop
  _OP_REQP = ["nodes", "filename"]
1646 a8083063 Iustin Pop
1647 a8083063 Iustin Pop
  def CheckPrereq(self):
1648 a8083063 Iustin Pop
    """Check prerequisites.
1649 a8083063 Iustin Pop

1650 a8083063 Iustin Pop
    It should check that the named file exists and that the given list
1651 a8083063 Iustin Pop
    of nodes is valid.
1652 a8083063 Iustin Pop

1653 a8083063 Iustin Pop
    """
1654 a8083063 Iustin Pop
    if not os.path.exists(self.op.filename):
1655 a8083063 Iustin Pop
      raise errors.OpPrereqError("No such filename '%s'" % self.op.filename)
1656 dcb93971 Michael Hanselmann
1657 dcb93971 Michael Hanselmann
    self.nodes = _GetWantedNodes(self, self.op.nodes)
1658 a8083063 Iustin Pop
1659 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1660 a8083063 Iustin Pop
    """Copy a file from master to some nodes.
1661 a8083063 Iustin Pop

1662 a8083063 Iustin Pop
    Args:
1663 a8083063 Iustin Pop
      opts - class with options as members
1664 a8083063 Iustin Pop
      args - list containing a single element, the file name
1665 a8083063 Iustin Pop
    Opts used:
1666 a8083063 Iustin Pop
      nodes - list containing the name of target nodes; if empty, all nodes
1667 a8083063 Iustin Pop

1668 a8083063 Iustin Pop
    """
1669 a8083063 Iustin Pop
    filename = self.op.filename
1670 a8083063 Iustin Pop
1671 89e1fc26 Iustin Pop
    myname = utils.HostInfo().name
1672 a8083063 Iustin Pop
1673 a7ba5e53 Iustin Pop
    for node in self.nodes:
1674 a8083063 Iustin Pop
      if node == myname:
1675 a8083063 Iustin Pop
        continue
1676 a8083063 Iustin Pop
      if not ssh.CopyFileToNode(node, filename):
1677 a8083063 Iustin Pop
        logger.Error("Copy of file %s to node %s failed" % (filename, node))
1678 a8083063 Iustin Pop
1679 a8083063 Iustin Pop
1680 a8083063 Iustin Pop
class LUDumpClusterConfig(NoHooksLU):
1681 a8083063 Iustin Pop
  """Return a text-representation of the cluster-config.
1682 a8083063 Iustin Pop

1683 a8083063 Iustin Pop
  """
1684 a8083063 Iustin Pop
  _OP_REQP = []
1685 a8083063 Iustin Pop
1686 a8083063 Iustin Pop
  def CheckPrereq(self):
1687 a8083063 Iustin Pop
    """No prerequisites.
1688 a8083063 Iustin Pop

1689 a8083063 Iustin Pop
    """
1690 a8083063 Iustin Pop
    pass
1691 a8083063 Iustin Pop
1692 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1693 a8083063 Iustin Pop
    """Dump a representation of the cluster config to the standard output.
1694 a8083063 Iustin Pop

1695 a8083063 Iustin Pop
    """
1696 a8083063 Iustin Pop
    return self.cfg.DumpConfig()
1697 a8083063 Iustin Pop
1698 a8083063 Iustin Pop
1699 a8083063 Iustin Pop
class LURunClusterCommand(NoHooksLU):
1700 a8083063 Iustin Pop
  """Run a command on some nodes.
1701 a8083063 Iustin Pop

1702 a8083063 Iustin Pop
  """
1703 a8083063 Iustin Pop
  _OP_REQP = ["command", "nodes"]
1704 a8083063 Iustin Pop
1705 a8083063 Iustin Pop
  def CheckPrereq(self):
1706 a8083063 Iustin Pop
    """Check prerequisites.
1707 a8083063 Iustin Pop

1708 a8083063 Iustin Pop
    It checks that the given list of nodes is valid.
1709 a8083063 Iustin Pop

1710 a8083063 Iustin Pop
    """
1711 dcb93971 Michael Hanselmann
    self.nodes = _GetWantedNodes(self, self.op.nodes)
1712 a8083063 Iustin Pop
1713 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1714 a8083063 Iustin Pop
    """Run a command on some nodes.
1715 a8083063 Iustin Pop

1716 a8083063 Iustin Pop
    """
1717 a8083063 Iustin Pop
    data = []
1718 a8083063 Iustin Pop
    for node in self.nodes:
1719 a7ba5e53 Iustin Pop
      result = ssh.SSHCall(node, "root", self.op.command)
1720 a7ba5e53 Iustin Pop
      data.append((node, result.output, result.exit_code))
1721 a8083063 Iustin Pop
1722 a8083063 Iustin Pop
    return data
1723 a8083063 Iustin Pop
1724 a8083063 Iustin Pop
1725 a8083063 Iustin Pop
class LUActivateInstanceDisks(NoHooksLU):
1726 a8083063 Iustin Pop
  """Bring up an instance's disks.
1727 a8083063 Iustin Pop

1728 a8083063 Iustin Pop
  """
1729 a8083063 Iustin Pop
  _OP_REQP = ["instance_name"]
1730 a8083063 Iustin Pop
1731 a8083063 Iustin Pop
  def CheckPrereq(self):
1732 a8083063 Iustin Pop
    """Check prerequisites.
1733 a8083063 Iustin Pop

1734 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
1735 a8083063 Iustin Pop

1736 a8083063 Iustin Pop
    """
1737 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
1738 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
1739 a8083063 Iustin Pop
    if instance is None:
1740 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
1741 3ecf6786 Iustin Pop
                                 self.op.instance_name)
1742 a8083063 Iustin Pop
    self.instance = instance
1743 a8083063 Iustin Pop
1744 a8083063 Iustin Pop
1745 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1746 a8083063 Iustin Pop
    """Activate the disks.
1747 a8083063 Iustin Pop

1748 a8083063 Iustin Pop
    """
1749 a8083063 Iustin Pop
    disks_ok, disks_info = _AssembleInstanceDisks(self.instance, self.cfg)
1750 a8083063 Iustin Pop
    if not disks_ok:
1751 3ecf6786 Iustin Pop
      raise errors.OpExecError("Cannot activate block devices")
1752 a8083063 Iustin Pop
1753 a8083063 Iustin Pop
    return disks_info
1754 a8083063 Iustin Pop
1755 a8083063 Iustin Pop
1756 a8083063 Iustin Pop
def _AssembleInstanceDisks(instance, cfg, ignore_secondaries=False):
1757 a8083063 Iustin Pop
  """Prepare the block devices for an instance.
1758 a8083063 Iustin Pop

1759 a8083063 Iustin Pop
  This sets up the block devices on all nodes.
1760 a8083063 Iustin Pop

1761 a8083063 Iustin Pop
  Args:
1762 a8083063 Iustin Pop
    instance: a ganeti.objects.Instance object
1763 a8083063 Iustin Pop
    ignore_secondaries: if true, errors on secondary nodes won't result
1764 a8083063 Iustin Pop
                        in an error return from the function
1765 a8083063 Iustin Pop

1766 a8083063 Iustin Pop
  Returns:
1767 a8083063 Iustin Pop
    false if the operation failed
1768 a8083063 Iustin Pop
    list of (host, instance_visible_name, node_visible_name) if the operation
1769 a8083063 Iustin Pop
         suceeded with the mapping from node devices to instance devices
1770 a8083063 Iustin Pop
  """
1771 a8083063 Iustin Pop
  device_info = []
1772 a8083063 Iustin Pop
  disks_ok = True
1773 a8083063 Iustin Pop
  for inst_disk in instance.disks:
1774 a8083063 Iustin Pop
    master_result = None
1775 a8083063 Iustin Pop
    for node, node_disk in inst_disk.ComputeNodeTree(instance.primary_node):
1776 a8083063 Iustin Pop
      cfg.SetDiskID(node_disk, node)
1777 a8083063 Iustin Pop
      is_primary = node == instance.primary_node
1778 3f78eef2 Iustin Pop
      result = rpc.call_blockdev_assemble(node, node_disk,
1779 3f78eef2 Iustin Pop
                                          instance.name, is_primary)
1780 a8083063 Iustin Pop
      if not result:
1781 a8083063 Iustin Pop
        logger.Error("could not prepare block device %s on node %s (is_pri"
1782 a8083063 Iustin Pop
                     "mary=%s)" % (inst_disk.iv_name, node, is_primary))
1783 a8083063 Iustin Pop
        if is_primary or not ignore_secondaries:
1784 a8083063 Iustin Pop
          disks_ok = False
1785 a8083063 Iustin Pop
      if is_primary:
1786 a8083063 Iustin Pop
        master_result = result
1787 a8083063 Iustin Pop
    device_info.append((instance.primary_node, inst_disk.iv_name,
1788 a8083063 Iustin Pop
                        master_result))
1789 a8083063 Iustin Pop
1790 b352ab5b Iustin Pop
  # leave the disks configured for the primary node
1791 b352ab5b Iustin Pop
  # this is a workaround that would be fixed better by
1792 b352ab5b Iustin Pop
  # improving the logical/physical id handling
1793 b352ab5b Iustin Pop
  for disk in instance.disks:
1794 b352ab5b Iustin Pop
    cfg.SetDiskID(disk, instance.primary_node)
1795 b352ab5b Iustin Pop
1796 a8083063 Iustin Pop
  return disks_ok, device_info
1797 a8083063 Iustin Pop
1798 a8083063 Iustin Pop
1799 fe7b0351 Michael Hanselmann
def _StartInstanceDisks(cfg, instance, force):
1800 3ecf6786 Iustin Pop
  """Start the disks of an instance.
1801 3ecf6786 Iustin Pop

1802 3ecf6786 Iustin Pop
  """
1803 fe7b0351 Michael Hanselmann
  disks_ok, dummy = _AssembleInstanceDisks(instance, cfg,
1804 fe7b0351 Michael Hanselmann
                                           ignore_secondaries=force)
1805 fe7b0351 Michael Hanselmann
  if not disks_ok:
1806 fe7b0351 Michael Hanselmann
    _ShutdownInstanceDisks(instance, cfg)
1807 fe7b0351 Michael Hanselmann
    if force is not None and not force:
1808 fe7b0351 Michael Hanselmann
      logger.Error("If the message above refers to a secondary node,"
1809 fe7b0351 Michael Hanselmann
                   " you can retry the operation using '--force'.")
1810 3ecf6786 Iustin Pop
    raise errors.OpExecError("Disk consistency error")
1811 fe7b0351 Michael Hanselmann
1812 fe7b0351 Michael Hanselmann
1813 a8083063 Iustin Pop
class LUDeactivateInstanceDisks(NoHooksLU):
1814 a8083063 Iustin Pop
  """Shutdown an instance's disks.
1815 a8083063 Iustin Pop

1816 a8083063 Iustin Pop
  """
1817 a8083063 Iustin Pop
  _OP_REQP = ["instance_name"]
1818 a8083063 Iustin Pop
1819 a8083063 Iustin Pop
  def CheckPrereq(self):
1820 a8083063 Iustin Pop
    """Check prerequisites.
1821 a8083063 Iustin Pop

1822 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
1823 a8083063 Iustin Pop

1824 a8083063 Iustin Pop
    """
1825 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
1826 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
1827 a8083063 Iustin Pop
    if instance is None:
1828 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
1829 3ecf6786 Iustin Pop
                                 self.op.instance_name)
1830 a8083063 Iustin Pop
    self.instance = instance
1831 a8083063 Iustin Pop
1832 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1833 a8083063 Iustin Pop
    """Deactivate the disks
1834 a8083063 Iustin Pop

1835 a8083063 Iustin Pop
    """
1836 a8083063 Iustin Pop
    instance = self.instance
1837 a8083063 Iustin Pop
    ins_l = rpc.call_instance_list([instance.primary_node])
1838 a8083063 Iustin Pop
    ins_l = ins_l[instance.primary_node]
1839 a8083063 Iustin Pop
    if not type(ins_l) is list:
1840 3ecf6786 Iustin Pop
      raise errors.OpExecError("Can't contact node '%s'" %
1841 3ecf6786 Iustin Pop
                               instance.primary_node)
1842 a8083063 Iustin Pop
1843 a8083063 Iustin Pop
    if self.instance.name in ins_l:
1844 3ecf6786 Iustin Pop
      raise errors.OpExecError("Instance is running, can't shutdown"
1845 3ecf6786 Iustin Pop
                               " block devices.")
1846 a8083063 Iustin Pop
1847 a8083063 Iustin Pop
    _ShutdownInstanceDisks(instance, self.cfg)
1848 a8083063 Iustin Pop
1849 a8083063 Iustin Pop
1850 a8083063 Iustin Pop
def _ShutdownInstanceDisks(instance, cfg, ignore_primary=False):
1851 a8083063 Iustin Pop
  """Shutdown block devices of an instance.
1852 a8083063 Iustin Pop

1853 a8083063 Iustin Pop
  This does the shutdown on all nodes of the instance.
1854 a8083063 Iustin Pop

1855 a8083063 Iustin Pop
  If the ignore_primary is false, errors on the primary node are
1856 a8083063 Iustin Pop
  ignored.
1857 a8083063 Iustin Pop

1858 a8083063 Iustin Pop
  """
1859 a8083063 Iustin Pop
  result = True
1860 a8083063 Iustin Pop
  for disk in instance.disks:
1861 a8083063 Iustin Pop
    for node, top_disk in disk.ComputeNodeTree(instance.primary_node):
1862 a8083063 Iustin Pop
      cfg.SetDiskID(top_disk, node)
1863 a8083063 Iustin Pop
      if not rpc.call_blockdev_shutdown(node, top_disk):
1864 a8083063 Iustin Pop
        logger.Error("could not shutdown block device %s on node %s" %
1865 a8083063 Iustin Pop
                     (disk.iv_name, node))
1866 a8083063 Iustin Pop
        if not ignore_primary or node != instance.primary_node:
1867 a8083063 Iustin Pop
          result = False
1868 a8083063 Iustin Pop
  return result
1869 a8083063 Iustin Pop
1870 a8083063 Iustin Pop
1871 a8083063 Iustin Pop
class LUStartupInstance(LogicalUnit):
1872 a8083063 Iustin Pop
  """Starts an instance.
1873 a8083063 Iustin Pop

1874 a8083063 Iustin Pop
  """
1875 a8083063 Iustin Pop
  HPATH = "instance-start"
1876 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
1877 a8083063 Iustin Pop
  _OP_REQP = ["instance_name", "force"]
1878 a8083063 Iustin Pop
1879 a8083063 Iustin Pop
  def BuildHooksEnv(self):
1880 a8083063 Iustin Pop
    """Build hooks env.
1881 a8083063 Iustin Pop

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

1884 a8083063 Iustin Pop
    """
1885 a8083063 Iustin Pop
    env = {
1886 a8083063 Iustin Pop
      "FORCE": self.op.force,
1887 a8083063 Iustin Pop
      }
1888 396e1b78 Michael Hanselmann
    env.update(_BuildInstanceHookEnvByObject(self.instance))
1889 880478f8 Iustin Pop
    nl = ([self.sstore.GetMasterNode(), self.instance.primary_node] +
1890 a8083063 Iustin Pop
          list(self.instance.secondary_nodes))
1891 a8083063 Iustin Pop
    return env, nl, nl
1892 a8083063 Iustin Pop
1893 a8083063 Iustin Pop
  def CheckPrereq(self):
1894 a8083063 Iustin Pop
    """Check prerequisites.
1895 a8083063 Iustin Pop

1896 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
1897 a8083063 Iustin Pop

1898 a8083063 Iustin Pop
    """
1899 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
1900 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
1901 a8083063 Iustin Pop
    if instance is None:
1902 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
1903 3ecf6786 Iustin Pop
                                 self.op.instance_name)
1904 a8083063 Iustin Pop
1905 a8083063 Iustin Pop
    # check bridges existance
1906 bf6929a2 Alexander Schreiber
    _CheckInstanceBridgesExist(instance)
1907 a8083063 Iustin Pop
1908 a8083063 Iustin Pop
    self.instance = instance
1909 a8083063 Iustin Pop
    self.op.instance_name = instance.name
1910 a8083063 Iustin Pop
1911 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
1912 a8083063 Iustin Pop
    """Start the instance.
1913 a8083063 Iustin Pop

1914 a8083063 Iustin Pop
    """
1915 a8083063 Iustin Pop
    instance = self.instance
1916 a8083063 Iustin Pop
    force = self.op.force
1917 a8083063 Iustin Pop
    extra_args = getattr(self.op, "extra_args", "")
1918 a8083063 Iustin Pop
1919 a8083063 Iustin Pop
    node_current = instance.primary_node
1920 a8083063 Iustin Pop
1921 a8083063 Iustin Pop
    nodeinfo = rpc.call_node_info([node_current], self.cfg.GetVGName())
1922 a8083063 Iustin Pop
    if not nodeinfo:
1923 3ecf6786 Iustin Pop
      raise errors.OpExecError("Could not contact node %s for infos" %
1924 3ecf6786 Iustin Pop
                               (node_current))
1925 a8083063 Iustin Pop
1926 a8083063 Iustin Pop
    freememory = nodeinfo[node_current]['memory_free']
1927 a8083063 Iustin Pop
    memory = instance.memory
1928 a8083063 Iustin Pop
    if memory > freememory:
1929 3ecf6786 Iustin Pop
      raise errors.OpExecError("Not enough memory to start instance"
1930 3ecf6786 Iustin Pop
                               " %s on node %s"
1931 3ecf6786 Iustin Pop
                               " needed %s MiB, available %s MiB" %
1932 3ecf6786 Iustin Pop
                               (instance.name, node_current, memory,
1933 3ecf6786 Iustin Pop
                                freememory))
1934 a8083063 Iustin Pop
1935 fe7b0351 Michael Hanselmann
    _StartInstanceDisks(self.cfg, instance, force)
1936 a8083063 Iustin Pop
1937 a8083063 Iustin Pop
    if not rpc.call_instance_start(node_current, instance, extra_args):
1938 a8083063 Iustin Pop
      _ShutdownInstanceDisks(instance, self.cfg)
1939 3ecf6786 Iustin Pop
      raise errors.OpExecError("Could not start instance")
1940 a8083063 Iustin Pop
1941 a8083063 Iustin Pop
    self.cfg.MarkInstanceUp(instance.name)
1942 a8083063 Iustin Pop
1943 a8083063 Iustin Pop
1944 bf6929a2 Alexander Schreiber
class LURebootInstance(LogicalUnit):
1945 bf6929a2 Alexander Schreiber
  """Reboot an instance.
1946 bf6929a2 Alexander Schreiber

1947 bf6929a2 Alexander Schreiber
  """
1948 bf6929a2 Alexander Schreiber
  HPATH = "instance-reboot"
1949 bf6929a2 Alexander Schreiber
  HTYPE = constants.HTYPE_INSTANCE
1950 bf6929a2 Alexander Schreiber
  _OP_REQP = ["instance_name", "ignore_secondaries", "reboot_type"]
1951 bf6929a2 Alexander Schreiber
1952 bf6929a2 Alexander Schreiber
  def BuildHooksEnv(self):
1953 bf6929a2 Alexander Schreiber
    """Build hooks env.
1954 bf6929a2 Alexander Schreiber

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

1957 bf6929a2 Alexander Schreiber
    """
1958 bf6929a2 Alexander Schreiber
    env = {
1959 bf6929a2 Alexander Schreiber
      "IGNORE_SECONDARIES": self.op.ignore_secondaries,
1960 bf6929a2 Alexander Schreiber
      }
1961 bf6929a2 Alexander Schreiber
    env.update(_BuildInstanceHookEnvByObject(self.instance))
1962 bf6929a2 Alexander Schreiber
    nl = ([self.sstore.GetMasterNode(), self.instance.primary_node] +
1963 bf6929a2 Alexander Schreiber
          list(self.instance.secondary_nodes))
1964 bf6929a2 Alexander Schreiber
    return env, nl, nl
1965 bf6929a2 Alexander Schreiber
1966 bf6929a2 Alexander Schreiber
  def CheckPrereq(self):
1967 bf6929a2 Alexander Schreiber
    """Check prerequisites.
1968 bf6929a2 Alexander Schreiber

1969 bf6929a2 Alexander Schreiber
    This checks that the instance is in the cluster.
1970 bf6929a2 Alexander Schreiber

1971 bf6929a2 Alexander Schreiber
    """
1972 bf6929a2 Alexander Schreiber
    instance = self.cfg.GetInstanceInfo(
1973 bf6929a2 Alexander Schreiber
      self.cfg.ExpandInstanceName(self.op.instance_name))
1974 bf6929a2 Alexander Schreiber
    if instance is None:
1975 bf6929a2 Alexander Schreiber
      raise errors.OpPrereqError("Instance '%s' not known" %
1976 bf6929a2 Alexander Schreiber
                                 self.op.instance_name)
1977 bf6929a2 Alexander Schreiber
1978 bf6929a2 Alexander Schreiber
    # check bridges existance
1979 bf6929a2 Alexander Schreiber
    _CheckInstanceBridgesExist(instance)
1980 bf6929a2 Alexander Schreiber
1981 bf6929a2 Alexander Schreiber
    self.instance = instance
1982 bf6929a2 Alexander Schreiber
    self.op.instance_name = instance.name
1983 bf6929a2 Alexander Schreiber
1984 bf6929a2 Alexander Schreiber
  def Exec(self, feedback_fn):
1985 bf6929a2 Alexander Schreiber
    """Reboot the instance.
1986 bf6929a2 Alexander Schreiber

1987 bf6929a2 Alexander Schreiber
    """
1988 bf6929a2 Alexander Schreiber
    instance = self.instance
1989 bf6929a2 Alexander Schreiber
    ignore_secondaries = self.op.ignore_secondaries
1990 bf6929a2 Alexander Schreiber
    reboot_type = self.op.reboot_type
1991 bf6929a2 Alexander Schreiber
    extra_args = getattr(self.op, "extra_args", "")
1992 bf6929a2 Alexander Schreiber
1993 bf6929a2 Alexander Schreiber
    node_current = instance.primary_node
1994 bf6929a2 Alexander Schreiber
1995 bf6929a2 Alexander Schreiber
    if reboot_type not in [constants.INSTANCE_REBOOT_SOFT,
1996 bf6929a2 Alexander Schreiber
                           constants.INSTANCE_REBOOT_HARD,
1997 bf6929a2 Alexander Schreiber
                           constants.INSTANCE_REBOOT_FULL]:
1998 bf6929a2 Alexander Schreiber
      raise errors.ParameterError("reboot type not in [%s, %s, %s]" %
1999 bf6929a2 Alexander Schreiber
                                  (constants.INSTANCE_REBOOT_SOFT,
2000 bf6929a2 Alexander Schreiber
                                   constants.INSTANCE_REBOOT_HARD,
2001 bf6929a2 Alexander Schreiber
                                   constants.INSTANCE_REBOOT_FULL))
2002 bf6929a2 Alexander Schreiber
2003 bf6929a2 Alexander Schreiber
    if reboot_type in [constants.INSTANCE_REBOOT_SOFT,
2004 bf6929a2 Alexander Schreiber
                       constants.INSTANCE_REBOOT_HARD]:
2005 bf6929a2 Alexander Schreiber
      if not rpc.call_instance_reboot(node_current, instance,
2006 bf6929a2 Alexander Schreiber
                                      reboot_type, extra_args):
2007 bf6929a2 Alexander Schreiber
        raise errors.OpExecError("Could not reboot instance")
2008 bf6929a2 Alexander Schreiber
    else:
2009 bf6929a2 Alexander Schreiber
      if not rpc.call_instance_shutdown(node_current, instance):
2010 bf6929a2 Alexander Schreiber
        raise errors.OpExecError("could not shutdown instance for full reboot")
2011 bf6929a2 Alexander Schreiber
      _ShutdownInstanceDisks(instance, self.cfg)
2012 bf6929a2 Alexander Schreiber
      _StartInstanceDisks(self.cfg, instance, ignore_secondaries)
2013 bf6929a2 Alexander Schreiber
      if not rpc.call_instance_start(node_current, instance, extra_args):
2014 bf6929a2 Alexander Schreiber
        _ShutdownInstanceDisks(instance, self.cfg)
2015 bf6929a2 Alexander Schreiber
        raise errors.OpExecError("Could not start instance for full reboot")
2016 bf6929a2 Alexander Schreiber
2017 bf6929a2 Alexander Schreiber
    self.cfg.MarkInstanceUp(instance.name)
2018 bf6929a2 Alexander Schreiber
2019 bf6929a2 Alexander Schreiber
2020 a8083063 Iustin Pop
class LUShutdownInstance(LogicalUnit):
2021 a8083063 Iustin Pop
  """Shutdown an instance.
2022 a8083063 Iustin Pop

2023 a8083063 Iustin Pop
  """
2024 a8083063 Iustin Pop
  HPATH = "instance-stop"
2025 a8083063 Iustin Pop
  HTYPE = constants.HTYPE_INSTANCE
2026 a8083063 Iustin Pop
  _OP_REQP = ["instance_name"]
2027 a8083063 Iustin Pop
2028 a8083063 Iustin Pop
  def BuildHooksEnv(self):
2029 a8083063 Iustin Pop
    """Build hooks env.
2030 a8083063 Iustin Pop

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

2033 a8083063 Iustin Pop
    """
2034 396e1b78 Michael Hanselmann
    env = _BuildInstanceHookEnvByObject(self.instance)
2035 880478f8 Iustin Pop
    nl = ([self.sstore.GetMasterNode(), self.instance.primary_node] +
2036 a8083063 Iustin Pop
          list(self.instance.secondary_nodes))
2037 a8083063 Iustin Pop
    return env, nl, nl
2038 a8083063 Iustin Pop
2039 a8083063 Iustin Pop
  def CheckPrereq(self):
2040 a8083063 Iustin Pop
    """Check prerequisites.
2041 a8083063 Iustin Pop

2042 a8083063 Iustin Pop
    This checks that the instance is in the cluster.
2043 a8083063 Iustin Pop

2044 a8083063 Iustin Pop
    """
2045 a8083063 Iustin Pop
    instance = self.cfg.GetInstanceInfo(
2046 a8083063 Iustin Pop
      self.cfg.ExpandInstanceName(self.op.instance_name))
2047 a8083063 Iustin Pop
    if instance is None:
2048 3ecf6786 Iustin Pop
      raise errors.OpPrereqError("Instance '%s' not known" %
2049 3ecf6786 Iustin Pop
                                 self.op.instance_name)
2050 a8083063 Iustin Pop
    self.instance = instance
2051 a8083063 Iustin Pop
2052 a8083063 Iustin Pop
  def Exec(self, feedback_fn):
2053 a8083063 Iustin Pop
    """Shutdown the instance.
2054 a8083063 Iustin Pop

2055 a8083063 Iustin Pop
    """
2056 a8083063 Iustin Pop
    instance = self.instance
2057 a8083063 Iustin Pop
    node_current = instance.primary_node
2058 a8083063 Iustin Pop
    if not rpc.call_instance_shutdown(node_current, instance):
2059 a8083063 Iustin Pop
      logger.Error("could not shutdown instance")
2060 a8083063 Iustin Pop
2061 a8083063 Iustin Pop
    self.cfg.MarkInstanceDown(instance.name)
2062 a8083063 Iustin Pop
    _ShutdownInstanceDisks(instance, self.cfg)
2063 a8083063 Iustin Pop
2064 a8083063 Iustin Pop
2065 fe7b0351 Michael Hanselmann
class LUReinstallInstance(LogicalUnit):
2066 fe7b0351 Michael Hanselmann
  """Reinstall an instance.
2067 fe7b0351 Michael Hanselmann

2068 fe7b0351 Michael Hanselmann
  """
2069 fe7b0351 Michael Hanselmann
  HPATH = "instance-reinstall"
2070 fe7b0351 Michael Hanselmann
  HTYPE = constants.HTYPE_INSTANCE
2071 fe7b0351 Michael Hanselmann
  _OP_REQP = ["instance_name"]
2072 fe7b0351 Michael Hanselmann
2073 fe7b0351 Michael Hanselmann
  def BuildHooksEnv(self):
2074 fe7b0351 Michael Hanselmann
    """Build hooks env.
2075 fe7b0351 Michael Hanselmann

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

2078 fe7b0351 Michael Hanselmann
    </