root / lib / masterd / iallocator.py @ b82d7182
History | View | Annotate | Download (25 kB)
1 | 0fcd0cad | René Nussbaumer | #
|
---|---|---|---|
2 | 0fcd0cad | René Nussbaumer | #
|
3 | 0fcd0cad | René Nussbaumer | |
4 | 473d87a3 | Iustin Pop | # Copyright (C) 2012, 2013 Google Inc.
|
5 | 0fcd0cad | René Nussbaumer | #
|
6 | 0fcd0cad | René Nussbaumer | # This program is free software; you can redistribute it and/or modify
|
7 | 0fcd0cad | René Nussbaumer | # it under the terms of the GNU General Public License as published by
|
8 | 0fcd0cad | René Nussbaumer | # the Free Software Foundation; either version 2 of the License, or
|
9 | 0fcd0cad | René Nussbaumer | # (at your option) any later version.
|
10 | 0fcd0cad | René Nussbaumer | #
|
11 | 0fcd0cad | René Nussbaumer | # This program is distributed in the hope that it will be useful, but
|
12 | 0fcd0cad | René Nussbaumer | # WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 | 0fcd0cad | René Nussbaumer | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14 | 0fcd0cad | René Nussbaumer | # General Public License for more details.
|
15 | 0fcd0cad | René Nussbaumer | #
|
16 | 0fcd0cad | René Nussbaumer | # You should have received a copy of the GNU General Public License
|
17 | 0fcd0cad | René Nussbaumer | # along with this program; if not, write to the Free Software
|
18 | 0fcd0cad | René Nussbaumer | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
19 | 0fcd0cad | René Nussbaumer | # 02110-1301, USA.
|
20 | 0fcd0cad | René Nussbaumer | |
21 | 0fcd0cad | René Nussbaumer | |
22 | 0fcd0cad | René Nussbaumer | """Module implementing the iallocator code."""
|
23 | 0fcd0cad | René Nussbaumer | |
24 | 0fcd0cad | René Nussbaumer | from ganeti import compat |
25 | 0fcd0cad | René Nussbaumer | from ganeti import constants |
26 | 0fcd0cad | René Nussbaumer | from ganeti import errors |
27 | 0fcd0cad | René Nussbaumer | from ganeti import ht |
28 | 473d87a3 | Iustin Pop | from ganeti import outils |
29 | 0fcd0cad | René Nussbaumer | from ganeti import opcodes |
30 | 0fcd0cad | René Nussbaumer | from ganeti import rpc |
31 | 0fcd0cad | René Nussbaumer | from ganeti import serializer |
32 | 0fcd0cad | René Nussbaumer | from ganeti import utils |
33 | 0fcd0cad | René Nussbaumer | |
34 | 0fcd0cad | René Nussbaumer | import ganeti.masterd.instance as gmi |
35 | 0fcd0cad | René Nussbaumer | |
36 | 0fcd0cad | René Nussbaumer | |
37 | 0fcd0cad | René Nussbaumer | _STRING_LIST = ht.TListOf(ht.TString) |
38 | 0fcd0cad | René Nussbaumer | _JOB_LIST = ht.TListOf(ht.TListOf(ht.TStrictDict(True, False, { |
39 | 0fcd0cad | René Nussbaumer | # pylint: disable=E1101
|
40 | 0fcd0cad | René Nussbaumer | # Class '...' has no 'OP_ID' member
|
41 | 0fcd0cad | René Nussbaumer | "OP_ID": ht.TElemOf([opcodes.OpInstanceFailover.OP_ID,
|
42 | 0fcd0cad | René Nussbaumer | opcodes.OpInstanceMigrate.OP_ID, |
43 | 3c286190 | Dimitris Aragiorgis | opcodes.OpInstanceReplaceDisks.OP_ID]), |
44 | 0fcd0cad | René Nussbaumer | }))) |
45 | 0fcd0cad | René Nussbaumer | |
46 | 0fcd0cad | René Nussbaumer | _NEVAC_MOVED = \ |
47 | 0fcd0cad | René Nussbaumer | ht.TListOf(ht.TAnd(ht.TIsLength(3),
|
48 | 0fcd0cad | René Nussbaumer | ht.TItems([ht.TNonEmptyString, |
49 | 0fcd0cad | René Nussbaumer | ht.TNonEmptyString, |
50 | 0fcd0cad | René Nussbaumer | ht.TListOf(ht.TNonEmptyString), |
51 | 0fcd0cad | René Nussbaumer | ]))) |
52 | 0fcd0cad | René Nussbaumer | _NEVAC_FAILED = \ |
53 | 0fcd0cad | René Nussbaumer | ht.TListOf(ht.TAnd(ht.TIsLength(2),
|
54 | 0fcd0cad | René Nussbaumer | ht.TItems([ht.TNonEmptyString, |
55 | 0fcd0cad | René Nussbaumer | ht.TMaybeString, |
56 | 0fcd0cad | René Nussbaumer | ]))) |
57 | 0fcd0cad | René Nussbaumer | _NEVAC_RESULT = ht.TAnd(ht.TIsLength(3),
|
58 | 0fcd0cad | René Nussbaumer | ht.TItems([_NEVAC_MOVED, _NEVAC_FAILED, _JOB_LIST])) |
59 | 0fcd0cad | René Nussbaumer | |
60 | 3d7d3a12 | René Nussbaumer | _INST_NAME = ("name", ht.TNonEmptyString)
|
61 | da4a52a3 | Thomas Thrainer | _INST_UUID = ("inst_uuid", ht.TNonEmptyString)
|
62 | 3d7d3a12 | René Nussbaumer | |
63 | 0fcd0cad | René Nussbaumer | |
64 | 473d87a3 | Iustin Pop | class _AutoReqParam(outils.AutoSlots): |
65 | 0fcd0cad | René Nussbaumer | """Meta class for request definitions.
|
66 | 0fcd0cad | René Nussbaumer |
|
67 | 0fcd0cad | René Nussbaumer | """
|
68 | 0fcd0cad | René Nussbaumer | @classmethod
|
69 | 0fcd0cad | René Nussbaumer | def _GetSlots(mcs, attrs): |
70 | 0fcd0cad | René Nussbaumer | """Extract the slots out of REQ_PARAMS.
|
71 | 0fcd0cad | René Nussbaumer |
|
72 | 0fcd0cad | René Nussbaumer | """
|
73 | 0fcd0cad | René Nussbaumer | params = attrs.setdefault("REQ_PARAMS", [])
|
74 | 0fcd0cad | René Nussbaumer | return [slot for (slot, _) in params] |
75 | 0fcd0cad | René Nussbaumer | |
76 | 0fcd0cad | René Nussbaumer | |
77 | 473d87a3 | Iustin Pop | class IARequestBase(outils.ValidatedSlots): |
78 | 0fcd0cad | René Nussbaumer | """A generic IAllocator request object.
|
79 | 0fcd0cad | René Nussbaumer |
|
80 | 0fcd0cad | René Nussbaumer | """
|
81 | 0fcd0cad | René Nussbaumer | __metaclass__ = _AutoReqParam |
82 | 0fcd0cad | René Nussbaumer | |
83 | 0fcd0cad | René Nussbaumer | MODE = NotImplemented
|
84 | 776b6291 | René Nussbaumer | REQ_PARAMS = [] |
85 | 0fcd0cad | René Nussbaumer | REQ_RESULT = NotImplemented
|
86 | 0fcd0cad | René Nussbaumer | |
87 | 0fcd0cad | René Nussbaumer | def __init__(self, **kwargs): |
88 | 0fcd0cad | René Nussbaumer | """Constructor for IARequestBase.
|
89 | 0fcd0cad | René Nussbaumer |
|
90 | 0fcd0cad | René Nussbaumer | The constructor takes only keyword arguments and will set
|
91 | 0fcd0cad | René Nussbaumer | attributes on this object based on the passed arguments. As such,
|
92 | 0fcd0cad | René Nussbaumer | it means that you should not pass arguments which are not in the
|
93 | 0fcd0cad | René Nussbaumer | REQ_PARAMS attribute for this class.
|
94 | 0fcd0cad | René Nussbaumer |
|
95 | 0fcd0cad | René Nussbaumer | """
|
96 | 473d87a3 | Iustin Pop | outils.ValidatedSlots.__init__(self, **kwargs)
|
97 | 0fcd0cad | René Nussbaumer | |
98 | 0fcd0cad | René Nussbaumer | self.Validate()
|
99 | 0fcd0cad | René Nussbaumer | |
100 | 0fcd0cad | René Nussbaumer | def Validate(self): |
101 | 0fcd0cad | René Nussbaumer | """Validates all parameters of the request.
|
102 | 0fcd0cad | René Nussbaumer |
|
103 | 0fcd0cad | René Nussbaumer | """
|
104 | 0fcd0cad | René Nussbaumer | assert self.MODE in constants.VALID_IALLOCATOR_MODES |
105 | 0fcd0cad | René Nussbaumer | |
106 | 0fcd0cad | René Nussbaumer | for (param, validator) in self.REQ_PARAMS: |
107 | 0fcd0cad | René Nussbaumer | if not hasattr(self, param): |
108 | 0fcd0cad | René Nussbaumer | raise errors.OpPrereqError("Request is missing '%s' parameter" % param, |
109 | 0fcd0cad | René Nussbaumer | errors.ECODE_INVAL) |
110 | 0fcd0cad | René Nussbaumer | |
111 | 0fcd0cad | René Nussbaumer | value = getattr(self, param) |
112 | 0fcd0cad | René Nussbaumer | if not validator(value): |
113 | 0fcd0cad | René Nussbaumer | raise errors.OpPrereqError(("Request parameter '%s' has invalid" |
114 | 0fcd0cad | René Nussbaumer | " type %s/value %s") %
|
115 | 0fcd0cad | René Nussbaumer | (param, type(value), value),
|
116 | 0fcd0cad | René Nussbaumer | errors.ECODE_INVAL) |
117 | 0fcd0cad | René Nussbaumer | |
118 | 0fcd0cad | René Nussbaumer | def GetRequest(self, cfg): |
119 | 0fcd0cad | René Nussbaumer | """Gets the request data dict.
|
120 | 0fcd0cad | René Nussbaumer |
|
121 | 0fcd0cad | René Nussbaumer | @param cfg: The configuration instance
|
122 | 0fcd0cad | René Nussbaumer |
|
123 | 0fcd0cad | René Nussbaumer | """
|
124 | 0fcd0cad | René Nussbaumer | raise NotImplementedError |
125 | 0fcd0cad | René Nussbaumer | |
126 | 0fcd0cad | René Nussbaumer | def ValidateResult(self, ia, result): |
127 | 0fcd0cad | René Nussbaumer | """Validates the result of an request.
|
128 | 0fcd0cad | René Nussbaumer |
|
129 | 0fcd0cad | René Nussbaumer | @param ia: The IAllocator instance
|
130 | 0fcd0cad | René Nussbaumer | @param result: The IAllocator run result
|
131 | 776b6291 | René Nussbaumer | @raises ResultValidationError: If validation fails
|
132 | 0fcd0cad | René Nussbaumer |
|
133 | 0fcd0cad | René Nussbaumer | """
|
134 | 69b0d82a | René Nussbaumer | if ia.success and not self.REQ_RESULT(result): |
135 | 776b6291 | René Nussbaumer | raise errors.ResultValidationError("iallocator returned invalid result," |
136 | 776b6291 | René Nussbaumer | " expected %s, got %s" %
|
137 | 776b6291 | René Nussbaumer | (self.REQ_RESULT, result))
|
138 | 0fcd0cad | René Nussbaumer | |
139 | 0fcd0cad | René Nussbaumer | |
140 | 0fcd0cad | René Nussbaumer | class IAReqInstanceAlloc(IARequestBase): |
141 | 0fcd0cad | René Nussbaumer | """An instance allocation request.
|
142 | 0fcd0cad | René Nussbaumer |
|
143 | 0fcd0cad | René Nussbaumer | """
|
144 | c269efc3 | René Nussbaumer | # pylint: disable=E1101
|
145 | 0fcd0cad | René Nussbaumer | MODE = constants.IALLOCATOR_MODE_ALLOC |
146 | 0fcd0cad | René Nussbaumer | REQ_PARAMS = [ |
147 | 3d7d3a12 | René Nussbaumer | _INST_NAME, |
148 | 2c9fa1ff | Iustin Pop | ("memory", ht.TNonNegativeInt),
|
149 | 2c9fa1ff | Iustin Pop | ("spindle_use", ht.TNonNegativeInt),
|
150 | 0fcd0cad | René Nussbaumer | ("disks", ht.TListOf(ht.TDict)),
|
151 | 0fcd0cad | René Nussbaumer | ("disk_template", ht.TString),
|
152 | 0fcd0cad | René Nussbaumer | ("os", ht.TString),
|
153 | 0fcd0cad | René Nussbaumer | ("tags", _STRING_LIST),
|
154 | 0fcd0cad | René Nussbaumer | ("nics", ht.TListOf(ht.TDict)),
|
155 | 0fcd0cad | René Nussbaumer | ("vcpus", ht.TInt),
|
156 | 0fcd0cad | René Nussbaumer | ("hypervisor", ht.TString),
|
157 | fb60bc6a | Michael Hanselmann | ("node_whitelist", ht.TMaybeListOf(ht.TNonEmptyString)),
|
158 | 0fcd0cad | René Nussbaumer | ] |
159 | 0fcd0cad | René Nussbaumer | REQ_RESULT = ht.TList |
160 | 0fcd0cad | René Nussbaumer | |
161 | 776b6291 | René Nussbaumer | def RequiredNodes(self): |
162 | 776b6291 | René Nussbaumer | """Calculates the required nodes based on the disk_template.
|
163 | 776b6291 | René Nussbaumer |
|
164 | 776b6291 | René Nussbaumer | """
|
165 | 776b6291 | René Nussbaumer | if self.disk_template in constants.DTS_INT_MIRROR: |
166 | 776b6291 | René Nussbaumer | return 2 |
167 | 776b6291 | René Nussbaumer | else:
|
168 | 776b6291 | René Nussbaumer | return 1 |
169 | 776b6291 | René Nussbaumer | |
170 | 0fcd0cad | René Nussbaumer | def GetRequest(self, cfg): |
171 | 0fcd0cad | René Nussbaumer | """Requests a new instance.
|
172 | 0fcd0cad | René Nussbaumer |
|
173 | 0fcd0cad | René Nussbaumer | The checks for the completeness of the opcode must have already been
|
174 | 0fcd0cad | René Nussbaumer | done.
|
175 | 0fcd0cad | René Nussbaumer |
|
176 | 0fcd0cad | René Nussbaumer | """
|
177 | 0fcd0cad | René Nussbaumer | disk_space = gmi.ComputeDiskSize(self.disk_template, self.disks) |
178 | 0fcd0cad | René Nussbaumer | |
179 | 0fcd0cad | René Nussbaumer | return {
|
180 | 0fcd0cad | René Nussbaumer | "name": self.name, |
181 | 0fcd0cad | René Nussbaumer | "disk_template": self.disk_template, |
182 | 0fcd0cad | René Nussbaumer | "tags": self.tags, |
183 | 0fcd0cad | René Nussbaumer | "os": self.os, |
184 | 0fcd0cad | René Nussbaumer | "vcpus": self.vcpus, |
185 | 0fcd0cad | René Nussbaumer | "memory": self.memory, |
186 | 0fcd0cad | René Nussbaumer | "spindle_use": self.spindle_use, |
187 | 0fcd0cad | René Nussbaumer | "disks": self.disks, |
188 | 0fcd0cad | René Nussbaumer | "disk_space_total": disk_space,
|
189 | 0fcd0cad | René Nussbaumer | "nics": self.nics, |
190 | 776b6291 | René Nussbaumer | "required_nodes": self.RequiredNodes(), |
191 | 0fcd0cad | René Nussbaumer | "hypervisor": self.hypervisor, |
192 | 0fcd0cad | René Nussbaumer | } |
193 | 0fcd0cad | René Nussbaumer | |
194 | 776b6291 | René Nussbaumer | def ValidateResult(self, ia, result): |
195 | 776b6291 | René Nussbaumer | """Validates an single instance allocation request.
|
196 | 776b6291 | René Nussbaumer |
|
197 | 776b6291 | René Nussbaumer | """
|
198 | 776b6291 | René Nussbaumer | IARequestBase.ValidateResult(self, ia, result)
|
199 | 776b6291 | René Nussbaumer | |
200 | 579f4ee5 | René Nussbaumer | if ia.success and len(result) != self.RequiredNodes(): |
201 | 776b6291 | René Nussbaumer | raise errors.ResultValidationError("iallocator returned invalid number" |
202 | 776b6291 | René Nussbaumer | " of nodes (%s), required %s" %
|
203 | 776b6291 | René Nussbaumer | (len(result), self.RequiredNodes())) |
204 | 776b6291 | René Nussbaumer | |
205 | 0fcd0cad | René Nussbaumer | |
206 | b1e47e2d | René Nussbaumer | class IAReqMultiInstanceAlloc(IARequestBase): |
207 | b1e47e2d | René Nussbaumer | """An multi instance allocation request.
|
208 | b1e47e2d | René Nussbaumer |
|
209 | b1e47e2d | René Nussbaumer | """
|
210 | c269efc3 | René Nussbaumer | # pylint: disable=E1101
|
211 | b1e47e2d | René Nussbaumer | MODE = constants.IALLOCATOR_MODE_MULTI_ALLOC |
212 | b1e47e2d | René Nussbaumer | REQ_PARAMS = [ |
213 | 3c286190 | Dimitris Aragiorgis | ("instances", ht.TListOf(ht.TInstanceOf(IAReqInstanceAlloc))),
|
214 | b1e47e2d | René Nussbaumer | ] |
215 | b1e47e2d | René Nussbaumer | _MASUCCESS = \ |
216 | b1e47e2d | René Nussbaumer | ht.TListOf(ht.TAnd(ht.TIsLength(2),
|
217 | b1e47e2d | René Nussbaumer | ht.TItems([ht.TNonEmptyString, |
218 | b1e47e2d | René Nussbaumer | ht.TListOf(ht.TNonEmptyString), |
219 | b1e47e2d | René Nussbaumer | ]))) |
220 | b1e47e2d | René Nussbaumer | _MAFAILED = ht.TListOf(ht.TNonEmptyString) |
221 | 32eae1ec | René Nussbaumer | REQ_RESULT = ht.TAnd(ht.TList, ht.TIsLength(2),
|
222 | 32eae1ec | René Nussbaumer | ht.TItems([_MASUCCESS, _MAFAILED])) |
223 | b1e47e2d | René Nussbaumer | |
224 | b1e47e2d | René Nussbaumer | def GetRequest(self, cfg): |
225 | b1e47e2d | René Nussbaumer | return {
|
226 | 3c286190 | Dimitris Aragiorgis | "instances": [iareq.GetRequest(cfg) for iareq in self.instances], |
227 | b1e47e2d | René Nussbaumer | } |
228 | b1e47e2d | René Nussbaumer | |
229 | b1e47e2d | René Nussbaumer | |
230 | 0fcd0cad | René Nussbaumer | class IAReqRelocate(IARequestBase): |
231 | 0fcd0cad | René Nussbaumer | """A relocation request.
|
232 | 0fcd0cad | René Nussbaumer |
|
233 | 0fcd0cad | René Nussbaumer | """
|
234 | c269efc3 | René Nussbaumer | # pylint: disable=E1101
|
235 | 0fcd0cad | René Nussbaumer | MODE = constants.IALLOCATOR_MODE_RELOC |
236 | 0fcd0cad | René Nussbaumer | REQ_PARAMS = [ |
237 | da4a52a3 | Thomas Thrainer | _INST_UUID, |
238 | 1c3231aa | Thomas Thrainer | ("relocate_from_node_uuids", _STRING_LIST),
|
239 | 0fcd0cad | René Nussbaumer | ] |
240 | 0fcd0cad | René Nussbaumer | REQ_RESULT = ht.TList |
241 | 0fcd0cad | René Nussbaumer | |
242 | 0fcd0cad | René Nussbaumer | def GetRequest(self, cfg): |
243 | 0fcd0cad | René Nussbaumer | """Request an relocation of an instance
|
244 | 0fcd0cad | René Nussbaumer |
|
245 | 0fcd0cad | René Nussbaumer | The checks for the completeness of the opcode must have already been
|
246 | 0fcd0cad | René Nussbaumer | done.
|
247 | 0fcd0cad | René Nussbaumer |
|
248 | 0fcd0cad | René Nussbaumer | """
|
249 | da4a52a3 | Thomas Thrainer | instance = cfg.GetInstanceInfo(self.inst_uuid)
|
250 | 0fcd0cad | René Nussbaumer | if instance is None: |
251 | 0fcd0cad | René Nussbaumer | raise errors.ProgrammerError("Unknown instance '%s' passed to" |
252 | da4a52a3 | Thomas Thrainer | " IAllocator" % self.inst_uuid) |
253 | 0fcd0cad | René Nussbaumer | |
254 | 0fcd0cad | René Nussbaumer | if instance.disk_template not in constants.DTS_MIRRORED: |
255 | 0fcd0cad | René Nussbaumer | raise errors.OpPrereqError("Can't relocate non-mirrored instances", |
256 | 0fcd0cad | René Nussbaumer | errors.ECODE_INVAL) |
257 | 0fcd0cad | René Nussbaumer | |
258 | 6953756f | René Nussbaumer | if (instance.disk_template in constants.DTS_INT_MIRROR and |
259 | 6953756f | René Nussbaumer | len(instance.secondary_nodes) != 1): |
260 | 0fcd0cad | René Nussbaumer | raise errors.OpPrereqError("Instance has not exactly one secondary node", |
261 | 0fcd0cad | René Nussbaumer | errors.ECODE_STATE) |
262 | 0fcd0cad | René Nussbaumer | |
263 | 0fcd0cad | René Nussbaumer | disk_sizes = [{constants.IDISK_SIZE: disk.size} for disk in instance.disks] |
264 | 0fcd0cad | René Nussbaumer | disk_space = gmi.ComputeDiskSize(instance.disk_template, disk_sizes) |
265 | 0fcd0cad | René Nussbaumer | |
266 | 0fcd0cad | René Nussbaumer | return {
|
267 | da4a52a3 | Thomas Thrainer | "name": instance.name,
|
268 | 0fcd0cad | René Nussbaumer | "disk_space_total": disk_space,
|
269 | 776b6291 | René Nussbaumer | "required_nodes": 1, |
270 | 1c3231aa | Thomas Thrainer | "relocate_from": cfg.GetNodeNames(self.relocate_from_node_uuids), |
271 | 0fcd0cad | René Nussbaumer | } |
272 | 0fcd0cad | René Nussbaumer | |
273 | 0fcd0cad | René Nussbaumer | def ValidateResult(self, ia, result): |
274 | 0fcd0cad | René Nussbaumer | """Validates the result of an relocation request.
|
275 | 0fcd0cad | René Nussbaumer |
|
276 | 0fcd0cad | René Nussbaumer | """
|
277 | 776b6291 | René Nussbaumer | IARequestBase.ValidateResult(self, ia, result)
|
278 | 776b6291 | René Nussbaumer | |
279 | 0fcd0cad | René Nussbaumer | node2group = dict((name, ndata["group"]) |
280 | 0fcd0cad | René Nussbaumer | for (name, ndata) in ia.in_data["nodes"].items()) |
281 | 0fcd0cad | René Nussbaumer | |
282 | 0fcd0cad | René Nussbaumer | fn = compat.partial(self._NodesToGroups, node2group,
|
283 | 0fcd0cad | René Nussbaumer | ia.in_data["nodegroups"])
|
284 | 0fcd0cad | René Nussbaumer | |
285 | da4a52a3 | Thomas Thrainer | instance = ia.cfg.GetInstanceInfo(self.inst_uuid)
|
286 | 1c3231aa | Thomas Thrainer | request_groups = fn(ia.cfg.GetNodeNames(self.relocate_from_node_uuids) +
|
287 | 1c3231aa | Thomas Thrainer | ia.cfg.GetNodeNames([instance.primary_node])) |
288 | 1c3231aa | Thomas Thrainer | result_groups = fn(result + ia.cfg.GetNodeNames([instance.primary_node])) |
289 | 0fcd0cad | René Nussbaumer | |
290 | 0fcd0cad | René Nussbaumer | if ia.success and not set(result_groups).issubset(request_groups): |
291 | 776b6291 | René Nussbaumer | raise errors.ResultValidationError("Groups of nodes returned by" |
292 | 1c3231aa | Thomas Thrainer | " iallocator (%s) differ from original"
|
293 | 776b6291 | René Nussbaumer | " groups (%s)" %
|
294 | 776b6291 | René Nussbaumer | (utils.CommaJoin(result_groups), |
295 | 776b6291 | René Nussbaumer | utils.CommaJoin(request_groups))) |
296 | 0fcd0cad | René Nussbaumer | |
297 | 0fcd0cad | René Nussbaumer | @staticmethod
|
298 | 0fcd0cad | René Nussbaumer | def _NodesToGroups(node2group, groups, nodes): |
299 | 0fcd0cad | René Nussbaumer | """Returns a list of unique group names for a list of nodes.
|
300 | 0fcd0cad | René Nussbaumer |
|
301 | 0fcd0cad | René Nussbaumer | @type node2group: dict
|
302 | 0fcd0cad | René Nussbaumer | @param node2group: Map from node name to group UUID
|
303 | 0fcd0cad | René Nussbaumer | @type groups: dict
|
304 | 0fcd0cad | René Nussbaumer | @param groups: Group information
|
305 | 0fcd0cad | René Nussbaumer | @type nodes: list
|
306 | 0fcd0cad | René Nussbaumer | @param nodes: Node names
|
307 | 0fcd0cad | René Nussbaumer |
|
308 | 0fcd0cad | René Nussbaumer | """
|
309 | 0fcd0cad | René Nussbaumer | result = set()
|
310 | 0fcd0cad | René Nussbaumer | |
311 | 0fcd0cad | René Nussbaumer | for node in nodes: |
312 | 0fcd0cad | René Nussbaumer | try:
|
313 | 0fcd0cad | René Nussbaumer | group_uuid = node2group[node] |
314 | 0fcd0cad | René Nussbaumer | except KeyError: |
315 | 0fcd0cad | René Nussbaumer | # Ignore unknown node
|
316 | 0fcd0cad | René Nussbaumer | pass
|
317 | 0fcd0cad | René Nussbaumer | else:
|
318 | 0fcd0cad | René Nussbaumer | try:
|
319 | 0fcd0cad | René Nussbaumer | group = groups[group_uuid] |
320 | 0fcd0cad | René Nussbaumer | except KeyError: |
321 | 0fcd0cad | René Nussbaumer | # Can't find group, let's use UUID
|
322 | 0fcd0cad | René Nussbaumer | group_name = group_uuid |
323 | 0fcd0cad | René Nussbaumer | else:
|
324 | 0fcd0cad | René Nussbaumer | group_name = group["name"]
|
325 | 0fcd0cad | René Nussbaumer | |
326 | 0fcd0cad | René Nussbaumer | result.add(group_name) |
327 | 0fcd0cad | René Nussbaumer | |
328 | 0fcd0cad | René Nussbaumer | return sorted(result) |
329 | 0fcd0cad | René Nussbaumer | |
330 | 0fcd0cad | René Nussbaumer | |
331 | 0fcd0cad | René Nussbaumer | class IAReqNodeEvac(IARequestBase): |
332 | 0fcd0cad | René Nussbaumer | """A node evacuation request.
|
333 | 0fcd0cad | René Nussbaumer |
|
334 | 0fcd0cad | René Nussbaumer | """
|
335 | c269efc3 | René Nussbaumer | # pylint: disable=E1101
|
336 | 0fcd0cad | René Nussbaumer | MODE = constants.IALLOCATOR_MODE_NODE_EVAC |
337 | 0fcd0cad | René Nussbaumer | REQ_PARAMS = [ |
338 | 0fcd0cad | René Nussbaumer | ("instances", _STRING_LIST),
|
339 | 0fcd0cad | René Nussbaumer | ("evac_mode", ht.TElemOf(constants.IALLOCATOR_NEVAC_MODES)),
|
340 | 0fcd0cad | René Nussbaumer | ] |
341 | 0fcd0cad | René Nussbaumer | REQ_RESULT = _NEVAC_RESULT |
342 | 0fcd0cad | René Nussbaumer | |
343 | 0fcd0cad | René Nussbaumer | def GetRequest(self, cfg): |
344 | 0fcd0cad | René Nussbaumer | """Get data for node-evacuate requests.
|
345 | 0fcd0cad | René Nussbaumer |
|
346 | 0fcd0cad | René Nussbaumer | """
|
347 | 0fcd0cad | René Nussbaumer | return {
|
348 | 0fcd0cad | René Nussbaumer | "instances": self.instances, |
349 | 0fcd0cad | René Nussbaumer | "evac_mode": self.evac_mode, |
350 | 0fcd0cad | René Nussbaumer | } |
351 | 0fcd0cad | René Nussbaumer | |
352 | 0fcd0cad | René Nussbaumer | |
353 | 0fcd0cad | René Nussbaumer | class IAReqGroupChange(IARequestBase): |
354 | 0fcd0cad | René Nussbaumer | """A group change request.
|
355 | 0fcd0cad | René Nussbaumer |
|
356 | 0fcd0cad | René Nussbaumer | """
|
357 | c269efc3 | René Nussbaumer | # pylint: disable=E1101
|
358 | 0fcd0cad | René Nussbaumer | MODE = constants.IALLOCATOR_MODE_CHG_GROUP |
359 | 0fcd0cad | René Nussbaumer | REQ_PARAMS = [ |
360 | 0fcd0cad | René Nussbaumer | ("instances", _STRING_LIST),
|
361 | 0fcd0cad | René Nussbaumer | ("target_groups", _STRING_LIST),
|
362 | 0fcd0cad | René Nussbaumer | ] |
363 | 0fcd0cad | René Nussbaumer | REQ_RESULT = _NEVAC_RESULT |
364 | 0fcd0cad | René Nussbaumer | |
365 | 0fcd0cad | René Nussbaumer | def GetRequest(self, cfg): |
366 | 0fcd0cad | René Nussbaumer | """Get data for node-evacuate requests.
|
367 | 0fcd0cad | René Nussbaumer |
|
368 | 0fcd0cad | René Nussbaumer | """
|
369 | 0fcd0cad | René Nussbaumer | return {
|
370 | 0fcd0cad | René Nussbaumer | "instances": self.instances, |
371 | 0fcd0cad | René Nussbaumer | "target_groups": self.target_groups, |
372 | 0fcd0cad | René Nussbaumer | } |
373 | 0fcd0cad | René Nussbaumer | |
374 | 0fcd0cad | René Nussbaumer | |
375 | 0fcd0cad | René Nussbaumer | class IAllocator(object): |
376 | 0fcd0cad | René Nussbaumer | """IAllocator framework.
|
377 | 0fcd0cad | René Nussbaumer |
|
378 | 0fcd0cad | René Nussbaumer | An IAllocator instance has three sets of attributes:
|
379 | 0fcd0cad | René Nussbaumer | - cfg that is needed to query the cluster
|
380 | 0fcd0cad | René Nussbaumer | - input data (all members of the _KEYS class attribute are required)
|
381 | 0fcd0cad | René Nussbaumer | - four buffer attributes (in|out_data|text), that represent the
|
382 | 0fcd0cad | René Nussbaumer | input (to the external script) in text and data structure format,
|
383 | 0fcd0cad | René Nussbaumer | and the output from it, again in two formats
|
384 | 0fcd0cad | René Nussbaumer | - the result variables from the script (success, info, nodes) for
|
385 | 0fcd0cad | René Nussbaumer | easy usage
|
386 | 0fcd0cad | René Nussbaumer |
|
387 | 0fcd0cad | René Nussbaumer | """
|
388 | 0fcd0cad | René Nussbaumer | # pylint: disable=R0902
|
389 | 0fcd0cad | René Nussbaumer | # lots of instance attributes
|
390 | 0fcd0cad | René Nussbaumer | |
391 | 0fcd0cad | René Nussbaumer | def __init__(self, cfg, rpc_runner, req): |
392 | 0fcd0cad | René Nussbaumer | self.cfg = cfg
|
393 | 0fcd0cad | René Nussbaumer | self.rpc = rpc_runner
|
394 | 0fcd0cad | René Nussbaumer | self.req = req
|
395 | 0fcd0cad | René Nussbaumer | # init buffer variables
|
396 | 0fcd0cad | René Nussbaumer | self.in_text = self.out_text = self.in_data = self.out_data = None |
397 | 0fcd0cad | René Nussbaumer | # init result fields
|
398 | 0fcd0cad | René Nussbaumer | self.success = self.info = self.result = None |
399 | 0fcd0cad | René Nussbaumer | |
400 | 0fcd0cad | René Nussbaumer | self._BuildInputData(req)
|
401 | 0fcd0cad | René Nussbaumer | |
402 | c9c4b92d | Helga Velroyen | def _ComputerClusterDataNodeInfo(self, node_list, cluster_info, |
403 | c9c4b92d | Helga Velroyen | hypervisor_name): |
404 | c9c4b92d | Helga Velroyen | """Prepare and execute node info call.
|
405 | c9c4b92d | Helga Velroyen |
|
406 | c9c4b92d | Helga Velroyen | @type node_list: list of strings
|
407 | c9c4b92d | Helga Velroyen | @param node_list: list of nodes' UUIDs
|
408 | c9c4b92d | Helga Velroyen | @type cluster_info: L{objects.Cluster}
|
409 | c9c4b92d | Helga Velroyen | @param cluster_info: the cluster's information from the config
|
410 | c9c4b92d | Helga Velroyen | @type hypervisor_name: string
|
411 | c9c4b92d | Helga Velroyen | @param hypervisor_name: the hypervisor name
|
412 | c9c4b92d | Helga Velroyen | @rtype: same as the result of the node info RPC call
|
413 | c9c4b92d | Helga Velroyen | @return: the result of the node info RPC call
|
414 | c9c4b92d | Helga Velroyen |
|
415 | c9c4b92d | Helga Velroyen | """
|
416 | c9c4b92d | Helga Velroyen | es_flags = rpc.GetExclusiveStorageForNodes(self.cfg, node_list)
|
417 | c9c4b92d | Helga Velroyen | storage_units = utils.storage.GetStorageUnitsOfCluster( |
418 | c9c4b92d | Helga Velroyen | self.cfg, include_spindles=True) |
419 | c9c4b92d | Helga Velroyen | hvspecs = [(hypervisor_name, cluster_info.hvparams[hypervisor_name])] |
420 | c9c4b92d | Helga Velroyen | return self.rpc.call_node_info(node_list, storage_units, hvspecs, es_flags) |
421 | c9c4b92d | Helga Velroyen | |
422 | 0fcd0cad | René Nussbaumer | def _ComputeClusterData(self): |
423 | 0fcd0cad | René Nussbaumer | """Compute the generic allocator input data.
|
424 | 0fcd0cad | René Nussbaumer |
|
425 | 0fcd0cad | René Nussbaumer | This is the data that is independent of the actual operation.
|
426 | 0fcd0cad | René Nussbaumer |
|
427 | 0fcd0cad | René Nussbaumer | """
|
428 | d0d7d7cf | Thomas Thrainer | cluster_info = self.cfg.GetClusterInfo()
|
429 | 0fcd0cad | René Nussbaumer | # cluster data
|
430 | 0fcd0cad | René Nussbaumer | data = { |
431 | 0fcd0cad | René Nussbaumer | "version": constants.IALLOCATOR_VERSION,
|
432 | d0d7d7cf | Thomas Thrainer | "cluster_name": self.cfg.GetClusterName(), |
433 | 0fcd0cad | René Nussbaumer | "cluster_tags": list(cluster_info.GetTags()), |
434 | 0fcd0cad | René Nussbaumer | "enabled_hypervisors": list(cluster_info.enabled_hypervisors), |
435 | 0fcd0cad | René Nussbaumer | "ipolicy": cluster_info.ipolicy,
|
436 | 0fcd0cad | René Nussbaumer | } |
437 | d0d7d7cf | Thomas Thrainer | ninfo = self.cfg.GetAllNodesInfo()
|
438 | d0d7d7cf | Thomas Thrainer | iinfo = self.cfg.GetAllInstancesInfo().values()
|
439 | 0fcd0cad | René Nussbaumer | i_list = [(inst, cluster_info.FillBE(inst)) for inst in iinfo] |
440 | 0fcd0cad | René Nussbaumer | |
441 | 0fcd0cad | René Nussbaumer | # node data
|
442 | 1c3231aa | Thomas Thrainer | node_list = [n.uuid for n in ninfo.values() if n.vm_capable] |
443 | 0fcd0cad | René Nussbaumer | |
444 | 0fcd0cad | René Nussbaumer | if isinstance(self.req, IAReqInstanceAlloc): |
445 | 0fcd0cad | René Nussbaumer | hypervisor_name = self.req.hypervisor
|
446 | fb60bc6a | Michael Hanselmann | node_whitelist = self.req.node_whitelist
|
447 | 0fcd0cad | René Nussbaumer | elif isinstance(self.req, IAReqRelocate): |
448 | da4a52a3 | Thomas Thrainer | hypervisor_name = self.cfg.GetInstanceInfo(self.req.inst_uuid).hypervisor |
449 | fb60bc6a | Michael Hanselmann | node_whitelist = None
|
450 | 0fcd0cad | René Nussbaumer | else:
|
451 | 0fcd0cad | René Nussbaumer | hypervisor_name = cluster_info.primary_hypervisor |
452 | fb60bc6a | Michael Hanselmann | node_whitelist = None
|
453 | 0fcd0cad | René Nussbaumer | |
454 | 32389d91 | Helga Velroyen | has_lvm = utils.storage.IsLvmEnabled(cluster_info.enabled_disk_templates) |
455 | c9c4b92d | Helga Velroyen | node_data = self._ComputerClusterDataNodeInfo(node_list, cluster_info,
|
456 | c9c4b92d | Helga Velroyen | hypervisor_name) |
457 | c9c4b92d | Helga Velroyen | |
458 | 0fcd0cad | René Nussbaumer | node_iinfo = \ |
459 | 0fcd0cad | René Nussbaumer | self.rpc.call_all_instances_info(node_list,
|
460 | 0200a1af | Helga Velroyen | cluster_info.enabled_hypervisors, |
461 | 0200a1af | Helga Velroyen | cluster_info.hvparams) |
462 | 0fcd0cad | René Nussbaumer | |
463 | d0d7d7cf | Thomas Thrainer | data["nodegroups"] = self._ComputeNodeGroupData(self.cfg) |
464 | 0fcd0cad | René Nussbaumer | |
465 | d0d7d7cf | Thomas Thrainer | config_ndata = self._ComputeBasicNodeData(self.cfg, ninfo, node_whitelist) |
466 | 0fcd0cad | René Nussbaumer | data["nodes"] = self._ComputeDynamicNodeData(ninfo, node_data, node_iinfo, |
467 | 36a566e8 | Iustin Pop | i_list, config_ndata, has_lvm) |
468 | 0fcd0cad | René Nussbaumer | assert len(data["nodes"]) == len(ninfo), \ |
469 | 0fcd0cad | René Nussbaumer | "Incomplete node data computed"
|
470 | 0fcd0cad | René Nussbaumer | |
471 | d0d7d7cf | Thomas Thrainer | data["instances"] = self._ComputeInstanceData(self.cfg, cluster_info, |
472 | d0d7d7cf | Thomas Thrainer | i_list) |
473 | 0fcd0cad | René Nussbaumer | |
474 | 0fcd0cad | René Nussbaumer | self.in_data = data
|
475 | 0fcd0cad | René Nussbaumer | |
476 | 0fcd0cad | René Nussbaumer | @staticmethod
|
477 | 0fcd0cad | René Nussbaumer | def _ComputeNodeGroupData(cfg): |
478 | 0fcd0cad | René Nussbaumer | """Compute node groups data.
|
479 | 0fcd0cad | René Nussbaumer |
|
480 | 0fcd0cad | René Nussbaumer | """
|
481 | 0fcd0cad | René Nussbaumer | cluster = cfg.GetClusterInfo() |
482 | 0fcd0cad | René Nussbaumer | ng = dict((guuid, {
|
483 | 0fcd0cad | René Nussbaumer | "name": gdata.name,
|
484 | 0fcd0cad | René Nussbaumer | "alloc_policy": gdata.alloc_policy,
|
485 | 98ae702b | Thomas Thrainer | "networks": [net_uuid for net_uuid, _ in gdata.networks.items()], |
486 | 0fcd0cad | René Nussbaumer | "ipolicy": gmi.CalculateGroupIPolicy(cluster, gdata),
|
487 | f1222089 | Dimitris Aragiorgis | "tags": list(gdata.GetTags()), |
488 | 0fcd0cad | René Nussbaumer | }) |
489 | 0fcd0cad | René Nussbaumer | for guuid, gdata in cfg.GetAllNodeGroupsInfo().items()) |
490 | 0fcd0cad | René Nussbaumer | |
491 | 0fcd0cad | René Nussbaumer | return ng
|
492 | 0fcd0cad | René Nussbaumer | |
493 | 0fcd0cad | René Nussbaumer | @staticmethod
|
494 | fb60bc6a | Michael Hanselmann | def _ComputeBasicNodeData(cfg, node_cfg, node_whitelist): |
495 | 0fcd0cad | René Nussbaumer | """Compute global node data.
|
496 | 0fcd0cad | René Nussbaumer |
|
497 | 0fcd0cad | René Nussbaumer | @rtype: dict
|
498 | 0fcd0cad | René Nussbaumer | @returns: a dict of name: (node dict, node config)
|
499 | 0fcd0cad | René Nussbaumer |
|
500 | 0fcd0cad | René Nussbaumer | """
|
501 | 0fcd0cad | René Nussbaumer | # fill in static (config-based) values
|
502 | 0fcd0cad | René Nussbaumer | node_results = dict((ninfo.name, {
|
503 | 0fcd0cad | René Nussbaumer | "tags": list(ninfo.GetTags()), |
504 | 0fcd0cad | René Nussbaumer | "primary_ip": ninfo.primary_ip,
|
505 | 0fcd0cad | René Nussbaumer | "secondary_ip": ninfo.secondary_ip,
|
506 | fb60bc6a | Michael Hanselmann | "offline": (ninfo.offline or |
507 | fb60bc6a | Michael Hanselmann | not (node_whitelist is None or |
508 | fb60bc6a | Michael Hanselmann | ninfo.name in node_whitelist)),
|
509 | 0fcd0cad | René Nussbaumer | "drained": ninfo.drained,
|
510 | 0fcd0cad | René Nussbaumer | "master_candidate": ninfo.master_candidate,
|
511 | 0fcd0cad | René Nussbaumer | "group": ninfo.group,
|
512 | 0fcd0cad | René Nussbaumer | "master_capable": ninfo.master_capable,
|
513 | 0fcd0cad | René Nussbaumer | "vm_capable": ninfo.vm_capable,
|
514 | 0fcd0cad | René Nussbaumer | "ndparams": cfg.GetNdParams(ninfo),
|
515 | 0fcd0cad | René Nussbaumer | }) |
516 | 0fcd0cad | René Nussbaumer | for ninfo in node_cfg.values()) |
517 | 0fcd0cad | René Nussbaumer | |
518 | 0fcd0cad | René Nussbaumer | return node_results
|
519 | 0fcd0cad | René Nussbaumer | |
520 | 0fcd0cad | René Nussbaumer | @staticmethod
|
521 | b82d7182 | Helga Velroyen | def _GetAttributeFromHypervisorNodeData(hv_info, node_name, attr): |
522 | b82d7182 | Helga Velroyen | """Extract an attribute from the hypervisor's node information.
|
523 | 0f70b3fb | Helga Velroyen |
|
524 | b82d7182 | Helga Velroyen | This is a helper function to extract data from the hypervisor's information
|
525 | b82d7182 | Helga Velroyen | about the node, as part of the result of a node_info query.
|
526 | b82d7182 | Helga Velroyen |
|
527 | b82d7182 | Helga Velroyen | @type hv_info: dict of strings
|
528 | b82d7182 | Helga Velroyen | @param hv_info: dictionary of node information from the hypervisor
|
529 | 0f70b3fb | Helga Velroyen | @type node_name: string
|
530 | 0f70b3fb | Helga Velroyen | @param node_name: name of the node
|
531 | 0f70b3fb | Helga Velroyen | @type attr: string
|
532 | b82d7182 | Helga Velroyen | @param attr: key of the attribute in the hv_info dictionary
|
533 | 0f70b3fb | Helga Velroyen | @rtype: integer
|
534 | 0f70b3fb | Helga Velroyen | @return: the value of the attribute
|
535 | 0f70b3fb | Helga Velroyen | @raises errors.OpExecError: if key not in dictionary or value not
|
536 | 0f70b3fb | Helga Velroyen | integer
|
537 | 0f70b3fb | Helga Velroyen |
|
538 | 0f70b3fb | Helga Velroyen | """
|
539 | b82d7182 | Helga Velroyen | if attr not in hv_info: |
540 | 0f70b3fb | Helga Velroyen | raise errors.OpExecError("Node '%s' didn't return attribute" |
541 | 0f70b3fb | Helga Velroyen | " '%s'" % (node_name, attr))
|
542 | b82d7182 | Helga Velroyen | value = hv_info[attr] |
543 | 0f70b3fb | Helga Velroyen | if not isinstance(value, int): |
544 | 0f70b3fb | Helga Velroyen | raise errors.OpExecError("Node '%s' returned invalid value" |
545 | 0f70b3fb | Helga Velroyen | " for '%s': %s" %
|
546 | 0f70b3fb | Helga Velroyen | (node_name, attr, value)) |
547 | 0f70b3fb | Helga Velroyen | return value
|
548 | 0f70b3fb | Helga Velroyen | |
549 | 20529708 | Helga Velroyen | @staticmethod
|
550 | 11aa3ca5 | Helga Velroyen | def _ComputeStorageDataFromNodeInfo(node_info, node_name, has_lvm): |
551 | 11aa3ca5 | Helga Velroyen | """Extract storage data from node info (_not_ legacy node info).
|
552 | 20529708 | Helga Velroyen |
|
553 | 11aa3ca5 | Helga Velroyen | @type node_info: see result of the RPC call node info
|
554 | 11aa3ca5 | Helga Velroyen | @param node_info: the result of the RPC call node info
|
555 | 20529708 | Helga Velroyen | @type node_name: string
|
556 | 20529708 | Helga Velroyen | @param node_name: the node's name
|
557 | 20529708 | Helga Velroyen | @type has_lvm: boolean
|
558 | 11aa3ca5 | Helga Velroyen | @param has_lvm: whether or not LVM storage information is requested
|
559 | 20529708 | Helga Velroyen | @rtype: 4-tuple of integers
|
560 | 20529708 | Helga Velroyen | @return: tuple of storage info (total_disk, free_disk, total_spindles,
|
561 | 20529708 | Helga Velroyen | free_spindles)
|
562 | 20529708 | Helga Velroyen |
|
563 | 20529708 | Helga Velroyen | """
|
564 | 11aa3ca5 | Helga Velroyen | (_, space_info, _) = node_info |
565 | 20529708 | Helga Velroyen | # TODO: replace this with proper storage reporting
|
566 | 20529708 | Helga Velroyen | if has_lvm:
|
567 | 11aa3ca5 | Helga Velroyen | lvm_vg_info = utils.storage.LookupSpaceInfoByStorageType( |
568 | 11aa3ca5 | Helga Velroyen | space_info, constants.ST_LVM_VG) |
569 | 11aa3ca5 | Helga Velroyen | if not lvm_vg_info: |
570 | 11aa3ca5 | Helga Velroyen | raise errors.OpExecError("Node '%s' didn't return LVM vg space info." |
571 | 11aa3ca5 | Helga Velroyen | % (node_name)) |
572 | 11aa3ca5 | Helga Velroyen | total_disk = lvm_vg_info["storage_size"]
|
573 | 11aa3ca5 | Helga Velroyen | free_disk = lvm_vg_info["storage_free"]
|
574 | 11aa3ca5 | Helga Velroyen | lvm_pv_info = utils.storage.LookupSpaceInfoByStorageType( |
575 | 11aa3ca5 | Helga Velroyen | space_info, constants.ST_LVM_PV) |
576 | 11aa3ca5 | Helga Velroyen | if not lvm_vg_info: |
577 | 11aa3ca5 | Helga Velroyen | raise errors.OpExecError("Node '%s' didn't return LVM pv space info." |
578 | 11aa3ca5 | Helga Velroyen | % (node_name)) |
579 | 11aa3ca5 | Helga Velroyen | total_spindles = lvm_pv_info["storage_size"]
|
580 | 11aa3ca5 | Helga Velroyen | free_spindles = lvm_pv_info["storage_free"]
|
581 | 20529708 | Helga Velroyen | else:
|
582 | 20529708 | Helga Velroyen | # we didn't even ask the node for VG status, so use zeros
|
583 | 20529708 | Helga Velroyen | total_disk = free_disk = 0
|
584 | 20529708 | Helga Velroyen | total_spindles = free_spindles = 0
|
585 | 20529708 | Helga Velroyen | return (total_disk, free_disk, total_spindles, free_spindles)
|
586 | 20529708 | Helga Velroyen | |
587 | 0ac34c90 | Helga Velroyen | @staticmethod
|
588 | 0ac34c90 | Helga Velroyen | def _ComputeInstanceMemory(instance_list, node_instances_info, node_uuid, |
589 | 0ac34c90 | Helga Velroyen | input_mem_free): |
590 | 0ac34c90 | Helga Velroyen | """Compute memory used by primary instances.
|
591 | 0ac34c90 | Helga Velroyen |
|
592 | 0ac34c90 | Helga Velroyen | @rtype: tuple (int, int, int)
|
593 | 0ac34c90 | Helga Velroyen | @returns: A tuple of three integers: 1. the sum of memory used by primary
|
594 | 0ac34c90 | Helga Velroyen | instances on the node (including the ones that are currently down), 2.
|
595 | 0ac34c90 | Helga Velroyen | the sum of memory used by primary instances of the node that are up, 3.
|
596 | 0ac34c90 | Helga Velroyen | the amount of memory that is free on the node considering the current
|
597 | 0ac34c90 | Helga Velroyen | usage of the instances.
|
598 | 0ac34c90 | Helga Velroyen |
|
599 | 0ac34c90 | Helga Velroyen | """
|
600 | 0ac34c90 | Helga Velroyen | i_p_mem = i_p_up_mem = 0
|
601 | 0ac34c90 | Helga Velroyen | mem_free = input_mem_free |
602 | 0ac34c90 | Helga Velroyen | for iinfo, beinfo in instance_list: |
603 | 0ac34c90 | Helga Velroyen | if iinfo.primary_node == node_uuid:
|
604 | 0ac34c90 | Helga Velroyen | i_p_mem += beinfo[constants.BE_MAXMEM] |
605 | 0ac34c90 | Helga Velroyen | if iinfo.name not in node_instances_info[node_uuid].payload: |
606 | 0ac34c90 | Helga Velroyen | i_used_mem = 0
|
607 | 0ac34c90 | Helga Velroyen | else:
|
608 | 0ac34c90 | Helga Velroyen | i_used_mem = int(node_instances_info[node_uuid]
|
609 | 0ac34c90 | Helga Velroyen | .payload[iinfo.name]["memory"])
|
610 | 0ac34c90 | Helga Velroyen | i_mem_diff = beinfo[constants.BE_MAXMEM] - i_used_mem |
611 | 0ac34c90 | Helga Velroyen | mem_free -= max(0, i_mem_diff) |
612 | 0ac34c90 | Helga Velroyen | |
613 | 0ac34c90 | Helga Velroyen | if iinfo.admin_state == constants.ADMINST_UP:
|
614 | 0ac34c90 | Helga Velroyen | i_p_up_mem += beinfo[constants.BE_MAXMEM] |
615 | 0ac34c90 | Helga Velroyen | return (i_p_mem, i_p_up_mem, mem_free)
|
616 | 0ac34c90 | Helga Velroyen | |
617 | 0f70b3fb | Helga Velroyen | def _ComputeDynamicNodeData(self, node_cfg, node_data, node_iinfo, i_list, |
618 | 36a566e8 | Iustin Pop | node_results, has_lvm): |
619 | 0fcd0cad | René Nussbaumer | """Compute global node data.
|
620 | 0fcd0cad | René Nussbaumer |
|
621 | 0fcd0cad | René Nussbaumer | @param node_results: the basic node structures as filled from the config
|
622 | 0fcd0cad | René Nussbaumer |
|
623 | 0fcd0cad | René Nussbaumer | """
|
624 | 0fcd0cad | René Nussbaumer | #TODO(dynmem): compute the right data on MAX and MIN memory
|
625 | 0fcd0cad | René Nussbaumer | # make a copy of the current dict
|
626 | 0fcd0cad | René Nussbaumer | node_results = dict(node_results)
|
627 | 1c3231aa | Thomas Thrainer | for nuuid, nresult in node_data.items(): |
628 | 1c3231aa | Thomas Thrainer | ninfo = node_cfg[nuuid] |
629 | 1c3231aa | Thomas Thrainer | assert ninfo.name in node_results, "Missing basic data for node %s" % \ |
630 | 1c3231aa | Thomas Thrainer | ninfo.name |
631 | 0fcd0cad | René Nussbaumer | |
632 | 0fcd0cad | René Nussbaumer | if not (ninfo.offline or ninfo.drained): |
633 | 1c3231aa | Thomas Thrainer | nresult.Raise("Can't get data for node %s" % ninfo.name)
|
634 | 1c3231aa | Thomas Thrainer | node_iinfo[nuuid].Raise("Can't get node instance info from node %s" %
|
635 | 1c3231aa | Thomas Thrainer | ninfo.name) |
636 | b82d7182 | Helga Velroyen | (_, _, (hv_info, )) = nresult.payload |
637 | 0fcd0cad | René Nussbaumer | |
638 | b82d7182 | Helga Velroyen | mem_free = self._GetAttributeFromHypervisorNodeData(hv_info, ninfo.name,
|
639 | b82d7182 | Helga Velroyen | "memory_free")
|
640 | 36a566e8 | Iustin Pop | |
641 | 0ac34c90 | Helga Velroyen | (i_p_mem, i_p_up_mem, mem_free) = self._ComputeInstanceMemory(
|
642 | 0ac34c90 | Helga Velroyen | i_list, node_iinfo, nuuid, mem_free) |
643 | 20529708 | Helga Velroyen | (total_disk, free_disk, total_spindles, free_spindles) = \ |
644 | 11aa3ca5 | Helga Velroyen | self._ComputeStorageDataFromNodeInfo(nresult.payload, ninfo.name,
|
645 | 11aa3ca5 | Helga Velroyen | has_lvm) |
646 | 36a566e8 | Iustin Pop | |
647 | 0fcd0cad | René Nussbaumer | # compute memory used by instances
|
648 | 0fcd0cad | René Nussbaumer | pnr_dyn = { |
649 | b82d7182 | Helga Velroyen | "total_memory": self._GetAttributeFromHypervisorNodeData( |
650 | b82d7182 | Helga Velroyen | hv_info, ninfo.name, "memory_total"),
|
651 | b82d7182 | Helga Velroyen | "reserved_memory": self._GetAttributeFromHypervisorNodeData( |
652 | b82d7182 | Helga Velroyen | hv_info, ninfo.name, "memory_dom0"),
|
653 | 36a566e8 | Iustin Pop | "free_memory": mem_free,
|
654 | 36a566e8 | Iustin Pop | "total_disk": total_disk,
|
655 | 36a566e8 | Iustin Pop | "free_disk": free_disk,
|
656 | 06fb92cf | Bernardo Dal Seno | "total_spindles": total_spindles,
|
657 | 06fb92cf | Bernardo Dal Seno | "free_spindles": free_spindles,
|
658 | b82d7182 | Helga Velroyen | "total_cpus": self._GetAttributeFromHypervisorNodeData( |
659 | b82d7182 | Helga Velroyen | hv_info, ninfo.name, "cpu_total"),
|
660 | 0fcd0cad | René Nussbaumer | "i_pri_memory": i_p_mem,
|
661 | 0fcd0cad | René Nussbaumer | "i_pri_up_memory": i_p_up_mem,
|
662 | 0fcd0cad | René Nussbaumer | } |
663 | 1c3231aa | Thomas Thrainer | pnr_dyn.update(node_results[ninfo.name]) |
664 | 1c3231aa | Thomas Thrainer | node_results[ninfo.name] = pnr_dyn |
665 | 0fcd0cad | René Nussbaumer | |
666 | 0fcd0cad | René Nussbaumer | return node_results
|
667 | 0fcd0cad | René Nussbaumer | |
668 | 0fcd0cad | René Nussbaumer | @staticmethod
|
669 | 1c3231aa | Thomas Thrainer | def _ComputeInstanceData(cfg, cluster_info, i_list): |
670 | 0fcd0cad | René Nussbaumer | """Compute global instance data.
|
671 | 0fcd0cad | René Nussbaumer |
|
672 | 0fcd0cad | René Nussbaumer | """
|
673 | 0fcd0cad | René Nussbaumer | instance_data = {} |
674 | 0fcd0cad | René Nussbaumer | for iinfo, beinfo in i_list: |
675 | 0fcd0cad | René Nussbaumer | nic_data = [] |
676 | 0fcd0cad | René Nussbaumer | for nic in iinfo.nics: |
677 | 0fcd0cad | René Nussbaumer | filled_params = cluster_info.SimpleFillNIC(nic.nicparams) |
678 | 0fcd0cad | René Nussbaumer | nic_dict = { |
679 | 0fcd0cad | René Nussbaumer | "mac": nic.mac,
|
680 | 0fcd0cad | René Nussbaumer | "ip": nic.ip,
|
681 | 0fcd0cad | René Nussbaumer | "mode": filled_params[constants.NIC_MODE],
|
682 | 0fcd0cad | René Nussbaumer | "link": filled_params[constants.NIC_LINK],
|
683 | 0fcd0cad | René Nussbaumer | } |
684 | 0fcd0cad | René Nussbaumer | if filled_params[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
|
685 | 0fcd0cad | René Nussbaumer | nic_dict["bridge"] = filled_params[constants.NIC_LINK]
|
686 | 0fcd0cad | René Nussbaumer | nic_data.append(nic_dict) |
687 | 0fcd0cad | René Nussbaumer | pir = { |
688 | 0fcd0cad | René Nussbaumer | "tags": list(iinfo.GetTags()), |
689 | 0fcd0cad | René Nussbaumer | "admin_state": iinfo.admin_state,
|
690 | 0fcd0cad | René Nussbaumer | "vcpus": beinfo[constants.BE_VCPUS],
|
691 | 0fcd0cad | René Nussbaumer | "memory": beinfo[constants.BE_MAXMEM],
|
692 | 0fcd0cad | René Nussbaumer | "spindle_use": beinfo[constants.BE_SPINDLE_USE],
|
693 | 0fcd0cad | René Nussbaumer | "os": iinfo.os,
|
694 | 1c3231aa | Thomas Thrainer | "nodes": [cfg.GetNodeName(iinfo.primary_node)] +
|
695 | 1c3231aa | Thomas Thrainer | cfg.GetNodeNames(iinfo.secondary_nodes), |
696 | 0fcd0cad | René Nussbaumer | "nics": nic_data,
|
697 | 0fcd0cad | René Nussbaumer | "disks": [{constants.IDISK_SIZE: dsk.size,
|
698 | 0e514de1 | Bernardo Dal Seno | constants.IDISK_MODE: dsk.mode, |
699 | 0e514de1 | Bernardo Dal Seno | constants.IDISK_SPINDLES: dsk.spindles} |
700 | 0fcd0cad | René Nussbaumer | for dsk in iinfo.disks], |
701 | 0fcd0cad | René Nussbaumer | "disk_template": iinfo.disk_template,
|
702 | 1d4a4b26 | Thomas Thrainer | "disks_active": iinfo.disks_active,
|
703 | 0fcd0cad | René Nussbaumer | "hypervisor": iinfo.hypervisor,
|
704 | 0fcd0cad | René Nussbaumer | } |
705 | 0fcd0cad | René Nussbaumer | pir["disk_space_total"] = gmi.ComputeDiskSize(iinfo.disk_template,
|
706 | 0fcd0cad | René Nussbaumer | pir["disks"])
|
707 | 0fcd0cad | René Nussbaumer | instance_data[iinfo.name] = pir |
708 | 0fcd0cad | René Nussbaumer | |
709 | 0fcd0cad | René Nussbaumer | return instance_data
|
710 | 0fcd0cad | René Nussbaumer | |
711 | 0fcd0cad | René Nussbaumer | def _BuildInputData(self, req): |
712 | 0fcd0cad | René Nussbaumer | """Build input data structures.
|
713 | 0fcd0cad | René Nussbaumer |
|
714 | 0fcd0cad | René Nussbaumer | """
|
715 | 0fcd0cad | René Nussbaumer | self._ComputeClusterData()
|
716 | 0fcd0cad | René Nussbaumer | |
717 | 0fcd0cad | René Nussbaumer | request = req.GetRequest(self.cfg)
|
718 | 0fcd0cad | René Nussbaumer | request["type"] = req.MODE
|
719 | 0fcd0cad | René Nussbaumer | self.in_data["request"] = request |
720 | 0fcd0cad | René Nussbaumer | |
721 | 0fcd0cad | René Nussbaumer | self.in_text = serializer.Dump(self.in_data) |
722 | 0fcd0cad | René Nussbaumer | |
723 | 0fcd0cad | René Nussbaumer | def Run(self, name, validate=True, call_fn=None): |
724 | 0fcd0cad | René Nussbaumer | """Run an instance allocator and return the results.
|
725 | 0fcd0cad | René Nussbaumer |
|
726 | 0fcd0cad | René Nussbaumer | """
|
727 | 0fcd0cad | René Nussbaumer | if call_fn is None: |
728 | 0fcd0cad | René Nussbaumer | call_fn = self.rpc.call_iallocator_runner
|
729 | 0fcd0cad | René Nussbaumer | |
730 | 0fcd0cad | René Nussbaumer | result = call_fn(self.cfg.GetMasterNode(), name, self.in_text) |
731 | 0fcd0cad | René Nussbaumer | result.Raise("Failure while running the iallocator script")
|
732 | 0fcd0cad | René Nussbaumer | |
733 | 0fcd0cad | René Nussbaumer | self.out_text = result.payload
|
734 | 0fcd0cad | René Nussbaumer | if validate:
|
735 | 0fcd0cad | René Nussbaumer | self._ValidateResult()
|
736 | 0fcd0cad | René Nussbaumer | |
737 | 0fcd0cad | René Nussbaumer | def _ValidateResult(self): |
738 | 0fcd0cad | René Nussbaumer | """Process the allocator results.
|
739 | 0fcd0cad | René Nussbaumer |
|
740 | 0fcd0cad | René Nussbaumer | This will process and if successful save the result in
|
741 | 0fcd0cad | René Nussbaumer | self.out_data and the other parameters.
|
742 | 0fcd0cad | René Nussbaumer |
|
743 | 0fcd0cad | René Nussbaumer | """
|
744 | 0fcd0cad | René Nussbaumer | try:
|
745 | 0fcd0cad | René Nussbaumer | rdict = serializer.Load(self.out_text)
|
746 | 0fcd0cad | René Nussbaumer | except Exception, err: |
747 | 0fcd0cad | René Nussbaumer | raise errors.OpExecError("Can't parse iallocator results: %s" % str(err)) |
748 | 0fcd0cad | René Nussbaumer | |
749 | 0fcd0cad | René Nussbaumer | if not isinstance(rdict, dict): |
750 | 0fcd0cad | René Nussbaumer | raise errors.OpExecError("Can't parse iallocator results: not a dict") |
751 | 0fcd0cad | René Nussbaumer | |
752 | 0fcd0cad | René Nussbaumer | # TODO: remove backwards compatiblity in later versions
|
753 | 0fcd0cad | René Nussbaumer | if "nodes" in rdict and "result" not in rdict: |
754 | 0fcd0cad | René Nussbaumer | rdict["result"] = rdict["nodes"] |
755 | 0fcd0cad | René Nussbaumer | del rdict["nodes"] |
756 | 0fcd0cad | René Nussbaumer | |
757 | 0fcd0cad | René Nussbaumer | for key in "success", "info", "result": |
758 | 0fcd0cad | René Nussbaumer | if key not in rdict: |
759 | 0fcd0cad | René Nussbaumer | raise errors.OpExecError("Can't parse iallocator results:" |
760 | 0fcd0cad | René Nussbaumer | " missing key '%s'" % key)
|
761 | 0fcd0cad | René Nussbaumer | setattr(self, key, rdict[key]) |
762 | 0fcd0cad | René Nussbaumer | |
763 | 0fcd0cad | René Nussbaumer | self.req.ValidateResult(self, self.result) |
764 | 0fcd0cad | René Nussbaumer | self.out_data = rdict |