From 4c7cc736711e195f88ae3a6b8a3ff28fba9afb62 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Thu, 30 Oct 2014 07:17:22 +0000 Subject: [PATCH] Add self-bootstrap feature for embedded config server Also switch to use SpringApplicationEnvironmentRepository in "native" profile (it's more useful as a "getting started" tool). Fixes gh-21, fixes gh-33 --- .../ConfigServerBootstrapConfiguration.java | 52 ++++++++++++++++ .../server/ConfigServerConfiguration.java | 12 ++-- .../server/ConfigServerMvcConfiguration.java | 51 ++++++++++++++++ .../config/server/ConfigServerTestUtils.java | 11 ---- .../config/server/EnableConfigServer.java | 2 +- ...onmentRepositoryPropertySourceLocator.java | 59 +++++++++++++++++++ .../server/JGitEnvironmentRepository.java | 20 +++++++ .../main/resources/META-INF/spring.factories | 3 + 8 files changed, 191 insertions(+), 19 deletions(-) create mode 100644 spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ConfigServerBootstrapConfiguration.java create mode 100644 spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ConfigServerMvcConfiguration.java create mode 100644 spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/EnvironmentRepositoryPropertySourceLocator.java create mode 100644 spring-cloud-config-server/src/main/resources/META-INF/spring.factories diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ConfigServerBootstrapConfiguration.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ConfigServerBootstrapConfiguration.java new file mode 100644 index 00000000..a95de220 --- /dev/null +++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ConfigServerBootstrapConfiguration.java @@ -0,0 +1,52 @@ +/* + * 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; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.cloud.config.client.ConfigClientProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +/** + * Bootstrap configuration to fetch external configuration from a (possibly remote) + * {@link EnvironmentRepository}. Off by default because it can delay startup, but can be + * enabled with spring.cloud.config.server.bootstrap=true. This would be + * useful, for example, if the config server were embedded in another app that wanted to + * be configured from the same repository as all the other clients. + * + * @author Dave Syer + * + */ +@ConditionalOnProperty("spring.cloud.config.server.bootstrap") +@Configuration +@Import(ConfigServerConfiguration.class) +public class ConfigServerBootstrapConfiguration { + + @Autowired + private EnvironmentRepository repository; + + @Autowired + private ConfigClientProperties client; + + @Bean + public EnvironmentRepositoryPropertySourceLocator environmentRepositoryPropertySourceLocator() { + return new EnvironmentRepositoryPropertySourceLocator(repository, + client.getName(), client.getEnv(), client.getLabel()); + } + +} diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ConfigServerConfiguration.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ConfigServerConfiguration.java index 1914fba0..cf8d4a46 100644 --- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ConfigServerConfiguration.java +++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ConfigServerConfiguration.java @@ -16,9 +16,9 @@ package org.springframework.cloud.config.server; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import org.springframework.core.env.ConfigurableEnvironment; @@ -28,18 +28,16 @@ import org.springframework.core.env.ConfigurableEnvironment; * */ @Configuration -@ComponentScan +@ConditionalOnMissingBean(EnvironmentRepository.class) public class ConfigServerConfiguration { @Configuration @Profile("native") protected static class NativeRepositoryConfiguration { - @Autowired - private ConfigurableEnvironment environment; - @Bean - public NativeEnvironmentRepository repository() { - return new NativeEnvironmentRepository(environment); + @ConfigurationProperties("spring.cloud.config.server") + public SpringApplicationEnvironmentRepository repository() { + return new SpringApplicationEnvironmentRepository(); } } diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ConfigServerMvcConfiguration.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ConfigServerMvcConfiguration.java new file mode 100644 index 00000000..359f4fd8 --- /dev/null +++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ConfigServerMvcConfiguration.java @@ -0,0 +1,51 @@ +/* + * 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; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.crypto.encrypt.TextEncryptor; + +/** + * @author Dave Syer + * + */ +@Configuration +@ConditionalOnWebApplication +public class ConfigServerMvcConfiguration { + + @Autowired(required = false) + private TextEncryptor encryptor; + + @Autowired + private EnvironmentRepository repository; + + @Bean + public EnvironmentController environmentController() { + return new EnvironmentController(repository, encryptionController()); + } + + @Bean + public EncryptionController encryptionController() { + EncryptionController controller = new EncryptionController(); + if (encryptor!=null) { + controller.setEncryptor(encryptor); + } + return controller; + } +} \ No newline at end of file diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ConfigServerTestUtils.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ConfigServerTestUtils.java index 1081effe..ed511857 100644 --- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ConfigServerTestUtils.java +++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ConfigServerTestUtils.java @@ -18,13 +18,8 @@ package org.springframework.cloud.config.server; import java.io.File; import java.io.IOException; -import org.eclipse.jgit.transport.JschConfigSessionFactory; -import org.eclipse.jgit.transport.OpenSshConfig.Host; -import org.eclipse.jgit.transport.SshSessionFactory; import org.eclipse.jgit.util.FileUtils; -import com.jcraft.jsch.Session; - /** * @author Dave Syer * @@ -43,12 +38,6 @@ public class ConfigServerTestUtils { if (!repoPath.endsWith("/")) { repoPath = repoPath + "/"; } - SshSessionFactory.setInstance(new JschConfigSessionFactory() { - @Override - protected void configure(Host hc, Session session) { - session.setConfig("StrictHostKeyChecking", "no"); - } - }); File dotGit = new File(buildDir + repoPath + ".git"); File git = new File(buildDir + repoPath + "git"); if (git.exists()) { diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/EnableConfigServer.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/EnableConfigServer.java index 378b4b8b..47c147e8 100644 --- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/EnableConfigServer.java +++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/EnableConfigServer.java @@ -30,7 +30,7 @@ import org.springframework.context.annotation.Import; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented -@Import(ConfigServerConfiguration.class) +@Import({ConfigServerConfiguration.class, ConfigServerMvcConfiguration.class}) public @interface EnableConfigServer { } diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/EnvironmentRepositoryPropertySourceLocator.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/EnvironmentRepositoryPropertySourceLocator.java new file mode 100644 index 00000000..7727cecc --- /dev/null +++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/EnvironmentRepositoryPropertySourceLocator.java @@ -0,0 +1,59 @@ +/* + * 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; + +import java.util.Map; + +import org.springframework.cloud.config.PropertySource; +import org.springframework.cloud.config.client.PropertySourceLocator; +import org.springframework.core.env.CompositePropertySource; +import org.springframework.core.env.Environment; +import org.springframework.core.env.MapPropertySource; + +/** + * A PropertySourceLocator that reads from an EnvironmentRepository. + * + * @author Dave Syer + * + */ +public class EnvironmentRepositoryPropertySourceLocator implements PropertySourceLocator { + + private EnvironmentRepository repository; + private String name; + private String profiles; + private String label; + + public EnvironmentRepositoryPropertySourceLocator(EnvironmentRepository repository, + String name, String profiles, String label) { + this.repository = repository; + this.name = name; + this.profiles = profiles; + this.label = label; + } + + @Override + public org.springframework.core.env.PropertySource locate(Environment environment) { + CompositePropertySource composite = new CompositePropertySource("configService"); + for (PropertySource source : repository.findOne(name, profiles, label) + .getPropertySources()) { + @SuppressWarnings("unchecked") + Map map = (Map) source.getSource(); + composite.addPropertySource(new MapPropertySource(source.getName(), map)); + } + return composite; + } + +} diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/JGitEnvironmentRepository.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/JGitEnvironmentRepository.java index 3e281f38..f8395dfb 100644 --- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/JGitEnvironmentRepository.java +++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/JGitEnvironmentRepository.java @@ -37,7 +37,10 @@ import org.eclipse.jgit.api.PullCommand; import org.eclipse.jgit.api.TransportCommand; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.util.FileUtils; +import org.eclipse.jgit.transport.JschConfigSessionFactory; +import org.eclipse.jgit.transport.SshSessionFactory; import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider; +import org.eclipse.jgit.transport.OpenSshConfig.Host; import org.springframework.cloud.config.Environment; import org.springframework.cloud.config.PropertySource; import org.springframework.core.env.ConfigurableEnvironment; @@ -45,6 +48,8 @@ import org.springframework.core.io.UrlResource; import org.springframework.util.Assert; import org.springframework.util.FileSystemUtils; +import com.jcraft.jsch.Session; + /** * @author Dave Syer * @@ -65,6 +70,8 @@ public class JGitEnvironmentRepository implements EnvironmentRepository { private String password; + private boolean initialized; + public JGitEnvironmentRepository(ConfigurableEnvironment environment) { this.environment = environment; try { @@ -124,6 +131,7 @@ public class JGitEnvironmentRepository implements EnvironmentRepository { @Override public Environment findOne(String application, String profile, String label) { + initialize(); try { Git git; if (new File(basedir, ".git").exists()) { @@ -203,6 +211,18 @@ public class JGitEnvironmentRepository implements EnvironmentRepository { } } + private void initialize() { + if (uri.startsWith("file:") && !initialized) { + SshSessionFactory.setInstance(new JschConfigSessionFactory() { + @Override + protected void configure(Host hc, Session session) { + session.setConfig("StrictHostKeyChecking", "no"); + } + }); + initialized = true; + } + } + private void setCredentialsProvider(TransportCommand cmd) { cmd.setCredentialsProvider(new UsernamePasswordCredentialsProvider(username, password)); diff --git a/spring-cloud-config-server/src/main/resources/META-INF/spring.factories b/spring-cloud-config-server/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..5b4ba62c --- /dev/null +++ b/spring-cloud-config-server/src/main/resources/META-INF/spring.factories @@ -0,0 +1,3 @@ +# Bootstrap components +org.springframework.cloud.bootstrap.BootstrapConfiguration=\ +org.springframework.cloud.config.server.ConfigServerBootstrapConfiguration \ No newline at end of file