This commit is contained in:
erabii
2023-04-24 21:28:42 +03:00
committed by GitHub
parent 86d380154b
commit 061709a014
7 changed files with 403 additions and 28 deletions

View File

@@ -0,0 +1,61 @@
/*
* Copyright 2013-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.kubernetes.commons;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
import org.springframework.context.annotation.Conditional;
/**
* {@link Conditional @Conditional} that matches when either or both of
* {@link ConditionalOnKubernetesConfigEnabled @ConditionalOnKubernetesConfigEnabled} and
* {@link ConditionalOnKubernetesSecretsEnabled @ConditionalOnKubernetesSecretsEnabled}.
*
* @author wind57
*/
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Conditional(ConditionalOnKubernetesConfigMapsOrSecretsEnabled.OnKubernetesConfigMapsOrSecretesEnabled.class)
public @interface ConditionalOnKubernetesConfigMapsOrSecretsEnabled {
class OnKubernetesConfigMapsOrSecretesEnabled extends AnyNestedCondition {
OnKubernetesConfigMapsOrSecretesEnabled() {
super(ConfigurationPhase.REGISTER_BEAN);
}
@ConditionalOnKubernetesConfigEnabled
static class OnConfigMapPropertiesRetryEnabled {
}
@ConditionalOnKubernetesSecretsEnabled
static class OnSecretsPropertiesRetryEnabled {
}
}
}

View File

@@ -23,13 +23,15 @@ import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfi
import org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnCloudPlatform;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.cloud.CloudPlatform;
import org.springframework.cloud.autoconfigure.RefreshAutoConfiguration;
import org.springframework.cloud.autoconfigure.RefreshEndpointAutoConfiguration;
import org.springframework.cloud.commons.util.TaskSchedulerWrapper;
import org.springframework.cloud.context.refresh.ContextRefresher;
import org.springframework.cloud.context.restart.RestartEndpoint;
import org.springframework.cloud.kubernetes.commons.config.ConditionalOnKubernetesAndConfigEnabled;
import org.springframework.cloud.kubernetes.commons.ConditionalOnKubernetesConfigMapsOrSecretsEnabled;
import org.springframework.cloud.kubernetes.commons.config.reload.condition.ConditionalOnKubernetesReloadEnabled;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
@@ -41,7 +43,8 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
* @author Ryan Baxter
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnKubernetesAndConfigEnabled
@ConditionalOnCloudPlatform(CloudPlatform.KUBERNETES)
@ConditionalOnKubernetesConfigMapsOrSecretsEnabled
@ConditionalOnKubernetesReloadEnabled
@ConditionalOnClass({ EndpointAutoConfiguration.class, RestartEndpoint.class, ContextRefresher.class })
@AutoConfigureAfter({ InfoEndpointAutoConfiguration.class, RefreshEndpointAutoConfiguration.class,

View File

@@ -0,0 +1,148 @@
/*
* Copyright 2013-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.kubernetes.commons.reload;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.cloud.autoconfigure.RefreshAutoConfiguration;
import org.springframework.cloud.autoconfigure.RefreshEndpointAutoConfiguration;
import org.springframework.cloud.commons.util.TaskSchedulerWrapper;
import org.springframework.cloud.context.properties.ConfigurationPropertiesRebinder;
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadAutoConfiguration;
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadPropertiesAutoConfiguration;
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigurationUpdateStrategy;
import org.springframework.context.annotation.Bean;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author wind57
*/
class ConfigReloadAutoConfigurationApplicationContextTests {
private ApplicationContextRunner applicationContextRunner;
/**
* no special properties provided.
*/
@Test
void testDefault() {
setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.kubernetes.reload.enabled=true");
applicationContextRunner.run(context -> assertThat(context).hasSingleBean(TaskSchedulerWrapper.class));
applicationContextRunner.run(context -> assertThat(context).hasSingleBean(ConfigurationUpdateStrategy.class));
}
/**
* reload is disabled.
*/
@Test
void testReloadDisabled() {
setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.kubernetes.reload.enabled=false");
applicationContextRunner.run(context -> assertThat(context).doesNotHaveBean(TaskSchedulerWrapper.class));
applicationContextRunner.run(context -> assertThat(context).doesNotHaveBean(ConfigurationUpdateStrategy.class));
}
/**
* config maps support is enabled.
*/
@Test
void testConfigMapsSupportEnabled() {
setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.kubernetes.reload.enabled=true",
"spring.cloud.kubernetes.config.enabled=true");
applicationContextRunner.run(context -> assertThat(context).hasSingleBean(TaskSchedulerWrapper.class));
applicationContextRunner.run(context -> assertThat(context).hasSingleBean(ConfigurationUpdateStrategy.class));
}
/**
* secrets support is enabled.
*/
@Test
void testSecretsSupportEnabled() {
setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.kubernetes.reload.enabled=true",
"spring.cloud.kubernetes.secrets.enabled=true");
applicationContextRunner.run(context -> assertThat(context).hasSingleBean(TaskSchedulerWrapper.class));
applicationContextRunner.run(context -> assertThat(context).hasSingleBean(ConfigurationUpdateStrategy.class));
}
/**
* config maps and secrets support is enabled.
*/
@Test
void testConfigMapsAndSecretsSupportEnabled() {
setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.kubernetes.reload.enabled=true",
"spring.cloud.kubernetes.config.enabled=true", "spring.cloud.kubernetes.secrets.enabled=true");
applicationContextRunner.run(context -> assertThat(context).hasSingleBean(TaskSchedulerWrapper.class));
applicationContextRunner.run(context -> assertThat(context).hasSingleBean(ConfigurationUpdateStrategy.class));
}
/**
* config maps and secrets support is disabled.
*/
@Test
void testConfigMapsAndSecretsSupportDisabled() {
setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.kubernetes.reload.enabled=true",
"spring.cloud.kubernetes.config.enabled=false", "spring.cloud.kubernetes.secrets.enabled=false");
applicationContextRunner.run(context -> assertThat(context).doesNotHaveBean(TaskSchedulerWrapper.class));
applicationContextRunner.run(context -> assertThat(context).doesNotHaveBean(ConfigurationUpdateStrategy.class));
}
/**
* config maps support disabled and secrets support is enabled.
*/
@Test
void testConfigMapsDisabledAndSecretsSupportEnabled() {
setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.kubernetes.reload.enabled=true",
"spring.cloud.kubernetes.config.enabled=false", "spring.cloud.kubernetes.secrets.enabled=true");
applicationContextRunner.run(context -> assertThat(context).hasSingleBean(TaskSchedulerWrapper.class));
applicationContextRunner.run(context -> assertThat(context).hasSingleBean(ConfigurationUpdateStrategy.class));
}
/**
* config maps support enabled and secrets support is disable.
*/
@Test
void testConfigMapsEnabledAndSecretsSupportDisabled() {
setup("spring.main.cloud-platform=KUBERNETES", "spring.cloud.kubernetes.reload.enabled=true",
"spring.cloud.kubernetes.config.enabled=true", "spring.cloud.kubernetes.secrets.enabled=false");
applicationContextRunner.run(context -> assertThat(context).hasSingleBean(TaskSchedulerWrapper.class));
applicationContextRunner.run(context -> assertThat(context).hasSingleBean(ConfigurationUpdateStrategy.class));
}
private void setup(String... properties) {
applicationContextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(InfoEndpointAutoConfiguration.class,
RefreshEndpointAutoConfiguration.class, ConfigReloadPropertiesAutoConfiguration.class,
RefreshAutoConfiguration.class, ConfigReloadAutoConfiguration.class))
.withUserConfiguration(RebinderConfig.class).withPropertyValues(properties);
}
@TestConfiguration
static class RebinderConfig {
@Bean
ConfigurationPropertiesRebinder rebinder() {
return Mockito.mock(ConfigurationPropertiesRebinder.class);
}
}
}

View File

@@ -17,8 +17,11 @@
package org.springframework.cloud.kubernetes.client.configmap.event.reload;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;
@@ -28,6 +31,7 @@ import io.kubernetes.client.openapi.apis.CoreV1Api;
import io.kubernetes.client.openapi.models.V1ConfigMap;
import io.kubernetes.client.openapi.models.V1ConfigMapBuilder;
import io.kubernetes.client.openapi.models.V1Deployment;
import io.kubernetes.client.openapi.models.V1EnvVar;
import io.kubernetes.client.openapi.models.V1Ingress;
import io.kubernetes.client.openapi.models.V1ObjectMeta;
import io.kubernetes.client.openapi.models.V1Service;
@@ -94,7 +98,7 @@ class ConfigMapEventReloadIT {
*/
@Test
void testInformFromOneNamespaceEventNotTriggered() throws Exception {
manifests("one", Phase.CREATE);
manifests("one", Phase.CREATE, false);
Commons.assertReloadLogStatements("added configmap informer for namespace",
"added secret informer for namespace", IMAGE_NAME);
@@ -125,7 +129,7 @@ class ConfigMapEventReloadIT {
// left configmap has not changed, no restart of app has happened
Assertions.assertEquals("left-initial", result);
manifests("one", Phase.DELETE);
manifests("one", Phase.DELETE, false);
}
/**
@@ -138,7 +142,7 @@ class ConfigMapEventReloadIT {
*/
@Test
void testInformFromOneNamespaceEventTriggered() throws Exception {
manifests("two", Phase.CREATE);
manifests("two", Phase.CREATE, false);
Commons.assertReloadLogStatements("added configmap informer for namespace",
"added secret informer for namespace", IMAGE_NAME);
@@ -166,7 +170,7 @@ class ConfigMapEventReloadIT {
});
Assertions.assertEquals("right-after-change", resultAfterChange[0]);
manifests("two", Phase.DELETE);
manifests("two", Phase.DELETE, false);
}
/**
@@ -180,7 +184,7 @@ class ConfigMapEventReloadIT {
*/
@Test
void testInform() throws Exception {
manifests("three", Phase.CREATE);
manifests("three", Phase.CREATE, false);
Commons.assertReloadLogStatements("added configmap informer for namespace",
"added secret informer for namespace", IMAGE_NAME);
@@ -236,10 +240,51 @@ class ConfigMapEventReloadIT {
.block();
Assertions.assertEquals("right-after-change", rightResult);
manifests("three", Phase.DELETE);
manifests("three", Phase.DELETE, false);
}
private static void manifests(String deploymentRoot, Phase phase) {
/**
* <pre>
* - there are two namespaces : left and right
* - each of the namespaces has one configmap
* - we watch the "right" namespace and make a change in the configmap in the same namespace
* - as such, event is triggered and we see the updated value
* </pre>
*/
@Test
void testInformFromOneNamespaceEventTriggeredSecretsDisabled() throws Exception {
manifests("two", Phase.CREATE, true);
Commons.assertReloadLogStatements("added configmap informer for namespace",
"added secret informer for namespace", IMAGE_NAME);
// read the value from the right-configmap
WebClient webClient = builder().baseUrl("http://localhost/right").build();
String result = webClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class).retryWhen(retrySpec())
.block();
Assertions.assertEquals("right-initial", result);
// then deploy a new version of right-configmap
V1ConfigMap rightConfigMapAfterChange = new V1ConfigMapBuilder()
.withMetadata(new V1ObjectMeta().namespace("right").name("right-configmap"))
.withData(Map.of("right.value", "right-after-change")).build();
replaceConfigMap(rightConfigMapAfterChange, "right-configmap");
String[] resultAfterChange = new String[1];
await().pollInterval(Duration.ofSeconds(3)).atMost(Duration.ofSeconds(90)).until(() -> {
WebClient innerWebClient = builder().baseUrl("http://localhost/right").build();
String innerResult = innerWebClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class)
.retryWhen(retrySpec()).block();
resultAfterChange[0] = innerResult;
return innerResult != null;
});
Assertions.assertEquals("right-after-change", resultAfterChange[0]);
manifests("two", Phase.DELETE, true);
}
private static void manifests(String deploymentRoot, Phase phase, boolean secretsDisabled) {
try {
@@ -251,6 +296,16 @@ class ConfigMapEventReloadIT {
V1Service service = (V1Service) util.yaml("service.yaml");
V1Ingress ingress = (V1Ingress) util.yaml("ingress.yaml");
List<V1EnvVar> envVars = new ArrayList<>(
Optional.ofNullable(deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getEnv())
.orElse(List.of()));
if (secretsDisabled) {
V1EnvVar secretsDisabledEnvVar = new V1EnvVar().name("SPRING_CLOUD_KUBERNETES_SECRETS_ENABLED").value("FALSE");
envVars.add(secretsDisabledEnvVar);
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setEnv(envVars);
}
if (phase.equals(Phase.CREATE)) {
util.createAndWait("left", leftConfigMap, null);
util.createAndWait("right", rightConfigMap, null);

View File

@@ -17,16 +17,19 @@
package org.springframework.cloud.kubernetes.client.secrets.event.reload;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import io.kubernetes.client.openapi.apis.CoreV1Api;
import io.kubernetes.client.openapi.models.V1Deployment;
import io.kubernetes.client.openapi.models.V1EnvVar;
import io.kubernetes.client.openapi.models.V1Ingress;
import io.kubernetes.client.openapi.models.V1Secret;
import io.kubernetes.client.openapi.models.V1Service;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.testcontainers.k3s.K3sContainer;
@@ -75,17 +78,22 @@ class SecretsEventReloadIT {
Commons.cleanUp(IMAGE_NAME, K3S);
}
@AfterEach
void after() {
configK8sClientIt(Phase.DELETE);
}
@Test
void testSecretReload() throws Exception {
configK8sClientIt(Phase.CREATE);
configK8sClientIt(Phase.CREATE, false);
Commons.assertReloadLogStatements("added secret informer for namespace",
"added configmap informer for namespace", IMAGE_NAME);
testSecretEventReload();
configK8sClientIt(Phase.DELETE, false);
}
@Test
void testSecretReloadConfigDisabled() throws Exception {
configK8sClientIt(Phase.CREATE, true);
Commons.assertReloadLogStatements("added secret informer for namespace",
"added configmap informer for namespace", IMAGE_NAME);
testSecretEventReload();
configK8sClientIt(Phase.DELETE, true);
}
void testSecretEventReload() throws Exception {
@@ -108,12 +116,22 @@ class SecretsEventReloadIT {
.retryWhen(retrySpec()).block().equals("after-change"));
}
private void configK8sClientIt(Phase phase) {
private void configK8sClientIt(Phase phase, boolean configDisabled) {
V1Deployment deployment = (V1Deployment) util.yaml("deployment.yaml");
V1Service service = (V1Service) util.yaml("service.yaml");
V1Ingress ingress = (V1Ingress) util.yaml("ingress.yaml");
V1Secret secret = (V1Secret) util.yaml("secret.yaml");
List<V1EnvVar> envVars = new ArrayList<>(
Optional.ofNullable(deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getEnv())
.orElse(List.of()));
if (configDisabled) {
V1EnvVar disableConfig = new V1EnvVar().name("SPRING_CLOUD_KUBERNETES_CONFIG_ENABLED").value("FALSE");
envVars.add(disableConfig);
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setEnv(envVars);
}
if (phase.equals(Phase.CREATE)) {
util.createAndWait(NAMESPACE, null, deployment, service, ingress, true);
util.createAndWait(NAMESPACE, null, secret);

View File

@@ -99,7 +99,7 @@ class ConfigMapEventReloadIT {
*/
@Test
void testInformFromOneNamespaceEventNotTriggered() {
manifests("one", Phase.CREATE);
manifests("one", Phase.CREATE, false);
Commons.assertReloadLogStatements("added configmap informer for namespace",
"added secret informer for namespace", IMAGE_NAME);
@@ -130,7 +130,7 @@ class ConfigMapEventReloadIT {
// left configmap has not changed, no restart of app has happened
Assertions.assertEquals("left-initial", result);
manifests("one", Phase.DELETE);
manifests("one", Phase.DELETE, false);
}
/**
@@ -143,7 +143,7 @@ class ConfigMapEventReloadIT {
*/
@Test
void testInformFromOneNamespaceEventTriggered() {
manifests("two", Phase.CREATE);
manifests("two", Phase.CREATE, false);
Commons.assertReloadLogStatements("added configmap informer for namespace",
"added secret informer for namespace", IMAGE_NAME);
@@ -170,7 +170,7 @@ class ConfigMapEventReloadIT {
});
Assertions.assertEquals("right-after-change", resultAfterChange[0]);
manifests("two", Phase.DELETE);
manifests("two", Phase.DELETE, false);
}
/**
@@ -184,7 +184,7 @@ class ConfigMapEventReloadIT {
*/
@Test
void testInform() {
manifests("three", Phase.CREATE);
manifests("three", Phase.CREATE, false);
Commons.assertReloadLogStatements("added configmap informer for namespace",
"added secret informer for namespace", IMAGE_NAME);
@@ -241,10 +241,51 @@ class ConfigMapEventReloadIT {
.block();
Assertions.assertEquals("right-after-change", rightResult);
manifests("three", Phase.DELETE);
manifests("three", Phase.DELETE, false);
}
private static void manifests(String activeProfile, Phase phase) {
/**
* <pre>
* - there are two namespaces : left and right
* - each of the namespaces has one configmap
* - secrets are disabled
* - we watch the "right" namespace and make a change in the configmap in the same namespace
* - as such, event is triggered and we see the updated value
* </pre>
*/
@Test
void testInformFromOneNamespaceEventTriggeredSecretsDisabled() {
manifests("two", Phase.CREATE, true);
Commons.assertReloadLogStatements("added configmap informer for namespace",
"added secret informer for namespace", IMAGE_NAME);
// read the value from the right-configmap
WebClient webClient = builder().baseUrl("http://localhost/right").build();
String result = webClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class).retryWhen(retrySpec())
.block();
Assertions.assertEquals("right-initial", result);
// then deploy a new version of right-configmap
ConfigMap rightConfigMapAfterChange = new ConfigMapBuilder()
.withMetadata(new ObjectMetaBuilder().withNamespace("right").withName("right-configmap").build())
.withData(Map.of("right.value", "right-after-change")).build();
replaceConfigMap(rightConfigMapAfterChange);
String[] resultAfterChange = new String[1];
await().pollInterval(Duration.ofSeconds(3)).atMost(Duration.ofSeconds(90)).until(() -> {
WebClient innerWebClient = builder().baseUrl("http://localhost/right").build();
String innerResult = innerWebClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class)
.retryWhen(retrySpec()).block();
resultAfterChange[0] = innerResult;
return innerResult != null;
});
Assertions.assertEquals("right-after-change", resultAfterChange[0]);
manifests("two", Phase.DELETE, true);
}
private static void manifests(String activeProfile, Phase phase, boolean secretsDisabled) {
InputStream deploymentStream = util.inputStream("deployment.yaml");
InputStream serviceStream = util.inputStream("service.yaml");
@@ -261,6 +302,13 @@ class ConfigMapEventReloadIT {
.build();
envVars.add(activeProfileProperty);
if (secretsDisabled) {
EnvVar secretsDisabledEnvVar = new EnvVarBuilder().withName("SPRING_CLOUD_KUBERNETES_SECRETS_ENABLED")
.withValue("FALSE").build();
envVars.add(secretsDisabledEnvVar);
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setEnv(envVars);
}
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setEnv(envVars);
Service service = client.services().load(serviceStream).get();

View File

@@ -18,10 +18,14 @@ package org.springframework.cloud.kubernetes.fabric8.secrets.event.reload;
import java.io.InputStream;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import io.fabric8.kubernetes.api.model.EnvVar;
import io.fabric8.kubernetes.api.model.EnvVarBuilder;
import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
import io.fabric8.kubernetes.api.model.Secret;
import io.fabric8.kubernetes.api.model.SecretBuilder;
@@ -71,17 +75,16 @@ class SecretsEventsReloadIT {
util = new Util(K3S);
client = util.client();
util.setUp(NAMESPACE);
manifests(Phase.CREATE);
}
@AfterAll
static void after() throws Exception {
manifests(Phase.DELETE);
Commons.cleanUp(IMAGE_NAME, K3S);
}
@Test
void test() {
void testSimple() {
manifests(Phase.CREATE, false);
Commons.assertReloadLogStatements("added secret informer for namespace",
"added configmap informer for namespace", IMAGE_NAME);
WebClient webClient = builder().baseUrl("http://localhost/key").build();
@@ -104,9 +107,39 @@ class SecretsEventsReloadIT {
await().timeout(Duration.ofSeconds(120)).until(() -> webClient.method(HttpMethod.GET).retrieve()
.bodyToMono(String.class).retryWhen(retrySpec()).block().equals("after-change"));
manifests(Phase.DELETE, false);
}
private static void manifests(Phase phase) {
@Test
void testSimpleConfigMapsDisabled() {
manifests(Phase.CREATE, true);
Commons.assertReloadLogStatements("added secret informer for namespace",
"added configmap informer for namespace", IMAGE_NAME);
WebClient webClient = builder().baseUrl("http://localhost/key").build();
String result = webClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class).retryWhen(retrySpec())
.block();
// we first read the initial value from the secret
Assertions.assertEquals("initial", result);
// then deploy a new version of the secret
// since we poll and have reload in place, the new property must be visible
Secret secret = new SecretBuilder()
.withMetadata(new ObjectMetaBuilder().withNamespace("default").withName("event-reload").build())
.withData(Map.of("application.properties",
Base64.getEncoder().encodeToString("from.properties.key=after-change".getBytes())))
.build();
client.secrets().inNamespace("default").resource(secret).createOrReplace();
await().timeout(Duration.ofSeconds(120)).until(() -> webClient.method(HttpMethod.GET).retrieve()
.bodyToMono(String.class).retryWhen(retrySpec()).block().equals("after-change"));
manifests(Phase.DELETE, true);
}
private static void manifests(Phase phase, boolean configMapsDisabled) {
InputStream deploymentStream = util.inputStream("deployment.yaml");
InputStream serviceStream = util.inputStream("service.yaml");
@@ -118,6 +151,15 @@ class SecretsEventsReloadIT {
Ingress ingress = client.network().v1().ingresses().load(ingressStream).get();
Secret secret = client.secrets().load(secretStream).get();
if (configMapsDisabled) {
List<EnvVar> envVars = new ArrayList<>(
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getEnv());
EnvVar configMapsDisabledEnvVar = new EnvVarBuilder().withName("SPRING_CLOUD_KUBERNETES_CONFIG_ENABLED")
.withValue("FALSE").build();
envVars.add(configMapsDisabledEnvVar);
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setEnv(envVars);
}
if (phase.equals(Phase.CREATE)) {
util.createAndWait(NAMESPACE, null, secret);
util.createAndWait(NAMESPACE, null, deployment, service, ingress, true);