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

Add aws-parameterstore: prefix config import #750

Merged
merged 2 commits into from
Dec 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions docs/src/main/asciidoc/parameter-store.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,22 @@ logging.level.org.springframework.cloud.aws.paramstore.AwsParamStorePropertySour
----
====

In `spring-cloud` `2020.0.0` (aka Ilford), the bootstrap phase is no longer enabled by default. In order
enable it you need an additional dependency:

[source,xml,indent=0]
----
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
<version>{spring-cloud-version}</version>
</dependency>
----

However, starting at `spring-cloud-aws` `2.3`, allows import default aws' parameterstore keys
(`spring.config.import=aws-parameterstore:`) or individual keys
(`spring.config.import=aws-parameterstore:config-key;other-config-key`)

=== IAM Permissions
Following IAM permissions are required by Spring Cloud AWS:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,16 @@
* from the AWS Parameter Store using the provided SSM client.
*
* @author Joris Kuipers
* @author Eddú Meléndez
* @since 2.0.0
*/
public class AwsParamStorePropertySource extends EnumerablePropertySource<AWSSimpleSystemsManagement> {

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

private String context;
private final String context;

private Map<String, Object> properties = new LinkedHashMap<>();
private final Map<String, Object> properties = new LinkedHashMap<>();

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

@Override
public String[] getPropertyNames() {
Set<String> strings = properties.keySet();
Set<String> strings = this.properties.keySet();
return strings.toArray(new String[strings.size()]);
}

@Override
public Object getProperty(String name) {
return properties.get(name);
return this.properties.get(name);
}

private void getParameters(GetParametersByPathRequest paramsRequest) {
GetParametersByPathResult paramsResult = source.getParametersByPath(paramsRequest);
GetParametersByPathResult paramsResult = this.source.getParametersByPath(paramsRequest);
for (Parameter parameter : paramsResult.getParameters()) {
String key = parameter.getName().replace(context, "").replace('/', '.');
String key = parameter.getName().replace(this.context, "").replace('/', '.');
LOGGER.debug("Populating property retrieved from AWS Parameter Store: {}", key);
properties.put(key, parameter.getValue());
this.properties.put(key, parameter.getValue());
}
if (paramsResult.getNextToken() != null) {
getParameters(paramsRequest.withNextToken(paramsResult.getNextToken()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertySource;
import org.springframework.util.ReflectionUtils;

/**
* Builds a {@link CompositePropertySource} with various
Expand All @@ -43,6 +42,7 @@
*
* @author Joris Kuipers
* @author Matej Nedic
* @author Eddú Meléndez
* @since 2.0.0
*/
public class AwsParamStorePropertySourceLocator implements PropertySourceLocator {
Expand Down Expand Up @@ -73,56 +73,22 @@ public PropertySource<?> locate(Environment environment) {

ConfigurableEnvironment env = (ConfigurableEnvironment) environment;

String appName = properties.getName();

if (appName == null) {
appName = env.getProperty("spring.application.name");
}
AwsParamStorePropertySources sources = new AwsParamStorePropertySources(this.properties, this.logger);

List<String> profiles = Arrays.asList(env.getActiveProfiles());

String prefix = this.properties.getPrefix();

String appContext = prefix + "/" + appName;
addProfiles(this.contexts, appContext, profiles);
this.contexts.add(appContext + "/");

String defaultContext = prefix + "/" + this.properties.getDefaultContext();
addProfiles(this.contexts, defaultContext, profiles);
this.contexts.add(defaultContext + "/");
this.contexts.addAll(sources.getAutomaticContexts(profiles));

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

for (String propertySourceContext : this.contexts) {
try {
composite.addPropertySource(create(propertySourceContext));
}
catch (Exception e) {
if (this.properties.isFailFast()) {
logger.error(
"Fail fast is set and there was an error reading configuration from AWS Parameter Store:\n"
+ e.getMessage());
ReflectionUtils.rethrowRuntimeException(e);
}
else {
logger.warn("Unable to load AWS config from " + propertySourceContext, e);
}
PropertySource<AWSSimpleSystemsManagement> propertySource = sources
.createPropertySource(propertySourceContext, !this.properties.isFailFast(), this.ssmClient);
if (propertySource != null) {
composite.addPropertySource(propertySource);
}
}

return composite;
}

private AwsParamStorePropertySource create(String context) {
AwsParamStorePropertySource propertySource = new AwsParamStorePropertySource(context, this.ssmClient);
propertySource.init();
return propertySource;
}

private void addProfiles(Set<String> contexts, String baseContext, List<String> profiles) {
for (String profile : profiles) {
contexts.add(baseContext + this.properties.getProfileSeparator() + profile + "/");
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/*
* 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.paramstore;

import java.util.ArrayList;
import java.util.List;

import com.amazonaws.services.simplesystemsmanagement.AWSSimpleSystemsManagement;
import org.apache.commons.logging.Log;

import org.springframework.util.StringUtils;

/**
* @author Eddú Meléndez
* @since 2.3
*/
public class AwsParamStorePropertySources {

private final AwsParamStoreProperties properties;

private final Log log;

public AwsParamStorePropertySources(AwsParamStoreProperties properties, Log log) {
this.properties = properties;
this.log = log;
}

public List<String> getAutomaticContexts(List<String> profiles) {
List<String> contexts = new ArrayList<>();
String prefix = this.properties.getPrefix();
String defaultContext = getContext(prefix, this.properties.getDefaultContext());

String appName = this.properties.getName();

String appContext = prefix + "/" + appName;
addProfiles(contexts, appContext, profiles);
contexts.add(appContext + "/");

addProfiles(contexts, defaultContext, profiles);
contexts.add(defaultContext + "/");
return contexts;
}

protected String getContext(String prefix, String context) {
if (StringUtils.hasLength(prefix)) {
return prefix + "/" + context;
}
return context;
}

private void addProfiles(List<String> contexts, String baseContext, List<String> profiles) {
for (String profile : profiles) {
contexts.add(baseContext + this.properties.getProfileSeparator() + profile + "/");
}
}

/**
* Creates property source for given context.
* @param context property source context equivalent to the parameter name
* @param optional if creating context should fail with exception if parameter cannot
* be loaded
* @param client System Manager Management client
* @return a property source or null if parameter could not be loaded and optional is
* set to true
*/
public AwsParamStorePropertySource createPropertySource(String context, boolean optional,
AWSSimpleSystemsManagement client) {
log.info("Loading property from AWS Parameter Store with name: " + context + ", optional: " + optional);
try {
AwsParamStorePropertySource propertySource = new AwsParamStorePropertySource(context, client);
propertySource.init();
return propertySource;
// TODO: howto call close when /refresh
}
catch (Exception e) {
if (!optional) {
throw new AwsParameterPropertySourceNotFoundException(e);
}
else {
log.warn("Unable to load AWS parameter from " + context + ". " + e.getMessage());
}
}
return null;
}

static class AwsParameterPropertySourceNotFoundException extends RuntimeException {

AwsParameterPropertySourceNotFoundException(Exception source) {
super(source);
}

}

}
Loading