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

Commit e14114b

Browse files
Add aws-parameterstore: prefix config import (#750)
In `spring-boot` 2.4, `Volume Mounted Config Directory Trees` was added. This commit introduces the prefix `aws-parameterstore:` which will resolve the values given the configuration properties supported by parameter store integration. Also, if keys are added after the prefix then just these will be resolved. Use: `aws-parameterstore:` or `aws-secretsmanager:my-config-key` or `aws-parameterstore:my-config-key;my-anoter-config-key` Closes gh-654 Co-authored-by: Eddú Meléndez <[email protected]>
1 parent 30d1d66 commit e14114b

File tree

11 files changed

+588
-89
lines changed

11 files changed

+588
-89
lines changed

docs/src/main/asciidoc/parameter-store.adoc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,22 @@ logging.level.org.springframework.cloud.aws.paramstore.AwsParamStorePropertySour
9393
----
9494
====
9595

96+
In `spring-cloud` `2020.0.0` (aka Ilford), the bootstrap phase is no longer enabled by default. In order
97+
enable it you need an additional dependency:
98+
99+
[source,xml,indent=0]
100+
----
101+
<dependency>
102+
<groupId>org.springframework.cloud</groupId>
103+
<artifactId>spring-cloud-starter-bootstrap</artifactId>
104+
<version>{spring-cloud-version}</version>
105+
</dependency>
106+
----
107+
108+
However, starting at `spring-cloud-aws` `2.3`, allows import default aws' parameterstore keys
109+
(`spring.config.import=aws-parameterstore:`) or individual keys
110+
(`spring.config.import=aws-parameterstore:config-key;other-config-key`)
111+
96112
=== IAM Permissions
97113
Following IAM permissions are required by Spring Cloud AWS:
98114

spring-cloud-aws-parameter-store-config/src/main/java/org/springframework/cloud/aws/paramstore/AwsParamStorePropertySource.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,16 @@
3434
* from the AWS Parameter Store using the provided SSM client.
3535
*
3636
* @author Joris Kuipers
37+
* @author Eddú Meléndez
3738
* @since 2.0.0
3839
*/
3940
public class AwsParamStorePropertySource extends EnumerablePropertySource<AWSSimpleSystemsManagement> {
4041

4142
private static final Logger LOGGER = LoggerFactory.getLogger(AwsParamStorePropertySource.class);
4243

43-
private String context;
44+
private final String context;
4445

45-
private Map<String, Object> properties = new LinkedHashMap<>();
46+
private final Map<String, Object> properties = new LinkedHashMap<>();
4647

4748
public AwsParamStorePropertySource(String context, AWSSimpleSystemsManagement ssmClient) {
4849
super(context, ssmClient);
@@ -57,21 +58,21 @@ public void init() {
5758

5859
@Override
5960
public String[] getPropertyNames() {
60-
Set<String> strings = properties.keySet();
61+
Set<String> strings = this.properties.keySet();
6162
return strings.toArray(new String[strings.size()]);
6263
}
6364

6465
@Override
6566
public Object getProperty(String name) {
66-
return properties.get(name);
67+
return this.properties.get(name);
6768
}
6869

6970
private void getParameters(GetParametersByPathRequest paramsRequest) {
70-
GetParametersByPathResult paramsResult = source.getParametersByPath(paramsRequest);
71+
GetParametersByPathResult paramsResult = this.source.getParametersByPath(paramsRequest);
7172
for (Parameter parameter : paramsResult.getParameters()) {
72-
String key = parameter.getName().replace(context, "").replace('/', '.');
73+
String key = parameter.getName().replace(this.context, "").replace('/', '.');
7374
LOGGER.debug("Populating property retrieved from AWS Parameter Store: {}", key);
74-
properties.put(key, parameter.getValue());
75+
this.properties.put(key, parameter.getValue());
7576
}
7677
if (paramsResult.getNextToken() != null) {
7778
getParameters(paramsRequest.withNextToken(paramsResult.getNextToken()));

spring-cloud-aws-parameter-store-config/src/main/java/org/springframework/cloud/aws/paramstore/AwsParamStorePropertySourceLocator.java

Lines changed: 7 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
import org.springframework.core.env.ConfigurableEnvironment;
3232
import org.springframework.core.env.Environment;
3333
import org.springframework.core.env.PropertySource;
34-
import org.springframework.util.ReflectionUtils;
3534

3635
/**
3736
* Builds a {@link CompositePropertySource} with various
@@ -43,6 +42,7 @@
4342
*
4443
* @author Joris Kuipers
4544
* @author Matej Nedic
45+
* @author Eddú Meléndez
4646
* @since 2.0.0
4747
*/
4848
public class AwsParamStorePropertySourceLocator implements PropertySourceLocator {
@@ -73,56 +73,22 @@ public PropertySource<?> locate(Environment environment) {
7373

7474
ConfigurableEnvironment env = (ConfigurableEnvironment) environment;
7575

76-
String appName = properties.getName();
77-
78-
if (appName == null) {
79-
appName = env.getProperty("spring.application.name");
80-
}
76+
AwsParamStorePropertySources sources = new AwsParamStorePropertySources(this.properties, this.logger);
8177

8278
List<String> profiles = Arrays.asList(env.getActiveProfiles());
83-
84-
String prefix = this.properties.getPrefix();
85-
86-
String appContext = prefix + "/" + appName;
87-
addProfiles(this.contexts, appContext, profiles);
88-
this.contexts.add(appContext + "/");
89-
90-
String defaultContext = prefix + "/" + this.properties.getDefaultContext();
91-
addProfiles(this.contexts, defaultContext, profiles);
92-
this.contexts.add(defaultContext + "/");
79+
this.contexts.addAll(sources.getAutomaticContexts(profiles));
9380

9481
CompositePropertySource composite = new CompositePropertySource("aws-param-store");
9582

9683
for (String propertySourceContext : this.contexts) {
97-
try {
98-
composite.addPropertySource(create(propertySourceContext));
99-
}
100-
catch (Exception e) {
101-
if (this.properties.isFailFast()) {
102-
logger.error(
103-
"Fail fast is set and there was an error reading configuration from AWS Parameter Store:\n"
104-
+ e.getMessage());
105-
ReflectionUtils.rethrowRuntimeException(e);
106-
}
107-
else {
108-
logger.warn("Unable to load AWS config from " + propertySourceContext, e);
109-
}
84+
PropertySource<AWSSimpleSystemsManagement> propertySource = sources
85+
.createPropertySource(propertySourceContext, !this.properties.isFailFast(), this.ssmClient);
86+
if (propertySource != null) {
87+
composite.addPropertySource(propertySource);
11088
}
11189
}
11290

11391
return composite;
11492
}
11593

116-
private AwsParamStorePropertySource create(String context) {
117-
AwsParamStorePropertySource propertySource = new AwsParamStorePropertySource(context, this.ssmClient);
118-
propertySource.init();
119-
return propertySource;
120-
}
121-
122-
private void addProfiles(Set<String> contexts, String baseContext, List<String> profiles) {
123-
for (String profile : profiles) {
124-
contexts.add(baseContext + this.properties.getProfileSeparator() + profile + "/");
125-
}
126-
}
127-
12894
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/*
2+
* Copyright 2013-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.cloud.aws.paramstore;
18+
19+
import java.util.ArrayList;
20+
import java.util.List;
21+
22+
import com.amazonaws.services.simplesystemsmanagement.AWSSimpleSystemsManagement;
23+
import org.apache.commons.logging.Log;
24+
25+
import org.springframework.util.StringUtils;
26+
27+
/**
28+
* @author Eddú Meléndez
29+
* @since 2.3
30+
*/
31+
public class AwsParamStorePropertySources {
32+
33+
private final AwsParamStoreProperties properties;
34+
35+
private final Log log;
36+
37+
public AwsParamStorePropertySources(AwsParamStoreProperties properties, Log log) {
38+
this.properties = properties;
39+
this.log = log;
40+
}
41+
42+
public List<String> getAutomaticContexts(List<String> profiles) {
43+
List<String> contexts = new ArrayList<>();
44+
String prefix = this.properties.getPrefix();
45+
String defaultContext = getContext(prefix, this.properties.getDefaultContext());
46+
47+
String appName = this.properties.getName();
48+
49+
String appContext = prefix + "/" + appName;
50+
addProfiles(contexts, appContext, profiles);
51+
contexts.add(appContext + "/");
52+
53+
addProfiles(contexts, defaultContext, profiles);
54+
contexts.add(defaultContext + "/");
55+
return contexts;
56+
}
57+
58+
protected String getContext(String prefix, String context) {
59+
if (StringUtils.hasLength(prefix)) {
60+
return prefix + "/" + context;
61+
}
62+
return context;
63+
}
64+
65+
private void addProfiles(List<String> contexts, String baseContext, List<String> profiles) {
66+
for (String profile : profiles) {
67+
contexts.add(baseContext + this.properties.getProfileSeparator() + profile + "/");
68+
}
69+
}
70+
71+
/**
72+
* Creates property source for given context.
73+
* @param context property source context equivalent to the parameter name
74+
* @param optional if creating context should fail with exception if parameter cannot
75+
* be loaded
76+
* @param client System Manager Management client
77+
* @return a property source or null if parameter could not be loaded and optional is
78+
* set to true
79+
*/
80+
public AwsParamStorePropertySource createPropertySource(String context, boolean optional,
81+
AWSSimpleSystemsManagement client) {
82+
log.info("Loading property from AWS Parameter Store with name: " + context + ", optional: " + optional);
83+
try {
84+
AwsParamStorePropertySource propertySource = new AwsParamStorePropertySource(context, client);
85+
propertySource.init();
86+
return propertySource;
87+
// TODO: howto call close when /refresh
88+
}
89+
catch (Exception e) {
90+
if (!optional) {
91+
throw new AwsParameterPropertySourceNotFoundException(e);
92+
}
93+
else {
94+
log.warn("Unable to load AWS parameter from " + context + ". " + e.getMessage());
95+
}
96+
}
97+
return null;
98+
}
99+
100+
static class AwsParameterPropertySourceNotFoundException extends RuntimeException {
101+
102+
AwsParameterPropertySourceNotFoundException(Exception source) {
103+
super(source);
104+
}
105+
106+
}
107+
108+
}

0 commit comments

Comments
 (0)