Closed RajeevMasseyTR closed 2 weeks ago
@graemerocher
CustomPropertySourceLoader
cannot be a bean.
Look at different implementations of io.micronaut.discovery.config.ConfigurationClient
@dstepanov
Would writing a custom implementation on io.micronaut.discovery.config.ConfigurationClient help. Resolving the purpose
I think something like this should help
import com.fasterxml.jackson.databind.ObjectMapper;
import io.micronaut.context.annotation.BootstrapContextCompatible;
import io.micronaut.context.annotation.Requires;
import io.micronaut.context.env.Environment;
import io.micronaut.context.env.PropertySource;
import io.micronaut.core.annotation.Nullable;
import io.micronaut.runtime.ApplicationConfiguration;
import io.micronaut.scheduling.TaskExecutors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import software.amazon.awssdk.services.ssm.SsmAsyncClient;
import software.amazon.awssdk.services.ssm.model.GetParameterRequest;
import software.amazon.awssdk.services.ssm.model.GetParameterResponse;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
@Singleton
@Requires(env = Environment.AMAZON_EC2)
@Requires(beans = {CustomSSMConfiguration.class, SsmAsyncClient.class})
@BootstrapContextCompatible
public class CustomSSMConfigClient implements ConfigurationClient {
private static final Logger LOG = LoggerFactory.getLogger(CustomSSMConfigClient.class);
private final CustomSSMConfiguration customSSMConfiguration;
private final String configurationParameterStorePath;
private final ObjectMapper jsonMapper;
private SsmAsyncClient client;
private ExecutorService executorService;
@Inject
public CustomSSMConfigClient(
SsmAsyncClient asyncClient,
CustomSSMConfiguration customSSMConfiguration,
ApplicationConfiguration applicationConfiguration,
ObjectMapper jsonMapper,
@Nullable AwsServiceDiscoveryConfiguration serviceDiscoveryConfiguration) {
this.customSSMConfiguration = customSSMConfiguration;
this.client = asyncClient;
this.jsonMapper = jsonMapper;
this.configurationParameterStorePath = serviceDiscoveryConfiguration != null ? serviceDiscoveryConfiguration.getAwsServiceId() : applicationConfiguration.getName().orElse(null);
}
@Override
public Publisher<PropertySource> getPropertySources(Environment environment) {
if (!customSSMConfiguration.isEnabled()) {
return Flux.empty();
}
return Mono.fromFuture(this::loadConfiguration)
.map(configMap -> PropertySource.of(configurationParameterStorePath, configMap))
.flux()
.onErrorResume(this::onPropertySourceError);
}
@Override
public String getDescription() {
return "Custom SSM Configuration Client";
}
public CompletableFuture<Map<String, Object>> loadConfiguration() {
try {
GetParameterRequest parameterRequest = GetParameterRequest.builder()
.name(customSSMConfiguration.getParameterStorePath())
.withDecryption(customSSMConfiguration.getUseSecureParameters())
.build();
CompletableFuture<GetParameterResponse> future = client.getParameter(parameterRequest);
return future.thenApply(response -> {
String jsonConfig = response.parameter().value();
LOG.info("Retrieved configuration from SSM");
try {
Map<String, Object> configMap = jsonMapper.readValue(jsonConfig, Map.class);
verifyConfiguration(configMap.keySet());
return configMap;
} catch (Exception e) {
throw new RuntimeException("Error parsing JSON configuration from SSM", e);
}
});
} catch (Exception e) {
CompletableFuture<Map<String, Object>> future = new CompletableFuture<>();
future.completeExceptionally(new RuntimeException("Error loading configuration from SSM", e));
return future;
}
}
private void verifyConfiguration(Set<String> keys) {
// Implement your verification logic here
LOG.info("Verifying configuration keys: {}", keys);
}
private Publisher<? extends PropertySource> onPropertySourceError(Throwable throwable) {
if (throwable instanceof ConfigurationException) {
return Flux.error(throwable);
} else {
return Flux.error(new ConfigurationException("Error reading configuration from SSM: " + throwable.getMessage(), throwable));
}
}
@Inject
void setExecutionService(@Named(TaskExecutors.IO) @Nullable ExecutorService executorService) {
if (executorService != null) {
this.executorService = executorService;
}
}
protected void setClient(SsmAsyncClient client) {
this.client = client;
}
protected SsmAsyncClient getClient() {
return client;
}
}
import io.micronaut.context.annotation.ConfigurationProperties;
import io.micronaut.context.annotation.Requires;
import io.micronaut.context.env.Environment;
import io.micronaut.core.util.StringUtils;
import io.micronaut.core.util.Toggleable;
@ConfigurationProperties(CustomSSMConfiguration.CONFIGURATION_PREFIX)
@Requires(env = Environment.AMAZON_EC2)
@Requires(property = CustomSSMConfiguration.ENABLED, value = StringUtils.TRUE, defaultValue = StringUtils.FALSE)
public class CustomSSMConfiguration implements Toggleable {
public static final String ENABLED = "custom.ssm.parameterstore.enabled";
public static final String CONFIGURATION_PREFIX = "custom.ssm.parameterstore";
private static final boolean DEFAULT_SECURE = false;
private static final boolean DEFAULT_ENABLED = false;
private boolean useSecureParameters = DEFAULT_SECURE;
private boolean enabled = DEFAULT_ENABLED;
private String parameterStorePath;
@Override
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public boolean getUseSecureParameters() {
return useSecureParameters;
}
public void setUseSecureParameters(boolean useSecureParameters) {
this.useSecureParameters = useSecureParameters;
}
public String getParameterStorePath() {
return parameterStorePath;
}
public void setParameterStorePath(String parameterStorePath) {
this.parameterStorePath = parameterStorePath;
}
}
@dstepanov @graemerocher still the default AWS Configuration is called
Issue description
I want to load the configuration into the "env" from aws ssm store which reads the json and loads it into the "env" environment variables which is something like this
This is the CustomPropertySourceLoader supposed to load the configuration in "env" environment variables;
I have also included src/main/resources/META-INF/services/io.micronaut.context.env.PropertySourceLoader with this configuration.CustomPropertySourceLoader
But the problem is still the values are not being loaded into "env" from the CustomPropertySourceLoader
Also these two gradle build dependencies have been included
Micronaut Version 4.2.x
Note : AwsParameterStoreConfigurationLoader works when inject at other places .