From 065747efabd1cbea9b14e93e905e304b9973d355 Mon Sep 17 00:00:00 2001 From: Vinod Kumar Vavilapalli Date: Thu, 16 May 2013 06:58:34 +0000 Subject: [PATCH] YARN-628. Fix the way YarnRemoteException is being unrolled to extract out the underlying exception. Contributed by Siddharth Seth. git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1483207 13f79535-47bb-0310-9956-ffa450edef68 --- hadoop-yarn-project/CHANGES.txt | 3 + .../org/apache/hadoop/yarn/YarnException.java | 4 + .../pb/client/AMRMProtocolPBClientImpl.java | 9 +- .../client/ClientRMProtocolPBClientImpl.java | 36 +++-- .../client/ContainerManagerPBClientImpl.java | 9 +- .../client/RMAdminProtocolPBClientImpl.java | 18 ++- .../org/apache/hadoop/yarn/ipc/RPCUtil.java | 104 +++++++----- .../hadoop/yarn/TestContainerLaunchRPC.java | 15 +- .../apache/hadoop/yarn/ipc/TestRPCUtil.java | 148 ++++++++++++++++++ .../client/ResourceTrackerPBClientImpl.java | 6 +- .../LocalizationProtocolPBClientImpl.java | 3 +- .../resourcemanager/TestClientRMTokens.java | 40 +++-- .../security/TestClientTokens.java | 15 +- .../server/TestContainerManagerSecurity.java | 3 +- 14 files changed, 323 insertions(+), 90 deletions(-) create mode 100644 hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/test/java/org/apache/hadoop/yarn/ipc/TestRPCUtil.java diff --git a/hadoop-yarn-project/CHANGES.txt b/hadoop-yarn-project/CHANGES.txt index 7cfb6c05e0..ab70194d26 100644 --- a/hadoop-yarn-project/CHANGES.txt +++ b/hadoop-yarn-project/CHANGES.txt @@ -388,6 +388,9 @@ Release 2.0.5-beta - UNRELEASED YARN-655. Fair scheduler metrics should subtract allocated memory from available memory. (sandyr via tucu) + YARN-628. Fix the way YarnRemoteException is being unrolled to extract out + the underlying exception. (Siddharth Seth via vinodkv) + Release 2.0.4-alpha - 2013-04-25 INCOMPATIBLE CHANGES diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/YarnException.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/YarnException.java index b12fc81ef5..29279b6a46 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/YarnException.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/YarnException.java @@ -19,6 +19,10 @@ package org.apache.hadoop.yarn; /** Base Yarn Exception. + * + * NOTE: All derivatives of this exception, which may be thrown by a remote + * service, must include a String only constructor for the exception to be + * unwrapped on the client. */ public class YarnException extends RuntimeException { public YarnException(Throwable cause) { super(cause); } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/api/impl/pb/client/AMRMProtocolPBClientImpl.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/api/impl/pb/client/AMRMProtocolPBClientImpl.java index 7c99a41f30..5ab35d32c9 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/api/impl/pb/client/AMRMProtocolPBClientImpl.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/api/impl/pb/client/AMRMProtocolPBClientImpl.java @@ -74,7 +74,8 @@ public AllocateResponse allocate(AllocateRequest request) try { return new AllocateResponsePBImpl(proxy.allocate(null, requestProto)); } catch (ServiceException e) { - throw RPCUtil.unwrapAndThrowException(e); + RPCUtil.unwrapAndThrowException(e); + return null; } } @@ -88,7 +89,8 @@ public FinishApplicationMasterResponse finishApplicationMaster( return new FinishApplicationMasterResponsePBImpl( proxy.finishApplicationMaster(null, requestProto)); } catch (ServiceException e) { - throw RPCUtil.unwrapAndThrowException(e); + RPCUtil.unwrapAndThrowException(e); + return null; } } @@ -102,7 +104,8 @@ public RegisterApplicationMasterResponse registerApplicationMaster( return new RegisterApplicationMasterResponsePBImpl( proxy.registerApplicationMaster(null, requestProto)); } catch (ServiceException e) { - throw RPCUtil.unwrapAndThrowException(e); + RPCUtil.unwrapAndThrowException(e); + return null; } } } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/api/impl/pb/client/ClientRMProtocolPBClientImpl.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/api/impl/pb/client/ClientRMProtocolPBClientImpl.java index bd436f2bd5..096bedf743 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/api/impl/pb/client/ClientRMProtocolPBClientImpl.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/api/impl/pb/client/ClientRMProtocolPBClientImpl.java @@ -120,7 +120,8 @@ public KillApplicationResponse forceKillApplication( return new KillApplicationResponsePBImpl(proxy.forceKillApplication(null, requestProto)); } catch (ServiceException e) { - throw RPCUtil.unwrapAndThrowException(e); + RPCUtil.unwrapAndThrowException(e); + return null; } } @@ -134,7 +135,8 @@ public GetApplicationReportResponse getApplicationReport( return new GetApplicationReportResponsePBImpl(proxy.getApplicationReport( null, requestProto)); } catch (ServiceException e) { - throw RPCUtil.unwrapAndThrowException(e); + RPCUtil.unwrapAndThrowException(e); + return null; } } @@ -148,7 +150,8 @@ public GetClusterMetricsResponse getClusterMetrics( return new GetClusterMetricsResponsePBImpl(proxy.getClusterMetrics(null, requestProto)); } catch (ServiceException e) { - throw RPCUtil.unwrapAndThrowException(e); + RPCUtil.unwrapAndThrowException(e); + return null; } } @@ -162,7 +165,8 @@ public GetNewApplicationResponse getNewApplication( return new GetNewApplicationResponsePBImpl(proxy.getNewApplication(null, requestProto)); } catch (ServiceException e) { - throw RPCUtil.unwrapAndThrowException(e); + RPCUtil.unwrapAndThrowException(e); + return null; } } @@ -176,7 +180,8 @@ public SubmitApplicationResponse submitApplication( return new SubmitApplicationResponsePBImpl(proxy.submitApplication(null, requestProto)); } catch (ServiceException e) { - throw RPCUtil.unwrapAndThrowException(e); + RPCUtil.unwrapAndThrowException(e); + return null; } } @@ -190,7 +195,8 @@ public GetAllApplicationsResponse getAllApplications( return new GetAllApplicationsResponsePBImpl(proxy.getAllApplications( null, requestProto)); } catch (ServiceException e) { - throw RPCUtil.unwrapAndThrowException(e); + RPCUtil.unwrapAndThrowException(e); + return null; } } @@ -204,7 +210,8 @@ public GetAllApplicationsResponse getAllApplications( return new GetClusterNodesResponsePBImpl(proxy.getClusterNodes(null, requestProto)); } catch (ServiceException e) { - throw RPCUtil.unwrapAndThrowException(e); + RPCUtil.unwrapAndThrowException(e); + return null; } } @@ -217,7 +224,8 @@ public GetQueueInfoResponse getQueueInfo(GetQueueInfoRequest request) return new GetQueueInfoResponsePBImpl(proxy.getQueueInfo(null, requestProto)); } catch (ServiceException e) { - throw RPCUtil.unwrapAndThrowException(e); + RPCUtil.unwrapAndThrowException(e); + return null; } } @@ -231,7 +239,8 @@ public GetQueueUserAclsInfoResponse getQueueUserAcls( return new GetQueueUserAclsInfoResponsePBImpl(proxy.getQueueUserAcls( null, requestProto)); } catch (ServiceException e) { - throw RPCUtil.unwrapAndThrowException(e); + RPCUtil.unwrapAndThrowException(e); + return null; } } @@ -245,7 +254,8 @@ public GetDelegationTokenResponse getDelegationToken( return new GetDelegationTokenResponsePBImpl(proxy.getDelegationToken( null, requestProto)); } catch (ServiceException e) { - throw RPCUtil.unwrapAndThrowException(e); + RPCUtil.unwrapAndThrowException(e); + return null; } } @@ -259,7 +269,8 @@ public RenewDelegationTokenResponse renewDelegationToken( return new RenewDelegationTokenResponsePBImpl(proxy.renewDelegationToken( null, requestProto)); } catch (ServiceException e) { - throw RPCUtil.unwrapAndThrowException(e); + RPCUtil.unwrapAndThrowException(e); + return null; } } @@ -274,7 +285,8 @@ public CancelDelegationTokenResponse cancelDelegationToken( proxy.cancelDelegationToken(null, requestProto)); } catch (ServiceException e) { - throw RPCUtil.unwrapAndThrowException(e); + RPCUtil.unwrapAndThrowException(e); + return null; } } } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/api/impl/pb/client/ContainerManagerPBClientImpl.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/api/impl/pb/client/ContainerManagerPBClientImpl.java index 4c242d9bf7..2f16479a88 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/api/impl/pb/client/ContainerManagerPBClientImpl.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/api/impl/pb/client/ContainerManagerPBClientImpl.java @@ -94,7 +94,8 @@ public GetContainerStatusResponse getContainerStatus( return new GetContainerStatusResponsePBImpl(proxy.getContainerStatus( null, requestProto)); } catch (ServiceException e) { - throw RPCUtil.unwrapAndThrowException(e); + RPCUtil.unwrapAndThrowException(e); + return null; } } @@ -107,7 +108,8 @@ public StartContainerResponse startContainer(StartContainerRequest request) return new StartContainerResponsePBImpl(proxy.startContainer(null, requestProto)); } catch (ServiceException e) { - throw RPCUtil.unwrapAndThrowException(e); + RPCUtil.unwrapAndThrowException(e); + return null; } } @@ -120,7 +122,8 @@ public StopContainerResponse stopContainer(StopContainerRequest request) return new StopContainerResponsePBImpl(proxy.stopContainer(null, requestProto)); } catch (ServiceException e) { - throw RPCUtil.unwrapAndThrowException(e); + RPCUtil.unwrapAndThrowException(e); + return null; } } } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/api/impl/pb/client/RMAdminProtocolPBClientImpl.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/api/impl/pb/client/RMAdminProtocolPBClientImpl.java index 8d60038dbe..3d4f7fd1d2 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/api/impl/pb/client/RMAdminProtocolPBClientImpl.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/api/impl/pb/client/RMAdminProtocolPBClientImpl.java @@ -94,7 +94,8 @@ public RefreshQueuesResponse refreshQueues(RefreshQueuesRequest request) return new RefreshQueuesResponsePBImpl( proxy.refreshQueues(null, requestProto)); } catch (ServiceException e) { - throw RPCUtil.unwrapAndThrowException(e); + RPCUtil.unwrapAndThrowException(e); + return null; } } @@ -107,7 +108,8 @@ public RefreshNodesResponse refreshNodes(RefreshNodesRequest request) return new RefreshNodesResponsePBImpl( proxy.refreshNodes(null, requestProto)); } catch (ServiceException e) { - throw RPCUtil.unwrapAndThrowException(e); + RPCUtil.unwrapAndThrowException(e); + return null; } } @@ -121,7 +123,8 @@ public RefreshSuperUserGroupsConfigurationResponse refreshSuperUserGroupsConfigu return new RefreshSuperUserGroupsConfigurationResponsePBImpl( proxy.refreshSuperUserGroupsConfiguration(null, requestProto)); } catch (ServiceException e) { - throw RPCUtil.unwrapAndThrowException(e); + RPCUtil.unwrapAndThrowException(e); + return null; } } @@ -135,7 +138,8 @@ public RefreshUserToGroupsMappingsResponse refreshUserToGroupsMappings( return new RefreshUserToGroupsMappingsResponsePBImpl( proxy.refreshUserToGroupsMappings(null, requestProto)); } catch (ServiceException e) { - throw RPCUtil.unwrapAndThrowException(e); + RPCUtil.unwrapAndThrowException(e); + return null; } } @@ -148,7 +152,8 @@ public RefreshAdminAclsResponse refreshAdminAcls( return new RefreshAdminAclsResponsePBImpl( proxy.refreshAdminAcls(null, requestProto)); } catch (ServiceException e) { - throw RPCUtil.unwrapAndThrowException(e); + RPCUtil.unwrapAndThrowException(e); + return null; } } @@ -162,7 +167,8 @@ public RefreshServiceAclsResponse refreshServiceAcls( return new RefreshServiceAclsResponsePBImpl(proxy.refreshServiceAcls( null, requestProto)); } catch (ServiceException e) { - throw RPCUtil.unwrapAndThrowException(e); + RPCUtil.unwrapAndThrowException(e); + return null; } } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/ipc/RPCUtil.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/ipc/RPCUtil.java index 7c190e9c5d..4e93d03abf 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/ipc/RPCUtil.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/ipc/RPCUtil.java @@ -20,7 +20,7 @@ import java.io.IOException; import java.lang.reflect.Constructor; -import java.lang.reflect.UndeclaredThrowableException; +import java.lang.reflect.InvocationTargetException; import org.apache.hadoop.ipc.RemoteException; import org.apache.hadoop.yarn.exceptions.YarnRemoteException; @@ -43,45 +43,77 @@ public static YarnRemoteException getRemoteException(String message) { return new YarnRemoteException(message); } + private static T instantiateException( + Class cls, RemoteException re) throws RemoteException { + try { + Constructor cn = cls.getConstructor(String.class); + cn.setAccessible(true); + T ex = cn.newInstance(re.getMessage()); + ex.initCause(re); + return ex; + // RemoteException contains useful information as against the + // java.lang.reflect exceptions. + } catch (NoSuchMethodException e) { + throw re; + } catch (IllegalArgumentException e) { + throw re; + } catch (SecurityException e) { + throw re; + } catch (InstantiationException e) { + throw re; + } catch (IllegalAccessException e) { + throw re; + } catch (InvocationTargetException e) { + throw re; + } + } + /** - * Utility method that unwraps and throws appropriate exception. + * Utility method that unwraps and returns appropriate exceptions. * - * @param se ServiceException - * @throws YarnRemoteException - * @throws UndeclaredThrowableException + * @param se + * ServiceException + * @return An instance of the actual exception, which will be a subclass of + * {@link YarnRemoteException} or {@link IOException} */ - public static YarnRemoteException unwrapAndThrowException(ServiceException se) - throws UndeclaredThrowableException { - if (se.getCause() instanceof RemoteException) { - try { - RemoteException re = (RemoteException) se.getCause(); - Class realClass = Class.forName(re.getClassName()); - //YarnRemoteException is not rooted as IOException. - //Do the explicitly check if it is YarnRemoteException - if (YarnRemoteException.class.isAssignableFrom(realClass)) { - Constructor cn = - realClass.asSubclass(YarnRemoteException.class).getConstructor( - String.class); - cn.setAccessible(true); - YarnRemoteException ex = cn.newInstance(re.getMessage()); - ex.initCause(re); - return ex; - } else { - // TODO Fix in YARN-628. - throw new IOException((RemoteException) se.getCause()); - } - } catch (IOException e1) { - throw new UndeclaredThrowableException(e1); - } catch (Exception ex) { - throw new UndeclaredThrowableException( - (RemoteException) se.getCause()); - } - } else if (se.getCause() instanceof YarnRemoteException) { - return (YarnRemoteException) se.getCause(); - } else if (se.getCause() instanceof UndeclaredThrowableException) { - throw (UndeclaredThrowableException) se.getCause(); + public static Void unwrapAndThrowException(ServiceException se) + throws IOException, YarnRemoteException { + Throwable cause = se.getCause(); + if (cause == null) { + // SE generated by the RPC layer itself. + throw new IOException(se); } else { - throw new UndeclaredThrowableException(se); + if (cause instanceof RemoteException) { + RemoteException re = (RemoteException) cause; + Class realClass = null; + try { + realClass = Class.forName(re.getClassName()); + } catch (ClassNotFoundException cnf) { + // Assume this to be a new exception type added to YARN. This isn't + // absolutely correct since the RPC layer could add an exception as + // well. + throw instantiateException(YarnRemoteException.class, re); + } + + if (YarnRemoteException.class.isAssignableFrom(realClass)) { + throw instantiateException( + realClass.asSubclass(YarnRemoteException.class), re); + } else if (IOException.class.isAssignableFrom(realClass)) { + throw instantiateException(realClass.asSubclass(IOException.class), + re); + } else { + throw re; + } + // RemoteException contains useful information as against the + // java.lang.reflect exceptions. + + } else if (cause instanceof IOException) { + // RPC Client exception. + throw (IOException) cause; + } else { + // Should not be generated. + throw new IOException(se); + } } } } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/test/java/org/apache/hadoop/yarn/TestContainerLaunchRPC.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/test/java/org/apache/hadoop/yarn/TestContainerLaunchRPC.java index 2c03c35074..cf0a441b17 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/test/java/org/apache/hadoop/yarn/TestContainerLaunchRPC.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/test/java/org/apache/hadoop/yarn/TestContainerLaunchRPC.java @@ -18,8 +18,9 @@ package org.apache.hadoop.yarn; -import java.lang.reflect.UndeclaredThrowableException; +import java.io.IOException; import java.net.InetSocketAddress; +import java.net.SocketTimeoutException; import junit.framework.Assert; @@ -61,7 +62,6 @@ public class TestContainerLaunchRPC { static final Log LOG = LogFactory.getLog(TestContainerLaunchRPC.class); - private static final String EXCEPTION_CAUSE = "java.net.SocketTimeoutException"; private static final RecordFactory recordFactory = RecordFactoryProvider .getRecordFactory(null); @@ -114,10 +114,9 @@ private void testRPCTimeout(String rpcClass) throws Exception { proxy.startContainer(scRequest); } catch (Exception e) { LOG.info(StringUtils.stringifyException(e)); - Assert.assertTrue("Error, exception does not contain: " - + EXCEPTION_CAUSE, - e.getCause().getMessage().contains(EXCEPTION_CAUSE)); - + Assert.assertEquals("Error, exception is not: " + + SocketTimeoutException.class.getName(), + SocketTimeoutException.class.getName(), e.getClass().getName()); return; } } finally { @@ -142,7 +141,7 @@ public GetContainerStatusResponse getContainerStatus( @Override public StartContainerResponse startContainer(StartContainerRequest request) - throws YarnRemoteException { + throws YarnRemoteException, IOException { StartContainerResponse response = recordFactory .newRecordInstance(StartContainerResponse.class); status = recordFactory.newRecordInstance(ContainerStatus.class); @@ -151,7 +150,7 @@ public StartContainerResponse startContainer(StartContainerRequest request) Thread.sleep(10000); } catch (Exception e) { LOG.error(e); - throw new UndeclaredThrowableException(e); + throw new YarnRemoteException(e); } status.setState(ContainerState.RUNNING); status.setContainerId(request.getContainer().getId()); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/test/java/org/apache/hadoop/yarn/ipc/TestRPCUtil.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/test/java/org/apache/hadoop/yarn/ipc/TestRPCUtil.java new file mode 100644 index 0000000000..82e20cd00c --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/test/java/org/apache/hadoop/yarn/ipc/TestRPCUtil.java @@ -0,0 +1,148 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.yarn.ipc; + +import java.io.FileNotFoundException; +import java.io.IOException; + +import junit.framework.Assert; + +import org.apache.hadoop.ipc.RemoteException; +import org.apache.hadoop.yarn.exceptions.YarnRemoteException; +import org.junit.Test; + +import com.google.protobuf.ServiceException; + +public class TestRPCUtil { + + @Test + public void testUnknownExceptionUnwrapping() { + Class exception = YarnRemoteException.class; + String className = "UnknownException.class"; + verifyRemoteExceptionUnwrapping(exception, className); + } + + @Test + public void testRemoteIOExceptionUnwrapping() { + Class exception = IOException.class; + verifyRemoteExceptionUnwrapping(exception, exception.getName()); + } + + @Test + public void testRemoteIOExceptionDerivativeUnwrapping() { + // Test IOException sub-class + Class exception = FileNotFoundException.class; + verifyRemoteExceptionUnwrapping(exception, exception.getName()); + } + + @Test + public void testRemoteYarnExceptionUnwrapping() { + Class exception = YarnRemoteException.class; + verifyRemoteExceptionUnwrapping(exception, exception.getName()); + + } + + @Test + public void testRemoteYarnExceptionDerivativeUnwrapping() { + Class exception = YarnTestException.class; + verifyRemoteExceptionUnwrapping(exception, exception.getName()); + } + + @Test + public void testUnexpectedRemoteExceptionUnwrapping() { + // Non IOException, YarnException thrown by the remote side. + Class exception = Exception.class; + verifyRemoteExceptionUnwrapping(RemoteException.class, exception.getName()); + } + + @Test + public void testRemoteYarnExceptionWithoutStringConstructor() { + // Derivatives of YarnException should always defined a string constructor. + Class exception = YarnTestExceptionNoConstructor.class; + verifyRemoteExceptionUnwrapping(RemoteException.class, exception.getName()); + } + + @Test + public void testRPCServiceExceptionUnwrapping() { + String message = "ServiceExceptionMessage"; + ServiceException se = new ServiceException(message); + + Throwable t = null; + try { + RPCUtil.unwrapAndThrowException(se); + } catch (Throwable thrown) { + t = thrown; + } + + Assert.assertTrue(IOException.class.isInstance(t)); + Assert.assertTrue(t.getMessage().contains(message)); + } + + @Test + public void testRPCIOExceptionUnwrapping() { + String message = "DirectIOExceptionMessage"; + IOException ioException = new FileNotFoundException(message); + ServiceException se = new ServiceException(ioException); + + Throwable t = null; + try { + RPCUtil.unwrapAndThrowException(se); + } catch (Throwable thrown) { + t = thrown; + } + Assert.assertTrue(FileNotFoundException.class.isInstance(t)); + Assert.assertTrue(t.getMessage().contains(message)); + } + + private void verifyRemoteExceptionUnwrapping( + Class expectedLocalException, + String realExceptionClassName) { + String message = realExceptionClassName + "Message"; + RemoteException re = new RemoteException(realExceptionClassName, message); + ServiceException se = new ServiceException(re); + + Throwable t = null; + try { + RPCUtil.unwrapAndThrowException(se); + } catch (Throwable thrown) { + t = thrown; + } + + Assert.assertTrue("Expected exception [" + expectedLocalException + + "] but found " + t, expectedLocalException.isInstance(t)); + Assert.assertTrue( + "Expected message [" + message + "] but found " + t.getMessage(), t + .getMessage().contains(message)); + } + + private static class YarnTestException extends YarnRemoteException { + private static final long serialVersionUID = 1L; + + @SuppressWarnings("unused") + public YarnTestException(String message) { + super(message); + } + } + + private static class YarnTestExceptionNoConstructor extends + YarnRemoteException { + private static final long serialVersionUID = 1L; + + } +} diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/api/impl/pb/client/ResourceTrackerPBClientImpl.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/api/impl/pb/client/ResourceTrackerPBClientImpl.java index 71472410ea..b6382840bd 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/api/impl/pb/client/ResourceTrackerPBClientImpl.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/api/impl/pb/client/ResourceTrackerPBClientImpl.java @@ -59,7 +59,8 @@ public RegisterNodeManagerResponse registerNodeManager( try { return new RegisterNodeManagerResponsePBImpl(proxy.registerNodeManager(null, requestProto)); } catch (ServiceException e) { - throw RPCUtil.unwrapAndThrowException(e); + RPCUtil.unwrapAndThrowException(e); + return null; } } @@ -70,7 +71,8 @@ public NodeHeartbeatResponse nodeHeartbeat(NodeHeartbeatRequest request) try { return new NodeHeartbeatResponsePBImpl(proxy.nodeHeartbeat(null, requestProto)); } catch (ServiceException e) { - throw RPCUtil.unwrapAndThrowException(e); + RPCUtil.unwrapAndThrowException(e); + return null; } } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/api/impl/pb/client/LocalizationProtocolPBClientImpl.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/api/impl/pb/client/LocalizationProtocolPBClientImpl.java index 4e13c3affe..8ec1e81e12 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/api/impl/pb/client/LocalizationProtocolPBClientImpl.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/api/impl/pb/client/LocalizationProtocolPBClientImpl.java @@ -62,7 +62,8 @@ public LocalizerHeartbeatResponse heartbeat(LocalizerStatus status) return new LocalizerHeartbeatResponsePBImpl( proxy.heartbeat(null, statusProto)); } catch (ServiceException e) { - throw RPCUtil.unwrapAndThrowException(e); + RPCUtil.unwrapAndThrowException(e); + return null; } } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/TestClientRMTokens.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/TestClientRMTokens.java index d334cc5f7c..88f68e4fba 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/TestClientRMTokens.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/TestClientRMTokens.java @@ -17,11 +17,19 @@ package org.apache.hadoop.yarn.server.resourcemanager; -import static org.junit.Assert.*; -import static org.mockito.Mockito.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.verify; import java.io.IOException; -import java.lang.reflect.UndeclaredThrowableException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.security.PrivilegedAction; @@ -40,6 +48,7 @@ import org.apache.hadoop.security.UserGroupInformation; import org.apache.hadoop.security.UserGroupInformation.AuthenticationMethod; import org.apache.hadoop.security.token.SecretManager; +import org.apache.hadoop.security.token.SecretManager.InvalidToken; import org.apache.hadoop.security.token.Token; import org.apache.hadoop.security.token.TokenIdentifier; import org.apache.hadoop.yarn.api.ClientRMProtocol; @@ -72,8 +81,7 @@ public void resetSecretManager() { } @Test - public void testDelegationToken() throws IOException, InterruptedException, - YarnRemoteException { + public void testDelegationToken() throws IOException, InterruptedException { final YarnConfiguration conf = new YarnConfiguration(); conf.set(YarnConfiguration.RM_PRINCIPAL, "testuser/localhost@apache.org"); @@ -123,7 +131,9 @@ public void testDelegationToken() throws IOException, InterruptedException, try { clientRMWithDT.getNewApplication(request); - } catch (UndeclaredThrowableException e) { + } catch (IOException e) { + fail("Unexpected exception" + e); + } catch (YarnRemoteException e) { fail("Unexpected exception" + e); } @@ -146,7 +156,9 @@ public void testDelegationToken() throws IOException, InterruptedException, // Valid token because of renewal. try { clientRMWithDT.getNewApplication(request); - } catch (UndeclaredThrowableException e) { + } catch (IOException e) { + fail("Unexpected exception" + e); + } catch (YarnRemoteException e) { fail("Unexpected exception" + e); } @@ -160,9 +172,10 @@ public void testDelegationToken() throws IOException, InterruptedException, try { clientRMWithDT.getNewApplication(request); fail("Should not have succeeded with an expired token"); - } catch (UndeclaredThrowableException e) { - assertTrue(e.getCause().getMessage().contains("is expired")); - } + } catch (Exception e) { + assertEquals(InvalidToken.class.getName(), e.getClass().getName()); + assertTrue(e.getMessage().contains("is expired")); + } // Test cancellation // Stop the existing proxy, start another. @@ -183,7 +196,9 @@ public void testDelegationToken() throws IOException, InterruptedException, try { clientRMWithDT.getNewApplication(request); - } catch (UndeclaredThrowableException e) { + } catch (IOException e) { + fail("Unexpected exception" + e); + } catch (YarnRemoteException e) { fail("Unexpected exception" + e); } cancelDelegationToken(loggedInUser, clientRMService, token); @@ -200,7 +215,8 @@ public void testDelegationToken() throws IOException, InterruptedException, try { clientRMWithDT.getNewApplication(request); fail("Should not have succeeded with a cancelled delegation token"); - } catch (UndeclaredThrowableException e) { + } catch (IOException e) { + } catch (YarnRemoteException e) { } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/security/TestClientTokens.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/security/TestClientTokens.java index 58b558fe74..9cdd544436 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/security/TestClientTokens.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/security/TestClientTokens.java @@ -25,12 +25,15 @@ import java.net.InetSocketAddress; import java.security.PrivilegedExceptionAction; +import javax.security.sasl.SaslException; + import junit.framework.Assert; import org.apache.commons.codec.binary.Base64; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.CommonConfigurationKeysPublic; import org.apache.hadoop.ipc.RPC; +import org.apache.hadoop.ipc.RemoteException; import org.apache.hadoop.ipc.Server; import org.apache.hadoop.net.NetUtils; import org.apache.hadoop.security.KerberosInfo; @@ -53,7 +56,6 @@ import org.apache.hadoop.yarn.api.protocolrecords.StopContainerRequest; import org.apache.hadoop.yarn.api.protocolrecords.StopContainerResponse; import org.apache.hadoop.yarn.api.records.ApplicationAttemptId; -import org.apache.hadoop.yarn.api.records.ApplicationId; import org.apache.hadoop.yarn.api.records.ApplicationReport; import org.apache.hadoop.yarn.api.records.ClientToken; import org.apache.hadoop.yarn.event.Dispatcher; @@ -76,9 +78,10 @@ public class TestClientTokens { private interface CustomProtocol { + @SuppressWarnings("unused") public static final long versionID = 1L; - public void ping() throws YarnRemoteException; + public void ping() throws YarnRemoteException, IOException; } private static class CustomSecurityInfo extends SecurityInfo { @@ -121,7 +124,7 @@ public CustomAM(ApplicationAttemptId appId, String secretKeyStr) { } @Override - public void ping() throws YarnRemoteException { + public void ping() throws YarnRemoteException, IOException { this.pinged = true; } @@ -289,11 +292,13 @@ public Void run() throws Exception { } }); } catch (Exception e) { + Assert.assertEquals(RemoteException.class.getName(), e.getClass() + .getName()); + e = ((RemoteException)e).unwrapRemoteException(); Assert - .assertEquals(java.lang.reflect.UndeclaredThrowableException.class + .assertEquals(SaslException.class .getCanonicalName(), e.getClass().getCanonicalName()); Assert.assertTrue(e - .getCause() .getMessage() .contains( "DIGEST-MD5: digest response format violation. " diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-tests/src/test/java/org/apache/hadoop/yarn/server/TestContainerManagerSecurity.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-tests/src/test/java/org/apache/hadoop/yarn/server/TestContainerManagerSecurity.java index fdde3ba8ac..a70a3b69f3 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-tests/src/test/java/org/apache/hadoop/yarn/server/TestContainerManagerSecurity.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-tests/src/test/java/org/apache/hadoop/yarn/server/TestContainerManagerSecurity.java @@ -247,10 +247,9 @@ public Void run() { + "it will indicate RPC success"); } catch (Exception e) { Assert.assertEquals( - java.lang.reflect.UndeclaredThrowableException.class + javax.security.sasl.SaslException.class .getCanonicalName(), e.getClass().getCanonicalName()); Assert.assertTrue(e - .getCause() .getMessage() .contains( "DIGEST-MD5: digest response format violation. "