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