spring-cloud / spring-cloud-kubernetes

Kubernetes integration with Spring Cloud Discovery Client, Configuration, etc...
Apache License 2.0
3.45k stars 1.03k forks source link

How to detect that a configmap is present #1682

Closed c4rth closed 2 weeks ago

c4rth commented 1 month ago

I have a spring boot 3 application deployed in Kubernetes and also a configmap The spring app uses : implementation("org.springframework.cloud:spring-cloud-starter") implementation("org.springframework.cloud:spring-cloud-starter-kubernetes-fabric8-all")

In Kubernetes, the app has an environment variable SPRING_CLOUD_BOOTSTRAP_ENABLED to true.

I would like to verify that a configmap linked to the application is available and has been loaded.

rem: I don't known which values will be defined in it, I cannot check one value, I just want check its existence.

What I tried

Here is the code of my EnvironmentPostProcessor

public class TestEnvironmentPostProcessor implements EnvironmentPostProcessor {

    private final Log log;

    public TestEnvironmentPostProcessor(DeferredLogFactory logFactory) {
        this.log = logFactory.getLog(getClass());
    }

    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        if (isKubernetes(environment)) {
            log.info("Running in Kubernetes");
        } else {
            log.info("NOT running in Kubernetes");
            return;
        }
        environment.getPropertySources().forEach(ps -> {
            log.info(ps.getName() + " = " + ps.getClass().getName());
            if (ps.getName().equals("KUBERNETES_NAMESPACE_PROPERTY_SOURCE")) {
                log.info("--> KUBERNETES_NAMESPACE_PROPERTY_SOURCE");
                MapPropertySource mps = (MapPropertySource) ps;
                var str1 = Arrays.stream(mps.getPropertyNames()).map(key -> key + " = " + mps.getProperty(key))
                        .collect(Collectors.joining(", ", "{", "}"));
                log.info("properties = " + str1);
                var source = mps.getSource();
                var str2 = source.keySet().stream()
                        .map(key -> key + " = " + source.get(key))
                        .collect(Collectors.joining(", ", "{", "}"));
                log.info("source = " + str2);
                List.of("spring.application.name", "k8s.key1", "k8s.key2").forEach(key -> {
                var x= environment.getProperty(key);
                log.warn(key + " = " + x);
              });
            }
        });

    }

    private boolean isKubernetes(ConfigurableEnvironment environment) {
        return CloudPlatform.KUBERNETES.isActive(environment);
    }
}

An other strange thing: the TestEnvironmentPostProcessor runs before the app starts and after. In both case the properties defined in configmap are unknow. When my app has started, the values are known, here is the log

[           main] g.p.b.v.TestEnvironmentPostProcessor     : *******************************
[           main] g.p.b.v.TestEnvironmentPostProcessor     : Running in Kubernetes
[           main] g.p.b.v.TestEnvironmentPostProcessor     : configurationProperties = org.springframework.boot.context.properties.source.ConfigurationPropertySourcesPropertySource
[           main] g.p.b.v.TestEnvironmentPostProcessor     : bootstrap = org.springframework.core.env.MapPropertySource
[           main] g.p.b.v.TestEnvironmentPostProcessor     : systemProperties = org.springframework.core.env.PropertiesPropertySource
[           main] g.p.b.v.TestEnvironmentPostProcessor     : systemEnvironment = org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor$OriginAwareSystemEnvironmentPropertySource
[           main] g.p.b.v.TestEnvironmentPostProcessor     : random = org.springframework.boot.env.RandomValuePropertySource
[           main] g.p.b.v.TestEnvironmentPostProcessor     : cachedrandom = org.springframework.cloud.util.random.CachedRandomPropertySource
[           main] g.p.b.v.TestEnvironmentPostProcessor     : KUBERNETES_NAMESPACE_PROPERTY_SOURCE = org.springframework.core.env.MapPropertySource
[           main] g.p.b.v.TestEnvironmentPostProcessor     : --> KUBERNETES_NAMESPACE_PROPERTY_SOURCE
[           main] g.p.b.v.TestEnvironmentPostProcessor     : properties = {spring.cloud.kubernetes.client.namespace = default}
[           main] g.p.b.v.TestEnvironmentPostProcessor     : source = {spring.cloud.kubernetes.client.namespace = default}
[           main] g.p.b.v.TestEnvironmentPostProcessor     : springCloudClientHostInfo = org.springframework.core.env.MapPropertySource
[           main] g.p.b.v.TestEnvironmentPostProcessor     : spring.application.name = null
[           main] g.p.b.v.TestEnvironmentPostProcessor     : k8s.key1 = null
[           main] g.p.b.v.TestEnvironmentPostProcessor     : k8s.key2 = null

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/

 :: Spring Boot ::                (v3.3.2)

[spring-app-virtual] [           main] o.s.c.k.commons.config.ConfigUtils       : ConfigMap name has not been set, taking it from property/env spring.application.name (default=application)
[spring-app-virtual] [           main] s.c.k.c.c.ConfigMapPropertySourceLocator : Config Map normalized sources : [{ config-map name : 'Optional[spring-app-virtual]', namespace : 'Optional.empty', prefix : '[ConfigUtils.Prefix@36417a54 name = 'DEFAULT']' }]
[spring-app-virtual] [           main] o.s.c.kubernetes.fabric8.Fabric8Utils    : configmap namespace from provider : default
[spring-app-virtual] [           main] o.s.c.k.f.config.Fabric8ConfigMapsCache  : Loaded all config maps in namespace 'default'
[spring-app-virtual] [           main] o.s.c.k.commons.config.ConfigUtils       : Found source with name : 'spring-app-virtual in namespace: 'default'
[spring-app-virtual] [           main] o.s.c.k.c.c.SourceDataEntriesProcessor   : The single property with name: [application.yaml] will be treated as a yaml file
[spring-app-virtual] [           main] s.c.k.c.c.ConfigMapPropertySourceLocator : paths property sources : []
[spring-app-virtual] [           main] b.c.PropertySourceBootstrapConfiguration : Located property source: [BootstrapPropertySource {name='bootstrapProperties-configmap.spring-app-virtual.default'}]
[spring-app-virtual] [           main] o.s.c.k.commons.config.ConfigUtils       : Secret name has not been set, taking it from property/env spring.application.name (default=application)
[spring-app-virtual] [           main] o.s.c.k.c.c.SecretsPropertySourceLocator : Secrets normalized sources : [{ secret name : 'Optional[spring-app-virtual]', namespace : 'Optional.empty']
[spring-app-virtual] [           main] ubernetesProfileEnvironmentPostProcessor : 'kubernetes' already in list of active profiles
[spring-app-virtual] [           main] gae.piaz.boot.virtual.Application        : The following 1 profile is active: "kubernetes"
[spring-app-virtual] [           main] g.p.b.v.TestEnvironmentPostProcessor     : *******************************
[spring-app-virtual] [           main] g.p.b.v.TestEnvironmentPostProcessor     : Running in Kubernetes
[spring-app-virtual] [           main] g.p.b.v.TestEnvironmentPostProcessor     : configurationProperties = org.springframework.boot.context.properties.source.ConfigurationPropertySourcesPropertySource
[spring-app-virtual] [           main] g.p.b.v.TestEnvironmentPostProcessor     : servletConfigInitParams = org.springframework.core.env.PropertySource$StubPropertySource
[spring-app-virtual] [           main] g.p.b.v.TestEnvironmentPostProcessor     : servletContextInitParams = org.springframework.core.env.PropertySource$StubPropertySource
[spring-app-virtual] [           main] g.p.b.v.TestEnvironmentPostProcessor     : systemProperties = org.springframework.core.env.PropertiesPropertySource
[spring-app-virtual] [           main] g.p.b.v.TestEnvironmentPostProcessor     : systemEnvironment = org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor$OriginAwareSystemEnvironmentPropertySource
[spring-app-virtual] [           main] g.p.b.v.TestEnvironmentPostProcessor     : random = org.springframework.boot.env.RandomValuePropertySource
[spring-app-virtual] [           main] g.p.b.v.TestEnvironmentPostProcessor     : springCloudDefaultProperties = org.springframework.cloud.bootstrap.BootstrapApplicationListener$ExtendedDefaultPropertySource
[spring-app-virtual] [           main] g.p.b.v.TestEnvironmentPostProcessor     : cachedrandom = org.springframework.cloud.util.random.CachedRandomPropertySource
[spring-app-virtual] [           main] g.p.b.v.TestEnvironmentPostProcessor     : KUBERNETES_NAMESPACE_PROPERTY_SOURCE = org.springframework.core.env.MapPropertySource
[spring-app-virtual] [           main] g.p.b.v.TestEnvironmentPostProcessor     : --> KUBERNETES_NAMESPACE_PROPERTY_SOURCE
[spring-app-virtual] [           main] g.p.b.v.TestEnvironmentPostProcessor     : properties = {spring.cloud.kubernetes.client.namespace = default}
[spring-app-virtual] [           main] g.p.b.v.TestEnvironmentPostProcessor     : source = {spring.cloud.kubernetes.client.namespace = default}
[spring-app-virtual] [           main] g.p.b.v.TestEnvironmentPostProcessor     : Config resource 'class path resource [application.yaml]' via location 'optional:classpath:/' = org.springframework.boot.env.OriginTrackedMapPropertySource
[spring-app-virtual] [           main] g.p.b.v.TestEnvironmentPostProcessor     : springCloudClientHostInfo = org.springframework.core.env.MapPropertySource
[spring-app-virtual] [           main] g.p.b.v.TestEnvironmentPostProcessor     : applicationConfig: [classpath:/application.yaml] = org.springframework.boot.env.OriginTrackedMapPropertySource
[spring-app-virtual] [           main] g.p.b.v.TestEnvironmentPostProcessor     : spring.application.name = spring-app-virtual
[spring-app-virtual] [           main] g.p.b.v.TestEnvironmentPostProcessor     : k8s.key1 = null
[spring-app-virtual] [           main] g.p.b.v.TestEnvironmentPostProcessor     : k8s.key2 = null
[spring-app-virtual] [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
[spring-app-virtual] [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 100 ms. Found 3 JPA repository interfaces.
[spring-app-virtual] [           main] led$OnBlockingOrReactiveDiscoveryEnabled : Condition ConditionalOnBlockingOrReactiveDiscoveryEnabled.OnBlockingOrReactiveDiscoveryEnabled on org.springframework.cloud.kubernetes.fabric8.discovery.KubernetesCatalogWatchAutoConfiguration matched due to AnyNestedCondition 1 matched 1 did not; NestedCondition on ConditionalOnBlockingOrReactiveDiscoveryEnabled.OnBlockingOrReactiveDiscoveryEnabled.OnReactiveDiscoveryEnabled found non-matching nested conditions @ConditionalOnClass did not find required class 'org.springframework.web.reactive.function.client.WebClient'; NestedCondition on ConditionalOnBlockingOrReactiveDiscoveryEnabled.OnBlockingOrReactiveDiscoveryEnabled.OnBlockingDiscoveryEnabled @ConditionalOnProperty (spring.cloud.discovery.blocking.enabled) matched
[spring-app-virtual] [           main] o.s.cloud.context.scope.GenericScope     : BeanFactory id=aa14e53e-a512-3d44-9df4-9fdd14a1a107
[spring-app-virtual] [           main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration$DeferringLoadBalancerInterceptorConfig' of type [org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration$DeferringLoadBalancerInterceptorConfig] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). The currently created BeanPostProcessor [lbRestClientPostProcessor] is declared through a non-static factory method on that class; consider declaring it as static instead.
[spring-app-virtual] [           main] trationDelegate$BeanPostProcessorChecker : Bean 'deferringLoadBalancerInterceptor' of type [org.springframework.cloud.client.loadbalancer.DeferringLoadBalancerInterceptor] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected into a currently created BeanPostProcessor [lbRestClientPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies.
[spring-app-virtual] [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port 8080 (http)
[spring-app-virtual] [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
[spring-app-virtual] [           main] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: [Apache Tomcat/10.1.26]
[spring-app-virtual] [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
[spring-app-virtual] [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1393 ms
[spring-app-virtual] [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [name: default]
[spring-app-virtual] [           main] org.hibernate.Version                    : HHH000412: Hibernate ORM core version 6.5.2.Final
[spring-app-virtual] [           main] o.h.c.internal.RegionFactoryInitiator    : HHH000026: Second-level cache disabled
[spring-app-virtual] [           main] o.s.o.j.p.SpringPersistenceUnitInfo      : No LoadTimeWeaver setup: ignoring JPA class transformer
[spring-app-virtual] [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
[spring-app-virtual] [           main] com.zaxxer.hikari.pool.HikariPool        : HikariPool-1 - Added connection conn0: url=jdbc:h2:mem:testdb user=SA
[spring-app-virtual] [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
[spring-app-virtual] [           main] org.hibernate.orm.deprecation            : HHH90000025: H2Dialect does not need to be specified explicitly using 'hibernate.dialect' (remove the property setting and it will be selected by default)
[spring-app-virtual] [           main] o.h.e.t.j.p.i.JtaPlatformInitiator       : HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
[spring-app-virtual] [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
[spring-app-virtual] [           main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
[spring-app-virtual] [           main] o.s.c.k.c.KubernetesNamespaceProvider    : Looking for service account namespace at: [/var/run/secrets/kubernetes.io/serviceaccount/namespace].
[spring-app-virtual] [           main] o.s.c.k.c.KubernetesNamespaceProvider    : Found service account namespace at: [/var/run/secrets/kubernetes.io/serviceaccount/namespace].
[spring-app-virtual] [           main] o.s.c.k.c.KubernetesNamespaceProvider    : Service account namespace value: /var/run/secrets/kubernetes.io/serviceaccount/namespace
[spring-app-virtual] [           main] bernetesDiscoveryClientAutoConfiguration : Will publish InstanceRegisteredEvent from blocking implementation
[spring-app-virtual] [           main] iscoveryClientHealthIndicatorInitializer : publishing InstanceRegisteredEvent
[spring-app-virtual] [           main] o.s.c.k.f.d.KubernetesCatalogWatch       : stateGenerator is of type: Fabric8EndpointsCatalogWatch
[spring-app-virtual] [           main] iguration$LoadBalancerCaffeineWarnLogger : Spring Cloud LoadBalancer is currently working with the default cache. While this cache implementation is useful for development and tests, it's recommended to use Caffeine cache in production.You can switch to using Caffeine cache, by adding it and org.springframework.cache.caffeine.CaffeineCacheManager to the classpath.
[spring-app-virtual] [           main] o.s.b.a.e.web.EndpointLinksResolver      : Exposing 17 endpoints beneath base path '/actuator'
[spring-app-virtual] [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port 8080 (http) with context path '/'
[spring-app-virtual] [           main] gae.piaz.boot.virtual.Application        : Started Application in 5.525 seconds (process running for 5.715)
[spring-app-virtual] [           main] gae.piaz.boot.virtual.Application        : spring.application.name = spring-app-virtual
[spring-app-virtual] [           main] gae.piaz.boot.virtual.Application        : k8s.key1 = value1
[spring-app-virtual] [           main] gae.piaz.boot.virtual.Application        : k8s.key2 = value2
ryanjbaxter commented 1 month ago

I would like to verify that a configmap linked to the application is available and has been loaded.

Can I ask why and what you are trying to accomplish by knowing this?

c4rth commented 1 month ago

Sure. I just would like to know when I start an application if a configmap is loaded, to validate that the deployments in k8s are ok. Sometimes, the configmap definition is not right: name that doesn't match the spring app name, wrong namespace or not deployed. It is simply to add a validation step.

ryanjbaxter commented 1 month ago

One approach I can think of is to have a Bean which takes in all SourceDataEntriesProcessor or Fabric8ConfigMapPropertySource if you really want to by hyper-specific. You can look at the name of those PropertySources to determine whether one of them is the config map you are concerned about and if not throw an Exception. You could then use AbstractFailureAnalyze from Spring Boot to produce a FailureAnalysis object and provide a meaningful reason for the failure.

c4rth commented 1 month ago

Thanks for this possible solution.

With spring.config.import: 'kubernetes:', I can find a CompositePropertySource named composite-configmap containing a Fabric8ConfigMapPropertySource containing all the properties of the configmap and if no configmap, the properties are empty.

With 'spring.cloud.bootstrap.enabled: true', no Fabric8ConfigMapPropertySource but a BootstrapPropertySource containing all the properties of the configmap and if no configmap, the properties are empty.

I prefer the 1st possibility, but the issue is if I add org.springframework.cloud:spring-cloud-starter-bootstrap or spring.cloud.bootstrap.enabled:, the app doesn't start.

ryanjbaxter commented 1 month ago

You are going to have to provide more information than "the app doesn't start" for us to help

c4rth commented 1 month ago

Indeed, sorry.

2024-08-06T16:16:50.748+01:00  WARN 1 --- [           main] [                                                 ] s.c.a.AnnotationConfigApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'configMapPropertySourceLocator' defined in class path resource [org/springframework/cloud/kubernetes/fabric8/config/Fabric8BootstrapConfiguration.class]: Unsatisfied dependency expressed through method 'configMapPropertySourceLocator' parameter 0: No qualifying bean of type 'org.springframework.cloud.kubernetes.commons.config.ConfigMapConfigProperties' available: expected single matching bean but found 2: spring.cloud.kubernetes.config-org.springframework.cloud.kubernetes.commons.config.ConfigMapConfigProperties,configDataConfigMapConfigProperties
2024-08-06T16:16:50.749+01:00  INFO 1 --- [           main] [                                                 ] .s.b.a.l.ConditionEvaluationReportLogger : 

Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
2024-08-06T16:16:50.760+01:00 ERROR 1 --- [           main] [                                                 ] o.s.b.d.LoggingFailureAnalysisReporter   : 

***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 0 of method configMapPropertySourceLocator in org.springframework.cloud.kubernetes.fabric8.config.Fabric8BootstrapConfiguration required a single bean, but 2 were found:
    - spring.cloud.kubernetes.config-org.springframework.cloud.kubernetes.commons.config.ConfigMapConfigProperties: defined in unknown location
    - configDataConfigMapConfigProperties: a programmatically registered singleton

This may be due to missing parameter name information

Action:

Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed

Ensure that your compiler is configured to use the '-parameters' flag.
You may need to update both your build tool settings as well as your IDE.
(See https://github.com/spring-projects/spring-framework/wiki/Upgrading-to-Spring-Framework-6.x#parameter-name-retention)

2024-08-06T16:16:50.761+01:00 ERROR 1 --- [           main] [                                                 ] o.s.boot.SpringApplication               : Application run failed

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'configMapPropertySourceLocator' defined in class path resource [org/springframework/cloud/kubernetes/fabric8/config/Fabric8BootstrapConfiguration.class]: Unsatisfied dependency expressed through method 'configMapPropertySourceLocator' parameter 0: No qualifying bean of type 'org.springframework.cloud.kubernetes.commons.config.ConfigMapConfigProperties' available: expected single matching bean but found 2: spring.cloud.kubernetes.config-org.springframework.cloud.kubernetes.commons.config.ConfigMapConfigProperties,configDataConfigMapConfigProperties
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:795) ~[spring-beans-6.1.11.jar:6.1.11]
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:542) ~[spring-beans-6.1.11.jar:6.1.11]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1355) ~[spring-beans-6.1.11.jar:6.1.11]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1185) ~[spring-beans-6.1.11.jar:6.1.11]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:562) ~[spring-beans-6.1.11.jar:6.1.11]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:522) ~[spring-beans-6.1.11.jar:6.1.11]
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:337) ~[spring-beans-6.1.11.jar:6.1.11]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-6.1.11.jar:6.1.11]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:335) ~[spring-beans-6.1.11.jar:6.1.11]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-beans-6.1.11.jar:6.1.11]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:975) ~[spring-beans-6.1.11.jar:6.1.11]
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:971) ~[spring-context-6.1.11.jar:6.1.11]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:625) ~[spring-context-6.1.11.jar:6.1.11]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) ~[spring-boot-3.3.2.jar:3.3.2]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:456) ~[spring-boot-3.3.2.jar:3.3.2]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:335) ~[spring-boot-3.3.2.jar:3.3.2]
    at org.springframework.boot.builder.SpringApplicationBuilder.run(SpringApplicationBuilder.java:149) ~[spring-boot-3.3.2.jar:3.3.2]
    at org.springframework.cloud.bootstrap.BootstrapApplicationListener.bootstrapServiceContext(BootstrapApplicationListener.java:195) ~[spring-cloud-context-4.1.4.jar:4.1.4]
    at org.springframework.cloud.bootstrap.BootstrapApplicationListener.onApplicationEvent(BootstrapApplicationListener.java:114) ~[spring-cloud-context-4.1.4.jar:4.1.4]
    at org.springframework.cloud.bootstrap.BootstrapApplicationListener.onApplicationEvent(BootstrapApplicationListener.java:77) ~[spring-cloud-context-4.1.4.jar:4.1.4]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:185) ~[spring-context-6.1.11.jar:6.1.11]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:178) ~[spring-context-6.1.11.jar:6.1.11]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:156) ~[spring-context-6.1.11.jar:6.1.11]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:138) ~[spring-context-6.1.11.jar:6.1.11]
    at org.springframework.boot.context.event.EventPublishingRunListener.multicastInitialEvent(EventPublishingRunListener.java:136) ~[spring-boot-3.3.2.jar:3.3.2]
    at org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:81) ~[spring-boot-3.3.2.jar:3.3.2]
    at org.springframework.boot.SpringApplicationRunListeners.lambda$environmentPrepared$2(SpringApplicationRunListeners.java:64) ~[spring-boot-3.3.2.jar:3.3.2]
    at java.base/java.lang.Iterable.forEach(Iterable.java:75) ~[na:na]
    at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:118) ~[spring-boot-3.3.2.jar:3.3.2]
    at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:112) ~[spring-boot-3.3.2.jar:3.3.2]
    at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:63) ~[spring-boot-3.3.2.jar:3.3.2]
    at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:370) ~[spring-boot-3.3.2.jar:3.3.2]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:330) ~[spring-boot-3.3.2.jar:3.3.2]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1363) ~[spring-boot-3.3.2.jar:3.3.2]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1352) ~[spring-boot-3.3.2.jar:3.3.2]
    at org.c4rth.virtual.Application.main(Application.java:21) ~[classes/:0.0.1-SNAPSHOT]
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[na:na]
    at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:91) ~[application/:na]
    at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:53) ~[application/:na]
    at org.springframework.boot.loader.launch.JarLauncher.main(JarLauncher.java:58) ~[application/:na]
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'org.springframework.cloud.kubernetes.commons.config.ConfigMapConfigProperties' available: expected single matching bean but found 2: spring.cloud.kubernetes.config-org.springframework.cloud.kubernetes.commons.config.ConfigMapConfigProperties,configDataConfigMapConfigProperties
    at org.springframework.beans.factory.config.DependencyDescriptor.resolveNotUnique(DependencyDescriptor.java:218) ~[spring-beans-6.1.11.jar:6.1.11]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1420) ~[spring-beans-6.1.11.jar:6.1.11]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1353) ~[spring-beans-6.1.11.jar:6.1.11]
    at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:904) ~[spring-beans-6.1.11.jar:6.1.11]
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:782) ~[spring-beans-6.1.11.jar:6.1.11]
    ... 40 common frames omitted
ryanjbaxter commented 3 weeks ago

Do you have any idea where this is coming from configDataConfigMapConfigProperties? Can you provide a sample?

c4rth commented 2 weeks ago

Here is a sample repository https://github.com/c4rth/spring-k8s

The 'configDataConfigMapConfigProperties' is defined in method registerProperties of KubernetesConfigDataLocationResolver For the other, I'm still looking.

ryanjbaxter commented 2 weeks ago

OK looking at your sample gave me more clues.

Why are you specifying spring.config.import=kubernetes: and enabling Bootstrap? You are running into issues because we are trying to load configuration using two different approaches and this is not supported.

c4rth commented 2 weeks ago

So spring.config.import=kubernetes: and Cloud Bootstrap are mutually exclusive. OK, it's was not clear for me. Maybe mentioning it in the documentation would be useful for others. Thanks for your support and your patience.