Skip to content

Commit

Permalink
Adds array properties support to parameter store (#852, merge #248 fr…
Browse files Browse the repository at this point in the history
…om 2.4.x) (#894)

Co-authored-by: Rafael Pestano <rpestano@mobiquityinc.com>

Fixes #852
  • Loading branch information
deki authored Oct 23, 2023
1 parent 53926a0 commit 8c5238b
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 8 deletions.
3 changes: 3 additions & 0 deletions docs/src/main/asciidoc/parameter-store.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ spring.config.import[0]=optional:aws-parameterstore=/config/spring
spring.config.import[1]=aws-parameterstore=/config/optional-params/
----

If you add indexed parameter names such as `/config/application/cloud.aws.stack_0_.name`, `/config/application/cloud.aws.stack_1_.name`, ... to Parameter Store,
these will become accessible as array properties `cloud.aws.stack[0].name`, `cloud.aws.stack[1].name`, ... in Spring.

=== Using SsmClient

The starter automatically configures and registers a `SsmClient` bean in the Spring application context. The `SsmClient` bean can be used to create or retrieve parameters from Parameter Store.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,33 @@ void parameterStoreClientUsesGlobalRegion() {
}
}

@Test
void arrayParameterNames() {
SpringApplication application = new SpringApplication(App.class);
application.setWebApplicationType(WebApplicationType.NONE);

putParameter(localstack, "/config/myservice/key_0_.value", "value1", REGION);
putParameter(localstack, "/config/myservice/key_0_.nested_0_.nestedValue", "key_nestedValue1", REGION);
putParameter(localstack, "/config/myservice/key_0_.nested_1_.nestedValue", "key_nestedValue2", REGION);
putParameter(localstack, "/config/myservice/key_1_.value", "value2", REGION);
putParameter(localstack, "/config/myservice/key_1_.nested_0_.nestedValue", "key_nestedValue3", REGION);
putParameter(localstack, "/config/myservice/key_1_.nested_1_.nestedValue", "key_nestedValue4", REGION);

try (ConfigurableApplicationContext context = runApplication(application,
"aws-parameterstore:/config/myservice/")) {
assertThat(context.getEnvironment().getProperty("key[0].value")).isEqualTo("value1");
assertThat(context.getEnvironment().getProperty("key[0].nested[0].nestedValue"))
.isEqualTo("key_nestedValue1");
assertThat(context.getEnvironment().getProperty("key[0].nested[1].nestedValue"))
.isEqualTo("key_nestedValue2");
assertThat(context.getEnvironment().getProperty("key[1].value")).isEqualTo("value2");
assertThat(context.getEnvironment().getProperty("key[1].nested[0].nestedValue"))
.isEqualTo("key_nestedValue3");
assertThat(context.getEnvironment().getProperty("key[1].nested[1].nestedValue"))
.isEqualTo("key_nestedValue4");
}
}

@Nested
class ReloadConfigurationTests {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import io.awspring.cloud.core.config.AwsPropertySource;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.lang.Nullable;
Expand Down Expand Up @@ -65,8 +64,7 @@ public ParameterStorePropertySource copy() {

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

@Override
Expand All @@ -78,7 +76,7 @@ public Object getProperty(String name) {
private void getParameters(GetParametersByPathRequest paramsRequest) {
GetParametersByPathResponse paramsResult = this.source.getParametersByPath(paramsRequest);
for (Parameter parameter : paramsResult.parameters()) {
String key = parameter.name().replace(this.context, "").replace('/', '.');
String key = parameter.name().replace(this.context, "").replace('/', '.').replaceAll("_(\\d)_", "[$1]");
LOG.debug("Populating property retrieved from AWS Parameter Store: " + key);
this.properties.put(key, parameter.value());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package io.awspring.cloud.parameterstore;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.SoftAssertions.assertSoftly;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
Expand Down Expand Up @@ -62,4 +63,31 @@ void followsNextToken() {
assertThat(propertySource.getProperty("key3")).isEqualTo("value3");
}

@Test
void arrayParameterNames() {
GetParametersByPathResponse result = GetParametersByPathResponse.builder()
.parameters(Parameter.builder().name("/config/myservice/key_0_.value").value("value1").build(),
Parameter.builder().name("/config/myservice/key_0_.nested_0_.nestedValue")
.value("key_nestedValue1").build(),
Parameter.builder().name("/config/myservice/key_0_.nested_1_.nestedValue")
.value("key_nestedValue2").build(),
Parameter.builder().name("/config/myservice/key_1_.value").value("value2").build(),
Parameter.builder().name("/config/myservice/key_1_.nested_0_.nestedValue")
.value("key_nestedValue1").build(),
Parameter.builder().name("/config/myservice/key_1_.nested_1_.nestedValue")
.value("key_nestedValue2").build())
.build();

when(ssmClient.getParametersByPath(any(GetParametersByPathRequest.class))).thenReturn(result);

propertySource.init();

assertSoftly(it -> {
it.assertThat(propertySource.getPropertyNames()).containsExactly("key[0].value",
"key[0].nested[0].nestedValue", "key[0].nested[1].nestedValue", "key[1].value",
"key[1].nested[0].nestedValue", "key[1].nested[1].nestedValue");
it.assertThat(propertySource.getProperty("key[0].value")).isEqualTo("value1");
it.assertThat(propertySource.getProperty("key[1].nested[1].nestedValue")).isEqualTo("key_nestedValue2");
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ public InfrastructureStack(final Construct scope, final String id, final StackPr
StringParameter.Builder.create(this, "Parameter").parameterName("/config/spring/message")
.stringValue("Spring-cloud-aws value!").build();

StringParameter.Builder.create(this, "Parameter2").parameterName("/config/spring/messages_0_")
.stringValue("Spring-cloud-aws msg0!").build();

StringParameter.Builder.create(this, "Parameter3").parameterName("/config/spring/messages_1_")
.stringValue("Spring-cloud-aws msg1!").build();

// Secrets Manager
SecretStringGenerator secretStringGenerator = SecretStringGenerator.builder().generateStringKey("password")
.secretStringTemplate("{}").build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ public static void main(String[] args) {
}

@Bean
ApplicationRunner applicationRunner(@Value("${message}") String message) {
return args -> {
LOGGER.info("`message` loaded from the AWS Parameter store: {}", message);
};
ApplicationRunner applicationRunner(@Value("${message}") String message, @Value("${messages[0]}") String msg1,
@Value("${messages[1]}") String msg2) {
return args -> LOGGER.info("`messages` loaded from the AWS Parameter store: {}, {} and {}", message, msg1,
msg2);
}

}

0 comments on commit 8c5238b

Please sign in to comment.