diff --git a/spring-cloud-config-client/src/main/java/org/springframework/cloud/bootstrap/config/PropertySourceBootstrapConfiguration.java b/spring-cloud-config-client/src/main/java/org/springframework/cloud/bootstrap/config/PropertySourceBootstrapConfiguration.java index 2504e3c6..51e934b1 100644 --- a/spring-cloud-config-client/src/main/java/org/springframework/cloud/bootstrap/config/PropertySourceBootstrapConfiguration.java +++ b/spring-cloud-config-client/src/main/java/org/springframework/cloud/bootstrap/config/PropertySourceBootstrapConfiguration.java @@ -24,6 +24,8 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.bind.PropertySourcesPropertyValues; +import org.springframework.boot.bind.RelaxedDataBinder; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.bootstrap.BootstrapApplicationListener; import org.springframework.cloud.config.client.ConfigClientProperties; @@ -38,13 +40,14 @@ import org.springframework.core.env.CompositePropertySource; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.MutablePropertySources; import org.springframework.core.env.PropertySource; +import org.springframework.core.env.StandardEnvironment; /** * @author Dave Syer * */ @Configuration -@EnableConfigurationProperties +@EnableConfigurationProperties(PropertySourceBootstrapProperties.class) public class PropertySourceBootstrapConfiguration implements ApplicationContextInitializer { @@ -56,8 +59,8 @@ public class PropertySourceBootstrapConfiguration implements @Autowired(required = false) private List propertySourceLocators = new ArrayList<>(); - @Autowired(required = false) - private ConfigClientProperties configClientProperties; + @Autowired + private PropertySourceBootstrapProperties properties; public void setPropertySourceLocators( Collection propertySourceLocators) { @@ -72,15 +75,7 @@ public class PropertySourceBootstrapConfiguration implements boolean empty = true; for (PropertySourceLocator locator : propertySourceLocators) { PropertySource source = null; - try { - source = locator.locate(applicationContext.getEnvironment()); - } - catch (Exception e) { - if (configClientProperties != null && configClientProperties.isFailFast()) { - throw new IllegalStateException("Could not locate PropertySource. The fail fast property is set, failing", e); - } - logger.error("Could not locate PropertySource: " + e.getMessage()); - } + source = locator.locate(applicationContext.getEnvironment()); if (source == null) { continue; } @@ -92,11 +87,32 @@ public class PropertySourceBootstrapConfiguration implements MutablePropertySources propertySources = applicationContext.getEnvironment() .getPropertySources(); if (propertySources.contains(BOOTSTRAP_PROPERTY_SOURCE_NAME)) { - propertySources.replace(BOOTSTRAP_PROPERTY_SOURCE_NAME, composite); - } - else { - propertySources.addFirst(composite); + propertySources.remove(BOOTSTRAP_PROPERTY_SOURCE_NAME); } + insertPropertySources(propertySources, composite); + } + } + + private void insertPropertySources(MutablePropertySources propertySources, + CompositePropertySource composite) { + MutablePropertySources incoming = new MutablePropertySources(); + incoming.addFirst(composite); + PropertySourceBootstrapProperties remoteProperties = new PropertySourceBootstrapProperties(); + new RelaxedDataBinder(remoteProperties, "spring.cloud.config").bind(new PropertySourcesPropertyValues( + incoming)); + if (!remoteProperties.isAllowOverride() + || remoteProperties.isSystemPropertiesOverride()) { + propertySources.addFirst(composite); + return; + } + if (propertySources + .contains(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME)) { + propertySources.addAfter( + StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, + composite); + } + else { + propertySources.addLast(composite); } } diff --git a/spring-cloud-config-client/src/main/java/org/springframework/cloud/bootstrap/config/PropertySourceBootstrapProperties.java b/spring-cloud-config-client/src/main/java/org/springframework/cloud/bootstrap/config/PropertySourceBootstrapProperties.java new file mode 100644 index 00000000..eaf9cfd0 --- /dev/null +++ b/spring-cloud-config-client/src/main/java/org/springframework/cloud/bootstrap/config/PropertySourceBootstrapProperties.java @@ -0,0 +1,37 @@ +package org.springframework.cloud.bootstrap.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties("spring.cloud.config") +public class PropertySourceBootstrapProperties { + + /** + * Flag to indicate that the external properties should override system properties. + * Default true. + */ + private boolean systemPropertiesOverride = true; + + /** + * Flag to indicate that {@link #isSystemPropertiesOverride() + * systemPropertiesOverride} can be used. Set to false to prevent users from changing + * the default accidentally. Default true. + */ + private boolean allowOverride = true; + + public boolean isSystemPropertiesOverride() { + return systemPropertiesOverride; + } + + public void setSystemPropertiesOverride(boolean systemPropertiesOverride) { + this.systemPropertiesOverride = systemPropertiesOverride; + } + + public boolean isAllowOverride() { + return allowOverride; + } + + public void setAllowOverride(boolean allowOverride) { + this.allowOverride = allowOverride; + } + +} diff --git a/spring-cloud-config-client/src/main/java/org/springframework/cloud/config/Environment.java b/spring-cloud-config-client/src/main/java/org/springframework/cloud/config/Environment.java index 13eb5a0e..4c5a1c63 100644 --- a/spring-cloud-config-client/src/main/java/org/springframework/cloud/config/Environment.java +++ b/spring-cloud-config-client/src/main/java/org/springframework/cloud/config/Environment.java @@ -46,6 +46,10 @@ public class Environment { this.propertySources.add(propertySource); } + public void addFirst(PropertySource propertySource) { + this.propertySources.add(0, propertySource); + } + public List getPropertySources() { return propertySources; } diff --git a/spring-cloud-config-client/src/main/java/org/springframework/cloud/config/client/ConfigClientProperties.java b/spring-cloud-config-client/src/main/java/org/springframework/cloud/config/client/ConfigClientProperties.java index b1f0853e..548930f6 100644 --- a/spring-cloud-config-client/src/main/java/org/springframework/cloud/config/client/ConfigClientProperties.java +++ b/spring-cloud-config-client/src/main/java/org/springframework/cloud/config/client/ConfigClientProperties.java @@ -35,9 +35,15 @@ public class ConfigClientProperties { public static final String PREFIX = "spring.cloud.config"; + /** + * Flag to say that remote configuration is enabled. Default true; + */ private boolean enabled = true; - private String env = "default"; + /** + * The default profile to use when fetching remote configuration (comma-separated). Default is "default". + */ + private String profile = "default"; @Value("${spring.application.name:'application'}") private String name; @@ -53,7 +59,7 @@ public class ConfigClientProperties { private Discovery discovery = new Discovery(); private boolean failFast = false; - + private ConfigClientProperties() { } @@ -62,7 +68,7 @@ public class ConfigClientProperties { if (profiles.length == 0) { profiles = environment.getDefaultProfiles(); } - this.setEnv(StringUtils.arrayToCommaDelimitedString(profiles)); + this.setProfile(StringUtils.arrayToCommaDelimitedString(profiles)); } public boolean isEnabled() { @@ -89,12 +95,12 @@ public class ConfigClientProperties { this.name = name; } - public String getEnv() { - return env; + public String getProfile() { + return profile; } - public void setEnv(String env) { - this.env = env; + public void setProfile(String env) { + this.profile = env; } public String getLabel() { @@ -214,8 +220,8 @@ public class ConfigClientProperties { override.setName(environment.resolvePlaceholders("${" + ConfigClientProperties.PREFIX + ".name:${spring.application.name:'application'}}")); - if (environment.containsProperty(ConfigClientProperties.PREFIX + ".env")) { - override.setEnv(environment.getProperty(ConfigClientProperties.PREFIX + ".env")); + if (environment.containsProperty(ConfigClientProperties.PREFIX + ".profile")) { + override.setProfile(environment.getProperty(ConfigClientProperties.PREFIX + ".profile")); } if (environment.containsProperty(ConfigClientProperties.PREFIX + ".label")) { override.setLabel(environment.getProperty(ConfigClientProperties.PREFIX + ".label")); @@ -225,7 +231,7 @@ public class ConfigClientProperties { @Override public String toString() { - return "ConfigClientProperties [name=" + name + ", env=" + env + ", label=" + return "ConfigClientProperties [name=" + name + ", env=" + profile + ", label=" + label + ", uri=" + uri + ", discovery.enabled=" + discovery.enabled + ", failFast="+ failFast + "]"; } diff --git a/spring-cloud-config-client/src/main/java/org/springframework/cloud/config/client/ConfigServicePropertySourceLocator.java b/spring-cloud-config-client/src/main/java/org/springframework/cloud/config/client/ConfigServicePropertySourceLocator.java index 3df33c11..94851342 100644 --- a/spring-cloud-config-client/src/main/java/org/springframework/cloud/config/client/ConfigServicePropertySourceLocator.java +++ b/spring-cloud-config-client/src/main/java/org/springframework/cloud/config/client/ConfigServicePropertySourceLocator.java @@ -20,6 +20,8 @@ import java.io.IOException; import java.util.Arrays; import java.util.Map; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.springframework.cloud.config.Environment; import org.springframework.cloud.config.PropertySource; import org.springframework.core.annotation.Order; @@ -41,6 +43,9 @@ import org.springframework.web.client.RestTemplate; @Order(0) public class ConfigServicePropertySourceLocator implements PropertySourceLocator { + private static Log logger = LogFactory + .getLog(ConfigServicePropertySourceLocator.class); + private RestTemplate restTemplate; private ConfigClientProperties defaults; @@ -55,16 +60,28 @@ public class ConfigServicePropertySourceLocator implements PropertySourceLocator CompositePropertySource composite = new CompositePropertySource("configService"); RestTemplate restTemplate = this.restTemplate == null ? getSecureRestTemplate(client) : this.restTemplate; - Environment result = restTemplate.exchange( - client.getUri() + "/{name}/{env}/{label}", HttpMethod.GET, - new HttpEntity((Void) null), Environment.class, client.getName(), - client.getEnv(), client.getLabel()).getBody(); - for (PropertySource source : result.getPropertySources()) { - @SuppressWarnings("unchecked") - Map map = (Map) source.getSource(); - composite.addPropertySource(new MapPropertySource(source.getName(), map)); + try { + Environment result = restTemplate.exchange( + client.getUri() + "/{name}/{profile}/{label}", HttpMethod.GET, + new HttpEntity((Void) null), Environment.class, + client.getName(), client.getProfile(), client.getLabel()).getBody(); + for (PropertySource source : result.getPropertySources()) { + @SuppressWarnings("unchecked") + Map map = (Map) source.getSource(); + composite.addPropertySource(new MapPropertySource(source.getName(), map)); + } + return composite; } - return composite; + catch (Exception e) { + if (client != null && client.isFailFast()) { + throw new IllegalStateException( + "Could not locate PropertySource. The fail fast property is set, failing", + e); + } + logger.error("Could not locate PropertySource: " + e.getMessage()); + return null; + } + } public void setRestTemplate(RestTemplate restTemplate) { diff --git a/spring-cloud-config-client/src/main/java/org/springframework/cloud/config/client/PropertySourceLocator.java b/spring-cloud-config-client/src/main/java/org/springframework/cloud/config/client/PropertySourceLocator.java index 6fd62ccf..a04be177 100644 --- a/spring-cloud-config-client/src/main/java/org/springframework/cloud/config/client/PropertySourceLocator.java +++ b/spring-cloud-config-client/src/main/java/org/springframework/cloud/config/client/PropertySourceLocator.java @@ -18,13 +18,22 @@ package org.springframework.cloud.config.client; import org.springframework.core.env.Environment; import org.springframework.core.env.PropertySource; - /** + * Strategy for locating (possibly remote) property sources for the Environment. + * Implementations should not fail unless they intend to prevent the application from + * starting. + * * @author Dave Syer * */ public interface PropertySourceLocator { + /** + * @param environment the current Environment + * @return a PropertySource or null if there is none + * + * @throws IllegalStateException if there is a fail fast condition + */ PropertySource locate(Environment environment); } diff --git a/spring-cloud-config-client/src/test/java/org/springframework/cloud/bootstrap/BootstrapConfigurationTests.java b/spring-cloud-config-client/src/test/java/org/springframework/cloud/bootstrap/config/BootstrapConfigurationTests.java similarity index 76% rename from spring-cloud-config-client/src/test/java/org/springframework/cloud/bootstrap/BootstrapConfigurationTests.java rename to spring-cloud-config-client/src/test/java/org/springframework/cloud/bootstrap/config/BootstrapConfigurationTests.java index 7114afc6..1fbbb435 100644 --- a/spring-cloud-config-client/src/test/java/org/springframework/cloud/bootstrap/BootstrapConfigurationTests.java +++ b/spring-cloud-config-client/src/test/java/org/springframework/cloud/bootstrap/config/BootstrapConfigurationTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.cloud.bootstrap; +package org.springframework.cloud.bootstrap.config; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -24,6 +24,8 @@ import static org.junit.Assert.assertTrue; import java.io.File; import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import org.junit.After; import org.junit.Test; @@ -51,7 +53,11 @@ public class BootstrapConfigurationTests { @After public void close() { + // Expected.* is bound to the PropertySourceConfiguration below System.clearProperty("expected.name"); + // Used to test system properties override + System.clearProperty("bootstrap.foo"); + PropertySourceConfiguration.MAP.clear(); if (context != null) { context.close(); } @@ -61,26 +67,32 @@ public class BootstrapConfigurationTests { public void pickupExternalBootstrapProperties() { String externalPropertiesPath = getExternalProperties(); - System.setProperty("spring.cloud.bootstrap.location", externalPropertiesPath); context = new SpringApplicationBuilder().web(false) - .sources(BareConfiguration.class).run(); - assertEquals("externalPropertiesInfoName", context.getEnvironment().getProperty("info.name")); + .sources(BareConfiguration.class) + .properties("spring.cloud.bootstrap.location:" + externalPropertiesPath) + .run(); + assertEquals("externalPropertiesInfoName", + context.getEnvironment().getProperty("info.name")); assertTrue(context.getEnvironment().getPropertySources().contains("bootstrap")); assertNotNull(context.getBean(ConfigClientProperties.class)); } /** - * Running the test from maven will start from a different directory then starting it from intellij + * Running the test from maven will start from a different directory then starting it + * from intellij * * @return */ private String getExternalProperties() { String externalPropertiesPath = ""; - File externalProperties = new File("src/test/external-properties/bootstrap.properties"); + File externalProperties = new File( + "src/test/resources/external-properties/bootstrap.properties"); if (externalProperties.exists()) { externalPropertiesPath = externalProperties.getAbsolutePath(); - } else { - externalProperties = new File("spring-cloud-config-client/src/test/external-properties/bootstrap.properties"); + } + else { + externalProperties = new File( + "spring-cloud-config-client/src/test/resources/external-properties/bootstrap.properties"); externalPropertiesPath = externalProperties.getAbsolutePath(); } return externalPropertiesPath; @@ -88,6 +100,7 @@ public class BootstrapConfigurationTests { @Test public void picksUpAdditionalPropertySource() { + PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar"); System.setProperty("expected.name", "bootstrap"); context = new SpringApplicationBuilder().web(false) .sources(BareConfiguration.class).run(); @@ -96,6 +109,41 @@ public class BootstrapConfigurationTests { assertNotNull(context.getBean(ConfigClientProperties.class)); } + @Test + public void overrideSystemPropertySourceByDefault() { + PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar"); + System.setProperty("bootstrap.foo", "system"); + context = new SpringApplicationBuilder().web(false) + .sources(BareConfiguration.class).run(); + assertEquals("bar", context.getEnvironment().getProperty("bootstrap.foo")); + } + + @Test + public void systemPropertyOverrideFalse() { + PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar"); + PropertySourceConfiguration.MAP.put( + "spring.cloud.config.systemPropertiesOverride", "false"); + System.setProperty("bootstrap.foo", "system"); + context = new SpringApplicationBuilder().web(false) + .sources(BareConfiguration.class).run(); + assertEquals("system", context.getEnvironment().getProperty("bootstrap.foo")); + } + + @Test + public void systemPropertyOverrideWhenOverrideDisallowed() { + PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar"); + PropertySourceConfiguration.MAP.put( + "spring.cloud.config.systemPropertiesOverride", "false"); + // If spring.cloud.config.allowOverride=false is in the remote property sources + // with sufficiently high priority it always wins. Admins can enforce it by adding + // their own remote property source. + PropertySourceConfiguration.MAP.put("spring.cloud.config.allowOverride", "false"); + System.setProperty("bootstrap.foo", "system"); + context = new SpringApplicationBuilder().web(false) + .sources(BareConfiguration.class).run(); + assertEquals("bar", context.getEnvironment().getProperty("bootstrap.foo")); + } + @Test public void applicationNameInBootstrapAndMain() { System.setProperty("expected.name", "main"); @@ -158,6 +206,7 @@ public class BootstrapConfigurationTests { @Test public void environmentEnrichedOnceWhenSharedWithChildContext() { + PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar"); context = new SpringApplicationBuilder().sources(BareConfiguration.class) .environment(new StandardEnvironment()).child(BareConfiguration.class) .web(false).run(); @@ -171,6 +220,7 @@ public class BootstrapConfigurationTests { @Test public void environmentEnrichedInParentContext() { + PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar"); context = new SpringApplicationBuilder().sources(BareConfiguration.class) .child(BareConfiguration.class).web(false).run(); assertEquals("bar", context.getEnvironment().getProperty("bootstrap.foo")); @@ -182,6 +232,7 @@ public class BootstrapConfigurationTests { @Test public void differentProfileInChild() { + PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar"); // Profiles are always merged with the child ConfigurableApplicationContext parent = new SpringApplicationBuilder() .sources(BareConfiguration.class).profiles("parent").web(false).run(); @@ -217,6 +268,9 @@ public class BootstrapConfigurationTests { // This is added to bootstrap context as a source in bootstrap.properties protected static class PropertySourceConfiguration implements PropertySourceLocator { + public static Map MAP = new HashMap( + Collections. singletonMap("bootstrap.foo", "bar")); + private String name; @Override @@ -224,8 +278,7 @@ public class BootstrapConfigurationTests { if (name != null) { assertEquals(name, environment.getProperty("spring.application.name")); } - return new MapPropertySource("testBootstrap", - Collections. singletonMap("bootstrap.foo", "bar")); + return new MapPropertySource("testBootstrap", MAP); } public String getName() { diff --git a/spring-cloud-config-client/src/test/resources/bootstrap.properties b/spring-cloud-config-client/src/test/resources/bootstrap.properties index 981dfb73..878343cb 100644 --- a/spring-cloud-config-client/src/test/resources/bootstrap.properties +++ b/spring-cloud-config-client/src/test/resources/bootstrap.properties @@ -1,2 +1,2 @@ -spring.main.sources: org.springframework.cloud.bootstrap.BootstrapConfigurationTests.PropertySourceConfiguration +spring.main.sources: org.springframework.cloud.bootstrap.config.BootstrapConfigurationTests.PropertySourceConfiguration info.name: child \ No newline at end of file diff --git a/spring-cloud-config-client/src/test/external-properties/bootstrap.properties b/spring-cloud-config-client/src/test/resources/external-properties/bootstrap.properties similarity index 100% rename from spring-cloud-config-client/src/test/external-properties/bootstrap.properties rename to spring-cloud-config-client/src/test/resources/external-properties/bootstrap.properties diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ConfigServerBootstrapConfiguration.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ConfigServerBootstrapConfiguration.java index a95de220..a1ce1fbf 100644 --- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ConfigServerBootstrapConfiguration.java +++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ConfigServerBootstrapConfiguration.java @@ -46,7 +46,7 @@ public class ConfigServerBootstrapConfiguration { @Bean public EnvironmentRepositoryPropertySourceLocator environmentRepositoryPropertySourceLocator() { return new EnvironmentRepositoryPropertySourceLocator(repository, - client.getName(), client.getEnv(), client.getLabel()); + client.getName(), client.getProfile(), client.getLabel()); } } diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ConfigServerMvcConfiguration.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ConfigServerMvcConfiguration.java index 01aa80f2..8f5db3d5 100644 --- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ConfigServerMvcConfiguration.java +++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ConfigServerMvcConfiguration.java @@ -42,6 +42,7 @@ public class ConfigServerMvcConfiguration { public EnvironmentController environmentController() { EnvironmentController controller = new EnvironmentController(repository, encryptionController()); controller.setDefaultLabel(server.getDefaultLabel()); + controller.setOverrides(server.getOverrides()); return controller; } diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ConfigServerProperties.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ConfigServerProperties.java index d0fc16b8..c1db1de1 100644 --- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ConfigServerProperties.java +++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ConfigServerProperties.java @@ -15,6 +15,9 @@ */ package org.springframework.cloud.config.server; +import java.util.LinkedHashMap; +import java.util.Map; + import org.springframework.boot.context.properties.ConfigurationProperties; /** @@ -28,7 +31,15 @@ public class ConfigServerProperties { private boolean bootstrap; private String prefix; + /** + * Default repository label (defaults to "master") when incoming requests do not have + * a specific label. + */ private String defaultLabel = ConfigServerProperties.MASTER; + /** + * Extra map for a property source to be sent to all clients. + */ + private Map overrides = new LinkedHashMap(); public String getDefaultLabel() { return defaultLabel; } @@ -47,5 +58,11 @@ public class ConfigServerProperties { public void setPrefix(String prefix) { this.prefix = prefix; } + public Map getOverrides() { + return overrides; + } + public void setOverrides(Map overrides) { + this.overrides = overrides; + } } diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/EnvironmentController.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/EnvironmentController.java index 115b4c48..6dae5c09 100644 --- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/EnvironmentController.java +++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/EnvironmentController.java @@ -36,6 +36,8 @@ public class EnvironmentController { private String defaultLabel = ConfigServerProperties.MASTER; + private Map overrides = new LinkedHashMap(); + @Autowired public EnvironmentController(EnvironmentRepository repository, EncryptionController encryption) { @@ -52,7 +54,12 @@ public class EnvironmentController { @RequestMapping("/{name}/{profiles}/{label}") public Environment labelled(@PathVariable String name, @PathVariable String profiles, @PathVariable String label) { - return encryption.decrypt(repository.findOne(name, profiles, label)); + Environment environment = encryption.decrypt(repository.findOne(name, profiles, + label)); + if (!overrides.isEmpty()) { + environment.addFirst(new PropertySource("overrides", overrides)); + } + return environment; } @RequestMapping("/{name}-{profiles}.properties") @@ -65,7 +72,8 @@ public class EnvironmentController { public ResponseEntity labelledProperties(@PathVariable String name, @PathVariable String profiles, @PathVariable String label) throws IOException { if (name.contains("-") || profiles.contains("-")) { - throw new IllegalArgumentException("Properties output not supported for name or profiles containing hyphens"); + throw new IllegalArgumentException( + "Properties output not supported for name or profiles containing hyphens"); } Properties properties = convertToProperties(labelled(name, profiles, label)); return getSuccess(sortLines(properties)); @@ -92,8 +100,8 @@ public class EnvironmentController { } @RequestMapping({ "/{name}-{profiles}.yml", "/{name}-{profiles}.yaml" }) - public ResponseEntity yaml(@PathVariable String name, @PathVariable String profiles) - throws Exception { + public ResponseEntity yaml(@PathVariable String name, + @PathVariable String profiles) throws Exception { return labelledYaml(name, profiles, defaultLabel); } @@ -101,7 +109,8 @@ public class EnvironmentController { public ResponseEntity labelledYaml(@PathVariable String name, @PathVariable String profiles, @PathVariable String label) throws Exception { if (name.contains("-") || profiles.contains("-")) { - throw new IllegalArgumentException("YAML output not supported for name or profiles containing hyphens"); + throw new IllegalArgumentException( + "YAML output not supported for name or profiles containing hyphens"); } LinkedHashMap target = new LinkedHashMap(); PropertiesConfigurationFactory> factory = new PropertiesConfigurationFactory>( @@ -113,7 +122,7 @@ public class EnvironmentController { Map input = factory.getObject(); return getSuccess(new Yaml().dumpAsMap(input)); } - + @ExceptionHandler(IllegalArgumentException.class) public void illegalArgument(HttpServletResponse response) throws IOException { response.sendError(HttpStatus.BAD_REQUEST.value()); @@ -186,7 +195,14 @@ public class EnvironmentController { * @param defaultLabel */ public void setDefaultLabel(String defaultLabel) { - this.defaultLabel = defaultLabel; + this.defaultLabel = defaultLabel; + } + + /** + * @param overrides the overrides to set + */ + public void setOverrides(Map overrides) { + this.overrides = overrides; } } diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/EnvironmentRepository.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/EnvironmentRepository.java index f2c6e451..a60b0984 100644 --- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/EnvironmentRepository.java +++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/EnvironmentRepository.java @@ -24,6 +24,6 @@ import org.springframework.cloud.config.Environment; */ public interface EnvironmentRepository { - Environment findOne(String application, String name, String label); + Environment findOne(String application, String profile, String label); } diff --git a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/ApplicationTests.java b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/ApplicationTests.java index e187df81..08b0cd61 100644 --- a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/ApplicationTests.java +++ b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/ApplicationTests.java @@ -1,5 +1,6 @@ package org.springframework.cloud.config.server; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import java.io.IOException; @@ -35,6 +36,8 @@ public class ApplicationTests { public void contextLoads() { Environment environment = new TestRestTemplate().getForObject("http://localhost:" + port + "/foo/development/", Environment.class); assertFalse(environment.getPropertySources().isEmpty()); + assertEquals("overrides", environment.getPropertySources().get(0).getName()); + assertEquals("{spring.cloud.config.enabled=true}", environment.getPropertySources().get(0).getSource().toString()); } } diff --git a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/EnvironmentControllerTests.java b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/EnvironmentControllerTests.java index 23bc74e7..8743875f 100644 --- a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/EnvironmentControllerTests.java +++ b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/EnvironmentControllerTests.java @@ -17,6 +17,7 @@ package org.springframework.cloud.config.server; import static org.junit.Assert.assertEquals; +import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; @@ -38,7 +39,7 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders; * */ public class EnvironmentControllerTests { - + @Rule public ExpectedException expected = ExpectedException.none(); @@ -120,9 +121,22 @@ public class EnvironmentControllerTests { @Test public void mappingForLabelledYamlWithHyphen() throws Exception { - Mockito.when(repository.findOne("foo", "bar-spam", "other")).thenReturn(environment); + Mockito.when(repository.findOne("foo", "bar-spam", "other")).thenReturn( + environment); MockMvc mvc = MockMvcBuilders.standaloneSetup(controller).build(); mvc.perform(MockMvcRequestBuilders.get("/other/foo-bar-spam.yml")).andExpect( MockMvcResultMatchers.status().isBadRequest()); } + + @Test + public void allowOverrideFalse() throws Exception { + controller.setOverrides(Collections.singletonMap("foo", "bar")); + Map map = new HashMap(); + map.put("a.b.c", "d"); + environment.add(new PropertySource("one", map)); + Mockito.when(repository.findOne("foo", "bar", "master")).thenReturn(environment); + assertEquals("{foo=bar}", controller.master("foo", "bar").getPropertySources() + .get(0).getSource().toString()); + } + } diff --git a/spring-cloud-config-server/src/test/resources/configserver-test.yml b/spring-cloud-config-server/src/test/resources/configserver-test.yml index 5c0101a5..7446b648 100644 --- a/spring-cloud-config-server/src/test/resources/configserver-test.yml +++ b/spring-cloud-config-server/src/test/resources/configserver-test.yml @@ -4,3 +4,8 @@ spring: server: git: basedir: target/config + overrides: + spring: + cloud: + config: + enabled: true \ No newline at end of file