Skip to content

Commit 6e03afb

Browse files
committed
Refine support for optional Vault config locations.
We now propagate the optional config location flag to the config data infrastructure. Also, the check whether Vault is enabled is moved from the resolver into the loader returning null if Vault support is enabled. This allows Spring Boot to skip optional config data locations. Closes gh-571
1 parent 5c7c305 commit 6e03afb

File tree

6 files changed

+91
-19
lines changed

6 files changed

+91
-19
lines changed

docs/src/main/asciidoc/config-data.adoc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,18 @@ spring.config.import: vault://first/context/path, vault://other/path, vault://
3838
----
3939
====
4040

41+
[[vault.configdata.location.optional]]
42+
=== Conditionally enable/disable Vault Configuration
43+
44+
In some cases, it can be required to launch an application without Vault. You can express whether a Vault config location should be optional or mandatory (default) through the location string:
45+
46+
* `optional:vault://` (default location)
47+
* `optional:vault:///<context-path>` (contextual location)
48+
49+
Optional locations are skipped during application startup if Vault support was disabled through `spring.cloud.vault.enabled=false`.
50+
51+
NOTE: Vault context paths that cannot be found (HTTP Status 404) are skipped regardless of whether the config location is marked optional. <<vault.config.fail-fast>> allows failing on start if a Vault context path cannot be found because of HTTP Status 404.
52+
4153
[[vault.configdata.customization]]
4254
=== Infrastructure Customization
4355

spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultConfigDataLoader.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
package org.springframework.cloud.vault.config;
1818

19-
import java.io.IOException;
2019
import java.lang.reflect.Field;
2120
import java.lang.reflect.Modifier;
2221
import java.util.Arrays;
@@ -93,6 +92,8 @@
9392
*/
9493
public class VaultConfigDataLoader implements ConfigDataLoader<VaultConfigLocation> {
9594

95+
private final static ConfigData SKIP_LOCATION = null;
96+
9697
private final static boolean FLUX_AVAILABLE = ClassUtils.isPresent("reactor.core.publisher.Flux",
9798
VaultConfigDataLoader.class.getClassLoader());
9899

@@ -110,11 +111,15 @@ public VaultConfigDataLoader(DeferredLogFactory logFactory) {
110111

111112
@Override
112113
public ConfigData load(ConfigDataLoaderContext context, VaultConfigLocation location)
113-
throws IOException, ConfigDataLocationNotFoundException {
114+
throws ConfigDataLocationNotFoundException {
114115

115116
ConfigurableBootstrapContext bootstrap = context.getBootstrapContext();
116117
VaultProperties vaultProperties = bootstrap.get(VaultProperties.class);
117118

119+
if (!vaultProperties.isEnabled()) {
120+
return SKIP_LOCATION;
121+
}
122+
118123
if (vaultProperties.getSession().getLifecycle().isEnabled()
119124
|| vaultProperties.getConfig().getLifecycle().isEnabled()) {
120125
registerVaultTaskScheduler(bootstrap);

spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultConfigDataLocationResolver.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,7 @@ public class VaultConfigDataLocationResolver implements ConfigDataLocationResolv
8181

8282
@Override
8383
public boolean isResolvable(ConfigDataLocationResolverContext context, ConfigDataLocation location) {
84-
boolean vaultEnabled = context.getBinder().bind(VaultProperties.PREFIX + ".enabled", Boolean.class)
85-
.orElse(true);
86-
87-
return location.getValue().startsWith(VaultConfigLocation.VAULT_PREFIX) && vaultEnabled;
84+
return location.getValue().startsWith(VaultConfigLocation.VAULT_PREFIX);
8885
}
8986

9087
@Override

spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultConfigLocation.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ public class VaultConfigLocation extends ConfigDataResource {
4242

4343
public VaultConfigLocation(String contextPath, boolean optional) {
4444

45+
super(optional);
46+
4547
Assert.hasText(contextPath, "Context path must not be empty");
4648

4749
this.secretBackendMetadata = KeyValueSecretBackendMetadata.create(contextPath);

spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultConfigDataLoaderIntegrationTests.java

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818

1919
import java.util.Collections;
2020

21-
import org.junit.After;
2221
import org.junit.Before;
2322
import org.junit.Test;
2423

@@ -33,14 +32,12 @@
3332
import static org.assertj.core.api.Assertions.assertThat;
3433

3534
/**
36-
* Unit tests for {@link VaultConfigDataLoader}.
35+
* Integration tests for {@link VaultConfigDataLoader}.
3736
*
3837
* @author Mark Paluch
3938
*/
4039
public class VaultConfigDataLoaderIntegrationTests extends IntegrationTestSupport {
4140

42-
private ConfigurableApplicationContext context;
43-
4441
@Before
4542
public void before() {
4643

@@ -49,24 +46,32 @@ public void before() {
4946

5047
this.vaultRule.prepare().getVaultOperations().write("secret/my-config-loader/cloud",
5148
Collections.singletonMap("default-key", "cloud"));
49+
}
50+
51+
@Test
52+
public void shouldConsiderProfiles() {
5253

5354
SpringApplication application = new SpringApplication(Config.class);
5455
application.setWebApplicationType(WebApplicationType.NONE);
5556
application.setAdditionalProfiles("cloud");
5657

57-
this.context = application.run("--spring.application.name=my-config-loader", "--spring.config.import=vault:",
58-
"--spring.cloud.vault.token=" + Settings.token().getToken());
58+
try (ConfigurableApplicationContext context = application.run("--spring.application.name=my-config-loader",
59+
"--spring.config.import=vault:", "--spring.cloud.vault.token=" + Settings.token().getToken())) {
60+
61+
assertThat(context.getEnvironment().getProperty("default-key")).isEqualTo("cloud");
62+
}
5963
}
6064

6165
@Test
62-
public void shouldConsiderProfiles() {
63-
assertThat(this.context.getEnvironment().getProperty("default-key")).isEqualTo("cloud");
64-
}
66+
public void shouldConsiderDisabledVault() {
67+
68+
SpringApplication application = new SpringApplication(Config.class);
69+
application.setWebApplicationType(WebApplicationType.NONE);
70+
71+
try (ConfigurableApplicationContext context = application.run("--spring.application.name=my-config-loader",
72+
"--spring.config.import=optional:vault:", "--spring.cloud.vault.enabled=false")) {
6573

66-
@After
67-
public void after() {
68-
if (this.context != null) {
69-
this.context.close();
74+
assertThat(context.getEnvironment().getProperty("default-key")).isNull();
7075
}
7176
}
7277

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright 2020-2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.cloud.vault.config;
18+
19+
import org.junit.Test;
20+
21+
import org.springframework.boot.DefaultBootstrapContext;
22+
import org.springframework.boot.context.config.ConfigData;
23+
import org.springframework.boot.logging.DeferredLogs;
24+
import org.springframework.cloud.vault.util.IntegrationTestSupport;
25+
26+
import static org.assertj.core.api.Assertions.assertThat;
27+
28+
/**
29+
* Unit tests for {@link VaultConfigDataLoader}.
30+
*
31+
* @author Mark Paluch
32+
*/
33+
public class VaultConfigDataLoaderUnitTests extends IntegrationTestSupport {
34+
35+
@Test
36+
public void shouldConsiderDisabledVault() {
37+
38+
VaultConfigDataLoader loader = new VaultConfigDataLoader(new DeferredLogs());
39+
DefaultBootstrapContext context = new DefaultBootstrapContext();
40+
41+
VaultProperties properties = new VaultProperties();
42+
properties.setEnabled(false);
43+
44+
context.register(VaultProperties.class, it -> properties);
45+
46+
ConfigData vaultDisabled = loader.load(() -> context, new VaultConfigLocation("foo", true));
47+
48+
assertThat(vaultDisabled).isNull();
49+
}
50+
51+
}

0 commit comments

Comments
 (0)