diff --git a/spring-cloud-kubernetes-integration-tests/pom.xml b/spring-cloud-kubernetes-integration-tests/pom.xml index 03363f50..daae6f36 100644 --- a/spring-cloud-kubernetes-integration-tests/pom.xml +++ b/spring-cloud-kubernetes-integration-tests/pom.xml @@ -52,9 +52,8 @@ spring-cloud-kubernetes-fabric8-istio-it spring-cloud-kubernetes-fabric8-client-discovery spring-cloud-kubernetes-fabric8-client-loadbalancer - spring-cloud-kubernetes-fabric8-client-configmap-polling-reload spring-cloud-kubernetes-fabric8-client-secrets-event-reload - spring-cloud-kubernetes-fabric8-client-configmap-event-reload + spring-cloud-kubernetes-fabric8-client-reload spring-cloud-kubernetes-discoveryclient-it spring-cloud-kubernetes-client-loadbalancer-it diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/pom.xml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/pom.xml deleted file mode 100644 index a1ba8bb1..00000000 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/pom.xml +++ /dev/null @@ -1,113 +0,0 @@ - - - - spring-cloud-kubernetes-integration-tests - org.springframework.cloud - 3.0.5-SNAPSHOT - - 4.0.0 - - spring-cloud-kubernetes-fabric8-client-configmap-event-reload - - - - - org.springframework.cloud - spring-cloud-kubernetes-fabric8-config - - - org.springframework.boot - spring-boot-starter-webflux - - - org.springframework.boot - spring-boot-starter-actuator - - - - org.springframework.cloud - spring-cloud-starter-bootstrap - - - - org.springframework.cloud - spring-cloud-kubernetes-test-support - - - - - - - - ../src/main/resources - true - - - src/main/resources - true - - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - docker.io/springcloud/${project.artifactId}:${project.version} - - - - build-image - - ${skip.build.image} - - package - - build-image - - - - repackage - package - - repackage - - - - - - - - org.apache.maven.plugins - maven-surefire-plugin - - true - - - - - - org.apache.maven.plugins - maven-failsafe-plugin - - - - integration-test - - - - - - ${testsToRun} - - - - - - - - diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/test/resources/service.yaml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/test/resources/service.yaml deleted file mode 100644 index bbaf7b1e..00000000 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/test/resources/service.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - labels: - app: spring-cloud-kubernetes-fabric8-client-configmap-event-reload - name: spring-cloud-kubernetes-fabric8-client-configmap-event-reload -spec: - ports: - - name: http - port: 8080 - targetPort: 8080 - selector: - app: spring-cloud-kubernetes-fabric8-client-configmap-event-reload - type: ClusterIP diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/configmap/polling/reload/ConfigMapApp.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/configmap/polling/reload/ConfigMapApp.java deleted file mode 100644 index 8594a99c..00000000 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/configmap/polling/reload/ConfigMapApp.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2013-2022 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.kubernetes.fabric8.configmap.polling.reload; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.context.properties.EnableConfigurationProperties; - -/** - * @author wind57 - */ - -@SpringBootApplication -@EnableConfigurationProperties(ConfigMapProperties.class) -public class ConfigMapApp { - - public static void main(String[] args) { - SpringApplication.run(ConfigMapApp.class, args); - } - -} diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/configmap/polling/reload/ConfigMapController.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/configmap/polling/reload/ConfigMapController.java deleted file mode 100644 index c59aa7fc..00000000 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/configmap/polling/reload/ConfigMapController.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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.fabric8.configmap.polling.reload; - -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; - -/** - * @author wind57 - */ -@RestController -public class ConfigMapController { - - private final ConfigMapProperties properties; - - public ConfigMapController(ConfigMapProperties properties) { - this.properties = properties; - } - - @GetMapping("/key") - public String key() { - return properties.getKey(); - } - -} diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/test/java/org/springframework/cloud/kubernetes/fabric8/configmap/polling/reload/BootstrapEnabledPollingReloadConfigMapMountIT.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/test/java/org/springframework/cloud/kubernetes/fabric8/configmap/polling/reload/BootstrapEnabledPollingReloadConfigMapMountIT.java deleted file mode 100644 index 245ffaf4..00000000 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/test/java/org/springframework/cloud/kubernetes/fabric8/configmap/polling/reload/BootstrapEnabledPollingReloadConfigMapMountIT.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * 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.fabric8.configmap.polling.reload; - -import java.io.InputStream; -import java.time.Duration; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -import io.fabric8.kubernetes.api.model.ConfigMap; -import io.fabric8.kubernetes.api.model.EnvVar; -import io.fabric8.kubernetes.api.model.EnvVarBuilder; -import io.fabric8.kubernetes.api.model.Service; -import io.fabric8.kubernetes.api.model.apps.Deployment; -import io.fabric8.kubernetes.api.model.networking.v1.Ingress; -import io.fabric8.kubernetes.client.KubernetesClient; -import io.fabric8.kubernetes.client.utils.Serialization; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.testcontainers.containers.Container; -import org.testcontainers.k3s.K3sContainer; -import reactor.netty.http.client.HttpClient; -import reactor.util.retry.Retry; -import reactor.util.retry.RetryBackoffSpec; - -import org.springframework.cloud.kubernetes.integration.tests.commons.Commons; -import org.springframework.cloud.kubernetes.integration.tests.commons.Phase; -import org.springframework.cloud.kubernetes.integration.tests.commons.fabric8_client.Util; -import org.springframework.http.HttpMethod; -import org.springframework.http.client.reactive.ReactorClientHttpConnector; -import org.springframework.web.reactive.function.client.WebClient; - -import static org.awaitility.Awaitility.await; - -public class BootstrapEnabledPollingReloadConfigMapMountIT { - - private static final String IMAGE_NAME = "spring-cloud-kubernetes-fabric8-client-configmap-polling-reload"; - - private static final String NAMESPACE = "default"; - - private static Util util; - - private static KubernetesClient client; - - private static final K3sContainer K3S = Commons.container(); - - @BeforeAll - static void beforeAll() throws Exception { - K3S.start(); - Commons.validateImage(IMAGE_NAME, K3S); - Commons.loadSpringCloudKubernetesImage(IMAGE_NAME, K3S); - 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); - Commons.systemPrune(); - } - - /** - *
-	 *     - we have bootstrap enabled, which means we will 'locate' property sources
-	 *       from config maps.
-	 *     - there are no explicit config maps to search for, but what we will also read,
-	 *     	 is 'spring.cloud.kubernetes.config.paths', which we have set to
-	 *     	 '/tmp/application.properties'
-	 *       in this test. That is populated by the volumeMounts (see deployment-mount.yaml)
-	 *     - we first assert that we are actually reading the path based source via (1), (2) and (3).
-	 *
-	 *     - we then change the config map content, wait for k8s to pick it up and replace them
-	 *     - our polling will then detect that change, and trigger a reload.
-	 * 
- */ - @Test - void test() { - String logs = logs(); - // (1) - Assertions.assertTrue(logs.contains("paths property sources : [/tmp/application.properties]")); - // (2) - Assertions.assertTrue(logs.contains("will add file-based property source : /tmp/application.properties")); - // (3) - 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 configmap - Assertions.assertEquals("as-mount-initial", result); - - // replace data in configmap and wait for k8s to pick it up - // our polling will detect that and restart the app - InputStream configMapStream = util.inputStream("mount/configmap-mount.yaml"); - ConfigMap configMap = Serialization.unmarshal(configMapStream, ConfigMap.class); - configMap.setData(Map.of("application.properties", "from.properties.key=as-mount-changed")); - client.configMaps().inNamespace("default").resource(configMap).createOrReplace(); - - await().timeout(Duration.ofSeconds(360)).until(() -> webClient.method(HttpMethod.GET).retrieve() - .bodyToMono(String.class).retryWhen(retrySpec()).block().equals("as-mount-changed")); - - } - - private static void manifests(Phase phase) { - - InputStream deploymentStream = util.inputStream("mount/deployment-mount.yaml"); - InputStream serviceStream = util.inputStream("service.yaml"); - InputStream ingressStream = util.inputStream("ingress.yaml"); - InputStream configMapStream = util.inputStream("mount/configmap-mount.yaml"); - - Deployment deployment = Serialization.unmarshal(deploymentStream, Deployment.class); - Service service = Serialization.unmarshal(serviceStream, Service.class); - Ingress ingress = Serialization.unmarshal(ingressStream, Ingress.class); - ConfigMap configMap = Serialization.unmarshal(configMapStream, ConfigMap.class); - - List existing = new ArrayList<>( - deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getEnv()); - - // bootstrap is enabled, which means that in 'application-with-bootstrap.yaml', - // config-data support is disabled. - EnvVar withBootstrapActiveProfile = new EnvVarBuilder().withName("SPRING_PROFILES_ACTIVE") - .withValue("with-bootstrap").build(); - EnvVar enabledBootstrap = new EnvVarBuilder().withName("SPRING_CLOUD_BOOTSTRAP_ENABLED").withValue("TRUE") - .build(); - - EnvVar debugLevelReloadCommons = new EnvVarBuilder() - .withName("LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_COMMONS_CONFIG_RELOAD").withValue("DEBUG") - .build(); - EnvVar debugLevelConfig = new EnvVarBuilder() - .withName("LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_COMMONS_CONFIG").withValue("DEBUG") - .build(); - EnvVar debugLevelCommons = new EnvVarBuilder() - .withName("LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_COMMONS").withValue("DEBUG").build(); - - existing.add(withBootstrapActiveProfile); - existing.add(enabledBootstrap); - existing.add(debugLevelReloadCommons); - existing.add(debugLevelCommons); - existing.add(debugLevelConfig); - deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setEnv(existing); - - if (phase.equals(Phase.CREATE)) { - util.createAndWait(NAMESPACE, configMap, null); - util.createAndWait(NAMESPACE, null, deployment, service, ingress, true); - } - else { - util.deleteAndWait(NAMESPACE, configMap, null); - util.deleteAndWait(NAMESPACE, deployment, service, ingress); - } - - } - - private WebClient.Builder builder() { - return WebClient.builder().clientConnector(new ReactorClientHttpConnector(HttpClient.create())); - } - - private RetryBackoffSpec retrySpec() { - return Retry.fixedDelay(60, Duration.ofSeconds(1)).filter(Objects::nonNull); - } - - private String logs() { - try { - String appPodName = K3S.execInContainer("sh", "-c", - "kubectl get pods -l app=" + IMAGE_NAME + " -o=name --no-headers | tr -d '\n'").getStdout(); - - Container.ExecResult execResult = K3S.execInContainer("sh", "-c", "kubectl logs " + appPodName.trim()); - return execResult.getStdout(); - } - catch (Exception e) { - e.printStackTrace(); - throw new RuntimeException(e); - } - } - -} diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/test/java/org/springframework/cloud/kubernetes/fabric8/configmap/polling/reload/ConfigMapPollingReloadIT.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/test/java/org/springframework/cloud/kubernetes/fabric8/configmap/polling/reload/ConfigMapPollingReloadIT.java deleted file mode 100644 index 699e2058..00000000 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/test/java/org/springframework/cloud/kubernetes/fabric8/configmap/polling/reload/ConfigMapPollingReloadIT.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright 2013-2022 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.kubernetes.fabric8.configmap.polling.reload; - -import java.io.InputStream; -import java.time.Duration; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -import io.fabric8.kubernetes.api.model.ConfigMap; -import io.fabric8.kubernetes.api.model.ConfigMapBuilder; -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.Service; -import io.fabric8.kubernetes.api.model.apps.Deployment; -import io.fabric8.kubernetes.api.model.networking.v1.Ingress; -import io.fabric8.kubernetes.client.KubernetesClient; -import io.fabric8.kubernetes.client.utils.Serialization; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.testcontainers.k3s.K3sContainer; -import reactor.netty.http.client.HttpClient; -import reactor.util.retry.Retry; -import reactor.util.retry.RetryBackoffSpec; - -import org.springframework.cloud.kubernetes.integration.tests.commons.Commons; -import org.springframework.cloud.kubernetes.integration.tests.commons.Phase; -import org.springframework.cloud.kubernetes.integration.tests.commons.fabric8_client.Util; -import org.springframework.http.HttpMethod; -import org.springframework.http.client.reactive.ReactorClientHttpConnector; -import org.springframework.web.reactive.function.client.WebClient; - -import static org.awaitility.Awaitility.await; - -/** - * @author wind57 - */ -class ConfigMapPollingReloadIT { - - private static final String IMAGE_NAME = "spring-cloud-kubernetes-fabric8-client-configmap-polling-reload"; - - private static final String NAMESPACE = "default"; - - private static Util util; - - private static KubernetesClient client; - - private static final K3sContainer K3S = Commons.container(); - - @BeforeAll - static void beforeAll() throws Exception { - K3S.start(); - Commons.validateImage(IMAGE_NAME, K3S); - Commons.loadSpringCloudKubernetesImage(IMAGE_NAME, K3S); - 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); - Commons.systemPrune(); - } - - @Test - void test() { - 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 configmap - Assertions.assertEquals("initial", result); - - // then deploy a new version of configmap - // since we poll and have reload in place, the new property must be visible - ConfigMap map = new ConfigMapBuilder() - .withMetadata(new ObjectMetaBuilder().withNamespace("default").withName("poll-reload").build()) - .withData(Map.of("application.properties", "from.properties.key=after-change")).build(); - - client.configMaps().inNamespace("default").resource(map).createOrReplace(); - - await().timeout(Duration.ofSeconds(60)).until(() -> webClient.method(HttpMethod.GET).retrieve() - .bodyToMono(String.class).retryWhen(retrySpec()).block().equals("after-change")); - - } - - private static void manifests(Phase phase) { - - InputStream deploymentStream = util.inputStream("deployment.yaml"); - InputStream serviceStream = util.inputStream("service.yaml"); - InputStream ingressStream = util.inputStream("ingress.yaml"); - InputStream configMapStream = util.inputStream("configmap.yaml"); - - Deployment deployment = Serialization.unmarshal(deploymentStream, Deployment.class); - Service service = Serialization.unmarshal(serviceStream, Service.class); - Ingress ingress = Serialization.unmarshal(ingressStream, Ingress.class); - ConfigMap configMap = Serialization.unmarshal(configMapStream, ConfigMap.class); - - List existing = new ArrayList<>( - deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getEnv()); - existing.add(new EnvVarBuilder().withName("SPRING_PROFILES_ACTIVE").withValue("no-mount").build()); - deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setEnv(existing); - - if (phase.equals(Phase.CREATE)) { - util.createAndWait(NAMESPACE, configMap, null); - util.createAndWait(NAMESPACE, null, deployment, service, ingress, true); - } - else { - util.deleteAndWait(NAMESPACE, configMap, null); - util.deleteAndWait(NAMESPACE, deployment, service, ingress); - } - - } - - private WebClient.Builder builder() { - return WebClient.builder().clientConnector(new ReactorClientHttpConnector(HttpClient.create())); - } - - private RetryBackoffSpec retrySpec() { - return Retry.fixedDelay(60, Duration.ofSeconds(1)).filter(Objects::nonNull); - } - -} diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/test/java/org/springframework/cloud/kubernetes/fabric8/configmap/polling/reload/PollingReloadConfigMapMountIT.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/test/java/org/springframework/cloud/kubernetes/fabric8/configmap/polling/reload/PollingReloadConfigMapMountIT.java deleted file mode 100644 index 0ab3bebc..00000000 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/test/java/org/springframework/cloud/kubernetes/fabric8/configmap/polling/reload/PollingReloadConfigMapMountIT.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * 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.fabric8.configmap.polling.reload; - -import java.io.InputStream; -import java.time.Duration; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -import io.fabric8.kubernetes.api.model.ConfigMap; -import io.fabric8.kubernetes.api.model.EnvVar; -import io.fabric8.kubernetes.api.model.EnvVarBuilder; -import io.fabric8.kubernetes.api.model.Service; -import io.fabric8.kubernetes.api.model.apps.Deployment; -import io.fabric8.kubernetes.api.model.networking.v1.Ingress; -import io.fabric8.kubernetes.client.KubernetesClient; -import io.fabric8.kubernetes.client.utils.Serialization; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.testcontainers.containers.Container; -import org.testcontainers.k3s.K3sContainer; -import reactor.netty.http.client.HttpClient; -import reactor.util.retry.Retry; -import reactor.util.retry.RetryBackoffSpec; - -import org.springframework.cloud.kubernetes.integration.tests.commons.Commons; -import org.springframework.cloud.kubernetes.integration.tests.commons.Phase; -import org.springframework.cloud.kubernetes.integration.tests.commons.fabric8_client.Util; -import org.springframework.http.HttpMethod; -import org.springframework.http.client.reactive.ReactorClientHttpConnector; -import org.springframework.web.reactive.function.client.WebClient; - -import static org.awaitility.Awaitility.await; - -/** - * @author wind57 - */ -class PollingReloadConfigMapMountIT { - - private static final String IMAGE_NAME = "spring-cloud-kubernetes-fabric8-client-configmap-polling-reload"; - - private static final String NAMESPACE = "default"; - - private static Util util; - - private static KubernetesClient client; - - private static final K3sContainer K3S = Commons.container(); - - @BeforeAll - static void beforeAll() throws Exception { - K3S.start(); - Commons.validateImage(IMAGE_NAME, K3S); - Commons.loadSpringCloudKubernetesImage(IMAGE_NAME, K3S); - 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); - Commons.systemPrune(); - } - - /** - *
-	 *     - we have "spring.config.import: kubernetes", which means we will 'locate' property sources
-	 *       from config maps.
-	 *     - the property above means that at the moment we will be searching for config maps that only
-	 *       match the application name, in this specific test there is no such config map.
-	 *     - what we will also read, is 'spring.cloud.kubernetes.config.paths', which we have set to
-	 *     	 '/tmp/application.properties'
-	 *       in this test. That is populated by the volumeMounts (see deployment-mount.yaml)
-	 *     - we first assert that we are actually reading the path based source via (1), (2) and (3).
-	 *
-	 *     - we then change the config map content, wait for k8s to pick it up and replace them
-	 *     - our polling will then detect that change, and trigger a reload.
-	 * 
- */ - @Test - void test() { - String logs = logs(); - // (1) - Assertions.assertTrue(logs.contains("paths property sources : [/tmp/application.properties]")); - // (2) - Assertions.assertTrue(logs.contains("will add file-based property source : /tmp/application.properties")); - // (3) - 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 configmap - Assertions.assertEquals("as-mount-initial", result); - - // replace data in configmap and wait for k8s to pick it up - // our polling will detect that and restart the app - InputStream configMapStream = util.inputStream("mount/configmap-mount.yaml"); - ConfigMap configMap = Serialization.unmarshal(configMapStream, ConfigMap.class); - configMap.setData(Map.of("application.properties", "from.properties.key=as-mount-changed")); - client.configMaps().inNamespace("default").resource(configMap).createOrReplace(); - - await().timeout(Duration.ofSeconds(360)).until(() -> webClient.method(HttpMethod.GET).retrieve() - .bodyToMono(String.class).retryWhen(retrySpec()).block().equals("as-mount-changed")); - - } - - private static void manifests(Phase phase) { - - InputStream deploymentStream = util.inputStream("mount/deployment-mount.yaml"); - InputStream serviceStream = util.inputStream("service.yaml"); - InputStream ingressStream = util.inputStream("ingress.yaml"); - InputStream configMapStream = util.inputStream("mount/configmap-mount.yaml"); - - Deployment deployment = Serialization.unmarshal(deploymentStream, Deployment.class); - Service service = Serialization.unmarshal(serviceStream, Service.class); - Ingress ingress = Serialization.unmarshal(ingressStream, Ingress.class); - ConfigMap configMap = Serialization.unmarshal(configMapStream, ConfigMap.class); - - List existing = new ArrayList<>( - deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getEnv()); - - // bootstrap is disabled, which means that in 'application-mount.yaml', - // config-data support is enabled. - EnvVar mountActiveProfile = new EnvVarBuilder().withName("SPRING_PROFILES_ACTIVE").withValue("mount").build(); - EnvVar disableBootstrap = new EnvVarBuilder().withName("SPRING_CLOUD_BOOTSTRAP_ENABLED").withValue("FALSE") - .build(); - - EnvVar debugLevelReloadCommons = new EnvVarBuilder() - .withName("LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_COMMONS_CONFIG_RELOAD").withValue("DEBUG") - .build(); - EnvVar debugLevelConfig = new EnvVarBuilder() - .withName("LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_COMMONS_CONFIG").withValue("DEBUG") - .build(); - EnvVar debugLevelCommons = new EnvVarBuilder() - .withName("LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_COMMONS").withValue("DEBUG").build(); - - existing.add(mountActiveProfile); - existing.add(disableBootstrap); - existing.add(debugLevelReloadCommons); - existing.add(debugLevelCommons); - existing.add(debugLevelConfig); - deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setEnv(existing); - - if (phase.equals(Phase.CREATE)) { - util.createAndWait(NAMESPACE, configMap, null); - util.createAndWait(NAMESPACE, null, deployment, service, ingress, true); - } - else { - util.deleteAndWait(NAMESPACE, configMap, null); - util.deleteAndWait(NAMESPACE, deployment, service, ingress); - } - - } - - private WebClient.Builder builder() { - return WebClient.builder().clientConnector(new ReactorClientHttpConnector(HttpClient.create())); - } - - private RetryBackoffSpec retrySpec() { - return Retry.fixedDelay(60, Duration.ofSeconds(1)).filter(Objects::nonNull); - } - - private String logs() { - try { - String appPodName = K3S.execInContainer("sh", "-c", - "kubectl get pods -l app=" + IMAGE_NAME + " -o=name --no-headers | tr -d '\n'").getStdout(); - - Container.ExecResult execResult = K3S.execInContainer("sh", "-c", "kubectl logs " + appPodName.trim()); - return execResult.getStdout(); - } - catch (Exception e) { - e.printStackTrace(); - throw new RuntimeException(e); - } - } - -} diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/test/resources/deployment.yaml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/test/resources/deployment.yaml deleted file mode 100644 index 39f4572c..00000000 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/test/resources/deployment.yaml +++ /dev/null @@ -1,28 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: spring-cloud-kubernetes-fabric8-client-configmap-deployment-polling-reload -spec: - selector: - matchLabels: - app: spring-cloud-kubernetes-fabric8-client-configmap-polling-reload - template: - metadata: - labels: - app: spring-cloud-kubernetes-fabric8-client-configmap-polling-reload - spec: - serviceAccountName: spring-cloud-kubernetes-serviceaccount - containers: - - name: spring-cloud-kubernetes-fabric8-client-configmap-polling-reload - image: docker.io/springcloud/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload - imagePullPolicy: IfNotPresent - readinessProbe: - httpGet: - port: 8080 - path: /actuator/health/readiness - livenessProbe: - httpGet: - port: 8080 - path: /actuator/health/liveness - ports: - - containerPort: 8080 diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/test/resources/ingress.yaml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/test/resources/ingress.yaml deleted file mode 100644 index fd53e216..00000000 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/test/resources/ingress.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: spring-cloud-kubernetes-fabric8-client-configmap-ingress-polling-reload - namespace: default -spec: - rules: - - http: - paths: - - path: / - pathType: Prefix - backend: - service: - name: spring-cloud-kubernetes-fabric8-client-configmap-polling-reload - port: - number: 8080 diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/test/resources/logback-test.xml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/test/resources/logback-test.xml deleted file mode 100644 index ee243343..00000000 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/test/resources/logback-test.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n - - - - - - - - - - - diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/test/resources/mount/configmap-mount.yaml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/test/resources/mount/configmap-mount.yaml deleted file mode 100644 index f2ea29a5..00000000 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/test/resources/mount/configmap-mount.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: poll-reload-as-mount - namespace: default -data: - application.properties: | - from.properties.key=as-mount-initial diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/test/resources/mount/deployment-mount.yaml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/test/resources/mount/deployment-mount.yaml deleted file mode 100644 index 46783986..00000000 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/test/resources/mount/deployment-mount.yaml +++ /dev/null @@ -1,37 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: spring-cloud-kubernetes-fabric8-client-configmap-deployment-polling-reload -spec: - selector: - matchLabels: - app: spring-cloud-kubernetes-fabric8-client-configmap-polling-reload - template: - metadata: - labels: - app: spring-cloud-kubernetes-fabric8-client-configmap-polling-reload - spec: - serviceAccountName: spring-cloud-kubernetes-serviceaccount - containers: - - name: spring-cloud-kubernetes-fabric8-client-configmap-polling-reload - image: docker.io/springcloud/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload - imagePullPolicy: IfNotPresent - readinessProbe: - httpGet: - port: 8080 - path: /actuator/health/readiness - livenessProbe: - httpGet: - port: 8080 - path: /actuator/health/liveness - ports: - - containerPort: 8080 - - volumeMounts: - - name: config-map-volume - mountPath: /tmp - - volumes: - - name: config-map-volume - configMap: - name: poll-reload-as-mount diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/test/resources/service.yaml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/test/resources/service.yaml deleted file mode 100644 index 2995e2b6..00000000 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/test/resources/service.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - labels: - app: spring-cloud-kubernetes-fabric8-client-configmap-polling-reload - name: spring-cloud-kubernetes-fabric8-client-configmap-polling-reload -spec: - ports: - - name: http - port: 8080 - targetPort: 8080 - selector: - app: spring-cloud-kubernetes-fabric8-client-configmap-polling-reload - type: ClusterIP diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/pom.xml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/pom.xml similarity index 97% rename from spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/pom.xml rename to spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/pom.xml index c5b250af..3164c0c2 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/pom.xml +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/pom.xml @@ -3,13 +3,13 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - org.springframework.cloud spring-cloud-kubernetes-integration-tests + org.springframework.cloud 3.0.5-SNAPSHOT 4.0.0 - spring-cloud-kubernetes-fabric8-client-configmap-polling-reload + spring-cloud-kubernetes-fabric8-client-reload diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/configmap/event/reload/App.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/reload/App.java similarity index 88% rename from spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/configmap/event/reload/App.java rename to spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/reload/App.java index de569386..29771fb8 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/configmap/event/reload/App.java +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/reload/App.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.cloud.kubernetes.fabric8.configmap.event.reload; +package org.springframework.cloud.kubernetes.fabric8.reload; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @@ -24,7 +24,8 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties * @author wind57 */ @SpringBootApplication -@EnableConfigurationProperties({ LeftProperties.class, RightProperties.class, RightWithLabelsProperties.class }) +@EnableConfigurationProperties({ LeftProperties.class, RightProperties.class, RightWithLabelsProperties.class, + ConfigMapProperties.class }) public class App { public static void main(String[] args) { diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/configmap/polling/reload/ConfigMapProperties.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/reload/ConfigMapProperties.java similarity index 92% rename from spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/configmap/polling/reload/ConfigMapProperties.java rename to spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/reload/ConfigMapProperties.java index 0b6f7e61..3310c277 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/configmap/polling/reload/ConfigMapProperties.java +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/reload/ConfigMapProperties.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.cloud.kubernetes.fabric8.configmap.polling.reload; +package org.springframework.cloud.kubernetes.fabric8.reload; import org.springframework.boot.context.properties.ConfigurationProperties; diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/configmap/event/reload/Controller.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/reload/Controller.java similarity index 80% rename from spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/configmap/event/reload/Controller.java rename to spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/reload/Controller.java index ff3a8c85..8087f875 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/configmap/event/reload/Controller.java +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/reload/Controller.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.cloud.kubernetes.fabric8.configmap.event.reload; +package org.springframework.cloud.kubernetes.fabric8.reload; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @@ -31,11 +31,14 @@ public class Controller { private final RightWithLabelsProperties rightWithLabelsProperties; + private final ConfigMapProperties configMapProperties; + public Controller(LeftProperties leftProperties, RightProperties rightProperties, - RightWithLabelsProperties rightWithLabelsProperties) { + RightWithLabelsProperties rightWithLabelsProperties, ConfigMapProperties configMapProperties) { this.leftProperties = leftProperties; this.rightProperties = rightProperties; this.rightWithLabelsProperties = rightWithLabelsProperties; + this.configMapProperties = configMapProperties; } @GetMapping("/left") @@ -53,4 +56,9 @@ public class Controller { return rightWithLabelsProperties.getValue(); } + @GetMapping("/key") + public String key() { + return configMapProperties.getKey(); + } + } diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/configmap/event/reload/LeftProperties.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/reload/LeftProperties.java similarity index 92% rename from spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/configmap/event/reload/LeftProperties.java rename to spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/reload/LeftProperties.java index 4be53d92..4d3d30d5 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/configmap/event/reload/LeftProperties.java +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/reload/LeftProperties.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.cloud.kubernetes.fabric8.configmap.event.reload; +package org.springframework.cloud.kubernetes.fabric8.reload; import org.springframework.boot.context.properties.ConfigurationProperties; diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/configmap/event/reload/RightProperties.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/reload/RightProperties.java similarity index 92% rename from spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/configmap/event/reload/RightProperties.java rename to spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/reload/RightProperties.java index f4e28d29..ac0355c6 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/configmap/event/reload/RightProperties.java +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/reload/RightProperties.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.cloud.kubernetes.fabric8.configmap.event.reload; +package org.springframework.cloud.kubernetes.fabric8.reload; import org.springframework.boot.context.properties.ConfigurationProperties; diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/configmap/event/reload/RightWithLabelsProperties.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/reload/RightWithLabelsProperties.java similarity index 92% rename from spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/configmap/event/reload/RightWithLabelsProperties.java rename to spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/reload/RightWithLabelsProperties.java index e4a9c340..9c13bc12 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/configmap/event/reload/RightWithLabelsProperties.java +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/main/java/org/springframework/cloud/kubernetes/fabric8/reload/RightWithLabelsProperties.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.cloud.kubernetes.fabric8.configmap.event.reload; +package org.springframework.cloud.kubernetes.fabric8.reload; import org.springframework.boot.context.properties.ConfigurationProperties; diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/main/resources/application-mount.yaml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/main/resources/application-mount.yaml similarity index 100% rename from spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/main/resources/application-mount.yaml rename to spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/main/resources/application-mount.yaml diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/main/resources/application-no-mount.yaml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/main/resources/application-no-mount.yaml similarity index 100% rename from spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/main/resources/application-no-mount.yaml rename to spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/main/resources/application-no-mount.yaml diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/main/resources/application-one.yaml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/main/resources/application-one.yaml similarity index 100% rename from spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/main/resources/application-one.yaml rename to spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/main/resources/application-one.yaml diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/main/resources/application-three.yaml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/main/resources/application-three.yaml similarity index 100% rename from spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/main/resources/application-three.yaml rename to spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/main/resources/application-three.yaml diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/main/resources/application-two.yaml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/main/resources/application-two.yaml similarity index 100% rename from spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/main/resources/application-two.yaml rename to spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/main/resources/application-two.yaml diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/main/resources/application-with-bootstrap.yaml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/main/resources/application-with-bootstrap.yaml similarity index 100% rename from spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/main/resources/application-with-bootstrap.yaml rename to spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/main/resources/application-with-bootstrap.yaml diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/main/resources/bootstrap-one.yaml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/main/resources/bootstrap-one.yaml similarity index 100% rename from spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/main/resources/bootstrap-one.yaml rename to spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/main/resources/bootstrap-one.yaml diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/main/resources/bootstrap-three.yaml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/main/resources/bootstrap-three.yaml similarity index 100% rename from spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/main/resources/bootstrap-three.yaml rename to spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/main/resources/bootstrap-three.yaml diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/main/resources/bootstrap-two.yaml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/main/resources/bootstrap-two.yaml similarity index 100% rename from spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/main/resources/bootstrap-two.yaml rename to spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/main/resources/bootstrap-two.yaml diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/main/resources/bootstrap-with-bootstrap.yaml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/main/resources/bootstrap-with-bootstrap.yaml similarity index 100% rename from spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/main/resources/bootstrap-with-bootstrap.yaml rename to spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/main/resources/bootstrap-with-bootstrap.yaml diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/test/java/org/springframework/cloud/kubernetes/fabric8/reload/BootstrapEnabledPollingReloadConfigMapMountDelegate.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/test/java/org/springframework/cloud/kubernetes/fabric8/reload/BootstrapEnabledPollingReloadConfigMapMountDelegate.java new file mode 100644 index 00000000..24a5e0dc --- /dev/null +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/test/java/org/springframework/cloud/kubernetes/fabric8/reload/BootstrapEnabledPollingReloadConfigMapMountDelegate.java @@ -0,0 +1,79 @@ +/* + * 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.fabric8.reload; + +import java.io.InputStream; +import java.time.Duration; +import java.util.Map; + +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.utils.Serialization; +import org.junit.jupiter.api.Assertions; +import org.testcontainers.k3s.K3sContainer; + +import org.springframework.cloud.kubernetes.integration.tests.commons.Commons; +import org.springframework.cloud.kubernetes.integration.tests.commons.fabric8_client.Util; +import org.springframework.http.HttpMethod; +import org.springframework.web.reactive.function.client.WebClient; + +import static org.awaitility.Awaitility.await; + +final class BootstrapEnabledPollingReloadConfigMapMountDelegate { + + /** + *
+	 *     - we have bootstrap enabled, which means we will 'locate' property sources
+	 *       from config maps.
+	 *     - there are no explicit config maps to search for, but what we will also read,
+	 *     	 is 'spring.cloud.kubernetes.config.paths', which we have set to
+	 *     	 '/tmp/application.properties'
+	 *       in this test. That is populated by the volumeMounts (see deployment-mount.yaml)
+	 *     - we first assert that we are actually reading the path based source via (1), (2) and (3).
+	 *
+	 *     - we then change the config map content, wait for k8s to pick it up and replace them
+	 *     - our polling will then detect that change, and trigger a reload.
+	 * 
+ */ + static void testPollingReloadConfigMapWithBootstrap(KubernetesClient client, Util util, K3sContainer container, + String appLabelValue) { + // (1) + Commons.waitForLogStatement("paths property sources : [/tmp/application.properties]", container, appLabelValue); + // (2) + Commons.waitForLogStatement("will add file-based property source : /tmp/application.properties", container, + appLabelValue); + // (3) + WebClient webClient = TestUtil.builder().baseUrl("http://localhost/key").build(); + String result = webClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class).retryWhen(TestUtil.retrySpec()) + .block(); + + // we first read the initial value from the configmap + Assertions.assertEquals("as-mount-initial", result); + + // replace data in configmap and wait for k8s to pick it up + // our polling will detect that and restart the app + InputStream configMapStream = util.inputStream("configmap.yaml"); + ConfigMap configMap = Serialization.unmarshal(configMapStream, ConfigMap.class); + configMap.setData(Map.of("application.properties", "from.properties.key=as-mount-changed")); + client.configMaps().inNamespace("default").resource(configMap).createOrReplace(); + + await().timeout(Duration.ofSeconds(360)).until(() -> webClient.method(HttpMethod.GET).retrieve() + .bodyToMono(String.class).retryWhen(TestUtil.retrySpec()).block().equals("as-mount-changed")); + + } + +} diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/test/java/org/springframework/cloud/kubernetes/fabric8/reload/ConfigMapMountPollingReloadDelegate.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/test/java/org/springframework/cloud/kubernetes/fabric8/reload/ConfigMapMountPollingReloadDelegate.java new file mode 100644 index 00000000..d91978c6 --- /dev/null +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/test/java/org/springframework/cloud/kubernetes/fabric8/reload/ConfigMapMountPollingReloadDelegate.java @@ -0,0 +1,83 @@ +/* + * 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.fabric8.reload; + +import java.io.InputStream; +import java.time.Duration; +import java.util.Map; + +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.utils.Serialization; +import org.junit.jupiter.api.Assertions; +import org.testcontainers.k3s.K3sContainer; + +import org.springframework.cloud.kubernetes.integration.tests.commons.Commons; +import org.springframework.cloud.kubernetes.integration.tests.commons.fabric8_client.Util; +import org.springframework.http.HttpMethod; +import org.springframework.web.reactive.function.client.WebClient; + +import static org.awaitility.Awaitility.await; + +/** + * @author wind57 + */ +final class ConfigMapMountPollingReloadDelegate { + + /** + *
+	 *     - we have "spring.config.import: kubernetes", which means we will 'locate' property sources
+	 *       from config maps.
+	 *     - the property above means that at the moment we will be searching for config maps that only
+	 *       match the application name, in this specific test there is no such config map.
+	 *     - what we will also read, is 'spring.cloud.kubernetes.config.paths', which we have set to
+	 *     	 '/tmp/application.properties'
+	 *       in this test. That is populated by the volumeMounts (see deployment-mount.yaml)
+	 *     - we first assert that we are actually reading the path based source via (1), (2) and (3).
+	 *
+	 *     - we then change the config map content, wait for k8s to pick it up and replace them
+	 *     - our polling will then detect that change, and trigger a reload.
+	 * 
+ */ + static void testConfigMapMountPollingReload(KubernetesClient client, Util util, K3sContainer container, + String appLabelValue) { + // (1) + Commons.waitForLogStatement("paths property sources : [/tmp/application.properties]", container, appLabelValue); + // (2) + Commons.waitForLogStatement("will add file-based property source : /tmp/application.properties", container, + appLabelValue); + // (3) + WebClient webClient = TestUtil.builder().baseUrl("http://localhost/key").build(); + String result = webClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class).retryWhen(TestUtil.retrySpec()) + .block(); + + // we first read the initial value from the configmap + Assertions.assertEquals("as-mount-initial", result); + + // replace data in configmap and wait for k8s to pick it up + // our polling will detect that and restart the app + InputStream configMapStream = util.inputStream("configmap.yaml"); + ConfigMap configMap = Serialization.unmarshal(configMapStream, ConfigMap.class); + configMap.setData(Map.of("application.properties", "from.properties.key=as-mount-changed")); + client.configMaps().inNamespace("default").resource(configMap).createOrReplace(); + + await().timeout(Duration.ofSeconds(360)).until(() -> webClient.method(HttpMethod.GET).retrieve() + .bodyToMono(String.class).retryWhen(TestUtil.retrySpec()).block().equals("as-mount-changed")); + + } + +} diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/test/java/org/springframework/cloud/kubernetes/fabric8/reload/ConfigMapPollingReloadDelegate.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/test/java/org/springframework/cloud/kubernetes/fabric8/reload/ConfigMapPollingReloadDelegate.java new file mode 100644 index 00000000..6f5499cd --- /dev/null +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/test/java/org/springframework/cloud/kubernetes/fabric8/reload/ConfigMapPollingReloadDelegate.java @@ -0,0 +1,61 @@ +/* + * Copyright 2013-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.kubernetes.fabric8.reload; + +import java.time.Duration; +import java.util.Map; + +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.ConfigMapBuilder; +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.fabric8.kubernetes.client.KubernetesClient; +import org.junit.jupiter.api.Assertions; + +import org.springframework.http.HttpMethod; +import org.springframework.web.client.HttpServerErrorException; +import org.springframework.web.reactive.function.client.WebClient; + +import static org.awaitility.Awaitility.await; + +/** + * @author wind57 + */ +final class ConfigMapPollingReloadDelegate { + + static void testConfigMapPollingReload(KubernetesClient client) { + WebClient webClient = TestUtil.builder().baseUrl("http://localhost/key").build(); + String result = webClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class).retryWhen(TestUtil.retrySpec()) + .block(); + + // we first read the initial value from the configmap + Assertions.assertEquals("as-mount-initial", result); + + // then deploy a new version of configmap + // since we poll and have reload in place, the new property must be visible + ConfigMap map = new ConfigMapBuilder() + .withMetadata(new ObjectMetaBuilder().withNamespace("default").withName("poll-reload").build()) + .withData(Map.of("application.properties", "from.properties.key=after-change")).build(); + + client.configMaps().inNamespace("default").resource(map).createOrReplace(); + + await().ignoreException(HttpServerErrorException.BadGateway.class).timeout(Duration.ofSeconds(120)) + .until(() -> webClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class).retryWhen(TestUtil.retrySpec()) + .block().equals("after-change")); + + } + +} diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/test/java/org/springframework/cloud/kubernetes/fabric8/configmap/event/reload/DataChangesInConfigMapReloadDelegate.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/test/java/org/springframework/cloud/kubernetes/fabric8/reload/DataChangesInConfigMapReloadDelegate.java similarity index 78% rename from spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/test/java/org/springframework/cloud/kubernetes/fabric8/configmap/event/reload/DataChangesInConfigMapReloadDelegate.java rename to spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/test/java/org/springframework/cloud/kubernetes/fabric8/reload/DataChangesInConfigMapReloadDelegate.java index f9d0ac0e..688b859d 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/test/java/org/springframework/cloud/kubernetes/fabric8/configmap/event/reload/DataChangesInConfigMapReloadDelegate.java +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/test/java/org/springframework/cloud/kubernetes/fabric8/reload/DataChangesInConfigMapReloadDelegate.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.cloud.kubernetes.fabric8.configmap.event.reload; +package org.springframework.cloud.kubernetes.fabric8.reload; import java.time.Duration; import java.util.Map; @@ -24,7 +24,6 @@ import io.fabric8.kubernetes.api.model.ConfigMapBuilder; import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; import io.fabric8.kubernetes.client.KubernetesClient; import org.junit.jupiter.api.Assertions; -import org.testcontainers.containers.Container; import org.testcontainers.k3s.K3sContainer; import org.springframework.cloud.kubernetes.integration.tests.commons.Commons; @@ -32,18 +31,17 @@ import org.springframework.http.HttpMethod; import org.springframework.web.reactive.function.client.WebClient; import static org.awaitility.Awaitility.await; -import static org.springframework.cloud.kubernetes.fabric8.configmap.event.reload.TestUtil.builder; -import static org.springframework.cloud.kubernetes.fabric8.configmap.event.reload.TestUtil.replaceConfigMap; -import static org.springframework.cloud.kubernetes.fabric8.configmap.event.reload.TestUtil.retrySpec; +import static org.springframework.cloud.kubernetes.fabric8.reload.TestUtil.builder; +import static org.springframework.cloud.kubernetes.fabric8.reload.TestUtil.logs; +import static org.springframework.cloud.kubernetes.fabric8.reload.TestUtil.replaceConfigMap; +import static org.springframework.cloud.kubernetes.fabric8.reload.TestUtil.retrySpec; final class DataChangesInConfigMapReloadDelegate { - private static final String IMAGE_NAME = "spring-cloud-kubernetes-fabric8-client-configmap-event-reload"; + private static final String IMAGE_NAME = "spring-cloud-kubernetes-fabric8-client-reload"; private static final String LEFT_NAMESPACE = "left"; - private static final K3sContainer K3S = Commons.container(); - /** *
 	 *     - configMap with no labels and data: left.value = left-initial exists in namespace left
@@ -55,7 +53,7 @@ final class DataChangesInConfigMapReloadDelegate {
 	 *     - then we change data inside the config map, and we must see the updated value
 	 * 
*/ - static void testDataChangesInConfigMap(KubernetesClient client) { + static void testDataChangesInConfigMap(KubernetesClient client, K3sContainer container, String appLabelValue) { Commons.assertReloadLogStatements("added configmap informer for namespace", "added secret informer for namespace", IMAGE_NAME); @@ -81,7 +79,7 @@ final class DataChangesInConfigMapReloadDelegate { return "left-initial".equals(innerResult); }); - String logs = logs(); + String logs = logs(container, appLabelValue); Assertions.assertTrue(logs.contains("ConfigMap left-configmap was updated in namespace left")); Assertions.assertTrue(logs.contains("data in configmap has not changed, will not reload")); @@ -102,18 +100,4 @@ final class DataChangesInConfigMapReloadDelegate { } - private static String logs() { - try { - String appPodName = K3S.execInContainer("sh", "-c", - "kubectl get pods -l app=" + IMAGE_NAME + " -o=name --no-headers | tr -d '\n'").getStdout(); - - Container.ExecResult execResult = K3S.execInContainer("sh", "-c", "kubectl logs " + appPodName.trim()); - return execResult.getStdout(); - } - catch (Exception e) { - e.printStackTrace(); - throw new RuntimeException(e); - } - } - } diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/test/java/org/springframework/cloud/kubernetes/fabric8/configmap/event/reload/ConfigMapEventReloadIT.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/test/java/org/springframework/cloud/kubernetes/fabric8/reload/Fabric8EventReloadIT.java similarity index 76% rename from spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/test/java/org/springframework/cloud/kubernetes/fabric8/configmap/event/reload/ConfigMapEventReloadIT.java rename to spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/test/java/org/springframework/cloud/kubernetes/fabric8/reload/Fabric8EventReloadIT.java index 9ce9a8ab..a2974be4 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/test/java/org/springframework/cloud/kubernetes/fabric8/configmap/event/reload/ConfigMapEventReloadIT.java +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/test/java/org/springframework/cloud/kubernetes/fabric8/reload/Fabric8EventReloadIT.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.cloud.kubernetes.fabric8.configmap.event.reload; +package org.springframework.cloud.kubernetes.fabric8.reload; import java.io.InputStream; import java.time.Duration; @@ -42,22 +42,14 @@ import org.springframework.http.HttpMethod; import org.springframework.web.reactive.function.client.WebClient; import static org.awaitility.Awaitility.await; -import static org.springframework.cloud.kubernetes.fabric8.configmap.event.reload.TestUtil.builder; -import static org.springframework.cloud.kubernetes.fabric8.configmap.event.reload.TestUtil.patchFour; -import static org.springframework.cloud.kubernetes.fabric8.configmap.event.reload.TestUtil.patchOne; -import static org.springframework.cloud.kubernetes.fabric8.configmap.event.reload.TestUtil.patchThree; -import static org.springframework.cloud.kubernetes.fabric8.configmap.event.reload.TestUtil.patchTwo; -import static org.springframework.cloud.kubernetes.fabric8.configmap.event.reload.TestUtil.reCreateConfigMaps; -import static org.springframework.cloud.kubernetes.fabric8.configmap.event.reload.TestUtil.replaceConfigMap; -import static org.springframework.cloud.kubernetes.fabric8.configmap.event.reload.TestUtil.retrySpec; import static org.springframework.cloud.kubernetes.integration.tests.commons.Commons.pomVersion; /** * @author wind57 */ -class ConfigMapEventReloadIT { +class Fabric8EventReloadIT { - private static final String IMAGE_NAME = "spring-cloud-kubernetes-fabric8-client-configmap-event-reload"; + private static final String IMAGE_NAME = "spring-cloud-kubernetes-fabric8-client-reload"; private static final String DOCKER_IMAGE = "docker.io/springcloud/" + IMAGE_NAME + ":" + pomVersion(); @@ -81,6 +73,7 @@ class ConfigMapEventReloadIT { util.createNamespace("left"); util.createNamespace("right"); util.setUpClusterWide(NAMESPACE, Set.of("left", "right")); + util.setUp(NAMESPACE); manifests(Phase.CREATE); } @@ -108,16 +101,16 @@ class ConfigMapEventReloadIT { Commons.assertReloadLogStatements("added configmap informer for namespace", "added secret informer for namespace", IMAGE_NAME); - WebClient webClient = builder().baseUrl("http://localhost/left").build(); - String result = webClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class).retryWhen(retrySpec()) + WebClient webClient = TestUtil.builder().baseUrl("http://localhost/left").build(); + String result = webClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class).retryWhen(TestUtil.retrySpec()) .block(); // we first read the initial value from the left-configmap Assertions.assertEquals("left-initial", result); // then read the value from the right-configmap - webClient = builder().baseUrl("http://localhost/right").build(); - result = webClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class).retryWhen(retrySpec()).block(); + webClient = TestUtil.builder().baseUrl("http://localhost/right").build(); + result = webClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class).retryWhen(TestUtil.retrySpec()).block(); Assertions.assertEquals("right-initial", result); // then deploy a new version of right-configmap @@ -125,14 +118,14 @@ class ConfigMapEventReloadIT { .withMetadata(new ObjectMetaBuilder().withNamespace("right").withName("right-configmap").build()) .withData(Map.of("right.value", "right-after-change")).build(); - replaceConfigMap(client, rightConfigMapAfterChange, "right"); + TestUtil.replaceConfigMap(client, rightConfigMapAfterChange, "right"); - webClient = builder().baseUrl("http://localhost/left").build(); + webClient = TestUtil.builder().baseUrl("http://localhost/left").build(); WebClient finalWebClient = webClient; await().pollInterval(Duration.ofSeconds(1)).atMost(Duration.ofSeconds(30)).until(() -> { String innerResult = finalWebClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class) - .retryWhen(retrySpec()).block(); + .retryWhen(TestUtil.retrySpec()).block(); // left configmap has not changed, no restart of app has happened return "left-initial".equals(innerResult); }); @@ -141,6 +134,9 @@ class ConfigMapEventReloadIT { testInform(); testInformFromOneNamespaceEventTriggeredSecretsDisabled(); testDataChangesInConfigMap(); + testConfigMapPollingReload(); + testConfigMapMountPollingReload(); + testPollingReloadConfigMapWithBootstrap(); } /** @@ -154,15 +150,15 @@ class ConfigMapEventReloadIT { */ void testInformFromOneNamespaceEventTriggered() { - reCreateConfigMaps(util, client); - patchOne(util, DOCKER_IMAGE, IMAGE_NAME, NAMESPACE); + TestUtil.reCreateConfigMaps(util, client); + TestUtil.patchOne(util, DOCKER_IMAGE, IMAGE_NAME, NAMESPACE); 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()) + WebClient webClient = TestUtil.builder().baseUrl("http://localhost/right").build(); + String result = webClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class).retryWhen(TestUtil.retrySpec()) .block(); Assertions.assertEquals("right-initial", result); @@ -171,13 +167,13 @@ class ConfigMapEventReloadIT { .withMetadata(new ObjectMetaBuilder().withNamespace("right").withName("right-configmap").build()) .withData(Map.of("right.value", "right-after-change")).build(); - replaceConfigMap(client, rightConfigMapAfterChange, "right"); + TestUtil.replaceConfigMap(client, rightConfigMapAfterChange, "right"); String[] resultAfterChange = new String[1]; await().pollInterval(Duration.ofSeconds(3)).atMost(Duration.ofSeconds(90)).until(() -> { - WebClient innerWebClient = builder().baseUrl("http://localhost/right").build(); + WebClient innerWebClient = TestUtil.builder().baseUrl("http://localhost/right").build(); String innerResult = innerWebClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class) - .retryWhen(retrySpec()).block(); + .retryWhen(TestUtil.retrySpec()).block(); resultAfterChange[0] = innerResult; return innerResult != null; }); @@ -196,22 +192,22 @@ class ConfigMapEventReloadIT { */ void testInform() { - reCreateConfigMaps(util, client); - patchTwo(util, DOCKER_IMAGE, IMAGE_NAME, NAMESPACE); + TestUtil.reCreateConfigMaps(util, client); + TestUtil.patchTwo(util, DOCKER_IMAGE, IMAGE_NAME, NAMESPACE); Commons.assertReloadLogStatements("added configmap informer for namespace", "added secret informer for namespace", IMAGE_NAME); // read the initial value from the right-configmap - WebClient rightWebClient = builder().baseUrl("http://localhost/right").build(); + WebClient rightWebClient = TestUtil.builder().baseUrl("http://localhost/right").build(); String rightResult = rightWebClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class) - .retryWhen(retrySpec()).block(); + .retryWhen(TestUtil.retrySpec()).block(); Assertions.assertEquals("right-initial", rightResult); // then read the initial value from the right-with-label-configmap - WebClient rightWithLabelWebClient = builder().baseUrl("http://localhost/with-label").build(); + WebClient rightWithLabelWebClient = TestUtil.builder().baseUrl("http://localhost/with-label").build(); String rightWithLabelResult = rightWithLabelWebClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class) - .retryWhen(retrySpec()).block(); + .retryWhen(TestUtil.retrySpec()).block(); Assertions.assertEquals("right-with-label-initial", rightWithLabelResult); // then deploy a new version of right-configmap @@ -219,12 +215,12 @@ class ConfigMapEventReloadIT { .withMetadata(new ObjectMetaBuilder().withNamespace("right").withName("right-configmap").build()) .withData(Map.of("right.value", "right-after-change")).build(); - replaceConfigMap(client, rightConfigMapAfterChange, "right"); + TestUtil.replaceConfigMap(client, rightConfigMapAfterChange, "right"); // nothing changes in our app, because we are watching only labeled configmaps await().pollInterval(Duration.ofSeconds(1)).atMost(Duration.ofSeconds(30)).until(() -> { String innerRightResult = rightWebClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class) - .retryWhen(retrySpec()).block(); + .retryWhen(TestUtil.retrySpec()).block(); return "right-initial".equals(innerRightResult); }); @@ -234,15 +230,15 @@ class ConfigMapEventReloadIT { new ObjectMetaBuilder().withNamespace("right").withName("right-configmap-with-label").build()) .withData(Map.of("right.with.label.value", "right-with-label-after-change")).build(); - replaceConfigMap(client, rightWithLabelConfigMapAfterChange, "right"); + TestUtil.replaceConfigMap(client, rightWithLabelConfigMapAfterChange, "right"); // since we have changed a labeled configmap, app will restart and pick up the new // value String[] resultAfterChange = new String[1]; await().pollInterval(Duration.ofSeconds(3)).atMost(Duration.ofSeconds(90)).until(() -> { - WebClient innerWebClient = builder().baseUrl("http://localhost/with-label").build(); + WebClient innerWebClient = TestUtil.builder().baseUrl("http://localhost/with-label").build(); String innerResult = innerWebClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class) - .retryWhen(retrySpec()).block(); + .retryWhen(TestUtil.retrySpec()).block(); resultAfterChange[0] = innerResult; return innerResult != null; }); @@ -250,7 +246,7 @@ class ConfigMapEventReloadIT { // right-configmap now will see the new value also, but only because the other // configmap has triggered the restart - rightResult = rightWebClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class).retryWhen(retrySpec()) + rightResult = rightWebClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class).retryWhen(TestUtil.retrySpec()) .block(); Assertions.assertEquals("right-after-change", rightResult); } @@ -267,15 +263,15 @@ class ConfigMapEventReloadIT { */ void testInformFromOneNamespaceEventTriggeredSecretsDisabled() { - reCreateConfigMaps(util, client); - patchThree(util, DOCKER_IMAGE, IMAGE_NAME, NAMESPACE); + TestUtil.reCreateConfigMaps(util, client); + TestUtil.patchThree(util, DOCKER_IMAGE, IMAGE_NAME, NAMESPACE); 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()) + WebClient webClient = TestUtil.builder().baseUrl("http://localhost/right").build(); + String result = webClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class).retryWhen(TestUtil.retrySpec()) .block(); Assertions.assertEquals("right-initial", result); @@ -284,13 +280,13 @@ class ConfigMapEventReloadIT { .withMetadata(new ObjectMetaBuilder().withNamespace("right").withName("right-configmap").build()) .withData(Map.of("right.value", "right-after-change")).build(); - replaceConfigMap(client, rightConfigMapAfterChange, "right"); + TestUtil.replaceConfigMap(client, rightConfigMapAfterChange, "right"); String[] resultAfterChange = new String[1]; await().pollInterval(Duration.ofSeconds(3)).atMost(Duration.ofSeconds(90)).until(() -> { - WebClient innerWebClient = builder().baseUrl("http://localhost/right").build(); + WebClient innerWebClient = TestUtil.builder().baseUrl("http://localhost/right").build(); String innerResult = innerWebClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class) - .retryWhen(retrySpec()).block(); + .retryWhen(TestUtil.retrySpec()).block(); resultAfterChange[0] = innerResult; return innerResult != null; }); @@ -299,9 +295,27 @@ class ConfigMapEventReloadIT { } void testDataChangesInConfigMap() { - reCreateConfigMaps(util, client); - patchFour(util, DOCKER_IMAGE, IMAGE_NAME, NAMESPACE); - DataChangesInConfigMapReloadDelegate.testDataChangesInConfigMap(client); + TestUtil.reCreateConfigMaps(util, client); + TestUtil.patchFour(util, DOCKER_IMAGE, IMAGE_NAME, NAMESPACE); + DataChangesInConfigMapReloadDelegate.testDataChangesInConfigMap(client, K3S, IMAGE_NAME); + } + + void testConfigMapPollingReload() { + TestUtil.patchFive(util, DOCKER_IMAGE, IMAGE_NAME, NAMESPACE); + ConfigMapPollingReloadDelegate.testConfigMapPollingReload(client); + } + + void testConfigMapMountPollingReload() { + TestUtil.reCreateConfigMaps(util, client); + TestUtil.patchSix(util, DOCKER_IMAGE, IMAGE_NAME, NAMESPACE); + ConfigMapMountPollingReloadDelegate.testConfigMapMountPollingReload(client, util, K3S, IMAGE_NAME); + } + + void testPollingReloadConfigMapWithBootstrap() { + TestUtil.reCreateConfigMaps(util, client); + TestUtil.patchSeven(util, DOCKER_IMAGE, IMAGE_NAME, NAMESPACE); + BootstrapEnabledPollingReloadConfigMapMountDelegate.testPollingReloadConfigMapWithBootstrap(client, util, K3S, + IMAGE_NAME); } private static void manifests(Phase phase) { @@ -312,6 +326,7 @@ class ConfigMapEventReloadIT { InputStream leftConfigMapStream = util.inputStream("left-configmap.yaml"); InputStream rightConfigMapStream = util.inputStream("right-configmap.yaml"); InputStream rightWithLabelConfigMapStream = util.inputStream("right-configmap-with-label.yaml"); + InputStream configMapAsStream = util.inputStream("configmap.yaml"); Deployment deployment = Serialization.unmarshal(deploymentStream, Deployment.class); @@ -320,17 +335,20 @@ class ConfigMapEventReloadIT { ConfigMap leftConfigMap = Serialization.unmarshal(leftConfigMapStream, ConfigMap.class); ConfigMap rightConfigMap = Serialization.unmarshal(rightConfigMapStream, ConfigMap.class); ConfigMap rightWithLabelConfigMap = Serialization.unmarshal(rightWithLabelConfigMapStream, ConfigMap.class); + ConfigMap configMap = Serialization.unmarshal(configMapAsStream, ConfigMap.class); if (phase.equals(Phase.CREATE)) { util.createAndWait("left", leftConfigMap, null); util.createAndWait("right", rightConfigMap, null); util.createAndWait("right", rightWithLabelConfigMap, null); + util.createAndWait(NAMESPACE, configMap, null); util.createAndWait(NAMESPACE, null, deployment, service, ingress, true); } else { util.deleteAndWait("left", leftConfigMap, null); util.deleteAndWait("right", rightConfigMap, null); util.deleteAndWait("right", rightWithLabelConfigMap, null); + util.deleteAndWait(NAMESPACE, configMap, null); util.deleteAndWait(NAMESPACE, deployment, service, ingress); } diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/test/java/org/springframework/cloud/kubernetes/fabric8/configmap/event/reload/TestUtil.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/test/java/org/springframework/cloud/kubernetes/fabric8/reload/TestUtil.java similarity index 54% rename from spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/test/java/org/springframework/cloud/kubernetes/fabric8/configmap/event/reload/TestUtil.java rename to spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/test/java/org/springframework/cloud/kubernetes/fabric8/reload/TestUtil.java index f0723aeb..50df50dd 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/test/java/org/springframework/cloud/kubernetes/fabric8/configmap/event/reload/TestUtil.java +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/test/java/org/springframework/cloud/kubernetes/fabric8/reload/TestUtil.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.cloud.kubernetes.fabric8.configmap.event.reload; +package org.springframework.cloud.kubernetes.fabric8.reload; import java.io.InputStream; import java.time.Duration; @@ -24,6 +24,8 @@ import java.util.Objects; import io.fabric8.kubernetes.api.model.ConfigMap; import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.utils.Serialization; +import org.testcontainers.containers.Container; +import org.testcontainers.k3s.K3sContainer; import reactor.netty.http.client.HttpClient; import reactor.util.retry.Retry; import reactor.util.retry.RetryBackoffSpec; @@ -38,7 +40,7 @@ import org.springframework.web.reactive.function.client.WebClient; final class TestUtil { private static final Map POD_LABELS = Map.of("app", - "spring-cloud-kubernetes-fabric8-client-configmap-event-reload"); + "spring-cloud-kubernetes-fabric8-client-reload"); private static final String BODY_ONE = """ { @@ -56,6 +58,10 @@ final class TestUtil { { "name": "SPRING_PROFILES_ACTIVE", "value": "two" + }, + { + "name": "SPRING_CLOUD_BOOTSTRAP_ENABLED", + "value": "TRUE" } ] }] @@ -81,6 +87,10 @@ final class TestUtil { { "name": "SPRING_PROFILES_ACTIVE", "value": "three" + }, + { + "name": "SPRING_CLOUD_BOOTSTRAP_ENABLED", + "value": "TRUE" } ] }] @@ -110,6 +120,10 @@ final class TestUtil { { "name": "SPRING_CLOUD_KUBERNETES_SECRETS_ENABLED", "value": "FALSE" + }, + { + "name": "SPRING_CLOUD_BOOTSTRAP_ENABLED", + "value": "TRUE" } ] }] @@ -143,6 +157,139 @@ final class TestUtil { { "name": "LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_CLIENT_CONFIG_RELOAD", "value": "DEBUG" + }, + { + "name": "SPRING_CLOUD_BOOTSTRAP_ENABLED", + "value": "TRUE" + } + ] + }] + } + } + } + } + """; + + private static final String BODY_FIVE = """ + { + "spec": { + "template": { + "spec": { + "containers": [{ + "name": "spring-cloud-kubernetes-fabric8-client-configmap-event-reload", + "image": "image_name_here", + "env": [ + { + "name": "SPRING_PROFILES_ACTIVE", + "value": "no-mount" + }, + { + "name": "SPRING_CLOUD_BOOTSTRAP_ENABLED", + "value": "FALSE" + } + ] + }] + } + } + } + } + """; + + private static final String BODY_SIX = """ + { + "spec": { + "template": { + "spec": { + "volumes": [ + { + "configMap": { + "defaultMode": 420, + "name": "poll-reload" + }, + "name": "config-map-volume" + } + ], + "containers": [{ + "volumeMounts": [ + { + "mountPath": "/tmp", + "name": "config-map-volume" + } + ], + "name": "spring-cloud-kubernetes-fabric8-client-configmap-event-reload", + "image": "image_name_here", + "env": [ + { + "name": "SPRING_PROFILES_ACTIVE", + "value": "mount" + }, + { + "name": "SPRING_CLOUD_BOOTSTRAP_ENABLED", + "value": "FALSE" + }, + { + "name": "LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_COMMONS_CONFIG_RELOAD", + "value": "DEBUG" + }, + { + "name": "LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_COMMONS_CONFIG", + "value": "DEBUG" + }, + { + "name": "LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_COMMONS", + "value": "DEBUG" + } + ] + }] + } + } + } + } + """; + + private static final String BODY_SEVEN = """ + { + "spec": { + "template": { + "spec": { + "volumes": [ + { + "configMap": { + "defaultMode": 420, + "name": "poll-reload" + }, + "name": "config-map-volume" + } + ], + "containers": [{ + "volumeMounts": [ + { + "mountPath": "/tmp", + "name": "config-map-volume" + } + ], + "name": "spring-cloud-kubernetes-fabric8-client-configmap-event-reload", + "image": "image_name_here", + "env": [ + { + "name": "SPRING_PROFILES_ACTIVE", + "value": "with-bootstrap" + }, + { + "name": "SPRING_CLOUD_BOOTSTRAP_ENABLED", + "value": "TRUE" + }, + { + "name": "LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_COMMONS_CONFIG_RELOAD", + "value": "DEBUG" + }, + { + "name": "LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_COMMONS_CONFIG", + "value": "DEBUG" + }, + { + "name": "LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_COMMONS", + "value": "DEBUG" } ] }] @@ -159,12 +306,15 @@ final class TestUtil { static void reCreateConfigMaps(Util util, KubernetesClient client) { InputStream leftConfigMapStream = util.inputStream("left-configmap.yaml"); InputStream rightConfigMapStream = util.inputStream("right-configmap.yaml"); + InputStream configMapStream = util.inputStream("configmap.yaml"); ConfigMap leftConfigMap = Serialization.unmarshal(leftConfigMapStream, ConfigMap.class); ConfigMap rightConfigMap = Serialization.unmarshal(rightConfigMapStream, ConfigMap.class); + ConfigMap configMap = Serialization.unmarshal(configMapStream, ConfigMap.class); replaceConfigMap(client, leftConfigMap, "left"); replaceConfigMap(client, rightConfigMap, "right"); + replaceConfigMap(client, configMap, "default"); } static void replaceConfigMap(KubernetesClient client, ConfigMap configMap, String namespace) { @@ -187,6 +337,18 @@ final class TestUtil { util.patchWithReplace(dockerImage, deploymentName, namespace, BODY_FOUR, POD_LABELS); } + static void patchFive(Util util, String dockerImage, String deploymentName, String namespace) { + util.patchWithReplace(dockerImage, deploymentName, namespace, BODY_FIVE, POD_LABELS); + } + + static void patchSix(Util util, String dockerImage, String deploymentName, String namespace) { + util.patchWithReplace(dockerImage, deploymentName, namespace, BODY_SIX, POD_LABELS); + } + + static void patchSeven(Util util, String dockerImage, String deploymentName, String namespace) { + util.patchWithReplace(dockerImage, deploymentName, namespace, BODY_SEVEN, POD_LABELS); + } + static WebClient.Builder builder() { return WebClient.builder().clientConnector(new ReactorClientHttpConnector(HttpClient.create())); } @@ -195,4 +357,20 @@ final class TestUtil { return Retry.fixedDelay(120, Duration.ofSeconds(2)).filter(Objects::nonNull); } + static String logs(K3sContainer container, String appLabelValue) { + try { + String appPodName = container + .execInContainer("sh", "-c", + "kubectl get pods -l app=" + appLabelValue + " -o=name --no-headers | tr -d '\n'") + .getStdout(); + + Container.ExecResult execResult = container.execInContainer("sh", "-c", + "kubectl logs " + appPodName.trim()); + return execResult.getStdout(); + } + catch (Exception e) { + throw new RuntimeException(e); + } + } + } diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/test/resources/configmap.yaml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/test/resources/configmap.yaml similarity index 72% rename from spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/test/resources/configmap.yaml rename to spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/test/resources/configmap.yaml index 19460308..2c6c6d08 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-polling-reload/src/test/resources/configmap.yaml +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/test/resources/configmap.yaml @@ -5,4 +5,4 @@ metadata: namespace: default data: application.properties: | - from.properties.key=initial + from.properties.key=as-mount-initial diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/test/resources/deployment.yaml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/test/resources/deployment.yaml similarity index 70% rename from spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/test/resources/deployment.yaml rename to spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/test/resources/deployment.yaml index d234ee89..aba13d51 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/test/resources/deployment.yaml +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/test/resources/deployment.yaml @@ -1,20 +1,20 @@ apiVersion: apps/v1 kind: Deployment metadata: - name: spring-cloud-kubernetes-fabric8-client-configmap-event-reload + name: spring-cloud-kubernetes-fabric8-client-reload spec: selector: matchLabels: - app: spring-cloud-kubernetes-fabric8-client-configmap-event-reload + app: spring-cloud-kubernetes-fabric8-client-reload template: metadata: labels: - app: spring-cloud-kubernetes-fabric8-client-configmap-event-reload + app: spring-cloud-kubernetes-fabric8-client-reload spec: serviceAccountName: spring-cloud-kubernetes-serviceaccount containers: - - name: spring-cloud-kubernetes-fabric8-client-configmap-event-reload - image: docker.io/springcloud/spring-cloud-kubernetes-fabric8-client-configmap-event-reload + - name: spring-cloud-kubernetes-fabric8-client-reload + image: docker.io/springcloud/spring-cloud-kubernetes-fabric8-client-reload imagePullPolicy: IfNotPresent readinessProbe: httpGet: @@ -31,3 +31,5 @@ spec: value: "DEBUG" - name: SPRING_PROFILES_ACTIVE value: "one" + - name: SPRING_CLOUD_BOOTSTRAP_ENABLED + value: "TRUE" diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/test/resources/ingress.yaml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/test/resources/ingress.yaml similarity index 62% rename from spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/test/resources/ingress.yaml rename to spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/test/resources/ingress.yaml index 1069481e..d6e9e49a 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/test/resources/ingress.yaml +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/test/resources/ingress.yaml @@ -1,7 +1,7 @@ apiVersion: networking.k8s.io/v1 kind: Ingress metadata: - name: spring-cloud-kubernetes-fabric8-client-configmap-ingress-event-reload + name: spring-cloud-kubernetes-fabric8-client-reload-ingress namespace: default spec: rules: @@ -11,6 +11,6 @@ spec: pathType: Prefix backend: service: - name: spring-cloud-kubernetes-fabric8-client-configmap-event-reload + name: spring-cloud-kubernetes-fabric8-client-reload port: number: 8080 diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/test/resources/left-configmap.yaml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/test/resources/left-configmap.yaml similarity index 75% rename from spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/test/resources/left-configmap.yaml rename to spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/test/resources/left-configmap.yaml index 560954be..a72d8af5 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/test/resources/left-configmap.yaml +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/test/resources/left-configmap.yaml @@ -4,4 +4,4 @@ metadata: name: left-configmap namespace: left data: - left.value: left-initial + left.value: "left-initial" diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/test/resources/logback-test.xml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/test/resources/logback-test.xml similarity index 100% rename from spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/test/resources/logback-test.xml rename to spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/test/resources/logback-test.xml diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/test/resources/right-configmap-with-label.yaml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/test/resources/right-configmap-with-label.yaml similarity index 76% rename from spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/test/resources/right-configmap-with-label.yaml rename to spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/test/resources/right-configmap-with-label.yaml index 56531a63..658ebca4 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/test/resources/right-configmap-with-label.yaml +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/test/resources/right-configmap-with-label.yaml @@ -6,4 +6,4 @@ metadata: labels: spring.cloud.kubernetes.config.informer.enabled: true data: - right.with.label.value: right-with-label-initial + right.with.label.value: "right-with-label-initial" diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/test/resources/right-configmap.yaml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/test/resources/right-configmap.yaml similarity index 74% rename from spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/test/resources/right-configmap.yaml rename to spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/test/resources/right-configmap.yaml index a1427327..0ede471d 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-configmap-event-reload/src/test/resources/right-configmap.yaml +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/test/resources/right-configmap.yaml @@ -4,4 +4,4 @@ metadata: name: right-configmap namespace: right data: - right.value: right-initial + right.value: "right-initial" diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/test/resources/service.yaml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/test/resources/service.yaml new file mode 100644 index 00000000..3f73ad07 --- /dev/null +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-reload/src/test/resources/service.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + app: spring-cloud-kubernetes-fabric8-client-reload + name: spring-cloud-kubernetes-fabric8-client-reload +spec: + ports: + - name: http + port: 8080 + targetPort: 8080 + selector: + app: spring-cloud-kubernetes-fabric8-client-reload + type: ClusterIP diff --git a/spring-cloud-kubernetes-test-support/src/main/java/org/springframework/cloud/kubernetes/integration/tests/commons/Commons.java b/spring-cloud-kubernetes-test-support/src/main/java/org/springframework/cloud/kubernetes/integration/tests/commons/Commons.java index 1c802a74..3ae02cfd 100644 --- a/spring-cloud-kubernetes-test-support/src/main/java/org/springframework/cloud/kubernetes/integration/tests/commons/Commons.java +++ b/spring-cloud-kubernetes-test-support/src/main/java/org/springframework/cloud/kubernetes/integration/tests/commons/Commons.java @@ -116,7 +116,7 @@ public final class Commons { LOG.info("appPodName : ->" + appPodName + "<-"); // we issue a pollDelay to let the logs sync in, otherwise the results are not // going to be correctly asserted - await().pollDelay(20, TimeUnit.SECONDS).pollInterval(Duration.ofSeconds(5)).atMost(Duration.ofSeconds(600)) + await().pollDelay(20, TimeUnit.SECONDS).pollInterval(Duration.ofSeconds(5)).atMost(Duration.ofSeconds(120)) .until(() -> { Container.ExecResult result = CONTAINER.execInContainer("sh", "-c",