EnvironmentRepositoryConfiguration.java
/*
* Copyright 2013-2020 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
*
* https://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.List;
import java.util.Optional;
import com.google.cloud.secretmanager.v1.SecretManagerServiceClient;
import io.micrometer.observation.ObservationRegistry;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.http.client.HttpClient;
import org.eclipse.jgit.api.TransportConfigCallback;
import org.tmatesoft.svn.core.SVNException;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.secretsmanager.SecretsManagerClient;
import software.amazon.awssdk.services.ssm.SsmClient;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.config.server.composite.CompositeEnvironmentBeanFactoryPostProcessor;
import org.springframework.cloud.config.server.composite.ConditionalOnMissingSearchPathLocator;
import org.springframework.cloud.config.server.composite.ConditionalOnSearchPathLocator;
import org.springframework.cloud.config.server.environment.AwsParameterStoreEnvironmentProperties;
import org.springframework.cloud.config.server.environment.AwsParameterStoreEnvironmentRepository;
import org.springframework.cloud.config.server.environment.AwsParameterStoreEnvironmentRepositoryFactory;
import org.springframework.cloud.config.server.environment.AwsS3EnvironmentProperties;
import org.springframework.cloud.config.server.environment.AwsS3EnvironmentRepository;
import org.springframework.cloud.config.server.environment.AwsS3EnvironmentRepositoryFactory;
import org.springframework.cloud.config.server.environment.AwsSecretsManagerEnvironmentProperties;
import org.springframework.cloud.config.server.environment.AwsSecretsManagerEnvironmentRepository;
import org.springframework.cloud.config.server.environment.AwsSecretsManagerEnvironmentRepositoryFactory;
import org.springframework.cloud.config.server.environment.CompositeEnvironmentRepository;
import org.springframework.cloud.config.server.environment.ConfigTokenProvider;
import org.springframework.cloud.config.server.environment.ConfigurableHttpConnectionFactory;
import org.springframework.cloud.config.server.environment.ConsulEnvironmentWatch;
import org.springframework.cloud.config.server.environment.CredhubEnvironmentProperties;
import org.springframework.cloud.config.server.environment.CredhubEnvironmentRepository;
import org.springframework.cloud.config.server.environment.CredhubEnvironmentRepositoryFactory;
import org.springframework.cloud.config.server.environment.EnvironmentRepository;
import org.springframework.cloud.config.server.environment.EnvironmentWatch;
import org.springframework.cloud.config.server.environment.GoogleSecretManagerEnvironmentProperties;
import org.springframework.cloud.config.server.environment.GoogleSecretManagerEnvironmentRepository;
import org.springframework.cloud.config.server.environment.GoogleSecretManagerEnvironmentRepositoryFactory;
import org.springframework.cloud.config.server.environment.HttpClientConfigurableHttpConnectionFactory;
import org.springframework.cloud.config.server.environment.HttpClientVaultRestTemplateFactory;
import org.springframework.cloud.config.server.environment.HttpRequestConfigTokenProvider;
import org.springframework.cloud.config.server.environment.JdbcEnvironmentProperties;
import org.springframework.cloud.config.server.environment.JdbcEnvironmentRepository;
import org.springframework.cloud.config.server.environment.JdbcEnvironmentRepositoryFactory;
import org.springframework.cloud.config.server.environment.MultipleJGitEnvironmentProperties;
import org.springframework.cloud.config.server.environment.MultipleJGitEnvironmentRepository;
import org.springframework.cloud.config.server.environment.MultipleJGitEnvironmentRepositoryFactory;
import org.springframework.cloud.config.server.environment.NativeEnvironmentProperties;
import org.springframework.cloud.config.server.environment.NativeEnvironmentRepository;
import org.springframework.cloud.config.server.environment.NativeEnvironmentRepositoryFactory;
import org.springframework.cloud.config.server.environment.RedisEnvironmentProperties;
import org.springframework.cloud.config.server.environment.RedisEnvironmentRepository;
import org.springframework.cloud.config.server.environment.RedisEnvironmentRepositoryFactory;
import org.springframework.cloud.config.server.environment.SearchPathCompositeEnvironmentRepository;
import org.springframework.cloud.config.server.environment.SvnEnvironmentRepositoryFactory;
import org.springframework.cloud.config.server.environment.SvnKitEnvironmentProperties;
import org.springframework.cloud.config.server.environment.SvnKitEnvironmentRepository;
import org.springframework.cloud.config.server.environment.VaultEnvironmentProperties;
import org.springframework.cloud.config.server.environment.VaultEnvironmentRepository;
import org.springframework.cloud.config.server.environment.VaultEnvironmentRepositoryFactory;
import org.springframework.cloud.config.server.environment.vault.SpringVaultClientConfiguration;
import org.springframework.cloud.config.server.environment.vault.SpringVaultEnvironmentRepository;
import org.springframework.cloud.config.server.environment.vault.SpringVaultEnvironmentRepositoryFactory;
import org.springframework.cloud.config.server.support.GitCredentialsProviderFactory;
import org.springframework.cloud.config.server.support.GoogleCloudSourceSupport;
import org.springframework.cloud.config.server.support.TransportConfigCallbackFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Profile;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.credhub.core.CredHubOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.vault.core.VaultTemplate;
/**
* @author Dave Syer
* @author Ryan Baxter
* @author Daniel Lavoie
* @author Dylan Roberts
* @author Alberto C. R��os
* @author Scott Frederick
* @author Tejas Pandilwar
* @author Iulian Antohe
*/
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties({ SvnKitEnvironmentProperties.class, CredhubEnvironmentProperties.class,
JdbcEnvironmentProperties.class, NativeEnvironmentProperties.class, VaultEnvironmentProperties.class,
RedisEnvironmentProperties.class, AwsS3EnvironmentProperties.class,
AwsSecretsManagerEnvironmentProperties.class, AwsParameterStoreEnvironmentProperties.class,
GoogleSecretManagerEnvironmentProperties.class })
@Import({ CompositeRepositoryConfiguration.class, JdbcRepositoryConfiguration.class, VaultConfiguration.class,
VaultRepositoryConfiguration.class, SpringVaultRepositoryConfiguration.class, CredhubConfiguration.class,
CredhubRepositoryConfiguration.class, SvnRepositoryConfiguration.class, NativeRepositoryConfiguration.class,
GitRepositoryConfiguration.class, RedisRepositoryConfiguration.class, GoogleCloudSourceConfiguration.class,
AwsS3RepositoryConfiguration.class, AwsSecretsManagerRepositoryConfiguration.class,
AwsParameterStoreRepositoryConfiguration.class, GoogleSecretManagerRepositoryConfiguration.class,
// DefaultRepositoryConfiguration must be last
DefaultRepositoryConfiguration.class })
public class EnvironmentRepositoryConfiguration {
@Bean
@ConditionalOnMissingBean(search = SearchStrategy.CURRENT)
public MultipleJGitEnvironmentProperties multipleJGitEnvironmentProperties() {
return new MultipleJGitEnvironmentProperties();
}
@Bean
@ConditionalOnMissingBean(ConfigTokenProvider.class)
public ConfigTokenProvider defaultConfigTokenProvider(ObjectProvider<HttpServletRequest> httpRequest) {
return new HttpRequestConfigTokenProvider(httpRequest);
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(AbstractHealthIndicator.class)
@ConditionalOnProperty(value = "spring.cloud.config.server.health.enabled", matchIfMissing = true)
protected static class ConfigServerActuatorConfiguration {
@Bean
public ConfigServerHealthIndicator configServerHealthIndicator(EnvironmentRepository repository) {
return new ConfigServerHealthIndicator(repository);
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty("spring.cloud.config.server.consul.watch.enabled")
protected static class ConsulEnvironmentWatchConfiguration {
@Bean
public EnvironmentWatch environmentWatch() {
return new ConsulEnvironmentWatch();
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(EnvironmentWatch.class)
protected static class DefaultEnvironmentWatch {
@Bean
public EnvironmentWatch environmentWatch() {
return new EnvironmentWatch.Default();
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(TransportConfigCallback.class)
static class JGitFactoryConfig {
@Bean
public MultipleJGitEnvironmentRepositoryFactory gitEnvironmentRepositoryFactory(
ConfigurableEnvironment environment, ConfigServerProperties server,
Optional<ConfigurableHttpConnectionFactory> jgitHttpConnectionFactory,
Optional<TransportConfigCallback> customTransportConfigCallback,
Optional<GoogleCloudSourceSupport> googleCloudSourceSupport,
GitCredentialsProviderFactory gitCredentialsProviderFactory) {
final TransportConfigCallbackFactory transportConfigCallbackFactory = new TransportConfigCallbackFactory(
customTransportConfigCallback.orElse(null), googleCloudSourceSupport.orElse(null));
return new MultipleJGitEnvironmentRepositoryFactory(environment, server, jgitHttpConnectionFactory,
transportConfigCallbackFactory, gitCredentialsProviderFactory);
}
@Bean
@ConditionalOnMissingBean
public GitCredentialsProviderFactory gitCredentialsProviderFactory() {
return new GitCredentialsProviderFactory();
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ HttpClient.class, TransportConfigCallback.class })
static class JGitHttpClientConfig {
@Bean
public ConfigurableHttpConnectionFactory httpClientConnectionFactory() {
return new HttpClientConfigurableHttpConnectionFactory();
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(S3Client.class)
static class AwsS3FactoryConfig {
@Bean
public AwsS3EnvironmentRepositoryFactory awsS3EnvironmentRepositoryFactory(ConfigServerProperties server) {
return new AwsS3EnvironmentRepositoryFactory(server);
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(SecretsManagerClient.class)
static class AwsSecretsManagerFactoryConfig {
@Bean
public AwsSecretsManagerEnvironmentRepositoryFactory awsSecretsManagerEnvironmentRepositoryFactory(
ConfigServerProperties configServerProperties) {
return new AwsSecretsManagerEnvironmentRepositoryFactory(configServerProperties);
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(SsmClient.class)
static class AwsParameterStoreFactoryConfig {
@Bean
public AwsParameterStoreEnvironmentRepositoryFactory awsParameterStoreEnvironmentRepositoryFactory(
ConfigServerProperties server) {
return new AwsParameterStoreEnvironmentRepositoryFactory(server);
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(SVNException.class)
static class SvnFactoryConfig {
@Bean
public SvnEnvironmentRepositoryFactory svnEnvironmentRepositoryFactory(ConfigurableEnvironment environment,
ConfigServerProperties server, ObjectProvider<ObservationRegistry> observationRegistry) {
return new SvnEnvironmentRepositoryFactory(environment, server,
observationRegistry.getIfAvailable(() -> ObservationRegistry.NOOP));
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingClass("org.springframework.vault.core.VaultTemplate")
@SuppressWarnings("deprecation")
static class VaultFactoryConfig {
@Bean
public VaultEnvironmentRepositoryFactory vaultEnvironmentRepositoryFactory(
ObjectProvider<HttpServletRequest> request, EnvironmentWatch watch,
Optional<VaultEnvironmentRepositoryFactory.VaultRestTemplateFactory> vaultRestTemplateFactory,
ConfigTokenProvider tokenProvider) {
return new VaultEnvironmentRepositoryFactory(request, watch, vaultRestTemplateFactory, tokenProvider);
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(SecretManagerServiceClient.class)
static class GoogleSecretManagerFactoryConfig {
@Bean
public GoogleSecretManagerEnvironmentRepositoryFactory googleSecretManagerEnvironmentRepositoryFactory(
ObjectProvider<HttpServletRequest> request) {
return new GoogleSecretManagerEnvironmentRepositoryFactory(request);
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(HttpClient.class)
@ConditionalOnMissingClass("org.springframework.vault.core.VaultTemplate")
@SuppressWarnings("deprecation")
static class VaultHttpClientConfig {
@Bean
public VaultEnvironmentRepositoryFactory.VaultRestTemplateFactory vaultRestTemplateFactory() {
return new HttpClientVaultRestTemplateFactory();
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(VaultTemplate.class)
@Import(SpringVaultClientConfiguration.class)
static class SpringVaultFactoryConfig {
@Bean
public SpringVaultEnvironmentRepositoryFactory vaultEnvironmentRepositoryFactory(
ObjectProvider<HttpServletRequest> request, EnvironmentWatch watch,
SpringVaultClientConfiguration vaultClientConfiguration) {
return new SpringVaultEnvironmentRepositoryFactory(request, watch, vaultClientConfiguration);
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(JdbcTemplate.class)
@ConditionalOnProperty(value = "spring.cloud.config.server.jdbc.enabled", matchIfMissing = true)
static class JdbcFactoryConfig {
@Bean
@ConditionalOnBean(JdbcTemplate.class)
public JdbcEnvironmentRepositoryFactory jdbcEnvironmentRepositoryFactory(JdbcTemplate jdbc,
JdbcEnvironmentRepository.PropertiesResultSetExtractor propertiesResultSetExtractor) {
return new JdbcEnvironmentRepositoryFactory(jdbc, propertiesResultSetExtractor);
}
@Bean
@ConditionalOnMissingBean(JdbcEnvironmentRepository.PropertiesResultSetExtractor.class)
public JdbcEnvironmentRepository.PropertiesResultSetExtractor propertiesResultSetExtractor() {
return new JdbcEnvironmentRepository.PropertiesResultSetExtractor();
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(StringRedisTemplate.class)
static class RedisFactoryConfig {
@Bean
@ConditionalOnBean(StringRedisTemplate.class)
public RedisEnvironmentRepositoryFactory redisEnvironmentRepositoryFactory(StringRedisTemplate redis) {
return new RedisEnvironmentRepositoryFactory(redis);
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(CredHubOperations.class)
static class CredhubFactoryConfig {
@Bean
public CredhubEnvironmentRepositoryFactory credhubEnvironmentRepositoryFactory(
Optional<CredHubOperations> credHubOperations) {
return new CredhubEnvironmentRepositoryFactory(credHubOperations.orElse(null));
}
}
@Configuration(proxyBeanMethods = false)
static class NativeFactoryConfig {
@Bean
public NativeEnvironmentRepositoryFactory nativeEnvironmentRepositoryFactory(
ConfigurableEnvironment environment, ConfigServerProperties properties,
ObjectProvider<ObservationRegistry> observationRegistry) {
return new NativeEnvironmentRepositoryFactory(environment, properties,
observationRegistry.getIfAvailable(() -> ObservationRegistry.NOOP));
}
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(value = EnvironmentRepository.class, search = SearchStrategy.CURRENT)
class DefaultRepositoryConfiguration {
@Bean
public MultipleJGitEnvironmentRepository defaultEnvironmentRepository(
MultipleJGitEnvironmentRepositoryFactory gitEnvironmentRepositoryFactory,
MultipleJGitEnvironmentProperties environmentProperties) throws Exception {
return gitEnvironmentRepositoryFactory.build(environmentProperties);
}
}
@Configuration(proxyBeanMethods = false)
@Profile("native")
class NativeRepositoryConfiguration {
@Bean
public NativeEnvironmentRepository nativeEnvironmentRepository(NativeEnvironmentRepositoryFactory factory,
NativeEnvironmentProperties environmentProperties) {
return factory.build(environmentProperties);
}
}
@Configuration(proxyBeanMethods = false)
@Profile("git")
class GitRepositoryConfiguration extends DefaultRepositoryConfiguration {
}
@Configuration(proxyBeanMethods = false)
@Profile("awss3")
class AwsS3RepositoryConfiguration {
@Bean
@ConditionalOnMissingBean(AwsS3EnvironmentRepository.class)
public AwsS3EnvironmentRepository awsS3EnvironmentRepository(AwsS3EnvironmentRepositoryFactory factory,
AwsS3EnvironmentProperties environmentProperties) {
return factory.build(environmentProperties);
}
}
@Configuration(proxyBeanMethods = false)
@Profile("awsparamstore")
class AwsParameterStoreRepositoryConfiguration {
@Bean
@ConditionalOnMissingBean(AwsParameterStoreEnvironmentRepository.class)
public AwsParameterStoreEnvironmentRepository awsParameterStoreEnvironmentRepository(
AwsParameterStoreEnvironmentRepositoryFactory factory,
AwsParameterStoreEnvironmentProperties environmentProperties) {
return factory.build(environmentProperties);
}
}
@Configuration(proxyBeanMethods = false)
@Profile("awssecretsmanager")
class AwsSecretsManagerRepositoryConfiguration {
@Bean
@ConditionalOnMissingBean(AwsSecretsManagerEnvironmentRepository.class)
public AwsSecretsManagerEnvironmentRepository awsSecretsManagerEnvironmentRepository(
AwsSecretsManagerEnvironmentRepositoryFactory factory,
AwsSecretsManagerEnvironmentProperties environmentProperties) {
return factory.build(environmentProperties);
}
}
@Configuration(proxyBeanMethods = false)
@Profile("subversion")
class SvnRepositoryConfiguration {
@Bean
public SvnKitEnvironmentRepository svnKitEnvironmentRepository(SvnEnvironmentRepositoryFactory factory,
SvnKitEnvironmentProperties environmentProperties) {
return factory.build(environmentProperties);
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingClass("org.springframework.vault.core.VaultTemplate")
@Profile("vault")
@SuppressWarnings("deprecation")
class VaultRepositoryConfiguration {
@Bean
public VaultEnvironmentRepository vaultEnvironmentRepository(VaultEnvironmentRepositoryFactory factory,
VaultEnvironmentProperties environmentProperties) throws Exception {
return factory.build(environmentProperties);
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(VaultTemplate.class)
@Profile("vault")
class SpringVaultRepositoryConfiguration {
@Bean
public SpringVaultEnvironmentRepository vaultEnvironmentRepository(SpringVaultEnvironmentRepositoryFactory factory,
VaultEnvironmentProperties environmentProperties) {
return factory.build(environmentProperties);
}
}
@Configuration(proxyBeanMethods = false)
@Profile("credhub")
class CredhubRepositoryConfiguration {
@Bean
public CredhubEnvironmentRepository credhubEnvironmentRepository(CredhubEnvironmentRepositoryFactory factory,
CredhubEnvironmentProperties environmentProperties) {
return factory.build(environmentProperties);
}
}
@Configuration(proxyBeanMethods = false)
@Profile("jdbc")
@ConditionalOnClass(JdbcTemplate.class)
@ConditionalOnProperty(value = "spring.cloud.config.server.jdbc.enabled", matchIfMissing = true)
class JdbcRepositoryConfiguration {
@Bean
@ConditionalOnBean(JdbcTemplate.class)
public JdbcEnvironmentRepository jdbcEnvironmentRepository(JdbcEnvironmentRepositoryFactory factory,
JdbcEnvironmentProperties environmentProperties) {
return factory.build(environmentProperties);
}
}
@Configuration(proxyBeanMethods = false)
@Profile("redis")
@ConditionalOnClass(StringRedisTemplate.class)
class RedisRepositoryConfiguration {
@Bean
@ConditionalOnBean(StringRedisTemplate.class)
public RedisEnvironmentRepository redisEnvironmentRepository(RedisEnvironmentRepositoryFactory factory,
RedisEnvironmentProperties environmentProperties) {
return factory.build(environmentProperties);
}
}
@Configuration(proxyBeanMethods = false)
@Profile("composite")
class CompositeRepositoryConfiguration {
@Bean
public static CompositeEnvironmentBeanFactoryPostProcessor compositeEnvironmentRepositoryBeanFactoryPostProcessor(
Environment environment) {
return new CompositeEnvironmentBeanFactoryPostProcessor(environment);
}
@Primary
@Bean
@ConditionalOnSearchPathLocator
public SearchPathCompositeEnvironmentRepository searchPathCompositeEnvironmentRepository(
List<EnvironmentRepository> environmentRepositories, ConfigServerProperties properties,
ObjectProvider<ObservationRegistry> observationRegistry) {
return new SearchPathCompositeEnvironmentRepository(environmentRepositories,
observationRegistry.getIfAvailable(() -> ObservationRegistry.NOOP),
properties.isFailOnCompositeError());
}
@Primary
@Bean
@ConditionalOnMissingSearchPathLocator
public CompositeEnvironmentRepository compositeEnvironmentRepository(
List<EnvironmentRepository> environmentRepositories, ConfigServerProperties properties,
ObjectProvider<ObservationRegistry> observationRegistry) {
return new CompositeEnvironmentRepository(environmentRepositories,
observationRegistry.getIfAvailable(() -> ObservationRegistry.NOOP),
properties.isFailOnCompositeError());
}
}
@Configuration(proxyBeanMethods = false)
@Profile("secret-manager")
@ConditionalOnClass(SecretManagerServiceClient.class)
class GoogleSecretManagerRepositoryConfiguration {
@Bean
public GoogleSecretManagerEnvironmentRepository googleSecretManagerEnvironmentRepository(
GoogleSecretManagerEnvironmentRepositoryFactory factory,
GoogleSecretManagerEnvironmentProperties environmentProperties) throws Exception {
return factory.build(environmentProperties);
}
}