By default it'll now evacuate all instances from the node, not
just secondaries.
---
lib/cli.py | 13 ++++++++
lib/client/gnt_node.py | 73 +++++++++++++++++++++++++++++++-----------------
man/gnt-node.rst | 11 ++++--
3 files changed, 67 insertions(+), 30 deletions(-)
diff --git a/lib/cli.py b/lib/cli.py
index aba1f1b..6d260ed 100644
--- a/lib/cli.py
+++ b/lib/cli.py
@@ -143,6 +143,7 @@ __all__ = [
"POWER_DELAY_OPT",
"PREALLOC_WIPE_DISKS_OPT",
"PRIMARY_IP_VERSION_OPT",
+ "PRIMARY_ONLY_OPT",
"PRIORITY_OPT",
"RAPI_CERT_OPT",
"READD_OPT",
@@ -152,6 +153,7 @@ __all__ = [
"RESERVED_LVS_OPT",
"ROMAN_OPT",
"SECONDARY_IP_OPT",
+ "SECONDARY_ONLY_OPT",
"SELECT_OS_OPT",
"SEP_OPT",
"SHOWCMD_OPT",
@@ -1205,6 +1207,17 @@ NO_REMEMBER_OPT = cli_option("--no-remember",
help="Perform but do not record the change"
" in the configuration")
+PRIMARY_ONLY_OPT = cli_option("-p", "--primary-only",
+ default=False, action="store_true",
+ help="Evacuate primary instances only")
+
+SECONDARY_ONLY_OPT = cli_option("-s", "--secondary-only",
+ default=False, action="store_true",
+ help="Evacuate secondary instances only"
+ " (applies only to internally mirrored"
+ " disk templates, e.g. %s)" %
+ utils.CommaJoin(constants.DTS_INT_MIRROR))
+
#: Options provided by all commands
COMMON_OPTS = [DEBUG_OPT]
diff --git a/lib/client/gnt_node.py b/lib/client/gnt_node.py
index a56e449..7da4e66 100644
--- a/lib/client/gnt_node.py
+++ b/lib/client/gnt_node.py
@@ -26,6 +26,8 @@
# W0614: Unused import %s from wildcard import (since we need cli)
# C0103: Invalid name gnt-node
+import itertools
+
from ganeti.cli import *
from ganeti import cli
from ganeti import bootstrap
@@ -263,47 +265,66 @@ def EvacuateNode(opts, args):
@return: the desired exit code
"""
+ if opts.dst_node is not None:
+ ToStderr("New secondary node given (disabling iallocator), hence
evacuating"
+ " secondary instances only.")
+ opts.secondary_only = True
+ opts.primary_only = False
+
+ if opts.secondary_only and opts.primary_only:
+ raise errors.OpPrereqError("Only one of the --primary-only and"
+ " --secondary-only options can be passed",
+ errors.ECODE_INVAL)
+
cl = GetClient()
- force = opts.force
- dst_node = opts.dst_node
- iallocator = opts.iallocator
+ # Determine affected instances
+ fields = []
- op = opcodes.OpNodeEvacStrategy(nodes=args,
- iallocator=iallocator,
- remote_node=dst_node)
+ if not opts.secondary_only:
+ fields.append("pinst_list")
+ if not opts.primary_only:
+ fields.append("sinst_list")
- result = SubmitOpCode(op, cl=cl, opts=opts)
- if not result:
- # no instances to migrate
- ToStderr("No secondary instances on node(s) %s, exiting.",
+ result = cl.QueryNodes(names=args, fields=fields, use_locking=False)
+ instances = set(itertools.chain(*itertools.chain(*itertools.chain(result))))
+
+ if not instances:
+ # No instances to evacuate
+ ToStderr("No instances to evacuate on node(s) %s, exiting.",
utils.CommaJoin(args))
return constants.EXIT_SUCCESS
- if not force and not AskUser("Relocate instance(s) %s from node(s) %s?" %
- (",".join("'%s'" % name[0] for name in result),
- utils.CommaJoin(args))):
+ if not (opts.force or
+ AskUser("Relocate instance(s) %s from node(s) %s?" %
+ (utils.CommaJoin(utils.NiceSort(instances)),
+ utils.CommaJoin(args)))):
return constants.EXIT_CONFIRMATION
+ # Evacuate node
+ op = opcodes.OpNodeEvacuate(nodes=args,
+ remote_node=opts.dst_node,
+ iallocator=opts.iallocator,
+ primary=not opts.secondary_only,
+ secondary=not opts.primary_only,
+ early_release=opts.early_release)
+ result = SubmitOpCode(op, cl=cl, opts=opts)
+
+ # Keep track of submitted jobs
jex = JobExecutor(cl=cl, opts=opts)
- for row in result:
- iname = row[0]
- node = row[1]
- ToStdout("Will relocate instance %s to node %s", iname, node)
- op = opcodes.OpInstanceReplaceDisks(instance_name=iname,
- remote_node=node, disks=[],
- mode=constants.REPLACE_DISK_CHG,
- early_release=opts.early_release)
- jex.QueueJob(iname, op)
+
+ for (status, job_id) in result[constants.JOB_IDS_KEY]:
+ jex.AddJobId(None, status, job_id)
+
results = jex.GetResults()
bad_cnt = len([row for row in results if not row[0]])
if bad_cnt == 0:
- ToStdout("All %d instance(s) failed over successfully.", len(results))
+ ToStdout("All instances evacuated successfully.")
rcode = constants.EXIT_SUCCESS
else:
- ToStdout("There were errors during the failover:\n"
- "%d error(s) out of %d instance(s).", bad_cnt, len(results))
+ ToStdout("There were %s errors during the evacuation.", bad_cnt)
rcode = constants.EXIT_FAILURE
+
return rcode
@@ -838,7 +859,7 @@ commands = {
'evacuate': (
EvacuateNode, [ArgNode(min=1)],
[FORCE_OPT, IALLOCATOR_OPT, NEW_SECONDARY_OPT, EARLY_RELEASE_OPT,
- PRIORITY_OPT],
+ PRIORITY_OPT, PRIMARY_ONLY_OPT, SECONDARY_ONLY_OPT],
"[-f] {-I <iallocator> | -n <dst>} <node>",
"Relocate the secondary instances from a node"
" to other nodes (only for instances with drbd disk template)"),
diff --git a/man/gnt-node.rst b/man/gnt-node.rst
index aa3a9f5..86683e9 100644
--- a/man/gnt-node.rst
+++ b/man/gnt-node.rst
@@ -87,10 +87,14 @@ EVACUATE
~~~~~~~~
**evacuate** [-f] [--early-release] [--iallocator *NAME* \|
---new-secondary *destination\_node*] {*node*...}
+--new-secondary *destination\_node*]
+[--primary-only \| --secondary-only] [--early-release] {*node*...}
-This command will move all secondary instances away from the given
-node(s). It works only for instances having a drbd disk template.
+This command will move instances away from the given node(s). If
+``--primary-only`` is given, only primary instances are evacuated, with
+``--secondary-only`` only secondaries. If neither is given, all
+instances are evacuated. It works only for instances having a drbd disk
+template.
The new location for the instances can be specified in two ways:
@@ -101,7 +105,6 @@ The new location for the instances can be specified in two
ways:
parameter, so each instance will be in turn placed on the (per the
script) optimal node
-
The ``--early-release`` changes the code so that the old storage on
node being evacuated is removed early (before the resync is
completed) and the internal Ganeti locks are also released for both
--
1.7.3.5