Return-Path: X-Original-To: apmail-hadoop-hdfs-commits-archive@minotaur.apache.org Delivered-To: apmail-hadoop-hdfs-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id EC44A118E9 for ; Tue, 24 Jun 2014 23:09:49 +0000 (UTC) Received: (qmail 48134 invoked by uid 500); 24 Jun 2014 23:09:49 -0000 Delivered-To: apmail-hadoop-hdfs-commits-archive@hadoop.apache.org Received: (qmail 48076 invoked by uid 500); 24 Jun 2014 23:09:49 -0000 Mailing-List: contact hdfs-commits-help@hadoop.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: hdfs-dev@hadoop.apache.org Delivered-To: mailing list hdfs-commits@hadoop.apache.org Received: (qmail 48064 invoked by uid 99); 24 Jun 2014 23:09:49 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 24 Jun 2014 23:09:49 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 24 Jun 2014 23:09:47 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 9757A23889D5; Tue, 24 Jun 2014 23:09:27 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1605218 - in /hadoop/common/branches/branch-2/hadoop-hdfs-project/hadoop-hdfs: ./ src/main/java/org/apache/hadoop/hdfs/web/resources/ src/test/java/org/apache/hadoop/hdfs/server/namenode/ha/ Date: Tue, 24 Jun 2014 23:09:27 -0000 To: hdfs-commits@hadoop.apache.org From: atm@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20140624230927.9757A23889D5@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: atm Date: Tue Jun 24 23:09:27 2014 New Revision: 1605218 URL: http://svn.apache.org/r1605218 Log: HDFS-6475. WebHdfs clients fail without retry because incorrect handling of StandbyException. Contributed by Yongjun Zhang. Modified: hadoop/common/branches/branch-2/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt hadoop/common/branches/branch-2/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/resources/ExceptionHandler.java hadoop/common/branches/branch-2/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/ha/TestDelegationTokensWithHA.java Modified: hadoop/common/branches/branch-2/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-2/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt?rev=1605218&r1=1605217&r2=1605218&view=diff ============================================================================== --- hadoop/common/branches/branch-2/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt (original) +++ hadoop/common/branches/branch-2/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt Tue Jun 24 23:09:27 2014 @@ -464,6 +464,9 @@ Release 2.5.0 - UNRELEASED HDFS-6598. Fix a typo in message issued from explorer.js. (Yongjun Zhang via wheat9) + HDFS-6475. WebHdfs clients fail without retry because incorrect handling + of StandbyException. (Yongjun Zhang via atm) + BREAKDOWN OF HDFS-2006 SUBTASKS AND RELATED JIRAS HDFS-6299. Protobuf for XAttr and client-side implementation. (Yi Liu via umamahesh) Modified: hadoop/common/branches/branch-2/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/resources/ExceptionHandler.java URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-2/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/resources/ExceptionHandler.java?rev=1605218&r1=1605217&r2=1605218&view=diff ============================================================================== --- hadoop/common/branches/branch-2/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/resources/ExceptionHandler.java (original) +++ hadoop/common/branches/branch-2/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/resources/ExceptionHandler.java Tue Jun 24 23:09:27 2014 @@ -31,8 +31,11 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.hdfs.web.JsonUtil; import org.apache.hadoop.ipc.RemoteException; +import org.apache.hadoop.ipc.StandbyException; import org.apache.hadoop.security.authorize.AuthorizationException; +import org.apache.hadoop.security.token.SecretManager.InvalidToken; +import com.google.common.annotations.VisibleForTesting; import com.sun.jersey.api.ParamException; import com.sun.jersey.api.container.ContainerException; @@ -42,9 +45,22 @@ public class ExceptionHandler implements public static final Log LOG = LogFactory.getLog(ExceptionHandler.class); private static Exception toCause(Exception e) { - final Throwable t = e.getCause(); - if (t != null && t instanceof Exception) { - e = (Exception)e.getCause(); + final Throwable t = e.getCause(); + if (e instanceof SecurityException) { + // For the issue reported in HDFS-6475, if SecurityException's cause + // is InvalidToken, and the InvalidToken's cause is StandbyException, + // return StandbyException; Otherwise, leave the exception as is, + // since they are handled elsewhere. See HDFS-6588. + if (t != null && t instanceof InvalidToken) { + final Throwable t1 = t.getCause(); + if (t1 != null && t1 instanceof StandbyException) { + e = (StandbyException)t1; + } + } + } else { + if (t != null && t instanceof Exception) { + e = (Exception)t; + } } return e; } @@ -74,6 +90,10 @@ public class ExceptionHandler implements e = ((RemoteException)e).unwrapRemoteException(); } + if (e instanceof SecurityException) { + e = toCause(e); + } + //Map response status final Response.Status s; if (e instanceof SecurityException) { @@ -96,4 +116,9 @@ public class ExceptionHandler implements final String js = JsonUtil.toJsonString(e); return Response.status(s).type(MediaType.APPLICATION_JSON).entity(js).build(); } + + @VisibleForTesting + public void initResponse(HttpServletResponse response) { + this.response = response; + } } Modified: hadoop/common/branches/branch-2/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/ha/TestDelegationTokensWithHA.java URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-2/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/ha/TestDelegationTokensWithHA.java?rev=1605218&r1=1605217&r2=1605218&view=diff ============================================================================== --- hadoop/common/branches/branch-2/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/ha/TestDelegationTokensWithHA.java (original) +++ hadoop/common/branches/branch-2/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/ha/TestDelegationTokensWithHA.java Tue Jun 24 23:09:27 2014 @@ -23,6 +23,7 @@ import static org.junit.Assert.assertNot import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; import java.io.ByteArrayInputStream; import java.io.DataInputStream; @@ -32,6 +33,10 @@ import java.net.URI; import java.security.PrivilegedExceptionAction; import java.util.Collection; import java.util.HashSet; +import java.util.Map; + +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.core.Response; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -51,7 +56,10 @@ import org.apache.hadoop.hdfs.security.t import org.apache.hadoop.hdfs.server.namenode.FSNamesystem; import org.apache.hadoop.hdfs.server.namenode.NameNode; import org.apache.hadoop.hdfs.server.namenode.NameNodeAdapter; +import org.apache.hadoop.hdfs.web.JsonUtil; +import org.apache.hadoop.hdfs.web.resources.ExceptionHandler; import org.apache.hadoop.io.Text; +import org.apache.hadoop.ipc.RemoteException; import org.apache.hadoop.ipc.RetriableException; import org.apache.hadoop.ipc.StandbyException; import org.apache.hadoop.security.SecurityUtil; @@ -64,6 +72,7 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.mockito.internal.util.reflection.Whitebox; +import org.mortbay.util.ajax.JSON; import com.google.common.base.Joiner; @@ -372,6 +381,90 @@ public class TestDelegationTokensWithHA token.cancel(conf); } + /** + * Test if StandbyException can be thrown from StandbyNN, when it's requested for + * password. (HDFS-6475). With StandbyException, the client can failover to try + * activeNN. + */ + @Test + public void testDelegationTokenStandbyNNAppearFirst() throws Exception { + // make nn0 the standby NN, and nn1 the active NN + cluster.transitionToStandby(0); + cluster.transitionToActive(1); + + final DelegationTokenSecretManager stSecretManager = + NameNodeAdapter.getDtSecretManager( + nn1.getNamesystem()); + + // create token + final Token token = + getDelegationToken(fs, "JobTracker"); + final DelegationTokenIdentifier identifier = new DelegationTokenIdentifier(); + byte[] tokenId = token.getIdentifier(); + identifier.readFields(new DataInputStream( + new ByteArrayInputStream(tokenId))); + + assertTrue(null != stSecretManager.retrievePassword(identifier)); + + final UserGroupInformation ugi = UserGroupInformation + .createRemoteUser("JobTracker"); + ugi.addToken(token); + + ugi.doAs(new PrivilegedExceptionAction() { + @Override + public Object run() { + try { + try { + byte[] tmppw = dtSecretManager.retrievePassword(identifier); + fail("InvalidToken with cause StandbyException is expected" + + " since nn0 is standby"); + return tmppw; + } catch (IOException e) { + // Mimic the UserProvider class logic (server side) by throwing + // SecurityException here + throw new SecurityException( + "Failed to obtain user group information: " + e, e); + } + } catch (Exception oe) { + // + // The exception oe caught here is + // java.lang.SecurityException: Failed to obtain user group + // information: org.apache.hadoop.security.token. + // SecretManager$InvalidToken: StandbyException + // + HttpServletResponse response = mock(HttpServletResponse.class); + ExceptionHandler eh = new ExceptionHandler(); + eh.initResponse(response); + + // The Response (resp) below is what the server will send to client + // + // BEFORE HDFS-6475 fix, the resp.entity is + // {"RemoteException":{"exception":"SecurityException", + // "javaClassName":"java.lang.SecurityException", + // "message":"Failed to obtain user group information: + // org.apache.hadoop.security.token.SecretManager$InvalidToken: + // StandbyException"}} + // AFTER the fix, the resp.entity is + // {"RemoteException":{"exception":"StandbyException", + // "javaClassName":"org.apache.hadoop.ipc.StandbyException", + // "message":"Operation category READ is not supported in + // state standby"}} + // + Response resp = eh.toResponse(oe); + + // Mimic the client side logic by parsing the response from server + // + Map m = (Map)JSON.parse(resp.getEntity().toString()); + RemoteException re = JsonUtil.toRemoteException(m); + Exception unwrapped = ((RemoteException)re).unwrapRemoteException( + StandbyException.class); + assertTrue (unwrapped instanceof StandbyException); + return null; + } + } + }); + } + @SuppressWarnings("unchecked") private Token getDelegationToken(FileSystem fs, String renewer) throws IOException {