diff --git a/man/gnt-node.sgml b/man/gnt-node.sgml index c1980f23d706d1cae307dd5bd2ef5bd423de15f1..9f1c8fbf265dcd52fb74bc76600d3be9e61e380e 100644 --- a/man/gnt-node.sgml +++ b/man/gnt-node.sgml @@ -148,12 +148,12 @@ <arg>--iallocator <replaceable>NAME</replaceable></arg> <arg>--new-secondary <replaceable>destination_node</replaceable></arg> </group> - <arg choice="req"><replaceable>node</replaceable></arg> + <arg choice="req" rep="repeat"><replaceable>node</replaceable></arg> </cmdsynopsis> <para> This command will move all secondary instances away from the - given node. It works only for instances having a drbd disk + given node(s). It works only for instances having a drbd disk template. </para> diff --git a/scripts/gnt-node b/scripts/gnt-node index 3e9b0b4c5c14016b698bbf390f1db55a10b91845..55d36bcdf5bdb83bcf33fa0c089474b668a6f9bb 100755 --- a/scripts/gnt-node +++ b/scripts/gnt-node @@ -255,41 +255,42 @@ def EvacuateNode(opts, args): raise errors.OpPrereqError("One and only one of the -n and -I" " options must be passed", errors.ECODE_INVAL) - selected_fields = ["name", "sinst_list"] - src_node = args[0] - - result = cl.QueryNodes(names=[src_node], fields=selected_fields, - use_locking=False) - src_node, sinst = result[0] - - if not sinst: - ToStderr("No secondary instances on node %s, exiting.", src_node) + op = opcodes.OpNodeEvacuationStrategy(nodes=args, + iallocator=iallocator, + remote_node=dst_node) + + result = SubmitOpCode(op, cl=cl, opts=opts) + if not result: + # no instances to migrate + ToStderr("No secondary instances on node(s) %s, exiting.", + utils.CommaJoin(args)) return constants.EXIT_SUCCESS - if dst_node is not None: - result = cl.QueryNodes(names=[dst_node], fields=["name"], - use_locking=False) - dst_node = result[0][0] - - if src_node == dst_node: - raise errors.OpPrereqError("Evacuate node needs different source and" - " target nodes (node %s given twice)" % - src_node, errors.ECODE_INVAL) - txt_msg = "to node %s" % dst_node - else: - txt_msg = "using iallocator %s" % iallocator - - sinst = utils.NiceSort(sinst) - - if not force and not AskUser("Relocate instance(s) %s from node\n" - " %s %s?" % - (",".join("'%s'" % name for name in sinst), - src_node, txt_msg)): + 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))): return constants.EXIT_CONFIRMATION - op = opcodes.OpEvacuateNode(node_name=args[0], remote_node=dst_node, - iallocator=iallocator) - SubmitOpCode(op, cl=cl, opts=opts) + 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.OpReplaceDisks(instance_name=iname, + remote_node=node, disks=[], + mode=constants.REPLACE_DISK_CHG, + early_release=opts.early_release) + jex.QueueJob(iname, op) + 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)) + 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)) + rcode = constants.EXIT_FAILURE + return rcode def FailoverNode(opts, args): @@ -653,8 +654,8 @@ commands = { "[-s ip] [--readd] [--no-ssh-key-check] <node_name>", "Add a node to the cluster"), 'evacuate': ( - EvacuateNode, ARGS_ONE_NODE, - [FORCE_OPT, IALLOCATOR_OPT, NEW_SECONDARY_OPT], + EvacuateNode, [ArgNode(min=1)], + [FORCE_OPT, IALLOCATOR_OPT, NEW_SECONDARY_OPT, EARLY_RELEASE_OPT], "[-f] {-I <iallocator> | -n <dst>} <node>", "Relocate the secondary instances from a node" " to other nodes (only for instances with drbd disk template)"),