Merge branch '3.1.x'
This commit is contained in:
@@ -1628,11 +1628,12 @@ server {
|
||||
[[spring-cloud-config-serving-plain-text-aws-s3]]
|
||||
==== AWS S3
|
||||
|
||||
To enable serving plain text for AWS s3, the Config Server application needs to include a dependency on Spring Cloud AWS.
|
||||
To enable serving plain text for AWS s3, the Config Server application needs to include a dependency on `io.awspring.cloud:spring-cloud-aws-context`.
|
||||
For details on how to set up that dependency, see the
|
||||
https://cloud.spring.io/spring-cloud-static/spring-cloud-aws/2.1.3.RELEASE/single/spring-cloud-aws.html#_spring_cloud_aws_maven_dependency_management[Spring Cloud AWS Reference Guide].
|
||||
https://docs.awspring.io/spring-cloud-aws/docs/2.4.3/reference/html/index.html#spring-cloud-aws-maven-dependency-management[Spring Cloud AWS Reference Guide].
|
||||
In addition, when using Spring Cloud AWS with Spring Boot it is useful to include the https://docs.awspring.io/spring-cloud-aws/docs/2.4.3/reference/html/index.html#spring-boot-auto-configuration[auto-configuration dependency].
|
||||
Then you need to configure Spring Cloud AWS, as described in the
|
||||
https://cloud.spring.io/spring-cloud-static/spring-cloud-aws/2.1.3.RELEASE/single/spring-cloud-aws.html#_configuring_credentials[Spring Cloud AWS Reference Guide].
|
||||
https://docs.awspring.io/spring-cloud-aws/docs/2.4.3/reference/html/index.html#configuring-credentials[Spring Cloud AWS Reference Guide].
|
||||
|
||||
==== Decrypting Plain Text
|
||||
|
||||
|
||||
@@ -163,9 +163,16 @@ public class AwsS3EnvironmentRepository implements EnvironmentRepository, Ordere
|
||||
|
||||
@Override
|
||||
public Locations getLocations(String application, String profiles, String label) {
|
||||
String baseLocation = AWS_S3_RESOURCE_SCHEME + bucketName + PATH_SEPARATOR + application;
|
||||
StringBuilder baseLocation = new StringBuilder(AWS_S3_RESOURCE_SCHEME + bucketName + PATH_SEPARATOR);
|
||||
if (!StringUtils.hasText(label) && StringUtils.hasText(serverProperties.getDefaultLabel())) {
|
||||
label = serverProperties.getDefaultLabel();
|
||||
}
|
||||
// both the passed in label and the default label property could be null
|
||||
if (StringUtils.hasText(label)) {
|
||||
baseLocation.append(label);
|
||||
}
|
||||
|
||||
return new Locations(application, profiles, label, null, new String[] { baseLocation });
|
||||
return new Locations(application, profiles, label, null, new String[] { baseLocation.toString() });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.cloud.config.server.environment;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Strategy for locating a search path for resource (e.g. in the file system or
|
||||
@@ -78,6 +79,28 @@ public interface SearchPathLocator {
|
||||
+ ", locations=" + Arrays.toString(this.locations) + ", version=" + this.version + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Locations locations1 = (Locations) o;
|
||||
return getApplication().equals(locations1.getApplication()) && getProfile().equals(locations1.getProfile())
|
||||
&& Objects.equals(getLabel(), locations1.getLabel())
|
||||
&& Arrays.equals(getLocations(), locations1.getLocations())
|
||||
&& Objects.equals(getVersion(), locations1.getVersion());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = Objects.hash(getApplication(), getProfile(), getLabel(), getVersion());
|
||||
result = 31 * result + Arrays.hashCode(getLocations());
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.springframework.cloud.config.server.support;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
@@ -266,7 +267,10 @@ public abstract class PathUtils {
|
||||
return true;
|
||||
}
|
||||
locationPath = (locationPath.endsWith("/") || locationPath.isEmpty() ? locationPath : locationPath + "/");
|
||||
return (resourcePath.startsWith(locationPath) && !isInvalidEncodedPath(resourcePath));
|
||||
String encodedLocationPath = locationPath.endsWith("/")
|
||||
? locationPath.substring(0, locationPath.length() - 1) + URLEncoder.encode("/", "UTF-8") : locationPath;
|
||||
return ((resourcePath.startsWith(locationPath) || resourcePath.startsWith(encodedLocationPath))
|
||||
&& !isInvalidEncodedPath(resourcePath));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -250,11 +250,39 @@ public class AwsS3EnvironmentRepositoryTests {
|
||||
assertThat(repository).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getLocationsTest() {
|
||||
AwsS3EnvironmentRepositoryFactory factory = new AwsS3EnvironmentRepositoryFactory(new ConfigServerProperties());
|
||||
AwsS3EnvironmentProperties properties = new AwsS3EnvironmentProperties();
|
||||
properties.setRegion("us-east-1");
|
||||
properties.setBucket("test");
|
||||
AwsS3EnvironmentRepository repository = factory.build(properties);
|
||||
|
||||
assertThat(repository.getLocations("app", "default", "main")).isEqualTo(
|
||||
new SearchPathLocator.Locations("app", "default", "main", null, new String[] { "s3://test/main" }));
|
||||
|
||||
assertThat(repository.getLocations("app", "default", null)).isEqualTo(
|
||||
new SearchPathLocator.Locations("app", "default", null, null, new String[] { "s3://test/" }));
|
||||
|
||||
assertThat(repository.getLocations("app", "default", ""))
|
||||
.isEqualTo(new SearchPathLocator.Locations("app", "default", "", null, new String[] { "s3://test/" }));
|
||||
|
||||
ConfigServerProperties configServerProperties = new ConfigServerProperties();
|
||||
configServerProperties.setDefaultLabel("defaultlabel");
|
||||
factory = new AwsS3EnvironmentRepositoryFactory(configServerProperties);
|
||||
repository = factory.build(properties);
|
||||
|
||||
assertThat(repository.getLocations("app", "default", null)).isEqualTo(new SearchPathLocator.Locations("app",
|
||||
"default", "defaultlabel", null, new String[] { "s3://test/defaultlabel" }));
|
||||
|
||||
assertThat(repository.getLocations("app", "default", "")).isEqualTo(new SearchPathLocator.Locations("app",
|
||||
"default", "defaultlabel", null, new String[] { "s3://test/defaultlabel" }));
|
||||
}
|
||||
|
||||
private String putFiles(String fileName, String propertyContent) {
|
||||
toBeRemoved.add(fileName);
|
||||
return s3Client.putObject(PutObjectRequest.builder().bucket("bucket1").key(fileName).build(),
|
||||
RequestBody.fromString((propertyContent))).versionId();
|
||||
|
||||
}
|
||||
|
||||
private void assertExpectedEnvironment(Environment env, String applicationName, String label, String versionId,
|
||||
|
||||
@@ -16,23 +16,35 @@
|
||||
|
||||
package org.springframework.cloud.config.server.resource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import software.amazon.awssdk.services.s3.S3Client;
|
||||
|
||||
import org.springframework.boot.WebApplicationType;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.boot.test.system.OutputCaptureRule;
|
||||
import org.springframework.cloud.config.server.config.ConfigServerProperties;
|
||||
import org.springframework.cloud.config.server.environment.AwsS3EnvironmentRepository;
|
||||
import org.springframework.cloud.config.server.environment.NativeEnvironmentProperties;
|
||||
import org.springframework.cloud.config.server.environment.NativeEnvironmentRepository;
|
||||
import org.springframework.cloud.config.server.environment.NativeEnvironmentRepositoryTests;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
@@ -132,4 +144,46 @@ public class GenericResourceRepositoryTests {
|
||||
this.repository.findOne("blah", "local", label, "foo.properties");
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* This test is mocking what happens when using Spring Cloud AWS ProtocolResolver to
|
||||
* server text files from S3 buckets. Rather than put Spring Cloud AWS on the
|
||||
* classpath we just mock the behavior. Specifically we are testing to make sure the
|
||||
* encoding of the / in the path is taken into account in the
|
||||
* GenericResourceRepository.
|
||||
*/
|
||||
public void tests3() throws IOException {
|
||||
S3Client s3 = mock(S3Client.class);
|
||||
AwsS3EnvironmentRepository awsS3EnvironmentRepository = new AwsS3EnvironmentRepository(s3, "test",
|
||||
new ConfigServerProperties());
|
||||
GenericResourceRepository genericResourceRepository = new GenericResourceRepository(awsS3EnvironmentRepository);
|
||||
genericResourceRepository.setResourceLoader(new ResourceLoader() {
|
||||
@Override
|
||||
public Resource getResource(String location) {
|
||||
Resource relativeResource = mock(Resource.class);
|
||||
when(relativeResource.exists()).thenReturn(true);
|
||||
when(relativeResource.isReadable()).thenReturn(true);
|
||||
Resource resource = null;
|
||||
try {
|
||||
when(relativeResource.getURL()).thenReturn(new URL("https://us-east-1/test/main%2Fdata.json"));
|
||||
resource = mock(Resource.class);
|
||||
when(resource.getURL()).thenReturn(new URL("https://us-east-1/test"));
|
||||
when(resource.createRelative(eq("data.json"))).thenReturn(relativeResource);
|
||||
}
|
||||
catch (IOException e) {
|
||||
fail("Exception thrown", e);
|
||||
}
|
||||
return resource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassLoader getClassLoader() {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
Resource resource = genericResourceRepository.findOne("app", "default", "main", "data.json");
|
||||
assertThat(resource.getURL()).isEqualTo(new URL("https://us-east-1/test/main%2Fdata.json"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user