Statistics
| Branch: | Tag: | Revision:

root / lib / masterd / iallocator.py @ b82d7182

History | View | Annotate | Download (25 kB)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

524 b82d7182 Helga Velroyen
    This is a helper function to extract data from the hypervisor's information
525 b82d7182 Helga Velroyen
    about the node, as part of the result of a node_info query.
526 b82d7182 Helga Velroyen

527 b82d7182 Helga Velroyen
    @type hv_info: dict of strings
528 b82d7182 Helga Velroyen
    @param hv_info: dictionary of node information from the hypervisor
529 0f70b3fb Helga Velroyen
    @type node_name: string
530 0f70b3fb Helga Velroyen
    @param node_name: name of the node
531 0f70b3fb Helga Velroyen
    @type attr: string
532 b82d7182 Helga Velroyen
    @param attr: key of the attribute in the hv_info dictionary
533 0f70b3fb Helga Velroyen
    @rtype: integer
534 0f70b3fb Helga Velroyen
    @return: the value of the attribute
535 0f70b3fb Helga Velroyen
    @raises errors.OpExecError: if key not in dictionary or value not
536 0f70b3fb Helga Velroyen
      integer
537 0f70b3fb Helga Velroyen

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

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

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

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

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

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

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

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

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

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

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

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