Add ResourceController for serving plain text config files
Can be adapted to serve content in any format (e.g. nginx config file, XML configuration for logger, etc.) - basically anything that can be stored in plain text and doesn't require streaming. Fixes gh-147, see also gh-198
This commit is contained in:
@@ -526,6 +526,80 @@ TIP: the `{name:value}` prefixes can also be added to plaintext posted
|
||||
to the `/encrypt` endpoint, if you want to let the Config Server
|
||||
handle all encryption as well as decryption.
|
||||
|
||||
== Serving Plain Text
|
||||
|
||||
Instead of using the `Environment` abstraction (or one of the
|
||||
alternative representations of it in YAML or properties format) your
|
||||
applications might need generic plain text configuration files,
|
||||
tailored to their environment. The Config Server provides these
|
||||
through an additional endpoint at `/{name}/{profile}/{label}/{path}`
|
||||
where "name", "profile" and "label" have the same meaning as the
|
||||
regular environment endpoint, but "path" is a file name
|
||||
(e.g. `log.xml`). The source files for this endpoint are located in
|
||||
the same way as for the environment endpoints: the same search path is
|
||||
used as for properties or YAML files, but instead of aggregating all
|
||||
matching resources, only the first one to match is returned.
|
||||
|
||||
After a resource is located, placeholders in the normal format
|
||||
(`${...}`) are resolved using the effective `Environment` for the
|
||||
application name, profile and label supplied. In this way the resource
|
||||
endpoint is tightly integrated with the environment
|
||||
endpoints. Example, if you have this layout for a GIT (or SVN)
|
||||
repository:
|
||||
|
||||
----
|
||||
application.yml
|
||||
nginx.conf
|
||||
----
|
||||
|
||||
where `nginx.conf` looks like this:
|
||||
|
||||
----
|
||||
server {
|
||||
listen 80;
|
||||
server_name ${nginx.server.name};
|
||||
}
|
||||
----
|
||||
|
||||
and `application.yml` like this:
|
||||
|
||||
[source,yaml]
|
||||
----
|
||||
nginx:
|
||||
server:
|
||||
name: example.com
|
||||
---
|
||||
spring:
|
||||
profiles: development
|
||||
nginx:
|
||||
server:
|
||||
name: develop.com
|
||||
----
|
||||
|
||||
then the `/foo/default/master/nginx.conf` resource looks like this:
|
||||
|
||||
----
|
||||
server {
|
||||
listen 80;
|
||||
server_name example.com;
|
||||
}
|
||||
----
|
||||
|
||||
and `/foo/development/master/nginx.conf` like this:
|
||||
|
||||
----
|
||||
server {
|
||||
listen 80;
|
||||
server_name develop.com;
|
||||
}
|
||||
----
|
||||
|
||||
NOTE: just like the source files for environment configuration, the
|
||||
"profile" is used to resolve the file name, so if you want a
|
||||
profile-specific file you can use a file called
|
||||
`logback-development.xml` to be resolved by
|
||||
`/\*/development/*/logback.xml`.
|
||||
|
||||
== Embedding the Config Server
|
||||
|
||||
The Config Server runs best as a standalone application, but if you
|
||||
|
||||
@@ -34,7 +34,7 @@ import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.config.server.AbstractScmAccessor;
|
||||
import org.springframework.cloud.config.server.AbstractScmEnvironmentRepository;
|
||||
import org.springframework.cloud.config.server.NativeEnvironmentRepository;
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
import org.springframework.context.SmartLifecycle;
|
||||
@@ -66,7 +66,7 @@ public class FileMonitorConfiguration implements SmartLifecycle, ResourceLoaderA
|
||||
PropertyPathEndpoint endpoint;
|
||||
|
||||
@Autowired(required = false)
|
||||
AbstractScmAccessor scmRepository;
|
||||
AbstractScmEnvironmentRepository scmRepository;
|
||||
|
||||
@Autowired(required = false)
|
||||
NativeEnvironmentRepository nativeEnvironmentRepository;
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.config.server;
|
||||
|
||||
import org.springframework.cloud.config.environment.Environment;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractScmEnvironmentRepository extends AbstractScmAccessor
|
||||
implements EnvironmentRepository, ResourceLocationService {
|
||||
|
||||
private EnvironmentCleaner cleaner = new EnvironmentCleaner();
|
||||
|
||||
public AbstractScmEnvironmentRepository(ConfigurableEnvironment environment) {
|
||||
super(environment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Environment findOne(String application, String profile, String label) {
|
||||
NativeEnvironmentRepository delegate = new NativeEnvironmentRepository(
|
||||
getEnvironment());
|
||||
delegate.setSearchLocations(getLocations(application, profile, label));
|
||||
Environment result = delegate.findOne(application, profile, "");
|
||||
result.setLabel(label);
|
||||
return this.cleaner.clean(result, getWorkingDirectory().toURI().toString(),
|
||||
getUri());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import java.lang.annotation.Target;
|
||||
import org.springframework.cloud.config.server.config.ConfigServerEncryptionConfiguration;
|
||||
import org.springframework.cloud.config.server.config.ConfigServerMvcConfiguration;
|
||||
import org.springframework.cloud.config.server.config.EnvironmentRepositoryConfiguration;
|
||||
import org.springframework.cloud.config.server.config.ResourceRepositoryConfiguration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
@@ -33,7 +34,7 @@ import org.springframework.context.annotation.Import;
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Import({ EnvironmentRepositoryConfiguration.class,
|
||||
@Import({ EnvironmentRepositoryConfiguration.class, ResourceRepositoryConfiguration.class,
|
||||
ConfigServerEncryptionConfiguration.class, ConfigServerMvcConfiguration.class })
|
||||
public @interface EnableConfigServer {
|
||||
|
||||
|
||||
@@ -74,6 +74,10 @@ public class EnvironmentController {
|
||||
|
||||
private boolean stripDocument = true;
|
||||
|
||||
public EnvironmentController(EnvironmentRepository repository) {
|
||||
this(repository, null);
|
||||
}
|
||||
|
||||
public EnvironmentController(EnvironmentRepository repository,
|
||||
EnvironmentEncryptor environmentEncryptor) {
|
||||
this.repository = repository;
|
||||
|
||||
@@ -17,7 +17,6 @@ package org.springframework.cloud.config.server;
|
||||
|
||||
import org.springframework.cloud.config.environment.Environment;
|
||||
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
* @author Roy Clarkson
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.config.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* An {@link ResourceRepository} backed by a {@link ResourceLocationService}.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class GenericResourceRepository
|
||||
implements ResourceRepository, ResourceLoaderAware {
|
||||
|
||||
private ResourceLoader resourceLoader;
|
||||
|
||||
private ResourceLocationService service;
|
||||
|
||||
public GenericResourceRepository(ResourceLocationService service) {
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResourceLoader(ResourceLoader resourceLoader) {
|
||||
this.resourceLoader = resourceLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Resource findOne(String application, String profile, String label,
|
||||
String path) {
|
||||
String[] locations = this.service.getLocations(application, "default", label);
|
||||
try {
|
||||
for (int i = locations.length; i-- > 0;) {
|
||||
String location = locations[i];
|
||||
for (String local : getProfilePaths(profile, path)) {
|
||||
Resource file = this.resourceLoader.getResource(location)
|
||||
.createRelative(local);
|
||||
if (file.exists() && file.isReadable()) {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new NoSuchResourceException(
|
||||
"Error : " + path + ". (" + e.getMessage() + ")");
|
||||
}
|
||||
throw new NoSuchResourceException("Not found: " + path);
|
||||
}
|
||||
|
||||
private Collection<String> getProfilePaths(String profiles, String path) {
|
||||
Set<String> paths = new LinkedHashSet<>();
|
||||
for (String profile : StringUtils.commaDelimitedListToSet(profiles)) {
|
||||
if (!StringUtils.hasText(profile) || "default".equals(profile)) {
|
||||
paths.add(path);
|
||||
}
|
||||
else {
|
||||
String ext = StringUtils.getFilenameExtension(path);
|
||||
if (ext != null) {
|
||||
ext = "." + ext;
|
||||
path = StringUtils.stripFilenameExtension(path);
|
||||
}
|
||||
else {
|
||||
ext = "";
|
||||
}
|
||||
paths.add(path + "-" + profile + ext);
|
||||
}
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -39,7 +39,6 @@ import org.eclipse.jgit.transport.SshSessionFactory;
|
||||
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
|
||||
import org.eclipse.jgit.util.FileUtils;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.cloud.config.environment.Environment;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.io.UrlResource;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -53,13 +52,15 @@ import com.jcraft.jsch.Session;
|
||||
* @author Dave Syer
|
||||
* @author Roy Clarkson
|
||||
*/
|
||||
public class JGitEnvironmentRepository extends AbstractScmAccessor implements EnvironmentRepository, InitializingBean {
|
||||
public class JGitEnvironmentRepository extends AbstractScmEnvironmentRepository
|
||||
implements EnvironmentRepository, ResourceLocationService, InitializingBean {
|
||||
|
||||
private static final String DEFAULT_LABEL = "master";
|
||||
private static final String FILE_URI_PREFIX = "file:";
|
||||
|
||||
/**
|
||||
* Timeout (in seconds) for obtaining HTTP or SSH connection (if applicable). Default 5 seconds.
|
||||
* Timeout (in seconds) for obtaining HTTP or SSH connection (if applicable). Default
|
||||
* 5 seconds.
|
||||
*/
|
||||
private int timeout = 5;
|
||||
|
||||
@@ -71,8 +72,6 @@ public class JGitEnvironmentRepository extends AbstractScmAccessor implements En
|
||||
*/
|
||||
private boolean cloneOnStart = false;
|
||||
|
||||
private EnvironmentCleaner cleaner = new EnvironmentCleaner();
|
||||
|
||||
private JGitEnvironmentRepository.JGitFactory gitFactory = new JGitEnvironmentRepository.JGitFactory();
|
||||
|
||||
public JGitEnvironmentRepository(ConfigurableEnvironment environment) {
|
||||
@@ -109,12 +108,33 @@ public class JGitEnvironmentRepository extends AbstractScmAccessor implements En
|
||||
}
|
||||
|
||||
@Override
|
||||
public Environment findOne(String application, String profile, String label) {
|
||||
public String[] getLocations(String application, String profile, String label) {
|
||||
refresh(application, label);
|
||||
return getSearchLocations(getWorkingDirectory());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.state(getUri() != null,
|
||||
"You need to configure a uri for the git repository");
|
||||
if (this.cloneOnStart) {
|
||||
initClonedRepository();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the working directory ready.
|
||||
*/
|
||||
private void refresh(String application, String label) {
|
||||
initialize();
|
||||
Git git = null;
|
||||
try {
|
||||
git = createGitClient();
|
||||
return loadEnvironment(git, application, profile, label);
|
||||
git.getRepository().getConfig().setString("branch", label, "merge", label);
|
||||
Ref ref = checkout(git, label);
|
||||
if (shouldPull(git, ref)) {
|
||||
pull(git, label, ref);
|
||||
}
|
||||
}
|
||||
catch (RefNotFoundException e) {
|
||||
throw new NoSuchLabelException("No such label: " + label);
|
||||
@@ -137,15 +157,6 @@ public class JGitEnvironmentRepository extends AbstractScmAccessor implements En
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.state(getUri() != null,
|
||||
"You need to configure a uri for the git repository");
|
||||
if (this.cloneOnStart) {
|
||||
initClonedRepository();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clones the remote repository and then opens a connection to it.
|
||||
* @throws GitAPIException
|
||||
@@ -160,21 +171,6 @@ public class JGitEnvironmentRepository extends AbstractScmAccessor implements En
|
||||
|
||||
}
|
||||
|
||||
private synchronized Environment loadEnvironment(Git git, String application,
|
||||
String profile, String label) throws GitAPIException {
|
||||
NativeEnvironmentRepository environment = new NativeEnvironmentRepository(
|
||||
getEnvironment());
|
||||
git.getRepository().getConfig().setString("branch", label, "merge", label);
|
||||
Ref ref = checkout(git, label);
|
||||
if (shouldPull(git, ref)) {
|
||||
pull(git, label, ref);
|
||||
}
|
||||
environment.setSearchLocations(getSearchLocations(getWorkingDirectory()));
|
||||
Environment result = environment.findOne(application, profile, "");
|
||||
result.setLabel(label);
|
||||
return this.cleaner.clean(result, getWorkingDirectory().toURI().toString(), getUri());
|
||||
}
|
||||
|
||||
private Ref checkout(Git git, String label) throws GitAPIException {
|
||||
CheckoutCommand checkout = git.checkout();
|
||||
if (shouldTrack(git, label)) {
|
||||
@@ -299,8 +295,8 @@ public class JGitEnvironmentRepository extends AbstractScmAccessor implements En
|
||||
|
||||
private void trackBranch(Git git, CheckoutCommand checkout, String label) {
|
||||
checkout.setCreateBranch(true).setName(label)
|
||||
.setUpstreamMode(SetupUpstreamMode.TRACK)
|
||||
.setStartPoint("origin/" + label);
|
||||
.setUpstreamMode(SetupUpstreamMode.TRACK)
|
||||
.setStartPoint("origin/" + label);
|
||||
}
|
||||
|
||||
private boolean isBranch(Git git, String label) throws GitAPIException {
|
||||
|
||||
@@ -79,6 +79,17 @@ public class MultipleJGitEnvironmentRepository extends JGitEnvironmentRepository
|
||||
return this.repos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getLocations(String application, String profile, String label) {
|
||||
for (PatternMatchingJGitEnvironmentRepository repository : this.repos.values()) {
|
||||
Environment source = repository.findOne(application, profile, label);
|
||||
if (source != null) {
|
||||
return repository.getLocations(application, profile, label);
|
||||
}
|
||||
}
|
||||
return super.getLocations(application, profile, label);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Environment findOne(String application, String profile, String label) {
|
||||
for (PatternMatchingJGitEnvironmentRepository repository : this.repos.values()) {
|
||||
|
||||
@@ -47,7 +47,8 @@ import org.springframework.util.StringUtils;
|
||||
* @author Roy Clarkson
|
||||
*/
|
||||
@ConfigurationProperties("spring.cloud.config.server.native")
|
||||
public class NativeEnvironmentRepository implements EnvironmentRepository {
|
||||
public class NativeEnvironmentRepository
|
||||
implements EnvironmentRepository, ResourceLocationService {
|
||||
|
||||
private static Log logger = LogFactory.getLog(NativeEnvironmentRepository.class);
|
||||
|
||||
@@ -96,8 +97,8 @@ public class NativeEnvironmentRepository implements EnvironmentRepository {
|
||||
String[] args = getArgs(config, label);
|
||||
// Explicitly set the listeners (to exclude logging listener which would change
|
||||
// log levels in the caller)
|
||||
builder.application().setListeners(
|
||||
Arrays.asList(new ConfigFileEnvironmentPostProcessor(),
|
||||
builder.application()
|
||||
.setListeners(Arrays.asList(new ConfigFileEnvironmentPostProcessor(),
|
||||
new EnvironmentPostProcessingApplicationListener()));
|
||||
ConfigurableApplicationContext context = builder.run(args);
|
||||
environment.getPropertySources().remove("profiles");
|
||||
@@ -110,13 +111,30 @@ public class NativeEnvironmentRepository implements EnvironmentRepository {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getLocations(String application, String profile, String label) {
|
||||
String[] locations = this.searchLocations;
|
||||
if (this.searchLocations == null) {
|
||||
locations = DEFAULT_LOCATIONS;
|
||||
}
|
||||
List<String> output = new ArrayList<String>();
|
||||
for (String location : locations) {
|
||||
output.add(location);
|
||||
}
|
||||
for (String location : locations) {
|
||||
if (isDirectory(location) && StringUtils.hasText(label)) {
|
||||
output.add(location + label.trim() + "/");
|
||||
}
|
||||
}
|
||||
return output.toArray(new String[0]);
|
||||
}
|
||||
|
||||
private ConfigurableEnvironment getEnvironment(String profile) {
|
||||
ConfigurableEnvironment environment = new StandardEnvironment();
|
||||
environment.getPropertySources()
|
||||
.addFirst(
|
||||
new MapPropertySource("profiles", Collections
|
||||
.<String, Object> singletonMap("spring.profiles.active",
|
||||
profile)));
|
||||
.addFirst(new MapPropertySource("profiles",
|
||||
Collections.<String, Object> singletonMap(
|
||||
"spring.profiles.active", profile)));
|
||||
return environment;
|
||||
}
|
||||
|
||||
@@ -134,18 +152,19 @@ public class NativeEnvironmentRepository implements EnvironmentRepository {
|
||||
boolean matches = false;
|
||||
String normal = name;
|
||||
if (normal.startsWith("file:")) {
|
||||
normal = StringUtils.cleanPath(new File(normal.substring("file:"
|
||||
.length())).getAbsolutePath());
|
||||
normal = StringUtils
|
||||
.cleanPath(new File(normal.substring("file:".length()))
|
||||
.getAbsolutePath());
|
||||
}
|
||||
for (String pattern : StringUtils
|
||||
.commaDelimitedListToStringArray(getLocations(
|
||||
this.searchLocations, result.getLabel()))) {
|
||||
for (String pattern : getLocations(null, null, result.getLabel())) {
|
||||
if (!pattern.contains(":")) {
|
||||
pattern = "file:" + pattern;
|
||||
}
|
||||
if (pattern.startsWith("file:")) {
|
||||
pattern = StringUtils.cleanPath(new File(pattern
|
||||
.substring("file:".length())).getAbsolutePath()) + "/";
|
||||
pattern = StringUtils
|
||||
.cleanPath(new File(pattern.substring("file:".length()))
|
||||
.getAbsolutePath())
|
||||
+ "/";
|
||||
}
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Testing pattern: " + pattern
|
||||
@@ -179,27 +198,10 @@ public class NativeEnvironmentRepository implements EnvironmentRepository {
|
||||
list.add("--spring.config.name=" + config);
|
||||
list.add("--spring.cloud.bootstrap.enabled=false");
|
||||
list.add("--encrypt.failOnError=" + this.failOnError);
|
||||
String[] locations = this.searchLocations;
|
||||
if (this.searchLocations == null) {
|
||||
locations = DEFAULT_LOCATIONS;
|
||||
}
|
||||
list.add("--spring.config.location=" + getLocations(locations, label));
|
||||
list.add("--spring.config.location=" + StringUtils.arrayToCommaDelimitedString(getLocations(null, null, label)));
|
||||
return list.toArray(new String[0]);
|
||||
}
|
||||
|
||||
private String getLocations(String[] locations, String label) {
|
||||
List<String> output = new ArrayList<String>();
|
||||
for (String location : locations) {
|
||||
output.add(location);
|
||||
}
|
||||
for (String location : locations) {
|
||||
if (isDirectory(location) && StringUtils.hasText(label)) {
|
||||
output.add(location + label.trim() + "/");
|
||||
}
|
||||
}
|
||||
return StringUtils.collectionToCommaDelimitedString(output);
|
||||
}
|
||||
|
||||
public String[] getSearchLocations() {
|
||||
return this.searchLocations;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.config.server;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class NoSuchResourceException extends RuntimeException {
|
||||
|
||||
public NoSuchResourceException(String string) {
|
||||
super(string);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.config.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.cloud.config.environment.Environment;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.core.env.StandardEnvironment;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.util.StreamUtils;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* An HTTP endpoint for serving up templated plain text resources from an underlying
|
||||
* repository. Can be used to supply config files for consumption by a wide variety of
|
||||
* applications and services. A {@link ResourceRepository} is used to locate a
|
||||
* {@link Resource}, specific to an application, and the contents are transformed to text.
|
||||
* Then an {@link EnvironmentController} is used to supply key-value pairs which are used
|
||||
* to replace placeholders in the resource text.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping(method = RequestMethod.GET, value = "${spring.cloud.config.server.prefix:}")
|
||||
public class ResourceController {
|
||||
|
||||
private ResourceRepository resourceRepository;
|
||||
|
||||
private EnvironmentController environmentController;
|
||||
|
||||
public ResourceController(ResourceRepository resourceRepository,
|
||||
EnvironmentController environmentController) {
|
||||
this.resourceRepository = resourceRepository;
|
||||
this.environmentController = environmentController;
|
||||
}
|
||||
|
||||
@RequestMapping("/{name}/{profile}/{label}/{path:.*}")
|
||||
public synchronized String resolve(@PathVariable String name,
|
||||
@PathVariable String profile, @PathVariable String label,
|
||||
@PathVariable String path) throws IOException {
|
||||
StandardEnvironment environment = new StandardEnvironment();
|
||||
environment.getPropertySources().addAfter(
|
||||
StandardEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME,
|
||||
new EnvironmentPropertySource(
|
||||
this.environmentController.labelled(name, profile, label)));
|
||||
String text = StreamUtils.copyToString(
|
||||
this.resourceRepository.findOne(name, profile, label, path).getInputStream(),
|
||||
Charset.forName("UTF-8"));
|
||||
// Mask out escaped placeholders
|
||||
text = text.replace("\\${", "$_{");
|
||||
return environment.resolvePlaceholders(text).replace("$_{", "${");
|
||||
}
|
||||
|
||||
@ExceptionHandler(NoSuchResourceException.class)
|
||||
@ResponseStatus(HttpStatus.NOT_FOUND)
|
||||
public void notFound(NoSuchResourceException e) {
|
||||
}
|
||||
|
||||
private static class EnvironmentPropertySource extends PropertySource<Environment> {
|
||||
|
||||
public EnvironmentPropertySource(Environment sources) {
|
||||
super("cloudEnvironment", sources);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getProperty(String name) {
|
||||
for (org.springframework.cloud.config.environment.PropertySource source : getSource()
|
||||
.getPropertySources()) {
|
||||
Map<?, ?> map = source.getSource();
|
||||
if (map.containsKey(name)) {
|
||||
return map.get(name);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.config.server;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public interface ResourceLocationService {
|
||||
|
||||
String[] getLocations(String application, String profile, String label);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.config.server;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public interface ResourceRepository {
|
||||
|
||||
Resource findOne(String name, String profile, String label, String path);
|
||||
|
||||
}
|
||||
@@ -23,7 +23,6 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.cloud.config.environment.Environment;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -42,22 +41,20 @@ import org.tmatesoft.svn.core.wc2.SvnUpdate;
|
||||
* @author Roy Clarkson
|
||||
*/
|
||||
@ConfigurationProperties("spring.cloud.config.server.svn")
|
||||
public class SvnKitEnvironmentRepository extends AbstractScmAccessor
|
||||
public class SvnKitEnvironmentRepository extends AbstractScmEnvironmentRepository
|
||||
implements EnvironmentRepository, InitializingBean {
|
||||
|
||||
private static Log logger = LogFactory.getLog(SvnKitEnvironmentRepository.class);
|
||||
|
||||
private static final String DEFAULT_LABEL = "trunk";
|
||||
|
||||
private EnvironmentCleaner cleaner = new EnvironmentCleaner();
|
||||
|
||||
@Override
|
||||
public String getDefaultLabel() {
|
||||
return DEFAULT_LABEL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Environment findOne(String application, String profile, String label) {
|
||||
public String[] getLocations(String application, String profile, String label) {
|
||||
SvnOperationFactory svnOperationFactory = new SvnOperationFactory();
|
||||
if (hasText(getUsername())) {
|
||||
svnOperationFactory
|
||||
@@ -71,8 +68,7 @@ public class SvnKitEnvironmentRepository extends AbstractScmAccessor
|
||||
else {
|
||||
checkout(svnOperationFactory);
|
||||
}
|
||||
return this.cleaner.clean(loadEnvironment(application, profile, label),
|
||||
getWorkingDirectory().toURI().toString(), getUri());
|
||||
return getLocations(label);
|
||||
}
|
||||
catch (SVNException e) {
|
||||
throw new IllegalStateException("Cannot checkout repository", e);
|
||||
@@ -82,10 +78,7 @@ public class SvnKitEnvironmentRepository extends AbstractScmAccessor
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized Environment loadEnvironment(String application, String profile,
|
||||
String label) {
|
||||
final NativeEnvironmentRepository environmentRepository = new NativeEnvironmentRepository(
|
||||
getEnvironment());
|
||||
private String[] getLocations(String label) {
|
||||
String[] locations = getSearchLocations(getSvnPath(getWorkingDirectory(), label));
|
||||
boolean exists = false;
|
||||
for (String location : locations) {
|
||||
@@ -100,8 +93,7 @@ public class SvnKitEnvironmentRepository extends AbstractScmAccessor
|
||||
if (!exists) {
|
||||
throw new NoSuchLabelException("No label found for: " + label);
|
||||
}
|
||||
environmentRepository.setSearchLocations(locations);
|
||||
return environmentRepository.findOne(application, profile, label);
|
||||
return locations;
|
||||
}
|
||||
|
||||
private void checkout(SvnOperationFactory svnOperationFactory) throws SVNException {
|
||||
|
||||
@@ -20,6 +20,8 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplicat
|
||||
import org.springframework.cloud.config.server.ConfigServerProperties;
|
||||
import org.springframework.cloud.config.server.EnvironmentController;
|
||||
import org.springframework.cloud.config.server.EnvironmentRepository;
|
||||
import org.springframework.cloud.config.server.ResourceController;
|
||||
import org.springframework.cloud.config.server.ResourceRepository;
|
||||
import org.springframework.cloud.config.server.encryption.EnvironmentEncryptor;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -35,6 +37,9 @@ public class ConfigServerMvcConfiguration {
|
||||
@Autowired
|
||||
private EnvironmentRepository repository;
|
||||
|
||||
@Autowired
|
||||
private ResourceRepository resources;
|
||||
|
||||
@Autowired
|
||||
private ConfigServerProperties server;
|
||||
|
||||
@@ -43,19 +48,25 @@ public class ConfigServerMvcConfiguration {
|
||||
|
||||
@Bean
|
||||
public EnvironmentController environmentController() {
|
||||
EnvironmentController controller = new EnvironmentController(repository, environmentEncryptor);
|
||||
EnvironmentController controller = new EnvironmentController(this.repository, this.environmentEncryptor);
|
||||
controller.setDefaultLabel(getDefaultLabel());
|
||||
controller.setOverrides(server.getOverrides());
|
||||
controller.setStripDocumentFromYaml(server.isStripDocumentFromYaml());
|
||||
controller.setOverrides(this.server.getOverrides());
|
||||
controller.setStripDocumentFromYaml(this.server.isStripDocumentFromYaml());
|
||||
return controller;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ResourceController resourceController() {
|
||||
ResourceController controller = new ResourceController(this.resources, environmentController());
|
||||
return controller;
|
||||
}
|
||||
|
||||
private String getDefaultLabel() {
|
||||
if (StringUtils.hasText(server.getDefaultLabel())) {
|
||||
return server.getDefaultLabel();
|
||||
if (StringUtils.hasText(this.server.getDefaultLabel())) {
|
||||
return this.server.getDefaultLabel();
|
||||
}
|
||||
else {
|
||||
return repository.getDefaultLabel();
|
||||
return this.repository.getDefaultLabel();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,11 +50,11 @@ public class EnvironmentRepositoryConfiguration {
|
||||
protected static class NativeRepositoryConfiguration {
|
||||
|
||||
@Autowired
|
||||
private ConfigurableEnvironment environment;
|
||||
|
||||
private ConfigurableEnvironment environment;
|
||||
|
||||
@Bean
|
||||
public EnvironmentRepository environmentRepository() {
|
||||
return new NativeEnvironmentRepository(environment);
|
||||
return new NativeEnvironmentRepository(this.environment);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -62,16 +62,16 @@ public class EnvironmentRepositoryConfiguration {
|
||||
@Configuration
|
||||
@ConditionalOnMissingBean(EnvironmentRepository.class)
|
||||
protected static class GitRepositoryConfiguration {
|
||||
|
||||
|
||||
@Autowired
|
||||
private ConfigurableEnvironment environment;
|
||||
|
||||
private ConfigurableEnvironment environment;
|
||||
|
||||
@Bean
|
||||
public EnvironmentRepository environmentRepository() {
|
||||
return new MultipleJGitEnvironmentRepository(environment);
|
||||
return new MultipleJGitEnvironmentRepository(this.environment);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
@Profile("subversion")
|
||||
protected static class SvnRepositoryConfiguration {
|
||||
@@ -80,7 +80,7 @@ public class EnvironmentRepositoryConfiguration {
|
||||
|
||||
@Bean
|
||||
public EnvironmentRepository environmentRepository() {
|
||||
return new SvnKitEnvironmentRepository(environment);
|
||||
return new SvnKitEnvironmentRepository(this.environment);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2013-2014 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cloud.config.server.config;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.config.server.ConfigServerProperties;
|
||||
import org.springframework.cloud.config.server.GenericResourceRepository;
|
||||
import org.springframework.cloud.config.server.ResourceLocationService;
|
||||
import org.springframework.cloud.config.server.ResourceRepository;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnMissingBean(ResourceRepository.class)
|
||||
@EnableConfigurationProperties(ConfigServerProperties.class)
|
||||
public class ResourceRepositoryConfiguration {
|
||||
|
||||
@Bean
|
||||
public ResourceRepository resourceRepository(ResourceLocationService service) {
|
||||
return new GenericResourceRepository(service);
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,16 @@
|
||||
package org.springframework.cloud.config.server;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
@@ -20,15 +24,11 @@ import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringApplicationConfiguration(classes = TestConfiguration.class)
|
||||
@IntegrationTest("server.port:0")
|
||||
@@ -50,27 +50,34 @@ public class ConfigClientOffIntegrationTests {
|
||||
@Test
|
||||
public void contextLoads() {
|
||||
Environment environment = new TestRestTemplate().getForObject("http://localhost:"
|
||||
+ port + "/foo/development/", Environment.class);
|
||||
+ this.port + "/foo/development/", Environment.class);
|
||||
assertTrue(environment.getPropertySources().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configClientDisabled() throws Exception {
|
||||
assertEquals(0, BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context,
|
||||
assertEquals(0, BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.context,
|
||||
ConfigServicePropertySourceLocator.class).length);
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
@Import(ConfigServerApplication.class)
|
||||
protected static class TestConfiguration {
|
||||
|
||||
|
||||
@Bean
|
||||
public EnvironmentRepository environmentRepository() {
|
||||
EnvironmentRepository repository = Mockito.mock(EnvironmentRepository.class);
|
||||
given(repository.findOne(anyString(), anyString(), anyString())).willReturn(new Environment("", ""));
|
||||
return repository;
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
public ResourceRepository resourceRepository() {
|
||||
ResourceRepository repository = Mockito.mock(ResourceRepository.class);
|
||||
given(repository.findOne(anyString(), anyString(), anyString(), anyString())).willReturn(new ByteArrayResource("".getBytes()));
|
||||
return repository;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
package org.springframework.cloud.config.server;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
@@ -20,15 +24,11 @@ import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringApplicationConfiguration(classes = TestConfiguration.class)
|
||||
@IntegrationTest({ "server.port:0", "spring.cloud.config.enabled:true" })
|
||||
@@ -50,27 +50,34 @@ public class ConfigClientOnIntegrationTests {
|
||||
@Test
|
||||
public void contextLoads() {
|
||||
Environment environment = new TestRestTemplate().getForObject("http://localhost:"
|
||||
+ port + "/foo/development/", Environment.class);
|
||||
+ this.port + "/foo/development/", Environment.class);
|
||||
assertTrue(environment.getPropertySources().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configClientEnabled() throws Exception {
|
||||
assertEquals(1, BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context,
|
||||
assertEquals(1, BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.context,
|
||||
ConfigServicePropertySourceLocator.class).length);
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
@Import(ConfigServerApplication.class)
|
||||
protected static class TestConfiguration {
|
||||
|
||||
|
||||
@Bean
|
||||
public EnvironmentRepository environmentRepository() {
|
||||
EnvironmentRepository repository = Mockito.mock(EnvironmentRepository.class);
|
||||
given(repository.findOne(anyString(), anyString(), anyString())).willReturn(new Environment("", ""));
|
||||
return repository;
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
public ResourceRepository resourceRepository() {
|
||||
ResourceRepository repository = Mockito.mock(ResourceRepository.class);
|
||||
given(repository.findOne(anyString(), anyString(), anyString(), anyString())).willReturn(new ByteArrayResource("".getBytes()));
|
||||
return repository;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.config.server;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class GenericResourceRepositoryTests {
|
||||
|
||||
private GenericResourceRepository repository;
|
||||
private ConfigurableApplicationContext context;
|
||||
|
||||
@After
|
||||
public void close() {
|
||||
if (this.context != null) {
|
||||
this.context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
this.context = new SpringApplicationBuilder(
|
||||
NativeEnvironmentRepositoryTests.class).web(false).run();
|
||||
this.repository = new GenericResourceRepository(
|
||||
new NativeEnvironmentRepository(this.context.getEnvironment()));
|
||||
this.repository.setResourceLoader(this.context);
|
||||
this.context.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void locateResource() {
|
||||
assertNotNull(this.repository.findOne("blah", "default", "master", "foo.properties"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void locateProfiledResource() {
|
||||
assertNotNull(this.repository.findOne("blah", "local", "master", "foo.txt"));
|
||||
}
|
||||
|
||||
@Test(expected=NoSuchResourceException.class)
|
||||
public void locateMissingResource() {
|
||||
assertNotNull(this.repository.findOne("blah", "default", "master", "foo.txt"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -71,7 +71,7 @@ public class NativeEnvironmentRepositoryTests {
|
||||
this.repository.setSearchLocations("classpath:/test");
|
||||
Environment environment = this.repository.findOne("foo", "development", "dev");
|
||||
assertEquals(3, environment.getPropertySources().size());
|
||||
// position 1 because it has higher precendence than anything except the
|
||||
// position 1 because it has higher precedence than anything except the
|
||||
// foo-development.properties
|
||||
assertEquals("dev_bar",
|
||||
environment.getPropertySources().get(1).getSource().get("foo"));
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.config.server;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class ResourceControllerTests {
|
||||
|
||||
private ResourceController controller;
|
||||
private GenericResourceRepository repository;
|
||||
private ConfigurableApplicationContext context;
|
||||
private NativeEnvironmentRepository environmentRepository;
|
||||
|
||||
@After
|
||||
public void close() {
|
||||
if (this.context != null) {
|
||||
this.context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
this.context = new SpringApplicationBuilder(
|
||||
NativeEnvironmentRepositoryTests.class).web(false).run();
|
||||
this.environmentRepository = new NativeEnvironmentRepository(
|
||||
this.context.getEnvironment());
|
||||
this.repository = new GenericResourceRepository(this.environmentRepository);
|
||||
this.repository.setResourceLoader(this.context);
|
||||
this.controller = new ResourceController(this.repository,
|
||||
new EnvironmentController(this.environmentRepository));
|
||||
this.context.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void templateReplacement() throws Exception {
|
||||
this.environmentRepository.setSearchLocations("classpath:/test");
|
||||
String resource = this.controller.resolve("foo", "bar", "dev", "template.json");
|
||||
assertEquals("{\n \"foo\": \"dev_bar\"\n}", resource);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void escapedPlaceholder() throws Exception {
|
||||
this.environmentRepository.setSearchLocations("classpath:/test");
|
||||
String resource = this.controller.resolve("foo", "bar", "dev", "placeholder.txt");
|
||||
assertEquals("foo: ${foo}", resource);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,7 +5,4 @@ spring:
|
||||
git:
|
||||
basedir: target/config
|
||||
overrides:
|
||||
spring:
|
||||
cloud:
|
||||
config:
|
||||
enabled: true
|
||||
spring.cloud.config.enabled: true
|
||||
@@ -0,0 +1 @@
|
||||
foo: local
|
||||
@@ -0,0 +1 @@
|
||||
foo: \${foo}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"foo": "${foo}"
|
||||
}
|
||||
Reference in New Issue
Block a user