Skip to content

Commit

Permalink
Support multiple prefixes for aws distributed configuration (#1577)
Browse files Browse the repository at this point in the history
  • Loading branch information
marcin-majewski-sonarsource authored Jan 27, 2023
1 parent 5c6b34a commit 0f6842f
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@

import io.micronaut.core.annotation.Experimental;
import io.micronaut.core.annotation.NonNull;
import java.util.List;

import static java.util.Collections.emptyList;

/**
* Configuration for Distributed Configuration using AWS services such as AWS Parameter Store or Secrets Manager.
Expand All @@ -29,11 +32,24 @@ public interface AwsDistributedConfiguration {

/**
*
* @return Prefix for AWS Distributed Configuration resources names. For example `/config/`
* @return Prefix for AWS Distributed Configuration resources names. For example `/config/`.
* If {@link AwsDistributedConfiguration#getPrefixes()} returns non-empty list, this value is
* ignored.
*/
@NonNull
String getPrefix();

/**
* @return List of prefixes for AWS Distributed Configuration resources names. If it is non-empty,
* {@link AwsDistributedConfiguration#getPrefix()} is not used.
*
* @since 3.12.1
*/
@NonNull
default List<String> getPrefixes() {
return emptyList();
}

/**
* Delimiter after prefix and application name. For /config/application_dev/micronaut.security.oauth2.clients.mycompanyauth.client-secret
* delimiter will be / The character between /config/application_dev and micronaut.security.oauth2.clients.mycompanyauth.client-secret
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@
import java.util.Map;
import java.util.Optional;

import static java.util.Collections.singletonList;
import static java.util.stream.Collectors.toList;

/**
* Base implementation for AWS services contributing distributed configuration.
*
Expand Down Expand Up @@ -151,32 +154,43 @@ private List<String> generateConfigurationResolutionPrefixes(@NonNull Environmen
if (applicationName != null) {
if (awsDistributedConfiguration.isSearchActiveEnvironments()) {
for (String name : environment.getActiveNames()) {
configurationResolutionPrefixes.add(prefix(applicationName, name));
}
configurationResolutionPrefixes.addAll(prefix(applicationName, name));
}
}
configurationResolutionPrefixes.add(prefix(applicationName));
configurationResolutionPrefixes.addAll(prefix(applicationName));
}
if (awsDistributedConfiguration.isSearchCommonApplication()) {
if (awsDistributedConfiguration.isSearchActiveEnvironments()) {
for (String name : environment.getActiveNames()) {
configurationResolutionPrefixes.add(prefix(awsDistributedConfiguration.getCommonApplicationName(), name));
configurationResolutionPrefixes.addAll(prefix(awsDistributedConfiguration.getCommonApplicationName(), name));
}
}
configurationResolutionPrefixes.add(prefix(awsDistributedConfiguration.getCommonApplicationName()));
configurationResolutionPrefixes.addAll(prefix(awsDistributedConfiguration.getCommonApplicationName()));
}
return configurationResolutionPrefixes;
}

@NonNull
private String prefix(@NonNull String appName) {
private List<String> prefix(@NonNull String appName) {
return prefix(appName, null);
}

@NonNull
private String prefix(@NonNull String appName, @Nullable String envName) {
private List<String> prefix(@NonNull String appName, @Nullable String envName) {
List<String> prefixes = awsDistributedConfiguration.getPrefixes().isEmpty() ?
singletonList(awsDistributedConfiguration.getPrefix()) :
awsDistributedConfiguration.getPrefixes();

return prefixes.stream()
.map(p -> buildPrefix(p, appName, envName))
.collect(toList());
}

private String buildPrefix(@NonNull String inputPrefix, @NonNull String appName, @Nullable String envName) {
String delimiter = awsDistributedConfiguration.getDelimiter();
if (envName != null) {
return awsDistributedConfiguration.getPrefix() + appName + UNDERSCORE + envName + awsDistributedConfiguration.getDelimiter();
return inputPrefix + appName + UNDERSCORE + envName + delimiter;
}
return awsDistributedConfiguration.getPrefix() + appName + awsDistributedConfiguration.getDelimiter();
return inputPrefix + appName + delimiter;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import io.micronaut.context.annotation.ConfigurationProperties;
import io.micronaut.core.annotation.Experimental;
import io.micronaut.core.annotation.NonNull;
import java.util.ArrayList;
import java.util.List;

/**
* {@link ConfigurationProperties} implementation of {@link AwsDistributedConfiguration}.
Expand Down Expand Up @@ -51,6 +53,9 @@ public class AwsDistributedConfigurationProperties implements AwsDistributedConf
@NonNull
String prefix = DEFAULT_PREFIX;

@NonNull
private List<String> prefixes = new ArrayList<>();

@NonNull
private String commonApplicationName = DEFAULT_COMMON_APPLICATION_NAME;

Expand Down Expand Up @@ -107,6 +112,16 @@ public void setSearchCommonApplication(boolean searchCommonApplication) {
this.searchCommonApplication = searchCommonApplication;
}

@Override
@NonNull
public List<String> getPrefixes() {
return prefixes;
}

public void setPrefixes(@NonNull List<String> prefixes) {
this.prefixes = prefixes;
}

@Override
@NonNull
public String getPrefix() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class AwsDistributedConfigurationSpec extends Specification {
'spec.name': 'AwsDistributedConfigurationSpec',
'aws.distributed-configuration.delimiter': '-',
'aws.distributed-configuration.prefix': 'foo',
'aws.distributed-configuration.prefixes': ['foo', 'bar'],
'aws.distributed-configuration.common-application-name': 'bar',
]
when:
Expand All @@ -30,6 +31,7 @@ class AwsDistributedConfigurationSpec extends Specification {
then:
awsDistributedConfiguration.delimiter == '-'
awsDistributedConfiguration.prefix == 'foo'
awsDistributedConfiguration.prefixes == ['foo', 'bar']
awsDistributedConfiguration.commonApplicationName == 'bar'

cleanup:
Expand All @@ -48,6 +50,7 @@ class AwsDistributedConfigurationSpec extends Specification {
then:
awsDistributedConfiguration.delimiter == '/'
awsDistributedConfiguration.prefix == '/config/'
awsDistributedConfiguration.prefixes == []
awsDistributedConfiguration.commonApplicationName == 'application'

cleanup:
Expand Down Expand Up @@ -87,6 +90,44 @@ class AwsDistributedConfigurationSpec extends Specification {
'otherapp' | 'foo' || 'application_fooYYY'
}

@RestoreSystemProperties
void "multiple prefixes are used to read from secrets" (String appName,
String env,
List<String> prefixes,
String expectedSecret,
String expectedToken){
given:
System.setProperty(Environment.BOOTSTRAP_CONTEXT_PROPERTY, StringUtils.TRUE)
Map<String, Object> properties = [
'spec.name': 'AwsDistributedConfigurationSpec',
'micronaut.application.name': appName,
'micronaut.config-client.enabled': true,
'aws.distributed-configuration.prefixes': prefixes,
'aws.distributed-configuration.delimiter': '/',
]

when:
EmbeddedServer embeddedServer = env ? ApplicationContext.run(EmbeddedServer, properties, env) : ApplicationContext.run(EmbeddedServer, properties)
ApplicationContext context = embeddedServer.applicationContext
Optional<String> clientSecretOptional = context.getProperty('micronaut.security.oauth2.clients.companyauthserver.client-secret', String)
Optional<String> clientIdOptional = context.getProperty('micronaut.security.oauth2.clients.companyauthserver.client-id', String)

then:
clientSecretOptional.isPresent()
clientSecretOptional.get() == expectedSecret
clientIdOptional.isPresent()
clientIdOptional.get() == expectedToken

cleanup:
context.close()
embeddedServer.close()

where:
appName | env | prefixes | expectedSecret | expectedToken
'myapp' | 'foo' | ['/config/', '/other/'] | 'myapp_fooYYY' | 'myapp_fooXXX'
'otherapp' | null | ['/demo/'] | 'otherapp_fooYYY' | 'otherapp_fooXXX'
}

@Requires(beans = [AwsDistributedConfiguration, KeyValueFetcher])
@Requires(property = 'spec.name', value = 'AwsDistributedConfigurationSpec')
@BootstrapContextCompatible
Expand Down Expand Up @@ -138,8 +179,16 @@ class AwsDistributedConfigurationSpec extends Specification {
'/config/myapp_foo/OpenID':
[
'micronaut.security.oauth2.clients.companyauthserver.client-secret': 'myapp_fooYYY'
],
'/other/myapp_foo/OpenID':
[
'micronaut.security.oauth2.clients.companyauthserver.client-id': 'myapp_fooXXX'
],
'/demo/otherapp/OpenID':
[
'micronaut.security.oauth2.clients.companyauthserver.client-secret': 'otherapp_fooYYY',
'micronaut.security.oauth2.clients.companyauthserver.client-id': 'otherapp_fooXXX'
]

]

@Override
Expand Down

0 comments on commit 0f6842f

Please sign in to comment.