root / lib / cmdlib / group.py @ 31d3b918
History | View | Annotate | Download (31.3 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 utils |
32 | f380d53c | Thomas Thrainer | from ganeti.masterd import iallocator |
33 | 081dc516 | Helga Velroyen | from ganeti.cmdlib.base import LogicalUnit, NoHooksLU, ResultWithJobs |
34 | 5eacbcae | Thomas Thrainer | from ganeti.cmdlib.common import MergeAndVerifyHvState, \ |
35 | 5eacbcae | Thomas Thrainer | MergeAndVerifyDiskState, GetWantedNodes, GetUpdatedParams, \ |
36 | 5eacbcae | Thomas Thrainer | CheckNodeGroupInstances, GetUpdatedIPolicy, \ |
37 | 5eacbcae | Thomas Thrainer | ComputeNewInstanceViolations, GetDefaultIAllocator, ShareAll, \ |
38 | 702243ec | Helga Velroyen | CheckInstancesNodeGroups, LoadNodeEvacResult, MapInstanceLvsToNodes, \ |
39 | 294254b1 | Raffa Santi | CheckIpolicyVsDiskTemplates, CheckDiskAccessModeValidity, \ |
40 | 294254b1 | Raffa Santi | CheckDiskAccessModeConsistency
|
41 | f380d53c | Thomas Thrainer | |
42 | f380d53c | Thomas Thrainer | import ganeti.masterd.instance |
43 | f380d53c | Thomas Thrainer | |
44 | f380d53c | Thomas Thrainer | |
45 | f380d53c | Thomas Thrainer | class LUGroupAdd(LogicalUnit): |
46 | f380d53c | Thomas Thrainer | """Logical unit for creating node groups.
|
47 | f380d53c | Thomas Thrainer |
|
48 | f380d53c | Thomas Thrainer | """
|
49 | f380d53c | Thomas Thrainer | HPATH = "group-add"
|
50 | f380d53c | Thomas Thrainer | HTYPE = constants.HTYPE_GROUP |
51 | f380d53c | Thomas Thrainer | REQ_BGL = False
|
52 | f380d53c | Thomas Thrainer | |
53 | f380d53c | Thomas Thrainer | def ExpandNames(self): |
54 | f380d53c | Thomas Thrainer | # We need the new group's UUID here so that we can create and acquire the
|
55 | f380d53c | Thomas Thrainer | # corresponding lock. Later, in Exec(), we'll indicate to cfg.AddNodeGroup
|
56 | f380d53c | Thomas Thrainer | # that it should not check whether the UUID exists in the configuration.
|
57 | f380d53c | Thomas Thrainer | self.group_uuid = self.cfg.GenerateUniqueID(self.proc.GetECId()) |
58 | f380d53c | Thomas Thrainer | self.needed_locks = {}
|
59 | f380d53c | Thomas Thrainer | self.add_locks[locking.LEVEL_NODEGROUP] = self.group_uuid |
60 | f380d53c | Thomas Thrainer | |
61 | 702243ec | Helga Velroyen | def _CheckIpolicy(self): |
62 | 702243ec | Helga Velroyen | """Checks the group's ipolicy for consistency and validity.
|
63 | 702243ec | Helga Velroyen |
|
64 | 702243ec | Helga Velroyen | """
|
65 | 702243ec | Helga Velroyen | if self.op.ipolicy: |
66 | 702243ec | Helga Velroyen | cluster = self.cfg.GetClusterInfo()
|
67 | 702243ec | Helga Velroyen | full_ipolicy = cluster.SimpleFillIPolicy(self.op.ipolicy)
|
68 | 702243ec | Helga Velroyen | try:
|
69 | 702243ec | Helga Velroyen | objects.InstancePolicy.CheckParameterSyntax(full_ipolicy, False)
|
70 | 702243ec | Helga Velroyen | except errors.ConfigurationError, err:
|
71 | 702243ec | Helga Velroyen | raise errors.OpPrereqError("Invalid instance policy: %s" % err, |
72 | 702243ec | Helga Velroyen | errors.ECODE_INVAL) |
73 | 702243ec | Helga Velroyen | CheckIpolicyVsDiskTemplates(full_ipolicy, |
74 | 702243ec | Helga Velroyen | cluster.enabled_disk_templates) |
75 | 702243ec | Helga Velroyen | |
76 | f380d53c | Thomas Thrainer | def CheckPrereq(self): |
77 | f380d53c | Thomas Thrainer | """Check prerequisites.
|
78 | f380d53c | Thomas Thrainer |
|
79 | f380d53c | Thomas Thrainer | This checks that the given group name is not an existing node group
|
80 | f380d53c | Thomas Thrainer | already.
|
81 | f380d53c | Thomas Thrainer |
|
82 | f380d53c | Thomas Thrainer | """
|
83 | f380d53c | Thomas Thrainer | try:
|
84 | f380d53c | Thomas Thrainer | existing_uuid = self.cfg.LookupNodeGroup(self.op.group_name) |
85 | f380d53c | Thomas Thrainer | except errors.OpPrereqError:
|
86 | f380d53c | Thomas Thrainer | pass
|
87 | f380d53c | Thomas Thrainer | else:
|
88 | f380d53c | Thomas Thrainer | raise errors.OpPrereqError("Desired group name '%s' already exists as a" |
89 | f380d53c | Thomas Thrainer | " node group (UUID: %s)" %
|
90 | f380d53c | Thomas Thrainer | (self.op.group_name, existing_uuid),
|
91 | f380d53c | Thomas Thrainer | errors.ECODE_EXISTS) |
92 | f380d53c | Thomas Thrainer | |
93 | f380d53c | Thomas Thrainer | if self.op.ndparams: |
94 | f380d53c | Thomas Thrainer | utils.ForceDictType(self.op.ndparams, constants.NDS_PARAMETER_TYPES)
|
95 | f380d53c | Thomas Thrainer | |
96 | f380d53c | Thomas Thrainer | if self.op.hv_state: |
97 | 5eacbcae | Thomas Thrainer | self.new_hv_state = MergeAndVerifyHvState(self.op.hv_state, None) |
98 | f380d53c | Thomas Thrainer | else:
|
99 | f380d53c | Thomas Thrainer | self.new_hv_state = None |
100 | f380d53c | Thomas Thrainer | |
101 | f380d53c | Thomas Thrainer | if self.op.disk_state: |
102 | 5eacbcae | Thomas Thrainer | self.new_disk_state = MergeAndVerifyDiskState(self.op.disk_state, None) |
103 | f380d53c | Thomas Thrainer | else:
|
104 | f380d53c | Thomas Thrainer | self.new_disk_state = None |
105 | f380d53c | Thomas Thrainer | |
106 | f380d53c | Thomas Thrainer | if self.op.diskparams: |
107 | f380d53c | Thomas Thrainer | for templ in constants.DISK_TEMPLATES: |
108 | f380d53c | Thomas Thrainer | if templ in self.op.diskparams: |
109 | f380d53c | Thomas Thrainer | utils.ForceDictType(self.op.diskparams[templ],
|
110 | f380d53c | Thomas Thrainer | constants.DISK_DT_TYPES) |
111 | f380d53c | Thomas Thrainer | self.new_diskparams = self.op.diskparams |
112 | f380d53c | Thomas Thrainer | try:
|
113 | f380d53c | Thomas Thrainer | utils.VerifyDictOptions(self.new_diskparams, constants.DISK_DT_DEFAULTS)
|
114 | f380d53c | Thomas Thrainer | except errors.OpPrereqError, err:
|
115 | f380d53c | Thomas Thrainer | raise errors.OpPrereqError("While verify diskparams options: %s" % err, |
116 | f380d53c | Thomas Thrainer | errors.ECODE_INVAL) |
117 | f380d53c | Thomas Thrainer | else:
|
118 | f380d53c | Thomas Thrainer | self.new_diskparams = {}
|
119 | f380d53c | Thomas Thrainer | |
120 | 702243ec | Helga Velroyen | self._CheckIpolicy()
|
121 | f380d53c | Thomas Thrainer | |
122 | f380d53c | Thomas Thrainer | def BuildHooksEnv(self): |
123 | f380d53c | Thomas Thrainer | """Build hooks env.
|
124 | f380d53c | Thomas Thrainer |
|
125 | f380d53c | Thomas Thrainer | """
|
126 | f380d53c | Thomas Thrainer | return {
|
127 | f380d53c | Thomas Thrainer | "GROUP_NAME": self.op.group_name, |
128 | f380d53c | Thomas Thrainer | } |
129 | f380d53c | Thomas Thrainer | |
130 | f380d53c | Thomas Thrainer | def BuildHooksNodes(self): |
131 | f380d53c | Thomas Thrainer | """Build hooks nodes.
|
132 | f380d53c | Thomas Thrainer |
|
133 | f380d53c | Thomas Thrainer | """
|
134 | f380d53c | Thomas Thrainer | mn = self.cfg.GetMasterNode()
|
135 | f380d53c | Thomas Thrainer | return ([mn], [mn])
|
136 | f380d53c | Thomas Thrainer | |
137 | f380d53c | Thomas Thrainer | def Exec(self, feedback_fn): |
138 | f380d53c | Thomas Thrainer | """Add the node group to the cluster.
|
139 | f380d53c | Thomas Thrainer |
|
140 | f380d53c | Thomas Thrainer | """
|
141 | f380d53c | Thomas Thrainer | group_obj = objects.NodeGroup(name=self.op.group_name, members=[],
|
142 | f380d53c | Thomas Thrainer | uuid=self.group_uuid,
|
143 | f380d53c | Thomas Thrainer | alloc_policy=self.op.alloc_policy,
|
144 | f380d53c | Thomas Thrainer | ndparams=self.op.ndparams,
|
145 | f380d53c | Thomas Thrainer | diskparams=self.new_diskparams,
|
146 | f380d53c | Thomas Thrainer | ipolicy=self.op.ipolicy,
|
147 | f380d53c | Thomas Thrainer | hv_state_static=self.new_hv_state,
|
148 | f380d53c | Thomas Thrainer | disk_state_static=self.new_disk_state)
|
149 | f380d53c | Thomas Thrainer | |
150 | f380d53c | Thomas Thrainer | self.cfg.AddNodeGroup(group_obj, self.proc.GetECId(), check_uuid=False) |
151 | f380d53c | Thomas Thrainer | del self.remove_locks[locking.LEVEL_NODEGROUP] |
152 | f380d53c | Thomas Thrainer | |
153 | f380d53c | Thomas Thrainer | |
154 | f380d53c | Thomas Thrainer | class LUGroupAssignNodes(NoHooksLU): |
155 | f380d53c | Thomas Thrainer | """Logical unit for assigning nodes to groups.
|
156 | f380d53c | Thomas Thrainer |
|
157 | f380d53c | Thomas Thrainer | """
|
158 | f380d53c | Thomas Thrainer | REQ_BGL = False
|
159 | f380d53c | Thomas Thrainer | |
160 | f380d53c | Thomas Thrainer | def ExpandNames(self): |
161 | f380d53c | Thomas Thrainer | # These raise errors.OpPrereqError on their own:
|
162 | f380d53c | Thomas Thrainer | self.group_uuid = self.cfg.LookupNodeGroup(self.op.group_name) |
163 | 1c3231aa | Thomas Thrainer | (self.op.node_uuids, self.op.nodes) = GetWantedNodes(self, self.op.nodes) |
164 | f380d53c | Thomas Thrainer | |
165 | f380d53c | Thomas Thrainer | # We want to lock all the affected nodes and groups. We have readily
|
166 | f380d53c | Thomas Thrainer | # available the list of nodes, and the *destination* group. To gather the
|
167 | f380d53c | Thomas Thrainer | # list of "source" groups, we need to fetch node information later on.
|
168 | f380d53c | Thomas Thrainer | self.needed_locks = {
|
169 | f380d53c | Thomas Thrainer | locking.LEVEL_NODEGROUP: set([self.group_uuid]), |
170 | 1c3231aa | Thomas Thrainer | locking.LEVEL_NODE: self.op.node_uuids,
|
171 | f380d53c | Thomas Thrainer | } |
172 | f380d53c | Thomas Thrainer | |
173 | f380d53c | Thomas Thrainer | def DeclareLocks(self, level): |
174 | f380d53c | Thomas Thrainer | if level == locking.LEVEL_NODEGROUP:
|
175 | f380d53c | Thomas Thrainer | assert len(self.needed_locks[locking.LEVEL_NODEGROUP]) == 1 |
176 | f380d53c | Thomas Thrainer | |
177 | f380d53c | Thomas Thrainer | # Try to get all affected nodes' groups without having the group or node
|
178 | f380d53c | Thomas Thrainer | # lock yet. Needs verification later in the code flow.
|
179 | 1c3231aa | Thomas Thrainer | groups = self.cfg.GetNodeGroupsFromNodes(self.op.node_uuids) |
180 | f380d53c | Thomas Thrainer | |
181 | f380d53c | Thomas Thrainer | self.needed_locks[locking.LEVEL_NODEGROUP].update(groups)
|
182 | f380d53c | Thomas Thrainer | |
183 | f380d53c | Thomas Thrainer | def CheckPrereq(self): |
184 | f380d53c | Thomas Thrainer | """Check prerequisites.
|
185 | f380d53c | Thomas Thrainer |
|
186 | f380d53c | Thomas Thrainer | """
|
187 | f380d53c | Thomas Thrainer | assert self.needed_locks[locking.LEVEL_NODEGROUP] |
188 | f380d53c | Thomas Thrainer | assert (frozenset(self.owned_locks(locking.LEVEL_NODE)) == |
189 | 1c3231aa | Thomas Thrainer | frozenset(self.op.node_uuids)) |
190 | f380d53c | Thomas Thrainer | |
191 | f380d53c | Thomas Thrainer | expected_locks = (set([self.group_uuid]) | |
192 | 1c3231aa | Thomas Thrainer | self.cfg.GetNodeGroupsFromNodes(self.op.node_uuids)) |
193 | f380d53c | Thomas Thrainer | actual_locks = self.owned_locks(locking.LEVEL_NODEGROUP)
|
194 | f380d53c | Thomas Thrainer | if actual_locks != expected_locks:
|
195 | f380d53c | Thomas Thrainer | raise errors.OpExecError("Nodes changed groups since locks were acquired," |
196 | f380d53c | Thomas Thrainer | " current groups are '%s', used to be '%s'" %
|
197 | f380d53c | Thomas Thrainer | (utils.CommaJoin(expected_locks), |
198 | f380d53c | Thomas Thrainer | utils.CommaJoin(actual_locks))) |
199 | f380d53c | Thomas Thrainer | |
200 | f380d53c | Thomas Thrainer | self.node_data = self.cfg.GetAllNodesInfo() |
201 | f380d53c | Thomas Thrainer | self.group = self.cfg.GetNodeGroup(self.group_uuid) |
202 | f380d53c | Thomas Thrainer | instance_data = self.cfg.GetAllInstancesInfo()
|
203 | f380d53c | Thomas Thrainer | |
204 | f380d53c | Thomas Thrainer | if self.group is None: |
205 | f380d53c | Thomas Thrainer | raise errors.OpExecError("Could not retrieve group '%s' (UUID: %s)" % |
206 | f380d53c | Thomas Thrainer | (self.op.group_name, self.group_uuid)) |
207 | f380d53c | Thomas Thrainer | |
208 | f380d53c | Thomas Thrainer | (new_splits, previous_splits) = \ |
209 | 1c3231aa | Thomas Thrainer | self.CheckAssignmentForSplitInstances([(uuid, self.group_uuid) |
210 | 1c3231aa | Thomas Thrainer | for uuid in self.op.node_uuids], |
211 | f380d53c | Thomas Thrainer | self.node_data, instance_data)
|
212 | f380d53c | Thomas Thrainer | |
213 | f380d53c | Thomas Thrainer | if new_splits:
|
214 | da4a52a3 | Thomas Thrainer | fmt_new_splits = utils.CommaJoin(utils.NiceSort( |
215 | da4a52a3 | Thomas Thrainer | self.cfg.GetInstanceNames(new_splits)))
|
216 | f380d53c | Thomas Thrainer | |
217 | f380d53c | Thomas Thrainer | if not self.op.force: |
218 | f380d53c | Thomas Thrainer | raise errors.OpExecError("The following instances get split by this" |
219 | f380d53c | Thomas Thrainer | " change and --force was not given: %s" %
|
220 | f380d53c | Thomas Thrainer | fmt_new_splits) |
221 | f380d53c | Thomas Thrainer | else:
|
222 | f380d53c | Thomas Thrainer | self.LogWarning("This operation will split the following instances: %s", |
223 | f380d53c | Thomas Thrainer | fmt_new_splits) |
224 | f380d53c | Thomas Thrainer | |
225 | f380d53c | Thomas Thrainer | if previous_splits:
|
226 | f380d53c | Thomas Thrainer | self.LogWarning("In addition, these already-split instances continue" |
227 | f380d53c | Thomas Thrainer | " to be split across groups: %s",
|
228 | da4a52a3 | Thomas Thrainer | utils.CommaJoin(utils.NiceSort( |
229 | da4a52a3 | Thomas Thrainer | self.cfg.GetInstanceNames(previous_splits))))
|
230 | f380d53c | Thomas Thrainer | |
231 | f380d53c | Thomas Thrainer | def Exec(self, feedback_fn): |
232 | f380d53c | Thomas Thrainer | """Assign nodes to a new group.
|
233 | f380d53c | Thomas Thrainer |
|
234 | f380d53c | Thomas Thrainer | """
|
235 | 1c3231aa | Thomas Thrainer | mods = [(node_uuid, self.group_uuid) for node_uuid in self.op.node_uuids] |
236 | f380d53c | Thomas Thrainer | |
237 | f380d53c | Thomas Thrainer | self.cfg.AssignGroupNodes(mods)
|
238 | f380d53c | Thomas Thrainer | |
239 | f380d53c | Thomas Thrainer | @staticmethod
|
240 | f380d53c | Thomas Thrainer | def CheckAssignmentForSplitInstances(changes, node_data, instance_data): |
241 | f380d53c | Thomas Thrainer | """Check for split instances after a node assignment.
|
242 | f380d53c | Thomas Thrainer |
|
243 | f380d53c | Thomas Thrainer | This method considers a series of node assignments as an atomic operation,
|
244 | f380d53c | Thomas Thrainer | and returns information about split instances after applying the set of
|
245 | f380d53c | Thomas Thrainer | changes.
|
246 | f380d53c | Thomas Thrainer |
|
247 | f380d53c | Thomas Thrainer | In particular, it returns information about newly split instances, and
|
248 | f380d53c | Thomas Thrainer | instances that were already split, and remain so after the change.
|
249 | f380d53c | Thomas Thrainer |
|
250 | f380d53c | Thomas Thrainer | Only instances whose disk template is listed in constants.DTS_INT_MIRROR are
|
251 | f380d53c | Thomas Thrainer | considered.
|
252 | f380d53c | Thomas Thrainer |
|
253 | 1c3231aa | Thomas Thrainer | @type changes: list of (node_uuid, new_group_uuid) pairs.
|
254 | f380d53c | Thomas Thrainer | @param changes: list of node assignments to consider.
|
255 | f380d53c | Thomas Thrainer | @param node_data: a dict with data for all nodes
|
256 | f380d53c | Thomas Thrainer | @param instance_data: a dict with all instances to consider
|
257 | f380d53c | Thomas Thrainer | @rtype: a two-tuple
|
258 | f380d53c | Thomas Thrainer | @return: a list of instances that were previously okay and result split as a
|
259 | f380d53c | Thomas Thrainer | consequence of this change, and a list of instances that were previously
|
260 | f380d53c | Thomas Thrainer | split and this change does not fix.
|
261 | f380d53c | Thomas Thrainer |
|
262 | f380d53c | Thomas Thrainer | """
|
263 | 1c3231aa | Thomas Thrainer | changed_nodes = dict((uuid, group) for uuid, group in changes |
264 | 1c3231aa | Thomas Thrainer | if node_data[uuid].group != group)
|
265 | f380d53c | Thomas Thrainer | |
266 | f380d53c | Thomas Thrainer | all_split_instances = set()
|
267 | f380d53c | Thomas Thrainer | previously_split_instances = set()
|
268 | f380d53c | Thomas Thrainer | |
269 | f380d53c | Thomas Thrainer | for inst in instance_data.values(): |
270 | f380d53c | Thomas Thrainer | if inst.disk_template not in constants.DTS_INT_MIRROR: |
271 | f380d53c | Thomas Thrainer | continue
|
272 | f380d53c | Thomas Thrainer | |
273 | 1c3231aa | Thomas Thrainer | if len(set(node_data[node_uuid].group |
274 | 1c3231aa | Thomas Thrainer | for node_uuid in inst.all_nodes)) > 1: |
275 | da4a52a3 | Thomas Thrainer | previously_split_instances.add(inst.uuid) |
276 | f380d53c | Thomas Thrainer | |
277 | 1c3231aa | Thomas Thrainer | if len(set(changed_nodes.get(node_uuid, node_data[node_uuid].group) |
278 | 1c3231aa | Thomas Thrainer | for node_uuid in inst.all_nodes)) > 1: |
279 | da4a52a3 | Thomas Thrainer | all_split_instances.add(inst.uuid) |
280 | f380d53c | Thomas Thrainer | |
281 | f380d53c | Thomas Thrainer | return (list(all_split_instances - previously_split_instances), |
282 | f380d53c | Thomas Thrainer | list(previously_split_instances & all_split_instances))
|
283 | f380d53c | Thomas Thrainer | |
284 | f380d53c | Thomas Thrainer | |
285 | f380d53c | Thomas Thrainer | class LUGroupSetParams(LogicalUnit): |
286 | f380d53c | Thomas Thrainer | """Modifies the parameters of a node group.
|
287 | f380d53c | Thomas Thrainer |
|
288 | f380d53c | Thomas Thrainer | """
|
289 | f380d53c | Thomas Thrainer | HPATH = "group-modify"
|
290 | f380d53c | Thomas Thrainer | HTYPE = constants.HTYPE_GROUP |
291 | f380d53c | Thomas Thrainer | REQ_BGL = False
|
292 | f380d53c | Thomas Thrainer | |
293 | f380d53c | Thomas Thrainer | def CheckArguments(self): |
294 | f380d53c | Thomas Thrainer | all_changes = [ |
295 | f380d53c | Thomas Thrainer | self.op.ndparams,
|
296 | f380d53c | Thomas Thrainer | self.op.diskparams,
|
297 | f380d53c | Thomas Thrainer | self.op.alloc_policy,
|
298 | f380d53c | Thomas Thrainer | self.op.hv_state,
|
299 | f380d53c | Thomas Thrainer | self.op.disk_state,
|
300 | f380d53c | Thomas Thrainer | self.op.ipolicy,
|
301 | f380d53c | Thomas Thrainer | ] |
302 | f380d53c | Thomas Thrainer | |
303 | f380d53c | Thomas Thrainer | if all_changes.count(None) == len(all_changes): |
304 | f380d53c | Thomas Thrainer | raise errors.OpPrereqError("Please pass at least one modification", |
305 | f380d53c | Thomas Thrainer | errors.ECODE_INVAL) |
306 | f380d53c | Thomas Thrainer | |
307 | 294254b1 | Raffa Santi | if self.op.diskparams: |
308 | 294254b1 | Raffa Santi | CheckDiskAccessModeValidity(self.op.diskparams)
|
309 | 294254b1 | Raffa Santi | |
310 | f380d53c | Thomas Thrainer | def ExpandNames(self): |
311 | f380d53c | Thomas Thrainer | # This raises errors.OpPrereqError on its own:
|
312 | f380d53c | Thomas Thrainer | self.group_uuid = self.cfg.LookupNodeGroup(self.op.group_name) |
313 | f380d53c | Thomas Thrainer | |
314 | f380d53c | Thomas Thrainer | self.needed_locks = {
|
315 | f380d53c | Thomas Thrainer | locking.LEVEL_INSTANCE: [], |
316 | f380d53c | Thomas Thrainer | locking.LEVEL_NODEGROUP: [self.group_uuid],
|
317 | f380d53c | Thomas Thrainer | } |
318 | f380d53c | Thomas Thrainer | |
319 | f380d53c | Thomas Thrainer | self.share_locks[locking.LEVEL_INSTANCE] = 1 |
320 | f380d53c | Thomas Thrainer | |
321 | f380d53c | Thomas Thrainer | def DeclareLocks(self, level): |
322 | f380d53c | Thomas Thrainer | if level == locking.LEVEL_INSTANCE:
|
323 | f380d53c | Thomas Thrainer | assert not self.needed_locks[locking.LEVEL_INSTANCE] |
324 | f380d53c | Thomas Thrainer | |
325 | f380d53c | Thomas Thrainer | # Lock instances optimistically, needs verification once group lock has
|
326 | f380d53c | Thomas Thrainer | # been acquired
|
327 | f380d53c | Thomas Thrainer | self.needed_locks[locking.LEVEL_INSTANCE] = \
|
328 | da4a52a3 | Thomas Thrainer | self.cfg.GetInstanceNames(
|
329 | da4a52a3 | Thomas Thrainer | self.cfg.GetNodeGroupInstances(self.group_uuid)) |
330 | f380d53c | Thomas Thrainer | |
331 | f380d53c | Thomas Thrainer | @staticmethod
|
332 | f380d53c | Thomas Thrainer | def _UpdateAndVerifyDiskParams(old, new): |
333 | f380d53c | Thomas Thrainer | """Updates and verifies disk parameters.
|
334 | f380d53c | Thomas Thrainer |
|
335 | f380d53c | Thomas Thrainer | """
|
336 | 5eacbcae | Thomas Thrainer | new_params = GetUpdatedParams(old, new) |
337 | f380d53c | Thomas Thrainer | utils.ForceDictType(new_params, constants.DISK_DT_TYPES) |
338 | f380d53c | Thomas Thrainer | return new_params
|
339 | f380d53c | Thomas Thrainer | |
340 | 702243ec | Helga Velroyen | def _CheckIpolicy(self, cluster, owned_instance_names): |
341 | 702243ec | Helga Velroyen | """Sanity checks for the ipolicy.
|
342 | 702243ec | Helga Velroyen |
|
343 | 702243ec | Helga Velroyen | @type cluster: C{objects.Cluster}
|
344 | 702243ec | Helga Velroyen | @param cluster: the cluster's configuration
|
345 | 702243ec | Helga Velroyen | @type owned_instance_names: list of string
|
346 | 702243ec | Helga Velroyen | @param owned_instance_names: list of instances
|
347 | 702243ec | Helga Velroyen |
|
348 | 702243ec | Helga Velroyen | """
|
349 | 702243ec | Helga Velroyen | if self.op.ipolicy: |
350 | 702243ec | Helga Velroyen | self.new_ipolicy = GetUpdatedIPolicy(self.group.ipolicy, |
351 | 702243ec | Helga Velroyen | self.op.ipolicy,
|
352 | 702243ec | Helga Velroyen | group_policy=True)
|
353 | 702243ec | Helga Velroyen | |
354 | 702243ec | Helga Velroyen | new_ipolicy = cluster.SimpleFillIPolicy(self.new_ipolicy)
|
355 | 702243ec | Helga Velroyen | CheckIpolicyVsDiskTemplates(new_ipolicy, |
356 | 702243ec | Helga Velroyen | cluster.enabled_disk_templates) |
357 | bbe0f264 | Thomas Thrainer | instances = \ |
358 | bbe0f264 | Thomas Thrainer | dict(self.cfg.GetMultiInstanceInfoByName(owned_instance_names)) |
359 | 702243ec | Helga Velroyen | gmi = ganeti.masterd.instance |
360 | 702243ec | Helga Velroyen | violations = \ |
361 | 702243ec | Helga Velroyen | ComputeNewInstanceViolations(gmi.CalculateGroupIPolicy(cluster, |
362 | 702243ec | Helga Velroyen | self.group),
|
363 | bbe0f264 | Thomas Thrainer | new_ipolicy, instances.values(), |
364 | bbe0f264 | Thomas Thrainer | self.cfg)
|
365 | 702243ec | Helga Velroyen | |
366 | 702243ec | Helga Velroyen | if violations:
|
367 | 702243ec | Helga Velroyen | self.LogWarning("After the ipolicy change the following instances" |
368 | 702243ec | Helga Velroyen | " violate them: %s",
|
369 | 702243ec | Helga Velroyen | utils.CommaJoin(violations)) |
370 | 702243ec | Helga Velroyen | |
371 | f380d53c | Thomas Thrainer | def CheckPrereq(self): |
372 | f380d53c | Thomas Thrainer | """Check prerequisites.
|
373 | f380d53c | Thomas Thrainer |
|
374 | f380d53c | Thomas Thrainer | """
|
375 | da4a52a3 | Thomas Thrainer | owned_instance_names = frozenset(self.owned_locks(locking.LEVEL_INSTANCE)) |
376 | f380d53c | Thomas Thrainer | |
377 | f380d53c | Thomas Thrainer | # Check if locked instances are still correct
|
378 | da4a52a3 | Thomas Thrainer | CheckNodeGroupInstances(self.cfg, self.group_uuid, owned_instance_names) |
379 | f380d53c | Thomas Thrainer | |
380 | f380d53c | Thomas Thrainer | self.group = self.cfg.GetNodeGroup(self.group_uuid) |
381 | f380d53c | Thomas Thrainer | cluster = self.cfg.GetClusterInfo()
|
382 | f380d53c | Thomas Thrainer | |
383 | f380d53c | Thomas Thrainer | if self.group is None: |
384 | f380d53c | Thomas Thrainer | raise errors.OpExecError("Could not retrieve group '%s' (UUID: %s)" % |
385 | f380d53c | Thomas Thrainer | (self.op.group_name, self.group_uuid)) |
386 | f380d53c | Thomas Thrainer | |
387 | f380d53c | Thomas Thrainer | if self.op.ndparams: |
388 | 5eacbcae | Thomas Thrainer | new_ndparams = GetUpdatedParams(self.group.ndparams, self.op.ndparams) |
389 | f380d53c | Thomas Thrainer | utils.ForceDictType(new_ndparams, constants.NDS_PARAMETER_TYPES) |
390 | f380d53c | Thomas Thrainer | self.new_ndparams = new_ndparams
|
391 | f380d53c | Thomas Thrainer | |
392 | f380d53c | Thomas Thrainer | if self.op.diskparams: |
393 | f380d53c | Thomas Thrainer | diskparams = self.group.diskparams
|
394 | f380d53c | Thomas Thrainer | uavdp = self._UpdateAndVerifyDiskParams
|
395 | f380d53c | Thomas Thrainer | # For each disktemplate subdict update and verify the values
|
396 | f380d53c | Thomas Thrainer | new_diskparams = dict((dt,
|
397 | f380d53c | Thomas Thrainer | uavdp(diskparams.get(dt, {}), |
398 | f380d53c | Thomas Thrainer | self.op.diskparams[dt]))
|
399 | f380d53c | Thomas Thrainer | for dt in constants.DISK_TEMPLATES |
400 | f380d53c | Thomas Thrainer | if dt in self.op.diskparams) |
401 | f380d53c | Thomas Thrainer | # As we've all subdicts of diskparams ready, lets merge the actual
|
402 | f380d53c | Thomas Thrainer | # dict with all updated subdicts
|
403 | f380d53c | Thomas Thrainer | self.new_diskparams = objects.FillDict(diskparams, new_diskparams)
|
404 | 294254b1 | Raffa Santi | |
405 | f380d53c | Thomas Thrainer | try:
|
406 | f380d53c | Thomas Thrainer | utils.VerifyDictOptions(self.new_diskparams, constants.DISK_DT_DEFAULTS)
|
407 | 294254b1 | Raffa Santi | CheckDiskAccessModeConsistency(self.new_diskparams, self.cfg, |
408 | 294254b1 | Raffa Santi | group=self.group)
|
409 | f380d53c | Thomas Thrainer | except errors.OpPrereqError, err:
|
410 | f380d53c | Thomas Thrainer | raise errors.OpPrereqError("While verify diskparams options: %s" % err, |
411 | f380d53c | Thomas Thrainer | errors.ECODE_INVAL) |
412 | f380d53c | Thomas Thrainer | |
413 | f380d53c | Thomas Thrainer | if self.op.hv_state: |
414 | 5eacbcae | Thomas Thrainer | self.new_hv_state = MergeAndVerifyHvState(self.op.hv_state, |
415 | 5eacbcae | Thomas Thrainer | self.group.hv_state_static)
|
416 | f380d53c | Thomas Thrainer | |
417 | f380d53c | Thomas Thrainer | if self.op.disk_state: |
418 | f380d53c | Thomas Thrainer | self.new_disk_state = \
|
419 | 5eacbcae | Thomas Thrainer | MergeAndVerifyDiskState(self.op.disk_state,
|
420 | 5eacbcae | Thomas Thrainer | self.group.disk_state_static)
|
421 | f380d53c | Thomas Thrainer | |
422 | 702243ec | Helga Velroyen | self._CheckIpolicy(cluster, owned_instance_names)
|
423 | f380d53c | Thomas Thrainer | |
424 | f380d53c | Thomas Thrainer | def BuildHooksEnv(self): |
425 | f380d53c | Thomas Thrainer | """Build hooks env.
|
426 | f380d53c | Thomas Thrainer |
|
427 | f380d53c | Thomas Thrainer | """
|
428 | f380d53c | Thomas Thrainer | return {
|
429 | f380d53c | Thomas Thrainer | "GROUP_NAME": self.op.group_name, |
430 | f380d53c | Thomas Thrainer | "NEW_ALLOC_POLICY": self.op.alloc_policy, |
431 | f380d53c | Thomas Thrainer | } |
432 | f380d53c | Thomas Thrainer | |
433 | f380d53c | Thomas Thrainer | def BuildHooksNodes(self): |
434 | f380d53c | Thomas Thrainer | """Build hooks nodes.
|
435 | f380d53c | Thomas Thrainer |
|
436 | f380d53c | Thomas Thrainer | """
|
437 | f380d53c | Thomas Thrainer | mn = self.cfg.GetMasterNode()
|
438 | f380d53c | Thomas Thrainer | return ([mn], [mn])
|
439 | f380d53c | Thomas Thrainer | |
440 | f380d53c | Thomas Thrainer | def Exec(self, feedback_fn): |
441 | f380d53c | Thomas Thrainer | """Modifies the node group.
|
442 | f380d53c | Thomas Thrainer |
|
443 | f380d53c | Thomas Thrainer | """
|
444 | f380d53c | Thomas Thrainer | result = [] |
445 | f380d53c | Thomas Thrainer | |
446 | f380d53c | Thomas Thrainer | if self.op.ndparams: |
447 | f380d53c | Thomas Thrainer | self.group.ndparams = self.new_ndparams |
448 | f380d53c | Thomas Thrainer | result.append(("ndparams", str(self.group.ndparams))) |
449 | f380d53c | Thomas Thrainer | |
450 | f380d53c | Thomas Thrainer | if self.op.diskparams: |
451 | f380d53c | Thomas Thrainer | self.group.diskparams = self.new_diskparams |
452 | f380d53c | Thomas Thrainer | result.append(("diskparams", str(self.group.diskparams))) |
453 | f380d53c | Thomas Thrainer | |
454 | f380d53c | Thomas Thrainer | if self.op.alloc_policy: |
455 | f380d53c | Thomas Thrainer | self.group.alloc_policy = self.op.alloc_policy |
456 | f380d53c | Thomas Thrainer | |
457 | f380d53c | Thomas Thrainer | if self.op.hv_state: |
458 | f380d53c | Thomas Thrainer | self.group.hv_state_static = self.new_hv_state |
459 | f380d53c | Thomas Thrainer | |
460 | f380d53c | Thomas Thrainer | if self.op.disk_state: |
461 | f380d53c | Thomas Thrainer | self.group.disk_state_static = self.new_disk_state |
462 | f380d53c | Thomas Thrainer | |
463 | f380d53c | Thomas Thrainer | if self.op.ipolicy: |
464 | f380d53c | Thomas Thrainer | self.group.ipolicy = self.new_ipolicy |
465 | f380d53c | Thomas Thrainer | |
466 | f380d53c | Thomas Thrainer | self.cfg.Update(self.group, feedback_fn) |
467 | f380d53c | Thomas Thrainer | return result
|
468 | f380d53c | Thomas Thrainer | |
469 | f380d53c | Thomas Thrainer | |
470 | f380d53c | Thomas Thrainer | class LUGroupRemove(LogicalUnit): |
471 | f380d53c | Thomas Thrainer | HPATH = "group-remove"
|
472 | f380d53c | Thomas Thrainer | HTYPE = constants.HTYPE_GROUP |
473 | f380d53c | Thomas Thrainer | REQ_BGL = False
|
474 | f380d53c | Thomas Thrainer | |
475 | f380d53c | Thomas Thrainer | def ExpandNames(self): |
476 | f380d53c | Thomas Thrainer | # This will raises errors.OpPrereqError on its own:
|
477 | f380d53c | Thomas Thrainer | self.group_uuid = self.cfg.LookupNodeGroup(self.op.group_name) |
478 | f380d53c | Thomas Thrainer | self.needed_locks = {
|
479 | f380d53c | Thomas Thrainer | locking.LEVEL_NODEGROUP: [self.group_uuid],
|
480 | f380d53c | Thomas Thrainer | } |
481 | f380d53c | Thomas Thrainer | |
482 | f380d53c | Thomas Thrainer | def CheckPrereq(self): |
483 | f380d53c | Thomas Thrainer | """Check prerequisites.
|
484 | f380d53c | Thomas Thrainer |
|
485 | f380d53c | Thomas Thrainer | This checks that the given group name exists as a node group, that is
|
486 | f380d53c | Thomas Thrainer | empty (i.e., contains no nodes), and that is not the last group of the
|
487 | f380d53c | Thomas Thrainer | cluster.
|
488 | f380d53c | Thomas Thrainer |
|
489 | f380d53c | Thomas Thrainer | """
|
490 | f380d53c | Thomas Thrainer | # Verify that the group is empty.
|
491 | 1c3231aa | Thomas Thrainer | group_nodes = [node.uuid |
492 | f380d53c | Thomas Thrainer | for node in self.cfg.GetAllNodesInfo().values() |
493 | f380d53c | Thomas Thrainer | if node.group == self.group_uuid] |
494 | f380d53c | Thomas Thrainer | |
495 | f380d53c | Thomas Thrainer | if group_nodes:
|
496 | f380d53c | Thomas Thrainer | raise errors.OpPrereqError("Group '%s' not empty, has the following" |
497 | f380d53c | Thomas Thrainer | " nodes: %s" %
|
498 | f380d53c | Thomas Thrainer | (self.op.group_name,
|
499 | f380d53c | Thomas Thrainer | utils.CommaJoin(utils.NiceSort(group_nodes))), |
500 | f380d53c | Thomas Thrainer | errors.ECODE_STATE) |
501 | f380d53c | Thomas Thrainer | |
502 | f380d53c | Thomas Thrainer | # Verify the cluster would not be left group-less.
|
503 | f380d53c | Thomas Thrainer | if len(self.cfg.GetNodeGroupList()) == 1: |
504 | f380d53c | Thomas Thrainer | raise errors.OpPrereqError("Group '%s' is the only group, cannot be" |
505 | f380d53c | Thomas Thrainer | " removed" % self.op.group_name, |
506 | f380d53c | Thomas Thrainer | errors.ECODE_STATE) |
507 | f380d53c | Thomas Thrainer | |
508 | f380d53c | Thomas Thrainer | def BuildHooksEnv(self): |
509 | f380d53c | Thomas Thrainer | """Build hooks env.
|
510 | f380d53c | Thomas Thrainer |
|
511 | f380d53c | Thomas Thrainer | """
|
512 | f380d53c | Thomas Thrainer | return {
|
513 | f380d53c | Thomas Thrainer | "GROUP_NAME": self.op.group_name, |
514 | f380d53c | Thomas Thrainer | } |
515 | f380d53c | Thomas Thrainer | |
516 | f380d53c | Thomas Thrainer | def BuildHooksNodes(self): |
517 | f380d53c | Thomas Thrainer | """Build hooks nodes.
|
518 | f380d53c | Thomas Thrainer |
|
519 | f380d53c | Thomas Thrainer | """
|
520 | f380d53c | Thomas Thrainer | mn = self.cfg.GetMasterNode()
|
521 | f380d53c | Thomas Thrainer | return ([mn], [mn])
|
522 | f380d53c | Thomas Thrainer | |
523 | f380d53c | Thomas Thrainer | def Exec(self, feedback_fn): |
524 | f380d53c | Thomas Thrainer | """Remove the node group.
|
525 | f380d53c | Thomas Thrainer |
|
526 | f380d53c | Thomas Thrainer | """
|
527 | f380d53c | Thomas Thrainer | try:
|
528 | f380d53c | Thomas Thrainer | self.cfg.RemoveNodeGroup(self.group_uuid) |
529 | f380d53c | Thomas Thrainer | except errors.ConfigurationError:
|
530 | f380d53c | Thomas Thrainer | raise errors.OpExecError("Group '%s' with UUID %s disappeared" % |
531 | f380d53c | Thomas Thrainer | (self.op.group_name, self.group_uuid)) |
532 | f380d53c | Thomas Thrainer | |
533 | f380d53c | Thomas Thrainer | self.remove_locks[locking.LEVEL_NODEGROUP] = self.group_uuid |
534 | f380d53c | Thomas Thrainer | |
535 | f380d53c | Thomas Thrainer | |
536 | f380d53c | Thomas Thrainer | class LUGroupRename(LogicalUnit): |
537 | f380d53c | Thomas Thrainer | HPATH = "group-rename"
|
538 | f380d53c | Thomas Thrainer | HTYPE = constants.HTYPE_GROUP |
539 | f380d53c | Thomas Thrainer | REQ_BGL = False
|
540 | f380d53c | Thomas Thrainer | |
541 | f380d53c | Thomas Thrainer | def ExpandNames(self): |
542 | f380d53c | Thomas Thrainer | # This raises errors.OpPrereqError on its own:
|
543 | f380d53c | Thomas Thrainer | self.group_uuid = self.cfg.LookupNodeGroup(self.op.group_name) |
544 | f380d53c | Thomas Thrainer | |
545 | f380d53c | Thomas Thrainer | self.needed_locks = {
|
546 | f380d53c | Thomas Thrainer | locking.LEVEL_NODEGROUP: [self.group_uuid],
|
547 | f380d53c | Thomas Thrainer | } |
548 | f380d53c | Thomas Thrainer | |
549 | f380d53c | Thomas Thrainer | def CheckPrereq(self): |
550 | f380d53c | Thomas Thrainer | """Check prerequisites.
|
551 | f380d53c | Thomas Thrainer |
|
552 | f380d53c | Thomas Thrainer | Ensures requested new name is not yet used.
|
553 | f380d53c | Thomas Thrainer |
|
554 | f380d53c | Thomas Thrainer | """
|
555 | f380d53c | Thomas Thrainer | try:
|
556 | f380d53c | Thomas Thrainer | new_name_uuid = self.cfg.LookupNodeGroup(self.op.new_name) |
557 | f380d53c | Thomas Thrainer | except errors.OpPrereqError:
|
558 | f380d53c | Thomas Thrainer | pass
|
559 | f380d53c | Thomas Thrainer | else:
|
560 | f380d53c | Thomas Thrainer | raise errors.OpPrereqError("Desired new name '%s' clashes with existing" |
561 | f380d53c | Thomas Thrainer | " node group (UUID: %s)" %
|
562 | f380d53c | Thomas Thrainer | (self.op.new_name, new_name_uuid),
|
563 | f380d53c | Thomas Thrainer | errors.ECODE_EXISTS) |
564 | f380d53c | Thomas Thrainer | |
565 | f380d53c | Thomas Thrainer | def BuildHooksEnv(self): |
566 | f380d53c | Thomas Thrainer | """Build hooks env.
|
567 | f380d53c | Thomas Thrainer |
|
568 | f380d53c | Thomas Thrainer | """
|
569 | f380d53c | Thomas Thrainer | return {
|
570 | f380d53c | Thomas Thrainer | "OLD_NAME": self.op.group_name, |
571 | f380d53c | Thomas Thrainer | "NEW_NAME": self.op.new_name, |
572 | f380d53c | Thomas Thrainer | } |
573 | f380d53c | Thomas Thrainer | |
574 | f380d53c | Thomas Thrainer | def BuildHooksNodes(self): |
575 | f380d53c | Thomas Thrainer | """Build hooks nodes.
|
576 | f380d53c | Thomas Thrainer |
|
577 | f380d53c | Thomas Thrainer | """
|
578 | f380d53c | Thomas Thrainer | mn = self.cfg.GetMasterNode()
|
579 | f380d53c | Thomas Thrainer | |
580 | f380d53c | Thomas Thrainer | all_nodes = self.cfg.GetAllNodesInfo()
|
581 | f380d53c | Thomas Thrainer | all_nodes.pop(mn, None)
|
582 | f380d53c | Thomas Thrainer | |
583 | f380d53c | Thomas Thrainer | run_nodes = [mn] |
584 | 1c3231aa | Thomas Thrainer | run_nodes.extend(node.uuid for node in all_nodes.values() |
585 | f380d53c | Thomas Thrainer | if node.group == self.group_uuid) |
586 | f380d53c | Thomas Thrainer | |
587 | f380d53c | Thomas Thrainer | return (run_nodes, run_nodes)
|
588 | f380d53c | Thomas Thrainer | |
589 | f380d53c | Thomas Thrainer | def Exec(self, feedback_fn): |
590 | f380d53c | Thomas Thrainer | """Rename the node group.
|
591 | f380d53c | Thomas Thrainer |
|
592 | f380d53c | Thomas Thrainer | """
|
593 | f380d53c | Thomas Thrainer | group = self.cfg.GetNodeGroup(self.group_uuid) |
594 | f380d53c | Thomas Thrainer | |
595 | f380d53c | Thomas Thrainer | if group is None: |
596 | f380d53c | Thomas Thrainer | raise errors.OpExecError("Could not retrieve group '%s' (UUID: %s)" % |
597 | f380d53c | Thomas Thrainer | (self.op.group_name, self.group_uuid)) |
598 | f380d53c | Thomas Thrainer | |
599 | f380d53c | Thomas Thrainer | group.name = self.op.new_name
|
600 | f380d53c | Thomas Thrainer | self.cfg.Update(group, feedback_fn)
|
601 | f380d53c | Thomas Thrainer | |
602 | f380d53c | Thomas Thrainer | return self.op.new_name |
603 | f380d53c | Thomas Thrainer | |
604 | f380d53c | Thomas Thrainer | |
605 | f380d53c | Thomas Thrainer | class LUGroupEvacuate(LogicalUnit): |
606 | f380d53c | Thomas Thrainer | HPATH = "group-evacuate"
|
607 | f380d53c | Thomas Thrainer | HTYPE = constants.HTYPE_GROUP |
608 | f380d53c | Thomas Thrainer | REQ_BGL = False
|
609 | f380d53c | Thomas Thrainer | |
610 | f380d53c | Thomas Thrainer | def ExpandNames(self): |
611 | f380d53c | Thomas Thrainer | # This raises errors.OpPrereqError on its own:
|
612 | f380d53c | Thomas Thrainer | self.group_uuid = self.cfg.LookupNodeGroup(self.op.group_name) |
613 | f380d53c | Thomas Thrainer | |
614 | f380d53c | Thomas Thrainer | if self.op.target_groups: |
615 | f380d53c | Thomas Thrainer | self.req_target_uuids = map(self.cfg.LookupNodeGroup, |
616 | f380d53c | Thomas Thrainer | self.op.target_groups)
|
617 | f380d53c | Thomas Thrainer | else:
|
618 | f380d53c | Thomas Thrainer | self.req_target_uuids = []
|
619 | f380d53c | Thomas Thrainer | |
620 | f380d53c | Thomas Thrainer | if self.group_uuid in self.req_target_uuids: |
621 | f380d53c | Thomas Thrainer | raise errors.OpPrereqError("Group to be evacuated (%s) can not be used" |
622 | f380d53c | Thomas Thrainer | " as a target group (targets are %s)" %
|
623 | f380d53c | Thomas Thrainer | (self.group_uuid,
|
624 | f380d53c | Thomas Thrainer | utils.CommaJoin(self.req_target_uuids)),
|
625 | f380d53c | Thomas Thrainer | errors.ECODE_INVAL) |
626 | f380d53c | Thomas Thrainer | |
627 | 5eacbcae | Thomas Thrainer | self.op.iallocator = GetDefaultIAllocator(self.cfg, self.op.iallocator) |
628 | f380d53c | Thomas Thrainer | |
629 | 5eacbcae | Thomas Thrainer | self.share_locks = ShareAll()
|
630 | f380d53c | Thomas Thrainer | self.needed_locks = {
|
631 | f380d53c | Thomas Thrainer | locking.LEVEL_INSTANCE: [], |
632 | f380d53c | Thomas Thrainer | locking.LEVEL_NODEGROUP: [], |
633 | f380d53c | Thomas Thrainer | locking.LEVEL_NODE: [], |
634 | f380d53c | Thomas Thrainer | } |
635 | f380d53c | Thomas Thrainer | |
636 | f380d53c | Thomas Thrainer | def DeclareLocks(self, level): |
637 | f380d53c | Thomas Thrainer | if level == locking.LEVEL_INSTANCE:
|
638 | f380d53c | Thomas Thrainer | assert not self.needed_locks[locking.LEVEL_INSTANCE] |
639 | f380d53c | Thomas Thrainer | |
640 | f380d53c | Thomas Thrainer | # Lock instances optimistically, needs verification once node and group
|
641 | f380d53c | Thomas Thrainer | # locks have been acquired
|
642 | f380d53c | Thomas Thrainer | self.needed_locks[locking.LEVEL_INSTANCE] = \
|
643 | da4a52a3 | Thomas Thrainer | self.cfg.GetInstanceNames(
|
644 | da4a52a3 | Thomas Thrainer | self.cfg.GetNodeGroupInstances(self.group_uuid)) |
645 | f380d53c | Thomas Thrainer | |
646 | f380d53c | Thomas Thrainer | elif level == locking.LEVEL_NODEGROUP:
|
647 | f380d53c | Thomas Thrainer | assert not self.needed_locks[locking.LEVEL_NODEGROUP] |
648 | f380d53c | Thomas Thrainer | |
649 | f380d53c | Thomas Thrainer | if self.req_target_uuids: |
650 | f380d53c | Thomas Thrainer | lock_groups = set([self.group_uuid] + self.req_target_uuids) |
651 | f380d53c | Thomas Thrainer | |
652 | f380d53c | Thomas Thrainer | # Lock all groups used by instances optimistically; this requires going
|
653 | f380d53c | Thomas Thrainer | # via the node before it's locked, requiring verification later on
|
654 | f380d53c | Thomas Thrainer | lock_groups.update(group_uuid |
655 | f380d53c | Thomas Thrainer | for instance_name in |
656 | f380d53c | Thomas Thrainer | self.owned_locks(locking.LEVEL_INSTANCE)
|
657 | f380d53c | Thomas Thrainer | for group_uuid in |
658 | da4a52a3 | Thomas Thrainer | self.cfg.GetInstanceNodeGroups(
|
659 | da4a52a3 | Thomas Thrainer | self.cfg.GetInstanceInfoByName(instance_name)
|
660 | da4a52a3 | Thomas Thrainer | .uuid)) |
661 | f380d53c | Thomas Thrainer | else:
|
662 | f380d53c | Thomas Thrainer | # No target groups, need to lock all of them
|
663 | f380d53c | Thomas Thrainer | lock_groups = locking.ALL_SET |
664 | f380d53c | Thomas Thrainer | |
665 | f380d53c | Thomas Thrainer | self.needed_locks[locking.LEVEL_NODEGROUP] = lock_groups
|
666 | f380d53c | Thomas Thrainer | |
667 | f380d53c | Thomas Thrainer | elif level == locking.LEVEL_NODE:
|
668 | f380d53c | Thomas Thrainer | # This will only lock the nodes in the group to be evacuated which
|
669 | f380d53c | Thomas Thrainer | # contain actual instances
|
670 | f380d53c | Thomas Thrainer | self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_APPEND
|
671 | f380d53c | Thomas Thrainer | self._LockInstancesNodes()
|
672 | f380d53c | Thomas Thrainer | |
673 | f380d53c | Thomas Thrainer | # Lock all nodes in group to be evacuated and target groups
|
674 | f380d53c | Thomas Thrainer | owned_groups = frozenset(self.owned_locks(locking.LEVEL_NODEGROUP)) |
675 | f380d53c | Thomas Thrainer | assert self.group_uuid in owned_groups |
676 | 1c3231aa | Thomas Thrainer | member_node_uuids = [node_uuid |
677 | 1c3231aa | Thomas Thrainer | for group in owned_groups |
678 | 1c3231aa | Thomas Thrainer | for node_uuid in |
679 | 1c3231aa | Thomas Thrainer | self.cfg.GetNodeGroup(group).members]
|
680 | 1c3231aa | Thomas Thrainer | self.needed_locks[locking.LEVEL_NODE].extend(member_node_uuids)
|
681 | f380d53c | Thomas Thrainer | |
682 | f380d53c | Thomas Thrainer | def CheckPrereq(self): |
683 | da4a52a3 | Thomas Thrainer | owned_instance_names = frozenset(self.owned_locks(locking.LEVEL_INSTANCE)) |
684 | f380d53c | Thomas Thrainer | owned_groups = frozenset(self.owned_locks(locking.LEVEL_NODEGROUP)) |
685 | 1c3231aa | Thomas Thrainer | owned_node_uuids = frozenset(self.owned_locks(locking.LEVEL_NODE)) |
686 | f380d53c | Thomas Thrainer | |
687 | f380d53c | Thomas Thrainer | assert owned_groups.issuperset(self.req_target_uuids) |
688 | f380d53c | Thomas Thrainer | assert self.group_uuid in owned_groups |
689 | f380d53c | Thomas Thrainer | |
690 | f380d53c | Thomas Thrainer | # Check if locked instances are still correct
|
691 | da4a52a3 | Thomas Thrainer | CheckNodeGroupInstances(self.cfg, self.group_uuid, owned_instance_names) |
692 | f380d53c | Thomas Thrainer | |
693 | f380d53c | Thomas Thrainer | # Get instance information
|
694 | da4a52a3 | Thomas Thrainer | self.instances = \
|
695 | da4a52a3 | Thomas Thrainer | dict(self.cfg.GetMultiInstanceInfoByName(owned_instance_names)) |
696 | f380d53c | Thomas Thrainer | |
697 | f380d53c | Thomas Thrainer | # Check if node groups for locked instances are still correct
|
698 | 5eacbcae | Thomas Thrainer | CheckInstancesNodeGroups(self.cfg, self.instances, |
699 | 1c3231aa | Thomas Thrainer | owned_groups, owned_node_uuids, self.group_uuid)
|
700 | f380d53c | Thomas Thrainer | |
701 | f380d53c | Thomas Thrainer | if self.req_target_uuids: |
702 | f380d53c | Thomas Thrainer | # User requested specific target groups
|
703 | f380d53c | Thomas Thrainer | self.target_uuids = self.req_target_uuids |
704 | f380d53c | Thomas Thrainer | else:
|
705 | f380d53c | Thomas Thrainer | # All groups except the one to be evacuated are potential targets
|
706 | f380d53c | Thomas Thrainer | self.target_uuids = [group_uuid for group_uuid in owned_groups |
707 | f380d53c | Thomas Thrainer | if group_uuid != self.group_uuid] |
708 | f380d53c | Thomas Thrainer | |
709 | f380d53c | Thomas Thrainer | if not self.target_uuids: |
710 | f380d53c | Thomas Thrainer | raise errors.OpPrereqError("There are no possible target groups", |
711 | f380d53c | Thomas Thrainer | errors.ECODE_INVAL) |
712 | f380d53c | Thomas Thrainer | |
713 | f380d53c | Thomas Thrainer | def BuildHooksEnv(self): |
714 | f380d53c | Thomas Thrainer | """Build hooks env.
|
715 | f380d53c | Thomas Thrainer |
|
716 | f380d53c | Thomas Thrainer | """
|
717 | f380d53c | Thomas Thrainer | return {
|
718 | f380d53c | Thomas Thrainer | "GROUP_NAME": self.op.group_name, |
719 | f380d53c | Thomas Thrainer | "TARGET_GROUPS": " ".join(self.target_uuids), |
720 | f380d53c | Thomas Thrainer | } |
721 | f380d53c | Thomas Thrainer | |
722 | f380d53c | Thomas Thrainer | def BuildHooksNodes(self): |
723 | f380d53c | Thomas Thrainer | """Build hooks nodes.
|
724 | f380d53c | Thomas Thrainer |
|
725 | f380d53c | Thomas Thrainer | """
|
726 | f380d53c | Thomas Thrainer | mn = self.cfg.GetMasterNode()
|
727 | f380d53c | Thomas Thrainer | |
728 | f380d53c | Thomas Thrainer | assert self.group_uuid in self.owned_locks(locking.LEVEL_NODEGROUP) |
729 | f380d53c | Thomas Thrainer | |
730 | f380d53c | Thomas Thrainer | run_nodes = [mn] + self.cfg.GetNodeGroup(self.group_uuid).members |
731 | f380d53c | Thomas Thrainer | |
732 | f380d53c | Thomas Thrainer | return (run_nodes, run_nodes)
|
733 | f380d53c | Thomas Thrainer | |
734 | f380d53c | Thomas Thrainer | def Exec(self, feedback_fn): |
735 | da4a52a3 | Thomas Thrainer | inst_names = list(self.owned_locks(locking.LEVEL_INSTANCE)) |
736 | f380d53c | Thomas Thrainer | |
737 | f380d53c | Thomas Thrainer | assert self.group_uuid not in self.target_uuids |
738 | f380d53c | Thomas Thrainer | |
739 | da4a52a3 | Thomas Thrainer | req = iallocator.IAReqGroupChange(instances=inst_names, |
740 | f380d53c | Thomas Thrainer | target_groups=self.target_uuids)
|
741 | f380d53c | Thomas Thrainer | ial = iallocator.IAllocator(self.cfg, self.rpc, req) |
742 | f380d53c | Thomas Thrainer | |
743 | f380d53c | Thomas Thrainer | ial.Run(self.op.iallocator)
|
744 | f380d53c | Thomas Thrainer | |
745 | f380d53c | Thomas Thrainer | if not ial.success: |
746 | f380d53c | Thomas Thrainer | raise errors.OpPrereqError("Can't compute group evacuation using" |
747 | f380d53c | Thomas Thrainer | " iallocator '%s': %s" %
|
748 | f380d53c | Thomas Thrainer | (self.op.iallocator, ial.info),
|
749 | f380d53c | Thomas Thrainer | errors.ECODE_NORES) |
750 | f380d53c | Thomas Thrainer | |
751 | 5eacbcae | Thomas Thrainer | jobs = LoadNodeEvacResult(self, ial.result, self.op.early_release, False) |
752 | f380d53c | Thomas Thrainer | |
753 | f380d53c | Thomas Thrainer | self.LogInfo("Iallocator returned %s job(s) for evacuating node group %s", |
754 | f380d53c | Thomas Thrainer | len(jobs), self.op.group_name) |
755 | f380d53c | Thomas Thrainer | |
756 | f380d53c | Thomas Thrainer | return ResultWithJobs(jobs)
|
757 | f380d53c | Thomas Thrainer | |
758 | f380d53c | Thomas Thrainer | |
759 | f380d53c | Thomas Thrainer | class LUGroupVerifyDisks(NoHooksLU): |
760 | f380d53c | Thomas Thrainer | """Verifies the status of all disks in a node group.
|
761 | f380d53c | Thomas Thrainer |
|
762 | f380d53c | Thomas Thrainer | """
|
763 | f380d53c | Thomas Thrainer | REQ_BGL = False
|
764 | f380d53c | Thomas Thrainer | |
765 | f380d53c | Thomas Thrainer | def ExpandNames(self): |
766 | f380d53c | Thomas Thrainer | # Raises errors.OpPrereqError on its own if group can't be found
|
767 | f380d53c | Thomas Thrainer | self.group_uuid = self.cfg.LookupNodeGroup(self.op.group_name) |
768 | f380d53c | Thomas Thrainer | |
769 | 5eacbcae | Thomas Thrainer | self.share_locks = ShareAll()
|
770 | f380d53c | Thomas Thrainer | self.needed_locks = {
|
771 | f380d53c | Thomas Thrainer | locking.LEVEL_INSTANCE: [], |
772 | f380d53c | Thomas Thrainer | locking.LEVEL_NODEGROUP: [], |
773 | f380d53c | Thomas Thrainer | locking.LEVEL_NODE: [], |
774 | f380d53c | Thomas Thrainer | |
775 | f380d53c | Thomas Thrainer | # This opcode is acquires all node locks in a group. LUClusterVerifyDisks
|
776 | f380d53c | Thomas Thrainer | # starts one instance of this opcode for every group, which means all
|
777 | f380d53c | Thomas Thrainer | # nodes will be locked for a short amount of time, so it's better to
|
778 | f380d53c | Thomas Thrainer | # acquire the node allocation lock as well.
|
779 | f380d53c | Thomas Thrainer | locking.LEVEL_NODE_ALLOC: locking.ALL_SET, |
780 | f380d53c | Thomas Thrainer | } |
781 | f380d53c | Thomas Thrainer | |
782 | f380d53c | Thomas Thrainer | def DeclareLocks(self, level): |
783 | f380d53c | Thomas Thrainer | if level == locking.LEVEL_INSTANCE:
|
784 | f380d53c | Thomas Thrainer | assert not self.needed_locks[locking.LEVEL_INSTANCE] |
785 | f380d53c | Thomas Thrainer | |
786 | f380d53c | Thomas Thrainer | # Lock instances optimistically, needs verification once node and group
|
787 | f380d53c | Thomas Thrainer | # locks have been acquired
|
788 | f380d53c | Thomas Thrainer | self.needed_locks[locking.LEVEL_INSTANCE] = \
|
789 | da4a52a3 | Thomas Thrainer | self.cfg.GetInstanceNames(
|
790 | da4a52a3 | Thomas Thrainer | self.cfg.GetNodeGroupInstances(self.group_uuid)) |
791 | f380d53c | Thomas Thrainer | |
792 | f380d53c | Thomas Thrainer | elif level == locking.LEVEL_NODEGROUP:
|
793 | f380d53c | Thomas Thrainer | assert not self.needed_locks[locking.LEVEL_NODEGROUP] |
794 | f380d53c | Thomas Thrainer | |
795 | f380d53c | Thomas Thrainer | self.needed_locks[locking.LEVEL_NODEGROUP] = \
|
796 | f380d53c | Thomas Thrainer | set([self.group_uuid] + |
797 | f380d53c | Thomas Thrainer | # Lock all groups used by instances optimistically; this requires
|
798 | f380d53c | Thomas Thrainer | # going via the node before it's locked, requiring verification
|
799 | f380d53c | Thomas Thrainer | # later on
|
800 | f380d53c | Thomas Thrainer | [group_uuid |
801 | f380d53c | Thomas Thrainer | for instance_name in self.owned_locks(locking.LEVEL_INSTANCE) |
802 | da4a52a3 | Thomas Thrainer | for group_uuid in |
803 | da4a52a3 | Thomas Thrainer | self.cfg.GetInstanceNodeGroups(
|
804 | da4a52a3 | Thomas Thrainer | self.cfg.GetInstanceInfoByName(instance_name).uuid)])
|
805 | f380d53c | Thomas Thrainer | |
806 | f380d53c | Thomas Thrainer | elif level == locking.LEVEL_NODE:
|
807 | f380d53c | Thomas Thrainer | # This will only lock the nodes in the group to be verified which contain
|
808 | f380d53c | Thomas Thrainer | # actual instances
|
809 | f380d53c | Thomas Thrainer | self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_APPEND
|
810 | f380d53c | Thomas Thrainer | self._LockInstancesNodes()
|
811 | f380d53c | Thomas Thrainer | |
812 | f380d53c | Thomas Thrainer | # Lock all nodes in group to be verified
|
813 | f380d53c | Thomas Thrainer | assert self.group_uuid in self.owned_locks(locking.LEVEL_NODEGROUP) |
814 | 1c3231aa | Thomas Thrainer | member_node_uuids = self.cfg.GetNodeGroup(self.group_uuid).members |
815 | 1c3231aa | Thomas Thrainer | self.needed_locks[locking.LEVEL_NODE].extend(member_node_uuids)
|
816 | f380d53c | Thomas Thrainer | |
817 | f380d53c | Thomas Thrainer | def CheckPrereq(self): |
818 | da4a52a3 | Thomas Thrainer | owned_inst_names = frozenset(self.owned_locks(locking.LEVEL_INSTANCE)) |
819 | f380d53c | Thomas Thrainer | owned_groups = frozenset(self.owned_locks(locking.LEVEL_NODEGROUP)) |
820 | 1c3231aa | Thomas Thrainer | owned_node_uuids = frozenset(self.owned_locks(locking.LEVEL_NODE)) |
821 | f380d53c | Thomas Thrainer | |
822 | f380d53c | Thomas Thrainer | assert self.group_uuid in owned_groups |
823 | f380d53c | Thomas Thrainer | |
824 | f380d53c | Thomas Thrainer | # Check if locked instances are still correct
|
825 | da4a52a3 | Thomas Thrainer | CheckNodeGroupInstances(self.cfg, self.group_uuid, owned_inst_names) |
826 | f380d53c | Thomas Thrainer | |
827 | f380d53c | Thomas Thrainer | # Get instance information
|
828 | da4a52a3 | Thomas Thrainer | self.instances = dict(self.cfg.GetMultiInstanceInfoByName(owned_inst_names)) |
829 | f380d53c | Thomas Thrainer | |
830 | f380d53c | Thomas Thrainer | # Check if node groups for locked instances are still correct
|
831 | 5eacbcae | Thomas Thrainer | CheckInstancesNodeGroups(self.cfg, self.instances, |
832 | 1c3231aa | Thomas Thrainer | owned_groups, owned_node_uuids, self.group_uuid)
|
833 | f380d53c | Thomas Thrainer | |
834 | 235a6b29 | Thomas Thrainer | def _VerifyInstanceLvs(self, node_errors, offline_disk_instance_names, |
835 | 235a6b29 | Thomas Thrainer | missing_disks): |
836 | 843094ad | Thomas Thrainer | node_lv_to_inst = MapInstanceLvsToNodes( |
837 | 1d4a4b26 | Thomas Thrainer | [inst for inst in self.instances.values() if inst.disks_active]) |
838 | 843094ad | Thomas Thrainer | if node_lv_to_inst:
|
839 | 1c3231aa | Thomas Thrainer | node_uuids = utils.NiceSort(set(self.owned_locks(locking.LEVEL_NODE)) & |
840 | 1c3231aa | Thomas Thrainer | set(self.cfg.GetVmCapableNodeList())) |
841 | f380d53c | Thomas Thrainer | |
842 | 1c3231aa | Thomas Thrainer | node_lvs = self.rpc.call_lv_list(node_uuids, [])
|
843 | f380d53c | Thomas Thrainer | |
844 | 1c3231aa | Thomas Thrainer | for (node_uuid, node_res) in node_lvs.items(): |
845 | f380d53c | Thomas Thrainer | if node_res.offline:
|
846 | f380d53c | Thomas Thrainer | continue
|
847 | f380d53c | Thomas Thrainer | |
848 | f380d53c | Thomas Thrainer | msg = node_res.fail_msg |
849 | f380d53c | Thomas Thrainer | if msg:
|
850 | 1c3231aa | Thomas Thrainer | logging.warning("Error enumerating LVs on node %s: %s",
|
851 | 1c3231aa | Thomas Thrainer | self.cfg.GetNodeName(node_uuid), msg)
|
852 | 843094ad | Thomas Thrainer | node_errors[node_uuid] = msg |
853 | f380d53c | Thomas Thrainer | continue
|
854 | f380d53c | Thomas Thrainer | |
855 | f380d53c | Thomas Thrainer | for lv_name, (_, _, lv_online) in node_res.payload.items(): |
856 | 843094ad | Thomas Thrainer | inst = node_lv_to_inst.pop((node_uuid, lv_name), None)
|
857 | 843094ad | Thomas Thrainer | if not lv_online and inst is not None: |
858 | 235a6b29 | Thomas Thrainer | offline_disk_instance_names.add(inst.name) |
859 | f380d53c | Thomas Thrainer | |
860 | f380d53c | Thomas Thrainer | # any leftover items in nv_dict are missing LVs, let's arrange the data
|
861 | f380d53c | Thomas Thrainer | # better
|
862 | 843094ad | Thomas Thrainer | for key, inst in node_lv_to_inst.iteritems(): |
863 | 235a6b29 | Thomas Thrainer | missing_disks.setdefault(inst.name, []).append(list(key))
|
864 | 235a6b29 | Thomas Thrainer | |
865 | 235a6b29 | Thomas Thrainer | def _VerifyDrbdStates(self, node_errors, offline_disk_instance_names): |
866 | 235a6b29 | Thomas Thrainer | node_to_inst = {} |
867 | 235a6b29 | Thomas Thrainer | for inst in self.instances.values(): |
868 | 235a6b29 | Thomas Thrainer | if not inst.disks_active or inst.disk_template != constants.DT_DRBD8: |
869 | 235a6b29 | Thomas Thrainer | continue
|
870 | 235a6b29 | Thomas Thrainer | |
871 | 235a6b29 | Thomas Thrainer | for node_uuid in itertools.chain([inst.primary_node], |
872 | 235a6b29 | Thomas Thrainer | inst.secondary_nodes): |
873 | 235a6b29 | Thomas Thrainer | node_to_inst.setdefault(node_uuid, []).append(inst) |
874 | 235a6b29 | Thomas Thrainer | |
875 | 235a6b29 | Thomas Thrainer | for (node_uuid, insts) in node_to_inst.items(): |
876 | 235a6b29 | Thomas Thrainer | node_disks = [(inst.disks, inst) for inst in insts] |
877 | 0c3d9c7c | Thomas Thrainer | node_res = self.rpc.call_drbd_needs_activation(node_uuid, node_disks)
|
878 | 235a6b29 | Thomas Thrainer | msg = node_res.fail_msg |
879 | 235a6b29 | Thomas Thrainer | if msg:
|
880 | 235a6b29 | Thomas Thrainer | logging.warning("Error getting DRBD status on node %s: %s",
|
881 | 235a6b29 | Thomas Thrainer | self.cfg.GetNodeName(node_uuid), msg)
|
882 | 235a6b29 | Thomas Thrainer | node_errors[node_uuid] = msg |
883 | 235a6b29 | Thomas Thrainer | continue
|
884 | 235a6b29 | Thomas Thrainer | |
885 | 235a6b29 | Thomas Thrainer | faulty_disk_uuids = set(node_res.payload)
|
886 | 235a6b29 | Thomas Thrainer | for inst in self.instances.values(): |
887 | 235a6b29 | Thomas Thrainer | inst_disk_uuids = set([disk.uuid for disk in inst.disks]) |
888 | 235a6b29 | Thomas Thrainer | if inst_disk_uuids.intersection(faulty_disk_uuids):
|
889 | 235a6b29 | Thomas Thrainer | offline_disk_instance_names.add(inst.name) |
890 | 235a6b29 | Thomas Thrainer | |
891 | 235a6b29 | Thomas Thrainer | def Exec(self, feedback_fn): |
892 | 235a6b29 | Thomas Thrainer | """Verify integrity of cluster disks.
|
893 | 235a6b29 | Thomas Thrainer |
|
894 | 235a6b29 | Thomas Thrainer | @rtype: tuple of three items
|
895 | 235a6b29 | Thomas Thrainer | @return: a tuple of (dict of node-to-node_error, list of instances
|
896 | 235a6b29 | Thomas Thrainer | which need activate-disks, dict of instance: (node, volume) for
|
897 | 235a6b29 | Thomas Thrainer | missing volumes
|
898 | 235a6b29 | Thomas Thrainer |
|
899 | 235a6b29 | Thomas Thrainer | """
|
900 | 235a6b29 | Thomas Thrainer | node_errors = {} |
901 | 235a6b29 | Thomas Thrainer | offline_disk_instance_names = set()
|
902 | 235a6b29 | Thomas Thrainer | missing_disks = {} |
903 | 235a6b29 | Thomas Thrainer | |
904 | 235a6b29 | Thomas Thrainer | self._VerifyInstanceLvs(node_errors, offline_disk_instance_names,
|
905 | 235a6b29 | Thomas Thrainer | missing_disks) |
906 | 235a6b29 | Thomas Thrainer | self._VerifyDrbdStates(node_errors, offline_disk_instance_names)
|
907 | f380d53c | Thomas Thrainer | |
908 | 235a6b29 | Thomas Thrainer | return (node_errors, list(offline_disk_instance_names), missing_disks) |