Skip to content
This repository has been archived by the owner on Jan 19, 2022. It is now read-only.

Commit

Permalink
Add option to use default AWS region provider chain.
Browse files Browse the repository at this point in the history
Fixes gh-553
Fixes gh-120
Closes gh-559
Closes gh-560
  • Loading branch information
maciejwalkowiak committed May 31, 2020
1 parent e72a3d2 commit 159200b
Show file tree
Hide file tree
Showing 13 changed files with 156 additions and 22 deletions.
11 changes: 6 additions & 5 deletions docs/src/main/asciidoc/_configprops.adoc
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
|===
|Name | Default | Description

|aws.paramstore.default-context | application |
|aws.paramstore.default-context | application |
|aws.paramstore.enabled | true | Is AWS Parameter Store support enabled.
|aws.paramstore.fail-fast | true | Throw exceptions during config lookup if true, otherwise, log warnings.
|aws.paramstore.name | | Alternative to spring.application.name to use in looking up values in AWS Parameter Store.
|aws.paramstore.prefix | /config | Prefix indicating first level for every property. Value must start with a forward slash followed by a valid path segment or be empty. Defaults to "/config".
|aws.paramstore.profile-separator | _ |
|aws.secretsmanager.default-context | application |
|aws.paramstore.profile-separator | _ |
|aws.secretsmanager.default-context | application |
|aws.secretsmanager.enabled | true | Is AWS Secrets Manager support enabled.
|aws.secretsmanager.fail-fast | true | Throw exceptions during config lookup if true, otherwise, log warnings.
|aws.secretsmanager.name | | Alternative to spring.application.name to use in looking up values in AWS Secrets Manager.
|aws.secretsmanager.prefix | /secret | Prefix indicating first level for every property. Value must start with a forward slash followed by a valid path segment or be empty. Defaults to "/config".
|aws.secretsmanager.profile-separator | _ |
|aws.secretsmanager.profile-separator | _ |
|cloud.aws.credentials.access-key | | The access key to be used with a static provider.
|cloud.aws.credentials.instance-profile | true | Configures an instance profile credentials provider with no further configuration.
|cloud.aws.credentials.profile-name | | The AWS profile name.
Expand All @@ -23,7 +23,8 @@
|cloud.aws.loader.max-pool-size | | The maximum pool size of the Task Executor used for parallel S3 interaction. @see org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor#setMaxPoolSize(int)
|cloud.aws.loader.queue-capacity | | The maximum queue capacity for backed up S3 requests. @see org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor#setQueueCapacity(int)
|cloud.aws.region.auto | true | Enables automatic region detection based on the EC2 meta data service.
|cloud.aws.region.static | |
|cloud.aws.region.use-default-aws-region-chain | false | Use the DefaultAwsRegion Chain instead of configuring a custom region provider chain.
|cloud.aws.region.static | |
|cloud.aws.stack.auto | true | Enables the automatic stack name detection for the application.
|cloud.aws.stack.name | myStackName | The name of the manually configured stack name that will be used to retrieve the resources.

Expand Down
4 changes: 4 additions & 0 deletions docs/src/main/asciidoc/spring-cloud-aws.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,10 @@ The properties to configure the region are shown below
|true
|Enables automatic region detection based on the EC2 meta data service

|cloud.aws.region.useDefaultAwsRegionChain
|true
|Use the DefaultAWSRegion Chain instead of configuring a custom region chain

|cloud.aws.region.static
|eu-west-1
|Configures a static region for the application. Possible regions are (currently) us-east-1, us-west-1, us-west-2,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,11 @@ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
return;
}

Boolean useDefaultCredentialsChain = this.environment.getProperty(
AWS_CREDENTIALS_PROPERTY_PREFIX + ".use-default-aws-credentials-chain",
Boolean.class, false);
Boolean useDefaultCredentialsChain = this.environment
.getProperty(
AWS_CREDENTIALS_PROPERTY_PREFIX
+ ".use-default-aws-credentials-chain",
Boolean.class, false);
String accessKey = this.environment
.getProperty(AWS_CREDENTIALS_PROPERTY_PREFIX + ".access-key");
String secretKey = this.environment
Expand All @@ -99,7 +101,7 @@ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
AWS_CREDENTIALS_PROPERTY_PREFIX + ".instance-profile",
Boolean.class, true)
&& !this.environment.containsProperty(
AWS_CREDENTIALS_PROPERTY_PREFIX + ".access-key"),
AWS_CREDENTIALS_PROPERTY_PREFIX + ".access-key"),
this.environment.getProperty(
AWS_CREDENTIALS_PROPERTY_PREFIX + ".profile-name",
DEFAULT_PROFILE_NAME),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,19 @@ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
return;
}

registerRegionProvider(registry, this.environment.getProperty(
boolean useDefaultRegionChain = this.environment.getProperty(
AWS_REGION_PROPERTIES_PREFIX + ".use-default-aws-region-chain",
Boolean.class, false);

String staticRegion = this.environment
.getProperty(AWS_REGION_PROPERTIES_PREFIX + ".static");

boolean autoDetect = this.environment.getProperty(
AWS_REGION_PROPERTIES_PREFIX + ".auto", Boolean.class, true)
&& !StringUtils.hasText(this.environment
.getProperty(AWS_REGION_PROPERTIES_PREFIX + ".static")),
this.environment
.getProperty(AWS_REGION_PROPERTIES_PREFIX + ".static"));
&& !StringUtils.hasText(staticRegion);

registerRegionProvider(registry, autoDetect, useDefaultRegionChain,
staticRegion);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
* Properties related to AWS region configuration.
*
* @author Tom Gianos
* @author Maciej Walkowiak
* @since 2.0.2
* @see org.springframework.cloud.aws.autoconfigure.context.ContextRegionProviderAutoConfiguration
*/
Expand All @@ -30,6 +31,12 @@ public class AwsRegionProperties {
*/
private boolean auto = true;

/**
* Whether default AWS SDK region provider chain should be used when auto is set to
* true.
*/
private boolean useDefaultAwsRegionChain;

/**
* Configures a static region for the application. Possible regions are (currently)
* us-east-1, us-west-1, us-west-2, eu-west-1, eu-central-1, ap-southeast-1,
Expand Down Expand Up @@ -60,4 +67,12 @@ public void setStatic(String staticRegion) {
this.staticRegion = staticRegion;
}

public boolean isUseDefaultAwsRegionChain() {
return useDefaultAwsRegionChain;
}

public void setUseDefaultAwsRegionChain(boolean useDefaultAwsRegionChain) {
this.useDefaultAwsRegionChain = useDefaultAwsRegionChain;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,8 @@ public void credentialsProvider_propertyToUseDefaultIsSet_configuresDefaultAwsCr
public void credentialsProvider_dashSeparatedPropertyToUseDefaultIsSet_configuresDefaultAwsCredentialsProvider() {
this.context = new AnnotationConfigApplicationContext();
this.context.register(ContextCredentialsAutoConfiguration.class);
TestPropertyValues.of("cloud.aws.credentials.use-default-aws-credentials-chain:true")
TestPropertyValues
.of("cloud.aws.credentials.use-default-aws-credentials-chain:true")
.applyTo(this.context);
this.context.refresh();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,20 @@
import org.junit.After;
import org.junit.Test;

import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.cloud.aws.core.region.DefaultAwsRegionProviderChainDelegate;
import org.springframework.cloud.aws.core.region.Ec2MetadataRegionProvider;
import org.springframework.cloud.aws.core.region.StaticRegionProvider;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

/**
* @author Agim Emruli
* @author Petromir Dzhunev
* @author Maciej Walkowiak
*/
public class ContextRegionProviderAutoConfigurationTest {

Expand Down Expand Up @@ -93,4 +97,23 @@ public void regionProvider_staticRegionConfigured_staticRegionProviderWithConfig
.isEqualTo(Region.getRegion(Regions.EU_WEST_1));
}

@Test
public void regionProvider_autoDetectionAndDefaultChainConfigured_DefaultAwsRegionProviderChainDelegateConfigured() {
// Arrange
this.context = new AnnotationConfigApplicationContext();
this.context.register(ContextRegionProviderAutoConfiguration.class);
TestPropertyValues.of("cloud.aws.region.auto:true").applyTo(this.context);
TestPropertyValues.of("cloud.aws.region.useDefaultAwsRegionChain:true")
.applyTo(this.context);

// Act
this.context.refresh();

// Assert
assertThat(this.context.getBean(DefaultAwsRegionProviderChainDelegate.class))
.isNotNull();
assertThatThrownBy(() -> this.context.getBean(Ec2MetadataRegionProvider.class))
.isInstanceOf(NoSuchBeanDefinitionException.class);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,12 @@ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
+ importingClassMetadata.getClassName());

boolean autoDetect = annotationAttributes.getBoolean("autoDetect");
boolean useDefaultAwsRegionChain = annotationAttributes
.getBoolean("useDefaultAwsRegionChain");
String configuredRegion = annotationAttributes.getString("region");

registerRegionProvider(registry, autoDetect, configuredRegion);
registerRegionProvider(registry, autoDetect, useDefaultAwsRegionChain,
configuredRegion);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import com.amazonaws.regions.AwsRegionProviderChain;

import org.springframework.context.annotation.Import;

/**
Expand All @@ -29,11 +31,15 @@
* Service clients that are created inside the application context (by the Spring Cloud
* AWS classes). A region can be either manually configured
* {@link EnableContextRegion#region()} with a constant expression, dynamic expression
* (using a SpEL expression) or a place holder. The region can also be dynamically
* retrieved from the EC2 instance meta-data if the application context is running inside
* a EC2 instance by enabling the {@link EnableContextRegion#autoDetect()} attribute.
* (using a SpEL expression) or a place holder. If the application context is running
* inside a EC2 instance The region can also be dynamically retrieved from the EC2
* instance meta-data by enabling the {@link EnableContextRegion#autoDetect()} attribute
* or from the default AWS SDK {@link AwsRegionProviderChain} by enabling
* {@link EnableContextRegion#autoDetect()} and
* {@link EnableContextRegion#useDefaultAwsRegionChain()}.
*
* @author Agim Emruli
* @author Maciej Walkowiak
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
Expand All @@ -58,4 +64,12 @@
*/
boolean autoDetect() default false;

/**
* Whether default AWS SDK region provider chain should be used when auto is set to
* true.
* @return - if default AWS SDK region provider chain should be used for region
* resolution.
*/
boolean useDefaultAwsRegionChain() default false;

}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.cloud.aws.core.config.AmazonWebserviceClientConfigurationUtils;
import org.springframework.cloud.aws.core.credentials.CredentialsProviderFactoryBean;
import org.springframework.cloud.aws.core.region.DefaultAwsRegionProviderChainDelegate;
import org.springframework.cloud.aws.core.region.Ec2MetadataRegionProvider;
import org.springframework.cloud.aws.core.region.StaticRegionProvider;
import org.springframework.util.StringUtils;
Expand All @@ -55,7 +56,7 @@ private ContextConfigurationUtils() {
}

public static void registerRegionProvider(BeanDefinitionRegistry registry,
boolean autoDetect, String configuredRegion) {
boolean autoDetect, boolean useDefaultRegionChain, String configuredRegion) {
if (autoDetect && StringUtils.hasText(configuredRegion)) {
throw new IllegalArgumentException(
"No region must be configured if autoDetect is defined as true");
Expand All @@ -64,8 +65,9 @@ public static void registerRegionProvider(BeanDefinitionRegistry registry,
AbstractBeanDefinition beanDefinition;

if (autoDetect) {
beanDefinition = BeanDefinitionBuilder
.genericBeanDefinition(Ec2MetadataRegionProvider.class)
beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(
useDefaultRegionChain ? DefaultAwsRegionProviderChainDelegate.class
: Ec2MetadataRegionProvider.class)
.getBeanDefinition();
}
else if (StringUtils.hasText(configuredRegion)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,21 @@ public void regionProvider_withAutoDetectedRegion_dynamicRegionProviderConfigure
assertThat(staticRegionProvider).isNotNull();
}

@Test
public void regionProvider_withAutoDetectedRegionAndDefaultChain_defaulAwsChainRegionProviderConfigured()
throws Exception {
// Arrange
this.context = new AnnotationConfigApplicationContext(
ApplicationConfigurationWithDynamicRegionProvider.class);

// Act
Ec2MetadataRegionProvider staticRegionProvider = this.context
.getBean(Ec2MetadataRegionProvider.class);

// Assert
assertThat(staticRegionProvider).isNotNull();
}

@Test
public void regionProvider_withExpressionConfiguredRegion_staticRegionProviderConfigured()
throws Exception {
Expand Down Expand Up @@ -219,4 +234,10 @@ static class ApplicationConfigurationWithWrongRegion {

}

@Configuration(proxyBeanMethods = false)
@EnableContextRegion(autoDetect = true, useDefaultAwsRegionChain = true)
static class ApplicationConfigurationWithAutoDetectionAndDefaultChain {

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.cloud.aws.core.region;

import com.amazonaws.regions.DefaultAwsRegionProviderChain;
import com.amazonaws.regions.Region;
import com.amazonaws.regions.RegionUtils;

/**
* {@link RegionProvider} implementation that delegates to
* {@link DefaultAwsRegionProviderChain} enabling loading region configuration from
* environment variables, system properties, AWS profile, and instance metadata.
*
* @author Maciej Walkowiak
* @since 1.0
*/
public class DefaultAwsRegionProviderChainDelegate implements RegionProvider {

private final DefaultAwsRegionProviderChain delegate = new DefaultAwsRegionProviderChain();

@Override
public Region getRegion() {
return RegionUtils.getRegion(delegate.getRegion());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,5 @@ public void addArgumentResolvers(
}
};
}

}

0 comments on commit 159200b

Please sign in to comment.