Statistics
| Branch: | Tag: | Revision:

root / lib / cmdlib / group.py @ 70b634e6

History | View | Annotate | Download (34.5 kB)

1 f380d53c Thomas Thrainer
#
2 f380d53c Thomas Thrainer
#
3 f380d53c Thomas Thrainer
4 f380d53c Thomas Thrainer
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Google Inc.
5 f380d53c Thomas Thrainer
#
6 f380d53c Thomas Thrainer
# This program is free software; you can redistribute it and/or modify
7 f380d53c Thomas Thrainer
# it under the terms of the GNU General Public License as published by
8 f380d53c Thomas Thrainer
# the Free Software Foundation; either version 2 of the License, or
9 f380d53c Thomas Thrainer
# (at your option) any later version.
10 f380d53c Thomas Thrainer
#
11 f380d53c Thomas Thrainer
# This program is distributed in the hope that it will be useful, but
12 f380d53c Thomas Thrainer
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 f380d53c Thomas Thrainer
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 f380d53c Thomas Thrainer
# General Public License for more details.
15 f380d53c Thomas Thrainer
#
16 f380d53c Thomas Thrainer
# You should have received a copy of the GNU General Public License
17 f380d53c Thomas Thrainer
# along with this program; if not, write to the Free Software
18 f380d53c Thomas Thrainer
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 f380d53c Thomas Thrainer
# 02110-1301, USA.
20 f380d53c Thomas Thrainer
21 f380d53c Thomas Thrainer
22 f380d53c Thomas Thrainer
"""Logical units dealing with node groups."""
23 f380d53c Thomas Thrainer
24 235a6b29 Thomas Thrainer
import itertools
25 f380d53c Thomas Thrainer
import logging
26 f380d53c Thomas Thrainer
27 f380d53c Thomas Thrainer
from ganeti import constants
28 f380d53c Thomas Thrainer
from ganeti import errors
29 f380d53c Thomas Thrainer
from ganeti import locking
30 f380d53c Thomas Thrainer
from ganeti import objects
31 f380d53c Thomas Thrainer
from ganeti import qlang
32 f380d53c Thomas Thrainer
from ganeti import query
33 f380d53c Thomas Thrainer
from ganeti import utils
34 f380d53c Thomas Thrainer
from ganeti.masterd import iallocator
35 5eacbcae Thomas Thrainer
from ganeti.cmdlib.base import LogicalUnit, NoHooksLU, QueryBase, \
36 f380d53c Thomas Thrainer
  ResultWithJobs
37 5eacbcae Thomas Thrainer
from ganeti.cmdlib.common import MergeAndVerifyHvState, \
38 5eacbcae Thomas Thrainer
  MergeAndVerifyDiskState, GetWantedNodes, GetUpdatedParams, \
39 5eacbcae Thomas Thrainer
  CheckNodeGroupInstances, GetUpdatedIPolicy, \
40 5eacbcae Thomas Thrainer
  ComputeNewInstanceViolations, GetDefaultIAllocator, ShareAll, \
41 702243ec Helga Velroyen
  CheckInstancesNodeGroups, LoadNodeEvacResult, MapInstanceLvsToNodes, \
42 294254b1 Raffa Santi
  CheckIpolicyVsDiskTemplates, CheckDiskAccessModeValidity, \
43 294254b1 Raffa Santi
  CheckDiskAccessModeConsistency
44 f380d53c Thomas Thrainer
45 f380d53c Thomas Thrainer
import ganeti.masterd.instance
46 f380d53c Thomas Thrainer
47 f380d53c Thomas Thrainer
48 f380d53c Thomas Thrainer
class LUGroupAdd(LogicalUnit):
49 f380d53c Thomas Thrainer
  """Logical unit for creating node groups.
50 f380d53c Thomas Thrainer

51 f380d53c Thomas Thrainer
  """
52 f380d53c Thomas Thrainer
  HPATH = "group-add"
53 f380d53c Thomas Thrainer
  HTYPE = constants.HTYPE_GROUP
54 f380d53c Thomas Thrainer
  REQ_BGL = False
55 f380d53c Thomas Thrainer
56 f380d53c Thomas Thrainer
  def ExpandNames(self):
57 f380d53c Thomas Thrainer
    # We need the new group's UUID here so that we can create and acquire the
58 f380d53c Thomas Thrainer
    # corresponding lock. Later, in Exec(), we'll indicate to cfg.AddNodeGroup
59 f380d53c Thomas Thrainer
    # that it should not check whether the UUID exists in the configuration.
60 f380d53c Thomas Thrainer
    self.group_uuid = self.cfg.GenerateUniqueID(self.proc.GetECId())
61 f380d53c Thomas Thrainer
    self.needed_locks = {}
62 f380d53c Thomas Thrainer
    self.add_locks[locking.LEVEL_NODEGROUP] = self.group_uuid
63 f380d53c Thomas Thrainer
64 702243ec Helga Velroyen
  def _CheckIpolicy(self):
65 702243ec Helga Velroyen
    """Checks the group's ipolicy for consistency and validity.
66 702243ec Helga Velroyen

67 702243ec Helga Velroyen
    """
68 702243ec Helga Velroyen
    if self.op.ipolicy:
69 702243ec Helga Velroyen
      cluster = self.cfg.GetClusterInfo()
70 702243ec Helga Velroyen
      full_ipolicy = cluster.SimpleFillIPolicy(self.op.ipolicy)
71 702243ec Helga Velroyen
      try:
72 702243ec Helga Velroyen
        objects.InstancePolicy.CheckParameterSyntax(full_ipolicy, False)
73 702243ec Helga Velroyen
      except errors.ConfigurationError, err:
74 702243ec Helga Velroyen
        raise errors.OpPrereqError("Invalid instance policy: %s" % err,
75 702243ec Helga Velroyen
                                   errors.ECODE_INVAL)
76 702243ec Helga Velroyen
      CheckIpolicyVsDiskTemplates(full_ipolicy,
77 702243ec Helga Velroyen
                                  cluster.enabled_disk_templates)
78 702243ec Helga Velroyen
79 f380d53c Thomas Thrainer
  def CheckPrereq(self):
80 f380d53c Thomas Thrainer
    """Check prerequisites.
81 f380d53c Thomas Thrainer

82 f380d53c Thomas Thrainer
    This checks that the given group name is not an existing node group
83 f380d53c Thomas Thrainer
    already.
84 f380d53c Thomas Thrainer

85 f380d53c Thomas Thrainer
    """
86 f380d53c Thomas Thrainer
    try:
87 f380d53c Thomas Thrainer
      existing_uuid = self.cfg.LookupNodeGroup(self.op.group_name)
88 f380d53c Thomas Thrainer
    except errors.OpPrereqError:
89 f380d53c Thomas Thrainer
      pass
90 f380d53c Thomas Thrainer
    else:
91 f380d53c Thomas Thrainer
      raise errors.OpPrereqError("Desired group name '%s' already exists as a"
92 f380d53c Thomas Thrainer
                                 " node group (UUID: %s)" %
93 f380d53c Thomas Thrainer
                                 (self.op.group_name, existing_uuid),
94 f380d53c Thomas Thrainer
                                 errors.ECODE_EXISTS)
95 f380d53c Thomas Thrainer
96 f380d53c Thomas Thrainer
    if self.op.ndparams:
97 f380d53c Thomas Thrainer
      utils.ForceDictType(self.op.ndparams, constants.NDS_PARAMETER_TYPES)
98 f380d53c Thomas Thrainer
99 f380d53c Thomas Thrainer
    if self.op.hv_state:
100 5eacbcae Thomas Thrainer
      self.new_hv_state = MergeAndVerifyHvState(self.op.hv_state, None)
101 f380d53c Thomas Thrainer
    else:
102 f380d53c Thomas Thrainer
      self.new_hv_state = None
103 f380d53c Thomas Thrainer
104 f380d53c Thomas Thrainer
    if self.op.disk_state:
105 5eacbcae Thomas Thrainer
      self.new_disk_state = MergeAndVerifyDiskState(self.op.disk_state, None)
106 f380d53c Thomas Thrainer
    else:
107 f380d53c Thomas Thrainer
      self.new_disk_state = None
108 f380d53c Thomas Thrainer
109 f380d53c Thomas Thrainer
    if self.op.diskparams:
110 f380d53c Thomas Thrainer
      for templ in constants.DISK_TEMPLATES:
111 f380d53c Thomas Thrainer
        if templ in self.op.diskparams:
112 f380d53c Thomas Thrainer
          utils.ForceDictType(self.op.diskparams[templ],
113 f380d53c Thomas Thrainer
                              constants.DISK_DT_TYPES)
114 f380d53c Thomas Thrainer
      self.new_diskparams = self.op.diskparams
115 f380d53c Thomas Thrainer
      try:
116 f380d53c Thomas Thrainer
        utils.VerifyDictOptions(self.new_diskparams, constants.DISK_DT_DEFAULTS)
117 f380d53c Thomas Thrainer
      except errors.OpPrereqError, err:
118 f380d53c Thomas Thrainer
        raise errors.OpPrereqError("While verify diskparams options: %s" % err,
119 f380d53c Thomas Thrainer
                                   errors.ECODE_INVAL)
120 f380d53c Thomas Thrainer
    else:
121 f380d53c Thomas Thrainer
      self.new_diskparams = {}
122 f380d53c Thomas Thrainer
123 702243ec Helga Velroyen
    self._CheckIpolicy()
124 f380d53c Thomas Thrainer
125 f380d53c Thomas Thrainer
  def BuildHooksEnv(self):
126 f380d53c Thomas Thrainer
    """Build hooks env.
127 f380d53c Thomas Thrainer

128 f380d53c Thomas Thrainer
    """
129 f380d53c Thomas Thrainer
    return {
130 f380d53c Thomas Thrainer
      "GROUP_NAME": self.op.group_name,
131 f380d53c Thomas Thrainer
      }
132 f380d53c Thomas Thrainer
133 f380d53c Thomas Thrainer
  def BuildHooksNodes(self):
134 f380d53c Thomas Thrainer
    """Build hooks nodes.
135 f380d53c Thomas Thrainer

136 f380d53c Thomas Thrainer
    """
137 f380d53c Thomas Thrainer
    mn = self.cfg.GetMasterNode()
138 f380d53c Thomas Thrainer
    return ([mn], [mn])
139 f380d53c Thomas Thrainer
140 f380d53c Thomas Thrainer
  def Exec(self, feedback_fn):
141 f380d53c Thomas Thrainer
    """Add the node group to the cluster.
142 f380d53c Thomas Thrainer

143 f380d53c Thomas Thrainer
    """
144 f380d53c Thomas Thrainer
    group_obj = objects.NodeGroup(name=self.op.group_name, members=[],
145 f380d53c Thomas Thrainer
                                  uuid=self.group_uuid,
146 f380d53c Thomas Thrainer
                                  alloc_policy=self.op.alloc_policy,
147 f380d53c Thomas Thrainer
                                  ndparams=self.op.ndparams,
148 f380d53c Thomas Thrainer
                                  diskparams=self.new_diskparams,
149 f380d53c Thomas Thrainer
                                  ipolicy=self.op.ipolicy,
150 f380d53c Thomas Thrainer
                                  hv_state_static=self.new_hv_state,
151 f380d53c Thomas Thrainer
                                  disk_state_static=self.new_disk_state)
152 f380d53c Thomas Thrainer
153 f380d53c Thomas Thrainer
    self.cfg.AddNodeGroup(group_obj, self.proc.GetECId(), check_uuid=False)
154 f380d53c Thomas Thrainer
    del self.remove_locks[locking.LEVEL_NODEGROUP]
155 f380d53c Thomas Thrainer
156 f380d53c Thomas Thrainer
157 f380d53c Thomas Thrainer
class LUGroupAssignNodes(NoHooksLU):
158 f380d53c Thomas Thrainer
  """Logical unit for assigning nodes to groups.
159 f380d53c Thomas Thrainer

160 f380d53c Thomas Thrainer
  """
161 f380d53c Thomas Thrainer
  REQ_BGL = False
162 f380d53c Thomas Thrainer
163 f380d53c Thomas Thrainer
  def ExpandNames(self):
164 f380d53c Thomas Thrainer
    # These raise errors.OpPrereqError on their own:
165 f380d53c Thomas Thrainer
    self.group_uuid = self.cfg.LookupNodeGroup(self.op.group_name)
166 1c3231aa Thomas Thrainer
    (self.op.node_uuids, self.op.nodes) = GetWantedNodes(self, self.op.nodes)
167 f380d53c Thomas Thrainer
168 f380d53c Thomas Thrainer
    # We want to lock all the affected nodes and groups. We have readily
169 f380d53c Thomas Thrainer
    # available the list of nodes, and the *destination* group. To gather the
170 f380d53c Thomas Thrainer
    # list of "source" groups, we need to fetch node information later on.
171 f380d53c Thomas Thrainer
    self.needed_locks = {
172 f380d53c Thomas Thrainer
      locking.LEVEL_NODEGROUP: set([self.group_uuid]),
173 1c3231aa Thomas Thrainer
      locking.LEVEL_NODE: self.op.node_uuids,
174 f380d53c Thomas Thrainer
      }
175 f380d53c Thomas Thrainer
176 f380d53c Thomas Thrainer
  def DeclareLocks(self, level):
177 f380d53c Thomas Thrainer
    if level == locking.LEVEL_NODEGROUP:
178 f380d53c Thomas Thrainer
      assert len(self.needed_locks[locking.LEVEL_NODEGROUP]) == 1
179 f380d53c Thomas Thrainer
180 f380d53c Thomas Thrainer
      # Try to get all affected nodes' groups without having the group or node
181 f380d53c Thomas Thrainer
      # lock yet. Needs verification later in the code flow.
182 1c3231aa Thomas Thrainer
      groups = self.cfg.GetNodeGroupsFromNodes(self.op.node_uuids)
183 f380d53c Thomas Thrainer
184 f380d53c Thomas Thrainer
      self.needed_locks[locking.LEVEL_NODEGROUP].update(groups)
185 f380d53c Thomas Thrainer
186 f380d53c Thomas Thrainer
  def CheckPrereq(self):
187 f380d53c Thomas Thrainer
    """Check prerequisites.
188 f380d53c Thomas Thrainer

189 f380d53c Thomas Thrainer
    """
190 f380d53c Thomas Thrainer
    assert self.needed_locks[locking.LEVEL_NODEGROUP]
191 f380d53c Thomas Thrainer
    assert (frozenset(self.owned_locks(locking.LEVEL_NODE)) ==
192 1c3231aa Thomas Thrainer
            frozenset(self.op.node_uuids))
193 f380d53c Thomas Thrainer
194 f380d53c Thomas Thrainer
    expected_locks = (set([self.group_uuid]) |
195 1c3231aa Thomas Thrainer
                      self.cfg.GetNodeGroupsFromNodes(self.op.node_uuids))
196 f380d53c Thomas Thrainer
    actual_locks = self.owned_locks(locking.LEVEL_NODEGROUP)
197 f380d53c Thomas Thrainer
    if actual_locks != expected_locks:
198 f380d53c Thomas Thrainer
      raise errors.OpExecError("Nodes changed groups since locks were acquired,"
199 f380d53c Thomas Thrainer
                               " current groups are '%s', used to be '%s'" %
200 f380d53c Thomas Thrainer
                               (utils.CommaJoin(expected_locks),
201 f380d53c Thomas Thrainer
                                utils.CommaJoin(actual_locks)))
202 f380d53c Thomas Thrainer
203 f380d53c Thomas Thrainer
    self.node_data = self.cfg.GetAllNodesInfo()
204 f380d53c Thomas Thrainer
    self.group = self.cfg.GetNodeGroup(self.group_uuid)
205 f380d53c Thomas Thrainer
    instance_data = self.cfg.GetAllInstancesInfo()
206 f380d53c Thomas Thrainer
207 f380d53c Thomas Thrainer
    if self.group is None:
208 f380d53c Thomas Thrainer
      raise errors.OpExecError("Could not retrieve group '%s' (UUID: %s)" %
209 f380d53c Thomas Thrainer
                               (self.op.group_name, self.group_uuid))
210 f380d53c Thomas Thrainer
211 f380d53c Thomas Thrainer
    (new_splits, previous_splits) = \
212 1c3231aa Thomas Thrainer
      self.CheckAssignmentForSplitInstances([(uuid, self.group_uuid)
213 1c3231aa Thomas Thrainer
                                             for uuid in self.op.node_uuids],
214 f380d53c Thomas Thrainer
                                            self.node_data, instance_data)
215 f380d53c Thomas Thrainer
216 f380d53c Thomas Thrainer
    if new_splits:
217 da4a52a3 Thomas Thrainer
      fmt_new_splits = utils.CommaJoin(utils.NiceSort(
218 da4a52a3 Thomas Thrainer
                         self.cfg.GetInstanceNames(new_splits)))
219 f380d53c Thomas Thrainer
220 f380d53c Thomas Thrainer
      if not self.op.force:
221 f380d53c Thomas Thrainer
        raise errors.OpExecError("The following instances get split by this"
222 f380d53c Thomas Thrainer
                                 " change and --force was not given: %s" %
223 f380d53c Thomas Thrainer
                                 fmt_new_splits)
224 f380d53c Thomas Thrainer
      else:
225 f380d53c Thomas Thrainer
        self.LogWarning("This operation will split the following instances: %s",
226 f380d53c Thomas Thrainer
                        fmt_new_splits)
227 f380d53c Thomas Thrainer
228 f380d53c Thomas Thrainer
        if previous_splits:
229 f380d53c Thomas Thrainer
          self.LogWarning("In addition, these already-split instances continue"
230 f380d53c Thomas Thrainer
                          " to be split across groups: %s",
231 da4a52a3 Thomas Thrainer
                          utils.CommaJoin(utils.NiceSort(
232 da4a52a3 Thomas Thrainer
                            self.cfg.GetInstanceNames(previous_splits))))
233 f380d53c Thomas Thrainer
234 f380d53c Thomas Thrainer
  def Exec(self, feedback_fn):
235 f380d53c Thomas Thrainer
    """Assign nodes to a new group.
236 f380d53c Thomas Thrainer

237 f380d53c Thomas Thrainer
    """
238 1c3231aa Thomas Thrainer
    mods = [(node_uuid, self.group_uuid) for node_uuid in self.op.node_uuids]
239 f380d53c Thomas Thrainer
240 f380d53c Thomas Thrainer
    self.cfg.AssignGroupNodes(mods)
241 f380d53c Thomas Thrainer
242 f380d53c Thomas Thrainer
  @staticmethod
243 f380d53c Thomas Thrainer
  def CheckAssignmentForSplitInstances(changes, node_data, instance_data):
244 f380d53c Thomas Thrainer
    """Check for split instances after a node assignment.
245 f380d53c Thomas Thrainer

246 f380d53c Thomas Thrainer
    This method considers a series of node assignments as an atomic operation,
247 f380d53c Thomas Thrainer
    and returns information about split instances after applying the set of
248 f380d53c Thomas Thrainer
    changes.
249 f380d53c Thomas Thrainer

250 f380d53c Thomas Thrainer
    In particular, it returns information about newly split instances, and
251 f380d53c Thomas Thrainer
    instances that were already split, and remain so after the change.
252 f380d53c Thomas Thrainer

253 f380d53c Thomas Thrainer
    Only instances whose disk template is listed in constants.DTS_INT_MIRROR are
254 f380d53c Thomas Thrainer
    considered.
255 f380d53c Thomas Thrainer

256 1c3231aa Thomas Thrainer
    @type changes: list of (node_uuid, new_group_uuid) pairs.
257 f380d53c Thomas Thrainer
    @param changes: list of node assignments to consider.
258 f380d53c Thomas Thrainer
    @param node_data: a dict with data for all nodes
259 f380d53c Thomas Thrainer
    @param instance_data: a dict with all instances to consider
260 f380d53c Thomas Thrainer
    @rtype: a two-tuple
261 f380d53c Thomas Thrainer
    @return: a list of instances that were previously okay and result split as a
262 f380d53c Thomas Thrainer
      consequence of this change, and a list of instances that were previously
263 f380d53c Thomas Thrainer
      split and this change does not fix.
264 f380d53c Thomas Thrainer

265 f380d53c Thomas Thrainer
    """
266 1c3231aa Thomas Thrainer
    changed_nodes = dict((uuid, group) for uuid, group in changes
267 1c3231aa Thomas Thrainer
                         if node_data[uuid].group != group)
268 f380d53c Thomas Thrainer
269 f380d53c Thomas Thrainer
    all_split_instances = set()
270 f380d53c Thomas Thrainer
    previously_split_instances = set()
271 f380d53c Thomas Thrainer
272 f380d53c Thomas Thrainer
    for inst in instance_data.values():
273 f380d53c Thomas Thrainer
      if inst.disk_template not in constants.DTS_INT_MIRROR:
274 f380d53c Thomas Thrainer
        continue
275 f380d53c Thomas Thrainer
276 1c3231aa Thomas Thrainer
      if len(set(node_data[node_uuid].group
277 1c3231aa Thomas Thrainer
                 for node_uuid in inst.all_nodes)) > 1:
278 da4a52a3 Thomas Thrainer
        previously_split_instances.add(inst.uuid)
279 f380d53c Thomas Thrainer
280 1c3231aa Thomas Thrainer
      if len(set(changed_nodes.get(node_uuid, node_data[node_uuid].group)
281 1c3231aa Thomas Thrainer
                 for node_uuid in inst.all_nodes)) > 1:
282 da4a52a3 Thomas Thrainer
        all_split_instances.add(inst.uuid)
283 f380d53c Thomas Thrainer
284 f380d53c Thomas Thrainer
    return (list(all_split_instances - previously_split_instances),
285 f380d53c Thomas Thrainer
            list(previously_split_instances & all_split_instances))
286 f380d53c Thomas Thrainer
287 f380d53c Thomas Thrainer
288 5eacbcae Thomas Thrainer
class GroupQuery(QueryBase):
289 f380d53c Thomas Thrainer
  FIELDS = query.GROUP_FIELDS
290 f380d53c Thomas Thrainer
291 f380d53c Thomas Thrainer
  def ExpandNames(self, lu):
292 f380d53c Thomas Thrainer
    lu.needed_locks = {}
293 f380d53c Thomas Thrainer
294 f380d53c Thomas Thrainer
    self._all_groups = lu.cfg.GetAllNodeGroupsInfo()
295 f380d53c Thomas Thrainer
    self._cluster = lu.cfg.GetClusterInfo()
296 f380d53c Thomas Thrainer
    name_to_uuid = dict((g.name, g.uuid) for g in self._all_groups.values())
297 f380d53c Thomas Thrainer
298 f380d53c Thomas Thrainer
    if not self.names:
299 f380d53c Thomas Thrainer
      self.wanted = [name_to_uuid[name]
300 f380d53c Thomas Thrainer
                     for name in utils.NiceSort(name_to_uuid.keys())]
301 f380d53c Thomas Thrainer
    else:
302 f380d53c Thomas Thrainer
      # Accept names to be either names or UUIDs.
303 f380d53c Thomas Thrainer
      missing = []
304 f380d53c Thomas Thrainer
      self.wanted = []
305 f380d53c Thomas Thrainer
      all_uuid = frozenset(self._all_groups.keys())
306 f380d53c Thomas Thrainer
307 f380d53c Thomas Thrainer
      for name in self.names:
308 f380d53c Thomas Thrainer
        if name in all_uuid:
309 f380d53c Thomas Thrainer
          self.wanted.append(name)
310 f380d53c Thomas Thrainer
        elif name in name_to_uuid:
311 f380d53c Thomas Thrainer
          self.wanted.append(name_to_uuid[name])
312 f380d53c Thomas Thrainer
        else:
313 f380d53c Thomas Thrainer
          missing.append(name)
314 f380d53c Thomas Thrainer
315 f380d53c Thomas Thrainer
      if missing:
316 f380d53c Thomas Thrainer
        raise errors.OpPrereqError("Some groups do not exist: %s" %
317 f380d53c Thomas Thrainer
                                   utils.CommaJoin(missing),
318 f380d53c Thomas Thrainer
                                   errors.ECODE_NOENT)
319 f380d53c Thomas Thrainer
320 f380d53c Thomas Thrainer
  def DeclareLocks(self, lu, level):
321 f380d53c Thomas Thrainer
    pass
322 f380d53c Thomas Thrainer
323 f380d53c Thomas Thrainer
  def _GetQueryData(self, lu):
324 f380d53c Thomas Thrainer
    """Computes the list of node groups and their attributes.
325 f380d53c Thomas Thrainer

326 f380d53c Thomas Thrainer
    """
327 f380d53c Thomas Thrainer
    do_nodes = query.GQ_NODE in self.requested_data
328 f380d53c Thomas Thrainer
    do_instances = query.GQ_INST in self.requested_data
329 f380d53c Thomas Thrainer
330 f380d53c Thomas Thrainer
    group_to_nodes = None
331 f380d53c Thomas Thrainer
    group_to_instances = None
332 f380d53c Thomas Thrainer
333 f380d53c Thomas Thrainer
    # For GQ_NODE, we need to map group->[nodes], and group->[instances] for
334 f380d53c Thomas Thrainer
    # GQ_INST. The former is attainable with just GetAllNodesInfo(), but for the
335 f380d53c Thomas Thrainer
    # latter GetAllInstancesInfo() is not enough, for we have to go through
336 f380d53c Thomas Thrainer
    # instance->node. Hence, we will need to process nodes even if we only need
337 f380d53c Thomas Thrainer
    # instance information.
338 f380d53c Thomas Thrainer
    if do_nodes or do_instances:
339 f380d53c Thomas Thrainer
      all_nodes = lu.cfg.GetAllNodesInfo()
340 f380d53c Thomas Thrainer
      group_to_nodes = dict((uuid, []) for uuid in self.wanted)
341 f380d53c Thomas Thrainer
      node_to_group = {}
342 f380d53c Thomas Thrainer
343 f380d53c Thomas Thrainer
      for node in all_nodes.values():
344 f380d53c Thomas Thrainer
        if node.group in group_to_nodes:
345 1c3231aa Thomas Thrainer
          group_to_nodes[node.group].append(node.uuid)
346 1c3231aa Thomas Thrainer
          node_to_group[node.uuid] = node.group
347 f380d53c Thomas Thrainer
348 f380d53c Thomas Thrainer
      if do_instances:
349 f380d53c Thomas Thrainer
        all_instances = lu.cfg.GetAllInstancesInfo()
350 f380d53c Thomas Thrainer
        group_to_instances = dict((uuid, []) for uuid in self.wanted)
351 f380d53c Thomas Thrainer
352 f380d53c Thomas Thrainer
        for instance in all_instances.values():
353 f380d53c Thomas Thrainer
          node = instance.primary_node
354 f380d53c Thomas Thrainer
          if node in node_to_group:
355 da4a52a3 Thomas Thrainer
            group_to_instances[node_to_group[node]].append(instance.uuid)
356 f380d53c Thomas Thrainer
357 f380d53c Thomas Thrainer
        if not do_nodes:
358 f380d53c Thomas Thrainer
          # Do not pass on node information if it was not requested.
359 f380d53c Thomas Thrainer
          group_to_nodes = None
360 f380d53c Thomas Thrainer
361 f380d53c Thomas Thrainer
    return query.GroupQueryData(self._cluster,
362 f380d53c Thomas Thrainer
                                [self._all_groups[uuid]
363 f380d53c Thomas Thrainer
                                 for uuid in self.wanted],
364 f380d53c Thomas Thrainer
                                group_to_nodes, group_to_instances,
365 f380d53c Thomas Thrainer
                                query.GQ_DISKPARAMS in self.requested_data)
366 f380d53c Thomas Thrainer
367 f380d53c Thomas Thrainer
368 f380d53c Thomas Thrainer
class LUGroupQuery(NoHooksLU):
369 f380d53c Thomas Thrainer
  """Logical unit for querying node groups.
370 f380d53c Thomas Thrainer

371 f380d53c Thomas Thrainer
  """
372 f380d53c Thomas Thrainer
  REQ_BGL = False
373 f380d53c Thomas Thrainer
374 f380d53c Thomas Thrainer
  def CheckArguments(self):
375 5eacbcae Thomas Thrainer
    self.gq = GroupQuery(qlang.MakeSimpleFilter("name", self.op.names),
376 f380d53c Thomas Thrainer
                          self.op.output_fields, False)
377 f380d53c Thomas Thrainer
378 f380d53c Thomas Thrainer
  def ExpandNames(self):
379 f380d53c Thomas Thrainer
    self.gq.ExpandNames(self)
380 f380d53c Thomas Thrainer
381 f380d53c Thomas Thrainer
  def DeclareLocks(self, level):
382 f380d53c Thomas Thrainer
    self.gq.DeclareLocks(self, level)
383 f380d53c Thomas Thrainer
384 f380d53c Thomas Thrainer
  def Exec(self, feedback_fn):
385 f380d53c Thomas Thrainer
    return self.gq.OldStyleQuery(self)
386 f380d53c Thomas Thrainer
387 f380d53c Thomas Thrainer
388 f380d53c Thomas Thrainer
class LUGroupSetParams(LogicalUnit):
389 f380d53c Thomas Thrainer
  """Modifies the parameters of a node group.
390 f380d53c Thomas Thrainer

391 f380d53c Thomas Thrainer
  """
392 f380d53c Thomas Thrainer
  HPATH = "group-modify"
393 f380d53c Thomas Thrainer
  HTYPE = constants.HTYPE_GROUP
394 f380d53c Thomas Thrainer
  REQ_BGL = False
395 f380d53c Thomas Thrainer
396 f380d53c Thomas Thrainer
  def CheckArguments(self):
397 f380d53c Thomas Thrainer
    all_changes = [
398 f380d53c Thomas Thrainer
      self.op.ndparams,
399 f380d53c Thomas Thrainer
      self.op.diskparams,
400 f380d53c Thomas Thrainer
      self.op.alloc_policy,
401 f380d53c Thomas Thrainer
      self.op.hv_state,
402 f380d53c Thomas Thrainer
      self.op.disk_state,
403 f380d53c Thomas Thrainer
      self.op.ipolicy,
404 f380d53c Thomas Thrainer
      ]
405 f380d53c Thomas Thrainer
406 f380d53c Thomas Thrainer
    if all_changes.count(None) == len(all_changes):
407 f380d53c Thomas Thrainer
      raise errors.OpPrereqError("Please pass at least one modification",
408 f380d53c Thomas Thrainer
                                 errors.ECODE_INVAL)
409 f380d53c Thomas Thrainer
410 294254b1 Raffa Santi
    if self.op.diskparams:
411 294254b1 Raffa Santi
      CheckDiskAccessModeValidity(self.op.diskparams)
412 294254b1 Raffa Santi
413 f380d53c Thomas Thrainer
  def ExpandNames(self):
414 f380d53c Thomas Thrainer
    # This raises errors.OpPrereqError on its own:
415 f380d53c Thomas Thrainer
    self.group_uuid = self.cfg.LookupNodeGroup(self.op.group_name)
416 f380d53c Thomas Thrainer
417 f380d53c Thomas Thrainer
    self.needed_locks = {
418 f380d53c Thomas Thrainer
      locking.LEVEL_INSTANCE: [],
419 f380d53c Thomas Thrainer
      locking.LEVEL_NODEGROUP: [self.group_uuid],
420 f380d53c Thomas Thrainer
      }
421 f380d53c Thomas Thrainer
422 f380d53c Thomas Thrainer
    self.share_locks[locking.LEVEL_INSTANCE] = 1
423 f380d53c Thomas Thrainer
424 f380d53c Thomas Thrainer
  def DeclareLocks(self, level):
425 f380d53c Thomas Thrainer
    if level == locking.LEVEL_INSTANCE:
426 f380d53c Thomas Thrainer
      assert not self.needed_locks[locking.LEVEL_INSTANCE]
427 f380d53c Thomas Thrainer
428 f380d53c Thomas Thrainer
      # Lock instances optimistically, needs verification once group lock has
429 f380d53c Thomas Thrainer
      # been acquired
430 f380d53c Thomas Thrainer
      self.needed_locks[locking.LEVEL_INSTANCE] = \
431 da4a52a3 Thomas Thrainer
        self.cfg.GetInstanceNames(
432 da4a52a3 Thomas Thrainer
          self.cfg.GetNodeGroupInstances(self.group_uuid))
433 f380d53c Thomas Thrainer
434 f380d53c Thomas Thrainer
  @staticmethod
435 f380d53c Thomas Thrainer
  def _UpdateAndVerifyDiskParams(old, new):
436 f380d53c Thomas Thrainer
    """Updates and verifies disk parameters.
437 f380d53c Thomas Thrainer

438 f380d53c Thomas Thrainer
    """
439 5eacbcae Thomas Thrainer
    new_params = GetUpdatedParams(old, new)
440 f380d53c Thomas Thrainer
    utils.ForceDictType(new_params, constants.DISK_DT_TYPES)
441 f380d53c Thomas Thrainer
    return new_params
442 f380d53c Thomas Thrainer
443 702243ec Helga Velroyen
  def _CheckIpolicy(self, cluster, owned_instance_names):
444 702243ec Helga Velroyen
    """Sanity checks for the ipolicy.
445 702243ec Helga Velroyen

446 702243ec Helga Velroyen
    @type cluster: C{objects.Cluster}
447 702243ec Helga Velroyen
    @param cluster: the cluster's configuration
448 702243ec Helga Velroyen
    @type owned_instance_names: list of string
449 702243ec Helga Velroyen
    @param owned_instance_names: list of instances
450 702243ec Helga Velroyen

451 702243ec Helga Velroyen
    """
452 702243ec Helga Velroyen
    if self.op.ipolicy:
453 702243ec Helga Velroyen
      self.new_ipolicy = GetUpdatedIPolicy(self.group.ipolicy,
454 702243ec Helga Velroyen
                                           self.op.ipolicy,
455 702243ec Helga Velroyen
                                           group_policy=True)
456 702243ec Helga Velroyen
457 702243ec Helga Velroyen
      new_ipolicy = cluster.SimpleFillIPolicy(self.new_ipolicy)
458 702243ec Helga Velroyen
      CheckIpolicyVsDiskTemplates(new_ipolicy,
459 702243ec Helga Velroyen
                                  cluster.enabled_disk_templates)
460 bbe0f264 Thomas Thrainer
      instances = \
461 bbe0f264 Thomas Thrainer
        dict(self.cfg.GetMultiInstanceInfoByName(owned_instance_names))
462 702243ec Helga Velroyen
      gmi = ganeti.masterd.instance
463 702243ec Helga Velroyen
      violations = \
464 702243ec Helga Velroyen
          ComputeNewInstanceViolations(gmi.CalculateGroupIPolicy(cluster,
465 702243ec Helga Velroyen
                                                                 self.group),
466 bbe0f264 Thomas Thrainer
                                       new_ipolicy, instances.values(),
467 bbe0f264 Thomas Thrainer
                                       self.cfg)
468 702243ec Helga Velroyen
469 702243ec Helga Velroyen
      if violations:
470 702243ec Helga Velroyen
        self.LogWarning("After the ipolicy change the following instances"
471 702243ec Helga Velroyen
                        " violate them: %s",
472 702243ec Helga Velroyen
                        utils.CommaJoin(violations))
473 702243ec Helga Velroyen
474 f380d53c Thomas Thrainer
  def CheckPrereq(self):
475 f380d53c Thomas Thrainer
    """Check prerequisites.
476 f380d53c Thomas Thrainer

477 f380d53c Thomas Thrainer
    """
478 da4a52a3 Thomas Thrainer
    owned_instance_names = frozenset(self.owned_locks(locking.LEVEL_INSTANCE))
479 f380d53c Thomas Thrainer
480 f380d53c Thomas Thrainer
    # Check if locked instances are still correct
481 da4a52a3 Thomas Thrainer
    CheckNodeGroupInstances(self.cfg, self.group_uuid, owned_instance_names)
482 f380d53c Thomas Thrainer
483 f380d53c Thomas Thrainer
    self.group = self.cfg.GetNodeGroup(self.group_uuid)
484 f380d53c Thomas Thrainer
    cluster = self.cfg.GetClusterInfo()
485 f380d53c Thomas Thrainer
486 f380d53c Thomas Thrainer
    if self.group is None:
487 f380d53c Thomas Thrainer
      raise errors.OpExecError("Could not retrieve group '%s' (UUID: %s)" %
488 f380d53c Thomas Thrainer
                               (self.op.group_name, self.group_uuid))
489 f380d53c Thomas Thrainer
490 f380d53c Thomas Thrainer
    if self.op.ndparams:
491 5eacbcae Thomas Thrainer
      new_ndparams = GetUpdatedParams(self.group.ndparams, self.op.ndparams)
492 f380d53c Thomas Thrainer
      utils.ForceDictType(new_ndparams, constants.NDS_PARAMETER_TYPES)
493 f380d53c Thomas Thrainer
      self.new_ndparams = new_ndparams
494 f380d53c Thomas Thrainer
495 f380d53c Thomas Thrainer
    if self.op.diskparams:
496 f380d53c Thomas Thrainer
      diskparams = self.group.diskparams
497 f380d53c Thomas Thrainer
      uavdp = self._UpdateAndVerifyDiskParams
498 f380d53c Thomas Thrainer
      # For each disktemplate subdict update and verify the values
499 f380d53c Thomas Thrainer
      new_diskparams = dict((dt,
500 f380d53c Thomas Thrainer
                             uavdp(diskparams.get(dt, {}),
501 f380d53c Thomas Thrainer
                                   self.op.diskparams[dt]))
502 f380d53c Thomas Thrainer
                            for dt in constants.DISK_TEMPLATES
503 f380d53c Thomas Thrainer
                            if dt in self.op.diskparams)
504 f380d53c Thomas Thrainer
      # As we've all subdicts of diskparams ready, lets merge the actual
505 f380d53c Thomas Thrainer
      # dict with all updated subdicts
506 f380d53c Thomas Thrainer
      self.new_diskparams = objects.FillDict(diskparams, new_diskparams)
507 294254b1 Raffa Santi
508 f380d53c Thomas Thrainer
      try:
509 f380d53c Thomas Thrainer
        utils.VerifyDictOptions(self.new_diskparams, constants.DISK_DT_DEFAULTS)
510 294254b1 Raffa Santi
        CheckDiskAccessModeConsistency(self.new_diskparams, self.cfg,
511 294254b1 Raffa Santi
                                       group=self.group)
512 f380d53c Thomas Thrainer
      except errors.OpPrereqError, err:
513 f380d53c Thomas Thrainer
        raise errors.OpPrereqError("While verify diskparams options: %s" % err,
514 f380d53c Thomas Thrainer
                                   errors.ECODE_INVAL)
515 f380d53c Thomas Thrainer
516 f380d53c Thomas Thrainer
    if self.op.hv_state:
517 5eacbcae Thomas Thrainer
      self.new_hv_state = MergeAndVerifyHvState(self.op.hv_state,
518 5eacbcae Thomas Thrainer
                                                self.group.hv_state_static)
519 f380d53c Thomas Thrainer
520 f380d53c Thomas Thrainer
    if self.op.disk_state:
521 f380d53c Thomas Thrainer
      self.new_disk_state = \
522 5eacbcae Thomas Thrainer
        MergeAndVerifyDiskState(self.op.disk_state,
523 5eacbcae Thomas Thrainer
                                self.group.disk_state_static)
524 f380d53c Thomas Thrainer
525 702243ec Helga Velroyen
    self._CheckIpolicy(cluster, owned_instance_names)
526 f380d53c Thomas Thrainer
527 f380d53c Thomas Thrainer
  def BuildHooksEnv(self):
528 f380d53c Thomas Thrainer
    """Build hooks env.
529 f380d53c Thomas Thrainer

530 f380d53c Thomas Thrainer
    """
531 f380d53c Thomas Thrainer
    return {
532 f380d53c Thomas Thrainer
      "GROUP_NAME": self.op.group_name,
533 f380d53c Thomas Thrainer
      "NEW_ALLOC_POLICY": self.op.alloc_policy,
534 f380d53c Thomas Thrainer
      }
535 f380d53c Thomas Thrainer
536 f380d53c Thomas Thrainer
  def BuildHooksNodes(self):
537 f380d53c Thomas Thrainer
    """Build hooks nodes.
538 f380d53c Thomas Thrainer

539 f380d53c Thomas Thrainer
    """
540 f380d53c Thomas Thrainer
    mn = self.cfg.GetMasterNode()
541 f380d53c Thomas Thrainer
    return ([mn], [mn])
542 f380d53c Thomas Thrainer
543 f380d53c Thomas Thrainer
  def Exec(self, feedback_fn):
544 f380d53c Thomas Thrainer
    """Modifies the node group.
545 f380d53c Thomas Thrainer

546 f380d53c Thomas Thrainer
    """
547 f380d53c Thomas Thrainer
    result = []
548 f380d53c Thomas Thrainer
549 f380d53c Thomas Thrainer
    if self.op.ndparams:
550 f380d53c Thomas Thrainer
      self.group.ndparams = self.new_ndparams
551 f380d53c Thomas Thrainer
      result.append(("ndparams", str(self.group.ndparams)))
552 f380d53c Thomas Thrainer
553 f380d53c Thomas Thrainer
    if self.op.diskparams:
554 f380d53c Thomas Thrainer
      self.group.diskparams = self.new_diskparams
555 f380d53c Thomas Thrainer
      result.append(("diskparams", str(self.group.diskparams)))
556 f380d53c Thomas Thrainer
557 f380d53c Thomas Thrainer
    if self.op.alloc_policy:
558 f380d53c Thomas Thrainer
      self.group.alloc_policy = self.op.alloc_policy
559 f380d53c Thomas Thrainer
560 f380d53c Thomas Thrainer
    if self.op.hv_state:
561 f380d53c Thomas Thrainer
      self.group.hv_state_static = self.new_hv_state
562 f380d53c Thomas Thrainer
563 f380d53c Thomas Thrainer
    if self.op.disk_state:
564 f380d53c Thomas Thrainer
      self.group.disk_state_static = self.new_disk_state
565 f380d53c Thomas Thrainer
566 f380d53c Thomas Thrainer
    if self.op.ipolicy:
567 f380d53c Thomas Thrainer
      self.group.ipolicy = self.new_ipolicy
568 f380d53c Thomas Thrainer
569 f380d53c Thomas Thrainer
    self.cfg.Update(self.group, feedback_fn)
570 f380d53c Thomas Thrainer
    return result
571 f380d53c Thomas Thrainer
572 f380d53c Thomas Thrainer
573 f380d53c Thomas Thrainer
class LUGroupRemove(LogicalUnit):
574 f380d53c Thomas Thrainer
  HPATH = "group-remove"
575 f380d53c Thomas Thrainer
  HTYPE = constants.HTYPE_GROUP
576 f380d53c Thomas Thrainer
  REQ_BGL = False
577 f380d53c Thomas Thrainer
578 f380d53c Thomas Thrainer
  def ExpandNames(self):
579 f380d53c Thomas Thrainer
    # This will raises errors.OpPrereqError on its own:
580 f380d53c Thomas Thrainer
    self.group_uuid = self.cfg.LookupNodeGroup(self.op.group_name)
581 f380d53c Thomas Thrainer
    self.needed_locks = {
582 f380d53c Thomas Thrainer
      locking.LEVEL_NODEGROUP: [self.group_uuid],
583 f380d53c Thomas Thrainer
      }
584 f380d53c Thomas Thrainer
585 f380d53c Thomas Thrainer
  def CheckPrereq(self):
586 f380d53c Thomas Thrainer
    """Check prerequisites.
587 f380d53c Thomas Thrainer

588 f380d53c Thomas Thrainer
    This checks that the given group name exists as a node group, that is
589 f380d53c Thomas Thrainer
    empty (i.e., contains no nodes), and that is not the last group of the
590 f380d53c Thomas Thrainer
    cluster.
591 f380d53c Thomas Thrainer

592 f380d53c Thomas Thrainer
    """
593 f380d53c Thomas Thrainer
    # Verify that the group is empty.
594 1c3231aa Thomas Thrainer
    group_nodes = [node.uuid
595 f380d53c Thomas Thrainer
                   for node in self.cfg.GetAllNodesInfo().values()
596 f380d53c Thomas Thrainer
                   if node.group == self.group_uuid]
597 f380d53c Thomas Thrainer
598 f380d53c Thomas Thrainer
    if group_nodes:
599 f380d53c Thomas Thrainer
      raise errors.OpPrereqError("Group '%s' not empty, has the following"
600 f380d53c Thomas Thrainer
                                 " nodes: %s" %
601 f380d53c Thomas Thrainer
                                 (self.op.group_name,
602 f380d53c Thomas Thrainer
                                  utils.CommaJoin(utils.NiceSort(group_nodes))),
603 f380d53c Thomas Thrainer
                                 errors.ECODE_STATE)
604 f380d53c Thomas Thrainer
605 f380d53c Thomas Thrainer
    # Verify the cluster would not be left group-less.
606 f380d53c Thomas Thrainer
    if len(self.cfg.GetNodeGroupList()) == 1:
607 f380d53c Thomas Thrainer
      raise errors.OpPrereqError("Group '%s' is the only group, cannot be"
608 f380d53c Thomas Thrainer
                                 " removed" % self.op.group_name,
609 f380d53c Thomas Thrainer
                                 errors.ECODE_STATE)
610 f380d53c Thomas Thrainer
611 f380d53c Thomas Thrainer
  def BuildHooksEnv(self):
612 f380d53c Thomas Thrainer
    """Build hooks env.
613 f380d53c Thomas Thrainer

614 f380d53c Thomas Thrainer
    """
615 f380d53c Thomas Thrainer
    return {
616 f380d53c Thomas Thrainer
      "GROUP_NAME": self.op.group_name,
617 f380d53c Thomas Thrainer
      }
618 f380d53c Thomas Thrainer
619 f380d53c Thomas Thrainer
  def BuildHooksNodes(self):
620 f380d53c Thomas Thrainer
    """Build hooks nodes.
621 f380d53c Thomas Thrainer

622 f380d53c Thomas Thrainer
    """
623 f380d53c Thomas Thrainer
    mn = self.cfg.GetMasterNode()
624 f380d53c Thomas Thrainer
    return ([mn], [mn])
625 f380d53c Thomas Thrainer
626 f380d53c Thomas Thrainer
  def Exec(self, feedback_fn):
627 f380d53c Thomas Thrainer
    """Remove the node group.
628 f380d53c Thomas Thrainer

629 f380d53c Thomas Thrainer
    """
630 f380d53c Thomas Thrainer
    try:
631 f380d53c Thomas Thrainer
      self.cfg.RemoveNodeGroup(self.group_uuid)
632 f380d53c Thomas Thrainer
    except errors.ConfigurationError:
633 f380d53c Thomas Thrainer
      raise errors.OpExecError("Group '%s' with UUID %s disappeared" %
634 f380d53c Thomas Thrainer
                               (self.op.group_name, self.group_uuid))
635 f380d53c Thomas Thrainer
636 f380d53c Thomas Thrainer
    self.remove_locks[locking.LEVEL_NODEGROUP] = self.group_uuid
637 f380d53c Thomas Thrainer
638 f380d53c Thomas Thrainer
639 f380d53c Thomas Thrainer
class LUGroupRename(LogicalUnit):
640 f380d53c Thomas Thrainer
  HPATH = "group-rename"
641 f380d53c Thomas Thrainer
  HTYPE = constants.HTYPE_GROUP
642 f380d53c Thomas Thrainer
  REQ_BGL = False
643 f380d53c Thomas Thrainer
644 f380d53c Thomas Thrainer
  def ExpandNames(self):
645 f380d53c Thomas Thrainer
    # This raises errors.OpPrereqError on its own:
646 f380d53c Thomas Thrainer
    self.group_uuid = self.cfg.LookupNodeGroup(self.op.group_name)
647 f380d53c Thomas Thrainer
648 f380d53c Thomas Thrainer
    self.needed_locks = {
649 f380d53c Thomas Thrainer
      locking.LEVEL_NODEGROUP: [self.group_uuid],
650 f380d53c Thomas Thrainer
      }
651 f380d53c Thomas Thrainer
652 f380d53c Thomas Thrainer
  def CheckPrereq(self):
653 f380d53c Thomas Thrainer
    """Check prerequisites.
654 f380d53c Thomas Thrainer

655 f380d53c Thomas Thrainer
    Ensures requested new name is not yet used.
656 f380d53c Thomas Thrainer

657 f380d53c Thomas Thrainer
    """
658 f380d53c Thomas Thrainer
    try:
659 f380d53c Thomas Thrainer
      new_name_uuid = self.cfg.LookupNodeGroup(self.op.new_name)
660 f380d53c Thomas Thrainer
    except errors.OpPrereqError:
661 f380d53c Thomas Thrainer
      pass
662 f380d53c Thomas Thrainer
    else:
663 f380d53c Thomas Thrainer
      raise errors.OpPrereqError("Desired new name '%s' clashes with existing"
664 f380d53c Thomas Thrainer
                                 " node group (UUID: %s)" %
665 f380d53c Thomas Thrainer
                                 (self.op.new_name, new_name_uuid),
666 f380d53c Thomas Thrainer
                                 errors.ECODE_EXISTS)
667 f380d53c Thomas Thrainer
668 f380d53c Thomas Thrainer
  def BuildHooksEnv(self):
669 f380d53c Thomas Thrainer
    """Build hooks env.
670 f380d53c Thomas Thrainer

671 f380d53c Thomas Thrainer
    """
672 f380d53c Thomas Thrainer
    return {
673 f380d53c Thomas Thrainer
      "OLD_NAME": self.op.group_name,
674 f380d53c Thomas Thrainer
      "NEW_NAME": self.op.new_name,
675 f380d53c Thomas Thrainer
      }
676 f380d53c Thomas Thrainer
677 f380d53c Thomas Thrainer
  def BuildHooksNodes(self):
678 f380d53c Thomas Thrainer
    """Build hooks nodes.
679 f380d53c Thomas Thrainer

680 f380d53c Thomas Thrainer
    """
681 f380d53c Thomas Thrainer
    mn = self.cfg.GetMasterNode()
682 f380d53c Thomas Thrainer
683 f380d53c Thomas Thrainer
    all_nodes = self.cfg.GetAllNodesInfo()
684 f380d53c Thomas Thrainer
    all_nodes.pop(mn, None)
685 f380d53c Thomas Thrainer
686 f380d53c Thomas Thrainer
    run_nodes = [mn]
687 1c3231aa Thomas Thrainer
    run_nodes.extend(node.uuid for node in all_nodes.values()
688 f380d53c Thomas Thrainer
                     if node.group == self.group_uuid)
689 f380d53c Thomas Thrainer
690 f380d53c Thomas Thrainer
    return (run_nodes, run_nodes)
691 f380d53c Thomas Thrainer
692 f380d53c Thomas Thrainer
  def Exec(self, feedback_fn):
693 f380d53c Thomas Thrainer
    """Rename the node group.
694 f380d53c Thomas Thrainer

695 f380d53c Thomas Thrainer
    """
696 f380d53c Thomas Thrainer
    group = self.cfg.GetNodeGroup(self.group_uuid)
697 f380d53c Thomas Thrainer
698 f380d53c Thomas Thrainer
    if group is None:
699 f380d53c Thomas Thrainer
      raise errors.OpExecError("Could not retrieve group '%s' (UUID: %s)" %
700 f380d53c Thomas Thrainer
                               (self.op.group_name, self.group_uuid))
701 f380d53c Thomas Thrainer
702 f380d53c Thomas Thrainer
    group.name = self.op.new_name
703 f380d53c Thomas Thrainer
    self.cfg.Update(group, feedback_fn)
704 f380d53c Thomas Thrainer
705 f380d53c Thomas Thrainer
    return self.op.new_name
706 f380d53c Thomas Thrainer
707 f380d53c Thomas Thrainer
708 f380d53c Thomas Thrainer
class LUGroupEvacuate(LogicalUnit):
709 f380d53c Thomas Thrainer
  HPATH = "group-evacuate"
710 f380d53c Thomas Thrainer
  HTYPE = constants.HTYPE_GROUP
711 f380d53c Thomas Thrainer
  REQ_BGL = False
712 f380d53c Thomas Thrainer
713 f380d53c Thomas Thrainer
  def ExpandNames(self):
714 f380d53c Thomas Thrainer
    # This raises errors.OpPrereqError on its own:
715 f380d53c Thomas Thrainer
    self.group_uuid = self.cfg.LookupNodeGroup(self.op.group_name)
716 f380d53c Thomas Thrainer
717 f380d53c Thomas Thrainer
    if self.op.target_groups:
718 f380d53c Thomas Thrainer
      self.req_target_uuids = map(self.cfg.LookupNodeGroup,
719 f380d53c Thomas Thrainer
                                  self.op.target_groups)
720 f380d53c Thomas Thrainer
    else:
721 f380d53c Thomas Thrainer
      self.req_target_uuids = []
722 f380d53c Thomas Thrainer
723 f380d53c Thomas Thrainer
    if self.group_uuid in self.req_target_uuids:
724 f380d53c Thomas Thrainer
      raise errors.OpPrereqError("Group to be evacuated (%s) can not be used"
725 f380d53c Thomas Thrainer
                                 " as a target group (targets are %s)" %
726 f380d53c Thomas Thrainer
                                 (self.group_uuid,
727 f380d53c Thomas Thrainer
                                  utils.CommaJoin(self.req_target_uuids)),
728 f380d53c Thomas Thrainer
                                 errors.ECODE_INVAL)
729 f380d53c Thomas Thrainer
730 5eacbcae Thomas Thrainer
    self.op.iallocator = GetDefaultIAllocator(self.cfg, self.op.iallocator)
731 f380d53c Thomas Thrainer
732 5eacbcae Thomas Thrainer
    self.share_locks = ShareAll()
733 f380d53c Thomas Thrainer
    self.needed_locks = {
734 f380d53c Thomas Thrainer
      locking.LEVEL_INSTANCE: [],
735 f380d53c Thomas Thrainer
      locking.LEVEL_NODEGROUP: [],
736 f380d53c Thomas Thrainer
      locking.LEVEL_NODE: [],
737 f380d53c Thomas Thrainer
      }
738 f380d53c Thomas Thrainer
739 f380d53c Thomas Thrainer
  def DeclareLocks(self, level):
740 f380d53c Thomas Thrainer
    if level == locking.LEVEL_INSTANCE:
741 f380d53c Thomas Thrainer
      assert not self.needed_locks[locking.LEVEL_INSTANCE]
742 f380d53c Thomas Thrainer
743 f380d53c Thomas Thrainer
      # Lock instances optimistically, needs verification once node and group
744 f380d53c Thomas Thrainer
      # locks have been acquired
745 f380d53c Thomas Thrainer
      self.needed_locks[locking.LEVEL_INSTANCE] = \
746 da4a52a3 Thomas Thrainer
        self.cfg.GetInstanceNames(
747 da4a52a3 Thomas Thrainer
          self.cfg.GetNodeGroupInstances(self.group_uuid))
748 f380d53c Thomas Thrainer
749 f380d53c Thomas Thrainer
    elif level == locking.LEVEL_NODEGROUP:
750 f380d53c Thomas Thrainer
      assert not self.needed_locks[locking.LEVEL_NODEGROUP]
751 f380d53c Thomas Thrainer
752 f380d53c Thomas Thrainer
      if self.req_target_uuids:
753 f380d53c Thomas Thrainer
        lock_groups = set([self.group_uuid] + self.req_target_uuids)
754 f380d53c Thomas Thrainer
755 f380d53c Thomas Thrainer
        # Lock all groups used by instances optimistically; this requires going
756 f380d53c Thomas Thrainer
        # via the node before it's locked, requiring verification later on
757 f380d53c Thomas Thrainer
        lock_groups.update(group_uuid
758 f380d53c Thomas Thrainer
                           for instance_name in
759 f380d53c Thomas Thrainer
                             self.owned_locks(locking.LEVEL_INSTANCE)
760 f380d53c Thomas Thrainer
                           for group_uuid in
761 da4a52a3 Thomas Thrainer
                             self.cfg.GetInstanceNodeGroups(
762 da4a52a3 Thomas Thrainer
                               self.cfg.GetInstanceInfoByName(instance_name)
763 da4a52a3 Thomas Thrainer
                                 .uuid))
764 f380d53c Thomas Thrainer
      else:
765 f380d53c Thomas Thrainer
        # No target groups, need to lock all of them
766 f380d53c Thomas Thrainer
        lock_groups = locking.ALL_SET
767 f380d53c Thomas Thrainer
768 f380d53c Thomas Thrainer
      self.needed_locks[locking.LEVEL_NODEGROUP] = lock_groups
769 f380d53c Thomas Thrainer
770 f380d53c Thomas Thrainer
    elif level == locking.LEVEL_NODE:
771 f380d53c Thomas Thrainer
      # This will only lock the nodes in the group to be evacuated which
772 f380d53c Thomas Thrainer
      # contain actual instances
773 f380d53c Thomas Thrainer
      self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_APPEND
774 f380d53c Thomas Thrainer
      self._LockInstancesNodes()
775 f380d53c Thomas Thrainer
776 f380d53c Thomas Thrainer
      # Lock all nodes in group to be evacuated and target groups
777 f380d53c Thomas Thrainer
      owned_groups = frozenset(self.owned_locks(locking.LEVEL_NODEGROUP))
778 f380d53c Thomas Thrainer
      assert self.group_uuid in owned_groups
779 1c3231aa Thomas Thrainer
      member_node_uuids = [node_uuid
780 1c3231aa Thomas Thrainer
                           for group in owned_groups
781 1c3231aa Thomas Thrainer
                           for node_uuid in
782 1c3231aa Thomas Thrainer
                             self.cfg.GetNodeGroup(group).members]
783 1c3231aa Thomas Thrainer
      self.needed_locks[locking.LEVEL_NODE].extend(member_node_uuids)
784 f380d53c Thomas Thrainer
785 f380d53c Thomas Thrainer
  def CheckPrereq(self):
786 da4a52a3 Thomas Thrainer
    owned_instance_names = frozenset(self.owned_locks(locking.LEVEL_INSTANCE))
787 f380d53c Thomas Thrainer
    owned_groups = frozenset(self.owned_locks(locking.LEVEL_NODEGROUP))
788 1c3231aa Thomas Thrainer
    owned_node_uuids = frozenset(self.owned_locks(locking.LEVEL_NODE))
789 f380d53c Thomas Thrainer
790 f380d53c Thomas Thrainer
    assert owned_groups.issuperset(self.req_target_uuids)
791 f380d53c Thomas Thrainer
    assert self.group_uuid in owned_groups
792 f380d53c Thomas Thrainer
793 f380d53c Thomas Thrainer
    # Check if locked instances are still correct
794 da4a52a3 Thomas Thrainer
    CheckNodeGroupInstances(self.cfg, self.group_uuid, owned_instance_names)
795 f380d53c Thomas Thrainer
796 f380d53c Thomas Thrainer
    # Get instance information
797 da4a52a3 Thomas Thrainer
    self.instances = \
798 da4a52a3 Thomas Thrainer
      dict(self.cfg.GetMultiInstanceInfoByName(owned_instance_names))
799 f380d53c Thomas Thrainer
800 f380d53c Thomas Thrainer
    # Check if node groups for locked instances are still correct
801 5eacbcae Thomas Thrainer
    CheckInstancesNodeGroups(self.cfg, self.instances,
802 1c3231aa Thomas Thrainer
                             owned_groups, owned_node_uuids, self.group_uuid)
803 f380d53c Thomas Thrainer
804 f380d53c Thomas Thrainer
    if self.req_target_uuids:
805 f380d53c Thomas Thrainer
      # User requested specific target groups
806 f380d53c Thomas Thrainer
      self.target_uuids = self.req_target_uuids
807 f380d53c Thomas Thrainer
    else:
808 f380d53c Thomas Thrainer
      # All groups except the one to be evacuated are potential targets
809 f380d53c Thomas Thrainer
      self.target_uuids = [group_uuid for group_uuid in owned_groups
810 f380d53c Thomas Thrainer
                           if group_uuid != self.group_uuid]
811 f380d53c Thomas Thrainer
812 f380d53c Thomas Thrainer
      if not self.target_uuids:
813 f380d53c Thomas Thrainer
        raise errors.OpPrereqError("There are no possible target groups",
814 f380d53c Thomas Thrainer
                                   errors.ECODE_INVAL)
815 f380d53c Thomas Thrainer
816 f380d53c Thomas Thrainer
  def BuildHooksEnv(self):
817 f380d53c Thomas Thrainer
    """Build hooks env.
818 f380d53c Thomas Thrainer

819 f380d53c Thomas Thrainer
    """
820 f380d53c Thomas Thrainer
    return {
821 f380d53c Thomas Thrainer
      "GROUP_NAME": self.op.group_name,
822 f380d53c Thomas Thrainer
      "TARGET_GROUPS": " ".join(self.target_uuids),
823 f380d53c Thomas Thrainer
      }
824 f380d53c Thomas Thrainer
825 f380d53c Thomas Thrainer
  def BuildHooksNodes(self):
826 f380d53c Thomas Thrainer
    """Build hooks nodes.
827 f380d53c Thomas Thrainer

828 f380d53c Thomas Thrainer
    """
829 f380d53c Thomas Thrainer
    mn = self.cfg.GetMasterNode()
830 f380d53c Thomas Thrainer
831 f380d53c Thomas Thrainer
    assert self.group_uuid in self.owned_locks(locking.LEVEL_NODEGROUP)
832 f380d53c Thomas Thrainer
833 f380d53c Thomas Thrainer
    run_nodes = [mn] + self.cfg.GetNodeGroup(self.group_uuid).members
834 f380d53c Thomas Thrainer
835 f380d53c Thomas Thrainer
    return (run_nodes, run_nodes)
836 f380d53c Thomas Thrainer
837 f380d53c Thomas Thrainer
  def Exec(self, feedback_fn):
838 da4a52a3 Thomas Thrainer
    inst_names = list(self.owned_locks(locking.LEVEL_INSTANCE))
839 f380d53c Thomas Thrainer
840 f380d53c Thomas Thrainer
    assert self.group_uuid not in self.target_uuids
841 f380d53c Thomas Thrainer
842 da4a52a3 Thomas Thrainer
    req = iallocator.IAReqGroupChange(instances=inst_names,
843 f380d53c Thomas Thrainer
                                      target_groups=self.target_uuids)
844 f380d53c Thomas Thrainer
    ial = iallocator.IAllocator(self.cfg, self.rpc, req)
845 f380d53c Thomas Thrainer
846 f380d53c Thomas Thrainer
    ial.Run(self.op.iallocator)
847 f380d53c Thomas Thrainer
848 f380d53c Thomas Thrainer
    if not ial.success:
849 f380d53c Thomas Thrainer
      raise errors.OpPrereqError("Can't compute group evacuation using"
850 f380d53c Thomas Thrainer
                                 " iallocator '%s': %s" %
851 f380d53c Thomas Thrainer
                                 (self.op.iallocator, ial.info),
852 f380d53c Thomas Thrainer
                                 errors.ECODE_NORES)
853 f380d53c Thomas Thrainer
854 5eacbcae Thomas Thrainer
    jobs = LoadNodeEvacResult(self, ial.result, self.op.early_release, False)
855 f380d53c Thomas Thrainer
856 f380d53c Thomas Thrainer
    self.LogInfo("Iallocator returned %s job(s) for evacuating node group %s",
857 f380d53c Thomas Thrainer
                 len(jobs), self.op.group_name)
858 f380d53c Thomas Thrainer
859 f380d53c Thomas Thrainer
    return ResultWithJobs(jobs)
860 f380d53c Thomas Thrainer
861 f380d53c Thomas Thrainer
862 f380d53c Thomas Thrainer
class LUGroupVerifyDisks(NoHooksLU):
863 f380d53c Thomas Thrainer
  """Verifies the status of all disks in a node group.
864 f380d53c Thomas Thrainer

865 f380d53c Thomas Thrainer
  """
866 f380d53c Thomas Thrainer
  REQ_BGL = False
867 f380d53c Thomas Thrainer
868 f380d53c Thomas Thrainer
  def ExpandNames(self):
869 f380d53c Thomas Thrainer
    # Raises errors.OpPrereqError on its own if group can't be found
870 f380d53c Thomas Thrainer
    self.group_uuid = self.cfg.LookupNodeGroup(self.op.group_name)
871 f380d53c Thomas Thrainer
872 5eacbcae Thomas Thrainer
    self.share_locks = ShareAll()
873 f380d53c Thomas Thrainer
    self.needed_locks = {
874 f380d53c Thomas Thrainer
      locking.LEVEL_INSTANCE: [],
875 f380d53c Thomas Thrainer
      locking.LEVEL_NODEGROUP: [],
876 f380d53c Thomas Thrainer
      locking.LEVEL_NODE: [],
877 f380d53c Thomas Thrainer
878 f380d53c Thomas Thrainer
      # This opcode is acquires all node locks in a group. LUClusterVerifyDisks
879 f380d53c Thomas Thrainer
      # starts one instance of this opcode for every group, which means all
880 f380d53c Thomas Thrainer
      # nodes will be locked for a short amount of time, so it's better to
881 f380d53c Thomas Thrainer
      # acquire the node allocation lock as well.
882 f380d53c Thomas Thrainer
      locking.LEVEL_NODE_ALLOC: locking.ALL_SET,
883 f380d53c Thomas Thrainer
      }
884 f380d53c Thomas Thrainer
885 f380d53c Thomas Thrainer
  def DeclareLocks(self, level):
886 f380d53c Thomas Thrainer
    if level == locking.LEVEL_INSTANCE:
887 f380d53c Thomas Thrainer
      assert not self.needed_locks[locking.LEVEL_INSTANCE]
888 f380d53c Thomas Thrainer
889 f380d53c Thomas Thrainer
      # Lock instances optimistically, needs verification once node and group
890 f380d53c Thomas Thrainer
      # locks have been acquired
891 f380d53c Thomas Thrainer
      self.needed_locks[locking.LEVEL_INSTANCE] = \
892 da4a52a3 Thomas Thrainer
        self.cfg.GetInstanceNames(
893 da4a52a3 Thomas Thrainer
          self.cfg.GetNodeGroupInstances(self.group_uuid))
894 f380d53c Thomas Thrainer
895 f380d53c Thomas Thrainer
    elif level == locking.LEVEL_NODEGROUP:
896 f380d53c Thomas Thrainer
      assert not self.needed_locks[locking.LEVEL_NODEGROUP]
897 f380d53c Thomas Thrainer
898 f380d53c Thomas Thrainer
      self.needed_locks[locking.LEVEL_NODEGROUP] = \
899 f380d53c Thomas Thrainer
        set([self.group_uuid] +
900 f380d53c Thomas Thrainer
            # Lock all groups used by instances optimistically; this requires
901 f380d53c Thomas Thrainer
            # going via the node before it's locked, requiring verification
902 f380d53c Thomas Thrainer
            # later on
903 f380d53c Thomas Thrainer
            [group_uuid
904 f380d53c Thomas Thrainer
             for instance_name in self.owned_locks(locking.LEVEL_INSTANCE)
905 da4a52a3 Thomas Thrainer
             for group_uuid in
906 da4a52a3 Thomas Thrainer
               self.cfg.GetInstanceNodeGroups(
907 da4a52a3 Thomas Thrainer
                 self.cfg.GetInstanceInfoByName(instance_name).uuid)])
908 f380d53c Thomas Thrainer
909 f380d53c Thomas Thrainer
    elif level == locking.LEVEL_NODE:
910 f380d53c Thomas Thrainer
      # This will only lock the nodes in the group to be verified which contain
911 f380d53c Thomas Thrainer
      # actual instances
912 f380d53c Thomas Thrainer
      self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_APPEND
913 f380d53c Thomas Thrainer
      self._LockInstancesNodes()
914 f380d53c Thomas Thrainer
915 f380d53c Thomas Thrainer
      # Lock all nodes in group to be verified
916 f380d53c Thomas Thrainer
      assert self.group_uuid in self.owned_locks(locking.LEVEL_NODEGROUP)
917 1c3231aa Thomas Thrainer
      member_node_uuids = self.cfg.GetNodeGroup(self.group_uuid).members
918 1c3231aa Thomas Thrainer
      self.needed_locks[locking.LEVEL_NODE].extend(member_node_uuids)
919 f380d53c Thomas Thrainer
920 f380d53c Thomas Thrainer
  def CheckPrereq(self):
921 da4a52a3 Thomas Thrainer
    owned_inst_names = frozenset(self.owned_locks(locking.LEVEL_INSTANCE))
922 f380d53c Thomas Thrainer
    owned_groups = frozenset(self.owned_locks(locking.LEVEL_NODEGROUP))
923 1c3231aa Thomas Thrainer
    owned_node_uuids = frozenset(self.owned_locks(locking.LEVEL_NODE))
924 f380d53c Thomas Thrainer
925 f380d53c Thomas Thrainer
    assert self.group_uuid in owned_groups
926 f380d53c Thomas Thrainer
927 f380d53c Thomas Thrainer
    # Check if locked instances are still correct
928 da4a52a3 Thomas Thrainer
    CheckNodeGroupInstances(self.cfg, self.group_uuid, owned_inst_names)
929 f380d53c Thomas Thrainer
930 f380d53c Thomas Thrainer
    # Get instance information
931 da4a52a3 Thomas Thrainer
    self.instances = dict(self.cfg.GetMultiInstanceInfoByName(owned_inst_names))
932 f380d53c Thomas Thrainer
933 f380d53c Thomas Thrainer
    # Check if node groups for locked instances are still correct
934 5eacbcae Thomas Thrainer
    CheckInstancesNodeGroups(self.cfg, self.instances,
935 1c3231aa Thomas Thrainer
                             owned_groups, owned_node_uuids, self.group_uuid)
936 f380d53c Thomas Thrainer
937 235a6b29 Thomas Thrainer
  def _VerifyInstanceLvs(self, node_errors, offline_disk_instance_names,
938 235a6b29 Thomas Thrainer
                         missing_disks):
939 843094ad Thomas Thrainer
    node_lv_to_inst = MapInstanceLvsToNodes(
940 1d4a4b26 Thomas Thrainer
      [inst for inst in self.instances.values() if inst.disks_active])
941 843094ad Thomas Thrainer
    if node_lv_to_inst:
942 1c3231aa Thomas Thrainer
      node_uuids = utils.NiceSort(set(self.owned_locks(locking.LEVEL_NODE)) &
943 1c3231aa Thomas Thrainer
                                  set(self.cfg.GetVmCapableNodeList()))
944 f380d53c Thomas Thrainer
945 1c3231aa Thomas Thrainer
      node_lvs = self.rpc.call_lv_list(node_uuids, [])
946 f380d53c Thomas Thrainer
947 1c3231aa Thomas Thrainer
      for (node_uuid, node_res) in node_lvs.items():
948 f380d53c Thomas Thrainer
        if node_res.offline:
949 f380d53c Thomas Thrainer
          continue
950 f380d53c Thomas Thrainer
951 f380d53c Thomas Thrainer
        msg = node_res.fail_msg
952 f380d53c Thomas Thrainer
        if msg:
953 1c3231aa Thomas Thrainer
          logging.warning("Error enumerating LVs on node %s: %s",
954 1c3231aa Thomas Thrainer
                          self.cfg.GetNodeName(node_uuid), msg)
955 843094ad Thomas Thrainer
          node_errors[node_uuid] = msg
956 f380d53c Thomas Thrainer
          continue
957 f380d53c Thomas Thrainer
958 f380d53c Thomas Thrainer
        for lv_name, (_, _, lv_online) in node_res.payload.items():
959 843094ad Thomas Thrainer
          inst = node_lv_to_inst.pop((node_uuid, lv_name), None)
960 843094ad Thomas Thrainer
          if not lv_online and inst is not None:
961 235a6b29 Thomas Thrainer
            offline_disk_instance_names.add(inst.name)
962 f380d53c Thomas Thrainer
963 f380d53c Thomas Thrainer
      # any leftover items in nv_dict are missing LVs, let's arrange the data
964 f380d53c Thomas Thrainer
      # better
965 843094ad Thomas Thrainer
      for key, inst in node_lv_to_inst.iteritems():
966 235a6b29 Thomas Thrainer
        missing_disks.setdefault(inst.name, []).append(list(key))
967 235a6b29 Thomas Thrainer
968 235a6b29 Thomas Thrainer
  def _VerifyDrbdStates(self, node_errors, offline_disk_instance_names):
969 235a6b29 Thomas Thrainer
    node_to_inst = {}
970 235a6b29 Thomas Thrainer
    for inst in self.instances.values():
971 235a6b29 Thomas Thrainer
      if not inst.disks_active or inst.disk_template != constants.DT_DRBD8:
972 235a6b29 Thomas Thrainer
        continue
973 235a6b29 Thomas Thrainer
974 235a6b29 Thomas Thrainer
      for node_uuid in itertools.chain([inst.primary_node],
975 235a6b29 Thomas Thrainer
                                       inst.secondary_nodes):
976 235a6b29 Thomas Thrainer
        node_to_inst.setdefault(node_uuid, []).append(inst)
977 235a6b29 Thomas Thrainer
978 235a6b29 Thomas Thrainer
    for (node_uuid, insts) in node_to_inst.items():
979 235a6b29 Thomas Thrainer
      node_disks = [(inst.disks, inst) for inst in insts]
980 0c3d9c7c Thomas Thrainer
      node_res = self.rpc.call_drbd_needs_activation(node_uuid, node_disks)
981 235a6b29 Thomas Thrainer
      msg = node_res.fail_msg
982 235a6b29 Thomas Thrainer
      if msg:
983 235a6b29 Thomas Thrainer
        logging.warning("Error getting DRBD status on node %s: %s",
984 235a6b29 Thomas Thrainer
                        self.cfg.GetNodeName(node_uuid), msg)
985 235a6b29 Thomas Thrainer
        node_errors[node_uuid] = msg
986 235a6b29 Thomas Thrainer
        continue
987 235a6b29 Thomas Thrainer
988 235a6b29 Thomas Thrainer
      faulty_disk_uuids = set(node_res.payload)
989 235a6b29 Thomas Thrainer
      for inst in self.instances.values():
990 235a6b29 Thomas Thrainer
        inst_disk_uuids = set([disk.uuid for disk in inst.disks])
991 235a6b29 Thomas Thrainer
        if inst_disk_uuids.intersection(faulty_disk_uuids):
992 235a6b29 Thomas Thrainer
          offline_disk_instance_names.add(inst.name)
993 235a6b29 Thomas Thrainer
994 235a6b29 Thomas Thrainer
  def Exec(self, feedback_fn):
995 235a6b29 Thomas Thrainer
    """Verify integrity of cluster disks.
996 235a6b29 Thomas Thrainer

997 235a6b29 Thomas Thrainer
    @rtype: tuple of three items
998 235a6b29 Thomas Thrainer
    @return: a tuple of (dict of node-to-node_error, list of instances
999 235a6b29 Thomas Thrainer
        which need activate-disks, dict of instance: (node, volume) for
1000 235a6b29 Thomas Thrainer
        missing volumes
1001 235a6b29 Thomas Thrainer

1002 235a6b29 Thomas Thrainer
    """
1003 235a6b29 Thomas Thrainer
    node_errors = {}
1004 235a6b29 Thomas Thrainer
    offline_disk_instance_names = set()
1005 235a6b29 Thomas Thrainer
    missing_disks = {}
1006 235a6b29 Thomas Thrainer
1007 235a6b29 Thomas Thrainer
    self._VerifyInstanceLvs(node_errors, offline_disk_instance_names,
1008 235a6b29 Thomas Thrainer
                            missing_disks)
1009 235a6b29 Thomas Thrainer
    self._VerifyDrbdStates(node_errors, offline_disk_instance_names)
1010 f380d53c Thomas Thrainer
1011 235a6b29 Thomas Thrainer
    return (node_errors, list(offline_disk_instance_names), missing_disks)