Statistics
| Branch: | Tag: | Revision:

root / lib / masterd / iallocator.py @ 0ac34c90

History | View | Annotate | Download (24.9 kB)

1 0fcd0cad René Nussbaumer
#
2 0fcd0cad René Nussbaumer
#
3 0fcd0cad René Nussbaumer
4 473d87a3 Iustin Pop
# Copyright (C) 2012, 2013 Google Inc.
5 0fcd0cad René Nussbaumer
#
6 0fcd0cad René Nussbaumer
# This program is free software; you can redistribute it and/or modify
7 0fcd0cad René Nussbaumer
# it under the terms of the GNU General Public License as published by
8 0fcd0cad René Nussbaumer
# the Free Software Foundation; either version 2 of the License, or
9 0fcd0cad René Nussbaumer
# (at your option) any later version.
10 0fcd0cad René Nussbaumer
#
11 0fcd0cad René Nussbaumer
# This program is distributed in the hope that it will be useful, but
12 0fcd0cad René Nussbaumer
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 0fcd0cad René Nussbaumer
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 0fcd0cad René Nussbaumer
# General Public License for more details.
15 0fcd0cad René Nussbaumer
#
16 0fcd0cad René Nussbaumer
# You should have received a copy of the GNU General Public License
17 0fcd0cad René Nussbaumer
# along with this program; if not, write to the Free Software
18 0fcd0cad René Nussbaumer
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 0fcd0cad René Nussbaumer
# 02110-1301, USA.
20 0fcd0cad René Nussbaumer
21 0fcd0cad René Nussbaumer
22 0fcd0cad René Nussbaumer
"""Module implementing the iallocator code."""
23 0fcd0cad René Nussbaumer
24 0fcd0cad René Nussbaumer
from ganeti import compat
25 0fcd0cad René Nussbaumer
from ganeti import constants
26 0fcd0cad René Nussbaumer
from ganeti import errors
27 0fcd0cad René Nussbaumer
from ganeti import ht
28 473d87a3 Iustin Pop
from ganeti import outils
29 0fcd0cad René Nussbaumer
from ganeti import opcodes
30 0fcd0cad René Nussbaumer
from ganeti import rpc
31 0fcd0cad René Nussbaumer
from ganeti import serializer
32 0fcd0cad René Nussbaumer
from ganeti import utils
33 0fcd0cad René Nussbaumer
34 0fcd0cad René Nussbaumer
import ganeti.masterd.instance as gmi
35 0fcd0cad René Nussbaumer
36 0fcd0cad René Nussbaumer
37 0fcd0cad René Nussbaumer
_STRING_LIST = ht.TListOf(ht.TString)
38 0fcd0cad René Nussbaumer
_JOB_LIST = ht.TListOf(ht.TListOf(ht.TStrictDict(True, False, {
39 0fcd0cad René Nussbaumer
   # pylint: disable=E1101
40 0fcd0cad René Nussbaumer
   # Class '...' has no 'OP_ID' member
41 0fcd0cad René Nussbaumer
   "OP_ID": ht.TElemOf([opcodes.OpInstanceFailover.OP_ID,
42 0fcd0cad René Nussbaumer
                        opcodes.OpInstanceMigrate.OP_ID,
43 3c286190 Dimitris Aragiorgis
                        opcodes.OpInstanceReplaceDisks.OP_ID]),
44 0fcd0cad René Nussbaumer
   })))
45 0fcd0cad René Nussbaumer
46 0fcd0cad René Nussbaumer
_NEVAC_MOVED = \
47 0fcd0cad René Nussbaumer
  ht.TListOf(ht.TAnd(ht.TIsLength(3),
48 0fcd0cad René Nussbaumer
                     ht.TItems([ht.TNonEmptyString,
49 0fcd0cad René Nussbaumer
                                ht.TNonEmptyString,
50 0fcd0cad René Nussbaumer
                                ht.TListOf(ht.TNonEmptyString),
51 0fcd0cad René Nussbaumer
                                ])))
52 0fcd0cad René Nussbaumer
_NEVAC_FAILED = \
53 0fcd0cad René Nussbaumer
  ht.TListOf(ht.TAnd(ht.TIsLength(2),
54 0fcd0cad René Nussbaumer
                     ht.TItems([ht.TNonEmptyString,
55 0fcd0cad René Nussbaumer
                                ht.TMaybeString,
56 0fcd0cad René Nussbaumer
                                ])))
57 0fcd0cad René Nussbaumer
_NEVAC_RESULT = ht.TAnd(ht.TIsLength(3),
58 0fcd0cad René Nussbaumer
                        ht.TItems([_NEVAC_MOVED, _NEVAC_FAILED, _JOB_LIST]))
59 0fcd0cad René Nussbaumer
60 3d7d3a12 René Nussbaumer
_INST_NAME = ("name", ht.TNonEmptyString)
61 da4a52a3 Thomas Thrainer
_INST_UUID = ("inst_uuid", ht.TNonEmptyString)
62 3d7d3a12 René Nussbaumer
63 0fcd0cad René Nussbaumer
64 473d87a3 Iustin Pop
class _AutoReqParam(outils.AutoSlots):
65 0fcd0cad René Nussbaumer
  """Meta class for request definitions.
66 0fcd0cad René Nussbaumer

67 0fcd0cad René Nussbaumer
  """
68 0fcd0cad René Nussbaumer
  @classmethod
69 0fcd0cad René Nussbaumer
  def _GetSlots(mcs, attrs):
70 0fcd0cad René Nussbaumer
    """Extract the slots out of REQ_PARAMS.
71 0fcd0cad René Nussbaumer

72 0fcd0cad René Nussbaumer
    """
73 0fcd0cad René Nussbaumer
    params = attrs.setdefault("REQ_PARAMS", [])
74 0fcd0cad René Nussbaumer
    return [slot for (slot, _) in params]
75 0fcd0cad René Nussbaumer
76 0fcd0cad René Nussbaumer
77 473d87a3 Iustin Pop
class IARequestBase(outils.ValidatedSlots):
78 0fcd0cad René Nussbaumer
  """A generic IAllocator request object.
79 0fcd0cad René Nussbaumer

80 0fcd0cad René Nussbaumer
  """
81 0fcd0cad René Nussbaumer
  __metaclass__ = _AutoReqParam
82 0fcd0cad René Nussbaumer
83 0fcd0cad René Nussbaumer
  MODE = NotImplemented
84 776b6291 René Nussbaumer
  REQ_PARAMS = []
85 0fcd0cad René Nussbaumer
  REQ_RESULT = NotImplemented
86 0fcd0cad René Nussbaumer
87 0fcd0cad René Nussbaumer
  def __init__(self, **kwargs):
88 0fcd0cad René Nussbaumer
    """Constructor for IARequestBase.
89 0fcd0cad René Nussbaumer

90 0fcd0cad René Nussbaumer
    The constructor takes only keyword arguments and will set
91 0fcd0cad René Nussbaumer
    attributes on this object based on the passed arguments. As such,
92 0fcd0cad René Nussbaumer
    it means that you should not pass arguments which are not in the
93 0fcd0cad René Nussbaumer
    REQ_PARAMS attribute for this class.
94 0fcd0cad René Nussbaumer

95 0fcd0cad René Nussbaumer
    """
96 473d87a3 Iustin Pop
    outils.ValidatedSlots.__init__(self, **kwargs)
97 0fcd0cad René Nussbaumer
98 0fcd0cad René Nussbaumer
    self.Validate()
99 0fcd0cad René Nussbaumer
100 0fcd0cad René Nussbaumer
  def Validate(self):
101 0fcd0cad René Nussbaumer
    """Validates all parameters of the request.
102 0fcd0cad René Nussbaumer

103 0fcd0cad René Nussbaumer
    """
104 0fcd0cad René Nussbaumer
    assert self.MODE in constants.VALID_IALLOCATOR_MODES
105 0fcd0cad René Nussbaumer
106 0fcd0cad René Nussbaumer
    for (param, validator) in self.REQ_PARAMS:
107 0fcd0cad René Nussbaumer
      if not hasattr(self, param):
108 0fcd0cad René Nussbaumer
        raise errors.OpPrereqError("Request is missing '%s' parameter" % param,
109 0fcd0cad René Nussbaumer
                                   errors.ECODE_INVAL)
110 0fcd0cad René Nussbaumer
111 0fcd0cad René Nussbaumer
      value = getattr(self, param)
112 0fcd0cad René Nussbaumer
      if not validator(value):
113 0fcd0cad René Nussbaumer
        raise errors.OpPrereqError(("Request parameter '%s' has invalid"
114 0fcd0cad René Nussbaumer
                                    " type %s/value %s") %
115 0fcd0cad René Nussbaumer
                                    (param, type(value), value),
116 0fcd0cad René Nussbaumer
                                    errors.ECODE_INVAL)
117 0fcd0cad René Nussbaumer
118 0fcd0cad René Nussbaumer
  def GetRequest(self, cfg):
119 0fcd0cad René Nussbaumer
    """Gets the request data dict.
120 0fcd0cad René Nussbaumer

121 0fcd0cad René Nussbaumer
    @param cfg: The configuration instance
122 0fcd0cad René Nussbaumer

123 0fcd0cad René Nussbaumer
    """
124 0fcd0cad René Nussbaumer
    raise NotImplementedError
125 0fcd0cad René Nussbaumer
126 0fcd0cad René Nussbaumer
  def ValidateResult(self, ia, result):
127 0fcd0cad René Nussbaumer
    """Validates the result of an request.
128 0fcd0cad René Nussbaumer

129 0fcd0cad René Nussbaumer
    @param ia: The IAllocator instance
130 0fcd0cad René Nussbaumer
    @param result: The IAllocator run result
131 776b6291 René Nussbaumer
    @raises ResultValidationError: If validation fails
132 0fcd0cad René Nussbaumer

133 0fcd0cad René Nussbaumer
    """
134 69b0d82a René Nussbaumer
    if ia.success and not self.REQ_RESULT(result):
135 776b6291 René Nussbaumer
      raise errors.ResultValidationError("iallocator returned invalid result,"
136 776b6291 René Nussbaumer
                                         " expected %s, got %s" %
137 776b6291 René Nussbaumer
                                         (self.REQ_RESULT, result))
138 0fcd0cad René Nussbaumer
139 0fcd0cad René Nussbaumer
140 0fcd0cad René Nussbaumer
class IAReqInstanceAlloc(IARequestBase):
141 0fcd0cad René Nussbaumer
  """An instance allocation request.
142 0fcd0cad René Nussbaumer

143 0fcd0cad René Nussbaumer
  """
144 c269efc3 René Nussbaumer
  # pylint: disable=E1101
145 0fcd0cad René Nussbaumer
  MODE = constants.IALLOCATOR_MODE_ALLOC
146 0fcd0cad René Nussbaumer
  REQ_PARAMS = [
147 3d7d3a12 René Nussbaumer
    _INST_NAME,
148 2c9fa1ff Iustin Pop
    ("memory", ht.TNonNegativeInt),
149 2c9fa1ff Iustin Pop
    ("spindle_use", ht.TNonNegativeInt),
150 0fcd0cad René Nussbaumer
    ("disks", ht.TListOf(ht.TDict)),
151 0fcd0cad René Nussbaumer
    ("disk_template", ht.TString),
152 0fcd0cad René Nussbaumer
    ("os", ht.TString),
153 0fcd0cad René Nussbaumer
    ("tags", _STRING_LIST),
154 0fcd0cad René Nussbaumer
    ("nics", ht.TListOf(ht.TDict)),
155 0fcd0cad René Nussbaumer
    ("vcpus", ht.TInt),
156 0fcd0cad René Nussbaumer
    ("hypervisor", ht.TString),
157 fb60bc6a Michael Hanselmann
    ("node_whitelist", ht.TMaybeListOf(ht.TNonEmptyString)),
158 0fcd0cad René Nussbaumer
    ]
159 0fcd0cad René Nussbaumer
  REQ_RESULT = ht.TList
160 0fcd0cad René Nussbaumer
161 776b6291 René Nussbaumer
  def RequiredNodes(self):
162 776b6291 René Nussbaumer
    """Calculates the required nodes based on the disk_template.
163 776b6291 René Nussbaumer

164 776b6291 René Nussbaumer
    """
165 776b6291 René Nussbaumer
    if self.disk_template in constants.DTS_INT_MIRROR:
166 776b6291 René Nussbaumer
      return 2
167 776b6291 René Nussbaumer
    else:
168 776b6291 René Nussbaumer
      return 1
169 776b6291 René Nussbaumer
170 0fcd0cad René Nussbaumer
  def GetRequest(self, cfg):
171 0fcd0cad René Nussbaumer
    """Requests a new instance.
172 0fcd0cad René Nussbaumer

173 0fcd0cad René Nussbaumer
    The checks for the completeness of the opcode must have already been
174 0fcd0cad René Nussbaumer
    done.
175 0fcd0cad René Nussbaumer

176 0fcd0cad René Nussbaumer
    """
177 0fcd0cad René Nussbaumer
    disk_space = gmi.ComputeDiskSize(self.disk_template, self.disks)
178 0fcd0cad René Nussbaumer
179 0fcd0cad René Nussbaumer
    return {
180 0fcd0cad René Nussbaumer
      "name": self.name,
181 0fcd0cad René Nussbaumer
      "disk_template": self.disk_template,
182 0fcd0cad René Nussbaumer
      "tags": self.tags,
183 0fcd0cad René Nussbaumer
      "os": self.os,
184 0fcd0cad René Nussbaumer
      "vcpus": self.vcpus,
185 0fcd0cad René Nussbaumer
      "memory": self.memory,
186 0fcd0cad René Nussbaumer
      "spindle_use": self.spindle_use,
187 0fcd0cad René Nussbaumer
      "disks": self.disks,
188 0fcd0cad René Nussbaumer
      "disk_space_total": disk_space,
189 0fcd0cad René Nussbaumer
      "nics": self.nics,
190 776b6291 René Nussbaumer
      "required_nodes": self.RequiredNodes(),
191 0fcd0cad René Nussbaumer
      "hypervisor": self.hypervisor,
192 0fcd0cad René Nussbaumer
      }
193 0fcd0cad René Nussbaumer
194 776b6291 René Nussbaumer
  def ValidateResult(self, ia, result):
195 776b6291 René Nussbaumer
    """Validates an single instance allocation request.
196 776b6291 René Nussbaumer

197 776b6291 René Nussbaumer
    """
198 776b6291 René Nussbaumer
    IARequestBase.ValidateResult(self, ia, result)
199 776b6291 René Nussbaumer
200 579f4ee5 René Nussbaumer
    if ia.success and len(result) != self.RequiredNodes():
201 776b6291 René Nussbaumer
      raise errors.ResultValidationError("iallocator returned invalid number"
202 776b6291 René Nussbaumer
                                         " of nodes (%s), required %s" %
203 776b6291 René Nussbaumer
                                         (len(result), self.RequiredNodes()))
204 776b6291 René Nussbaumer
205 0fcd0cad René Nussbaumer
206 b1e47e2d René Nussbaumer
class IAReqMultiInstanceAlloc(IARequestBase):
207 b1e47e2d René Nussbaumer
  """An multi instance allocation request.
208 b1e47e2d René Nussbaumer

209 b1e47e2d René Nussbaumer
  """
210 c269efc3 René Nussbaumer
  # pylint: disable=E1101
211 b1e47e2d René Nussbaumer
  MODE = constants.IALLOCATOR_MODE_MULTI_ALLOC
212 b1e47e2d René Nussbaumer
  REQ_PARAMS = [
213 3c286190 Dimitris Aragiorgis
    ("instances", ht.TListOf(ht.TInstanceOf(IAReqInstanceAlloc))),
214 b1e47e2d René Nussbaumer
    ]
215 b1e47e2d René Nussbaumer
  _MASUCCESS = \
216 b1e47e2d René Nussbaumer
    ht.TListOf(ht.TAnd(ht.TIsLength(2),
217 b1e47e2d René Nussbaumer
                       ht.TItems([ht.TNonEmptyString,
218 b1e47e2d René Nussbaumer
                                  ht.TListOf(ht.TNonEmptyString),
219 b1e47e2d René Nussbaumer
                                  ])))
220 b1e47e2d René Nussbaumer
  _MAFAILED = ht.TListOf(ht.TNonEmptyString)
221 32eae1ec René Nussbaumer
  REQ_RESULT = ht.TAnd(ht.TList, ht.TIsLength(2),
222 32eae1ec René Nussbaumer
                       ht.TItems([_MASUCCESS, _MAFAILED]))
223 b1e47e2d René Nussbaumer
224 b1e47e2d René Nussbaumer
  def GetRequest(self, cfg):
225 b1e47e2d René Nussbaumer
    return {
226 3c286190 Dimitris Aragiorgis
      "instances": [iareq.GetRequest(cfg) for iareq in self.instances],
227 b1e47e2d René Nussbaumer
      }
228 b1e47e2d René Nussbaumer
229 b1e47e2d René Nussbaumer
230 0fcd0cad René Nussbaumer
class IAReqRelocate(IARequestBase):
231 0fcd0cad René Nussbaumer
  """A relocation request.
232 0fcd0cad René Nussbaumer

233 0fcd0cad René Nussbaumer
  """
234 c269efc3 René Nussbaumer
  # pylint: disable=E1101
235 0fcd0cad René Nussbaumer
  MODE = constants.IALLOCATOR_MODE_RELOC
236 0fcd0cad René Nussbaumer
  REQ_PARAMS = [
237 da4a52a3 Thomas Thrainer
    _INST_UUID,
238 1c3231aa Thomas Thrainer
    ("relocate_from_node_uuids", _STRING_LIST),
239 0fcd0cad René Nussbaumer
    ]
240 0fcd0cad René Nussbaumer
  REQ_RESULT = ht.TList
241 0fcd0cad René Nussbaumer
242 0fcd0cad René Nussbaumer
  def GetRequest(self, cfg):
243 0fcd0cad René Nussbaumer
    """Request an relocation of an instance
244 0fcd0cad René Nussbaumer

245 0fcd0cad René Nussbaumer
    The checks for the completeness of the opcode must have already been
246 0fcd0cad René Nussbaumer
    done.
247 0fcd0cad René Nussbaumer

248 0fcd0cad René Nussbaumer
    """
249 da4a52a3 Thomas Thrainer
    instance = cfg.GetInstanceInfo(self.inst_uuid)
250 0fcd0cad René Nussbaumer
    if instance is None:
251 0fcd0cad René Nussbaumer
      raise errors.ProgrammerError("Unknown instance '%s' passed to"
252 da4a52a3 Thomas Thrainer
                                   " IAllocator" % self.inst_uuid)
253 0fcd0cad René Nussbaumer
254 0fcd0cad René Nussbaumer
    if instance.disk_template not in constants.DTS_MIRRORED:
255 0fcd0cad René Nussbaumer
      raise errors.OpPrereqError("Can't relocate non-mirrored instances",
256 0fcd0cad René Nussbaumer
                                 errors.ECODE_INVAL)
257 0fcd0cad René Nussbaumer
258 6953756f René Nussbaumer
    if (instance.disk_template in constants.DTS_INT_MIRROR and
259 6953756f René Nussbaumer
        len(instance.secondary_nodes) != 1):
260 0fcd0cad René Nussbaumer
      raise errors.OpPrereqError("Instance has not exactly one secondary node",
261 0fcd0cad René Nussbaumer
                                 errors.ECODE_STATE)
262 0fcd0cad René Nussbaumer
263 0fcd0cad René Nussbaumer
    disk_sizes = [{constants.IDISK_SIZE: disk.size} for disk in instance.disks]
264 0fcd0cad René Nussbaumer
    disk_space = gmi.ComputeDiskSize(instance.disk_template, disk_sizes)
265 0fcd0cad René Nussbaumer
266 0fcd0cad René Nussbaumer
    return {
267 da4a52a3 Thomas Thrainer
      "name": instance.name,
268 0fcd0cad René Nussbaumer
      "disk_space_total": disk_space,
269 776b6291 René Nussbaumer
      "required_nodes": 1,
270 1c3231aa Thomas Thrainer
      "relocate_from": cfg.GetNodeNames(self.relocate_from_node_uuids),
271 0fcd0cad René Nussbaumer
      }
272 0fcd0cad René Nussbaumer
273 0fcd0cad René Nussbaumer
  def ValidateResult(self, ia, result):
274 0fcd0cad René Nussbaumer
    """Validates the result of an relocation request.
275 0fcd0cad René Nussbaumer

276 0fcd0cad René Nussbaumer
    """
277 776b6291 René Nussbaumer
    IARequestBase.ValidateResult(self, ia, result)
278 776b6291 René Nussbaumer
279 0fcd0cad René Nussbaumer
    node2group = dict((name, ndata["group"])
280 0fcd0cad René Nussbaumer
                      for (name, ndata) in ia.in_data["nodes"].items())
281 0fcd0cad René Nussbaumer
282 0fcd0cad René Nussbaumer
    fn = compat.partial(self._NodesToGroups, node2group,
283 0fcd0cad René Nussbaumer
                        ia.in_data["nodegroups"])
284 0fcd0cad René Nussbaumer
285 da4a52a3 Thomas Thrainer
    instance = ia.cfg.GetInstanceInfo(self.inst_uuid)
286 1c3231aa Thomas Thrainer
    request_groups = fn(ia.cfg.GetNodeNames(self.relocate_from_node_uuids) +
287 1c3231aa Thomas Thrainer
                        ia.cfg.GetNodeNames([instance.primary_node]))
288 1c3231aa Thomas Thrainer
    result_groups = fn(result + ia.cfg.GetNodeNames([instance.primary_node]))
289 0fcd0cad René Nussbaumer
290 0fcd0cad René Nussbaumer
    if ia.success and not set(result_groups).issubset(request_groups):
291 776b6291 René Nussbaumer
      raise errors.ResultValidationError("Groups of nodes returned by"
292 1c3231aa Thomas Thrainer
                                         " iallocator (%s) differ from original"
293 776b6291 René Nussbaumer
                                         " groups (%s)" %
294 776b6291 René Nussbaumer
                                         (utils.CommaJoin(result_groups),
295 776b6291 René Nussbaumer
                                          utils.CommaJoin(request_groups)))
296 0fcd0cad René Nussbaumer
297 0fcd0cad René Nussbaumer
  @staticmethod
298 0fcd0cad René Nussbaumer
  def _NodesToGroups(node2group, groups, nodes):
299 0fcd0cad René Nussbaumer
    """Returns a list of unique group names for a list of nodes.
300 0fcd0cad René Nussbaumer

301 0fcd0cad René Nussbaumer
    @type node2group: dict
302 0fcd0cad René Nussbaumer
    @param node2group: Map from node name to group UUID
303 0fcd0cad René Nussbaumer
    @type groups: dict
304 0fcd0cad René Nussbaumer
    @param groups: Group information
305 0fcd0cad René Nussbaumer
    @type nodes: list
306 0fcd0cad René Nussbaumer
    @param nodes: Node names
307 0fcd0cad René Nussbaumer

308 0fcd0cad René Nussbaumer
    """
309 0fcd0cad René Nussbaumer
    result = set()
310 0fcd0cad René Nussbaumer
311 0fcd0cad René Nussbaumer
    for node in nodes:
312 0fcd0cad René Nussbaumer
      try:
313 0fcd0cad René Nussbaumer
        group_uuid = node2group[node]
314 0fcd0cad René Nussbaumer
      except KeyError:
315 0fcd0cad René Nussbaumer
        # Ignore unknown node
316 0fcd0cad René Nussbaumer
        pass
317 0fcd0cad René Nussbaumer
      else:
318 0fcd0cad René Nussbaumer
        try:
319 0fcd0cad René Nussbaumer
          group = groups[group_uuid]
320 0fcd0cad René Nussbaumer
        except KeyError:
321 0fcd0cad René Nussbaumer
          # Can't find group, let's use UUID
322 0fcd0cad René Nussbaumer
          group_name = group_uuid
323 0fcd0cad René Nussbaumer
        else:
324 0fcd0cad René Nussbaumer
          group_name = group["name"]
325 0fcd0cad René Nussbaumer
326 0fcd0cad René Nussbaumer
        result.add(group_name)
327 0fcd0cad René Nussbaumer
328 0fcd0cad René Nussbaumer
    return sorted(result)
329 0fcd0cad René Nussbaumer
330 0fcd0cad René Nussbaumer
331 0fcd0cad René Nussbaumer
class IAReqNodeEvac(IARequestBase):
332 0fcd0cad René Nussbaumer
  """A node evacuation request.
333 0fcd0cad René Nussbaumer

334 0fcd0cad René Nussbaumer
  """
335 c269efc3 René Nussbaumer
  # pylint: disable=E1101
336 0fcd0cad René Nussbaumer
  MODE = constants.IALLOCATOR_MODE_NODE_EVAC
337 0fcd0cad René Nussbaumer
  REQ_PARAMS = [
338 0fcd0cad René Nussbaumer
    ("instances", _STRING_LIST),
339 0fcd0cad René Nussbaumer
    ("evac_mode", ht.TElemOf(constants.IALLOCATOR_NEVAC_MODES)),
340 0fcd0cad René Nussbaumer
    ]
341 0fcd0cad René Nussbaumer
  REQ_RESULT = _NEVAC_RESULT
342 0fcd0cad René Nussbaumer
343 0fcd0cad René Nussbaumer
  def GetRequest(self, cfg):
344 0fcd0cad René Nussbaumer
    """Get data for node-evacuate requests.
345 0fcd0cad René Nussbaumer

346 0fcd0cad René Nussbaumer
    """
347 0fcd0cad René Nussbaumer
    return {
348 0fcd0cad René Nussbaumer
      "instances": self.instances,
349 0fcd0cad René Nussbaumer
      "evac_mode": self.evac_mode,
350 0fcd0cad René Nussbaumer
      }
351 0fcd0cad René Nussbaumer
352 0fcd0cad René Nussbaumer
353 0fcd0cad René Nussbaumer
class IAReqGroupChange(IARequestBase):
354 0fcd0cad René Nussbaumer
  """A group change request.
355 0fcd0cad René Nussbaumer

356 0fcd0cad René Nussbaumer
  """
357 c269efc3 René Nussbaumer
  # pylint: disable=E1101
358 0fcd0cad René Nussbaumer
  MODE = constants.IALLOCATOR_MODE_CHG_GROUP
359 0fcd0cad René Nussbaumer
  REQ_PARAMS = [
360 0fcd0cad René Nussbaumer
    ("instances", _STRING_LIST),
361 0fcd0cad René Nussbaumer
    ("target_groups", _STRING_LIST),
362 0fcd0cad René Nussbaumer
    ]
363 0fcd0cad René Nussbaumer
  REQ_RESULT = _NEVAC_RESULT
364 0fcd0cad René Nussbaumer
365 0fcd0cad René Nussbaumer
  def GetRequest(self, cfg):
366 0fcd0cad René Nussbaumer
    """Get data for node-evacuate requests.
367 0fcd0cad René Nussbaumer

368 0fcd0cad René Nussbaumer
    """
369 0fcd0cad René Nussbaumer
    return {
370 0fcd0cad René Nussbaumer
      "instances": self.instances,
371 0fcd0cad René Nussbaumer
      "target_groups": self.target_groups,
372 0fcd0cad René Nussbaumer
      }
373 0fcd0cad René Nussbaumer
374 0fcd0cad René Nussbaumer
375 0fcd0cad René Nussbaumer
class IAllocator(object):
376 0fcd0cad René Nussbaumer
  """IAllocator framework.
377 0fcd0cad René Nussbaumer

378 0fcd0cad René Nussbaumer
  An IAllocator instance has three sets of attributes:
379 0fcd0cad René Nussbaumer
    - cfg that is needed to query the cluster
380 0fcd0cad René Nussbaumer
    - input data (all members of the _KEYS class attribute are required)
381 0fcd0cad René Nussbaumer
    - four buffer attributes (in|out_data|text), that represent the
382 0fcd0cad René Nussbaumer
      input (to the external script) in text and data structure format,
383 0fcd0cad René Nussbaumer
      and the output from it, again in two formats
384 0fcd0cad René Nussbaumer
    - the result variables from the script (success, info, nodes) for
385 0fcd0cad René Nussbaumer
      easy usage
386 0fcd0cad René Nussbaumer

387 0fcd0cad René Nussbaumer
  """
388 0fcd0cad René Nussbaumer
  # pylint: disable=R0902
389 0fcd0cad René Nussbaumer
  # lots of instance attributes
390 0fcd0cad René Nussbaumer
391 0fcd0cad René Nussbaumer
  def __init__(self, cfg, rpc_runner, req):
392 0fcd0cad René Nussbaumer
    self.cfg = cfg
393 0fcd0cad René Nussbaumer
    self.rpc = rpc_runner
394 0fcd0cad René Nussbaumer
    self.req = req
395 0fcd0cad René Nussbaumer
    # init buffer variables
396 0fcd0cad René Nussbaumer
    self.in_text = self.out_text = self.in_data = self.out_data = None
397 0fcd0cad René Nussbaumer
    # init result fields
398 0fcd0cad René Nussbaumer
    self.success = self.info = self.result = None
399 0fcd0cad René Nussbaumer
400 0fcd0cad René Nussbaumer
    self._BuildInputData(req)
401 0fcd0cad René Nussbaumer
402 c9c4b92d Helga Velroyen
  def _ComputerClusterDataNodeInfo(self, node_list, cluster_info,
403 c9c4b92d Helga Velroyen
                                   hypervisor_name):
404 c9c4b92d Helga Velroyen
    """Prepare and execute node info call.
405 c9c4b92d Helga Velroyen

406 c9c4b92d Helga Velroyen
    @type node_list: list of strings
407 c9c4b92d Helga Velroyen
    @param node_list: list of nodes' UUIDs
408 c9c4b92d Helga Velroyen
    @type cluster_info: L{objects.Cluster}
409 c9c4b92d Helga Velroyen
    @param cluster_info: the cluster's information from the config
410 c9c4b92d Helga Velroyen
    @type hypervisor_name: string
411 c9c4b92d Helga Velroyen
    @param hypervisor_name: the hypervisor name
412 c9c4b92d Helga Velroyen
    @rtype: same as the result of the node info RPC call
413 c9c4b92d Helga Velroyen
    @return: the result of the node info RPC call
414 c9c4b92d Helga Velroyen

415 c9c4b92d Helga Velroyen
    """
416 c9c4b92d Helga Velroyen
    es_flags = rpc.GetExclusiveStorageForNodes(self.cfg, node_list)
417 c9c4b92d Helga Velroyen
    storage_units = utils.storage.GetStorageUnitsOfCluster(
418 c9c4b92d Helga Velroyen
        self.cfg, include_spindles=True)
419 c9c4b92d Helga Velroyen
    hvspecs = [(hypervisor_name, cluster_info.hvparams[hypervisor_name])]
420 c9c4b92d Helga Velroyen
    return self.rpc.call_node_info(node_list, storage_units, hvspecs, es_flags)
421 c9c4b92d Helga Velroyen
422 0fcd0cad René Nussbaumer
  def _ComputeClusterData(self):
423 0fcd0cad René Nussbaumer
    """Compute the generic allocator input data.
424 0fcd0cad René Nussbaumer

425 0fcd0cad René Nussbaumer
    This is the data that is independent of the actual operation.
426 0fcd0cad René Nussbaumer

427 0fcd0cad René Nussbaumer
    """
428 d0d7d7cf Thomas Thrainer
    cluster_info = self.cfg.GetClusterInfo()
429 0fcd0cad René Nussbaumer
    # cluster data
430 0fcd0cad René Nussbaumer
    data = {
431 0fcd0cad René Nussbaumer
      "version": constants.IALLOCATOR_VERSION,
432 d0d7d7cf Thomas Thrainer
      "cluster_name": self.cfg.GetClusterName(),
433 0fcd0cad René Nussbaumer
      "cluster_tags": list(cluster_info.GetTags()),
434 0fcd0cad René Nussbaumer
      "enabled_hypervisors": list(cluster_info.enabled_hypervisors),
435 0fcd0cad René Nussbaumer
      "ipolicy": cluster_info.ipolicy,
436 0fcd0cad René Nussbaumer
      }
437 d0d7d7cf Thomas Thrainer
    ninfo = self.cfg.GetAllNodesInfo()
438 d0d7d7cf Thomas Thrainer
    iinfo = self.cfg.GetAllInstancesInfo().values()
439 0fcd0cad René Nussbaumer
    i_list = [(inst, cluster_info.FillBE(inst)) for inst in iinfo]
440 0fcd0cad René Nussbaumer
441 0fcd0cad René Nussbaumer
    # node data
442 1c3231aa Thomas Thrainer
    node_list = [n.uuid for n in ninfo.values() if n.vm_capable]
443 0fcd0cad René Nussbaumer
444 0fcd0cad René Nussbaumer
    if isinstance(self.req, IAReqInstanceAlloc):
445 0fcd0cad René Nussbaumer
      hypervisor_name = self.req.hypervisor
446 fb60bc6a Michael Hanselmann
      node_whitelist = self.req.node_whitelist
447 0fcd0cad René Nussbaumer
    elif isinstance(self.req, IAReqRelocate):
448 da4a52a3 Thomas Thrainer
      hypervisor_name = self.cfg.GetInstanceInfo(self.req.inst_uuid).hypervisor
449 fb60bc6a Michael Hanselmann
      node_whitelist = None
450 0fcd0cad René Nussbaumer
    else:
451 0fcd0cad René Nussbaumer
      hypervisor_name = cluster_info.primary_hypervisor
452 fb60bc6a Michael Hanselmann
      node_whitelist = None
453 0fcd0cad René Nussbaumer
454 32389d91 Helga Velroyen
    has_lvm = utils.storage.IsLvmEnabled(cluster_info.enabled_disk_templates)
455 c9c4b92d Helga Velroyen
    node_data = self._ComputerClusterDataNodeInfo(node_list, cluster_info,
456 c9c4b92d Helga Velroyen
                                                  hypervisor_name)
457 c9c4b92d Helga Velroyen
458 0fcd0cad René Nussbaumer
    node_iinfo = \
459 0fcd0cad René Nussbaumer
      self.rpc.call_all_instances_info(node_list,
460 0200a1af Helga Velroyen
                                       cluster_info.enabled_hypervisors,
461 0200a1af Helga Velroyen
                                       cluster_info.hvparams)
462 0fcd0cad René Nussbaumer
463 d0d7d7cf Thomas Thrainer
    data["nodegroups"] = self._ComputeNodeGroupData(self.cfg)
464 0fcd0cad René Nussbaumer
465 d0d7d7cf Thomas Thrainer
    config_ndata = self._ComputeBasicNodeData(self.cfg, ninfo, node_whitelist)
466 0fcd0cad René Nussbaumer
    data["nodes"] = self._ComputeDynamicNodeData(ninfo, node_data, node_iinfo,
467 36a566e8 Iustin Pop
                                                 i_list, config_ndata, has_lvm)
468 0fcd0cad René Nussbaumer
    assert len(data["nodes"]) == len(ninfo), \
469 0fcd0cad René Nussbaumer
        "Incomplete node data computed"
470 0fcd0cad René Nussbaumer
471 d0d7d7cf Thomas Thrainer
    data["instances"] = self._ComputeInstanceData(self.cfg, cluster_info,
472 d0d7d7cf Thomas Thrainer
                                                  i_list)
473 0fcd0cad René Nussbaumer
474 0fcd0cad René Nussbaumer
    self.in_data = data
475 0fcd0cad René Nussbaumer
476 0fcd0cad René Nussbaumer
  @staticmethod
477 0fcd0cad René Nussbaumer
  def _ComputeNodeGroupData(cfg):
478 0fcd0cad René Nussbaumer
    """Compute node groups data.
479 0fcd0cad René Nussbaumer

480 0fcd0cad René Nussbaumer
    """
481 0fcd0cad René Nussbaumer
    cluster = cfg.GetClusterInfo()
482 0fcd0cad René Nussbaumer
    ng = dict((guuid, {
483 0fcd0cad René Nussbaumer
      "name": gdata.name,
484 0fcd0cad René Nussbaumer
      "alloc_policy": gdata.alloc_policy,
485 98ae702b Thomas Thrainer
      "networks": [net_uuid for net_uuid, _ in gdata.networks.items()],
486 0fcd0cad René Nussbaumer
      "ipolicy": gmi.CalculateGroupIPolicy(cluster, gdata),
487 f1222089 Dimitris Aragiorgis
      "tags": list(gdata.GetTags()),
488 0fcd0cad René Nussbaumer
      })
489 0fcd0cad René Nussbaumer
      for guuid, gdata in cfg.GetAllNodeGroupsInfo().items())
490 0fcd0cad René Nussbaumer
491 0fcd0cad René Nussbaumer
    return ng
492 0fcd0cad René Nussbaumer
493 0fcd0cad René Nussbaumer
  @staticmethod
494 fb60bc6a Michael Hanselmann
  def _ComputeBasicNodeData(cfg, node_cfg, node_whitelist):
495 0fcd0cad René Nussbaumer
    """Compute global node data.
496 0fcd0cad René Nussbaumer

497 0fcd0cad René Nussbaumer
    @rtype: dict
498 0fcd0cad René Nussbaumer
    @returns: a dict of name: (node dict, node config)
499 0fcd0cad René Nussbaumer

500 0fcd0cad René Nussbaumer
    """
501 0fcd0cad René Nussbaumer
    # fill in static (config-based) values
502 0fcd0cad René Nussbaumer
    node_results = dict((ninfo.name, {
503 0fcd0cad René Nussbaumer
      "tags": list(ninfo.GetTags()),
504 0fcd0cad René Nussbaumer
      "primary_ip": ninfo.primary_ip,
505 0fcd0cad René Nussbaumer
      "secondary_ip": ninfo.secondary_ip,
506 fb60bc6a Michael Hanselmann
      "offline": (ninfo.offline or
507 fb60bc6a Michael Hanselmann
                  not (node_whitelist is None or
508 fb60bc6a Michael Hanselmann
                       ninfo.name in node_whitelist)),
509 0fcd0cad René Nussbaumer
      "drained": ninfo.drained,
510 0fcd0cad René Nussbaumer
      "master_candidate": ninfo.master_candidate,
511 0fcd0cad René Nussbaumer
      "group": ninfo.group,
512 0fcd0cad René Nussbaumer
      "master_capable": ninfo.master_capable,
513 0fcd0cad René Nussbaumer
      "vm_capable": ninfo.vm_capable,
514 0fcd0cad René Nussbaumer
      "ndparams": cfg.GetNdParams(ninfo),
515 0fcd0cad René Nussbaumer
      })
516 0fcd0cad René Nussbaumer
      for ninfo in node_cfg.values())
517 0fcd0cad René Nussbaumer
518 0fcd0cad René Nussbaumer
    return node_results
519 0fcd0cad René Nussbaumer
520 0fcd0cad René Nussbaumer
  @staticmethod
521 0f70b3fb Helga Velroyen
  def _GetAttributeFromNodeData(node_data, node_name, attr):
522 0f70b3fb Helga Velroyen
    """Helper function to extract an attribute from the node data dictionary.
523 0f70b3fb Helga Velroyen

524 0f70b3fb Helga Velroyen
    @type node_data: dict of strings
525 0f70b3fb Helga Velroyen
    @param node_data: result of C{rpc.MakeLegacyNodeInfo}
526 0f70b3fb Helga Velroyen
    @type node_name: string
527 0f70b3fb Helga Velroyen
    @param node_name: name of the node
528 0f70b3fb Helga Velroyen
    @type attr: string
529 0f70b3fb Helga Velroyen
    @param attr: key of the attribute in the node_data dictionary
530 0f70b3fb Helga Velroyen
    @rtype: integer
531 0f70b3fb Helga Velroyen
    @return: the value of the attribute
532 0f70b3fb Helga Velroyen
    @raises errors.OpExecError: if key not in dictionary or value not
533 0f70b3fb Helga Velroyen
      integer
534 0f70b3fb Helga Velroyen

535 0f70b3fb Helga Velroyen
    """
536 0f70b3fb Helga Velroyen
    if attr not in node_data:
537 0f70b3fb Helga Velroyen
      raise errors.OpExecError("Node '%s' didn't return attribute"
538 0f70b3fb Helga Velroyen
                               " '%s'" % (node_name, attr))
539 0f70b3fb Helga Velroyen
    value = node_data[attr]
540 0f70b3fb Helga Velroyen
    if not isinstance(value, int):
541 0f70b3fb Helga Velroyen
      raise errors.OpExecError("Node '%s' returned invalid value"
542 0f70b3fb Helga Velroyen
                               " for '%s': %s" %
543 0f70b3fb Helga Velroyen
                               (node_name, attr, value))
544 0f70b3fb Helga Velroyen
    return value
545 0f70b3fb Helga Velroyen
546 20529708 Helga Velroyen
  @staticmethod
547 11aa3ca5 Helga Velroyen
  def _ComputeStorageDataFromNodeInfo(node_info, node_name, has_lvm):
548 11aa3ca5 Helga Velroyen
    """Extract storage data from node info (_not_ legacy node info).
549 20529708 Helga Velroyen

550 11aa3ca5 Helga Velroyen
    @type node_info: see result of the RPC call node info
551 11aa3ca5 Helga Velroyen
    @param node_info: the result of the RPC call node info
552 20529708 Helga Velroyen
    @type node_name: string
553 20529708 Helga Velroyen
    @param node_name: the node's name
554 20529708 Helga Velroyen
    @type has_lvm: boolean
555 11aa3ca5 Helga Velroyen
    @param has_lvm: whether or not LVM storage information is requested
556 20529708 Helga Velroyen
    @rtype: 4-tuple of integers
557 20529708 Helga Velroyen
    @return: tuple of storage info (total_disk, free_disk, total_spindles,
558 20529708 Helga Velroyen
       free_spindles)
559 20529708 Helga Velroyen

560 20529708 Helga Velroyen
    """
561 11aa3ca5 Helga Velroyen
    (_, space_info, _) = node_info
562 20529708 Helga Velroyen
    # TODO: replace this with proper storage reporting
563 20529708 Helga Velroyen
    if has_lvm:
564 11aa3ca5 Helga Velroyen
      lvm_vg_info = utils.storage.LookupSpaceInfoByStorageType(
565 11aa3ca5 Helga Velroyen
         space_info, constants.ST_LVM_VG)
566 11aa3ca5 Helga Velroyen
      if not lvm_vg_info:
567 11aa3ca5 Helga Velroyen
        raise errors.OpExecError("Node '%s' didn't return LVM vg space info."
568 11aa3ca5 Helga Velroyen
                                 % (node_name))
569 11aa3ca5 Helga Velroyen
      total_disk = lvm_vg_info["storage_size"]
570 11aa3ca5 Helga Velroyen
      free_disk = lvm_vg_info["storage_free"]
571 11aa3ca5 Helga Velroyen
      lvm_pv_info = utils.storage.LookupSpaceInfoByStorageType(
572 11aa3ca5 Helga Velroyen
         space_info, constants.ST_LVM_PV)
573 11aa3ca5 Helga Velroyen
      if not lvm_vg_info:
574 11aa3ca5 Helga Velroyen
        raise errors.OpExecError("Node '%s' didn't return LVM pv space info."
575 11aa3ca5 Helga Velroyen
                                 % (node_name))
576 11aa3ca5 Helga Velroyen
      total_spindles = lvm_pv_info["storage_size"]
577 11aa3ca5 Helga Velroyen
      free_spindles = lvm_pv_info["storage_free"]
578 20529708 Helga Velroyen
    else:
579 20529708 Helga Velroyen
      # we didn't even ask the node for VG status, so use zeros
580 20529708 Helga Velroyen
      total_disk = free_disk = 0
581 20529708 Helga Velroyen
      total_spindles = free_spindles = 0
582 20529708 Helga Velroyen
    return (total_disk, free_disk, total_spindles, free_spindles)
583 20529708 Helga Velroyen
584 0ac34c90 Helga Velroyen
  @staticmethod
585 0ac34c90 Helga Velroyen
  def _ComputeInstanceMemory(instance_list, node_instances_info, node_uuid,
586 0ac34c90 Helga Velroyen
                             input_mem_free):
587 0ac34c90 Helga Velroyen
    """Compute memory used by primary instances.
588 0ac34c90 Helga Velroyen

589 0ac34c90 Helga Velroyen
    @rtype: tuple (int, int, int)
590 0ac34c90 Helga Velroyen
    @returns: A tuple of three integers: 1. the sum of memory used by primary
591 0ac34c90 Helga Velroyen
      instances on the node (including the ones that are currently down), 2.
592 0ac34c90 Helga Velroyen
      the sum of memory used by primary instances of the node that are up, 3.
593 0ac34c90 Helga Velroyen
      the amount of memory that is free on the node considering the current
594 0ac34c90 Helga Velroyen
      usage of the instances.
595 0ac34c90 Helga Velroyen

596 0ac34c90 Helga Velroyen
    """
597 0ac34c90 Helga Velroyen
    i_p_mem = i_p_up_mem = 0
598 0ac34c90 Helga Velroyen
    mem_free = input_mem_free
599 0ac34c90 Helga Velroyen
    for iinfo, beinfo in instance_list:
600 0ac34c90 Helga Velroyen
      if iinfo.primary_node == node_uuid:
601 0ac34c90 Helga Velroyen
        i_p_mem += beinfo[constants.BE_MAXMEM]
602 0ac34c90 Helga Velroyen
        if iinfo.name not in node_instances_info[node_uuid].payload:
603 0ac34c90 Helga Velroyen
          i_used_mem = 0
604 0ac34c90 Helga Velroyen
        else:
605 0ac34c90 Helga Velroyen
          i_used_mem = int(node_instances_info[node_uuid]
606 0ac34c90 Helga Velroyen
                           .payload[iinfo.name]["memory"])
607 0ac34c90 Helga Velroyen
        i_mem_diff = beinfo[constants.BE_MAXMEM] - i_used_mem
608 0ac34c90 Helga Velroyen
        mem_free -= max(0, i_mem_diff)
609 0ac34c90 Helga Velroyen
610 0ac34c90 Helga Velroyen
        if iinfo.admin_state == constants.ADMINST_UP:
611 0ac34c90 Helga Velroyen
          i_p_up_mem += beinfo[constants.BE_MAXMEM]
612 0ac34c90 Helga Velroyen
    return (i_p_mem, i_p_up_mem, mem_free)
613 0ac34c90 Helga Velroyen
614 0f70b3fb Helga Velroyen
  def _ComputeDynamicNodeData(self, node_cfg, node_data, node_iinfo, i_list,
615 36a566e8 Iustin Pop
                              node_results, has_lvm):
616 0fcd0cad René Nussbaumer
    """Compute global node data.
617 0fcd0cad René Nussbaumer

618 0fcd0cad René Nussbaumer
    @param node_results: the basic node structures as filled from the config
619 0fcd0cad René Nussbaumer

620 0fcd0cad René Nussbaumer
    """
621 0fcd0cad René Nussbaumer
    #TODO(dynmem): compute the right data on MAX and MIN memory
622 0fcd0cad René Nussbaumer
    # make a copy of the current dict
623 0fcd0cad René Nussbaumer
    node_results = dict(node_results)
624 1c3231aa Thomas Thrainer
    for nuuid, nresult in node_data.items():
625 1c3231aa Thomas Thrainer
      ninfo = node_cfg[nuuid]
626 1c3231aa Thomas Thrainer
      assert ninfo.name in node_results, "Missing basic data for node %s" % \
627 1c3231aa Thomas Thrainer
                                         ninfo.name
628 0fcd0cad René Nussbaumer
629 0fcd0cad René Nussbaumer
      if not (ninfo.offline or ninfo.drained):
630 1c3231aa Thomas Thrainer
        nresult.Raise("Can't get data for node %s" % ninfo.name)
631 1c3231aa Thomas Thrainer
        node_iinfo[nuuid].Raise("Can't get node instance info from node %s" %
632 1c3231aa Thomas Thrainer
                                ninfo.name)
633 36a566e8 Iustin Pop
        remote_info = rpc.MakeLegacyNodeInfo(nresult.payload,
634 36a566e8 Iustin Pop
                                             require_vg_info=has_lvm)
635 0fcd0cad René Nussbaumer
636 0f70b3fb Helga Velroyen
        mem_free = self._GetAttributeFromNodeData(remote_info, ninfo.name,
637 0f70b3fb Helga Velroyen
                                                  "memory_free")
638 36a566e8 Iustin Pop
639 0ac34c90 Helga Velroyen
        (i_p_mem, i_p_up_mem, mem_free) = self._ComputeInstanceMemory(
640 0ac34c90 Helga Velroyen
             i_list, node_iinfo, nuuid, mem_free)
641 20529708 Helga Velroyen
        (total_disk, free_disk, total_spindles, free_spindles) = \
642 11aa3ca5 Helga Velroyen
            self._ComputeStorageDataFromNodeInfo(nresult.payload, ninfo.name,
643 11aa3ca5 Helga Velroyen
                                                 has_lvm)
644 36a566e8 Iustin Pop
645 0fcd0cad René Nussbaumer
        # compute memory used by instances
646 0fcd0cad René Nussbaumer
        pnr_dyn = {
647 0f70b3fb Helga Velroyen
          "total_memory": self._GetAttributeFromNodeData(
648 0f70b3fb Helga Velroyen
              remote_info, ninfo.name, "memory_total"),
649 0f70b3fb Helga Velroyen
          "reserved_memory": self._GetAttributeFromNodeData(
650 0f70b3fb Helga Velroyen
              remote_info, ninfo.name, "memory_dom0"),
651 36a566e8 Iustin Pop
          "free_memory": mem_free,
652 36a566e8 Iustin Pop
          "total_disk": total_disk,
653 36a566e8 Iustin Pop
          "free_disk": free_disk,
654 06fb92cf Bernardo Dal Seno
          "total_spindles": total_spindles,
655 06fb92cf Bernardo Dal Seno
          "free_spindles": free_spindles,
656 0f70b3fb Helga Velroyen
          "total_cpus": self._GetAttributeFromNodeData(
657 0f70b3fb Helga Velroyen
              remote_info, ninfo.name, "cpu_total"),
658 0fcd0cad René Nussbaumer
          "i_pri_memory": i_p_mem,
659 0fcd0cad René Nussbaumer
          "i_pri_up_memory": i_p_up_mem,
660 0fcd0cad René Nussbaumer
          }
661 1c3231aa Thomas Thrainer
        pnr_dyn.update(node_results[ninfo.name])
662 1c3231aa Thomas Thrainer
        node_results[ninfo.name] = pnr_dyn
663 0fcd0cad René Nussbaumer
664 0fcd0cad René Nussbaumer
    return node_results
665 0fcd0cad René Nussbaumer
666 0fcd0cad René Nussbaumer
  @staticmethod
667 1c3231aa Thomas Thrainer
  def _ComputeInstanceData(cfg, cluster_info, i_list):
668 0fcd0cad René Nussbaumer
    """Compute global instance data.
669 0fcd0cad René Nussbaumer

670 0fcd0cad René Nussbaumer
    """
671 0fcd0cad René Nussbaumer
    instance_data = {}
672 0fcd0cad René Nussbaumer
    for iinfo, beinfo in i_list:
673 0fcd0cad René Nussbaumer
      nic_data = []
674 0fcd0cad René Nussbaumer
      for nic in iinfo.nics:
675 0fcd0cad René Nussbaumer
        filled_params = cluster_info.SimpleFillNIC(nic.nicparams)
676 0fcd0cad René Nussbaumer
        nic_dict = {
677 0fcd0cad René Nussbaumer
          "mac": nic.mac,
678 0fcd0cad René Nussbaumer
          "ip": nic.ip,
679 0fcd0cad René Nussbaumer
          "mode": filled_params[constants.NIC_MODE],
680 0fcd0cad René Nussbaumer
          "link": filled_params[constants.NIC_LINK],
681 0fcd0cad René Nussbaumer
          }
682 0fcd0cad René Nussbaumer
        if filled_params[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
683 0fcd0cad René Nussbaumer
          nic_dict["bridge"] = filled_params[constants.NIC_LINK]
684 0fcd0cad René Nussbaumer
        nic_data.append(nic_dict)
685 0fcd0cad René Nussbaumer
      pir = {
686 0fcd0cad René Nussbaumer
        "tags": list(iinfo.GetTags()),
687 0fcd0cad René Nussbaumer
        "admin_state": iinfo.admin_state,
688 0fcd0cad René Nussbaumer
        "vcpus": beinfo[constants.BE_VCPUS],
689 0fcd0cad René Nussbaumer
        "memory": beinfo[constants.BE_MAXMEM],
690 0fcd0cad René Nussbaumer
        "spindle_use": beinfo[constants.BE_SPINDLE_USE],
691 0fcd0cad René Nussbaumer
        "os": iinfo.os,
692 1c3231aa Thomas Thrainer
        "nodes": [cfg.GetNodeName(iinfo.primary_node)] +
693 1c3231aa Thomas Thrainer
                 cfg.GetNodeNames(iinfo.secondary_nodes),
694 0fcd0cad René Nussbaumer
        "nics": nic_data,
695 0fcd0cad René Nussbaumer
        "disks": [{constants.IDISK_SIZE: dsk.size,
696 0e514de1 Bernardo Dal Seno
                   constants.IDISK_MODE: dsk.mode,
697 0e514de1 Bernardo Dal Seno
                   constants.IDISK_SPINDLES: dsk.spindles}
698 0fcd0cad René Nussbaumer
                  for dsk in iinfo.disks],
699 0fcd0cad René Nussbaumer
        "disk_template": iinfo.disk_template,
700 1d4a4b26 Thomas Thrainer
        "disks_active": iinfo.disks_active,
701 0fcd0cad René Nussbaumer
        "hypervisor": iinfo.hypervisor,
702 0fcd0cad René Nussbaumer
        }
703 0fcd0cad René Nussbaumer
      pir["disk_space_total"] = gmi.ComputeDiskSize(iinfo.disk_template,
704 0fcd0cad René Nussbaumer
                                                    pir["disks"])
705 0fcd0cad René Nussbaumer
      instance_data[iinfo.name] = pir
706 0fcd0cad René Nussbaumer
707 0fcd0cad René Nussbaumer
    return instance_data
708 0fcd0cad René Nussbaumer
709 0fcd0cad René Nussbaumer
  def _BuildInputData(self, req):
710 0fcd0cad René Nussbaumer
    """Build input data structures.
711 0fcd0cad René Nussbaumer

712 0fcd0cad René Nussbaumer
    """
713 0fcd0cad René Nussbaumer
    self._ComputeClusterData()
714 0fcd0cad René Nussbaumer
715 0fcd0cad René Nussbaumer
    request = req.GetRequest(self.cfg)
716 0fcd0cad René Nussbaumer
    request["type"] = req.MODE
717 0fcd0cad René Nussbaumer
    self.in_data["request"] = request
718 0fcd0cad René Nussbaumer
719 0fcd0cad René Nussbaumer
    self.in_text = serializer.Dump(self.in_data)
720 0fcd0cad René Nussbaumer
721 0fcd0cad René Nussbaumer
  def Run(self, name, validate=True, call_fn=None):
722 0fcd0cad René Nussbaumer
    """Run an instance allocator and return the results.
723 0fcd0cad René Nussbaumer

724 0fcd0cad René Nussbaumer
    """
725 0fcd0cad René Nussbaumer
    if call_fn is None:
726 0fcd0cad René Nussbaumer
      call_fn = self.rpc.call_iallocator_runner
727 0fcd0cad René Nussbaumer
728 0fcd0cad René Nussbaumer
    result = call_fn(self.cfg.GetMasterNode(), name, self.in_text)
729 0fcd0cad René Nussbaumer
    result.Raise("Failure while running the iallocator script")
730 0fcd0cad René Nussbaumer
731 0fcd0cad René Nussbaumer
    self.out_text = result.payload
732 0fcd0cad René Nussbaumer
    if validate:
733 0fcd0cad René Nussbaumer
      self._ValidateResult()
734 0fcd0cad René Nussbaumer
735 0fcd0cad René Nussbaumer
  def _ValidateResult(self):
736 0fcd0cad René Nussbaumer
    """Process the allocator results.
737 0fcd0cad René Nussbaumer

738 0fcd0cad René Nussbaumer
    This will process and if successful save the result in
739 0fcd0cad René Nussbaumer
    self.out_data and the other parameters.
740 0fcd0cad René Nussbaumer

741 0fcd0cad René Nussbaumer
    """
742 0fcd0cad René Nussbaumer
    try:
743 0fcd0cad René Nussbaumer
      rdict = serializer.Load(self.out_text)
744 0fcd0cad René Nussbaumer
    except Exception, err:
745 0fcd0cad René Nussbaumer
      raise errors.OpExecError("Can't parse iallocator results: %s" % str(err))
746 0fcd0cad René Nussbaumer
747 0fcd0cad René Nussbaumer
    if not isinstance(rdict, dict):
748 0fcd0cad René Nussbaumer
      raise errors.OpExecError("Can't parse iallocator results: not a dict")
749 0fcd0cad René Nussbaumer
750 0fcd0cad René Nussbaumer
    # TODO: remove backwards compatiblity in later versions
751 0fcd0cad René Nussbaumer
    if "nodes" in rdict and "result" not in rdict:
752 0fcd0cad René Nussbaumer
      rdict["result"] = rdict["nodes"]
753 0fcd0cad René Nussbaumer
      del rdict["nodes"]
754 0fcd0cad René Nussbaumer
755 0fcd0cad René Nussbaumer
    for key in "success", "info", "result":
756 0fcd0cad René Nussbaumer
      if key not in rdict:
757 0fcd0cad René Nussbaumer
        raise errors.OpExecError("Can't parse iallocator results:"
758 0fcd0cad René Nussbaumer
                                 " missing key '%s'" % key)
759 0fcd0cad René Nussbaumer
      setattr(self, key, rdict[key])
760 0fcd0cad René Nussbaumer
761 0fcd0cad René Nussbaumer
    self.req.ValidateResult(self, self.result)
762 0fcd0cad René Nussbaumer
    self.out_data = rdict