Add support for matching profiles as well as applications

Patterns in the form {application}/{profile} are now supported with
the old behaviour being the default (all profiles matched if none
are specified).

Fixes gh-214
This commit is contained in:
Dave Syer
2015-09-25 09:50:52 +01:00
parent da2b20c8be
commit 25dfa37612
3 changed files with 143 additions and 27 deletions

View File

@@ -143,7 +143,10 @@ the URL if you are using a command line client like curl (e.g. escape
them from the shell with quotes '').
Spring Cloud Config Server supports a single or multiple git
repositories:
repositories with pattern matching on the application and profile
name. The pattern format is a comma-separated list of
`{application}/{profile}` names with wildcards (where a pattern
beginning with a wildcard may need to be quoted). Example:
----
spring:
@@ -155,25 +158,59 @@ spring:
repos:
simple: https://github.com/simple/config-repo
special:
pattern: pattern*,*pattern1*
pattern: special*/dev*,*special*/dev*
uri: https://github.com/special/config-repo
local:
pattern: local*
uri: file:/home/configsvc/config-repo
----
In the above example, if `{application}` does not match any of the
patterns, it will use the default uri defined under
"spring.cloud.config.server.git.uri". For the "simple" repository, the
pattern is "simple" (i.e. it only matches one application named "simple").
The pattern format is a comma-separated list of application names with
wildcards (a pattern beginning with a wildcard may need to be quoted).
If `{application}/{profile}` does not match any of the patterns, it
will use the default uri defined under
"spring.cloud.config.server.git.uri". In the above example, for the
"simple" repository, the pattern is `simple/\*` (i.e. it only matches
one application named "simple" in all profiles). The "local"
repository matches all application names beginning with "local" in all
profiles (the `/*` suffix is added automatically to any pattern that
doesn't have a profile matcher).
NOTE: the "one-liner" short cut used in the "simple" example above can
only be used if the only property to be set is the URI. If you need to
set anything else (credentials, pattern, etc.) you need to use the full
form.
The `pattern` property in the repo is actually an array, so you can
use a YAML array (or `[0]`, `[1]`, etc. suffixes in properties files)
to bind to multiple patterns. You may need to do this if you are going
to run apps with multiple profiles. Example:
----
spring:
cloud:
config:
server:
git:
uri: https://github.com/spring-cloud-samples/config-repo
repos:
development:
pattern:
- */development
- */staging
uri: https://github.com/development/config-repo
staging:
pattern:
- */qa
- */production
uri: https://github.com/staging/config-repo
----
NOTE: Spring Cloud will guess that a pattern containing a profile that
doesn't end in `\*` implies that you actually want to match a list of
profiles starting with this pattern (so `*/staging` is a shortcut for
`["\*/staging", "*/staging,*"]`). This is common where you need to run
apps in the "development" profile locally but also the "cloud" profile
remotely, for instance.
Every repository can also optionally store config files in
sub-directories, and patterns to search for those directories can be
specified as `searchPaths`. For example at the top level:

View File

@@ -16,7 +16,11 @@
package org.springframework.cloud.config.server;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import org.springframework.boot.context.properties.ConfigurationProperties;
@@ -87,10 +91,10 @@ public class MultipleJGitEnvironmentRepository extends JGitEnvironmentRepository
return super.findOne(application, profile, label);
}
public static class PatternMatchingJGitEnvironmentRepository extends
JGitEnvironmentRepository {
public static class PatternMatchingJGitEnvironmentRepository
extends JGitEnvironmentRepository {
private String[] pattern;
private String[] pattern = new String[0];
private String name;
public PatternMatchingJGitEnvironmentRepository() {
@@ -109,7 +113,8 @@ public class MultipleJGitEnvironmentRepository extends JGitEnvironmentRepository
return null;
}
if (PatternMatchUtils.simpleMatch(this.pattern, application)) {
if (PatternMatchUtils.simpleMatch(this.pattern,
application + "/" + profile)) {
return super.findOne(application, profile, label);
}
@@ -130,7 +135,27 @@ public class MultipleJGitEnvironmentRepository extends JGitEnvironmentRepository
}
public void setPattern(String[] pattern) {
this.pattern = pattern;
Collection<String> patterns = new ArrayList<>();
List<String> otherProfiles = new ArrayList<>();
for (String p : pattern) {
if (p != null) {
if (!p.contains("/")) {
// Match any profile
patterns.add(p + "/*");
}
if (!p.endsWith("*")) {
// If user supplies only one profile, allow others
otherProfiles.add(p + ",*");
}
}
patterns.add(p);
}
patterns.addAll(otherProfiles);
if (!patterns.contains(null)) {
// Make sure they are unique
patterns = new LinkedHashSet<>(patterns);
}
this.pattern = patterns.toArray(new String[0]);
}
}

View File

@@ -30,8 +30,6 @@ import org.junit.Test;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.config.environment.Environment;
import org.springframework.cloud.config.server.ConfigServerTestUtils;
import org.springframework.cloud.config.server.EnvironmentRepository;
import org.springframework.cloud.config.server.config.EnvironmentRepositoryConfiguration;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
@@ -39,6 +37,7 @@ import org.springframework.context.annotation.Import;
/**
* @author Andy Chan (iceycake)
* @author Dave Syer
*
*/
public class MultipleJGitEnvironmentRepositoryIntegrationTests {
@@ -49,25 +48,25 @@ public class MultipleJGitEnvironmentRepositoryIntegrationTests {
@Before
public void init() throws Exception {
if (basedir.exists()) {
FileUtils.delete(basedir, FileUtils.RECURSIVE);
if (this.basedir.exists()) {
FileUtils.delete(this.basedir, FileUtils.RECURSIVE);
}
ConfigServerTestUtils.deleteLocalRepo("config-copy");
}
@After
public void close() {
if (context != null) {
context.close();
if (this.context != null) {
this.context.close();
}
}
@Test
public void defaultRepo() throws IOException {
String defaultRepoUri = ConfigServerTestUtils.prepareLocalRepo("config-repo");
context = new SpringApplicationBuilder(TestConfiguration.class).web(false)
this.context = new SpringApplicationBuilder(TestConfiguration.class).web(false)
.properties("spring.cloud.config.server.git.uri:" + defaultRepoUri).run();
EnvironmentRepository repository = context.getBean(EnvironmentRepository.class);
EnvironmentRepository repository = this.context.getBean(EnvironmentRepository.class);
repository.findOne("bar", "staging", "master");
Environment environment = repository.findOne("bar", "staging", "master");
assertEquals(2, environment.getPropertySources().size());
@@ -80,27 +79,82 @@ public class MultipleJGitEnvironmentRepositoryIntegrationTests {
Map<String, Object> repoMapping = new LinkedHashMap<String, Object>();
repoMapping.put("spring.cloud.config.server.git.repos[test1].pattern", "*test1*");
repoMapping.put("spring.cloud.config.server.git.repos[test1].uri", test1RepoUri);
context = new SpringApplicationBuilder(TestConfiguration.class).web(false)
repoMapping.put("spring.cloud.config.server.git.repos[test1].uri", test1RepoUri);
this.context = new SpringApplicationBuilder(TestConfiguration.class).web(false)
.properties("spring.cloud.config.server.git.uri:" + defaultRepoUri)
.properties(repoMapping).run();
EnvironmentRepository repository = context.getBean(EnvironmentRepository.class);
EnvironmentRepository repository = this.context.getBean(EnvironmentRepository.class);
repository.findOne("test1-svc", "staging", "master");
Environment environment = repository.findOne("test1-svc", "staging", "master");
assertEquals(2, environment.getPropertySources().size());
}
@Test
public void mappingRepoWithProfile() throws IOException {
String defaultRepoUri = ConfigServerTestUtils.prepareLocalRepo("config-repo");
String test1RepoUri = ConfigServerTestUtils.prepareLocalRepo("test1-config-repo");
Map<String, Object> repoMapping = new LinkedHashMap<String, Object>();
repoMapping.put("spring.cloud.config.server.git.repos[test1].pattern", "*/staging");
repoMapping.put("spring.cloud.config.server.git.repos[test1].uri", test1RepoUri);
this.context = new SpringApplicationBuilder(TestConfiguration.class).web(false)
.properties("spring.cloud.config.server.git.uri:" + defaultRepoUri)
.properties(repoMapping).run();
EnvironmentRepository repository = this.context.getBean(EnvironmentRepository.class);
repository.findOne("test1-svc", "staging", "master");
Environment environment = repository.findOne("test1-svc", "staging", "master");
assertEquals(2, environment.getPropertySources().size());
}
@Test
public void mappingRepoWithProfileDefaultPatterns() throws IOException {
String defaultRepoUri = ConfigServerTestUtils.prepareLocalRepo("config-repo");
String test1RepoUri = ConfigServerTestUtils.prepareLocalRepo("test1-config-repo");
Map<String, Object> repoMapping = new LinkedHashMap<String, Object>();
repoMapping.put("spring.cloud.config.server.git.repos[test1].pattern", "*/staging");
repoMapping.put("spring.cloud.config.server.git.repos[test1].uri", test1RepoUri);
this.context = new SpringApplicationBuilder(TestConfiguration.class).web(false)
.properties("spring.cloud.config.server.git.uri:" + defaultRepoUri)
.properties(repoMapping).run();
EnvironmentRepository repository = this.context.getBean(EnvironmentRepository.class);
repository.findOne("test1-svc", "staging", "master");
Environment environment = repository.findOne("test1-svc", "staging,cloud", "master");
assertEquals(2, environment.getPropertySources().size());
}
@Test
public void mappingRepoWithProfiles() throws IOException {
String defaultRepoUri = ConfigServerTestUtils.prepareLocalRepo("config-repo");
String test1RepoUri = ConfigServerTestUtils.prepareLocalRepo("test1-config-repo");
Map<String, Object> repoMapping = new LinkedHashMap<String, Object>();
repoMapping.put("spring.cloud.config.server.git.repos[test1].pattern[0]", "*/staging,*");
repoMapping.put("spring.cloud.config.server.git.repos[test1].pattern[1]", "*/*,staging");
repoMapping.put("spring.cloud.config.server.git.repos[test1].pattern[2]", "*/staging");
repoMapping.put("spring.cloud.config.server.git.repos[test1].uri", test1RepoUri);
this.context = new SpringApplicationBuilder(TestConfiguration.class).web(false)
.properties("spring.cloud.config.server.git.uri:" + defaultRepoUri)
.properties(repoMapping).run();
EnvironmentRepository repository = this.context.getBean(EnvironmentRepository.class);
repository.findOne("test1-svc", "staging", "master");
Environment environment = repository.findOne("test1-svc", "cloud,staging", "master");
assertEquals(2, environment.getPropertySources().size());
environment = repository.findOne("test1-svc", "staging,cloud", "master");
assertEquals(2, environment.getPropertySources().size());
}
@Test
public void mappingRepoWithJustUri() throws IOException {
String defaultRepoUri = ConfigServerTestUtils.prepareLocalRepo("config-repo");
String test1RepoUri = ConfigServerTestUtils.prepareLocalRepo("test1-config-repo");
Map<String, Object> repoMapping = new LinkedHashMap<String, Object>();
repoMapping.put("spring.cloud.config.server.git.repos.test1-svc", test1RepoUri);
context = new SpringApplicationBuilder(TestConfiguration.class).web(false)
repoMapping.put("spring.cloud.config.server.git.repos.test1-svc", test1RepoUri);
this.context = new SpringApplicationBuilder(TestConfiguration.class).web(false)
.properties("spring.cloud.config.server.git.uri:" + defaultRepoUri)
.properties(repoMapping).run();
EnvironmentRepository repository = context.getBean(EnvironmentRepository.class);
EnvironmentRepository repository = this.context.getBean(EnvironmentRepository.class);
repository.findOne("test1-svc", "staging", "master");
Environment environment = repository.findOne("test1-svc", "staging", "master");
assertEquals(2, environment.getPropertySources().size());