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