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