|
@@ -18,9 +18,11 @@
|
|
|
|
|
|
package org.apache.hadoop.fs.azurebfs.oauth2;
|
|
package org.apache.hadoop.fs.azurebfs.oauth2;
|
|
|
|
|
|
|
|
+import java.io.FileNotFoundException;
|
|
import java.io.IOException;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.io.InputStream;
|
|
import java.net.HttpURLConnection;
|
|
import java.net.HttpURLConnection;
|
|
|
|
+import java.net.MalformedURLException;
|
|
import java.net.URL;
|
|
import java.net.URL;
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.util.Date;
|
|
import java.util.Date;
|
|
@@ -34,6 +36,7 @@ import org.codehaus.jackson.JsonToken;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
|
|
|
|
+import org.apache.hadoop.fs.azurebfs.AbfsConfiguration;
|
|
import org.apache.hadoop.classification.InterfaceAudience;
|
|
import org.apache.hadoop.classification.InterfaceAudience;
|
|
import org.apache.hadoop.classification.InterfaceStability;
|
|
import org.apache.hadoop.classification.InterfaceStability;
|
|
import org.apache.hadoop.fs.azurebfs.services.AbfsIoUtils;
|
|
import org.apache.hadoop.fs.azurebfs.services.AbfsIoUtils;
|
|
@@ -56,10 +59,16 @@ public final class AzureADAuthenticator {
|
|
private static final int CONNECT_TIMEOUT = 30 * 1000;
|
|
private static final int CONNECT_TIMEOUT = 30 * 1000;
|
|
private static final int READ_TIMEOUT = 30 * 1000;
|
|
private static final int READ_TIMEOUT = 30 * 1000;
|
|
|
|
|
|
|
|
+ private static ExponentialRetryPolicy tokenFetchRetryPolicy;
|
|
|
|
+
|
|
private AzureADAuthenticator() {
|
|
private AzureADAuthenticator() {
|
|
// no operation
|
|
// no operation
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ public static void init(AbfsConfiguration abfsConfiguration) {
|
|
|
|
+ tokenFetchRetryPolicy = abfsConfiguration.getOauthTokenFetchRetryPolicy();
|
|
|
|
+ }
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* gets Azure Active Directory token using the user ID and password of
|
|
* gets Azure Active Directory token using the user ID and password of
|
|
* a service principal (that is, Web App in Azure Active Directory).
|
|
* a service principal (that is, Web App in Azure Active Directory).
|
|
@@ -81,8 +90,7 @@ public final class AzureADAuthenticator {
|
|
* @throws IOException throws IOException if there is a failure in connecting to Azure AD
|
|
* @throws IOException throws IOException if there is a failure in connecting to Azure AD
|
|
*/
|
|
*/
|
|
public static AzureADToken getTokenUsingClientCreds(String authEndpoint,
|
|
public static AzureADToken getTokenUsingClientCreds(String authEndpoint,
|
|
- String clientId, String clientSecret)
|
|
|
|
- throws IOException {
|
|
|
|
|
|
+ String clientId, String clientSecret) throws IOException {
|
|
Preconditions.checkNotNull(authEndpoint, "authEndpoint");
|
|
Preconditions.checkNotNull(authEndpoint, "authEndpoint");
|
|
Preconditions.checkNotNull(clientId, "clientId");
|
|
Preconditions.checkNotNull(clientId, "clientId");
|
|
Preconditions.checkNotNull(clientSecret, "clientSecret");
|
|
Preconditions.checkNotNull(clientSecret, "clientSecret");
|
|
@@ -283,13 +291,14 @@ public final class AzureADAuthenticator {
|
|
Hashtable<String, String> headers, String httpMethod, boolean isMsi)
|
|
Hashtable<String, String> headers, String httpMethod, boolean isMsi)
|
|
throws IOException {
|
|
throws IOException {
|
|
AzureADToken token = null;
|
|
AzureADToken token = null;
|
|
- ExponentialRetryPolicy retryPolicy
|
|
|
|
- = new ExponentialRetryPolicy(3, 0, 1000, 2);
|
|
|
|
|
|
|
|
int httperror = 0;
|
|
int httperror = 0;
|
|
IOException ex = null;
|
|
IOException ex = null;
|
|
boolean succeeded = false;
|
|
boolean succeeded = false;
|
|
|
|
+ boolean isRecoverableFailure = true;
|
|
int retryCount = 0;
|
|
int retryCount = 0;
|
|
|
|
+ boolean shouldRetry;
|
|
|
|
+ LOG.trace("First execution of REST operation getTokenSingleCall");
|
|
do {
|
|
do {
|
|
httperror = 0;
|
|
httperror = 0;
|
|
ex = null;
|
|
ex = null;
|
|
@@ -299,17 +308,38 @@ public final class AzureADAuthenticator {
|
|
httperror = e.httpErrorCode;
|
|
httperror = e.httpErrorCode;
|
|
ex = e;
|
|
ex = e;
|
|
} catch (IOException e) {
|
|
} catch (IOException e) {
|
|
- ex = e;
|
|
|
|
|
|
+ httperror = -1;
|
|
|
|
+ isRecoverableFailure = isRecoverableFailure(e);
|
|
|
|
+ ex = new HttpException(httperror, "", String
|
|
|
|
+ .format("AzureADAuthenticator.getTokenCall threw %s : %s",
|
|
|
|
+ e.getClass().getTypeName(), e.getMessage()), authEndpoint, "",
|
|
|
|
+ "");
|
|
}
|
|
}
|
|
succeeded = ((httperror == 0) && (ex == null));
|
|
succeeded = ((httperror == 0) && (ex == null));
|
|
|
|
+ shouldRetry = !succeeded && isRecoverableFailure
|
|
|
|
+ && tokenFetchRetryPolicy.shouldRetry(retryCount, httperror);
|
|
retryCount++;
|
|
retryCount++;
|
|
- } while (!succeeded && retryPolicy.shouldRetry(retryCount, httperror));
|
|
|
|
|
|
+ if (shouldRetry) {
|
|
|
|
+ LOG.debug("Retrying getTokenSingleCall. RetryCount = {}", retryCount);
|
|
|
|
+ try {
|
|
|
|
+ Thread.sleep(tokenFetchRetryPolicy.getRetryInterval(retryCount));
|
|
|
|
+ } catch (InterruptedException e) {
|
|
|
|
+ Thread.currentThread().interrupt();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ } while (shouldRetry);
|
|
if (!succeeded) {
|
|
if (!succeeded) {
|
|
throw ex;
|
|
throw ex;
|
|
}
|
|
}
|
|
return token;
|
|
return token;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ private static boolean isRecoverableFailure(IOException e) {
|
|
|
|
+ return !(e instanceof MalformedURLException
|
|
|
|
+ || e instanceof FileNotFoundException);
|
|
|
|
+ }
|
|
|
|
+
|
|
private static AzureADToken getTokenSingleCall(String authEndpoint,
|
|
private static AzureADToken getTokenSingleCall(String authEndpoint,
|
|
String payload, Hashtable<String, String> headers, String httpMethod,
|
|
String payload, Hashtable<String, String> headers, String httpMethod,
|
|
boolean isMsi)
|
|
boolean isMsi)
|