Add property to reverse location order. Fixes #1910 (#2239)

Co-authored-by: Ryan Baxter <524254+ryanjbaxter@users.noreply.github.com>
This commit is contained in:
Ryan Baxter
2023-03-09 10:59:41 -05:00
committed by Ryan Baxter
parent 4440775661
commit 8478a5263f
4 changed files with 87 additions and 3 deletions

View File

@@ -95,6 +95,14 @@ public class ConfigServerProperties {
*/
private boolean failOnCompositeError = true;
/**
* By default the location order we use in GenericResourceRepository is the order in
* which they are listed. Prior to Hoxton.SR11 the order used to be reverse. If this
* property is set to true then we will reverse ther order like it used to be prior to
* Hoxton.SR11.
*/
private boolean reverseLocationOrder = false;
/**
* Decryption configuration for when server handles encrypted properties before
* sending them to clients.
@@ -185,13 +193,22 @@ public class ConfigServerProperties {
this.failOnCompositeError = failOnCompositeError;
}
public boolean isReverseLocationOrder() {
return reverseLocationOrder;
}
public void setReverseLocationOrder(boolean reverseLocationOrder) {
this.reverseLocationOrder = reverseLocationOrder;
}
@Override
public String toString() {
return new ToStringCreator(this).append("enabled", enabled).append("bootstrap", bootstrap)
.append("prefix", prefix).append("defaultLabel", defaultLabel).append("overrides", overrides)
.append("stripDocumentFromYaml", stripDocumentFromYaml).append("acceptEmpty", acceptEmpty)
.append("defaultApplicationName", defaultApplicationName).append("defaultProfile", defaultProfile)
.append("failOnCompositeError", failOnCompositeError).append("encrypt", encrypt).toString();
.append("failOnCompositeError", failOnCompositeError).append("encrypt", encrypt)
.append("reverseLocationOrder", reverseLocationOrder).toString();
}

View File

@@ -34,8 +34,8 @@ public class ResourceRepositoryConfiguration {
@Bean
@ConditionalOnBean(SearchPathLocator.class)
public ResourceRepository resourceRepository(SearchPathLocator service) {
return new GenericResourceRepository(service);
public ResourceRepository resourceRepository(SearchPathLocator service, ConfigServerProperties properties) {
return new GenericResourceRepository(service, properties);
}
}

View File

@@ -18,15 +18,19 @@ package org.springframework.cloud.config.server.resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import org.springframework.cloud.config.server.config.ConfigServerProperties;
import org.springframework.cloud.config.server.environment.SearchPathLocator;
import org.springframework.cloud.config.server.support.PathUtils;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/**
@@ -40,10 +44,17 @@ public class GenericResourceRepository implements ResourceRepository, ResourceLo
private SearchPathLocator service;
private ConfigServerProperties properties;
public GenericResourceRepository(SearchPathLocator service) {
this.service = service;
}
public GenericResourceRepository(SearchPathLocator service, ConfigServerProperties properties) {
this(service);
this.properties = properties;
}
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
@@ -54,6 +65,9 @@ public class GenericResourceRepository implements ResourceRepository, ResourceLo
if (StringUtils.hasText(path)) {
String[] locations = this.service.getLocations(application, profile, label).getLocations();
if (!ObjectUtils.isEmpty(properties) && properties.isReverseLocationOrder()) {
Collections.reverse(Arrays.asList(locations));
}
ArrayList<Resource> locationResources = new ArrayList<>();
for (String location : locations) {
if (!PathUtils.isInvalidEncodedLocation(location)) {

View File

@@ -94,6 +94,59 @@ public class CompositeIntegrationTests {
}
@RunWith(SpringRunner.class)
@SpringBootTest(classes = TestConfigServerApplication.class,
properties = { "spring.config.name:compositeconfigserver",
"spring.cloud.config.server.svn.uri:file:///./target/repos/svn-config-repo",
"spring.cloud.config.server.svn.order:2",
"spring.cloud.config.server.git.uri:file:./target/repos/config-repo",
"spring.cloud.config.server.git.order:1", "spring.cloud.config.server.reverseLocationOrder:true" },
webEnvironment = RANDOM_PORT)
@ActiveProfiles({ "test", "git", "subversion" })
public static class ReverseLocationOrderTest {
@LocalServerPort
private int port;
@BeforeClass
public static void init() throws Exception {
// mock Git configuration to make tests independent of local Git configuration
SystemReader.setInstance(new MockSystemReader());
ConfigServerTestUtils.prepareLocalRepo();
ConfigServerTestUtils.prepareLocalSvnRepo("src/test/resources/svn-config-repo",
"target/repos/svn-config-repo");
}
@Test
public void contextLoads() {
ResponseEntity<Environment> response = new TestRestTemplate().exchange(
"http://localhost:" + this.port + "/foo/development/", HttpMethod.GET, getV2AcceptEntity(),
Environment.class);
Environment environment = response.getBody();
assertThat(3).isEqualTo(environment.getPropertySources().size());
assertThat("overrides").isEqualTo(environment.getPropertySources().get(0).getName());
assertThat(environment.getPropertySources().get(1).getName().contains("config-repo")
&& !environment.getPropertySources().get(1).getName().contains("svn-config-repo")).isTrue();
assertThat(environment.getPropertySources().get(2).getName().contains("svn-config-repo")).isTrue();
ConfigServerTestUtils.assertConfigEnabled(environment);
}
@Test
public void resourceEndpointsWork() {
// This request will get the file from the Git Repo because its order is first
// However since spring.cloud.config.server.reverseLocationOrder is true, the
// SVN repo
// will be searched first and return the file from that repo
String text = new TestRestTemplate().getForObject(
"http://localhost:" + this.port + "/foo/development/composite/bar.properties", String.class);
String expected = "foo: bar";
assertThat(expected).isEqualTo(text).as("invalid content");
}
}
@RunWith(SpringRunner.class)
@SpringBootTest(classes = TestConfigServerApplication.class,
properties = { "spring.config.name:compositeconfigserver",