mirror of
https://github.com/spring-projects/spring-boot.git
synced 2026-09-24 02:09:05 +00:00
Merge pull request #25456 from bono007
* pr/25456: Polish contribution Add configuration properties for Flyway's Vault and Conjur support Closes gh-25456
This commit is contained in:
+9
@@ -91,6 +91,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Dan Zheng
|
||||
* @author András Deák
|
||||
* @author Semyon Danilov
|
||||
* @author Chris Bono
|
||||
* @since 1.1.0
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@@ -245,6 +246,14 @@ public class FlywayAutoConfiguration {
|
||||
// No method reference for compatibility with Flyway 6.x
|
||||
map.from(properties.getSkipExecutingMigrations()).whenNonNull()
|
||||
.to((skipExecutingMigrations) -> configuration.skipExecutingMigrations(skipExecutingMigrations));
|
||||
// Teams secrets management properties (all non-method reference for
|
||||
// compatibility with Flyway 6.x)
|
||||
map.from(properties.getConjurUrl()).to((conjurUrl) -> configuration.conjurUrl(conjurUrl));
|
||||
map.from(properties.getConjurToken()).to((conjurToken) -> configuration.conjurToken(conjurToken));
|
||||
map.from(properties.getVaultUrl()).to((vaultUrl) -> configuration.vaultUrl(vaultUrl));
|
||||
map.from(properties.getVaultToken()).to((vaultToken) -> configuration.vaultToken(vaultToken));
|
||||
map.from(properties.getVaultSecrets()).whenNot(List::isEmpty)
|
||||
.to((vaultSecrets) -> configuration.vaultSecrets(vaultSecrets.toArray(new String[0])));
|
||||
}
|
||||
|
||||
private void configureCreateSchemas(FluentConfiguration configuration, boolean createSchemas) {
|
||||
|
||||
+70
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -33,6 +33,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
* @author Dave Syer
|
||||
* @author Eddú Meléndez
|
||||
* @author Stephane Nicoll
|
||||
* @author Chris Bono
|
||||
* @since 1.1.0
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "spring.flyway")
|
||||
@@ -328,6 +329,34 @@ public class FlywayProperties {
|
||||
*/
|
||||
private Boolean skipExecutingMigrations;
|
||||
|
||||
/**
|
||||
* REST API URL of the Conjur server. Requires Flyway teams.
|
||||
*/
|
||||
private String conjurUrl;
|
||||
|
||||
/**
|
||||
* Conjur token required to access secrets. Requires Flyway teams.
|
||||
*/
|
||||
private String conjurToken;
|
||||
|
||||
/**
|
||||
* REST API URL of the Vault server. Requires Flyway teams.
|
||||
*/
|
||||
private String vaultUrl;
|
||||
|
||||
/**
|
||||
* Vault token required to access secrets. Requires Flyway teams.
|
||||
*/
|
||||
private String vaultToken;
|
||||
|
||||
/**
|
||||
* Comma-separated list of paths to secrets that contain Flyway configurations. This
|
||||
* must start with the name of the engine followed by '/data/' and end with the name
|
||||
* of the secret. The resulting form is '{engine}/data/{path}/{to}/{secret_name}'.
|
||||
* Requires Flyway teams.
|
||||
*/
|
||||
private List<String> vaultSecrets;
|
||||
|
||||
public boolean isEnabled() {
|
||||
return this.enabled;
|
||||
}
|
||||
@@ -772,4 +801,44 @@ public class FlywayProperties {
|
||||
this.skipExecutingMigrations = skipExecutingMigrations;
|
||||
}
|
||||
|
||||
public String getConjurUrl() {
|
||||
return this.conjurUrl;
|
||||
}
|
||||
|
||||
public void setConjurUrl(String conjurUrl) {
|
||||
this.conjurUrl = conjurUrl;
|
||||
}
|
||||
|
||||
public String getConjurToken() {
|
||||
return this.conjurToken;
|
||||
}
|
||||
|
||||
public void setConjurToken(String conjurToken) {
|
||||
this.conjurToken = conjurToken;
|
||||
}
|
||||
|
||||
public String getVaultUrl() {
|
||||
return this.vaultUrl;
|
||||
}
|
||||
|
||||
public void setVaultUrl(String vaultUrl) {
|
||||
this.vaultUrl = vaultUrl;
|
||||
}
|
||||
|
||||
public String getVaultToken() {
|
||||
return this.vaultToken;
|
||||
}
|
||||
|
||||
public void setVaultToken(String vaultToken) {
|
||||
this.vaultToken = vaultToken;
|
||||
}
|
||||
|
||||
public List<String> getVaultSecrets() {
|
||||
return this.vaultSecrets;
|
||||
}
|
||||
|
||||
public void setVaultSecrets(List<String> vaultSecrets) {
|
||||
this.vaultSecrets = vaultSecrets;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+70
-78
@@ -46,7 +46,9 @@ import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfigurati
|
||||
import org.springframework.boot.jdbc.DataSourceBuilder;
|
||||
import org.springframework.boot.jdbc.SchemaManagement;
|
||||
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
|
||||
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.test.context.runner.ContextConsumer;
|
||||
import org.springframework.boot.test.system.CapturedOutput;
|
||||
import org.springframework.boot.test.system.OutputCaptureExtension;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -82,6 +84,7 @@ import static org.mockito.Mockito.mock;
|
||||
* @author Dominic Gunn
|
||||
* @author András Deák
|
||||
* @author Takaaki Shimbo
|
||||
* @author Chris Bono
|
||||
*/
|
||||
@ExtendWith(OutputCaptureExtension.class)
|
||||
class FlywayAutoConfigurationTests {
|
||||
@@ -413,34 +416,21 @@ class FlywayAutoConfigurationTests {
|
||||
@Test
|
||||
void batchIsCorrectlyMapped() {
|
||||
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
|
||||
.withPropertyValues("spring.flyway.batch=true").run((context) -> {
|
||||
assertThat(context).hasFailed();
|
||||
Throwable failure = context.getStartupFailure();
|
||||
assertThat(failure).hasRootCauseInstanceOf(FlywayTeamsUpgradeRequiredException.class);
|
||||
assertThat(failure).hasMessageContaining(" batch ");
|
||||
});
|
||||
.withPropertyValues("spring.flyway.batch=true").run(validateFlywayTeamsPropertyOnly("batch"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void dryRunOutputIsCorrectlyMapped() {
|
||||
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
|
||||
.withPropertyValues("spring.flyway.dryRunOutput=dryrun.sql").run((context) -> {
|
||||
assertThat(context).hasFailed();
|
||||
Throwable failure = context.getStartupFailure();
|
||||
assertThat(failure).hasRootCauseInstanceOf(FlywayTeamsUpgradeRequiredException.class);
|
||||
assertThat(failure).hasMessageContaining(" dryRunOutput ");
|
||||
});
|
||||
.withPropertyValues("spring.flyway.dryRunOutput=dryrun.sql")
|
||||
.run(validateFlywayTeamsPropertyOnly("dryRunOutput"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void errorOverridesIsCorrectlyMapped() {
|
||||
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
|
||||
.withPropertyValues("spring.flyway.errorOverrides=D12345").run((context) -> {
|
||||
assertThat(context).hasFailed();
|
||||
Throwable failure = context.getStartupFailure();
|
||||
assertThat(failure).hasRootCauseInstanceOf(FlywayTeamsUpgradeRequiredException.class);
|
||||
assertThat(failure).hasMessageContaining(" errorOverrides ");
|
||||
});
|
||||
.withPropertyValues("spring.flyway.errorOverrides=D12345")
|
||||
.run(validateFlywayTeamsPropertyOnly("errorOverrides"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -453,45 +443,28 @@ class FlywayAutoConfigurationTests {
|
||||
@Test
|
||||
void oracleSqlplusIsCorrectlyMapped() {
|
||||
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
|
||||
.withPropertyValues("spring.flyway.oracle-sqlplus=true").run((context) -> {
|
||||
assertThat(context).hasFailed();
|
||||
Throwable failure = context.getStartupFailure();
|
||||
assertThat(failure).hasRootCauseInstanceOf(FlywayTeamsUpgradeRequiredException.class);
|
||||
assertThat(failure).hasMessageContaining(" oracle.sqlplus ");
|
||||
});
|
||||
.withPropertyValues("spring.flyway.oracle-sqlplus=true")
|
||||
.run(validateFlywayTeamsPropertyOnly("oracle.sqlplus"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void oracleSqlplusWarnIsCorrectlyMapped() {
|
||||
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
|
||||
.withPropertyValues("spring.flyway.oracle-sqlplus-warn=true").run((context) -> {
|
||||
assertThat(context).hasFailed();
|
||||
Throwable failure = context.getStartupFailure();
|
||||
assertThat(failure).hasRootCauseInstanceOf(FlywayTeamsUpgradeRequiredException.class);
|
||||
assertThat(failure).hasMessageContaining(" oracle.sqlplusWarn ");
|
||||
});
|
||||
.withPropertyValues("spring.flyway.oracle-sqlplus-warn=true")
|
||||
.run(validateFlywayTeamsPropertyOnly("oracle.sqlplusWarn"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void streamIsCorrectlyMapped() {
|
||||
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
|
||||
.withPropertyValues("spring.flyway.stream=true").run((context) -> {
|
||||
assertThat(context).hasFailed();
|
||||
Throwable failure = context.getStartupFailure();
|
||||
assertThat(failure).hasRootCauseInstanceOf(FlywayTeamsUpgradeRequiredException.class);
|
||||
assertThat(failure).hasMessageContaining(" stream ");
|
||||
});
|
||||
.withPropertyValues("spring.flyway.stream=true").run(validateFlywayTeamsPropertyOnly("stream"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void undoSqlMigrationPrefix() {
|
||||
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
|
||||
.withPropertyValues("spring.flyway.undo-sql-migration-prefix=undo").run((context) -> {
|
||||
assertThat(context).hasFailed();
|
||||
Throwable failure = context.getStartupFailure();
|
||||
assertThat(failure).hasRootCauseInstanceOf(FlywayTeamsUpgradeRequiredException.class);
|
||||
assertThat(failure).hasMessageContaining(" undoSqlMigrationPrefix ");
|
||||
});
|
||||
.withPropertyValues("spring.flyway.undo-sql-migration-prefix=undo")
|
||||
.run(validateFlywayTeamsPropertyOnly("undoSqlMigrationPrefix"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -526,67 +499,77 @@ class FlywayAutoConfigurationTests {
|
||||
@Test
|
||||
void cherryPickIsCorrectlyMapped() {
|
||||
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
|
||||
.withPropertyValues("spring.flyway.cherry-pick=1.1").run((context) -> {
|
||||
assertThat(context).hasFailed();
|
||||
Throwable failure = context.getStartupFailure();
|
||||
assertThat(failure).hasRootCauseInstanceOf(FlywayTeamsUpgradeRequiredException.class);
|
||||
assertThat(failure).hasMessageContaining(" cherryPick ");
|
||||
});
|
||||
.withPropertyValues("spring.flyway.cherry-pick=1.1").run(validateFlywayTeamsPropertyOnly("cherryPick"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void jdbcPropertiesAreCorrectlyMapped() {
|
||||
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
|
||||
.withPropertyValues("spring.flyway.jdbc-properties.prop=value").run((context) -> {
|
||||
assertThat(context).hasFailed();
|
||||
Throwable failure = context.getStartupFailure();
|
||||
assertThat(failure).hasRootCauseInstanceOf(FlywayTeamsUpgradeRequiredException.class);
|
||||
assertThat(failure).hasMessageContaining(" jdbcProperties ");
|
||||
});
|
||||
.withPropertyValues("spring.flyway.jdbc-properties.prop=value")
|
||||
.run(validateFlywayTeamsPropertyOnly("jdbcProperties"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void oracleKerberosCacheFileIsCorrectlyMapped() {
|
||||
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
|
||||
.withPropertyValues("spring.flyway.oracle-kerberos-cache-file=/tmp/cache").run((context) -> {
|
||||
assertThat(context).hasFailed();
|
||||
Throwable failure = context.getStartupFailure();
|
||||
assertThat(failure).hasRootCauseInstanceOf(FlywayTeamsUpgradeRequiredException.class);
|
||||
assertThat(failure).hasMessageContaining(" oracle.kerberosCacheFile ");
|
||||
});
|
||||
.withPropertyValues("spring.flyway.oracle-kerberos-cache-file=/tmp/cache")
|
||||
.run(validateFlywayTeamsPropertyOnly("oracle.kerberosCacheFile"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void oracleKerberosConfigFileIsCorrectlyMapped() {
|
||||
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
|
||||
.withPropertyValues("spring.flyway.oracle-kerberos-config-file=/tmp/config").run((context) -> {
|
||||
assertThat(context).hasFailed();
|
||||
Throwable failure = context.getStartupFailure();
|
||||
assertThat(failure).hasRootCauseInstanceOf(FlywayTeamsUpgradeRequiredException.class);
|
||||
assertThat(failure).hasMessageContaining(" oracle.kerberosConfigFile ");
|
||||
});
|
||||
.withPropertyValues("spring.flyway.oracle-kerberos-config-file=/tmp/config")
|
||||
.run(validateFlywayTeamsPropertyOnly("oracle.kerberosConfigFile"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void outputQueryResultsIsCorrectlyMapped() {
|
||||
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
|
||||
.withPropertyValues("spring.flyway.output-query-results=false").run((context) -> {
|
||||
assertThat(context).hasFailed();
|
||||
Throwable failure = context.getStartupFailure();
|
||||
assertThat(failure).hasRootCauseInstanceOf(FlywayTeamsUpgradeRequiredException.class);
|
||||
assertThat(failure).hasMessageContaining(" outputQueryResults ");
|
||||
});
|
||||
.withPropertyValues("spring.flyway.output-query-results=false")
|
||||
.run(validateFlywayTeamsPropertyOnly("outputQueryResults"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void skipExecutingMigrationsIsCorrectlyMapped() {
|
||||
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
|
||||
.withPropertyValues("spring.flyway.skip-executing-migrations=true").run((context) -> {
|
||||
assertThat(context).hasFailed();
|
||||
Throwable failure = context.getStartupFailure();
|
||||
assertThat(failure).hasRootCauseInstanceOf(FlywayTeamsUpgradeRequiredException.class);
|
||||
assertThat(failure).hasMessageContaining(" skipExecutingMigrations ");
|
||||
});
|
||||
.withPropertyValues("spring.flyway.skip-executing-migrations=true")
|
||||
.run(validateFlywayTeamsPropertyOnly("skipExecutingMigrations"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void conjurUrlIsCorrectlyMapped() {
|
||||
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
|
||||
.withPropertyValues("spring.flyway.conjur-url=http://foo.com/secrets")
|
||||
.run(validateFlywayTeamsPropertyOnly("conjurUrl"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void conjurTokenIsCorrectlyMapped() {
|
||||
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
|
||||
.withPropertyValues("spring.flyway.conjur-token=5150")
|
||||
.run(validateFlywayTeamsPropertyOnly("conjurToken"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void vaultUrlIsCorrectlyMapped() {
|
||||
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
|
||||
.withPropertyValues("spring.flyway.vault-url=http://foo.com/secrets")
|
||||
.run(validateFlywayTeamsPropertyOnly("vaultUrl"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void vaultTokenIsCorrectlyMapped() {
|
||||
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
|
||||
.withPropertyValues("spring.flyway.vault-token=5150")
|
||||
.run(validateFlywayTeamsPropertyOnly("vaultToken"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void vaultSecretsIsCorrectlyMapped() {
|
||||
this.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)
|
||||
.withPropertyValues("spring.flyway.vault-secrets=kv/data/test/1/config,kv/data/test/2/config")
|
||||
.run(validateFlywayTeamsPropertyOnly("vaultSecrets"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -616,6 +599,15 @@ class FlywayAutoConfigurationTests {
|
||||
});
|
||||
}
|
||||
|
||||
private ContextConsumer<AssertableApplicationContext> validateFlywayTeamsPropertyOnly(String propertyName) {
|
||||
return (context) -> {
|
||||
assertThat(context).hasFailed();
|
||||
Throwable failure = context.getStartupFailure();
|
||||
assertThat(failure).hasRootCauseInstanceOf(FlywayTeamsUpgradeRequiredException.class);
|
||||
assertThat(failure).hasMessageContaining(String.format(" %s ", propertyName));
|
||||
};
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class FlywayDataSourceConfiguration {
|
||||
|
||||
|
||||
+1
-3
@@ -40,6 +40,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* Tests for {@link FlywayProperties}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Chris Bono
|
||||
*/
|
||||
class FlywayPropertiesTests {
|
||||
|
||||
@@ -108,9 +109,6 @@ class FlywayPropertiesTests {
|
||||
// Handled by the conversion service
|
||||
ignoreProperties(configuration, "baselineVersionAsString", "encodingAsString", "locationsAsStrings",
|
||||
"targetAsString");
|
||||
// Teams-only properties that we cannot detect as no exception is thrown and
|
||||
// getters return null
|
||||
ignoreProperties(configuration, "conjurToken", "conjurUrl", "vaultSecrets", "vaultToken", "vaultUrl");
|
||||
// Handled as initSql array
|
||||
ignoreProperties(configuration, "initSql");
|
||||
ignoreProperties(properties, "initSqls");
|
||||
|
||||
Reference in New Issue
Block a user