root / lib / masterd / iallocator.py @ 4869595d
History | View | Annotate | Download (27.1 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 | 4869595d | Petr Pudlak | import ganeti.rpc.node as 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 | d067f40b | Jose A. Lopes | ("evac_mode", ht.TEvacMode),
|
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 | e8936ef7 | Helga Velroyen | def _ComputeClusterDataNodeInfo(self, disk_templates, node_list, |
403 | e8936ef7 | Helga Velroyen | cluster_info, hypervisor_name): |
404 | c9c4b92d | Helga Velroyen | """Prepare and execute node info call.
|
405 | c9c4b92d | Helga Velroyen |
|
406 | e8936ef7 | Helga Velroyen | @type disk_templates: list of string
|
407 | e8936ef7 | Helga Velroyen | @param disk_templates: the disk templates of the instances to be allocated
|
408 | c9c4b92d | Helga Velroyen | @type node_list: list of strings
|
409 | c9c4b92d | Helga Velroyen | @param node_list: list of nodes' UUIDs
|
410 | c9c4b92d | Helga Velroyen | @type cluster_info: L{objects.Cluster}
|
411 | c9c4b92d | Helga Velroyen | @param cluster_info: the cluster's information from the config
|
412 | c9c4b92d | Helga Velroyen | @type hypervisor_name: string
|
413 | c9c4b92d | Helga Velroyen | @param hypervisor_name: the hypervisor name
|
414 | c9c4b92d | Helga Velroyen | @rtype: same as the result of the node info RPC call
|
415 | c9c4b92d | Helga Velroyen | @return: the result of the node info RPC call
|
416 | c9c4b92d | Helga Velroyen |
|
417 | c9c4b92d | Helga Velroyen | """
|
418 | 6c00b2c7 | Helga Velroyen | storage_units_raw = utils.storage.GetStorageUnits(self.cfg, disk_templates)
|
419 | da803ff1 | Helga Velroyen | storage_units = rpc.PrepareStorageUnitsForNodes(self.cfg, storage_units_raw,
|
420 | da803ff1 | Helga Velroyen | node_list) |
421 | c9c4b92d | Helga Velroyen | hvspecs = [(hypervisor_name, cluster_info.hvparams[hypervisor_name])] |
422 | da803ff1 | Helga Velroyen | return self.rpc.call_node_info(node_list, storage_units, hvspecs) |
423 | c9c4b92d | Helga Velroyen | |
424 | e8936ef7 | Helga Velroyen | def _ComputeClusterData(self, disk_template=None): |
425 | 0fcd0cad | René Nussbaumer | """Compute the generic allocator input data.
|
426 | 0fcd0cad | René Nussbaumer |
|
427 | e8936ef7 | Helga Velroyen | @type disk_template: list of string
|
428 | e8936ef7 | Helga Velroyen | @param disk_template: the disk templates of the instances to be allocated
|
429 | 0fcd0cad | René Nussbaumer |
|
430 | 0fcd0cad | René Nussbaumer | """
|
431 | d0d7d7cf | Thomas Thrainer | cluster_info = self.cfg.GetClusterInfo()
|
432 | 0fcd0cad | René Nussbaumer | # cluster data
|
433 | 0fcd0cad | René Nussbaumer | data = { |
434 | 0fcd0cad | René Nussbaumer | "version": constants.IALLOCATOR_VERSION,
|
435 | d0d7d7cf | Thomas Thrainer | "cluster_name": self.cfg.GetClusterName(), |
436 | 0fcd0cad | René Nussbaumer | "cluster_tags": list(cluster_info.GetTags()), |
437 | 0fcd0cad | René Nussbaumer | "enabled_hypervisors": list(cluster_info.enabled_hypervisors), |
438 | 0fcd0cad | René Nussbaumer | "ipolicy": cluster_info.ipolicy,
|
439 | 0fcd0cad | René Nussbaumer | } |
440 | d0d7d7cf | Thomas Thrainer | ninfo = self.cfg.GetAllNodesInfo()
|
441 | d0d7d7cf | Thomas Thrainer | iinfo = self.cfg.GetAllInstancesInfo().values()
|
442 | 0fcd0cad | René Nussbaumer | i_list = [(inst, cluster_info.FillBE(inst)) for inst in iinfo] |
443 | 0fcd0cad | René Nussbaumer | |
444 | 0fcd0cad | René Nussbaumer | # node data
|
445 | 1c3231aa | Thomas Thrainer | node_list = [n.uuid for n in ninfo.values() if n.vm_capable] |
446 | 0fcd0cad | René Nussbaumer | |
447 | 0fcd0cad | René Nussbaumer | if isinstance(self.req, IAReqInstanceAlloc): |
448 | 0fcd0cad | René Nussbaumer | hypervisor_name = self.req.hypervisor
|
449 | fb60bc6a | Michael Hanselmann | node_whitelist = self.req.node_whitelist
|
450 | 0fcd0cad | René Nussbaumer | elif isinstance(self.req, IAReqRelocate): |
451 | da4a52a3 | Thomas Thrainer | hypervisor_name = self.cfg.GetInstanceInfo(self.req.inst_uuid).hypervisor |
452 | fb60bc6a | Michael Hanselmann | node_whitelist = None
|
453 | 0fcd0cad | René Nussbaumer | else:
|
454 | 0fcd0cad | René Nussbaumer | hypervisor_name = cluster_info.primary_hypervisor |
455 | fb60bc6a | Michael Hanselmann | node_whitelist = None
|
456 | 0fcd0cad | René Nussbaumer | |
457 | e8936ef7 | Helga Velroyen | if not disk_template: |
458 | e8936ef7 | Helga Velroyen | disk_template = cluster_info.enabled_disk_templates[0]
|
459 | e8936ef7 | Helga Velroyen | |
460 | e8936ef7 | Helga Velroyen | node_data = self._ComputeClusterDataNodeInfo([disk_template], node_list,
|
461 | e8936ef7 | Helga Velroyen | cluster_info, hypervisor_name) |
462 | c9c4b92d | Helga Velroyen | |
463 | 0fcd0cad | René Nussbaumer | node_iinfo = \ |
464 | 0fcd0cad | René Nussbaumer | self.rpc.call_all_instances_info(node_list,
|
465 | 0200a1af | Helga Velroyen | cluster_info.enabled_hypervisors, |
466 | 0200a1af | Helga Velroyen | cluster_info.hvparams) |
467 | 0fcd0cad | René Nussbaumer | |
468 | d0d7d7cf | Thomas Thrainer | data["nodegroups"] = self._ComputeNodeGroupData(self.cfg) |
469 | 0fcd0cad | René Nussbaumer | |
470 | d0d7d7cf | Thomas Thrainer | config_ndata = self._ComputeBasicNodeData(self.cfg, ninfo, node_whitelist) |
471 | e8936ef7 | Helga Velroyen | data["nodes"] = self._ComputeDynamicNodeData( |
472 | e8936ef7 | Helga Velroyen | ninfo, node_data, node_iinfo, i_list, config_ndata, disk_template) |
473 | 0fcd0cad | René Nussbaumer | assert len(data["nodes"]) == len(ninfo), \ |
474 | 0fcd0cad | René Nussbaumer | "Incomplete node data computed"
|
475 | 0fcd0cad | René Nussbaumer | |
476 | d0d7d7cf | Thomas Thrainer | data["instances"] = self._ComputeInstanceData(self.cfg, cluster_info, |
477 | d0d7d7cf | Thomas Thrainer | i_list) |
478 | 0fcd0cad | René Nussbaumer | |
479 | 0fcd0cad | René Nussbaumer | self.in_data = data
|
480 | 0fcd0cad | René Nussbaumer | |
481 | 0fcd0cad | René Nussbaumer | @staticmethod
|
482 | 0fcd0cad | René Nussbaumer | def _ComputeNodeGroupData(cfg): |
483 | 0fcd0cad | René Nussbaumer | """Compute node groups data.
|
484 | 0fcd0cad | René Nussbaumer |
|
485 | 0fcd0cad | René Nussbaumer | """
|
486 | 0fcd0cad | René Nussbaumer | cluster = cfg.GetClusterInfo() |
487 | 0fcd0cad | René Nussbaumer | ng = dict((guuid, {
|
488 | 0fcd0cad | René Nussbaumer | "name": gdata.name,
|
489 | 0fcd0cad | René Nussbaumer | "alloc_policy": gdata.alloc_policy,
|
490 | 98ae702b | Thomas Thrainer | "networks": [net_uuid for net_uuid, _ in gdata.networks.items()], |
491 | 0fcd0cad | René Nussbaumer | "ipolicy": gmi.CalculateGroupIPolicy(cluster, gdata),
|
492 | f1222089 | Dimitris Aragiorgis | "tags": list(gdata.GetTags()), |
493 | 0fcd0cad | René Nussbaumer | }) |
494 | 0fcd0cad | René Nussbaumer | for guuid, gdata in cfg.GetAllNodeGroupsInfo().items()) |
495 | 0fcd0cad | René Nussbaumer | |
496 | 0fcd0cad | René Nussbaumer | return ng
|
497 | 0fcd0cad | René Nussbaumer | |
498 | 0fcd0cad | René Nussbaumer | @staticmethod
|
499 | fb60bc6a | Michael Hanselmann | def _ComputeBasicNodeData(cfg, node_cfg, node_whitelist): |
500 | 0fcd0cad | René Nussbaumer | """Compute global node data.
|
501 | 0fcd0cad | René Nussbaumer |
|
502 | 0fcd0cad | René Nussbaumer | @rtype: dict
|
503 | 0fcd0cad | René Nussbaumer | @returns: a dict of name: (node dict, node config)
|
504 | 0fcd0cad | René Nussbaumer |
|
505 | 0fcd0cad | René Nussbaumer | """
|
506 | 0fcd0cad | René Nussbaumer | # fill in static (config-based) values
|
507 | 0fcd0cad | René Nussbaumer | node_results = dict((ninfo.name, {
|
508 | 0fcd0cad | René Nussbaumer | "tags": list(ninfo.GetTags()), |
509 | 0fcd0cad | René Nussbaumer | "primary_ip": ninfo.primary_ip,
|
510 | 0fcd0cad | René Nussbaumer | "secondary_ip": ninfo.secondary_ip,
|
511 | fb60bc6a | Michael Hanselmann | "offline": (ninfo.offline or |
512 | fb60bc6a | Michael Hanselmann | not (node_whitelist is None or |
513 | fb60bc6a | Michael Hanselmann | ninfo.name in node_whitelist)),
|
514 | 0fcd0cad | René Nussbaumer | "drained": ninfo.drained,
|
515 | 0fcd0cad | René Nussbaumer | "master_candidate": ninfo.master_candidate,
|
516 | 0fcd0cad | René Nussbaumer | "group": ninfo.group,
|
517 | 0fcd0cad | René Nussbaumer | "master_capable": ninfo.master_capable,
|
518 | 0fcd0cad | René Nussbaumer | "vm_capable": ninfo.vm_capable,
|
519 | 0fcd0cad | René Nussbaumer | "ndparams": cfg.GetNdParams(ninfo),
|
520 | 0fcd0cad | René Nussbaumer | }) |
521 | 0fcd0cad | René Nussbaumer | for ninfo in node_cfg.values()) |
522 | 0fcd0cad | René Nussbaumer | |
523 | 0fcd0cad | René Nussbaumer | return node_results
|
524 | 0fcd0cad | René Nussbaumer | |
525 | 0fcd0cad | René Nussbaumer | @staticmethod
|
526 | b82d7182 | Helga Velroyen | def _GetAttributeFromHypervisorNodeData(hv_info, node_name, attr): |
527 | b82d7182 | Helga Velroyen | """Extract an attribute from the hypervisor's node information.
|
528 | 0f70b3fb | Helga Velroyen |
|
529 | b82d7182 | Helga Velroyen | This is a helper function to extract data from the hypervisor's information
|
530 | b82d7182 | Helga Velroyen | about the node, as part of the result of a node_info query.
|
531 | b82d7182 | Helga Velroyen |
|
532 | b82d7182 | Helga Velroyen | @type hv_info: dict of strings
|
533 | b82d7182 | Helga Velroyen | @param hv_info: dictionary of node information from the hypervisor
|
534 | 0f70b3fb | Helga Velroyen | @type node_name: string
|
535 | 0f70b3fb | Helga Velroyen | @param node_name: name of the node
|
536 | 0f70b3fb | Helga Velroyen | @type attr: string
|
537 | b82d7182 | Helga Velroyen | @param attr: key of the attribute in the hv_info dictionary
|
538 | 0f70b3fb | Helga Velroyen | @rtype: integer
|
539 | 0f70b3fb | Helga Velroyen | @return: the value of the attribute
|
540 | 0f70b3fb | Helga Velroyen | @raises errors.OpExecError: if key not in dictionary or value not
|
541 | 0f70b3fb | Helga Velroyen | integer
|
542 | 0f70b3fb | Helga Velroyen |
|
543 | 0f70b3fb | Helga Velroyen | """
|
544 | b82d7182 | Helga Velroyen | if attr not in hv_info: |
545 | 0f70b3fb | Helga Velroyen | raise errors.OpExecError("Node '%s' didn't return attribute" |
546 | 0f70b3fb | Helga Velroyen | " '%s'" % (node_name, attr))
|
547 | b82d7182 | Helga Velroyen | value = hv_info[attr] |
548 | 0f70b3fb | Helga Velroyen | if not isinstance(value, int): |
549 | 0f70b3fb | Helga Velroyen | raise errors.OpExecError("Node '%s' returned invalid value" |
550 | 0f70b3fb | Helga Velroyen | " for '%s': %s" %
|
551 | 0f70b3fb | Helga Velroyen | (node_name, attr, value)) |
552 | 0f70b3fb | Helga Velroyen | return value
|
553 | 0f70b3fb | Helga Velroyen | |
554 | 20529708 | Helga Velroyen | @staticmethod
|
555 | e8936ef7 | Helga Velroyen | def _ComputeStorageDataFromSpaceInfoByTemplate( |
556 | e8936ef7 | Helga Velroyen | space_info, node_name, disk_template): |
557 | e8936ef7 | Helga Velroyen | """Extract storage data from node info.
|
558 | e8936ef7 | Helga Velroyen |
|
559 | e8936ef7 | Helga Velroyen | @type space_info: see result of the RPC call node info
|
560 | e8936ef7 | Helga Velroyen | @param space_info: the storage reporting part of the result of the RPC call
|
561 | e8936ef7 | Helga Velroyen | node info
|
562 | e8936ef7 | Helga Velroyen | @type node_name: string
|
563 | e8936ef7 | Helga Velroyen | @param node_name: the node's name
|
564 | e8936ef7 | Helga Velroyen | @type disk_template: string
|
565 | e8936ef7 | Helga Velroyen | @param disk_template: the disk template to report space for
|
566 | e8936ef7 | Helga Velroyen | @rtype: 4-tuple of integers
|
567 | e8936ef7 | Helga Velroyen | @return: tuple of storage info (total_disk, free_disk, total_spindles,
|
568 | e8936ef7 | Helga Velroyen | free_spindles)
|
569 | e8936ef7 | Helga Velroyen |
|
570 | e8936ef7 | Helga Velroyen | """
|
571 | e8936ef7 | Helga Velroyen | storage_type = constants.MAP_DISK_TEMPLATE_STORAGE_TYPE[disk_template] |
572 | e8936ef7 | Helga Velroyen | if storage_type not in constants.STS_REPORT: |
573 | e8936ef7 | Helga Velroyen | total_disk = total_spindles = 0
|
574 | e8936ef7 | Helga Velroyen | free_disk = free_spindles = 0
|
575 | e8936ef7 | Helga Velroyen | else:
|
576 | e8936ef7 | Helga Velroyen | template_space_info = utils.storage.LookupSpaceInfoByDiskTemplate( |
577 | e8936ef7 | Helga Velroyen | space_info, disk_template) |
578 | e8936ef7 | Helga Velroyen | if not template_space_info: |
579 | e8936ef7 | Helga Velroyen | raise errors.OpExecError("Node '%s' didn't return space info for disk" |
580 | e8936ef7 | Helga Velroyen | "template '%s'" % (node_name, disk_template))
|
581 | e8936ef7 | Helga Velroyen | total_disk = template_space_info["storage_size"]
|
582 | e8936ef7 | Helga Velroyen | free_disk = template_space_info["storage_free"]
|
583 | e8936ef7 | Helga Velroyen | |
584 | 6c00b2c7 | Helga Velroyen | total_spindles = 0
|
585 | 6c00b2c7 | Helga Velroyen | free_spindles = 0
|
586 | e8936ef7 | Helga Velroyen | if disk_template in constants.DTS_LVM: |
587 | e8936ef7 | Helga Velroyen | lvm_pv_info = utils.storage.LookupSpaceInfoByStorageType( |
588 | e8936ef7 | Helga Velroyen | space_info, constants.ST_LVM_PV) |
589 | 6c00b2c7 | Helga Velroyen | if lvm_pv_info:
|
590 | 6c00b2c7 | Helga Velroyen | total_spindles = lvm_pv_info["storage_size"]
|
591 | 6c00b2c7 | Helga Velroyen | free_spindles = lvm_pv_info["storage_free"]
|
592 | e8936ef7 | Helga Velroyen | return (total_disk, free_disk, total_spindles, free_spindles)
|
593 | e8936ef7 | Helga Velroyen | |
594 | e8936ef7 | Helga Velroyen | @staticmethod
|
595 | 9353adde | Helga Velroyen | def _ComputeStorageDataFromSpaceInfo(space_info, node_name, has_lvm): |
596 | 9353adde | Helga Velroyen | """Extract storage data from node info.
|
597 | 20529708 | Helga Velroyen |
|
598 | 9353adde | Helga Velroyen | @type space_info: see result of the RPC call node info
|
599 | 9353adde | Helga Velroyen | @param space_info: the storage reporting part of the result of the RPC call
|
600 | 9353adde | Helga Velroyen | node info
|
601 | 20529708 | Helga Velroyen | @type node_name: string
|
602 | 20529708 | Helga Velroyen | @param node_name: the node's name
|
603 | 20529708 | Helga Velroyen | @type has_lvm: boolean
|
604 | 11aa3ca5 | Helga Velroyen | @param has_lvm: whether or not LVM storage information is requested
|
605 | 20529708 | Helga Velroyen | @rtype: 4-tuple of integers
|
606 | 20529708 | Helga Velroyen | @return: tuple of storage info (total_disk, free_disk, total_spindles,
|
607 | 20529708 | Helga Velroyen | free_spindles)
|
608 | 20529708 | Helga Velroyen |
|
609 | 20529708 | Helga Velroyen | """
|
610 | 20529708 | Helga Velroyen | # TODO: replace this with proper storage reporting
|
611 | 20529708 | Helga Velroyen | if has_lvm:
|
612 | 11aa3ca5 | Helga Velroyen | lvm_vg_info = utils.storage.LookupSpaceInfoByStorageType( |
613 | 11aa3ca5 | Helga Velroyen | space_info, constants.ST_LVM_VG) |
614 | 11aa3ca5 | Helga Velroyen | if not lvm_vg_info: |
615 | 11aa3ca5 | Helga Velroyen | raise errors.OpExecError("Node '%s' didn't return LVM vg space info." |
616 | 11aa3ca5 | Helga Velroyen | % (node_name)) |
617 | 11aa3ca5 | Helga Velroyen | total_disk = lvm_vg_info["storage_size"]
|
618 | 11aa3ca5 | Helga Velroyen | free_disk = lvm_vg_info["storage_free"]
|
619 | 11aa3ca5 | Helga Velroyen | lvm_pv_info = utils.storage.LookupSpaceInfoByStorageType( |
620 | 11aa3ca5 | Helga Velroyen | space_info, constants.ST_LVM_PV) |
621 | e8936ef7 | Helga Velroyen | if not lvm_pv_info: |
622 | 11aa3ca5 | Helga Velroyen | raise errors.OpExecError("Node '%s' didn't return LVM pv space info." |
623 | 11aa3ca5 | Helga Velroyen | % (node_name)) |
624 | 11aa3ca5 | Helga Velroyen | total_spindles = lvm_pv_info["storage_size"]
|
625 | 11aa3ca5 | Helga Velroyen | free_spindles = lvm_pv_info["storage_free"]
|
626 | 20529708 | Helga Velroyen | else:
|
627 | 20529708 | Helga Velroyen | # we didn't even ask the node for VG status, so use zeros
|
628 | 20529708 | Helga Velroyen | total_disk = free_disk = 0
|
629 | 20529708 | Helga Velroyen | total_spindles = free_spindles = 0
|
630 | 20529708 | Helga Velroyen | return (total_disk, free_disk, total_spindles, free_spindles)
|
631 | 20529708 | Helga Velroyen | |
632 | 0ac34c90 | Helga Velroyen | @staticmethod
|
633 | 0ac34c90 | Helga Velroyen | def _ComputeInstanceMemory(instance_list, node_instances_info, node_uuid, |
634 | 0ac34c90 | Helga Velroyen | input_mem_free): |
635 | 0ac34c90 | Helga Velroyen | """Compute memory used by primary instances.
|
636 | 0ac34c90 | Helga Velroyen |
|
637 | 0ac34c90 | Helga Velroyen | @rtype: tuple (int, int, int)
|
638 | 0ac34c90 | Helga Velroyen | @returns: A tuple of three integers: 1. the sum of memory used by primary
|
639 | 0ac34c90 | Helga Velroyen | instances on the node (including the ones that are currently down), 2.
|
640 | 0ac34c90 | Helga Velroyen | the sum of memory used by primary instances of the node that are up, 3.
|
641 | 0ac34c90 | Helga Velroyen | the amount of memory that is free on the node considering the current
|
642 | 0ac34c90 | Helga Velroyen | usage of the instances.
|
643 | 0ac34c90 | Helga Velroyen |
|
644 | 0ac34c90 | Helga Velroyen | """
|
645 | 0ac34c90 | Helga Velroyen | i_p_mem = i_p_up_mem = 0
|
646 | 0ac34c90 | Helga Velroyen | mem_free = input_mem_free |
647 | 0ac34c90 | Helga Velroyen | for iinfo, beinfo in instance_list: |
648 | 0ac34c90 | Helga Velroyen | if iinfo.primary_node == node_uuid:
|
649 | 0ac34c90 | Helga Velroyen | i_p_mem += beinfo[constants.BE_MAXMEM] |
650 | 0ac34c90 | Helga Velroyen | if iinfo.name not in node_instances_info[node_uuid].payload: |
651 | 0ac34c90 | Helga Velroyen | i_used_mem = 0
|
652 | 0ac34c90 | Helga Velroyen | else:
|
653 | 0ac34c90 | Helga Velroyen | i_used_mem = int(node_instances_info[node_uuid]
|
654 | 0ac34c90 | Helga Velroyen | .payload[iinfo.name]["memory"])
|
655 | 0ac34c90 | Helga Velroyen | i_mem_diff = beinfo[constants.BE_MAXMEM] - i_used_mem |
656 | 0ac34c90 | Helga Velroyen | mem_free -= max(0, i_mem_diff) |
657 | 0ac34c90 | Helga Velroyen | |
658 | 0ac34c90 | Helga Velroyen | if iinfo.admin_state == constants.ADMINST_UP:
|
659 | 0ac34c90 | Helga Velroyen | i_p_up_mem += beinfo[constants.BE_MAXMEM] |
660 | 0ac34c90 | Helga Velroyen | return (i_p_mem, i_p_up_mem, mem_free)
|
661 | 0ac34c90 | Helga Velroyen | |
662 | 0f70b3fb | Helga Velroyen | def _ComputeDynamicNodeData(self, node_cfg, node_data, node_iinfo, i_list, |
663 | e8936ef7 | Helga Velroyen | node_results, disk_template): |
664 | 0fcd0cad | René Nussbaumer | """Compute global node data.
|
665 | 0fcd0cad | René Nussbaumer |
|
666 | 0fcd0cad | René Nussbaumer | @param node_results: the basic node structures as filled from the config
|
667 | 0fcd0cad | René Nussbaumer |
|
668 | 0fcd0cad | René Nussbaumer | """
|
669 | 0fcd0cad | René Nussbaumer | #TODO(dynmem): compute the right data on MAX and MIN memory
|
670 | 0fcd0cad | René Nussbaumer | # make a copy of the current dict
|
671 | 0fcd0cad | René Nussbaumer | node_results = dict(node_results)
|
672 | 1c3231aa | Thomas Thrainer | for nuuid, nresult in node_data.items(): |
673 | 1c3231aa | Thomas Thrainer | ninfo = node_cfg[nuuid] |
674 | 1c3231aa | Thomas Thrainer | assert ninfo.name in node_results, "Missing basic data for node %s" % \ |
675 | 1c3231aa | Thomas Thrainer | ninfo.name |
676 | 0fcd0cad | René Nussbaumer | |
677 | 0fcd0cad | René Nussbaumer | if not (ninfo.offline or ninfo.drained): |
678 | 1c3231aa | Thomas Thrainer | nresult.Raise("Can't get data for node %s" % ninfo.name)
|
679 | 1c3231aa | Thomas Thrainer | node_iinfo[nuuid].Raise("Can't get node instance info from node %s" %
|
680 | 1c3231aa | Thomas Thrainer | ninfo.name) |
681 | 9353adde | Helga Velroyen | (_, space_info, (hv_info, )) = nresult.payload |
682 | 0fcd0cad | René Nussbaumer | |
683 | b82d7182 | Helga Velroyen | mem_free = self._GetAttributeFromHypervisorNodeData(hv_info, ninfo.name,
|
684 | b82d7182 | Helga Velroyen | "memory_free")
|
685 | 36a566e8 | Iustin Pop | |
686 | 0ac34c90 | Helga Velroyen | (i_p_mem, i_p_up_mem, mem_free) = self._ComputeInstanceMemory(
|
687 | 0ac34c90 | Helga Velroyen | i_list, node_iinfo, nuuid, mem_free) |
688 | 20529708 | Helga Velroyen | (total_disk, free_disk, total_spindles, free_spindles) = \ |
689 | e8936ef7 | Helga Velroyen | self._ComputeStorageDataFromSpaceInfoByTemplate(
|
690 | e8936ef7 | Helga Velroyen | space_info, ninfo.name, disk_template) |
691 | 36a566e8 | Iustin Pop | |
692 | 0fcd0cad | René Nussbaumer | # compute memory used by instances
|
693 | 0fcd0cad | René Nussbaumer | pnr_dyn = { |
694 | b82d7182 | Helga Velroyen | "total_memory": self._GetAttributeFromHypervisorNodeData( |
695 | b82d7182 | Helga Velroyen | hv_info, ninfo.name, "memory_total"),
|
696 | b82d7182 | Helga Velroyen | "reserved_memory": self._GetAttributeFromHypervisorNodeData( |
697 | b82d7182 | Helga Velroyen | hv_info, ninfo.name, "memory_dom0"),
|
698 | 36a566e8 | Iustin Pop | "free_memory": mem_free,
|
699 | 36a566e8 | Iustin Pop | "total_disk": total_disk,
|
700 | 36a566e8 | Iustin Pop | "free_disk": free_disk,
|
701 | 06fb92cf | Bernardo Dal Seno | "total_spindles": total_spindles,
|
702 | 06fb92cf | Bernardo Dal Seno | "free_spindles": free_spindles,
|
703 | b82d7182 | Helga Velroyen | "total_cpus": self._GetAttributeFromHypervisorNodeData( |
704 | b82d7182 | Helga Velroyen | hv_info, ninfo.name, "cpu_total"),
|
705 | f43c898d | Bernardo Dal Seno | "reserved_cpus": self._GetAttributeFromHypervisorNodeData( |
706 | f43c898d | Bernardo Dal Seno | hv_info, ninfo.name, "cpu_dom0"),
|
707 | 0fcd0cad | René Nussbaumer | "i_pri_memory": i_p_mem,
|
708 | 0fcd0cad | René Nussbaumer | "i_pri_up_memory": i_p_up_mem,
|
709 | 0fcd0cad | René Nussbaumer | } |
710 | 1c3231aa | Thomas Thrainer | pnr_dyn.update(node_results[ninfo.name]) |
711 | 1c3231aa | Thomas Thrainer | node_results[ninfo.name] = pnr_dyn |
712 | 0fcd0cad | René Nussbaumer | |
713 | 0fcd0cad | René Nussbaumer | return node_results
|
714 | 0fcd0cad | René Nussbaumer | |
715 | 0fcd0cad | René Nussbaumer | @staticmethod
|
716 | 1c3231aa | Thomas Thrainer | def _ComputeInstanceData(cfg, cluster_info, i_list): |
717 | 0fcd0cad | René Nussbaumer | """Compute global instance data.
|
718 | 0fcd0cad | René Nussbaumer |
|
719 | 0fcd0cad | René Nussbaumer | """
|
720 | 0fcd0cad | René Nussbaumer | instance_data = {} |
721 | 0fcd0cad | René Nussbaumer | for iinfo, beinfo in i_list: |
722 | 0fcd0cad | René Nussbaumer | nic_data = [] |
723 | 0fcd0cad | René Nussbaumer | for nic in iinfo.nics: |
724 | 0fcd0cad | René Nussbaumer | filled_params = cluster_info.SimpleFillNIC(nic.nicparams) |
725 | 0fcd0cad | René Nussbaumer | nic_dict = { |
726 | 0fcd0cad | René Nussbaumer | "mac": nic.mac,
|
727 | 0fcd0cad | René Nussbaumer | "ip": nic.ip,
|
728 | 0fcd0cad | René Nussbaumer | "mode": filled_params[constants.NIC_MODE],
|
729 | 0fcd0cad | René Nussbaumer | "link": filled_params[constants.NIC_LINK],
|
730 | 0fcd0cad | René Nussbaumer | } |
731 | 0fcd0cad | René Nussbaumer | if filled_params[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
|
732 | 0fcd0cad | René Nussbaumer | nic_dict["bridge"] = filled_params[constants.NIC_LINK]
|
733 | 0fcd0cad | René Nussbaumer | nic_data.append(nic_dict) |
734 | 0fcd0cad | René Nussbaumer | pir = { |
735 | 0fcd0cad | René Nussbaumer | "tags": list(iinfo.GetTags()), |
736 | 0fcd0cad | René Nussbaumer | "admin_state": iinfo.admin_state,
|
737 | 0fcd0cad | René Nussbaumer | "vcpus": beinfo[constants.BE_VCPUS],
|
738 | 0fcd0cad | René Nussbaumer | "memory": beinfo[constants.BE_MAXMEM],
|
739 | 0fcd0cad | René Nussbaumer | "spindle_use": beinfo[constants.BE_SPINDLE_USE],
|
740 | 0fcd0cad | René Nussbaumer | "os": iinfo.os,
|
741 | 1c3231aa | Thomas Thrainer | "nodes": [cfg.GetNodeName(iinfo.primary_node)] +
|
742 | 1c3231aa | Thomas Thrainer | cfg.GetNodeNames(iinfo.secondary_nodes), |
743 | 0fcd0cad | René Nussbaumer | "nics": nic_data,
|
744 | 0fcd0cad | René Nussbaumer | "disks": [{constants.IDISK_SIZE: dsk.size,
|
745 | 0e514de1 | Bernardo Dal Seno | constants.IDISK_MODE: dsk.mode, |
746 | 0e514de1 | Bernardo Dal Seno | constants.IDISK_SPINDLES: dsk.spindles} |
747 | 0fcd0cad | René Nussbaumer | for dsk in iinfo.disks], |
748 | 0fcd0cad | René Nussbaumer | "disk_template": iinfo.disk_template,
|
749 | 1d4a4b26 | Thomas Thrainer | "disks_active": iinfo.disks_active,
|
750 | 0fcd0cad | René Nussbaumer | "hypervisor": iinfo.hypervisor,
|
751 | 0fcd0cad | René Nussbaumer | } |
752 | 0fcd0cad | René Nussbaumer | pir["disk_space_total"] = gmi.ComputeDiskSize(iinfo.disk_template,
|
753 | 0fcd0cad | René Nussbaumer | pir["disks"])
|
754 | 0fcd0cad | René Nussbaumer | instance_data[iinfo.name] = pir |
755 | 0fcd0cad | René Nussbaumer | |
756 | 0fcd0cad | René Nussbaumer | return instance_data
|
757 | 0fcd0cad | René Nussbaumer | |
758 | 0fcd0cad | René Nussbaumer | def _BuildInputData(self, req): |
759 | 0fcd0cad | René Nussbaumer | """Build input data structures.
|
760 | 0fcd0cad | René Nussbaumer |
|
761 | 0fcd0cad | René Nussbaumer | """
|
762 | 0fcd0cad | René Nussbaumer | request = req.GetRequest(self.cfg)
|
763 | e8936ef7 | Helga Velroyen | disk_template = None
|
764 | e8936ef7 | Helga Velroyen | if "disk_template" in request: |
765 | e8936ef7 | Helga Velroyen | disk_template = request["disk_template"]
|
766 | e8936ef7 | Helga Velroyen | self._ComputeClusterData(disk_template=disk_template)
|
767 | e8936ef7 | Helga Velroyen | |
768 | 0fcd0cad | René Nussbaumer | request["type"] = req.MODE
|
769 | 0fcd0cad | René Nussbaumer | self.in_data["request"] = request |
770 | 0fcd0cad | René Nussbaumer | |
771 | 0fcd0cad | René Nussbaumer | self.in_text = serializer.Dump(self.in_data) |
772 | 0fcd0cad | René Nussbaumer | |
773 | 0fcd0cad | René Nussbaumer | def Run(self, name, validate=True, call_fn=None): |
774 | 0fcd0cad | René Nussbaumer | """Run an instance allocator and return the results.
|
775 | 0fcd0cad | René Nussbaumer |
|
776 | 0fcd0cad | René Nussbaumer | """
|
777 | 0fcd0cad | René Nussbaumer | if call_fn is None: |
778 | 0fcd0cad | René Nussbaumer | call_fn = self.rpc.call_iallocator_runner
|
779 | 0fcd0cad | René Nussbaumer | |
780 | 0359e5d0 | Spyros Trigazis | ial_params = self.cfg.GetDefaultIAllocatorParameters()
|
781 | 0359e5d0 | Spyros Trigazis | |
782 | 0359e5d0 | Spyros Trigazis | result = call_fn(self.cfg.GetMasterNode(), name, self.in_text, ial_params) |
783 | 0fcd0cad | René Nussbaumer | result.Raise("Failure while running the iallocator script")
|
784 | 0fcd0cad | René Nussbaumer | |
785 | 0fcd0cad | René Nussbaumer | self.out_text = result.payload
|
786 | 0fcd0cad | René Nussbaumer | if validate:
|
787 | 0fcd0cad | René Nussbaumer | self._ValidateResult()
|
788 | 0fcd0cad | René Nussbaumer | |
789 | 0fcd0cad | René Nussbaumer | def _ValidateResult(self): |
790 | 0fcd0cad | René Nussbaumer | """Process the allocator results.
|
791 | 0fcd0cad | René Nussbaumer |
|
792 | 0fcd0cad | René Nussbaumer | This will process and if successful save the result in
|
793 | 0fcd0cad | René Nussbaumer | self.out_data and the other parameters.
|
794 | 0fcd0cad | René Nussbaumer |
|
795 | 0fcd0cad | René Nussbaumer | """
|
796 | 0fcd0cad | René Nussbaumer | try:
|
797 | 0fcd0cad | René Nussbaumer | rdict = serializer.Load(self.out_text)
|
798 | 0fcd0cad | René Nussbaumer | except Exception, err: |
799 | 0fcd0cad | René Nussbaumer | raise errors.OpExecError("Can't parse iallocator results: %s" % str(err)) |
800 | 0fcd0cad | René Nussbaumer | |
801 | 0fcd0cad | René Nussbaumer | if not isinstance(rdict, dict): |
802 | 0fcd0cad | René Nussbaumer | raise errors.OpExecError("Can't parse iallocator results: not a dict") |
803 | 0fcd0cad | René Nussbaumer | |
804 | 0fcd0cad | René Nussbaumer | # TODO: remove backwards compatiblity in later versions
|
805 | 0fcd0cad | René Nussbaumer | if "nodes" in rdict and "result" not in rdict: |
806 | 0fcd0cad | René Nussbaumer | rdict["result"] = rdict["nodes"] |
807 | 0fcd0cad | René Nussbaumer | del rdict["nodes"] |
808 | 0fcd0cad | René Nussbaumer | |
809 | 0fcd0cad | René Nussbaumer | for key in "success", "info", "result": |
810 | 0fcd0cad | René Nussbaumer | if key not in rdict: |
811 | 0fcd0cad | René Nussbaumer | raise errors.OpExecError("Can't parse iallocator results:" |
812 | 0fcd0cad | René Nussbaumer | " missing key '%s'" % key)
|
813 | 0fcd0cad | René Nussbaumer | setattr(self, key, rdict[key]) |
814 | 0fcd0cad | René Nussbaumer | |
815 | 0fcd0cad | René Nussbaumer | self.req.ValidateResult(self, self.result) |
816 | 0fcd0cad | René Nussbaumer | self.out_data = rdict |