From d0eede8855a52d0b0ece7674944d8fb6755ec05d Mon Sep 17 00:00:00 2001 From: Anthony Dahanne Date: Tue, 14 Feb 2023 18:34:46 -0500 Subject: [PATCH] Compat with Spring Boot 3 Contains feedback from @Kehrlann Original commit by @abelsromero - amended to keep compatibility with Spring Boot 2 * Artemis * Updated 'host' to 'broker-url' * Fixed some rabbitmq properties in ArtemisBindingsPropertiesProcessor * Cassandra * Fixed configuration properties: see https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.0-Migration-Guide#cassandra-properties * Added 'throttler' properties: see https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.5-Release-Notes#cassandra-throttling-properties * Couchbase * Updated based on https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html#appendix.application-properties.data and spring-projects/spring-boot@abe43b2 * Elastic * Based on docs, clients have been consolidated, so most properties have been removed. * Updated based on https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.6-Release-Notes#elasticsearch-property-consolidation * Neo4j * Updated properties prefix: https://github.com/spring-projects/spring-data-neo4j/blob/main/src/main/asciidoc/appendix/migrating.adoc * Redis * Updated properties prefix: https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.0-Migration-Guide#redis-properties * Vault, matched properties with https://github.com/spring-cloud/spring-cloud-vault/blob/main/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultProperties.java * NOTE: 'spring.cloud.vault.aws-iam.server-id' seems it never existed, it was alwasy serverName and spring-cloud/spring-cloud-vault@9cff9eb * Added new metadata-service and identity-token-service properties for AZURE_MSI * Added 'trust-store' configuration for CERT. * Ignored 'key-store-type' & 'trust-store-type' for simplicity. Current approach implies users need to convert to JKS. * Fixed 'gcp-service-account' * Added K8s token-file --- README.md | 182 +++++++++---- .../ArtemisBindingsPropertiesProcessor.java | 116 ++++++-- ...dingFlattenedEnvironmentPostProcessor.java | 10 +- ...ndingSpecificEnvironmentPostProcessor.java | 13 +- .../CassandraBindingsPropertiesProcessor.java | 93 +++++-- .../CouchbaseBindingsPropertiesProcessor.java | 82 ++++-- ...sticsearchBindingsPropertiesProcessor.java | 83 ++++-- .../Neo4JBindingsPropertiesProcessor.java | 70 ++++- ...PostgreSqlBindingsPropertiesProcessor.java | 3 +- .../RedisBindingsPropertiesProcessor.java | 97 +++++-- .../boot/SpringBootVersionResolver.java | 23 ++ .../VaultBindingsPropertiesProcessor.java | 249 +++++++++++++----- src/main/resources/META-INF/spring.factories | 24 +- ...rtemisBindingsPropertiesProcessorTest.java | 34 ++- ...FlattenedEnvironmentPostProcessorTest.java | 8 +- ...gSpecificEnvironmentPostProcessorTest.java | 6 +- ...sandraBindingsPropertiesProcessorTest.java | 39 ++- ...chbaseBindingsPropertiesProcessorTest.java | 34 ++- ...searchBindingsPropertiesProcessorTest.java | 33 ++- .../Neo4JBindingsPropertiesProcessorTest.java | 23 +- .../RedisBindingsPropertiesProcessorTest.java | 32 ++- .../boot/SpringBootVersionResolverTest.java | 33 +++ .../VaultBindingsPropertiesProcessorTest.java | 83 +++++- 23 files changed, 1077 insertions(+), 293 deletions(-) create mode 100644 src/main/java/org/springframework/cloud/bindings/boot/SpringBootVersionResolver.java create mode 100644 src/test/java/org/springframework/cloud/bindings/boot/SpringBootVersionResolverTest.java diff --git a/README.md b/README.md index 8a0b947..1ed4715 100644 --- a/README.md +++ b/README.md @@ -38,12 +38,25 @@ Each auto-configuration is triggered by the type of binding. Each auto-configur Type: `artemis` Disable Property: `org.springframework.cloud.bindings.boot.artemis.enable` +#### Spring Boot 2 properties + | Property | Value | | --------------------------------------------------- | -------------------------------------- | | `spring.artemis.host` | `{host}` | +| `spring.artemis.port` | `{port}` | + +#### Spring Boot 3 properties + +| Property | Value | +| --------------------------------------------------- | -------------------------------------- | +| `spring.artemis.broker-url` | `{broker-url}` | + +#### Common properties + +| Property | Value | +| --------------------------------------------------- | -------------------------------------- | | `spring.artemis.mode` | `{mode}` | | `spring.artemis.password` | `{password}` | -| `spring.artemis.port` | `{port}` | | `spring.artemis.user` | `{user}` | | `spring.artemis.embedded.cluster-password` | `{embedded.cluster-password}` | | `spring.artemis.embedded.data-directory` | `{embedded.data-directory}` | @@ -65,30 +78,67 @@ Disable Property: `org.springframework.cloud.bindings.boot.artemis.enable` Type: `cassandra` Disable Property: `org.springframework.cloud.bindings.boot.cassandra.enable` -| Property | Value | -| -------------------------------------- | ------------------ | -| `spring.data.cassandra.cluster-name` | `{cluster-name}` | -| `spring.data.cassandra.compression` | `{compression}` | -| `spring.data.cassandra.contact-points` | `{contact-points}` | -| `spring.data.cassandra.keyspace-name` | `{keyspace-name}` | -| `spring.data.cassandra.password` | `{password}` | -| `spring.data.cassandra.port` | `{port}` | -| `spring.data.cassandra.ssl` | `{ssl}` | -| `spring.data.cassandra.username` | `{username}` | +#### Spring Boot 2 properties + +| Property | Value | +|-------------------------------------------------------------------|-----------------------------------------------| +| `spring.data.cassandra.cluster-name` | `{cluster-name}` | +| `spring.data.cassandra.compression` | `{compression}` | +| `spring.data.cassandra.contact-points` | `{contact-points}` | +| `spring.data.cassandra.keyspace-name` | `{keyspace-name}` | +| `spring.data.cassandra.password` | `{password}` | +| `spring.data.cassandra.port` | `{port}` | +| `spring.data.cassandra.ssl` | `{ssl}` | +| `spring.data.cassandra.username` | `{username}` | +| `spring.data.cassandra.request.throttler.drain-interval` | `{request.throttler.drain-interval}` | +| `spring.data.cassandra.request.throttler.max-concurrent-requests` | `{request.throttler.max-concurrent-requests}` | +| `spring.data.cassandra.request.throttler.max-queue-size` | `{request.throttler.max-queue-size}` | +| `spring.data.cassandra.request.throttler.max-requests-per-second` | `{request.throttler.max-requests-per-second}` | + +#### Spring Boot 3 properties + +| Property | Value | +|--------------------------------------------------------------|-----------------------------------------------| +| `spring.cassandra.cluster-name` | `{cluster-name}` | +| `spring.cassandra.compression` | `{compression}` | +| `spring.cassandra.contact-points` | `{contact-points}` | +| `spring.cassandra.keyspace-name` | `{keyspace-name}` | +| `spring.cassandra.password` | `{password}` | +| `spring.cassandra.port` | `{port}` | +| `spring.cassandra.ssl` | `{ssl}` | +| `spring.cassandra.username` | `{username}` | +| `spring.cassandra.request.throttler.drain-interval` | `{request.throttler.drain-interval}` | +| `spring.cassandra.request.throttler.max-concurrent-requests` | `{request.throttler.max-concurrent-requests}` | +| `spring.cassandra.request.throttler.max-queue-size` | `{request.throttler.max-queue-size}` | +| `spring.cassandra.request.throttler.max-requests-per-second` | `{request.throttler.max-requests-per-second}` | ### Couchbase Type: `couchbase` Disable Property: `org.springframework.cloud.bindings.boot.couchbase.enable` +#### Spring Boot 2 properties + | Property | Value | -| ------------------------------------------------- | ---------------------------------- | +|---------------------------------------------------|------------------------------------| | `spring.couchbase.bootstrap-hosts` | `{bootstrap-hosts}` | | `spring.couchbase.bucket.name` | `{bucket.name}` | | `spring.couchbase.bucket.password` | `{bucket.passsword}` | | `spring.couchbase.env.bootstrap.http-direct-port` | `{env.bootstrap.http-direct-port}` | | `spring.couchbase.env.bootstrap.http-ssl-port` | `{env.bootstrap.http-ssl-port}` | -| `spring.couchbase.password` | `{password}` | -| `spring.couchbase.username` | `{username}` | + +#### Spring Boot 3 properties + +| Property | Value | +|--------------------------------------------------|---------------------------| +| `spring.couchbase.connection-string` | `{connection-string}` | +| `spring.data.couchbase.bucket-name` | `{bucket-name}` | + +#### Common properties + +| Property | Value | +|---------------------------------------------------|---------------------------| +| `spring.couchbase.password` | `{password}` | +| `spring.couchbase.username` | `{username}` | ### DB2 RDBMS Type: `db2` @@ -109,6 +159,8 @@ Disable Property: `org.springframework.cloud.bindings.boot.db2.enable` Type: `elasticsearch` Disable Property: `org.springframework.cloud.bindings.boot.elasticsearch.enable` +#### Spring Boot 2 properties + | Property | Value | | ----------------------------------------------------- | -------------- | | `spring.data.elasticsearch.client.reactive.endpoints` | `{endpoints}` | @@ -123,6 +175,14 @@ Disable Property: `org.springframework.cloud.bindings.boot.elasticsearch.enable` | `spring.elasticsearch.rest.uris` | `{uris}` | | `spring.elasticsearch.rest.username` | `{username}` | +#### Spring Boot 3 properties + +| Property | Value | +|---------------------------------|---------------| +| `spring.elasticsearch.password` | `{password}` | +| `spring.elasticsearch.uris` | `{uris}` | +| `spring.elasticsearch.username` | `{username}` | + ### Kafka Type: `kafka` Disable Property: `org.springframework.cloud.bindings.boot.kafka.enable` @@ -180,11 +240,21 @@ Disable Property: `org.springframework.cloud.bindings.boot.mysql.enable` Type: `neo4j` Disable Property: `org.springframework.cloud.bindings.boot.neo4j.enable` +#### Spring Boot 2 properties + | Property | Value | | ---------------------------- | ------------ | -| `spring.data.neo4j.password` | `{password}` | | `spring.data.neo4j.uri` | `{uri}` | | `spring.data.neo4j.username` | `{username}` | +| `spring.data.neo4j.password` | `{password}` | + +#### Spring Boot 3 properties + +| Property | Value | +|-----------------------------------------|----------------| +| `spring.neo4j.uri` | `{uri}` | +| `spring.neo4j.authentication.username` | `{username}` | +| `spring.neo4j.authentication.password` | `{password}` | ### Oracle RDBMS Type: `oracle` @@ -231,6 +301,8 @@ Disable Property: `org.springframework.cloud.bindings.boot.rabbitmq.enable` Type: `redis` Disable Property: `org.springframework.cloud.bindings.boot.redis.enable` +#### Spring Boot 2 properties + | Property | Value | | ------------------------------------ | ------------------------- | | `spring.redis.client-name` | `{client-name}` | @@ -245,6 +317,22 @@ Disable Property: `org.springframework.cloud.bindings.boot.redis.enable` | `spring.redis.ssl` | `{ssl}` | | `spring.redis.url` | `{url}` | +#### Spring Boot 3 properties + +| Property | Value | +|-------------------------------------------|---------------------------| +| `spring.data.redis.client-name` | `{client-name}` | +| `spring.data.redis.cluster.max-redirects` | `{cluster.max-redirects}` | +| `spring.data.redis.cluster.nodes` | `{cluster.nodes}` | +| `spring.data.redis.database` | `{database}` | +| `spring.data.redis.host` | `{host}` | +| `spring.data.redis.password` | `{password}` | +| `spring.data.redis.port` | `{port}` | +| `spring.data.redis.sentinel.master` | `{sentinel.master}` | +| `spring.data.redis.sentinel.nodes` | `{sentinel.nodes}` | +| `spring.data.redis.ssl` | `{ssl}` | +| `spring.data.redis.url` | `{url}` | + ### SAP Hana Type: `hana` Disable Property: `org.springframework.cloud.bindings.boot.hana.enable` @@ -361,25 +449,30 @@ If `{authentication-method}` is equal to `aws_ec2`: | `spring.cloud.vault.aws-ec2.role` | `{role}` | If `{authentication-method}` is equal to `aws_iam`: -| Property | Value | -| ----------------------------------------- | ------------------------ | -| `spring.cloud.vault.aws-iam.aws-path` | `{aws-path}` | -| `spring.cloud.vault.aws-iam.endpoint-uri` | `{aws-sts-endpoint-uri}` | -| `spring.cloud.vault.aws-iam.role` | `{role}` | -| `spring.cloud.vault.aws-iam.server-id` | `{aws-iam-server-id}` | +| Property | Value | +|-------------------------------------------|----------------------------------------| +| `spring.cloud.vault.aws-iam.aws-path` | `{aws-path}` | +| `spring.cloud.vault.aws-iam.endpoint-uri` | `{aws-sts-endpoint-uri}` | +| `spring.cloud.vault.aws-iam.role` | `{role}` | +| `spring.cloud.vault.aws-iam.server-id` | `{aws-iam-server-id}` Spring Boot 2 | +| `spring.cloud.vault.aws-iam.server-name` | `{aws-iam-server-name}` Spring Boot 3 | If `{authentication-method}` is equal to `azure_msi`: -| Property | Value | -| ----------------------------------------- | -------------- | -| `spring.cloud.vault.azure-msi.azure-path` | `{azure-path}` | -| `spring.cloud.vault.azure-msi.role` | `{role}` | +| Property | Value | +|-------------------------------------------------------|------------------------------------------| +| `spring.cloud.vault.azure-msi.azure-path` | `{azure-path}` | +| `spring.cloud.vault.azure-msi.role` | `{role}` | +| `spring.cloud.vault.azure-msi.metadata-service` | `{metadata-service}` Spring Boot 3 | +| `spring.cloud.vault.azure-msi.identity-token-service` | `{identity-token-service}` Spring Boot 3 | If `{authentication-method}` is equal to `cert`: -| Property | Value | -| ------------------------------------------- | --------------------------------------------- | -| `spring.cloud.vault.ssl.cert-auth-path` | `{cert-auth-path}` | -| `spring.cloud.vault.ssl.key-store-password` | `{key-store-password}` | -| `spring.cloud.vault.ssl.key-store` | `${SERVICE_BINDING_ROOT}/{name}/keystore.jks` | +| Property | Value | +|-----------------------------------------------|---------------------------------------------------------------| +| `spring.cloud.vault.ssl.cert-auth-path` | `{cert-auth-path}` | +| `spring.cloud.vault.ssl.key-store-password` | `{key-store-password}` | +| `spring.cloud.vault.ssl.key-store` | `${SERVICE_BINDING_ROOT}/{name}/keystore.jks` | +| `spring.cloud.vault.ssl.trust-store` | `${SERVICE_BINDING_ROOT}/{name}/truststore.jks` Spring Boot 3 | +| `spring.cloud.vault.ssl.trust-store-password` | `{trust-store-password}` Spring Boot 3 | If `{authentication-method}` is equal to `cubbyhole`: | Property | Value | @@ -393,23 +486,24 @@ If `{authentication-method}` is equal to `gcp_gce`: | `spring.cloud.vault.gcp-gce.role` | `{role}` | | `spring.cloud.vault.gcp-gce.service-account` | `{gcp-service-account}` | - If `{authentication-method}` is equal to `gcp_iam`: -| Property | Value | -| ---------------------------------------------------- | ------------------------------------------------- | -| `spring.cloud.vault.gcp-iam.credentials.encoded-key` | `{encoded-key}` | -| `spring.cloud.vault.gcp-iam.credentials.location` | `${SERVICE_BINDING_ROOT}/{name}/credentials.json` | -| `spring.cloud.vault.gcp-iam.gcp-path` | `{gcp-path}` | -| `spring.cloud.vault.gcp-iam.jwt-validity` | `{jwt-validity}` | -| `spring.cloud.vault.gcp-iam.project-id` | `{gcp-project-id}` | -| `spring.cloud.vault.gcp-iam.role` | `{role}` | -| `spring.cloud.vault.gcp-iam.service-account` | `{gcp-service-account}` | +| Property | Value | +|------------------------------------------------------|----------------------------------------------------| +| `spring.cloud.vault.gcp-iam.credentials.encoded-key` | `{encoded-key}` | +| `spring.cloud.vault.gcp-iam.credentials.location` | `${SERVICE_BINDING_ROOT}/{name}/credentials.json` | +| `spring.cloud.vault.gcp-iam.gcp-path` | `{gcp-path}` | +| `spring.cloud.vault.gcp-iam.jwt-validity` | `{jwt-validity}` | +| `spring.cloud.vault.gcp-iam.project-id` | `{gcp-project-id}` | +| `spring.cloud.vault.gcp-iam.role` | `{role}` | +| `spring.cloud.vault.gcp-iam.service-account` | `{gcp-service-account}` Spring Boot 2 | +| `spring.cloud.vault.gcp-iam.service-account-id` | `{gcp-service-account}` Spring Boot 3 | If `{authentication-method}` is equal to `kubernetes`: -| Property | Value | -| ----------------------------------------------- | ------------------- | -| `spring.cloud.vault.kubernetes.kubernetes-path` | `{kubernetes-path}` | -| `spring.cloud.vault.kubernetes.role` | `{role}` | +| Property | Value | +|-----------------------------------------------------------------------|---------------------------------------------------------| +| `spring.cloud.vault.kubernetes.role` | `{role}` | +| `spring.cloud.vault.kubernetes.kubernetes-path` | `{kubernetes-path}` | +| `spring.cloud.vault.kubernetes.kubernetes-service-account-token-file` | `{kubernetes-service-account-token-file}` Spring Boot 3 | If `{authentication-method}` is equal to `token`: | Property | Value | diff --git a/src/main/java/org/springframework/cloud/bindings/boot/ArtemisBindingsPropertiesProcessor.java b/src/main/java/org/springframework/cloud/bindings/boot/ArtemisBindingsPropertiesProcessor.java index 0461210..fb9e328 100644 --- a/src/main/java/org/springframework/cloud/bindings/boot/ArtemisBindingsPropertiesProcessor.java +++ b/src/main/java/org/springframework/cloud/bindings/boot/ArtemisBindingsPropertiesProcessor.java @@ -27,45 +27,105 @@ import static org.springframework.cloud.bindings.boot.Guards.isTypeEnabled; /** * An implementation of {@link BindingsPropertiesProcessor} that detects {@link Binding}s of type: {@value TYPE}. */ -public final class ArtemisBindingsPropertiesProcessor implements BindingsPropertiesProcessor { +public final class ArtemisBindingsPropertiesProcessor { /** * The {@link Binding} type that this processor is interested in: {@value}. **/ public static final String TYPE = "artemis"; - @Override - public void process(Environment environment, Bindings bindings, Map properties) { - if (!isTypeEnabled(environment, TYPE)) { - return; + public final static class Boot2 extends SpringBootVersionResolver implements BindingsPropertiesProcessor { + + private static final int BOOT_VERSION = 2; + + Boot2(int forcedVersion) { + super(forcedVersion); } - bindings.filterBindings(TYPE).forEach(binding -> { - MapMapper map = new MapMapper(binding.getSecret(), properties); + public Boot2() { + } - map.from("host").to("spring.artemis.host"); - map.from("mode").to("spring.artemis.mode"); - map.from("password").to("spring.artemis.password"); - map.from("port").to("spring.artemis.port"); - map.from("user").to("spring.artemis.user"); + @Override + public void process(Environment environment, Bindings bindings, Map properties) { + if (!isTypeEnabled(environment, TYPE)) { + return; + } + if (!isBootMajorVersionEnabled(BOOT_VERSION)) { + return; + } - map.from("embedded.cluster-password").to("spring.artemis.embedded.cluster-password"); - map.from("embedded.data-directory").to("spring.artemis.embedded.data-directory"); - map.from("embedded.enabled").to("spring.artemis.embedded.enabled"); - map.from("embedded.persistent").to("spring.artemis.embedded.persistent"); - map.from("embedded.queues").to("spring.artemis.embedded.queues"); - map.from("embedded.server-id").to("spring.artemis.embedded.server-id"); - map.from("embedded.topics").to("spring.artemis.embedded.topics"); + bindings.filterBindings(TYPE).forEach(binding -> { + MapMapper map = new MapMapper(binding.getSecret(), properties); + map.from("host").to("spring.artemis.host"); + map.from("port").to("spring.artemis.port"); - map.from("pool.block-if-full").to("spring.rabbitmq.pool.block-if-full"); - map.from("pool.block-if-full-timeout").to("spring.rabbitmq.pool.block-if-full-timeout"); - map.from("pool.enabled").to("spring.rabbitmq.pool.enabled"); - map.from("pool.idle-timeout").to("spring.rabbitmq.pool.idle-timeout"); - map.from("pool.max-connections").to("spring.rabbitmq.pool.max-connections"); - map.from("pool.max-sessions-per-connection").to("spring.rabbitmq.pool.max-sessions-per-connection"); - map.from("pool.time-between-expiration-check").to("spring.rabbitmq.pool.time-between-expiration-check"); - map.from("pool.use-anonymous-producers").to("spring.rabbitmq.pool.use-anonymous-producers"); - }); + map.from("pool.block-if-full").to("spring.rabbitmq.pool.block-if-full"); + map.from("pool.block-if-full-timeout").to("spring.rabbitmq.pool.block-if-full-timeout"); + map.from("pool.enabled").to("spring.rabbitmq.pool.enabled"); + map.from("pool.idle-timeout").to("spring.rabbitmq.pool.idle-timeout"); + map.from("pool.max-connections").to("spring.rabbitmq.pool.max-connections"); + map.from("pool.max-sessions-per-connection").to("spring.rabbitmq.pool.max-sessions-per-connection"); + map.from("pool.time-between-expiration-check").to("spring.rabbitmq.pool.time-between-expiration-check"); + map.from("pool.use-anonymous-producers").to("spring.rabbitmq.pool.use-anonymous-producers"); + + commonProperties(map); + }); + } + } + + /** + * This is a special case for Boot 3. + */ + public final static class Boot3 extends SpringBootVersionResolver implements BindingsPropertiesProcessor { + + private static final int BOOT_VERSION = 3; + + Boot3(int forcedVersion) { + super(forcedVersion); + } + + public Boot3() { + } + + @Override + public void process(Environment environment, Bindings bindings, Map properties) { + if (!isTypeEnabled(environment, TYPE)) { + return; + } + if (!isBootMajorVersionEnabled(BOOT_VERSION)) { + return; + } + + bindings.filterBindings(TYPE).forEach(binding -> { + MapMapper map = new MapMapper(binding.getSecret(), properties); + map.from("broker-url").to("spring.artemis.broker-url"); + + map.from("pool.block-if-full").to("spring.artemis.pool.block-if-full"); + map.from("pool.block-if-full-timeout").to("spring.artemis.pool.block-if-full-timeout"); + map.from("pool.enabled").to("spring.artemis.pool.enabled"); + map.from("pool.idle-timeout").to("spring.artemis.pool.idle-timeout"); + map.from("pool.max-connections").to("spring.artemis.pool.max-connections"); + map.from("pool.max-sessions-per-connection").to("spring.artemis.pool.max-sessions-per-connection"); + map.from("pool.time-between-expiration-check").to("spring.artemis.pool.time-between-expiration-check"); + map.from("pool.use-anonymous-producers").to("spring.artemis.pool.use-anonymous-producers"); + + commonProperties(map); + }); + } + } + + private static void commonProperties(MapMapper map) { + map.from("mode").to("spring.artemis.mode"); + map.from("password").to("spring.artemis.password"); + map.from("user").to("spring.artemis.user"); + + map.from("embedded.cluster-password").to("spring.artemis.embedded.cluster-password"); + map.from("embedded.data-directory").to("spring.artemis.embedded.data-directory"); + map.from("embedded.enabled").to("spring.artemis.embedded.enabled"); + map.from("embedded.persistent").to("spring.artemis.embedded.persistent"); + map.from("embedded.queues").to("spring.artemis.embedded.queues"); + map.from("embedded.server-id").to("spring.artemis.embedded.server-id"); + map.from("embedded.topics").to("spring.artemis.embedded.topics"); } } diff --git a/src/main/java/org/springframework/cloud/bindings/boot/BindingFlattenedEnvironmentPostProcessor.java b/src/main/java/org/springframework/cloud/bindings/boot/BindingFlattenedEnvironmentPostProcessor.java index 7f7d4a9..82ce617 100644 --- a/src/main/java/org/springframework/cloud/bindings/boot/BindingFlattenedEnvironmentPostProcessor.java +++ b/src/main/java/org/springframework/cloud/bindings/boot/BindingFlattenedEnvironmentPostProcessor.java @@ -16,8 +16,11 @@ package org.springframework.cloud.bindings.boot; +import java.util.HashMap; +import java.util.Map; + import org.springframework.boot.SpringApplication; -import org.springframework.boot.context.config.ConfigFileApplicationListener; +import org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor; import org.springframework.boot.context.event.ApplicationPreparedEvent; import org.springframework.boot.env.EnvironmentPostProcessor; import org.springframework.boot.logging.DeferredLog; @@ -26,9 +29,6 @@ import org.springframework.context.ApplicationListener; import org.springframework.core.Ordered; import org.springframework.core.env.ConfigurableEnvironment; -import java.util.HashMap; -import java.util.Map; - import static org.springframework.cloud.bindings.boot.PropertySourceContributor.contributePropertySource; /** @@ -59,7 +59,7 @@ public final class BindingFlattenedEnvironmentPostProcessor implements Applicati @Override public int getOrder() { // Before ConfigFileApplicationListener so values there can use values from {@link Bindings}. - return ConfigFileApplicationListener.DEFAULT_ORDER - 1; + return ConfigDataEnvironmentPostProcessor.ORDER - 1; } @Override diff --git a/src/main/java/org/springframework/cloud/bindings/boot/BindingSpecificEnvironmentPostProcessor.java b/src/main/java/org/springframework/cloud/bindings/boot/BindingSpecificEnvironmentPostProcessor.java index f02c588..2e86133 100644 --- a/src/main/java/org/springframework/cloud/bindings/boot/BindingSpecificEnvironmentPostProcessor.java +++ b/src/main/java/org/springframework/cloud/bindings/boot/BindingSpecificEnvironmentPostProcessor.java @@ -16,8 +16,13 @@ package org.springframework.cloud.bindings.boot; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import org.springframework.boot.SpringApplication; -import org.springframework.boot.context.config.ConfigFileApplicationListener; +import org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor; import org.springframework.boot.context.event.ApplicationPreparedEvent; import org.springframework.boot.env.EnvironmentPostProcessor; import org.springframework.boot.logging.DeferredLog; @@ -28,10 +33,6 @@ import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.PropertySource; import org.springframework.core.io.support.SpringFactoriesLoader; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; import static org.springframework.cloud.bindings.boot.Guards.isGlobalEnabled; import static org.springframework.cloud.bindings.boot.PropertySourceContributor.contributePropertySource; @@ -77,7 +78,7 @@ public final class BindingSpecificEnvironmentPostProcessor implements Applicatio @Override public int getOrder() { // Before ConfigFileApplicationListener so values there can use values from {@link Bindings}. - return ConfigFileApplicationListener.DEFAULT_ORDER - 1; + return ConfigDataEnvironmentPostProcessor.ORDER - 1; } @Override diff --git a/src/main/java/org/springframework/cloud/bindings/boot/CassandraBindingsPropertiesProcessor.java b/src/main/java/org/springframework/cloud/bindings/boot/CassandraBindingsPropertiesProcessor.java index d6936c4..7955681 100644 --- a/src/main/java/org/springframework/cloud/bindings/boot/CassandraBindingsPropertiesProcessor.java +++ b/src/main/java/org/springframework/cloud/bindings/boot/CassandraBindingsPropertiesProcessor.java @@ -27,31 +27,92 @@ import static org.springframework.cloud.bindings.boot.Guards.isTypeEnabled; /** * An implementation of {@link BindingsPropertiesProcessor} that detects {@link Binding}s of type: {@value TYPE}. */ -public final class CassandraBindingsPropertiesProcessor implements BindingsPropertiesProcessor { +public final class CassandraBindingsPropertiesProcessor { /** * The {@link Binding} type that this processor is interested in: {@value}. **/ public static final String TYPE = "cassandra"; - @Override - public void process(Environment environment, Bindings bindings, Map properties) { - if (!isTypeEnabled(environment, TYPE)) { - return; + public final static class Boot2 extends SpringBootVersionResolver implements BindingsPropertiesProcessor { + + private static final int BOOT_VERSION = 2; + + Boot2(int forcedVersion) { + super(forcedVersion); } - bindings.filterBindings(TYPE).forEach(binding -> { - MapMapper map = new MapMapper(binding.getSecret(), properties); + public Boot2() { + } - map.from("cluster-name").to("spring.data.cassandra.cluster-name"); - map.from("compression").to("spring.data.cassandra.compression"); - map.from("contact-points").to("spring.data.cassandra.contact-points"); - map.from("keyspace-name").to("spring.data.cassandra.keyspace-name"); - map.from("password").to("spring.data.cassandra.password"); - map.from("port").to("spring.data.cassandra.port"); - map.from("ssl").to("spring.data.cassandra.ssl"); - map.from("username").to("spring.data.cassandra.username"); - }); + @Override + public void process(Environment environment, Bindings bindings, Map properties) { + if (!isTypeEnabled(environment, TYPE)) { + return; + } + if (!isBootMajorVersionEnabled(BOOT_VERSION)) { + return; + } + + bindings.filterBindings(TYPE).forEach(binding -> { + MapMapper map = new MapMapper(binding.getSecret(), properties); + map.from("cluster-name").to("spring.data.cassandra.cluster-name"); + map.from("compression").to("spring.data.cassandra.compression"); + map.from("contact-points").to("spring.data.cassandra.contact-points"); + map.from("keyspace-name").to("spring.data.cassandra.keyspace-name"); + map.from("password").to("spring.data.cassandra.password"); + map.from("port").to("spring.data.cassandra.port"); + map.from("ssl").to("spring.data.cassandra.ssl"); + map.from("username").to("spring.data.cassandra.username"); + + map.from("request.throttler.drain-interval").to("spring.data.cassandra.request.throttler.drain-interval"); + map.from("request.throttler.max-concurrent-requests").to("spring.data.cassandra.request.throttler.max-concurrent-requests"); + map.from("request.throttler.max-queue-size").to("spring.data.cassandra.request.throttler.max-queue-size"); + map.from("request.throttler.max-requests-per-second").to("spring.data.cassandra.request.throttler.max-requests-per-second"); + }); + } + } + + /** + * This is a special case for Boot 3. + */ + public final static class Boot3 extends SpringBootVersionResolver implements BindingsPropertiesProcessor { + + private static final int BOOT_VERSION = 3; + + Boot3(int forcedVersion) { + super(forcedVersion); + } + + public Boot3() { + } + + @Override + public void process(Environment environment, Bindings bindings, Map properties) { + if (!isTypeEnabled(environment, TYPE)) { + return; + } + if (!isBootMajorVersionEnabled(BOOT_VERSION)) { + return; + } + + bindings.filterBindings(TYPE).forEach(binding -> { + MapMapper map = new MapMapper(binding.getSecret(), properties); + map.from("cluster-name").to("spring.cassandra.cluster-name"); + map.from("compression").to("spring.cassandra.compression"); + map.from("contact-points").to("spring.cassandra.contact-points"); + map.from("keyspace-name").to("spring.cassandra.keyspace-name"); + map.from("password").to("spring.cassandra.password"); + map.from("port").to("spring.cassandra.port"); + map.from("ssl").to("spring.cassandra.ssl"); + map.from("username").to("spring.cassandra.username"); + + map.from("request.throttler.drain-interval").to("spring.cassandra.request.throttler.drain-interval"); + map.from("request.throttler.max-concurrent-requests").to("spring.cassandra.request.throttler.max-concurrent-requests"); + map.from("request.throttler.max-queue-size").to("spring.cassandra.request.throttler.max-queue-size"); + map.from("request.throttler.max-requests-per-second").to("spring.cassandra.request.throttler.max-requests-per-second"); + }); + } } } diff --git a/src/main/java/org/springframework/cloud/bindings/boot/CouchbaseBindingsPropertiesProcessor.java b/src/main/java/org/springframework/cloud/bindings/boot/CouchbaseBindingsPropertiesProcessor.java index 6602989..c595422 100644 --- a/src/main/java/org/springframework/cloud/bindings/boot/CouchbaseBindingsPropertiesProcessor.java +++ b/src/main/java/org/springframework/cloud/bindings/boot/CouchbaseBindingsPropertiesProcessor.java @@ -27,30 +27,82 @@ import static org.springframework.cloud.bindings.boot.Guards.isTypeEnabled; /** * An implementation of {@link BindingsPropertiesProcessor} that detects {@link Binding}s of type: {@value TYPE}. */ -final class CouchbaseBindingsPropertiesProcessor implements BindingsPropertiesProcessor { +final class CouchbaseBindingsPropertiesProcessor { /** * The {@link Binding} type that this processor is interested in: {@value}. **/ public static final String TYPE = "couchbase"; - @Override - public void process(Environment environment, Bindings bindings, Map properties) { - if (!isTypeEnabled(environment, TYPE)) { - return; + public final static class Boot2 extends SpringBootVersionResolver implements BindingsPropertiesProcessor { + + private static final int BOOT_VERSION = 2; + + Boot2(int forcedVersion) { + super(forcedVersion); } - bindings.filterBindings(TYPE).forEach(binding -> { - MapMapper map = new MapMapper(binding.getSecret(), properties); + public Boot2() { + } - map.from("bootstrap-hosts").to("spring.couchbase.bootstrap-hosts"); - map.from("bucket.name").to("spring.couchbase.bucket.name"); - map.from("bucket.password").to("spring.couchbase.bucket.password"); - map.from("env.bootstrap.http-direct-port").to("spring.couchbase.env.bootstrap.http-direct-port"); - map.from("env.bootstrap.http-ssl-port").to("spring.couchbase.env.bootstrap.http-ssl-port"); - map.from("password").to("spring.couchbase.password"); - map.from("username").to("spring.couchbase.username"); - }); + @Override + public void process(Environment environment, Bindings bindings, Map properties) { + if (!isTypeEnabled(environment, TYPE)) { + return; + } + if (!isBootMajorVersionEnabled(BOOT_VERSION)) { + return; + } + + bindings.filterBindings(TYPE).forEach(binding -> { + MapMapper map = new MapMapper(binding.getSecret(), properties); + map.from("bootstrap-hosts").to("spring.couchbase.bootstrap-hosts"); + map.from("bucket.name").to("spring.couchbase.bucket.name"); + map.from("bucket.password").to("spring.couchbase.bucket.password"); + map.from("env.bootstrap.http-direct-port").to("spring.couchbase.env.bootstrap.http-direct-port"); + map.from("env.bootstrap.http-ssl-port").to("spring.couchbase.env.bootstrap.http-ssl-port"); + commonProperties(map); + + }); + } + } + + /** + * This is a special case for Boot 3. + */ + public final static class Boot3 extends SpringBootVersionResolver implements BindingsPropertiesProcessor { + + private static final int BOOT_VERSION = 3; + + Boot3(int forcedVersion) { + super(forcedVersion); + } + + public Boot3() { + } + + @Override + public void process(Environment environment, Bindings bindings, Map properties) { + if (!isTypeEnabled(environment, TYPE)) { + return; + } + if (!isBootMajorVersionEnabled(BOOT_VERSION)) { + return; + } + + bindings.filterBindings(TYPE).forEach(binding -> { + MapMapper map = new MapMapper(binding.getSecret(), properties); + map.from("bucket-name").to("spring.data.couchbase.bucket-name"); + map.from("connection-string").to("spring.couchbase.connection-string"); + commonProperties(map); + + }); + } + } + + private static void commonProperties(MapMapper map) { + map.from("password").to("spring.couchbase.password"); + map.from("username").to("spring.couchbase.username"); } } diff --git a/src/main/java/org/springframework/cloud/bindings/boot/ElasticsearchBindingsPropertiesProcessor.java b/src/main/java/org/springframework/cloud/bindings/boot/ElasticsearchBindingsPropertiesProcessor.java index 1cc75df..0d21031 100644 --- a/src/main/java/org/springframework/cloud/bindings/boot/ElasticsearchBindingsPropertiesProcessor.java +++ b/src/main/java/org/springframework/cloud/bindings/boot/ElasticsearchBindingsPropertiesProcessor.java @@ -27,35 +27,80 @@ import static org.springframework.cloud.bindings.boot.Guards.isTypeEnabled; /** * An implementation of {@link BindingsPropertiesProcessor} that detects {@link Binding}s of type: {@value TYPE}. */ -final class ElasticsearchBindingsPropertiesProcessor implements BindingsPropertiesProcessor { +final class ElasticsearchBindingsPropertiesProcessor { /** * The {@link Binding} type that this processor is interested in: {@value}. **/ public static final String TYPE = "elasticsearch"; + public final static class Boot2 extends SpringBootVersionResolver implements BindingsPropertiesProcessor { - @Override - public void process(Environment environment, Bindings bindings, Map properties) { - if (!isTypeEnabled(environment, TYPE)) { - return; + private static final int BOOT_VERSION = 2; + + Boot2(int forcedVersion) { + super(forcedVersion); } - bindings.filterBindings(TYPE).forEach(binding -> { - MapMapper map = new MapMapper(binding.getSecret(), properties); + public Boot2() { + } - map.from("endpoints").to("spring.data.elasticsearch.client.reactive.endpoints"); - map.from("password").to("spring.data.elasticsearch.client.reactive.password"); - map.from("use-ssl").to("spring.data.elasticsearch.client.reactive.use-ssl"); - map.from("username").to("spring.data.elasticsearch.client.reactive.username"); - map.from("password").to("spring.elasticsearch.jest.password"); - map.from("proxy.host").to("spring.elasticsearch.jest.proxy.host"); - map.from("proxy.port").to("spring.elasticsearch.jest.proxy.port"); - map.from("username").to("spring.elasticsearch.jest.username"); - map.from("password").to("spring.elasticsearch.rest.password"); - map.from("uris").to("spring.elasticsearch.rest.uris"); - map.from("username").to("spring.elasticsearch.rest.username"); - }); + @Override + public void process(Environment environment, Bindings bindings, Map properties) { + if (!isTypeEnabled(environment, TYPE)) { + return; + } + if (!isBootMajorVersionEnabled(BOOT_VERSION)) { + return; + } + + bindings.filterBindings(TYPE).forEach(binding -> { + MapMapper map = new MapMapper(binding.getSecret(), properties); + map.from("endpoints").to("spring.data.elasticsearch.client.reactive.endpoints"); + map.from("password").to("spring.data.elasticsearch.client.reactive.password"); + map.from("use-ssl").to("spring.data.elasticsearch.client.reactive.use-ssl"); + map.from("username").to("spring.data.elasticsearch.client.reactive.username"); + map.from("password").to("spring.elasticsearch.jest.password"); + map.from("proxy.host").to("spring.elasticsearch.jest.proxy.host"); + map.from("proxy.port").to("spring.elasticsearch.jest.proxy.port"); + map.from("username").to("spring.elasticsearch.jest.username"); + map.from("password").to("spring.elasticsearch.rest.password"); + map.from("uris").to("spring.elasticsearch.rest.uris"); + map.from("username").to("spring.elasticsearch.rest.username"); + }); + } + } + + /** + * This is a special case for Boot 3. + */ + public final static class Boot3 extends SpringBootVersionResolver implements BindingsPropertiesProcessor { + + private static final int BOOT_VERSION = 3; + + Boot3(int forcedVersion) { + super(forcedVersion); + } + + public Boot3() { + } + + @Override + public void process(Environment environment, Bindings bindings, Map properties) { + if (!isTypeEnabled(environment, TYPE)) { + return; + } + if (!isBootMajorVersionEnabled(BOOT_VERSION)) { + return; + } + + bindings.filterBindings(TYPE).forEach(binding -> { + MapMapper map = new MapMapper(binding.getSecret(), properties); + map.from("password").to("spring.elasticsearch.password"); + map.from("uris").to("spring.elasticsearch.uris"); + map.from("username").to("spring.elasticsearch.username"); + }); + } } } diff --git a/src/main/java/org/springframework/cloud/bindings/boot/Neo4JBindingsPropertiesProcessor.java b/src/main/java/org/springframework/cloud/bindings/boot/Neo4JBindingsPropertiesProcessor.java index b40be29..2daffb1 100644 --- a/src/main/java/org/springframework/cloud/bindings/boot/Neo4JBindingsPropertiesProcessor.java +++ b/src/main/java/org/springframework/cloud/bindings/boot/Neo4JBindingsPropertiesProcessor.java @@ -27,25 +27,73 @@ import static org.springframework.cloud.bindings.boot.Guards.isTypeEnabled; /** * An implementation of {@link BindingsPropertiesProcessor} that detects {@link Binding}s of type: {@value TYPE}. */ -final class Neo4JBindingsPropertiesProcessor implements BindingsPropertiesProcessor { +final class Neo4JBindingsPropertiesProcessor { /** * The {@link Binding} type that this processor is interested in: {@value}. **/ public static final String TYPE = "neo4j"; - @Override - public void process(Environment environment, Bindings bindings, Map properties) { - if (!isTypeEnabled(environment, TYPE)) { - return; + public final static class Boot2 extends SpringBootVersionResolver implements BindingsPropertiesProcessor { + + private static final int BOOT_VERSION = 2; + + Boot2(int forcedVersion) { + super(forcedVersion); } - bindings.filterBindings(TYPE).forEach(binding -> { - MapMapper map = new MapMapper(binding.getSecret(), properties); + public Boot2() { + } - map.from("password").to("spring.data.neo4j.password"); - map.from("uri").to("spring.data.neo4j.uri"); - map.from("username").to("spring.data.neo4j.username"); - }); + @Override + public void process(Environment environment, Bindings bindings, Map properties) { + if (!isTypeEnabled(environment, TYPE)) { + return; + } + if (!isBootMajorVersionEnabled(BOOT_VERSION)) { + return; + } + + bindings.filterBindings(TYPE).forEach(binding -> { + MapMapper map = new MapMapper(binding.getSecret(), properties); + map.from("password").to("spring.data.neo4j.password"); + map.from("uri").to("spring.data.neo4j.uri"); + map.from("username").to("spring.data.neo4j.username"); + + }); + } + } + + /** + * This is a special case for Boot 3. + */ + public final static class Boot3 extends SpringBootVersionResolver implements BindingsPropertiesProcessor { + + private static final int BOOT_VERSION = 3; + + Boot3(int forcedVersion) { + super(forcedVersion); + } + + public Boot3() { + } + + @Override + public void process(Environment environment, Bindings bindings, Map properties) { + if (!isTypeEnabled(environment, TYPE)) { + return; + } + if (!isBootMajorVersionEnabled(BOOT_VERSION)) { + return; + } + + bindings.filterBindings(TYPE).forEach(binding -> { + MapMapper map = new MapMapper(binding.getSecret(), properties); + map.from("password").to("spring.neo4j.authentication.password"); + map.from("uri").to("spring.neo4j.uri"); + map.from("username").to("spring.neo4j.authentication.username"); + + }); + } } } diff --git a/src/main/java/org/springframework/cloud/bindings/boot/PostgreSqlBindingsPropertiesProcessor.java b/src/main/java/org/springframework/cloud/bindings/boot/PostgreSqlBindingsPropertiesProcessor.java index b5dbe72..4cdd783 100644 --- a/src/main/java/org/springframework/cloud/bindings/boot/PostgreSqlBindingsPropertiesProcessor.java +++ b/src/main/java/org/springframework/cloud/bindings/boot/PostgreSqlBindingsPropertiesProcessor.java @@ -69,8 +69,7 @@ public final class PostgreSqlBindingsPropertiesProcessor implements BindingsProp (host, port, database) -> String.format("jdbc:postgresql://%s:%s/%s", host, port, database)); String sslParam = buildSslModeParam(binding); - String dbOptions = buildDbOptions(binding); - String sslModeOptions = dbOptions; + String sslModeOptions = buildDbOptions(binding); if (!"".equals(sslParam) && !"".equals(sslModeOptions)) { sslModeOptions = sslParam + "&" + sslModeOptions; } else if (!"".equals(sslParam) ) { diff --git a/src/main/java/org/springframework/cloud/bindings/boot/RedisBindingsPropertiesProcessor.java b/src/main/java/org/springframework/cloud/bindings/boot/RedisBindingsPropertiesProcessor.java index b1d1a71..1d54e1a 100644 --- a/src/main/java/org/springframework/cloud/bindings/boot/RedisBindingsPropertiesProcessor.java +++ b/src/main/java/org/springframework/cloud/bindings/boot/RedisBindingsPropertiesProcessor.java @@ -27,34 +27,93 @@ import static org.springframework.cloud.bindings.boot.Guards.isTypeEnabled; /** * An implementation of {@link BindingsPropertiesProcessor} that detects {@link Binding}s of type: {@value TYPE}. */ -public final class RedisBindingsPropertiesProcessor implements BindingsPropertiesProcessor { +public final class RedisBindingsPropertiesProcessor { /** * The {@link Binding} type that this processor is interested in: {@value}. **/ public static final String TYPE = "redis"; - @Override - public void process(Environment environment, Bindings bindings, Map properties) { - if (!isTypeEnabled(environment, TYPE)) { - return; + /** + * This is a special case for Boot 2. + */ + public final static class Boot2 extends SpringBootVersionResolver implements BindingsPropertiesProcessor { + + private static final int BOOT_VERSION = 2; + + Boot2(int forcedVersion) { + super(forcedVersion); } - bindings.filterBindings(TYPE).forEach(binding -> { - MapMapper map = new MapMapper(binding.getSecret(), properties); + public Boot2() { + } - map.from("client-name").to("spring.redis.client-name"); - map.from("cluster.max-redirects").to("spring.redis.cluster.max-redirects"); - map.from("cluster.nodes").to("spring.redis.cluster.nodes"); - map.from("database").to("spring.redis.database"); - map.from("host").to("spring.redis.host"); - map.from("password").to("spring.redis.password"); - map.from("port").to("spring.redis.port"); - map.from("sentinel.master").to("spring.redis.sentinel.master"); - map.from("sentinel.nodes").to("spring.redis.sentinel.nodes"); - map.from("ssl").to("spring.redis.ssl"); - map.from("url").to("spring.redis.url"); - }); + @Override + public void process(Environment environment, Bindings bindings, Map properties) { + if (!isTypeEnabled(environment, TYPE)) { + return; + } + if (!isBootMajorVersionEnabled(BOOT_VERSION)) { + return; + } + + bindings.filterBindings(TYPE).forEach(binding -> { + MapMapper map = new MapMapper(binding.getSecret(), properties); + + map.from("client-name").to("spring.redis.client-name"); + map.from("cluster.max-redirects").to("spring.redis.cluster.max-redirects"); + map.from("cluster.nodes").to("spring.redis.cluster.nodes"); + map.from("database").to("spring.redis.database"); + map.from("host").to("spring.redis.host"); + map.from("password").to("spring.redis.password"); + map.from("port").to("spring.redis.port"); + map.from("sentinel.master").to("spring.redis.sentinel.master"); + map.from("sentinel.nodes").to("spring.redis.sentinel.nodes"); + map.from("ssl").to("spring.redis.ssl"); + map.from("url").to("spring.redis.url"); + }); + } + } + + /** + * This is a special case for Boot 3. + */ + public final static class Boot3 extends SpringBootVersionResolver implements BindingsPropertiesProcessor { + + private static final int BOOT_VERSION = 3; + + Boot3(int forcedVersion) { + super(forcedVersion); + } + + public Boot3() { + } + + @Override + public void process(Environment environment, Bindings bindings, Map properties) { + if (!isTypeEnabled(environment, TYPE)) { + return; + } + if (!isBootMajorVersionEnabled(BOOT_VERSION)) { + return; + } + + bindings.filterBindings(TYPE).forEach(binding -> { + MapMapper map = new MapMapper(binding.getSecret(), properties); + + map.from("client-name").to("spring.data.redis.client-name"); + map.from("cluster.max-redirects").to("spring.data.redis.cluster.max-redirects"); + map.from("cluster.nodes").to("spring.data.redis.cluster.nodes"); + map.from("database").to("spring.data.redis.database"); + map.from("host").to("spring.data.redis.host"); + map.from("password").to("spring.data.redis.password"); + map.from("port").to("spring.data.redis.port"); + map.from("sentinel.master").to("spring.data.redis.sentinel.master"); + map.from("sentinel.nodes").to("spring.data.redis.sentinel.nodes"); + map.from("ssl").to("spring.data.redis.ssl"); + map.from("url").to("spring.data.redis.url"); + }); + } } } diff --git a/src/main/java/org/springframework/cloud/bindings/boot/SpringBootVersionResolver.java b/src/main/java/org/springframework/cloud/bindings/boot/SpringBootVersionResolver.java new file mode 100644 index 0000000..ba02cc9 --- /dev/null +++ b/src/main/java/org/springframework/cloud/bindings/boot/SpringBootVersionResolver.java @@ -0,0 +1,23 @@ +package org.springframework.cloud.bindings.boot; + +import org.springframework.boot.SpringBootVersion; + +public class SpringBootVersionResolver { + + private int forcedVersion; + + public SpringBootVersionResolver() { + } + + protected SpringBootVersionResolver(int forcedVersion) { + this.forcedVersion = forcedVersion; + } + + public boolean isBootMajorVersionEnabled(int bootVersion) { + if (forcedVersion != 0) { + return forcedVersion == bootVersion; + } + int major = Integer.parseInt(SpringBootVersion.getVersion().split("\\.")[0]); + return major == bootVersion; + } +} diff --git a/src/main/java/org/springframework/cloud/bindings/boot/VaultBindingsPropertiesProcessor.java b/src/main/java/org/springframework/cloud/bindings/boot/VaultBindingsPropertiesProcessor.java index f9e09a6..4a116c5 100644 --- a/src/main/java/org/springframework/cloud/bindings/boot/VaultBindingsPropertiesProcessor.java +++ b/src/main/java/org/springframework/cloud/bindings/boot/VaultBindingsPropertiesProcessor.java @@ -30,7 +30,7 @@ import static org.springframework.cloud.bindings.boot.Guards.isTypeEnabled; /** * An implementation of {@link BindingsPropertiesProcessor} that detects {@link Binding}s of type: {@value TYPE}. */ -public final class VaultBindingsPropertiesProcessor implements BindingsPropertiesProcessor, ApplicationListener { +public final class VaultBindingsPropertiesProcessor { /** * The {@link Binding} type that this processor is interested in: {@value}. @@ -39,83 +39,190 @@ public final class VaultBindingsPropertiesProcessor implements BindingsPropertie private static final DeferredLog LOG = new DeferredLog(); - @Override - public void process(Environment environment, Bindings bindings, Map properties) { - if (!isTypeEnabled(environment, TYPE)) { - return; + public final static class Boot2 extends SpringBootVersionResolver implements BindingsPropertiesProcessor, ApplicationListener { + + private static final int BOOT_VERSION = 2; + + Boot2(int forcedVersion) { + super(forcedVersion); } - bindings.filterBindings(TYPE).forEach(binding -> { - MapMapper map = new MapMapper(binding.getSecret(), properties); - map.from("uri").to("spring.cloud.vault.uri"); - map.from("namespace").to("spring.cloud.vault.namespace"); // vault enterprise feature + public Boot2() { + } - String authenticationMethod = binding.getSecret().get("authentication-method"); - if (authenticationMethod == null) { - LOG.warn(String.format("Key 'method' is missing from secret of binding '%s'", binding.getName())); + @Override + public void process(Environment environment, Bindings bindings, Map properties) { + if (!isTypeEnabled(environment, TYPE)) { return; } - properties.put("spring.cloud.vault.authentication", authenticationMethod); - switch (authenticationMethod.toUpperCase()) { - case "TOKEN": - case "CUBBYHOLE": - map.from("token").to("spring.cloud.vault.token"); - break; - case "APPROLE": - map.from("role-id").to("spring.cloud.vault.app-role.role-id"); - map.from("secret-id").to("spring.cloud.vault.app-role.secret-id"); - map.from("role").to("spring.cloud.vault.app-role.role"); - map.from("app-role-path").to("spring.cloud.vault.app-role.app-role-path"); - break; - case "AWS_EC2": - map.from("role").to("spring.cloud.vault.aws-ec2.role"); - map.from("aws-ec2-path").to("spring.cloud.vault.aws-ec2.aws-ec2-path"); - map.from("aws-ec2-instance-identity-document").to("spring.cloud.vault.aws-ec2.identity-document"); - map.from("nonce").to("spring.cloud.vault.aws-ec2.nonce"); - break; - case "AWS_IAM": - map.from("role").to("spring.cloud.vault.aws-iam.role"); - map.from("aws-path").to("spring.cloud.vault.aws-iam.aws-path"); - map.from("aws-iam-server-id").to("spring.cloud.vault.aws-iam.server-id"); - map.from("aws-sts-endpoint-uri").to("spring.cloud.vault.aws-iam.endpoint-uri"); - break; - case "AZURE_MSI": - map.from("role").to("spring.cloud.vault.azure-msi.role"); - map.from("azure-path").to("spring.cloud.vault.azure-msi.azure-path"); - break; - case "CERT": - properties.put("spring.cloud.vault.ssl.key-store", binding.getSecretFilePath("keystore.jks").toString()); - map.from("key-store-password").to("spring.cloud.vault.ssl.key-store-password"); - map.from("cert-auth-path").to("spring.cloud.vault.ssl.cert-auth-path"); - break; - case "GCP_GCE": - map.from("role").to("spring.cloud.vault.gcp-gce.role"); - map.from("gcp-path").to("spring.cloud.vault.gcp-gce.gcp-path"); - map.from("gcp-service-account").to("spring.cloud.vault.gcp-gce.service-account"); - break; - case "GCP_IAM": - if (binding.getSecret().containsKey("credentials.json")) { - properties.put("spring.cloud.vault.gcp-iam.credentials.location", binding.getSecretFilePath("credentials.json").toString()); - } - map.from("role").to("spring.cloud.vault.gcp-iam.role"); - map.from("encoded-key").to("spring.cloud.vault.gcp-iam.credentials.encoded-key"); - map.from("gcp-path").to("spring.cloud.vault.gcp-iam.gcp-path"); - map.from("jwt-validity").to("spring.cloud.vault.gcp-iam.jwt-validity"); - map.from("gcp-project-id").to("spring.cloud.vault.gcp-iam.project-id"); - map.from("gcp-service-account").to("spring.cloud.vault.gcp-iam.service-account"); - break; - case "KUBERNETES": - map.from("role").to("spring.cloud.vault.kubernetes.role"); - map.from("kubernetes-path").to("spring.cloud.vault.kubernetes.kubernetes-path"); - break; - default: - LOG.warn(String.format("Binding '%s' contains unrecognized 'method'", binding.getName())); + if (!isBootMajorVersionEnabled(BOOT_VERSION)) { + return; } - }); + + bindings.filterBindings(TYPE).forEach(binding -> { + MapMapper map = new MapMapper(binding.getSecret(), properties); + map.from("uri").to("spring.cloud.vault.uri"); + map.from("namespace").to("spring.cloud.vault.namespace"); // vault enterprise feature + + String authenticationMethod = binding.getSecret().get("authentication-method"); + if (authenticationMethod == null) { + LOG.warn(String.format("Key 'method' is missing from secret of binding '%s'", binding.getName())); + return; + } + properties.put("spring.cloud.vault.authentication", authenticationMethod); + switchCommonProperties(map, authenticationMethod); + switch (authenticationMethod.toUpperCase()) { + case "AWS_IAM": + map.from("role").to("spring.cloud.vault.aws-iam.role"); + map.from("aws-path").to("spring.cloud.vault.aws-iam.aws-path"); + map.from("aws-sts-endpoint-uri").to("spring.cloud.vault.aws-iam.endpoint-uri"); + map.from("aws-iam-server-id").to("spring.cloud.vault.aws-iam.server-id"); + break; + case "AZURE_MSI": + map.from("role").to("spring.cloud.vault.azure-msi.role"); + map.from("azure-path").to("spring.cloud.vault.azure-msi.azure-path"); + break; + case "CERT": + properties.put("spring.cloud.vault.ssl.key-store", binding.getSecretFilePath("keystore.jks").toString()); + map.from("key-store-password").to("spring.cloud.vault.ssl.key-store-password"); + map.from("cert-auth-path").to("spring.cloud.vault.ssl.cert-auth-path"); + break; + case "GCP_IAM": + if (binding.getSecret().containsKey("credentials.json")) { + properties.put("spring.cloud.vault.gcp-iam.credentials.location", binding.getSecretFilePath("credentials.json").toString()); + } + map.from("role").to("spring.cloud.vault.gcp-iam.role"); + map.from("encoded-key").to("spring.cloud.vault.gcp-iam.credentials.encoded-key"); + map.from("gcp-path").to("spring.cloud.vault.gcp-iam.gcp-path"); + map.from("jwt-validity").to("spring.cloud.vault.gcp-iam.jwt-validity"); + map.from("gcp-project-id").to("spring.cloud.vault.gcp-iam.project-id"); + map.from("gcp-service-account").to("spring.cloud.vault.gcp-iam.service-account"); + break; + case "KUBERNETES": + map.from("role").to("spring.cloud.vault.kubernetes.role"); + map.from("kubernetes-path").to("spring.cloud.vault.kubernetes.kubernetes-path"); + break; + default: + LOG.warn(String.format("Binding '%s' contains unrecognized 'method'", binding.getName())); + } + + }); + } + + @Override + public void onApplicationEvent(ApplicationPreparedEvent event) { + LOG.replayTo(getClass()); + } } - @Override - public void onApplicationEvent(ApplicationPreparedEvent event) { - LOG.replayTo(getClass()); + /** + * This is a special case for Boot 3. + */ + public final static class Boot3 extends SpringBootVersionResolver implements BindingsPropertiesProcessor, ApplicationListener { + + private static final int BOOT_VERSION = 3; + + Boot3(int forcedVersion) { + super(forcedVersion); + } + + public Boot3() { + } + + @Override + public void process(Environment environment, Bindings bindings, Map properties) { + if (!isTypeEnabled(environment, TYPE)) { + return; + } + if (!isBootMajorVersionEnabled(BOOT_VERSION)) { + return; + } + + bindings.filterBindings(TYPE).forEach(binding -> { + MapMapper map = new MapMapper(binding.getSecret(), properties); + map.from("uri").to("spring.cloud.vault.uri"); + map.from("namespace").to("spring.cloud.vault.namespace"); // vault enterprise feature + + String authenticationMethod = binding.getSecret().get("authentication-method"); + if (authenticationMethod == null) { + LOG.warn(String.format("Key 'method' is missing from secret of binding '%s'", binding.getName())); + return; + } + properties.put("spring.cloud.vault.authentication", authenticationMethod); + switchCommonProperties(map, authenticationMethod); + switch (authenticationMethod.toUpperCase()) { + case "AWS_IAM": + map.from("role").to("spring.cloud.vault.aws-iam.role"); + map.from("aws-path").to("spring.cloud.vault.aws-iam.aws-path"); + map.from("aws-sts-endpoint-uri").to("spring.cloud.vault.aws-iam.endpoint-uri"); + map.from("aws-iam-server-name").to("spring.cloud.vault.aws-iam.server-name"); + break; + case "AZURE_MSI": + map.from("role").to("spring.cloud.vault.azure-msi.role"); + map.from("azure-path").to("spring.cloud.vault.azure-msi.azure-path"); + map.from("metadata-service").to("spring.cloud.vault.azure-msi.metadata-service"); + map.from("identity-token-service").to("spring.cloud.vault.azure-msi.identity-token-service"); + break; + case "CERT": + properties.put("spring.cloud.vault.ssl.key-store", binding.getSecretFilePath("keystore.jks").toString()); + map.from("key-store-password").to("spring.cloud.vault.ssl.key-store-password"); + map.from("cert-auth-path").to("spring.cloud.vault.ssl.cert-auth-path"); + properties.put("spring.cloud.vault.ssl.trust-store", binding.getSecretFilePath("truststore.jks").toString()); + map.from("trust-store").to("spring.cloud.vault.ssl.trust-store"); + map.from("trust-store-password").to("spring.cloud.vault.ssl.trust-store-password"); + break; + case "GCP_IAM": + if (binding.getSecret().containsKey("credentials.json")) { + properties.put("spring.cloud.vault.gcp-iam.credentials.location", binding.getSecretFilePath("credentials.json").toString()); + } + map.from("role").to("spring.cloud.vault.gcp-iam.role"); + map.from("encoded-key").to("spring.cloud.vault.gcp-iam.credentials.encoded-key"); + map.from("gcp-path").to("spring.cloud.vault.gcp-iam.gcp-path"); + map.from("jwt-validity").to("spring.cloud.vault.gcp-iam.jwt-validity"); + map.from("gcp-project-id").to("spring.cloud.vault.gcp-iam.project-id"); + map.from("gcp-service-account").to("spring.cloud.vault.gcp-iam.service-account-id"); + break; + case "KUBERNETES": + map.from("role").to("spring.cloud.vault.kubernetes.role"); + map.from("kubernetes-path").to("spring.cloud.vault.kubernetes.kubernetes-path"); + map.from("kubernetes-service-account-token-file").to("spring.cloud.vault.kubernetes.kubernetes-service-account-token-file"); + break; + default: + LOG.warn(String.format("Binding '%s' contains unrecognized 'method'", binding.getName())); + } + }); + } + + @Override + public void onApplicationEvent(ApplicationPreparedEvent event) { + LOG.replayTo(getClass()); + } } + + private static void switchCommonProperties(MapMapper map, String authenticationMethod) { + switch (authenticationMethod.toUpperCase()) { + case "TOKEN": + case "CUBBYHOLE": + map.from("token").to("spring.cloud.vault.token"); + break; + case "APPROLE": + map.from("role-id").to("spring.cloud.vault.app-role.role-id"); + map.from("secret-id").to("spring.cloud.vault.app-role.secret-id"); + map.from("role").to("spring.cloud.vault.app-role.role"); + map.from("app-role-path").to("spring.cloud.vault.app-role.app-role-path"); + break; + case "AWS_EC2": + map.from("role").to("spring.cloud.vault.aws-ec2.role"); + map.from("aws-ec2-path").to("spring.cloud.vault.aws-ec2.aws-ec2-path"); + map.from("aws-ec2-instance-identity-document").to("spring.cloud.vault.aws-ec2.identity-document"); + map.from("nonce").to("spring.cloud.vault.aws-ec2.nonce"); + break; + case "GCP_GCE": + map.from("role").to("spring.cloud.vault.gcp-gce.role"); + map.from("gcp-path").to("spring.cloud.vault.gcp-gce.gcp-path"); + map.from("gcp-service-account").to("spring.cloud.vault.gcp-gce.service-account"); + break; + } + } + } diff --git a/src/main/resources/META-INF/spring.factories b/src/main/resources/META-INF/spring.factories index cde7fc3..d3780d2 100644 --- a/src/main/resources/META-INF/spring.factories +++ b/src/main/resources/META-INF/spring.factories @@ -2,30 +2,38 @@ org.springframework.context.ApplicationListener=\ org.springframework.cloud.bindings.boot.BindingFlattenedEnvironmentPostProcessor, \ org.springframework.cloud.bindings.boot.BindingSpecificEnvironmentPostProcessor, \ org.springframework.cloud.bindings.boot.SpringSecurityOAuth2BindingsPropertiesProcessor, \ - org.springframework.cloud.bindings.boot.VaultBindingsPropertiesProcessor + org.springframework.cloud.bindings.boot.VaultBindingsPropertiesProcessor.Boot2, \ + org.springframework.cloud.bindings.boot.VaultBindingsPropertiesProcessor.Boot3 org.springframework.boot.env.EnvironmentPostProcessor=\ org.springframework.cloud.bindings.boot.BindingFlattenedEnvironmentPostProcessor, \ org.springframework.cloud.bindings.boot.BindingSpecificEnvironmentPostProcessor # Included implementations org.springframework.cloud.bindings.boot.BindingsPropertiesProcessor=\ - org.springframework.cloud.bindings.boot.ArtemisBindingsPropertiesProcessor, \ - org.springframework.cloud.bindings.boot.CassandraBindingsPropertiesProcessor, \ + org.springframework.cloud.bindings.boot.ArtemisBindingsPropertiesProcessor.Boot2, \ + org.springframework.cloud.bindings.boot.ArtemisBindingsPropertiesProcessor.Boot3, \ + org.springframework.cloud.bindings.boot.CassandraBindingsPropertiesProcessor.Boot2, \ + org.springframework.cloud.bindings.boot.CassandraBindingsPropertiesProcessor.Boot3, \ org.springframework.cloud.bindings.boot.ConfigServerBindingsPropertiesProcessor, \ - org.springframework.cloud.bindings.boot.CouchbaseBindingsPropertiesProcessor, \ + org.springframework.cloud.bindings.boot.CouchbaseBindingsPropertiesProcessor.Boot2, \ + org.springframework.cloud.bindings.boot.CouchbaseBindingsPropertiesProcessor.Boot3, \ org.springframework.cloud.bindings.boot.Db2BindingsPropertiesProcessor, \ - org.springframework.cloud.bindings.boot.ElasticsearchBindingsPropertiesProcessor, \ + org.springframework.cloud.bindings.boot.ElasticsearchBindingsPropertiesProcessor.Boot2, \ + org.springframework.cloud.bindings.boot.ElasticsearchBindingsPropertiesProcessor.Boot3, \ org.springframework.cloud.bindings.boot.EurekaBindingsPropertiesProcessor, \ org.springframework.cloud.bindings.boot.KafkaBindingsPropertiesProcessor, \ org.springframework.cloud.bindings.boot.LDAPBindingsPropertiesProcessor, \ org.springframework.cloud.bindings.boot.MongoDbBindingsPropertiesProcessor, \ org.springframework.cloud.bindings.boot.MySqlBindingsPropertiesProcessor, \ - org.springframework.cloud.bindings.boot.Neo4JBindingsPropertiesProcessor, \ + org.springframework.cloud.bindings.boot.Neo4JBindingsPropertiesProcessor.Boot2, \ + org.springframework.cloud.bindings.boot.Neo4JBindingsPropertiesProcessor.Boot3, \ org.springframework.cloud.bindings.boot.OracleBindingsPropertiesProcessor, \ org.springframework.cloud.bindings.boot.PostgreSqlBindingsPropertiesProcessor, \ org.springframework.cloud.bindings.boot.RabbitMqBindingsPropertiesProcessor, \ - org.springframework.cloud.bindings.boot.RedisBindingsPropertiesProcessor, \ + org.springframework.cloud.bindings.boot.RedisBindingsPropertiesProcessor.Boot2, \ + org.springframework.cloud.bindings.boot.RedisBindingsPropertiesProcessor.Boot3, \ org.springframework.cloud.bindings.boot.SapHanaBindingsPropertiesProcessor, \ org.springframework.cloud.bindings.boot.SpringSecurityOAuth2BindingsPropertiesProcessor, \ org.springframework.cloud.bindings.boot.SqlServerBindingsPropertiesProcessor, \ - org.springframework.cloud.bindings.boot.VaultBindingsPropertiesProcessor, \ + org.springframework.cloud.bindings.boot.VaultBindingsPropertiesProcessor.Boot2, \ + org.springframework.cloud.bindings.boot.VaultBindingsPropertiesProcessor.Boot3, \ org.springframework.cloud.bindings.boot.WavefrontBindingsPropertiesProcessor diff --git a/src/test/java/org/springframework/cloud/bindings/boot/ArtemisBindingsPropertiesProcessorTest.java b/src/test/java/org/springframework/cloud/bindings/boot/ArtemisBindingsPropertiesProcessorTest.java index 0dbb97e..b6a44cf 100644 --- a/src/test/java/org/springframework/cloud/bindings/boot/ArtemisBindingsPropertiesProcessorTest.java +++ b/src/test/java/org/springframework/cloud/bindings/boot/ArtemisBindingsPropertiesProcessorTest.java @@ -32,7 +32,7 @@ import static org.springframework.cloud.bindings.boot.ArtemisBindingsPropertiesP @DisplayName("ActiveMQ Artemis BindingsPropertiesProcessor") final class ArtemisBindingsPropertiesProcessorTest { - private final Bindings bindings = new Bindings( + private final Bindings bindingsSpringBoot2 = new Bindings( new Binding("test-name", Paths.get("test-path"), new FluentMap() .withEntry(Binding.TYPE, TYPE) @@ -44,14 +44,25 @@ final class ArtemisBindingsPropertiesProcessorTest { ) ); + private final Bindings bindingsSpringBoot3 = new Bindings( + new Binding("test-name", Paths.get("test-path"), + new FluentMap() + .withEntry(Binding.TYPE, TYPE) + .withEntry("mode", "EMBEDDED") + .withEntry("broker-url", "tcp://test-host:test-port") + .withEntry("user", "test-user") + .withEntry("password", "test-password") + ) + ); + private final MockEnvironment environment = new MockEnvironment(); private final HashMap properties = new HashMap<>(); @Test - @DisplayName("contributes properties") - void test() { - new ArtemisBindingsPropertiesProcessor().process(environment, bindings, properties); + @DisplayName("contributes properties - Spring Boot 2 flavor") + void testSb2() { + new ArtemisBindingsPropertiesProcessor.Boot2(2).process(environment, bindingsSpringBoot2, properties); assertThat(properties) .containsEntry("spring.artemis.mode", "EMBEDDED") .containsEntry("spring.artemis.host", "test-host") @@ -60,13 +71,26 @@ final class ArtemisBindingsPropertiesProcessorTest { .containsEntry("spring.artemis.user", "test-user"); } + @Test + @DisplayName("contributes properties - Spring Boot 3 flavor") + void testSb3() { + new ArtemisBindingsPropertiesProcessor.Boot3(3).process(environment, bindingsSpringBoot3, properties); + assertThat(properties) + .containsEntry("spring.artemis.mode", "EMBEDDED") + .containsEntry("spring.artemis.broker-url", "tcp://test-host:test-port") + .containsEntry("spring.artemis.password", "test-password") + .containsEntry("spring.artemis.user", "test-user"); + } + @Test @DisplayName("can be disabled") void disabled() { environment.setProperty("org.springframework.cloud.bindings.boot.artemis.enable", "false"); - new ArtemisBindingsPropertiesProcessor().process(environment, bindings, properties); + new ArtemisBindingsPropertiesProcessor.Boot2(2).process(environment, bindingsSpringBoot2, properties); + assertThat(properties).isEmpty(); + new ArtemisBindingsPropertiesProcessor.Boot3(3).process(environment, bindingsSpringBoot2, properties); assertThat(properties).isEmpty(); } diff --git a/src/test/java/org/springframework/cloud/bindings/boot/BindingFlattenedEnvironmentPostProcessorTest.java b/src/test/java/org/springframework/cloud/bindings/boot/BindingFlattenedEnvironmentPostProcessorTest.java index fe24d04..33bed83 100644 --- a/src/test/java/org/springframework/cloud/bindings/boot/BindingFlattenedEnvironmentPostProcessorTest.java +++ b/src/test/java/org/springframework/cloud/bindings/boot/BindingFlattenedEnvironmentPostProcessorTest.java @@ -16,17 +16,17 @@ package org.springframework.cloud.bindings.boot; +import java.nio.file.Paths; + import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.boot.SpringApplication; -import org.springframework.boot.context.config.ConfigFileApplicationListener; +import org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor; import org.springframework.cloud.bindings.Binding; import org.springframework.cloud.bindings.Bindings; import org.springframework.cloud.bindings.FluentMap; import org.springframework.mock.env.MockEnvironment; -import java.nio.file.Paths; - import static org.assertj.core.api.Assertions.assertThat; @DisplayName("Binding-flattened EnvironmentPostProcessor") @@ -82,7 +82,7 @@ final class BindingFlattenedEnvironmentPostProcessorTest { @DisplayName("has order before ConfigFileApplicationListener") void order() { assertThat(new BindingFlattenedEnvironmentPostProcessor(new Bindings()).getOrder()) - .isLessThan(ConfigFileApplicationListener.DEFAULT_ORDER); + .isLessThan(ConfigDataEnvironmentPostProcessor.ORDER); } } diff --git a/src/test/java/org/springframework/cloud/bindings/boot/BindingSpecificEnvironmentPostProcessorTest.java b/src/test/java/org/springframework/cloud/bindings/boot/BindingSpecificEnvironmentPostProcessorTest.java index 03a6151..416892f 100644 --- a/src/test/java/org/springframework/cloud/bindings/boot/BindingSpecificEnvironmentPostProcessorTest.java +++ b/src/test/java/org/springframework/cloud/bindings/boot/BindingSpecificEnvironmentPostProcessorTest.java @@ -19,7 +19,7 @@ package org.springframework.cloud.bindings.boot; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.boot.SpringApplication; -import org.springframework.boot.context.config.ConfigFileApplicationListener; +import org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor; import org.springframework.cloud.bindings.Binding; import org.springframework.cloud.bindings.Bindings; import org.springframework.cloud.bindings.FluentMap; @@ -98,13 +98,13 @@ final class BindingSpecificEnvironmentPostProcessorTest { @DisplayName("has order before ConfigFileApplicationListener") void order() { assertThat(new BindingSpecificEnvironmentPostProcessor(new Bindings()).getOrder()) - .isLessThan(ConfigFileApplicationListener.DEFAULT_ORDER); + .isLessThan(ConfigDataEnvironmentPostProcessor.ORDER); } @Test @DisplayName("included implementations are registered") void includedImplementations() { - assertThat(new BindingSpecificEnvironmentPostProcessor().processors).hasSize(21); + assertThat(new BindingSpecificEnvironmentPostProcessor().processors).hasSize(28); } } diff --git a/src/test/java/org/springframework/cloud/bindings/boot/CassandraBindingsPropertiesProcessorTest.java b/src/test/java/org/springframework/cloud/bindings/boot/CassandraBindingsPropertiesProcessorTest.java index e6624df..d17959b 100644 --- a/src/test/java/org/springframework/cloud/bindings/boot/CassandraBindingsPropertiesProcessorTest.java +++ b/src/test/java/org/springframework/cloud/bindings/boot/CassandraBindingsPropertiesProcessorTest.java @@ -44,6 +44,10 @@ final class CassandraBindingsPropertiesProcessorTest { .withEntry("port", "test-port") .withEntry("ssl", "test-ssl") .withEntry("username", "test-username") + .withEntry("request.throttler.drain-interval", "test-drain-interval") + .withEntry("request.throttler.max-concurrent-requests", "test-max-concurrent-requests") + .withEntry("request.throttler.max-queue-size", "test-max-queue-size") + .withEntry("request.throttler.max-requests-per-second", "test-max-requests-per-second") ) ); @@ -52,9 +56,9 @@ final class CassandraBindingsPropertiesProcessorTest { private final HashMap properties = new HashMap<>(); @Test - @DisplayName("contributes properties") - void test() { - new CassandraBindingsPropertiesProcessor().process(environment, bindings, properties); + @DisplayName("contributes properties - Spring Boot 2 flavor") + void testSb2() { + new CassandraBindingsPropertiesProcessor.Boot2(2).process(environment, bindings, properties); assertThat(properties) .containsEntry("spring.data.cassandra.cluster-name", "test-cluster-name") .containsEntry("spring.data.cassandra.compression", "test-compression") @@ -63,7 +67,30 @@ final class CassandraBindingsPropertiesProcessorTest { .containsEntry("spring.data.cassandra.password", "test-password") .containsEntry("spring.data.cassandra.port", "test-port") .containsEntry("spring.data.cassandra.ssl", "test-ssl") - .containsEntry("spring.data.cassandra.username", "test-username"); + .containsEntry("spring.data.cassandra.username", "test-username") + .containsEntry("spring.data.cassandra.request.throttler.drain-interval", "test-drain-interval") + .containsEntry("spring.data.cassandra.request.throttler.max-concurrent-requests", "test-max-concurrent-requests") + .containsEntry("spring.data.cassandra.request.throttler.max-queue-size", "test-max-queue-size") + .containsEntry("spring.data.cassandra.request.throttler.max-requests-per-second", "test-max-requests-per-second"); + } + + @Test + @DisplayName("contributes properties - Spring Boot 3 flavor") + void testSb3() { + new CassandraBindingsPropertiesProcessor.Boot3(3).process(environment, bindings, properties); + assertThat(properties) + .containsEntry("spring.cassandra.cluster-name", "test-cluster-name") + .containsEntry("spring.cassandra.compression", "test-compression") + .containsEntry("spring.cassandra.contact-points", "test-contact-points") + .containsEntry("spring.cassandra.keyspace-name", "test-keyspace-name") + .containsEntry("spring.cassandra.password", "test-password") + .containsEntry("spring.cassandra.port", "test-port") + .containsEntry("spring.cassandra.ssl", "test-ssl") + .containsEntry("spring.cassandra.username", "test-username") + .containsEntry("spring.cassandra.request.throttler.drain-interval", "test-drain-interval") + .containsEntry("spring.cassandra.request.throttler.max-concurrent-requests", "test-max-concurrent-requests") + .containsEntry("spring.cassandra.request.throttler.max-queue-size", "test-max-queue-size") + .containsEntry("spring.cassandra.request.throttler.max-requests-per-second", "test-max-requests-per-second"); } @Test @@ -71,8 +98,10 @@ final class CassandraBindingsPropertiesProcessorTest { void disabled() { environment.setProperty("org.springframework.cloud.bindings.boot.cassandra.enable", "false"); - new CassandraBindingsPropertiesProcessor().process(environment, bindings, properties); + new CassandraBindingsPropertiesProcessor.Boot2(2).process(environment, bindings, properties); + assertThat(properties).isEmpty(); + new CassandraBindingsPropertiesProcessor.Boot3(3).process(environment, bindings, properties); assertThat(properties).isEmpty(); } diff --git a/src/test/java/org/springframework/cloud/bindings/boot/CouchbaseBindingsPropertiesProcessorTest.java b/src/test/java/org/springframework/cloud/bindings/boot/CouchbaseBindingsPropertiesProcessorTest.java index 4e55d9b..f79de94 100644 --- a/src/test/java/org/springframework/cloud/bindings/boot/CouchbaseBindingsPropertiesProcessorTest.java +++ b/src/test/java/org/springframework/cloud/bindings/boot/CouchbaseBindingsPropertiesProcessorTest.java @@ -32,7 +32,7 @@ import static org.springframework.cloud.bindings.boot.CouchbaseBindingsPropertie @DisplayName("Couchbase BindingsPropertiesProcessor") final class CouchbaseBindingsPropertiesProcessorTest { - private final Bindings bindings = new Bindings( + private final Bindings bindingsSpringBoot2 = new Bindings( new Binding("test-name", Paths.get("test-path"), new FluentMap() .withEntry(Binding.TYPE, TYPE) @@ -46,14 +46,25 @@ final class CouchbaseBindingsPropertiesProcessorTest { ) ); + private final Bindings bindingsSpringBoot3 = new Bindings( + new Binding("test-name", Paths.get("test-path"), + new FluentMap() + .withEntry(Binding.TYPE, TYPE) + .withEntry("connection-string", "test-connection-string") + .withEntry("bucket-name", "test-bucket-name") + .withEntry("username", "test-username") + .withEntry("password", "test-password") + ) + ); + private final MockEnvironment environment = new MockEnvironment(); private final HashMap properties = new HashMap<>(); @Test - @DisplayName("contributes properties") - void test() { - new CouchbaseBindingsPropertiesProcessor().process(environment, bindings, properties); + @DisplayName("contributes properties - Spring Boot 2 flavor") + void testSb2() { + new CouchbaseBindingsPropertiesProcessor.Boot2(2).process(environment, bindingsSpringBoot2, properties); assertThat(properties) .containsEntry("spring.couchbase.bootstrap-hosts", "test-bootstrap-hosts") .containsEntry("spring.couchbase.bucket.name", "test-bucket-name") @@ -64,13 +75,26 @@ final class CouchbaseBindingsPropertiesProcessorTest { .containsEntry("spring.couchbase.username", "test-username"); } + @Test + @DisplayName("contributes properties - Spring Boot 3 flavor") + void testSb3() { + new CouchbaseBindingsPropertiesProcessor.Boot3(3).process(environment, bindingsSpringBoot3, properties); + assertThat(properties) + .containsEntry("spring.couchbase.connection-string", "test-connection-string") + .containsEntry("spring.data.couchbase.bucket-name", "test-bucket-name") + .containsEntry("spring.couchbase.username", "test-username") + .containsEntry("spring.couchbase.password", "test-password"); + } + @Test @DisplayName("can be disabled") void disabled() { environment.setProperty("org.springframework.cloud.bindings.boot.couchbase.enable", "false"); - new CouchbaseBindingsPropertiesProcessor().process(environment, bindings, properties); + new CouchbaseBindingsPropertiesProcessor.Boot2(2).process(environment, bindingsSpringBoot2, properties); + assertThat(properties).isEmpty(); + new CouchbaseBindingsPropertiesProcessor.Boot3(3).process(environment, bindingsSpringBoot3, properties); assertThat(properties).isEmpty(); } diff --git a/src/test/java/org/springframework/cloud/bindings/boot/ElasticsearchBindingsPropertiesProcessorTest.java b/src/test/java/org/springframework/cloud/bindings/boot/ElasticsearchBindingsPropertiesProcessorTest.java index f7ae1cc..e7ef72f 100644 --- a/src/test/java/org/springframework/cloud/bindings/boot/ElasticsearchBindingsPropertiesProcessorTest.java +++ b/src/test/java/org/springframework/cloud/bindings/boot/ElasticsearchBindingsPropertiesProcessorTest.java @@ -32,7 +32,7 @@ import static org.springframework.cloud.bindings.boot.ElasticsearchBindingsPrope @DisplayName("Elasticsearch BindingsPropertiesProcessor") final class ElasticsearchBindingsPropertiesProcessorTest { - private final Bindings bindings = new Bindings( + private final Bindings bindingsSpringBoot2 = new Bindings( new Binding("test-name", Paths.get("test-path"), new FluentMap() .withEntry(Binding.TYPE, TYPE) @@ -46,14 +46,25 @@ final class ElasticsearchBindingsPropertiesProcessorTest { ) ); + private final Bindings bindingsSpringBoot3 = new Bindings( + new Binding("test-name", Paths.get("test-path"), + new FluentMap() + .withEntry(Binding.TYPE, TYPE) + .withEntry("password", "test-password") + .withEntry("uris", "test-uris") + .withEntry("username", "test-username") + ) + ); + + private final MockEnvironment environment = new MockEnvironment(); private final HashMap properties = new HashMap<>(); @Test - @DisplayName("contributes properties") - void test() { - new ElasticsearchBindingsPropertiesProcessor().process(environment, bindings, properties); + @DisplayName("contributes properties - Spring Boot 2 flavor") + void testSb2() { + new ElasticsearchBindingsPropertiesProcessor.Boot2(2).process(environment, bindingsSpringBoot2, properties); assertThat(properties) .containsEntry("spring.data.elasticsearch.client.reactive.endpoints", "test-endpoints") .containsEntry("spring.data.elasticsearch.client.reactive.password", "test-password") @@ -68,13 +79,25 @@ final class ElasticsearchBindingsPropertiesProcessorTest { .containsEntry("spring.elasticsearch.rest.username", "test-username"); } + @Test + @DisplayName("contributes properties - Spring Boot 2 flavor") + void testSb3() { + new ElasticsearchBindingsPropertiesProcessor.Boot3(3).process(environment, bindingsSpringBoot3, properties); + assertThat(properties) + .containsEntry("spring.elasticsearch.password", "test-password") + .containsEntry("spring.elasticsearch.uris", "test-uris") + .containsEntry("spring.elasticsearch.username", "test-username"); + } + @Test @DisplayName("can be disabled") void disabled() { environment.setProperty("org.springframework.cloud.bindings.boot.elasticsearch.enable", "false"); - new ElasticsearchBindingsPropertiesProcessor().process(environment, bindings, properties); + new ElasticsearchBindingsPropertiesProcessor.Boot2(2).process(environment, bindingsSpringBoot2, properties); + assertThat(properties).isEmpty(); + new ElasticsearchBindingsPropertiesProcessor.Boot3(3).process(environment, bindingsSpringBoot3, properties); assertThat(properties).isEmpty(); } diff --git a/src/test/java/org/springframework/cloud/bindings/boot/Neo4JBindingsPropertiesProcessorTest.java b/src/test/java/org/springframework/cloud/bindings/boot/Neo4JBindingsPropertiesProcessorTest.java index 85d351b..3e42673 100644 --- a/src/test/java/org/springframework/cloud/bindings/boot/Neo4JBindingsPropertiesProcessorTest.java +++ b/src/test/java/org/springframework/cloud/bindings/boot/Neo4JBindingsPropertiesProcessorTest.java @@ -47,23 +47,36 @@ final class Neo4JBindingsPropertiesProcessorTest { private final HashMap properties = new HashMap<>(); @Test - @DisplayName("contributes properties") - void test() { - new Neo4JBindingsPropertiesProcessor().process(environment, bindings, properties); + @DisplayName("contributes properties - Spring Boot 2 flavor") + void testSb2() { + new Neo4JBindingsPropertiesProcessor.Boot2(2).process(environment, bindings, properties); assertThat(properties) .containsEntry("spring.data.neo4j.password", "test-password") .containsEntry("spring.data.neo4j.uri", "test-uri") .containsEntry("spring.data.neo4j.username", "test-username"); } + @Test + @DisplayName("contributes properties - Spring Boot 3 flavor") + void testSb3() { + new Neo4JBindingsPropertiesProcessor.Boot3(3).process(environment, bindings, properties); + assertThat(properties) + .containsEntry("spring.neo4j.authentication.password", "test-password") + .containsEntry("spring.neo4j.uri", "test-uri") + .containsEntry("spring.neo4j.authentication.username", "test-username"); + } + @Test @DisplayName("can be disabled") void disabled() { environment.setProperty("org.springframework.cloud.bindings.boot.neo4j.enable", "false"); - new Neo4JBindingsPropertiesProcessor().process(environment, bindings, properties); - + new Neo4JBindingsPropertiesProcessor.Boot2(2).process(environment, bindings, properties); assertThat(properties).isEmpty(); + + new Neo4JBindingsPropertiesProcessor.Boot3(3).process(environment, bindings, properties); + assertThat(properties).isEmpty(); + } } diff --git a/src/test/java/org/springframework/cloud/bindings/boot/RedisBindingsPropertiesProcessorTest.java b/src/test/java/org/springframework/cloud/bindings/boot/RedisBindingsPropertiesProcessorTest.java index 83de7fa..769ba8b 100644 --- a/src/test/java/org/springframework/cloud/bindings/boot/RedisBindingsPropertiesProcessorTest.java +++ b/src/test/java/org/springframework/cloud/bindings/boot/RedisBindingsPropertiesProcessorTest.java @@ -55,9 +55,9 @@ final class RedisBindingsPropertiesProcessorTest { private final HashMap properties = new HashMap<>(); @Test - @DisplayName("contributes properties") - void test() { - new RedisBindingsPropertiesProcessor().process(environment, bindings, properties); + @DisplayName("contributes properties - Spring Boot 2 flavor") + void testSb2() { + new RedisBindingsPropertiesProcessor.Boot2(2).process(environment, bindings, properties); assertThat(properties) .containsEntry("spring.redis.client-name", "test-client-name") .containsEntry("spring.redis.cluster.max-redirects", "test-cluster-max-redirects") @@ -72,14 +72,36 @@ final class RedisBindingsPropertiesProcessorTest { .containsEntry("spring.redis.url", "test-url"); } + @Test + @DisplayName("contributes properties - Spring Boot 3 flavor") + void testSb3() { + new RedisBindingsPropertiesProcessor.Boot3(3).process(environment, bindings, properties); + + assertThat(properties) + .containsEntry("spring.data.redis.client-name", "test-client-name") + .containsEntry("spring.data.redis.cluster.max-redirects", "test-cluster-max-redirects") + .containsEntry("spring.data.redis.cluster.nodes", "test-cluster-nodes") + .containsEntry("spring.data.redis.database", "test-database") + .containsEntry("spring.data.redis.host", "test-host") + .containsEntry("spring.data.redis.password", "test-password") + .containsEntry("spring.data.redis.port", "test-port") + .containsEntry("spring.data.redis.sentinel.master", "test-sentinel-master") + .containsEntry("spring.data.redis.sentinel.nodes", "test-sentinel-nodes") + .containsEntry("spring.data.redis.ssl", "test-ssl") + .containsEntry("spring.data.redis.url", "test-url"); + } + @Test @DisplayName("can be disabled") void disabled() { environment.setProperty("org.springframework.cloud.bindings.boot.redis.enable", "false"); - new RedisBindingsPropertiesProcessor().process(environment, bindings, properties); - + new RedisBindingsPropertiesProcessor.Boot2(2).process(environment, bindings, properties); assertThat(properties).isEmpty(); + + new RedisBindingsPropertiesProcessor.Boot2(3).process(environment, bindings, properties); + assertThat(properties).isEmpty(); + } } diff --git a/src/test/java/org/springframework/cloud/bindings/boot/SpringBootVersionResolverTest.java b/src/test/java/org/springframework/cloud/bindings/boot/SpringBootVersionResolverTest.java new file mode 100644 index 0000000..e76c275 --- /dev/null +++ b/src/test/java/org/springframework/cloud/bindings/boot/SpringBootVersionResolverTest.java @@ -0,0 +1,33 @@ +package org.springframework.cloud.bindings.boot; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class SpringBootVersionResolverTest { + + @Test + @DisplayName("Should return Spring Boot 2 as Major Version since it's the provided runtime") + void isBootMajorVersionEnabled() { + SpringBootVersionResolver springBootVersionResolver = new SpringBootVersionResolver(); + assertTrue(springBootVersionResolver.isBootMajorVersionEnabled(2)); + assertFalse(springBootVersionResolver.isBootMajorVersionEnabled(3)); + } + + @Test + @DisplayName("Should return the forced version 2") + void isBootMajorVersionEnabled_forced_version2() { + SpringBootVersionResolver springBootVersionResolver = new SpringBootVersionResolver(2); + assertTrue(springBootVersionResolver.isBootMajorVersionEnabled(2)); + assertFalse(springBootVersionResolver.isBootMajorVersionEnabled(3)); + } + + @Test + @DisplayName("Should return the forced version 3") + void isBootMajorVersionEnabled_forced_version3() { + SpringBootVersionResolver springBootVersionResolver = new SpringBootVersionResolver(3); + assertFalse(springBootVersionResolver.isBootMajorVersionEnabled(2)); + assertTrue(springBootVersionResolver.isBootMajorVersionEnabled(3)); + } +} \ No newline at end of file diff --git a/src/test/java/org/springframework/cloud/bindings/boot/VaultBindingsPropertiesProcessorTest.java b/src/test/java/org/springframework/cloud/bindings/boot/VaultBindingsPropertiesProcessorTest.java index 59a435d..fd243f9 100644 --- a/src/test/java/org/springframework/cloud/bindings/boot/VaultBindingsPropertiesProcessorTest.java +++ b/src/test/java/org/springframework/cloud/bindings/boot/VaultBindingsPropertiesProcessorTest.java @@ -47,7 +47,7 @@ final class VaultBindingsPropertiesProcessorTest { ) ); - new VaultBindingsPropertiesProcessor().process(environment, bindings, properties); + new VaultBindingsPropertiesProcessor.Boot2(2).process(environment, bindings, properties); assertThat(properties) .containsEntry("spring.cloud.vault.uri", "test-uri") .containsEntry("spring.cloud.vault.namespace", "test-namespace") @@ -69,7 +69,7 @@ final class VaultBindingsPropertiesProcessorTest { ) ); - new VaultBindingsPropertiesProcessor().process(environment, bindings, properties); + new VaultBindingsPropertiesProcessor.Boot2(2).process(environment, bindings, properties); assertThat(properties) .containsEntry("spring.cloud.vault.uri", "test-uri") .containsEntry("spring.cloud.vault.namespace", "test-namespace") @@ -91,7 +91,7 @@ final class VaultBindingsPropertiesProcessorTest { ) ); - new VaultBindingsPropertiesProcessor().process(environment, bindings, properties); + new VaultBindingsPropertiesProcessor.Boot2(2).process(environment, bindings, properties); assertThat(properties) .containsEntry("spring.cloud.vault.uri", "test-uri") .containsEntry("spring.cloud.vault.namespace", "test-namespace") @@ -108,11 +108,13 @@ final class VaultBindingsPropertiesProcessorTest { .withEntry("authentication-method", "cert") .withEntry("cert-auth-path", "test-cert-auth-path") .withEntry("key-store-password", "test-key-store-password") + .withEntry("truststore.jks", "trust store contents!") + .withEntry("trust-store-password", "test-trust-store-password") .withEntry("keystore.jks", "key store contents!") ) ); - new VaultBindingsPropertiesProcessor().process(environment, bindings, properties); + new VaultBindingsPropertiesProcessor.Boot2(2).process(environment, bindings, properties); assertThat(properties) .containsEntry("spring.cloud.vault.uri", "test-uri") .containsEntry("spring.cloud.vault.namespace", "test-namespace") @@ -120,6 +122,17 @@ final class VaultBindingsPropertiesProcessorTest { .containsEntry("spring.cloud.vault.ssl.key-store", "test-path/keystore.jks") .containsEntry("spring.cloud.vault.ssl.key-store-password", "test-key-store-password") .containsEntry("spring.cloud.vault.ssl.cert-auth-path", "test-cert-auth-path"); + + new VaultBindingsPropertiesProcessor.Boot3(3).process(environment, bindings, properties); + assertThat(properties) + .containsEntry("spring.cloud.vault.uri", "test-uri") + .containsEntry("spring.cloud.vault.namespace", "test-namespace") + .containsEntry("spring.cloud.vault.authentication", "cert") + .containsEntry("spring.cloud.vault.ssl.cert-auth-path", "test-cert-auth-path") + .containsEntry("spring.cloud.vault.ssl.key-store", "test-path/keystore.jks") + .containsEntry("spring.cloud.vault.ssl.key-store-password", "test-key-store-password") + .containsEntry("spring.cloud.vault.ssl.trust-store", "test-path/truststore.jks") + .containsEntry("spring.cloud.vault.ssl.trust-store-password", "test-trust-store-password"); } @Test @@ -136,7 +149,7 @@ final class VaultBindingsPropertiesProcessorTest { ) ); - new VaultBindingsPropertiesProcessor().process(environment, bindings, properties); + new VaultBindingsPropertiesProcessor.Boot2(2).process(environment, bindings, properties); assertThat(properties) .containsEntry("spring.cloud.vault.uri", "test-uri") .containsEntry("spring.cloud.vault.namespace", "test-namespace") @@ -155,13 +168,14 @@ final class VaultBindingsPropertiesProcessorTest { baseSecret() .withEntry("authentication-method", "aws_iam") .withEntry("aws-iam-server-id", "test-server-id") + .withEntry("aws-iam-server-name", "test-server-name") .withEntry("aws-path", "test-aws-path") .withEntry("aws-sts-endpoint-uri", "test-endpoint-uri") .withEntry("role", "test-role") ) ); - new VaultBindingsPropertiesProcessor().process(environment, bindings, properties); + new VaultBindingsPropertiesProcessor.Boot2(2).process(environment, bindings, properties); assertThat(properties) .containsEntry("spring.cloud.vault.uri", "test-uri") .containsEntry("spring.cloud.vault.namespace", "test-namespace") @@ -170,6 +184,16 @@ final class VaultBindingsPropertiesProcessorTest { .containsEntry("spring.cloud.vault.aws-iam.aws-path", "test-aws-path") .containsEntry("spring.cloud.vault.aws-iam.server-id", "test-server-id") .containsEntry("spring.cloud.vault.aws-iam.endpoint-uri", "test-endpoint-uri"); + + new VaultBindingsPropertiesProcessor.Boot3(3).process(environment, bindings, properties); + assertThat(properties) + .containsEntry("spring.cloud.vault.uri", "test-uri") + .containsEntry("spring.cloud.vault.namespace", "test-namespace") + .containsEntry("spring.cloud.vault.authentication", "aws_iam") + .containsEntry("spring.cloud.vault.aws-iam.role", "test-role") + .containsEntry("spring.cloud.vault.aws-iam.aws-path", "test-aws-path") + .containsEntry("spring.cloud.vault.aws-iam.server-name", "test-server-name") + .containsEntry("spring.cloud.vault.aws-iam.endpoint-uri", "test-endpoint-uri"); } @Test @@ -181,16 +205,28 @@ final class VaultBindingsPropertiesProcessorTest { .withEntry("authentication-method", "azure_msi") .withEntry("azure-path", "test-azure-path") .withEntry("role", "test-role") + .withEntry("metadata-service", "test-metadata-service") + .withEntry("identity-token-service", "test-identity-token-service") ) ); - new VaultBindingsPropertiesProcessor().process(environment, bindings, properties); + new VaultBindingsPropertiesProcessor.Boot2(2).process(environment, bindings, properties); assertThat(properties) .containsEntry("spring.cloud.vault.uri", "test-uri") .containsEntry("spring.cloud.vault.namespace", "test-namespace") .containsEntry("spring.cloud.vault.authentication", "azure_msi") .containsEntry("spring.cloud.vault.azure-msi.role", "test-role") .containsEntry("spring.cloud.vault.azure-msi.azure-path", "test-azure-path"); + + new VaultBindingsPropertiesProcessor.Boot3(3).process(environment, bindings, properties); + assertThat(properties) + .containsEntry("spring.cloud.vault.uri", "test-uri") + .containsEntry("spring.cloud.vault.namespace", "test-namespace") + .containsEntry("spring.cloud.vault.authentication", "azure_msi") + .containsEntry("spring.cloud.vault.azure-msi.role", "test-role") + .containsEntry("spring.cloud.vault.azure-msi.azure-path", "test-azure-path") + .containsEntry("spring.cloud.vault.azure-msi.metadata-service", "test-metadata-service") + .containsEntry("spring.cloud.vault.azure-msi.identity-token-service", "test-identity-token-service"); } @Test @@ -206,7 +242,7 @@ final class VaultBindingsPropertiesProcessorTest { ) ); - new VaultBindingsPropertiesProcessor().process(environment, bindings, properties); + new VaultBindingsPropertiesProcessor.Boot2(2).process(environment, bindings, properties); assertThat(properties) .containsEntry("spring.cloud.vault.uri", "test-uri") .containsEntry("spring.cloud.vault.namespace", "test-namespace") @@ -233,7 +269,7 @@ final class VaultBindingsPropertiesProcessorTest { ) ); - new VaultBindingsPropertiesProcessor().process(environment, bindings, properties); + new VaultBindingsPropertiesProcessor.Boot2(2).process(environment, bindings, properties); assertThat(properties) .containsEntry("spring.cloud.vault.uri", "test-uri") .containsEntry("spring.cloud.vault.namespace", "test-namespace") @@ -245,6 +281,19 @@ final class VaultBindingsPropertiesProcessorTest { .containsEntry("spring.cloud.vault.gcp-iam.jwt-validity", "test-jwt-validity") .containsEntry("spring.cloud.vault.gcp-iam.project-id", "test-project-id") .containsEntry("spring.cloud.vault.gcp-iam.service-account", "test-service-account"); + + new VaultBindingsPropertiesProcessor.Boot3(3).process(environment, bindings, properties); + assertThat(properties) + .containsEntry("spring.cloud.vault.uri", "test-uri") + .containsEntry("spring.cloud.vault.namespace", "test-namespace") + .containsEntry("spring.cloud.vault.authentication", "gcp_iam") + .containsEntry("spring.cloud.vault.gcp-iam.role", "test-role") + .containsEntry("spring.cloud.vault.gcp-iam.credentials.location", "test-path/credentials.json") + .containsEntry("spring.cloud.vault.gcp-iam.credentials.encoded-key", "test-encoded-key") + .containsEntry("spring.cloud.vault.gcp-iam.gcp-path", "test-gcp-path") + .containsEntry("spring.cloud.vault.gcp-iam.jwt-validity", "test-jwt-validity") + .containsEntry("spring.cloud.vault.gcp-iam.project-id", "test-project-id") + .containsEntry("spring.cloud.vault.gcp-iam.service-account-id", "test-service-account"); } @Test @@ -256,16 +305,26 @@ final class VaultBindingsPropertiesProcessorTest { .withEntry("authentication-method", "kubernetes") .withEntry("role", "test-role") .withEntry("kubernetes-path", "test-kubernetes-path") + .withEntry("kubernetes-service-account-token-file", "test-kubernetes-service-account-token-file") ) ); - new VaultBindingsPropertiesProcessor().process(environment, bindings, properties); + new VaultBindingsPropertiesProcessor.Boot2(2).process(environment, bindings, properties); assertThat(properties) .containsEntry("spring.cloud.vault.uri", "test-uri") .containsEntry("spring.cloud.vault.namespace", "test-namespace") .containsEntry("spring.cloud.vault.authentication", "kubernetes") .containsEntry("spring.cloud.vault.kubernetes.role", "test-role") .containsEntry("spring.cloud.vault.kubernetes.kubernetes-path", "test-kubernetes-path"); + + new VaultBindingsPropertiesProcessor.Boot3(3).process(environment, bindings, properties); + assertThat(properties) + .containsEntry("spring.cloud.vault.uri", "test-uri") + .containsEntry("spring.cloud.vault.namespace", "test-namespace") + .containsEntry("spring.cloud.vault.authentication", "kubernetes") + .containsEntry("spring.cloud.vault.kubernetes.role", "test-role") + .containsEntry("spring.cloud.vault.kubernetes.kubernetes-path", "test-kubernetes-path") + .containsEntry("spring.cloud.vault.kubernetes.kubernetes-service-account-token-file", "test-kubernetes-service-account-token-file"); } @Test @@ -277,7 +336,7 @@ final class VaultBindingsPropertiesProcessorTest { ) ); - new VaultBindingsPropertiesProcessor().process(environment, bindings, properties); + new VaultBindingsPropertiesProcessor.Boot2(2).process(environment, bindings, properties); assertThat(properties) .containsEntry("spring.cloud.vault.uri", "test-uri") .containsEntry("spring.cloud.vault.namespace", "test-namespace") @@ -317,7 +376,7 @@ final class VaultBindingsPropertiesProcessorTest { environment.setProperty("org.springframework.cloud.bindings.boot.vault.enable", "false"); - new VaultBindingsPropertiesProcessor().process(environment, bindings, properties); + new VaultBindingsPropertiesProcessor.Boot2(2).process(environment, bindings, properties); assertThat(properties).isEmpty(); }