diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/config/CompositeConfiguration.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/config/CompositeConfiguration.java index bd1aa753..2e8f362a 100644 --- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/config/CompositeConfiguration.java +++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/config/CompositeConfiguration.java @@ -39,18 +39,20 @@ public class CompositeConfiguration { private List 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; + } + } diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/config/ConfigServerProperties.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/config/ConfigServerProperties.java index 309f263d..90b5dc24 100644 --- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/config/ConfigServerProperties.java +++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/config/ConfigServerProperties.java @@ -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. */ diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/config/EnvironmentRepositoryConfiguration.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/config/EnvironmentRepositoryConfiguration.java index b70209bf..96b02c1c 100644 --- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/config/EnvironmentRepositoryConfiguration.java +++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/config/EnvironmentRepositoryConfiguration.java @@ -453,16 +453,17 @@ class CompositeRepositoryConfiguration { @Bean @ConditionalOnSearchPathLocator public SearchPathCompositeEnvironmentRepository searchPathCompositeEnvironmentRepository( - List environmentRepositories) { - return new SearchPathCompositeEnvironmentRepository(environmentRepositories); + List environmentRepositories, ConfigServerProperties properties) { + return new SearchPathCompositeEnvironmentRepository(environmentRepositories, + properties.isFailOnCompositeError()); } @Primary @Bean @ConditionalOnMissingSearchPathLocator public CompositeEnvironmentRepository compositeEnvironmentRepository( - List environmentRepositories) { - return new CompositeEnvironmentRepository(environmentRepositories); + List environmentRepositories, ConfigServerProperties properties) { + return new CompositeEnvironmentRepository(environmentRepositories, properties.isFailOnCompositeError()); } } diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/CompositeEnvironmentRepository.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/CompositeEnvironmentRepository.java index 8bdfc8dd..49dad95e 100644 --- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/CompositeEnvironmentRepository.java +++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/CompositeEnvironmentRepository.java @@ -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 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 environmentRepositories) { + public CompositeEnvironmentRepository(List 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; diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/SearchPathCompositeEnvironmentRepository.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/SearchPathCompositeEnvironmentRepository.java index 2e17c9ec..9bb5b845 100644 --- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/SearchPathCompositeEnvironmentRepository.java +++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/SearchPathCompositeEnvironmentRepository.java @@ -33,9 +33,9 @@ public class SearchPathCompositeEnvironmentRepository * @param environmentRepositories The {@link EnvironmentRepository}s to create this * composite from. */ - public SearchPathCompositeEnvironmentRepository( - List environmentRepositories) { - super(environmentRepositories); + public SearchPathCompositeEnvironmentRepository(List environmentRepositories, + boolean failOnError) { + super(environmentRepositories, failOnError); } @Override diff --git a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/CompositeEnvironmentRepositoryTests.java b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/CompositeEnvironmentRepositoryTests.java index 895274d9..5d0b92a0 100644 --- a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/CompositeEnvironmentRepositoryTests.java +++ b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/CompositeEnvironmentRepositoryTests.java @@ -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 propertySources = compositeEnv.getPropertySources(); assertThat(propertySources.size()).isEqualTo(5); @@ -123,17 +123,16 @@ public class CompositeEnvironmentRepositoryTests { List repos2 = new ArrayList(); 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 repos = new ArrayList(); + 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 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 - .asList(new TestOrderedEnvironmentRepository(1, - new Environment("app", "dev"), null))); + return new CompositeEnvironmentRepository(Arrays.asList( + new TestOrderedEnvironmentRepository(1, new Environment("app", "dev"), null)), true); } }