Bladeren bron

HADOOP-7961. Move HA fencing to common. Contributed by Eli Collins

git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/branches/HDFS-1623@1228510 13f79535-47bb-0310-9956-ffa450edef68
Eli Collins 13 jaren geleden
bovenliggende
commit
2d0b340c47

+ 4 - 0
hadoop-common-project/hadoop-common/pom.xml

@@ -264,6 +264,10 @@
       <artifactId>json-simple</artifactId>
       <scope>compile</scope>
     </dependency>
+    <dependency>
+      <groupId>com.jcraft</groupId>
+      <artifactId>jsch</artifactId>
+    </dependency>
   </dependencies>
 
   <build>

+ 0 - 0
hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/ha/BadFencingConfigurationException.java → hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/ha/BadFencingConfigurationException.java


+ 0 - 0
hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/ha/FenceMethod.java → hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/ha/FenceMethod.java


+ 0 - 0
hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/ha/NodeFencer.java → hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/ha/NodeFencer.java


+ 0 - 0
hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/ha/ShellCommandFencer.java → hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/ha/ShellCommandFencer.java


+ 15 - 30
hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/ha/SshFenceByTcpPort.java → hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/ha/SshFenceByTcpPort.java

@@ -27,7 +27,6 @@ import java.util.regex.Pattern;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.hadoop.conf.Configured;
-import org.apache.hadoop.hdfs.server.namenode.NameNode;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.jcraft.jsch.ChannelExec;
@@ -36,11 +35,11 @@ import com.jcraft.jsch.JSchException;
 import com.jcraft.jsch.Session;
 
 /**
- * This fencing implementation sshes to the target node and uses <code>fuser</code>
- * to kill the process listening on the NameNode's TCP port. This is
- * more accurate than using "jps" since it doesn't require parsing,
- * and will work even if there are multiple NameNodes running on the
- * same machine.<p>
+ * This fencing implementation sshes to the target node and uses 
+ * <code>fuser</code> to kill the process listening on the service's
+ * TCP port. This is more accurate than using "jps" since it doesn't 
+ * require parsing, and will work even if there are multiple service
+ * processes running on the same machine.<p>
  * It returns a successful status code if:
  * <ul>
  * <li><code>fuser</code> indicates it successfully killed a process, <em>or</em>
@@ -49,7 +48,7 @@ import com.jcraft.jsch.Session;
  * <p>
  * This fencing mechanism is configured as following in the fencing method
  * list:
- * <code>sshfence([username@]nnhost[:ssh-port][, target-nn-port])</code>
+ * <code>sshfence([username@]nnhost[:ssh-port], target-port)</code>
  * where the first argument specifies the username, host, and port to ssh
  * into, and the second argument specifies the port on which the target
  * NN process is listening on.
@@ -58,9 +57,6 @@ import com.jcraft.jsch.Session;
  * <code>other-nn<code> as the current user on the standard SSH port,
  * then kill whatever process is listening on port 8020.
  * <p>
- * If no <code>target-nn-port</code> is specified, it is assumed that the
- * target NameNode is listening on the same port as the local NameNode.
- * <p>
  * In order to achieve passwordless SSH, the operator must also configure
  * <code>dfs.namenode.ha.fencing.ssh.private-key-files<code> to point to an
  * SSH key that has passphrase-less access to the given username and host.
@@ -117,10 +113,8 @@ public class SshFenceByTcpPort extends Configured
     }
     LOG.info("Connected to " + args.host);
 
-    int targetPort = args.targetPort != null ?
-        args.targetPort : getDefaultNNPort();
     try {
-      return doFence(session, targetPort);
+      return doFence(session, args.targetPort);
     } catch (JSchException e) {
       LOG.warn("Unable to achieve fencing on remote host", e);
       return false;
@@ -142,14 +136,14 @@ public class SshFenceByTcpPort extends Configured
     return session;
   }
 
-  private boolean doFence(Session session, int nnPort) throws JSchException {
+  private boolean doFence(Session session, int port) throws JSchException {
     try {
-      LOG.info("Looking for process running on port " + nnPort);
+      LOG.info("Looking for process running on port " + port);
       int rc = execCommand(session,
-          "PATH=$PATH:/sbin:/usr/sbin fuser -v -k -n tcp " + nnPort);
+          "PATH=$PATH:/sbin:/usr/sbin fuser -v -k -n tcp " + port);
       if (rc == 0) {
         LOG.info("Successfully killed process that was " +
-            "listening on port " + nnPort);
+            "listening on port " + port);
         // exit code 0 indicates the process was successfully killed.
         return true;
       } else if (rc == 1) {
@@ -157,7 +151,7 @@ public class SshFenceByTcpPort extends Configured
         // or that fuser didn't have root privileges in order to find it
         // (eg running as a different user)
         LOG.info(
-            "Indeterminate response from trying to kill NameNode. " +
+            "Indeterminate response from trying to kill service. " +
             "Verifying whether it is running using nc...");
         rc = execCommand(session, "nc -z localhost 8020");
         if (rc == 0) {
@@ -234,10 +228,6 @@ public class SshFenceByTcpPort extends Configured
     return getConf().getTrimmedStringCollection(CONF_IDENTITIES_KEY);
   }
   
-  private int getDefaultNNPort() {
-    return NameNode.getAddress(getConf()).getPort();
-  }
-
   /**
    * Container for the parsed arg line for this fencing method.
    */
@@ -251,8 +241,7 @@ public class SshFenceByTcpPort extends Configured
     final String user;
     final String host;
     final int sshPort;
-    
-    final Integer targetPort;
+    final int targetPort;
     
     public Args(String args) throws BadFencingConfigurationException {
       if (args == null) {
@@ -260,7 +249,7 @@ public class SshFenceByTcpPort extends Configured
             "Must specify args for ssh fencing configuration");
       }
       String[] argList = args.split(",\\s*");
-      if (argList.length > 2 || argList.length == 0) {
+      if (argList.length != 2) {
         throw new BadFencingConfigurationException(
             "Incorrect number of arguments: " + args);
       }
@@ -287,11 +276,7 @@ public class SshFenceByTcpPort extends Configured
       }
       
       // Parse target port.
-      if (argList.length > 1) {
-        targetPort = parseConfiggedPort(argList[1]);
-      } else {
-        targetPort = null;
-      }
+      targetPort = parseConfiggedPort(argList[1]);
     }
 
     private Integer parseConfiggedPort(String portStr)

+ 0 - 0
hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/ha/StreamPumper.java → hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/ha/StreamPumper.java


+ 0 - 1
hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/ha/TestNodeFencer.java → hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ha/TestNodeFencer.java

@@ -23,7 +23,6 @@ import java.util.List;
 
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.conf.Configured;
-import org.apache.hadoop.test.GenericTestUtils;
 import org.junit.Before;
 import org.junit.Test;
 

+ 4 - 4
hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/ha/TestShellCommandFencer.java → hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ha/TestShellCommandFencer.java

@@ -20,7 +20,7 @@ package org.apache.hadoop.hdfs.server.namenode.ha;
 import static org.junit.Assert.*;
 
 import org.apache.hadoop.conf.Configuration;
-import org.apache.hadoop.test.GenericTestUtils;
+import org.apache.hadoop.util.StringUtils;
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -61,7 +61,6 @@ public class TestShellCommandFencer {
     assertFalse(fencer.tryFence("xxxxxxxxxxxx"));
   }
   
-  
   @Test
   public void testCheckArgs() {
     try {
@@ -70,8 +69,9 @@ public class TestShellCommandFencer {
       new NodeFencer(conf);
       fail("Didn't throw when passing no args to shell");
     } catch (BadFencingConfigurationException confe) {
-      GenericTestUtils.assertExceptionContains(
-          "No argument passed", confe);
+      assertTrue(
+        "Unexpected exception:" + StringUtils.stringifyException(confe),
+        confe.getMessage().contains("No argument passed"));    
     }
   }
   

+ 11 - 9
hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/ha/TestSshFenceByTcpPort.java → hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ha/TestSshFenceByTcpPort.java

@@ -61,37 +61,37 @@ public class TestSshFenceByTcpPort {
     SshFenceByTcpPort fence = new SshFenceByTcpPort();
     fence.setConf(conf);
     // Connect to Google's DNS server - not running ssh!
-    assertFalse(fence.tryFence("8.8.8.8"));
+    assertFalse(fence.tryFence("8.8.8.8, 1234"));
   }
   
   @Test
   public void testArgsParsing() throws BadFencingConfigurationException {
-    Args args = new SshFenceByTcpPort.Args("foo@bar.com:1234");
+    Args args = new SshFenceByTcpPort.Args("foo@bar.com:1234, 5678");
     assertEquals("foo", args.user);
     assertEquals("bar.com", args.host);
     assertEquals(1234, args.sshPort);
-    assertNull(args.targetPort);
+    assertEquals(5678, args.targetPort);
 
-    args = new SshFenceByTcpPort.Args("foo@bar.com");
+    args = new SshFenceByTcpPort.Args("foo@bar.com, 1234");
     assertEquals("foo", args.user);
     assertEquals("bar.com", args.host);
     assertEquals(22, args.sshPort);
-    assertNull(args.targetPort);
+    assertEquals(1234, args.targetPort);
     
-    args = new SshFenceByTcpPort.Args("bar.com");
+    args = new SshFenceByTcpPort.Args("bar.com, 1234");
     assertEquals(System.getProperty("user.name"), args.user);
     assertEquals("bar.com", args.host);
     assertEquals(22, args.sshPort);
-    assertNull(args.targetPort);
+    assertEquals(1234, args.targetPort);
     
     args = new SshFenceByTcpPort.Args("bar.com:1234, 12345");
     assertEquals(System.getProperty("user.name"), args.user);
     assertEquals("bar.com", args.host);
     assertEquals(1234, args.sshPort);
-    assertEquals(Integer.valueOf(12345), args.targetPort);
+    assertEquals(12345, args.targetPort);
     
     args = new SshFenceByTcpPort.Args("bar, 8020");
-    assertEquals(Integer.valueOf(8020), args.targetPort);    
+    assertEquals(8020, args.targetPort);    
   }
   
   @Test
@@ -101,6 +101,8 @@ public class TestSshFenceByTcpPort {
     assertBadArgs("bar.com:");
     assertBadArgs("bar.com:x");
     assertBadArgs("foo.com, x");
+    assertBadArgs("foo.com,");
+    assertBadArgs("foo.com, ");
   }
   
   private void assertBadArgs(String argStr) {

+ 0 - 4
hadoop-hdfs-project/hadoop-hdfs/pom.xml

@@ -109,10 +109,6 @@
       <artifactId>ant</artifactId>
       <scope>provided</scope>
     </dependency>
-    <dependency>
-      <groupId>com.jcraft</groupId>
-      <artifactId>jsch</artifactId>
-    </dependency>
   </dependencies>
 
   <build>