Skip to content

Commit

Permalink
Merge pull request #595 from ryanjbaxter/composite-envrepo-495
Browse files Browse the repository at this point in the history
Support for composite environment repos
  • Loading branch information
ryanjbaxter committed Dec 21, 2016
2 parents 47aa19f + 84db9b9 commit eb27590
Show file tree
Hide file tree
Showing 29 changed files with 626 additions and 38 deletions.
50 changes: 50 additions & 0 deletions docs/src/main/asciidoc/spring-cloud-config.adoc
Expand Up @@ -556,6 +556,56 @@ $ vault write secret/application foo=bar baz=bam
All applications using the config server will have the properties
`foo` and `baz` available to them.

==== Composite Environment Repositories

In some scenarios you may wish to pull configuration data from multiple
environment repositories. To do this just enable
multiple profiles in your config server's application properties or YAML file.
If, for example, you want to pull configuration data from a Git repository
as well as a SVN repository you would set the following properties for your
configuration server.

[source,yaml]
----
spring:
profiles:
active: git, svn
cloud:
config:
server:
svn:
uri: file:///path/to/svn/repo
order: 2
git:
uri: file:///path/to/git/repo
order: 1
----

In addition to each repo specifying a URI, you can also specify an `order` property.
The `order` property allows you to specify the priority order for all your repositories.
The lower the numerical value of the `order` property the higher priority it will have.
The priority order of a repository will help resolve any potential conflicts between
repositories that contain values for the same properties.

NOTE: Any type of failure when retrieving values from an environment repositoy
will result in a failure for the entire composite environment.

NOTE: When using a composite environment it is important that all repos contain
the same label(s). If you have an environment similar to the one above and you request
configuration data with the label `master` but the SVN
repo does not contain a branch called `master` the entire request will fail.

===== Custom Composite Environment Repositories

It is also possible to provide your own `EnvironmentRepository` bean
to be included as part of a composite environment in addition to
using one of the environment repositories from Spring Cloud. To do this your bean
must implement the `EnvironmentRepository` interface. If you would like to control
the priority of you custom `EnvironmentRepository` within the composite
environment you should also implement the `Ordered` interface and override the
`getOrdered` method. If you do not implement the `Ordered` interface than your
`EnvironmentRepository` will be given the lowest priority.

==== Property Overrides

The Config Server has an "overrides" feature that allows the operator
Expand Down
Expand Up @@ -76,6 +76,10 @@ public void add(PropertySource propertySource) {
this.propertySources.add(propertySource);
}

public void addAll(List<PropertySource> propertySources) {
this.propertySources.addAll(propertySources);
}

public void addFirst(PropertySource propertySource) {
this.propertySources.add(0, propertySource);
}
Expand Down
@@ -0,0 +1,58 @@
/*
* Copyright 2013-2016 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 java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cloud.config.server.environment.CompositeEnvironmentRepository;
import org.springframework.cloud.config.server.environment.EnvironmentRepository;
import org.springframework.cloud.config.server.environment.SearchPathCompositeEnvironmentRepository;
import org.springframework.cloud.config.server.environment.SearchPathLocator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

/**
* @author Ryan Baxter
*/
@Configuration
public class CompositeConfiguration {

private List<EnvironmentRepository> environmentRepos = new ArrayList<>();

@Bean
@Primary
@ConditionalOnBean(SearchPathLocator.class)
public SearchPathCompositeEnvironmentRepository searchPathCompositeEnvironmentRepository() {
return new SearchPathCompositeEnvironmentRepository(environmentRepos);
}

@Bean
@Primary
@ConditionalOnMissingBean(SearchPathLocator.class)
public CompositeEnvironmentRepository compositeEnvironmentRepository() {
return new CompositeEnvironmentRepository(environmentRepos);
}

@Autowired
public void setEnvironmentRepos(List<EnvironmentRepository> repos) {
this.environmentRepos = repos;
}

}
Expand Up @@ -28,7 +28,7 @@
@Configuration
@ConditionalOnBean(ConfigServerConfiguration.Marker.class)
@EnableConfigurationProperties(ConfigServerProperties.class)
@Import({ EnvironmentRepositoryConfiguration.class, ResourceRepositoryConfiguration.class,
@Import({ EnvironmentRepositoryConfiguration.class, CompositeConfiguration.class, ResourceRepositoryConfiguration.class,
ConfigServerEncryptionConfiguration.class, ConfigServerMvcConfiguration.class })
public class ConfigServerAutoConfiguration {

Expand Down
Expand Up @@ -20,7 +20,6 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.config.server.environment.ConsulEnvironmentWatch;
import org.springframework.cloud.config.server.environment.EnvironmentRepository;
import org.springframework.cloud.config.server.environment.EnvironmentWatch;
Expand All @@ -36,10 +35,10 @@

/**
* @author Dave Syer
* @author Ryan Baxter
*
*/
@Configuration
@ConditionalOnMissingBean(EnvironmentRepository.class)
public class EnvironmentRepositoryConfiguration {

@Bean
Expand All @@ -48,23 +47,9 @@ public ConfigServerHealthIndicator configServerHealthIndicator(EnvironmentReposi
return new ConfigServerHealthIndicator(repository);
}

@Configuration
@Profile("native")
protected static class NativeRepositoryConfiguration {

@Autowired
private ConfigurableEnvironment environment;

@Bean
public NativeEnvironmentRepository environmentRepository() {
return new NativeEnvironmentRepository(this.environment);
}

}

@Configuration
@ConditionalOnMissingBean(EnvironmentRepository.class)
protected static class GitRepositoryConfiguration {
protected static class DefaultRepositoryConfiguration {

@Autowired
private ConfigurableEnvironment environment;
Expand All @@ -73,7 +58,7 @@ protected static class GitRepositoryConfiguration {
private ConfigServerProperties server;

@Bean
public MultipleJGitEnvironmentRepository environmentRepository() {
public MultipleJGitEnvironmentRepository defaultEnvironmentRepository() {
MultipleJGitEnvironmentRepository repository = new MultipleJGitEnvironmentRepository(this.environment);
if (this.server.getDefaultLabel()!=null) {
repository.setDefaultLabel(this.server.getDefaultLabel());
Expand All @@ -82,6 +67,23 @@ public MultipleJGitEnvironmentRepository environmentRepository() {
}
}

@Configuration
@Profile("native")
protected static class NativeRepositoryConfiguration {

@Autowired
private ConfigurableEnvironment environment;

@Bean
public NativeEnvironmentRepository nativeEnvironmentRepository() {
return new NativeEnvironmentRepository(this.environment);
}
}

@Configuration
@Profile("git")
protected static class GitRepositoryConfiguration extends DefaultRepositoryConfiguration {}

@Configuration
@Profile("subversion")
protected static class SvnRepositoryConfiguration {
Expand All @@ -92,7 +94,7 @@ protected static class SvnRepositoryConfiguration {
private ConfigServerProperties server;

@Bean
public SvnKitEnvironmentRepository environmentRepository() {
public SvnKitEnvironmentRepository svnKitEnvironmentRepository() {
SvnKitEnvironmentRepository repository = new SvnKitEnvironmentRepository(this.environment);
if (this.server.getDefaultLabel()!=null) {
repository.setDefaultLabel(this.server.getDefaultLabel());
Expand All @@ -105,7 +107,7 @@ public SvnKitEnvironmentRepository environmentRepository() {
@Profile("vault")
protected static class VaultConfiguration {
@Bean
public EnvironmentRepository environmentRepository(HttpServletRequest request, EnvironmentWatch watch) {
public VaultEnvironmentRepository valutEnvironmentRepository(HttpServletRequest request, EnvironmentWatch watch) {
return new VaultEnvironmentRepository(request, watch, new RestTemplate());
}
}
Expand Down
Expand Up @@ -18,16 +18,18 @@

import org.springframework.cloud.config.environment.Environment;
import org.springframework.cloud.config.server.support.AbstractScmAccessor;
import org.springframework.core.Ordered;
import org.springframework.core.env.ConfigurableEnvironment;

/**
* @author Dave Syer
*
*/
public abstract class AbstractScmEnvironmentRepository extends AbstractScmAccessor
implements EnvironmentRepository, SearchPathLocator {
implements EnvironmentRepository, SearchPathLocator, Ordered {

private EnvironmentCleaner cleaner = new EnvironmentCleaner();
private int order = Ordered.LOWEST_PRECEDENCE;

public AbstractScmEnvironmentRepository(ConfigurableEnvironment environment) {
super(environment);
Expand All @@ -46,4 +48,12 @@ public synchronized Environment findOne(String application, String profile, Stri
getUri());
}

@Override
public int getOrder() {
return order;
}

public void setOrder(int order) {
this.order = order;
}
}
@@ -0,0 +1,49 @@
/*
* Copyright 2013-2016 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.environment;

import java.util.Collections;
import java.util.List;
import org.springframework.cloud.config.environment.Environment;
import org.springframework.core.OrderComparator;

/**
* An {@link EnvironmentRepository} composed of multiple ordered {@link EnvironmentRepository}s.
* @author Ryan Baxter
*/
public class CompositeEnvironmentRepository implements EnvironmentRepository {

protected List<EnvironmentRepository> environmentRepositories;

/**
* Creates a new {@link CompositeEnvironmentRepository}.
* @param environmentRepositories The list of {@link EnvironmentRepository}s to create the composite from.
*/
public CompositeEnvironmentRepository(List<EnvironmentRepository> environmentRepositories) {
//Sort the environment repositories by the priority
Collections.sort(environmentRepositories, OrderComparator.INSTANCE);
this.environmentRepositories = environmentRepositories;
}

@Override
public Environment findOne(String application, String profile, String label) {
Environment env = new Environment(application, new String[]{profile}, label, null, null);
for(EnvironmentRepository repo : environmentRepositories) {
env.addAll(repo.findOne(application, profile, label).getPropertySources());
}
return env;
}
}
Expand Up @@ -293,4 +293,8 @@ public void setPattern(String[] pattern) {

}

@Override
public void setOrder(int order) {
super.setOrder(order);
}
}
Expand Up @@ -32,6 +32,7 @@
import org.springframework.cloud.config.environment.Environment;
import org.springframework.cloud.config.environment.PropertySource;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.Ordered;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.StandardEnvironment;
Expand All @@ -47,8 +48,7 @@
* @author Roy Clarkson
*/
@ConfigurationProperties("spring.cloud.config.server.native")
public class NativeEnvironmentRepository
implements EnvironmentRepository, SearchPathLocator {
public class NativeEnvironmentRepository implements EnvironmentRepository, SearchPathLocator, Ordered {

private static Log logger = LogFactory.getLog(NativeEnvironmentRepository.class);

Expand All @@ -75,6 +75,8 @@ public class NativeEnvironmentRepository

private ConfigurableEnvironment environment;

private int order = Ordered.LOWEST_PRECEDENCE;

public NativeEnvironmentRepository(ConfigurableEnvironment environment) {
this.environment = environment;
}
Expand Down Expand Up @@ -275,4 +277,12 @@ private boolean isDirectory(String location) {
&& !location.endsWith(".yml") && !location.endsWith(".yaml");
}

@Override
public int getOrder() {
return order;
}

public void setOrder(int order) {
this.order = order;
}
}

0 comments on commit eb27590

Please sign in to comment.