|
@@ -20,15 +20,22 @@ import org.apache.hadoop.conf.Configuration;
|
|
|
import org.apache.hadoop.fs.CommonConfigurationKeysPublic;
|
|
|
import org.apache.hadoop.fs.Path;
|
|
|
import org.apache.hadoop.io.Text;
|
|
|
+import org.apache.hadoop.io.retry.RetryPolicies;
|
|
|
+import org.apache.hadoop.io.retry.RetryPolicy;
|
|
|
import org.apache.hadoop.metrics2.MetricsRecordBuilder;
|
|
|
import org.apache.hadoop.security.SaslRpcServer.AuthMethod;
|
|
|
import org.apache.hadoop.security.UserGroupInformation.AuthenticationMethod;
|
|
|
import org.apache.hadoop.security.authentication.util.KerberosName;
|
|
|
import org.apache.hadoop.security.token.Token;
|
|
|
import org.apache.hadoop.security.token.TokenIdentifier;
|
|
|
+import org.apache.hadoop.test.GenericTestUtils;
|
|
|
import org.apache.hadoop.util.Shell;
|
|
|
import org.apache.hadoop.util.StringUtils;
|
|
|
+import org.apache.hadoop.util.Time;
|
|
|
+import org.apache.log4j.Level;
|
|
|
import org.junit.*;
|
|
|
+import org.slf4j.Logger;
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
|
|
|
import javax.security.auth.Subject;
|
|
|
import javax.security.auth.kerberos.KerberosPrincipal;
|
|
@@ -44,10 +51,13 @@ import java.lang.reflect.Method;
|
|
|
import java.security.PrivilegedExceptionAction;
|
|
|
import java.util.Collection;
|
|
|
import java.util.ConcurrentModificationException;
|
|
|
+import java.util.Date;
|
|
|
import java.util.LinkedHashSet;
|
|
|
import java.util.Set;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
|
|
|
import static org.apache.hadoop.fs.CommonConfigurationKeys.HADOOP_USER_GROUP_METRICS_PERCENTILES_INTERVALS;
|
|
|
+import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.HADOOP_KERBEROS_MIN_SECONDS_BEFORE_RELOGIN;
|
|
|
import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTH_TO_LOCAL;
|
|
|
import static org.apache.hadoop.ipc.TestSaslRPC.*;
|
|
|
import static org.apache.hadoop.test.MetricsAsserts.*;
|
|
@@ -56,6 +66,9 @@ import static org.mockito.Mockito.mock;
|
|
|
import static org.mockito.Mockito.when;
|
|
|
|
|
|
public class TestUserGroupInformation {
|
|
|
+
|
|
|
+ static final Logger LOG = LoggerFactory.getLogger(
|
|
|
+ TestUserGroupInformation.class);
|
|
|
final private static String USER_NAME = "user1@HADOOP.APACHE.ORG";
|
|
|
final private static String GROUP1_NAME = "group1";
|
|
|
final private static String GROUP2_NAME = "group2";
|
|
@@ -1011,4 +1024,85 @@ public class TestUserGroupInformation {
|
|
|
// Restore hasSufficientTimElapsed back to private
|
|
|
method.setAccessible(false);
|
|
|
}
|
|
|
+
|
|
|
+ @Test
|
|
|
+ public void testGetNextRetryTime() throws Exception {
|
|
|
+ GenericTestUtils.setLogLevel(UserGroupInformation.LOG, Level.DEBUG);
|
|
|
+ final long reloginInterval = 1;
|
|
|
+ final long reloginIntervalMs = reloginInterval * 1000;
|
|
|
+ // Relogin happens every 1 second.
|
|
|
+ conf.setLong(HADOOP_KERBEROS_MIN_SECONDS_BEFORE_RELOGIN, reloginInterval);
|
|
|
+ SecurityUtil.setAuthenticationMethod(AuthenticationMethod.KERBEROS, conf);
|
|
|
+ UserGroupInformation.setConfiguration(conf);
|
|
|
+
|
|
|
+ // Suppose tgt start time is now, end time is 20 seconds from now.
|
|
|
+ final long now = Time.now();
|
|
|
+ final Date endDate = new Date(now + 20000);
|
|
|
+
|
|
|
+ // Explicitly test the exponential back-off logic.
|
|
|
+ // Suppose some time (10 seconds) passed.
|
|
|
+ // Verify exponential backoff and max=(login interval before endTime).
|
|
|
+ final long currentTime = now + 10000;
|
|
|
+ final long endTime = endDate.getTime();
|
|
|
+
|
|
|
+ assertEquals(0, UserGroupInformation.metrics.getRenewalFailures().value());
|
|
|
+ RetryPolicy rp = RetryPolicies.exponentialBackoffRetry(Long.SIZE - 2,
|
|
|
+ 1000, TimeUnit.MILLISECONDS);
|
|
|
+ long lastRetry =
|
|
|
+ UserGroupInformation.getNextTgtRenewalTime(endTime, currentTime, rp);
|
|
|
+ assertWithinBounds(
|
|
|
+ UserGroupInformation.metrics.getRenewalFailures().value(),
|
|
|
+ lastRetry, reloginIntervalMs, currentTime);
|
|
|
+
|
|
|
+ UserGroupInformation.metrics.getRenewalFailures().incr();
|
|
|
+ lastRetry =
|
|
|
+ UserGroupInformation.getNextTgtRenewalTime(endTime, currentTime, rp);
|
|
|
+ assertWithinBounds(
|
|
|
+ UserGroupInformation.metrics.getRenewalFailures().value(),
|
|
|
+ lastRetry, reloginIntervalMs, currentTime);
|
|
|
+
|
|
|
+ UserGroupInformation.metrics.getRenewalFailures().incr();
|
|
|
+ lastRetry =
|
|
|
+ UserGroupInformation.getNextTgtRenewalTime(endTime, currentTime, rp);
|
|
|
+ assertWithinBounds(
|
|
|
+ UserGroupInformation.metrics.getRenewalFailures().value(),
|
|
|
+ lastRetry, reloginIntervalMs, currentTime);
|
|
|
+
|
|
|
+ UserGroupInformation.metrics.getRenewalFailures().incr();
|
|
|
+ lastRetry =
|
|
|
+ UserGroupInformation.getNextTgtRenewalTime(endTime, currentTime, rp);
|
|
|
+ assertWithinBounds(
|
|
|
+ UserGroupInformation.metrics.getRenewalFailures().value(),
|
|
|
+ lastRetry, reloginIntervalMs, currentTime);
|
|
|
+
|
|
|
+ // last try should be right before expiry.
|
|
|
+ UserGroupInformation.metrics.getRenewalFailures().incr();
|
|
|
+ lastRetry =
|
|
|
+ UserGroupInformation.getNextTgtRenewalTime(endTime, currentTime, rp);
|
|
|
+ String str =
|
|
|
+ "5th retry, now:" + currentTime + ", retry:" + lastRetry;
|
|
|
+ LOG.info(str);
|
|
|
+ assertEquals(str, endTime - reloginIntervalMs, lastRetry);
|
|
|
+
|
|
|
+ // make sure no more retries after (tgt endTime - login interval).
|
|
|
+ UserGroupInformation.metrics.getRenewalFailures().incr();
|
|
|
+ lastRetry =
|
|
|
+ UserGroupInformation.getNextTgtRenewalTime(endTime, currentTime, rp);
|
|
|
+ str = "overflow retry, now:" + currentTime + ", retry:" + lastRetry;
|
|
|
+ LOG.info(str);
|
|
|
+ assertEquals(str, endTime - reloginIntervalMs, lastRetry);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void assertWithinBounds(final int numFailures, final long lastRetry,
|
|
|
+ final long reloginIntervalMs, long now) {
|
|
|
+ // shift is 2 to the power of (numFailure).
|
|
|
+ int shift = numFailures + 1;
|
|
|
+ final long lower = now + reloginIntervalMs * (long)((1 << shift) * 0.5);
|
|
|
+ final long upper = now + reloginIntervalMs * (long)((1 << shift) * 1.5);
|
|
|
+ final String str = new String("Retry#" + (numFailures + 1) + ", now:" + now
|
|
|
+ + ", lower bound:" + lower + ", upper bound:" + upper
|
|
|
+ + ", retry:" + lastRetry);
|
|
|
+ LOG.info(str);
|
|
|
+ assertTrue(str, lower <= lastRetry && lastRetry < upper);
|
|
|
+ }
|
|
|
}
|