diff --git a/.github/workflows/composites/pre-test-actions/action.yaml b/.github/workflows/composites/pre-test-actions/action.yaml index 2b372d2737..8e48f4a1f6 100644 --- a/.github/workflows/composites/pre-test-actions/action.yaml +++ b/.github/workflows/composites/pre-test-actions/action.yaml @@ -24,7 +24,7 @@ runs: - name: build project shell: bash run: | - ./mvnw clean install -Dskip.build.image=true -DskipITs -DskipTests -T1C -U -B -q + ./mvnw clean install -P 'run-on-github-actions' -Dskip.build.image=true -DskipITs -DskipTests -T1C -U -B -q - name: build controllers project uses: ./.github/workflows/composites/build-controllers-project diff --git a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientConfigDataLocationResolver.java b/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientConfigDataLocationResolver.java index 19d7f14ff9..e1f66263b1 100644 --- a/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientConfigDataLocationResolver.java +++ b/spring-cloud-kubernetes-client-config/src/main/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientConfigDataLocationResolver.java @@ -24,17 +24,16 @@ import org.springframework.boot.context.config.ConfigDataLocation; import org.springframework.boot.context.config.ConfigDataLocationResolverContext; import org.springframework.boot.context.config.Profiles; -import org.springframework.boot.logging.DeferredLogFactory; import org.springframework.cloud.kubernetes.commons.KubernetesClientProperties; import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; import org.springframework.cloud.kubernetes.commons.config.ConfigDataRetryableConfigMapPropertySourceLocator; import org.springframework.cloud.kubernetes.commons.config.ConfigDataRetryableSecretsPropertySourceLocator; import org.springframework.cloud.kubernetes.commons.config.ConfigMapConfigProperties; import org.springframework.cloud.kubernetes.commons.config.ConfigMapPropertySourceLocator; -import org.springframework.cloud.kubernetes.commons.config.KubernetesConfigDataLocationResolver; import org.springframework.cloud.kubernetes.commons.config.SecretsConfigProperties; import org.springframework.cloud.kubernetes.commons.config.SecretsPropertySourceLocator; -import org.springframework.core.env.Environment; +import org.springframework.cloud.kubernetes.commons.config.configdata.ConfigDataProperties; +import org.springframework.cloud.kubernetes.commons.config.configdata.KubernetesConfigDataLocationResolver; import static org.springframework.cloud.kubernetes.client.KubernetesClientUtils.kubernetesApiClient; import static org.springframework.cloud.kubernetes.commons.config.ConfigUtils.registerSingle; @@ -44,17 +43,12 @@ */ public class KubernetesClientConfigDataLocationResolver extends KubernetesConfigDataLocationResolver { - public KubernetesClientConfigDataLocationResolver(DeferredLogFactory factory) { - super(factory); - } - @Override protected void registerBeans(ConfigDataLocationResolverContext resolverContext, ConfigDataLocation location, - Profiles profiles, KubernetesConfigDataLocationResolver.PropertyHolder propertyHolder, - KubernetesNamespaceProvider namespaceProvider) { - KubernetesClientProperties kubernetesClientProperties = propertyHolder.kubernetesClientProperties(); - ConfigMapConfigProperties configMapProperties = propertyHolder.configMapConfigProperties(); - SecretsConfigProperties secretsProperties = propertyHolder.secretsProperties(); + Profiles profiles, ConfigDataProperties properties, KubernetesNamespaceProvider namespaceProvider) { + KubernetesClientProperties kubernetesClientProperties = properties.clientProperties(); + ConfigMapConfigProperties configMapProperties = properties.configMapProperties(); + SecretsConfigProperties secretsProperties = properties.secretsProperties(); ConfigurableBootstrapContext bootstrapContext = resolverContext.getBootstrapContext(); CoreV1Api coreV1Api = registerClientAndCoreV1Api(bootstrapContext, kubernetesClientProperties); @@ -96,8 +90,4 @@ private CoreV1Api registerClientAndCoreV1Api(ConfigurableBootstrapContext bootst return coreV1Api; } - protected KubernetesNamespaceProvider kubernetesNamespaceProvider(Environment environment) { - return new KubernetesNamespaceProvider(environment); - } - } diff --git a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientConfigDataLocationResolverTests.java b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientConfigDataLocationResolverTests.java index 178ecda362..933b17060d 100644 --- a/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientConfigDataLocationResolverTests.java +++ b/spring-cloud-kubernetes-client-config/src/test/java/org/springframework/cloud/kubernetes/client/config/KubernetesClientConfigDataLocationResolverTests.java @@ -16,8 +16,6 @@ package org.springframework.cloud.kubernetes.client.config; -import java.util.function.Supplier; - import io.kubernetes.client.openapi.ApiClient; import io.kubernetes.client.openapi.apis.CoreV1Api; import org.junit.jupiter.api.Assertions; @@ -31,7 +29,6 @@ import org.springframework.boot.context.config.Profiles; import org.springframework.boot.context.properties.bind.Binder; import org.springframework.boot.context.properties.source.ConfigurationPropertySources; -import org.springframework.boot.logging.DeferredLogFactory; import org.springframework.boot.test.system.CapturedOutput; import org.springframework.boot.test.system.OutputCaptureExtension; import org.springframework.cloud.kubernetes.commons.KubernetesClientProperties; @@ -49,13 +46,10 @@ @ExtendWith(OutputCaptureExtension.class) class KubernetesClientConfigDataLocationResolverTests { - private static final DeferredLogFactory FACTORY = Supplier::get; - private static final ConfigDataLocationResolverContext RESOLVER_CONTEXT = Mockito .mock(ConfigDataLocationResolverContext.class); - private static final KubernetesClientConfigDataLocationResolver RESOLVER = new KubernetesClientConfigDataLocationResolver( - FACTORY); + private static final KubernetesClientConfigDataLocationResolver RESOLVER = new KubernetesClientConfigDataLocationResolver(); /* * both ConfigMapConfigProperties and SecretsConfigProperties are null, thus they are diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/KubernetesConfigDataLocationResolver.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/KubernetesConfigDataLocationResolver.java deleted file mode 100644 index 95907843ad..0000000000 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/KubernetesConfigDataLocationResolver.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright 2013-2022 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.kubernetes.commons.config; - -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.commons.logging.Log; - -import org.springframework.boot.ConfigurableBootstrapContext; -import org.springframework.boot.context.config.ConfigDataLocation; -import org.springframework.boot.context.config.ConfigDataLocationNotFoundException; -import org.springframework.boot.context.config.ConfigDataLocationResolver; -import org.springframework.boot.context.config.ConfigDataLocationResolverContext; -import org.springframework.boot.context.config.ConfigDataResourceNotFoundException; -import org.springframework.boot.context.config.Profiles; -import org.springframework.boot.context.properties.bind.Bindable; -import org.springframework.boot.context.properties.bind.Binder; -import org.springframework.boot.logging.DeferredLogFactory; -import org.springframework.cloud.kubernetes.commons.KubernetesClientProperties; -import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; -import org.springframework.core.Ordered; -import org.springframework.core.env.ConfigurableEnvironment; -import org.springframework.core.env.Environment; -import org.springframework.core.env.MapPropertySource; -import org.springframework.core.env.PropertySource; -import org.springframework.core.env.StandardEnvironment; - -import static org.springframework.boot.cloud.CloudPlatform.KUBERNETES; -import static org.springframework.cloud.kubernetes.commons.config.ConfigUtils.registerSingle; -import static org.springframework.util.ClassUtils.isPresent; - -/** - * @author Ryan Baxter - */ -public abstract class KubernetesConfigDataLocationResolver - implements ConfigDataLocationResolver, Ordered { - - private static final boolean RETRY_IS_PRESENT = isPresent("org.springframework.retry.annotation.Retryable", null); - - private final Log log; - - public KubernetesConfigDataLocationResolver(DeferredLogFactory factory) { - this.log = factory.getLog(KubernetesConfigDataLocationResolver.class); - } - - protected final String getPrefix() { - return "kubernetes:"; - } - - @Override - public final int getOrder() { - return -1; - } - - @Override - public final boolean isResolvable(ConfigDataLocationResolverContext context, ConfigDataLocation location) { - return location.hasPrefix(getPrefix()) - && (KUBERNETES.isEnforced(context.getBinder()) || KUBERNETES.isDetected(new StandardEnvironment())); - } - - @Override - public final List resolve(ConfigDataLocationResolverContext context, - ConfigDataLocation location) - throws ConfigDataLocationNotFoundException, ConfigDataResourceNotFoundException { - return Collections.emptyList(); - } - - @Override - public final List resolveProfileSpecific( - ConfigDataLocationResolverContext resolverContext, ConfigDataLocation location, Profiles profiles) - throws ConfigDataLocationNotFoundException { - PropertyHolder propertyHolder = PropertyHolder.of(resolverContext); - KubernetesClientProperties clientProperties = propertyHolder.kubernetesClientProperties(); - ConfigMapConfigProperties configMapProperties = propertyHolder.configMapConfigProperties(); - SecretsConfigProperties secretsProperties = propertyHolder.secretsProperties(); - - registerProperties(resolverContext, clientProperties, configMapProperties, secretsProperties); - - HashMap kubernetesConfigData = new HashMap<>(); - kubernetesConfigData.put("spring.cloud.kubernetes.client.namespace", clientProperties.namespace()); - if (propertyHolder.applicationName() != null) { - // If its null it means sprig.application.name was not set so don't add it to - // the property source - kubernetesConfigData.put("spring.application.name", propertyHolder.applicationName()); - } - PropertySource> propertySource = new MapPropertySource("kubernetesConfigData", - kubernetesConfigData); - ConfigurableEnvironment environment = new StandardEnvironment(); - environment.getPropertySources().addLast(propertySource); - environment.setActiveProfiles(profiles.getAccepted().toArray(new String[0])); - KubernetesNamespaceProvider namespaceProvider = kubernetesNamespaceProvider(environment); - - registerBeans(resolverContext, location, profiles, propertyHolder, namespaceProvider); - - KubernetesConfigDataResource resource = new KubernetesConfigDataResource(clientProperties, configMapProperties, - secretsProperties, location.isOptional(), profiles, environment); - resource.setLog(log); - - return List.of(resource); - } - - protected abstract void registerBeans(ConfigDataLocationResolverContext resolverContext, - ConfigDataLocation location, Profiles profiles, PropertyHolder propertyHolder, - KubernetesNamespaceProvider namespaceProvider); - - protected final boolean isRetryEnabledForConfigMap(ConfigMapConfigProperties configMapProperties) { - return RETRY_IS_PRESENT && configMapProperties != null && configMapProperties.retry().enabled() - && configMapProperties.failFast(); - } - - protected final boolean isRetryEnabledForSecrets(SecretsConfigProperties secretsProperties) { - return RETRY_IS_PRESENT && secretsProperties != null && secretsProperties.retry().enabled() - && secretsProperties.failFast(); - } - - protected KubernetesNamespaceProvider kubernetesNamespaceProvider(Environment environment) { - return new KubernetesNamespaceProvider(environment); - } - - private void registerProperties(ConfigDataLocationResolverContext resolverContext, - KubernetesClientProperties clientProperties, ConfigMapConfigProperties configMapProperties, - SecretsConfigProperties secretsProperties) { - - ConfigurableBootstrapContext bootstrapContext = resolverContext.getBootstrapContext(); - registerSingle(bootstrapContext, KubernetesClientProperties.class, clientProperties, - "configDataKubernetesClientProperties"); - - if (configMapProperties != null) { - registerSingle(bootstrapContext, ConfigMapConfigProperties.class, configMapProperties, - "configDataConfigMapConfigProperties"); - } - - if (secretsProperties != null) { - registerSingle(bootstrapContext, SecretsConfigProperties.class, secretsProperties, - "configDataSecretsConfigProperties"); - } - } - - protected record PropertyHolder(KubernetesClientProperties kubernetesClientProperties, - ConfigMapConfigProperties configMapConfigProperties, SecretsConfigProperties secretsProperties, - String applicationName) { - - private static PropertyHolder of(ConfigDataLocationResolverContext context) { - Binder binder = context.getBinder(); - - String applicationName = binder.bind("spring.application.name", String.class).orElse(null); - String namespace = binder.bind("spring.cloud.kubernetes.client.namespace", String.class) - .orElse(binder.bind("kubernetes.namespace", String.class).orElse("")); - - KubernetesClientProperties kubernetesClientProperties = clientProperties(context, namespace); - ConfigMapAndSecrets both = ConfigMapAndSecrets.of(binder); - - return new PropertyHolder(kubernetesClientProperties, both.configMapProperties(), - both.secretsConfigProperties(), applicationName); - } - - private static KubernetesClientProperties clientProperties(ConfigDataLocationResolverContext context, - String namespace) { - KubernetesClientProperties kubernetesClientProperties; - - if (context.getBootstrapContext().isRegistered(KubernetesClientProperties.class)) { - kubernetesClientProperties = context.getBootstrapContext() - .get(KubernetesClientProperties.class) - .withNamespace(namespace); - } - else { - kubernetesClientProperties = context.getBinder() - .bindOrCreate(KubernetesClientProperties.PREFIX, Bindable.of(KubernetesClientProperties.class)) - .withNamespace(namespace); - } - - return kubernetesClientProperties; - - } - - } - - /** - * holds ConfigMapConfigProperties and SecretsConfigProperties, both can be null if - * using such sources is disabled. - */ - private record ConfigMapAndSecrets(ConfigMapConfigProperties configMapProperties, - SecretsConfigProperties secretsConfigProperties) { - - private static ConfigMapAndSecrets of(Binder binder) { - - boolean configEnabled = binder.bind("spring.cloud.kubernetes.config.enabled", boolean.class).orElse(true); - boolean secretsEnabled = binder.bind("spring.cloud.kubernetes.secrets.enabled", boolean.class).orElse(true); - - ConfigMapConfigProperties configMapConfigProperties = null; - if (configEnabled) { - configMapConfigProperties = binder.bindOrCreate(ConfigMapConfigProperties.PREFIX, - ConfigMapConfigProperties.class); - } - - SecretsConfigProperties secretsProperties = null; - if (secretsEnabled) { - secretsProperties = binder.bindOrCreate(SecretsConfigProperties.PREFIX, SecretsConfigProperties.class); - } - - return new ConfigMapAndSecrets(configMapConfigProperties, secretsProperties); - - } - } - -} diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/configdata/ConfigDataProperties.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/configdata/ConfigDataProperties.java new file mode 100644 index 0000000000..86a7ede3cb --- /dev/null +++ b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/configdata/ConfigDataProperties.java @@ -0,0 +1,67 @@ +/* + * Copyright 2013-2023 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.kubernetes.commons.config.configdata; + +import org.springframework.boot.ConfigurableBootstrapContext; +import org.springframework.boot.context.config.ConfigDataLocationResolverContext; +import org.springframework.cloud.kubernetes.commons.KubernetesClientProperties; +import org.springframework.cloud.kubernetes.commons.config.ConfigMapConfigProperties; +import org.springframework.cloud.kubernetes.commons.config.SecretsConfigProperties; + +import static org.springframework.cloud.kubernetes.commons.config.ConfigUtils.registerSingle; + +public record ConfigDataProperties(KubernetesClientProperties clientProperties, + ConfigMapConfigProperties configMapProperties, SecretsConfigProperties secretsProperties) { + + static Registrar of(ConfigDataLocationResolverContext context) { + Properties all = Properties.of(context); + return () -> { + registerProperties(context, all.clientProperties(), all.configMapProperties(), + all.secretsConfigProperties()); + return new ConfigDataProperties(all.clientProperties(), all.configMapProperties(), + all.secretsConfigProperties()); + }; + } + + private static void registerProperties(ConfigDataLocationResolverContext resolverContext, + KubernetesClientProperties clientProperties, ConfigMapConfigProperties configMapProperties, + SecretsConfigProperties secretsProperties) { + + ConfigurableBootstrapContext bootstrapContext = resolverContext.getBootstrapContext(); + + registerSingle(bootstrapContext, KubernetesClientProperties.class, clientProperties, + "configDataKubernetesClientProperties"); + + if (configMapProperties != null) { + registerSingle(bootstrapContext, ConfigMapConfigProperties.class, configMapProperties, + "configDataConfigMapConfigProperties"); + } + + if (secretsProperties != null) { + registerSingle(bootstrapContext, SecretsConfigProperties.class, secretsProperties, + "configDataSecretsConfigProperties"); + } + + } + + @FunctionalInterface + interface Registrar { + + ConfigDataProperties register(); + + } +} diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/KubernetesConfigDataLoader.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/configdata/KubernetesConfigDataLoader.java similarity index 92% rename from spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/KubernetesConfigDataLoader.java rename to spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/configdata/KubernetesConfigDataLoader.java index 3d0ae05cf8..344e183a9c 100644 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/KubernetesConfigDataLoader.java +++ b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/configdata/KubernetesConfigDataLoader.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.cloud.kubernetes.commons.config; +package org.springframework.cloud.kubernetes.commons.config.configdata; import java.io.IOException; import java.util.ArrayList; @@ -26,6 +26,8 @@ import org.springframework.boot.context.config.ConfigDataLoader; import org.springframework.boot.context.config.ConfigDataLoaderContext; import org.springframework.boot.context.config.ConfigDataResourceNotFoundException; +import org.springframework.cloud.kubernetes.commons.config.ConfigMapPropertySourceLocator; +import org.springframework.cloud.kubernetes.commons.config.SecretsPropertySourceLocator; import org.springframework.core.Ordered; import org.springframework.core.env.Environment; import org.springframework.core.env.PropertySource; diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/configdata/KubernetesConfigDataLocationResolver.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/configdata/KubernetesConfigDataLocationResolver.java new file mode 100644 index 0000000000..5ad2f009cf --- /dev/null +++ b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/configdata/KubernetesConfigDataLocationResolver.java @@ -0,0 +1,125 @@ +/* + * Copyright 2013-2022 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.kubernetes.commons.config.configdata; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.springframework.boot.context.config.ConfigDataLocation; +import org.springframework.boot.context.config.ConfigDataLocationNotFoundException; +import org.springframework.boot.context.config.ConfigDataLocationResolver; +import org.springframework.boot.context.config.ConfigDataLocationResolverContext; +import org.springframework.boot.context.config.ConfigDataResourceNotFoundException; +import org.springframework.boot.context.config.Profiles; +import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; +import org.springframework.cloud.kubernetes.commons.config.ConfigMapConfigProperties; +import org.springframework.cloud.kubernetes.commons.config.SecretsConfigProperties; +import org.springframework.core.Ordered; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.Environment; +import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.PropertySource; +import org.springframework.core.env.StandardEnvironment; + +import static org.springframework.boot.cloud.CloudPlatform.KUBERNETES; +import static org.springframework.util.ClassUtils.isPresent; + +/** + * @author Ryan Baxter + */ +public abstract class KubernetesConfigDataLocationResolver + implements ConfigDataLocationResolver, Ordered { + + private static final boolean RETRY_IS_PRESENT = isPresent("org.springframework.retry.annotation.Retryable", null); + + protected final String getPrefix() { + return "kubernetes:"; + } + + @Override + public final int getOrder() { + return -1; + } + + @Override + public final boolean isResolvable(ConfigDataLocationResolverContext context, ConfigDataLocation location) { + return location.hasPrefix(getPrefix()) + && (KUBERNETES.isEnforced(context.getBinder()) || KUBERNETES.isDetected(new StandardEnvironment())); + } + + @Override + public final List resolve(ConfigDataLocationResolverContext context, + ConfigDataLocation location) + throws ConfigDataLocationNotFoundException, ConfigDataResourceNotFoundException { + return Collections.emptyList(); + } + + @Override + public final List resolveProfileSpecific( + ConfigDataLocationResolverContext resolverContext, ConfigDataLocation location, Profiles profiles) + throws ConfigDataLocationNotFoundException { + + ConfigDataProperties properties = ConfigDataProperties.of(resolverContext).register(); + + Map kubernetesConfigData = new HashMap<>(); + kubernetesConfigData.put("spring.cloud.kubernetes.client.namespace", properties.clientProperties().namespace()); + String applicationName = resolverContext.getBinder().bind("spring.application.name", String.class).orElse(null); + if (applicationName != null) { + kubernetesConfigData.put("spring.application.name", applicationName); + } + + Environment environment = environment(kubernetesConfigData, profiles); + KubernetesNamespaceProvider namespaceProvider = kubernetesNamespaceProvider(environment); + registerBeans(resolverContext, location, profiles, properties, namespaceProvider); + + KubernetesConfigDataResource resource = new KubernetesConfigDataResource(properties.clientProperties(), + properties.configMapProperties(), properties.secretsProperties(), location.isOptional(), profiles, + environment); + + return List.of(resource); + } + + protected abstract void registerBeans(ConfigDataLocationResolverContext resolverContext, + ConfigDataLocation location, Profiles profiles, ConfigDataProperties properties, + KubernetesNamespaceProvider namespaceProvider); + + protected final boolean isRetryEnabledForConfigMap(ConfigMapConfigProperties configMapProperties) { + return RETRY_IS_PRESENT && configMapProperties != null && configMapProperties.retry().enabled() + && configMapProperties.failFast(); + } + + protected final boolean isRetryEnabledForSecrets(SecretsConfigProperties secretsProperties) { + return RETRY_IS_PRESENT && secretsProperties != null && secretsProperties.retry().enabled() + && secretsProperties.failFast(); + } + + private KubernetesNamespaceProvider kubernetesNamespaceProvider(Environment environment) { + return new KubernetesNamespaceProvider(environment); + } + + private Environment environment(Map kubernetesConfigData, Profiles profiles) { + PropertySource> propertySource = new MapPropertySource("kubernetesConfigData", + kubernetesConfigData); + ConfigurableEnvironment environment = new StandardEnvironment(); + environment.getPropertySources().addLast(propertySource); + environment.setActiveProfiles(profiles.getAccepted().toArray(new String[0])); + return environment; + } + +} diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/KubernetesConfigDataResource.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/configdata/KubernetesConfigDataResource.java similarity index 93% rename from spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/KubernetesConfigDataResource.java rename to spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/configdata/KubernetesConfigDataResource.java index d4355f8189..fdf34f2075 100644 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/KubernetesConfigDataResource.java +++ b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/configdata/KubernetesConfigDataResource.java @@ -14,16 +14,16 @@ * limitations under the License. */ -package org.springframework.cloud.kubernetes.commons.config; +package org.springframework.cloud.kubernetes.commons.config.configdata; import java.util.List; import java.util.Objects; -import org.apache.commons.logging.Log; - import org.springframework.boot.context.config.ConfigDataResource; import org.springframework.boot.context.config.Profiles; import org.springframework.cloud.kubernetes.commons.KubernetesClientProperties; +import org.springframework.cloud.kubernetes.commons.config.ConfigMapConfigProperties; +import org.springframework.cloud.kubernetes.commons.config.SecretsConfigProperties; import org.springframework.core.env.Environment; import org.springframework.core.style.ToStringCreator; import org.springframework.util.StringUtils; @@ -43,8 +43,6 @@ public class KubernetesConfigDataResource extends ConfigDataResource { private final Profiles profiles; - private Log log; - private Environment environment; public KubernetesConfigDataResource(KubernetesClientProperties properties, @@ -88,14 +86,6 @@ List getAcceptedProfiles() { return this.profiles.getAccepted(); } - public void setLog(Log log) { - this.log = log; - } - - public Log getLog() { - return this.log; - } - public Environment getEnvironment() { return environment; } diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/configdata/Properties.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/configdata/Properties.java new file mode 100644 index 0000000000..29fbe38e56 --- /dev/null +++ b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/configdata/Properties.java @@ -0,0 +1,73 @@ +/* + * Copyright 2013-2023 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.kubernetes.commons.config.configdata; + +import org.springframework.boot.context.config.ConfigDataLocationResolverContext; +import org.springframework.boot.context.properties.bind.Bindable; +import org.springframework.boot.context.properties.bind.Binder; +import org.springframework.cloud.kubernetes.commons.KubernetesClientProperties; +import org.springframework.cloud.kubernetes.commons.config.ConfigMapConfigProperties; +import org.springframework.cloud.kubernetes.commons.config.SecretsConfigProperties; + +/** + * @author wind57 + * + * holds properties needed for ConfigData. + */ +record Properties(KubernetesClientProperties clientProperties, ConfigMapConfigProperties configMapProperties, + SecretsConfigProperties secretsConfigProperties) { + + static Properties of(ConfigDataLocationResolverContext context) { + Binder binder = context.getBinder(); + + boolean configEnabled = binder.bind("spring.cloud.kubernetes.config.enabled", boolean.class).orElse(true); + boolean secretsEnabled = binder.bind("spring.cloud.kubernetes.secrets.enabled", boolean.class).orElse(true); + + ConfigMapConfigProperties configMapConfigProperties = null; + if (configEnabled) { + configMapConfigProperties = binder.bindOrCreate(ConfigMapConfigProperties.PREFIX, + ConfigMapConfigProperties.class); + } + + SecretsConfigProperties secretsProperties = null; + if (secretsEnabled) { + secretsProperties = binder.bindOrCreate(SecretsConfigProperties.PREFIX, SecretsConfigProperties.class); + } + + String namespace = binder.bind("spring.cloud.kubernetes.client.namespace", String.class) + .orElse(binder.bind("kubernetes.namespace", String.class).orElse("")); + KubernetesClientProperties clientProperties = clientProperties(context, namespace); + + return new Properties(clientProperties, configMapConfigProperties, secretsProperties); + } + + private static KubernetesClientProperties clientProperties(ConfigDataLocationResolverContext context, + String namespace) { + KubernetesClientProperties kubernetesClientProperties; + if (context.getBootstrapContext().isRegistered(KubernetesClientProperties.class)) { + kubernetesClientProperties = context.getBootstrapContext() + .get(KubernetesClientProperties.class) + .withNamespace(namespace); + } + else { + kubernetesClientProperties = context.getBinder() + .bindOrCreate(KubernetesClientProperties.PREFIX, Bindable.of(KubernetesClientProperties.class)) + .withNamespace(namespace); + } + return kubernetesClientProperties; + } +} diff --git a/spring-cloud-kubernetes-commons/src/main/resources/META-INF/spring.factories b/spring-cloud-kubernetes-commons/src/main/resources/META-INF/spring.factories index 03349b4bc7..9193cbfd7e 100644 --- a/spring-cloud-kubernetes-commons/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-kubernetes-commons/src/main/resources/META-INF/spring.factories @@ -3,4 +3,4 @@ org.springframework.cloud.kubernetes.commons.config.KubernetesBootstrapConfigura # ConfigData Loaders org.springframework.boot.context.config.ConfigDataLoader=\ -org.springframework.cloud.kubernetes.commons.config.KubernetesConfigDataLoader +org.springframework.cloud.kubernetes.commons.config.configdata.KubernetesConfigDataLoader diff --git a/spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/config/KubernetesConfigDataLoaderTests.java b/spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/config/configdata/KubernetesConfigDataLoaderTests.java similarity index 96% rename from spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/config/KubernetesConfigDataLoaderTests.java rename to spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/config/configdata/KubernetesConfigDataLoaderTests.java index 696ef7d992..643e14c47a 100644 --- a/spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/config/KubernetesConfigDataLoaderTests.java +++ b/spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/config/configdata/KubernetesConfigDataLoaderTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.cloud.kubernetes.commons.config; +package org.springframework.cloud.kubernetes.commons.config.configdata; import java.io.IOException; import java.util.List; @@ -27,6 +27,8 @@ import org.springframework.boot.context.config.ConfigData; import org.springframework.boot.context.config.ConfigDataLoaderContext; import org.springframework.boot.context.config.Profiles; +import org.springframework.cloud.kubernetes.commons.config.ConfigMapPropertySourceLocator; +import org.springframework.cloud.kubernetes.commons.config.SecretsPropertySourceLocator; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.PropertySource; import org.springframework.mock.env.MockEnvironment; diff --git a/spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/config/KubernetesConfigDataLocationResolverTests.java b/spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/config/configdata/KubernetesConfigDataLocationResolverTests.java similarity index 97% rename from spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/config/KubernetesConfigDataLocationResolverTests.java rename to spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/config/configdata/KubernetesConfigDataLocationResolverTests.java index e830ac4a08..d70c583f52 100644 --- a/spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/config/KubernetesConfigDataLocationResolverTests.java +++ b/spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/config/configdata/KubernetesConfigDataLocationResolverTests.java @@ -14,12 +14,11 @@ * limitations under the License. */ -package org.springframework.cloud.kubernetes.commons.config; +package org.springframework.cloud.kubernetes.commons.config.configdata; import java.util.Arrays; import java.util.List; import java.util.Map; -import java.util.function.Supplier; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -32,9 +31,10 @@ import org.springframework.boot.context.config.Profiles; import org.springframework.boot.context.properties.bind.Binder; import org.springframework.boot.context.properties.source.ConfigurationPropertySources; -import org.springframework.boot.logging.DeferredLogFactory; import org.springframework.cloud.kubernetes.commons.KubernetesClientProperties; import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; +import org.springframework.cloud.kubernetes.commons.config.ConfigMapConfigProperties; +import org.springframework.cloud.kubernetes.commons.config.SecretsConfigProperties; import org.springframework.mock.env.MockEnvironment; /** @@ -42,14 +42,11 @@ */ class KubernetesConfigDataLocationResolverTests { - private static final DeferredLogFactory FACTORY = Supplier::get; - // implementation that does nothing when registerBeans is called - private static final KubernetesConfigDataLocationResolver NOOP_RESOLVER = new KubernetesConfigDataLocationResolver( - FACTORY) { + private static final KubernetesConfigDataLocationResolver NOOP_RESOLVER = new KubernetesConfigDataLocationResolver() { @Override protected void registerBeans(ConfigDataLocationResolverContext resolverContext, ConfigDataLocation location, - Profiles profiles, PropertyHolder propertyHolder, KubernetesNamespaceProvider namespaceProvider) { + Profiles profiles, ConfigDataProperties properties, KubernetesNamespaceProvider namespaceProvider) { } }; diff --git a/spring-cloud-kubernetes-fabric8-config/src/main/java/org/springframework/cloud/kubernetes/fabric8/config/Fabric8ConfigDataLocationResolver.java b/spring-cloud-kubernetes-fabric8-config/src/main/java/org/springframework/cloud/kubernetes/fabric8/config/Fabric8ConfigDataLocationResolver.java index 278541ea66..f33330bcd1 100644 --- a/spring-cloud-kubernetes-fabric8-config/src/main/java/org/springframework/cloud/kubernetes/fabric8/config/Fabric8ConfigDataLocationResolver.java +++ b/spring-cloud-kubernetes-fabric8-config/src/main/java/org/springframework/cloud/kubernetes/fabric8/config/Fabric8ConfigDataLocationResolver.java @@ -23,20 +23,19 @@ import org.springframework.boot.context.config.ConfigDataLocation; import org.springframework.boot.context.config.ConfigDataLocationResolverContext; import org.springframework.boot.context.config.Profiles; -import org.springframework.boot.logging.DeferredLogFactory; import org.springframework.cloud.kubernetes.commons.KubernetesClientProperties; import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; import org.springframework.cloud.kubernetes.commons.config.ConfigDataRetryableConfigMapPropertySourceLocator; import org.springframework.cloud.kubernetes.commons.config.ConfigDataRetryableSecretsPropertySourceLocator; import org.springframework.cloud.kubernetes.commons.config.ConfigMapConfigProperties; import org.springframework.cloud.kubernetes.commons.config.ConfigMapPropertySourceLocator; -import org.springframework.cloud.kubernetes.commons.config.KubernetesConfigDataLocationResolver; import org.springframework.cloud.kubernetes.commons.config.SecretsConfigProperties; import org.springframework.cloud.kubernetes.commons.config.SecretsPropertySourceLocator; +import org.springframework.cloud.kubernetes.commons.config.configdata.ConfigDataProperties; +import org.springframework.cloud.kubernetes.commons.config.configdata.KubernetesConfigDataLocationResolver; import org.springframework.cloud.kubernetes.fabric8.Fabric8AutoConfiguration; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextClosedEvent; -import org.springframework.core.env.Environment; import static org.springframework.cloud.kubernetes.commons.config.ConfigUtils.registerSingle; @@ -45,17 +44,12 @@ */ public class Fabric8ConfigDataLocationResolver extends KubernetesConfigDataLocationResolver { - public Fabric8ConfigDataLocationResolver(DeferredLogFactory factory) { - super(factory); - } - @Override protected void registerBeans(ConfigDataLocationResolverContext resolverContext, ConfigDataLocation location, - Profiles profiles, KubernetesConfigDataLocationResolver.PropertyHolder propertyHolder, - KubernetesNamespaceProvider namespaceProvider) { - KubernetesClientProperties kubernetesClientProperties = propertyHolder.kubernetesClientProperties(); - ConfigMapConfigProperties configMapProperties = propertyHolder.configMapConfigProperties(); - SecretsConfigProperties secretsProperties = propertyHolder.secretsProperties(); + Profiles profiles, ConfigDataProperties properties, KubernetesNamespaceProvider namespaceProvider) { + KubernetesClientProperties kubernetesClientProperties = properties.clientProperties(); + ConfigMapConfigProperties configMapProperties = properties.configMapProperties(); + SecretsConfigProperties secretsProperties = properties.secretsProperties(); ConfigurableBootstrapContext bootstrapContext = resolverContext.getBootstrapContext(); KubernetesClient kubernetesClient = registerConfigAndClient(bootstrapContext, kubernetesClientProperties); @@ -97,9 +91,4 @@ private KubernetesClient registerConfigAndClient(ConfigurableBootstrapContext bo return kubernetesClient; } - @Override - protected KubernetesNamespaceProvider kubernetesNamespaceProvider(Environment environment) { - return new KubernetesNamespaceProvider(environment); - } - } diff --git a/spring-cloud-kubernetes-fabric8-config/src/test/java/org/springframework/cloud/kubernetes/fabric8/config/Fabric8ConfigDataLocationResolverTests.java b/spring-cloud-kubernetes-fabric8-config/src/test/java/org/springframework/cloud/kubernetes/fabric8/config/Fabric8ConfigDataLocationResolverTests.java index 03289fad26..63b20752d4 100644 --- a/spring-cloud-kubernetes-fabric8-config/src/test/java/org/springframework/cloud/kubernetes/fabric8/config/Fabric8ConfigDataLocationResolverTests.java +++ b/spring-cloud-kubernetes-fabric8-config/src/test/java/org/springframework/cloud/kubernetes/fabric8/config/Fabric8ConfigDataLocationResolverTests.java @@ -16,8 +16,6 @@ package org.springframework.cloud.kubernetes.fabric8.config; -import java.util.function.Supplier; - import io.fabric8.kubernetes.client.Config; import io.fabric8.kubernetes.client.KubernetesClient; import org.junit.jupiter.api.Assertions; @@ -30,7 +28,6 @@ import org.springframework.boot.context.config.Profiles; import org.springframework.boot.context.properties.bind.Binder; import org.springframework.boot.context.properties.source.ConfigurationPropertySources; -import org.springframework.boot.logging.DeferredLogFactory; import org.springframework.cloud.kubernetes.commons.KubernetesClientProperties; import org.springframework.cloud.kubernetes.commons.config.ConfigDataRetryableConfigMapPropertySourceLocator; import org.springframework.cloud.kubernetes.commons.config.ConfigDataRetryableSecretsPropertySourceLocator; @@ -45,12 +42,10 @@ */ class Fabric8ConfigDataLocationResolverTests { - private static final DeferredLogFactory FACTORY = Supplier::get; - private static final ConfigDataLocationResolverContext RESOLVER_CONTEXT = Mockito .mock(ConfigDataLocationResolverContext.class); - private static final Fabric8ConfigDataLocationResolver RESOLVER = new Fabric8ConfigDataLocationResolver(FACTORY); + private static final Fabric8ConfigDataLocationResolver RESOLVER = new Fabric8ConfigDataLocationResolver(); /* * both ConfigMapConfigProperties and SecretsConfigProperties are null, thus they are