You are viewing a plain text version of this content. The canonical link for it is here.
Posted to common-commits@hadoop.apache.org by aa...@apache.org on 2020/01/21 01:59:37 UTC

[hadoop] branch trunk updated: HADOOP-16753. Refactor HAAdmin. Contributed by Xieming Li.

This is an automated email from the ASF dual-hosted git repository.

aajisaka pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/hadoop.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 1defe3a  HADOOP-16753. Refactor HAAdmin. Contributed by Xieming Li.
1defe3a is described below

commit 1defe3a65af5faf5117978f4f2cf6a24d17a2e76
Author: Akira Ajisaka <aa...@apache.org>
AuthorDate: Tue Jan 21 10:58:32 2020 +0900

    HADOOP-16753. Refactor HAAdmin. Contributed by Xieming Li.
---
 .../main/java/org/apache/hadoop/ha/HAAdmin.java    | 258 +++++++--------------
 .../java/org/apache/hadoop/ha/TestHAAdmin.java     |   5 -
 .../org/apache/hadoop/hdfs/tools/DFSHAAdmin.java   | 216 ++++++++++++++++-
 .../apache/hadoop/yarn/client/cli/RMAdminCLI.java  |  16 +-
 4 files changed, 296 insertions(+), 199 deletions(-)

diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/ha/HAAdmin.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/ha/HAAdmin.java
index 0693dce..0950ea7 100644
--- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/ha/HAAdmin.java
+++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/ha/HAAdmin.java
@@ -39,7 +39,6 @@ import org.apache.hadoop.ha.HAServiceProtocol.RequestSource;
 import org.apache.hadoop.util.Tool;
 import org.apache.hadoop.util.ToolRunner;
 
-import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableMap;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -52,16 +51,15 @@ import org.slf4j.LoggerFactory;
 @InterfaceAudience.Private
 
 public abstract class HAAdmin extends Configured implements Tool {
-  
-  private static final String FORCEFENCE  = "forcefence";
-  private static final String FORCEACTIVE = "forceactive";
-  
+
+  protected static final String FORCEACTIVE = "forceactive";
+
   /**
    * Undocumented flag which allows an administrator to use manual failover
    * state transitions even when auto-failover is enabled. This is an unsafe
    * operation, which is why it is not documented in the usage below.
    */
-  private static final String FORCEMANUAL = "forcemanual";
+  protected static final String FORCEMANUAL = "forcemanual";
   private static final Logger LOG = LoggerFactory.getLogger(HAAdmin.class);
 
   private int rpcTimeoutForChecks = -1;
@@ -72,15 +70,6 @@ public abstract class HAAdmin extends Configured implements Tool {
         new UsageInfo("[--"+FORCEACTIVE+"] <serviceId>", "Transitions the service into Active state"))
     .put("-transitionToStandby",
         new UsageInfo("<serviceId>", "Transitions the service into Standby state"))
-      .put("-transitionToObserver",
-          new UsageInfo("<serviceId>",
-              "Transitions the service into Observer state"))
-    .put("-failover",
-        new UsageInfo("[--"+FORCEFENCE+"] [--"+FORCEACTIVE+"] <serviceId> <serviceId>",
-            "Failover from the first service to the second.\n" +
-            "Unconditionally fence services if the --"+FORCEFENCE+" option is used.\n" +
-            "Try to failover to the target service even if it is not ready if the " + 
-            "--" + FORCEACTIVE + " option is used."))
     .put("-getServiceState",
         new UsageInfo("<serviceId>", "Returns the state of the service"))
       .put("-getAllServiceState",
@@ -99,6 +88,14 @@ public abstract class HAAdmin extends Configured implements Tool {
   protected PrintStream out = System.out;
   private RequestSource requestSource = RequestSource.REQUEST_BY_USER;
 
+  protected RequestSource getRequestSource() {
+    return requestSource;
+  }
+
+  protected void setRequestSource(RequestSource requestSource) {
+    this.requestSource = requestSource;
+  }
+
   protected HAAdmin() {
     super();
   }
@@ -118,34 +115,44 @@ public abstract class HAAdmin extends Configured implements Tool {
     return "Usage: HAAdmin";
   }
 
-  protected void printUsage(PrintStream errOut) {
-    errOut.println(getUsageString());
-    for (Map.Entry<String, UsageInfo> e : USAGE.entrySet()) {
+  protected void printUsage(PrintStream pStr,
+      Map<String, UsageInfo> helpEntries) {
+    pStr.println(getUsageString());
+    for (Map.Entry<String, UsageInfo> e : helpEntries.entrySet()) {
       String cmd = e.getKey();
       UsageInfo usage = e.getValue();
-      
+
       if (usage.args == null) {
-        errOut.println("    [" + cmd + "]");
+        pStr.println("    [" + cmd + "]");
       } else {
-        errOut.println("    [" + cmd + " " + usage.args + "]");
+        pStr.println("    [" + cmd + " " + usage.args + "]");
       }
     }
-    errOut.println();
-    ToolRunner.printGenericCommandUsage(errOut);    
+    pStr.println();
+    ToolRunner.printGenericCommandUsage(pStr);
   }
-  
-  private void printUsage(PrintStream errOut, String cmd) {
-    UsageInfo usage = USAGE.get(cmd);
+
+  protected void printUsage(PrintStream pStr) {
+    printUsage(pStr, USAGE);
+  }
+
+  protected void printUsage(PrintStream pStr, String cmd,
+      Map<String, UsageInfo> helpEntries) {
+    UsageInfo usage = helpEntries.get(cmd);
     if (usage == null) {
       throw new RuntimeException("No usage for cmd " + cmd);
     }
     if (usage.args == null) {
-      errOut.println(getUsageString() + " [" + cmd + "]");
+      pStr.println(getUsageString() + " [" + cmd + "]");
     } else {
-      errOut.println(getUsageString() + " [" + cmd + " " + usage.args + "]");
+      pStr.println(getUsageString() + " [" + cmd + " " + usage.args + "]");
     }
   }
 
+  protected void printUsage(PrintStream pStr, String cmd) {
+    printUsage(pStr, cmd, USAGE);
+  }
+
   private int transitionToActive(final CommandLine cmd)
       throws IOException, ServiceFailedException {
     String[] argv = cmd.getArgs();
@@ -225,27 +232,6 @@ public abstract class HAAdmin extends Configured implements Tool {
     return 0;
   }
 
-  private int transitionToObserver(final CommandLine cmd)
-      throws IOException, ServiceFailedException {
-    String[] argv = cmd.getArgs();
-    if (argv.length != 1) {
-      errOut.println("transitionToObserver: incorrect number of arguments");
-      printUsage(errOut, "-transitionToObserver");
-      return -1;
-    }
-
-    HAServiceTarget target = resolveTarget(argv[0]);
-    if (!checkSupportObserver(target)) {
-      return -1;
-    }
-    if (!checkManualStateManagementOK(target)) {
-      return -1;
-    }
-    HAServiceProtocol proto = target.getProxy(getConf(), 0);
-    HAServiceProtocolHelper.transitionToObserver(proto, createReqInfo());
-    return 0;
-  }
-
   /**
    * Ensure that we are allowed to manually manage the HA state of the target
    * service. If automatic failover is configured, then the automatic
@@ -255,7 +241,7 @@ public abstract class HAAdmin extends Configured implements Tool {
    * @param target the target to check
    * @return true if manual state management is allowed
    */
-  private boolean checkManualStateManagementOK(HAServiceTarget target) {
+  protected boolean checkManualStateManagementOK(HAServiceTarget target) {
     if (target.isAutoFailoverEnabled()) {
       if (requestSource != RequestSource.REQUEST_BY_USER_FORCED) {
         errOut.println(
@@ -274,93 +260,19 @@ public abstract class HAAdmin extends Configured implements Tool {
     return true;
   }
 
-  /**
-   * Check if the target supports the Observer state.
-   * @param target the target to check
-   * @return true if the target support Observer state, false otherwise.
-   */
-  private boolean checkSupportObserver(HAServiceTarget target) {
-    if (target.supportObserver()) {
-      return true;
-    } else {
-      errOut.println(
-          "The target " + target + " doesn't support Observer state.");
-      return false;
-    }
-  }
-
-  private StateChangeRequestInfo createReqInfo() {
+  protected StateChangeRequestInfo createReqInfo() {
     return new StateChangeRequestInfo(requestSource);
   }
 
-  private int failover(CommandLine cmd)
-      throws IOException, ServiceFailedException {
-    boolean forceFence = cmd.hasOption(FORCEFENCE);
-    boolean forceActive = cmd.hasOption(FORCEACTIVE);
-
-    int numOpts = cmd.getOptions() == null ? 0 : cmd.getOptions().length;
-    final String[] args = cmd.getArgs();
-
-    if (numOpts > 3 || args.length != 2) {
-      errOut.println("failover: incorrect arguments");
-      printUsage(errOut, "-failover");
-      return -1;
-    }
-
-    HAServiceTarget fromNode = resolveTarget(args[0]);
-    HAServiceTarget toNode = resolveTarget(args[1]);
-    
-    // Check that auto-failover is consistently configured for both nodes.
-    Preconditions.checkState(
-        fromNode.isAutoFailoverEnabled() ==
-          toNode.isAutoFailoverEnabled(),
-          "Inconsistent auto-failover configs between %s and %s!",
-          fromNode, toNode);
-    
-    if (fromNode.isAutoFailoverEnabled()) {
-      if (forceFence || forceActive) {
-        // -forceActive doesn't make sense with auto-HA, since, if the node
-        // is not healthy, then its ZKFC will immediately quit the election
-        // again the next time a health check runs.
-        //
-        // -forceFence doesn't seem to have any real use cases with auto-HA
-        // so it isn't implemented.
-        errOut.println(FORCEFENCE + " and " + FORCEACTIVE + " flags not " +
-            "supported with auto-failover enabled.");
-        return -1;
-      }
-      try {
-        return gracefulFailoverThroughZKFCs(toNode);
-      } catch (UnsupportedOperationException e){
-        errOut.println("Failover command is not supported with " +
-            "auto-failover enabled: " + e.getLocalizedMessage());
-        return -1;
-      }
-    }
-    
-    FailoverController fc = new FailoverController(getConf(),
-        requestSource);
-    
-    try {
-      fc.failover(fromNode, toNode, forceFence, forceActive); 
-      out.println("Failover from "+args[0]+" to "+args[1]+" successful");
-    } catch (FailoverFailedException ffe) {
-      errOut.println("Failover failed: " + ffe.getLocalizedMessage());
-      return -1;
-    }
-    return 0;
-  }
-  
-
   /**
    * Initiate a graceful failover by talking to the target node's ZKFC.
    * This sends an RPC to the ZKFC, which coordinates the failover.
-   * 
+   *
    * @param toNode the node to fail to
    * @return status code (0 for success)
    * @throws IOException if failover does not succeed
    */
-  private int gracefulFailoverThroughZKFCs(HAServiceTarget toNode)
+  protected int gracefulFailoverThroughZKFCs(HAServiceTarget toNode)
       throws IOException {
 
     int timeout = FailoverController.getRpcTimeoutToNewActive(getConf());
@@ -443,45 +355,52 @@ public abstract class HAAdmin extends Configured implements Tool {
       return -1;
     }
   }
-  
-  protected int runCmd(String[] argv) throws Exception {
+
+  protected boolean checkParameterValidity(String[] argv,
+      Map<String, UsageInfo> helpEntries){
+
     if (argv.length < 1) {
-      printUsage(errOut);
-      return -1;
+      printUsage(errOut, helpEntries);
+      return false;
     }
 
     String cmd = argv[0];
-
     if (!cmd.startsWith("-")) {
-      errOut.println("Bad command '" + cmd + "': expected command starting with '-'");
-      printUsage(errOut);
-      return -1;
+      errOut.println("Bad command '" + cmd +
+          "': expected command starting with '-'");
+      printUsage(errOut, helpEntries);
+      return false;
     }
-    
-    if (!USAGE.containsKey(cmd)) {
+
+    if (!helpEntries.containsKey(cmd)) {
       errOut.println(cmd.substring(1) + ": Unknown command");
-      printUsage(errOut);
+      printUsage(errOut, helpEntries);
+      return false;
+    }
+    return true;
+  }
+
+  protected boolean checkParameterValidity(String[] argv){
+    return checkParameterValidity(argv, USAGE);
+  }
+
+  protected int runCmd(String[] argv) throws Exception {
+    if (!checkParameterValidity(argv, USAGE)){
       return -1;
     }
-    
-    Options opts = new Options();
 
+    String cmd = argv[0];
+    Options opts = new Options();
     // Add command-specific options
-    if ("-failover".equals(cmd)) {
-      addFailoverCliOpts(opts);
-    }
     if("-transitionToActive".equals(cmd)) {
       addTransitionToActiveCliOpts(opts);
     }
     // Mutative commands take FORCEMANUAL option
     if ("-transitionToActive".equals(cmd) ||
-        "-transitionToStandby".equals(cmd) ||
-        "-transitionToObserver".equals(cmd) ||
-        "-failover".equals(cmd)) {
+        "-transitionToStandby".equals(cmd)) {
       opts.addOption(FORCEMANUAL, false,
           "force manual control even if auto-failover is enabled");
     }
-         
     CommandLine cmdLine = parseOpts(cmd, opts, argv);
     if (cmdLine == null) {
       // error already printed
@@ -502,10 +421,6 @@ public abstract class HAAdmin extends Configured implements Tool {
       return transitionToActive(cmdLine);
     } else if ("-transitionToStandby".equals(cmd)) {
       return transitionToStandby(cmdLine);
-    } else if ("-transitionToObserver".equals(cmd)) {
-      return transitionToObserver(cmdLine);
-    } else if ("-failover".equals(cmd)) {
-      return failover(cmdLine);
     } else if ("-getServiceState".equals(cmd)) {
       return getServiceState(cmdLine);
     } else if ("-getAllServiceState".equals(cmd)) {
@@ -544,7 +459,7 @@ public abstract class HAAdmin extends Configured implements Tool {
     return 0;
   }
 
-  private boolean confirmForceManual() throws IOException {
+  protected boolean confirmForceManual() throws IOException {
      return ToolRunner.confirmPrompt(
         "You have specified the --" + FORCEMANUAL + " flag. This flag is " +
         "dangerous, as it can induce a split-brain scenario that WILL " +
@@ -559,16 +474,7 @@ public abstract class HAAdmin extends Configured implements Tool {
         "Are you sure you want to continue?");
   }
 
-  /**
-   * Add CLI options which are specific to the failover command and no
-   * others.
-   */
-  private void addFailoverCliOpts(Options failoverOpts) {
-    failoverOpts.addOption(FORCEFENCE, false, "force fencing");
-    failoverOpts.addOption(FORCEACTIVE, false, "force failover");
-    // Don't add FORCEMANUAL, since that's added separately for all commands
-    // that change state.
-  }
+
   
   /**
    * Add CLI options which are specific to the transitionToActive command and
@@ -577,39 +483,47 @@ public abstract class HAAdmin extends Configured implements Tool {
   private void addTransitionToActiveCliOpts(Options transitionToActiveCliOpts) {
     transitionToActiveCliOpts.addOption(FORCEACTIVE, false, "force active");
   }
-  
-  private CommandLine parseOpts(String cmdName, Options opts, String[] argv) {
+
+  protected CommandLine parseOpts(String cmdName, Options opts, String[] argv,
+      Map<String, UsageInfo> helpEntries) {
     try {
       // Strip off the first arg, since that's just the command name
-      argv = Arrays.copyOfRange(argv, 1, argv.length); 
+      argv = Arrays.copyOfRange(argv, 1, argv.length);
       return new GnuParser().parse(opts, argv);
     } catch (ParseException pe) {
       errOut.println(cmdName.substring(1) +
           ": incorrect arguments");
-      printUsage(errOut, cmdName);
+      printUsage(errOut, cmdName, helpEntries);
       return null;
     }
   }
   
-  private int help(String[] argv) {
+  protected CommandLine parseOpts(String cmdName, Options opts, String[] argv) {
+    return parseOpts(cmdName, opts, argv, USAGE);
+  }
+  protected int help(String[] argv) {
+    return help(argv, USAGE);
+  }
+
+  protected int help(String[] argv, Map<String, UsageInfo> helpEntries) {
     if (argv.length == 1) { // only -help
-      printUsage(out);
+      printUsage(out, helpEntries);
       return 0;
     } else if (argv.length != 2) {
-      printUsage(errOut, "-help");
+      printUsage(errOut, "-help", helpEntries);
       return -1;
     }
     String cmd = argv[1];
     if (!cmd.startsWith("-")) {
       cmd = "-" + cmd;
     }
-    UsageInfo usageInfo = USAGE.get(cmd);
+    UsageInfo usageInfo = helpEntries.get(cmd);
     if (usageInfo == null) {
       errOut.println(cmd + ": Unknown command");
-      printUsage(errOut);
+      printUsage(errOut, helpEntries);
       return -1;
     }
-    
+
     if (usageInfo.args == null) {
       out.println(cmd + ": " + usageInfo.help);
     } else {
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ha/TestHAAdmin.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ha/TestHAAdmin.java
index 0e59aa1..63b9c63 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ha/TestHAAdmin.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ha/TestHAAdmin.java
@@ -83,11 +83,6 @@ public class TestHAAdmin {
     assertOutputContains("transitionToActive: incorrect number of arguments");
     assertEquals(-1, runTool("-transitionToActive", "x", "y"));
     assertOutputContains("transitionToActive: incorrect number of arguments");
-    assertEquals(-1, runTool("-failover"));
-    assertOutputContains("failover: incorrect arguments");
-    assertOutputContains("failover: incorrect arguments");    
-    assertEquals(-1, runTool("-failover", "foo:1234"));
-    assertOutputContains("failover: incorrect arguments");
   }
 
   @Test
diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/tools/DFSHAAdmin.java b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/tools/DFSHAAdmin.java
index 71a66d4..fcfb47c 100644
--- a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/tools/DFSHAAdmin.java
+++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/tools/DFSHAAdmin.java
@@ -17,15 +17,28 @@
  */
 package org.apache.hadoop.hdfs.tools;
 
+import java.io.IOException;
 import java.io.PrintStream;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Map;
 
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSortedMap;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Options;
+import org.apache.hadoop.ha.FailoverController;
+import org.apache.hadoop.ha.FailoverFailedException;
+import org.apache.hadoop.ha.HAServiceProtocol;
+import org.apache.hadoop.ha.HAServiceProtocolHelper;
+import org.apache.hadoop.ha.ServiceFailedException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.fs.CommonConfigurationKeys;
 import org.apache.hadoop.ha.HAAdmin;
+import org.apache.hadoop.ha.HAServiceProtocol.RequestSource;
 import org.apache.hadoop.ha.HAServiceTarget;
 import org.apache.hadoop.hdfs.DFSConfigKeys;
 import org.apache.hadoop.hdfs.DFSUtil;
@@ -38,9 +51,29 @@ import org.apache.hadoop.util.ToolRunner;
  */
 public class DFSHAAdmin extends HAAdmin {
 
+  private static final String FORCEFENCE  = "forcefence";
   private static final Logger LOG = LoggerFactory.getLogger(DFSHAAdmin.class);
 
   private String nameserviceId;
+  private final static Map<String, UsageInfo> USAGE_DFS_ONLY =
+      ImmutableMap.<String, UsageInfo> builder()
+          .put("-transitionToObserver", new UsageInfo("<serviceId>",
+                  "Transitions the service into Observer state"))
+          .put("-failover", new UsageInfo(
+              "[--"+FORCEFENCE+"] [--"+FORCEACTIVE+"] "
+                  + "<serviceId> <serviceId>",
+              "Failover from the first service to the second.\n"
+                  + "Unconditionally fence services if the --" + FORCEFENCE
+                  + " option is used.\n"
+                  + "Try to failover to the target service "
+                  + "even if it is not ready if the "
+                  + "--" + FORCEACTIVE + " option is used.")).build();
+
+  private final static Map<String, UsageInfo> USAGE_DFS_MERGED =
+      ImmutableSortedMap.<String, UsageInfo> naturalOrder()
+          .putAll(USAGE)
+          .putAll(USAGE_DFS_ONLY)
+          .build();
 
   protected void setErrOut(PrintStream errOut) {
     this.errOut = errOut;
@@ -93,44 +126,205 @@ public class DFSHAAdmin extends HAAdmin {
     return "Usage: haadmin [-ns <nameserviceId>]";
   }
 
+  /**
+   * Add CLI options which are specific to the failover command and no
+   * others.
+   */
+  private void addFailoverCliOpts(Options failoverOpts) {
+    failoverOpts.addOption(FORCEFENCE, false, "force fencing");
+    failoverOpts.addOption(FORCEACTIVE, false, "force failover");
+    // Don't add FORCEMANUAL, since that's added separately for all commands
+    // that change state.
+  }
+  @Override
+  protected boolean checkParameterValidity(String[] argv){
+    return  checkParameterValidity(argv, USAGE_DFS_MERGED);
+  }
+
   @Override
   protected int runCmd(String[] argv) throws Exception {
-    if (argv.length < 1) {
-      printUsage(errOut);
+
+    if(argv.length < 1){
+      printUsage(errOut, USAGE_DFS_MERGED);
       return -1;
     }
 
     int i = 0;
     String cmd = argv[i++];
-
+    //Process "-ns" Option
     if ("-ns".equals(cmd)) {
       if (i == argv.length) {
         errOut.println("Missing nameservice ID");
-        printUsage(errOut);
+        printUsage(errOut, USAGE_DFS_MERGED);
         return -1;
       }
       nameserviceId = argv[i++];
       if (i >= argv.length) {
         errOut.println("Missing command");
-        printUsage(errOut);
+        printUsage(errOut, USAGE_DFS_MERGED);
         return -1;
       }
       argv = Arrays.copyOfRange(argv, i, argv.length);
+      cmd = argv[0];
+    }
+
+    if (!checkParameterValidity(argv)){
+      return -1;
+    }
+
+    /*
+       "-help" command has to to be handled here because it should
+       be supported both by HAAdmin and DFSHAAdmin but it is contained in
+       USAGE_DFS_ONLY
+    */
+    if ("-help".equals(cmd)){
+      return help(argv, USAGE_DFS_MERGED);
+    }
+
+    if (!USAGE_DFS_ONLY.containsKey(cmd)) {
+      return super.runCmd(argv);
+    }
+
+    Options opts = new Options();
+    // Add command-specific options
+    if ("-failover".equals(cmd)) {
+      addFailoverCliOpts(opts);
+    }
+    // Mutative commands take FORCEMANUAL option
+    if ("-transitionToObserver".equals(cmd) ||
+        "-failover".equals(cmd)) {
+      opts.addOption(FORCEMANUAL, false,
+          "force manual control even if auto-failover is enabled");
+    }
+    CommandLine cmdLine = parseOpts(cmd, opts, argv, USAGE_DFS_MERGED);
+    if (cmdLine == null) {
+      return -1;
     }
 
-    return super.runCmd(argv);
+    if (cmdLine.hasOption(FORCEMANUAL)) {
+      if (!confirmForceManual()) {
+        LOG.error("Aborted");
+        return -1;
+      }
+      // Instruct the NNs to honor this request even if they're
+      // configured for manual failover.
+      setRequestSource(RequestSource.REQUEST_BY_USER_FORCED);
+    }
+
+    if ("-transitionToObserver".equals(cmd)) {
+      return transitionToObserver(cmdLine);
+    } else if ("-failover".equals(cmd)) {
+      return failover(cmdLine);
+    } else {
+      // This line should not be reached
+      throw new AssertionError("Should not get here, command: " + cmd);
+    }
   }
   
   /**
-   * returns the list of all namenode ids for the given configuration 
+   * returns the list of all namenode ids for the given configuration.
    */
   @Override
   protected Collection<String> getTargetIds(String namenodeToActivate) {
-    return DFSUtilClient.getNameNodeIds(getConf(),
-                                        (nameserviceId != null) ? nameserviceId : DFSUtil.getNamenodeNameServiceId(
-                                            getConf()));
+    return DFSUtilClient.getNameNodeIds(
+        getConf(), (nameserviceId != null)?
+            nameserviceId : DFSUtil.getNamenodeNameServiceId(getConf()));
   }
-  
+
+  /**
+   * Check if the target supports the Observer state.
+   * @param target the target to check
+   * @return true if the target support Observer state, false otherwise.
+   */
+  private boolean checkSupportObserver(HAServiceTarget target) {
+    if (target.supportObserver()) {
+      return true;
+    } else {
+      errOut.println(
+          "The target " + target + " doesn't support Observer state.");
+      return false;
+    }
+  }
+
+  private int transitionToObserver(final CommandLine cmd)
+      throws IOException, ServiceFailedException {
+    String[] argv = cmd.getArgs();
+    if (argv.length != 1) {
+      errOut.println("transitionToObserver: incorrect number of arguments");
+      printUsage(errOut, "-transitionToObserver", USAGE_DFS_MERGED);
+      return -1;
+    }
+
+    HAServiceTarget target = resolveTarget(argv[0]);
+    if (!checkSupportObserver(target)) {
+      return -1;
+    }
+    if (!checkManualStateManagementOK(target)) {
+      return -1;
+    }
+    HAServiceProtocol proto = target.getProxy(getConf(), 0);
+    HAServiceProtocolHelper.transitionToObserver(proto, createReqInfo());
+    return 0;
+  }
+
+  private int failover(CommandLine cmd)
+      throws IOException, ServiceFailedException {
+    boolean forceFence = cmd.hasOption(FORCEFENCE);
+    boolean forceActive = cmd.hasOption(FORCEACTIVE);
+
+    int numOpts = cmd.getOptions() == null ? 0 : cmd.getOptions().length;
+    final String[] args = cmd.getArgs();
+
+    if (numOpts > 3 || args.length != 2) {
+      errOut.println("failover: incorrect arguments");
+      printUsage(errOut, "-failover", USAGE_DFS_MERGED);
+      return -1;
+    }
+
+    HAServiceTarget fromNode = resolveTarget(args[0]);
+    HAServiceTarget toNode = resolveTarget(args[1]);
+
+    // Check that auto-failover is consistently configured for both nodes.
+    Preconditions.checkState(
+        fromNode.isAutoFailoverEnabled() ==
+            toNode.isAutoFailoverEnabled(),
+        "Inconsistent auto-failover configs between %s and %s!",
+        fromNode, toNode);
+
+    if (fromNode.isAutoFailoverEnabled()) {
+      if (forceFence || forceActive) {
+        // -forceActive doesn't make sense with auto-HA, since, if the node
+        // is not healthy, then its ZKFC will immediately quit the election
+        // again the next time a health check runs.
+        //
+        // -forceFence doesn't seem to have any real use cases with auto-HA
+        // so it isn't implemented.
+        errOut.println(FORCEFENCE + " and " + FORCEACTIVE + " flags not " +
+            "supported with auto-failover enabled.");
+        return -1;
+      }
+      try {
+        return gracefulFailoverThroughZKFCs(toNode);
+      } catch (UnsupportedOperationException e){
+        errOut.println("Failover command is not supported with " +
+            "auto-failover enabled: " + e.getLocalizedMessage());
+        return -1;
+      }
+    }
+
+    FailoverController fc =
+        new FailoverController(getConf(), getRequestSource());
+
+    try {
+      fc.failover(fromNode, toNode, forceFence, forceActive);
+      out.println("Failover from "+args[0]+" to "+args[1]+" successful");
+    } catch (FailoverFailedException ffe) {
+      errOut.println("Failover failed: " + ffe.getLocalizedMessage());
+      return -1;
+    }
+    return 0;
+  }
+
   public static void main(String[] argv) throws Exception {
     int res = ToolRunner.run(new DFSHAAdmin(), argv);
     System.exit(res);
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/main/java/org/apache/hadoop/yarn/client/cli/RMAdminCLI.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/main/java/org/apache/hadoop/yarn/client/cli/RMAdminCLI.java
index 0e86046..489509b 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/main/java/org/apache/hadoop/yarn/client/cli/RMAdminCLI.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/main/java/org/apache/hadoop/yarn/client/cli/RMAdminCLI.java
@@ -186,9 +186,7 @@ public class RMAdminCLI extends HAAdmin {
 
   private static void appendHAUsage(final StringBuilder usageBuilder) {
     for (Map.Entry<String,UsageInfo> cmdEntry : USAGE.entrySet()) {
-      if (cmdEntry.getKey().equals("-help")
-          || cmdEntry.getKey().equals("-failover")
-          || cmdEntry.getKey().equals("-transitionToObserver")) {
+      if (cmdEntry.getKey().equals("-help")) {
         continue;
       }
       UsageInfo usageInfo = cmdEntry.getValue();
@@ -251,8 +249,7 @@ public class RMAdminCLI extends HAAdmin {
     if (isHAEnabled) {
       for (Map.Entry<String,UsageInfo> cmdEntry : USAGE.entrySet()) {
         String cmdKey = cmdEntry.getKey();
-        if (!cmdKey.equals("-help") && !cmdKey.equals("-failover")
-            && !cmdKey.equals("-transitionToObserver")) {
+        if (!cmdKey.equals("-help")) {
           UsageInfo usageInfo = cmdEntry.getValue();
           if (usageInfo.args == null) {
             builder.append("   " + cmdKey + "\n");
@@ -304,8 +301,7 @@ public class RMAdminCLI extends HAAdmin {
     }
     if (isHAEnabled) {
       for (String cmdKey : USAGE.keySet()) {
-        if (!cmdKey.equals("-help") && !cmdKey.equals("-failover")
-            && !cmdKey.equals("-transitionToObserver")) {
+        if (!cmdKey.equals("-help")) {
           buildHelpMsg(cmdKey, helpBuilder);
           helpBuilder.append("\n");
         }
@@ -324,8 +320,7 @@ public class RMAdminCLI extends HAAdmin {
    */
   private static void printUsage(String cmd, boolean isHAEnabled) {
     StringBuilder usageBuilder = new StringBuilder();
-    if (ADMIN_USAGE.containsKey(cmd) || USAGE.containsKey(cmd)
-        && (!cmd.equals("-failover") && !cmd.equals("-transitionToObserver"))) {
+    if (ADMIN_USAGE.containsKey(cmd) || USAGE.containsKey(cmd)) {
       buildIndividualUsageMsg(cmd, usageBuilder);
     } else {
       buildUsageMsg(usageBuilder, isHAEnabled);
@@ -732,8 +727,7 @@ public class RMAdminCLI extends HAAdmin {
       return exitCode;
     }
 
-    if (USAGE.containsKey(cmd) && !cmd.equals("-failover")
-        && !cmd.equals("-transitionToObserver")) {
+    if (USAGE.containsKey(cmd)) {
       if (isHAEnabled) {
         return super.run(args);
       }


---------------------------------------------------------------------
To unsubscribe, e-mail: common-commits-unsubscribe@hadoop.apache.org
For additional commands, e-mail: common-commits-help@hadoop.apache.org