HADOOP-15809. ABFS: better exception handling when making getAccessToken call.

Contributed by Da Zhou
This commit is contained in:
Steve Loughran 2018-10-05 11:29:03 +01:00
parent 94d82f4162
commit 273cc2d4e9
No known key found for this signature in database
GPG Key ID: D22CF846DBB162A0
3 changed files with 38 additions and 15 deletions

View File

@ -22,6 +22,7 @@
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.contracts.services.AzureServiceErrorCode; import org.apache.hadoop.fs.azurebfs.contracts.services.AzureServiceErrorCode;
import org.apache.hadoop.fs.azurebfs.oauth2.AzureADAuthenticator.HttpException;
import org.apache.hadoop.fs.azurebfs.services.AbfsHttpOperation; import org.apache.hadoop.fs.azurebfs.services.AbfsHttpOperation;
/** /**
@ -59,6 +60,14 @@ public AbfsRestOperationException(
this.errorMessage = errorMessage; this.errorMessage = errorMessage;
} }
public AbfsRestOperationException(final HttpException innerException) {
super(innerException.getMessage());
this.statusCode = innerException.getHttpErrorCode();
this.errorCode = AzureServiceErrorCode.UNKNOWN;
this.errorMessage = innerException.getMessage();
}
public int getStatusCode() { public int getStatusCode() {
return this.statusCode; return this.statusCode;
} }

View File

@ -161,14 +161,28 @@ public static AzureADToken getTokenUsingRefreshToken(String clientId,
return getTokenCall(authEndpoint, qp.serialize(), null, null); return getTokenCall(authEndpoint, qp.serialize(), null, null);
} }
private static class HttpException extends IOException {
/**
* This exception class contains the http error code,
* requestId and error message, it is thrown when AzureADAuthenticator
* failed to get the Azure Active Directory token.
*/
public static class HttpException extends IOException {
private int httpErrorCode; private int httpErrorCode;
private String requestId; private String requestId;
/**
* Gets Http error status code.
* @return http error code.
*/
public int getHttpErrorCode() { public int getHttpErrorCode() {
return this.httpErrorCode; return this.httpErrorCode;
} }
/**
* Gets http request id .
* @return http request id.
*/
public String getRequestId() { public String getRequestId() {
return this.requestId; return this.requestId;
} }
@ -188,21 +202,17 @@ private static AzureADToken getTokenCall(String authEndpoint, String body,
= new ExponentialRetryPolicy(3, 0, 1000, 2); = new ExponentialRetryPolicy(3, 0, 1000, 2);
int httperror = 0; int httperror = 0;
String requestId;
String httpExceptionMessage = null;
IOException ex = null; IOException ex = null;
boolean succeeded = false; boolean succeeded = false;
int retryCount = 0; int retryCount = 0;
do { do {
httperror = 0; httperror = 0;
requestId = "";
ex = null; ex = null;
try { try {
token = getTokenSingleCall(authEndpoint, body, headers, httpMethod); token = getTokenSingleCall(authEndpoint, body, headers, httpMethod);
} catch (HttpException e) { } catch (HttpException e) {
httperror = e.httpErrorCode; httperror = e.httpErrorCode;
requestId = e.requestId; ex = e;
httpExceptionMessage = e.getMessage();
} catch (IOException e) { } catch (IOException e) {
ex = e; ex = e;
} }
@ -210,13 +220,8 @@ private static AzureADToken getTokenCall(String authEndpoint, String body,
retryCount++; retryCount++;
} while (!succeeded && retryPolicy.shouldRetry(retryCount, httperror)); } while (!succeeded && retryPolicy.shouldRetry(retryCount, httperror));
if (!succeeded) { if (!succeeded) {
if (ex != null) {
throw ex; throw ex;
} }
if (httperror != 0) {
throw new IOException(httpExceptionMessage);
}
}
return token; return token;
} }
@ -263,7 +268,7 @@ private static AzureADToken getTokenSingleCall(
InputStream httpResponseStream = conn.getInputStream(); InputStream httpResponseStream = conn.getInputStream();
token = parseTokenFromStream(httpResponseStream); token = parseTokenFromStream(httpResponseStream);
} else { } else {
String responseBody = consumeInputStream(conn.getInputStream(), 1024); String responseBody = consumeInputStream(conn.getErrorStream(), 1024);
String proxies = "none"; String proxies = "none";
String httpProxy = System.getProperty("http.proxy"); String httpProxy = System.getProperty("http.proxy");
String httpsProxy = System.getProperty("https.proxy"); String httpsProxy = System.getProperty("https.proxy");
@ -273,11 +278,11 @@ private static AzureADToken getTokenSingleCall(
String logMessage = String logMessage =
"AADToken: HTTP connection failed for getting token from AzureAD. Http response: " "AADToken: HTTP connection failed for getting token from AzureAD. Http response: "
+ httpResponseCode + " " + conn.getResponseMessage() + httpResponseCode + " " + conn.getResponseMessage()
+ " Content-Type: " + responseContentType + "\nContent-Type: " + responseContentType
+ " Content-Length: " + responseContentLength + " Content-Length: " + responseContentLength
+ " Request ID: " + requestId.toString() + " Request ID: " + requestId.toString()
+ " Proxies: " + proxies + " Proxies: " + proxies
+ " First 1K of Body: " + responseBody; + "\nFirst 1K of Body: " + responseBody;
LOG.debug(logMessage); LOG.debug(logMessage);
throw new HttpException(httpResponseCode, requestId, logMessage); throw new HttpException(httpResponseCode, requestId, logMessage);
} }

View File

@ -31,6 +31,7 @@
import org.apache.hadoop.fs.azurebfs.contracts.exceptions.AzureBlobFileSystemException; import org.apache.hadoop.fs.azurebfs.contracts.exceptions.AzureBlobFileSystemException;
import org.apache.hadoop.fs.azurebfs.contracts.exceptions.InvalidAbfsRestOperationException; import org.apache.hadoop.fs.azurebfs.contracts.exceptions.InvalidAbfsRestOperationException;
import org.apache.hadoop.fs.azurebfs.constants.HttpHeaderConfigurations; import org.apache.hadoop.fs.azurebfs.constants.HttpHeaderConfigurations;
import org.apache.hadoop.fs.azurebfs.oauth2.AzureADAuthenticator.HttpException;
/** /**
* The AbfsRestOperation for Rest AbfsClient. * The AbfsRestOperation for Rest AbfsClient.
@ -175,6 +176,14 @@ private boolean executeHttpOperation(final int retryCount) throws AzureBlobFileS
if (!client.getRetryPolicy().shouldRetry(retryCount, -1)) { if (!client.getRetryPolicy().shouldRetry(retryCount, -1)) {
throw new InvalidAbfsRestOperationException(ex); throw new InvalidAbfsRestOperationException(ex);
} }
// once HttpException is thrown by AzureADAuthenticator,
// it indicates the policy in AzureADAuthenticator determined
// retry is not needed
if (ex instanceof HttpException) {
throw new AbfsRestOperationException((HttpException) ex);
}
return false; return false;
} finally { } finally {
AbfsClientThrottlingIntercept.updateMetrics(operationType, httpOperation); AbfsClientThrottlingIntercept.updateMetrics(operationType, httpOperation);