Merge branch '2.0.x' into main
This commit is contained in:
@@ -46,6 +46,9 @@ spring:
|
||||
|
||||
In the preceding example, if `spring.cloud.kubernetes.config.namespace` had not been set,
|
||||
the `ConfigMap` named `c1` would be looked up in the namespace that the application runs.
|
||||
See <<namespace-resolution,Namespace resolution>> to get a better understanding of how the namespace
|
||||
of the application is resolved.
|
||||
|
||||
|
||||
Any matching `ConfigMap` that is found is processed as follows:
|
||||
|
||||
@@ -562,7 +565,7 @@ spring:
|
||||
sources:
|
||||
# Spring Cloud Kubernetes looks up a Secret named s1 in namespace default-namespace
|
||||
- name: s1
|
||||
# Spring Cloud Kubernetes looks up a Secret named default-name in whatever namespace n2
|
||||
# Spring Cloud Kubernetes looks up a Secret named default-name in namespace n2
|
||||
- namespace: n2
|
||||
# Spring Cloud Kubernetes looks up a Secret named s3 in namespace n3
|
||||
- namespace: n3
|
||||
@@ -572,6 +575,8 @@ spring:
|
||||
|
||||
In the preceding example, if `spring.cloud.kubernetes.secrets.namespace` had not been set,
|
||||
the `Secret` named `s1` would be looked up in the namespace that the application runs.
|
||||
See <<namespace-resolution,namespace-resolution>> to get a better understanding of how the namespace
|
||||
of the application is resolved.
|
||||
|
||||
|
||||
.Properties:
|
||||
@@ -597,6 +602,44 @@ https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-Configuration-Bi
|
||||
You can find an example of an application that uses secrets (though it has not been updated to use the new `spring-cloud-kubernetes` project) at
|
||||
https://github.com/fabric8-quickstarts/spring-boot-camel-config[spring-boot-camel-config]
|
||||
|
||||
[[namespace-resolution]]
|
||||
=== Namespace resolution
|
||||
Finding an application namespace happens on a best-effort basis. There are some steps that we iterate in order
|
||||
to find it. The easiest and most common one, is to specify it in the proper configuration, for example:
|
||||
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
spring:
|
||||
application:
|
||||
name: app
|
||||
cloud:
|
||||
kubernetes:
|
||||
secrets:
|
||||
name: secret
|
||||
namespace: default
|
||||
sources:
|
||||
# Spring Cloud Kubernetes looks up a Secret named 'a' in namespace 'default'
|
||||
- name: a
|
||||
# Spring Cloud Kubernetes looks up a Secret named 'secret' in namespace 'b'
|
||||
- namespace: b
|
||||
# Spring Cloud Kubernetes looks up a Secret named 'd' in namespace 'c'
|
||||
- namespace: c
|
||||
name: d
|
||||
----
|
||||
====
|
||||
|
||||
Remember that the same can be done for config maps. If such a namespace is not specified, it will be read (in this order):
|
||||
|
||||
1. from property `spring.cloud.kubernetes.client.namespace`
|
||||
2. from a String residing in a file denoted by `spring.cloud.kubernetes.client.serviceAccountNamespacePath` property
|
||||
3. from a String residing in `/var/run/secrets/kubernetes.io/serviceaccount/namespace` file
|
||||
(kubernetes default namespace path)
|
||||
4. from a designated client method call (for example fabric8's : `KubernetesClient::getNamespace`), if the client provides
|
||||
such a method.
|
||||
|
||||
Failure to find a namespace from the above steps will result in an Exception being raised.
|
||||
|
||||
=== `PropertySource` Reload
|
||||
|
||||
WARNING: This functionality has been deprecated in the 2020.0 release. Please see
|
||||
|
||||
@@ -74,6 +74,12 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.tomakehurst</groupId>
|
||||
<artifactId>wiremock-jre8</artifactId>
|
||||
|
||||
@@ -22,10 +22,10 @@ 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.ConfigMapPropertySourceLocator;
|
||||
import org.springframework.cloud.kubernetes.commons.config.NamespaceResolutionFailedException;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
|
||||
import static org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigUtils.getNamespace;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
@@ -38,6 +38,14 @@ public class KubernetesClientConfigMapPropertySourceLocator extends ConfigMapPro
|
||||
|
||||
private final KubernetesNamespaceProvider kubernetesNamespaceProvider;
|
||||
|
||||
/**
|
||||
* This constructor is deprecated. Its usage might cause unexpected behavior when
|
||||
* looking for different properties. For example, in general, if a namespace is not
|
||||
* provided, we might look it up via other means: different documented environment
|
||||
* variables or from a kubernetes client itself. Using this constructor might not
|
||||
* reflect that.
|
||||
*/
|
||||
@Deprecated
|
||||
public KubernetesClientConfigMapPropertySourceLocator(CoreV1Api coreV1Api, ConfigMapConfigProperties properties,
|
||||
KubernetesClientProperties kubernetesClientProperties) {
|
||||
super(properties);
|
||||
@@ -59,10 +67,28 @@ public class KubernetesClientConfigMapPropertySourceLocator extends ConfigMapPro
|
||||
ConfigMapConfigProperties.NormalizedSource normalizedSource, String configurationTarget,
|
||||
ConfigurableEnvironment environment) {
|
||||
|
||||
String fallbackNamespace = kubernetesNamespaceProvider != null ? kubernetesNamespaceProvider.getNamespace()
|
||||
: kubernetesClientProperties.getNamespace();
|
||||
return new KubernetesClientConfigMapPropertySource(coreV1Api, name,
|
||||
getNamespace(normalizedSource, fallbackNamespace), environment, normalizedSource.getPrefix());
|
||||
String namespace;
|
||||
String normalizedNamespace = normalizedSource.getNamespace();
|
||||
|
||||
if (StringUtils.hasText(normalizedNamespace)) {
|
||||
namespace = normalizedNamespace;
|
||||
}
|
||||
else if (kubernetesClientProperties != null) {
|
||||
if (StringUtils.hasText(kubernetesClientProperties.getNamespace())) {
|
||||
namespace = kubernetesClientProperties.getNamespace();
|
||||
}
|
||||
else {
|
||||
throw new NamespaceResolutionFailedException(
|
||||
"could not resolve namespace in normalized source or KubernetesClientProperties");
|
||||
}
|
||||
}
|
||||
else {
|
||||
namespace = KubernetesClientConfigUtils.getApplicationNamespace(normalizedNamespace, "Config Map",
|
||||
kubernetesNamespaceProvider);
|
||||
}
|
||||
|
||||
return new KubernetesClientConfigMapPropertySource(coreV1Api, name, namespace, environment,
|
||||
normalizedSource.getPrefix());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,8 +16,13 @@
|
||||
|
||||
package org.springframework.cloud.kubernetes.client.config;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
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.NamespaceResolutionFailedException;
|
||||
import org.springframework.cloud.kubernetes.commons.config.SecretsConfigProperties;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -26,6 +31,8 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
public final class KubernetesClientConfigUtils {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(KubernetesClientConfigUtils.class);
|
||||
|
||||
private KubernetesClientConfigUtils() {
|
||||
}
|
||||
|
||||
@@ -51,16 +58,56 @@ public final class KubernetesClientConfigUtils {
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static String getNamespace(ConfigMapConfigProperties.NormalizedSource normalizedSource,
|
||||
String fallbackNamespace) {
|
||||
String normalizedNamespace = normalizedSource.getNamespace();
|
||||
return StringUtils.hasText(normalizedNamespace) ? normalizedNamespace : fallbackNamespace;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static String getNamespace(SecretsConfigProperties.NormalizedSource normalizedSource,
|
||||
String fallbackNamespace) {
|
||||
String normalizedNamespace = normalizedSource.getNamespace();
|
||||
return StringUtils.hasText(normalizedNamespace) ? normalizedNamespace : fallbackNamespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* this method does the namespace resolution for both config map and secrets
|
||||
* implementations. It tries these places to find the namespace:
|
||||
*
|
||||
* <pre>
|
||||
* 1. from a normalized source (which can be null)
|
||||
* 2. from a property 'spring.cloud.kubernetes.client.namespace', if such is present
|
||||
* 3. from a String residing in a file denoted by `spring.cloud.kubernetes.client.serviceAccountNamespacePath`
|
||||
* property, if such is present
|
||||
* 4. from a String residing in `/var/run/secrets/kubernetes.io/serviceaccount/namespace` file,
|
||||
* if such is present (kubernetes default path)
|
||||
* </pre>
|
||||
*
|
||||
* If any of the above fail, we throw a NamespaceResolutionFailedException.
|
||||
* @param namespace normalized namespace
|
||||
* @param configurationTarget Config Map/Secret
|
||||
* @param provider the provider which computes the namespace
|
||||
* @return application namespace
|
||||
* @throws NamespaceResolutionFailedException when namespace could not be resolved
|
||||
*/
|
||||
static String getApplicationNamespace(String namespace, String configurationTarget,
|
||||
KubernetesNamespaceProvider provider) {
|
||||
if (StringUtils.hasText(namespace)) {
|
||||
LOG.debug(configurationTarget + " namespace from normalized source : " + namespace);
|
||||
return namespace;
|
||||
}
|
||||
|
||||
if (provider != null) {
|
||||
String providerNamespace = provider.getNamespace();
|
||||
if (StringUtils.hasText(providerNamespace)) {
|
||||
LOG.debug(configurationTarget + " namespace from provider : " + namespace);
|
||||
return providerNamespace;
|
||||
}
|
||||
}
|
||||
|
||||
throw new NamespaceResolutionFailedException("unresolved namespace");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,12 +20,13 @@ import io.kubernetes.client.openapi.apis.CoreV1Api;
|
||||
|
||||
import org.springframework.cloud.kubernetes.commons.KubernetesClientProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider;
|
||||
import org.springframework.cloud.kubernetes.commons.config.NamespaceResolutionFailedException;
|
||||
import org.springframework.cloud.kubernetes.commons.config.SecretsConfigProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.config.SecretsPropertySourceLocator;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.springframework.cloud.kubernetes.client.config.KubernetesClientConfigUtils.getNamespace;
|
||||
import static org.springframework.cloud.kubernetes.commons.config.ConfigUtils.getApplicationName;
|
||||
|
||||
/**
|
||||
@@ -66,11 +67,30 @@ public class KubernetesClientSecretsPropertySourceLocator extends SecretsPropert
|
||||
@Override
|
||||
protected MapPropertySource getPropertySource(ConfigurableEnvironment environment,
|
||||
SecretsConfigProperties.NormalizedSource normalizedSource, String configurationTarget) {
|
||||
String fallbackNamespace = kubernetesNamespaceProvider != null ? kubernetesNamespaceProvider.getNamespace()
|
||||
: kubernetesClientProperties.getNamespace();
|
||||
return new KubernetesClientSecretsPropertySource(coreV1Api,
|
||||
getApplicationName(environment, normalizedSource.getName(), configurationTarget),
|
||||
getNamespace(normalizedSource, fallbackNamespace), environment, normalizedSource.getLabels());
|
||||
|
||||
String namespace;
|
||||
String normalizedNamespace = normalizedSource.getNamespace();
|
||||
String secretName = getApplicationName(environment, normalizedSource.getName(), configurationTarget);
|
||||
|
||||
if (StringUtils.hasText(normalizedNamespace)) {
|
||||
namespace = normalizedNamespace;
|
||||
}
|
||||
else if (kubernetesClientProperties != null) {
|
||||
if (StringUtils.hasText(kubernetesClientProperties.getNamespace())) {
|
||||
namespace = kubernetesClientProperties.getNamespace();
|
||||
}
|
||||
else {
|
||||
throw new NamespaceResolutionFailedException(
|
||||
"could not resolve namespace in normalized source or KubernetesClientProperties");
|
||||
}
|
||||
}
|
||||
else {
|
||||
namespace = KubernetesClientConfigUtils.getApplicationNamespace(normalizedNamespace, "Secret",
|
||||
kubernetesNamespaceProvider);
|
||||
}
|
||||
|
||||
return new KubernetesClientSecretsPropertySource(coreV1Api, secretName, namespace, environment,
|
||||
normalizedSource.getLabels());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.client.config;
|
||||
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author wind57
|
||||
*/
|
||||
public class KubernetesClientBootstrapConfigurationTests {
|
||||
|
||||
@SpringBootApplication
|
||||
static class Application {
|
||||
|
||||
}
|
||||
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class,
|
||||
properties = "spring.cloud.kubernetes.enabled=false")
|
||||
@Nested
|
||||
class KubernetesDisabled {
|
||||
|
||||
@Autowired
|
||||
ConfigurableApplicationContext context;
|
||||
|
||||
@Test
|
||||
void configAndSecretsBeansAreNotPresent() {
|
||||
assertThat(context.getBeanNamesForType(KubernetesClientConfigMapPropertySourceLocator.class)).hasSize(0);
|
||||
assertThat(context.getBeanNamesForType(KubernetesClientSecretsPropertySourceLocator.class)).hasSize(0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class,
|
||||
properties = { "spring.cloud.kubernetes.secrets.enabled=true",
|
||||
"spring.cloud.kubernetes.client.namespace=default" })
|
||||
@Nested
|
||||
class KubernetesEnabledOnPurpose {
|
||||
|
||||
@Autowired
|
||||
ConfigurableApplicationContext context;
|
||||
|
||||
@Test
|
||||
void configAndSecretsBeansArePresent() {
|
||||
assertThat(context.getBeanNamesForType(KubernetesClientConfigMapPropertySourceLocator.class)).hasSize(1);
|
||||
assertThat(context.getBeanNamesForType(KubernetesClientSecretsPropertySourceLocator.class)).hasSize(1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class,
|
||||
properties = "spring.cloud.kubernetes.client.namespace=default")
|
||||
@Nested
|
||||
class KubernetesEnabled {
|
||||
|
||||
@Autowired
|
||||
ConfigurableApplicationContext context;
|
||||
|
||||
@Test
|
||||
void configAndSecretsBeansArePresent() {
|
||||
assertThat(context.getBeanNamesForType(KubernetesClientConfigMapPropertySourceLocator.class)).hasSize(1);
|
||||
assertThat(context.getBeanNamesForType(KubernetesClientSecretsPropertySourceLocator.class)).hasSize(1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class,
|
||||
properties = "spring.cloud.kubernetes.config.enabled=false")
|
||||
@Nested
|
||||
class KubernetesEnabledConfigDisabled {
|
||||
|
||||
@Autowired
|
||||
ConfigurableApplicationContext context;
|
||||
|
||||
@Test
|
||||
void secretsOnlyPresent() {
|
||||
assertThat(context.getBeanNamesForType(KubernetesClientConfigMapPropertySourceLocator.class)).hasSize(0);
|
||||
assertThat(context.getBeanNamesForType(KubernetesClientSecretsPropertySourceLocator.class)).hasSize(1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class,
|
||||
properties = { "spring.cloud.kubernetes.secrets.enabled=false",
|
||||
"spring.cloud.kubernetes.client.namespace=default" })
|
||||
@Nested
|
||||
class KubernetesEnabledSecretsDisabled {
|
||||
|
||||
@Autowired
|
||||
ConfigurableApplicationContext context;
|
||||
|
||||
@Test
|
||||
void secretsOnlyPresent() {
|
||||
assertThat(context.getBeanNamesForType(KubernetesClientConfigMapPropertySourceLocator.class)).hasSize(1);
|
||||
assertThat(context.getBeanNamesForType(KubernetesClientSecretsPropertySourceLocator.class)).hasSize(0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class,
|
||||
properties = { "spring.cloud.kubernetes.secrets.enabled=false",
|
||||
"spring.cloud.kubernetes.config.enabled=false" })
|
||||
@Nested
|
||||
class KubernetesEnabledSecretsAndConfigDisabled {
|
||||
|
||||
@Autowired
|
||||
ConfigurableApplicationContext context;
|
||||
|
||||
@Test
|
||||
void secretsOnlyPresent() {
|
||||
assertThat(context.getBeanNamesForType(KubernetesClientConfigMapPropertySourceLocator.class)).hasSize(0);
|
||||
assertThat(context.getBeanNamesForType(KubernetesClientSecretsPropertySourceLocator.class)).hasSize(0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -35,7 +35,9 @@ import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
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.NamespaceResolutionFailedException;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.mock.env.MockEnvironment;
|
||||
|
||||
@@ -44,6 +46,7 @@ import static com.github.tomakehurst.wiremock.client.WireMock.get;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
|
||||
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
@@ -121,4 +124,48 @@ class KubernetesClientConfigMapPropertySourceLocatorTests {
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 1. using the deprecated constructor, and
|
||||
* 2. not providing the namespace
|
||||
* </pre>
|
||||
*
|
||||
* will result in an Exception
|
||||
*/
|
||||
@Test
|
||||
void testLocateWithoutNamespaceDeprecatedConstructor() {
|
||||
CoreV1Api api = new CoreV1Api();
|
||||
stubFor(get(API)
|
||||
.willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(PROPERTIES_CONFIGMAP_LIST))));
|
||||
ConfigMapConfigProperties configMapConfigProperties = new ConfigMapConfigProperties();
|
||||
configMapConfigProperties.setName("bootstrap-640");
|
||||
KubernetesClientProperties kubernetesClientProperties = new KubernetesClientProperties();
|
||||
kubernetesClientProperties.setNamespace(""); // empty on purpose
|
||||
assertThatThrownBy(() -> new KubernetesClientConfigMapPropertySourceLocator(api, configMapConfigProperties,
|
||||
kubernetesClientProperties).locate(new MockEnvironment()))
|
||||
.isInstanceOf(NamespaceResolutionFailedException.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 1. using the non-deprecated constructor, and
|
||||
* 2. not providing the namespace
|
||||
* </pre>
|
||||
*
|
||||
* will result in an Exception
|
||||
*/
|
||||
@Test
|
||||
void testLocateWithoutNamespace() {
|
||||
CoreV1Api api = new CoreV1Api();
|
||||
stubFor(get(API)
|
||||
.willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(PROPERTIES_CONFIGMAP_LIST))));
|
||||
ConfigMapConfigProperties configMapConfigProperties = new ConfigMapConfigProperties();
|
||||
configMapConfigProperties.setName("bootstrap-640");
|
||||
KubernetesClientProperties kubernetesClientProperties = new KubernetesClientProperties();
|
||||
kubernetesClientProperties.setNamespace(""); // empty on purpose
|
||||
assertThatThrownBy(() -> new KubernetesClientConfigMapPropertySourceLocator(api, configMapConfigProperties,
|
||||
new KubernetesNamespaceProvider(new MockEnvironment())).locate(new MockEnvironment()))
|
||||
.isInstanceOf(NamespaceResolutionFailedException.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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.client.config;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider;
|
||||
import org.springframework.cloud.kubernetes.commons.config.NamespaceResolutionFailedException;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
/**
|
||||
* @author wind57
|
||||
*/
|
||||
class KubernetesClientConfigUtilsTests {
|
||||
|
||||
private final KubernetesNamespaceProvider provider = Mockito.mock(KubernetesNamespaceProvider.class);
|
||||
|
||||
@Test
|
||||
void testNamespaceFromNormalizedSource() {
|
||||
String result = KubernetesClientConfigUtils.getApplicationNamespace("abc", "target", null);
|
||||
assertThat(result).isEqualTo("abc");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNamespaceFromProvider() {
|
||||
Mockito.when(provider.getNamespace()).thenReturn("def");
|
||||
String result = KubernetesClientConfigUtils.getApplicationNamespace("", "target", provider);
|
||||
assertThat(result).isEqualTo("def");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNamespaceResolutionFailed() {
|
||||
assertThatThrownBy(() -> KubernetesClientConfigUtils.getApplicationNamespace("", "target", null))
|
||||
.isInstanceOf(NamespaceResolutionFailedException.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -31,6 +31,8 @@ import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.cloud.kubernetes.commons.KubernetesClientProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider;
|
||||
import org.springframework.cloud.kubernetes.commons.config.NamespaceResolutionFailedException;
|
||||
import org.springframework.cloud.kubernetes.commons.config.SecretsConfigProperties;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.mock.env.MockEnvironment;
|
||||
@@ -40,15 +42,14 @@ import static com.github.tomakehurst.wiremock.client.WireMock.get;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
|
||||
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
class KubernetesClientSecretsPropertySourceLocatorTests {
|
||||
|
||||
private static final String LIST_API = "/api/v1/secrets";
|
||||
|
||||
private static final String LIST_API_WITH_LABEL = "/api/v1/secrets?labelSelector=spring.cloud.kubernetes.secret%3Dtrue";
|
||||
private static final String LIST_API = "/api/v1/namespaces/default/secrets";
|
||||
|
||||
private static final String LIST_BODY = "{\n" + "\t\"kind\": \"SecretList\",\n" + "\t\"apiVersion\": \"v1\",\n"
|
||||
+ "\t\"metadata\": {\n" + "\t\t\"selfLink\": \"/api/v1/secrets\",\n"
|
||||
@@ -112,10 +113,10 @@ class KubernetesClientSecretsPropertySourceLocatorTests {
|
||||
sources.add(source1);
|
||||
sources.add(source2);
|
||||
secretsConfigProperties.setName("app");
|
||||
secretsConfigProperties.setNamespace("");
|
||||
secretsConfigProperties.setNamespace("default");
|
||||
secretsConfigProperties.setSources(sources);
|
||||
secretsConfigProperties.setEnableApi(true);
|
||||
PropertySource propertySource = new KubernetesClientSecretsPropertySourceLocator(api,
|
||||
PropertySource<?> propertySource = new KubernetesClientSecretsPropertySourceLocator(api,
|
||||
new KubernetesClientProperties(), secretsConfigProperties).locate(new MockEnvironment());
|
||||
assertThat(propertySource.containsProperty("password")).isTrue();
|
||||
assertThat(propertySource.getProperty("password")).isEqualTo("p455w0rd");
|
||||
@@ -127,12 +128,54 @@ class KubernetesClientSecretsPropertySourceLocatorTests {
|
||||
stubFor(get(LIST_API).willReturn(aResponse().withStatus(200).withBody(LIST_BODY)));
|
||||
SecretsConfigProperties secretsConfigProperties = new SecretsConfigProperties();
|
||||
secretsConfigProperties.setName("db-secret");
|
||||
secretsConfigProperties.setNamespace("");
|
||||
secretsConfigProperties.setNamespace("default");
|
||||
secretsConfigProperties.setEnableApi(true);
|
||||
PropertySource propertySource = new KubernetesClientSecretsPropertySourceLocator(api,
|
||||
PropertySource<?> propertySource = new KubernetesClientSecretsPropertySourceLocator(api,
|
||||
new KubernetesClientProperties(), secretsConfigProperties).locate(new MockEnvironment());
|
||||
assertThat(propertySource.containsProperty("password")).isTrue();
|
||||
assertThat(propertySource.getProperty("password")).isEqualTo("p455w0rd");
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 1. using the deprecated constructor, and
|
||||
* 2. not providing the namespace
|
||||
* </pre>
|
||||
*
|
||||
* will result in an Exception
|
||||
*/
|
||||
@Test
|
||||
void testLocateWithoutNamespaceDeprecatedConstructor() {
|
||||
CoreV1Api api = new CoreV1Api();
|
||||
stubFor(get(LIST_API).willReturn(aResponse().withStatus(200).withBody(LIST_BODY)));
|
||||
SecretsConfigProperties secretsConfigProperties = new SecretsConfigProperties();
|
||||
secretsConfigProperties.setName("db-secret");
|
||||
secretsConfigProperties.setNamespace(""); // empty on purpose
|
||||
secretsConfigProperties.setEnableApi(true);
|
||||
assertThatThrownBy(() -> new KubernetesClientSecretsPropertySourceLocator(api, new KubernetesClientProperties(),
|
||||
secretsConfigProperties).locate(new MockEnvironment()))
|
||||
.isInstanceOf(NamespaceResolutionFailedException.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 1. using the non-deprecated constructor, and
|
||||
* 2. not providing the namespace
|
||||
* </pre>
|
||||
*
|
||||
* will result in an Exception
|
||||
*/
|
||||
@Test
|
||||
void testLocateWithoutNamespace() {
|
||||
CoreV1Api api = new CoreV1Api();
|
||||
stubFor(get(LIST_API).willReturn(aResponse().withStatus(200).withBody(LIST_BODY)));
|
||||
SecretsConfigProperties secretsConfigProperties = new SecretsConfigProperties();
|
||||
secretsConfigProperties.setName("db-secret");
|
||||
secretsConfigProperties.setNamespace(""); // empty on purpose
|
||||
secretsConfigProperties.setEnableApi(true);
|
||||
assertThatThrownBy(() -> new KubernetesClientSecretsPropertySourceLocator(api,
|
||||
new KubernetesNamespaceProvider(new MockEnvironment()), secretsConfigProperties)
|
||||
.locate(new MockEnvironment())).isInstanceOf(NamespaceResolutionFailedException.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* @author wind57
|
||||
*
|
||||
* Thrown when a namespace could not be resolved. Resolution of a namespace happens via
|
||||
* user provided input, environment properties or directly from the underlying client,
|
||||
* etc.
|
||||
*/
|
||||
public class NamespaceResolutionFailedException extends RuntimeException {
|
||||
|
||||
public NamespaceResolutionFailedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -29,14 +29,12 @@ import org.springframework.core.env.MapPropertySource;
|
||||
*/
|
||||
public class SecretsPropertySource extends MapPropertySource {
|
||||
|
||||
private static final String PREFIX = "secrets";
|
||||
|
||||
public SecretsPropertySource(String name, Map<String, Object> source) {
|
||||
super(name, source);
|
||||
}
|
||||
|
||||
protected static String getSourceName(String name, String namespace) {
|
||||
return PREFIX + Constants.PROPERTY_SOURCE_NAME_SEPARATOR + name + Constants.PROPERTY_SOURCE_NAME_SEPARATOR
|
||||
return "secrets" + Constants.PROPERTY_SOURCE_NAME_SEPARATOR + name + Constants.PROPERTY_SOURCE_NAME_SEPARATOR
|
||||
+ namespace;
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,11 @@ public class Fabric8ConfigMapPropertySource extends ConfigMapPropertySource {
|
||||
this(client, name, null, null, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* this constructor is present only for compatibility reasons, its usage is
|
||||
* discouraged.
|
||||
*/
|
||||
@Deprecated
|
||||
public Fabric8ConfigMapPropertySource(KubernetesClient client, String applicationName, String namespace,
|
||||
Environment environment) {
|
||||
super(getName(applicationName, getApplicationNamespace(client, namespace)),
|
||||
|
||||
@@ -66,9 +66,9 @@ public class Fabric8ConfigMapPropertySourceLocator extends ConfigMapPropertySour
|
||||
@Override
|
||||
protected MapPropertySource getMapPropertySource(String applicationName, NormalizedSource normalizedSource,
|
||||
String configurationTarget, ConfigurableEnvironment environment) {
|
||||
String configMapName = getApplicationNamespace(this.client, normalizedSource.getNamespace(),
|
||||
configurationTarget, provider);
|
||||
return new Fabric8ConfigMapPropertySource(this.client, applicationName, configMapName, environment,
|
||||
String namespace = getApplicationNamespace(this.client, normalizedSource.getNamespace(), configurationTarget,
|
||||
provider);
|
||||
return new Fabric8ConfigMapPropertySource(this.client, applicationName, namespace, environment,
|
||||
normalizedSource.getPrefix());
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider;
|
||||
import org.springframework.cloud.kubernetes.commons.config.NamespaceResolutionFailedException;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -39,6 +40,9 @@ public final class Fabric8ConfigUtils {
|
||||
private Fabric8ConfigUtils() {
|
||||
}
|
||||
|
||||
/*
|
||||
* this is not used, it is here for compatibility reasons only.
|
||||
*/
|
||||
@Deprecated
|
||||
public static String getApplicationNamespace(KubernetesClient client, String namespace,
|
||||
String configurationTarget) {
|
||||
@@ -51,6 +55,28 @@ public final class Fabric8ConfigUtils {
|
||||
return namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* this method does the namespace resolution for both config map and secrets
|
||||
* implementations. It tries these places to find the namespace:
|
||||
*
|
||||
* <pre>
|
||||
* 1. from a normalized source (which can be null)
|
||||
* 2. from a property 'spring.cloud.kubernetes.client.namespace', if such is present
|
||||
* 3. from a String residing in a file denoted by `spring.cloud.kubernetes.client.serviceAccountNamespacePath`
|
||||
* property, if such is present
|
||||
* 4. from a String residing in `/var/run/secrets/kubernetes.io/serviceaccount/namespace` file,
|
||||
* if such is present (kubernetes default path)
|
||||
* 5. from KubernetesClient::getNamespace, which is implementation specific.
|
||||
* </pre>
|
||||
*
|
||||
* If any of the above fail, we throw a NamespaceResolutionFailedException.
|
||||
* @param namespace normalized namespace
|
||||
* @param configurationTarget Config Map/Secret
|
||||
* @param provider the provider which computes the namespace
|
||||
* @param client fabric8 Kubernetes client
|
||||
* @return application namespace
|
||||
* @throws NamespaceResolutionFailedException when namespace could not be resolved
|
||||
*/
|
||||
static String getApplicationNamespace(KubernetesClient client, String namespace, String configurationTarget,
|
||||
KubernetesNamespaceProvider provider) {
|
||||
|
||||
@@ -63,11 +89,16 @@ public final class Fabric8ConfigUtils {
|
||||
String providerNamespace = provider.getNamespace();
|
||||
if (StringUtils.hasText(providerNamespace)) {
|
||||
LOG.debug(configurationTarget + " namespace from provider : " + namespace);
|
||||
return providerNamespace;
|
||||
}
|
||||
}
|
||||
|
||||
LOG.debug(configurationTarget + " namespace from client : " + client.getNamespace());
|
||||
return client.getNamespace();
|
||||
String clientNamespace = client.getNamespace();
|
||||
LOG.debug(configurationTarget + " namespace from client : " + clientNamespace);
|
||||
if (clientNamespace == null) {
|
||||
throw new NamespaceResolutionFailedException("unresolved namespace");
|
||||
}
|
||||
return clientNamespace;
|
||||
|
||||
}
|
||||
|
||||
@@ -75,7 +106,7 @@ public final class Fabric8ConfigUtils {
|
||||
return !StringUtils.hasLength(namespace) ? client.getNamespace() : namespace;
|
||||
}
|
||||
|
||||
public static Map<String, String> getConfigMapData(KubernetesClient client, String namespace, String name) {
|
||||
static Map<String, String> getConfigMapData(KubernetesClient client, String namespace, String name) {
|
||||
ConfigMap configMap = !StringUtils.hasLength(namespace) ? client.configMaps().withName(name).get()
|
||||
: client.configMaps().inNamespace(namespace).withName(name).get();
|
||||
|
||||
|
||||
@@ -39,7 +39,8 @@ public class Fabric8ActuatorTests {
|
||||
@Nested
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = App.class, properties = {
|
||||
"management.health.kubernetes.enabled=false", "management.endpoint.health.show-details=always",
|
||||
"management.endpoint.health.show-components=always", "management.endpoints.web.exposure.include=health" })
|
||||
"management.endpoint.health.show-components=always", "management.endpoints.web.exposure.include=health",
|
||||
"spring.cloud.kubernetes.client.namespace=default" })
|
||||
public class DisabledHealthTest {
|
||||
|
||||
@Autowired
|
||||
@@ -66,7 +67,8 @@ public class Fabric8ActuatorTests {
|
||||
@Nested
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = App.class, properties = {
|
||||
"management.health.kubernetes.enabled=true", "management.endpoint.health.show-details=always",
|
||||
"management.endpoint.health.show-components=always", "management.endpoints.web.exposure.include=health" })
|
||||
"management.endpoint.health.show-components=always", "management.endpoints.web.exposure.include=health",
|
||||
"spring.cloud.kubernetes.client.namespace=default" })
|
||||
public class EnabledHealthTest {
|
||||
|
||||
@Autowired
|
||||
|
||||
@@ -47,7 +47,8 @@ public class Fabric8BootstrapConfigurationTests {
|
||||
}
|
||||
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class,
|
||||
properties = "spring.cloud.kubernetes.enabled=true")
|
||||
properties = { "spring.cloud.kubernetes.secrets.enabled=true",
|
||||
"spring.cloud.kubernetes.client.namespace=default" })
|
||||
@Nested
|
||||
class KubernetesEnabledOnPurpose {
|
||||
|
||||
@@ -62,7 +63,8 @@ public class Fabric8BootstrapConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class,
|
||||
properties = "spring.cloud.kubernetes.client.namespace=default")
|
||||
@Nested
|
||||
class KubernetesEnabled {
|
||||
|
||||
@@ -94,7 +96,8 @@ public class Fabric8BootstrapConfigurationTests {
|
||||
}
|
||||
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class,
|
||||
properties = "spring.cloud.kubernetes.secrets.enabled=false")
|
||||
properties = { "spring.cloud.kubernetes.secrets.enabled=false",
|
||||
"spring.cloud.kubernetes.client.namespace=default" })
|
||||
@Nested
|
||||
class KubernetesEnabledSecretsDisabled {
|
||||
|
||||
|
||||
@@ -16,11 +16,17 @@
|
||||
|
||||
package org.springframework.cloud.kubernetes.fabric8.config;
|
||||
|
||||
import io.fabric8.kubernetes.client.DefaultKubernetesClient;
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
import io.fabric8.kubernetes.client.server.mock.EnableKubernetesMockClient;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider;
|
||||
import org.springframework.cloud.kubernetes.commons.config.NamespaceResolutionFailedException;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
/**
|
||||
* @author wind57
|
||||
@@ -30,6 +36,10 @@ public class Fabric8ConfigUtilsTests {
|
||||
|
||||
private KubernetesClient client;
|
||||
|
||||
private final DefaultKubernetesClient mockClient = Mockito.mock(DefaultKubernetesClient.class);
|
||||
|
||||
private final KubernetesNamespaceProvider provider = Mockito.mock(KubernetesNamespaceProvider.class);
|
||||
|
||||
@Test
|
||||
public void testGetApplicationNamespaceNotPresent() {
|
||||
String result = Fabric8ConfigUtils.getApplicationNamespace(client, "", "target");
|
||||
@@ -42,4 +52,30 @@ public class Fabric8ConfigUtilsTests {
|
||||
assertThat(result).isEqualTo("namespace");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNamespaceFromNormalizedSource() {
|
||||
String result = Fabric8ConfigUtils.getApplicationNamespace(client, "abc", "target", null);
|
||||
assertThat(result).isEqualTo("abc");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNamespaceFromProvider() {
|
||||
Mockito.when(provider.getNamespace()).thenReturn("def");
|
||||
String result = Fabric8ConfigUtils.getApplicationNamespace(client, "", "target", provider);
|
||||
assertThat(result).isEqualTo("def");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNamespaceFromClient() {
|
||||
Mockito.when(mockClient.getNamespace()).thenReturn("qwe");
|
||||
String result = Fabric8ConfigUtils.getApplicationNamespace(mockClient, "", "target", null);
|
||||
assertThat(result).isEqualTo("qwe");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNamespaceResolutionFailed() {
|
||||
assertThatThrownBy(() -> Fabric8ConfigUtils.getApplicationNamespace(mockClient, "", "target", null))
|
||||
.isInstanceOf(NamespaceResolutionFailedException.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -42,7 +42,8 @@ public class KubernetesConfigConfigurationTest extends KubernetesConfigTestBase
|
||||
|
||||
@Test
|
||||
public void kubernetesWhenKubernetesDefaultEnabled() {
|
||||
setup(KubernetesClientTestConfiguration.class, "spring.cloud.kubernetes.enabled=true");
|
||||
setup(KubernetesClientTestConfiguration.class, "spring.cloud.kubernetes.enabled=true",
|
||||
"spring.cloud.kubernetes.client.namespace=default");
|
||||
assertThat(getContext().containsBean("configMapPropertySourceLocator")).isTrue();
|
||||
assertThat(getContext().containsBean("secretsPropertySourceLocator")).isTrue();
|
||||
}
|
||||
@@ -65,7 +66,7 @@ public class KubernetesConfigConfigurationTest extends KubernetesConfigTestBase
|
||||
@Test
|
||||
public void kubernetesWhenKubernetesConfigEnabledButSecretDisabled() {
|
||||
setup(KubernetesClientTestConfiguration.class, "spring.cloud.kubernetes.config.enabled=true",
|
||||
"spring.cloud.kubernetes.secrets.enabled=false");
|
||||
"spring.cloud.kubernetes.secrets.enabled=false", "spring.cloud.kubernetes.client.namespace=default");
|
||||
assertThat(getContext().containsBean("configMapPropertySourceLocator")).isTrue();
|
||||
assertThat(getContext().containsBean("secretsPropertySourceLocator")).isFalse();
|
||||
}
|
||||
@@ -81,7 +82,7 @@ public class KubernetesConfigConfigurationTest extends KubernetesConfigTestBase
|
||||
@Test
|
||||
public void kubernetesConfigWhenKubernetesEnabledAndKubernetesConfigEnabled() {
|
||||
setup(KubernetesClientTestConfiguration.class, "spring.cloud.kubernetes.config.enabled=true",
|
||||
"spring.cloud.kubernetes.secrets.enabled=true");
|
||||
"spring.cloud.kubernetes.secrets.enabled=true", "spring.cloud.kubernetes.client.namespace=default");
|
||||
assertThat(getContext().containsBean("configMapPropertySourceLocator")).isTrue();
|
||||
assertThat(getContext().containsBean("secretsPropertySourceLocator")).isTrue();
|
||||
}
|
||||
|
||||
@@ -37,13 +37,14 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
@ClassPathExclusions({ "spring-boot-actuator-autoconfigure-*.jar", "spring-boot-starter-actuator-*.jar" })
|
||||
public class MissingActuatorTest {
|
||||
|
||||
private static ConfigurableApplicationContext getApplicationContext(Class<?> configuration, String... properties) {
|
||||
return new SpringApplicationBuilder(configuration).web(WebApplicationType.NONE).properties(properties).run();
|
||||
private static ConfigurableApplicationContext getApplicationContext(String... properties) {
|
||||
return new SpringApplicationBuilder(Config.class).web(WebApplicationType.NONE).properties(properties).run();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unknownClassProtected(CapturedOutput capturedOutput) {
|
||||
try (ConfigurableApplicationContext context = getApplicationContext(Config.class, "debug=true")) {
|
||||
try (ConfigurableApplicationContext context = getApplicationContext("debug=true",
|
||||
"spring.cloud.kubernetes.client.namespace=default")) {
|
||||
String output = capturedOutput.toString();
|
||||
assertThat(output)
|
||||
.doesNotContain("Failed to introspect annotations on"
|
||||
|
||||
Reference in New Issue
Block a user