9

I created spring boot(gradle) application, and included dependency: org.springframework.cloud:spring-cloud-starter-aws-parameter-store-config.

I want to use AWSSimpleSystemsManagement to read configuration from AWS parameter store, but I am forced to write it like this (in aws):

 config/application_dev/server.port: 8080

Is there any way to read something like this from spring boot: dev.application.server.port:8080

currently all of this is managed from autoconfiguration I think, is there a way to override it

RamPrakash
  • 1,687
  • 3
  • 20
  • 25
Invisible
  • 112
  • 1
  • 2
  • 13
  • https://medium.com/@ashoksl/spring-boot-with-aws-parameter-store-d94368fef55c, one of the links I followed – Invisible Jan 08 '20 at 12:53

3 Answers3

12

In application.properties you can define property server.port=8081.

The parameter formats supported by spring-cloud-starter-aws-parameter-store-config are:

  • /config/application/server.port
  • /config/application_dev/server.port
  • /config/my-service/server.port
  • /config/my-service_dev/server.port

By defining the following properties in the bootstrap.properties you can change the format in some way:

spring.application.name=my-service
aws.paramstore.prefix=/config
aws.paramstore.defaultContext=application
aws.paramstore.profileSeparator=_

But only a simple customisations are supported because the main parameter naming logic is hardcode in the AwsParamStorePropertySourceLocator.

To dramatically change the parameter format you have to define a custom PropertySourceLocator and register it as bootstrap configuration.

The problem is that dev.application.server.port is invalid parameter name.

AWS Systems Manager Parameter Store uses / as a path separator and Spring uses the operation get-parameters-by-path. A workaround is to use name dev.application/server.port.

But this name is invalid also. Parameter name must be a fully qualified name, so the valid name is /dev.application/server.port.

To support such parameter format define a custom PropertySourceLocator

@Configuration
public class CustomAwsParamStorePropertySourceLocator implements PropertySourceLocator {

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

  private AWSSimpleSystemsManagement ssmClient;

  private List<String> contexts = new ArrayList<>();

  public CustomAwsParamStorePropertySourceLocator(AWSSimpleSystemsManagement ssmClient) {
    this.ssmClient = ssmClient;
  }

  public List<String> getContexts() {
    return contexts;
  }

  @Override
  public PropertySource<?> locate(Environment environment) {
    if (!(environment instanceof ConfigurableEnvironment)) {
      return null;
    }

    ConfigurableEnvironment env = (ConfigurableEnvironment) environment;

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

    String defaultAppName = "application";
    this.contexts.add("/" + defaultAppName + "/");
    addProfiles(this.contexts, defaultAppName, profiles);

    String appName = env.getProperty("spring.application.name");
    this.contexts.add("/" + appName + "/");
    addProfiles(this.contexts, appName, profiles);

    Collections.reverse(this.contexts);

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

    for (String propertySourceContext : this.contexts) {
      try {
        composite.addPropertySource(create(propertySourceContext));
      } catch (Exception e) {
        LOGGER.warn("Unable to load AWS config from " + propertySourceContext, e);
      }
    }

    return composite;
  }

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

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

and register it in the bootstrap context by adding a file META-INF/spring.factories

org.springframework.cloud.bootstrap.BootstrapConfiguration=\
com.example.CustomAwsParamStorePropertySourceLocator
Eugene Khyst
  • 9,236
  • 7
  • 38
  • 65
  • 1
    is it possible to do this without spring.factories file? some annotation maybe – Invisible Jan 14 '20 at 07:31
  • 2
    A `spring.factories` is the only way Spring Cloud provides to register a new `PropertySouceLocator` - https://cloud.spring.io/spring-cloud-commons/multi/multi__spring_cloud_context_application_context_services.html#customizing-bootstrap-property-sources – Eugene Khyst Jan 14 '20 at 10:49
  • 1
    How can we disable existing AwsParamStorePropertySourceLocator? – Sarvesh Jun 22 '21 at 08:47
  • Even though this new PropertySourceLocator is being injected, the default one from SpringBoot is still kicking in. How can we disable it? – Deniss M. Sep 08 '21 at 05:46
0

You need yo create a bootstrap.propeties file in order to configure the root path add "aws.paramstore.prefix = dev" to the file to replace "config"

please refer to: https://cloud.spring.io/spring-cloud-static/spring-cloud-aws/2.0.0.RELEASE/multi/multi__cloud_environment.html section 3.2

asfmlr
  • 199
  • 11