Skip to content

Commit ba9d29c

Browse files
committed
Fail if no zookeeper config import.
Adds ZookeeperConfigDataMissingEnvironmentPostProcessor that checks if there is a spring.config.import=zookeeper: statement. If not, an exception is thrown and a FailureAnalyzer provides hints to fix the issue. Fixes gh-284
1 parent 9ba7c17 commit ba9d29c

File tree

3 files changed

+203
-0
lines changed

3 files changed

+203
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* Copyright 2015-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.zookeeper.config;
18+
19+
import org.springframework.boot.SpringApplication;
20+
import org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor;
21+
import org.springframework.boot.diagnostics.AbstractFailureAnalyzer;
22+
import org.springframework.boot.diagnostics.FailureAnalysis;
23+
import org.springframework.boot.env.EnvironmentPostProcessor;
24+
import org.springframework.cloud.zookeeper.ZookeeperProperties;
25+
import org.springframework.core.Ordered;
26+
import org.springframework.core.env.ConfigurableEnvironment;
27+
import org.springframework.util.StringUtils;
28+
29+
import static org.springframework.cloud.util.PropertyUtils.bootstrapEnabled;
30+
import static org.springframework.cloud.util.PropertyUtils.useLegacyProcessing;
31+
import static org.springframework.cloud.zookeeper.config.ZookeeperConfigDataLocationResolver.PREFIX;
32+
33+
public class ZookeeperConfigDataMissingEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {
34+
35+
/**
36+
* Order of post processor, set to run after
37+
* {@link ConfigDataEnvironmentPostProcessor}.
38+
*/
39+
public static final int ORDER = ConfigDataEnvironmentPostProcessor.ORDER + 1000;
40+
41+
@Override
42+
public int getOrder() {
43+
return ORDER;
44+
}
45+
46+
@Override
47+
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
48+
// don't run if using bootstrap or legacy processing
49+
if (bootstrapEnabled(environment) || useLegacyProcessing(environment)) {
50+
return;
51+
}
52+
boolean coreEnabled = environment.getProperty(ZookeeperProperties.PREFIX + ".enabled", Boolean.class,
53+
true);
54+
boolean configEnabled = environment.getProperty(ZookeeperConfigProperties.PREFIX + ".enabled", Boolean.class,
55+
true);
56+
boolean importCheckEnabled = environment.getProperty(ZookeeperConfigProperties.PREFIX + ".import-check.enabled",
57+
Boolean.class, true);
58+
if (!coreEnabled || !configEnabled || !importCheckEnabled) {
59+
return;
60+
}
61+
String property = environment.getProperty("spring.config.import");
62+
if (!StringUtils.hasText(property)) {
63+
throw new ImportException("No spring.config.import set", false);
64+
}
65+
if (!property.contains(PREFIX)) {
66+
throw new ImportException("spring.config.import missing " + PREFIX, true);
67+
}
68+
}
69+
70+
static class ImportException extends RuntimeException {
71+
72+
final boolean missingPrefix;
73+
74+
ImportException(String message, boolean missingPrefix) {
75+
super(message);
76+
this.missingPrefix = missingPrefix;
77+
}
78+
79+
}
80+
81+
static class ImportExceptionFailureAnalyzer extends AbstractFailureAnalyzer<ImportException> {
82+
83+
@Override
84+
protected FailureAnalysis analyze(Throwable rootFailure, ImportException cause) {
85+
String description;
86+
if (cause.missingPrefix) {
87+
description = "The spring.config.import property is missing a " + PREFIX + " entry";
88+
}
89+
else {
90+
description = "No spring.config.import property has been defined";
91+
}
92+
String action = "Add a spring.config.import=zookeeper: property to your configuration.\n"
93+
+ "\tIf configuration in not required add spring.config.import=optional:zookeeper: instead.\n"
94+
+ "\tTo disable this check, set spring.cloud.zookeeper.config.enabled=false or \n"
95+
+ "\tspring.cloud.zookeeper.config.import-check.enabled=false.";
96+
return new FailureAnalysis(description, action, cause);
97+
}
98+
99+
}
100+
101+
}

spring-cloud-zookeeper-config/src/main/resources/META-INF/spring.factories

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ org.springframework.cloud.zookeeper.config.ZookeeperConfigAutoConfiguration
66
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
77
org.springframework.cloud.zookeeper.config.ZookeeperConfigBootstrapConfiguration
88

9+
# Environment PostProcessor
10+
org.springframework.boot.env.EnvironmentPostProcessor=\
11+
org.springframework.cloud.zookeeper.config.ZookeeperConfigDataMissingEnvironmentPostProcessor
12+
13+
org.springframework.boot.diagnostics.FailureAnalyzer=\
14+
org.springframework.cloud.zookeeper.config.ZookeeperConfigDataMissingEnvironmentPostProcessor.ImportExceptionFailureAnalyzer
15+
916
# ConfigData Location Resolvers
1017
org.springframework.boot.context.config.ConfigDataLocationResolver=\
1118
org.springframework.cloud.zookeeper.config.ZookeeperConfigDataLocationResolver
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
* Copyright 2013-2019 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.zookeeper.config;
18+
19+
import org.assertj.core.api.Assertions;
20+
import org.junit.jupiter.api.Test;
21+
import org.junit.jupiter.api.extension.ExtendWith;
22+
23+
import org.springframework.boot.WebApplicationType;
24+
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
25+
import org.springframework.boot.builder.SpringApplicationBuilder;
26+
import org.springframework.boot.test.system.CapturedOutput;
27+
import org.springframework.boot.test.system.OutputCaptureExtension;
28+
import org.springframework.cloud.zookeeper.config.ZookeeperConfigDataMissingEnvironmentPostProcessor.ImportException;
29+
import org.springframework.context.ConfigurableApplicationContext;
30+
import org.springframework.context.annotation.Configuration;
31+
32+
import static org.assertj.core.api.Assertions.assertThat;
33+
import static org.springframework.cloud.zookeeper.config.ZookeeperConfigDataLocationResolver.PREFIX;
34+
35+
/**
36+
* @author Spencer Gibb
37+
*/
38+
@ExtendWith(OutputCaptureExtension.class)
39+
public class ZookeeperConfigDataNoImportIntegrationTests {
40+
41+
private static final String APP_NAME = "testZookeeperConfigDataNoImport";
42+
43+
@Test
44+
public void exceptionThrownIfNoImport(CapturedOutput output) {
45+
Assertions.assertThatThrownBy(() -> new SpringApplicationBuilder(Config.class).web(WebApplicationType.NONE)
46+
.run("--spring.application.name=" + APP_NAME)).isInstanceOf(ImportException.class);
47+
48+
assertThat(output).contains("No spring.config.import property has been defined")
49+
.contains("Add a spring.config.import=zookeeper: property to your configuration");
50+
}
51+
52+
@Test
53+
public void exceptionThrownIfImportMissingZookeeper(CapturedOutput output) {
54+
Assertions.assertThatThrownBy(() -> new SpringApplicationBuilder(Config.class).web(WebApplicationType.NONE).run(
55+
"--spring.config.import=optional:file:somefile.properties", "--spring.application.name=" + APP_NAME))
56+
.isInstanceOf(ImportException.class);
57+
58+
assertThat(output).contains("spring.config.import property is missing a " + PREFIX)
59+
.contains("Add a spring.config.import=zookeeper: property to your configuration");
60+
}
61+
62+
@Test
63+
public void noExceptionThrownIfZookeeperDisabled() {
64+
try (ConfigurableApplicationContext context = new SpringApplicationBuilder(Config.class)
65+
.web(WebApplicationType.NONE)
66+
.run("--spring.cloud.zookeeper.enabled=false", "--spring.application.name=" + APP_NAME)) {
67+
// nothing to do
68+
}
69+
}
70+
71+
@Test
72+
public void noExceptionThrownIfZookeeperConfigDisabled() {
73+
try (ConfigurableApplicationContext context = new SpringApplicationBuilder(Config.class)
74+
.web(WebApplicationType.NONE)
75+
.run("--spring.cloud.zookeeper.config.enabled=false", "--spring.application.name=" + APP_NAME)) {
76+
// nothing to do
77+
}
78+
}
79+
80+
@Test
81+
public void noExceptionThrownIfImportCheckDisabled() {
82+
try (ConfigurableApplicationContext context = new SpringApplicationBuilder(Config.class)
83+
.web(WebApplicationType.NONE).run("--spring.cloud.zookeeper.config.import-check.enabled=false",
84+
"--spring.application.name=" + APP_NAME)) {
85+
// nothing to do
86+
}
87+
}
88+
89+
@Configuration
90+
@EnableAutoConfiguration
91+
static class Config {
92+
93+
}
94+
95+
}

0 commit comments

Comments
 (0)