Revision f0edfcf6

b/doc/iallocator.rst
190 190

  
191 191
  type
192 192
    the request type; this can be either ``allocate``, ``relocate``,
193
    ``change-group``, ``node-evacuate`` or ``multi-evacuate``. The
193
    ``change-group`` or ``node-evacuate``. The
194 194
    ``allocate`` request is used when a new instance needs to be placed
195 195
    on the cluster. The ``relocate`` request is used when an existing
196 196
    instance needs to be moved within its node group.
197 197

  
198 198
    The ``multi-evacuate`` protocol used to request that the script
199 199
    computes the optimal relocate solution for all secondary instances
200
    of the given nodes. It is now deprecated and should no longer be
201
    used.
200
    of the given nodes. It is now deprecated and needs only be
201
    implemented if backwards compatibility with Ganeti 2.4 and lower is
202
    needed.
202 203

  
203 204
    The ``change-group`` request is used to relocate multiple instances
204 205
    across multiple node groups. ``node-evacuate`` evacuates instances
......
302 303
    should be considered for relocating instances to; type
303 304
    *list of strings*
304 305

  
305
Finally, in the case of multi-evacuate, there's one single request
306
argument (in addition to ``type``):
307

  
308
  evac_nodes
309
    the names of the nodes to be evacuated; type *list of strings*
310

  
311 306
Response message
312 307
~~~~~~~~~~~~~~~~
313 308

  
......
335 330
  serialized opcodes; see the :ref:`design document
336 331
  <multi-reloc-result>` for a detailed description
337 332

  
338
  for multi-evacuation mode, this is a list of lists; each element of
339
  the list is a list of instance name and the new secondary node
340

  
341 333
.. note:: Current Ganeti version accepts either ``result`` or ``nodes``
342 334
   as a backwards-compatibility measure (older versions only supported
343 335
   ``nodes``)
......
505 497
    }
506 498
  }
507 499

  
508
Input message, node evacuation::
509

  
510
  {
511
    "version": 2,
512
    ...
513
    "request": {
514
      "type": "multi-evacuate",
515
      "evac_nodes": [
516
        "node2"
517
      ],
518
    }
519
  }
520

  
521 500

  
522 501
Response messages
523 502
~~~~~~~~~~~~~~~~~
b/lib/client/gnt_debug.py
163 163

  
164 164
  op = opcodes.OpTestAllocator(mode=opts.mode,
165 165
                               name=args[0],
166
                               evac_nodes=args,
167 166
                               instances=args,
168 167
                               memory=opts.memory,
169 168
                               disks=disks,
b/lib/cmdlib.py
12759 12759
    self.hypervisor = None
12760 12760
    self.relocate_from = None
12761 12761
    self.name = None
12762
    self.evac_nodes = None
12763 12762
    self.instances = None
12764 12763
    self.evac_mode = None
12765 12764
    self.target_groups = []
......
13041 13040
      }
13042 13041
    return request
13043 13042

  
13044
  def _AddEvacuateNodes(self):
13045
    """Add evacuate nodes data to allocator structure.
13046

  
13047
    """
13048
    request = {
13049
      "evac_nodes": self.evac_nodes
13050
      }
13051
    return request
13052

  
13053 13043
  def _AddNodeEvacuate(self):
13054 13044
    """Get data for node-evacuate requests.
13055 13045

  
......
13130 13120
      (_AddRelocateInstance,
13131 13121
       [("name", ht.TString), ("relocate_from", _STRING_LIST)],
13132 13122
       ht.TList),
13133
    constants.IALLOCATOR_MODE_MEVAC:
13134
      (_AddEvacuateNodes, [("evac_nodes", _STRING_LIST)],
13135
       ht.TListOf(ht.TAnd(ht.TIsLength(2), _STRING_LIST))),
13136 13123
     constants.IALLOCATOR_MODE_NODE_EVAC:
13137 13124
      (_AddNodeEvacuate, [
13138 13125
        ("instances", _STRING_LIST),
......
13191 13178
                               (self._result_check, self.result),
13192 13179
                               errors.ECODE_INVAL)
13193 13180

  
13194
    if self.mode in (constants.IALLOCATOR_MODE_RELOC,
13195
                     constants.IALLOCATOR_MODE_MEVAC):
13181
    if self.mode == constants.IALLOCATOR_MODE_RELOC:
13196 13182
      node2group = dict((name, ndata["group"])
13197 13183
                        for (name, ndata) in self.in_data["nodes"].items())
13198 13184

  
......
13211 13197
                                   " differ from original groups (%s)" %
13212 13198
                                   (utils.CommaJoin(result_groups),
13213 13199
                                    utils.CommaJoin(request_groups)))
13214
      elif self.mode == constants.IALLOCATOR_MODE_MEVAC:
13215
        request_groups = fn(self.evac_nodes)
13216
        for (instance_name, secnode) in self.result:
13217
          result_groups = fn([secnode])
13218
          if result_groups != request_groups:
13219
            raise errors.OpExecError("Iallocator returned new secondary node"
13220
                                     " '%s' (group '%s') for instance '%s'"
13221
                                     " which is not in original group '%s'" %
13222
                                     (secnode, utils.CommaJoin(result_groups),
13223
                                      instance_name,
13224
                                      utils.CommaJoin(request_groups)))
13225 13200
      else:
13226 13201
        raise errors.ProgrammerError("Unhandled mode '%s'" % self.mode)
13227 13202

  
......
13307 13282
      self.op.name = fname
13308 13283
      self.relocate_from = \
13309 13284
          list(self.cfg.GetInstanceInfo(fname).secondary_nodes)
13310
    elif self.op.mode == constants.IALLOCATOR_MODE_MEVAC:
13311
      if not hasattr(self.op, "evac_nodes"):
13312
        raise errors.OpPrereqError("Missing attribute 'evac_nodes' on"
13313
                                   " opcode input", errors.ECODE_INVAL)
13314 13285
    elif self.op.mode in (constants.IALLOCATOR_MODE_CHG_GROUP,
13315 13286
                          constants.IALLOCATOR_MODE_NODE_EVAC):
13316 13287
      if not self.op.instances:
......
13351 13322
                       name=self.op.name,
13352 13323
                       relocate_from=list(self.relocate_from),
13353 13324
                       )
13354
    elif self.op.mode == constants.IALLOCATOR_MODE_MEVAC:
13355
      ial = IAllocator(self.cfg, self.rpc,
13356
                       mode=self.op.mode,
13357
                       evac_nodes=self.op.evac_nodes)
13358 13325
    elif self.op.mode == constants.IALLOCATOR_MODE_CHG_GROUP:
13359 13326
      ial = IAllocator(self.cfg, self.rpc,
13360 13327
                       mode=self.op.mode,
b/lib/constants.py
1025 1025
  ])
1026 1026
IALLOCATOR_MODE_ALLOC = "allocate"
1027 1027
IALLOCATOR_MODE_RELOC = "relocate"
1028
IALLOCATOR_MODE_MEVAC = "multi-evacuate"
1029 1028
IALLOCATOR_MODE_CHG_GROUP = "change-group"
1030 1029
IALLOCATOR_MODE_NODE_EVAC = "node-evacuate"
1031 1030
VALID_IALLOCATOR_MODES = frozenset([
1032 1031
  IALLOCATOR_MODE_ALLOC,
1033 1032
  IALLOCATOR_MODE_RELOC,
1034
  IALLOCATOR_MODE_MEVAC,
1035 1033
  IALLOCATOR_MODE_CHG_GROUP,
1036 1034
  IALLOCATOR_MODE_NODE_EVAC,
1037 1035
  ])
b/lib/opcodes.py
1541 1541
    ("vcpus", None, ht.TOr(ht.TNone, ht.TPositiveInt), None),
1542 1542
    ("os", None, ht.TMaybeString, None),
1543 1543
    ("disk_template", None, ht.TMaybeString, None),
1544
    ("evac_nodes", None, ht.TOr(ht.TNone, ht.TListOf(ht.TNonEmptyString)),
1545
     None),
1546 1544
    ("instances", None, ht.TOr(ht.TNone, ht.TListOf(ht.TNonEmptyString)),
1547 1545
     None),
1548 1546
    ("evac_mode", None,

Also available in: Unified diff