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
This commit is contained in:
parent
da05873e0e
commit
065747efab
|
@ -388,6 +388,9 @@ Release 2.0.5-beta - UNRELEASED
|
||||||
YARN-655. Fair scheduler metrics should subtract allocated memory from
|
YARN-655. Fair scheduler metrics should subtract allocated memory from
|
||||||
available memory. (sandyr via tucu)
|
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
|
Release 2.0.4-alpha - 2013-04-25
|
||||||
|
|
||||||
INCOMPATIBLE CHANGES
|
INCOMPATIBLE CHANGES
|
||||||
|
|
|
@ -19,6 +19,10 @@
|
||||||
package org.apache.hadoop.yarn;
|
package org.apache.hadoop.yarn;
|
||||||
|
|
||||||
/** Base Yarn Exception.
|
/** 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 class YarnException extends RuntimeException {
|
||||||
public YarnException(Throwable cause) { super(cause); }
|
public YarnException(Throwable cause) { super(cause); }
|
||||||
|
|
|
@ -74,7 +74,8 @@ public class AMRMProtocolPBClientImpl implements AMRMProtocol, Closeable {
|
||||||
try {
|
try {
|
||||||
return new AllocateResponsePBImpl(proxy.allocate(null, requestProto));
|
return new AllocateResponsePBImpl(proxy.allocate(null, requestProto));
|
||||||
} catch (ServiceException e) {
|
} catch (ServiceException e) {
|
||||||
throw RPCUtil.unwrapAndThrowException(e);
|
RPCUtil.unwrapAndThrowException(e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +89,8 @@ public class AMRMProtocolPBClientImpl implements AMRMProtocol, Closeable {
|
||||||
return new FinishApplicationMasterResponsePBImpl(
|
return new FinishApplicationMasterResponsePBImpl(
|
||||||
proxy.finishApplicationMaster(null, requestProto));
|
proxy.finishApplicationMaster(null, requestProto));
|
||||||
} catch (ServiceException e) {
|
} catch (ServiceException e) {
|
||||||
throw RPCUtil.unwrapAndThrowException(e);
|
RPCUtil.unwrapAndThrowException(e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,7 +104,8 @@ public class AMRMProtocolPBClientImpl implements AMRMProtocol, Closeable {
|
||||||
return new RegisterApplicationMasterResponsePBImpl(
|
return new RegisterApplicationMasterResponsePBImpl(
|
||||||
proxy.registerApplicationMaster(null, requestProto));
|
proxy.registerApplicationMaster(null, requestProto));
|
||||||
} catch (ServiceException e) {
|
} catch (ServiceException e) {
|
||||||
throw RPCUtil.unwrapAndThrowException(e);
|
RPCUtil.unwrapAndThrowException(e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,7 +120,8 @@ public class ClientRMProtocolPBClientImpl implements ClientRMProtocol,
|
||||||
return new KillApplicationResponsePBImpl(proxy.forceKillApplication(null,
|
return new KillApplicationResponsePBImpl(proxy.forceKillApplication(null,
|
||||||
requestProto));
|
requestProto));
|
||||||
} catch (ServiceException e) {
|
} catch (ServiceException e) {
|
||||||
throw RPCUtil.unwrapAndThrowException(e);
|
RPCUtil.unwrapAndThrowException(e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,7 +135,8 @@ public class ClientRMProtocolPBClientImpl implements ClientRMProtocol,
|
||||||
return new GetApplicationReportResponsePBImpl(proxy.getApplicationReport(
|
return new GetApplicationReportResponsePBImpl(proxy.getApplicationReport(
|
||||||
null, requestProto));
|
null, requestProto));
|
||||||
} catch (ServiceException e) {
|
} catch (ServiceException e) {
|
||||||
throw RPCUtil.unwrapAndThrowException(e);
|
RPCUtil.unwrapAndThrowException(e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,7 +150,8 @@ public class ClientRMProtocolPBClientImpl implements ClientRMProtocol,
|
||||||
return new GetClusterMetricsResponsePBImpl(proxy.getClusterMetrics(null,
|
return new GetClusterMetricsResponsePBImpl(proxy.getClusterMetrics(null,
|
||||||
requestProto));
|
requestProto));
|
||||||
} catch (ServiceException e) {
|
} catch (ServiceException e) {
|
||||||
throw RPCUtil.unwrapAndThrowException(e);
|
RPCUtil.unwrapAndThrowException(e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,7 +165,8 @@ public class ClientRMProtocolPBClientImpl implements ClientRMProtocol,
|
||||||
return new GetNewApplicationResponsePBImpl(proxy.getNewApplication(null,
|
return new GetNewApplicationResponsePBImpl(proxy.getNewApplication(null,
|
||||||
requestProto));
|
requestProto));
|
||||||
} catch (ServiceException e) {
|
} catch (ServiceException e) {
|
||||||
throw RPCUtil.unwrapAndThrowException(e);
|
RPCUtil.unwrapAndThrowException(e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,7 +180,8 @@ public class ClientRMProtocolPBClientImpl implements ClientRMProtocol,
|
||||||
return new SubmitApplicationResponsePBImpl(proxy.submitApplication(null,
|
return new SubmitApplicationResponsePBImpl(proxy.submitApplication(null,
|
||||||
requestProto));
|
requestProto));
|
||||||
} catch (ServiceException e) {
|
} catch (ServiceException e) {
|
||||||
throw RPCUtil.unwrapAndThrowException(e);
|
RPCUtil.unwrapAndThrowException(e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,7 +195,8 @@ public class ClientRMProtocolPBClientImpl implements ClientRMProtocol,
|
||||||
return new GetAllApplicationsResponsePBImpl(proxy.getAllApplications(
|
return new GetAllApplicationsResponsePBImpl(proxy.getAllApplications(
|
||||||
null, requestProto));
|
null, requestProto));
|
||||||
} catch (ServiceException e) {
|
} catch (ServiceException e) {
|
||||||
throw RPCUtil.unwrapAndThrowException(e);
|
RPCUtil.unwrapAndThrowException(e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,7 +210,8 @@ public class ClientRMProtocolPBClientImpl implements ClientRMProtocol,
|
||||||
return new GetClusterNodesResponsePBImpl(proxy.getClusterNodes(null,
|
return new GetClusterNodesResponsePBImpl(proxy.getClusterNodes(null,
|
||||||
requestProto));
|
requestProto));
|
||||||
} catch (ServiceException e) {
|
} catch (ServiceException e) {
|
||||||
throw RPCUtil.unwrapAndThrowException(e);
|
RPCUtil.unwrapAndThrowException(e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,7 +224,8 @@ public class ClientRMProtocolPBClientImpl implements ClientRMProtocol,
|
||||||
return new GetQueueInfoResponsePBImpl(proxy.getQueueInfo(null,
|
return new GetQueueInfoResponsePBImpl(proxy.getQueueInfo(null,
|
||||||
requestProto));
|
requestProto));
|
||||||
} catch (ServiceException e) {
|
} catch (ServiceException e) {
|
||||||
throw RPCUtil.unwrapAndThrowException(e);
|
RPCUtil.unwrapAndThrowException(e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,7 +239,8 @@ public class ClientRMProtocolPBClientImpl implements ClientRMProtocol,
|
||||||
return new GetQueueUserAclsInfoResponsePBImpl(proxy.getQueueUserAcls(
|
return new GetQueueUserAclsInfoResponsePBImpl(proxy.getQueueUserAcls(
|
||||||
null, requestProto));
|
null, requestProto));
|
||||||
} catch (ServiceException e) {
|
} catch (ServiceException e) {
|
||||||
throw RPCUtil.unwrapAndThrowException(e);
|
RPCUtil.unwrapAndThrowException(e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,7 +254,8 @@ public class ClientRMProtocolPBClientImpl implements ClientRMProtocol,
|
||||||
return new GetDelegationTokenResponsePBImpl(proxy.getDelegationToken(
|
return new GetDelegationTokenResponsePBImpl(proxy.getDelegationToken(
|
||||||
null, requestProto));
|
null, requestProto));
|
||||||
} catch (ServiceException e) {
|
} catch (ServiceException e) {
|
||||||
throw RPCUtil.unwrapAndThrowException(e);
|
RPCUtil.unwrapAndThrowException(e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,7 +269,8 @@ public class ClientRMProtocolPBClientImpl implements ClientRMProtocol,
|
||||||
return new RenewDelegationTokenResponsePBImpl(proxy.renewDelegationToken(
|
return new RenewDelegationTokenResponsePBImpl(proxy.renewDelegationToken(
|
||||||
null, requestProto));
|
null, requestProto));
|
||||||
} catch (ServiceException e) {
|
} catch (ServiceException e) {
|
||||||
throw RPCUtil.unwrapAndThrowException(e);
|
RPCUtil.unwrapAndThrowException(e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,7 +285,8 @@ public class ClientRMProtocolPBClientImpl implements ClientRMProtocol,
|
||||||
proxy.cancelDelegationToken(null, requestProto));
|
proxy.cancelDelegationToken(null, requestProto));
|
||||||
|
|
||||||
} catch (ServiceException e) {
|
} catch (ServiceException e) {
|
||||||
throw RPCUtil.unwrapAndThrowException(e);
|
RPCUtil.unwrapAndThrowException(e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,7 +94,8 @@ public class ContainerManagerPBClientImpl implements ContainerManager,
|
||||||
return new GetContainerStatusResponsePBImpl(proxy.getContainerStatus(
|
return new GetContainerStatusResponsePBImpl(proxy.getContainerStatus(
|
||||||
null, requestProto));
|
null, requestProto));
|
||||||
} catch (ServiceException e) {
|
} catch (ServiceException e) {
|
||||||
throw RPCUtil.unwrapAndThrowException(e);
|
RPCUtil.unwrapAndThrowException(e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,7 +108,8 @@ public class ContainerManagerPBClientImpl implements ContainerManager,
|
||||||
return new StartContainerResponsePBImpl(proxy.startContainer(null,
|
return new StartContainerResponsePBImpl(proxy.startContainer(null,
|
||||||
requestProto));
|
requestProto));
|
||||||
} catch (ServiceException e) {
|
} catch (ServiceException e) {
|
||||||
throw RPCUtil.unwrapAndThrowException(e);
|
RPCUtil.unwrapAndThrowException(e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,7 +122,8 @@ public class ContainerManagerPBClientImpl implements ContainerManager,
|
||||||
return new StopContainerResponsePBImpl(proxy.stopContainer(null,
|
return new StopContainerResponsePBImpl(proxy.stopContainer(null,
|
||||||
requestProto));
|
requestProto));
|
||||||
} catch (ServiceException e) {
|
} catch (ServiceException e) {
|
||||||
throw RPCUtil.unwrapAndThrowException(e);
|
RPCUtil.unwrapAndThrowException(e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,7 +94,8 @@ public class RMAdminProtocolPBClientImpl implements RMAdminProtocol, Closeable {
|
||||||
return new RefreshQueuesResponsePBImpl(
|
return new RefreshQueuesResponsePBImpl(
|
||||||
proxy.refreshQueues(null, requestProto));
|
proxy.refreshQueues(null, requestProto));
|
||||||
} catch (ServiceException e) {
|
} catch (ServiceException e) {
|
||||||
throw RPCUtil.unwrapAndThrowException(e);
|
RPCUtil.unwrapAndThrowException(e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,7 +108,8 @@ public class RMAdminProtocolPBClientImpl implements RMAdminProtocol, Closeable {
|
||||||
return new RefreshNodesResponsePBImpl(
|
return new RefreshNodesResponsePBImpl(
|
||||||
proxy.refreshNodes(null, requestProto));
|
proxy.refreshNodes(null, requestProto));
|
||||||
} catch (ServiceException e) {
|
} catch (ServiceException e) {
|
||||||
throw RPCUtil.unwrapAndThrowException(e);
|
RPCUtil.unwrapAndThrowException(e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,7 +123,8 @@ public class RMAdminProtocolPBClientImpl implements RMAdminProtocol, Closeable {
|
||||||
return new RefreshSuperUserGroupsConfigurationResponsePBImpl(
|
return new RefreshSuperUserGroupsConfigurationResponsePBImpl(
|
||||||
proxy.refreshSuperUserGroupsConfiguration(null, requestProto));
|
proxy.refreshSuperUserGroupsConfiguration(null, requestProto));
|
||||||
} catch (ServiceException e) {
|
} catch (ServiceException e) {
|
||||||
throw RPCUtil.unwrapAndThrowException(e);
|
RPCUtil.unwrapAndThrowException(e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,7 +138,8 @@ public class RMAdminProtocolPBClientImpl implements RMAdminProtocol, Closeable {
|
||||||
return new RefreshUserToGroupsMappingsResponsePBImpl(
|
return new RefreshUserToGroupsMappingsResponsePBImpl(
|
||||||
proxy.refreshUserToGroupsMappings(null, requestProto));
|
proxy.refreshUserToGroupsMappings(null, requestProto));
|
||||||
} catch (ServiceException e) {
|
} catch (ServiceException e) {
|
||||||
throw RPCUtil.unwrapAndThrowException(e);
|
RPCUtil.unwrapAndThrowException(e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,7 +152,8 @@ public class RMAdminProtocolPBClientImpl implements RMAdminProtocol, Closeable {
|
||||||
return new RefreshAdminAclsResponsePBImpl(
|
return new RefreshAdminAclsResponsePBImpl(
|
||||||
proxy.refreshAdminAcls(null, requestProto));
|
proxy.refreshAdminAcls(null, requestProto));
|
||||||
} catch (ServiceException e) {
|
} catch (ServiceException e) {
|
||||||
throw RPCUtil.unwrapAndThrowException(e);
|
RPCUtil.unwrapAndThrowException(e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,7 +167,8 @@ public class RMAdminProtocolPBClientImpl implements RMAdminProtocol, Closeable {
|
||||||
return new RefreshServiceAclsResponsePBImpl(proxy.refreshServiceAcls(
|
return new RefreshServiceAclsResponsePBImpl(proxy.refreshServiceAcls(
|
||||||
null, requestProto));
|
null, requestProto));
|
||||||
} catch (ServiceException e) {
|
} catch (ServiceException e) {
|
||||||
throw RPCUtil.unwrapAndThrowException(e);
|
RPCUtil.unwrapAndThrowException(e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ package org.apache.hadoop.yarn.ipc;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Constructor;
|
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.ipc.RemoteException;
|
||||||
import org.apache.hadoop.yarn.exceptions.YarnRemoteException;
|
import org.apache.hadoop.yarn.exceptions.YarnRemoteException;
|
||||||
|
@ -43,45 +43,77 @@ public class RPCUtil {
|
||||||
return new YarnRemoteException(message);
|
return new YarnRemoteException(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private static <T extends Throwable> T instantiateException(
|
||||||
* Utility method that unwraps and throws appropriate exception.
|
Class<? extends T> cls, RemoteException re) throws RemoteException {
|
||||||
*
|
|
||||||
* @param se ServiceException
|
|
||||||
* @throws YarnRemoteException
|
|
||||||
* @throws UndeclaredThrowableException
|
|
||||||
*/
|
|
||||||
public static YarnRemoteException unwrapAndThrowException(ServiceException se)
|
|
||||||
throws UndeclaredThrowableException {
|
|
||||||
if (se.getCause() instanceof RemoteException) {
|
|
||||||
try {
|
try {
|
||||||
RemoteException re = (RemoteException) se.getCause();
|
Constructor<? extends T> cn = cls.getConstructor(String.class);
|
||||||
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<? extends YarnRemoteException> cn =
|
|
||||||
realClass.asSubclass(YarnRemoteException.class).getConstructor(
|
|
||||||
String.class);
|
|
||||||
cn.setAccessible(true);
|
cn.setAccessible(true);
|
||||||
YarnRemoteException ex = cn.newInstance(re.getMessage());
|
T ex = cn.newInstance(re.getMessage());
|
||||||
ex.initCause(re);
|
ex.initCause(re);
|
||||||
return ex;
|
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 returns appropriate exceptions.
|
||||||
|
*
|
||||||
|
* @param se
|
||||||
|
* ServiceException
|
||||||
|
* @return An instance of the actual exception, which will be a subclass of
|
||||||
|
* {@link YarnRemoteException} or {@link IOException}
|
||||||
|
*/
|
||||||
|
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 {
|
} else {
|
||||||
// TODO Fix in YARN-628.
|
if (cause instanceof RemoteException) {
|
||||||
throw new IOException((RemoteException) se.getCause());
|
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);
|
||||||
}
|
}
|
||||||
} catch (IOException e1) {
|
|
||||||
throw new UndeclaredThrowableException(e1);
|
if (YarnRemoteException.class.isAssignableFrom(realClass)) {
|
||||||
} catch (Exception ex) {
|
throw instantiateException(
|
||||||
throw new UndeclaredThrowableException(
|
realClass.asSubclass(YarnRemoteException.class), re);
|
||||||
(RemoteException) se.getCause());
|
} else if (IOException.class.isAssignableFrom(realClass)) {
|
||||||
}
|
throw instantiateException(realClass.asSubclass(IOException.class),
|
||||||
} else if (se.getCause() instanceof YarnRemoteException) {
|
re);
|
||||||
return (YarnRemoteException) se.getCause();
|
|
||||||
} else if (se.getCause() instanceof UndeclaredThrowableException) {
|
|
||||||
throw (UndeclaredThrowableException) se.getCause();
|
|
||||||
} else {
|
} else {
|
||||||
throw new UndeclaredThrowableException(se);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,9 @@
|
||||||
|
|
||||||
package org.apache.hadoop.yarn;
|
package org.apache.hadoop.yarn;
|
||||||
|
|
||||||
import java.lang.reflect.UndeclaredThrowableException;
|
import java.io.IOException;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.SocketTimeoutException;
|
||||||
|
|
||||||
import junit.framework.Assert;
|
import junit.framework.Assert;
|
||||||
|
|
||||||
|
@ -61,7 +62,6 @@ public class TestContainerLaunchRPC {
|
||||||
|
|
||||||
static final Log LOG = LogFactory.getLog(TestContainerLaunchRPC.class);
|
static final Log LOG = LogFactory.getLog(TestContainerLaunchRPC.class);
|
||||||
|
|
||||||
private static final String EXCEPTION_CAUSE = "java.net.SocketTimeoutException";
|
|
||||||
private static final RecordFactory recordFactory = RecordFactoryProvider
|
private static final RecordFactory recordFactory = RecordFactoryProvider
|
||||||
.getRecordFactory(null);
|
.getRecordFactory(null);
|
||||||
|
|
||||||
|
@ -114,10 +114,9 @@ public class TestContainerLaunchRPC {
|
||||||
proxy.startContainer(scRequest);
|
proxy.startContainer(scRequest);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.info(StringUtils.stringifyException(e));
|
LOG.info(StringUtils.stringifyException(e));
|
||||||
Assert.assertTrue("Error, exception does not contain: "
|
Assert.assertEquals("Error, exception is not: "
|
||||||
+ EXCEPTION_CAUSE,
|
+ SocketTimeoutException.class.getName(),
|
||||||
e.getCause().getMessage().contains(EXCEPTION_CAUSE));
|
SocketTimeoutException.class.getName(), e.getClass().getName());
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -142,7 +141,7 @@ public class TestContainerLaunchRPC {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StartContainerResponse startContainer(StartContainerRequest request)
|
public StartContainerResponse startContainer(StartContainerRequest request)
|
||||||
throws YarnRemoteException {
|
throws YarnRemoteException, IOException {
|
||||||
StartContainerResponse response = recordFactory
|
StartContainerResponse response = recordFactory
|
||||||
.newRecordInstance(StartContainerResponse.class);
|
.newRecordInstance(StartContainerResponse.class);
|
||||||
status = recordFactory.newRecordInstance(ContainerStatus.class);
|
status = recordFactory.newRecordInstance(ContainerStatus.class);
|
||||||
|
@ -151,7 +150,7 @@ public class TestContainerLaunchRPC {
|
||||||
Thread.sleep(10000);
|
Thread.sleep(10000);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.error(e);
|
LOG.error(e);
|
||||||
throw new UndeclaredThrowableException(e);
|
throw new YarnRemoteException(e);
|
||||||
}
|
}
|
||||||
status.setState(ContainerState.RUNNING);
|
status.setState(ContainerState.RUNNING);
|
||||||
status.setContainerId(request.getContainer().getId());
|
status.setContainerId(request.getContainer().getId());
|
||||||
|
|
|
@ -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<? extends Throwable> exception = YarnRemoteException.class;
|
||||||
|
String className = "UnknownException.class";
|
||||||
|
verifyRemoteExceptionUnwrapping(exception, className);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoteIOExceptionUnwrapping() {
|
||||||
|
Class<? extends Throwable> exception = IOException.class;
|
||||||
|
verifyRemoteExceptionUnwrapping(exception, exception.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoteIOExceptionDerivativeUnwrapping() {
|
||||||
|
// Test IOException sub-class
|
||||||
|
Class<? extends Throwable> exception = FileNotFoundException.class;
|
||||||
|
verifyRemoteExceptionUnwrapping(exception, exception.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoteYarnExceptionUnwrapping() {
|
||||||
|
Class<? extends Throwable> exception = YarnRemoteException.class;
|
||||||
|
verifyRemoteExceptionUnwrapping(exception, exception.getName());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoteYarnExceptionDerivativeUnwrapping() {
|
||||||
|
Class<? extends Throwable> exception = YarnTestException.class;
|
||||||
|
verifyRemoteExceptionUnwrapping(exception, exception.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUnexpectedRemoteExceptionUnwrapping() {
|
||||||
|
// Non IOException, YarnException thrown by the remote side.
|
||||||
|
Class<? extends Throwable> exception = Exception.class;
|
||||||
|
verifyRemoteExceptionUnwrapping(RemoteException.class, exception.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoteYarnExceptionWithoutStringConstructor() {
|
||||||
|
// Derivatives of YarnException should always defined a string constructor.
|
||||||
|
Class<? extends Throwable> 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<? extends Throwable> 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;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -59,7 +59,8 @@ private ResourceTrackerPB proxy;
|
||||||
try {
|
try {
|
||||||
return new RegisterNodeManagerResponsePBImpl(proxy.registerNodeManager(null, requestProto));
|
return new RegisterNodeManagerResponsePBImpl(proxy.registerNodeManager(null, requestProto));
|
||||||
} catch (ServiceException e) {
|
} catch (ServiceException e) {
|
||||||
throw RPCUtil.unwrapAndThrowException(e);
|
RPCUtil.unwrapAndThrowException(e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +71,8 @@ private ResourceTrackerPB proxy;
|
||||||
try {
|
try {
|
||||||
return new NodeHeartbeatResponsePBImpl(proxy.nodeHeartbeat(null, requestProto));
|
return new NodeHeartbeatResponsePBImpl(proxy.nodeHeartbeat(null, requestProto));
|
||||||
} catch (ServiceException e) {
|
} catch (ServiceException e) {
|
||||||
throw RPCUtil.unwrapAndThrowException(e);
|
RPCUtil.unwrapAndThrowException(e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,8 @@ public class LocalizationProtocolPBClientImpl implements LocalizationProtocol,
|
||||||
return new LocalizerHeartbeatResponsePBImpl(
|
return new LocalizerHeartbeatResponsePBImpl(
|
||||||
proxy.heartbeat(null, statusProto));
|
proxy.heartbeat(null, statusProto));
|
||||||
} catch (ServiceException e) {
|
} catch (ServiceException e) {
|
||||||
throw RPCUtil.unwrapAndThrowException(e);
|
RPCUtil.unwrapAndThrowException(e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,11 +17,19 @@
|
||||||
|
|
||||||
package org.apache.hadoop.yarn.server.resourcemanager;
|
package org.apache.hadoop.yarn.server.resourcemanager;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.mockito.Mockito.*;
|
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.io.IOException;
|
||||||
import java.lang.reflect.UndeclaredThrowableException;
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.security.PrivilegedAction;
|
import java.security.PrivilegedAction;
|
||||||
|
@ -40,6 +48,7 @@ import org.apache.hadoop.security.SecurityUtil;
|
||||||
import org.apache.hadoop.security.UserGroupInformation;
|
import org.apache.hadoop.security.UserGroupInformation;
|
||||||
import org.apache.hadoop.security.UserGroupInformation.AuthenticationMethod;
|
import org.apache.hadoop.security.UserGroupInformation.AuthenticationMethod;
|
||||||
import org.apache.hadoop.security.token.SecretManager;
|
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.Token;
|
||||||
import org.apache.hadoop.security.token.TokenIdentifier;
|
import org.apache.hadoop.security.token.TokenIdentifier;
|
||||||
import org.apache.hadoop.yarn.api.ClientRMProtocol;
|
import org.apache.hadoop.yarn.api.ClientRMProtocol;
|
||||||
|
@ -72,8 +81,7 @@ public class TestClientRMTokens {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDelegationToken() throws IOException, InterruptedException,
|
public void testDelegationToken() throws IOException, InterruptedException {
|
||||||
YarnRemoteException {
|
|
||||||
|
|
||||||
final YarnConfiguration conf = new YarnConfiguration();
|
final YarnConfiguration conf = new YarnConfiguration();
|
||||||
conf.set(YarnConfiguration.RM_PRINCIPAL, "testuser/localhost@apache.org");
|
conf.set(YarnConfiguration.RM_PRINCIPAL, "testuser/localhost@apache.org");
|
||||||
|
@ -123,7 +131,9 @@ public class TestClientRMTokens {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
clientRMWithDT.getNewApplication(request);
|
clientRMWithDT.getNewApplication(request);
|
||||||
} catch (UndeclaredThrowableException e) {
|
} catch (IOException e) {
|
||||||
|
fail("Unexpected exception" + e);
|
||||||
|
} catch (YarnRemoteException e) {
|
||||||
fail("Unexpected exception" + e);
|
fail("Unexpected exception" + e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,7 +156,9 @@ public class TestClientRMTokens {
|
||||||
// Valid token because of renewal.
|
// Valid token because of renewal.
|
||||||
try {
|
try {
|
||||||
clientRMWithDT.getNewApplication(request);
|
clientRMWithDT.getNewApplication(request);
|
||||||
} catch (UndeclaredThrowableException e) {
|
} catch (IOException e) {
|
||||||
|
fail("Unexpected exception" + e);
|
||||||
|
} catch (YarnRemoteException e) {
|
||||||
fail("Unexpected exception" + e);
|
fail("Unexpected exception" + e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,8 +172,9 @@ public class TestClientRMTokens {
|
||||||
try {
|
try {
|
||||||
clientRMWithDT.getNewApplication(request);
|
clientRMWithDT.getNewApplication(request);
|
||||||
fail("Should not have succeeded with an expired token");
|
fail("Should not have succeeded with an expired token");
|
||||||
} catch (UndeclaredThrowableException e) {
|
} catch (Exception e) {
|
||||||
assertTrue(e.getCause().getMessage().contains("is expired"));
|
assertEquals(InvalidToken.class.getName(), e.getClass().getName());
|
||||||
|
assertTrue(e.getMessage().contains("is expired"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test cancellation
|
// Test cancellation
|
||||||
|
@ -183,7 +196,9 @@ public class TestClientRMTokens {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
clientRMWithDT.getNewApplication(request);
|
clientRMWithDT.getNewApplication(request);
|
||||||
} catch (UndeclaredThrowableException e) {
|
} catch (IOException e) {
|
||||||
|
fail("Unexpected exception" + e);
|
||||||
|
} catch (YarnRemoteException e) {
|
||||||
fail("Unexpected exception" + e);
|
fail("Unexpected exception" + e);
|
||||||
}
|
}
|
||||||
cancelDelegationToken(loggedInUser, clientRMService, token);
|
cancelDelegationToken(loggedInUser, clientRMService, token);
|
||||||
|
@ -200,7 +215,8 @@ public class TestClientRMTokens {
|
||||||
try {
|
try {
|
||||||
clientRMWithDT.getNewApplication(request);
|
clientRMWithDT.getNewApplication(request);
|
||||||
fail("Should not have succeeded with a cancelled delegation token");
|
fail("Should not have succeeded with a cancelled delegation token");
|
||||||
} catch (UndeclaredThrowableException e) {
|
} catch (IOException e) {
|
||||||
|
} catch (YarnRemoteException e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -25,12 +25,15 @@ import java.lang.annotation.Annotation;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.security.PrivilegedExceptionAction;
|
import java.security.PrivilegedExceptionAction;
|
||||||
|
|
||||||
|
import javax.security.sasl.SaslException;
|
||||||
|
|
||||||
import junit.framework.Assert;
|
import junit.framework.Assert;
|
||||||
|
|
||||||
import org.apache.commons.codec.binary.Base64;
|
import org.apache.commons.codec.binary.Base64;
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
import org.apache.hadoop.fs.CommonConfigurationKeysPublic;
|
import org.apache.hadoop.fs.CommonConfigurationKeysPublic;
|
||||||
import org.apache.hadoop.ipc.RPC;
|
import org.apache.hadoop.ipc.RPC;
|
||||||
|
import org.apache.hadoop.ipc.RemoteException;
|
||||||
import org.apache.hadoop.ipc.Server;
|
import org.apache.hadoop.ipc.Server;
|
||||||
import org.apache.hadoop.net.NetUtils;
|
import org.apache.hadoop.net.NetUtils;
|
||||||
import org.apache.hadoop.security.KerberosInfo;
|
import org.apache.hadoop.security.KerberosInfo;
|
||||||
|
@ -53,7 +56,6 @@ import org.apache.hadoop.yarn.api.protocolrecords.StartContainerResponse;
|
||||||
import org.apache.hadoop.yarn.api.protocolrecords.StopContainerRequest;
|
import org.apache.hadoop.yarn.api.protocolrecords.StopContainerRequest;
|
||||||
import org.apache.hadoop.yarn.api.protocolrecords.StopContainerResponse;
|
import org.apache.hadoop.yarn.api.protocolrecords.StopContainerResponse;
|
||||||
import org.apache.hadoop.yarn.api.records.ApplicationAttemptId;
|
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.ApplicationReport;
|
||||||
import org.apache.hadoop.yarn.api.records.ClientToken;
|
import org.apache.hadoop.yarn.api.records.ClientToken;
|
||||||
import org.apache.hadoop.yarn.event.Dispatcher;
|
import org.apache.hadoop.yarn.event.Dispatcher;
|
||||||
|
@ -76,9 +78,10 @@ import org.junit.Test;
|
||||||
public class TestClientTokens {
|
public class TestClientTokens {
|
||||||
|
|
||||||
private interface CustomProtocol {
|
private interface CustomProtocol {
|
||||||
|
@SuppressWarnings("unused")
|
||||||
public static final long versionID = 1L;
|
public static final long versionID = 1L;
|
||||||
|
|
||||||
public void ping() throws YarnRemoteException;
|
public void ping() throws YarnRemoteException, IOException;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class CustomSecurityInfo extends SecurityInfo {
|
private static class CustomSecurityInfo extends SecurityInfo {
|
||||||
|
@ -121,7 +124,7 @@ public class TestClientTokens {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void ping() throws YarnRemoteException {
|
public void ping() throws YarnRemoteException, IOException {
|
||||||
this.pinged = true;
|
this.pinged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,11 +292,13 @@ public class TestClientTokens {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
Assert.assertEquals(RemoteException.class.getName(), e.getClass()
|
||||||
|
.getName());
|
||||||
|
e = ((RemoteException)e).unwrapRemoteException();
|
||||||
Assert
|
Assert
|
||||||
.assertEquals(java.lang.reflect.UndeclaredThrowableException.class
|
.assertEquals(SaslException.class
|
||||||
.getCanonicalName(), e.getClass().getCanonicalName());
|
.getCanonicalName(), e.getClass().getCanonicalName());
|
||||||
Assert.assertTrue(e
|
Assert.assertTrue(e
|
||||||
.getCause()
|
|
||||||
.getMessage()
|
.getMessage()
|
||||||
.contains(
|
.contains(
|
||||||
"DIGEST-MD5: digest response format violation. "
|
"DIGEST-MD5: digest response format violation. "
|
||||||
|
|
|
@ -247,10 +247,9 @@ public class TestContainerManagerSecurity {
|
||||||
+ "it will indicate RPC success");
|
+ "it will indicate RPC success");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Assert.assertEquals(
|
Assert.assertEquals(
|
||||||
java.lang.reflect.UndeclaredThrowableException.class
|
javax.security.sasl.SaslException.class
|
||||||
.getCanonicalName(), e.getClass().getCanonicalName());
|
.getCanonicalName(), e.getClass().getCanonicalName());
|
||||||
Assert.assertTrue(e
|
Assert.assertTrue(e
|
||||||
.getCause()
|
|
||||||
.getMessage()
|
.getMessage()
|
||||||
.contains(
|
.contains(
|
||||||
"DIGEST-MD5: digest response format violation. "
|
"DIGEST-MD5: digest response format violation. "
|
||||||
|
|
Loading…
Reference in New Issue