Allow system property override to be switched off
The default behaviour is the same as before, so a config client adds the remote property sources "first" (i.e. ahead of system properties). If the user sets up a remote config repo with spring.cloud.config.overrideSystemProperties=false they can change this behaviour and insert the new property source after systemEnvironment (i.e. before local config files but after the other local sources). Of course using an `application.yml` on the server you can change the default for all applications. There is also a new feature in the config server where the operator can add a map of override properties in spring.cloud.config.server.overrides.* and have them added with highest priority in the Environment returned from the server. Using that the operator can prevent config repositories from changing the override behaviour by setting spring.cloud.config.allowOverride=false. Fixes gh-57
This commit is contained in:
@@ -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<ConfigurableApplicationContext> {
|
||||
|
||||
@@ -56,8 +59,8 @@ public class PropertySourceBootstrapConfiguration implements
|
||||
@Autowired(required = false)
|
||||
private List<PropertySourceLocator> propertySourceLocators = new ArrayList<>();
|
||||
|
||||
@Autowired(required = false)
|
||||
private ConfigClientProperties configClientProperties;
|
||||
@Autowired
|
||||
private PropertySourceBootstrapProperties properties;
|
||||
|
||||
public void setPropertySourceLocators(
|
||||
Collection<PropertySourceLocator> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -46,6 +46,10 @@ public class Environment {
|
||||
this.propertySources.add(propertySource);
|
||||
}
|
||||
|
||||
public void addFirst(PropertySource propertySource) {
|
||||
this.propertySources.add(0, propertySource);
|
||||
}
|
||||
|
||||
public List<PropertySource> getPropertySources() {
|
||||
return propertySources;
|
||||
}
|
||||
|
||||
@@ -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 + "]";
|
||||
}
|
||||
|
||||
@@ -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>((Void) null), Environment.class, client.getName(),
|
||||
client.getEnv(), client.getLabel()).getBody();
|
||||
for (PropertySource source : result.getPropertySources()) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> map = (Map<String, Object>) source.getSource();
|
||||
composite.addPropertySource(new MapPropertySource(source.getName(), map));
|
||||
try {
|
||||
Environment result = restTemplate.exchange(
|
||||
client.getUri() + "/{name}/{profile}/{label}", HttpMethod.GET,
|
||||
new HttpEntity<Void>((Void) null), Environment.class,
|
||||
client.getName(), client.getProfile(), client.getLabel()).getBody();
|
||||
for (PropertySource source : result.getPropertySources()) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> map = (Map<String, Object>) 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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
@@ -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<String, Object> MAP = new HashMap<String, Object>(
|
||||
Collections.<String, Object> 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.<String, Object> singletonMap("bootstrap.foo", "bar"));
|
||||
return new MapPropertySource("testBootstrap", MAP);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
@@ -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
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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<String, String> overrides = new LinkedHashMap<String, String>();
|
||||
public String getDefaultLabel() {
|
||||
return defaultLabel;
|
||||
}
|
||||
@@ -47,5 +58,11 @@ public class ConfigServerProperties {
|
||||
public void setPrefix(String prefix) {
|
||||
this.prefix = prefix;
|
||||
}
|
||||
public Map<String, String> getOverrides() {
|
||||
return overrides;
|
||||
}
|
||||
public void setOverrides(Map<String, String> overrides) {
|
||||
this.overrides = overrides;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,6 +36,8 @@ public class EnvironmentController {
|
||||
|
||||
private String defaultLabel = ConfigServerProperties.MASTER;
|
||||
|
||||
private Map<String, String> overrides = new LinkedHashMap<String, String>();
|
||||
|
||||
@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<String> 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<String> yaml(@PathVariable String name, @PathVariable String profiles)
|
||||
throws Exception {
|
||||
public ResponseEntity<String> yaml(@PathVariable String name,
|
||||
@PathVariable String profiles) throws Exception {
|
||||
return labelledYaml(name, profiles, defaultLabel);
|
||||
}
|
||||
|
||||
@@ -101,7 +109,8 @@ public class EnvironmentController {
|
||||
public ResponseEntity<String> 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<String, Object> target = new LinkedHashMap<String, Object>();
|
||||
PropertiesConfigurationFactory<Map<String, Object>> factory = new PropertiesConfigurationFactory<Map<String, Object>>(
|
||||
@@ -113,7 +122,7 @@ public class EnvironmentController {
|
||||
Map<String, Object> 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<String, String> overrides) {
|
||||
this.overrides = overrides;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<String, Object> map = new HashMap<String, Object>();
|
||||
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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,3 +4,8 @@ spring:
|
||||
server:
|
||||
git:
|
||||
basedir: target/config
|
||||
overrides:
|
||||
spring:
|
||||
cloud:
|
||||
config:
|
||||
enabled: true
|
||||
Reference in New Issue
Block a user