HADOOP-14982. Clients using FailoverOnNetworkExceptionRetry can go into a loop if they're used without authenticating with kerberos in HA env (pbacsko via rkanter)
This commit is contained in:
parent
6bf2c30192
commit
f2efaf013f
|
@ -32,11 +32,14 @@ import java.util.Map.Entry;
|
|||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.security.sasl.SaslException;
|
||||
|
||||
import org.apache.hadoop.ipc.RemoteException;
|
||||
import org.apache.hadoop.ipc.RetriableException;
|
||||
import org.apache.hadoop.ipc.StandbyException;
|
||||
import org.apache.hadoop.net.ConnectTimeoutException;
|
||||
import org.apache.hadoop.security.token.SecretManager.InvalidToken;
|
||||
import org.ietf.jgss.GSSException;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -663,6 +666,11 @@ public class RetryPolicies {
|
|||
+ retries + ") exceeded maximum allowed (" + maxRetries + ")");
|
||||
}
|
||||
|
||||
if (isSaslFailure(e)) {
|
||||
return new RetryAction(RetryAction.RetryDecision.FAIL, 0,
|
||||
"SASL failure");
|
||||
}
|
||||
|
||||
if (e instanceof ConnectException ||
|
||||
e instanceof EOFException ||
|
||||
e instanceof NoRouteToHostException ||
|
||||
|
@ -716,7 +724,7 @@ public class RetryPolicies {
|
|||
private static long calculateExponentialTime(long time, int retries) {
|
||||
return calculateExponentialTime(time, retries, Long.MAX_VALUE);
|
||||
}
|
||||
|
||||
|
||||
private static boolean isWrappedStandbyException(Exception e) {
|
||||
if (!(e instanceof RemoteException)) {
|
||||
return false;
|
||||
|
@ -725,6 +733,18 @@ public class RetryPolicies {
|
|||
StandbyException.class);
|
||||
return unwrapped instanceof StandbyException;
|
||||
}
|
||||
|
||||
private static boolean isSaslFailure(Exception e) {
|
||||
Throwable current = e;
|
||||
do {
|
||||
if (current instanceof SaslException) {
|
||||
return true;
|
||||
}
|
||||
current = current.getCause();
|
||||
} while (current != null);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static RetriableException getWrappedRetriableException(Exception e) {
|
||||
if (!(e instanceof RemoteException)) {
|
||||
|
|
|
@ -39,6 +39,8 @@ import java.util.concurrent.*;
|
|||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import javax.security.sasl.SaslException;
|
||||
|
||||
import static org.apache.hadoop.io.retry.RetryPolicies.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Matchers.any;
|
||||
|
@ -326,4 +328,24 @@ public class TestRetryProxy {
|
|||
assertEquals(InterruptedException.class, e.getCause().getClass());
|
||||
assertEquals("sleep interrupted", e.getCause().getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoRetryOnSaslError() throws Exception {
|
||||
RetryPolicy policy = mock(RetryPolicy.class);
|
||||
RetryPolicy realPolicy = RetryPolicies.failoverOnNetworkException(5);
|
||||
setupMockPolicy(policy, realPolicy);
|
||||
|
||||
UnreliableInterface unreliable = (UnreliableInterface) RetryProxy.create(
|
||||
UnreliableInterface.class, unreliableImpl, policy);
|
||||
|
||||
try {
|
||||
unreliable.failsWithSASLExceptionTenTimes();
|
||||
fail("Should fail");
|
||||
} catch (SaslException e) {
|
||||
// expected
|
||||
verify(policy, times(1)).shouldRetry(any(Exception.class), anyInt(),
|
||||
anyInt(), anyBoolean());
|
||||
assertEquals(RetryDecision.FAIL, caughtRetryAction.action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,8 @@ package org.apache.hadoop.io.retry;
|
|||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.security.sasl.SaslException;
|
||||
|
||||
import org.apache.hadoop.ipc.RemoteException;
|
||||
import org.apache.hadoop.ipc.StandbyException;
|
||||
|
||||
|
@ -29,6 +31,7 @@ class UnreliableImplementation implements UnreliableInterface {
|
|||
failsOnceIOExceptionInvocationCount,
|
||||
failsOnceRemoteExceptionInvocationCount,
|
||||
failsTenTimesInvocationCount,
|
||||
failsWithSASLExceptionTenTimesInvocationCount,
|
||||
succeedsOnceThenFailsCount,
|
||||
succeedsOnceThenFailsIdempotentCount,
|
||||
succeedsTenTimesThenFailsCount;
|
||||
|
@ -113,6 +116,13 @@ class UnreliableImplementation implements UnreliableInterface {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failsWithSASLExceptionTenTimes() throws SaslException {
|
||||
if (failsWithSASLExceptionTenTimesInvocationCount ++ < 10) {
|
||||
throw new SaslException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String succeedsOnceThenFailsReturningString()
|
||||
throws UnreliableException, IOException, StandbyException {
|
||||
|
|
|
@ -20,6 +20,8 @@ package org.apache.hadoop.io.retry;
|
|||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.security.sasl.SaslException;
|
||||
|
||||
import org.apache.hadoop.ipc.RemoteException;
|
||||
import org.apache.hadoop.ipc.StandbyException;
|
||||
|
||||
|
@ -61,7 +63,9 @@ public interface UnreliableInterface {
|
|||
boolean failsOnceThenSucceedsWithReturnValue() throws UnreliableException;
|
||||
|
||||
void failsTenTimesThenSucceeds() throws UnreliableException;
|
||||
|
||||
|
||||
void failsWithSASLExceptionTenTimes() throws SaslException;
|
||||
|
||||
public String succeedsOnceThenFailsReturningString()
|
||||
throws UnreliableException, StandbyException, IOException;
|
||||
@Idempotent
|
||||
|
|
Loading…
Reference in New Issue