root / lib / masterd / iallocator.py @ d948c101
History | View | Annotate | Download (20.5 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 | 3d7d3a12 | René Nussbaumer | |
62 | 0fcd0cad | René Nussbaumer | |
63 | 473d87a3 | Iustin Pop | class _AutoReqParam(outils.AutoSlots): |
64 | 0fcd0cad | René Nussbaumer | """Meta class for request definitions.
|
65 | 0fcd0cad | René Nussbaumer |
|
66 | 0fcd0cad | René Nussbaumer | """
|
67 | 0fcd0cad | René Nussbaumer | @classmethod
|
68 | 0fcd0cad | René Nussbaumer | def _GetSlots(mcs, attrs): |
69 | 0fcd0cad | René Nussbaumer | """Extract the slots out of REQ_PARAMS.
|
70 | 0fcd0cad | René Nussbaumer |
|
71 | 0fcd0cad | René Nussbaumer | """
|
72 | 0fcd0cad | René Nussbaumer | params = attrs.setdefault("REQ_PARAMS", [])
|
73 | 0fcd0cad | René Nussbaumer | return [slot for (slot, _) in params] |
74 | 0fcd0cad | René Nussbaumer | |
75 | 0fcd0cad | René Nussbaumer | |
76 | 473d87a3 | Iustin Pop | class IARequestBase(outils.ValidatedSlots): |
77 | 0fcd0cad | René Nussbaumer | """A generic IAllocator request object.
|
78 | 0fcd0cad | René Nussbaumer |
|
79 | 0fcd0cad | René Nussbaumer | """
|
80 | 0fcd0cad | René Nussbaumer | __metaclass__ = _AutoReqParam |
81 | 0fcd0cad | René Nussbaumer | |
82 | 0fcd0cad | René Nussbaumer | MODE = NotImplemented
|
83 | 776b6291 | René Nussbaumer | REQ_PARAMS = [] |
84 | 0fcd0cad | René Nussbaumer | REQ_RESULT = NotImplemented
|
85 | 0fcd0cad | René Nussbaumer | |
86 | 0fcd0cad | René Nussbaumer | def __init__(self, **kwargs): |
87 | 0fcd0cad | René Nussbaumer | """Constructor for IARequestBase.
|
88 | 0fcd0cad | René Nussbaumer |
|
89 | 0fcd0cad | René Nussbaumer | The constructor takes only keyword arguments and will set
|
90 | 0fcd0cad | René Nussbaumer | attributes on this object based on the passed arguments. As such,
|
91 | 0fcd0cad | René Nussbaumer | it means that you should not pass arguments which are not in the
|
92 | 0fcd0cad | René Nussbaumer | REQ_PARAMS attribute for this class.
|
93 | 0fcd0cad | René Nussbaumer |
|
94 | 0fcd0cad | René Nussbaumer | """
|
95 | 473d87a3 | Iustin Pop | outils.ValidatedSlots.__init__(self, **kwargs)
|
96 | 0fcd0cad | René Nussbaumer | |
97 | 0fcd0cad | René Nussbaumer | self.Validate()
|
98 | 0fcd0cad | René Nussbaumer | |
99 | 0fcd0cad | René Nussbaumer | def Validate(self): |
100 | 0fcd0cad | René Nussbaumer | """Validates all parameters of the request.
|
101 | 0fcd0cad | René Nussbaumer |
|
102 | 0fcd0cad | René Nussbaumer | """
|
103 | 0fcd0cad | René Nussbaumer | assert self.MODE in constants.VALID_IALLOCATOR_MODES |
104 | 0fcd0cad | René Nussbaumer | |
105 | 0fcd0cad | René Nussbaumer | for (param, validator) in self.REQ_PARAMS: |
106 | 0fcd0cad | René Nussbaumer | if not hasattr(self, param): |
107 | 0fcd0cad | René Nussbaumer | raise errors.OpPrereqError("Request is missing '%s' parameter" % param, |
108 | 0fcd0cad | René Nussbaumer | errors.ECODE_INVAL) |
109 | 0fcd0cad | René Nussbaumer | |
110 | 0fcd0cad | René Nussbaumer | value = getattr(self, param) |
111 | 0fcd0cad | René Nussbaumer | if not validator(value): |
112 | 0fcd0cad | René Nussbaumer | raise errors.OpPrereqError(("Request parameter '%s' has invalid" |
113 | 0fcd0cad | René Nussbaumer | " type %s/value %s") %
|
114 | 0fcd0cad | René Nussbaumer | (param, type(value), value),
|
115 | 0fcd0cad | René Nussbaumer | errors.ECODE_INVAL) |
116 | 0fcd0cad | René Nussbaumer | |
117 | 0fcd0cad | René Nussbaumer | def GetRequest(self, cfg): |
118 | 0fcd0cad | René Nussbaumer | """Gets the request data dict.
|
119 | 0fcd0cad | René Nussbaumer |
|
120 | 0fcd0cad | René Nussbaumer | @param cfg: The configuration instance
|
121 | 0fcd0cad | René Nussbaumer |
|
122 | 0fcd0cad | René Nussbaumer | """
|
123 | 0fcd0cad | René Nussbaumer | raise NotImplementedError |
124 | 0fcd0cad | René Nussbaumer | |
125 | 0fcd0cad | René Nussbaumer | def ValidateResult(self, ia, result): |
126 | 0fcd0cad | René Nussbaumer | """Validates the result of an request.
|
127 | 0fcd0cad | René Nussbaumer |
|
128 | 0fcd0cad | René Nussbaumer | @param ia: The IAllocator instance
|
129 | 0fcd0cad | René Nussbaumer | @param result: The IAllocator run result
|
130 | 776b6291 | René Nussbaumer | @raises ResultValidationError: If validation fails
|
131 | 0fcd0cad | René Nussbaumer |
|
132 | 0fcd0cad | René Nussbaumer | """
|
133 | 69b0d82a | René Nussbaumer | if ia.success and not self.REQ_RESULT(result): |
134 | 776b6291 | René Nussbaumer | raise errors.ResultValidationError("iallocator returned invalid result," |
135 | 776b6291 | René Nussbaumer | " expected %s, got %s" %
|
136 | 776b6291 | René Nussbaumer | (self.REQ_RESULT, result))
|
137 | 0fcd0cad | René Nussbaumer | |
138 | 0fcd0cad | René Nussbaumer | |
139 | 0fcd0cad | René Nussbaumer | class IAReqInstanceAlloc(IARequestBase): |
140 | 0fcd0cad | René Nussbaumer | """An instance allocation request.
|
141 | 0fcd0cad | René Nussbaumer |
|
142 | 0fcd0cad | René Nussbaumer | """
|
143 | c269efc3 | René Nussbaumer | # pylint: disable=E1101
|
144 | 0fcd0cad | René Nussbaumer | MODE = constants.IALLOCATOR_MODE_ALLOC |
145 | 0fcd0cad | René Nussbaumer | REQ_PARAMS = [ |
146 | 3d7d3a12 | René Nussbaumer | _INST_NAME, |
147 | 2c9fa1ff | Iustin Pop | ("memory", ht.TNonNegativeInt),
|
148 | 2c9fa1ff | Iustin Pop | ("spindle_use", ht.TNonNegativeInt),
|
149 | 0fcd0cad | René Nussbaumer | ("disks", ht.TListOf(ht.TDict)),
|
150 | 0fcd0cad | René Nussbaumer | ("disk_template", ht.TString),
|
151 | 0fcd0cad | René Nussbaumer | ("os", ht.TString),
|
152 | 0fcd0cad | René Nussbaumer | ("tags", _STRING_LIST),
|
153 | 0fcd0cad | René Nussbaumer | ("nics", ht.TListOf(ht.TDict)),
|
154 | 0fcd0cad | René Nussbaumer | ("vcpus", ht.TInt),
|
155 | 0fcd0cad | René Nussbaumer | ("hypervisor", ht.TString),
|
156 | fb60bc6a | Michael Hanselmann | ("node_whitelist", ht.TMaybeListOf(ht.TNonEmptyString)),
|
157 | 0fcd0cad | René Nussbaumer | ] |
158 | 0fcd0cad | René Nussbaumer | REQ_RESULT = ht.TList |
159 | 0fcd0cad | René Nussbaumer | |
160 | 776b6291 | René Nussbaumer | def RequiredNodes(self): |
161 | 776b6291 | René Nussbaumer | """Calculates the required nodes based on the disk_template.
|
162 | 776b6291 | René Nussbaumer |
|
163 | 776b6291 | René Nussbaumer | """
|
164 | 776b6291 | René Nussbaumer | if self.disk_template in constants.DTS_INT_MIRROR: |
165 | 776b6291 | René Nussbaumer | return 2 |
166 | 776b6291 | René Nussbaumer | else:
|
167 | 776b6291 | René Nussbaumer | return 1 |
168 | 776b6291 | René Nussbaumer | |
169 | 0fcd0cad | René Nussbaumer | def GetRequest(self, cfg): |
170 | 0fcd0cad | René Nussbaumer | """Requests a new instance.
|
171 | 0fcd0cad | René Nussbaumer |
|
172 | 0fcd0cad | René Nussbaumer | The checks for the completeness of the opcode must have already been
|
173 | 0fcd0cad | René Nussbaumer | done.
|
174 | 0fcd0cad | René Nussbaumer |
|
175 | 0fcd0cad | René Nussbaumer | """
|
176 | 0fcd0cad | René Nussbaumer | disk_space = gmi.ComputeDiskSize(self.disk_template, self.disks) |
177 | 0fcd0cad | René Nussbaumer | |
178 | 0fcd0cad | René Nussbaumer | return {
|
179 | 0fcd0cad | René Nussbaumer | "name": self.name, |
180 | 0fcd0cad | René Nussbaumer | "disk_template": self.disk_template, |
181 | 0fcd0cad | René Nussbaumer | "tags": self.tags, |
182 | 0fcd0cad | René Nussbaumer | "os": self.os, |
183 | 0fcd0cad | René Nussbaumer | "vcpus": self.vcpus, |
184 | 0fcd0cad | René Nussbaumer | "memory": self.memory, |
185 | 0fcd0cad | René Nussbaumer | "spindle_use": self.spindle_use, |
186 | 0fcd0cad | René Nussbaumer | "disks": self.disks, |
187 | 0fcd0cad | René Nussbaumer | "disk_space_total": disk_space,
|
188 | 0fcd0cad | René Nussbaumer | "nics": self.nics, |
189 | 776b6291 | René Nussbaumer | "required_nodes": self.RequiredNodes(), |
190 | 0fcd0cad | René Nussbaumer | "hypervisor": self.hypervisor, |
191 | 0fcd0cad | René Nussbaumer | } |
192 | 0fcd0cad | René Nussbaumer | |
193 | 776b6291 | René Nussbaumer | def ValidateResult(self, ia, result): |
194 | 776b6291 | René Nussbaumer | """Validates an single instance allocation request.
|
195 | 776b6291 | René Nussbaumer |
|
196 | 776b6291 | René Nussbaumer | """
|
197 | 776b6291 | René Nussbaumer | IARequestBase.ValidateResult(self, ia, result)
|
198 | 776b6291 | René Nussbaumer | |
199 | 579f4ee5 | René Nussbaumer | if ia.success and len(result) != self.RequiredNodes(): |
200 | 776b6291 | René Nussbaumer | raise errors.ResultValidationError("iallocator returned invalid number" |
201 | 776b6291 | René Nussbaumer | " of nodes (%s), required %s" %
|
202 | 776b6291 | René Nussbaumer | (len(result), self.RequiredNodes())) |
203 | 776b6291 | René Nussbaumer | |
204 | 0fcd0cad | René Nussbaumer | |
205 | b1e47e2d | René Nussbaumer | class IAReqMultiInstanceAlloc(IARequestBase): |
206 | b1e47e2d | René Nussbaumer | """An multi instance allocation request.
|
207 | b1e47e2d | René Nussbaumer |
|
208 | b1e47e2d | René Nussbaumer | """
|
209 | c269efc3 | René Nussbaumer | # pylint: disable=E1101
|
210 | b1e47e2d | René Nussbaumer | MODE = constants.IALLOCATOR_MODE_MULTI_ALLOC |
211 | b1e47e2d | René Nussbaumer | REQ_PARAMS = [ |
212 | 3c286190 | Dimitris Aragiorgis | ("instances", ht.TListOf(ht.TInstanceOf(IAReqInstanceAlloc))),
|
213 | b1e47e2d | René Nussbaumer | ] |
214 | b1e47e2d | René Nussbaumer | _MASUCCESS = \ |
215 | b1e47e2d | René Nussbaumer | ht.TListOf(ht.TAnd(ht.TIsLength(2),
|
216 | b1e47e2d | René Nussbaumer | ht.TItems([ht.TNonEmptyString, |
217 | b1e47e2d | René Nussbaumer | ht.TListOf(ht.TNonEmptyString), |
218 | b1e47e2d | René Nussbaumer | ]))) |
219 | b1e47e2d | René Nussbaumer | _MAFAILED = ht.TListOf(ht.TNonEmptyString) |
220 | 32eae1ec | René Nussbaumer | REQ_RESULT = ht.TAnd(ht.TList, ht.TIsLength(2),
|
221 | 32eae1ec | René Nussbaumer | ht.TItems([_MASUCCESS, _MAFAILED])) |
222 | b1e47e2d | René Nussbaumer | |
223 | b1e47e2d | René Nussbaumer | def GetRequest(self, cfg): |
224 | b1e47e2d | René Nussbaumer | return {
|
225 | 3c286190 | Dimitris Aragiorgis | "instances": [iareq.GetRequest(cfg) for iareq in self.instances], |
226 | b1e47e2d | René Nussbaumer | } |
227 | b1e47e2d | René Nussbaumer | |
228 | b1e47e2d | René Nussbaumer | |
229 | 0fcd0cad | René Nussbaumer | class IAReqRelocate(IARequestBase): |
230 | 0fcd0cad | René Nussbaumer | """A relocation request.
|
231 | 0fcd0cad | René Nussbaumer |
|
232 | 0fcd0cad | René Nussbaumer | """
|
233 | c269efc3 | René Nussbaumer | # pylint: disable=E1101
|
234 | 0fcd0cad | René Nussbaumer | MODE = constants.IALLOCATOR_MODE_RELOC |
235 | 0fcd0cad | René Nussbaumer | REQ_PARAMS = [ |
236 | 3d7d3a12 | René Nussbaumer | _INST_NAME, |
237 | 0fcd0cad | René Nussbaumer | ("relocate_from", _STRING_LIST),
|
238 | 0fcd0cad | René Nussbaumer | ] |
239 | 0fcd0cad | René Nussbaumer | REQ_RESULT = ht.TList |
240 | 0fcd0cad | René Nussbaumer | |
241 | 0fcd0cad | René Nussbaumer | def GetRequest(self, cfg): |
242 | 0fcd0cad | René Nussbaumer | """Request an relocation of an instance
|
243 | 0fcd0cad | René Nussbaumer |
|
244 | 0fcd0cad | René Nussbaumer | The checks for the completeness of the opcode must have already been
|
245 | 0fcd0cad | René Nussbaumer | done.
|
246 | 0fcd0cad | René Nussbaumer |
|
247 | 0fcd0cad | René Nussbaumer | """
|
248 | 0fcd0cad | René Nussbaumer | instance = cfg.GetInstanceInfo(self.name)
|
249 | 0fcd0cad | René Nussbaumer | if instance is None: |
250 | 0fcd0cad | René Nussbaumer | raise errors.ProgrammerError("Unknown instance '%s' passed to" |
251 | 0fcd0cad | René Nussbaumer | " IAllocator" % self.name) |
252 | 0fcd0cad | René Nussbaumer | |
253 | 0fcd0cad | René Nussbaumer | if instance.disk_template not in constants.DTS_MIRRORED: |
254 | 0fcd0cad | René Nussbaumer | raise errors.OpPrereqError("Can't relocate non-mirrored instances", |
255 | 0fcd0cad | René Nussbaumer | errors.ECODE_INVAL) |
256 | 0fcd0cad | René Nussbaumer | |
257 | 6953756f | René Nussbaumer | if (instance.disk_template in constants.DTS_INT_MIRROR and |
258 | 6953756f | René Nussbaumer | len(instance.secondary_nodes) != 1): |
259 | 0fcd0cad | René Nussbaumer | raise errors.OpPrereqError("Instance has not exactly one secondary node", |
260 | 0fcd0cad | René Nussbaumer | errors.ECODE_STATE) |
261 | 0fcd0cad | René Nussbaumer | |
262 | 0fcd0cad | René Nussbaumer | disk_sizes = [{constants.IDISK_SIZE: disk.size} for disk in instance.disks] |
263 | 0fcd0cad | René Nussbaumer | disk_space = gmi.ComputeDiskSize(instance.disk_template, disk_sizes) |
264 | 0fcd0cad | René Nussbaumer | |
265 | 0fcd0cad | René Nussbaumer | return {
|
266 | 0fcd0cad | René Nussbaumer | "name": self.name, |
267 | 0fcd0cad | René Nussbaumer | "disk_space_total": disk_space,
|
268 | 776b6291 | René Nussbaumer | "required_nodes": 1, |
269 | 0fcd0cad | René Nussbaumer | "relocate_from": self.relocate_from, |
270 | 0fcd0cad | René Nussbaumer | } |
271 | 0fcd0cad | René Nussbaumer | |
272 | 0fcd0cad | René Nussbaumer | def ValidateResult(self, ia, result): |
273 | 0fcd0cad | René Nussbaumer | """Validates the result of an relocation request.
|
274 | 0fcd0cad | René Nussbaumer |
|
275 | 0fcd0cad | René Nussbaumer | """
|
276 | 776b6291 | René Nussbaumer | IARequestBase.ValidateResult(self, ia, result)
|
277 | 776b6291 | René Nussbaumer | |
278 | 0fcd0cad | René Nussbaumer | node2group = dict((name, ndata["group"]) |
279 | 0fcd0cad | René Nussbaumer | for (name, ndata) in ia.in_data["nodes"].items()) |
280 | 0fcd0cad | René Nussbaumer | |
281 | 0fcd0cad | René Nussbaumer | fn = compat.partial(self._NodesToGroups, node2group,
|
282 | 0fcd0cad | René Nussbaumer | ia.in_data["nodegroups"])
|
283 | 0fcd0cad | René Nussbaumer | |
284 | 0fcd0cad | René Nussbaumer | instance = ia.cfg.GetInstanceInfo(self.name)
|
285 | 0fcd0cad | René Nussbaumer | request_groups = fn(self.relocate_from + [instance.primary_node])
|
286 | 0fcd0cad | René Nussbaumer | result_groups = fn(result + [instance.primary_node]) |
287 | 0fcd0cad | René Nussbaumer | |
288 | 0fcd0cad | René Nussbaumer | if ia.success and not set(result_groups).issubset(request_groups): |
289 | 776b6291 | René Nussbaumer | raise errors.ResultValidationError("Groups of nodes returned by" |
290 | 776b6291 | René Nussbaumer | "iallocator (%s) differ from original"
|
291 | 776b6291 | René Nussbaumer | " groups (%s)" %
|
292 | 776b6291 | René Nussbaumer | (utils.CommaJoin(result_groups), |
293 | 776b6291 | René Nussbaumer | utils.CommaJoin(request_groups))) |
294 | 0fcd0cad | René Nussbaumer | |
295 | 0fcd0cad | René Nussbaumer | @staticmethod
|
296 | 0fcd0cad | René Nussbaumer | def _NodesToGroups(node2group, groups, nodes): |
297 | 0fcd0cad | René Nussbaumer | """Returns a list of unique group names for a list of nodes.
|
298 | 0fcd0cad | René Nussbaumer |
|
299 | 0fcd0cad | René Nussbaumer | @type node2group: dict
|
300 | 0fcd0cad | René Nussbaumer | @param node2group: Map from node name to group UUID
|
301 | 0fcd0cad | René Nussbaumer | @type groups: dict
|
302 | 0fcd0cad | René Nussbaumer | @param groups: Group information
|
303 | 0fcd0cad | René Nussbaumer | @type nodes: list
|
304 | 0fcd0cad | René Nussbaumer | @param nodes: Node names
|
305 | 0fcd0cad | René Nussbaumer |
|
306 | 0fcd0cad | René Nussbaumer | """
|
307 | 0fcd0cad | René Nussbaumer | result = set()
|
308 | 0fcd0cad | René Nussbaumer | |
309 | 0fcd0cad | René Nussbaumer | for node in nodes: |
310 | 0fcd0cad | René Nussbaumer | try:
|
311 | 0fcd0cad | René Nussbaumer | group_uuid = node2group[node] |
312 | 0fcd0cad | René Nussbaumer | except KeyError: |
313 | 0fcd0cad | René Nussbaumer | # Ignore unknown node
|
314 | 0fcd0cad | René Nussbaumer | pass
|
315 | 0fcd0cad | René Nussbaumer | else:
|
316 | 0fcd0cad | René Nussbaumer | try:
|
317 | 0fcd0cad | René Nussbaumer | group = groups[group_uuid] |
318 | 0fcd0cad | René Nussbaumer | except KeyError: |
319 | 0fcd0cad | René Nussbaumer | # Can't find group, let's use UUID
|
320 | 0fcd0cad | René Nussbaumer | group_name = group_uuid |
321 | 0fcd0cad | René Nussbaumer | else:
|
322 | 0fcd0cad | René Nussbaumer | group_name = group["name"]
|
323 | 0fcd0cad | René Nussbaumer | |
324 | 0fcd0cad | René Nussbaumer | result.add(group_name) |
325 | 0fcd0cad | René Nussbaumer | |
326 | 0fcd0cad | René Nussbaumer | return sorted(result) |
327 | 0fcd0cad | René Nussbaumer | |
328 | 0fcd0cad | René Nussbaumer | |
329 | 0fcd0cad | René Nussbaumer | class IAReqNodeEvac(IARequestBase): |
330 | 0fcd0cad | René Nussbaumer | """A node evacuation request.
|
331 | 0fcd0cad | René Nussbaumer |
|
332 | 0fcd0cad | René Nussbaumer | """
|
333 | c269efc3 | René Nussbaumer | # pylint: disable=E1101
|
334 | 0fcd0cad | René Nussbaumer | MODE = constants.IALLOCATOR_MODE_NODE_EVAC |
335 | 0fcd0cad | René Nussbaumer | REQ_PARAMS = [ |
336 | 0fcd0cad | René Nussbaumer | ("instances", _STRING_LIST),
|
337 | 0fcd0cad | René Nussbaumer | ("evac_mode", ht.TElemOf(constants.IALLOCATOR_NEVAC_MODES)),
|
338 | 0fcd0cad | René Nussbaumer | ] |
339 | 0fcd0cad | René Nussbaumer | REQ_RESULT = _NEVAC_RESULT |
340 | 0fcd0cad | René Nussbaumer | |
341 | 0fcd0cad | René Nussbaumer | def GetRequest(self, cfg): |
342 | 0fcd0cad | René Nussbaumer | """Get data for node-evacuate requests.
|
343 | 0fcd0cad | René Nussbaumer |
|
344 | 0fcd0cad | René Nussbaumer | """
|
345 | 0fcd0cad | René Nussbaumer | return {
|
346 | 0fcd0cad | René Nussbaumer | "instances": self.instances, |
347 | 0fcd0cad | René Nussbaumer | "evac_mode": self.evac_mode, |
348 | 0fcd0cad | René Nussbaumer | } |
349 | 0fcd0cad | René Nussbaumer | |
350 | 0fcd0cad | René Nussbaumer | |
351 | 0fcd0cad | René Nussbaumer | class IAReqGroupChange(IARequestBase): |
352 | 0fcd0cad | René Nussbaumer | """A group change request.
|
353 | 0fcd0cad | René Nussbaumer |
|
354 | 0fcd0cad | René Nussbaumer | """
|
355 | c269efc3 | René Nussbaumer | # pylint: disable=E1101
|
356 | 0fcd0cad | René Nussbaumer | MODE = constants.IALLOCATOR_MODE_CHG_GROUP |
357 | 0fcd0cad | René Nussbaumer | REQ_PARAMS = [ |
358 | 0fcd0cad | René Nussbaumer | ("instances", _STRING_LIST),
|
359 | 0fcd0cad | René Nussbaumer | ("target_groups", _STRING_LIST),
|
360 | 0fcd0cad | René Nussbaumer | ] |
361 | 0fcd0cad | René Nussbaumer | REQ_RESULT = _NEVAC_RESULT |
362 | 0fcd0cad | René Nussbaumer | |
363 | 0fcd0cad | René Nussbaumer | def GetRequest(self, cfg): |
364 | 0fcd0cad | René Nussbaumer | """Get data for node-evacuate requests.
|
365 | 0fcd0cad | René Nussbaumer |
|
366 | 0fcd0cad | René Nussbaumer | """
|
367 | 0fcd0cad | René Nussbaumer | return {
|
368 | 0fcd0cad | René Nussbaumer | "instances": self.instances, |
369 | 0fcd0cad | René Nussbaumer | "target_groups": self.target_groups, |
370 | 0fcd0cad | René Nussbaumer | } |
371 | 0fcd0cad | René Nussbaumer | |
372 | 0fcd0cad | René Nussbaumer | |
373 | 0fcd0cad | René Nussbaumer | class IAllocator(object): |
374 | 0fcd0cad | René Nussbaumer | """IAllocator framework.
|
375 | 0fcd0cad | René Nussbaumer |
|
376 | 0fcd0cad | René Nussbaumer | An IAllocator instance has three sets of attributes:
|
377 | 0fcd0cad | René Nussbaumer | - cfg that is needed to query the cluster
|
378 | 0fcd0cad | René Nussbaumer | - input data (all members of the _KEYS class attribute are required)
|
379 | 0fcd0cad | René Nussbaumer | - four buffer attributes (in|out_data|text), that represent the
|
380 | 0fcd0cad | René Nussbaumer | input (to the external script) in text and data structure format,
|
381 | 0fcd0cad | René Nussbaumer | and the output from it, again in two formats
|
382 | 0fcd0cad | René Nussbaumer | - the result variables from the script (success, info, nodes) for
|
383 | 0fcd0cad | René Nussbaumer | easy usage
|
384 | 0fcd0cad | René Nussbaumer |
|
385 | 0fcd0cad | René Nussbaumer | """
|
386 | 0fcd0cad | René Nussbaumer | # pylint: disable=R0902
|
387 | 0fcd0cad | René Nussbaumer | # lots of instance attributes
|
388 | 0fcd0cad | René Nussbaumer | |
389 | 0fcd0cad | René Nussbaumer | def __init__(self, cfg, rpc_runner, req): |
390 | 0fcd0cad | René Nussbaumer | self.cfg = cfg
|
391 | 0fcd0cad | René Nussbaumer | self.rpc = rpc_runner
|
392 | 0fcd0cad | René Nussbaumer | self.req = req
|
393 | 0fcd0cad | René Nussbaumer | # init buffer variables
|
394 | 0fcd0cad | René Nussbaumer | self.in_text = self.out_text = self.in_data = self.out_data = None |
395 | 0fcd0cad | René Nussbaumer | # init result fields
|
396 | 0fcd0cad | René Nussbaumer | self.success = self.info = self.result = None |
397 | 0fcd0cad | René Nussbaumer | |
398 | 0fcd0cad | René Nussbaumer | self._BuildInputData(req)
|
399 | 0fcd0cad | René Nussbaumer | |
400 | 0fcd0cad | René Nussbaumer | def _ComputeClusterData(self): |
401 | 0fcd0cad | René Nussbaumer | """Compute the generic allocator input data.
|
402 | 0fcd0cad | René Nussbaumer |
|
403 | 0fcd0cad | René Nussbaumer | This is the data that is independent of the actual operation.
|
404 | 0fcd0cad | René Nussbaumer |
|
405 | 0fcd0cad | René Nussbaumer | """
|
406 | 0fcd0cad | René Nussbaumer | cfg = self.cfg
|
407 | 0fcd0cad | René Nussbaumer | cluster_info = cfg.GetClusterInfo() |
408 | 0fcd0cad | René Nussbaumer | # cluster data
|
409 | 0fcd0cad | René Nussbaumer | data = { |
410 | 0fcd0cad | René Nussbaumer | "version": constants.IALLOCATOR_VERSION,
|
411 | 0fcd0cad | René Nussbaumer | "cluster_name": cfg.GetClusterName(),
|
412 | 0fcd0cad | René Nussbaumer | "cluster_tags": list(cluster_info.GetTags()), |
413 | 0fcd0cad | René Nussbaumer | "enabled_hypervisors": list(cluster_info.enabled_hypervisors), |
414 | 0fcd0cad | René Nussbaumer | "ipolicy": cluster_info.ipolicy,
|
415 | 0fcd0cad | René Nussbaumer | } |
416 | 0fcd0cad | René Nussbaumer | ninfo = cfg.GetAllNodesInfo() |
417 | 0fcd0cad | René Nussbaumer | iinfo = cfg.GetAllInstancesInfo().values() |
418 | 0fcd0cad | René Nussbaumer | i_list = [(inst, cluster_info.FillBE(inst)) for inst in iinfo] |
419 | 0fcd0cad | René Nussbaumer | |
420 | 0fcd0cad | René Nussbaumer | # node data
|
421 | 0fcd0cad | René Nussbaumer | node_list = [n.name for n in ninfo.values() if n.vm_capable] |
422 | 0fcd0cad | René Nussbaumer | |
423 | 0fcd0cad | René Nussbaumer | if isinstance(self.req, IAReqInstanceAlloc): |
424 | 0fcd0cad | René Nussbaumer | hypervisor_name = self.req.hypervisor
|
425 | fb60bc6a | Michael Hanselmann | node_whitelist = self.req.node_whitelist
|
426 | 0fcd0cad | René Nussbaumer | elif isinstance(self.req, IAReqRelocate): |
427 | 0fcd0cad | René Nussbaumer | hypervisor_name = cfg.GetInstanceInfo(self.req.name).hypervisor
|
428 | fb60bc6a | Michael Hanselmann | node_whitelist = None
|
429 | 0fcd0cad | René Nussbaumer | else:
|
430 | 0fcd0cad | René Nussbaumer | hypervisor_name = cluster_info.primary_hypervisor |
431 | fb60bc6a | Michael Hanselmann | node_whitelist = None
|
432 | 0fcd0cad | René Nussbaumer | |
433 | 319322a7 | Bernardo Dal Seno | es_flags = rpc.GetExclusiveStorageForNodeNames(cfg, node_list) |
434 | 36a566e8 | Iustin Pop | vg_name = cfg.GetVGName() |
435 | 36a566e8 | Iustin Pop | if vg_name is not None: |
436 | 36a566e8 | Iustin Pop | has_lvm = True
|
437 | 36a566e8 | Iustin Pop | vg_req = [vg_name] |
438 | 36a566e8 | Iustin Pop | else:
|
439 | 36a566e8 | Iustin Pop | has_lvm = False
|
440 | 36a566e8 | Iustin Pop | vg_req = [] |
441 | 36a566e8 | Iustin Pop | node_data = self.rpc.call_node_info(node_list, vg_req,
|
442 | 319322a7 | Bernardo Dal Seno | [hypervisor_name], es_flags) |
443 | 0fcd0cad | René Nussbaumer | node_iinfo = \ |
444 | 0fcd0cad | René Nussbaumer | self.rpc.call_all_instances_info(node_list,
|
445 | 0fcd0cad | René Nussbaumer | cluster_info.enabled_hypervisors) |
446 | 0fcd0cad | René Nussbaumer | |
447 | 0fcd0cad | René Nussbaumer | data["nodegroups"] = self._ComputeNodeGroupData(cfg) |
448 | 0fcd0cad | René Nussbaumer | |
449 | fb60bc6a | Michael Hanselmann | config_ndata = self._ComputeBasicNodeData(cfg, ninfo, node_whitelist)
|
450 | 0fcd0cad | René Nussbaumer | data["nodes"] = self._ComputeDynamicNodeData(ninfo, node_data, node_iinfo, |
451 | 36a566e8 | Iustin Pop | i_list, config_ndata, has_lvm) |
452 | 0fcd0cad | René Nussbaumer | assert len(data["nodes"]) == len(ninfo), \ |
453 | 0fcd0cad | René Nussbaumer | "Incomplete node data computed"
|
454 | 0fcd0cad | René Nussbaumer | |
455 | 0fcd0cad | René Nussbaumer | data["instances"] = self._ComputeInstanceData(cluster_info, i_list) |
456 | 0fcd0cad | René Nussbaumer | |
457 | 0fcd0cad | René Nussbaumer | self.in_data = data
|
458 | 0fcd0cad | René Nussbaumer | |
459 | 0fcd0cad | René Nussbaumer | @staticmethod
|
460 | 0fcd0cad | René Nussbaumer | def _ComputeNodeGroupData(cfg): |
461 | 0fcd0cad | René Nussbaumer | """Compute node groups data.
|
462 | 0fcd0cad | René Nussbaumer |
|
463 | 0fcd0cad | René Nussbaumer | """
|
464 | 0fcd0cad | René Nussbaumer | cluster = cfg.GetClusterInfo() |
465 | 0fcd0cad | René Nussbaumer | ng = dict((guuid, {
|
466 | 0fcd0cad | René Nussbaumer | "name": gdata.name,
|
467 | 0fcd0cad | René Nussbaumer | "alloc_policy": gdata.alloc_policy,
|
468 | 0fcd0cad | René Nussbaumer | "ipolicy": gmi.CalculateGroupIPolicy(cluster, gdata),
|
469 | f1222089 | Dimitris Aragiorgis | "tags": list(gdata.GetTags()), |
470 | 0fcd0cad | René Nussbaumer | }) |
471 | 0fcd0cad | René Nussbaumer | for guuid, gdata in cfg.GetAllNodeGroupsInfo().items()) |
472 | 0fcd0cad | René Nussbaumer | |
473 | 0fcd0cad | René Nussbaumer | return ng
|
474 | 0fcd0cad | René Nussbaumer | |
475 | 0fcd0cad | René Nussbaumer | @staticmethod
|
476 | fb60bc6a | Michael Hanselmann | def _ComputeBasicNodeData(cfg, node_cfg, node_whitelist): |
477 | 0fcd0cad | René Nussbaumer | """Compute global node data.
|
478 | 0fcd0cad | René Nussbaumer |
|
479 | 0fcd0cad | René Nussbaumer | @rtype: dict
|
480 | 0fcd0cad | René Nussbaumer | @returns: a dict of name: (node dict, node config)
|
481 | 0fcd0cad | René Nussbaumer |
|
482 | 0fcd0cad | René Nussbaumer | """
|
483 | 0fcd0cad | René Nussbaumer | # fill in static (config-based) values
|
484 | 0fcd0cad | René Nussbaumer | node_results = dict((ninfo.name, {
|
485 | 0fcd0cad | René Nussbaumer | "tags": list(ninfo.GetTags()), |
486 | 0fcd0cad | René Nussbaumer | "primary_ip": ninfo.primary_ip,
|
487 | 0fcd0cad | René Nussbaumer | "secondary_ip": ninfo.secondary_ip,
|
488 | fb60bc6a | Michael Hanselmann | "offline": (ninfo.offline or |
489 | fb60bc6a | Michael Hanselmann | not (node_whitelist is None or |
490 | fb60bc6a | Michael Hanselmann | ninfo.name in node_whitelist)),
|
491 | 0fcd0cad | René Nussbaumer | "drained": ninfo.drained,
|
492 | 0fcd0cad | René Nussbaumer | "master_candidate": ninfo.master_candidate,
|
493 | 0fcd0cad | René Nussbaumer | "group": ninfo.group,
|
494 | 0fcd0cad | René Nussbaumer | "master_capable": ninfo.master_capable,
|
495 | 0fcd0cad | René Nussbaumer | "vm_capable": ninfo.vm_capable,
|
496 | 0fcd0cad | René Nussbaumer | "ndparams": cfg.GetNdParams(ninfo),
|
497 | 0fcd0cad | René Nussbaumer | }) |
498 | 0fcd0cad | René Nussbaumer | for ninfo in node_cfg.values()) |
499 | 0fcd0cad | René Nussbaumer | |
500 | 0fcd0cad | René Nussbaumer | return node_results
|
501 | 0fcd0cad | René Nussbaumer | |
502 | 0fcd0cad | René Nussbaumer | @staticmethod
|
503 | 0fcd0cad | René Nussbaumer | def _ComputeDynamicNodeData(node_cfg, node_data, node_iinfo, i_list, |
504 | 36a566e8 | Iustin Pop | node_results, has_lvm): |
505 | 0fcd0cad | René Nussbaumer | """Compute global node data.
|
506 | 0fcd0cad | René Nussbaumer |
|
507 | 0fcd0cad | René Nussbaumer | @param node_results: the basic node structures as filled from the config
|
508 | 0fcd0cad | René Nussbaumer |
|
509 | 0fcd0cad | René Nussbaumer | """
|
510 | 0fcd0cad | René Nussbaumer | #TODO(dynmem): compute the right data on MAX and MIN memory
|
511 | 0fcd0cad | René Nussbaumer | # make a copy of the current dict
|
512 | 0fcd0cad | René Nussbaumer | node_results = dict(node_results)
|
513 | 0fcd0cad | René Nussbaumer | for nname, nresult in node_data.items(): |
514 | 0fcd0cad | René Nussbaumer | assert nname in node_results, "Missing basic data for node %s" % nname |
515 | 0fcd0cad | René Nussbaumer | ninfo = node_cfg[nname] |
516 | 0fcd0cad | René Nussbaumer | |
517 | 0fcd0cad | René Nussbaumer | if not (ninfo.offline or ninfo.drained): |
518 | 0fcd0cad | René Nussbaumer | nresult.Raise("Can't get data for node %s" % nname)
|
519 | 0fcd0cad | René Nussbaumer | node_iinfo[nname].Raise("Can't get node instance info from node %s" %
|
520 | 0fcd0cad | René Nussbaumer | nname) |
521 | 36a566e8 | Iustin Pop | remote_info = rpc.MakeLegacyNodeInfo(nresult.payload, |
522 | 36a566e8 | Iustin Pop | require_vg_info=has_lvm) |
523 | 0fcd0cad | René Nussbaumer | |
524 | 36a566e8 | Iustin Pop | def get_attr(attr): |
525 | 0fcd0cad | René Nussbaumer | if attr not in remote_info: |
526 | 0fcd0cad | René Nussbaumer | raise errors.OpExecError("Node '%s' didn't return attribute" |
527 | 0fcd0cad | René Nussbaumer | " '%s'" % (nname, attr))
|
528 | 36a566e8 | Iustin Pop | value = remote_info[attr] |
529 | 36a566e8 | Iustin Pop | if not isinstance(value, int): |
530 | 0fcd0cad | René Nussbaumer | raise errors.OpExecError("Node '%s' returned invalid value" |
531 | 0fcd0cad | René Nussbaumer | " for '%s': %s" %
|
532 | 36a566e8 | Iustin Pop | (nname, attr, value)) |
533 | 36a566e8 | Iustin Pop | return value
|
534 | 36a566e8 | Iustin Pop | |
535 | 36a566e8 | Iustin Pop | mem_free = get_attr("memory_free")
|
536 | 36a566e8 | Iustin Pop | |
537 | 0fcd0cad | René Nussbaumer | # compute memory used by primary instances
|
538 | 0fcd0cad | René Nussbaumer | i_p_mem = i_p_up_mem = 0
|
539 | 0fcd0cad | René Nussbaumer | for iinfo, beinfo in i_list: |
540 | 0fcd0cad | René Nussbaumer | if iinfo.primary_node == nname:
|
541 | 0fcd0cad | René Nussbaumer | i_p_mem += beinfo[constants.BE_MAXMEM] |
542 | 0fcd0cad | René Nussbaumer | if iinfo.name not in node_iinfo[nname].payload: |
543 | 0fcd0cad | René Nussbaumer | i_used_mem = 0
|
544 | 0fcd0cad | René Nussbaumer | else:
|
545 | 0fcd0cad | René Nussbaumer | i_used_mem = int(node_iinfo[nname].payload[iinfo.name]["memory"]) |
546 | 0fcd0cad | René Nussbaumer | i_mem_diff = beinfo[constants.BE_MAXMEM] - i_used_mem |
547 | 36a566e8 | Iustin Pop | mem_free -= max(0, i_mem_diff) |
548 | 0fcd0cad | René Nussbaumer | |
549 | 0fcd0cad | René Nussbaumer | if iinfo.admin_state == constants.ADMINST_UP:
|
550 | 0fcd0cad | René Nussbaumer | i_p_up_mem += beinfo[constants.BE_MAXMEM] |
551 | 0fcd0cad | René Nussbaumer | |
552 | 36a566e8 | Iustin Pop | # TODO: replace this with proper storage reporting
|
553 | 36a566e8 | Iustin Pop | if has_lvm:
|
554 | 36a566e8 | Iustin Pop | total_disk = get_attr("vg_size")
|
555 | 36a566e8 | Iustin Pop | free_disk = get_attr("vg_free")
|
556 | 36a566e8 | Iustin Pop | else:
|
557 | 36a566e8 | Iustin Pop | # we didn't even ask the node for VG status, so use zeros
|
558 | 36a566e8 | Iustin Pop | total_disk = free_disk = 0
|
559 | 36a566e8 | Iustin Pop | |
560 | 0fcd0cad | René Nussbaumer | # compute memory used by instances
|
561 | 0fcd0cad | René Nussbaumer | pnr_dyn = { |
562 | 36a566e8 | Iustin Pop | "total_memory": get_attr("memory_total"), |
563 | 36a566e8 | Iustin Pop | "reserved_memory": get_attr("memory_dom0"), |
564 | 36a566e8 | Iustin Pop | "free_memory": mem_free,
|
565 | 36a566e8 | Iustin Pop | "total_disk": total_disk,
|
566 | 36a566e8 | Iustin Pop | "free_disk": free_disk,
|
567 | 36a566e8 | Iustin Pop | "total_cpus": get_attr("cpu_total"), |
568 | 0fcd0cad | René Nussbaumer | "i_pri_memory": i_p_mem,
|
569 | 0fcd0cad | René Nussbaumer | "i_pri_up_memory": i_p_up_mem,
|
570 | 0fcd0cad | René Nussbaumer | } |
571 | 0fcd0cad | René Nussbaumer | pnr_dyn.update(node_results[nname]) |
572 | 0fcd0cad | René Nussbaumer | node_results[nname] = pnr_dyn |
573 | 0fcd0cad | René Nussbaumer | |
574 | 0fcd0cad | René Nussbaumer | return node_results
|
575 | 0fcd0cad | René Nussbaumer | |
576 | 0fcd0cad | René Nussbaumer | @staticmethod
|
577 | 0fcd0cad | René Nussbaumer | def _ComputeInstanceData(cluster_info, i_list): |
578 | 0fcd0cad | René Nussbaumer | """Compute global instance data.
|
579 | 0fcd0cad | René Nussbaumer |
|
580 | 0fcd0cad | René Nussbaumer | """
|
581 | 0fcd0cad | René Nussbaumer | instance_data = {} |
582 | 0fcd0cad | René Nussbaumer | for iinfo, beinfo in i_list: |
583 | 0fcd0cad | René Nussbaumer | nic_data = [] |
584 | 0fcd0cad | René Nussbaumer | for nic in iinfo.nics: |
585 | 0fcd0cad | René Nussbaumer | filled_params = cluster_info.SimpleFillNIC(nic.nicparams) |
586 | 0fcd0cad | René Nussbaumer | nic_dict = { |
587 | 0fcd0cad | René Nussbaumer | "mac": nic.mac,
|
588 | 0fcd0cad | René Nussbaumer | "ip": nic.ip,
|
589 | 0fcd0cad | René Nussbaumer | "mode": filled_params[constants.NIC_MODE],
|
590 | 0fcd0cad | René Nussbaumer | "link": filled_params[constants.NIC_LINK],
|
591 | 0fcd0cad | René Nussbaumer | } |
592 | 0fcd0cad | René Nussbaumer | if filled_params[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
|
593 | 0fcd0cad | René Nussbaumer | nic_dict["bridge"] = filled_params[constants.NIC_LINK]
|
594 | 0fcd0cad | René Nussbaumer | nic_data.append(nic_dict) |
595 | 0fcd0cad | René Nussbaumer | pir = { |
596 | 0fcd0cad | René Nussbaumer | "tags": list(iinfo.GetTags()), |
597 | 0fcd0cad | René Nussbaumer | "admin_state": iinfo.admin_state,
|
598 | 0fcd0cad | René Nussbaumer | "vcpus": beinfo[constants.BE_VCPUS],
|
599 | 0fcd0cad | René Nussbaumer | "memory": beinfo[constants.BE_MAXMEM],
|
600 | 0fcd0cad | René Nussbaumer | "spindle_use": beinfo[constants.BE_SPINDLE_USE],
|
601 | 0fcd0cad | René Nussbaumer | "os": iinfo.os,
|
602 | 0fcd0cad | René Nussbaumer | "nodes": [iinfo.primary_node] + list(iinfo.secondary_nodes), |
603 | 0fcd0cad | René Nussbaumer | "nics": nic_data,
|
604 | 0fcd0cad | René Nussbaumer | "disks": [{constants.IDISK_SIZE: dsk.size,
|
605 | 0fcd0cad | René Nussbaumer | constants.IDISK_MODE: dsk.mode} |
606 | 0fcd0cad | René Nussbaumer | for dsk in iinfo.disks], |
607 | 0fcd0cad | René Nussbaumer | "disk_template": iinfo.disk_template,
|
608 | 0fcd0cad | René Nussbaumer | "hypervisor": iinfo.hypervisor,
|
609 | 0fcd0cad | René Nussbaumer | } |
610 | 0fcd0cad | René Nussbaumer | pir["disk_space_total"] = gmi.ComputeDiskSize(iinfo.disk_template,
|
611 | 0fcd0cad | René Nussbaumer | pir["disks"])
|
612 | 0fcd0cad | René Nussbaumer | instance_data[iinfo.name] = pir |
613 | 0fcd0cad | René Nussbaumer | |
614 | 0fcd0cad | René Nussbaumer | return instance_data
|
615 | 0fcd0cad | René Nussbaumer | |
616 | 0fcd0cad | René Nussbaumer | def _BuildInputData(self, req): |
617 | 0fcd0cad | René Nussbaumer | """Build input data structures.
|
618 | 0fcd0cad | René Nussbaumer |
|
619 | 0fcd0cad | René Nussbaumer | """
|
620 | 0fcd0cad | René Nussbaumer | self._ComputeClusterData()
|
621 | 0fcd0cad | René Nussbaumer | |
622 | 0fcd0cad | René Nussbaumer | request = req.GetRequest(self.cfg)
|
623 | 0fcd0cad | René Nussbaumer | request["type"] = req.MODE
|
624 | 0fcd0cad | René Nussbaumer | self.in_data["request"] = request |
625 | 0fcd0cad | René Nussbaumer | |
626 | 0fcd0cad | René Nussbaumer | self.in_text = serializer.Dump(self.in_data) |
627 | 0fcd0cad | René Nussbaumer | |
628 | 0fcd0cad | René Nussbaumer | def Run(self, name, validate=True, call_fn=None): |
629 | 0fcd0cad | René Nussbaumer | """Run an instance allocator and return the results.
|
630 | 0fcd0cad | René Nussbaumer |
|
631 | 0fcd0cad | René Nussbaumer | """
|
632 | 0fcd0cad | René Nussbaumer | if call_fn is None: |
633 | 0fcd0cad | René Nussbaumer | call_fn = self.rpc.call_iallocator_runner
|
634 | 0fcd0cad | René Nussbaumer | |
635 | 0fcd0cad | René Nussbaumer | result = call_fn(self.cfg.GetMasterNode(), name, self.in_text) |
636 | 0fcd0cad | René Nussbaumer | result.Raise("Failure while running the iallocator script")
|
637 | 0fcd0cad | René Nussbaumer | |
638 | 0fcd0cad | René Nussbaumer | self.out_text = result.payload
|
639 | 0fcd0cad | René Nussbaumer | if validate:
|
640 | 0fcd0cad | René Nussbaumer | self._ValidateResult()
|
641 | 0fcd0cad | René Nussbaumer | |
642 | 0fcd0cad | René Nussbaumer | def _ValidateResult(self): |
643 | 0fcd0cad | René Nussbaumer | """Process the allocator results.
|
644 | 0fcd0cad | René Nussbaumer |
|
645 | 0fcd0cad | René Nussbaumer | This will process and if successful save the result in
|
646 | 0fcd0cad | René Nussbaumer | self.out_data and the other parameters.
|
647 | 0fcd0cad | René Nussbaumer |
|
648 | 0fcd0cad | René Nussbaumer | """
|
649 | 0fcd0cad | René Nussbaumer | try:
|
650 | 0fcd0cad | René Nussbaumer | rdict = serializer.Load(self.out_text)
|
651 | 0fcd0cad | René Nussbaumer | except Exception, err: |
652 | 0fcd0cad | René Nussbaumer | raise errors.OpExecError("Can't parse iallocator results: %s" % str(err)) |
653 | 0fcd0cad | René Nussbaumer | |
654 | 0fcd0cad | René Nussbaumer | if not isinstance(rdict, dict): |
655 | 0fcd0cad | René Nussbaumer | raise errors.OpExecError("Can't parse iallocator results: not a dict") |
656 | 0fcd0cad | René Nussbaumer | |
657 | 0fcd0cad | René Nussbaumer | # TODO: remove backwards compatiblity in later versions
|
658 | 0fcd0cad | René Nussbaumer | if "nodes" in rdict and "result" not in rdict: |
659 | 0fcd0cad | René Nussbaumer | rdict["result"] = rdict["nodes"] |
660 | 0fcd0cad | René Nussbaumer | del rdict["nodes"] |
661 | 0fcd0cad | René Nussbaumer | |
662 | 0fcd0cad | René Nussbaumer | for key in "success", "info", "result": |
663 | 0fcd0cad | René Nussbaumer | if key not in rdict: |
664 | 0fcd0cad | René Nussbaumer | raise errors.OpExecError("Can't parse iallocator results:" |
665 | 0fcd0cad | René Nussbaumer | " missing key '%s'" % key)
|
666 | 0fcd0cad | René Nussbaumer | setattr(self, key, rdict[key]) |
667 | 0fcd0cad | René Nussbaumer | |
668 | 0fcd0cad | René Nussbaumer | self.req.ValidateResult(self, self.result) |
669 | 0fcd0cad | René Nussbaumer | self.out_data = rdict |