From 4afb5ef168d7de6b7bc79471c5b9f7ec9f59270f Mon Sep 17 00:00:00 2001 From: wind57 Date: Sun, 31 Aug 2025 10:43:17 +0300 Subject: [PATCH 1/5] continue Signed-off-by: wind57 --- ...netesClientConfigDataLocationResolver.java | 38 ++- ...ClientConfigDataLocationResolverTests.java | 12 +- .../KubernetesConfigDataLocationResolver.java | 223 ------------------ .../configdata/ConfigDataProperties.java | 99 ++++++++ .../KubernetesConfigDataLoader.java | 8 +- .../KubernetesConfigDataLocationResolver.java | 126 ++++++++++ .../KubernetesConfigDataResource.java | 30 +-- .../main/resources/META-INF/spring.factories | 2 +- .../KubernetesConfigDataLoaderTests.java | 4 +- ...rnetesConfigDataLocationResolverTests.java | 10 +- .../Fabric8ConfigDataLocationResolver.java | 41 ++-- ...abric8ConfigDataLocationResolverTests.java | 2 +- .../DummyConfigDataLocationResolver.java | 2 +- 13 files changed, 282 insertions(+), 315 deletions(-) delete mode 100644 spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/KubernetesConfigDataLocationResolver.java create mode 100644 spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/configdata/ConfigDataProperties.java rename spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/{ => configdata}/KubernetesConfigDataLoader.java (87%) create mode 100644 spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/configdata/KubernetesConfigDataLocationResolver.java rename spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/{ => configdata}/KubernetesConfigDataResource.java (82%) rename spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/config/{ => configdata}/KubernetesConfigDataLoaderTests.java (96%) rename spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/config/{ => configdata}/KubernetesConfigDataLocationResolverTests.java (97%) 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 99a4a84fb7..3f55a860ec 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 @@ -1,5 +1,5 @@ /* - * Copyright 2013-present the original author or authors. + * 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. @@ -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,48 +43,43 @@ */ 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); if (configMapProperties != null && configMapProperties.enabled()) { ConfigMapPropertySourceLocator configMapPropertySourceLocator = new KubernetesClientConfigMapPropertySourceLocator( - coreV1Api, configMapProperties, namespaceProvider); + coreV1Api, configMapProperties, namespaceProvider); if (isRetryEnabledForConfigMap(configMapProperties)) { configMapPropertySourceLocator = new ConfigDataRetryableConfigMapPropertySourceLocator( - configMapPropertySourceLocator, configMapProperties, new KubernetesClientConfigMapsCache()); + configMapPropertySourceLocator, configMapProperties, new KubernetesClientConfigMapsCache()); } registerSingle(bootstrapContext, ConfigMapPropertySourceLocator.class, configMapPropertySourceLocator, - "configDataConfigMapPropertySourceLocator"); + "configDataConfigMapPropertySourceLocator"); } if (secretsProperties != null && secretsProperties.enabled()) { SecretsPropertySourceLocator secretsPropertySourceLocator = new KubernetesClientSecretsPropertySourceLocator( - coreV1Api, namespaceProvider, secretsProperties); + coreV1Api, namespaceProvider, secretsProperties); if (isRetryEnabledForSecrets(secretsProperties)) { secretsPropertySourceLocator = new ConfigDataRetryableSecretsPropertySourceLocator( - secretsPropertySourceLocator, secretsProperties, new KubernetesClientSecretsCache()); + secretsPropertySourceLocator, secretsProperties, new KubernetesClientSecretsCache()); } registerSingle(bootstrapContext, SecretsPropertySourceLocator.class, secretsPropertySourceLocator, - "configDataSecretsPropertySourceLocator"); + "configDataSecretsPropertySourceLocator"); } } private CoreV1Api registerClientAndCoreV1Api(ConfigurableBootstrapContext bootstrapContext, - KubernetesClientProperties kubernetesClientProperties) { + KubernetesClientProperties kubernetesClientProperties) { ApiClient apiClient = kubernetesApiClient(); apiClient.setUserAgent(kubernetesClientProperties.userAgent()); registerSingle(bootstrapContext, ApiClient.class, apiClient, "configDataApiClient"); @@ -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 10d5f6d48e..8966059759 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 @@ -1,5 +1,5 @@ /* - * Copyright 2013-present the original author or authors. + * 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. @@ -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.assertj.core.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 @@ -179,7 +173,7 @@ void testBothPresentExplicitly(CapturedOutput capturedOutput) { Assertions.assertThat(capturedOutput.getOut()) .contains("Could not create the Kubernetes ApiClient in a cluster environment, because connection port " - + "was not provided."); + + "was not provided."); } /* 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 77d8aaa7ce..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-present 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 Class PROPERTIES_CLASS = KubernetesClientProperties.class; - - 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, PROPERTIES_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; - ConfigurableBootstrapContext bootstrapContext = context.getBootstrapContext(); - - if (bootstrapContext.isRegistered(PROPERTIES_CLASS) && bootstrapContext.get(PROPERTIES_CLASS) != null) { - kubernetesClientProperties = bootstrapContext.get(PROPERTIES_CLASS).withNamespace(namespace); - } - else { - kubernetesClientProperties = context.getBinder() - .bindOrCreate(KubernetesClientProperties.PREFIX, Bindable.of(PROPERTIES_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..34239d9007 --- /dev/null +++ b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/configdata/ConfigDataProperties.java @@ -0,0 +1,99 @@ +/* + * Copyright 2013-present 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.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; + +import static org.springframework.cloud.kubernetes.commons.config.ConfigUtils.registerSingle; + +/** + * @author wind57 + */ +record ConfigDataProperties(KubernetesClientProperties clientProperties, + ConfigMapConfigProperties configMapProperties, SecretsConfigProperties secretsProperties) { + + static ConfigDataProperties of(ConfigDataLocationResolverContext context) { + + KubernetesClientProperties clientProperties; + ConfigMapConfigProperties configMapProperties = null; + SecretsConfigProperties secretsProperties = null; + + Binder binder = context.getBinder(); + + boolean configEnabled = binder.bind("spring.cloud.kubernetes.config.enabled", boolean.class).orElse(true); + if (configEnabled) { + configMapProperties = binder.bindOrCreate(ConfigMapConfigProperties.PREFIX, + ConfigMapConfigProperties.class); + } + + boolean secretsEnabled = binder.bind("spring.cloud.kubernetes.secrets.enabled", boolean.class).orElse(true); + 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("")); + clientProperties = clientProperties(context, namespace); + + registerProperties(context, clientProperties, configMapProperties, secretsProperties); + return new ConfigDataProperties(clientProperties, configMapProperties, secretsProperties); + } + + 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"); + } + + } + + 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/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 87% 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 4b0e13a51c..d5d8841aa2 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; @@ -33,11 +35,11 @@ /** * @author Ryan Baxter */ -public class KubernetesConfigDataLoader implements ConfigDataLoader, Ordered { +final class KubernetesConfigDataLoader implements ConfigDataLoader, Ordered { @Override public ConfigData load(ConfigDataLoaderContext context, KubernetesConfigDataResource resource) - throws IOException, ConfigDataResourceNotFoundException { + throws ConfigDataResourceNotFoundException { List> propertySources = new ArrayList<>(2); ConfigurableBootstrapContext bootstrapContext = context.getBootstrapContext(); 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..0a97616d65 --- /dev/null +++ b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/configdata/KubernetesConfigDataLocationResolver.java @@ -0,0 +1,126 @@ +/* + * Copyright 2013-present 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 + * @author wind57 + */ +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); + + 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 82% 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 4afd1015cc..d77a564848 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; @@ -31,7 +31,7 @@ /** * @author Ryan Baxter */ -public class KubernetesConfigDataResource extends ConfigDataResource { +public final class KubernetesConfigDataResource extends ConfigDataResource { private final KubernetesClientProperties properties; @@ -43,13 +43,11 @@ public class KubernetesConfigDataResource extends ConfigDataResource { private final Profiles profiles; - private Log log; - - private Environment environment; + private final Environment environment; - public KubernetesConfigDataResource(KubernetesClientProperties properties, - ConfigMapConfigProperties configMapProperties, SecretsConfigProperties secretsConfigProperties, - boolean optional, Profiles profiles, Environment environment) { + KubernetesConfigDataResource(KubernetesClientProperties properties, ConfigMapConfigProperties configMapProperties, + SecretsConfigProperties secretsConfigProperties, boolean optional, Profiles profiles, + Environment environment) { this.properties = properties; this.configMapProperties = configMapProperties; this.secretsConfigProperties = secretsConfigProperties; @@ -88,22 +86,10 @@ 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; } - public void setEnvironment(Environment environment) { - this.environment = environment; - } - @Override public boolean equals(Object o) { if (this == o) { 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 e9662453cd..d2d4572918 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 53b3ba4581..5e603d2370 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,7 +14,7 @@ * 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; @@ -35,6 +35,8 @@ 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; /** @@ -45,11 +47,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 022e31f0d7..9c494285fa 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 @@ -1,5 +1,5 @@ /* - * Copyright 2013-present the original author or authors. + * Copyright 2013-2021 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. @@ -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,61 +44,51 @@ */ 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); if (configMapProperties != null && configMapProperties.enabled()) { ConfigMapPropertySourceLocator configMapPropertySourceLocator = new Fabric8ConfigMapPropertySourceLocator( - kubernetesClient, configMapProperties, namespaceProvider); + kubernetesClient, configMapProperties, namespaceProvider); if (isRetryEnabledForConfigMap(configMapProperties)) { configMapPropertySourceLocator = new ConfigDataRetryableConfigMapPropertySourceLocator( - configMapPropertySourceLocator, configMapProperties, new Fabric8ConfigMapsCache()); + configMapPropertySourceLocator, configMapProperties, new Fabric8ConfigMapsCache()); } registerSingle(bootstrapContext, ConfigMapPropertySourceLocator.class, configMapPropertySourceLocator, - "configDataConfigMapPropertySourceLocator"); + "configDataConfigMapPropertySourceLocator"); } if (secretsProperties != null && secretsProperties.enabled()) { SecretsPropertySourceLocator secretsPropertySourceLocator = new Fabric8SecretsPropertySourceLocator( - kubernetesClient, secretsProperties, namespaceProvider); + kubernetesClient, secretsProperties, namespaceProvider); if (isRetryEnabledForSecrets(secretsProperties)) { secretsPropertySourceLocator = new ConfigDataRetryableSecretsPropertySourceLocator( - secretsPropertySourceLocator, secretsProperties, new Fabric8SecretsCache()); + secretsPropertySourceLocator, secretsProperties, new Fabric8SecretsCache()); } registerSingle(bootstrapContext, SecretsPropertySourceLocator.class, secretsPropertySourceLocator, - "configDataSecretsPropertySourceLocator"); + "configDataSecretsPropertySourceLocator"); } } private KubernetesClient registerConfigAndClient(ConfigurableBootstrapContext bootstrapContext, - KubernetesClientProperties kubernetesClientProperties) { + KubernetesClientProperties kubernetesClientProperties) { Config config = new Fabric8AutoConfiguration().kubernetesClientConfig(kubernetesClientProperties); registerSingle(bootstrapContext, Config.class, config, "fabric8Config"); KubernetesClient kubernetesClient = new Fabric8AutoConfiguration().kubernetesClient(config); registerSingle(bootstrapContext, KubernetesClient.class, kubernetesClient, "configKubernetesClient", - (ApplicationListener) event -> kubernetesClient.close()); + (ApplicationListener) event -> kubernetesClient.close()); 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 dc9fb438ac..8a033e19bb 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 @@ -50,7 +50,7 @@ class Fabric8ConfigDataLocationResolverTests { 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 diff --git a/spring-cloud-kubernetes-fabric8-discovery/src/test/java/org/springframework/cloud/kubernetes/DummyConfigDataLocationResolver.java b/spring-cloud-kubernetes-fabric8-discovery/src/test/java/org/springframework/cloud/kubernetes/DummyConfigDataLocationResolver.java index 8aa2366eb7..b7c6c5bd70 100644 --- a/spring-cloud-kubernetes-fabric8-discovery/src/test/java/org/springframework/cloud/kubernetes/DummyConfigDataLocationResolver.java +++ b/spring-cloud-kubernetes-fabric8-discovery/src/test/java/org/springframework/cloud/kubernetes/DummyConfigDataLocationResolver.java @@ -22,7 +22,7 @@ import org.springframework.boot.context.config.Profiles; import org.springframework.boot.logging.DeferredLogFactory; import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; -import org.springframework.cloud.kubernetes.commons.config.KubernetesConfigDataLocationResolver; +import org.springframework.cloud.kubernetes.commons.config.configdata.KubernetesConfigDataLocationResolver; /** * @author wind57 From 31cf2af979a07c36f0e939e61e290a5aa39161f5 Mon Sep 17 00:00:00 2001 From: wind57 Date: Mon, 1 Sep 2025 10:37:22 +0300 Subject: [PATCH 2/5] refactor code Signed-off-by: wind57 --- ...netesClientConfigDataLocationResolver.java | 18 ++-- ...ClientConfigDataLocationResolverTests.java | 4 +- .../configdata/ConfigDataProperties.java | 4 +- .../KubernetesConfigDataLoader.java | 1 - .../KubernetesConfigDataLocationResolver.java | 16 ++-- .../KubernetesConfigDataResource.java | 84 ++----------------- .../KubernetesConfigDataLoaderTests.java | 8 +- ...rnetesConfigDataLocationResolverTests.java | 51 ++++++----- .../configdata/StorePropertiesResolver.java | 48 +++++++++++ .../Fabric8ConfigDataLocationResolver.java | 20 ++--- .../DummyConfigDataLocationResolver.java | 8 +- 11 files changed, 115 insertions(+), 147 deletions(-) create mode 100644 spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/config/configdata/StorePropertiesResolver.java 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 3f55a860ec..3aa4ce7cf1 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 @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 the original author or authors. + * Copyright 2013-present 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. @@ -45,7 +45,7 @@ public class KubernetesClientConfigDataLocationResolver extends KubernetesConfig @Override protected void registerBeans(ConfigDataLocationResolverContext resolverContext, ConfigDataLocation location, - Profiles profiles, ConfigDataProperties properties, KubernetesNamespaceProvider namespaceProvider) { + Profiles profiles, ConfigDataProperties properties, KubernetesNamespaceProvider namespaceProvider) { KubernetesClientProperties kubernetesClientProperties = properties.clientProperties(); ConfigMapConfigProperties configMapProperties = properties.configMapProperties(); SecretsConfigProperties secretsProperties = properties.secretsProperties(); @@ -55,31 +55,31 @@ protected void registerBeans(ConfigDataLocationResolverContext resolverContext, if (configMapProperties != null && configMapProperties.enabled()) { ConfigMapPropertySourceLocator configMapPropertySourceLocator = new KubernetesClientConfigMapPropertySourceLocator( - coreV1Api, configMapProperties, namespaceProvider); + coreV1Api, configMapProperties, namespaceProvider); if (isRetryEnabledForConfigMap(configMapProperties)) { configMapPropertySourceLocator = new ConfigDataRetryableConfigMapPropertySourceLocator( - configMapPropertySourceLocator, configMapProperties, new KubernetesClientConfigMapsCache()); + configMapPropertySourceLocator, configMapProperties, new KubernetesClientConfigMapsCache()); } registerSingle(bootstrapContext, ConfigMapPropertySourceLocator.class, configMapPropertySourceLocator, - "configDataConfigMapPropertySourceLocator"); + "configDataConfigMapPropertySourceLocator"); } if (secretsProperties != null && secretsProperties.enabled()) { SecretsPropertySourceLocator secretsPropertySourceLocator = new KubernetesClientSecretsPropertySourceLocator( - coreV1Api, namespaceProvider, secretsProperties); + coreV1Api, namespaceProvider, secretsProperties); if (isRetryEnabledForSecrets(secretsProperties)) { secretsPropertySourceLocator = new ConfigDataRetryableSecretsPropertySourceLocator( - secretsPropertySourceLocator, secretsProperties, new KubernetesClientSecretsCache()); + secretsPropertySourceLocator, secretsProperties, new KubernetesClientSecretsCache()); } registerSingle(bootstrapContext, SecretsPropertySourceLocator.class, secretsPropertySourceLocator, - "configDataSecretsPropertySourceLocator"); + "configDataSecretsPropertySourceLocator"); } } private CoreV1Api registerClientAndCoreV1Api(ConfigurableBootstrapContext bootstrapContext, - KubernetesClientProperties kubernetesClientProperties) { + KubernetesClientProperties kubernetesClientProperties) { ApiClient apiClient = kubernetesApiClient(); apiClient.setUserAgent(kubernetesClientProperties.userAgent()); registerSingle(bootstrapContext, ApiClient.class, apiClient, "configDataApiClient"); 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 8966059759..ccd6baf28f 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 @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 the original author or authors. + * Copyright 2013-present 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. @@ -173,7 +173,7 @@ void testBothPresentExplicitly(CapturedOutput capturedOutput) { Assertions.assertThat(capturedOutput.getOut()) .contains("Could not create the Kubernetes ApiClient in a cluster environment, because connection port " - + "was not provided."); + + "was not provided."); } /* 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 index 34239d9007..1446353f3b 100644 --- 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 @@ -29,7 +29,7 @@ /** * @author wind57 */ -record ConfigDataProperties(KubernetesClientProperties clientProperties, +public record ConfigDataProperties(KubernetesClientProperties clientProperties, ConfigMapConfigProperties configMapProperties, SecretsConfigProperties secretsProperties) { static ConfigDataProperties of(ConfigDataLocationResolverContext context) { @@ -43,7 +43,7 @@ static ConfigDataProperties of(ConfigDataLocationResolverContext context) { boolean configEnabled = binder.bind("spring.cloud.kubernetes.config.enabled", boolean.class).orElse(true); if (configEnabled) { configMapProperties = binder.bindOrCreate(ConfigMapConfigProperties.PREFIX, - ConfigMapConfigProperties.class); + ConfigMapConfigProperties.class); } boolean secretsEnabled = binder.bind("spring.cloud.kubernetes.secrets.enabled", boolean.class).orElse(true); diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/configdata/KubernetesConfigDataLoader.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/configdata/KubernetesConfigDataLoader.java index d5d8841aa2..9a3a08de36 100644 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/configdata/KubernetesConfigDataLoader.java +++ b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/configdata/KubernetesConfigDataLoader.java @@ -16,7 +16,6 @@ package org.springframework.cloud.kubernetes.commons.config.configdata; -import java.io.IOException; import java.util.ArrayList; import java.util.List; 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 index 0a97616d65..9dacb184c3 100644 --- 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 @@ -21,6 +21,9 @@ import java.util.List; import java.util.Map; +import jakarta.annotation.Nonnull; +import reactor.util.annotation.NonNull; + import org.springframework.boot.context.config.ConfigDataLocation; import org.springframework.boot.context.config.ConfigDataLocationNotFoundException; import org.springframework.boot.context.config.ConfigDataLocationResolver; @@ -59,22 +62,22 @@ public final int getOrder() { } @Override - public final boolean isResolvable(ConfigDataLocationResolverContext context, ConfigDataLocation location) { + public final boolean isResolvable(@Nonnull 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) + public final List resolve(@NonNull ConfigDataLocationResolverContext context, + @Nonnull ConfigDataLocation location) throws ConfigDataLocationNotFoundException, ConfigDataResourceNotFoundException { return Collections.emptyList(); } @Override public final List resolveProfileSpecific( - ConfigDataLocationResolverContext resolverContext, ConfigDataLocation location, Profiles profiles) - throws ConfigDataLocationNotFoundException { + @Nonnull ConfigDataLocationResolverContext resolverContext, @NonNull ConfigDataLocation location, + @Nonnull Profiles profiles) throws ConfigDataLocationNotFoundException { ConfigDataProperties properties = ConfigDataProperties.of(resolverContext); @@ -89,8 +92,7 @@ public final List resolveProfileSpecific( KubernetesNamespaceProvider namespaceProvider = kubernetesNamespaceProvider(environment); registerBeans(resolverContext, location, profiles, properties, namespaceProvider); - KubernetesConfigDataResource resource = new KubernetesConfigDataResource(properties.clientProperties(), - properties.configMapProperties(), properties.secretsProperties(), location.isOptional(), profiles, + KubernetesConfigDataResource resource = new KubernetesConfigDataResource(location.isOptional(), profiles, environment); return List.of(resource); diff --git a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/configdata/KubernetesConfigDataResource.java b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/configdata/KubernetesConfigDataResource.java index d77a564848..6c451cd94f 100644 --- a/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/configdata/KubernetesConfigDataResource.java +++ b/spring-cloud-kubernetes-commons/src/main/java/org/springframework/cloud/kubernetes/commons/config/configdata/KubernetesConfigDataResource.java @@ -17,106 +17,32 @@ package org.springframework.cloud.kubernetes.commons.config.configdata; import java.util.List; -import java.util.Objects; 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; /** * @author Ryan Baxter */ -public final class KubernetesConfigDataResource extends ConfigDataResource { - - private final KubernetesClientProperties properties; - - private final ConfigMapConfigProperties configMapProperties; - - private final SecretsConfigProperties secretsConfigProperties; - - private final boolean optional; +final class KubernetesConfigDataResource extends ConfigDataResource { private final Profiles profiles; private final Environment environment; - KubernetesConfigDataResource(KubernetesClientProperties properties, ConfigMapConfigProperties configMapProperties, - SecretsConfigProperties secretsConfigProperties, boolean optional, Profiles profiles, - Environment environment) { - this.properties = properties; - this.configMapProperties = configMapProperties; - this.secretsConfigProperties = secretsConfigProperties; - this.optional = optional; + KubernetesConfigDataResource(boolean optional, Profiles profiles, Environment environment) { + super(optional); this.profiles = profiles; this.environment = environment; } - public KubernetesClientProperties getProperties() { - return this.properties; - } - - /** - * ConfigMapConfigProperties that might be null. - */ - public ConfigMapConfigProperties getConfigMapProperties() { - return configMapProperties; - } - - /** - * SecretsConfigProperties that might be null. - */ - public SecretsConfigProperties getSecretsConfigProperties() { - return secretsConfigProperties; - } - - public boolean isOptional() { - return this.optional; - } - - public String getProfiles() { - return StringUtils.collectionToCommaDelimitedString(getAcceptedProfiles()); - } - List getAcceptedProfiles() { return this.profiles.getAccepted(); } - public Environment getEnvironment() { - return environment; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - KubernetesConfigDataResource that = (KubernetesConfigDataResource) o; - return Objects.equals(this.properties, that.properties) && Objects.equals(this.optional, that.optional) - && Objects.equals(this.profiles, that.profiles) - && Objects.equals(this.configMapProperties, that.configMapProperties) - && Objects.equals(this.secretsConfigProperties, that.secretsConfigProperties); - } - - @Override - public int hashCode() { - return Objects.hash(this.properties, this.optional, this.profiles, configMapProperties, - secretsConfigProperties); - } - - @Override - public String toString() { - return new ToStringCreator(this).append("optional", optional) - .append("profiles", profiles.getAccepted()) - .toString(); - + Environment getEnvironment() { + return this.environment; } } diff --git a/spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/config/configdata/KubernetesConfigDataLoaderTests.java b/spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/config/configdata/KubernetesConfigDataLoaderTests.java index d2d4572918..cd0393fd6d 100644 --- a/spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/config/configdata/KubernetesConfigDataLoaderTests.java +++ b/spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/config/configdata/KubernetesConfigDataLoaderTests.java @@ -52,8 +52,8 @@ class KubernetesConfigDataLoaderTests { private static final ConfigurableEnvironment ENVIRONMENT = new MockEnvironment(); - private static final KubernetesConfigDataResource EMPTY_RESOURCE = new KubernetesConfigDataResource(null, null, - null, false, PROFILES, ENVIRONMENT); + private static final KubernetesConfigDataResource EMPTY_RESOURCE = new KubernetesConfigDataResource(false, PROFILES, + ENVIRONMENT); /** * we do not override this method in our implementation, so it should report true for @@ -117,9 +117,9 @@ void testNeitherIsRegisteredDevProfilePresent() throws IOException { * both ConfigMapPropertySourceLocator and SecretsPropertySourceLocator are registered * in bootstrap context. */ - @SuppressWarnings({ "raw", "unchecked" }) + @SuppressWarnings({ "rawtypes", "unchecked" }) @Test - void testBothRegistered() throws IOException { + void testBothRegistered() { PropertySource configMapPropertySource = new MockPropertySource("k8s-config-map"); PropertySource secretsPropertySource = new MockPropertySource("k8s-secrets"); diff --git a/spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/config/configdata/KubernetesConfigDataLocationResolverTests.java b/spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/config/configdata/KubernetesConfigDataLocationResolverTests.java index 5e603d2370..81be9c8beb 100644 --- a/spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/config/configdata/KubernetesConfigDataLocationResolverTests.java +++ b/spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/config/configdata/KubernetesConfigDataLocationResolverTests.java @@ -19,7 +19,6 @@ import java.util.Arrays; import java.util.List; import java.util.Map; -import java.util.function.Supplier; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; @@ -32,7 +31,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.KubernetesNamespaceProvider; import org.springframework.cloud.kubernetes.commons.config.ConfigMapConfigProperties; @@ -44,9 +42,6 @@ */ 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() { @Override protected void registerBeans(ConfigDataLocationResolverContext resolverContext, ConfigDataLocation location, @@ -111,6 +106,7 @@ void testResolve() { @Test void testResolveProfileSpecificOne() { + StorePropertiesResolver storePropertiesResolver = new StorePropertiesResolver(); MockEnvironment environment = new MockEnvironment(); environment.setProperty("spring.application.name", "k8s-app-name"); environment.setProperty("spring.cloud.kubernetes.client.namespace", "non-default-namespace"); @@ -122,7 +118,7 @@ void testResolveProfileSpecificOne() { Profiles profiles = Mockito.mock(Profiles.class); ConfigDataLocation configDataLocation = ConfigDataLocation.of("kubernetes:abc"); - List result = NOOP_RESOLVER.resolveProfileSpecific(RESOLVER_CONTEXT, + List result = storePropertiesResolver.resolveProfileSpecific(RESOLVER_CONTEXT, configDataLocation, profiles); Assertions.assertThat(result.size()).isEqualTo(1); @@ -132,9 +128,10 @@ void testResolveProfileSpecificOne() { .assertThat(result.get(0).getEnvironment().getRequiredProperty("spring.cloud.kubernetes.client.namespace")) .isEqualTo("non-default-namespace"); // ensures that we called 'bindOrCreate' and as such @Default is picked-up - Assertions.assertThat(result.get(0).getProperties().userAgent()) + Assertions.assertThat(storePropertiesResolver.kubernetesClientProperties.userAgent()) .isEqualTo("Spring-Cloud-Kubernetes-Application"); - Assertions.assertThat(result.get(0).getProperties().namespace()).isEqualTo("non-default-namespace"); + Assertions.assertThat(storePropertiesResolver.kubernetesClientProperties.namespace()) + .isEqualTo("non-default-namespace"); } @@ -149,6 +146,7 @@ void testResolveProfileSpecificOne() { @Test void testResolveProfileSpecificTwo() { + StorePropertiesResolver storePropertiesResolver = new StorePropertiesResolver(); MockEnvironment environment = new MockEnvironment(); environment.setProperty("spring.application.name", "k8s-app-name"); environment.setProperty("kubernetes.namespace", "non-default-namespace"); @@ -166,7 +164,7 @@ void testResolveProfileSpecificTwo() { Profiles profiles = Mockito.mock(Profiles.class); ConfigDataLocation configDataLocation = ConfigDataLocation.of("kubernetes:abc"); - List result = NOOP_RESOLVER.resolveProfileSpecific(RESOLVER_CONTEXT, + List result = storePropertiesResolver.resolveProfileSpecific(RESOLVER_CONTEXT, configDataLocation, profiles); Assertions.assertThat(result.size()).isEqualTo(1); @@ -176,8 +174,9 @@ void testResolveProfileSpecificTwo() { .assertThat(result.get(0).getEnvironment().getRequiredProperty("spring.cloud.kubernetes.client.namespace")) .isEqualTo("non-default-namespace"); // ensures we bind existing from bootstrap context, and not call 'bindOrCreate' - Assertions.assertThat(result.get(0).getProperties().userAgent()).isEqualTo("user-agent"); - Assertions.assertThat(result.get(0).getProperties().namespace()).isEqualTo("non-default-namespace"); + Assertions.assertThat(storePropertiesResolver.kubernetesClientProperties.userAgent()).isEqualTo("user-agent"); + Assertions.assertThat(storePropertiesResolver.kubernetesClientProperties.namespace()) + .isEqualTo("non-default-namespace"); } /** @@ -253,6 +252,7 @@ void testResolveProfileSpecificFour() { */ @Test void testResolveProfileSpecificFive() { + StorePropertiesResolver storePropertiesResolver = new StorePropertiesResolver(); MockEnvironment environment = new MockEnvironment(); ConfigurationPropertySources.attach(environment); Binder binder = new Binder(ConfigurationPropertySources.get(environment)); @@ -262,14 +262,13 @@ void testResolveProfileSpecificFive() { Profiles profiles = Mockito.mock(Profiles.class); ConfigDataLocation configDataLocation = ConfigDataLocation.of("kubernetes:abc"); - List result = NOOP_RESOLVER.resolveProfileSpecific(RESOLVER_CONTEXT, - configDataLocation, profiles); + storePropertiesResolver.resolveProfileSpecific(RESOLVER_CONTEXT, configDataLocation, profiles); // we have @DefaultValue("true") boolean enableApi - Assertions.assertThat(result.get(0).getConfigMapProperties().enableApi()).isTrue(); + Assertions.assertThat(storePropertiesResolver.configMapConfigProperties.enableApi()).isTrue(); // we have @DefaultValue("true") boolean enabled - Assertions.assertThat(result.get(0).getSecretsConfigProperties().enabled()).isTrue(); + Assertions.assertThat(storePropertiesResolver.secretsConfigProperties.enabled()).isTrue(); } /** @@ -278,6 +277,7 @@ void testResolveProfileSpecificFive() { */ @Test void testResolveProfileSpecificSix() { + StorePropertiesResolver storePropertiesResolver = new StorePropertiesResolver(); MockEnvironment environment = new MockEnvironment(); environment.setProperty("spring.cloud.kubernetes.config.enable-api", "false"); environment.setProperty("spring.cloud.kubernetes.secrets.paths[0]", "a"); @@ -289,25 +289,25 @@ void testResolveProfileSpecificSix() { Profiles profiles = Mockito.mock(Profiles.class); ConfigDataLocation configDataLocation = ConfigDataLocation.of("kubernetes:abc"); - List result = NOOP_RESOLVER.resolveProfileSpecific(RESOLVER_CONTEXT, - configDataLocation, profiles); + storePropertiesResolver.resolveProfileSpecific(RESOLVER_CONTEXT, configDataLocation, profiles); // we have @DefaultValue("true") boolean enableApi, but it is not going to be // picked up // because of the explicit property we set in environment - Assertions.assertThat(result.get(0).getConfigMapProperties().enableApi()).isFalse(); + Assertions.assertThat(storePropertiesResolver.configMapConfigProperties.enableApi()).isFalse(); // on the other hand, @Default will be picked here - Assertions.assertThat(result.get(0).getConfigMapProperties().enabled()).isTrue(); + Assertions.assertThat(storePropertiesResolver.configMapConfigProperties.enabled()).isTrue(); // we have @DefaultValue enabled on paths, but it is not going to be picked up // because of the explicit property we set in environment - Assertions.assertThat(result.get(0).getSecretsConfigProperties().paths().get(0)).isEqualTo("a"); + Assertions.assertThat(storePropertiesResolver.secretsConfigProperties.paths().get(0)).isEqualTo("a"); // on the other hand, @Default will be picked here - Assertions.assertThat(result.get(0).getSecretsConfigProperties().includeProfileSpecificSources()).isTrue(); + Assertions.assertThat(storePropertiesResolver.secretsConfigProperties.includeProfileSpecificSources()).isTrue(); } @Test void testIsOptional() { + StorePropertiesResolver storePropertiesResolver = new StorePropertiesResolver(); MockEnvironment environment = new MockEnvironment(); ConfigurationPropertySources.attach(environment); Binder binder = new Binder(ConfigurationPropertySources.get(environment)); @@ -317,14 +317,12 @@ void testIsOptional() { Profiles profiles = Mockito.mock(Profiles.class); ConfigDataLocation configDataLocation = ConfigDataLocation.of("kubernetes:abc"); - List result = NOOP_RESOLVER.resolveProfileSpecific(RESOLVER_CONTEXT, - configDataLocation, profiles); - - Assertions.assertThat(result.get(0).isOptional()).isFalse(); + storePropertiesResolver.resolveProfileSpecific(RESOLVER_CONTEXT, configDataLocation, profiles); } @Test void testProfiles() { + StorePropertiesResolver storePropertiesResolver = new StorePropertiesResolver(); MockEnvironment environment = new MockEnvironment(); ConfigurationPropertySources.attach(environment); Binder binder = new Binder(ConfigurationPropertySources.get(environment)); @@ -336,12 +334,11 @@ void testProfiles() { Mockito.when(profiles.getAccepted()).thenReturn(List.of("a", "b")); ConfigDataLocation configDataLocation = ConfigDataLocation.of("kubernetes:abc"); - List result = NOOP_RESOLVER.resolveProfileSpecific(RESOLVER_CONTEXT, + List result = storePropertiesResolver.resolveProfileSpecific(RESOLVER_CONTEXT, configDataLocation, profiles); Assertions.assertThat(Arrays.stream(result.get(0).getEnvironment().getActiveProfiles()).toList()) .containsExactly("a", "b"); - Assertions.assertThat(result.get(0).getProfiles()).isEqualTo("a,b"); } } diff --git a/spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/config/configdata/StorePropertiesResolver.java b/spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/config/configdata/StorePropertiesResolver.java new file mode 100644 index 0000000000..b928193043 --- /dev/null +++ b/spring-cloud-kubernetes-commons/src/test/java/org/springframework/cloud/kubernetes/commons/config/configdata/StorePropertiesResolver.java @@ -0,0 +1,48 @@ +/* + * Copyright 2013-present 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.ConfigDataLocation; +import org.springframework.boot.context.config.ConfigDataLocationResolverContext; +import org.springframework.boot.context.config.Profiles; +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; + +/** + * @author wind57 + */ +class StorePropertiesResolver extends KubernetesConfigDataLocationResolver { + + SecretsConfigProperties secretsConfigProperties; + + ConfigMapConfigProperties configMapConfigProperties; + + KubernetesClientProperties kubernetesClientProperties; + + @Override + protected void registerBeans(ConfigDataLocationResolverContext resolverContext, ConfigDataLocation location, + Profiles profiles, ConfigDataProperties properties, KubernetesNamespaceProvider namespaceProvider) { + + secretsConfigProperties = properties.secretsProperties(); + configMapConfigProperties = properties.configMapProperties(); + kubernetesClientProperties = properties.clientProperties(); + + } + +} 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 9c494285fa..0251598c6d 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 @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 the original author or authors. + * Copyright 2013-present 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. @@ -46,7 +46,7 @@ public class Fabric8ConfigDataLocationResolver extends KubernetesConfigDataLocat @Override protected void registerBeans(ConfigDataLocationResolverContext resolverContext, ConfigDataLocation location, - Profiles profiles, ConfigDataProperties properties, KubernetesNamespaceProvider namespaceProvider) { + Profiles profiles, ConfigDataProperties properties, KubernetesNamespaceProvider namespaceProvider) { KubernetesClientProperties kubernetesClientProperties = properties.clientProperties(); ConfigMapConfigProperties configMapProperties = properties.configMapProperties(); SecretsConfigProperties secretsProperties = properties.secretsProperties(); @@ -56,38 +56,38 @@ protected void registerBeans(ConfigDataLocationResolverContext resolverContext, if (configMapProperties != null && configMapProperties.enabled()) { ConfigMapPropertySourceLocator configMapPropertySourceLocator = new Fabric8ConfigMapPropertySourceLocator( - kubernetesClient, configMapProperties, namespaceProvider); + kubernetesClient, configMapProperties, namespaceProvider); if (isRetryEnabledForConfigMap(configMapProperties)) { configMapPropertySourceLocator = new ConfigDataRetryableConfigMapPropertySourceLocator( - configMapPropertySourceLocator, configMapProperties, new Fabric8ConfigMapsCache()); + configMapPropertySourceLocator, configMapProperties, new Fabric8ConfigMapsCache()); } registerSingle(bootstrapContext, ConfigMapPropertySourceLocator.class, configMapPropertySourceLocator, - "configDataConfigMapPropertySourceLocator"); + "configDataConfigMapPropertySourceLocator"); } if (secretsProperties != null && secretsProperties.enabled()) { SecretsPropertySourceLocator secretsPropertySourceLocator = new Fabric8SecretsPropertySourceLocator( - kubernetesClient, secretsProperties, namespaceProvider); + kubernetesClient, secretsProperties, namespaceProvider); if (isRetryEnabledForSecrets(secretsProperties)) { secretsPropertySourceLocator = new ConfigDataRetryableSecretsPropertySourceLocator( - secretsPropertySourceLocator, secretsProperties, new Fabric8SecretsCache()); + secretsPropertySourceLocator, secretsProperties, new Fabric8SecretsCache()); } registerSingle(bootstrapContext, SecretsPropertySourceLocator.class, secretsPropertySourceLocator, - "configDataSecretsPropertySourceLocator"); + "configDataSecretsPropertySourceLocator"); } } private KubernetesClient registerConfigAndClient(ConfigurableBootstrapContext bootstrapContext, - KubernetesClientProperties kubernetesClientProperties) { + KubernetesClientProperties kubernetesClientProperties) { Config config = new Fabric8AutoConfiguration().kubernetesClientConfig(kubernetesClientProperties); registerSingle(bootstrapContext, Config.class, config, "fabric8Config"); KubernetesClient kubernetesClient = new Fabric8AutoConfiguration().kubernetesClient(config); registerSingle(bootstrapContext, KubernetesClient.class, kubernetesClient, "configKubernetesClient", - (ApplicationListener) event -> kubernetesClient.close()); + (ApplicationListener) event -> kubernetesClient.close()); return kubernetesClient; } diff --git a/spring-cloud-kubernetes-fabric8-discovery/src/test/java/org/springframework/cloud/kubernetes/DummyConfigDataLocationResolver.java b/spring-cloud-kubernetes-fabric8-discovery/src/test/java/org/springframework/cloud/kubernetes/DummyConfigDataLocationResolver.java index b7c6c5bd70..a729fa3973 100644 --- a/spring-cloud-kubernetes-fabric8-discovery/src/test/java/org/springframework/cloud/kubernetes/DummyConfigDataLocationResolver.java +++ b/spring-cloud-kubernetes-fabric8-discovery/src/test/java/org/springframework/cloud/kubernetes/DummyConfigDataLocationResolver.java @@ -20,8 +20,8 @@ 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.KubernetesNamespaceProvider; +import org.springframework.cloud.kubernetes.commons.config.configdata.ConfigDataProperties; import org.springframework.cloud.kubernetes.commons.config.configdata.KubernetesConfigDataLocationResolver; /** @@ -30,13 +30,9 @@ @ConditionalOnProperty(value = "dummy.config.loader.enabled", havingValue = "true", matchIfMissing = false) class DummyConfigDataLocationResolver extends KubernetesConfigDataLocationResolver { - DummyConfigDataLocationResolver(DeferredLogFactory factory) { - super(factory); - } - @Override protected void registerBeans(ConfigDataLocationResolverContext resolverContext, ConfigDataLocation location, - Profiles profiles, PropertyHolder propertyHolder, KubernetesNamespaceProvider namespaceProvider) { + Profiles profiles, ConfigDataProperties properties, KubernetesNamespaceProvider namespaceProvider) { } From c8fe4d6a082d586afef1b57422b809c51e5f1ea9 Mon Sep 17 00:00:00 2001 From: wind57 Date: Wed, 3 Sep 2025 22:28:39 +0300 Subject: [PATCH 3/5] WIP Signed-off-by: wind57 --- .../cloud/kubernetes/DummyConfigDataLocationResolver.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/spring-cloud-kubernetes-fabric8-discovery/src/test/java/org/springframework/cloud/kubernetes/DummyConfigDataLocationResolver.java b/spring-cloud-kubernetes-fabric8-discovery/src/test/java/org/springframework/cloud/kubernetes/DummyConfigDataLocationResolver.java index a729fa3973..52e8c19f16 100644 --- a/spring-cloud-kubernetes-fabric8-discovery/src/test/java/org/springframework/cloud/kubernetes/DummyConfigDataLocationResolver.java +++ b/spring-cloud-kubernetes-fabric8-discovery/src/test/java/org/springframework/cloud/kubernetes/DummyConfigDataLocationResolver.java @@ -32,8 +32,7 @@ class DummyConfigDataLocationResolver extends KubernetesConfigDataLocationResolv @Override protected void registerBeans(ConfigDataLocationResolverContext resolverContext, ConfigDataLocation location, - Profiles profiles, ConfigDataProperties properties, KubernetesNamespaceProvider namespaceProvider) { + Profiles profiles, ConfigDataProperties properties, KubernetesNamespaceProvider namespaceProvider) { } - } From ac96da8e8d2ba8d1123cb2db17c83a73a4453148 Mon Sep 17 00:00:00 2001 From: wind57 Date: Thu, 4 Sep 2025 18:02:18 +0300 Subject: [PATCH 4/5] fix broken tests Signed-off-by: wind57 --- .../configdata/ConfigDataProperties.java | 27 +++++++++++-------- .../DummyConfigDataLocationResolver.java | 3 ++- 2 files changed, 18 insertions(+), 12 deletions(-) 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 index 1446353f3b..81ce95ec32 100644 --- 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 @@ -32,6 +32,12 @@ public record ConfigDataProperties(KubernetesClientProperties clientProperties, ConfigMapConfigProperties configMapProperties, SecretsConfigProperties secretsProperties) { + private static final Class CONFIGMAP_PROPERTIES_CLASS = ConfigMapConfigProperties.class; + + private static final Class SECRETS_PROPERTIES_CLASS = SecretsConfigProperties.class; + + private static final Class CLIENT_PROPERTIES_CLASS = KubernetesClientProperties.class; + static ConfigDataProperties of(ConfigDataLocationResolverContext context) { KubernetesClientProperties clientProperties; @@ -42,13 +48,12 @@ static ConfigDataProperties of(ConfigDataLocationResolverContext context) { boolean configEnabled = binder.bind("spring.cloud.kubernetes.config.enabled", boolean.class).orElse(true); if (configEnabled) { - configMapProperties = binder.bindOrCreate(ConfigMapConfigProperties.PREFIX, - ConfigMapConfigProperties.class); + configMapProperties = binder.bindOrCreate(ConfigMapConfigProperties.PREFIX, CONFIGMAP_PROPERTIES_CLASS); } boolean secretsEnabled = binder.bind("spring.cloud.kubernetes.secrets.enabled", boolean.class).orElse(true); if (secretsEnabled) { - secretsProperties = binder.bindOrCreate(SecretsConfigProperties.PREFIX, SecretsConfigProperties.class); + secretsProperties = binder.bindOrCreate(SecretsConfigProperties.PREFIX, SECRETS_PROPERTIES_CLASS); } String namespace = binder.bind("spring.cloud.kubernetes.client.namespace", String.class) @@ -65,16 +70,16 @@ private static void registerProperties(ConfigDataLocationResolverContext resolve ConfigurableBootstrapContext bootstrapContext = resolverContext.getBootstrapContext(); - registerSingle(bootstrapContext, KubernetesClientProperties.class, clientProperties, + registerSingle(bootstrapContext, CLIENT_PROPERTIES_CLASS, clientProperties, "configDataKubernetesClientProperties"); if (configMapProperties != null) { - registerSingle(bootstrapContext, ConfigMapConfigProperties.class, configMapProperties, + registerSingle(bootstrapContext, CONFIGMAP_PROPERTIES_CLASS, configMapProperties, "configDataConfigMapConfigProperties"); } if (secretsProperties != null) { - registerSingle(bootstrapContext, SecretsConfigProperties.class, secretsProperties, + registerSingle(bootstrapContext, SECRETS_PROPERTIES_CLASS, secretsProperties, "configDataSecretsConfigProperties"); } @@ -83,14 +88,14 @@ private static void registerProperties(ConfigDataLocationResolverContext resolve private static KubernetesClientProperties clientProperties(ConfigDataLocationResolverContext context, String namespace) { KubernetesClientProperties kubernetesClientProperties; - if (context.getBootstrapContext().isRegistered(KubernetesClientProperties.class)) { - kubernetesClientProperties = context.getBootstrapContext() - .get(KubernetesClientProperties.class) - .withNamespace(namespace); + ConfigurableBootstrapContext bootstrapContext = context.getBootstrapContext(); + KubernetesClientProperties registeredClientProperties = bootstrapContext.get(CLIENT_PROPERTIES_CLASS); + if (bootstrapContext.isRegistered(CLIENT_PROPERTIES_CLASS) && registeredClientProperties != null) { + kubernetesClientProperties = registeredClientProperties.withNamespace(namespace); } else { kubernetesClientProperties = context.getBinder() - .bindOrCreate(KubernetesClientProperties.PREFIX, Bindable.of(KubernetesClientProperties.class)) + .bindOrCreate(KubernetesClientProperties.PREFIX, Bindable.of(CLIENT_PROPERTIES_CLASS)) .withNamespace(namespace); } return kubernetesClientProperties; diff --git a/spring-cloud-kubernetes-fabric8-discovery/src/test/java/org/springframework/cloud/kubernetes/DummyConfigDataLocationResolver.java b/spring-cloud-kubernetes-fabric8-discovery/src/test/java/org/springframework/cloud/kubernetes/DummyConfigDataLocationResolver.java index 52e8c19f16..a729fa3973 100644 --- a/spring-cloud-kubernetes-fabric8-discovery/src/test/java/org/springframework/cloud/kubernetes/DummyConfigDataLocationResolver.java +++ b/spring-cloud-kubernetes-fabric8-discovery/src/test/java/org/springframework/cloud/kubernetes/DummyConfigDataLocationResolver.java @@ -32,7 +32,8 @@ class DummyConfigDataLocationResolver extends KubernetesConfigDataLocationResolv @Override protected void registerBeans(ConfigDataLocationResolverContext resolverContext, ConfigDataLocation location, - Profiles profiles, ConfigDataProperties properties, KubernetesNamespaceProvider namespaceProvider) { + Profiles profiles, ConfigDataProperties properties, KubernetesNamespaceProvider namespaceProvider) { } + } From e7d3a0ec0d7c9d3692af341e12b48d99b6c7f02d Mon Sep 17 00:00:00 2001 From: wind57 Date: Thu, 4 Sep 2025 18:25:25 +0300 Subject: [PATCH 5/5] fix broken tests Signed-off-by: wind57 --- .../commons/config/configdata/ConfigDataProperties.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 index 81ce95ec32..ee31c35731 100644 --- 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 @@ -89,9 +89,9 @@ private static KubernetesClientProperties clientProperties(ConfigDataLocationRes String namespace) { KubernetesClientProperties kubernetesClientProperties; ConfigurableBootstrapContext bootstrapContext = context.getBootstrapContext(); - KubernetesClientProperties registeredClientProperties = bootstrapContext.get(CLIENT_PROPERTIES_CLASS); - if (bootstrapContext.isRegistered(CLIENT_PROPERTIES_CLASS) && registeredClientProperties != null) { - kubernetesClientProperties = registeredClientProperties.withNamespace(namespace); + if (bootstrapContext.isRegistered(CLIENT_PROPERTIES_CLASS) + && bootstrapContext.get(CLIENT_PROPERTIES_CLASS) != null) { + kubernetesClientProperties = bootstrapContext.get(CLIENT_PROPERTIES_CLASS).withNamespace(namespace); } else { kubernetesClientProperties = context.getBinder()