diff --git a/doc/iallocator.rst b/doc/iallocator.rst
index e8c371604b5ee6802368ca2dde67d8665a0ba5e7..ee519f3b9f4dcffadf662b3f821df3a0d4296904 100644
--- a/doc/iallocator.rst
+++ b/doc/iallocator.rst
@@ -291,7 +291,6 @@ As for ``node-evacuate``, it needs the following request arguments:
     specify which instances to evacuate; one of ``primary-only``,
     ``secondary-only``, ``all``, type *string*
 
-
 ``change-group`` needs the following request arguments:
 
   instances
diff --git a/lib/client/gnt_debug.py b/lib/client/gnt_debug.py
index 8065dd71dec5ebb572760f135245a3f74ab1f7f7..c7f0a7d400334cababbd3f357b92f9613df029cd 100644
--- a/lib/client/gnt_debug.py
+++ b/lib/client/gnt_debug.py
@@ -173,7 +173,7 @@ def TestAllocator(opts, args):
                                tags=opts.tags,
                                direction=opts.direction,
                                allocator=opts.iallocator,
-                               reloc_mode=opts.reloc_mode,
+                               evac_mode=opts.evac_mode,
                                target_groups=target_groups)
   result = SubmitOpCode(op, opts=opts)
   ToStdout("%s" % result)
@@ -582,11 +582,12 @@ commands = {
                 help="Select number of VCPUs for the instance"),
      cli_option("--tags", default=None,
                 help="Comma separated list of tags"),
-     cli_option("--reloc-mode", default=constants.IALLOCATOR_MRELOC_ANY,
-                choices=list(constants.IALLOCATOR_MRELOC_MODES),
-                help=("Instance relocation mode (one of %s)" %
-                      utils.CommaJoin(constants.IALLOCATOR_MRELOC_MODES))),
-     cli_option("--target-groups", help="Target groups for relocation"),
+     cli_option("--evac-mode", default=constants.IALLOCATOR_NEVAC_ALL,
+                choices=list(constants.IALLOCATOR_NEVAC_MODES),
+                help=("Node evacuation mode (one of %s)" %
+                      utils.CommaJoin(constants.IALLOCATOR_NEVAC_MODES))),
+     cli_option("--target-groups", help="Target groups for relocation",
+                default=[], action="append"),
      DRY_RUN_OPT, PRIORITY_OPT,
      ],
     "{opts...} <instance>", "Executes a TestAllocator OpCode"),
diff --git a/lib/cmdlib.py b/lib/cmdlib.py
index 5216b1cfb57e3b6310463540b1717dfcae97971f..9ee361fc408655112d0298c4d50b2e008b08c6d5 100644
--- a/lib/cmdlib.py
+++ b/lib/cmdlib.py
@@ -12033,7 +12033,7 @@ class IAllocator(object):
     self.name = None
     self.evac_nodes = None
     self.instances = None
-    self.reloc_mode = None
+    self.evac_mode = None
     self.target_groups = []
     # computed fields
     self.required_nodes = None
@@ -12087,8 +12087,7 @@ class IAllocator(object):
       hypervisor_name = self.hypervisor
     elif self.mode == constants.IALLOCATOR_MODE_RELOC:
       hypervisor_name = cfg.GetInstanceInfo(self.name).hypervisor
-    elif self.mode in (constants.IALLOCATOR_MODE_MEVAC,
-                       constants.IALLOCATOR_MODE_MRELOC):
+    else:
       hypervisor_name = cluster_info.enabled_hypervisors[0]
 
     node_data = self.rpc.call_node_info(node_list, cfg.GetVGName(),
@@ -12323,13 +12322,21 @@ class IAllocator(object):
       }
     return request
 
-  def _AddMultiRelocate(self):
-    """Get data for multi-relocate requests.
+  def _AddNodeEvacuate(self):
+    """Get data for node-evacuate requests.
+
+    """
+    return {
+      "instances": self.instances,
+      "evac_mode": self.evac_mode,
+      }
+
+  def _AddChangeGroup(self):
+    """Get data for node-evacuate requests.
 
     """
     return {
       "instances": self.instances,
-      "reloc_mode": self.reloc_mode,
       "target_groups": self.target_groups,
       }
 
@@ -12355,6 +12362,13 @@ class IAllocator(object):
     self.in_text = serializer.Dump(self.in_data)
 
   _STRING_LIST = ht.TListOf(ht.TString)
+  _JOBSET_LIST = ht.TListOf(ht.TListOf(ht.TStrictDict(True, False, {
+     # pylint: disable-msg=E1101
+     # Class '...' has no 'OP_ID' member
+     "OP_ID": ht.TElemOf([opcodes.OpInstanceFailover.OP_ID,
+                          opcodes.OpInstanceMigrate.OP_ID,
+                          opcodes.OpInstanceReplaceDisks.OP_ID])
+     })))
   _MODE_DATA = {
     constants.IALLOCATOR_MODE_ALLOC:
       (_AddNewInstance,
@@ -12376,19 +12390,16 @@ class IAllocator(object):
     constants.IALLOCATOR_MODE_MEVAC:
       (_AddEvacuateNodes, [("evac_nodes", _STRING_LIST)],
        ht.TListOf(ht.TAnd(ht.TIsLength(2), _STRING_LIST))),
-    constants.IALLOCATOR_MODE_MRELOC:
-      (_AddMultiRelocate, [
+     constants.IALLOCATOR_MODE_NODE_EVAC:
+      (_AddNodeEvacuate, [
+        ("instances", _STRING_LIST),
+        ("evac_mode", ht.TElemOf(constants.IALLOCATOR_NEVAC_MODES)),
+        ], _JOBSET_LIST),
+     constants.IALLOCATOR_MODE_CHG_GROUP:
+      (_AddChangeGroup, [
         ("instances", _STRING_LIST),
-        ("reloc_mode", ht.TElemOf(constants.IALLOCATOR_MRELOC_MODES)),
         ("target_groups", _STRING_LIST),
-        ],
-       ht.TListOf(ht.TListOf(ht.TStrictDict(True, False, {
-         # pylint: disable-msg=E1101
-         # Class '...' has no 'OP_ID' member
-         "OP_ID": ht.TElemOf([opcodes.OpInstanceFailover.OP_ID,
-                              opcodes.OpInstanceMigrate.OP_ID,
-                              opcodes.OpInstanceReplaceDisks.OP_ID])
-         })))),
+        ], _JOBSET_LIST),
     }
 
   def Run(self, name, validate=True, call_fn=None):
@@ -12553,12 +12564,11 @@ class LUTestAllocator(NoHooksLU):
       if not hasattr(self.op, "evac_nodes"):
         raise errors.OpPrereqError("Missing attribute 'evac_nodes' on"
                                    " opcode input", errors.ECODE_INVAL)
-    elif self.op.mode == constants.IALLOCATOR_MODE_MRELOC:
-      if self.op.instances:
-        self.op.instances = _GetWantedInstances(self, self.op.instances)
-      else:
-        raise errors.OpPrereqError("Missing instances to relocate",
-                                   errors.ECODE_INVAL)
+    elif self.op.mode in (constants.IALLOCATOR_MODE_CHG_GROUP,
+                          constants.IALLOCATOR_MODE_NODE_EVAC):
+      if not self.op.instances:
+        raise errors.OpPrereqError("Missing instances", errors.ECODE_INVAL)
+      self.op.instances = _GetWantedInstances(self, self.op.instances)
     else:
       raise errors.OpPrereqError("Invalid test allocator mode '%s'" %
                                  self.op.mode, errors.ECODE_INVAL)
@@ -12598,12 +12608,16 @@ class LUTestAllocator(NoHooksLU):
       ial = IAllocator(self.cfg, self.rpc,
                        mode=self.op.mode,
                        evac_nodes=self.op.evac_nodes)
-    elif self.op.mode == constants.IALLOCATOR_MODE_MRELOC:
+    elif self.op.mode == constants.IALLOCATOR_MODE_CHG_GROUP:
       ial = IAllocator(self.cfg, self.rpc,
                        mode=self.op.mode,
                        instances=self.op.instances,
-                       reloc_mode=self.op.reloc_mode,
                        target_groups=self.op.target_groups)
+    elif self.op.mode == constants.IALLOCATOR_MODE_NODE_EVAC:
+      ial = IAllocator(self.cfg, self.rpc,
+                       mode=self.op.mode,
+                       instances=self.op.instances,
+                       evac_mode=self.op.evac_mode)
     else:
       raise errors.ProgrammerError("Uncatched mode %s in"
                                    " LUTestAllocator.Exec", self.op.mode)
diff --git a/lib/constants.py b/lib/constants.py
index a33186b008268c380fd8195b587d8b9aee1e3819..bc048db7083dc8b805d187ca59d5a8d7dc672129 100644
--- a/lib/constants.py
+++ b/lib/constants.py
@@ -952,14 +952,28 @@ IALLOCATOR_MODE_ALLOC = "allocate"
 IALLOCATOR_MODE_RELOC = "relocate"
 IALLOCATOR_MODE_MEVAC = "multi-evacuate"
 IALLOCATOR_MODE_MRELOC = "multi-relocate"
+IALLOCATOR_MODE_CHG_GROUP = "change-group"
+IALLOCATOR_MODE_NODE_EVAC = "node-evacuate"
 VALID_IALLOCATOR_MODES = frozenset([
   IALLOCATOR_MODE_ALLOC,
   IALLOCATOR_MODE_RELOC,
   IALLOCATOR_MODE_MEVAC,
   IALLOCATOR_MODE_MRELOC,
+  IALLOCATOR_MODE_CHG_GROUP,
+  IALLOCATOR_MODE_NODE_EVAC,
   ])
 IALLOCATOR_SEARCH_PATH = _autoconf.IALLOCATOR_SEARCH_PATH
 
+IALLOCATOR_NEVAC_PRI = "primary-only"
+IALLOCATOR_NEVAC_SEC = "secondary-only"
+IALLOCATOR_NEVAC_ALL = "all"
+IALLOCATOR_NEVAC_MODES = frozenset([
+  IALLOCATOR_NEVAC_PRI,
+  IALLOCATOR_NEVAC_SEC,
+  IALLOCATOR_NEVAC_ALL,
+  ])
+
+# TODO: Remove multi-relocate constants, including IALLOCATOR_MODE_MRELOC
 IALLOCATOR_MRELOC_ANY = "any_group"
 IALLOCATOR_MRELOC_CHANGE = "change_group"
 IALLOCATOR_MRELOC_KEEP = "keep_group"
diff --git a/lib/opcodes.py b/lib/opcodes.py
index 1c7343e4256d9c71920b9ed9f3b8fe8531163540..38ca9353276b6a2ea54b0b8f2febeb3e6bc9a55d 100644
--- a/lib/opcodes.py
+++ b/lib/opcodes.py
@@ -1456,8 +1456,8 @@ class OpTestAllocator(OpCode):
      None),
     ("instances", None, ht.TOr(ht.TNone, ht.TListOf(ht.TNonEmptyString)),
      None),
-    ("reloc_mode", None,
-     ht.TOr(ht.TNone, ht.TElemOf(constants.IALLOCATOR_MRELOC_MODES)), None),
+    ("evac_mode", None,
+     ht.TOr(ht.TNone, ht.TElemOf(constants.IALLOCATOR_NEVAC_MODES)), None),
     ("target_groups", None, ht.TOr(ht.TNone, ht.TListOf(ht.TNonEmptyString)),
      None),
     ]