Statistics
| Branch: | Tag: | Revision:

root / lib / masterd / iallocator.py @ 653bc0f1

History | View | Annotate | Download (27.1 kB)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

417 c9c4b92d Helga Velroyen
    """
418 6c00b2c7 Helga Velroyen
    storage_units_raw = utils.storage.GetStorageUnits(self.cfg, disk_templates)
419 da803ff1 Helga Velroyen
    storage_units = rpc.PrepareStorageUnitsForNodes(self.cfg, storage_units_raw,
420 da803ff1 Helga Velroyen
                                                    node_list)
421 c9c4b92d Helga Velroyen
    hvspecs = [(hypervisor_name, cluster_info.hvparams[hypervisor_name])]
422 da803ff1 Helga Velroyen
    return self.rpc.call_node_info(node_list, storage_units, hvspecs)
423 c9c4b92d Helga Velroyen
424 e8936ef7 Helga Velroyen
  def _ComputeClusterData(self, disk_template=None):
425 0fcd0cad René Nussbaumer
    """Compute the generic allocator input data.
426 0fcd0cad René Nussbaumer

427 e8936ef7 Helga Velroyen
    @type disk_template: list of string
428 e8936ef7 Helga Velroyen
    @param disk_template: the disk templates of the instances to be allocated
429 0fcd0cad René Nussbaumer

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

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

502 0fcd0cad René Nussbaumer
    @rtype: dict
503 0fcd0cad René Nussbaumer
    @returns: a dict of name: (node dict, node config)
504 0fcd0cad René Nussbaumer

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

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

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

543 0f70b3fb Helga Velroyen
    """
544 b82d7182 Helga Velroyen
    if attr not in hv_info:
545 0f70b3fb Helga Velroyen
      raise errors.OpExecError("Node '%s' didn't return attribute"
546 0f70b3fb Helga Velroyen
                               " '%s'" % (node_name, attr))
547 b82d7182 Helga Velroyen
    value = hv_info[attr]
548 0f70b3fb Helga Velroyen
    if not isinstance(value, int):
549 0f70b3fb Helga Velroyen
      raise errors.OpExecError("Node '%s' returned invalid value"
550 0f70b3fb Helga Velroyen
                               " for '%s': %s" %
551 0f70b3fb Helga Velroyen
                               (node_name, attr, value))
552 0f70b3fb Helga Velroyen
    return value
553 0f70b3fb Helga Velroyen
554 20529708 Helga Velroyen
  @staticmethod
555 e8936ef7 Helga Velroyen
  def _ComputeStorageDataFromSpaceInfoByTemplate(
556 e8936ef7 Helga Velroyen
      space_info, node_name, disk_template):
557 e8936ef7 Helga Velroyen
    """Extract storage data from node info.
558 e8936ef7 Helga Velroyen

559 e8936ef7 Helga Velroyen
    @type space_info: see result of the RPC call node info
560 e8936ef7 Helga Velroyen
    @param space_info: the storage reporting part of the result of the RPC call
561 e8936ef7 Helga Velroyen
      node info
562 e8936ef7 Helga Velroyen
    @type node_name: string
563 e8936ef7 Helga Velroyen
    @param node_name: the node's name
564 e8936ef7 Helga Velroyen
    @type disk_template: string
565 e8936ef7 Helga Velroyen
    @param disk_template: the disk template to report space for
566 e8936ef7 Helga Velroyen
    @rtype: 4-tuple of integers
567 e8936ef7 Helga Velroyen
    @return: tuple of storage info (total_disk, free_disk, total_spindles,
568 e8936ef7 Helga Velroyen
       free_spindles)
569 e8936ef7 Helga Velroyen

570 e8936ef7 Helga Velroyen
    """
571 e8936ef7 Helga Velroyen
    storage_type = constants.MAP_DISK_TEMPLATE_STORAGE_TYPE[disk_template]
572 e8936ef7 Helga Velroyen
    if storage_type not in constants.STS_REPORT:
573 e8936ef7 Helga Velroyen
      total_disk = total_spindles = 0
574 e8936ef7 Helga Velroyen
      free_disk = free_spindles = 0
575 e8936ef7 Helga Velroyen
    else:
576 e8936ef7 Helga Velroyen
      template_space_info = utils.storage.LookupSpaceInfoByDiskTemplate(
577 e8936ef7 Helga Velroyen
          space_info, disk_template)
578 e8936ef7 Helga Velroyen
      if not template_space_info:
579 e8936ef7 Helga Velroyen
        raise errors.OpExecError("Node '%s' didn't return space info for disk"
580 e8936ef7 Helga Velroyen
                                   "template '%s'" % (node_name, disk_template))
581 e8936ef7 Helga Velroyen
      total_disk = template_space_info["storage_size"]
582 e8936ef7 Helga Velroyen
      free_disk = template_space_info["storage_free"]
583 e8936ef7 Helga Velroyen
584 6c00b2c7 Helga Velroyen
      total_spindles = 0
585 6c00b2c7 Helga Velroyen
      free_spindles = 0
586 e8936ef7 Helga Velroyen
      if disk_template in constants.DTS_LVM:
587 e8936ef7 Helga Velroyen
        lvm_pv_info = utils.storage.LookupSpaceInfoByStorageType(
588 e8936ef7 Helga Velroyen
           space_info, constants.ST_LVM_PV)
589 6c00b2c7 Helga Velroyen
        if lvm_pv_info:
590 6c00b2c7 Helga Velroyen
          total_spindles = lvm_pv_info["storage_size"]
591 6c00b2c7 Helga Velroyen
          free_spindles = lvm_pv_info["storage_free"]
592 e8936ef7 Helga Velroyen
    return (total_disk, free_disk, total_spindles, free_spindles)
593 e8936ef7 Helga Velroyen
594 e8936ef7 Helga Velroyen
  @staticmethod
595 9353adde Helga Velroyen
  def _ComputeStorageDataFromSpaceInfo(space_info, node_name, has_lvm):
596 9353adde Helga Velroyen
    """Extract storage data from node info.
597 20529708 Helga Velroyen

598 9353adde Helga Velroyen
    @type space_info: see result of the RPC call node info
599 9353adde Helga Velroyen
    @param space_info: the storage reporting part of the result of the RPC call
600 9353adde Helga Velroyen
      node info
601 20529708 Helga Velroyen
    @type node_name: string
602 20529708 Helga Velroyen
    @param node_name: the node's name
603 20529708 Helga Velroyen
    @type has_lvm: boolean
604 11aa3ca5 Helga Velroyen
    @param has_lvm: whether or not LVM storage information is requested
605 20529708 Helga Velroyen
    @rtype: 4-tuple of integers
606 20529708 Helga Velroyen
    @return: tuple of storage info (total_disk, free_disk, total_spindles,
607 20529708 Helga Velroyen
       free_spindles)
608 20529708 Helga Velroyen

609 20529708 Helga Velroyen
    """
610 20529708 Helga Velroyen
    # TODO: replace this with proper storage reporting
611 20529708 Helga Velroyen
    if has_lvm:
612 11aa3ca5 Helga Velroyen
      lvm_vg_info = utils.storage.LookupSpaceInfoByStorageType(
613 11aa3ca5 Helga Velroyen
         space_info, constants.ST_LVM_VG)
614 11aa3ca5 Helga Velroyen
      if not lvm_vg_info:
615 11aa3ca5 Helga Velroyen
        raise errors.OpExecError("Node '%s' didn't return LVM vg space info."
616 11aa3ca5 Helga Velroyen
                                 % (node_name))
617 11aa3ca5 Helga Velroyen
      total_disk = lvm_vg_info["storage_size"]
618 11aa3ca5 Helga Velroyen
      free_disk = lvm_vg_info["storage_free"]
619 11aa3ca5 Helga Velroyen
      lvm_pv_info = utils.storage.LookupSpaceInfoByStorageType(
620 11aa3ca5 Helga Velroyen
         space_info, constants.ST_LVM_PV)
621 e8936ef7 Helga Velroyen
      if not lvm_pv_info:
622 11aa3ca5 Helga Velroyen
        raise errors.OpExecError("Node '%s' didn't return LVM pv space info."
623 11aa3ca5 Helga Velroyen
                                 % (node_name))
624 11aa3ca5 Helga Velroyen
      total_spindles = lvm_pv_info["storage_size"]
625 11aa3ca5 Helga Velroyen
      free_spindles = lvm_pv_info["storage_free"]
626 20529708 Helga Velroyen
    else:
627 20529708 Helga Velroyen
      # we didn't even ask the node for VG status, so use zeros
628 20529708 Helga Velroyen
      total_disk = free_disk = 0
629 20529708 Helga Velroyen
      total_spindles = free_spindles = 0
630 20529708 Helga Velroyen
    return (total_disk, free_disk, total_spindles, free_spindles)
631 20529708 Helga Velroyen
632 0ac34c90 Helga Velroyen
  @staticmethod
633 0ac34c90 Helga Velroyen
  def _ComputeInstanceMemory(instance_list, node_instances_info, node_uuid,
634 0ac34c90 Helga Velroyen
                             input_mem_free):
635 0ac34c90 Helga Velroyen
    """Compute memory used by primary instances.
636 0ac34c90 Helga Velroyen

637 0ac34c90 Helga Velroyen
    @rtype: tuple (int, int, int)
638 0ac34c90 Helga Velroyen
    @returns: A tuple of three integers: 1. the sum of memory used by primary
639 0ac34c90 Helga Velroyen
      instances on the node (including the ones that are currently down), 2.
640 0ac34c90 Helga Velroyen
      the sum of memory used by primary instances of the node that are up, 3.
641 0ac34c90 Helga Velroyen
      the amount of memory that is free on the node considering the current
642 0ac34c90 Helga Velroyen
      usage of the instances.
643 0ac34c90 Helga Velroyen

644 0ac34c90 Helga Velroyen
    """
645 0ac34c90 Helga Velroyen
    i_p_mem = i_p_up_mem = 0
646 0ac34c90 Helga Velroyen
    mem_free = input_mem_free
647 0ac34c90 Helga Velroyen
    for iinfo, beinfo in instance_list:
648 0ac34c90 Helga Velroyen
      if iinfo.primary_node == node_uuid:
649 0ac34c90 Helga Velroyen
        i_p_mem += beinfo[constants.BE_MAXMEM]
650 0ac34c90 Helga Velroyen
        if iinfo.name not in node_instances_info[node_uuid].payload:
651 0ac34c90 Helga Velroyen
          i_used_mem = 0
652 0ac34c90 Helga Velroyen
        else:
653 0ac34c90 Helga Velroyen
          i_used_mem = int(node_instances_info[node_uuid]
654 0ac34c90 Helga Velroyen
                           .payload[iinfo.name]["memory"])
655 0ac34c90 Helga Velroyen
        i_mem_diff = beinfo[constants.BE_MAXMEM] - i_used_mem
656 0ac34c90 Helga Velroyen
        mem_free -= max(0, i_mem_diff)
657 0ac34c90 Helga Velroyen
658 0ac34c90 Helga Velroyen
        if iinfo.admin_state == constants.ADMINST_UP:
659 0ac34c90 Helga Velroyen
          i_p_up_mem += beinfo[constants.BE_MAXMEM]
660 0ac34c90 Helga Velroyen
    return (i_p_mem, i_p_up_mem, mem_free)
661 0ac34c90 Helga Velroyen
662 0f70b3fb Helga Velroyen
  def _ComputeDynamicNodeData(self, node_cfg, node_data, node_iinfo, i_list,
663 e8936ef7 Helga Velroyen
                              node_results, disk_template):
664 0fcd0cad René Nussbaumer
    """Compute global node data.
665 0fcd0cad René Nussbaumer

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

668 0fcd0cad René Nussbaumer
    """
669 0fcd0cad René Nussbaumer
    #TODO(dynmem): compute the right data on MAX and MIN memory
670 0fcd0cad René Nussbaumer
    # make a copy of the current dict
671 0fcd0cad René Nussbaumer
    node_results = dict(node_results)
672 1c3231aa Thomas Thrainer
    for nuuid, nresult in node_data.items():
673 1c3231aa Thomas Thrainer
      ninfo = node_cfg[nuuid]
674 1c3231aa Thomas Thrainer
      assert ninfo.name in node_results, "Missing basic data for node %s" % \
675 1c3231aa Thomas Thrainer
                                         ninfo.name
676 0fcd0cad René Nussbaumer
677 67ec18c0 Jose A. Lopes
      if not ninfo.offline:
678 1c3231aa Thomas Thrainer
        nresult.Raise("Can't get data for node %s" % ninfo.name)
679 1c3231aa Thomas Thrainer
        node_iinfo[nuuid].Raise("Can't get node instance info from node %s" %
680 1c3231aa Thomas Thrainer
                                ninfo.name)
681 9353adde Helga Velroyen
        (_, space_info, (hv_info, )) = nresult.payload
682 0fcd0cad René Nussbaumer
683 b82d7182 Helga Velroyen
        mem_free = self._GetAttributeFromHypervisorNodeData(hv_info, ninfo.name,
684 b82d7182 Helga Velroyen
                                                            "memory_free")
685 36a566e8 Iustin Pop
686 0ac34c90 Helga Velroyen
        (i_p_mem, i_p_up_mem, mem_free) = self._ComputeInstanceMemory(
687 0ac34c90 Helga Velroyen
             i_list, node_iinfo, nuuid, mem_free)
688 20529708 Helga Velroyen
        (total_disk, free_disk, total_spindles, free_spindles) = \
689 e8936ef7 Helga Velroyen
            self._ComputeStorageDataFromSpaceInfoByTemplate(
690 e8936ef7 Helga Velroyen
                space_info, ninfo.name, disk_template)
691 36a566e8 Iustin Pop
692 0fcd0cad René Nussbaumer
        # compute memory used by instances
693 0fcd0cad René Nussbaumer
        pnr_dyn = {
694 b82d7182 Helga Velroyen
          "total_memory": self._GetAttributeFromHypervisorNodeData(
695 b82d7182 Helga Velroyen
              hv_info, ninfo.name, "memory_total"),
696 b82d7182 Helga Velroyen
          "reserved_memory": self._GetAttributeFromHypervisorNodeData(
697 b82d7182 Helga Velroyen
              hv_info, ninfo.name, "memory_dom0"),
698 36a566e8 Iustin Pop
          "free_memory": mem_free,
699 36a566e8 Iustin Pop
          "total_disk": total_disk,
700 36a566e8 Iustin Pop
          "free_disk": free_disk,
701 06fb92cf Bernardo Dal Seno
          "total_spindles": total_spindles,
702 06fb92cf Bernardo Dal Seno
          "free_spindles": free_spindles,
703 b82d7182 Helga Velroyen
          "total_cpus": self._GetAttributeFromHypervisorNodeData(
704 b82d7182 Helga Velroyen
              hv_info, ninfo.name, "cpu_total"),
705 f43c898d Bernardo Dal Seno
          "reserved_cpus": self._GetAttributeFromHypervisorNodeData(
706 f43c898d Bernardo Dal Seno
            hv_info, ninfo.name, "cpu_dom0"),
707 0fcd0cad René Nussbaumer
          "i_pri_memory": i_p_mem,
708 0fcd0cad René Nussbaumer
          "i_pri_up_memory": i_p_up_mem,
709 0fcd0cad René Nussbaumer
          }
710 1c3231aa Thomas Thrainer
        pnr_dyn.update(node_results[ninfo.name])
711 1c3231aa Thomas Thrainer
        node_results[ninfo.name] = pnr_dyn
712 0fcd0cad René Nussbaumer
713 0fcd0cad René Nussbaumer
    return node_results
714 0fcd0cad René Nussbaumer
715 0fcd0cad René Nussbaumer
  @staticmethod
716 1c3231aa Thomas Thrainer
  def _ComputeInstanceData(cfg, cluster_info, i_list):
717 0fcd0cad René Nussbaumer
    """Compute global instance data.
718 0fcd0cad René Nussbaumer

719 0fcd0cad René Nussbaumer
    """
720 0fcd0cad René Nussbaumer
    instance_data = {}
721 0fcd0cad René Nussbaumer
    for iinfo, beinfo in i_list:
722 0fcd0cad René Nussbaumer
      nic_data = []
723 0fcd0cad René Nussbaumer
      for nic in iinfo.nics:
724 0fcd0cad René Nussbaumer
        filled_params = cluster_info.SimpleFillNIC(nic.nicparams)
725 0fcd0cad René Nussbaumer
        nic_dict = {
726 0fcd0cad René Nussbaumer
          "mac": nic.mac,
727 0fcd0cad René Nussbaumer
          "ip": nic.ip,
728 0fcd0cad René Nussbaumer
          "mode": filled_params[constants.NIC_MODE],
729 0fcd0cad René Nussbaumer
          "link": filled_params[constants.NIC_LINK],
730 0fcd0cad René Nussbaumer
          }
731 0fcd0cad René Nussbaumer
        if filled_params[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
732 0fcd0cad René Nussbaumer
          nic_dict["bridge"] = filled_params[constants.NIC_LINK]
733 0fcd0cad René Nussbaumer
        nic_data.append(nic_dict)
734 0fcd0cad René Nussbaumer
      pir = {
735 0fcd0cad René Nussbaumer
        "tags": list(iinfo.GetTags()),
736 0fcd0cad René Nussbaumer
        "admin_state": iinfo.admin_state,
737 0fcd0cad René Nussbaumer
        "vcpus": beinfo[constants.BE_VCPUS],
738 0fcd0cad René Nussbaumer
        "memory": beinfo[constants.BE_MAXMEM],
739 0fcd0cad René Nussbaumer
        "spindle_use": beinfo[constants.BE_SPINDLE_USE],
740 0fcd0cad René Nussbaumer
        "os": iinfo.os,
741 1c3231aa Thomas Thrainer
        "nodes": [cfg.GetNodeName(iinfo.primary_node)] +
742 1c3231aa Thomas Thrainer
                 cfg.GetNodeNames(iinfo.secondary_nodes),
743 0fcd0cad René Nussbaumer
        "nics": nic_data,
744 0fcd0cad René Nussbaumer
        "disks": [{constants.IDISK_SIZE: dsk.size,
745 0e514de1 Bernardo Dal Seno
                   constants.IDISK_MODE: dsk.mode,
746 0e514de1 Bernardo Dal Seno
                   constants.IDISK_SPINDLES: dsk.spindles}
747 0fcd0cad René Nussbaumer
                  for dsk in iinfo.disks],
748 0fcd0cad René Nussbaumer
        "disk_template": iinfo.disk_template,
749 1d4a4b26 Thomas Thrainer
        "disks_active": iinfo.disks_active,
750 0fcd0cad René Nussbaumer
        "hypervisor": iinfo.hypervisor,
751 0fcd0cad René Nussbaumer
        }
752 0fcd0cad René Nussbaumer
      pir["disk_space_total"] = gmi.ComputeDiskSize(iinfo.disk_template,
753 0fcd0cad René Nussbaumer
                                                    pir["disks"])
754 0fcd0cad René Nussbaumer
      instance_data[iinfo.name] = pir
755 0fcd0cad René Nussbaumer
756 0fcd0cad René Nussbaumer
    return instance_data
757 0fcd0cad René Nussbaumer
758 0fcd0cad René Nussbaumer
  def _BuildInputData(self, req):
759 0fcd0cad René Nussbaumer
    """Build input data structures.
760 0fcd0cad René Nussbaumer

761 0fcd0cad René Nussbaumer
    """
762 0fcd0cad René Nussbaumer
    request = req.GetRequest(self.cfg)
763 e8936ef7 Helga Velroyen
    disk_template = None
764 e8936ef7 Helga Velroyen
    if "disk_template" in request:
765 e8936ef7 Helga Velroyen
      disk_template = request["disk_template"]
766 e8936ef7 Helga Velroyen
    self._ComputeClusterData(disk_template=disk_template)
767 e8936ef7 Helga Velroyen
768 0fcd0cad René Nussbaumer
    request["type"] = req.MODE
769 0fcd0cad René Nussbaumer
    self.in_data["request"] = request
770 0fcd0cad René Nussbaumer
771 0fcd0cad René Nussbaumer
    self.in_text = serializer.Dump(self.in_data)
772 0fcd0cad René Nussbaumer
773 0fcd0cad René Nussbaumer
  def Run(self, name, validate=True, call_fn=None):
774 0fcd0cad René Nussbaumer
    """Run an instance allocator and return the results.
775 0fcd0cad René Nussbaumer

776 0fcd0cad René Nussbaumer
    """
777 0fcd0cad René Nussbaumer
    if call_fn is None:
778 0fcd0cad René Nussbaumer
      call_fn = self.rpc.call_iallocator_runner
779 0fcd0cad René Nussbaumer
780 0359e5d0 Spyros Trigazis
    ial_params = self.cfg.GetDefaultIAllocatorParameters()
781 0359e5d0 Spyros Trigazis
782 0359e5d0 Spyros Trigazis
    result = call_fn(self.cfg.GetMasterNode(), name, self.in_text, ial_params)
783 0fcd0cad René Nussbaumer
    result.Raise("Failure while running the iallocator script")
784 0fcd0cad René Nussbaumer
785 0fcd0cad René Nussbaumer
    self.out_text = result.payload
786 0fcd0cad René Nussbaumer
    if validate:
787 0fcd0cad René Nussbaumer
      self._ValidateResult()
788 0fcd0cad René Nussbaumer
789 0fcd0cad René Nussbaumer
  def _ValidateResult(self):
790 0fcd0cad René Nussbaumer
    """Process the allocator results.
791 0fcd0cad René Nussbaumer

792 0fcd0cad René Nussbaumer
    This will process and if successful save the result in
793 0fcd0cad René Nussbaumer
    self.out_data and the other parameters.
794 0fcd0cad René Nussbaumer

795 0fcd0cad René Nussbaumer
    """
796 0fcd0cad René Nussbaumer
    try:
797 0fcd0cad René Nussbaumer
      rdict = serializer.Load(self.out_text)
798 0fcd0cad René Nussbaumer
    except Exception, err:
799 0fcd0cad René Nussbaumer
      raise errors.OpExecError("Can't parse iallocator results: %s" % str(err))
800 0fcd0cad René Nussbaumer
801 0fcd0cad René Nussbaumer
    if not isinstance(rdict, dict):
802 0fcd0cad René Nussbaumer
      raise errors.OpExecError("Can't parse iallocator results: not a dict")
803 0fcd0cad René Nussbaumer
804 0fcd0cad René Nussbaumer
    # TODO: remove backwards compatiblity in later versions
805 0fcd0cad René Nussbaumer
    if "nodes" in rdict and "result" not in rdict:
806 0fcd0cad René Nussbaumer
      rdict["result"] = rdict["nodes"]
807 0fcd0cad René Nussbaumer
      del rdict["nodes"]
808 0fcd0cad René Nussbaumer
809 0fcd0cad René Nussbaumer
    for key in "success", "info", "result":
810 0fcd0cad René Nussbaumer
      if key not in rdict:
811 0fcd0cad René Nussbaumer
        raise errors.OpExecError("Can't parse iallocator results:"
812 0fcd0cad René Nussbaumer
                                 " missing key '%s'" % key)
813 0fcd0cad René Nussbaumer
      setattr(self, key, rdict[key])
814 0fcd0cad René Nussbaumer
815 0fcd0cad René Nussbaumer
    self.req.ValidateResult(self, self.result)
816 0fcd0cad René Nussbaumer
    self.out_data = rdict