Add version to environment response

Users see it logged by the config client, and it appears in the
Environment response from the config server. It's hard to add it
to the /env endpoint without some extension points in Boot.

Fixes gh-244, fixes gh-245
This commit is contained in:
Spencer Gibb
2015-10-01 12:47:20 -06:00
committed by Dave Syer
parent d4ce149f2d
commit 5ceca18292
15 changed files with 200 additions and 68 deletions

View File

@@ -80,6 +80,11 @@ public class ConfigServicePropertySourceLocator implements PropertySourceLocator
for (String label : labels) {
Environment result = getRemoteEnvironment(restTemplate, client.getRawUri(), client.getName(), client.getProfile(), label.trim());
if (result != null) {
logger.info(String.format("Located environment: name=%s, profiles=%s, label=%s, version=%s",
result.getName(),
result.getProfiles() == null ? "" : Arrays.asList(result.getProfiles()),
result.getLabel(), result.getVersion()));
for (PropertySource source : result.getPropertySources()) {
@SuppressWarnings("unchecked")
Map<String, Object> map = (Map<String, Object>) source

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2014 the original author or authors.
* Copyright 2013-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,8 +27,9 @@ import com.fasterxml.jackson.annotation.JsonProperty;
* Simple plain text serializable encapsulation of a list of property sources. Basically a
* DTO for {@link org.springframework.core.env.Environment}, but also applicable outside
* the domain of a Spring application.
*
*
* @author Dave Syer
* @author Spencer Gibb
*
*/
public class Environment {
@@ -41,18 +42,22 @@ public class Environment {
private List<PropertySource> propertySources = new ArrayList<PropertySource>();
private String version;
public Environment(String name, String... profiles) {
this(name, profiles, "master");
this(name, profiles, "master", null);
}
@JsonCreator
public Environment(@JsonProperty("name") String name,
@JsonProperty("profiles") String[] profiles,
@JsonProperty("label") String label) {
@JsonProperty("label") String label,
@JsonProperty("version") String version) {
super();
this.name = name;
this.profiles = profiles;
this.label = label;
this.version = version;
}
public void add(PropertySource propertySource) {
@@ -70,7 +75,7 @@ public class Environment {
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@@ -78,7 +83,7 @@ public class Environment {
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
@@ -91,10 +96,19 @@ public class Environment {
this.profiles = profiles;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
@Override
public String toString() {
return "Environment [name=" + name + ", profiles=" + Arrays.asList(profiles)
+ ", label=" + label + ", propertySources=" + propertySources + "]";
+ ", label=" + label + ", propertySources=" + propertySources
+ ", version=" + version+ "]";
}
}

View File

@@ -58,7 +58,7 @@ public class CipherEnvironmentEncryptor implements EnvironmentEncryptor {
private Environment decrypt(Environment environment, TextEncryptorLocator encryptor) {
Environment result = new Environment(environment.getName(),
environment.getProfiles(), environment.getLabel());
environment.getProfiles(), environment.getLabel(), environment.getVersion());
for (PropertySource source : environment.getPropertySources()) {
Map<Object, Object> map = new LinkedHashMap<Object, Object>(
source.getSource());

View File

@@ -37,8 +37,10 @@ public abstract class AbstractScmEnvironmentRepository extends AbstractScmAccess
public synchronized Environment findOne(String application, String profile, String label) {
NativeEnvironmentRepository delegate = new NativeEnvironmentRepository(
getEnvironment());
delegate.setSearchLocations(getLocations(application, profile, label));
Locations locations = getLocations(application, profile, label);
delegate.setSearchLocations(locations.getLocations());
Environment result = delegate.findOne(application, profile, "");
result.setVersion(locations.getVersion());
result.setLabel(label);
return this.cleaner.clean(result, getWorkingDirectory().toURI().toString(),
getUri());

View File

@@ -26,7 +26,7 @@ public class EnvironmentCleaner {
public Environment clean(Environment value, String workingDir, String uri) {
Environment result = new Environment(value.getName(), value.getProfiles(),
value.getLabel());
value.getLabel(), value.getVersion());
for (PropertySource source : value.getPropertySources()) {
String name = source.getName().replace(workingDir, "");
name = name.replace("applicationConfig: [", "");

View File

@@ -113,12 +113,16 @@ public class JGitEnvironmentRepository extends AbstractScmEnvironmentRepository
}
@Override
public String[] getLocations(String application, String profile, String label) {
public Locations getLocations(String application, String profile, String label) {
if (label==null) {
label = this.defaultLabel;
}
refresh(application, label);
return getSearchLocations(getWorkingDirectory());
Ref ref = refresh(application, label);
String version = null;
if (ref != null) {
version = ref.getObjectId().getName();
}
return new Locations(application, profile, label, version, getSearchLocations(getWorkingDirectory()));
}
@Override
@@ -133,7 +137,7 @@ public class JGitEnvironmentRepository extends AbstractScmEnvironmentRepository
/**
* Get the working directory ready.
*/
private void refresh(String application, String label) {
private Ref refresh(String application, String label) {
initialize();
Git git = null;
try {
@@ -143,6 +147,7 @@ public class JGitEnvironmentRepository extends AbstractScmEnvironmentRepository
if (shouldPull(git, ref)) {
pull(git, label, ref);
}
return ref;
}
catch (RefNotFoundException e) {
throw new NoSuchLabelException("No such label: " + label);

View File

@@ -80,7 +80,7 @@ public class MultipleJGitEnvironmentRepository extends JGitEnvironmentRepository
}
@Override
public String[] getLocations(String application, String profile, String label) {
public Locations getLocations(String application, String profile, String label) {
for (PatternMatchingJGitEnvironmentRepository repository : this.repos.values()) {
Environment source = repository.findOne(application, profile, label);
if (source != null) {

View File

@@ -65,6 +65,11 @@ public class NativeEnvironmentRepository
*/
private boolean failOnError = false;
/**
* Version string to be reported for native repository
*/
private String version;
private static final String[] DEFAULT_LOCATIONS = new String[] { "classpath:/",
"classpath:/config/", "file:./", "file:./config/" };
@@ -111,7 +116,7 @@ public class NativeEnvironmentRepository
}
@Override
public String[] getLocations(String application, String profile, String label) {
public Locations getLocations(String application, String profile, String label) {
String[] locations = this.searchLocations;
if (this.searchLocations == null) {
locations = DEFAULT_LOCATIONS;
@@ -125,7 +130,7 @@ public class NativeEnvironmentRepository
output.add(location + label.trim() + "/");
}
}
return output.toArray(new String[0]);
return new Locations(application, profile, label, this.version, output.toArray(new String[0]));
}
private ConfigurableEnvironment getEnvironment(String profile) {
@@ -139,7 +144,7 @@ public class NativeEnvironmentRepository
protected Environment clean(Environment value) {
Environment result = new Environment(value.getName(), value.getProfiles(),
value.getLabel());
value.getLabel(), this.version);
for (PropertySource source : value.getPropertySources()) {
String name = source.getName();
if (this.environment.getPropertySources().contains(name)) {
@@ -155,7 +160,7 @@ public class NativeEnvironmentRepository
.cleanPath(new File(normal.substring("file:".length()))
.getAbsolutePath());
}
for (String pattern : getLocations(null, null, result.getLabel())) {
for (String pattern : getLocations(null, null, result.getLabel()).getLocations()) {
if (!pattern.contains(":")) {
pattern = "file:" + pattern;
}
@@ -197,7 +202,7 @@ public class NativeEnvironmentRepository
list.add("--spring.config.name=" + config);
list.add("--spring.cloud.bootstrap.enabled=false");
list.add("--encrypt.failOnError=" + this.failOnError);
list.add("--spring.config.location=" + StringUtils.arrayToCommaDelimitedString(getLocations(null, null, label)));
list.add("--spring.config.location=" + StringUtils.arrayToCommaDelimitedString(getLocations(null, null, label).getLocations()));
return list.toArray(new String[0]);
}
@@ -216,6 +221,14 @@ public class NativeEnvironmentRepository
}
}
public String getVersion() {
return this.version;
}
public void setVersion(String version) {
this.version = version;
}
private boolean isDirectory(String location) {
return !location.endsWith(".properties") && !location.endsWith(".yml")
&& !location.endsWith(".yaml");

View File

@@ -60,7 +60,7 @@ public class PassthruEnvironmentRepository implements EnvironmentRepository {
@Override
public Environment findOne(String application, String env, String label) {
Environment result = new Environment(application, StringUtils.commaDelimitedListToStringArray(env), label);
Environment result = new Environment(application, StringUtils.commaDelimitedListToStringArray(env), label, null);
for (org.springframework.core.env.PropertySource<?> source : this.environment.getPropertySources()) {
String name = source.getName();
if (!this.standardSources.contains(name) && source instanceof MapPropertySource) {

View File

@@ -16,6 +16,8 @@
package org.springframework.cloud.config.server.environment;
import java.util.Arrays;
/**
* Strategy for locating a search path for resource (e.g. in the file system or
* classpath).
@@ -25,6 +27,49 @@ package org.springframework.cloud.config.server.environment;
*/
public interface SearchPathLocator {
String[] getLocations(String application, String profile, String label);
Locations getLocations(String application, String profile, String label);
class Locations {
private final String application;
private final String profile;
private final String label;
private final String[] locations;
private final String version;
public Locations(String application, String profile, String label, String version, String[] locations) {
this.application = application;
this.profile = profile;
this.label = label;
this.locations = locations;
this.version = version;
}
public String[] getLocations() {
return locations;
}
public String getVersion() {
return version;
}
public String getApplication() {
return application;
}
public String getProfile() {
return profile;
}
public String getLabel() {
return label;
}
@Override
public String toString() {
return "Locations [application=" + application + ", profile=" + profile
+ ", label=" + label + ", locations=" + Arrays.toString(locations)
+ ", version=" + version + "]";
}
}
}

View File

@@ -59,7 +59,7 @@ public class SvnKitEnvironmentRepository extends AbstractScmEnvironmentRepositor
}
@Override
public String[] getLocations(String application, String profile, String label) {
public Locations getLocations(String application, String profile, String label) {
if (label==null) {
label = this.defaultLabel;
}
@@ -70,13 +70,14 @@ public class SvnKitEnvironmentRepository extends AbstractScmEnvironmentRepositor
false, getUsername(), getPassword()));
}
try {
String version;
if (new File(getWorkingDirectory(), ".svn").exists()) {
update(svnOperationFactory);
version = update(svnOperationFactory);
}
else {
checkout(svnOperationFactory);
version = checkout(svnOperationFactory);
}
return getLocations(label);
return new Locations(application, profile, label, version, getLocations(label));
}
catch (SVNException e) {
throw new IllegalStateException("Cannot checkout repository", e);
@@ -104,20 +105,32 @@ public class SvnKitEnvironmentRepository extends AbstractScmEnvironmentRepositor
return locations;
}
private void checkout(SvnOperationFactory svnOperationFactory) throws SVNException {
private String checkout(SvnOperationFactory svnOperationFactory) throws SVNException {
logger.debug("Checking out " + getUri() + " to: "
+ getWorkingDirectory().getAbsolutePath());
final SvnCheckout checkout = svnOperationFactory.createCheckout();
checkout.setSource(SvnTarget.fromURL(SVNURL.parseURIEncoded(getUri())));
checkout.setSingleTarget(SvnTarget.fromFile(getWorkingDirectory()));
checkout.run();
Long id = checkout.run();
if (id == null) {
return null;
}
return id.toString();
}
private void update(SvnOperationFactory svnOperationFactory) throws SVNException {
private String update(SvnOperationFactory svnOperationFactory) throws SVNException {
logger.debug("Repo already checked out - updating instead.");
final SvnUpdate update = svnOperationFactory.createUpdate();
update.setSingleTarget(SvnTarget.fromFile(getWorkingDirectory()));
update.run();
long[] ids = update.run();
StringBuilder version = new StringBuilder();
for (long id : ids) {
if (version.length() > 0) {
version.append(",");
}
version.append(id);
}
return version.toString();
}
@Override

View File

@@ -51,7 +51,7 @@ public class GenericResourceRepository
@Override
public synchronized Resource findOne(String application, String profile, String label,
String path) {
String[] locations = this.service.getLocations(application, "default", label);
String[] locations = this.service.getLocations(application, "default", label).getLocations();
try {
for (int i = locations.length; i-- > 0;) {
String location = locations[i];

View File

@@ -17,6 +17,8 @@
package org.springframework.cloud.config.server.environment;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
@@ -34,7 +36,6 @@ import org.eclipse.jgit.util.FileUtils;
import org.junit.Before;
import org.junit.Test;
import org.springframework.cloud.config.environment.Environment;
import org.springframework.cloud.config.server.environment.JGitEnvironmentRepository;
import org.springframework.cloud.config.server.test.ConfigServerTestUtils;
import org.springframework.core.env.StandardEnvironment;
@@ -64,8 +65,9 @@ public class JGitEnvironmentRepositoryTests {
this.repository.findOne("bar", "staging", "master");
Environment environment = this.repository.findOne("bar", "staging", "master");
assertEquals(2, environment.getPropertySources().size());
assertEquals(this.repository.getUri() + "/bar.properties", environment
.getPropertySources().get(0).getName());
assertEquals(this.repository.getUri() + "/bar.properties",
environment.getPropertySources().get(0).getName());
assertVersion(environment);
}
@Test
@@ -76,8 +78,15 @@ public class JGitEnvironmentRepositoryTests {
this.repository.findOne("bar", "staging", "master");
Environment environment = this.repository.findOne("bar", "staging", "master");
assertEquals(2, environment.getPropertySources().size());
assertEquals(this.repository.getUri() + "/sub/application.yml", environment
.getPropertySources().get(0).getName());
assertEquals(this.repository.getUri() + "/sub/application.yml",
environment.getPropertySources().get(0).getName());
assertVersion(environment);
}
private void assertVersion(Environment environment) {
String version = environment.getVersion();
assertNotNull("version was null", version);
assertTrue("version length was wrong", version.length() >= 40 && version.length() <= 64);
}
@Test
@@ -88,8 +97,9 @@ public class JGitEnvironmentRepositoryTests {
this.repository.findOne("bar", "staging", "master");
Environment environment = this.repository.findOne("bar", "staging", "master");
assertEquals(2, environment.getPropertySources().size());
assertEquals(this.repository.getUri() + "/sub/application.yml", environment
.getPropertySources().get(0).getName());
assertEquals(this.repository.getUri() + "/sub/application.yml",
environment.getPropertySources().get(0).getName());
assertVersion(environment);
}
@Test
@@ -97,8 +107,9 @@ public class JGitEnvironmentRepositoryTests {
this.repository.setBasedir(this.basedir);
Environment environment = this.repository.findOne("bar", "staging", "raw");
assertEquals(2, environment.getPropertySources().size());
assertEquals(this.repository.getUri() + "/bar.properties", environment
.getPropertySources().get(0).getName());
assertEquals(this.repository.getUri() + "/bar.properties",
environment.getPropertySources().get(0).getName());
assertVersion(environment);
}
@Test
@@ -108,6 +119,8 @@ public class JGitEnvironmentRepositoryTests {
assertEquals(2, environment.getPropertySources().size());
assertEquals(this.repository.getUri() + "/bar.properties", environment
.getPropertySources().get(0).getName());
//TODO: why is the version null in tag?
assertNull("version was not null", environment.getVersion());
}
@Test
@@ -116,8 +129,9 @@ public class JGitEnvironmentRepositoryTests {
this.repository.findOne("bar", "staging", "master");
Environment environment = this.repository.findOne("bar", "staging", "master");
assertEquals(2, environment.getPropertySources().size());
assertEquals(this.repository.getUri() + "/bar.properties", environment
.getPropertySources().get(0).getName());
assertEquals(this.repository.getUri() + "/bar.properties",
environment.getPropertySources().get(0).getName());
assertVersion(environment);
}
@Test
@@ -128,8 +142,9 @@ public class JGitEnvironmentRepositoryTests {
this.repository.findOne("bar", "staging", "master");
Environment environment = this.repository.findOne("bar", "staging", "master");
assertEquals(2, environment.getPropertySources().size());
assertEquals(this.repository.getUri() + "/bar.properties", environment
.getPropertySources().get(0).getName());
assertEquals(this.repository.getUri() + "/bar.properties",
environment.getPropertySources().get(0).getName());
assertVersion(environment);
}
@Test

View File

@@ -16,6 +16,9 @@
package org.springframework.cloud.config.server.environment;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.util.HashMap;
@@ -24,14 +27,15 @@ import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.springframework.cloud.config.environment.Environment;
import org.springframework.cloud.config.server.environment.MultipleJGitEnvironmentRepository;
import org.springframework.cloud.config.server.environment.MultipleJGitEnvironmentRepository.PatternMatchingJGitEnvironmentRepository;
import org.springframework.cloud.config.server.test.ConfigServerTestUtils;
import org.springframework.cloud.config.server.environment.MultipleJGitEnvironmentRepository.PatternMatchingJGitEnvironmentRepository;
import org.springframework.core.env.StandardEnvironment;
/**
*
* @author Andy Chan (iceycake)
* @author Dave Syer
* @author Spencer Gibb
*
*/
public class MultipleJGitEnvironmentRepositoryTests {
@@ -42,20 +46,18 @@ public class MultipleJGitEnvironmentRepositoryTests {
@Before
public void init() throws Exception {
String defaultUri = ConfigServerTestUtils.prepareLocalRepo("config-repo");
repository.setUri(defaultUri);
repository.setRepos(createRepositories());
}
private Map<String, PatternMatchingJGitEnvironmentRepository> createRepositories() throws Exception {
String test1Uri = ConfigServerTestUtils.prepareLocalRepo("test1-config-repo");
Map<String, PatternMatchingJGitEnvironmentRepository> repos = new HashMap<String, PatternMatchingJGitEnvironmentRepository>();
Map<String, PatternMatchingJGitEnvironmentRepository> repos = new HashMap<>();
repos.put("test1", createRepository("test1", "*test1*", test1Uri));
return repos;
}
private PatternMatchingJGitEnvironmentRepository createRepository(String name, String pattern, String uri) {
PatternMatchingJGitEnvironmentRepository repo = new PatternMatchingJGitEnvironmentRepository();
repo.setEnvironment(environment);
@@ -69,9 +71,16 @@ public class MultipleJGitEnvironmentRepositoryTests {
public void defaultRepo() {
Environment environment = repository.findOne("bar", "staging", "master");
assertEquals(2, environment.getPropertySources().size());
assertEquals(repository.getUri() + "/bar.properties", environment
.getPropertySources().get(0).getName());
}
assertEquals(repository.getUri() + "/bar.properties",
environment.getPropertySources().get(0).getName());
assertVersion(environment);
}
private void assertVersion(Environment environment) {
String version = environment.getVersion();
assertNotNull("version was null", version);
assertTrue("version length was wrong", version.length() >= 40 && version.length() <= 64);
}
@Test
public void defaultRepoNested() throws IOException {
@@ -81,16 +90,18 @@ public class MultipleJGitEnvironmentRepositoryTests {
repository.findOne("bar", "staging", "master");
Environment environment = repository.findOne("bar", "staging", "master");
assertEquals(2, environment.getPropertySources().size());
assertEquals(repository.getUri() + "/sub/application.yml", environment
.getPropertySources().get(0).getName());
assertEquals(repository.getUri() + "/sub/application.yml",
environment.getPropertySources().get(0).getName());
assertVersion(environment);
}
@Test
public void defaultRepoBranch() {
Environment environment = repository.findOne("bar", "staging", "raw");
assertEquals(2, environment.getPropertySources().size());
assertEquals(repository.getUri() + "/bar.properties", environment
.getPropertySources().get(0).getName());
assertEquals(repository.getUri() + "/bar.properties",
environment.getPropertySources().get(0).getName());
assertVersion(environment);
}
@Test
@@ -99,6 +110,7 @@ public class MultipleJGitEnvironmentRepositoryTests {
assertEquals(2, environment.getPropertySources().size());
assertEquals(repository.getUri() + "/bar.properties", environment
.getPropertySources().get(0).getName());
assertNull("version was not null", environment.getVersion());
}
@Test
@@ -106,23 +118,25 @@ public class MultipleJGitEnvironmentRepositoryTests {
repository.findOne("bar", "staging", "master");
Environment environment = repository.findOne("bar", "staging", "master");
assertEquals(2, environment.getPropertySources().size());
assertEquals(repository.getUri() + "/bar.properties", environment
.getPropertySources().get(0).getName());
assertEquals(repository.getUri() + "/bar.properties",
environment.getPropertySources().get(0).getName());
assertVersion(environment);
}
@Test
public void mappingRepo() {
Environment environment = repository.findOne("test1-svc", "staging", "master");
assertEquals(2, environment.getPropertySources().size());
assertEquals(getUri("*test1*") + "/test1-svc.properties", environment
.getPropertySources().get(0).getName());
}
assertEquals(getUri("*test1*") + "/test1-svc.properties",
environment.getPropertySources().get(0).getName());
assertVersion(environment);
}
private String getUri(String pattern) {
String uri = null;
Map<String, PatternMatchingJGitEnvironmentRepository> repoMappings = repository.getRepos();
for (PatternMatchingJGitEnvironmentRepository repo : repoMappings.values()) {
String[] mappingPattern = repo.getPattern();
if (mappingPattern != null && mappingPattern.length!=0) {
@@ -130,7 +144,7 @@ public class MultipleJGitEnvironmentRepositoryTests {
break;
}
}
return uri;
}
}

View File

@@ -21,11 +21,11 @@ import org.junit.Before;
import org.junit.Test;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.config.environment.Environment;
import org.springframework.cloud.config.server.environment.NativeEnvironmentRepository;
import org.springframework.context.ConfigurableApplicationContext;
/**
* @author Dave Syer
* @author Spencer Gibb
*
*/
public class NativeEnvironmentRepositoryTests {
@@ -37,6 +37,7 @@ public class NativeEnvironmentRepositoryTests {
ConfigurableApplicationContext context = new SpringApplicationBuilder(
NativeEnvironmentRepositoryTests.class).web(false).run();
this.repository = new NativeEnvironmentRepository(context.getEnvironment());
this.repository.setVersion("myversion");
context.close();
}
@@ -44,6 +45,7 @@ public class NativeEnvironmentRepositoryTests {
public void vanilla() {
Environment environment = this.repository.findOne("foo", "development", "master");
assertEquals(2, environment.getPropertySources().size());
assertEquals("version was wrong", "myversion", environment.getVersion());
}
@Test
@@ -51,6 +53,7 @@ public class NativeEnvironmentRepositoryTests {
System.setProperty("spring.profiles.active", "cloud");
Environment environment = this.repository.findOne("foo", "main", "master");
assertEquals(1, environment.getPropertySources().size());
assertEquals("version was wrong", "myversion", environment.getVersion());
}
@Test
@@ -58,6 +61,7 @@ public class NativeEnvironmentRepositoryTests {
this.repository.setSearchLocations("classpath:/test");
Environment environment = this.repository.findOne("foo", "development", "master");
assertEquals(2, environment.getPropertySources().size());
assertEquals("version was wrong", "myversion", environment.getVersion());
}
@Test
@@ -65,6 +69,7 @@ public class NativeEnvironmentRepositoryTests {
this.repository.setSearchLocations("file:./src/test/resources/test");
Environment environment = this.repository.findOne("foo", "development", "master");
assertEquals(2, environment.getPropertySources().size());
assertEquals("version was wrong", "myversion", environment.getVersion());
}
@Test
@@ -76,6 +81,7 @@ public class NativeEnvironmentRepositoryTests {
// foo-development.properties
assertEquals("dev_bar",
environment.getPropertySources().get(1).getSource().get("foo"));
assertEquals("version was wrong", "myversion", environment.getVersion());
}
}