Statistics
| Branch: | Tag: | Revision:

root / lib / cmdlib / node.py @ 884ec6d4

History | View | Annotate | Download (60.1 kB)

1 31b836b8 Thomas Thrainer
#
2 31b836b8 Thomas Thrainer
#
3 31b836b8 Thomas Thrainer
4 31b836b8 Thomas Thrainer
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Google Inc.
5 31b836b8 Thomas Thrainer
#
6 31b836b8 Thomas Thrainer
# This program is free software; you can redistribute it and/or modify
7 31b836b8 Thomas Thrainer
# it under the terms of the GNU General Public License as published by
8 31b836b8 Thomas Thrainer
# the Free Software Foundation; either version 2 of the License, or
9 31b836b8 Thomas Thrainer
# (at your option) any later version.
10 31b836b8 Thomas Thrainer
#
11 31b836b8 Thomas Thrainer
# This program is distributed in the hope that it will be useful, but
12 31b836b8 Thomas Thrainer
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 31b836b8 Thomas Thrainer
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 31b836b8 Thomas Thrainer
# General Public License for more details.
15 31b836b8 Thomas Thrainer
#
16 31b836b8 Thomas Thrainer
# You should have received a copy of the GNU General Public License
17 31b836b8 Thomas Thrainer
# along with this program; if not, write to the Free Software
18 31b836b8 Thomas Thrainer
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 31b836b8 Thomas Thrainer
# 02110-1301, USA.
20 31b836b8 Thomas Thrainer
21 31b836b8 Thomas Thrainer
22 31b836b8 Thomas Thrainer
"""Logical units dealing with nodes."""
23 31b836b8 Thomas Thrainer
24 31b836b8 Thomas Thrainer
import logging
25 31b836b8 Thomas Thrainer
import operator
26 31b836b8 Thomas Thrainer
27 31b836b8 Thomas Thrainer
from ganeti import constants
28 31b836b8 Thomas Thrainer
from ganeti import errors
29 31b836b8 Thomas Thrainer
from ganeti import locking
30 31b836b8 Thomas Thrainer
from ganeti import netutils
31 31b836b8 Thomas Thrainer
from ganeti import objects
32 31b836b8 Thomas Thrainer
from ganeti import opcodes
33 31b836b8 Thomas Thrainer
from ganeti import qlang
34 31b836b8 Thomas Thrainer
from ganeti import query
35 31b836b8 Thomas Thrainer
from ganeti import rpc
36 31b836b8 Thomas Thrainer
from ganeti import utils
37 31b836b8 Thomas Thrainer
from ganeti.masterd import iallocator
38 31b836b8 Thomas Thrainer
39 5eacbcae Thomas Thrainer
from ganeti.cmdlib.base import LogicalUnit, NoHooksLU, QueryBase, \
40 31b836b8 Thomas Thrainer
  ResultWithJobs
41 5eacbcae Thomas Thrainer
from ganeti.cmdlib.common import CheckParamsNotGlobal, \
42 5eacbcae Thomas Thrainer
  MergeAndVerifyHvState, MergeAndVerifyDiskState, \
43 5eacbcae Thomas Thrainer
  IsExclusiveStorageEnabledNode, CheckNodePVs, \
44 1c3231aa Thomas Thrainer
  RedistributeAncillaryFiles, ExpandNodeUuidAndName, ShareAll, SupportsOob, \
45 5eacbcae Thomas Thrainer
  CheckInstanceState, INSTANCE_DOWN, GetUpdatedParams, \
46 5eacbcae Thomas Thrainer
  AdjustCandidatePool, CheckIAllocatorOrNode, LoadNodeEvacResult, \
47 843094ad Thomas Thrainer
  GetWantedNodes, MapInstanceLvsToNodes, RunPostHook, \
48 9d276e93 Helga Velroyen
  FindFaultyInstanceDisks, CheckStorageTypeEnabled
49 31b836b8 Thomas Thrainer
50 31b836b8 Thomas Thrainer
51 31b836b8 Thomas Thrainer
def _DecideSelfPromotion(lu, exceptions=None):
52 31b836b8 Thomas Thrainer
  """Decide whether I should promote myself as a master candidate.
53 31b836b8 Thomas Thrainer

54 31b836b8 Thomas Thrainer
  """
55 31b836b8 Thomas Thrainer
  cp_size = lu.cfg.GetClusterInfo().candidate_pool_size
56 31b836b8 Thomas Thrainer
  mc_now, mc_should, _ = lu.cfg.GetMasterCandidateStats(exceptions)
57 31b836b8 Thomas Thrainer
  # the new node will increase mc_max with one, so:
58 31b836b8 Thomas Thrainer
  mc_should = min(mc_should + 1, cp_size)
59 31b836b8 Thomas Thrainer
  return mc_now < mc_should
60 31b836b8 Thomas Thrainer
61 31b836b8 Thomas Thrainer
62 31b836b8 Thomas Thrainer
def _CheckNodeHasSecondaryIP(lu, node, secondary_ip, prereq):
63 31b836b8 Thomas Thrainer
  """Ensure that a node has the given secondary ip.
64 31b836b8 Thomas Thrainer

65 31b836b8 Thomas Thrainer
  @type lu: L{LogicalUnit}
66 31b836b8 Thomas Thrainer
  @param lu: the LU on behalf of which we make the check
67 1c3231aa Thomas Thrainer
  @type node: L{objects.Node}
68 31b836b8 Thomas Thrainer
  @param node: the node to check
69 31b836b8 Thomas Thrainer
  @type secondary_ip: string
70 31b836b8 Thomas Thrainer
  @param secondary_ip: the ip to check
71 31b836b8 Thomas Thrainer
  @type prereq: boolean
72 31b836b8 Thomas Thrainer
  @param prereq: whether to throw a prerequisite or an execute error
73 1c3231aa Thomas Thrainer
  @raise errors.OpPrereqError: if the node doesn't have the ip,
74 1c3231aa Thomas Thrainer
  and prereq=True
75 31b836b8 Thomas Thrainer
  @raise errors.OpExecError: if the node doesn't have the ip, and prereq=False
76 31b836b8 Thomas Thrainer

77 31b836b8 Thomas Thrainer
  """
78 1c3231aa Thomas Thrainer
  # this can be called with a new node, which has no UUID yet, so perform the
79 1c3231aa Thomas Thrainer
  # RPC call using its name
80 1c3231aa Thomas Thrainer
  result = lu.rpc.call_node_has_ip_address(node.name, secondary_ip)
81 1c3231aa Thomas Thrainer
  result.Raise("Failure checking secondary ip on node %s" % node.name,
82 31b836b8 Thomas Thrainer
               prereq=prereq, ecode=errors.ECODE_ENVIRON)
83 31b836b8 Thomas Thrainer
  if not result.payload:
84 31b836b8 Thomas Thrainer
    msg = ("Node claims it doesn't have the secondary ip you gave (%s),"
85 31b836b8 Thomas Thrainer
           " please fix and re-run this command" % secondary_ip)
86 31b836b8 Thomas Thrainer
    if prereq:
87 31b836b8 Thomas Thrainer
      raise errors.OpPrereqError(msg, errors.ECODE_ENVIRON)
88 31b836b8 Thomas Thrainer
    else:
89 31b836b8 Thomas Thrainer
      raise errors.OpExecError(msg)
90 31b836b8 Thomas Thrainer
91 31b836b8 Thomas Thrainer
92 31b836b8 Thomas Thrainer
class LUNodeAdd(LogicalUnit):
93 31b836b8 Thomas Thrainer
  """Logical unit for adding node to the cluster.
94 31b836b8 Thomas Thrainer

95 31b836b8 Thomas Thrainer
  """
96 31b836b8 Thomas Thrainer
  HPATH = "node-add"
97 31b836b8 Thomas Thrainer
  HTYPE = constants.HTYPE_NODE
98 31b836b8 Thomas Thrainer
  _NFLAGS = ["master_capable", "vm_capable"]
99 31b836b8 Thomas Thrainer
100 31b836b8 Thomas Thrainer
  def CheckArguments(self):
101 31b836b8 Thomas Thrainer
    self.primary_ip_family = self.cfg.GetPrimaryIPFamily()
102 31b836b8 Thomas Thrainer
    # validate/normalize the node name
103 31b836b8 Thomas Thrainer
    self.hostname = netutils.GetHostname(name=self.op.node_name,
104 31b836b8 Thomas Thrainer
                                         family=self.primary_ip_family)
105 31b836b8 Thomas Thrainer
    self.op.node_name = self.hostname.name
106 31b836b8 Thomas Thrainer
107 1c3231aa Thomas Thrainer
    if self.op.readd and self.op.node_name == self.cfg.GetMasterNodeName():
108 31b836b8 Thomas Thrainer
      raise errors.OpPrereqError("Cannot readd the master node",
109 31b836b8 Thomas Thrainer
                                 errors.ECODE_STATE)
110 31b836b8 Thomas Thrainer
111 31b836b8 Thomas Thrainer
    if self.op.readd and self.op.group:
112 31b836b8 Thomas Thrainer
      raise errors.OpPrereqError("Cannot pass a node group when a node is"
113 31b836b8 Thomas Thrainer
                                 " being readded", errors.ECODE_INVAL)
114 31b836b8 Thomas Thrainer
115 31b836b8 Thomas Thrainer
  def BuildHooksEnv(self):
116 31b836b8 Thomas Thrainer
    """Build hooks env.
117 31b836b8 Thomas Thrainer

118 31b836b8 Thomas Thrainer
    This will run on all nodes before, and on all nodes + the new node after.
119 31b836b8 Thomas Thrainer

120 31b836b8 Thomas Thrainer
    """
121 31b836b8 Thomas Thrainer
    return {
122 31b836b8 Thomas Thrainer
      "OP_TARGET": self.op.node_name,
123 31b836b8 Thomas Thrainer
      "NODE_NAME": self.op.node_name,
124 31b836b8 Thomas Thrainer
      "NODE_PIP": self.op.primary_ip,
125 31b836b8 Thomas Thrainer
      "NODE_SIP": self.op.secondary_ip,
126 31b836b8 Thomas Thrainer
      "MASTER_CAPABLE": str(self.op.master_capable),
127 31b836b8 Thomas Thrainer
      "VM_CAPABLE": str(self.op.vm_capable),
128 31b836b8 Thomas Thrainer
      }
129 31b836b8 Thomas Thrainer
130 31b836b8 Thomas Thrainer
  def BuildHooksNodes(self):
131 31b836b8 Thomas Thrainer
    """Build hooks nodes.
132 31b836b8 Thomas Thrainer

133 31b836b8 Thomas Thrainer
    """
134 1c3231aa Thomas Thrainer
    hook_nodes = self.cfg.GetNodeList()
135 1c3231aa Thomas Thrainer
    new_node_info = self.cfg.GetNodeInfoByName(self.op.node_name)
136 1c3231aa Thomas Thrainer
    if new_node_info is not None:
137 1c3231aa Thomas Thrainer
      # Exclude added node
138 1c3231aa Thomas Thrainer
      hook_nodes = list(set(hook_nodes) - set([new_node_info.uuid]))
139 31b836b8 Thomas Thrainer
140 1c3231aa Thomas Thrainer
    # add the new node as post hook node by name; it does not have an UUID yet
141 1c3231aa Thomas Thrainer
    return (hook_nodes, hook_nodes, [self.op.node_name, ])
142 31b836b8 Thomas Thrainer
143 31b836b8 Thomas Thrainer
  def CheckPrereq(self):
144 31b836b8 Thomas Thrainer
    """Check prerequisites.
145 31b836b8 Thomas Thrainer

146 31b836b8 Thomas Thrainer
    This checks:
147 31b836b8 Thomas Thrainer
     - the new node is not already in the config
148 31b836b8 Thomas Thrainer
     - it is resolvable
149 31b836b8 Thomas Thrainer
     - its parameters (single/dual homed) matches the cluster
150 31b836b8 Thomas Thrainer

151 31b836b8 Thomas Thrainer
    Any errors are signaled by raising errors.OpPrereqError.
152 31b836b8 Thomas Thrainer

153 31b836b8 Thomas Thrainer
    """
154 d0d7d7cf Thomas Thrainer
    node_name = self.hostname.name
155 d0d7d7cf Thomas Thrainer
    self.op.primary_ip = self.hostname.ip
156 31b836b8 Thomas Thrainer
    if self.op.secondary_ip is None:
157 31b836b8 Thomas Thrainer
      if self.primary_ip_family == netutils.IP6Address.family:
158 31b836b8 Thomas Thrainer
        raise errors.OpPrereqError("When using a IPv6 primary address, a valid"
159 31b836b8 Thomas Thrainer
                                   " IPv4 address must be given as secondary",
160 31b836b8 Thomas Thrainer
                                   errors.ECODE_INVAL)
161 d0d7d7cf Thomas Thrainer
      self.op.secondary_ip = self.op.primary_ip
162 31b836b8 Thomas Thrainer
163 31b836b8 Thomas Thrainer
    secondary_ip = self.op.secondary_ip
164 31b836b8 Thomas Thrainer
    if not netutils.IP4Address.IsValid(secondary_ip):
165 31b836b8 Thomas Thrainer
      raise errors.OpPrereqError("Secondary IP (%s) needs to be a valid IPv4"
166 31b836b8 Thomas Thrainer
                                 " address" % secondary_ip, errors.ECODE_INVAL)
167 31b836b8 Thomas Thrainer
168 d0d7d7cf Thomas Thrainer
    existing_node_info = self.cfg.GetNodeInfoByName(node_name)
169 1c3231aa Thomas Thrainer
    if not self.op.readd and existing_node_info is not None:
170 31b836b8 Thomas Thrainer
      raise errors.OpPrereqError("Node %s is already in the configuration" %
171 1c3231aa Thomas Thrainer
                                 node_name, errors.ECODE_EXISTS)
172 1c3231aa Thomas Thrainer
    elif self.op.readd and existing_node_info is None:
173 1c3231aa Thomas Thrainer
      raise errors.OpPrereqError("Node %s is not in the configuration" %
174 1c3231aa Thomas Thrainer
                                 node_name, errors.ECODE_NOENT)
175 31b836b8 Thomas Thrainer
176 31b836b8 Thomas Thrainer
    self.changed_primary_ip = False
177 31b836b8 Thomas Thrainer
178 d0d7d7cf Thomas Thrainer
    for existing_node in self.cfg.GetAllNodesInfo().values():
179 1c3231aa Thomas Thrainer
      if self.op.readd and node_name == existing_node.name:
180 31b836b8 Thomas Thrainer
        if existing_node.secondary_ip != secondary_ip:
181 31b836b8 Thomas Thrainer
          raise errors.OpPrereqError("Readded node doesn't have the same IP"
182 31b836b8 Thomas Thrainer
                                     " address configuration as before",
183 31b836b8 Thomas Thrainer
                                     errors.ECODE_INVAL)
184 d0d7d7cf Thomas Thrainer
        if existing_node.primary_ip != self.op.primary_ip:
185 31b836b8 Thomas Thrainer
          self.changed_primary_ip = True
186 31b836b8 Thomas Thrainer
187 31b836b8 Thomas Thrainer
        continue
188 31b836b8 Thomas Thrainer
189 d0d7d7cf Thomas Thrainer
      if (existing_node.primary_ip == self.op.primary_ip or
190 d0d7d7cf Thomas Thrainer
          existing_node.secondary_ip == self.op.primary_ip or
191 31b836b8 Thomas Thrainer
          existing_node.primary_ip == secondary_ip or
192 31b836b8 Thomas Thrainer
          existing_node.secondary_ip == secondary_ip):
193 31b836b8 Thomas Thrainer
        raise errors.OpPrereqError("New node ip address(es) conflict with"
194 31b836b8 Thomas Thrainer
                                   " existing node %s" % existing_node.name,
195 31b836b8 Thomas Thrainer
                                   errors.ECODE_NOTUNIQUE)
196 31b836b8 Thomas Thrainer
197 31b836b8 Thomas Thrainer
    # After this 'if' block, None is no longer a valid value for the
198 31b836b8 Thomas Thrainer
    # _capable op attributes
199 31b836b8 Thomas Thrainer
    if self.op.readd:
200 1c3231aa Thomas Thrainer
      assert existing_node_info is not None, \
201 1c3231aa Thomas Thrainer
        "Can't retrieve locked node %s" % node_name
202 31b836b8 Thomas Thrainer
      for attr in self._NFLAGS:
203 31b836b8 Thomas Thrainer
        if getattr(self.op, attr) is None:
204 1c3231aa Thomas Thrainer
          setattr(self.op, attr, getattr(existing_node_info, attr))
205 31b836b8 Thomas Thrainer
    else:
206 31b836b8 Thomas Thrainer
      for attr in self._NFLAGS:
207 31b836b8 Thomas Thrainer
        if getattr(self.op, attr) is None:
208 31b836b8 Thomas Thrainer
          setattr(self.op, attr, True)
209 31b836b8 Thomas Thrainer
210 31b836b8 Thomas Thrainer
    if self.op.readd and not self.op.vm_capable:
211 d0d7d7cf Thomas Thrainer
      pri, sec = self.cfg.GetNodeInstances(existing_node_info.uuid)
212 31b836b8 Thomas Thrainer
      if pri or sec:
213 31b836b8 Thomas Thrainer
        raise errors.OpPrereqError("Node %s being re-added with vm_capable"
214 31b836b8 Thomas Thrainer
                                   " flag set to false, but it already holds"
215 1c3231aa Thomas Thrainer
                                   " instances" % node_name,
216 31b836b8 Thomas Thrainer
                                   errors.ECODE_STATE)
217 31b836b8 Thomas Thrainer
218 31b836b8 Thomas Thrainer
    # check that the type of the node (single versus dual homed) is the
219 31b836b8 Thomas Thrainer
    # same as for the master
220 6bb43023 Thomas Thrainer
    myself = self.cfg.GetMasterNodeInfo()
221 31b836b8 Thomas Thrainer
    master_singlehomed = myself.secondary_ip == myself.primary_ip
222 d0d7d7cf Thomas Thrainer
    newbie_singlehomed = secondary_ip == self.op.primary_ip
223 31b836b8 Thomas Thrainer
    if master_singlehomed != newbie_singlehomed:
224 31b836b8 Thomas Thrainer
      if master_singlehomed:
225 31b836b8 Thomas Thrainer
        raise errors.OpPrereqError("The master has no secondary ip but the"
226 31b836b8 Thomas Thrainer
                                   " new node has one",
227 31b836b8 Thomas Thrainer
                                   errors.ECODE_INVAL)
228 31b836b8 Thomas Thrainer
      else:
229 31b836b8 Thomas Thrainer
        raise errors.OpPrereqError("The master has a secondary ip but the"
230 31b836b8 Thomas Thrainer
                                   " new node doesn't have one",
231 31b836b8 Thomas Thrainer
                                   errors.ECODE_INVAL)
232 31b836b8 Thomas Thrainer
233 31b836b8 Thomas Thrainer
    # checks reachability
234 d0d7d7cf Thomas Thrainer
    if not netutils.TcpPing(self.op.primary_ip, constants.DEFAULT_NODED_PORT):
235 31b836b8 Thomas Thrainer
      raise errors.OpPrereqError("Node not reachable by ping",
236 31b836b8 Thomas Thrainer
                                 errors.ECODE_ENVIRON)
237 31b836b8 Thomas Thrainer
238 31b836b8 Thomas Thrainer
    if not newbie_singlehomed:
239 31b836b8 Thomas Thrainer
      # check reachability from my secondary ip to newbie's secondary ip
240 31b836b8 Thomas Thrainer
      if not netutils.TcpPing(secondary_ip, constants.DEFAULT_NODED_PORT,
241 31b836b8 Thomas Thrainer
                              source=myself.secondary_ip):
242 31b836b8 Thomas Thrainer
        raise errors.OpPrereqError("Node secondary ip not reachable by TCP"
243 31b836b8 Thomas Thrainer
                                   " based ping to node daemon port",
244 31b836b8 Thomas Thrainer
                                   errors.ECODE_ENVIRON)
245 31b836b8 Thomas Thrainer
246 31b836b8 Thomas Thrainer
    if self.op.readd:
247 1c3231aa Thomas Thrainer
      exceptions = [existing_node_info.uuid]
248 31b836b8 Thomas Thrainer
    else:
249 31b836b8 Thomas Thrainer
      exceptions = []
250 31b836b8 Thomas Thrainer
251 31b836b8 Thomas Thrainer
    if self.op.master_capable:
252 31b836b8 Thomas Thrainer
      self.master_candidate = _DecideSelfPromotion(self, exceptions=exceptions)
253 31b836b8 Thomas Thrainer
    else:
254 31b836b8 Thomas Thrainer
      self.master_candidate = False
255 31b836b8 Thomas Thrainer
256 31b836b8 Thomas Thrainer
    if self.op.readd:
257 1c3231aa Thomas Thrainer
      self.new_node = existing_node_info
258 31b836b8 Thomas Thrainer
    else:
259 d0d7d7cf Thomas Thrainer
      node_group = self.cfg.LookupNodeGroup(self.op.group)
260 1c3231aa Thomas Thrainer
      self.new_node = objects.Node(name=node_name,
261 d0d7d7cf Thomas Thrainer
                                   primary_ip=self.op.primary_ip,
262 31b836b8 Thomas Thrainer
                                   secondary_ip=secondary_ip,
263 31b836b8 Thomas Thrainer
                                   master_candidate=self.master_candidate,
264 31b836b8 Thomas Thrainer
                                   offline=False, drained=False,
265 31b836b8 Thomas Thrainer
                                   group=node_group, ndparams={})
266 31b836b8 Thomas Thrainer
267 31b836b8 Thomas Thrainer
    if self.op.ndparams:
268 31b836b8 Thomas Thrainer
      utils.ForceDictType(self.op.ndparams, constants.NDS_PARAMETER_TYPES)
269 5eacbcae Thomas Thrainer
      CheckParamsNotGlobal(self.op.ndparams, constants.NDC_GLOBALS, "node",
270 5eacbcae Thomas Thrainer
                           "node", "cluster or group")
271 31b836b8 Thomas Thrainer
272 31b836b8 Thomas Thrainer
    if self.op.hv_state:
273 5eacbcae Thomas Thrainer
      self.new_hv_state = MergeAndVerifyHvState(self.op.hv_state, None)
274 31b836b8 Thomas Thrainer
275 31b836b8 Thomas Thrainer
    if self.op.disk_state:
276 5eacbcae Thomas Thrainer
      self.new_disk_state = MergeAndVerifyDiskState(self.op.disk_state, None)
277 31b836b8 Thomas Thrainer
278 31b836b8 Thomas Thrainer
    # TODO: If we need to have multiple DnsOnlyRunner we probably should make
279 31b836b8 Thomas Thrainer
    #       it a property on the base class.
280 31b836b8 Thomas Thrainer
    rpcrunner = rpc.DnsOnlyRunner()
281 1c3231aa Thomas Thrainer
    result = rpcrunner.call_version([node_name])[node_name]
282 1c3231aa Thomas Thrainer
    result.Raise("Can't get version information from node %s" % node_name)
283 31b836b8 Thomas Thrainer
    if constants.PROTOCOL_VERSION == result.payload:
284 31b836b8 Thomas Thrainer
      logging.info("Communication to node %s fine, sw version %s match",
285 1c3231aa Thomas Thrainer
                   node_name, result.payload)
286 31b836b8 Thomas Thrainer
    else:
287 31b836b8 Thomas Thrainer
      raise errors.OpPrereqError("Version mismatch master version %s,"
288 31b836b8 Thomas Thrainer
                                 " node version %s" %
289 31b836b8 Thomas Thrainer
                                 (constants.PROTOCOL_VERSION, result.payload),
290 31b836b8 Thomas Thrainer
                                 errors.ECODE_ENVIRON)
291 31b836b8 Thomas Thrainer
292 d0d7d7cf Thomas Thrainer
    vg_name = self.cfg.GetVGName()
293 31b836b8 Thomas Thrainer
    if vg_name is not None:
294 31b836b8 Thomas Thrainer
      vparams = {constants.NV_PVLIST: [vg_name]}
295 d0d7d7cf Thomas Thrainer
      excl_stor = IsExclusiveStorageEnabledNode(self.cfg, self.new_node)
296 31b836b8 Thomas Thrainer
      cname = self.cfg.GetClusterName()
297 5b0dfcef Helga Velroyen
      result = rpcrunner.call_node_verify_light(
298 d0d7d7cf Thomas Thrainer
          [node_name], vparams, cname,
299 d0d7d7cf Thomas Thrainer
          self.cfg.GetClusterInfo().hvparams)[node_name]
300 5eacbcae Thomas Thrainer
      (errmsgs, _) = CheckNodePVs(result.payload, excl_stor)
301 31b836b8 Thomas Thrainer
      if errmsgs:
302 31b836b8 Thomas Thrainer
        raise errors.OpPrereqError("Checks on node PVs failed: %s" %
303 31b836b8 Thomas Thrainer
                                   "; ".join(errmsgs), errors.ECODE_ENVIRON)
304 31b836b8 Thomas Thrainer
305 07e68848 Thomas Thrainer
  def _InitOpenVSwitch(self):
306 07e68848 Thomas Thrainer
    filled_ndparams = self.cfg.GetClusterInfo().FillND(
307 07e68848 Thomas Thrainer
      self.new_node, self.cfg.GetNodeGroup(self.new_node.group))
308 07e68848 Thomas Thrainer
309 07e68848 Thomas Thrainer
    ovs = filled_ndparams.get(constants.ND_OVS, None)
310 07e68848 Thomas Thrainer
    ovs_name = filled_ndparams.get(constants.ND_OVS_NAME, None)
311 07e68848 Thomas Thrainer
    ovs_link = filled_ndparams.get(constants.ND_OVS_LINK, None)
312 07e68848 Thomas Thrainer
313 07e68848 Thomas Thrainer
    if ovs:
314 07e68848 Thomas Thrainer
      if not ovs_link:
315 07e68848 Thomas Thrainer
        self.LogInfo("No physical interface for OpenvSwitch was given."
316 07e68848 Thomas Thrainer
                     " OpenvSwitch will not have an outside connection. This"
317 07e68848 Thomas Thrainer
                     " might not be what you want.")
318 07e68848 Thomas Thrainer
319 07e68848 Thomas Thrainer
      result = self.rpc.call_node_configure_ovs(
320 07e68848 Thomas Thrainer
                 self.new_node.name, ovs_name, ovs_link)
321 07e68848 Thomas Thrainer
      result.Raise("Failed to initialize OpenVSwitch on new node")
322 07e68848 Thomas Thrainer
323 31b836b8 Thomas Thrainer
  def Exec(self, feedback_fn):
324 31b836b8 Thomas Thrainer
    """Adds the new node to the cluster.
325 31b836b8 Thomas Thrainer

326 31b836b8 Thomas Thrainer
    """
327 31b836b8 Thomas Thrainer
    assert locking.BGL in self.owned_locks(locking.LEVEL_CLUSTER), \
328 31b836b8 Thomas Thrainer
      "Not owning BGL"
329 31b836b8 Thomas Thrainer
330 31b836b8 Thomas Thrainer
    # We adding a new node so we assume it's powered
331 d0d7d7cf Thomas Thrainer
    self.new_node.powered = True
332 31b836b8 Thomas Thrainer
333 31b836b8 Thomas Thrainer
    # for re-adds, reset the offline/drained/master-candidate flags;
334 31b836b8 Thomas Thrainer
    # we need to reset here, otherwise offline would prevent RPC calls
335 31b836b8 Thomas Thrainer
    # later in the procedure; this also means that if the re-add
336 31b836b8 Thomas Thrainer
    # fails, we are left with a non-offlined, broken node
337 31b836b8 Thomas Thrainer
    if self.op.readd:
338 30796ad6 Klaus Aehlig
      self.new_node.offline = False
339 d0d7d7cf Thomas Thrainer
      self.new_node.drained = False
340 31b836b8 Thomas Thrainer
      self.LogInfo("Readding a node, the offline/drained flags were reset")
341 31b836b8 Thomas Thrainer
      # if we demote the node, we do cleanup later in the procedure
342 d0d7d7cf Thomas Thrainer
      self.new_node.master_candidate = self.master_candidate
343 31b836b8 Thomas Thrainer
      if self.changed_primary_ip:
344 d0d7d7cf Thomas Thrainer
        self.new_node.primary_ip = self.op.primary_ip
345 31b836b8 Thomas Thrainer
346 31b836b8 Thomas Thrainer
    # copy the master/vm_capable flags
347 31b836b8 Thomas Thrainer
    for attr in self._NFLAGS:
348 d0d7d7cf Thomas Thrainer
      setattr(self.new_node, attr, getattr(self.op, attr))
349 31b836b8 Thomas Thrainer
350 31b836b8 Thomas Thrainer
    # notify the user about any possible mc promotion
351 d0d7d7cf Thomas Thrainer
    if self.new_node.master_candidate:
352 31b836b8 Thomas Thrainer
      self.LogInfo("Node will be a master candidate")
353 31b836b8 Thomas Thrainer
354 31b836b8 Thomas Thrainer
    if self.op.ndparams:
355 d0d7d7cf Thomas Thrainer
      self.new_node.ndparams = self.op.ndparams
356 31b836b8 Thomas Thrainer
    else:
357 d0d7d7cf Thomas Thrainer
      self.new_node.ndparams = {}
358 31b836b8 Thomas Thrainer
359 31b836b8 Thomas Thrainer
    if self.op.hv_state:
360 d0d7d7cf Thomas Thrainer
      self.new_node.hv_state_static = self.new_hv_state
361 31b836b8 Thomas Thrainer
362 31b836b8 Thomas Thrainer
    if self.op.disk_state:
363 d0d7d7cf Thomas Thrainer
      self.new_node.disk_state_static = self.new_disk_state
364 31b836b8 Thomas Thrainer
365 31b836b8 Thomas Thrainer
    # Add node to our /etc/hosts, and add key to known_hosts
366 31b836b8 Thomas Thrainer
    if self.cfg.GetClusterInfo().modify_etc_hosts:
367 31b836b8 Thomas Thrainer
      master_node = self.cfg.GetMasterNode()
368 1c3231aa Thomas Thrainer
      result = self.rpc.call_etc_hosts_modify(
369 1c3231aa Thomas Thrainer
                 master_node, constants.ETC_HOSTS_ADD, self.hostname.name,
370 1c3231aa Thomas Thrainer
                 self.hostname.ip)
371 31b836b8 Thomas Thrainer
      result.Raise("Can't update hosts file with new host data")
372 31b836b8 Thomas Thrainer
373 d0d7d7cf Thomas Thrainer
    if self.new_node.secondary_ip != self.new_node.primary_ip:
374 d0d7d7cf Thomas Thrainer
      _CheckNodeHasSecondaryIP(self, self.new_node, self.new_node.secondary_ip,
375 d0d7d7cf Thomas Thrainer
                               False)
376 31b836b8 Thomas Thrainer
377 1c3231aa Thomas Thrainer
    node_verifier_uuids = [self.cfg.GetMasterNode()]
378 31b836b8 Thomas Thrainer
    node_verify_param = {
379 d0d7d7cf Thomas Thrainer
      constants.NV_NODELIST: ([self.new_node.name], {}),
380 31b836b8 Thomas Thrainer
      # TODO: do a node-net-test as well?
381 31b836b8 Thomas Thrainer
    }
382 31b836b8 Thomas Thrainer
383 1c3231aa Thomas Thrainer
    result = self.rpc.call_node_verify(
384 1c3231aa Thomas Thrainer
               node_verifier_uuids, node_verify_param,
385 1c3231aa Thomas Thrainer
               self.cfg.GetClusterName(),
386 1c3231aa Thomas Thrainer
               self.cfg.GetClusterInfo().hvparams)
387 1c3231aa Thomas Thrainer
    for verifier in node_verifier_uuids:
388 31b836b8 Thomas Thrainer
      result[verifier].Raise("Cannot communicate with node %s" % verifier)
389 31b836b8 Thomas Thrainer
      nl_payload = result[verifier].payload[constants.NV_NODELIST]
390 31b836b8 Thomas Thrainer
      if nl_payload:
391 31b836b8 Thomas Thrainer
        for failed in nl_payload:
392 31b836b8 Thomas Thrainer
          feedback_fn("ssh/hostname verification failed"
393 31b836b8 Thomas Thrainer
                      " (checking from %s): %s" %
394 31b836b8 Thomas Thrainer
                      (verifier, nl_payload[failed]))
395 31b836b8 Thomas Thrainer
        raise errors.OpExecError("ssh/hostname verification failed")
396 31b836b8 Thomas Thrainer
397 07e68848 Thomas Thrainer
    self._InitOpenVSwitch()
398 8baa9ca7 Sebastian Gebhard
399 31b836b8 Thomas Thrainer
    if self.op.readd:
400 d0d7d7cf Thomas Thrainer
      self.context.ReaddNode(self.new_node)
401 1c3231aa Thomas Thrainer
      RedistributeAncillaryFiles(self)
402 31b836b8 Thomas Thrainer
      # make sure we redistribute the config
403 d0d7d7cf Thomas Thrainer
      self.cfg.Update(self.new_node, feedback_fn)
404 31b836b8 Thomas Thrainer
      # and make sure the new node will not have old files around
405 d0d7d7cf Thomas Thrainer
      if not self.new_node.master_candidate:
406 d0d7d7cf Thomas Thrainer
        result = self.rpc.call_node_demote_from_mc(self.new_node.uuid)
407 c7dd65be Klaus Aehlig
        result.Warn("Node failed to demote itself from master candidate status",
408 c7dd65be Klaus Aehlig
                    self.LogWarning)
409 31b836b8 Thomas Thrainer
    else:
410 d0d7d7cf Thomas Thrainer
      self.context.AddNode(self.new_node, self.proc.GetECId())
411 1c3231aa Thomas Thrainer
      RedistributeAncillaryFiles(self)
412 31b836b8 Thomas Thrainer
413 31b836b8 Thomas Thrainer
414 31b836b8 Thomas Thrainer
class LUNodeSetParams(LogicalUnit):
415 31b836b8 Thomas Thrainer
  """Modifies the parameters of a node.
416 31b836b8 Thomas Thrainer

417 31b836b8 Thomas Thrainer
  @cvar _F2R: a dictionary from tuples of flags (mc, drained, offline)
418 31b836b8 Thomas Thrainer
      to the node role (as _ROLE_*)
419 31b836b8 Thomas Thrainer
  @cvar _R2F: a dictionary from node role to tuples of flags
420 31b836b8 Thomas Thrainer
  @cvar _FLAGS: a list of attribute names corresponding to the flags
421 31b836b8 Thomas Thrainer

422 31b836b8 Thomas Thrainer
  """
423 31b836b8 Thomas Thrainer
  HPATH = "node-modify"
424 31b836b8 Thomas Thrainer
  HTYPE = constants.HTYPE_NODE
425 31b836b8 Thomas Thrainer
  REQ_BGL = False
426 31b836b8 Thomas Thrainer
  (_ROLE_CANDIDATE, _ROLE_DRAINED, _ROLE_OFFLINE, _ROLE_REGULAR) = range(4)
427 31b836b8 Thomas Thrainer
  _F2R = {
428 31b836b8 Thomas Thrainer
    (True, False, False): _ROLE_CANDIDATE,
429 31b836b8 Thomas Thrainer
    (False, True, False): _ROLE_DRAINED,
430 31b836b8 Thomas Thrainer
    (False, False, True): _ROLE_OFFLINE,
431 31b836b8 Thomas Thrainer
    (False, False, False): _ROLE_REGULAR,
432 31b836b8 Thomas Thrainer
    }
433 31b836b8 Thomas Thrainer
  _R2F = dict((v, k) for k, v in _F2R.items())
434 31b836b8 Thomas Thrainer
  _FLAGS = ["master_candidate", "drained", "offline"]
435 31b836b8 Thomas Thrainer
436 31b836b8 Thomas Thrainer
  def CheckArguments(self):
437 1c3231aa Thomas Thrainer
    (self.op.node_uuid, self.op.node_name) = \
438 1c3231aa Thomas Thrainer
      ExpandNodeUuidAndName(self.cfg, self.op.node_uuid, self.op.node_name)
439 31b836b8 Thomas Thrainer
    all_mods = [self.op.offline, self.op.master_candidate, self.op.drained,
440 31b836b8 Thomas Thrainer
                self.op.master_capable, self.op.vm_capable,
441 31b836b8 Thomas Thrainer
                self.op.secondary_ip, self.op.ndparams, self.op.hv_state,
442 31b836b8 Thomas Thrainer
                self.op.disk_state]
443 31b836b8 Thomas Thrainer
    if all_mods.count(None) == len(all_mods):
444 31b836b8 Thomas Thrainer
      raise errors.OpPrereqError("Please pass at least one modification",
445 31b836b8 Thomas Thrainer
                                 errors.ECODE_INVAL)
446 31b836b8 Thomas Thrainer
    if all_mods.count(True) > 1:
447 31b836b8 Thomas Thrainer
      raise errors.OpPrereqError("Can't set the node into more than one"
448 31b836b8 Thomas Thrainer
                                 " state at the same time",
449 31b836b8 Thomas Thrainer
                                 errors.ECODE_INVAL)
450 31b836b8 Thomas Thrainer
451 31b836b8 Thomas Thrainer
    # Boolean value that tells us whether we might be demoting from MC
452 31b836b8 Thomas Thrainer
    self.might_demote = (self.op.master_candidate is False or
453 31b836b8 Thomas Thrainer
                         self.op.offline is True or
454 31b836b8 Thomas Thrainer
                         self.op.drained is True or
455 31b836b8 Thomas Thrainer
                         self.op.master_capable is False)
456 31b836b8 Thomas Thrainer
457 31b836b8 Thomas Thrainer
    if self.op.secondary_ip:
458 31b836b8 Thomas Thrainer
      if not netutils.IP4Address.IsValid(self.op.secondary_ip):
459 31b836b8 Thomas Thrainer
        raise errors.OpPrereqError("Secondary IP (%s) needs to be a valid IPv4"
460 31b836b8 Thomas Thrainer
                                   " address" % self.op.secondary_ip,
461 31b836b8 Thomas Thrainer
                                   errors.ECODE_INVAL)
462 31b836b8 Thomas Thrainer
463 31b836b8 Thomas Thrainer
    self.lock_all = self.op.auto_promote and self.might_demote
464 31b836b8 Thomas Thrainer
    self.lock_instances = self.op.secondary_ip is not None
465 31b836b8 Thomas Thrainer
466 31b836b8 Thomas Thrainer
  def _InstanceFilter(self, instance):
467 31b836b8 Thomas Thrainer
    """Filter for getting affected instances.
468 31b836b8 Thomas Thrainer

469 31b836b8 Thomas Thrainer
    """
470 31b836b8 Thomas Thrainer
    return (instance.disk_template in constants.DTS_INT_MIRROR and
471 1c3231aa Thomas Thrainer
            self.op.node_uuid in instance.all_nodes)
472 31b836b8 Thomas Thrainer
473 31b836b8 Thomas Thrainer
  def ExpandNames(self):
474 31b836b8 Thomas Thrainer
    if self.lock_all:
475 31b836b8 Thomas Thrainer
      self.needed_locks = {
476 31b836b8 Thomas Thrainer
        locking.LEVEL_NODE: locking.ALL_SET,
477 31b836b8 Thomas Thrainer
478 31b836b8 Thomas Thrainer
        # Block allocations when all nodes are locked
479 31b836b8 Thomas Thrainer
        locking.LEVEL_NODE_ALLOC: locking.ALL_SET,
480 31b836b8 Thomas Thrainer
        }
481 31b836b8 Thomas Thrainer
    else:
482 31b836b8 Thomas Thrainer
      self.needed_locks = {
483 1c3231aa Thomas Thrainer
        locking.LEVEL_NODE: self.op.node_uuid,
484 31b836b8 Thomas Thrainer
        }
485 31b836b8 Thomas Thrainer
486 31b836b8 Thomas Thrainer
    # Since modifying a node can have severe effects on currently running
487 31b836b8 Thomas Thrainer
    # operations the resource lock is at least acquired in shared mode
488 31b836b8 Thomas Thrainer
    self.needed_locks[locking.LEVEL_NODE_RES] = \
489 31b836b8 Thomas Thrainer
      self.needed_locks[locking.LEVEL_NODE]
490 31b836b8 Thomas Thrainer
491 31b836b8 Thomas Thrainer
    # Get all locks except nodes in shared mode; they are not used for anything
492 31b836b8 Thomas Thrainer
    # but read-only access
493 5eacbcae Thomas Thrainer
    self.share_locks = ShareAll()
494 31b836b8 Thomas Thrainer
    self.share_locks[locking.LEVEL_NODE] = 0
495 31b836b8 Thomas Thrainer
    self.share_locks[locking.LEVEL_NODE_RES] = 0
496 31b836b8 Thomas Thrainer
    self.share_locks[locking.LEVEL_NODE_ALLOC] = 0
497 31b836b8 Thomas Thrainer
498 31b836b8 Thomas Thrainer
    if self.lock_instances:
499 31b836b8 Thomas Thrainer
      self.needed_locks[locking.LEVEL_INSTANCE] = \
500 da4a52a3 Thomas Thrainer
        self.cfg.GetInstanceNames(
501 da4a52a3 Thomas Thrainer
          self.cfg.GetInstancesInfoByFilter(self._InstanceFilter).keys())
502 31b836b8 Thomas Thrainer
503 31b836b8 Thomas Thrainer
  def BuildHooksEnv(self):
504 31b836b8 Thomas Thrainer
    """Build hooks env.
505 31b836b8 Thomas Thrainer

506 31b836b8 Thomas Thrainer
    This runs on the master node.
507 31b836b8 Thomas Thrainer

508 31b836b8 Thomas Thrainer
    """
509 31b836b8 Thomas Thrainer
    return {
510 31b836b8 Thomas Thrainer
      "OP_TARGET": self.op.node_name,
511 31b836b8 Thomas Thrainer
      "MASTER_CANDIDATE": str(self.op.master_candidate),
512 31b836b8 Thomas Thrainer
      "OFFLINE": str(self.op.offline),
513 31b836b8 Thomas Thrainer
      "DRAINED": str(self.op.drained),
514 31b836b8 Thomas Thrainer
      "MASTER_CAPABLE": str(self.op.master_capable),
515 31b836b8 Thomas Thrainer
      "VM_CAPABLE": str(self.op.vm_capable),
516 31b836b8 Thomas Thrainer
      }
517 31b836b8 Thomas Thrainer
518 31b836b8 Thomas Thrainer
  def BuildHooksNodes(self):
519 31b836b8 Thomas Thrainer
    """Build hooks nodes.
520 31b836b8 Thomas Thrainer

521 31b836b8 Thomas Thrainer
    """
522 1c3231aa Thomas Thrainer
    nl = [self.cfg.GetMasterNode(), self.op.node_uuid]
523 31b836b8 Thomas Thrainer
    return (nl, nl)
524 31b836b8 Thomas Thrainer
525 31b836b8 Thomas Thrainer
  def CheckPrereq(self):
526 31b836b8 Thomas Thrainer
    """Check prerequisites.
527 31b836b8 Thomas Thrainer

528 31b836b8 Thomas Thrainer
    This only checks the instance list against the existing names.
529 31b836b8 Thomas Thrainer

530 31b836b8 Thomas Thrainer
    """
531 1c3231aa Thomas Thrainer
    node = self.cfg.GetNodeInfo(self.op.node_uuid)
532 31b836b8 Thomas Thrainer
    if self.lock_instances:
533 31b836b8 Thomas Thrainer
      affected_instances = \
534 31b836b8 Thomas Thrainer
        self.cfg.GetInstancesInfoByFilter(self._InstanceFilter)
535 31b836b8 Thomas Thrainer
536 31b836b8 Thomas Thrainer
      # Verify instance locks
537 da4a52a3 Thomas Thrainer
      owned_instance_names = self.owned_locks(locking.LEVEL_INSTANCE)
538 da4a52a3 Thomas Thrainer
      wanted_instance_names = frozenset([inst.name for inst in
539 da4a52a3 Thomas Thrainer
                                         affected_instances.values()])
540 da4a52a3 Thomas Thrainer
      if wanted_instance_names - owned_instance_names:
541 31b836b8 Thomas Thrainer
        raise errors.OpPrereqError("Instances affected by changing node %s's"
542 31b836b8 Thomas Thrainer
                                   " secondary IP address have changed since"
543 31b836b8 Thomas Thrainer
                                   " locks were acquired, wanted '%s', have"
544 31b836b8 Thomas Thrainer
                                   " '%s'; retry the operation" %
545 1c3231aa Thomas Thrainer
                                   (node.name,
546 da4a52a3 Thomas Thrainer
                                    utils.CommaJoin(wanted_instance_names),
547 da4a52a3 Thomas Thrainer
                                    utils.CommaJoin(owned_instance_names)),
548 31b836b8 Thomas Thrainer
                                   errors.ECODE_STATE)
549 31b836b8 Thomas Thrainer
    else:
550 31b836b8 Thomas Thrainer
      affected_instances = None
551 31b836b8 Thomas Thrainer
552 31b836b8 Thomas Thrainer
    if (self.op.master_candidate is not None or
553 31b836b8 Thomas Thrainer
        self.op.drained is not None or
554 31b836b8 Thomas Thrainer
        self.op.offline is not None):
555 31b836b8 Thomas Thrainer
      # we can't change the master's node flags
556 1c3231aa Thomas Thrainer
      if node.uuid == self.cfg.GetMasterNode():
557 31b836b8 Thomas Thrainer
        raise errors.OpPrereqError("The master role can be changed"
558 31b836b8 Thomas Thrainer
                                   " only via master-failover",
559 31b836b8 Thomas Thrainer
                                   errors.ECODE_INVAL)
560 31b836b8 Thomas Thrainer
561 31b836b8 Thomas Thrainer
    if self.op.master_candidate and not node.master_capable:
562 31b836b8 Thomas Thrainer
      raise errors.OpPrereqError("Node %s is not master capable, cannot make"
563 31b836b8 Thomas Thrainer
                                 " it a master candidate" % node.name,
564 31b836b8 Thomas Thrainer
                                 errors.ECODE_STATE)
565 31b836b8 Thomas Thrainer
566 31b836b8 Thomas Thrainer
    if self.op.vm_capable is False:
567 1c3231aa Thomas Thrainer
      (ipri, isec) = self.cfg.GetNodeInstances(node.uuid)
568 31b836b8 Thomas Thrainer
      if ipri or isec:
569 31b836b8 Thomas Thrainer
        raise errors.OpPrereqError("Node %s hosts instances, cannot unset"
570 31b836b8 Thomas Thrainer
                                   " the vm_capable flag" % node.name,
571 31b836b8 Thomas Thrainer
                                   errors.ECODE_STATE)
572 31b836b8 Thomas Thrainer
573 31b836b8 Thomas Thrainer
    if node.master_candidate and self.might_demote and not self.lock_all:
574 31b836b8 Thomas Thrainer
      assert not self.op.auto_promote, "auto_promote set but lock_all not"
575 31b836b8 Thomas Thrainer
      # check if after removing the current node, we're missing master
576 31b836b8 Thomas Thrainer
      # candidates
577 31b836b8 Thomas Thrainer
      (mc_remaining, mc_should, _) = \
578 1c3231aa Thomas Thrainer
          self.cfg.GetMasterCandidateStats(exceptions=[node.uuid])
579 31b836b8 Thomas Thrainer
      if mc_remaining < mc_should:
580 31b836b8 Thomas Thrainer
        raise errors.OpPrereqError("Not enough master candidates, please"
581 31b836b8 Thomas Thrainer
                                   " pass auto promote option to allow"
582 31b836b8 Thomas Thrainer
                                   " promotion (--auto-promote or RAPI"
583 31b836b8 Thomas Thrainer
                                   " auto_promote=True)", errors.ECODE_STATE)
584 31b836b8 Thomas Thrainer
585 31b836b8 Thomas Thrainer
    self.old_flags = old_flags = (node.master_candidate,
586 31b836b8 Thomas Thrainer
                                  node.drained, node.offline)
587 31b836b8 Thomas Thrainer
    assert old_flags in self._F2R, "Un-handled old flags %s" % str(old_flags)
588 31b836b8 Thomas Thrainer
    self.old_role = old_role = self._F2R[old_flags]
589 31b836b8 Thomas Thrainer
590 31b836b8 Thomas Thrainer
    # Check for ineffective changes
591 31b836b8 Thomas Thrainer
    for attr in self._FLAGS:
592 1c3231aa Thomas Thrainer
      if getattr(self.op, attr) is False and getattr(node, attr) is False:
593 31b836b8 Thomas Thrainer
        self.LogInfo("Ignoring request to unset flag %s, already unset", attr)
594 31b836b8 Thomas Thrainer
        setattr(self.op, attr, None)
595 31b836b8 Thomas Thrainer
596 31b836b8 Thomas Thrainer
    # Past this point, any flag change to False means a transition
597 31b836b8 Thomas Thrainer
    # away from the respective state, as only real changes are kept
598 31b836b8 Thomas Thrainer
599 31b836b8 Thomas Thrainer
    # TODO: We might query the real power state if it supports OOB
600 5eacbcae Thomas Thrainer
    if SupportsOob(self.cfg, node):
601 31b836b8 Thomas Thrainer
      if self.op.offline is False and not (node.powered or
602 31b836b8 Thomas Thrainer
                                           self.op.powered is True):
603 31b836b8 Thomas Thrainer
        raise errors.OpPrereqError(("Node %s needs to be turned on before its"
604 31b836b8 Thomas Thrainer
                                    " offline status can be reset") %
605 31b836b8 Thomas Thrainer
                                   self.op.node_name, errors.ECODE_STATE)
606 31b836b8 Thomas Thrainer
    elif self.op.powered is not None:
607 31b836b8 Thomas Thrainer
      raise errors.OpPrereqError(("Unable to change powered state for node %s"
608 31b836b8 Thomas Thrainer
                                  " as it does not support out-of-band"
609 31b836b8 Thomas Thrainer
                                  " handling") % self.op.node_name,
610 31b836b8 Thomas Thrainer
                                 errors.ECODE_STATE)
611 31b836b8 Thomas Thrainer
612 31b836b8 Thomas Thrainer
    # If we're being deofflined/drained, we'll MC ourself if needed
613 31b836b8 Thomas Thrainer
    if (self.op.drained is False or self.op.offline is False or
614 31b836b8 Thomas Thrainer
        (self.op.master_capable and not node.master_capable)):
615 31b836b8 Thomas Thrainer
      if _DecideSelfPromotion(self):
616 31b836b8 Thomas Thrainer
        self.op.master_candidate = True
617 31b836b8 Thomas Thrainer
        self.LogInfo("Auto-promoting node to master candidate")
618 31b836b8 Thomas Thrainer
619 31b836b8 Thomas Thrainer
    # If we're no longer master capable, we'll demote ourselves from MC
620 31b836b8 Thomas Thrainer
    if self.op.master_capable is False and node.master_candidate:
621 31b836b8 Thomas Thrainer
      self.LogInfo("Demoting from master candidate")
622 31b836b8 Thomas Thrainer
      self.op.master_candidate = False
623 31b836b8 Thomas Thrainer
624 31b836b8 Thomas Thrainer
    # Compute new role
625 31b836b8 Thomas Thrainer
    assert [getattr(self.op, attr) for attr in self._FLAGS].count(True) <= 1
626 31b836b8 Thomas Thrainer
    if self.op.master_candidate:
627 31b836b8 Thomas Thrainer
      new_role = self._ROLE_CANDIDATE
628 31b836b8 Thomas Thrainer
    elif self.op.drained:
629 31b836b8 Thomas Thrainer
      new_role = self._ROLE_DRAINED
630 31b836b8 Thomas Thrainer
    elif self.op.offline:
631 31b836b8 Thomas Thrainer
      new_role = self._ROLE_OFFLINE
632 31b836b8 Thomas Thrainer
    elif False in [self.op.master_candidate, self.op.drained, self.op.offline]:
633 31b836b8 Thomas Thrainer
      # False is still in new flags, which means we're un-setting (the
634 31b836b8 Thomas Thrainer
      # only) True flag
635 31b836b8 Thomas Thrainer
      new_role = self._ROLE_REGULAR
636 31b836b8 Thomas Thrainer
    else: # no new flags, nothing, keep old role
637 31b836b8 Thomas Thrainer
      new_role = old_role
638 31b836b8 Thomas Thrainer
639 31b836b8 Thomas Thrainer
    self.new_role = new_role
640 31b836b8 Thomas Thrainer
641 31b836b8 Thomas Thrainer
    if old_role == self._ROLE_OFFLINE and new_role != old_role:
642 31b836b8 Thomas Thrainer
      # Trying to transition out of offline status
643 1c3231aa Thomas Thrainer
      result = self.rpc.call_version([node.uuid])[node.uuid]
644 31b836b8 Thomas Thrainer
      if result.fail_msg:
645 31b836b8 Thomas Thrainer
        raise errors.OpPrereqError("Node %s is being de-offlined but fails"
646 31b836b8 Thomas Thrainer
                                   " to report its version: %s" %
647 31b836b8 Thomas Thrainer
                                   (node.name, result.fail_msg),
648 31b836b8 Thomas Thrainer
                                   errors.ECODE_STATE)
649 31b836b8 Thomas Thrainer
      else:
650 31b836b8 Thomas Thrainer
        self.LogWarning("Transitioning node from offline to online state"
651 31b836b8 Thomas Thrainer
                        " without using re-add. Please make sure the node"
652 31b836b8 Thomas Thrainer
                        " is healthy!")
653 31b836b8 Thomas Thrainer
654 31b836b8 Thomas Thrainer
    # When changing the secondary ip, verify if this is a single-homed to
655 31b836b8 Thomas Thrainer
    # multi-homed transition or vice versa, and apply the relevant
656 31b836b8 Thomas Thrainer
    # restrictions.
657 31b836b8 Thomas Thrainer
    if self.op.secondary_ip:
658 31b836b8 Thomas Thrainer
      # Ok even without locking, because this can't be changed by any LU
659 6bb43023 Thomas Thrainer
      master = self.cfg.GetMasterNodeInfo()
660 31b836b8 Thomas Thrainer
      master_singlehomed = master.secondary_ip == master.primary_ip
661 31b836b8 Thomas Thrainer
      if master_singlehomed and self.op.secondary_ip != node.primary_ip:
662 1c3231aa Thomas Thrainer
        if self.op.force and node.uuid == master.uuid:
663 31b836b8 Thomas Thrainer
          self.LogWarning("Transitioning from single-homed to multi-homed"
664 31b836b8 Thomas Thrainer
                          " cluster; all nodes will require a secondary IP"
665 31b836b8 Thomas Thrainer
                          " address")
666 31b836b8 Thomas Thrainer
        else:
667 31b836b8 Thomas Thrainer
          raise errors.OpPrereqError("Changing the secondary ip on a"
668 31b836b8 Thomas Thrainer
                                     " single-homed cluster requires the"
669 31b836b8 Thomas Thrainer
                                     " --force option to be passed, and the"
670 31b836b8 Thomas Thrainer
                                     " target node to be the master",
671 31b836b8 Thomas Thrainer
                                     errors.ECODE_INVAL)
672 31b836b8 Thomas Thrainer
      elif not master_singlehomed and self.op.secondary_ip == node.primary_ip:
673 1c3231aa Thomas Thrainer
        if self.op.force and node.uuid == master.uuid:
674 31b836b8 Thomas Thrainer
          self.LogWarning("Transitioning from multi-homed to single-homed"
675 31b836b8 Thomas Thrainer
                          " cluster; secondary IP addresses will have to be"
676 31b836b8 Thomas Thrainer
                          " removed")
677 31b836b8 Thomas Thrainer
        else:
678 31b836b8 Thomas Thrainer
          raise errors.OpPrereqError("Cannot set the secondary IP to be the"
679 31b836b8 Thomas Thrainer
                                     " same as the primary IP on a multi-homed"
680 31b836b8 Thomas Thrainer
                                     " cluster, unless the --force option is"
681 31b836b8 Thomas Thrainer
                                     " passed, and the target node is the"
682 31b836b8 Thomas Thrainer
                                     " master", errors.ECODE_INVAL)
683 31b836b8 Thomas Thrainer
684 da4a52a3 Thomas Thrainer
      assert not (set([inst.name for inst in affected_instances.values()]) -
685 31b836b8 Thomas Thrainer
                  self.owned_locks(locking.LEVEL_INSTANCE))
686 31b836b8 Thomas Thrainer
687 31b836b8 Thomas Thrainer
      if node.offline:
688 31b836b8 Thomas Thrainer
        if affected_instances:
689 31b836b8 Thomas Thrainer
          msg = ("Cannot change secondary IP address: offline node has"
690 31b836b8 Thomas Thrainer
                 " instances (%s) configured to use it" %
691 da4a52a3 Thomas Thrainer
                 utils.CommaJoin(
692 da4a52a3 Thomas Thrainer
                   [inst.name for inst in affected_instances.values()]))
693 31b836b8 Thomas Thrainer
          raise errors.OpPrereqError(msg, errors.ECODE_STATE)
694 31b836b8 Thomas Thrainer
      else:
695 31b836b8 Thomas Thrainer
        # On online nodes, check that no instances are running, and that
696 31b836b8 Thomas Thrainer
        # the node has the new ip and we can reach it.
697 31b836b8 Thomas Thrainer
        for instance in affected_instances.values():
698 5eacbcae Thomas Thrainer
          CheckInstanceState(self, instance, INSTANCE_DOWN,
699 5eacbcae Thomas Thrainer
                             msg="cannot change secondary ip")
700 31b836b8 Thomas Thrainer
701 1c3231aa Thomas Thrainer
        _CheckNodeHasSecondaryIP(self, node, self.op.secondary_ip, True)
702 1c3231aa Thomas Thrainer
        if master.uuid != node.uuid:
703 31b836b8 Thomas Thrainer
          # check reachability from master secondary ip to new secondary ip
704 31b836b8 Thomas Thrainer
          if not netutils.TcpPing(self.op.secondary_ip,
705 31b836b8 Thomas Thrainer
                                  constants.DEFAULT_NODED_PORT,
706 31b836b8 Thomas Thrainer
                                  source=master.secondary_ip):
707 31b836b8 Thomas Thrainer
            raise errors.OpPrereqError("Node secondary ip not reachable by TCP"
708 31b836b8 Thomas Thrainer
                                       " based ping to node daemon port",
709 31b836b8 Thomas Thrainer
                                       errors.ECODE_ENVIRON)
710 31b836b8 Thomas Thrainer
711 31b836b8 Thomas Thrainer
    if self.op.ndparams:
712 1c3231aa Thomas Thrainer
      new_ndparams = GetUpdatedParams(node.ndparams, self.op.ndparams)
713 31b836b8 Thomas Thrainer
      utils.ForceDictType(new_ndparams, constants.NDS_PARAMETER_TYPES)
714 5eacbcae Thomas Thrainer
      CheckParamsNotGlobal(self.op.ndparams, constants.NDC_GLOBALS, "node",
715 5eacbcae Thomas Thrainer
                           "node", "cluster or group")
716 31b836b8 Thomas Thrainer
      self.new_ndparams = new_ndparams
717 31b836b8 Thomas Thrainer
718 31b836b8 Thomas Thrainer
    if self.op.hv_state:
719 5eacbcae Thomas Thrainer
      self.new_hv_state = MergeAndVerifyHvState(self.op.hv_state,
720 1c3231aa Thomas Thrainer
                                                node.hv_state_static)
721 31b836b8 Thomas Thrainer
722 31b836b8 Thomas Thrainer
    if self.op.disk_state:
723 31b836b8 Thomas Thrainer
      self.new_disk_state = \
724 1c3231aa Thomas Thrainer
        MergeAndVerifyDiskState(self.op.disk_state, node.disk_state_static)
725 31b836b8 Thomas Thrainer
726 31b836b8 Thomas Thrainer
  def Exec(self, feedback_fn):
727 31b836b8 Thomas Thrainer
    """Modifies a node.
728 31b836b8 Thomas Thrainer

729 31b836b8 Thomas Thrainer
    """
730 1c3231aa Thomas Thrainer
    node = self.cfg.GetNodeInfo(self.op.node_uuid)
731 31b836b8 Thomas Thrainer
    result = []
732 31b836b8 Thomas Thrainer
733 31b836b8 Thomas Thrainer
    if self.op.ndparams:
734 31b836b8 Thomas Thrainer
      node.ndparams = self.new_ndparams
735 31b836b8 Thomas Thrainer
736 31b836b8 Thomas Thrainer
    if self.op.powered is not None:
737 31b836b8 Thomas Thrainer
      node.powered = self.op.powered
738 31b836b8 Thomas Thrainer
739 31b836b8 Thomas Thrainer
    if self.op.hv_state:
740 31b836b8 Thomas Thrainer
      node.hv_state_static = self.new_hv_state
741 31b836b8 Thomas Thrainer
742 31b836b8 Thomas Thrainer
    if self.op.disk_state:
743 31b836b8 Thomas Thrainer
      node.disk_state_static = self.new_disk_state
744 31b836b8 Thomas Thrainer
745 31b836b8 Thomas Thrainer
    for attr in ["master_capable", "vm_capable"]:
746 31b836b8 Thomas Thrainer
      val = getattr(self.op, attr)
747 31b836b8 Thomas Thrainer
      if val is not None:
748 31b836b8 Thomas Thrainer
        setattr(node, attr, val)
749 31b836b8 Thomas Thrainer
        result.append((attr, str(val)))
750 31b836b8 Thomas Thrainer
751 d0d7d7cf Thomas Thrainer
    if self.new_role != self.old_role:
752 31b836b8 Thomas Thrainer
      # Tell the node to demote itself, if no longer MC and not offline
753 d0d7d7cf Thomas Thrainer
      if self.old_role == self._ROLE_CANDIDATE and \
754 d0d7d7cf Thomas Thrainer
          self.new_role != self._ROLE_OFFLINE:
755 31b836b8 Thomas Thrainer
        msg = self.rpc.call_node_demote_from_mc(node.name).fail_msg
756 31b836b8 Thomas Thrainer
        if msg:
757 31b836b8 Thomas Thrainer
          self.LogWarning("Node failed to demote itself: %s", msg)
758 31b836b8 Thomas Thrainer
759 d0d7d7cf Thomas Thrainer
      new_flags = self._R2F[self.new_role]
760 31b836b8 Thomas Thrainer
      for of, nf, desc in zip(self.old_flags, new_flags, self._FLAGS):
761 31b836b8 Thomas Thrainer
        if of != nf:
762 31b836b8 Thomas Thrainer
          result.append((desc, str(nf)))
763 31b836b8 Thomas Thrainer
      (node.master_candidate, node.drained, node.offline) = new_flags
764 31b836b8 Thomas Thrainer
765 31b836b8 Thomas Thrainer
      # we locked all nodes, we adjust the CP before updating this node
766 31b836b8 Thomas Thrainer
      if self.lock_all:
767 1c3231aa Thomas Thrainer
        AdjustCandidatePool(self, [node.uuid])
768 31b836b8 Thomas Thrainer
769 31b836b8 Thomas Thrainer
    if self.op.secondary_ip:
770 31b836b8 Thomas Thrainer
      node.secondary_ip = self.op.secondary_ip
771 31b836b8 Thomas Thrainer
      result.append(("secondary_ip", self.op.secondary_ip))
772 31b836b8 Thomas Thrainer
773 31b836b8 Thomas Thrainer
    # this will trigger configuration file update, if needed
774 31b836b8 Thomas Thrainer
    self.cfg.Update(node, feedback_fn)
775 31b836b8 Thomas Thrainer
776 31b836b8 Thomas Thrainer
    # this will trigger job queue propagation or cleanup if the mc
777 31b836b8 Thomas Thrainer
    # flag changed
778 d0d7d7cf Thomas Thrainer
    if [self.old_role, self.new_role].count(self._ROLE_CANDIDATE) == 1:
779 31b836b8 Thomas Thrainer
      self.context.ReaddNode(node)
780 31b836b8 Thomas Thrainer
781 31b836b8 Thomas Thrainer
    return result
782 31b836b8 Thomas Thrainer
783 31b836b8 Thomas Thrainer
784 31b836b8 Thomas Thrainer
class LUNodePowercycle(NoHooksLU):
785 31b836b8 Thomas Thrainer
  """Powercycles a node.
786 31b836b8 Thomas Thrainer

787 31b836b8 Thomas Thrainer
  """
788 31b836b8 Thomas Thrainer
  REQ_BGL = False
789 31b836b8 Thomas Thrainer
790 31b836b8 Thomas Thrainer
  def CheckArguments(self):
791 1c3231aa Thomas Thrainer
    (self.op.node_uuid, self.op.node_name) = \
792 1c3231aa Thomas Thrainer
      ExpandNodeUuidAndName(self.cfg, self.op.node_uuid, self.op.node_name)
793 1c3231aa Thomas Thrainer
794 1c3231aa Thomas Thrainer
    if self.op.node_uuid == self.cfg.GetMasterNode() and not self.op.force:
795 31b836b8 Thomas Thrainer
      raise errors.OpPrereqError("The node is the master and the force"
796 31b836b8 Thomas Thrainer
                                 " parameter was not set",
797 31b836b8 Thomas Thrainer
                                 errors.ECODE_INVAL)
798 31b836b8 Thomas Thrainer
799 31b836b8 Thomas Thrainer
  def ExpandNames(self):
800 31b836b8 Thomas Thrainer
    """Locking for PowercycleNode.
801 31b836b8 Thomas Thrainer

802 31b836b8 Thomas Thrainer
    This is a last-resort option and shouldn't block on other
803 31b836b8 Thomas Thrainer
    jobs. Therefore, we grab no locks.
804 31b836b8 Thomas Thrainer

805 31b836b8 Thomas Thrainer
    """
806 31b836b8 Thomas Thrainer
    self.needed_locks = {}
807 31b836b8 Thomas Thrainer
808 31b836b8 Thomas Thrainer
  def Exec(self, feedback_fn):
809 31b836b8 Thomas Thrainer
    """Reboots a node.
810 31b836b8 Thomas Thrainer

811 31b836b8 Thomas Thrainer
    """
812 8ef418bb Helga Velroyen
    default_hypervisor = self.cfg.GetHypervisorType()
813 8ef418bb Helga Velroyen
    hvparams = self.cfg.GetClusterInfo().hvparams[default_hypervisor]
814 1c3231aa Thomas Thrainer
    result = self.rpc.call_node_powercycle(self.op.node_uuid,
815 8ef418bb Helga Velroyen
                                           default_hypervisor,
816 8ef418bb Helga Velroyen
                                           hvparams)
817 31b836b8 Thomas Thrainer
    result.Raise("Failed to schedule the reboot")
818 31b836b8 Thomas Thrainer
    return result.payload
819 31b836b8 Thomas Thrainer
820 31b836b8 Thomas Thrainer
821 31b836b8 Thomas Thrainer
def _GetNodeInstancesInner(cfg, fn):
822 31b836b8 Thomas Thrainer
  return [i for i in cfg.GetAllInstancesInfo().values() if fn(i)]
823 31b836b8 Thomas Thrainer
824 31b836b8 Thomas Thrainer
825 1c3231aa Thomas Thrainer
def _GetNodePrimaryInstances(cfg, node_uuid):
826 31b836b8 Thomas Thrainer
  """Returns primary instances on a node.
827 31b836b8 Thomas Thrainer

828 31b836b8 Thomas Thrainer
  """
829 31b836b8 Thomas Thrainer
  return _GetNodeInstancesInner(cfg,
830 1c3231aa Thomas Thrainer
                                lambda inst: node_uuid == inst.primary_node)
831 31b836b8 Thomas Thrainer
832 31b836b8 Thomas Thrainer
833 1c3231aa Thomas Thrainer
def _GetNodeSecondaryInstances(cfg, node_uuid):
834 31b836b8 Thomas Thrainer
  """Returns secondary instances on a node.
835 31b836b8 Thomas Thrainer

836 31b836b8 Thomas Thrainer
  """
837 31b836b8 Thomas Thrainer
  return _GetNodeInstancesInner(cfg,
838 1c3231aa Thomas Thrainer
                                lambda inst: node_uuid in inst.secondary_nodes)
839 31b836b8 Thomas Thrainer
840 31b836b8 Thomas Thrainer
841 1c3231aa Thomas Thrainer
def _GetNodeInstances(cfg, node_uuid):
842 31b836b8 Thomas Thrainer
  """Returns a list of all primary and secondary instances on a node.
843 31b836b8 Thomas Thrainer

844 31b836b8 Thomas Thrainer
  """
845 31b836b8 Thomas Thrainer
846 1c3231aa Thomas Thrainer
  return _GetNodeInstancesInner(cfg, lambda inst: node_uuid in inst.all_nodes)
847 31b836b8 Thomas Thrainer
848 31b836b8 Thomas Thrainer
849 31b836b8 Thomas Thrainer
class LUNodeEvacuate(NoHooksLU):
850 31b836b8 Thomas Thrainer
  """Evacuates instances off a list of nodes.
851 31b836b8 Thomas Thrainer

852 31b836b8 Thomas Thrainer
  """
853 31b836b8 Thomas Thrainer
  REQ_BGL = False
854 31b836b8 Thomas Thrainer
855 31b836b8 Thomas Thrainer
  def CheckArguments(self):
856 5eacbcae Thomas Thrainer
    CheckIAllocatorOrNode(self, "iallocator", "remote_node")
857 31b836b8 Thomas Thrainer
858 31b836b8 Thomas Thrainer
  def ExpandNames(self):
859 1c3231aa Thomas Thrainer
    (self.op.node_uuid, self.op.node_name) = \
860 1c3231aa Thomas Thrainer
      ExpandNodeUuidAndName(self.cfg, self.op.node_uuid, self.op.node_name)
861 31b836b8 Thomas Thrainer
862 31b836b8 Thomas Thrainer
    if self.op.remote_node is not None:
863 1c3231aa Thomas Thrainer
      (self.op.remote_node_uuid, self.op.remote_node) = \
864 1c3231aa Thomas Thrainer
        ExpandNodeUuidAndName(self.cfg, self.op.remote_node_uuid,
865 1c3231aa Thomas Thrainer
                              self.op.remote_node)
866 31b836b8 Thomas Thrainer
      assert self.op.remote_node
867 31b836b8 Thomas Thrainer
868 1c3231aa Thomas Thrainer
      if self.op.node_uuid == self.op.remote_node_uuid:
869 31b836b8 Thomas Thrainer
        raise errors.OpPrereqError("Can not use evacuated node as a new"
870 31b836b8 Thomas Thrainer
                                   " secondary node", errors.ECODE_INVAL)
871 31b836b8 Thomas Thrainer
872 31b836b8 Thomas Thrainer
      if self.op.mode != constants.NODE_EVAC_SEC:
873 31b836b8 Thomas Thrainer
        raise errors.OpPrereqError("Without the use of an iallocator only"
874 31b836b8 Thomas Thrainer
                                   " secondary instances can be evacuated",
875 31b836b8 Thomas Thrainer
                                   errors.ECODE_INVAL)
876 31b836b8 Thomas Thrainer
877 31b836b8 Thomas Thrainer
    # Declare locks
878 5eacbcae Thomas Thrainer
    self.share_locks = ShareAll()
879 31b836b8 Thomas Thrainer
    self.needed_locks = {
880 31b836b8 Thomas Thrainer
      locking.LEVEL_INSTANCE: [],
881 31b836b8 Thomas Thrainer
      locking.LEVEL_NODEGROUP: [],
882 31b836b8 Thomas Thrainer
      locking.LEVEL_NODE: [],
883 31b836b8 Thomas Thrainer
      }
884 31b836b8 Thomas Thrainer
885 31b836b8 Thomas Thrainer
    # Determine nodes (via group) optimistically, needs verification once locks
886 31b836b8 Thomas Thrainer
    # have been acquired
887 31b836b8 Thomas Thrainer
    self.lock_nodes = self._DetermineNodes()
888 31b836b8 Thomas Thrainer
889 31b836b8 Thomas Thrainer
  def _DetermineNodes(self):
890 1c3231aa Thomas Thrainer
    """Gets the list of node UUIDs to operate on.
891 31b836b8 Thomas Thrainer

892 31b836b8 Thomas Thrainer
    """
893 31b836b8 Thomas Thrainer
    if self.op.remote_node is None:
894 31b836b8 Thomas Thrainer
      # Iallocator will choose any node(s) in the same group
895 1c3231aa Thomas Thrainer
      group_nodes = self.cfg.GetNodeGroupMembersByNodes([self.op.node_uuid])
896 31b836b8 Thomas Thrainer
    else:
897 1c3231aa Thomas Thrainer
      group_nodes = frozenset([self.op.remote_node_uuid])
898 31b836b8 Thomas Thrainer
899 31b836b8 Thomas Thrainer
    # Determine nodes to be locked
900 1c3231aa Thomas Thrainer
    return set([self.op.node_uuid]) | group_nodes
901 31b836b8 Thomas Thrainer
902 31b836b8 Thomas Thrainer
  def _DetermineInstances(self):
903 31b836b8 Thomas Thrainer
    """Builds list of instances to operate on.
904 31b836b8 Thomas Thrainer

905 31b836b8 Thomas Thrainer
    """
906 31b836b8 Thomas Thrainer
    assert self.op.mode in constants.NODE_EVAC_MODES
907 31b836b8 Thomas Thrainer
908 31b836b8 Thomas Thrainer
    if self.op.mode == constants.NODE_EVAC_PRI:
909 31b836b8 Thomas Thrainer
      # Primary instances only
910 31b836b8 Thomas Thrainer
      inst_fn = _GetNodePrimaryInstances
911 31b836b8 Thomas Thrainer
      assert self.op.remote_node is None, \
912 31b836b8 Thomas Thrainer
        "Evacuating primary instances requires iallocator"
913 31b836b8 Thomas Thrainer
    elif self.op.mode == constants.NODE_EVAC_SEC:
914 31b836b8 Thomas Thrainer
      # Secondary instances only
915 31b836b8 Thomas Thrainer
      inst_fn = _GetNodeSecondaryInstances
916 31b836b8 Thomas Thrainer
    else:
917 31b836b8 Thomas Thrainer
      # All instances
918 31b836b8 Thomas Thrainer
      assert self.op.mode == constants.NODE_EVAC_ALL
919 31b836b8 Thomas Thrainer
      inst_fn = _GetNodeInstances
920 31b836b8 Thomas Thrainer
      # TODO: In 2.6, change the iallocator interface to take an evacuation mode
921 31b836b8 Thomas Thrainer
      # per instance
922 31b836b8 Thomas Thrainer
      raise errors.OpPrereqError("Due to an issue with the iallocator"
923 31b836b8 Thomas Thrainer
                                 " interface it is not possible to evacuate"
924 31b836b8 Thomas Thrainer
                                 " all instances at once; specify explicitly"
925 31b836b8 Thomas Thrainer
                                 " whether to evacuate primary or secondary"
926 31b836b8 Thomas Thrainer
                                 " instances",
927 31b836b8 Thomas Thrainer
                                 errors.ECODE_INVAL)
928 31b836b8 Thomas Thrainer
929 1c3231aa Thomas Thrainer
    return inst_fn(self.cfg, self.op.node_uuid)
930 31b836b8 Thomas Thrainer
931 31b836b8 Thomas Thrainer
  def DeclareLocks(self, level):
932 31b836b8 Thomas Thrainer
    if level == locking.LEVEL_INSTANCE:
933 31b836b8 Thomas Thrainer
      # Lock instances optimistically, needs verification once node and group
934 31b836b8 Thomas Thrainer
      # locks have been acquired
935 31b836b8 Thomas Thrainer
      self.needed_locks[locking.LEVEL_INSTANCE] = \
936 31b836b8 Thomas Thrainer
        set(i.name for i in self._DetermineInstances())
937 31b836b8 Thomas Thrainer
938 31b836b8 Thomas Thrainer
    elif level == locking.LEVEL_NODEGROUP:
939 31b836b8 Thomas Thrainer
      # Lock node groups for all potential target nodes optimistically, needs
940 31b836b8 Thomas Thrainer
      # verification once nodes have been acquired
941 31b836b8 Thomas Thrainer
      self.needed_locks[locking.LEVEL_NODEGROUP] = \
942 31b836b8 Thomas Thrainer
        self.cfg.GetNodeGroupsFromNodes(self.lock_nodes)
943 31b836b8 Thomas Thrainer
944 31b836b8 Thomas Thrainer
    elif level == locking.LEVEL_NODE:
945 31b836b8 Thomas Thrainer
      self.needed_locks[locking.LEVEL_NODE] = self.lock_nodes
946 31b836b8 Thomas Thrainer
947 31b836b8 Thomas Thrainer
  def CheckPrereq(self):
948 31b836b8 Thomas Thrainer
    # Verify locks
949 da4a52a3 Thomas Thrainer
    owned_instance_names = self.owned_locks(locking.LEVEL_INSTANCE)
950 31b836b8 Thomas Thrainer
    owned_nodes = self.owned_locks(locking.LEVEL_NODE)
951 31b836b8 Thomas Thrainer
    owned_groups = self.owned_locks(locking.LEVEL_NODEGROUP)
952 31b836b8 Thomas Thrainer
953 31b836b8 Thomas Thrainer
    need_nodes = self._DetermineNodes()
954 31b836b8 Thomas Thrainer
955 31b836b8 Thomas Thrainer
    if not owned_nodes.issuperset(need_nodes):
956 31b836b8 Thomas Thrainer
      raise errors.OpPrereqError("Nodes in same group as '%s' changed since"
957 31b836b8 Thomas Thrainer
                                 " locks were acquired, current nodes are"
958 31b836b8 Thomas Thrainer
                                 " are '%s', used to be '%s'; retry the"
959 31b836b8 Thomas Thrainer
                                 " operation" %
960 31b836b8 Thomas Thrainer
                                 (self.op.node_name,
961 31b836b8 Thomas Thrainer
                                  utils.CommaJoin(need_nodes),
962 31b836b8 Thomas Thrainer
                                  utils.CommaJoin(owned_nodes)),
963 31b836b8 Thomas Thrainer
                                 errors.ECODE_STATE)
964 31b836b8 Thomas Thrainer
965 31b836b8 Thomas Thrainer
    wanted_groups = self.cfg.GetNodeGroupsFromNodes(owned_nodes)
966 31b836b8 Thomas Thrainer
    if owned_groups != wanted_groups:
967 31b836b8 Thomas Thrainer
      raise errors.OpExecError("Node groups changed since locks were acquired,"
968 31b836b8 Thomas Thrainer
                               " current groups are '%s', used to be '%s';"
969 31b836b8 Thomas Thrainer
                               " retry the operation" %
970 31b836b8 Thomas Thrainer
                               (utils.CommaJoin(wanted_groups),
971 31b836b8 Thomas Thrainer
                                utils.CommaJoin(owned_groups)))
972 31b836b8 Thomas Thrainer
973 31b836b8 Thomas Thrainer
    # Determine affected instances
974 31b836b8 Thomas Thrainer
    self.instances = self._DetermineInstances()
975 31b836b8 Thomas Thrainer
    self.instance_names = [i.name for i in self.instances]
976 31b836b8 Thomas Thrainer
977 da4a52a3 Thomas Thrainer
    if set(self.instance_names) != owned_instance_names:
978 31b836b8 Thomas Thrainer
      raise errors.OpExecError("Instances on node '%s' changed since locks"
979 31b836b8 Thomas Thrainer
                               " were acquired, current instances are '%s',"
980 31b836b8 Thomas Thrainer
                               " used to be '%s'; retry the operation" %
981 31b836b8 Thomas Thrainer
                               (self.op.node_name,
982 31b836b8 Thomas Thrainer
                                utils.CommaJoin(self.instance_names),
983 da4a52a3 Thomas Thrainer
                                utils.CommaJoin(owned_instance_names)))
984 31b836b8 Thomas Thrainer
985 31b836b8 Thomas Thrainer
    if self.instance_names:
986 31b836b8 Thomas Thrainer
      self.LogInfo("Evacuating instances from node '%s': %s",
987 31b836b8 Thomas Thrainer
                   self.op.node_name,
988 31b836b8 Thomas Thrainer
                   utils.CommaJoin(utils.NiceSort(self.instance_names)))
989 31b836b8 Thomas Thrainer
    else:
990 31b836b8 Thomas Thrainer
      self.LogInfo("No instances to evacuate from node '%s'",
991 31b836b8 Thomas Thrainer
                   self.op.node_name)
992 31b836b8 Thomas Thrainer
993 31b836b8 Thomas Thrainer
    if self.op.remote_node is not None:
994 31b836b8 Thomas Thrainer
      for i in self.instances:
995 1c3231aa Thomas Thrainer
        if i.primary_node == self.op.remote_node_uuid:
996 31b836b8 Thomas Thrainer
          raise errors.OpPrereqError("Node %s is the primary node of"
997 31b836b8 Thomas Thrainer
                                     " instance %s, cannot use it as"
998 31b836b8 Thomas Thrainer
                                     " secondary" %
999 31b836b8 Thomas Thrainer
                                     (self.op.remote_node, i.name),
1000 31b836b8 Thomas Thrainer
                                     errors.ECODE_INVAL)
1001 31b836b8 Thomas Thrainer
1002 31b836b8 Thomas Thrainer
  def Exec(self, feedback_fn):
1003 31b836b8 Thomas Thrainer
    assert (self.op.iallocator is not None) ^ (self.op.remote_node is not None)
1004 31b836b8 Thomas Thrainer
1005 31b836b8 Thomas Thrainer
    if not self.instance_names:
1006 31b836b8 Thomas Thrainer
      # No instances to evacuate
1007 31b836b8 Thomas Thrainer
      jobs = []
1008 31b836b8 Thomas Thrainer
1009 31b836b8 Thomas Thrainer
    elif self.op.iallocator is not None:
1010 31b836b8 Thomas Thrainer
      # TODO: Implement relocation to other group
1011 d4d424fb Jose A. Lopes
      req = iallocator.IAReqNodeEvac(evac_mode=self.op.mode,
1012 31b836b8 Thomas Thrainer
                                     instances=list(self.instance_names))
1013 31b836b8 Thomas Thrainer
      ial = iallocator.IAllocator(self.cfg, self.rpc, req)
1014 31b836b8 Thomas Thrainer
1015 31b836b8 Thomas Thrainer
      ial.Run(self.op.iallocator)
1016 31b836b8 Thomas Thrainer
1017 31b836b8 Thomas Thrainer
      if not ial.success:
1018 31b836b8 Thomas Thrainer
        raise errors.OpPrereqError("Can't compute node evacuation using"
1019 31b836b8 Thomas Thrainer
                                   " iallocator '%s': %s" %
1020 31b836b8 Thomas Thrainer
                                   (self.op.iallocator, ial.info),
1021 31b836b8 Thomas Thrainer
                                   errors.ECODE_NORES)
1022 31b836b8 Thomas Thrainer
1023 5eacbcae Thomas Thrainer
      jobs = LoadNodeEvacResult(self, ial.result, self.op.early_release, True)
1024 31b836b8 Thomas Thrainer
1025 31b836b8 Thomas Thrainer
    elif self.op.remote_node is not None:
1026 31b836b8 Thomas Thrainer
      assert self.op.mode == constants.NODE_EVAC_SEC
1027 31b836b8 Thomas Thrainer
      jobs = [
1028 31b836b8 Thomas Thrainer
        [opcodes.OpInstanceReplaceDisks(instance_name=instance_name,
1029 31b836b8 Thomas Thrainer
                                        remote_node=self.op.remote_node,
1030 31b836b8 Thomas Thrainer
                                        disks=[],
1031 31b836b8 Thomas Thrainer
                                        mode=constants.REPLACE_DISK_CHG,
1032 31b836b8 Thomas Thrainer
                                        early_release=self.op.early_release)]
1033 31b836b8 Thomas Thrainer
        for instance_name in self.instance_names]
1034 31b836b8 Thomas Thrainer
1035 31b836b8 Thomas Thrainer
    else:
1036 31b836b8 Thomas Thrainer
      raise errors.ProgrammerError("No iallocator or remote node")
1037 31b836b8 Thomas Thrainer
1038 31b836b8 Thomas Thrainer
    return ResultWithJobs(jobs)
1039 31b836b8 Thomas Thrainer
1040 31b836b8 Thomas Thrainer
1041 31b836b8 Thomas Thrainer
class LUNodeMigrate(LogicalUnit):
1042 31b836b8 Thomas Thrainer
  """Migrate all instances from a node.
1043 31b836b8 Thomas Thrainer

1044 31b836b8 Thomas Thrainer
  """
1045 31b836b8 Thomas Thrainer
  HPATH = "node-migrate"
1046 31b836b8 Thomas Thrainer
  HTYPE = constants.HTYPE_NODE
1047 31b836b8 Thomas Thrainer
  REQ_BGL = False
1048 31b836b8 Thomas Thrainer
1049 31b836b8 Thomas Thrainer
  def CheckArguments(self):
1050 31b836b8 Thomas Thrainer
    pass
1051 31b836b8 Thomas Thrainer
1052 31b836b8 Thomas Thrainer
  def ExpandNames(self):
1053 1c3231aa Thomas Thrainer
    (self.op.node_uuid, self.op.node_name) = \
1054 1c3231aa Thomas Thrainer
      ExpandNodeUuidAndName(self.cfg, self.op.node_uuid, self.op.node_name)
1055 31b836b8 Thomas Thrainer
1056 5eacbcae Thomas Thrainer
    self.share_locks = ShareAll()
1057 31b836b8 Thomas Thrainer
    self.needed_locks = {
1058 1c3231aa Thomas Thrainer
      locking.LEVEL_NODE: [self.op.node_uuid],
1059 31b836b8 Thomas Thrainer
      }
1060 31b836b8 Thomas Thrainer
1061 31b836b8 Thomas Thrainer
  def BuildHooksEnv(self):
1062 31b836b8 Thomas Thrainer
    """Build hooks env.
1063 31b836b8 Thomas Thrainer

1064 31b836b8 Thomas Thrainer
    This runs on the master, the primary and all the secondaries.
1065 31b836b8 Thomas Thrainer

1066 31b836b8 Thomas Thrainer
    """
1067 31b836b8 Thomas Thrainer
    return {
1068 31b836b8 Thomas Thrainer
      "NODE_NAME": self.op.node_name,
1069 31b836b8 Thomas Thrainer
      "ALLOW_RUNTIME_CHANGES": self.op.allow_runtime_changes,
1070 31b836b8 Thomas Thrainer
      }
1071 31b836b8 Thomas Thrainer
1072 31b836b8 Thomas Thrainer
  def BuildHooksNodes(self):
1073 31b836b8 Thomas Thrainer
    """Build hooks nodes.
1074 31b836b8 Thomas Thrainer

1075 31b836b8 Thomas Thrainer
    """
1076 31b836b8 Thomas Thrainer
    nl = [self.cfg.GetMasterNode()]
1077 31b836b8 Thomas Thrainer
    return (nl, nl)
1078 31b836b8 Thomas Thrainer
1079 31b836b8 Thomas Thrainer
  def CheckPrereq(self):
1080 31b836b8 Thomas Thrainer
    pass
1081 31b836b8 Thomas Thrainer
1082 31b836b8 Thomas Thrainer
  def Exec(self, feedback_fn):
1083 31b836b8 Thomas Thrainer
    # Prepare jobs for migration instances
1084 31b836b8 Thomas Thrainer
    jobs = [
1085 d0d7d7cf Thomas Thrainer
      [opcodes.OpInstanceMigrate(
1086 d0d7d7cf Thomas Thrainer
        instance_name=inst.name,
1087 d0d7d7cf Thomas Thrainer
        mode=self.op.mode,
1088 d0d7d7cf Thomas Thrainer
        live=self.op.live,
1089 d0d7d7cf Thomas Thrainer
        iallocator=self.op.iallocator,
1090 d0d7d7cf Thomas Thrainer
        target_node=self.op.target_node,
1091 d0d7d7cf Thomas Thrainer
        allow_runtime_changes=self.op.allow_runtime_changes,
1092 d0d7d7cf Thomas Thrainer
        ignore_ipolicy=self.op.ignore_ipolicy)]
1093 1c3231aa Thomas Thrainer
      for inst in _GetNodePrimaryInstances(self.cfg, self.op.node_uuid)]
1094 31b836b8 Thomas Thrainer
1095 31b836b8 Thomas Thrainer
    # TODO: Run iallocator in this opcode and pass correct placement options to
1096 31b836b8 Thomas Thrainer
    # OpInstanceMigrate. Since other jobs can modify the cluster between
1097 31b836b8 Thomas Thrainer
    # running the iallocator and the actual migration, a good consistency model
1098 31b836b8 Thomas Thrainer
    # will have to be found.
1099 31b836b8 Thomas Thrainer
1100 31b836b8 Thomas Thrainer
    assert (frozenset(self.owned_locks(locking.LEVEL_NODE)) ==
1101 5e568fee Thomas Thrainer
            frozenset([self.op.node_uuid]))
1102 31b836b8 Thomas Thrainer
1103 31b836b8 Thomas Thrainer
    return ResultWithJobs(jobs)
1104 31b836b8 Thomas Thrainer
1105 31b836b8 Thomas Thrainer
1106 31b836b8 Thomas Thrainer
def _GetStorageTypeArgs(cfg, storage_type):
1107 31b836b8 Thomas Thrainer
  """Returns the arguments for a storage type.
1108 31b836b8 Thomas Thrainer

1109 31b836b8 Thomas Thrainer
  """
1110 31b836b8 Thomas Thrainer
  # Special case for file storage
1111 31b836b8 Thomas Thrainer
  if storage_type == constants.ST_FILE:
1112 31b836b8 Thomas Thrainer
    # storage.FileStorage wants a list of storage directories
1113 31b836b8 Thomas Thrainer
    return [[cfg.GetFileStorageDir(), cfg.GetSharedFileStorageDir()]]
1114 31b836b8 Thomas Thrainer
1115 31b836b8 Thomas Thrainer
  return []
1116 31b836b8 Thomas Thrainer
1117 31b836b8 Thomas Thrainer
1118 31b836b8 Thomas Thrainer
class LUNodeModifyStorage(NoHooksLU):
1119 31b836b8 Thomas Thrainer
  """Logical unit for modifying a storage volume on a node.
1120 31b836b8 Thomas Thrainer

1121 31b836b8 Thomas Thrainer
  """
1122 31b836b8 Thomas Thrainer
  REQ_BGL = False
1123 31b836b8 Thomas Thrainer
1124 31b836b8 Thomas Thrainer
  def CheckArguments(self):
1125 1c3231aa Thomas Thrainer
    (self.op.node_uuid, self.op.node_name) = \
1126 1c3231aa Thomas Thrainer
      ExpandNodeUuidAndName(self.cfg, self.op.node_uuid, self.op.node_name)
1127 31b836b8 Thomas Thrainer
1128 31b836b8 Thomas Thrainer
    storage_type = self.op.storage_type
1129 31b836b8 Thomas Thrainer
1130 31b836b8 Thomas Thrainer
    try:
1131 31b836b8 Thomas Thrainer
      modifiable = constants.MODIFIABLE_STORAGE_FIELDS[storage_type]
1132 31b836b8 Thomas Thrainer
    except KeyError:
1133 31b836b8 Thomas Thrainer
      raise errors.OpPrereqError("Storage units of type '%s' can not be"
1134 31b836b8 Thomas Thrainer
                                 " modified" % storage_type,
1135 31b836b8 Thomas Thrainer
                                 errors.ECODE_INVAL)
1136 31b836b8 Thomas Thrainer
1137 31b836b8 Thomas Thrainer
    diff = set(self.op.changes.keys()) - modifiable
1138 31b836b8 Thomas Thrainer
    if diff:
1139 31b836b8 Thomas Thrainer
      raise errors.OpPrereqError("The following fields can not be modified for"
1140 31b836b8 Thomas Thrainer
                                 " storage units of type '%s': %r" %
1141 31b836b8 Thomas Thrainer
                                 (storage_type, list(diff)),
1142 31b836b8 Thomas Thrainer
                                 errors.ECODE_INVAL)
1143 31b836b8 Thomas Thrainer
1144 9d276e93 Helga Velroyen
  def CheckPrereq(self):
1145 9d276e93 Helga Velroyen
    """Check prerequisites.
1146 9d276e93 Helga Velroyen

1147 9d276e93 Helga Velroyen
    """
1148 9d276e93 Helga Velroyen
    CheckStorageTypeEnabled(self.cfg.GetClusterInfo(), self.op.storage_type)
1149 9d276e93 Helga Velroyen
1150 31b836b8 Thomas Thrainer
  def ExpandNames(self):
1151 31b836b8 Thomas Thrainer
    self.needed_locks = {
1152 1c3231aa Thomas Thrainer
      locking.LEVEL_NODE: self.op.node_uuid,
1153 31b836b8 Thomas Thrainer
      }
1154 31b836b8 Thomas Thrainer
1155 31b836b8 Thomas Thrainer
  def Exec(self, feedback_fn):
1156 31b836b8 Thomas Thrainer
    """Computes the list of nodes and their attributes.
1157 31b836b8 Thomas Thrainer

1158 31b836b8 Thomas Thrainer
    """
1159 31b836b8 Thomas Thrainer
    st_args = _GetStorageTypeArgs(self.cfg, self.op.storage_type)
1160 1c3231aa Thomas Thrainer
    result = self.rpc.call_storage_modify(self.op.node_uuid,
1161 31b836b8 Thomas Thrainer
                                          self.op.storage_type, st_args,
1162 31b836b8 Thomas Thrainer
                                          self.op.name, self.op.changes)
1163 31b836b8 Thomas Thrainer
    result.Raise("Failed to modify storage unit '%s' on %s" %
1164 31b836b8 Thomas Thrainer
                 (self.op.name, self.op.node_name))
1165 31b836b8 Thomas Thrainer
1166 31b836b8 Thomas Thrainer
1167 5eacbcae Thomas Thrainer
class NodeQuery(QueryBase):
1168 31b836b8 Thomas Thrainer
  FIELDS = query.NODE_FIELDS
1169 31b836b8 Thomas Thrainer
1170 31b836b8 Thomas Thrainer
  def ExpandNames(self, lu):
1171 31b836b8 Thomas Thrainer
    lu.needed_locks = {}
1172 5eacbcae Thomas Thrainer
    lu.share_locks = ShareAll()
1173 31b836b8 Thomas Thrainer
1174 31b836b8 Thomas Thrainer
    if self.names:
1175 1c3231aa Thomas Thrainer
      (self.wanted, _) = GetWantedNodes(lu, self.names)
1176 31b836b8 Thomas Thrainer
    else:
1177 31b836b8 Thomas Thrainer
      self.wanted = locking.ALL_SET
1178 31b836b8 Thomas Thrainer
1179 31b836b8 Thomas Thrainer
    self.do_locking = (self.use_locking and
1180 31b836b8 Thomas Thrainer
                       query.NQ_LIVE in self.requested_data)
1181 31b836b8 Thomas Thrainer
1182 31b836b8 Thomas Thrainer
    if self.do_locking:
1183 31b836b8 Thomas Thrainer
      # If any non-static field is requested we need to lock the nodes
1184 31b836b8 Thomas Thrainer
      lu.needed_locks[locking.LEVEL_NODE] = self.wanted
1185 31b836b8 Thomas Thrainer
      lu.needed_locks[locking.LEVEL_NODE_ALLOC] = locking.ALL_SET
1186 31b836b8 Thomas Thrainer
1187 31b836b8 Thomas Thrainer
  def DeclareLocks(self, lu, level):
1188 31b836b8 Thomas Thrainer
    pass
1189 31b836b8 Thomas Thrainer
1190 31b836b8 Thomas Thrainer
  def _GetQueryData(self, lu):
1191 31b836b8 Thomas Thrainer
    """Computes the list of nodes and their attributes.
1192 31b836b8 Thomas Thrainer

1193 31b836b8 Thomas Thrainer
    """
1194 31b836b8 Thomas Thrainer
    all_info = lu.cfg.GetAllNodesInfo()
1195 31b836b8 Thomas Thrainer
1196 1c3231aa Thomas Thrainer
    node_uuids = self._GetNames(lu, all_info.keys(), locking.LEVEL_NODE)
1197 31b836b8 Thomas Thrainer
1198 31b836b8 Thomas Thrainer
    # Gather data as requested
1199 31b836b8 Thomas Thrainer
    if query.NQ_LIVE in self.requested_data:
1200 31b836b8 Thomas Thrainer
      # filter out non-vm_capable nodes
1201 1c3231aa Thomas Thrainer
      toquery_node_uuids = [node.uuid for node in all_info.values()
1202 1c3231aa Thomas Thrainer
                            if node.vm_capable and node.uuid in node_uuids]
1203 6c00b2c7 Helga Velroyen
      default_template = lu.cfg.GetClusterInfo().enabled_disk_templates[0]
1204 6c00b2c7 Helga Velroyen
      raw_storage_units = utils.storage.GetStorageUnits(
1205 6c00b2c7 Helga Velroyen
          lu.cfg, [default_template])
1206 da803ff1 Helga Velroyen
      storage_units = rpc.PrepareStorageUnitsForNodes(
1207 da803ff1 Helga Velroyen
          lu.cfg, raw_storage_units, toquery_node_uuids)
1208 a295eb80 Helga Velroyen
      default_hypervisor = lu.cfg.GetHypervisorType()
1209 a295eb80 Helga Velroyen
      hvparams = lu.cfg.GetClusterInfo().hvparams[default_hypervisor]
1210 a295eb80 Helga Velroyen
      hvspecs = [(default_hypervisor, hvparams)]
1211 32389d91 Helga Velroyen
      node_data = lu.rpc.call_node_info(toquery_node_uuids, storage_units,
1212 da803ff1 Helga Velroyen
                                        hvspecs)
1213 32389d91 Helga Velroyen
      live_data = dict(
1214 6c00b2c7 Helga Velroyen
          (uuid, rpc.MakeLegacyNodeInfo(nresult.payload, default_template))
1215 32389d91 Helga Velroyen
          for (uuid, nresult) in node_data.items()
1216 32389d91 Helga Velroyen
          if not nresult.fail_msg and nresult.payload)
1217 31b836b8 Thomas Thrainer
    else:
1218 31b836b8 Thomas Thrainer
      live_data = None
1219 31b836b8 Thomas Thrainer
1220 31b836b8 Thomas Thrainer
    if query.NQ_INST in self.requested_data:
1221 1c3231aa Thomas Thrainer
      node_to_primary = dict([(uuid, set()) for uuid in node_uuids])
1222 1c3231aa Thomas Thrainer
      node_to_secondary = dict([(uuid, set()) for uuid in node_uuids])
1223 31b836b8 Thomas Thrainer
1224 31b836b8 Thomas Thrainer
      inst_data = lu.cfg.GetAllInstancesInfo()
1225 da4a52a3 Thomas Thrainer
      inst_uuid_to_inst_name = {}
1226 31b836b8 Thomas Thrainer
1227 31b836b8 Thomas Thrainer
      for inst in inst_data.values():
1228 da4a52a3 Thomas Thrainer
        inst_uuid_to_inst_name[inst.uuid] = inst.name
1229 31b836b8 Thomas Thrainer
        if inst.primary_node in node_to_primary:
1230 da4a52a3 Thomas Thrainer
          node_to_primary[inst.primary_node].add(inst.uuid)
1231 31b836b8 Thomas Thrainer
        for secnode in inst.secondary_nodes:
1232 31b836b8 Thomas Thrainer
          if secnode in node_to_secondary:
1233 da4a52a3 Thomas Thrainer
            node_to_secondary[secnode].add(inst.uuid)
1234 31b836b8 Thomas Thrainer
    else:
1235 31b836b8 Thomas Thrainer
      node_to_primary = None
1236 31b836b8 Thomas Thrainer
      node_to_secondary = None
1237 da4a52a3 Thomas Thrainer
      inst_uuid_to_inst_name = None
1238 31b836b8 Thomas Thrainer
1239 31b836b8 Thomas Thrainer
    if query.NQ_OOB in self.requested_data:
1240 1c3231aa Thomas Thrainer
      oob_support = dict((uuid, bool(SupportsOob(lu.cfg, node)))
1241 1c3231aa Thomas Thrainer
                         for uuid, node in all_info.iteritems())
1242 31b836b8 Thomas Thrainer
    else:
1243 31b836b8 Thomas Thrainer
      oob_support = None
1244 31b836b8 Thomas Thrainer
1245 31b836b8 Thomas Thrainer
    if query.NQ_GROUP in self.requested_data:
1246 31b836b8 Thomas Thrainer
      groups = lu.cfg.GetAllNodeGroupsInfo()
1247 31b836b8 Thomas Thrainer
    else:
1248 31b836b8 Thomas Thrainer
      groups = {}
1249 31b836b8 Thomas Thrainer
1250 1c3231aa Thomas Thrainer
    return query.NodeQueryData([all_info[uuid] for uuid in node_uuids],
1251 31b836b8 Thomas Thrainer
                               live_data, lu.cfg.GetMasterNode(),
1252 da4a52a3 Thomas Thrainer
                               node_to_primary, node_to_secondary,
1253 da4a52a3 Thomas Thrainer
                               inst_uuid_to_inst_name, groups, oob_support,
1254 da4a52a3 Thomas Thrainer
                               lu.cfg.GetClusterInfo())
1255 31b836b8 Thomas Thrainer
1256 31b836b8 Thomas Thrainer
1257 31b836b8 Thomas Thrainer
class LUNodeQuery(NoHooksLU):
1258 31b836b8 Thomas Thrainer
  """Logical unit for querying nodes.
1259 31b836b8 Thomas Thrainer

1260 31b836b8 Thomas Thrainer
  """
1261 31b836b8 Thomas Thrainer
  # pylint: disable=W0142
1262 31b836b8 Thomas Thrainer
  REQ_BGL = False
1263 31b836b8 Thomas Thrainer
1264 31b836b8 Thomas Thrainer
  def CheckArguments(self):
1265 5eacbcae Thomas Thrainer
    self.nq = NodeQuery(qlang.MakeSimpleFilter("name", self.op.names),
1266 31b836b8 Thomas Thrainer
                         self.op.output_fields, self.op.use_locking)
1267 31b836b8 Thomas Thrainer
1268 31b836b8 Thomas Thrainer
  def ExpandNames(self):
1269 31b836b8 Thomas Thrainer
    self.nq.ExpandNames(self)
1270 31b836b8 Thomas Thrainer
1271 31b836b8 Thomas Thrainer
  def DeclareLocks(self, level):
1272 31b836b8 Thomas Thrainer
    self.nq.DeclareLocks(self, level)
1273 31b836b8 Thomas Thrainer
1274 31b836b8 Thomas Thrainer
  def Exec(self, feedback_fn):
1275 31b836b8 Thomas Thrainer
    return self.nq.OldStyleQuery(self)
1276 31b836b8 Thomas Thrainer
1277 31b836b8 Thomas Thrainer
1278 6afb9fb4 Jose A. Lopes
def _CheckOutputFields(fields, selected):
1279 6afb9fb4 Jose A. Lopes
  """Checks whether all selected fields are valid according to fields.
1280 31b836b8 Thomas Thrainer

1281 6afb9fb4 Jose A. Lopes
  @type fields: L{utils.FieldSet}
1282 6afb9fb4 Jose A. Lopes
  @param fields: fields set
1283 6afb9fb4 Jose A. Lopes
  @type selected: L{utils.FieldSet}
1284 6afb9fb4 Jose A. Lopes
  @param selected: fields set
1285 31b836b8 Thomas Thrainer

1286 31b836b8 Thomas Thrainer
  """
1287 6afb9fb4 Jose A. Lopes
  delta = fields.NonMatching(selected)
1288 31b836b8 Thomas Thrainer
  if delta:
1289 31b836b8 Thomas Thrainer
    raise errors.OpPrereqError("Unknown output fields selected: %s"
1290 31b836b8 Thomas Thrainer
                               % ",".join(delta), errors.ECODE_INVAL)
1291 31b836b8 Thomas Thrainer
1292 31b836b8 Thomas Thrainer
1293 31b836b8 Thomas Thrainer
class LUNodeQueryvols(NoHooksLU):
1294 31b836b8 Thomas Thrainer
  """Logical unit for getting volumes on node(s).
1295 31b836b8 Thomas Thrainer

1296 31b836b8 Thomas Thrainer
  """
1297 31b836b8 Thomas Thrainer
  REQ_BGL = False
1298 31b836b8 Thomas Thrainer
1299 31b836b8 Thomas Thrainer
  def CheckArguments(self):
1300 b2fbea47 Jose A. Lopes
    _CheckOutputFields(utils.FieldSet(constants.VF_NODE, constants.VF_PHYS,
1301 b2fbea47 Jose A. Lopes
                                      constants.VF_VG, constants.VF_NAME,
1302 b2fbea47 Jose A. Lopes
                                      constants.VF_SIZE, constants.VF_INSTANCE),
1303 6afb9fb4 Jose A. Lopes
                       self.op.output_fields)
1304 31b836b8 Thomas Thrainer
1305 31b836b8 Thomas Thrainer
  def ExpandNames(self):
1306 5eacbcae Thomas Thrainer
    self.share_locks = ShareAll()
1307 31b836b8 Thomas Thrainer
1308 31b836b8 Thomas Thrainer
    if self.op.nodes:
1309 31b836b8 Thomas Thrainer
      self.needed_locks = {
1310 1c3231aa Thomas Thrainer
        locking.LEVEL_NODE: GetWantedNodes(self, self.op.nodes)[0],
1311 31b836b8 Thomas Thrainer
        }
1312 31b836b8 Thomas Thrainer
    else:
1313 31b836b8 Thomas Thrainer
      self.needed_locks = {
1314 31b836b8 Thomas Thrainer
        locking.LEVEL_NODE: locking.ALL_SET,
1315 31b836b8 Thomas Thrainer
        locking.LEVEL_NODE_ALLOC: locking.ALL_SET,
1316 31b836b8 Thomas Thrainer
        }
1317 31b836b8 Thomas Thrainer
1318 31b836b8 Thomas Thrainer
  def Exec(self, feedback_fn):
1319 31b836b8 Thomas Thrainer
    """Computes the list of nodes and their attributes.
1320 31b836b8 Thomas Thrainer

1321 31b836b8 Thomas Thrainer
    """
1322 1c3231aa Thomas Thrainer
    node_uuids = self.owned_locks(locking.LEVEL_NODE)
1323 1c3231aa Thomas Thrainer
    volumes = self.rpc.call_node_volumes(node_uuids)
1324 31b836b8 Thomas Thrainer
1325 31b836b8 Thomas Thrainer
    ilist = self.cfg.GetAllInstancesInfo()
1326 843094ad Thomas Thrainer
    vol2inst = MapInstanceLvsToNodes(ilist.values())
1327 31b836b8 Thomas Thrainer
1328 31b836b8 Thomas Thrainer
    output = []
1329 1c3231aa Thomas Thrainer
    for node_uuid in node_uuids:
1330 1c3231aa Thomas Thrainer
      nresult = volumes[node_uuid]
1331 31b836b8 Thomas Thrainer
      if nresult.offline:
1332 31b836b8 Thomas Thrainer
        continue
1333 31b836b8 Thomas Thrainer
      msg = nresult.fail_msg
1334 31b836b8 Thomas Thrainer
      if msg:
1335 1c3231aa Thomas Thrainer
        self.LogWarning("Can't compute volume data on node %s: %s",
1336 1c3231aa Thomas Thrainer
                        self.cfg.GetNodeName(node_uuid), msg)
1337 31b836b8 Thomas Thrainer
        continue
1338 31b836b8 Thomas Thrainer
1339 31b836b8 Thomas Thrainer
      node_vols = sorted(nresult.payload,
1340 b2fbea47 Jose A. Lopes
                         key=operator.itemgetter(constants.VF_DEV))
1341 31b836b8 Thomas Thrainer
1342 31b836b8 Thomas Thrainer
      for vol in node_vols:
1343 31b836b8 Thomas Thrainer
        node_output = []
1344 31b836b8 Thomas Thrainer
        for field in self.op.output_fields:
1345 b2fbea47 Jose A. Lopes
          if field == constants.VF_NODE:
1346 1c3231aa Thomas Thrainer
            val = self.cfg.GetNodeName(node_uuid)
1347 b2fbea47 Jose A. Lopes
          elif field == constants.VF_PHYS:
1348 b2fbea47 Jose A. Lopes
            val = vol[constants.VF_DEV]
1349 b2fbea47 Jose A. Lopes
          elif field == constants.VF_VG:
1350 b2fbea47 Jose A. Lopes
            val = vol[constants.VF_VG]
1351 b2fbea47 Jose A. Lopes
          elif field == constants.VF_NAME:
1352 b2fbea47 Jose A. Lopes
            val = vol[constants.VF_NAME]
1353 b2fbea47 Jose A. Lopes
          elif field == constants.VF_SIZE:
1354 b2fbea47 Jose A. Lopes
            val = int(float(vol[constants.VF_SIZE]))
1355 b2fbea47 Jose A. Lopes
          elif field == constants.VF_INSTANCE:
1356 b2fbea47 Jose A. Lopes
            inst = vol2inst.get((node_uuid, vol[constants.VF_VG] + "/" +
1357 b2fbea47 Jose A. Lopes
                                 vol[constants.VF_NAME]), None)
1358 843094ad Thomas Thrainer
            if inst is not None:
1359 843094ad Thomas Thrainer
              val = inst.name
1360 843094ad Thomas Thrainer
            else:
1361 843094ad Thomas Thrainer
              val = "-"
1362 31b836b8 Thomas Thrainer
          else:
1363 31b836b8 Thomas Thrainer
            raise errors.ParameterError(field)
1364 31b836b8 Thomas Thrainer
          node_output.append(str(val))
1365 31b836b8 Thomas Thrainer
1366 31b836b8 Thomas Thrainer
        output.append(node_output)
1367 31b836b8 Thomas Thrainer
1368 31b836b8 Thomas Thrainer
    return output
1369 31b836b8 Thomas Thrainer
1370 31b836b8 Thomas Thrainer
1371 31b836b8 Thomas Thrainer
class LUNodeQueryStorage(NoHooksLU):
1372 31b836b8 Thomas Thrainer
  """Logical unit for getting information on storage units on node(s).
1373 31b836b8 Thomas Thrainer

1374 31b836b8 Thomas Thrainer
  """
1375 31b836b8 Thomas Thrainer
  REQ_BGL = False
1376 31b836b8 Thomas Thrainer
1377 31b836b8 Thomas Thrainer
  def CheckArguments(self):
1378 6afb9fb4 Jose A. Lopes
    _CheckOutputFields(utils.FieldSet(*constants.VALID_STORAGE_FIELDS),
1379 6afb9fb4 Jose A. Lopes
                       self.op.output_fields)
1380 31b836b8 Thomas Thrainer
1381 31b836b8 Thomas Thrainer
  def ExpandNames(self):
1382 5eacbcae Thomas Thrainer
    self.share_locks = ShareAll()
1383 31b836b8 Thomas Thrainer
1384 31b836b8 Thomas Thrainer
    if self.op.nodes:
1385 31b836b8 Thomas Thrainer
      self.needed_locks = {
1386 1c3231aa Thomas Thrainer
        locking.LEVEL_NODE: GetWantedNodes(self, self.op.nodes)[0],
1387 31b836b8 Thomas Thrainer
        }
1388 31b836b8 Thomas Thrainer
    else:
1389 31b836b8 Thomas Thrainer
      self.needed_locks = {
1390 31b836b8 Thomas Thrainer
        locking.LEVEL_NODE: locking.ALL_SET,
1391 31b836b8 Thomas Thrainer
        locking.LEVEL_NODE_ALLOC: locking.ALL_SET,
1392 31b836b8 Thomas Thrainer
        }
1393 31b836b8 Thomas Thrainer
1394 4f90370c Helga Velroyen
  def _DetermineStorageType(self):
1395 4f90370c Helga Velroyen
    """Determines the default storage type of the cluster.
1396 4f90370c Helga Velroyen

1397 4f90370c Helga Velroyen
    """
1398 4f90370c Helga Velroyen
    enabled_disk_templates = self.cfg.GetClusterInfo().enabled_disk_templates
1399 4f90370c Helga Velroyen
    default_storage_type = \
1400 4f90370c Helga Velroyen
        constants.MAP_DISK_TEMPLATE_STORAGE_TYPE[enabled_disk_templates[0]]
1401 4f90370c Helga Velroyen
    return default_storage_type
1402 4f90370c Helga Velroyen
1403 9d276e93 Helga Velroyen
  def CheckPrereq(self):
1404 9d276e93 Helga Velroyen
    """Check prerequisites.
1405 9d276e93 Helga Velroyen

1406 9d276e93 Helga Velroyen
    """
1407 4f90370c Helga Velroyen
    if self.op.storage_type:
1408 4f90370c Helga Velroyen
      CheckStorageTypeEnabled(self.cfg.GetClusterInfo(), self.op.storage_type)
1409 4f90370c Helga Velroyen
      self.storage_type = self.op.storage_type
1410 4f90370c Helga Velroyen
    else:
1411 4f90370c Helga Velroyen
      self.storage_type = self._DetermineStorageType()
1412 4f90370c Helga Velroyen
      if self.storage_type not in constants.STS_REPORT:
1413 4f90370c Helga Velroyen
        raise errors.OpPrereqError(
1414 4f90370c Helga Velroyen
            "Storage reporting for storage type '%s' is not supported. Please"
1415 4f90370c Helga Velroyen
            " use the --storage-type option to specify one of the supported"
1416 4f90370c Helga Velroyen
            " storage types (%s) or set the default disk template to one that"
1417 4f90370c Helga Velroyen
            " supports storage reporting." %
1418 4f90370c Helga Velroyen
            (self.storage_type, utils.CommaJoin(constants.STS_REPORT)))
1419 9d276e93 Helga Velroyen
1420 31b836b8 Thomas Thrainer
  def Exec(self, feedback_fn):
1421 31b836b8 Thomas Thrainer
    """Computes the list of nodes and their attributes.
1422 31b836b8 Thomas Thrainer

1423 31b836b8 Thomas Thrainer
    """
1424 4f90370c Helga Velroyen
    if self.op.storage_type:
1425 4f90370c Helga Velroyen
      self.storage_type = self.op.storage_type
1426 4f90370c Helga Velroyen
    else:
1427 4f90370c Helga Velroyen
      self.storage_type = self._DetermineStorageType()
1428 4f90370c Helga Velroyen
1429 1c3231aa Thomas Thrainer
    self.node_uuids = self.owned_locks(locking.LEVEL_NODE)
1430 31b836b8 Thomas Thrainer
1431 31b836b8 Thomas Thrainer
    # Always get name to sort by
1432 31b836b8 Thomas Thrainer
    if constants.SF_NAME in self.op.output_fields:
1433 31b836b8 Thomas Thrainer
      fields = self.op.output_fields[:]
1434 31b836b8 Thomas Thrainer
    else:
1435 31b836b8 Thomas Thrainer
      fields = [constants.SF_NAME] + self.op.output_fields
1436 31b836b8 Thomas Thrainer
1437 31b836b8 Thomas Thrainer
    # Never ask for node or type as it's only known to the LU
1438 31b836b8 Thomas Thrainer
    for extra in [constants.SF_NODE, constants.SF_TYPE]:
1439 31b836b8 Thomas Thrainer
      while extra in fields:
1440 31b836b8 Thomas Thrainer
        fields.remove(extra)
1441 31b836b8 Thomas Thrainer
1442 31b836b8 Thomas Thrainer
    field_idx = dict([(name, idx) for (idx, name) in enumerate(fields)])
1443 31b836b8 Thomas Thrainer
    name_idx = field_idx[constants.SF_NAME]
1444 31b836b8 Thomas Thrainer
1445 4f90370c Helga Velroyen
    st_args = _GetStorageTypeArgs(self.cfg, self.storage_type)
1446 1c3231aa Thomas Thrainer
    data = self.rpc.call_storage_list(self.node_uuids,
1447 4f90370c Helga Velroyen
                                      self.storage_type, st_args,
1448 31b836b8 Thomas Thrainer
                                      self.op.name, fields)
1449 31b836b8 Thomas Thrainer
1450 31b836b8 Thomas Thrainer
    result = []
1451 31b836b8 Thomas Thrainer
1452 1c3231aa Thomas Thrainer
    for node_uuid in utils.NiceSort(self.node_uuids):
1453 1c3231aa Thomas Thrainer
      node_name = self.cfg.GetNodeName(node_uuid)
1454 1c3231aa Thomas Thrainer
      nresult = data[node_uuid]
1455 31b836b8 Thomas Thrainer
      if nresult.offline:
1456 31b836b8 Thomas Thrainer
        continue
1457 31b836b8 Thomas Thrainer
1458 31b836b8 Thomas Thrainer
      msg = nresult.fail_msg
1459 31b836b8 Thomas Thrainer
      if msg:
1460 1c3231aa Thomas Thrainer
        self.LogWarning("Can't get storage data from node %s: %s",
1461 1c3231aa Thomas Thrainer
                        node_name, msg)
1462 31b836b8 Thomas Thrainer
        continue
1463 31b836b8 Thomas Thrainer
1464 31b836b8 Thomas Thrainer
      rows = dict([(row[name_idx], row) for row in nresult.payload])
1465 31b836b8 Thomas Thrainer
1466 31b836b8 Thomas Thrainer
      for name in utils.NiceSort(rows.keys()):
1467 31b836b8 Thomas Thrainer
        row = rows[name]
1468 31b836b8 Thomas Thrainer
1469 31b836b8 Thomas Thrainer
        out = []
1470 31b836b8 Thomas Thrainer
1471 31b836b8 Thomas Thrainer
        for field in self.op.output_fields:
1472 31b836b8 Thomas Thrainer
          if field == constants.SF_NODE:
1473 1c3231aa Thomas Thrainer
            val = node_name
1474 31b836b8 Thomas Thrainer
          elif field == constants.SF_TYPE:
1475 4f90370c Helga Velroyen
            val = self.storage_type
1476 31b836b8 Thomas Thrainer
          elif field in field_idx:
1477 31b836b8 Thomas Thrainer
            val = row[field_idx[field]]
1478 31b836b8 Thomas Thrainer
          else:
1479 31b836b8 Thomas Thrainer
            raise errors.ParameterError(field)
1480 31b836b8 Thomas Thrainer
1481 31b836b8 Thomas Thrainer
          out.append(val)
1482 31b836b8 Thomas Thrainer
1483 31b836b8 Thomas Thrainer
        result.append(out)
1484 31b836b8 Thomas Thrainer
1485 31b836b8 Thomas Thrainer
    return result
1486 31b836b8 Thomas Thrainer
1487 31b836b8 Thomas Thrainer
1488 31b836b8 Thomas Thrainer
class LUNodeRemove(LogicalUnit):
1489 31b836b8 Thomas Thrainer
  """Logical unit for removing a node.
1490 31b836b8 Thomas Thrainer

1491 31b836b8 Thomas Thrainer
  """
1492 31b836b8 Thomas Thrainer
  HPATH = "node-remove"
1493 31b836b8 Thomas Thrainer
  HTYPE = constants.HTYPE_NODE
1494 31b836b8 Thomas Thrainer
1495 31b836b8 Thomas Thrainer
  def BuildHooksEnv(self):
1496 31b836b8 Thomas Thrainer
    """Build hooks env.
1497 31b836b8 Thomas Thrainer

1498 31b836b8 Thomas Thrainer
    """
1499 31b836b8 Thomas Thrainer
    return {
1500 31b836b8 Thomas Thrainer
      "OP_TARGET": self.op.node_name,
1501 31b836b8 Thomas Thrainer
      "NODE_NAME": self.op.node_name,
1502 31b836b8 Thomas Thrainer
      }
1503 31b836b8 Thomas Thrainer
1504 31b836b8 Thomas Thrainer
  def BuildHooksNodes(self):
1505 31b836b8 Thomas Thrainer
    """Build hooks nodes.
1506 31b836b8 Thomas Thrainer

1507 31b836b8 Thomas Thrainer
    This doesn't run on the target node in the pre phase as a failed
1508 31b836b8 Thomas Thrainer
    node would then be impossible to remove.
1509 31b836b8 Thomas Thrainer

1510 31b836b8 Thomas Thrainer
    """
1511 31b836b8 Thomas Thrainer
    all_nodes = self.cfg.GetNodeList()
1512 31b836b8 Thomas Thrainer
    try:
1513 1c3231aa Thomas Thrainer
      all_nodes.remove(self.op.node_uuid)
1514 31b836b8 Thomas Thrainer
    except ValueError:
1515 31b836b8 Thomas Thrainer
      pass
1516 31b836b8 Thomas Thrainer
    return (all_nodes, all_nodes)
1517 31b836b8 Thomas Thrainer
1518 31b836b8 Thomas Thrainer
  def CheckPrereq(self):
1519 31b836b8 Thomas Thrainer
    """Check prerequisites.
1520 31b836b8 Thomas Thrainer

1521 31b836b8 Thomas Thrainer
    This checks:
1522 31b836b8 Thomas Thrainer
     - the node exists in the configuration
1523 31b836b8 Thomas Thrainer
     - it does not have primary or secondary instances
1524 31b836b8 Thomas Thrainer
     - it's not the master
1525 31b836b8 Thomas Thrainer

1526 31b836b8 Thomas Thrainer
    Any errors are signaled by raising errors.OpPrereqError.
1527 31b836b8 Thomas Thrainer

1528 31b836b8 Thomas Thrainer
    """
1529 1c3231aa Thomas Thrainer
    (self.op.node_uuid, self.op.node_name) = \
1530 1c3231aa Thomas Thrainer
      ExpandNodeUuidAndName(self.cfg, self.op.node_uuid, self.op.node_name)
1531 1c3231aa Thomas Thrainer
    node = self.cfg.GetNodeInfo(self.op.node_uuid)
1532 31b836b8 Thomas Thrainer
    assert node is not None
1533 31b836b8 Thomas Thrainer
1534 31b836b8 Thomas Thrainer
    masternode = self.cfg.GetMasterNode()
1535 1c3231aa Thomas Thrainer
    if node.uuid == masternode:
1536 31b836b8 Thomas Thrainer
      raise errors.OpPrereqError("Node is the master node, failover to another"
1537 31b836b8 Thomas Thrainer
                                 " node is required", errors.ECODE_INVAL)
1538 31b836b8 Thomas Thrainer
1539 da4a52a3 Thomas Thrainer
    for _, instance in self.cfg.GetAllInstancesInfo().items():
1540 1c3231aa Thomas Thrainer
      if node.uuid in instance.all_nodes:
1541 31b836b8 Thomas Thrainer
        raise errors.OpPrereqError("Instance %s is still running on the node,"
1542 da4a52a3 Thomas Thrainer
                                   " please remove first" % instance.name,
1543 31b836b8 Thomas Thrainer
                                   errors.ECODE_INVAL)
1544 31b836b8 Thomas Thrainer
    self.op.node_name = node.name
1545 31b836b8 Thomas Thrainer
    self.node = node
1546 31b836b8 Thomas Thrainer
1547 31b836b8 Thomas Thrainer
  def Exec(self, feedback_fn):
1548 31b836b8 Thomas Thrainer
    """Removes the node from the cluster.
1549 31b836b8 Thomas Thrainer

1550 31b836b8 Thomas Thrainer
    """
1551 31b836b8 Thomas Thrainer
    logging.info("Stopping the node daemon and removing configs from node %s",
1552 d0d7d7cf Thomas Thrainer
                 self.node.name)
1553 31b836b8 Thomas Thrainer
1554 31b836b8 Thomas Thrainer
    modify_ssh_setup = self.cfg.GetClusterInfo().modify_ssh_setup
1555 31b836b8 Thomas Thrainer
1556 31b836b8 Thomas Thrainer
    assert locking.BGL in self.owned_locks(locking.LEVEL_CLUSTER), \
1557 31b836b8 Thomas Thrainer
      "Not owning BGL"
1558 31b836b8 Thomas Thrainer
1559 31b836b8 Thomas Thrainer
    # Promote nodes to master candidate as needed
1560 d0d7d7cf Thomas Thrainer
    AdjustCandidatePool(self, exceptions=[self.node.uuid])
1561 d0d7d7cf Thomas Thrainer
    self.context.RemoveNode(self.node)
1562 31b836b8 Thomas Thrainer
1563 31b836b8 Thomas Thrainer
    # Run post hooks on the node before it's removed
1564 d0d7d7cf Thomas Thrainer
    RunPostHook(self, self.node.name)
1565 31b836b8 Thomas Thrainer
1566 1c3231aa Thomas Thrainer
    # we have to call this by name rather than by UUID, as the node is no longer
1567 1c3231aa Thomas Thrainer
    # in the config
1568 d0d7d7cf Thomas Thrainer
    result = self.rpc.call_node_leave_cluster(self.node.name, modify_ssh_setup)
1569 31b836b8 Thomas Thrainer
    msg = result.fail_msg
1570 31b836b8 Thomas Thrainer
    if msg:
1571 31b836b8 Thomas Thrainer
      self.LogWarning("Errors encountered on the remote node while leaving"
1572 31b836b8 Thomas Thrainer
                      " the cluster: %s", msg)
1573 31b836b8 Thomas Thrainer
1574 31b836b8 Thomas Thrainer
    # Remove node from our /etc/hosts
1575 31b836b8 Thomas Thrainer
    if self.cfg.GetClusterInfo().modify_etc_hosts:
1576 1c3231aa Thomas Thrainer
      master_node_uuid = self.cfg.GetMasterNode()
1577 1c3231aa Thomas Thrainer
      result = self.rpc.call_etc_hosts_modify(master_node_uuid,
1578 31b836b8 Thomas Thrainer
                                              constants.ETC_HOSTS_REMOVE,
1579 d0d7d7cf Thomas Thrainer
                                              self.node.name, None)
1580 31b836b8 Thomas Thrainer
      result.Raise("Can't update hosts file with new host data")
1581 5eacbcae Thomas Thrainer
      RedistributeAncillaryFiles(self)
1582 31b836b8 Thomas Thrainer
1583 31b836b8 Thomas Thrainer
1584 31b836b8 Thomas Thrainer
class LURepairNodeStorage(NoHooksLU):
1585 31b836b8 Thomas Thrainer
  """Repairs the volume group on a node.
1586 31b836b8 Thomas Thrainer

1587 31b836b8 Thomas Thrainer
  """
1588 31b836b8 Thomas Thrainer
  REQ_BGL = False
1589 31b836b8 Thomas Thrainer
1590 31b836b8 Thomas Thrainer
  def CheckArguments(self):
1591 1c3231aa Thomas Thrainer
    (self.op.node_uuid, self.op.node_name) = \
1592 1c3231aa Thomas Thrainer
      ExpandNodeUuidAndName(self.cfg, self.op.node_uuid, self.op.node_name)
1593 31b836b8 Thomas Thrainer
1594 31b836b8 Thomas Thrainer
    storage_type = self.op.storage_type
1595 31b836b8 Thomas Thrainer
1596 31b836b8 Thomas Thrainer
    if (constants.SO_FIX_CONSISTENCY not in
1597 31b836b8 Thomas Thrainer
        constants.VALID_STORAGE_OPERATIONS.get(storage_type, [])):
1598 31b836b8 Thomas Thrainer
      raise errors.OpPrereqError("Storage units of type '%s' can not be"
1599 31b836b8 Thomas Thrainer
                                 " repaired" % storage_type,
1600 31b836b8 Thomas Thrainer
                                 errors.ECODE_INVAL)
1601 31b836b8 Thomas Thrainer
1602 31b836b8 Thomas Thrainer
  def ExpandNames(self):
1603 31b836b8 Thomas Thrainer
    self.needed_locks = {
1604 1c3231aa Thomas Thrainer
      locking.LEVEL_NODE: [self.op.node_uuid],
1605 31b836b8 Thomas Thrainer
      }
1606 31b836b8 Thomas Thrainer
1607 1c3231aa Thomas Thrainer
  def _CheckFaultyDisks(self, instance, node_uuid):
1608 31b836b8 Thomas Thrainer
    """Ensure faulty disks abort the opcode or at least warn."""
1609 31b836b8 Thomas Thrainer
    try:
1610 5eacbcae Thomas Thrainer
      if FindFaultyInstanceDisks(self.cfg, self.rpc, instance,
1611 1c3231aa Thomas Thrainer
                                 node_uuid, True):
1612 31b836b8 Thomas Thrainer
        raise errors.OpPrereqError("Instance '%s' has faulty disks on"
1613 1c3231aa Thomas Thrainer
                                   " node '%s'" %
1614 1c3231aa Thomas Thrainer
                                   (instance.name,
1615 1c3231aa Thomas Thrainer
                                    self.cfg.GetNodeName(node_uuid)),
1616 31b836b8 Thomas Thrainer
                                   errors.ECODE_STATE)
1617 31b836b8 Thomas Thrainer
    except errors.OpPrereqError, err:
1618 31b836b8 Thomas Thrainer
      if self.op.ignore_consistency:
1619 31b836b8 Thomas Thrainer
        self.LogWarning(str(err.args[0]))
1620 31b836b8 Thomas Thrainer
      else:
1621 31b836b8 Thomas Thrainer
        raise
1622 31b836b8 Thomas Thrainer
1623 31b836b8 Thomas Thrainer
  def CheckPrereq(self):
1624 31b836b8 Thomas Thrainer
    """Check prerequisites.
1625 31b836b8 Thomas Thrainer

1626 31b836b8 Thomas Thrainer
    """
1627 9d276e93 Helga Velroyen
    CheckStorageTypeEnabled(self.cfg.GetClusterInfo(), self.op.storage_type)
1628 9d276e93 Helga Velroyen
1629 31b836b8 Thomas Thrainer
    # Check whether any instance on this node has faulty disks
1630 1c3231aa Thomas Thrainer
    for inst in _GetNodeInstances(self.cfg, self.op.node_uuid):
1631 1d4a4b26 Thomas Thrainer
      if not inst.disks_active:
1632 31b836b8 Thomas Thrainer
        continue
1633 31b836b8 Thomas Thrainer
      check_nodes = set(inst.all_nodes)
1634 1c3231aa Thomas Thrainer
      check_nodes.discard(self.op.node_uuid)
1635 1c3231aa Thomas Thrainer
      for inst_node_uuid in check_nodes:
1636 1c3231aa Thomas Thrainer
        self._CheckFaultyDisks(inst, inst_node_uuid)
1637 31b836b8 Thomas Thrainer
1638 31b836b8 Thomas Thrainer
  def Exec(self, feedback_fn):
1639 31b836b8 Thomas Thrainer
    feedback_fn("Repairing storage unit '%s' on %s ..." %
1640 31b836b8 Thomas Thrainer
                (self.op.name, self.op.node_name))
1641 31b836b8 Thomas Thrainer
1642 31b836b8 Thomas Thrainer
    st_args = _GetStorageTypeArgs(self.cfg, self.op.storage_type)
1643 1c3231aa Thomas Thrainer
    result = self.rpc.call_storage_execute(self.op.node_uuid,
1644 31b836b8 Thomas Thrainer
                                           self.op.storage_type, st_args,
1645 31b836b8 Thomas Thrainer
                                           self.op.name,
1646 31b836b8 Thomas Thrainer
                                           constants.SO_FIX_CONSISTENCY)
1647 31b836b8 Thomas Thrainer
    result.Raise("Failed to repair storage unit '%s' on %s" %
1648 31b836b8 Thomas Thrainer
                 (self.op.name, self.op.node_name))