diff --git a/man/gnt-node.sgml b/man/gnt-node.sgml index dfa75f7778dfafb9dbed4ef9c976079a374267a3..3bf31fde6bb86480f3450631aecbd532530d79ca 100644 --- a/man/gnt-node.sgml +++ b/man/gnt-node.sgml @@ -125,6 +125,37 @@ </para> </refsect2> + <refsect2> + <title>FAILOVER</title> + + <cmdsynopsis> + <command>failover</command> + <arg>-f</arg> + <arg>--ignore-consistency</arg> + <arg choice="req"><replaceable>node</replaceable></arg> + </cmdsynopsis> + + <para> + This command will fail over all instances having the given + node as primary to their secondary nodes. This works only for + instances having a remote raid disk layout. + </para> + + <para> + Normally the failover will check the consistency of the disks + before failing over the instance. If you are trying to migrate + instances off a dead node, this will fail. Use the + <option>--ignore-consistency</option> option for this purpose. + </para> + + <para> + Example: + <screen> + # gnt-node failover node1.example.com + </screen> + </para> + </refsect2> + <refsect2> <title>INFO</title> diff --git a/scripts/gnt-node b/scripts/gnt-node index a22c2d87a8d07b74c254e4dbea295ca7b3395fc9..8d4cfcbb017dbb08789f7a2f12e4a092c0f33b58 100755 --- a/scripts/gnt-node +++ b/scripts/gnt-node @@ -27,6 +27,7 @@ from ganeti import opcodes from ganeti import logger from ganeti import utils from ganeti import constants +from ganeti import errors def AddNode(opts, args): @@ -93,6 +94,53 @@ def ListNodes(opts, args): return 0 +def FailoverNode(opts, args): + """Failover all primary instance on a node. + + """ + force = opts.force + selected_fields = ["name", "pinst_list"] + + op = opcodes.OpQueryNodes(output_fields=selected_fields, names=args) + result = SubmitOpCode(op) + node, pinst = result[0] + + if not pinst: + logger.ToStderr("No primary instances on node %s, exiting." % node) + return 0 + + pinst = utils.NiceSort(pinst) + + retcode = 0 + + if not force and not AskUser("Fail over instance(s) %s?" % + (",".join("'%s'" % name for name in pinst))): + return 2 + + good_cnt = bad_cnt = 0 + for iname in pinst: + op = opcodes.OpFailoverInstance(instance_name=iname, + ignore_consistency=opts.ignore_consistency) + try: + logger.ToStdout("Failing over instance %s" % iname) + SubmitOpCode(op) + logger.ToStdout("Instance %s has been failed over" % iname) + good_cnt += 1 + except errors.GenericError, err: + nret, msg = FormatError(err) + retcode |= nret + logger.ToStderr("Error failing over instance %s: %s" % (iname, msg)) + bad_cnt += 1 + + if retcode == 0: + logger.ToStdout("All %d instance(s) failed over successfully." % good_cnt) + else: + logger.ToStdout("There were errors during the failover:\n" + "%d error(s) out of %d instance(s)." % + (bad_cnt, good_cnt + bad_cnt)) + return retcode + + def ShowNodeConfig(opts, args): """Show node information. @@ -172,6 +220,16 @@ commands = { help="Specify the secondary ip for the node", metavar="ADDRESS", default=None),], "<node_name>", "Add a node to the cluster"), + 'failover': (FailoverNode, ARGS_ONE, + [DEBUG_OPT, FORCE_OPT, + make_option("--ignore-consistency", dest="ignore_consistency", + action="store_true", default=False, + help="Ignore the consistency of the disks on" + " the secondary"), + ], + "[-f] <node>", + "Stops the primary instances on a node and start them on their" + " secondary node (only for instances of type remote_raid1)"), 'info': (ShowNodeConfig, ARGS_ANY, [DEBUG_OPT], "[<node_name>...]", "Show information about the node(s)"), 'list': (ListNodes, ARGS_NONE,