Optionally throw exception when a repository can't be read.

By default, an exception will be thrown.

Fixes gh-661
Fixes gh-1712
This commit is contained in:
Craig Walls
2020-09-23 06:52:56 -06:00
committed by spencergibb
parent 7a6b32fcd8
commit 52e2d9bf64
6 changed files with 114 additions and 24 deletions

View File

@@ -39,18 +39,20 @@ public class CompositeConfiguration {
private List<EnvironmentRepository> environmentRepos = new ArrayList<>();
private ConfigServerProperties properties;
@Bean
@Primary
@ConditionalOnBean(SearchPathLocator.class)
public SearchPathCompositeEnvironmentRepository searchPathCompositeEnvironmentRepository() {
return new SearchPathCompositeEnvironmentRepository(this.environmentRepos);
return new SearchPathCompositeEnvironmentRepository(this.environmentRepos, properties.isFailOnCompositeError());
}
@Bean
@Primary
@ConditionalOnMissingBean(SearchPathLocator.class)
public CompositeEnvironmentRepository compositeEnvironmentRepository() {
return new CompositeEnvironmentRepository(this.environmentRepos);
return new CompositeEnvironmentRepository(this.environmentRepos, properties.isFailOnCompositeError());
}
@Autowired
@@ -58,4 +60,9 @@ public class CompositeConfiguration {
this.environmentRepos = repos;
}
@Autowired
public void setProperties(ConfigServerProperties properties) {
this.properties = properties;
}
}

View File

@@ -73,6 +73,17 @@ public class ConfigServerProperties {
*/
private String defaultProfile = "default";
/**
* Flag indicating that if there are any errors reading properties from a subordinate
* environment repository in a composite environment repository, then the entire
* composite read should fail. Useful when set to false when a Vault repository is in
* the composite to allow clients to still read properties from other repositories
* without providing a valid Vault token.
*
* Defaults to true, resulting in a failure on any error.
*/
private boolean failOnCompositeError = true;
/**
* Decryption configuration for when server handles encrypted properties before
* sending them to clients.
@@ -147,6 +158,14 @@ public class ConfigServerProperties {
this.defaultProfile = defaultProfile;
}
public boolean isFailOnCompositeError() {
return failOnCompositeError;
}
public void setFailOnCompositeError(boolean failOnCompositeError) {
this.failOnCompositeError = failOnCompositeError;
}
/**
* Encryption properties.
*/

View File

@@ -453,16 +453,17 @@ class CompositeRepositoryConfiguration {
@Bean
@ConditionalOnSearchPathLocator
public SearchPathCompositeEnvironmentRepository searchPathCompositeEnvironmentRepository(
List<EnvironmentRepository> environmentRepositories) {
return new SearchPathCompositeEnvironmentRepository(environmentRepositories);
List<EnvironmentRepository> environmentRepositories, ConfigServerProperties properties) {
return new SearchPathCompositeEnvironmentRepository(environmentRepositories,
properties.isFailOnCompositeError());
}
@Primary
@Bean
@ConditionalOnMissingSearchPathLocator
public CompositeEnvironmentRepository compositeEnvironmentRepository(
List<EnvironmentRepository> environmentRepositories) {
return new CompositeEnvironmentRepository(environmentRepositories);
List<EnvironmentRepository> environmentRepositories, ConfigServerProperties properties) {
return new CompositeEnvironmentRepository(environmentRepositories, properties.isFailOnCompositeError());
}
}

View File

@@ -19,6 +19,9 @@ package org.springframework.cloud.config.server.environment;
import java.util.Collections;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.config.environment.Environment;
import org.springframework.core.OrderComparator;
@@ -30,18 +33,22 @@ import org.springframework.core.OrderComparator;
*/
public class CompositeEnvironmentRepository implements EnvironmentRepository {
Log log = LogFactory.getLog(getClass());
protected List<EnvironmentRepository> environmentRepositories;
private boolean failOnError;
/**
* Creates a new {@link CompositeEnvironmentRepository}.
* @param environmentRepositories The list of {@link EnvironmentRepository}s to create
* the composite from.
*/
public CompositeEnvironmentRepository(
List<EnvironmentRepository> environmentRepositories) {
public CompositeEnvironmentRepository(List<EnvironmentRepository> environmentRepositories, boolean failOnError) {
// Sort the environment repositories by the priority
Collections.sort(environmentRepositories, OrderComparator.INSTANCE);
this.environmentRepositories = environmentRepositories;
this.failOnError = failOnError;
}
@Override
@@ -63,8 +70,17 @@ public class CompositeEnvironmentRepository implements EnvironmentRepository {
}
else {
for (EnvironmentRepository repo : environmentRepositories) {
env.addAll(repo.findOne(application, profile, label, includeOrigin)
.getPropertySources());
try {
env.addAll(repo.findOne(application, profile, label, includeOrigin).getPropertySources());
}
catch (Exception e) {
if (failOnError) {
throw e;
}
else {
log.info("Error adding environment for " + repo);
}
}
}
}
return env;

View File

@@ -33,9 +33,9 @@ public class SearchPathCompositeEnvironmentRepository
* @param environmentRepositories The {@link EnvironmentRepository}s to create this
* composite from.
*/
public SearchPathCompositeEnvironmentRepository(
List<EnvironmentRepository> environmentRepositories) {
super(environmentRepositories);
public SearchPathCompositeEnvironmentRepository(List<EnvironmentRepository> environmentRepositories,
boolean failOnError) {
super(environmentRepositories, failOnError);
}
@Override

View File

@@ -76,8 +76,8 @@ public class CompositeEnvironmentRepositoryTests {
repos.add(new TestOrderedEnvironmentRepository(3, e1, loc1));
repos.add(new TestOrderedEnvironmentRepository(2, e3, loc2));
repos.add(new TestOrderedEnvironmentRepository(1, e2, loc3));
SearchPathCompositeEnvironmentRepository compositeRepo = new SearchPathCompositeEnvironmentRepository(
repos);
SearchPathCompositeEnvironmentRepository compositeRepo = new SearchPathCompositeEnvironmentRepository(repos,
true);
Environment compositeEnv = compositeRepo.findOne("foo", "bar", "world", false);
List<PropertySource> propertySources = compositeEnv.getPropertySources();
assertThat(propertySources.size()).isEqualTo(5);
@@ -123,17 +123,16 @@ public class CompositeEnvironmentRepositoryTests {
List<EnvironmentRepository> repos2 = new ArrayList<EnvironmentRepository>();
repos2.add(new TestOrderedEnvironmentRepository(3, e1, loc1));
repos2.add(new TestOrderedEnvironmentRepository(3, e2, loc2));
SearchPathCompositeEnvironmentRepository compositeRepo = new SearchPathCompositeEnvironmentRepository(
repos);
SearchPathCompositeEnvironmentRepository compositeRepo = new SearchPathCompositeEnvironmentRepository(repos,
true);
SearchPathCompositeEnvironmentRepository multiCompositeRepo = new SearchPathCompositeEnvironmentRepository(
repos2);
repos2, true);
Environment env = compositeRepo.findOne("app", "dev", "label", false);
assertThat(env.getVersion()).isEqualTo("1");
assertThat(env.getState()).isEqualTo("state");
Environment multiEnv = multiCompositeRepo.findOne("app", "dev", "label", false);
assertThat(multiEnv.getVersion()).isEqualTo(null);
assertThat(multiEnv.getState()).isEqualTo(null);
}
@Test
@@ -145,8 +144,39 @@ public class CompositeEnvironmentRepositoryTests {
}
}
private static class TestOrderedEnvironmentRepository
implements EnvironmentRepository, SearchPathLocator, Ordered {
@Test
public void testFailingSubordinateRepositorySkipped() {
PropertySource p1 = mock(PropertySource.class);
doReturn("p1").when(p1).getName();
PropertySource p2 = mock(PropertySource.class);
doReturn("p2").when(p2).getName();
String sLoc1 = "loc1";
String sLoc2 = "loc2";
Environment e1 = new Environment("app", "dev");
e1.add(p1);
e1.setVersion("1");
e1.setState("state");
Environment e2 = new Environment("app", "dev");
e2.add(p2);
e2.setVersion("2");
e2.setState("state2");
SearchPathLocator.Locations loc1 = new SearchPathLocator.Locations("app", "dev", "label", "version",
new String[] { sLoc1 });
SearchPathLocator.Locations loc2 = new SearchPathLocator.Locations("app", "dev", "label", "version",
new String[] { sLoc1, sLoc2 });
List<EnvironmentRepository> repos = new ArrayList<EnvironmentRepository>();
repos.add(new TestOrderedEnvironmentRepository(2, e1, loc1));
repos.add(new TestFailingEnvironmentRepository(1, e2, loc2));
SearchPathCompositeEnvironmentRepository compositeRepo = new SearchPathCompositeEnvironmentRepository(repos,
false);
Environment env = compositeRepo.findOne("app", "dev", "label", false);
List<PropertySource> propertySources = env.getPropertySources();
assertThat(propertySources.size()).isEqualTo(1);
assertThat(propertySources.get(0).getName()).isEqualTo("p1");
}
private static class TestOrderedEnvironmentRepository implements EnvironmentRepository, SearchPathLocator, Ordered {
private Environment env;
@@ -184,15 +214,32 @@ public class CompositeEnvironmentRepositoryTests {
}
private static class TestFailingEnvironmentRepository extends TestOrderedEnvironmentRepository {
TestFailingEnvironmentRepository(int order, Environment env, Locations locations) {
super(order, env, locations);
}
@Override
public Environment findOne(String application, String profile, String label, boolean includeOrigin) {
throw new IllegalArgumentException("Failing for some reason");
}
@Override
public Environment findOne(String application, String profile, String label) {
throw new IllegalArgumentException("Failing for some reason");
}
}
@Configuration(proxyBeanMethods = false)
static class OverrideCompositeConfig {
@Bean
@Primary
CompositeEnvironmentRepository customCompositeEnvironmentRepository() {
return new CompositeEnvironmentRepository(Arrays
.<EnvironmentRepository>asList(new TestOrderedEnvironmentRepository(1,
new Environment("app", "dev"), null)));
return new CompositeEnvironmentRepository(Arrays.<EnvironmentRepository>asList(
new TestOrderedEnvironmentRepository(1, new Environment("app", "dev"), null)), true);
}
}