|
30 | 30 | import io.cdap.cdap.etl.api.exception.ErrorContext; |
31 | 31 |
|
32 | 32 | import java.io.IOException; |
| 33 | +import java.util.HashMap; |
33 | 34 | import java.util.List; |
| 35 | +import java.util.Map; |
34 | 36 | import javax.annotation.Nullable; |
35 | 37 |
|
36 | 38 | /** |
37 | 39 | * Common functions for GCP error details provider related functionalities. |
38 | 40 | */ |
39 | 41 | public final class GCPErrorDetailsProviderUtil { |
40 | 42 |
|
| 43 | + public static final Map<Integer, Integer> GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP = new HashMap<>(); |
| 44 | + |
| 45 | + static { |
| 46 | + // https://github.com/grpc/grpc/blob/master/doc/statuscodes.md |
| 47 | + // OK 0 <--> HTTP 200 (OK) |
| 48 | + GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP.put(0, 200); |
| 49 | + // CANCELLED 1 <--> HTTP 499 (Client Closed Request) |
| 50 | + GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP.put(1, 499); |
| 51 | + // UNKNOWN 2 <--> HTTP 500 (Internal Server Error) |
| 52 | + GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP.put(2, 500); |
| 53 | + // INVALID_ARGUMENT 3 <--> HTTP 400 (Bad Request) |
| 54 | + GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP.put(3, 400); |
| 55 | + // DEADLINE_EXCEEDED 4 <--> HTTP 504 (Gateway Timeout) |
| 56 | + GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP.put(4, 504); |
| 57 | + // NOT_FOUND 5 <--> HTTP 404 (Not Found) |
| 58 | + GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP.put(5, 404); |
| 59 | + // ALREADY_EXISTS 6 <--> HTTP 409 (Conflict) |
| 60 | + GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP.put(6, 409); |
| 61 | + // PERMISSION_DENIED 7 <--> HTTP 403 (Forbidden) |
| 62 | + GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP.put(7, 403); |
| 63 | + // RESOURCE_EXHAUSTED 8 <--> HTTP 429 (Too Many Requests) |
| 64 | + GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP.put(8, 429); |
| 65 | + // FAILED_PRECONDITION 9 <--> HTTP 400 (Bad Request) |
| 66 | + GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP.put(9, 400); |
| 67 | + // ABORTED 10 <--> HTTP 409 (Conflict) |
| 68 | + GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP.put(10, 409); |
| 69 | + // OUT_OF_RANGE 11 <--> HTTP 400 (Bad Request) |
| 70 | + GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP.put(11, 400); |
| 71 | + // UNIMPLEMENTED 12 <--> HTTP 501 (Not Implemented) |
| 72 | + GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP.put(12, 501); |
| 73 | + // INTERNAL 13 <--> HTTP 500 (Internal Server Error) |
| 74 | + GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP.put(13, 500); |
| 75 | + // UNAVAILABLE 14 <--> HTTP 503 (Service Unavailable) |
| 76 | + GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP.put(14, 503); |
| 77 | + // DATA_LOSS 15 <--> HTTP 500 (Internal Server Error) |
| 78 | + GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP.put(15, 500); |
| 79 | + // UNAUTHENTICATED 16 <--> HTTP 401 (Unauthorized) |
| 80 | + GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP.put(16, 401); |
| 81 | + } |
| 82 | + |
| 83 | + |
41 | 84 | /** |
42 | 85 | * Get a ProgramFailureException with the given error |
43 | 86 | * information from {@link HttpResponseException}. |
@@ -130,4 +173,39 @@ private static String getErrorMessage(GoogleJsonResponseException exception) { |
130 | 173 | } |
131 | 174 | return exception.getMessage(); |
132 | 175 | } |
| 176 | + |
| 177 | + |
| 178 | + /** |
| 179 | + * Get the HTTP status code for a given gRPC error code. |
| 180 | + * |
| 181 | + * @param grpcStatusCode the int value of the gRPC error code |
| 182 | + */ |
| 183 | + public static ErrorUtils.ActionErrorPair getActionErrorByGrpcStatusCode(int grpcStatusCode) { |
| 184 | + if (!GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP.containsKey(grpcStatusCode)) { |
| 185 | + return null; |
| 186 | + } |
| 187 | + return ErrorUtils.getActionErrorByStatusCode(GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP.get(grpcStatusCode)); |
| 188 | + } |
| 189 | + |
| 190 | + public static ProgramFailureException getProgramFailureExceptionByGrpcStatusCode(int grpcErrorCodeValue, |
| 191 | + String grpcErrorReason, String grpcErrorMessage, String supportedDocUrl, Exception se) { |
| 192 | + int httpStatusCode = GCPErrorDetailsProviderUtil.GCP_GRPC_ERROR_CODE_HTTP_STATUS_CODE_MAP.get(grpcErrorCodeValue); |
| 193 | + ErrorUtils.ActionErrorPair actionErrorPair = GCPErrorDetailsProviderUtil.getActionErrorByGrpcStatusCode( |
| 194 | + grpcErrorCodeValue); |
| 195 | + String errorReason = grpcErrorReason; |
| 196 | + if (actionErrorPair != null) { |
| 197 | + errorReason = String.format("%s %s. %s", httpStatusCode, grpcErrorMessage, actionErrorPair.getCorrectiveAction()); |
| 198 | + } |
| 199 | + if (!errorReason.endsWith(".")) { |
| 200 | + errorReason = errorReason + "."; |
| 201 | + } |
| 202 | + errorReason = String.format("%s For more details, see %s.", errorReason, supportedDocUrl); |
| 203 | + |
| 204 | + String errorMessageWithCode = String.format("[ErrorCode='%s'] %s", httpStatusCode, grpcErrorMessage); |
| 205 | + return ErrorUtils.getProgramFailureException(new ErrorCategory(ErrorCategory.ErrorCategoryEnum.PLUGIN), errorReason, |
| 206 | + String.format("%s: %s", se.getClass().getName(), errorMessageWithCode), |
| 207 | + actionErrorPair != null ? actionErrorPair.getErrorType() : ErrorType.UNKNOWN, true, ErrorCodeType.HTTP, |
| 208 | + String.valueOf(httpStatusCode), supportedDocUrl, se); |
| 209 | + } |
| 210 | + |
133 | 211 | } |
0 commit comments