Last active
May 2, 2023 14:43
-
-
Save mpatnode/e06e2dba5d2c5d59a49f0bbe04d36e52 to your computer and use it in GitHub Desktop.
Generic Wrapper for AWSClient Builder to override the endpoint URL using environment variables
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.britive.util; | |
import static org.apache.commons.lang3.ObjectUtils.defaultIfNull; | |
import com.amazonaws.auth.AWSCredentialsProvider; | |
import com.amazonaws.auth.AWSStaticCredentialsProvider; | |
import com.amazonaws.auth.BasicAWSCredentials; | |
import com.amazonaws.client.builder.AwsClientBuilder; | |
import java.util.Collections; | |
import java.util.HashMap; | |
import java.util.Map; | |
/** | |
* This class allows global and selective endpoint override for the following services via | |
* an environment variable | |
* | |
* DynamoDB - AWS_DYNAMO_ENDPOINT_URL | |
* SNS - AWS_SNS_ENDPOINT_URL | |
* SQS - AWS_SQS_ENDPOINT_URL | |
* SES - AWS_SES_ENDPOINT_URL | |
* S3 - AWS_S3_ENDPOINT_URL | |
* KMS - AWS_KMS_ENDPOINT_URL | |
* Cognito - AWS_IAM_ENDPOINT_URL | |
* | |
* You can globally override for all services by setting AWS_ENDPOINT_URL, but the specific | |
* ones above will override when necessary. For example: | |
* | |
* AWS_ENDPOINT_URL=http://localstack:4566 | |
* AWS_S3_ENDPOINT_URL=http://s3.localhost.localstack.cloud:4566 | |
* | |
* The region for each endpoint can be set as well: | |
* | |
* AWS_IAM_REGION=us-west-2 | |
* AWS_KMS_REGION=us-east-1 | |
* | |
* Otherwise the value of AWS_REGION is used. | |
* | |
* Note you must wrap your current code with this decorator as described below in the build() method. | |
**/ | |
public class AWSClientEnvConfig { | |
private AWSClientEnvConfig() {}; | |
private static Map<String, String> envMap = Collections.unmodifiableMap( | |
new HashMap<String, String>() {{ | |
// By not using <classname>.class.getSimpleName() we avoid the need | |
// to import all the packages and dependencies into this module | |
put("AmazonDynamoDBClientBuilder", "AWS_DYNAMO_ENDPOINT_URL"); | |
put("AmazonIdentityManagementClientBuilder", "AWS_IAM_ENDPOINT_URL"); | |
put("AWSCognitoIdentityProviderClientBuilder", "AWS_IAM_ENDPOINT_URL"); | |
put("AmazonKinesisFirehoseClientBuilder", "AWS_KFIRE_ENDPOINT_URL"); | |
put("AmazonS3ClientBuilder", "AWS_S3_ENDPOINT_URL"); | |
put("AmazonSNSAsyncClientBuilder", "AWS_SNS_ENDPOINT_URL"); | |
put("AmazonSNSClientBuilder", "AWS_SNS_ENDPOINT_URL"); | |
put("AmazonSQSAsyncClientBuilder", "AWS_SQS_ENDPOINT_URL"); | |
put("AmazonSQSClientBuilder", "AWS_SQS_ENDPOINT_URL"); | |
put("AmazonSimpleEmailServiceClientBuilder", "AWS_SES_ENDPOINT_URL"); | |
put("AWSKMSClientBuilder", "AWS_KMS_ENDPOINT_URL"); | |
put("AWSSimpleSystemsManagementClientBuilder", "AWS_SSM_ENDPOINT_URL"); | |
// The above was determined by grepping all our source. Feel free to add more as needed | |
}}); | |
private static String getEnvEndpoint(String classname) { | |
String globalEndpoint = System.getenv("AWS_ENDPOINT_URL"); | |
if (envMap.containsKey(classname)) { | |
String serviceEndpoint = System.getenv(envMap.get(classname)); | |
if (serviceEndpoint != null && !serviceEndpoint.isEmpty()) { | |
if (serviceEndpoint.contentEquals("default")) { | |
return null; | |
} | |
return serviceEndpoint; | |
} | |
} | |
return globalEndpoint; | |
} | |
/** | |
* Allow for environment endpoint URL override when creating an Amazon client (Dynamo, Dax, SNS, etc..) | |
* | |
* Example old code | |
* dynamoDB = AmazonDynamoDBClientBuilder.standard().build() | |
* snsClient = AmazonSNSAsyncClientBuilder.standard().build() | |
* sqs = AmazonSQSClientBuilder.defaultClient(); | |
* New code | |
* dynamoDB = AWSClientEnvConfig.build(AmazonDynamoDBClientBuilder.standard()); | |
* snsClient = AWSClientEnvConfig.build(AmazonSNSAsyncClientBuilder.standard()); | |
* sqs = AWSClientEnvConfig.build(AmazonSQSClientBuilder.standard()); | |
* | |
* @param builder | |
* @return an AWS Client of the desired type | |
* @param <T> The return type (IE: AWSDynamoDB) | |
* @param <B> The builder for the type. Typically the return from AWS*ClientBuilder.standard() | |
*/ | |
public static <T, B extends AwsClientBuilder<B, T>> T build(B builder) { | |
String endpointURL = getEnvEndpoint(builder.getClass().getSimpleName()); | |
if (endpointURL != null && !endpointURL.isEmpty()) { | |
if (endpointURL.contains("localstack")) { | |
// Reset the credentials. | |
// XXX: This should check an environment variable for the case where you want to test localstack IAM | |
AWSCredentialsProvider creds = new AWSStaticCredentialsProvider(new BasicAWSCredentials("none", "none")); | |
builder.setCredentials(creds); | |
} | |
String region = getEnvRegion(builder.getClass().getSimpleName()); | |
AwsClientBuilder.EndpointConfiguration epc = new AwsClientBuilder.EndpointConfiguration(endpointURL, region); | |
return builder.withEndpointConfiguration(epc).build(); | |
} else { | |
return builder.build(); | |
} | |
} | |
private static String getEnvRegion(String classname) { | |
String envVarName = envMap.get(classname); | |
String region = null; | |
if (envVarName != null) { | |
envVarName = envVarName.replace("ENDPOINT_URL", "REGION"); | |
region = System.getenv(envVarName); | |
} | |
return defaultIfNull(region, | |
defaultIfNull(System.getenv("AWS_REGION"), "us-east-1") | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Added per-service region support