spring-cloud-aws icon indicating copy to clipboard operation
spring-cloud-aws copied to clipboard

Simplify using Localstack with ParameterStore and SecretsManager

Open maciejwalkowiak opened this issue 11 months ago • 6 comments

@ServiceConnection support that's being added in https://github.com/awspring/spring-cloud-aws/pull/1075 does not help with ParameterStore and SecretsManager, as those integration are initiated in the bootstrap phase, before service connection related factories kick in.

We can provide a BootstrapRegistryInitializer implementation for Localstack:

import io.awspring.cloud.autoconfigure.core.AwsProperties;
import io.awspring.cloud.autoconfigure.core.CredentialsProperties;
import io.awspring.cloud.autoconfigure.core.RegionProperties;
import org.springframework.boot.BootstrapRegistry;
import org.springframework.boot.BootstrapRegistryInitializer;
import org.springframework.util.Assert;
import org.testcontainers.containers.localstack.LocalStackContainer;

public class LocalstackBootstrapInitializer implements BootstrapRegistryInitializer {

	private final AwsProperties awsProperties;
	private final RegionProperties regionProperties;
	private final CredentialsProperties credentialsProperties;

	public LocalstackBootstrapInitializer(LocalStackContainer localStackContainer) {
		Assert.notNull(localStackContainer, "localstack container cannot be null");
		this.awsProperties = awsProperties(localStackContainer);
		this.regionProperties = regionProperties(localStackContainer);
		this.credentialsProperties = credentialsProperties(localStackContainer);
	}

	@Override
	public void initialize(BootstrapRegistry registry) {
		registry.register(AwsProperties.class, context -> awsProperties);
		registry.register(RegionProperties.class, context -> regionProperties);
		registry.register(CredentialsProperties.class, context -> credentialsProperties);
	}

	private static CredentialsProperties credentialsProperties(LocalStackContainer localStackContainer) {
		CredentialsProperties properties = new CredentialsProperties();
		properties.setAccessKey(localStackContainer.getAccessKey());
		properties.setSecretKey(localStackContainer.getSecretKey());
		return properties;
	}

	private static RegionProperties regionProperties(LocalStackContainer localStackContainer) {
		RegionProperties properties = new RegionProperties();
		properties.setStatic(localStackContainer.getRegion());
		return properties;
	}

	private static AwsProperties awsProperties(LocalStackContainer localStackContainer) {
		AwsProperties properties = new AwsProperties();
		properties.setEndpoint(localStackContainer.getEndpoint());
		return properties;
	}
}

that can be used like this:

@SpringBootTest(classes = SpringCloudAwsParameterStoreSampleTest.TestApp.class, useMainMethod = SpringBootTest.UseMainMethod.ALWAYS)
@Testcontainers
class SpringCloudAwsParameterStoreSampleTest {

	@Container
	private static LocalStackContainer localStackContainer = new LocalStackContainer(DockerImageName.parse("localstack/localstack:3.2.0"));

	@Test
	void foo() {

	}

	@SpringBootApplication
	public static class TestApp {

		public static void main(String[] args) {
			var app = new SpringApplication(SpringCloudAwsParameterStoreSampleTest.class);
			app.addBootstrapRegistryInitializer(new LocalstackBootstrapInitializer(localStackContainer));
			app.run(args);
		}
	}
}

maciejwalkowiak avatar Mar 09 '24 07:03 maciejwalkowiak