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