From 1d5f46d85d320f3b04855690a19661a6aac1937d Mon Sep 17 00:00:00 2001 From: wind57 Date: Tue, 14 Jan 2025 20:34:21 +0200 Subject: [PATCH 01/11] placeholder commit Signed-off-by: wind57 From d1e555f62c739766a077e770f8fb2b44055b48c0 Mon Sep 17 00:00:00 2001 From: wind57 Date: Thu, 16 Jan 2025 16:08:37 +0200 Subject: [PATCH 02/11] started work Signed-off-by: wind57 --- .../KubernetesClientCatalogWatchIT.java | 14 --- .../it/KubernetesClientCatalogWatchBase.java | 84 +++++++++++++ ...bernetesClientCatalogWatchEndpointsIT.java | 100 +++++++++++++++ .../catalog/watcher/it/TestAssertions.java | 116 ++++++++++++++++++ 4 files changed, 300 insertions(+), 14 deletions(-) create mode 100644 spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/it/KubernetesClientCatalogWatchBase.java create mode 100644 spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/it/KubernetesClientCatalogWatchEndpointsIT.java create mode 100644 spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/it/TestAssertions.java diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/KubernetesClientCatalogWatchIT.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/KubernetesClientCatalogWatchIT.java index e235b491fb..cb082a5a6f 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/KubernetesClientCatalogWatchIT.java +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/KubernetesClientCatalogWatchIT.java @@ -97,20 +97,6 @@ void beforeEach() { util.busybox(NAMESPACE, Phase.CREATE); } - /** - *
-	 *     - we deploy a busybox service with 2 replica pods
-	 *     - we receive an event from KubernetesCatalogWatcher, assert what is inside it
-	 *     - delete the busybox service
-	 *     - assert that we receive only spring-cloud-kubernetes-client-catalog-watcher pod
-	 * 
- */ - @Test - @Order(1) - void testCatalogWatchWithEndpoints() { - waitForLogStatement("stateGenerator is of type: KubernetesEndpointsCatalogWatch", K3S, APP_NAME); - test(); - } @Test @Order(2) diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/it/KubernetesClientCatalogWatchBase.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/it/KubernetesClientCatalogWatchBase.java new file mode 100644 index 0000000000..9180a792cd --- /dev/null +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/it/KubernetesClientCatalogWatchBase.java @@ -0,0 +1,84 @@ +/* + * Copyright 2012-2024 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.k8s.client.catalog.watcher.it; + +import java.io.IOException; +import java.io.StringReader; +import java.util.Map; +import java.util.Set; + +import io.kubernetes.client.openapi.ApiClient; +import io.kubernetes.client.openapi.apis.CoreV1Api; +import io.kubernetes.client.util.Config; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.extension.ExtendWith; + +import org.springframework.boot.test.system.OutputCaptureExtension; +import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties; +import org.springframework.cloud.kubernetes.integration.tests.commons.Commons; +import org.springframework.cloud.kubernetes.integration.tests.commons.fabric8_client.Util; +import org.springframework.test.context.TestPropertySource; +import org.testcontainers.k3s.K3sContainer; + +/** + * @author wind57 + */ + +@TestPropertySource( + properties = { "spring.main.cloud-platform=kubernetes", "spring.cloud.config.import-check.enabled=false", + "spring.cloud.kubernetes.discovery.catalogServicesWatchDelay=2000", + "spring.cloud.kubernetes.client.namespace=default", + "logging.level.org.springframework.cloud.kubernetes.client.discovery.catalog=DEBUG" }) +@ExtendWith(OutputCaptureExtension.class) +abstract class KubernetesClientCatalogWatchBase { + + protected static final String NAMESPACE = "default"; + + protected static final String NAMESPACE_A = "a"; + + protected static final String NAMESPACE_B = "b"; + + protected static final K3sContainer K3S = Commons.container(); + + protected static Util util; + + @BeforeAll + protected static void beforeAll() { + K3S.start(); + util = new Util(K3S); + } + + protected static KubernetesDiscoveryProperties discoveryProperties(boolean useEndpointSlices) { + return new KubernetesDiscoveryProperties(true, false, Set.of(NAMESPACE, NAMESPACE_A), true, 60, false, null, + Set.of(443, 8443), Map.of(), null, KubernetesDiscoveryProperties.Metadata.DEFAULT, 0, useEndpointSlices, + false, null); + } + + protected static ApiClient apiClient() { + String kubeConfigYaml = K3S.getKubeConfigYaml(); + + ApiClient client; + try { + client = Config.fromConfig(new StringReader(kubeConfigYaml)); + } + catch (IOException e) { + throw new RuntimeException(e); + } + return new CoreV1Api(client).getApiClient(); + } + +} diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/it/KubernetesClientCatalogWatchEndpointsIT.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/it/KubernetesClientCatalogWatchEndpointsIT.java new file mode 100644 index 0000000000..076a41b874 --- /dev/null +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/it/KubernetesClientCatalogWatchEndpointsIT.java @@ -0,0 +1,100 @@ +/* + * Copyright 2013-2025 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.k8s.client.catalog.watcher.it; + +import java.util.Set; + +import io.kubernetes.client.openapi.ApiClient; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.boot.test.system.CapturedOutput; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties; +import org.springframework.cloud.kubernetes.integration.tests.commons.Images; +import org.springframework.cloud.kubernetes.integration.tests.commons.Phase; +import org.springframework.cloud.kubernetes.k8s.client.catalog.watcher.Application; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; + +import static org.springframework.cloud.kubernetes.k8s.client.catalog.watcher.it.TestAssertions.assertLogStatement; +import static org.springframework.cloud.kubernetes.k8s.client.catalog.watcher.it.TestAssertions.invokeAndAssert; + +@SpringBootTest(classes = { KubernetesClientCatalogWatchEndpointsIT.TestConfig.class, Application.class }, + webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +class KubernetesClientCatalogWatchEndpointsIT extends KubernetesClientCatalogWatchBase { + + @LocalServerPort + private int port; + + @BeforeEach + void beforeEach() { + + util.createNamespace(NAMESPACE_A); + util.createNamespace(NAMESPACE_B); + + Images.loadBusybox(K3S); + + util.busybox(NAMESPACE_A, Phase.CREATE); + util.busybox(NAMESPACE_B, Phase.CREATE); + + } + + @AfterEach + void afterEach() { + // busybox is deleted as part of the assertions, thus not seen here + util.deleteNamespace(NAMESPACE_A); + util.deleteNamespace(NAMESPACE_B); + } + + /** + *
+	 *     - we deploy a busybox service with 2 replica pods in two namespaces : a, b
+	 *     - we use endpoints
+	 *     - we enable namespace filtering for 'default' and 'a'
+	 *     - we receive an event from KubernetesCatalogWatcher, assert what is inside it
+	 *     - delete the busybox service in 'a' and 'b'
+	 *     - assert that we receive an empty response
+	 * 
+ */ + @Test + void testCatalogWatchWithEndpoints(CapturedOutput output) { + assertLogStatement(output, "stateGenerator is of type: KubernetesEndpointsCatalogWatch"); + invokeAndAssert(util, Set.of(NAMESPACE_A, NAMESPACE_B), port, NAMESPACE_A); + } + + @TestConfiguration + static class TestConfig { + + @Bean + @Primary + ApiClient client() { + return apiClient(); + } + + @Bean + @Primary + KubernetesDiscoveryProperties kubernetesDiscoveryProperties() { + return discoveryProperties(false); + } + + } + +} diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/it/TestAssertions.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/it/TestAssertions.java new file mode 100644 index 0000000000..7df7aa6fda --- /dev/null +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/it/TestAssertions.java @@ -0,0 +1,116 @@ +/* + * Copyright 2013-2025 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.k8s.client.catalog.watcher.it; + +import org.assertj.core.api.Assertions; +import org.awaitility.Awaitility; +import org.springframework.boot.test.system.CapturedOutput; +import org.springframework.cloud.kubernetes.commons.discovery.EndpointNameAndNamespace; +import org.springframework.cloud.kubernetes.integration.tests.commons.Phase; +import org.springframework.cloud.kubernetes.integration.tests.commons.fabric8_client.Util; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.core.ResolvableType; +import org.springframework.http.HttpMethod; +import org.springframework.web.reactive.function.client.WebClient; + +import java.time.Duration; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; +import static org.springframework.cloud.kubernetes.integration.tests.commons.Commons.builder; +import static org.springframework.cloud.kubernetes.integration.tests.commons.Commons.retrySpec; + +/** + * @author wind57 + */ +final class TestAssertions { + + private TestAssertions() { + + } + + static void assertLogStatement(CapturedOutput output, String textToAssert) { + Awaitility.await() + .during(Duration.ofSeconds(5)) + .pollInterval(Duration.ofMillis(200)) + .untilAsserted(() -> Assertions.assertThat(output.getOut()).contains(textToAssert)); + } + + /** + * the checks are the same for both endpoints and endpoint slices, while the set-up + * for them is different. + */ + @SuppressWarnings("unchecked") + static void invokeAndAssert(Util util, Set namespaces, int port, String assertionNamespace) { + + WebClient client = builder().baseUrl("http://localhost:" + port + "/result").build(); + EndpointNameAndNamespace[] holder = new EndpointNameAndNamespace[2]; + ResolvableType resolvableType = ResolvableType.forClassWithGenerics(List.class, EndpointNameAndNamespace.class); + + await().pollInterval(Duration.ofMillis(200)).atMost(Duration.ofSeconds(30)).until(() -> { + List result = (List) client.method(HttpMethod.GET) + .retrieve() + .bodyToMono(ParameterizedTypeReference.forType(resolvableType.getType())) + .retryWhen(retrySpec()) + .block(); + + if (result != null) { + if (result.size() != 2) { + return false; + } + holder[0] = result.get(0); + holder[1] = result.get(1); + return true; + } + + return false; + }); + + EndpointNameAndNamespace resultOne = holder[0]; + EndpointNameAndNamespace resultTwo = holder[1]; + + assertThat(resultOne).isNotNull(); + assertThat(resultTwo).isNotNull(); + + assertThat(resultOne.endpointName()).contains("busybox"); + assertThat(resultTwo.endpointName()).contains("busybox"); + + assertThat(resultOne.namespace()).isEqualTo(assertionNamespace); + assertThat(resultTwo.namespace()).isEqualTo(assertionNamespace); + + namespaces.forEach(namespace -> util.busybox(namespace, Phase.DELETE)); + + await().pollInterval(Duration.ofSeconds(1)).atMost(Duration.ofSeconds(240)).until(() -> { + List result = (List) client.method(HttpMethod.GET) + .retrieve() + .bodyToMono(ParameterizedTypeReference.forType(resolvableType.getType())) + .retryWhen(retrySpec()) + .block(); + + // we need to get the event from KubernetesCatalogWatch, but that happens + // on periodic bases. So in order to be sure we got the event we care about + // we wait until there is no entry, which means busybox was deleted + // and KubernetesCatalogWatch received that update. + return Objects.requireNonNull(result).isEmpty(); + }); + + } + +} From 5c0be414c6116daf4d1a366591e0e33214c283bd Mon Sep 17 00:00:00 2001 From: wind57 Date: Fri, 17 Jan 2025 16:42:35 +0200 Subject: [PATCH 03/11] dirty Signed-off-by: wind57 --- .../KubernetesClientCatalogWatchIT.java | 90 ---------------- .../KubernetesClientCatalogWatchUtils.java | 29 ----- ...tesClientCatalogWatchEndpointSlicesIT.java | 100 ++++++++++++++++++ ...atalogWatchEndpointsNamespaceFilterIT.java | 83 +++++++++++++++ 4 files changed, 183 insertions(+), 119 deletions(-) create mode 100644 spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/it/KubernetesClientCatalogWatchEndpointSlicesIT.java create mode 100644 spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/it/KubernetesClientCatalogWatchEndpointsNamespaceFilterIT.java diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/KubernetesClientCatalogWatchIT.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/KubernetesClientCatalogWatchIT.java index cb082a5a6f..2b1c9f541d 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/KubernetesClientCatalogWatchIT.java +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/KubernetesClientCatalogWatchIT.java @@ -101,9 +101,6 @@ void beforeEach() { @Test @Order(2) void testCatalogWatchWithEndpointSlices() { - KubernetesClientCatalogWatchUtils.patchForEndpointSlices(APP_NAME, NAMESPACE, DOCKER_IMAGE); - waitForLogStatement("stateGenerator is of type: KubernetesEndpointSlicesCatalogWatch", K3S, APP_NAME); - test(); testCatalogWatchWithEndpointsNamespaces(); } @@ -124,85 +121,6 @@ void testCatalogWatchWithEndpointsNamespaces() { KubernetesClientCatalogWatchNamespacesDelegate.testCatalogWatchWithEndpointSlicesNamespaces(APP_NAME); } - /** - * the test is the same for both endpoints and endpoint slices, the set-up for them is - * different. - */ - private void test() { - - WebClient client = builder().baseUrl("http://localhost/result").build(); - EndpointNameAndNamespace[] holder = new EndpointNameAndNamespace[2]; - ResolvableType resolvableType = ResolvableType.forClassWithGenerics(List.class, EndpointNameAndNamespace.class); - - await().pollInterval(Duration.ofSeconds(1)).atMost(Duration.ofSeconds(240)).until(() -> { - List result = (List) client.method(HttpMethod.GET) - .retrieve() - .bodyToMono(ParameterizedTypeReference.forType(resolvableType.getType())) - .retryWhen(retrySpec()) - .block(); - - // we get 3 pods as input, but because they are sorted by name in the catalog - // watcher implementation - // we will get the first busybox instances here. - - if (result != null) { - if (result.size() != 3) { - return false; - } - holder[0] = result.get(0); - holder[1] = result.get(1); - return true; - } - - return false; - }); - - EndpointNameAndNamespace resultOne = holder[0]; - EndpointNameAndNamespace resultTwo = holder[1]; - - Assertions.assertNotNull(resultOne); - Assertions.assertNotNull(resultTwo); - - Assertions.assertTrue(resultOne.endpointName().contains("busybox")); - Assertions.assertTrue(resultTwo.endpointName().contains("busybox")); - Assertions.assertEquals("default", resultOne.namespace()); - Assertions.assertEquals("default", resultTwo.namespace()); - - util.busybox(NAMESPACE, Phase.DELETE); - - // what we get after delete - EndpointNameAndNamespace[] afterDelete = new EndpointNameAndNamespace[1]; - - await().pollInterval(Duration.ofSeconds(1)).atMost(Duration.ofSeconds(240)).until(() -> { - List result = (List) client.method(HttpMethod.GET) - .retrieve() - .bodyToMono(ParameterizedTypeReference.forType(resolvableType.getType())) - .retryWhen(retrySpec()) - .block(); - - // we need to get the event from KubernetesCatalogWatch, but that happens - // on periodic bases. So in order to be sure we got the event we care about - // we wait until the result has a single entry, which means busybox was - // deleted - // + KubernetesCatalogWatch received the new update. - if (result != null && result.size() != 1) { - return false; - } - - // we will only receive one pod here, our own - if (result != null) { - afterDelete[0] = result.get(0); - return true; - } - - return false; - }); - - Assertions.assertTrue(afterDelete[0].endpointName().contains(APP_NAME)); - Assertions.assertEquals("default", afterDelete[0].namespace()); - - } - private static void app(Phase phase) { V1Deployment deployment = (V1Deployment) util.yaml("app/watcher-deployment.yaml"); V1Service service = (V1Service) util.yaml("app/watcher-service.yaml"); @@ -216,12 +134,4 @@ else if (phase.equals(Phase.DELETE)) { } } - private WebClient.Builder builder() { - return WebClient.builder().clientConnector(new ReactorClientHttpConnector(HttpClient.create())); - } - - private RetryBackoffSpec retrySpec() { - return Retry.fixedDelay(15, Duration.ofSeconds(1)).filter(Objects::nonNull); - } - } diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/KubernetesClientCatalogWatchUtils.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/KubernetesClientCatalogWatchUtils.java index 083b302495..f993e406b7 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/KubernetesClientCatalogWatchUtils.java +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/KubernetesClientCatalogWatchUtils.java @@ -32,31 +32,6 @@ private KubernetesClientCatalogWatchUtils() { } - private static final String BODY_ONE = """ - { - "spec": { - "template": { - "spec": { - "containers": [{ - "name": "spring-cloud-kubernetes-k8s-client-catalog-watcher", - "image": "image_name_here", - "env": [ - { - "name": "SPRING_CLOUD_KUBERNETES_DISCOVERY_USE_ENDPOINT_SLICES", - "value": "TRUE" - }, - { - "name": "LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_CLIENT_DISCOVERY_CATALOG", - "value": "DEBUG" - } - ] - }] - } - } - } - } - """; - private static final String BODY_TWO = """ { "spec": { @@ -123,10 +98,6 @@ private KubernetesClientCatalogWatchUtils() { } """; - static void patchForEndpointSlices(String deploymentName, String namespace, String imageName) { - patchWithReplace(imageName, deploymentName, namespace, BODY_ONE, POD_LABELS); - } - static void patchForEndpointsNamespaces(String deploymentName, String namespace, String imageName) { patchWithReplace(imageName, deploymentName, namespace, BODY_TWO, POD_LABELS); } diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/it/KubernetesClientCatalogWatchEndpointSlicesIT.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/it/KubernetesClientCatalogWatchEndpointSlicesIT.java new file mode 100644 index 0000000000..a5bacb33f1 --- /dev/null +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/it/KubernetesClientCatalogWatchEndpointSlicesIT.java @@ -0,0 +1,100 @@ +/* + * Copyright 2013-2025 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.k8s.client.catalog.watcher.it; + +import java.util.Set; + +import io.kubernetes.client.openapi.ApiClient; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.boot.test.system.CapturedOutput; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties; +import org.springframework.cloud.kubernetes.integration.tests.commons.Images; +import org.springframework.cloud.kubernetes.integration.tests.commons.Phase; +import org.springframework.cloud.kubernetes.k8s.client.catalog.watcher.Application; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; + +import static org.springframework.cloud.kubernetes.k8s.client.catalog.watcher.it.TestAssertions.assertLogStatement; +import static org.springframework.cloud.kubernetes.k8s.client.catalog.watcher.it.TestAssertions.invokeAndAssert; + +@SpringBootTest(classes = { KubernetesClientCatalogWatchEndpointSlicesIT.TestConfig.class, Application.class }, + webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +class KubernetesClientCatalogWatchEndpointSlicesIT extends KubernetesClientCatalogWatchBase { + + @LocalServerPort + private int port; + + @BeforeEach + void beforeEach() { + + util.createNamespace(NAMESPACE_A); + util.createNamespace(NAMESPACE_B); + + Images.loadBusybox(K3S); + + util.busybox(NAMESPACE_A, Phase.CREATE); + util.busybox(NAMESPACE_B, Phase.CREATE); + + } + + @AfterEach + void afterEach() { + // busybox is deleted as part of the assertions, thus not seen here + util.deleteNamespace(NAMESPACE_A); + util.deleteNamespace(NAMESPACE_B); + } + + /** + *
+	 *     - we deploy a busybox service with 2 replica pods in two namespaces : a, b
+	 *     - we use endpoints
+	 *     - we enable namespace filtering for 'default' and 'a'
+	 *     - we receive an event from KubernetesCatalogWatcher, assert what is inside it
+	 *     - delete the busybox service in 'a' and 'b'
+	 *     - assert that we receive an empty response
+	 * 
+ */ + @Test + void testCatalogWatchWithEndpoints(CapturedOutput output) { + assertLogStatement(output, "stateGenerator is of type: KubernetesEndpointSlicesCatalogWatch"); + invokeAndAssert(util, Set.of(NAMESPACE_A, NAMESPACE_B), port, NAMESPACE_A); + } + + @TestConfiguration + static class TestConfig { + + @Bean + @Primary + ApiClient client() { + return apiClient(); + } + + @Bean + @Primary + KubernetesDiscoveryProperties kubernetesDiscoveryProperties() { + return discoveryProperties(true); + } + + } + +} diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/it/KubernetesClientCatalogWatchEndpointsNamespaceFilterIT.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/it/KubernetesClientCatalogWatchEndpointsNamespaceFilterIT.java new file mode 100644 index 0000000000..9a9633460b --- /dev/null +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/it/KubernetesClientCatalogWatchEndpointsNamespaceFilterIT.java @@ -0,0 +1,83 @@ +package org.springframework.cloud.kubernetes.k8s.client.catalog.watcher.it; + +import io.kubernetes.client.openapi.ApiClient; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.boot.test.system.CapturedOutput; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties; +import org.springframework.cloud.kubernetes.integration.tests.commons.Images; +import org.springframework.cloud.kubernetes.integration.tests.commons.Phase; +import org.springframework.cloud.kubernetes.k8s.client.catalog.watcher.Application; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; + +import java.util.Set; + +import static org.springframework.cloud.kubernetes.k8s.client.catalog.watcher.it.TestAssertions.assertLogStatement; +import static org.springframework.cloud.kubernetes.k8s.client.catalog.watcher.it.TestAssertions.invokeAndAssert; + +@SpringBootTest(classes = { KubernetesClientCatalogWatchEndpointsNamespaceFilterIT.TestConfig.class, Application.class }, + webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +class KubernetesClientCatalogWatchEndpointsNamespaceFilterIT extends KubernetesClientCatalogWatchBase { + + @LocalServerPort + private int port; + + @BeforeEach + void beforeEach() { + + util.createNamespace(NAMESPACE_A); + util.createNamespace(NAMESPACE_B); + + Images.loadBusybox(K3S); + + util.busybox(NAMESPACE_A, Phase.CREATE); + util.busybox(NAMESPACE_B, Phase.CREATE); + + } + + @AfterEach + void afterEach() { + // busybox is deleted as part of the assertions, thus not seen here + util.deleteNamespace(NAMESPACE_A); + util.deleteNamespace(NAMESPACE_B); + } + + /** + *
+	 *     - we deploy a busybox service with 2 replica pods in two namespaces : a, b
+	 *     - we use endpoints
+	 *     - we enable namespace filtering for 'default' and 'a'
+	 *     - we receive an event from KubernetesCatalogWatcher, assert what is inside it
+	 *     - delete the busybox service in 'a' and 'b'
+	 *     - assert that we receive an empty response
+	 * 
+ */ + @Test + void testCatalogWatchWithEndpoints(CapturedOutput output) { + assertLogStatement(output, "stateGenerator is of type: KubernetesEndpointsCatalogWatch"); + invokeAndAssert(util, Set.of(NAMESPACE_A, NAMESPACE_B), port, NAMESPACE_A); + } + + @TestConfiguration + static class TestConfig { + + @Bean + @Primary + ApiClient client() { + return apiClient(); + } + + @Bean + @Primary + KubernetesDiscoveryProperties kubernetesDiscoveryProperties() { + return discoveryProperties(false); + } + + } + +} From d5859ffaed4e0271054cc6cb75369b9be91a06a3 Mon Sep 17 00:00:00 2001 From: wind57 Date: Wed, 22 Jan 2025 16:14:04 +0200 Subject: [PATCH 04/11] refactored Signed-off-by: wind57 --- ... Fabric8CatalogWatchEndpointSlicesIT.java} | 4 +- .../KubernetesClientCatalogWatchBase.java | 12 +- ...tesClientCatalogWatchEndpointSlicesIT.java | 11 +- ...bernetesClientCatalogWatchEndpointsIT.java | 11 +- .../KubernetesClientCatalogWatchIT.java | 137 ---------------- ...sClientCatalogWatchNamespacesDelegate.java | 153 ------------------ .../KubernetesClientCatalogWatchUtils.java | 109 ------------- .../watcher/{it => }/TestAssertions.java | 13 +- ...atalogWatchEndpointsNamespaceFilterIT.java | 83 ---------- 9 files changed, 25 insertions(+), 508 deletions(-) rename spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/fabric8/catalog/watch/{Fabric8CatalogWatchEndpointSlicesFilterIT.java => Fabric8CatalogWatchEndpointSlicesIT.java} (95%) rename spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/{it => }/KubernetesClientCatalogWatchBase.java (90%) rename spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/{it => }/KubernetesClientCatalogWatchEndpointSlicesIT.java (91%) rename spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/{it => }/KubernetesClientCatalogWatchEndpointsIT.java (91%) delete mode 100644 spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/KubernetesClientCatalogWatchIT.java delete mode 100644 spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/KubernetesClientCatalogWatchNamespacesDelegate.java delete mode 100644 spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/KubernetesClientCatalogWatchUtils.java rename spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/{it => }/TestAssertions.java (99%) delete mode 100644 spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/it/KubernetesClientCatalogWatchEndpointsNamespaceFilterIT.java diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/fabric8/catalog/watch/Fabric8CatalogWatchEndpointSlicesFilterIT.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/fabric8/catalog/watch/Fabric8CatalogWatchEndpointSlicesIT.java similarity index 95% rename from spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/fabric8/catalog/watch/Fabric8CatalogWatchEndpointSlicesFilterIT.java rename to spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/fabric8/catalog/watch/Fabric8CatalogWatchEndpointSlicesIT.java index 8933a76e2d..eee4bc048f 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/fabric8/catalog/watch/Fabric8CatalogWatchEndpointSlicesFilterIT.java +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/fabric8/catalog/watch/Fabric8CatalogWatchEndpointSlicesIT.java @@ -34,7 +34,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Primary; -import static org.springframework.cloud.kubernetes.fabric8.catalog.watch.Fabric8CatalogWatchEndpointSlicesFilterIT.TestConfig; +import static org.springframework.cloud.kubernetes.fabric8.catalog.watch.Fabric8CatalogWatchEndpointSlicesIT.TestConfig; import static org.springframework.cloud.kubernetes.fabric8.catalog.watch.TestAssertions.assertLogStatement; import static org.springframework.cloud.kubernetes.fabric8.catalog.watch.TestAssertions.invokeAndAssert; @@ -43,7 +43,7 @@ */ @SpringBootTest(classes = { KubernetesCatalogWatchAutoConfiguration.class, TestConfig.class, Application.class }, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -class Fabric8CatalogWatchEndpointSlicesFilterIT extends Fabric8CatalogWatchBase { +class Fabric8CatalogWatchEndpointSlicesIT extends Fabric8CatalogWatchBase { @LocalServerPort private int port; diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/it/KubernetesClientCatalogWatchBase.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/KubernetesClientCatalogWatchBase.java similarity index 90% rename from spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/it/KubernetesClientCatalogWatchBase.java rename to spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/KubernetesClientCatalogWatchBase.java index 9180a792cd..99781999af 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/it/KubernetesClientCatalogWatchBase.java +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/KubernetesClientCatalogWatchBase.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.cloud.kubernetes.k8s.client.catalog.watcher.it; +package org.springframework.cloud.kubernetes.k8s.client.catalog.watcher; import java.io.IOException; import java.io.StringReader; @@ -26,13 +26,13 @@ import io.kubernetes.client.util.Config; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.extension.ExtendWith; +import org.testcontainers.k3s.K3sContainer; import org.springframework.boot.test.system.OutputCaptureExtension; import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties; import org.springframework.cloud.kubernetes.integration.tests.commons.Commons; import org.springframework.cloud.kubernetes.integration.tests.commons.fabric8_client.Util; import org.springframework.test.context.TestPropertySource; -import org.testcontainers.k3s.K3sContainer; /** * @author wind57 @@ -62,10 +62,10 @@ protected static void beforeAll() { util = new Util(K3S); } - protected static KubernetesDiscoveryProperties discoveryProperties(boolean useEndpointSlices) { - return new KubernetesDiscoveryProperties(true, false, Set.of(NAMESPACE, NAMESPACE_A), true, 60, false, null, - Set.of(443, 8443), Map.of(), null, KubernetesDiscoveryProperties.Metadata.DEFAULT, 0, useEndpointSlices, - false, null); + protected static KubernetesDiscoveryProperties discoveryProperties(boolean useEndpointSlices, + Set namespaces) { + return new KubernetesDiscoveryProperties(true, false, namespaces, true, 60, false, null, Set.of(443, 8443), + Map.of(), null, KubernetesDiscoveryProperties.Metadata.DEFAULT, 0, useEndpointSlices, false, null); } protected static ApiClient apiClient() { diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/it/KubernetesClientCatalogWatchEndpointSlicesIT.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/KubernetesClientCatalogWatchEndpointSlicesIT.java similarity index 91% rename from spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/it/KubernetesClientCatalogWatchEndpointSlicesIT.java rename to spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/KubernetesClientCatalogWatchEndpointSlicesIT.java index a5bacb33f1..d88e7e8866 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/it/KubernetesClientCatalogWatchEndpointSlicesIT.java +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/KubernetesClientCatalogWatchEndpointSlicesIT.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.cloud.kubernetes.k8s.client.catalog.watcher.it; +package org.springframework.cloud.kubernetes.k8s.client.catalog.watcher; import java.util.Set; @@ -30,15 +30,14 @@ import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties; import org.springframework.cloud.kubernetes.integration.tests.commons.Images; import org.springframework.cloud.kubernetes.integration.tests.commons.Phase; -import org.springframework.cloud.kubernetes.k8s.client.catalog.watcher.Application; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Primary; -import static org.springframework.cloud.kubernetes.k8s.client.catalog.watcher.it.TestAssertions.assertLogStatement; -import static org.springframework.cloud.kubernetes.k8s.client.catalog.watcher.it.TestAssertions.invokeAndAssert; +import static org.springframework.cloud.kubernetes.k8s.client.catalog.watcher.TestAssertions.assertLogStatement; +import static org.springframework.cloud.kubernetes.k8s.client.catalog.watcher.TestAssertions.invokeAndAssert; @SpringBootTest(classes = { KubernetesClientCatalogWatchEndpointSlicesIT.TestConfig.class, Application.class }, - webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) + webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) class KubernetesClientCatalogWatchEndpointSlicesIT extends KubernetesClientCatalogWatchBase { @LocalServerPort @@ -92,7 +91,7 @@ ApiClient client() { @Bean @Primary KubernetesDiscoveryProperties kubernetesDiscoveryProperties() { - return discoveryProperties(true); + return discoveryProperties(true, Set.of(NAMESPACE, NAMESPACE_A)); } } diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/it/KubernetesClientCatalogWatchEndpointsIT.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/KubernetesClientCatalogWatchEndpointsIT.java similarity index 91% rename from spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/it/KubernetesClientCatalogWatchEndpointsIT.java rename to spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/KubernetesClientCatalogWatchEndpointsIT.java index 076a41b874..f2f9dcf8d6 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/it/KubernetesClientCatalogWatchEndpointsIT.java +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/KubernetesClientCatalogWatchEndpointsIT.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.cloud.kubernetes.k8s.client.catalog.watcher.it; +package org.springframework.cloud.kubernetes.k8s.client.catalog.watcher; import java.util.Set; @@ -30,15 +30,14 @@ import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties; import org.springframework.cloud.kubernetes.integration.tests.commons.Images; import org.springframework.cloud.kubernetes.integration.tests.commons.Phase; -import org.springframework.cloud.kubernetes.k8s.client.catalog.watcher.Application; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Primary; -import static org.springframework.cloud.kubernetes.k8s.client.catalog.watcher.it.TestAssertions.assertLogStatement; -import static org.springframework.cloud.kubernetes.k8s.client.catalog.watcher.it.TestAssertions.invokeAndAssert; +import static org.springframework.cloud.kubernetes.k8s.client.catalog.watcher.TestAssertions.assertLogStatement; +import static org.springframework.cloud.kubernetes.k8s.client.catalog.watcher.TestAssertions.invokeAndAssert; @SpringBootTest(classes = { KubernetesClientCatalogWatchEndpointsIT.TestConfig.class, Application.class }, - webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) + webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) class KubernetesClientCatalogWatchEndpointsIT extends KubernetesClientCatalogWatchBase { @LocalServerPort @@ -92,7 +91,7 @@ ApiClient client() { @Bean @Primary KubernetesDiscoveryProperties kubernetesDiscoveryProperties() { - return discoveryProperties(false); + return discoveryProperties(false, Set.of(NAMESPACE, NAMESPACE_A)); } } diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/KubernetesClientCatalogWatchIT.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/KubernetesClientCatalogWatchIT.java deleted file mode 100644 index 2b1c9f541d..0000000000 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/KubernetesClientCatalogWatchIT.java +++ /dev/null @@ -1,137 +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.k8s.client.catalog.watcher; - -import java.time.Duration; -import java.util.List; -import java.util.Objects; -import java.util.Set; - -import io.kubernetes.client.openapi.models.V1Deployment; -import io.kubernetes.client.openapi.models.V1Ingress; -import io.kubernetes.client.openapi.models.V1Service; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.MethodOrderer; -import org.junit.jupiter.api.Order; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestMethodOrder; -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.commons.discovery.EndpointNameAndNamespace; -import org.springframework.cloud.kubernetes.integration.tests.commons.Commons; -import org.springframework.cloud.kubernetes.integration.tests.commons.Images; -import org.springframework.cloud.kubernetes.integration.tests.commons.Phase; -import org.springframework.cloud.kubernetes.integration.tests.commons.native_client.Util; -import org.springframework.core.ParameterizedTypeReference; -import org.springframework.core.ResolvableType; -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; -import static org.springframework.cloud.kubernetes.integration.tests.commons.Commons.waitForLogStatement; - -/** - * @author wind57 - */ -@TestMethodOrder(MethodOrderer.OrderAnnotation.class) -class KubernetesClientCatalogWatchIT { - - private static final String APP_NAME = "spring-cloud-kubernetes-k8s-client-catalog-watcher"; - - private static final String NAMESPACE = "default"; - - private static final String NAMESPACE_A = "namespacea"; - - private static final String NAMESPACE_B = "namespaceb"; - - private static final K3sContainer K3S = Commons.container(); - - private static final String DOCKER_IMAGE = "docker.io/springcloud/" + APP_NAME + ":" + Commons.pomVersion(); - - private static Util util; - - @BeforeAll - static void beforeAll() throws Exception { - K3S.start(); - Commons.validateImage(APP_NAME, K3S); - Commons.loadSpringCloudKubernetesImage(APP_NAME, K3S); - - Images.loadBusybox(K3S); - - util = new Util(K3S); - util.setUp(NAMESPACE); - app(Phase.CREATE); - } - - @AfterAll - static void afterAll() { - util.deleteClusterWide(NAMESPACE, Set.of(NAMESPACE_A, NAMESPACE_B)); - util.deleteNamespace(NAMESPACE_A); - util.deleteNamespace(NAMESPACE_B); - app(Phase.DELETE); - } - - @BeforeEach - void beforeEach() { - util.busybox(NAMESPACE, Phase.CREATE); - } - - - @Test - @Order(2) - void testCatalogWatchWithEndpointSlices() { - - testCatalogWatchWithEndpointsNamespaces(); - } - - void testCatalogWatchWithEndpointsNamespaces() { - util.createNamespace(NAMESPACE_A); - util.createNamespace(NAMESPACE_B); - util.setUpClusterWide(NAMESPACE, Set.of(NAMESPACE_A, NAMESPACE_B)); - util.busybox(NAMESPACE_A, Phase.CREATE); - util.busybox(NAMESPACE_B, Phase.CREATE); - - KubernetesClientCatalogWatchUtils.patchForEndpointsNamespaces(APP_NAME, NAMESPACE, DOCKER_IMAGE); - KubernetesClientCatalogWatchNamespacesDelegate.testCatalogWatchWithEndpointsNamespaces(APP_NAME); - - util.busybox(NAMESPACE_A, Phase.CREATE); - util.busybox(NAMESPACE_B, Phase.CREATE); - KubernetesClientCatalogWatchUtils.patchForEndpointSlicesNamespaces(APP_NAME, NAMESPACE, DOCKER_IMAGE); - KubernetesClientCatalogWatchNamespacesDelegate.testCatalogWatchWithEndpointSlicesNamespaces(APP_NAME); - } - - private static void app(Phase phase) { - V1Deployment deployment = (V1Deployment) util.yaml("app/watcher-deployment.yaml"); - V1Service service = (V1Service) util.yaml("app/watcher-service.yaml"); - V1Ingress ingress = (V1Ingress) util.yaml("app/watcher-ingress.yaml"); - - if (phase.equals(Phase.CREATE)) { - util.createAndWait(NAMESPACE, null, deployment, service, ingress, true); - } - else if (phase.equals(Phase.DELETE)) { - util.deleteAndWait(NAMESPACE, deployment, service, ingress); - } - } - -} diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/KubernetesClientCatalogWatchNamespacesDelegate.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/KubernetesClientCatalogWatchNamespacesDelegate.java deleted file mode 100644 index d13b5c6734..0000000000 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/KubernetesClientCatalogWatchNamespacesDelegate.java +++ /dev/null @@ -1,153 +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.k8s.client.catalog.watcher; - -import java.time.Duration; -import java.util.Arrays; -import java.util.Comparator; -import java.util.List; -import java.util.Objects; - -import org.junit.jupiter.api.Assertions; -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.commons.discovery.EndpointNameAndNamespace; -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.native_client.Util; -import org.springframework.core.ParameterizedTypeReference; -import org.springframework.core.ResolvableType; -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; -import static org.springframework.cloud.kubernetes.integration.tests.commons.Commons.waitForLogStatement; - -final class KubernetesClientCatalogWatchNamespacesDelegate { - - private KubernetesClientCatalogWatchNamespacesDelegate() { - - } - - private static final String NAMESPACE_A = "namespacea"; - - private static final String NAMESPACE_B = "namespaceb"; - - private static final K3sContainer K3S = Commons.container(); - - private static Util util; - - /** - *
-	 *     - we deploy one busybox service with 2 replica pods in namespace namespacea
-	 *     - we deploy one busybox service with 2 replica pods in namespace namespaceb
-	 *     - we enable the search to be made in namespacea and default ones
-	 *     - we receive an event from KubernetesCatalogWatcher, assert what is inside it
-	 *     - delete both busybox services in namespacea and namespaceb
-	 *     - assert that we receive only spring-cloud-kubernetes-client-catalog-watcher pod
-	 * 
- */ - static void testCatalogWatchWithEndpointsNamespaces(String deploymentName) { - waitForLogStatement("stateGenerator is of type: KubernetesEndpointsCatalogWatch", K3S, deploymentName); - testForNamespacesFilter(); - } - - static void testCatalogWatchWithEndpointSlicesNamespaces(String deploymentName) { - waitForLogStatement("stateGenerator is of type: KubernetesEndpointSlicesCatalogWatch", K3S, deploymentName); - testForNamespacesFilter(); - } - - /** - * the test is the same for both endpoints and endpoint slices, the set-up for them is - * different. - */ - private static void testForNamespacesFilter() { - - WebClient client = builder().baseUrl("http://localhost/result").build(); - EndpointNameAndNamespace[] holder = new EndpointNameAndNamespace[4]; - ResolvableType resolvableType = ResolvableType.forClassWithGenerics(List.class, EndpointNameAndNamespace.class); - - await().pollInterval(Duration.ofSeconds(1)).atMost(Duration.ofSeconds(240)).until(() -> { - List result = (List) client.method(HttpMethod.GET) - .retrieve() - .bodyToMono(ParameterizedTypeReference.forType(resolvableType.getType())) - .retryWhen(retrySpec()) - .block(); - - if (result != null) { - // 2 from namespace-a, 2 from namespace-b - Assertions.assertEquals(result.size(), 4); - holder[0] = result.get(0); - holder[1] = result.get(1); - holder[2] = result.get(2); - holder[3] = result.get(3); - return true; - } - - return false; - }); - - EndpointNameAndNamespace resultOne = holder[0]; - EndpointNameAndNamespace resultTwo = holder[1]; - EndpointNameAndNamespace resultThree = holder[2]; - EndpointNameAndNamespace resultFour = holder[3]; - - Assertions.assertTrue(resultOne.endpointName().contains("busybox")); - Assertions.assertTrue(resultTwo.endpointName().contains("busybox")); - Assertions.assertTrue(resultThree.endpointName().contains("busybox")); - Assertions.assertTrue(resultFour.endpointName().contains("busybox")); - - List sorted = Arrays.stream(holder) - .sorted(Comparator.comparing(EndpointNameAndNamespace::namespace)) - .toList(); - - Assertions.assertEquals(NAMESPACE_A, sorted.get(0).namespace()); - Assertions.assertEquals(NAMESPACE_A, sorted.get(1).namespace()); - Assertions.assertEquals(NAMESPACE_B, sorted.get(2).namespace()); - Assertions.assertEquals(NAMESPACE_B, sorted.get(3).namespace()); - - util = new Util(K3S); - util.busybox(NAMESPACE_A, Phase.DELETE); - util.busybox(NAMESPACE_B, Phase.DELETE); - - await().pollInterval(Duration.ofSeconds(1)).atMost(Duration.ofSeconds(240)).until(() -> { - List result = (List) client.method(HttpMethod.GET) - .retrieve() - .bodyToMono(ParameterizedTypeReference.forType(resolvableType.getType())) - .retryWhen(retrySpec()) - .block(); - - // there is no update to receive anymore, as there is nothing in namespacea - // and namespaceb - return result.size() == 0; - }); - - } - - private static WebClient.Builder builder() { - return WebClient.builder().clientConnector(new ReactorClientHttpConnector(HttpClient.create())); - } - - private static RetryBackoffSpec retrySpec() { - return Retry.fixedDelay(15, Duration.ofSeconds(1)).filter(Objects::nonNull); - } - -} diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/KubernetesClientCatalogWatchUtils.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/KubernetesClientCatalogWatchUtils.java deleted file mode 100644 index f993e406b7..0000000000 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/KubernetesClientCatalogWatchUtils.java +++ /dev/null @@ -1,109 +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.k8s.client.catalog.watcher; - -import java.util.Map; - -import static org.springframework.cloud.kubernetes.integration.tests.commons.native_client.Util.patchWithReplace; - -/** - * @author wind57 - */ -final class KubernetesClientCatalogWatchUtils { - - private static final Map POD_LABELS = Map.of("app", - "spring-cloud-kubernetes-k8s-client-catalog-watcher"); - - private KubernetesClientCatalogWatchUtils() { - - } - - private static final String BODY_TWO = """ - { - "spec": { - "template": { - "spec": { - "containers": [{ - "name": "spring-cloud-kubernetes-k8s-client-catalog-watcher", - "image": "image_name_here", - "env": [ - { - "name": "SPRING_CLOUD_KUBERNETES_DISCOVERY_USE_ENDPOINT_SLICES", - "value": "FALSE" - }, - { - "name": "LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_CLIENT_DISCOVERY_CATALOG", - "value": "DEBUG" - }, - { - "name": "SPRING_CLOUD_KUBERNETES_DISCOVERY_NAMESPACES_0", - "value": "namespacea" - }, - { - "name": "SPRING_CLOUD_KUBERNETES_DISCOVERY_NAMESPACES_1", - "value": "namespaceb" - } - ] - }] - } - } - } - } - """; - - private static final String BODY_THREE = """ - { - "spec": { - "template": { - "spec": { - "containers": [{ - "name": "spring-cloud-kubernetes-k8s-client-catalog-watcher", - "image": "image_name_here", - "env": [ - { - "name": "SPRING_CLOUD_KUBERNETES_DISCOVERY_USE_ENDPOINT_SLICES", - "value": "TRUE" - }, - { - "name": "LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_CLIENT_DISCOVERY_CATALOG", - "value": "DEBUG" - }, - { - "name": "SPRING_CLOUD_KUBERNETES_DISCOVERY_NAMESPACES_0", - "value": "namespacea" - }, - { - "name": "SPRING_CLOUD_KUBERNETES_DISCOVERY_NAMESPACES_1", - "value": "namespaceb" - } - ] - }] - } - } - } - } - """; - - static void patchForEndpointsNamespaces(String deploymentName, String namespace, String imageName) { - patchWithReplace(imageName, deploymentName, namespace, BODY_TWO, POD_LABELS); - } - - static void patchForEndpointSlicesNamespaces(String deploymentName, String namespace, String imageName) { - patchWithReplace(imageName, deploymentName, namespace, BODY_THREE, POD_LABELS); - } - -} diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/it/TestAssertions.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/TestAssertions.java similarity index 99% rename from spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/it/TestAssertions.java rename to spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/TestAssertions.java index 7df7aa6fda..d13e327659 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/it/TestAssertions.java +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/TestAssertions.java @@ -14,10 +14,16 @@ * limitations under the License. */ -package org.springframework.cloud.kubernetes.k8s.client.catalog.watcher.it; +package org.springframework.cloud.kubernetes.k8s.client.catalog.watcher; + +import java.time.Duration; +import java.util.List; +import java.util.Objects; +import java.util.Set; import org.assertj.core.api.Assertions; import org.awaitility.Awaitility; + import org.springframework.boot.test.system.CapturedOutput; import org.springframework.cloud.kubernetes.commons.discovery.EndpointNameAndNamespace; import org.springframework.cloud.kubernetes.integration.tests.commons.Phase; @@ -27,11 +33,6 @@ import org.springframework.http.HttpMethod; import org.springframework.web.reactive.function.client.WebClient; -import java.time.Duration; -import java.util.List; -import java.util.Objects; -import java.util.Set; - import static org.assertj.core.api.Assertions.assertThat; import static org.awaitility.Awaitility.await; import static org.springframework.cloud.kubernetes.integration.tests.commons.Commons.builder; diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/it/KubernetesClientCatalogWatchEndpointsNamespaceFilterIT.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/it/KubernetesClientCatalogWatchEndpointsNamespaceFilterIT.java deleted file mode 100644 index 9a9633460b..0000000000 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/it/KubernetesClientCatalogWatchEndpointsNamespaceFilterIT.java +++ /dev/null @@ -1,83 +0,0 @@ -package org.springframework.cloud.kubernetes.k8s.client.catalog.watcher.it; - -import io.kubernetes.client.openapi.ApiClient; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.TestConfiguration; -import org.springframework.boot.test.system.CapturedOutput; -import org.springframework.boot.test.web.server.LocalServerPort; -import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties; -import org.springframework.cloud.kubernetes.integration.tests.commons.Images; -import org.springframework.cloud.kubernetes.integration.tests.commons.Phase; -import org.springframework.cloud.kubernetes.k8s.client.catalog.watcher.Application; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Primary; - -import java.util.Set; - -import static org.springframework.cloud.kubernetes.k8s.client.catalog.watcher.it.TestAssertions.assertLogStatement; -import static org.springframework.cloud.kubernetes.k8s.client.catalog.watcher.it.TestAssertions.invokeAndAssert; - -@SpringBootTest(classes = { KubernetesClientCatalogWatchEndpointsNamespaceFilterIT.TestConfig.class, Application.class }, - webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -class KubernetesClientCatalogWatchEndpointsNamespaceFilterIT extends KubernetesClientCatalogWatchBase { - - @LocalServerPort - private int port; - - @BeforeEach - void beforeEach() { - - util.createNamespace(NAMESPACE_A); - util.createNamespace(NAMESPACE_B); - - Images.loadBusybox(K3S); - - util.busybox(NAMESPACE_A, Phase.CREATE); - util.busybox(NAMESPACE_B, Phase.CREATE); - - } - - @AfterEach - void afterEach() { - // busybox is deleted as part of the assertions, thus not seen here - util.deleteNamespace(NAMESPACE_A); - util.deleteNamespace(NAMESPACE_B); - } - - /** - *
-	 *     - we deploy a busybox service with 2 replica pods in two namespaces : a, b
-	 *     - we use endpoints
-	 *     - we enable namespace filtering for 'default' and 'a'
-	 *     - we receive an event from KubernetesCatalogWatcher, assert what is inside it
-	 *     - delete the busybox service in 'a' and 'b'
-	 *     - assert that we receive an empty response
-	 * 
- */ - @Test - void testCatalogWatchWithEndpoints(CapturedOutput output) { - assertLogStatement(output, "stateGenerator is of type: KubernetesEndpointsCatalogWatch"); - invokeAndAssert(util, Set.of(NAMESPACE_A, NAMESPACE_B), port, NAMESPACE_A); - } - - @TestConfiguration - static class TestConfig { - - @Bean - @Primary - ApiClient client() { - return apiClient(); - } - - @Bean - @Primary - KubernetesDiscoveryProperties kubernetesDiscoveryProperties() { - return discoveryProperties(false); - } - - } - -} From 1e3fabd841c00a8dcf393fe7015d1f4f0c88e9c8 Mon Sep 17 00:00:00 2001 From: wind57 Date: Thu, 23 Jan 2025 11:05:57 +0200 Subject: [PATCH 05/11] started some basic work Signed-off-by: wind57 --- .../watcher/ActuatorRefreshIT.java | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-configuration-watcher/src/test/java/org/springframework/cloud/kubernetes/configuration/watcher/ActuatorRefreshIT.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-configuration-watcher/src/test/java/org/springframework/cloud/kubernetes/configuration/watcher/ActuatorRefreshIT.java index 26f7301c1b..ca8b66de36 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-configuration-watcher/src/test/java/org/springframework/cloud/kubernetes/configuration/watcher/ActuatorRefreshIT.java +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-configuration-watcher/src/test/java/org/springframework/cloud/kubernetes/configuration/watcher/ActuatorRefreshIT.java @@ -20,6 +20,7 @@ import java.time.Duration; import com.github.tomakehurst.wiremock.client.WireMock; +import com.github.tomakehurst.wiremock.stubbing.StubMapping; import io.kubernetes.client.openapi.models.V1ConfigMap; import io.kubernetes.client.openapi.models.V1ConfigMapBuilder; import io.kubernetes.client.openapi.models.V1Deployment; @@ -101,15 +102,20 @@ void after() { // curl :8080/__admin/mappings @Test void testActuatorRefresh() { - WireMock.configureFor(WIREMOCK_HOST, WIREMOCK_PORT); - await().timeout(Duration.ofSeconds(60)) + StubMapping stubMapping = WireMock.stubFor(WireMock.post(WireMock.urlEqualTo("/actuator/refresh")) + .willReturn(WireMock.aResponse().withBody("{}").withStatus(200))); + + await().atMost(Duration.ofSeconds(60)) + .pollInterval(Duration.ofSeconds(1)) .ignoreException(SocketTimeoutException.class) - .until(() -> WireMock - .stubFor(WireMock.post(WireMock.urlEqualTo("/actuator/refresh")) - .willReturn(WireMock.aResponse().withBody("{}").withStatus(200))) - .getResponse() - .wasConfigured()); + .until(() -> { + boolean configured = stubMapping.getResponse().wasConfigured(); + if (!configured) { + System.out.println("Not yet configured"); + } + return configured; + }); createConfigMap(); From 6d932b703c9a57b6fa202e658aad86336c7f7879 Mon Sep 17 00:00:00 2001 From: wind57 Date: Thu, 23 Jan 2025 12:59:47 +0200 Subject: [PATCH 06/11] continue refactor Signed-off-by: wind57 --- .../watcher/ActuatorRefreshIT.java | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-configuration-watcher/src/test/java/org/springframework/cloud/kubernetes/configuration/watcher/ActuatorRefreshIT.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-configuration-watcher/src/test/java/org/springframework/cloud/kubernetes/configuration/watcher/ActuatorRefreshIT.java index ca8b66de36..0bc25da3bd 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-configuration-watcher/src/test/java/org/springframework/cloud/kubernetes/configuration/watcher/ActuatorRefreshIT.java +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-configuration-watcher/src/test/java/org/springframework/cloud/kubernetes/configuration/watcher/ActuatorRefreshIT.java @@ -18,6 +18,7 @@ import java.net.SocketTimeoutException; import java.time.Duration; +import java.util.List; import com.github.tomakehurst.wiremock.client.WireMock; import com.github.tomakehurst.wiremock.stubbing.StubMapping; @@ -31,6 +32,8 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.springframework.http.HttpMethod; +import org.springframework.web.reactive.function.client.WebClient; import org.testcontainers.containers.Container; import org.testcontainers.k3s.K3sContainer; @@ -40,6 +43,8 @@ import org.springframework.cloud.kubernetes.integration.tests.commons.native_client.Util; import static org.awaitility.Awaitility.await; +import static org.springframework.cloud.kubernetes.integration.tests.commons.Commons.builder; +import static org.springframework.cloud.kubernetes.integration.tests.commons.Commons.retrySpec; /** * @author Ryan Baxter @@ -93,29 +98,33 @@ void after() { } /* - * this test loads uses two services: wiremock on port 8080 and configuration-watcher + * this test loads two services: wiremock on port 8080 and configuration-watcher * on port 8888. we deploy configuration-watcher first and configure it via a * configmap with the same name. then, we mock the call to actuator/refresh endpoint - * and deploy a new configmap: "service-wiremock", this in turn will trigger that + * and deploy a new configmap: "service-wiremock". This in turn will trigger a * refresh that we capture and assert for. */ - // curl :8080/__admin/mappings @Test void testActuatorRefresh() { WireMock.configureFor(WIREMOCK_HOST, WIREMOCK_PORT); + // the above statement configures the client, but we need to make sure the cluster + // is ready to take a request via 'Wiremock::stubFor' (because sometimes it fails) + // As such, get the existing mappings and retrySpec() makes sure we retry until + // we get a response back. + WebClient client = builder().baseUrl("http://localhost:80/__admin/mappings").build(); + client.method(HttpMethod.GET) + .retrieve() + .bodyToMono(String.class) + .retryWhen(retrySpec()) + .block(); + StubMapping stubMapping = WireMock.stubFor(WireMock.post(WireMock.urlEqualTo("/actuator/refresh")) .willReturn(WireMock.aResponse().withBody("{}").withStatus(200))); await().atMost(Duration.ofSeconds(60)) .pollInterval(Duration.ofSeconds(1)) .ignoreException(SocketTimeoutException.class) - .until(() -> { - boolean configured = stubMapping.getResponse().wasConfigured(); - if (!configured) { - System.out.println("Not yet configured"); - } - return configured; - }); + .until(() -> stubMapping.getResponse().wasConfigured()); createConfigMap(); From 36952188fc0e583de804a9219adc3f8622c1e631 Mon Sep 17 00:00:00 2001 From: wind57 Date: Fri, 24 Jan 2025 10:02:29 +0200 Subject: [PATCH 07/11] dirty Signed-off-by: wind57 --- .../watcher/ActuatorRefreshIT.java | 49 ++++++++----------- 1 file changed, 21 insertions(+), 28 deletions(-) diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-configuration-watcher/src/test/java/org/springframework/cloud/kubernetes/configuration/watcher/ActuatorRefreshIT.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-configuration-watcher/src/test/java/org/springframework/cloud/kubernetes/configuration/watcher/ActuatorRefreshIT.java index 0bc25da3bd..955df2ba7e 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-configuration-watcher/src/test/java/org/springframework/cloud/kubernetes/configuration/watcher/ActuatorRefreshIT.java +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-configuration-watcher/src/test/java/org/springframework/cloud/kubernetes/configuration/watcher/ActuatorRefreshIT.java @@ -51,8 +51,6 @@ */ class ActuatorRefreshIT { - private static final String SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME = "spring-cloud-kubernetes-configuration-watcher"; - private static final String WIREMOCK_HOST = "localhost"; private static final String WIREMOCK_PATH = "/"; @@ -61,18 +59,13 @@ class ActuatorRefreshIT { private static final String NAMESPACE = "default"; - private static final String DOCKER_IMAGE = "docker.io/springcloud/" + SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME + ":" - + Commons.pomVersion(); - private static final K3sContainer K3S = Commons.container(); private static Util util; @BeforeAll - static void beforeAll() throws Exception { + static void beforeAll() { K3S.start(); - Commons.validateImage(SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME, K3S); - Commons.loadSpringCloudKubernetesImage(SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME, K3S); Images.loadWiremock(K3S); @@ -146,7 +139,7 @@ void testActuatorRefresh() { */ void testActuatorRefreshReloadDisabled() { - TestUtil.patchForDisabledReload(SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME, NAMESPACE, DOCKER_IMAGE); + ///TestUtil.patchForDisabledReload(SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME, NAMESPACE, DOCKER_IMAGE); WireMock.configureFor(WIREMOCK_HOST, WIREMOCK_PORT); await().timeout(Duration.ofSeconds(60)) @@ -163,12 +156,12 @@ void testActuatorRefreshReloadDisabled() { .until(() -> !WireMock.findAll(WireMock.postRequestedFor(WireMock.urlEqualTo("/actuator/refresh"))) .isEmpty()); - Commons.waitForLogStatement("creating NOOP strategy because reload is disabled", K3S, - SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME); +// Commons.waitForLogStatement("creating NOOP strategy because reload is disabled", K3S, +// SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME); // nothing related to 'ConfigReloadUtil' is present in logs // this proves that once we disable reload everything still works - Assertions.assertFalse(logs().contains("ConfigReloadUtil")); + //Assertions.assertFalse(logs().contains("ConfigReloadUtil")); WireMock.verify(WireMock.postRequestedFor(WireMock.urlEqualTo("/actuator/refresh"))); deleteConfigMap(); @@ -215,21 +208,21 @@ private void deleteConfigMap() { util.deleteAndWait(NAMESPACE, configMap, null); } - private String logs() { - try { - String appPodName = K3S - .execInContainer("sh", "-c", - "kubectl get pods -l app=" + SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_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); - } - } +// private String logs() { +// try { +// String appPodName = K3S +// .execInContainer("sh", "-c", +// "kubectl get pods -l app=" + SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_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); +// } +// } } From 7bc17c7852a7202b3eb8d9a237dd46dfd6524f2b Mon Sep 17 00:00:00 2001 From: wind57 Date: Fri, 31 Jan 2025 13:30:15 +0200 Subject: [PATCH 08/11] almost Signed-off-by: wind57 --- spring-cloud-kubernetes-dependencies/pom.xml | 2 +- .../fabric8/client/istio/Fabric8IstioIT.java | 4 +- .../pom.xml | 15 +- .../watcher/ActuatorRefreshIT.java | 159 +++--------------- .../ActuatorRefreshMultipleNamespacesIT.java | 157 ++++------------- .../configuration/watcher/TestUtil.java | 129 ++++++++++---- ...netes-configuration-watcher-configmap.yaml | 9 - 7 files changed, 160 insertions(+), 315 deletions(-) delete mode 100644 spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-configuration-watcher/src/test/resources/config-watcher/spring-cloud-kubernetes-configuration-watcher-configmap.yaml diff --git a/spring-cloud-kubernetes-dependencies/pom.xml b/spring-cloud-kubernetes-dependencies/pom.xml index 43778f0d60..cbde7c83b0 100644 --- a/spring-cloud-kubernetes-dependencies/pom.xml +++ b/spring-cloud-kubernetes-dependencies/pom.xml @@ -34,7 +34,7 @@ 6.9.2 19.0.2 - 3.4.2 + 3.9.1 diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-istio/src/test/java/org/springframework/cloud/kubernetes/fabric8/client/istio/Fabric8IstioIT.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-istio/src/test/java/org/springframework/cloud/kubernetes/fabric8/client/istio/Fabric8IstioIT.java index 10f05cf098..6b03f24e46 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-istio/src/test/java/org/springframework/cloud/kubernetes/fabric8/client/istio/Fabric8IstioIT.java +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-istio/src/test/java/org/springframework/cloud/kubernetes/fabric8/client/istio/Fabric8IstioIT.java @@ -22,8 +22,8 @@ import io.fabric8.kubernetes.api.model.Service; import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.client.utils.Serialization; +import org.assertj.core.api.Assertions; 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; @@ -106,7 +106,7 @@ void test() { .block(); // istio profile is present - Assertions.assertTrue(result.contains("istio")); + Assertions.assertThat(result).contains("istio"); } private static void appManifests(Phase phase) { diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-configuration-watcher/pom.xml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-configuration-watcher/pom.xml index 4d01f8f512..08d029ec43 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-configuration-watcher/pom.xml +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-configuration-watcher/pom.xml @@ -12,10 +12,6 @@ spring-cloud-kubernetes-k8s-client-configuration-watcher jar - - 3.4.2 - - org.springframework.boot @@ -40,7 +36,6 @@ org.wiremock wiremock-standalone - ${wiremock.version} test @@ -67,13 +62,11 @@ true + org.springframework.boot spring-boot-maven-plugin - - true - build-image @@ -81,12 +74,6 @@ true - - repackage - - true - - diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-configuration-watcher/src/test/java/org/springframework/cloud/kubernetes/configuration/watcher/ActuatorRefreshIT.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-configuration-watcher/src/test/java/org/springframework/cloud/kubernetes/configuration/watcher/ActuatorRefreshIT.java index 955df2ba7e..da62ad2a08 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-configuration-watcher/src/test/java/org/springframework/cloud/kubernetes/configuration/watcher/ActuatorRefreshIT.java +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-configuration-watcher/src/test/java/org/springframework/cloud/kubernetes/configuration/watcher/ActuatorRefreshIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2020 the original author or authors. + * Copyright 2013-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,25 +16,16 @@ package org.springframework.cloud.kubernetes.configuration.watcher; -import java.net.SocketTimeoutException; -import java.time.Duration; import java.util.List; -import com.github.tomakehurst.wiremock.client.WireMock; -import com.github.tomakehurst.wiremock.stubbing.StubMapping; -import io.kubernetes.client.openapi.models.V1ConfigMap; -import io.kubernetes.client.openapi.models.V1ConfigMapBuilder; import io.kubernetes.client.openapi.models.V1Deployment; +import io.kubernetes.client.openapi.models.V1EnvVar; import io.kubernetes.client.openapi.models.V1Service; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.springframework.http.HttpMethod; -import org.springframework.web.reactive.function.client.WebClient; -import org.testcontainers.containers.Container; import org.testcontainers.k3s.K3sContainer; import org.springframework.cloud.kubernetes.integration.tests.commons.Commons; @@ -42,21 +33,19 @@ import org.springframework.cloud.kubernetes.integration.tests.commons.Phase; import org.springframework.cloud.kubernetes.integration.tests.commons.native_client.Util; -import static org.awaitility.Awaitility.await; -import static org.springframework.cloud.kubernetes.integration.tests.commons.Commons.builder; -import static org.springframework.cloud.kubernetes.integration.tests.commons.Commons.retrySpec; +import static org.springframework.cloud.kubernetes.configuration.watcher.TestUtil.SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME; +import static org.springframework.cloud.kubernetes.configuration.watcher.TestUtil.configureWireMock; +import static org.springframework.cloud.kubernetes.configuration.watcher.TestUtil.createConfigMap; +import static org.springframework.cloud.kubernetes.configuration.watcher.TestUtil.deleteConfigMap; +import static org.springframework.cloud.kubernetes.configuration.watcher.TestUtil.verifyActuatorCalled; /** * @author Ryan Baxter */ class ActuatorRefreshIT { - private static final String WIREMOCK_HOST = "localhost"; - private static final String WIREMOCK_PATH = "/"; - private static final int WIREMOCK_PORT = 80; - private static final String NAMESPACE = "default"; private static final K3sContainer K3S = Commons.container(); @@ -64,9 +53,10 @@ class ActuatorRefreshIT { private static Util util; @BeforeAll - static void beforeAll() { + static void beforeAll() throws Exception { K3S.start(); - + Commons.validateImage(SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME, K3S); + Commons.loadSpringCloudKubernetesImage(SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME, K3S); Images.loadWiremock(K3S); util = new Util(K3S); @@ -91,138 +81,45 @@ void after() { } /* - * this test loads two services: wiremock on port 8080 and configuration-watcher - * on port 8888. we deploy configuration-watcher first and configure it via a - * configmap with the same name. then, we mock the call to actuator/refresh endpoint - * and deploy a new configmap: "service-wiremock". This in turn will trigger a + * This test loads two services: wiremock on port 8080 and configuration-watcher on + * port 8888. We deploy configuration-watcher first and configure its env variables + * that we need for this test. Then, we mock the call to actuator/refresh endpoint and + * deploy a new configmap: "service-wiremock". Because This in turn will trigger a * refresh that we capture and assert for. */ @Test void testActuatorRefresh() { - WireMock.configureFor(WIREMOCK_HOST, WIREMOCK_PORT); - // the above statement configures the client, but we need to make sure the cluster - // is ready to take a request via 'Wiremock::stubFor' (because sometimes it fails) - // As such, get the existing mappings and retrySpec() makes sure we retry until - // we get a response back. - WebClient client = builder().baseUrl("http://localhost:80/__admin/mappings").build(); - client.method(HttpMethod.GET) - .retrieve() - .bodyToMono(String.class) - .retryWhen(retrySpec()) - .block(); - - StubMapping stubMapping = WireMock.stubFor(WireMock.post(WireMock.urlEqualTo("/actuator/refresh")) - .willReturn(WireMock.aResponse().withBody("{}").withStatus(200))); - - await().atMost(Duration.ofSeconds(60)) - .pollInterval(Duration.ofSeconds(1)) - .ignoreException(SocketTimeoutException.class) - .until(() -> stubMapping.getResponse().wasConfigured()); - - createConfigMap(); - - // Wait a bit before we verify - await().atMost(Duration.ofSeconds(30)) - .until(() -> !WireMock.findAll(WireMock.postRequestedFor(WireMock.urlEqualTo("/actuator/refresh"))) - .isEmpty()); - WireMock.verify(WireMock.postRequestedFor(WireMock.urlEqualTo("/actuator/refresh"))); - - deleteConfigMap(); - - // the other test - testActuatorRefreshReloadDisabled(); - - } - - /* - * same test as above, but reload is disabled. - */ - void testActuatorRefreshReloadDisabled() { - - ///TestUtil.patchForDisabledReload(SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME, NAMESPACE, DOCKER_IMAGE); - - WireMock.configureFor(WIREMOCK_HOST, WIREMOCK_PORT); - await().timeout(Duration.ofSeconds(60)) - .until(() -> WireMock - .stubFor(WireMock.post(WireMock.urlEqualTo("/actuator/refresh")) - .willReturn(WireMock.aResponse().withBody("{}").withStatus(200))) - .getResponse() - .wasConfigured()); - - createConfigMap(); + configureWireMock(); + createConfigMap(util, NAMESPACE); + verifyActuatorCalled(1); - // Wait a bit before we verify - await().atMost(Duration.ofSeconds(30)) - .until(() -> !WireMock.findAll(WireMock.postRequestedFor(WireMock.urlEqualTo("/actuator/refresh"))) - .isEmpty()); - -// Commons.waitForLogStatement("creating NOOP strategy because reload is disabled", K3S, -// SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME); - - // nothing related to 'ConfigReloadUtil' is present in logs - // this proves that once we disable reload everything still works - //Assertions.assertFalse(logs().contains("ConfigReloadUtil")); - WireMock.verify(WireMock.postRequestedFor(WireMock.urlEqualTo("/actuator/refresh"))); - - deleteConfigMap(); + Commons.waitForLogStatement("creating NOOP strategy because reload is disabled", K3S, + SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME); + deleteConfigMap(util, NAMESPACE); } private static void configWatcher(Phase phase) { - V1ConfigMap configMap = (V1ConfigMap) util - .yaml("config-watcher/spring-cloud-kubernetes-configuration-watcher-configmap.yaml"); V1Deployment deployment = (V1Deployment) util .yaml("config-watcher/spring-cloud-kubernetes-configuration-watcher-deployment.yaml"); V1Service service = (V1Service) util .yaml("config-watcher/spring-cloud-kubernetes-configuration-watcher-service.yaml"); + List envVars = List.of( + new V1EnvVar().name("SPRING_CLOUD_KUBERNETES_CONFIGURATION_WATCHER_REFRESHDELAY").value("0"), + new V1EnvVar().name("SPRING_CLOUD_KUBERNETES_RELOAD_ENABLED").value("FALSE"), + new V1EnvVar().name("LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_CONFIGURATION_WATCHER") + .value("DEBUG")); + + deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setEnv(envVars); + if (phase.equals(Phase.CREATE)) { - util.createAndWait(NAMESPACE, configMap, null); util.createAndWait(NAMESPACE, null, deployment, service, null, true); } else { - util.deleteAndWait(NAMESPACE, configMap, null); util.deleteAndWait(NAMESPACE, deployment, service, null); } } - // Create new configmap to trigger controller to signal app to refresh - private void createConfigMap() { - V1ConfigMap configMap = new V1ConfigMapBuilder().editOrNewMetadata() - .withName("service-wiremock") - .addToLabels("spring.cloud.kubernetes.config", "true") - .endMetadata() - .addToData("foo", "bar") - .build(); - util.createAndWait(NAMESPACE, configMap, null); - } - - private void deleteConfigMap() { - V1ConfigMap configMap = new V1ConfigMapBuilder().editOrNewMetadata() - .withName("service-wiremock") - .addToLabels("spring.cloud.kubernetes.config", "true") - .endMetadata() - .addToData("foo", "bar") - .build(); - util.deleteAndWait(NAMESPACE, configMap, null); - } - -// private String logs() { -// try { -// String appPodName = K3S -// .execInContainer("sh", "-c", -// "kubectl get pods -l app=" + SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_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-k8s-client-configuration-watcher/src/test/java/org/springframework/cloud/kubernetes/configuration/watcher/ActuatorRefreshMultipleNamespacesIT.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-configuration-watcher/src/test/java/org/springframework/cloud/kubernetes/configuration/watcher/ActuatorRefreshMultipleNamespacesIT.java index d09a9028bb..b74dbc03ce 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-configuration-watcher/src/test/java/org/springframework/cloud/kubernetes/configuration/watcher/ActuatorRefreshMultipleNamespacesIT.java +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-configuration-watcher/src/test/java/org/springframework/cloud/kubernetes/configuration/watcher/ActuatorRefreshMultipleNamespacesIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 the original author or authors. + * Copyright 2013-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,21 +16,11 @@ package org.springframework.cloud.kubernetes.configuration.watcher; -import java.net.SocketTimeoutException; -import java.nio.charset.StandardCharsets; -import java.time.Duration; -import java.util.Base64; import java.util.List; -import java.util.Map; import java.util.Set; -import com.github.tomakehurst.wiremock.client.WireMock; -import io.kubernetes.client.openapi.models.V1ConfigMap; -import io.kubernetes.client.openapi.models.V1ConfigMapBuilder; import io.kubernetes.client.openapi.models.V1Deployment; import io.kubernetes.client.openapi.models.V1EnvVar; -import io.kubernetes.client.openapi.models.V1Secret; -import io.kubernetes.client.openapi.models.V1SecretBuilder; import io.kubernetes.client.openapi.models.V1Service; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; @@ -41,18 +31,17 @@ import org.springframework.cloud.kubernetes.integration.tests.commons.Phase; import org.springframework.cloud.kubernetes.integration.tests.commons.native_client.Util; -import static org.awaitility.Awaitility.await; +import static org.springframework.cloud.kubernetes.configuration.watcher.TestUtil.configureWireMock; +import static org.springframework.cloud.kubernetes.configuration.watcher.TestUtil.createConfigMap; +import static org.springframework.cloud.kubernetes.configuration.watcher.TestUtil.createSecret; +import static org.springframework.cloud.kubernetes.configuration.watcher.TestUtil.deleteConfigMap; +import static org.springframework.cloud.kubernetes.configuration.watcher.TestUtil.deleteSecret; +import static org.springframework.cloud.kubernetes.configuration.watcher.TestUtil.verifyActuatorCalled; class ActuatorRefreshMultipleNamespacesIT { private static final String SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME = "spring-cloud-kubernetes-configuration-watcher"; - private static final String WIREMOCK_HOST = "localhost"; - - private static final String WIREMOCK_PATH = "/"; - - private static final int WIREMOCK_PORT = 80; - private static final String DEFAULT_NAMESPACE = "default"; private static final String LEFT_NAMESPACE = "left"; @@ -88,124 +77,50 @@ static void afterAll() { /** *
 	 *     - deploy config-watcher in default namespace
-	 *     - deploy wiremock in default namespace (so that we could assert calls to the actuator path)
-	 *     - deploy configmap-left in left namespaces with proper label and "service-wiremock" name. Because of the
-	 *       label, this will trigger a reload; because of the name this will trigger a reload against that name.
-	 *       This is a http refresh against the actuator.
-	 *     - same as above for the configmap-right.
+	 *     - deploy wiremock in default namespace
+	 *     - deploy 'service-wiremock' configmap/secret in 'left' namespace.
+	 *     - deploy 'service-wiremock' configmap/secret in 'right' namespace.
+	 *     - each of the above triggers configuration watcher to issue
+	 *       calls to /actuator/refresh
 	 * 
*/ @Test void testConfigMapActuatorRefreshMultipleNamespaces() { - WireMock.configureFor(WIREMOCK_HOST, WIREMOCK_PORT); - await().timeout(Duration.ofSeconds(60)) - .until(() -> WireMock - .stubFor(WireMock.post(WireMock.urlEqualTo("/actuator/refresh")) - .willReturn(WireMock.aResponse().withBody("{}").withStatus(200))) - .getResponse() - .wasConfigured()); - - // left-config-map - V1ConfigMap leftConfigMap = new V1ConfigMapBuilder().editOrNewMetadata() - .withLabels(Map.of("spring.cloud.kubernetes.config", "true")) - .withName("service-wiremock") - .withNamespace(LEFT_NAMESPACE) - .endMetadata() - .addToData("color", "purple") - .build(); - util.createAndWait(LEFT_NAMESPACE, leftConfigMap, null); - - // right-config-map - V1ConfigMap rightConfigMap = new V1ConfigMapBuilder().editOrNewMetadata() - .withLabels(Map.of("spring.cloud.kubernetes.config", "true")) - .withName("service-wiremock") - .withNamespace(RIGHT_NAMESPACE) - .endMetadata() - .addToData("color", "green") - .build(); - util.createAndWait(RIGHT_NAMESPACE, rightConfigMap, null); - - // comes from handler::onAdd (and as such from "onEvent") - Commons.assertReloadLogStatements("ConfigMap service-wiremock was added in namespace left", "", - "spring-cloud-kubernetes-configuration-watcher"); - - // comes from handler::onAdd (and as such from "onEvent") - Commons.assertReloadLogStatements("ConfigMap service-wiremock was added in namespace right", "", - "spring-cloud-kubernetes-configuration-watcher"); - - await().atMost(Duration.ofSeconds(30)) - .until(() -> !WireMock.findAll(WireMock.postRequestedFor(WireMock.urlEqualTo("/actuator/refresh"))) - .isEmpty()); - WireMock.verify(WireMock.exactly(2), WireMock.postRequestedFor(WireMock.urlEqualTo("/actuator/refresh"))); - - testSecretActuatorRefreshMultipleNamespaces(); + configureWireMock(); - } + createConfigMap(util, LEFT_NAMESPACE); + createConfigMap(util, RIGHT_NAMESPACE); - /** - *
-	 *     - deploy config-watcher in default namespace
-	 *     - deploy wiremock in default namespace (so that we could assert calls to the actuator path)
-	 *     - deploy secret-left in left namespaces with proper label and "service-wiremock". Because of the
-	 *       label, this will trigger a reload; because of the name this will trigger a reload against that name.
-	 *       This is a http refresh against the actuator.
-	 *     - same as above for the secret-right.
-	 * 
- */ - void testSecretActuatorRefreshMultipleNamespaces() { - await().timeout(Duration.ofSeconds(60)) - .ignoreException(SocketTimeoutException.class) - .until(() -> WireMock - .stubFor(WireMock.post(WireMock.urlEqualTo("/actuator/refresh")) - .willReturn(WireMock.aResponse().withBody("{}").withStatus(200))) - .getResponse() - .wasConfigured()); - - // left-secret - V1Secret leftSecret = new V1SecretBuilder().editOrNewMetadata() - .withLabels(Map.of("spring.cloud.kubernetes.secret", "true")) - .withName("service-wiremock") - .withNamespace(LEFT_NAMESPACE) - .endMetadata() - .addToData("color", Base64.getEncoder().encode("purple".getBytes(StandardCharsets.UTF_8))) - .build(); - util.createAndWait(LEFT_NAMESPACE, null, leftSecret); - - // right-secret - V1Secret rightSecret = new V1SecretBuilder().editOrNewMetadata() - .withLabels(Map.of("spring.cloud.kubernetes.secret", "true")) - .withName("service-wiremock") - .withNamespace(RIGHT_NAMESPACE) - .endMetadata() - .addToData("color", Base64.getEncoder().encode("green".getBytes(StandardCharsets.UTF_8))) - .build(); - util.createAndWait(RIGHT_NAMESPACE, null, rightSecret); - - // comes from handler::onAdd (and as such from "onEvent") - Commons.assertReloadLogStatements("Secret service-wiremock was added in namespace left", "", - "spring-cloud-kubernetes-configuration-watcher"); - - // comes from handler::onAdd (and as such from "onEvent") - Commons.assertReloadLogStatements("Secret service-wiremock was added in namespace right", "", - "spring-cloud-kubernetes-configuration-watcher"); - - await().atMost(Duration.ofSeconds(30)) - .until(() -> !WireMock.findAll(WireMock.postRequestedFor(WireMock.urlEqualTo("/actuator/refresh"))) - .isEmpty()); - WireMock.verify(WireMock.exactly(4), WireMock.postRequestedFor(WireMock.urlEqualTo("/actuator/refresh"))); + createSecret(util, LEFT_NAMESPACE); + createSecret(util, RIGHT_NAMESPACE); + + Commons.waitForLogStatement("ConfigMap service-wiremock was added in namespace left", K3S, + SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME); + Commons.waitForLogStatement("ConfigMap service-wiremock was added in namespace right", K3S, + SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME); + + Commons.waitForLogStatement("Secret service-wiremock was added in namespace left", K3S, + SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME); + Commons.waitForLogStatement("Secret service-wiremock was added in namespace right", K3S, + SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME); + verifyActuatorCalled(4); + deleteConfigMap(util, LEFT_NAMESPACE); + deleteConfigMap(util, RIGHT_NAMESPACE); + deleteSecret(util, LEFT_NAMESPACE); + deleteSecret(util, RIGHT_NAMESPACE); } private static void configWatcher(Phase phase) { - V1ConfigMap configMap = (V1ConfigMap) util - .yaml("config-watcher/spring-cloud-kubernetes-configuration-watcher-configmap.yaml"); V1Deployment deployment = (V1Deployment) util .yaml("config-watcher/spring-cloud-kubernetes-configuration-watcher-deployment.yaml"); List envVars = List.of( new V1EnvVar().name("SPRING_CLOUD_KUBERNETES_RELOAD_NAMESPACES_0").value(LEFT_NAMESPACE), + new V1EnvVar().name("SPRING_CLOUD_KUBERNETES_CONFIGURATION_WATCHER_REFRESHDELAY").value("0"), new V1EnvVar().name("SPRING_CLOUD_KUBERNETES_RELOAD_NAMESPACES_1").value(RIGHT_NAMESPACE), - new V1EnvVar().name("LOGGING_LEVEL_ORG_SPRINGFRAMEWORK").value("TRACE")); + new V1EnvVar().name("LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_CLIENT_CONFIG_RELOAD") + .value("DEBUG")); deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setEnv(envVars); @@ -213,11 +128,9 @@ private static void configWatcher(Phase phase) { .yaml("config-watcher/spring-cloud-kubernetes-configuration-watcher-service.yaml"); if (phase.equals(Phase.CREATE)) { - util.createAndWait(DEFAULT_NAMESPACE, configMap, null); util.createAndWait(DEFAULT_NAMESPACE, null, deployment, service, null, true); } else { - util.deleteAndWait(DEFAULT_NAMESPACE, configMap, null); util.deleteAndWait(DEFAULT_NAMESPACE, deployment, service, null); } diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-configuration-watcher/src/test/java/org/springframework/cloud/kubernetes/configuration/watcher/TestUtil.java b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-configuration-watcher/src/test/java/org/springframework/cloud/kubernetes/configuration/watcher/TestUtil.java index b9d77740a8..1eb5ad8291 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-configuration-watcher/src/test/java/org/springframework/cloud/kubernetes/configuration/watcher/TestUtil.java +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-configuration-watcher/src/test/java/org/springframework/cloud/kubernetes/configuration/watcher/TestUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 the original author or authors. + * Copyright 2013-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,53 +16,110 @@ package org.springframework.cloud.kubernetes.configuration.watcher; +import java.net.SocketTimeoutException; +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.util.Base64; +import java.util.List; import java.util.Map; -import static org.springframework.cloud.kubernetes.integration.tests.commons.native_client.Util.patchWithReplace; +import com.github.tomakehurst.wiremock.client.WireMock; +import com.github.tomakehurst.wiremock.stubbing.StubMapping; +import com.github.tomakehurst.wiremock.verification.LoggedRequest; +import io.kubernetes.client.openapi.models.V1ConfigMap; +import io.kubernetes.client.openapi.models.V1ConfigMapBuilder; +import io.kubernetes.client.openapi.models.V1Secret; +import io.kubernetes.client.openapi.models.V1SecretBuilder; + +import org.springframework.cloud.kubernetes.integration.tests.commons.native_client.Util; +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.integration.tests.commons.Commons.builder; +import static org.springframework.cloud.kubernetes.integration.tests.commons.Commons.retrySpec; /** * @author wind57 */ final class TestUtil { + private static final String WIREMOCK_HOST = "localhost"; + + private static final int WIREMOCK_PORT = 80; + + static final String SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME = "spring-cloud-kubernetes-configuration-watcher"; + private TestUtil() { } - private static final Map POD_LABELS = Map.of("app", - "spring-cloud-kubernetes-configuration-watcher"); - - private static final String BODY_ONE = """ - { - "spec": { - "template": { - "spec": { - "containers": [{ - "name": "spring-cloud-kubernetes-configuration-watcher", - "image": "image_name_here", - "env": [ - { - "name": "LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_COMMONS_CONFIG_RELOAD", - "value": "DEBUG" - }, - { - "name": "LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_CONFIGURATION_WATCHER", - "value": "DEBUG" - }, - { - "name": "SPRING_CLOUD_KUBERNETES_RELOAD_ENABLED", - "value": "FALSE" - } - ] - }] - } - } - } - } - """; - - static void patchForDisabledReload(String deploymentName, String namespace, String imageName) { - patchWithReplace(imageName, deploymentName, namespace, BODY_ONE, POD_LABELS); + static void configureWireMock() { + WireMock.configureFor(WIREMOCK_HOST, WIREMOCK_PORT); + // the above statement configures the client, but we need to make sure the cluster + // is ready to take a request via 'Wiremock::stubFor' (because sometimes it fails) + // As such, get the existing mappings and retrySpec() makes sure we retry until + // we get a response back. + WebClient client = builder().baseUrl("http://localhost:80/__admin/mappings").build(); + client.method(HttpMethod.GET).retrieve().bodyToMono(String.class).retryWhen(retrySpec()).block(); + + StubMapping stubMapping = WireMock.stubFor(WireMock.post(WireMock.urlEqualTo("/actuator/refresh")) + .willReturn(WireMock.aResponse().withBody("{}").withStatus(200))); + + await().atMost(Duration.ofSeconds(60)) + .pollInterval(Duration.ofSeconds(1)) + .ignoreException(SocketTimeoutException.class) + .until(() -> stubMapping.getResponse().wasConfigured()); + } + + static void verifyActuatorCalled(int timesCalled) { + await().atMost(Duration.ofSeconds(60)).pollInterval(Duration.ofSeconds(1)).until(() -> { + List requests = WireMock + .findAll(WireMock.postRequestedFor(WireMock.urlEqualTo("/actuator/refresh"))); + return !requests.isEmpty(); + }); + WireMock.verify(WireMock.exactly(timesCalled), + WireMock.postRequestedFor(WireMock.urlEqualTo("/actuator/refresh"))); + } + + static void createConfigMap(Util util, String namespace) { + V1ConfigMap configMap = new V1ConfigMapBuilder().editOrNewMetadata() + .withName("service-wiremock") + .withNamespace(namespace) + .addToLabels("spring.cloud.kubernetes.config", "true") + .endMetadata() + .addToData("foo", "bar") + .build(); + util.createAndWait(namespace, configMap, null); + } + + static void deleteConfigMap(Util util, String namespace) { + V1ConfigMap configMap = new V1ConfigMapBuilder().editOrNewMetadata() + .withName("service-wiremock") + .withNamespace(namespace) + .endMetadata() + .build(); + util.deleteAndWait(namespace, configMap, null); + } + + static void createSecret(Util util, String namespace) { + V1Secret secret = new V1SecretBuilder().editOrNewMetadata() + .withLabels(Map.of("spring.cloud.kubernetes.secret", "true")) + .withName("service-wiremock") + .withNamespace(namespace) + .endMetadata() + .addToData("color", Base64.getEncoder().encode("purple".getBytes(StandardCharsets.UTF_8))) + .build(); + util.createAndWait(namespace, null, secret); + } + + static void deleteSecret(Util util, String namespace) { + V1Secret secret = new V1SecretBuilder().editOrNewMetadata() + .withName("service-wiremock") + .withNamespace(namespace) + .endMetadata() + .build(); + util.deleteAndWait(namespace, null, secret); } } diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-configuration-watcher/src/test/resources/config-watcher/spring-cloud-kubernetes-configuration-watcher-configmap.yaml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-configuration-watcher/src/test/resources/config-watcher/spring-cloud-kubernetes-configuration-watcher-configmap.yaml deleted file mode 100644 index 9c2ea62e40..0000000000 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-configuration-watcher/src/test/resources/config-watcher/spring-cloud-kubernetes-configuration-watcher-configmap.yaml +++ /dev/null @@ -1,9 +0,0 @@ -apiVersion: v1 -data: - application.properties: |- - # Set the refresh interval to 0 so the refresh event gets sent immediately - spring.cloud.kubernetes.configuration.watcher.refreshDelay=0 - logging.level.org.springframework.cloud.kubernetes=TRACE -kind: ConfigMap -metadata: - name: spring-cloud-kubernetes-configuration-watcher From 25befe289279b95fee84804cb3724e6b4eaa6e28 Mon Sep 17 00:00:00 2001 From: wind57 Date: Fri, 31 Jan 2025 14:08:50 +0200 Subject: [PATCH 09/11] first test Signed-off-by: wind57 --- .../maven-build-with-dry-run-for-tests/action.yaml | 2 +- .github/workflows/composites/pre-test-actions/action.yaml | 2 +- .../run-and-save-test-times-when-cache-missing/action.yaml | 2 +- .../run-and-save-test-times-when-cache-present/action.yaml | 2 +- spring-cloud-kubernetes-controllers/pom.xml | 3 --- spring-cloud-kubernetes-integration-tests/README | 7 ------- spring-cloud-kubernetes-integration-tests/pom.xml | 3 --- 7 files changed, 4 insertions(+), 17 deletions(-) diff --git a/.github/workflows/composites/maven-build-with-dry-run-for-tests/action.yaml b/.github/workflows/composites/maven-build-with-dry-run-for-tests/action.yaml index 6a4b927ab1..3145fc9cac 100644 --- a/.github/workflows/composites/maven-build-with-dry-run-for-tests/action.yaml +++ b/.github/workflows/composites/maven-build-with-dry-run-for-tests/action.yaml @@ -8,7 +8,7 @@ runs: shell: bash run: | ./mvnw install -B \ - -Dskip.build.image=true \ + -Dspring-boot.build-image.skip=true \ -DskipTests -DskipITs \ -T 1C -U -q diff --git a/.github/workflows/composites/pre-test-actions/action.yaml b/.github/workflows/composites/pre-test-actions/action.yaml index 2b372d2737..1a39eaa5ec 100644 --- a/.github/workflows/composites/pre-test-actions/action.yaml +++ b/.github/workflows/composites/pre-test-actions/action.yaml @@ -24,7 +24,7 @@ runs: - name: build project shell: bash run: | - ./mvnw clean install -Dskip.build.image=true -DskipITs -DskipTests -T1C -U -B -q + ./mvnw clean install -Dspring-boot.build-image.skip=true -DskipITs -DskipTests -T1C -U -B -q - name: build controllers project uses: ./.github/workflows/composites/build-controllers-project diff --git a/.github/workflows/composites/run-and-save-test-times-when-cache-missing/action.yaml b/.github/workflows/composites/run-and-save-test-times-when-cache-missing/action.yaml index 786cd0ce95..8366aa3252 100644 --- a/.github/workflows/composites/run-and-save-test-times-when-cache-missing/action.yaml +++ b/.github/workflows/composites/run-and-save-test-times-when-cache-missing/action.yaml @@ -47,7 +47,7 @@ runs: -Dmaven.wagon.http.pool=false \ -Dmaven.wagon.http.retryHandler.class=standard \ -Dmaven.wagon.http.retryHandler.count=3 \ - -Dskip.build.image=true + -Dspring-boot.build-image.skip=true touch /tmp/test_times_${{ env.CURRENT_INDEX }}.txt diff --git a/.github/workflows/composites/run-and-save-test-times-when-cache-present/action.yaml b/.github/workflows/composites/run-and-save-test-times-when-cache-present/action.yaml index 15fb3abd1b..9cfbcaefd3 100644 --- a/.github/workflows/composites/run-and-save-test-times-when-cache-present/action.yaml +++ b/.github/workflows/composites/run-and-save-test-times-when-cache-present/action.yaml @@ -156,7 +156,7 @@ runs: -Dmaven.wagon.http.pool=false \ -Dmaven.wagon.http.retryHandler.class=standard \ -Dmaven.wagon.http.retryHandler.count=3 \ - -Dskip.build.image=true + -Dspring-boot.build-image.skip=true touch /tmp/test_times_${{ env.CURRENT_INDEX }}.txt diff --git a/spring-cloud-kubernetes-controllers/pom.xml b/spring-cloud-kubernetes-controllers/pom.xml index 4f26e4b6c3..d633ae3a80 100644 --- a/spring-cloud-kubernetes-controllers/pom.xml +++ b/spring-cloud-kubernetes-controllers/pom.xml @@ -33,9 +33,6 @@ build-image - - ${skip.build.image} - package build-image-no-fork diff --git a/spring-cloud-kubernetes-integration-tests/README b/spring-cloud-kubernetes-integration-tests/README index 14355d27f4..a1cc8c3e96 100644 --- a/spring-cloud-kubernetes-integration-tests/README +++ b/spring-cloud-kubernetes-integration-tests/README @@ -13,9 +13,6 @@ you must name the image with the same name as the module. For example: build-image - - ${skip.build.image} - package build-image-no-fork @@ -36,7 +33,3 @@ Notice this line: docker.io/springcloud/${project.artifactId}:${project.version} You must follow the same convention. - -One more important part in this configuration is : "${skip.build.image}". -We use this setting in the build pipeline where in some stages we skip the image build, -only to have it build in some latter ones. diff --git a/spring-cloud-kubernetes-integration-tests/pom.xml b/spring-cloud-kubernetes-integration-tests/pom.xml index 1ed9a978a2..eb44772b34 100644 --- a/spring-cloud-kubernetes-integration-tests/pom.xml +++ b/spring-cloud-kubernetes-integration-tests/pom.xml @@ -38,9 +38,6 @@ build-image - - ${skip.build.image} - package build-image-no-fork From 38037c7f43709ca17e36ce5245fb1eb950351fe7 Mon Sep 17 00:00:00 2001 From: wind57 Date: Fri, 31 Jan 2025 14:50:11 +0200 Subject: [PATCH 10/11] simpler Signed-off-by: wind57 --- .../pom.xml | 22 ++++-------------- .../pom.xml | 20 ++++------------ .../pom.xml | 23 ++++--------------- 3 files changed, 15 insertions(+), 50 deletions(-) diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-catalog-watcher/pom.xml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-catalog-watcher/pom.xml index 5163a6eae1..538674f073 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-catalog-watcher/pom.xml +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-catalog-watcher/pom.xml @@ -11,6 +11,11 @@ spring-cloud-kubernetes-fabric8-client-catalog-watcher + + true + true + + org.springframework.cloud @@ -42,22 +47,5 @@ true - - - - org.springframework.boot - spring-boot-maven-plugin - - - build-image - - true - - - - - - - diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-discovery/pom.xml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-discovery/pom.xml index 58685aac04..7e865822e6 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-discovery/pom.xml +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-client-discovery/pom.xml @@ -11,6 +11,11 @@ spring-cloud-kubernetes-fabric8-client-discovery + + true + true + + org.springframework.cloud @@ -50,21 +55,6 @@ true - - - - org.springframework.boot - spring-boot-maven-plugin - - - build-image - - true - - - - - diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/pom.xml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/pom.xml index e5a8d7bc00..63de926877 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/pom.xml +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/pom.xml @@ -11,6 +11,11 @@ spring-cloud-kubernetes-k8s-client-catalog-watcher + + true + true + + org.springframework.cloud @@ -42,23 +47,5 @@ true - - - - org.springframework.boot - spring-boot-maven-plugin - - - build-image - - true - - - - - - - - From 247c2750af3d3de159b5f016976dd1d8e3680559 Mon Sep 17 00:00:00 2001 From: wind57 Date: Fri, 31 Jan 2025 16:47:41 +0200 Subject: [PATCH 11/11] latest merge Signed-off-by: wind57 --- .../pom.xml | 22 +++++-------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-configuration-watcher/pom.xml b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-configuration-watcher/pom.xml index 08d029ec43..71a967e49c 100644 --- a/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-configuration-watcher/pom.xml +++ b/spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-configuration-watcher/pom.xml @@ -10,7 +10,11 @@ 4.0.0 spring-cloud-kubernetes-k8s-client-configuration-watcher - jar + + + true + true + @@ -62,21 +66,5 @@ true - - - - org.springframework.boot - spring-boot-maven-plugin - - - build-image - - true - - - - - -