Simplify integration tests (#1181)
This commit is contained in:
@@ -6,6 +6,11 @@ runs:
|
||||
- name: run fabric8 istio integration test
|
||||
shell: bash
|
||||
run: |
|
||||
|
||||
cd spring-cloud-kubernetes-test-support
|
||||
.././mvnw clean install
|
||||
cd ..
|
||||
|
||||
docker load -i /tmp/docker/images/spring-cloud-kubernetes-fabric8-istio-it.tar
|
||||
cd spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-fabric8-istio-it/
|
||||
../.././mvnw clean install -Dskip.build.image=true
|
||||
|
||||
@@ -20,13 +20,9 @@ import java.time.Duration;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import io.kubernetes.client.openapi.apis.AppsV1Api;
|
||||
import io.kubernetes.client.openapi.apis.CoreV1Api;
|
||||
import io.kubernetes.client.openapi.apis.NetworkingV1Api;
|
||||
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.AfterEach;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@@ -38,7 +34,8 @@ 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.K8SUtils;
|
||||
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;
|
||||
@@ -46,7 +43,6 @@ 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.K8SUtils.createApiClient;
|
||||
|
||||
/**
|
||||
* @author wind57
|
||||
@@ -59,47 +55,20 @@ class KubernetesClientCatalogWatchIT {
|
||||
|
||||
private static final K3sContainer K3S = Commons.container();
|
||||
|
||||
private static CoreV1Api api;
|
||||
|
||||
private static AppsV1Api appsApi;
|
||||
|
||||
private static NetworkingV1Api networkingApi;
|
||||
|
||||
private static K8SUtils k8SUtils;
|
||||
|
||||
private static String busyboxServiceName;
|
||||
|
||||
private static String busyboxDeploymentName;
|
||||
|
||||
private static String appDeploymentName;
|
||||
|
||||
private static String appServiceName;
|
||||
|
||||
private static String appIngressName;
|
||||
private static Util util;
|
||||
|
||||
@BeforeAll
|
||||
static void beforeAll() throws Exception {
|
||||
K3S.start();
|
||||
|
||||
Commons.validateImage(APP_NAME, K3S);
|
||||
Commons.loadSpringCloudKubernetesImage(APP_NAME, K3S);
|
||||
|
||||
createApiClient(K3S.getKubeConfigYaml());
|
||||
api = new CoreV1Api();
|
||||
appsApi = new AppsV1Api();
|
||||
networkingApi = new NetworkingV1Api();
|
||||
k8SUtils = new K8SUtils(api, appsApi);
|
||||
k8SUtils.setUp(NAMESPACE);
|
||||
util = new Util(K3S);
|
||||
util.setUp(NAMESPACE);
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() throws Exception {
|
||||
deployBusyboxManifests();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void afterEach() throws Exception {
|
||||
deleteApp();
|
||||
void beforeEach() {
|
||||
util.busybox(NAMESPACE, Phase.CREATE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -112,16 +81,18 @@ class KubernetesClientCatalogWatchIT {
|
||||
*/
|
||||
@Test
|
||||
void testCatalogWatchWithEndpoints() throws Exception {
|
||||
deployApp(false);
|
||||
app(false, Phase.CREATE);
|
||||
assertLogStatement("stateGenerator is of type: KubernetesEndpointsCatalogWatch");
|
||||
test();
|
||||
app(false, Phase.DELETE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCatalogWatchWithEndpointSlices() throws Exception {
|
||||
deployApp(true);
|
||||
app(true, Phase.CREATE);
|
||||
assertLogStatement("stateGenerator is of type: KubernetesEndpointSlicesCatalogWatch");
|
||||
test();
|
||||
app(true, Phase.DELETE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -140,8 +111,7 @@ class KubernetesClientCatalogWatchIT {
|
||||
* the test is the same for both endpoints and endpoint slices, the set-up for them is
|
||||
* different.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private void test() throws Exception {
|
||||
private void test() {
|
||||
|
||||
WebClient client = builder().baseUrl("localhost/result").build();
|
||||
EndpointNameAndNamespace[] holder = new EndpointNameAndNamespace[2];
|
||||
@@ -175,7 +145,7 @@ class KubernetesClientCatalogWatchIT {
|
||||
Assertions.assertEquals("default", resultOne.namespace());
|
||||
Assertions.assertEquals("default", resultTwo.namespace());
|
||||
|
||||
deleteBusyboxApp();
|
||||
util.busybox(NAMESPACE, Phase.DELETE);
|
||||
|
||||
// what we get after delete
|
||||
EndpointNameAndNamespace[] afterDelete = new EndpointNameAndNamespace[1];
|
||||
@@ -208,89 +178,19 @@ class KubernetesClientCatalogWatchIT {
|
||||
|
||||
}
|
||||
|
||||
private void deployBusyboxManifests() throws Exception {
|
||||
private static void app(boolean useEndpointSlices, Phase phase) {
|
||||
V1Deployment deployment = useEndpointSlices
|
||||
? (V1Deployment) util.yaml("app/watcher-endpoint-slices-deployment.yaml")
|
||||
: (V1Deployment) util.yaml("app/watcher-endpoints-deployment.yaml");
|
||||
V1Service service = (V1Service) util.yaml("app/watcher-service.yaml");
|
||||
V1Ingress ingress = (V1Ingress) util.yaml("app/watcher-ingress.yaml");
|
||||
|
||||
V1Deployment busyboxDeployment = (V1Deployment) K8SUtils.readYamlFromClasspath(getBusyboxDeployment());
|
||||
|
||||
String[] image = K8SUtils.getImageFromDeployment(busyboxDeployment).split(":");
|
||||
Commons.pullImage(image[0], image[1], K3S);
|
||||
Commons.loadImage(image[0], image[1], "busybox", K3S);
|
||||
|
||||
appsApi.createNamespacedDeployment(NAMESPACE, busyboxDeployment, null, null, null, null);
|
||||
busyboxDeploymentName = busyboxDeployment.getMetadata().getName();
|
||||
|
||||
V1Service busyboxService = (V1Service) K8SUtils.readYamlFromClasspath(getBusyboxService());
|
||||
busyboxServiceName = busyboxService.getMetadata().getName();
|
||||
api.createNamespacedService(NAMESPACE, busyboxService, null, null, null, null);
|
||||
|
||||
k8SUtils.waitForDeployment(busyboxDeploymentName, NAMESPACE);
|
||||
|
||||
}
|
||||
|
||||
private static void deployApp(boolean useEndpointSlices) throws Exception {
|
||||
|
||||
V1Deployment appDeployment = useEndpointSlices
|
||||
? (V1Deployment) K8SUtils.readYamlFromClasspath(getEndpointSlicesAppDeployment())
|
||||
: (V1Deployment) K8SUtils.readYamlFromClasspath(getEndpointsAppDeployment());
|
||||
|
||||
String version = K8SUtils.getPomVersion();
|
||||
String currentImage = appDeployment.getSpec().getTemplate().getSpec().getContainers().get(0).getImage();
|
||||
appDeployment.getSpec().getTemplate().getSpec().getContainers().get(0).setImage(currentImage + ":" + version);
|
||||
|
||||
appsApi.createNamespacedDeployment(NAMESPACE, appDeployment, null, null, null, null);
|
||||
appDeploymentName = appDeployment.getMetadata().getName();
|
||||
|
||||
V1Service appService = (V1Service) K8SUtils.readYamlFromClasspath(getAppService());
|
||||
appServiceName = appService.getMetadata().getName();
|
||||
api.createNamespacedService(NAMESPACE, appService, null, null, null, null);
|
||||
|
||||
k8SUtils.waitForDeployment(appDeploymentName, NAMESPACE);
|
||||
|
||||
V1Ingress appIngress = (V1Ingress) K8SUtils.readYamlFromClasspath(getAppIngress());
|
||||
appIngressName = appIngress.getMetadata().getName();
|
||||
networkingApi.createNamespacedIngress(NAMESPACE, appIngress, null, null, null, null);
|
||||
k8SUtils.waitForIngress(appIngressName, NAMESPACE);
|
||||
|
||||
}
|
||||
|
||||
private void deleteBusyboxApp() throws Exception {
|
||||
appsApi.deleteNamespacedDeployment(busyboxDeploymentName, NAMESPACE, null, null, null, null, null, null);
|
||||
api.deleteNamespacedService(busyboxServiceName, NAMESPACE, null, null, null, null, null, null);
|
||||
k8SUtils.waitForDeploymentToBeDeleted(busyboxDeploymentName, NAMESPACE);
|
||||
}
|
||||
|
||||
private void deleteApp() throws Exception {
|
||||
appsApi.deleteNamespacedDeployment(appDeploymentName, NAMESPACE, null, null, null, null, null, null);
|
||||
api.deleteNamespacedService(appServiceName, NAMESPACE, null, null, null, null, null, null);
|
||||
networkingApi.deleteNamespacedIngress(appIngressName, NAMESPACE, null, null, null, null, null, null);
|
||||
k8SUtils.waitForDeploymentToBeDeleted(busyboxDeploymentName, NAMESPACE);
|
||||
}
|
||||
|
||||
private static String getBusyboxService() {
|
||||
return "busybox/service.yaml";
|
||||
}
|
||||
|
||||
private static String getBusyboxDeployment() {
|
||||
return "busybox/deployment.yaml";
|
||||
}
|
||||
|
||||
/**
|
||||
* deployment where support for endpoint slices is equal to false
|
||||
*/
|
||||
private static String getEndpointsAppDeployment() {
|
||||
return "app/watcher-endpoints-deployment.yaml";
|
||||
}
|
||||
|
||||
private static String getEndpointSlicesAppDeployment() {
|
||||
return "app/watcher-endpoint-slices-deployment.yaml";
|
||||
}
|
||||
|
||||
private static String getAppIngress() {
|
||||
return "app/watcher-ingress.yaml";
|
||||
}
|
||||
|
||||
private static String getAppService() {
|
||||
return "app/watcher-service.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);
|
||||
}
|
||||
}
|
||||
|
||||
private WebClient.Builder builder() {
|
||||
|
||||
@@ -18,18 +18,16 @@ package org.springframework.cloud.kubernetes.client.catalog;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import io.kubernetes.client.openapi.apis.AppsV1Api;
|
||||
import io.kubernetes.client.openapi.apis.CoreV1Api;
|
||||
import io.kubernetes.client.openapi.apis.NetworkingV1Api;
|
||||
import io.kubernetes.client.openapi.models.V1Deployment;
|
||||
import io.kubernetes.client.openapi.models.V1EnvVar;
|
||||
import io.kubernetes.client.openapi.models.V1EnvVarBuilder;
|
||||
import io.kubernetes.client.openapi.models.V1Ingress;
|
||||
import io.kubernetes.client.openapi.models.V1NamespaceBuilder;
|
||||
import io.kubernetes.client.openapi.models.V1Service;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
@@ -43,7 +41,8 @@ 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.K8SUtils;
|
||||
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;
|
||||
@@ -51,7 +50,6 @@ 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.K8SUtils.createApiClient;
|
||||
|
||||
public class KubernetesClientCatalogWatchNamespacesIT {
|
||||
|
||||
@@ -65,58 +63,30 @@ public class KubernetesClientCatalogWatchNamespacesIT {
|
||||
|
||||
private static final K3sContainer K3S = Commons.container();
|
||||
|
||||
private static CoreV1Api api;
|
||||
|
||||
private static AppsV1Api appsApi;
|
||||
|
||||
private static NetworkingV1Api networkingApi;
|
||||
|
||||
private static K8SUtils k8SUtils;
|
||||
|
||||
private static String busyboxServiceNameA;
|
||||
|
||||
private static String busyboxServiceNameB;
|
||||
|
||||
private static String busyboxDeploymentNameA;
|
||||
|
||||
private static String busyboxDeploymentNameB;
|
||||
|
||||
private static String appDeploymentName;
|
||||
|
||||
private static String appServiceName;
|
||||
|
||||
private static String appIngressName;
|
||||
private static Util util;
|
||||
|
||||
@BeforeAll
|
||||
static void beforeAll() throws Exception {
|
||||
K3S.start();
|
||||
|
||||
Commons.validateImage(APP_NAME, K3S);
|
||||
Commons.loadSpringCloudKubernetesImage(APP_NAME, K3S);
|
||||
|
||||
createApiClient(K3S.getKubeConfigYaml());
|
||||
api = new CoreV1Api();
|
||||
appsApi = new AppsV1Api();
|
||||
networkingApi = new NetworkingV1Api();
|
||||
k8SUtils = new K8SUtils(api, appsApi);
|
||||
k8SUtils.setUp(NAMESPACE_DEFAULT);
|
||||
util = new Util(K3S);
|
||||
util.setUp(NAMESPACE_DEFAULT);
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() throws Exception {
|
||||
api.createNamespace(new V1NamespaceBuilder().withNewMetadata().withName(NAMESPACE_A).and().build(), null, null,
|
||||
null, null);
|
||||
api.createNamespace(new V1NamespaceBuilder().withNewMetadata().withName(NAMESPACE_B).and().build(), null, null,
|
||||
null, null);
|
||||
k8SUtils.setUpClusterWide(NAMESPACE_DEFAULT, Set.of(NAMESPACE_A, NAMESPACE_B));
|
||||
deployBusyboxManifests();
|
||||
void beforeEach() {
|
||||
util.createNamespace(NAMESPACE_A);
|
||||
util.createNamespace(NAMESPACE_B);
|
||||
util.setUpClusterWide(NAMESPACE_DEFAULT, Set.of(NAMESPACE_A, NAMESPACE_B));
|
||||
util.busybox(NAMESPACE_A, Phase.CREATE);
|
||||
util.busybox(NAMESPACE_B, Phase.CREATE);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void afterEach() throws Exception {
|
||||
deleteApp();
|
||||
k8SUtils.deleteNamespace(NAMESPACE_A);
|
||||
k8SUtils.deleteNamespace(NAMESPACE_B);
|
||||
void afterEach() {
|
||||
util.deleteNamespace(NAMESPACE_A);
|
||||
util.deleteNamespace(NAMESPACE_B);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -131,16 +101,18 @@ public class KubernetesClientCatalogWatchNamespacesIT {
|
||||
*/
|
||||
@Test
|
||||
void testCatalogWatchWithEndpoints() throws Exception {
|
||||
deployApp(false);
|
||||
app(false, Phase.CREATE);
|
||||
assertLogStatement("stateGenerator is of type: KubernetesEndpointsCatalogWatch");
|
||||
test();
|
||||
app(false, Phase.DELETE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCatalogWatchWithEndpointSlices() throws Exception {
|
||||
deployApp(true);
|
||||
app(true, Phase.CREATE);
|
||||
assertLogStatement("stateGenerator is of type: KubernetesEndpointSlicesCatalogWatch");
|
||||
test();
|
||||
app(true, Phase.DELETE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -149,10 +121,8 @@ public class KubernetesClientCatalogWatchNamespacesIT {
|
||||
* type.
|
||||
*/
|
||||
private void assertLogStatement(String log) throws Exception {
|
||||
String appPodName = K3S
|
||||
.execInContainer("kubectl", "get", "pods", "-l",
|
||||
"app=spring-cloud-kubernetes-client-catalog-watcher", "-o=name", "--no-headers")
|
||||
.getStdout();
|
||||
String appPodName = K3S.execInContainer("kubectl", "get", "pods", "-l",
|
||||
"app=spring-cloud-kubernetes-client-catalog-watcher", "-o=name", "--no-headers").getStdout();
|
||||
String allLogs = K3S.execInContainer("kubectl", "logs", appPodName.trim()).getStdout();
|
||||
Assertions.assertTrue(allLogs.contains(log));
|
||||
}
|
||||
@@ -161,11 +131,10 @@ public class KubernetesClientCatalogWatchNamespacesIT {
|
||||
* the test is the same for both endpoints and endpoint slices, the set-up for them is
|
||||
* different.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private void test() throws Exception {
|
||||
private void test() {
|
||||
|
||||
WebClient client = builder().baseUrl("localhost/result").build();
|
||||
EndpointNameAndNamespace[] holder = new EndpointNameAndNamespace[2];
|
||||
EndpointNameAndNamespace[] holder = new EndpointNameAndNamespace[4];
|
||||
ResolvableType resolvableType = ResolvableType.forClassWithGenerics(List.class, EndpointNameAndNamespace.class);
|
||||
|
||||
await().pollInterval(Duration.ofSeconds(1)).atMost(Duration.ofSeconds(240)).until(() -> {
|
||||
@@ -173,12 +142,13 @@ public class KubernetesClientCatalogWatchNamespacesIT {
|
||||
.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) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
@@ -187,159 +157,61 @@ public class KubernetesClientCatalogWatchNamespacesIT {
|
||||
|
||||
EndpointNameAndNamespace resultOne = holder[0];
|
||||
EndpointNameAndNamespace resultTwo = holder[1];
|
||||
|
||||
Assertions.assertNotNull(resultOne);
|
||||
Assertions.assertNotNull(resultTwo);
|
||||
EndpointNameAndNamespace resultThree = holder[2];
|
||||
EndpointNameAndNamespace resultFour = holder[3];
|
||||
|
||||
Assertions.assertTrue(resultOne.endpointName().contains("busybox"));
|
||||
Assertions.assertTrue(resultTwo.endpointName().contains("busybox"));
|
||||
Assertions.assertEquals(NAMESPACE_A, resultOne.namespace());
|
||||
Assertions.assertEquals(NAMESPACE_A, resultTwo.namespace());
|
||||
Assertions.assertTrue(resultThree.endpointName().contains("busybox"));
|
||||
Assertions.assertTrue(resultFour.endpointName().contains("busybox"));
|
||||
|
||||
deleteBusyboxApp();
|
||||
List<EndpointNameAndNamespace> sorted = Arrays.stream(holder)
|
||||
.sorted(Comparator.comparing(EndpointNameAndNamespace::namespace)).toList();
|
||||
|
||||
// what we get after delete
|
||||
EndpointNameAndNamespace[] afterDelete = new EndpointNameAndNamespace[1];
|
||||
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.busybox(NAMESPACE_A, Phase.DELETE);
|
||||
util.busybox(NAMESPACE_B, Phase.DELETE);
|
||||
|
||||
await().pollInterval(Duration.ofSeconds(1)).atMost(Duration.ofSeconds(240)).until(() -> {
|
||||
List<EndpointNameAndNamespace> result = (List<EndpointNameAndNamespace>) 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;
|
||||
// there is no update to receive anymore, as there is nothing in namespacea
|
||||
// and namespaceb
|
||||
return result.size() == 0;
|
||||
});
|
||||
|
||||
Assertions.assertTrue(afterDelete[0].endpointName().contains(APP_NAME));
|
||||
Assertions.assertEquals("default", afterDelete[0].namespace());
|
||||
|
||||
}
|
||||
|
||||
private void deployBusyboxManifests() throws Exception {
|
||||
private void app(boolean useEndpointSlices, Phase phase) {
|
||||
V1Deployment deployment = useEndpointSlices
|
||||
? (V1Deployment) util.yaml("app/watcher-endpoint-slices-deployment.yaml")
|
||||
: (V1Deployment) util.yaml("app/watcher-endpoints-deployment.yaml");
|
||||
V1Service service = (V1Service) util.yaml("app/watcher-service.yaml");
|
||||
V1Ingress ingress = (V1Ingress) util.yaml("app/watcher-ingress.yaml");
|
||||
|
||||
V1Deployment busyboxDeployment = (V1Deployment) K8SUtils.readYamlFromClasspath(getBusyboxDeployment());
|
||||
if (phase.equals(Phase.CREATE)) {
|
||||
V1EnvVar one = new V1EnvVarBuilder().withName("SPRING_CLOUD_KUBERNETES_DISCOVERY_NAMESPACES_0")
|
||||
.withValue(NAMESPACE_A).build();
|
||||
|
||||
String[] image = K8SUtils.getImageFromDeployment(busyboxDeployment).split(":");
|
||||
Commons.pullImage(image[0], image[1], K3S);
|
||||
Commons.loadImage(image[0], image[1], "busybox", K3S);
|
||||
V1EnvVar two = new V1EnvVarBuilder().withName("SPRING_CLOUD_KUBERNETES_DISCOVERY_NAMESPACES_1")
|
||||
.withValue(NAMESPACE_B).build();
|
||||
|
||||
// namespace_a
|
||||
appsApi.createNamespacedDeployment(NAMESPACE_A, busyboxDeployment, null, null, null, null);
|
||||
busyboxDeploymentNameA = busyboxDeployment.getMetadata().getName();
|
||||
|
||||
V1Service busyboxServiceA = (V1Service) K8SUtils.readYamlFromClasspath(getBusyboxService());
|
||||
busyboxServiceNameA = busyboxServiceA.getMetadata().getName();
|
||||
api.createNamespacedService(NAMESPACE_A, busyboxServiceA, null, null, null, null);
|
||||
|
||||
k8SUtils.waitForDeployment(busyboxDeploymentNameA, NAMESPACE_A);
|
||||
|
||||
// namespace_b
|
||||
appsApi.createNamespacedDeployment(NAMESPACE_B, busyboxDeployment, null, null, null, null);
|
||||
busyboxDeploymentNameB = busyboxDeployment.getMetadata().getName();
|
||||
|
||||
V1Service busyboxServiceB = (V1Service) K8SUtils.readYamlFromClasspath(getBusyboxService());
|
||||
busyboxServiceNameB = busyboxServiceB.getMetadata().getName();
|
||||
api.createNamespacedService(NAMESPACE_B, busyboxServiceB, null, null, null, null);
|
||||
|
||||
k8SUtils.waitForDeployment(busyboxDeploymentNameA, NAMESPACE_A);
|
||||
|
||||
}
|
||||
|
||||
private static void deployApp(boolean useEndpointSlices) throws Exception {
|
||||
|
||||
V1Deployment appDeployment = useEndpointSlices
|
||||
? (V1Deployment) K8SUtils.readYamlFromClasspath(getEndpointSlicesAppDeployment())
|
||||
: (V1Deployment) K8SUtils.readYamlFromClasspath(getEndpointsAppDeployment());
|
||||
|
||||
String version = K8SUtils.getPomVersion();
|
||||
String currentImage = appDeployment.getSpec().getTemplate().getSpec().getContainers().get(0).getImage();
|
||||
appDeployment.getSpec().getTemplate().getSpec().getContainers().get(0).setImage(currentImage + ":" + version);
|
||||
|
||||
List<V1EnvVar> envVars = new ArrayList<>(
|
||||
appDeployment.getSpec().getTemplate().getSpec().getContainers().get(0).getEnv());
|
||||
V1EnvVar namespaceAEnvVar = new V1EnvVarBuilder().withName("SPRING_CLOUD_KUBERNETES_DISCOVERY_NAMESPACES_0")
|
||||
.withValue(NAMESPACE_A).build();
|
||||
V1EnvVar namespaceDefaultEnvVar = new V1EnvVarBuilder()
|
||||
.withName("SPRING_CLOUD_KUBERNETES_DISCOVERY_NAMESPACES_1").withValue(NAMESPACE_DEFAULT).build();
|
||||
envVars.add(namespaceAEnvVar);
|
||||
envVars.add(namespaceDefaultEnvVar);
|
||||
|
||||
appDeployment.getSpec().getTemplate().getSpec().getContainers().get(0).setEnv(envVars);
|
||||
|
||||
appsApi.createNamespacedDeployment(NAMESPACE_DEFAULT, appDeployment, null, null, null, null);
|
||||
appDeploymentName = appDeployment.getMetadata().getName();
|
||||
|
||||
V1Service appService = (V1Service) K8SUtils.readYamlFromClasspath(getAppService());
|
||||
appServiceName = appService.getMetadata().getName();
|
||||
api.createNamespacedService(NAMESPACE_DEFAULT, appService, null, null, null, null);
|
||||
|
||||
k8SUtils.waitForDeployment(appDeploymentName, NAMESPACE_DEFAULT);
|
||||
|
||||
V1Ingress appIngress = (V1Ingress) K8SUtils.readYamlFromClasspath(getAppIngress());
|
||||
appIngressName = appIngress.getMetadata().getName();
|
||||
networkingApi.createNamespacedIngress(NAMESPACE_DEFAULT, appIngress, null, null, null, null);
|
||||
|
||||
k8SUtils.waitForIngress(appIngressName, NAMESPACE_DEFAULT);
|
||||
|
||||
}
|
||||
|
||||
private void deleteBusyboxApp() throws Exception {
|
||||
// namespacea
|
||||
appsApi.deleteNamespacedDeployment(busyboxDeploymentNameA, NAMESPACE_A, null, null, null, null, null, null);
|
||||
api.deleteNamespacedService(busyboxServiceNameA, NAMESPACE_A, null, null, null, null, null, null);
|
||||
k8SUtils.waitForDeploymentToBeDeleted(busyboxDeploymentNameA, NAMESPACE_A);
|
||||
|
||||
// namespaceb
|
||||
appsApi.deleteNamespacedDeployment(busyboxDeploymentNameB, NAMESPACE_B, null, null, null, null, null, null);
|
||||
api.deleteNamespacedService(busyboxServiceNameB, NAMESPACE_B, null, null, null, null, null, null);
|
||||
k8SUtils.waitForDeploymentToBeDeleted(busyboxDeploymentNameB, NAMESPACE_B);
|
||||
}
|
||||
|
||||
private void deleteApp() throws Exception {
|
||||
appsApi.deleteNamespacedDeployment(appDeploymentName, NAMESPACE_DEFAULT, null, null, null, null, null, null);
|
||||
api.deleteNamespacedService(appServiceName, NAMESPACE_DEFAULT, null, null, null, null, null, null);
|
||||
networkingApi.deleteNamespacedIngress(appIngressName, NAMESPACE_DEFAULT, null, null, null, null, null, null);
|
||||
}
|
||||
|
||||
private static String getBusyboxService() {
|
||||
return "busybox/service.yaml";
|
||||
}
|
||||
|
||||
private static String getBusyboxDeployment() {
|
||||
return "busybox/deployment.yaml";
|
||||
}
|
||||
|
||||
/**
|
||||
* deployment where support for endpoint slices is equal to false
|
||||
*/
|
||||
private static String getEndpointsAppDeployment() {
|
||||
return "app/watcher-endpoints-deployment.yaml";
|
||||
}
|
||||
|
||||
private static String getEndpointSlicesAppDeployment() {
|
||||
return "app/watcher-endpoint-slices-deployment.yaml";
|
||||
}
|
||||
|
||||
private static String getAppIngress() {
|
||||
return "app/watcher-ingress.yaml";
|
||||
}
|
||||
|
||||
private static String getAppService() {
|
||||
return "app/watcher-service.yaml";
|
||||
List<V1EnvVar> existing = new ArrayList<>(
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getEnv());
|
||||
existing.add(one);
|
||||
existing.add(two);
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setEnv(existing);
|
||||
util.createAndWait(NAMESPACE_DEFAULT, null, deployment, service, ingress, true);
|
||||
}
|
||||
else if (phase.equals(Phase.DELETE)) {
|
||||
util.deleteAndWait(NAMESPACE_DEFAULT, deployment, service, ingress);
|
||||
}
|
||||
}
|
||||
|
||||
private WebClient.Builder builder() {
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
apiVersion: v1
|
||||
data:
|
||||
application.yaml: |-
|
||||
my:
|
||||
config:
|
||||
myProperty: from-config-map
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: spring-cloud-kubernetes-client-config-it
|
||||
@@ -1,29 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
app: spring-cloud-kubernetes-client-config-it
|
||||
name: spring-cloud-kubernetes-client-config-it-deployment
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: spring-cloud-kubernetes-client-config-it
|
||||
strategy: {}
|
||||
template:
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
app: spring-cloud-kubernetes-client-config-it
|
||||
spec:
|
||||
serviceAccountName: spring-cloud-kubernetes-serviceaccount
|
||||
containers:
|
||||
- image: springcloud/spring-cloud-kubernetes-client-config-it:3.0.0-SNAPSHOT
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: spring-cloud-kubernetes-client-config-it
|
||||
resources: {}
|
||||
env:
|
||||
- name: SPRING_PROFILES_ACTIVE
|
||||
value: kubernetes
|
||||
status: {}
|
||||
@@ -1,31 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
app: spring-cloud-kubernetes-client-config-it
|
||||
name: spring-cloud-kubernetes-client-config-it-deployment
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: spring-cloud-kubernetes-client-config-it
|
||||
strategy: {}
|
||||
template:
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
app: spring-cloud-kubernetes-client-config-it
|
||||
spec:
|
||||
serviceAccountName: spring-cloud-kubernetes-serviceaccount
|
||||
containers:
|
||||
- image: springcloud/spring-cloud-kubernetes-client-config-it:3.0.0-SNAPSHOT
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: spring-cloud-kubernetes-client-config-it
|
||||
resources: {}
|
||||
env:
|
||||
- name: SPRING_PROFILES_ACTIVE
|
||||
value: kubernetes
|
||||
- name: SPRING_CLOUD_KUBERNETES_RELOAD_MODE
|
||||
value: polling
|
||||
status: {}
|
||||
@@ -1,7 +0,0 @@
|
||||
apiVersion: v1
|
||||
data:
|
||||
my.config.mySecret: cDQ1NXcwcmQ=
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: spring-cloud-kubernetes-client-config-it
|
||||
type: Opaque
|
||||
@@ -1,18 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
app: spring-cloud-kubernetes-client-config-it
|
||||
name: spring-cloud-kubernetes-client-config-it
|
||||
spec:
|
||||
ports:
|
||||
- name: 80-8080
|
||||
port: 80
|
||||
protocol: TCP
|
||||
targetPort: 8080
|
||||
selector:
|
||||
app: spring-cloud-kubernetes-client-config-it
|
||||
type: ClusterIP
|
||||
status:
|
||||
loadBalancer: {}
|
||||
@@ -1,33 +0,0 @@
|
||||
apiVersion: skaffold/v2alpha3
|
||||
kind: Config
|
||||
metadata:
|
||||
name: spring-cloud-kubernetes-client-config-it
|
||||
build:
|
||||
artifacts:
|
||||
- image: springcloud/spring-cloud-kubernetes-client-config-it
|
||||
custom:
|
||||
buildCommand: "../../mvnw clean install -Pskaffold"
|
||||
dependencies:
|
||||
paths:
|
||||
- src
|
||||
- pom.xml
|
||||
|
||||
profiles:
|
||||
- name: polling
|
||||
deploy:
|
||||
kubectl:
|
||||
manifests:
|
||||
- k8s/deployment-polling-it.yaml
|
||||
- k8s/service-it.yaml
|
||||
- k8s/configmap.yaml
|
||||
- k8s/secret.yaml
|
||||
- ../permissions.yaml
|
||||
|
||||
deploy:
|
||||
kubectl:
|
||||
manifests:
|
||||
- k8s/deployment-it.yaml
|
||||
- k8s/service-it.yaml
|
||||
- k8s/configmap.yaml
|
||||
- k8s/secret.yaml
|
||||
- ../permissions.yaml
|
||||
@@ -17,36 +17,38 @@
|
||||
package org.springframework.cloud.kubernetes.client.config.it;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import io.kubernetes.client.openapi.apis.AppsV1Api;
|
||||
import io.kubernetes.client.openapi.ApiException;
|
||||
import io.kubernetes.client.openapi.apis.CoreV1Api;
|
||||
import io.kubernetes.client.openapi.apis.NetworkingV1Api;
|
||||
import io.kubernetes.client.openapi.models.V1ConfigMap;
|
||||
import io.kubernetes.client.openapi.models.V1Deployment;
|
||||
import io.kubernetes.client.openapi.models.V1EnvVar;
|
||||
import io.kubernetes.client.openapi.models.V1EnvVarBuilder;
|
||||
import io.kubernetes.client.openapi.models.V1Ingress;
|
||||
import io.kubernetes.client.openapi.models.V1Secret;
|
||||
import io.kubernetes.client.openapi.models.V1Service;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.k3s.K3sContainer;
|
||||
import org.testcontainers.shaded.org.awaitility.Awaitility;
|
||||
import reactor.netty.http.client.HttpClient;
|
||||
import reactor.util.retry.Retry;
|
||||
import reactor.util.retry.RetryBackoffSpec;
|
||||
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Commons;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Phase;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.native_client.Util;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils.createApiClient;
|
||||
import static org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils.getPomVersion;
|
||||
import static org.awaitility.Awaitility.await;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
@@ -57,37 +59,26 @@ class ConfigMapAndSecretIT {
|
||||
|
||||
private static final String SECRET_URL = "localhost:80/mySecret";
|
||||
|
||||
private static final String SPRING_CLOUD_CLIENT_CONFIG_IT_DEPLOYMENT_NAME = "spring-cloud-kubernetes-client-config-it-deployment";
|
||||
|
||||
private static final String K8S_CONFIG_CLIENT_IT_NAME = "spring-cloud-kubernetes-client-config-it-deployment";
|
||||
|
||||
private static final String K8S_CONFIG_CLIENT_IT_SERVICE_NAME = "spring-cloud-kubernetes-client-config-it";
|
||||
|
||||
private static final String NAMESPACE = "default";
|
||||
|
||||
private static final String APP_NAME = "spring-cloud-kubernetes-client-config-it";
|
||||
|
||||
private static CoreV1Api api;
|
||||
|
||||
private static AppsV1Api appsApi;
|
||||
|
||||
private static NetworkingV1Api networkingApi;
|
||||
|
||||
private static K8SUtils k8SUtils;
|
||||
|
||||
private static final K3sContainer K3S = Commons.container();
|
||||
|
||||
private static Util util;
|
||||
|
||||
private static CoreV1Api coreV1Api;
|
||||
|
||||
@BeforeAll
|
||||
static void setup() throws Exception {
|
||||
K3S.start();
|
||||
Commons.validateImage(K8S_CONFIG_CLIENT_IT_SERVICE_NAME, K3S);
|
||||
Commons.loadSpringCloudKubernetesImage(K8S_CONFIG_CLIENT_IT_SERVICE_NAME, K3S);
|
||||
createApiClient(K3S.getKubeConfigYaml());
|
||||
api = new CoreV1Api();
|
||||
appsApi = new AppsV1Api();
|
||||
networkingApi = new NetworkingV1Api();
|
||||
k8SUtils = new K8SUtils(api, appsApi);
|
||||
k8SUtils.setUp(NAMESPACE);
|
||||
util = new Util(K3S);
|
||||
coreV1Api = new CoreV1Api();
|
||||
util.setUp(NAMESPACE);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
@@ -96,117 +87,93 @@ class ConfigMapAndSecretIT {
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void after() throws Exception {
|
||||
appsApi.deleteCollectionNamespacedDeployment(NAMESPACE, null, null, null,
|
||||
"metadata.name=" + K8S_CONFIG_CLIENT_IT_NAME, null, null, null, null, null, null, null, null, null);
|
||||
api.deleteNamespacedService(K8S_CONFIG_CLIENT_IT_SERVICE_NAME, NAMESPACE, null, null, null, null, null, null);
|
||||
networkingApi.deleteNamespacedIngress("it-ingress", NAMESPACE, null, null, null, null, null, null);
|
||||
api.deleteNamespacedConfigMap(APP_NAME, NAMESPACE, null, null, null, null, null, null);
|
||||
api.deleteNamespacedSecret(APP_NAME, NAMESPACE, null, null, null, null, null, null);
|
||||
void after() {
|
||||
configK8sClientIt(false, Phase.DELETE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testConfigMapAndSecretWatchRefresh() throws Exception {
|
||||
deployConfigK8sClientIt();
|
||||
|
||||
// Check to make sure the controller deployment is ready
|
||||
k8SUtils.waitForDeployment(SPRING_CLOUD_CLIENT_CONFIG_IT_DEPLOYMENT_NAME, NAMESPACE);
|
||||
void testConfigMapAndSecretWatchRefresh() {
|
||||
configK8sClientIt(false, Phase.CREATE);
|
||||
testConfigMapAndSecretRefresh();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testConfigMapAndSecretPollingRefresh() throws Exception {
|
||||
deployConfigK8sClientPollingIt();
|
||||
|
||||
// Check to make sure the controller deployment is ready
|
||||
k8SUtils.waitForDeployment(SPRING_CLOUD_CLIENT_CONFIG_IT_DEPLOYMENT_NAME, NAMESPACE);
|
||||
void testConfigMapAndSecretPollingRefresh() {
|
||||
configK8sClientIt(true, Phase.CREATE);
|
||||
testConfigMapAndSecretRefresh();
|
||||
}
|
||||
|
||||
void testConfigMapAndSecretRefresh() throws Exception {
|
||||
/**
|
||||
* <pre>
|
||||
* - read configmap/secrets the way we initially build them and assert their values
|
||||
* - replace the above and assert we get the new values.
|
||||
* </pre>
|
||||
*/
|
||||
void testConfigMapAndSecretRefresh() {
|
||||
|
||||
WebClient.Builder builder = builder();
|
||||
WebClient propertyClient = builder.baseUrl(PROPERTY_URL).build();
|
||||
|
||||
String property = propertyClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class)
|
||||
.retryWhen(retrySpec()).block();
|
||||
assertThat(property).isEqualTo("from-config-map");
|
||||
await().timeout(Duration.ofSeconds(60)).pollInterval(Duration.ofSeconds(2)).until(() -> propertyClient
|
||||
.method(HttpMethod.GET).retrieve().bodyToMono(String.class).block().equals("from-config-map"));
|
||||
|
||||
WebClient secretClient = builder.baseUrl(SECRET_URL).build();
|
||||
String secret = secretClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class).retryWhen(retrySpec())
|
||||
.block();
|
||||
assertThat(secret).isEqualTo("p455w0rd");
|
||||
Assertions.assertEquals(secret, "p455w0rd");
|
||||
|
||||
V1ConfigMap configMap = getConfigK8sClientItConfigMap();
|
||||
V1ConfigMap configMap = (V1ConfigMap) util.yaml("spring-cloud-kubernetes-client-config-it-configmap.yaml");
|
||||
Map<String, String> data = configMap.getData();
|
||||
data.replace("application.yaml", data.get("application.yaml").replace("from-config-map", "from-unit-test"));
|
||||
configMap.data(data);
|
||||
api.replaceNamespacedConfigMap(APP_NAME, NAMESPACE, configMap, null, null, null, null);
|
||||
Awaitility.await().timeout(Duration.ofSeconds(60)).pollInterval(Duration.ofSeconds(2))
|
||||
.until(() -> propertyClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class).block()
|
||||
.equals("from-unit-test"));
|
||||
V1Secret v1Secret = getConfigK8sClientItCSecret();
|
||||
try {
|
||||
coreV1Api.replaceNamespacedConfigMap(APP_NAME, NAMESPACE, configMap, null, null, null, null);
|
||||
}
|
||||
catch (ApiException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
await().timeout(Duration.ofSeconds(60)).pollInterval(Duration.ofSeconds(2)).until(() -> propertyClient
|
||||
.method(HttpMethod.GET).retrieve().bodyToMono(String.class).block().equals("from-unit-test"));
|
||||
V1Secret v1Secret = (V1Secret) util.yaml("spring-cloud-kubernetes-client-config-it-secret.yaml");
|
||||
Map<String, byte[]> secretData = v1Secret.getData();
|
||||
secretData.replace("my.config.mySecret", "p455w1rd".getBytes());
|
||||
v1Secret.setData(secretData);
|
||||
api.replaceNamespacedSecret(APP_NAME, NAMESPACE, v1Secret, null, null, null, null);
|
||||
Awaitility.await().timeout(Duration.ofSeconds(60)).pollInterval(Duration.ofSeconds(2)).until(() -> secretClient
|
||||
try {
|
||||
coreV1Api.replaceNamespacedSecret(APP_NAME, NAMESPACE, v1Secret, null, null, null, null);
|
||||
}
|
||||
catch (ApiException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
await().timeout(Duration.ofSeconds(60)).pollInterval(Duration.ofSeconds(2)).until(() -> secretClient
|
||||
.method(HttpMethod.GET).retrieve().bodyToMono(String.class).block().equals("p455w1rd"));
|
||||
}
|
||||
|
||||
private static void deployConfigK8sClientIt() throws Exception {
|
||||
k8SUtils.waitForDeploymentToBeDeleted(K8S_CONFIG_CLIENT_IT_NAME, NAMESPACE);
|
||||
api.createNamespacedSecret(NAMESPACE, getConfigK8sClientItCSecret(), null, null, null, null);
|
||||
api.createNamespacedConfigMap(NAMESPACE, getConfigK8sClientItConfigMap(), null, null, null, null);
|
||||
appsApi.createNamespacedDeployment(NAMESPACE, getConfigK8sClientItDeployment(), null, null, null, null);
|
||||
api.createNamespacedService(NAMESPACE, getConfigK8sClientItService(), null, null, null, null);
|
||||
private static void configK8sClientIt(boolean pooling, Phase phase) {
|
||||
V1Deployment deployment = (V1Deployment) util.yaml("spring-cloud-kubernetes-client-config-it-deployment.yaml");
|
||||
|
||||
V1Ingress ingress = getConfigK8sClientItIngress();
|
||||
networkingApi.createNamespacedIngress(NAMESPACE, ingress, null, null, null, null);
|
||||
k8SUtils.waitForIngress(ingress.getMetadata().getName(), NAMESPACE);
|
||||
}
|
||||
if (pooling) {
|
||||
V1EnvVar one = new V1EnvVarBuilder().withName("SPRING_CLOUD_KUBERNETES_RELOAD_MODE").withValue("polling")
|
||||
.build();
|
||||
List<V1EnvVar> existing = new ArrayList<>(
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getEnv());
|
||||
existing.add(one);
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setEnv(existing);
|
||||
}
|
||||
|
||||
private static void deployConfigK8sClientPollingIt() throws Exception {
|
||||
k8SUtils.waitForDeploymentToBeDeleted(K8S_CONFIG_CLIENT_IT_NAME, NAMESPACE);
|
||||
api.createNamespacedSecret(NAMESPACE, getConfigK8sClientItCSecret(), null, null, null, null);
|
||||
api.createNamespacedConfigMap(NAMESPACE, getConfigK8sClientItConfigMap(), null, null, null, null);
|
||||
appsApi.createNamespacedDeployment(NAMESPACE, getConfigK8sClientItPollingDeployment(), null, null, null, null);
|
||||
api.createNamespacedService(NAMESPACE, getConfigK8sClientItService(), null, null, null, null);
|
||||
networkingApi.createNamespacedIngress(NAMESPACE, getConfigK8sClientItIngress(), null, null, null, null);
|
||||
}
|
||||
V1Service service = (V1Service) util.yaml("spring-cloud-kubernetes-client-config-it-service.yaml");
|
||||
V1Ingress ingress = (V1Ingress) util.yaml("spring-cloud-kubernetes-client-config-it-ingress.yaml");
|
||||
|
||||
private static V1Deployment getConfigK8sClientItDeployment() throws Exception {
|
||||
V1Deployment deployment = (V1Deployment) K8SUtils
|
||||
.readYamlFromClasspath("spring-cloud-kubernetes-client-config-it-deployment.yaml");
|
||||
String image = deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getImage() + ":"
|
||||
+ getPomVersion();
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setImage(image);
|
||||
return deployment;
|
||||
}
|
||||
V1ConfigMap configMap = (V1ConfigMap) util.yaml("spring-cloud-kubernetes-client-config-it-configmap.yaml");
|
||||
V1Secret secret = (V1Secret) util.yaml("spring-cloud-kubernetes-client-config-it-secret.yaml");
|
||||
|
||||
private static V1Deployment getConfigK8sClientItPollingDeployment() throws Exception {
|
||||
V1Deployment deployment = (V1Deployment) K8SUtils
|
||||
.readYamlFromClasspath("spring-cloud-kubernetes-client-config-it-polling-deployment.yaml");
|
||||
String image = deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getImage() + ":"
|
||||
+ getPomVersion();
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setImage(image);
|
||||
return deployment;
|
||||
}
|
||||
|
||||
private static V1Service getConfigK8sClientItService() throws Exception {
|
||||
return (V1Service) K8SUtils.readYamlFromClasspath("spring-cloud-kubernetes-client-config-it-service.yaml");
|
||||
}
|
||||
|
||||
private static V1Ingress getConfigK8sClientItIngress() throws Exception {
|
||||
return (V1Ingress) K8SUtils.readYamlFromClasspath("spring-cloud-kubernetes-client-config-it-ingress.yaml");
|
||||
}
|
||||
|
||||
private static V1ConfigMap getConfigK8sClientItConfigMap() throws Exception {
|
||||
return (V1ConfigMap) K8SUtils.readYamlFromClasspath("spring-cloud-kubernetes-client-config-it-configmap.yaml");
|
||||
}
|
||||
|
||||
private static V1Secret getConfigK8sClientItCSecret() throws Exception {
|
||||
return (V1Secret) K8SUtils.readYamlFromClasspath("spring-cloud-kubernetes-client-config-it-secret.yaml");
|
||||
if (phase.equals(Phase.CREATE)) {
|
||||
util.createAndWait(NAMESPACE, null, deployment, service, ingress, true);
|
||||
util.createAndWait(NAMESPACE, configMap, secret);
|
||||
}
|
||||
else if (phase.equals(Phase.DELETE)) {
|
||||
util.deleteAndWait(NAMESPACE, deployment, service, ingress);
|
||||
util.deleteAndWait(NAMESPACE, configMap, secret);
|
||||
}
|
||||
}
|
||||
|
||||
private WebClient.Builder builder() {
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: spring-cloud-kubernetes-client-config-it-deployment
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: spring-cloud-kubernetes-client-config-it
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: spring-cloud-kubernetes-client-config-it
|
||||
spec:
|
||||
serviceAccountName: spring-cloud-kubernetes-serviceaccount
|
||||
containers:
|
||||
- name: spring-cloud-kubernetes-client-config-it
|
||||
image: docker.io/springcloud/spring-cloud-kubernetes-client-config-it
|
||||
imagePullPolicy: IfNotPresent
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
port: 8080
|
||||
path: /actuator/health/readiness
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
port: 8080
|
||||
path: /actuator/health/liveness
|
||||
env:
|
||||
- name: SPRING_PROFILES_ACTIVE
|
||||
value: kubernetes
|
||||
- name: SPRING_CLOUD_KUBERNETES_RELOAD_MODE
|
||||
value: polling
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
@@ -18,11 +18,6 @@
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.vintage</groupId>
|
||||
<artifactId>junit-vintage-engine</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-kubernetes-test-support</artifactId>
|
||||
|
||||
@@ -18,19 +18,15 @@ package org.springframework.cloud.kubernetes.configuration.watcher.multiple.apps
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import io.kubernetes.client.openapi.apis.AppsV1Api;
|
||||
import io.kubernetes.client.openapi.apis.CoreV1Api;
|
||||
import io.kubernetes.client.openapi.apis.NetworkingV1Api;
|
||||
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.V1Ingress;
|
||||
import io.kubernetes.client.openapi.models.V1Service;
|
||||
import org.assertj.core.api.Assertions;
|
||||
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;
|
||||
@@ -40,14 +36,13 @@ import reactor.util.retry.Retry;
|
||||
import reactor.util.retry.RetryBackoffSpec;
|
||||
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Commons;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Phase;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.native_client.Util;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import static org.awaitility.Awaitility.await;
|
||||
import static org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils.createApiClient;
|
||||
import static org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils.getPomVersion;
|
||||
|
||||
/**
|
||||
* @author wind57
|
||||
@@ -58,39 +53,20 @@ class ConfigurationWatcherMultipleAppsIT {
|
||||
|
||||
private static final String CONFIG_WATCHER_APP_B_IMAGE = "spring-cloud-kubernetes-client-configuration-watcher-configmap-app-b";
|
||||
|
||||
private static final String CONFIG_WATCHER_DEPLOYMENT_APP_A_NAME = "app-a-deployment";
|
||||
|
||||
private static final String CONFIG_WATCHER_DEPLOYMENT_APP_B_NAME = "app-b-deployment";
|
||||
|
||||
private static final String SPRING_CLOUD_K8S_CONFIG_WATCHER_DEPLOYMENT_NAME = "spring-cloud-kubernetes-configuration-watcher-deployment";
|
||||
|
||||
private static final String SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME = "spring-cloud-kubernetes-configuration-watcher";
|
||||
|
||||
private static final String CONFIG_MAP_NAME = "multiple-apps";
|
||||
|
||||
private static final String NAMESPACE = "default";
|
||||
|
||||
private static final String KAFKA_BROKER = "kafka-broker";
|
||||
|
||||
private static final String KAFKA_SERVICE = "kafka";
|
||||
|
||||
private static final String ZOOKEEPER_SERVICE = "zookeeper";
|
||||
|
||||
private static final String ZOOKEEPER_DEPLOYMENT = "zookeeper";
|
||||
|
||||
private static CoreV1Api api;
|
||||
|
||||
private static AppsV1Api appsApi;
|
||||
|
||||
private static NetworkingV1Api networkingApi;
|
||||
|
||||
private static K8SUtils k8SUtils;
|
||||
|
||||
private static final K3sContainer K3S = Commons.container();
|
||||
|
||||
private static Util util;
|
||||
|
||||
@BeforeAll
|
||||
static void beforeAll() throws Exception {
|
||||
K3S.start();
|
||||
util = new Util(K3S);
|
||||
|
||||
Commons.validateImage(SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME, K3S);
|
||||
Commons.loadSpringCloudKubernetesImage(SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME, K3S);
|
||||
@@ -101,12 +77,8 @@ class ConfigurationWatcherMultipleAppsIT {
|
||||
Commons.validateImage(CONFIG_WATCHER_APP_B_IMAGE, K3S);
|
||||
Commons.loadSpringCloudKubernetesImage(CONFIG_WATCHER_APP_B_IMAGE, K3S);
|
||||
|
||||
createApiClient(K3S.getKubeConfigYaml());
|
||||
api = new CoreV1Api();
|
||||
appsApi = new AppsV1Api();
|
||||
k8SUtils = new K8SUtils(api, appsApi);
|
||||
networkingApi = new NetworkingV1Api();
|
||||
k8SUtils.setUp(NAMESPACE);
|
||||
util = new Util(K3S);
|
||||
util.setUp(NAMESPACE);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
@@ -117,41 +89,25 @@ class ConfigurationWatcherMultipleAppsIT {
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void setup() throws Exception {
|
||||
|
||||
deployZookeeper();
|
||||
deployKafka();
|
||||
deployAppA();
|
||||
deployAppB();
|
||||
deployIngress();
|
||||
deployConfigWatcher();
|
||||
|
||||
waitForDeployment(ZOOKEEPER_DEPLOYMENT);
|
||||
waitForDeployment(KAFKA_BROKER);
|
||||
waitForDeployment(CONFIG_WATCHER_DEPLOYMENT_APP_A_NAME);
|
||||
waitForDeployment(CONFIG_WATCHER_DEPLOYMENT_APP_B_NAME);
|
||||
waitForDeployment(SPRING_CLOUD_K8S_CONFIG_WATCHER_DEPLOYMENT_NAME);
|
||||
void setup() {
|
||||
util.zookeeper(NAMESPACE, Phase.CREATE);
|
||||
util.kafka(NAMESPACE, Phase.CREATE);
|
||||
appA(Phase.CREATE);
|
||||
appB(Phase.CREATE);
|
||||
configWatcher(Phase.CREATE);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void after() throws Exception {
|
||||
|
||||
cleanUpKafka();
|
||||
cleanUpZookeeper();
|
||||
cleanUpServices();
|
||||
cleanUpDeployments();
|
||||
cleanUpIngress();
|
||||
cleanUpConfigMaps();
|
||||
|
||||
k8SUtils.waitForDeploymentToBeDeleted(KAFKA_BROKER, NAMESPACE);
|
||||
k8SUtils.waitForDeploymentToBeDeleted(ZOOKEEPER_DEPLOYMENT, NAMESPACE);
|
||||
k8SUtils.waitForDeploymentToBeDeleted(SPRING_CLOUD_K8S_CONFIG_WATCHER_DEPLOYMENT_NAME, NAMESPACE);
|
||||
k8SUtils.waitForDeploymentToBeDeleted(CONFIG_WATCHER_DEPLOYMENT_APP_A_NAME, NAMESPACE);
|
||||
k8SUtils.waitForDeploymentToBeDeleted(CONFIG_WATCHER_DEPLOYMENT_APP_B_NAME, NAMESPACE);
|
||||
void afterEach() {
|
||||
util.zookeeper(NAMESPACE, Phase.DELETE);
|
||||
util.kafka(NAMESPACE, Phase.DELETE);
|
||||
appA(Phase.DELETE);
|
||||
appB(Phase.DELETE);
|
||||
configWatcher(Phase.DELETE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRefresh() throws Exception {
|
||||
void testRefresh() {
|
||||
|
||||
// configmap has one label, one that says that we should refresh
|
||||
// and one annotation that says that we should refresh some specific services
|
||||
@@ -161,7 +117,7 @@ class ConfigurationWatcherMultipleAppsIT {
|
||||
"spring-cloud-kubernetes-client-configuration-watcher-configmap-app-a, "
|
||||
+ "spring-cloud-kubernetes-client-configuration-watcher-configmap-app-b")
|
||||
.endMetadata().addToData("foo", "hello world").build();
|
||||
api.createNamespacedConfigMap(NAMESPACE, configMap, null, null, null, null);
|
||||
util.createAndWait(NAMESPACE, configMap, null);
|
||||
|
||||
WebClient.Builder builderA = builder();
|
||||
WebClient serviceClientA = builderA.baseUrl("http://localhost:80/app-a").build();
|
||||
@@ -176,7 +132,7 @@ class ConfigurationWatcherMultipleAppsIT {
|
||||
return valueA[0];
|
||||
});
|
||||
|
||||
Assertions.assertThat(valueA[0]).isTrue();
|
||||
Assertions.assertTrue(valueA[0]);
|
||||
|
||||
Boolean[] valueB = new Boolean[1];
|
||||
await().pollInterval(Duration.ofSeconds(3)).atMost(Duration.ofSeconds(240)).until(() -> {
|
||||
@@ -185,191 +141,48 @@ class ConfigurationWatcherMultipleAppsIT {
|
||||
return valueB[0];
|
||||
});
|
||||
|
||||
Assertions.assertThat(valueB[0]).isTrue();
|
||||
Assertions.assertTrue(valueB[0]);
|
||||
util.deleteAndWait(NAMESPACE, configMap, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
--------------------------------------------------- zookeeper ----------------------------------------------
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
</pre>
|
||||
*/
|
||||
private void deployZookeeper() throws Exception {
|
||||
api.createNamespacedService(NAMESPACE, getZookeeperService(), null, null, null, null);
|
||||
V1Deployment deployment = getZookeeperDeployment();
|
||||
String[] image = K8SUtils.getImageFromDeployment(deployment).split(":");
|
||||
Commons.pullImage(image[0], image[1], K3S);
|
||||
Commons.loadImage(image[0], image[1], "zookeeper", K3S);
|
||||
appsApi.createNamespacedDeployment(NAMESPACE, deployment, null, null, null, null);
|
||||
private void appA(Phase phase) {
|
||||
V1Deployment deployment = (V1Deployment) util.yaml("app-a/app-a-deployment.yaml");
|
||||
V1Service service = (V1Service) util.yaml("app-a/app-a-service.yaml");
|
||||
V1Ingress ingress = (V1Ingress) util
|
||||
.yaml("ingress/spring-cloud-kubernetes-configuration-watcher-multiple-apps-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);
|
||||
}
|
||||
}
|
||||
|
||||
private V1Deployment getZookeeperDeployment() throws Exception {
|
||||
return (V1Deployment) K8SUtils.readYamlFromClasspath("zookeeper/zookeeper-deployment.yaml");
|
||||
private void appB(Phase phase) {
|
||||
V1Deployment deployment = (V1Deployment) util.yaml("app-b/app-b-deployment.yaml");
|
||||
V1Service service = (V1Service) util.yaml("app-b/app-b-service.yaml");
|
||||
|
||||
if (phase.equals(Phase.CREATE)) {
|
||||
util.createAndWait(NAMESPACE, null, deployment, service, null, true);
|
||||
}
|
||||
else if (phase.equals(Phase.DELETE)) {
|
||||
util.deleteAndWait(NAMESPACE, deployment, service, null);
|
||||
}
|
||||
}
|
||||
|
||||
private V1Service getZookeeperService() throws Exception {
|
||||
return (V1Service) K8SUtils.readYamlFromClasspath("zookeeper/zookeeper-service.yaml");
|
||||
}
|
||||
private void configWatcher(Phase phase) {
|
||||
V1Deployment deployment = (V1Deployment) util
|
||||
.yaml("config-watcher/spring-cloud-kubernetes-configuration-watcher-bus-kafka-deployment.yaml");
|
||||
V1Service service = (V1Service) util
|
||||
.yaml("config-watcher/spring-cloud-kubernetes-configuration-watcher-service.yaml");
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
----------------------------------------------------- kafka ------------------------------------------------
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
</pre>
|
||||
*/
|
||||
private void deployKafka() throws Exception {
|
||||
api.createNamespacedService(NAMESPACE, getKafkaService(), null, null, null, null);
|
||||
V1Deployment deployment = getKafkaDeployment();
|
||||
String[] image = K8SUtils.getImageFromDeployment(deployment).split(":");
|
||||
Commons.pullImage(image[0], image[1], K3S);
|
||||
Commons.loadImage(image[0], image[1], "kafka", K3S);
|
||||
appsApi.createNamespacedDeployment(NAMESPACE, getKafkaDeployment(), null, null, null, null);
|
||||
}
|
||||
|
||||
private V1Deployment getKafkaDeployment() throws Exception {
|
||||
return (V1Deployment) K8SUtils.readYamlFromClasspath("kafka/kafka-deployment.yaml");
|
||||
}
|
||||
|
||||
private V1Service getKafkaService() throws Exception {
|
||||
return (V1Service) K8SUtils.readYamlFromClasspath("kafka/kafka-service.yaml");
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
----------------------------------------------------- app-a ------------------------------------------------
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
</pre>
|
||||
*/
|
||||
private void deployAppA() throws Exception {
|
||||
appsApi.createNamespacedDeployment(NAMESPACE, getAppADeployment(), null, null, null, null);
|
||||
api.createNamespacedService(NAMESPACE, getAppAService(), null, null, null, null);
|
||||
}
|
||||
|
||||
private V1Deployment getAppADeployment() throws Exception {
|
||||
String urlString = "app-a/app-a-deployment.yaml";
|
||||
V1Deployment deployment = (V1Deployment) K8SUtils.readYamlFromClasspath(urlString);
|
||||
String image = K8SUtils.getImageFromDeployment(deployment) + ":" + getPomVersion();
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setImage(image);
|
||||
return deployment;
|
||||
}
|
||||
|
||||
private V1Service getAppAService() throws Exception {
|
||||
return (V1Service) K8SUtils.readYamlFromClasspath("app-a/app-a-service.yaml");
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
--------------------------------------------------- app-b --------------------------------------------------
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
</pre>
|
||||
*/
|
||||
private void deployAppB() throws Exception {
|
||||
appsApi.createNamespacedDeployment(NAMESPACE, getAppBDeployment(), null, null, null, null);
|
||||
api.createNamespacedService(NAMESPACE, getAppBService(), null, null, null, null);
|
||||
}
|
||||
|
||||
private V1Deployment getAppBDeployment() throws Exception {
|
||||
String urlString = "app-b/app-b-deployment.yaml";
|
||||
V1Deployment deployment = (V1Deployment) K8SUtils.readYamlFromClasspath(urlString);
|
||||
String image = K8SUtils.getImageFromDeployment(deployment) + ":" + getPomVersion();
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setImage(image);
|
||||
return deployment;
|
||||
}
|
||||
|
||||
private V1Service getAppBService() throws Exception {
|
||||
return (V1Service) K8SUtils.readYamlFromClasspath("app-b/app-b-service.yaml");
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
------------------------------------------------ config-watcher --------------------------------------------
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
</pre>
|
||||
*/
|
||||
private void deployConfigWatcher() throws Exception {
|
||||
appsApi.createNamespacedDeployment(NAMESPACE, getConfigWatcherDeployment(), null, null, null, null);
|
||||
api.createNamespacedService(NAMESPACE, getConfigWatcherService(), null, null, null, null);
|
||||
}
|
||||
|
||||
private V1Deployment getConfigWatcherDeployment() throws Exception {
|
||||
V1Deployment deployment = (V1Deployment) K8SUtils.readYamlFromClasspath(
|
||||
"config-watcher/spring-cloud-kubernetes-configuration-watcher-bus-kafka-deployment.yaml");
|
||||
String image = K8SUtils.getImageFromDeployment(deployment) + ":" + getPomVersion();
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setImage(image);
|
||||
return deployment;
|
||||
}
|
||||
|
||||
private V1Service getConfigWatcherService() throws Exception {
|
||||
return (V1Service) K8SUtils
|
||||
.readYamlFromClasspath("config-watcher/spring-cloud-kubernetes-configuration-watcher-service.yaml");
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
------------------------------------------------ common ----------------------------------------------------
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
</pre>
|
||||
*/
|
||||
|
||||
private void deployIngress() throws Exception {
|
||||
V1Ingress ingress = (V1Ingress) K8SUtils.readYamlFromClasspath(
|
||||
"ingress/spring-cloud-kubernetes-configuration-watcher-multiple-apps-ingress.yaml");
|
||||
|
||||
networkingApi.createNamespacedIngress(NAMESPACE, ingress, null, null, null, null);
|
||||
k8SUtils.waitForIngress(ingress.getMetadata().getName(), NAMESPACE);
|
||||
}
|
||||
|
||||
private void waitForDeployment(String deploymentName) {
|
||||
await().pollInterval(Duration.ofSeconds(3)).atMost(600, TimeUnit.SECONDS)
|
||||
.until(() -> k8SUtils.isDeploymentReady(deploymentName, NAMESPACE));
|
||||
}
|
||||
|
||||
private void cleanUpKafka() throws Exception {
|
||||
appsApi.deleteNamespacedDeployment(KAFKA_BROKER, NAMESPACE, null, null, null, null, null, null);
|
||||
api.deleteNamespacedService(KAFKA_SERVICE, NAMESPACE, null, null, null, null, null, null);
|
||||
}
|
||||
|
||||
private void cleanUpZookeeper() throws Exception {
|
||||
appsApi.deleteNamespacedDeployment(ZOOKEEPER_DEPLOYMENT, NAMESPACE, null, null, null, null, null, null);
|
||||
api.deleteNamespacedService(ZOOKEEPER_SERVICE, NAMESPACE, null, null, null, null, null, null);
|
||||
}
|
||||
|
||||
private void cleanUpServices() throws Exception {
|
||||
api.deleteNamespacedService("app-a", NAMESPACE, null, null, null, null, null, null);
|
||||
api.deleteNamespacedService("app-b", NAMESPACE, null, null, null, null, null, null);
|
||||
api.deleteNamespacedService(SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME, NAMESPACE, null, null, null, null, null,
|
||||
null);
|
||||
}
|
||||
|
||||
private void cleanUpDeployments() throws Exception {
|
||||
appsApi.deleteNamespacedDeployment(SPRING_CLOUD_K8S_CONFIG_WATCHER_DEPLOYMENT_NAME, NAMESPACE, null, null, null,
|
||||
null, null, null);
|
||||
appsApi.deleteNamespacedDeployment(CONFIG_WATCHER_DEPLOYMENT_APP_A_NAME, NAMESPACE, null, null, null, null,
|
||||
null, null);
|
||||
|
||||
appsApi.deleteNamespacedDeployment(CONFIG_WATCHER_DEPLOYMENT_APP_B_NAME, NAMESPACE, null, null, null, null,
|
||||
null, null);
|
||||
}
|
||||
|
||||
private void cleanUpConfigMaps() throws Exception {
|
||||
api.deleteNamespacedConfigMap(CONFIG_MAP_NAME, NAMESPACE, null, null, null, null, null, null);
|
||||
}
|
||||
|
||||
private void cleanUpIngress() throws Exception {
|
||||
networkingApi.deleteNamespacedIngress("it-ingress-multiple-apps", NAMESPACE, null, null, null, null, null,
|
||||
null);
|
||||
if (phase.equals(Phase.CREATE)) {
|
||||
util.createAndWait(NAMESPACE, null, deployment, service, null, true);
|
||||
}
|
||||
else if (phase.equals(Phase.DELETE)) {
|
||||
util.deleteAndWait(NAMESPACE, deployment, service, null);
|
||||
}
|
||||
}
|
||||
|
||||
private WebClient.Builder builder() {
|
||||
|
||||
@@ -24,9 +24,7 @@ import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.LockSupport;
|
||||
|
||||
import io.kubernetes.client.openapi.ApiException;
|
||||
import io.kubernetes.client.openapi.apis.AppsV1Api;
|
||||
import io.kubernetes.client.openapi.apis.CoreV1Api;
|
||||
import io.kubernetes.client.openapi.apis.NetworkingV1Api;
|
||||
import io.kubernetes.client.openapi.models.V1ConfigMap;
|
||||
import io.kubernetes.client.openapi.models.V1ConfigMapBuilder;
|
||||
import io.kubernetes.client.openapi.models.V1Deployment;
|
||||
@@ -34,6 +32,7 @@ import io.kubernetes.client.openapi.models.V1Ingress;
|
||||
import io.kubernetes.client.openapi.models.V1ObjectMeta;
|
||||
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.Test;
|
||||
import org.testcontainers.k3s.K3sContainer;
|
||||
@@ -42,15 +41,13 @@ import reactor.util.retry.Retry;
|
||||
import reactor.util.retry.RetryBackoffSpec;
|
||||
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Commons;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Phase;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.native_client.Util;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.cloud.kubernetes.integration.tests.commons.Commons.processExecResult;
|
||||
import static org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils.createApiClient;
|
||||
import static org.testcontainers.shaded.org.awaitility.Awaitility.await;
|
||||
import static org.awaitility.Awaitility.await;
|
||||
|
||||
/**
|
||||
* @author wind57
|
||||
@@ -61,46 +58,28 @@ class ConfigMapEventReloadIT {
|
||||
|
||||
private static final String NAMESPACE = "default";
|
||||
|
||||
private static String deploymentName;
|
||||
private static final K3sContainer K3S = Commons.container();
|
||||
|
||||
private static String serviceName;
|
||||
|
||||
private static String ingressName;
|
||||
|
||||
private static String leftConfigMapName;
|
||||
|
||||
private static String rightConfigMapName;
|
||||
|
||||
private static String rightWithLabelConfigMapName;
|
||||
private static Util util;
|
||||
|
||||
private static CoreV1Api api;
|
||||
|
||||
private static AppsV1Api appsApi;
|
||||
|
||||
private static NetworkingV1Api networkingApi;
|
||||
|
||||
private static K8SUtils k8SUtils;
|
||||
|
||||
private static final K3sContainer K3S = Commons.container();
|
||||
|
||||
@BeforeAll
|
||||
static void beforeAll() throws Exception {
|
||||
K3S.start();
|
||||
Commons.validateImage(IMAGE_NAME, K3S);
|
||||
Commons.loadSpringCloudKubernetesImage(IMAGE_NAME, K3S);
|
||||
createApiClient(K3S.getKubeConfigYaml());
|
||||
createNamespaces();
|
||||
util = new Util(K3S);
|
||||
util.createNamespace("left");
|
||||
util.createNamespace("right");
|
||||
util.setUpClusterWide(NAMESPACE, Set.of("left", "right"));
|
||||
api = new CoreV1Api();
|
||||
appsApi = new AppsV1Api();
|
||||
networkingApi = new NetworkingV1Api();
|
||||
k8SUtils = new K8SUtils(api, appsApi);
|
||||
|
||||
k8SUtils.setUpClusterWide(NAMESPACE, Set.of("left", "right"));
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void afterAll() throws Exception {
|
||||
deleteNamespaces();
|
||||
util.deleteNamespace("left");
|
||||
util.deleteNamespace("right");
|
||||
Commons.cleanUp(IMAGE_NAME, K3S);
|
||||
}
|
||||
|
||||
@@ -114,19 +93,19 @@ class ConfigMapEventReloadIT {
|
||||
*/
|
||||
@Test
|
||||
void testInformFromOneNamespaceEventNotTriggered() throws Exception {
|
||||
deployManifests("one");
|
||||
manifests("one", Phase.CREATE);
|
||||
|
||||
WebClient webClient = builder().baseUrl("localhost/left").build();
|
||||
String result = webClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class).retryWhen(retrySpec())
|
||||
.block();
|
||||
|
||||
// we first read the initial value from the left-configmap
|
||||
assertThat("left-initial").isEqualTo(result);
|
||||
Assertions.assertEquals("left-initial", result);
|
||||
|
||||
// then read the value from the right-configmap
|
||||
webClient = builder().baseUrl("localhost/right").build();
|
||||
result = webClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class).retryWhen(retrySpec()).block();
|
||||
assertThat("right-initial").isEqualTo(result);
|
||||
Assertions.assertEquals("right-initial", result);
|
||||
|
||||
// then deploy a new version of right-configmap
|
||||
V1ConfigMap rightConfigMapAfterChange = new V1ConfigMapBuilder()
|
||||
@@ -141,9 +120,9 @@ class ConfigMapEventReloadIT {
|
||||
webClient = builder().baseUrl("localhost/left").build();
|
||||
result = webClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class).retryWhen(retrySpec()).block();
|
||||
// left configmap has not changed, no restart of app has happened
|
||||
assertThat("left-initial").isEqualTo(result);
|
||||
Assertions.assertEquals("left-initial", result);
|
||||
|
||||
deleteManifests();
|
||||
manifests("one", Phase.DELETE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -156,13 +135,13 @@ class ConfigMapEventReloadIT {
|
||||
*/
|
||||
@Test
|
||||
void testInformFromOneNamespaceEventTriggered() throws Exception {
|
||||
deployManifests("two");
|
||||
manifests("two", Phase.CREATE);
|
||||
|
||||
// read the value from the right-configmap
|
||||
WebClient webClient = builder().baseUrl("localhost/right").build();
|
||||
String result = webClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class).retryWhen(retrySpec())
|
||||
.block();
|
||||
assertThat("right-initial").isEqualTo(result);
|
||||
Assertions.assertEquals("right-initial", result);
|
||||
|
||||
// then deploy a new version of right-configmap
|
||||
V1ConfigMap rightConfigMapAfterChange = new V1ConfigMapBuilder()
|
||||
@@ -180,9 +159,9 @@ class ConfigMapEventReloadIT {
|
||||
resultAfterChange[0] = innerResult;
|
||||
return innerResult != null;
|
||||
});
|
||||
assertThat("right-after-change").isEqualTo(resultAfterChange[0]);
|
||||
Assertions.assertEquals("right-after-change", resultAfterChange[0]);
|
||||
|
||||
deleteManifests();
|
||||
manifests("two", Phase.DELETE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -196,19 +175,19 @@ class ConfigMapEventReloadIT {
|
||||
*/
|
||||
@Test
|
||||
void testInform() throws Exception {
|
||||
deployManifests("three");
|
||||
manifests("three", Phase.CREATE);
|
||||
|
||||
// read the initial value from the right-configmap
|
||||
WebClient rightWebClient = builder().baseUrl("localhost/right").build();
|
||||
String rightResult = rightWebClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class)
|
||||
.retryWhen(retrySpec()).block();
|
||||
assertThat("right-initial").isEqualTo(rightResult);
|
||||
Assertions.assertEquals("right-initial", rightResult);
|
||||
|
||||
// then read the initial value from the right-with-label-configmap
|
||||
WebClient rightWithLabelWebClient = builder().baseUrl("localhost/with-label").build();
|
||||
String rightWithLabelResult = rightWithLabelWebClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class)
|
||||
.retryWhen(retrySpec()).block();
|
||||
assertThat("right-with-label-initial").isEqualTo(rightWithLabelResult);
|
||||
Assertions.assertEquals("right-with-label-initial", rightWithLabelResult);
|
||||
|
||||
// then deploy a new version of right-configmap
|
||||
V1ConfigMap rightConfigMapAfterChange = new V1ConfigMapBuilder()
|
||||
@@ -223,7 +202,7 @@ class ConfigMapEventReloadIT {
|
||||
// nothing changes in our app, because we are watching only labeled configmaps
|
||||
rightResult = rightWebClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class).retryWhen(retrySpec())
|
||||
.block();
|
||||
assertThat("right-initial").isEqualTo(rightResult);
|
||||
Assertions.assertEquals("right-initial", rightResult);
|
||||
|
||||
// then deploy a new version of right-with-label-configmap
|
||||
V1ConfigMap rightWithLabelConfigMapAfterChange = new V1ConfigMapBuilder()
|
||||
@@ -242,62 +221,47 @@ class ConfigMapEventReloadIT {
|
||||
resultAfterChange[0] = innerResult;
|
||||
return innerResult != null;
|
||||
});
|
||||
assertThat("right-with-label-after-change").isEqualTo(resultAfterChange[0]);
|
||||
Assertions.assertEquals("right-with-label-after-change", resultAfterChange[0]);
|
||||
|
||||
// right-configmap now will see the new value also, but only because the other
|
||||
// configmap has triggered the restart
|
||||
rightResult = rightWebClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class).retryWhen(retrySpec())
|
||||
.block();
|
||||
assertThat("right-after-change").isEqualTo(rightResult);
|
||||
Assertions.assertEquals("right-after-change", rightResult);
|
||||
|
||||
deleteManifests();
|
||||
manifests("three", Phase.DELETE);
|
||||
}
|
||||
|
||||
private static void createNamespaces() throws Exception {
|
||||
processExecResult(K3S.execInContainer("sh", "-c", "kubectl create namespace left"));
|
||||
processExecResult(K3S.execInContainer("sh", "-c", "kubectl create namespace right"));
|
||||
}
|
||||
|
||||
private static void deleteNamespaces() throws Exception {
|
||||
processExecResult(K3S.execInContainer("sh", "-c", "kubectl delete namespace left"));
|
||||
processExecResult(K3S.execInContainer("sh", "-c", "kubectl delete namespace right"));
|
||||
}
|
||||
|
||||
private static void deployManifests(String deploymentRoot) {
|
||||
private static void manifests(String deploymentRoot, Phase phase) {
|
||||
|
||||
try {
|
||||
|
||||
V1ConfigMap leftConfigMap = leftConfigMap();
|
||||
leftConfigMapName = leftConfigMap.getMetadata().getName();
|
||||
api.createNamespacedConfigMap("left", leftConfigMap, null, null, null, null);
|
||||
V1ConfigMap leftConfigMap = (V1ConfigMap) util.yaml("left-configmap.yaml");
|
||||
V1ConfigMap rightConfigMap = (V1ConfigMap) util.yaml("right-configmap.yaml");
|
||||
V1ConfigMap rightWithLabelConfigMap = (V1ConfigMap) util.yaml("right-configmap-with-label.yaml");
|
||||
|
||||
V1ConfigMap rightConfigMap = rightConfigMap();
|
||||
rightConfigMapName = rightConfigMap.getMetadata().getName();
|
||||
api.createNamespacedConfigMap("right", rightConfigMap, null, null, null, null);
|
||||
V1Deployment deployment = (V1Deployment) util.yaml(deploymentRoot + "/deployment.yaml");
|
||||
V1Service service = (V1Service) util.yaml("service.yaml");
|
||||
V1Ingress ingress = (V1Ingress) util.yaml("ingress.yaml");
|
||||
|
||||
if ("three".equals(deploymentRoot)) {
|
||||
V1ConfigMap rightWithLabelConfigMap = rightWithLabelConfigMap();
|
||||
rightWithLabelConfigMapName = rightWithLabelConfigMap.getMetadata().getName();
|
||||
api.createNamespacedConfigMap("right", rightWithLabelConfigMap, null, null, null, null);
|
||||
if (phase.equals(Phase.CREATE)) {
|
||||
util.createAndWait("left", leftConfigMap, null);
|
||||
util.createAndWait("right", rightConfigMap, null);
|
||||
|
||||
if ("three".equals(deploymentRoot)) {
|
||||
util.createAndWait("right", rightWithLabelConfigMap, null);
|
||||
}
|
||||
util.createAndWait(NAMESPACE, null, deployment, service, ingress, true);
|
||||
}
|
||||
|
||||
V1Deployment deployment = getDeployment(deploymentRoot);
|
||||
String version = K8SUtils.getPomVersion();
|
||||
String currentImage = deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getImage();
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setImage(currentImage + ":" + version);
|
||||
deploymentName = deployment.getMetadata().getName();
|
||||
appsApi.createNamespacedDeployment(NAMESPACE, deployment, null, null, null, null);
|
||||
|
||||
V1Service service = getService();
|
||||
serviceName = service.getMetadata().getName();
|
||||
api.createNamespacedService(NAMESPACE, service, null, null, null, null);
|
||||
|
||||
V1Ingress ingress = getIngress();
|
||||
ingressName = ingress.getMetadata().getName();
|
||||
networkingApi.createNamespacedIngress(NAMESPACE, ingress, null, null, null, null);
|
||||
|
||||
k8SUtils.waitForIngress(ingressName, NAMESPACE);
|
||||
k8SUtils.waitForDeployment("spring-cloud-kubernetes-client-configmap-deployment-event-reload", NAMESPACE);
|
||||
if (phase.equals(Phase.DELETE)) {
|
||||
util.deleteAndWait("left", leftConfigMap, null);
|
||||
util.deleteAndWait("right", rightConfigMap, null);
|
||||
if ("three".equals(deploymentRoot)) {
|
||||
util.deleteAndWait("right", rightWithLabelConfigMap, null);
|
||||
}
|
||||
util.deleteAndWait(NAMESPACE, deployment, service, ingress);
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception e) {
|
||||
@@ -306,52 +270,6 @@ class ConfigMapEventReloadIT {
|
||||
|
||||
}
|
||||
|
||||
private static void deleteManifests() {
|
||||
|
||||
try {
|
||||
|
||||
api.deleteNamespacedConfigMap(leftConfigMapName, "left", null, null, null, null, null, null);
|
||||
api.deleteNamespacedConfigMap(rightConfigMapName, "right", null, null, null, null, null, null);
|
||||
|
||||
if (rightWithLabelConfigMapName != null) {
|
||||
api.deleteNamespacedConfigMap(rightWithLabelConfigMapName, "right", null, null, null, null, null, null);
|
||||
}
|
||||
|
||||
appsApi.deleteNamespacedDeployment(deploymentName, NAMESPACE, null, null, null, null, null, null);
|
||||
api.deleteNamespacedService(serviceName, NAMESPACE, null, null, null, null, null, null);
|
||||
networkingApi.deleteNamespacedIngress(ingressName, NAMESPACE, null, null, null, null, null, null);
|
||||
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static V1ConfigMap leftConfigMap() throws Exception {
|
||||
return (V1ConfigMap) K8SUtils.readYamlFromClasspath("left-configmap.yaml");
|
||||
}
|
||||
|
||||
private static V1ConfigMap rightConfigMap() throws Exception {
|
||||
return (V1ConfigMap) K8SUtils.readYamlFromClasspath("right-configmap.yaml");
|
||||
}
|
||||
|
||||
private static V1ConfigMap rightWithLabelConfigMap() throws Exception {
|
||||
return (V1ConfigMap) K8SUtils.readYamlFromClasspath("right-configmap-with-label.yaml");
|
||||
}
|
||||
|
||||
private static V1Deployment getDeployment(String root) throws Exception {
|
||||
return (V1Deployment) K8SUtils.readYamlFromClasspath(root + "/deployment.yaml");
|
||||
}
|
||||
|
||||
private static V1Service getService() throws Exception {
|
||||
return (V1Service) K8SUtils.readYamlFromClasspath("service.yaml");
|
||||
}
|
||||
|
||||
private static V1Ingress getIngress() throws Exception {
|
||||
return (V1Ingress) K8SUtils.readYamlFromClasspath("ingress.yaml");
|
||||
}
|
||||
|
||||
private WebClient.Builder builder() {
|
||||
return WebClient.builder().clientConnector(new ReactorClientHttpConnector(HttpClient.create()));
|
||||
}
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
app: spring-cloud-kubernetes-client-loadbalancer-it
|
||||
name: spring-cloud-kubernetes-client-loadbalancer-it-deployment
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: spring-cloud-kubernetes-client-loadbalancer-it
|
||||
strategy: {}
|
||||
template:
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
app: spring-cloud-kubernetes-client-loadbalancer-it
|
||||
spec:
|
||||
serviceAccountName: spring-cloud-kubernetes-serviceaccount
|
||||
containers:
|
||||
- image: springcloud/spring-cloud-kubernetes-client-loadbalancer-it:3.0.0-SNAPSHOT
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: spring-cloud-kubernetes-client-loadbalancer-it
|
||||
resources: {}
|
||||
status: {}
|
||||
@@ -1,18 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
app: spring-cloud-kubernetes-client-loadbalancer-it
|
||||
name: spring-cloud-kubernetes-client-loadbalancer-it
|
||||
spec:
|
||||
ports:
|
||||
- name: 80-8080
|
||||
port: 80
|
||||
protocol: TCP
|
||||
targetPort: 8080
|
||||
selector:
|
||||
app: spring-cloud-kubernetes-client-loadbalancer-it
|
||||
type: ClusterIP
|
||||
status:
|
||||
loadBalancer: {}
|
||||
@@ -1,19 +0,0 @@
|
||||
apiVersion: skaffold/v2alpha3
|
||||
kind: Config
|
||||
metadata:
|
||||
name: spring-cloud-kubernetes-client-loadbalancer-it
|
||||
build:
|
||||
artifacts:
|
||||
- image: springcloud/spring-cloud-kubernetes-client-loadbalancer-it
|
||||
custom:
|
||||
buildCommand: "../../mvnw clean install -Pskaffold"
|
||||
dependencies:
|
||||
paths:
|
||||
- src
|
||||
- pom.xml
|
||||
deploy:
|
||||
kubectl:
|
||||
manifests:
|
||||
- k8s/deployment-it.yaml
|
||||
- k8s/service-it.yaml
|
||||
- ../permissions.yaml
|
||||
@@ -40,7 +40,7 @@ import org.springframework.web.reactive.function.client.WebClient;
|
||||
@RestController
|
||||
public class KubernetesClientLoadBalancerApplicationIt {
|
||||
|
||||
private static final String URL = "http://servicea-wiremock/__admin/mappings";
|
||||
private static final String URL = "http://service-wiremock/__admin/mappings";
|
||||
|
||||
private final DiscoveryClient discoveryClient;
|
||||
|
||||
@@ -58,7 +58,7 @@ public class KubernetesClientLoadBalancerApplicationIt {
|
||||
return WebClient.builder();
|
||||
}
|
||||
|
||||
@GetMapping("/loadbalancer-it/servicea")
|
||||
@GetMapping("/loadbalancer-it/service")
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<String, Object> greeting() {
|
||||
return (Map<String, Object>) client().clientConnector(new ReactorClientHttpConnector(HttpClient.create()))
|
||||
|
||||
@@ -20,16 +20,12 @@ import java.time.Duration;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import io.kubernetes.client.openapi.ApiException;
|
||||
import io.kubernetes.client.openapi.apis.AppsV1Api;
|
||||
import io.kubernetes.client.openapi.apis.CoreV1Api;
|
||||
import io.kubernetes.client.openapi.apis.NetworkingV1Api;
|
||||
import io.kubernetes.client.openapi.models.V1Deployment;
|
||||
import io.kubernetes.client.openapi.models.V1Ingress;
|
||||
import io.kubernetes.client.openapi.models.V1Service;
|
||||
import org.assertj.core.api.Assertions;
|
||||
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;
|
||||
@@ -39,93 +35,68 @@ import reactor.util.retry.Retry;
|
||||
import reactor.util.retry.RetryBackoffSpec;
|
||||
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Commons;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils;
|
||||
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.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils.createApiClient;
|
||||
import static org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils.getPomVersion;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
class LoadBalancerIT {
|
||||
|
||||
private static final String SERVICE_URL = "localhost:80/loadbalancer-it/servicea";
|
||||
|
||||
private static final String SPRING_CLOUD_K8S_LOADBALANCER_DEPLOYMENT_NAME = "spring-cloud-kubernetes-client-loadbalancer-it-deployment";
|
||||
private static final String SERVICE_URL = "localhost:80/loadbalancer-it/service";
|
||||
|
||||
private static final String SPRING_CLOUD_K8S_LOADBALANCER_APP_NAME = "spring-cloud-kubernetes-client-loadbalancer-it";
|
||||
|
||||
private static final String NAMESPACE = "default";
|
||||
|
||||
private static CoreV1Api api;
|
||||
|
||||
private static AppsV1Api appsApi;
|
||||
|
||||
private static NetworkingV1Api networkingApi;
|
||||
|
||||
private static K8SUtils k8SUtils;
|
||||
|
||||
private static final K3sContainer K3S = Commons.container();
|
||||
|
||||
private static Util util;
|
||||
|
||||
@BeforeAll
|
||||
static void beforeAll() throws Exception {
|
||||
K3S.start();
|
||||
Commons.validateImage(SPRING_CLOUD_K8S_LOADBALANCER_APP_NAME, K3S);
|
||||
Commons.loadSpringCloudKubernetesImage(SPRING_CLOUD_K8S_LOADBALANCER_APP_NAME, K3S);
|
||||
createApiClient(K3S.getKubeConfigYaml());
|
||||
api = new CoreV1Api();
|
||||
appsApi = new AppsV1Api();
|
||||
networkingApi = new NetworkingV1Api();
|
||||
k8SUtils = new K8SUtils(api, appsApi);
|
||||
k8SUtils.setUp(NAMESPACE);
|
||||
util = new Util(K3S);
|
||||
util.setUp(NAMESPACE);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void afterAll() throws Exception {
|
||||
Commons.cleanUp(SPRING_CLOUD_K8S_LOADBALANCER_APP_NAME, K3S);
|
||||
k8SUtils.removeWiremockImage();
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void setup() throws Exception {
|
||||
k8SUtils.deployWiremock(NAMESPACE, false, K3S);
|
||||
void setup() {
|
||||
util.wiremock(NAMESPACE, "/wiremock", Phase.CREATE);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void afterEach() throws Exception {
|
||||
cleanup();
|
||||
k8SUtils.cleanUpWiremock(NAMESPACE);
|
||||
void afterEach() {
|
||||
util.wiremock(NAMESPACE, "/wiremock", Phase.DELETE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLoadBalancerServiceMode() throws Exception {
|
||||
deployLoadbalancerServiceIt();
|
||||
void testLoadBalancerServiceMode() {
|
||||
loadbalancerIt(false, Phase.CREATE);
|
||||
testLoadBalancer();
|
||||
loadbalancerIt(false, Phase.DELETE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLoadBalancerPodMode() throws Exception {
|
||||
deployLoadbalancerPodIt();
|
||||
void testLoadBalancerPodMode() {
|
||||
loadbalancerIt(true, Phase.CREATE);
|
||||
testLoadBalancer();
|
||||
}
|
||||
|
||||
private void cleanup() throws ApiException {
|
||||
appsApi.deleteCollectionNamespacedDeployment(NAMESPACE, null, null, null,
|
||||
"metadata.name=" + SPRING_CLOUD_K8S_LOADBALANCER_DEPLOYMENT_NAME, null, null, null, null, null, null,
|
||||
null, null, null);
|
||||
api.deleteNamespacedService(SPRING_CLOUD_K8S_LOADBALANCER_APP_NAME, NAMESPACE, null, null, null, null, null,
|
||||
null);
|
||||
networkingApi.deleteNamespacedIngress("it-ingress", NAMESPACE, null, null, null, null, null, null);
|
||||
loadbalancerIt(true, Phase.DELETE);
|
||||
}
|
||||
|
||||
private void testLoadBalancer() {
|
||||
// Check to make sure the controller deployment is ready
|
||||
k8SUtils.waitForDeployment(SPRING_CLOUD_K8S_LOADBALANCER_DEPLOYMENT_NAME, NAMESPACE);
|
||||
|
||||
WebClient.Builder builder = builder();
|
||||
WebClient serviceClient = builder.baseUrl(SERVICE_URL).build();
|
||||
@@ -136,55 +107,24 @@ class LoadBalancerIT {
|
||||
.bodyToMono(ParameterizedTypeReference.forType(resolvableType.getType())).retryWhen(retrySpec())
|
||||
.block();
|
||||
|
||||
Assertions.assertThat(result.containsKey("mappings")).isTrue();
|
||||
Assertions.assertThat(result.containsKey("meta")).isTrue();
|
||||
Assertions.assertTrue(result.containsKey("mappings"));
|
||||
Assertions.assertTrue(result.containsKey("meta"));
|
||||
|
||||
}
|
||||
|
||||
private void deployLoadbalancerServiceIt() throws Exception {
|
||||
appsApi.createNamespacedDeployment(NAMESPACE, getLoadbalancerServiceItDeployment(), null, null, null, null);
|
||||
api.createNamespacedService(NAMESPACE, getLoadbalancerItService(), null, null, null, null);
|
||||
deployIngress();
|
||||
}
|
||||
private void loadbalancerIt(boolean podBased, Phase phase) {
|
||||
V1Deployment deployment = podBased
|
||||
? (V1Deployment) util.yaml("spring-cloud-kubernetes-client-loadbalancer-pod-it-deployment.yaml")
|
||||
: (V1Deployment) util.yaml("spring-cloud-kubernetes-client-loadbalancer-service-it-deployment.yaml");
|
||||
V1Service service = (V1Service) util.yaml("spring-cloud-kubernetes-client-loadbalancer-it-service.yaml");
|
||||
V1Ingress ingress = (V1Ingress) util.yaml("spring-cloud-kubernetes-client-loadbalancer-it-ingress.yaml");
|
||||
|
||||
private void deployLoadbalancerPodIt() throws Exception {
|
||||
appsApi.createNamespacedDeployment(NAMESPACE, getLoadbalancerPodItDeployment(), null, null, null, null);
|
||||
api.createNamespacedService(NAMESPACE, getLoadbalancerItService(), null, null, null, null);
|
||||
deployIngress();
|
||||
}
|
||||
|
||||
private void deployIngress() throws Exception {
|
||||
V1Ingress ingress = getLoadbalancerItIngress();
|
||||
networkingApi.createNamespacedIngress(NAMESPACE, ingress, null, null, null, null);
|
||||
k8SUtils.waitForIngress(ingress.getMetadata().getName(), NAMESPACE);
|
||||
}
|
||||
|
||||
private V1Deployment getLoadbalancerServiceItDeployment() throws Exception {
|
||||
V1Deployment deployment = (V1Deployment) K8SUtils
|
||||
.readYamlFromClasspath("spring-cloud-kubernetes-client-loadbalancer-service-it-deployment.yaml");
|
||||
String image = deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getImage() + ":"
|
||||
+ getPomVersion();
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setImage(image);
|
||||
return deployment;
|
||||
}
|
||||
|
||||
private V1Deployment getLoadbalancerPodItDeployment() throws Exception {
|
||||
V1Deployment deployment = (V1Deployment) K8SUtils
|
||||
.readYamlFromClasspath("spring-cloud-kubernetes-client-loadbalancer-service-it-deployment.yaml");
|
||||
String image = deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getImage() + ":"
|
||||
+ getPomVersion();
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setImage(image);
|
||||
return deployment;
|
||||
}
|
||||
|
||||
private V1Ingress getLoadbalancerItIngress() throws Exception {
|
||||
return (V1Ingress) K8SUtils
|
||||
.readYamlFromClasspath("spring-cloud-kubernetes-client-loadbalancer-it-ingress.yaml");
|
||||
}
|
||||
|
||||
private V1Service getLoadbalancerItService() throws Exception {
|
||||
return (V1Service) K8SUtils
|
||||
.readYamlFromClasspath("spring-cloud-kubernetes-client-loadbalancer-it-service.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);
|
||||
}
|
||||
}
|
||||
|
||||
private WebClient.Builder builder() {
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: servicea-wiremock-deployment
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: servicea-wiremock
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: servicea-wiremock
|
||||
spec:
|
||||
containers:
|
||||
- name: servicea-wiremock
|
||||
image: wiremock/wiremock:2.32.0
|
||||
imagePullPolicy: IfNotPresent
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
port: 8080
|
||||
path: /__admin/mappings
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
port: 8080
|
||||
path: /__admin/mappings
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
@@ -1,17 +0,0 @@
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: wiremock-ingress
|
||||
namespace: default
|
||||
spec:
|
||||
rules:
|
||||
- http:
|
||||
paths:
|
||||
- path: /wiremock/
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: servicea-wiremock
|
||||
port:
|
||||
number: 8080
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app: servicea-wiremock
|
||||
name: servicea-wiremock
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 8080
|
||||
targetPort: 8080
|
||||
selector:
|
||||
app: servicea-wiremock
|
||||
type: ClusterIP
|
||||
@@ -1,26 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
app: spring-cloud-kubernetes-client-reactive-discovery-it
|
||||
name: spring-cloud-kubernetes-client-reactive-discovery-it-deployment
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: spring-cloud-kubernetes-client-reactive-discovery-it
|
||||
strategy: {}
|
||||
template:
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
app: spring-cloud-kubernetes-client-reactive-discovery-it
|
||||
spec:
|
||||
serviceAccountName: spring-cloud-kubernetes-serviceaccount
|
||||
containers:
|
||||
- image: springcloud/spring-cloud-kubernetes-client-reactive-discovery-it:3.0.0-SNAPSHOT
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: spring-cloud-kubernetes-client-reactive-discovery-it
|
||||
resources: {}
|
||||
status: {}
|
||||
@@ -1,18 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
app: spring-cloud-kubernetes-client-reactive-discovery-it
|
||||
name: spring-cloud-kubernetes-client-reactive-discovery-it
|
||||
spec:
|
||||
ports:
|
||||
- name: 80-8080
|
||||
port: 80
|
||||
protocol: TCP
|
||||
targetPort: 8080
|
||||
selector:
|
||||
app: spring-cloud-kubernetes-client-reactive-discovery-it
|
||||
type: ClusterIP
|
||||
status:
|
||||
loadBalancer: {}
|
||||
@@ -1,19 +0,0 @@
|
||||
apiVersion: skaffold/v2alpha3
|
||||
kind: Config
|
||||
metadata:
|
||||
name: spring-cloud-kubernetes-client-reactive-discovery-it
|
||||
build:
|
||||
artifacts:
|
||||
- image: springcloud/spring-cloud-kubernetes-client-reactive-discovery-it
|
||||
custom:
|
||||
buildCommand: "../../mvnw clean install -Pskaffold"
|
||||
dependencies:
|
||||
paths:
|
||||
- src
|
||||
- pom.xml
|
||||
deploy:
|
||||
kubectl:
|
||||
manifests:
|
||||
- k8s/deployment-it.yaml
|
||||
- k8s/service-it.yaml
|
||||
- ../permissions.yaml
|
||||
@@ -21,16 +21,12 @@ import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import io.kubernetes.client.openapi.ApiException;
|
||||
import io.kubernetes.client.openapi.apis.AppsV1Api;
|
||||
import io.kubernetes.client.openapi.apis.CoreV1Api;
|
||||
import io.kubernetes.client.openapi.apis.NetworkingV1Api;
|
||||
import io.kubernetes.client.openapi.models.V1Deployment;
|
||||
import io.kubernetes.client.openapi.models.V1Ingress;
|
||||
import io.kubernetes.client.openapi.models.V1Service;
|
||||
import org.assertj.core.api.Assertions;
|
||||
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;
|
||||
@@ -40,17 +36,14 @@ import reactor.util.retry.Retry;
|
||||
import reactor.util.retry.RetryBackoffSpec;
|
||||
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Commons;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils;
|
||||
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.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils.createApiClient;
|
||||
import static org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils.getPomVersion;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
@@ -60,55 +53,42 @@ class ReactiveDiscoveryClientIT {
|
||||
|
||||
private static final String SERVICES_URL = "localhost:80/reactive-discovery-it/services";
|
||||
|
||||
private static final String SPRING_CLOUD_K8S_REACTIVE_DISCOVERY_DEPLOYMENT_NAME = "spring-cloud-kubernetes-client-reactive-discoveryclient-it-deployment";
|
||||
|
||||
private static final String SPRING_CLOUD_K8S_REACTIVE_DISCOVERY_APP_NAME = "spring-cloud-kubernetes-client-reactive-discoveryclient-it";
|
||||
|
||||
private static final String NAMESPACE = "default";
|
||||
|
||||
private static CoreV1Api api;
|
||||
|
||||
private static AppsV1Api appsApi;
|
||||
|
||||
private static NetworkingV1Api networkingApi;
|
||||
|
||||
private static K8SUtils k8SUtils;
|
||||
|
||||
private static final K3sContainer K3S = Commons.container();
|
||||
|
||||
private static Util util;
|
||||
|
||||
@BeforeAll
|
||||
static void beforeAll() throws Exception {
|
||||
K3S.start();
|
||||
Commons.validateImage(SPRING_CLOUD_K8S_REACTIVE_DISCOVERY_APP_NAME, K3S);
|
||||
Commons.loadSpringCloudKubernetesImage(SPRING_CLOUD_K8S_REACTIVE_DISCOVERY_APP_NAME, K3S);
|
||||
createApiClient(K3S.getKubeConfigYaml());
|
||||
api = new CoreV1Api();
|
||||
appsApi = new AppsV1Api();
|
||||
networkingApi = new NetworkingV1Api();
|
||||
k8SUtils = new K8SUtils(api, appsApi);
|
||||
k8SUtils.setUp(NAMESPACE);
|
||||
util = new Util(K3S);
|
||||
util.setUp(NAMESPACE);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void afterAll() throws Exception {
|
||||
Commons.cleanUp(SPRING_CLOUD_K8S_REACTIVE_DISCOVERY_APP_NAME, K3S);
|
||||
k8SUtils.removeWiremockImage();
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void setup() throws Exception {
|
||||
k8SUtils.deployWiremock(NAMESPACE, false, K3S);
|
||||
void setup() {
|
||||
util.wiremock(NAMESPACE, "/wiremock", Phase.CREATE);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void after() throws Exception {
|
||||
k8SUtils.cleanUpWiremock(NAMESPACE);
|
||||
cleanup();
|
||||
void after() {
|
||||
util.wiremock(NAMESPACE, "/wiremock", Phase.DELETE);
|
||||
reactiveDiscoveryIt(Phase.DELETE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testReactiveDiscoveryClient() throws Exception {
|
||||
deployReactiveDiscoveryIt();
|
||||
void testReactiveDiscoveryClient() {
|
||||
reactiveDiscoveryIt(Phase.CREATE);
|
||||
testLoadBalancer();
|
||||
testHealth();
|
||||
}
|
||||
@@ -126,64 +106,36 @@ class ReactiveDiscoveryClientIT {
|
||||
|
||||
Map<String, Object> components = (Map<String, Object>) health.get("components");
|
||||
|
||||
assertThat(components.containsKey("reactiveDiscoveryClients")).isTrue();
|
||||
Assertions.assertTrue(components.containsKey("reactiveDiscoveryClients"));
|
||||
Map<String, Object> discoveryComposite = (Map<String, Object>) components.get("discoveryComposite");
|
||||
assertThat(discoveryComposite.get("status")).isEqualTo("UP");
|
||||
}
|
||||
|
||||
private void cleanup() throws ApiException {
|
||||
appsApi.deleteCollectionNamespacedDeployment(NAMESPACE, null, null, null,
|
||||
"metadata.name=" + SPRING_CLOUD_K8S_REACTIVE_DISCOVERY_DEPLOYMENT_NAME, null, null, null, null, null,
|
||||
null, null, null, null);
|
||||
api.deleteNamespacedService(SPRING_CLOUD_K8S_REACTIVE_DISCOVERY_APP_NAME, NAMESPACE, null, null, null, null,
|
||||
null, null);
|
||||
networkingApi.deleteNamespacedIngress("it-ingress", NAMESPACE, null, null, null, null, null, null);
|
||||
Assertions.assertEquals(discoveryComposite.get("status"), "UP");
|
||||
}
|
||||
|
||||
private void testLoadBalancer() {
|
||||
|
||||
// Check to make sure the controller deployment is ready
|
||||
k8SUtils.waitForDeployment(SPRING_CLOUD_K8S_REACTIVE_DISCOVERY_DEPLOYMENT_NAME, NAMESPACE);
|
||||
|
||||
WebClient.Builder builder = builder();
|
||||
WebClient serviceClient = builder.baseUrl(SERVICES_URL).build();
|
||||
String servicesResponse = serviceClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class)
|
||||
.retryWhen(retrySpec()).block();
|
||||
|
||||
Assertions
|
||||
.assertThat(Arrays.stream(servicesResponse.split(",")).anyMatch("servicea-wiremock"::equalsIgnoreCase))
|
||||
.isTrue();
|
||||
|
||||
.assertTrue(Arrays.stream(servicesResponse.split(",")).anyMatch("service-wiremock"::equalsIgnoreCase));
|
||||
}
|
||||
|
||||
private void deployIngress(V1Ingress ingress) throws Exception {
|
||||
networkingApi.createNamespacedIngress(NAMESPACE, ingress, null, null, null, null);
|
||||
k8SUtils.waitForIngress(ingress.getMetadata().getName(), NAMESPACE);
|
||||
}
|
||||
private void reactiveDiscoveryIt(Phase phase) {
|
||||
V1Deployment deployment = (V1Deployment) util
|
||||
.yaml("spring-cloud-kubernetes-client-reactive-discoveryclient-it-deployment.yaml");
|
||||
V1Service service = (V1Service) util
|
||||
.yaml("spring-cloud-kubernetes-client-reactive-discoveryclient-it-service.yaml");
|
||||
V1Ingress ingress = (V1Ingress) util
|
||||
.yaml("spring-cloud-kubernetes-client-reactive-discoveryclient-it-ingress.yaml");
|
||||
|
||||
private void deployReactiveDiscoveryIt() throws Exception {
|
||||
appsApi.createNamespacedDeployment(NAMESPACE, getReactiveDiscoveryItDeployment(), null, null, null, null);
|
||||
api.createNamespacedService(NAMESPACE, getReactiveDiscoveryService(), null, null, null, null);
|
||||
deployIngress(getReactiveDiscoveryItIngress());
|
||||
}
|
||||
|
||||
private V1Deployment getReactiveDiscoveryItDeployment() throws Exception {
|
||||
V1Deployment deployment = (V1Deployment) K8SUtils
|
||||
.readYamlFromClasspath("spring-cloud-kubernetes-client-reactive-discoveryclient-it-deployment.yaml");
|
||||
String image = deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getImage() + ":"
|
||||
+ getPomVersion();
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setImage(image);
|
||||
return deployment;
|
||||
}
|
||||
|
||||
private V1Service getReactiveDiscoveryService() throws Exception {
|
||||
return (V1Service) K8SUtils
|
||||
.readYamlFromClasspath("spring-cloud-kubernetes-client-reactive-discoveryclient-it-service.yaml");
|
||||
}
|
||||
|
||||
private V1Ingress getReactiveDiscoveryItIngress() throws Exception {
|
||||
return (V1Ingress) K8SUtils
|
||||
.readYamlFromClasspath("spring-cloud-kubernetes-client-reactive-discoveryclient-it-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);
|
||||
}
|
||||
}
|
||||
|
||||
private WebClient.Builder builder() {
|
||||
|
||||
@@ -18,11 +18,6 @@
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.vintage</groupId>
|
||||
<artifactId>junit-vintage-engine</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-kubernetes-test-support</artifactId>
|
||||
|
||||
@@ -18,20 +18,15 @@ package org.springframework.cloud.kubernetes.configuration.watcher.multiple.apps
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import io.kubernetes.client.openapi.apis.AppsV1Api;
|
||||
import io.kubernetes.client.openapi.apis.CoreV1Api;
|
||||
import io.kubernetes.client.openapi.apis.NetworkingV1Api;
|
||||
import io.kubernetes.client.openapi.models.V1Deployment;
|
||||
import io.kubernetes.client.openapi.models.V1Ingress;
|
||||
import io.kubernetes.client.openapi.models.V1ReplicationController;
|
||||
import io.kubernetes.client.openapi.models.V1Secret;
|
||||
import io.kubernetes.client.openapi.models.V1SecretBuilder;
|
||||
import io.kubernetes.client.openapi.models.V1Service;
|
||||
import org.assertj.core.api.Assertions;
|
||||
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;
|
||||
@@ -41,14 +36,13 @@ import reactor.util.retry.Retry;
|
||||
import reactor.util.retry.RetryBackoffSpec;
|
||||
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Commons;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Phase;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.native_client.Util;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import static org.awaitility.Awaitility.await;
|
||||
import static org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils.createApiClient;
|
||||
import static org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils.getPomVersion;
|
||||
|
||||
/**
|
||||
* @author wind57
|
||||
@@ -59,28 +53,16 @@ class ConfigurationWatcherMultipleAppIT {
|
||||
|
||||
private static final String CONFIG_WATCHER_APP_B_IMAGE = "spring-cloud-kubernetes-client-configuration-watcher-secrets-app-b";
|
||||
|
||||
private static final String CONFIG_WATCHER_DEPLOYMENT_APP_A_NAME = "app-a-deployment";
|
||||
|
||||
private static final String CONFIG_WATCHER_DEPLOYMENT_APP_B_NAME = "app-b-deployment";
|
||||
|
||||
private static final String SPRING_CLOUD_K8S_CONFIG_WATCHER_DEPLOYMENT_NAME = "spring-cloud-kubernetes-configuration-watcher-deployment";
|
||||
|
||||
private static final String SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME = "spring-cloud-kubernetes-configuration-watcher";
|
||||
|
||||
private static final String SECRET_NAME = "multiple-apps";
|
||||
|
||||
private static final String NAMESPACE = "default";
|
||||
|
||||
private static CoreV1Api api;
|
||||
|
||||
private static AppsV1Api appsApi;
|
||||
|
||||
private static NetworkingV1Api networkingApi;
|
||||
|
||||
private static K8SUtils k8SUtils;
|
||||
|
||||
private static final K3sContainer K3S = Commons.container();
|
||||
|
||||
private static Util util;
|
||||
|
||||
@BeforeAll
|
||||
static void beforeAll() throws Exception {
|
||||
K3S.start();
|
||||
@@ -94,12 +76,8 @@ class ConfigurationWatcherMultipleAppIT {
|
||||
Commons.validateImage(CONFIG_WATCHER_APP_B_IMAGE, K3S);
|
||||
Commons.loadSpringCloudKubernetesImage(CONFIG_WATCHER_APP_B_IMAGE, K3S);
|
||||
|
||||
createApiClient(K3S.getKubeConfigYaml());
|
||||
api = new CoreV1Api();
|
||||
appsApi = new AppsV1Api();
|
||||
k8SUtils = new K8SUtils(api, appsApi);
|
||||
networkingApi = new NetworkingV1Api();
|
||||
k8SUtils.setUp(NAMESPACE);
|
||||
util = new Util(K3S);
|
||||
util.setUp(NAMESPACE);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
@@ -110,36 +88,23 @@ class ConfigurationWatcherMultipleAppIT {
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void setup() throws Exception {
|
||||
|
||||
deployRabbitMq();
|
||||
deployAppA();
|
||||
deployAppB();
|
||||
deployIngress();
|
||||
deployConfigWatcher();
|
||||
|
||||
k8SUtils.waitForReplicationController("rabbitmq-controller", NAMESPACE);
|
||||
waitForDeployment(CONFIG_WATCHER_DEPLOYMENT_APP_A_NAME);
|
||||
waitForDeployment(CONFIG_WATCHER_DEPLOYMENT_APP_B_NAME);
|
||||
waitForDeployment(SPRING_CLOUD_K8S_CONFIG_WATCHER_DEPLOYMENT_NAME);
|
||||
void setup() {
|
||||
util.rabbitMq(NAMESPACE, Phase.CREATE);
|
||||
appA(Phase.CREATE);
|
||||
appB(Phase.CREATE);
|
||||
configWatcher(Phase.CREATE);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void after() throws Exception {
|
||||
|
||||
cleanRabbitMq();
|
||||
cleanUpServices();
|
||||
cleanUpDeployments();
|
||||
cleanUpIngress();
|
||||
cleanUpConfigMaps();
|
||||
|
||||
k8SUtils.waitForDeploymentToBeDeleted(SPRING_CLOUD_K8S_CONFIG_WATCHER_DEPLOYMENT_NAME, NAMESPACE);
|
||||
k8SUtils.waitForDeploymentToBeDeleted(CONFIG_WATCHER_DEPLOYMENT_APP_A_NAME, NAMESPACE);
|
||||
k8SUtils.waitForDeploymentToBeDeleted(CONFIG_WATCHER_DEPLOYMENT_APP_B_NAME, NAMESPACE);
|
||||
void after() {
|
||||
util.rabbitMq(NAMESPACE, Phase.DELETE);
|
||||
appA(Phase.DELETE);
|
||||
appB(Phase.DELETE);
|
||||
configWatcher(Phase.DELETE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRefresh() throws Exception {
|
||||
void testRefresh() {
|
||||
|
||||
// secret has one label, one that says that we should refresh
|
||||
// and one annotation that says that we should refresh some specific services
|
||||
@@ -149,7 +114,7 @@ class ConfigurationWatcherMultipleAppIT {
|
||||
"spring-cloud-kubernetes-client-configuration-watcher-secret-app-a, "
|
||||
+ "spring-cloud-kubernetes-client-configuration-watcher-secret-app-b")
|
||||
.endMetadata().build();
|
||||
api.createNamespacedSecret(NAMESPACE, secret, null, null, null, null);
|
||||
util.createAndWait(NAMESPACE, null, secret);
|
||||
|
||||
WebClient.Builder builderA = builder();
|
||||
WebClient serviceClientA = builderA.baseUrl("http://localhost:80/app-a").build();
|
||||
@@ -164,7 +129,7 @@ class ConfigurationWatcherMultipleAppIT {
|
||||
return valueA[0];
|
||||
});
|
||||
|
||||
Assertions.assertThat(valueA[0]).isTrue();
|
||||
Assertions.assertTrue(valueA[0]);
|
||||
|
||||
Boolean[] valueB = new Boolean[1];
|
||||
await().pollInterval(Duration.ofSeconds(3)).atMost(Duration.ofSeconds(240)).until(() -> {
|
||||
@@ -173,170 +138,48 @@ class ConfigurationWatcherMultipleAppIT {
|
||||
return valueB[0];
|
||||
});
|
||||
|
||||
Assertions.assertThat(valueB[0]).isTrue();
|
||||
Assertions.assertTrue(valueB[0]);
|
||||
util.deleteAndWait(NAMESPACE, null, secret);
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
--------------------------------------------------- rabbitmq -----------------------------------------------
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
</pre>
|
||||
*/
|
||||
private void deployRabbitMq() throws Exception {
|
||||
api.createNamespacedService(NAMESPACE, getRabbitMqService(), null, null, null, null);
|
||||
String[] image = getRabbitMQReplicationController().getSpec().getTemplate().getSpec().getContainers().get(0)
|
||||
.getImage().split(":");
|
||||
Commons.pullImage(image[0], image[1], K3S);
|
||||
Commons.loadImage(image[0], image[1], "rabbitmq", K3S);
|
||||
api.createNamespacedReplicationController(NAMESPACE, getRabbitMQReplicationController(), null, null, null,
|
||||
null);
|
||||
}
|
||||
private void appA(Phase phase) {
|
||||
V1Deployment deployment = (V1Deployment) util.yaml("app-a/app-a-deployment.yaml");
|
||||
V1Service service = (V1Service) util.yaml("app-a/app-a-service.yaml");
|
||||
V1Ingress ingress = (V1Ingress) util
|
||||
.yaml("ingress/spring-cloud-kubernetes-configuration-watcher-multiple-apps-ingress.yaml");
|
||||
|
||||
private V1ReplicationController getRabbitMQReplicationController() throws Exception {
|
||||
return (V1ReplicationController) K8SUtils.readYamlFromClasspath("rabbitmq/rabbitmq-controller.yaml");
|
||||
}
|
||||
|
||||
private V1Service getRabbitMqService() throws Exception {
|
||||
return (V1Service) K8SUtils.readYamlFromClasspath("rabbitmq/rabbitmq-service.yaml");
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
----------------------------------------------------- app-a ------------------------------------------------
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
</pre>
|
||||
*/
|
||||
private void deployAppA() throws Exception {
|
||||
appsApi.createNamespacedDeployment(NAMESPACE, getAppADeployment(), null, null, null, null);
|
||||
api.createNamespacedService(NAMESPACE, getAppAService(), null, null, null, null);
|
||||
}
|
||||
|
||||
private V1Deployment getAppADeployment() throws Exception {
|
||||
String urlString = "app-a/app-a-deployment.yaml";
|
||||
V1Deployment deployment = (V1Deployment) K8SUtils.readYamlFromClasspath(urlString);
|
||||
String image = K8SUtils.getImageFromDeployment(deployment) + ":" + getPomVersion();
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setImage(image);
|
||||
return deployment;
|
||||
}
|
||||
|
||||
private V1Service getAppAService() throws Exception {
|
||||
return (V1Service) K8SUtils.readYamlFromClasspath("app-a/app-a-service.yaml");
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
--------------------------------------------------- app-b --------------------------------------------------
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
</pre>
|
||||
*/
|
||||
private void deployAppB() throws Exception {
|
||||
appsApi.createNamespacedDeployment(NAMESPACE, getAppBDeployment(), null, null, null, null);
|
||||
api.createNamespacedService(NAMESPACE, getAppBService(), null, null, null, null);
|
||||
}
|
||||
|
||||
private V1Deployment getAppBDeployment() throws Exception {
|
||||
String urlString = "app-b/app-b-deployment.yaml";
|
||||
V1Deployment deployment = (V1Deployment) K8SUtils.readYamlFromClasspath(urlString);
|
||||
String image = K8SUtils.getImageFromDeployment(deployment) + ":" + getPomVersion();
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setImage(image);
|
||||
return deployment;
|
||||
}
|
||||
|
||||
private V1Service getAppBService() throws Exception {
|
||||
return (V1Service) K8SUtils.readYamlFromClasspath("app-b/app-b-service.yaml");
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
------------------------------------------------ config-watcher --------------------------------------------
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
</pre>
|
||||
*/
|
||||
private void deployConfigWatcher() throws Exception {
|
||||
appsApi.createNamespacedDeployment(NAMESPACE, getConfigWatcherDeployment(), null, null, null, null);
|
||||
api.createNamespacedService(NAMESPACE, getConfigWatcherService(), null, null, null, null);
|
||||
}
|
||||
|
||||
private V1Deployment getConfigWatcherDeployment() throws Exception {
|
||||
V1Deployment deployment = (V1Deployment) K8SUtils.readYamlFromClasspath(
|
||||
"config-watcher/spring-cloud-kubernetes-configuration-watcher-it-bus-amqp-deployment.yaml");
|
||||
String image = K8SUtils.getImageFromDeployment(deployment) + ":" + getPomVersion();
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setImage(image);
|
||||
return deployment;
|
||||
}
|
||||
|
||||
private V1Service getConfigWatcherService() throws Exception {
|
||||
return (V1Service) K8SUtils
|
||||
.readYamlFromClasspath("config-watcher/spring-cloud-kubernetes-configuration-watcher-service.yaml");
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
------------------------------------------------ common ----------------------------------------------------
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
</pre>
|
||||
*/
|
||||
|
||||
private void deployIngress() throws Exception {
|
||||
V1Ingress ingress = (V1Ingress) K8SUtils.readYamlFromClasspath(
|
||||
"ingress/spring-cloud-kubernetes-configuration-watcher-multiple-apps-ingress.yaml");
|
||||
|
||||
networkingApi.createNamespacedIngress(NAMESPACE, ingress, null, null, null, null);
|
||||
k8SUtils.waitForIngress(ingress.getMetadata().getName(), NAMESPACE);
|
||||
}
|
||||
|
||||
private void waitForDeployment(String deploymentName) {
|
||||
await().pollInterval(Duration.ofSeconds(3)).atMost(600, TimeUnit.SECONDS)
|
||||
.until(() -> k8SUtils.isDeploymentReady(deploymentName, NAMESPACE));
|
||||
}
|
||||
|
||||
private void cleanRabbitMq() throws Exception {
|
||||
api.deleteNamespacedService("rabbitmq-service", NAMESPACE, null, null, null, null, null, null);
|
||||
try {
|
||||
api.deleteNamespacedReplicationController("rabbitmq-controller", NAMESPACE, null, null, null, null, null,
|
||||
null);
|
||||
if (phase.equals(Phase.CREATE)) {
|
||||
util.createAndWait(NAMESPACE, null, deployment, service, ingress, true);
|
||||
}
|
||||
catch (Exception e) {
|
||||
// swallowing this exception, delete does actually happen, it's a problem
|
||||
// downstream from the k8s client; see:
|
||||
// https://github.com/kubernetes-client/java/issues/86#issuecomment-411234259
|
||||
else if (phase.equals(Phase.DELETE)) {
|
||||
util.deleteAndWait(NAMESPACE, deployment, service, ingress);
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanUpServices() throws Exception {
|
||||
api.deleteNamespacedService("app-a", NAMESPACE, null, null, null, null, null, null);
|
||||
api.deleteNamespacedService("app-b", NAMESPACE, null, null, null, null, null, null);
|
||||
api.deleteNamespacedService(SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME, NAMESPACE, null, null, null, null, null,
|
||||
null);
|
||||
private void appB(Phase phase) {
|
||||
V1Deployment deployment = (V1Deployment) util.yaml("app-b/app-b-deployment.yaml");
|
||||
V1Service service = (V1Service) util.yaml("app-b/app-b-service.yaml");
|
||||
|
||||
if (phase.equals(Phase.CREATE)) {
|
||||
util.createAndWait(NAMESPACE, null, deployment, service, null, true);
|
||||
}
|
||||
else if (phase.equals(Phase.DELETE)) {
|
||||
util.deleteAndWait(NAMESPACE, deployment, service, null);
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanUpDeployments() throws Exception {
|
||||
appsApi.deleteNamespacedDeployment(SPRING_CLOUD_K8S_CONFIG_WATCHER_DEPLOYMENT_NAME, NAMESPACE, null, null, null,
|
||||
null, null, null);
|
||||
appsApi.deleteNamespacedDeployment(CONFIG_WATCHER_DEPLOYMENT_APP_A_NAME, NAMESPACE, null, null, null, null,
|
||||
null, null);
|
||||
private void configWatcher(Phase phase) {
|
||||
V1Deployment deployment = (V1Deployment) util
|
||||
.yaml("config-watcher/spring-cloud-kubernetes-configuration-watcher-it-bus-amqp-deployment.yaml");
|
||||
V1Service service = (V1Service) util
|
||||
.yaml("config-watcher/spring-cloud-kubernetes-configuration-watcher-service.yaml");
|
||||
|
||||
appsApi.deleteNamespacedDeployment(CONFIG_WATCHER_DEPLOYMENT_APP_B_NAME, NAMESPACE, null, null, null, null,
|
||||
null, null);
|
||||
}
|
||||
|
||||
private void cleanUpConfigMaps() throws Exception {
|
||||
api.deleteNamespacedSecret(SECRET_NAME, NAMESPACE, null, null, null, null, null, null);
|
||||
}
|
||||
|
||||
private void cleanUpIngress() throws Exception {
|
||||
networkingApi.deleteNamespacedIngress("it-ingress-multiple-apps", NAMESPACE, null, null, null, null, null,
|
||||
null);
|
||||
if (phase.equals(Phase.CREATE)) {
|
||||
util.createAndWait(NAMESPACE, null, deployment, service, null, true);
|
||||
}
|
||||
else if (phase.equals(Phase.DELETE)) {
|
||||
util.deleteAndWait(NAMESPACE, deployment, service, null);
|
||||
}
|
||||
}
|
||||
|
||||
private WebClient.Builder builder() {
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: ReplicationController
|
||||
metadata:
|
||||
labels:
|
||||
component: rabbitmq
|
||||
name: rabbitmq-controller
|
||||
spec:
|
||||
replicas: 1
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: taskQueue
|
||||
component: rabbitmq
|
||||
spec:
|
||||
containers:
|
||||
- image: rabbitmq:3-management
|
||||
name: rabbitmq
|
||||
ports:
|
||||
- name: amqp
|
||||
containerPort: 5672
|
||||
- name: http-stats
|
||||
containerPort: 15672
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
port: 15672
|
||||
path: /api/healthchecks/node
|
||||
httpHeaders:
|
||||
- name: Authorization
|
||||
value: Basic Z3Vlc3Q6Z3Vlc3Q=
|
||||
@@ -20,9 +20,7 @@ import java.time.Duration;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import io.kubernetes.client.openapi.apis.AppsV1Api;
|
||||
import io.kubernetes.client.openapi.apis.CoreV1Api;
|
||||
import io.kubernetes.client.openapi.apis.NetworkingV1Api;
|
||||
import io.kubernetes.client.openapi.models.V1Deployment;
|
||||
import io.kubernetes.client.openapi.models.V1Ingress;
|
||||
import io.kubernetes.client.openapi.models.V1Secret;
|
||||
@@ -32,20 +30,18 @@ import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.k3s.K3sContainer;
|
||||
import org.testcontainers.shaded.org.awaitility.Awaitility;
|
||||
import reactor.netty.http.client.HttpClient;
|
||||
import reactor.util.retry.Retry;
|
||||
import reactor.util.retry.RetryBackoffSpec;
|
||||
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Commons;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Phase;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.native_client.Util;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils.createApiClient;
|
||||
import static org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils.getPomVersion;
|
||||
import static org.awaitility.Awaitility.await;
|
||||
|
||||
/**
|
||||
* @author wind57
|
||||
@@ -54,33 +50,24 @@ class SecretsEventReloadIT {
|
||||
|
||||
private static final String PROPERTY_URL = "localhost:80/key";
|
||||
|
||||
private static final String SPRING_CLOUD_CLIENT_CONFIG_IT_DEPLOYMENT_NAME = "spring-cloud-kubernetes-client-secrets-deployment-event-reload";
|
||||
|
||||
private static final String K8S_CONFIG_CLIENT_IT_SERVICE_NAME = "spring-cloud-kubernetes-client-secrets-event-reload";
|
||||
|
||||
private static final String NAMESPACE = "default";
|
||||
|
||||
private static CoreV1Api api;
|
||||
|
||||
private static AppsV1Api appsApi;
|
||||
|
||||
private static NetworkingV1Api networkingApi;
|
||||
|
||||
private static K8SUtils k8SUtils;
|
||||
|
||||
private static final K3sContainer K3S = Commons.container();
|
||||
|
||||
private static Util util;
|
||||
|
||||
private static CoreV1Api coreV1Api;
|
||||
|
||||
@BeforeAll
|
||||
static void setup() throws Exception {
|
||||
K3S.start();
|
||||
Commons.validateImage(K8S_CONFIG_CLIENT_IT_SERVICE_NAME, K3S);
|
||||
Commons.loadSpringCloudKubernetesImage(K8S_CONFIG_CLIENT_IT_SERVICE_NAME, K3S);
|
||||
createApiClient(K3S.getKubeConfigYaml());
|
||||
api = new CoreV1Api();
|
||||
appsApi = new AppsV1Api();
|
||||
networkingApi = new NetworkingV1Api();
|
||||
k8SUtils = new K8SUtils(api, appsApi);
|
||||
k8SUtils.setUp(NAMESPACE);
|
||||
util = new Util(K3S);
|
||||
coreV1Api = new CoreV1Api();
|
||||
util.setUp(NAMESPACE);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
@@ -89,22 +76,13 @@ class SecretsEventReloadIT {
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void after() throws Exception {
|
||||
appsApi.deleteCollectionNamespacedDeployment(NAMESPACE, null, null, null,
|
||||
"metadata.name=" + SPRING_CLOUD_CLIENT_CONFIG_IT_DEPLOYMENT_NAME, null, null, null, null, null, null,
|
||||
null, null, null);
|
||||
api.deleteNamespacedService(K8S_CONFIG_CLIENT_IT_SERVICE_NAME, NAMESPACE, null, null, null, null, null, null);
|
||||
networkingApi.deleteNamespacedIngress("spring-cloud-kubernetes-client-secrets-ingress-event-reload", NAMESPACE,
|
||||
null, null, null, null, null, null);
|
||||
api.deleteNamespacedSecret("event-reload", NAMESPACE, null, null, null, null, null, null);
|
||||
void after() {
|
||||
configK8sClientIt(Phase.DELETE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSecretReload() throws Exception {
|
||||
deployConfigK8sClientIt();
|
||||
|
||||
// Check to make sure the controller deployment is ready
|
||||
k8SUtils.waitForDeployment(SPRING_CLOUD_CLIENT_CONFIG_IT_DEPLOYMENT_NAME, NAMESPACE);
|
||||
configK8sClientIt(Phase.CREATE);
|
||||
testSecretEventReload();
|
||||
}
|
||||
|
||||
@@ -112,50 +90,36 @@ class SecretsEventReloadIT {
|
||||
|
||||
WebClient.Builder builder = builder();
|
||||
WebClient secretClient = builder.baseUrl(PROPERTY_URL).build();
|
||||
String secret = secretClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class).retryWhen(retrySpec())
|
||||
.block();
|
||||
assertThat(secret).isEqualTo("initial");
|
||||
|
||||
V1Secret v1Secret = getConfigK8sClientItCSecret();
|
||||
await().timeout(Duration.ofSeconds(120)).pollInterval(Duration.ofSeconds(2))
|
||||
.until(() -> secretClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class)
|
||||
.retryWhen(retrySpec()).block().equals("initial"));
|
||||
|
||||
V1Secret v1Secret = (V1Secret) util.yaml("secret.yaml");
|
||||
Map<String, byte[]> secretData = v1Secret.getData();
|
||||
secretData.replace("application.properties", "from.properties.key: after-change".getBytes());
|
||||
v1Secret.setData(secretData);
|
||||
api.replaceNamespacedSecret("event-reload", NAMESPACE, v1Secret, null, null, null, null);
|
||||
coreV1Api.replaceNamespacedSecret("event-reload", NAMESPACE, v1Secret, null, null, null, null);
|
||||
|
||||
Awaitility.await().timeout(Duration.ofSeconds(120)).pollInterval(Duration.ofSeconds(2))
|
||||
await().timeout(Duration.ofSeconds(120)).pollInterval(Duration.ofSeconds(2))
|
||||
.until(() -> secretClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class)
|
||||
.retryWhen(retrySpec()).block().equals("after-change"));
|
||||
}
|
||||
|
||||
private static void deployConfigK8sClientIt() throws Exception {
|
||||
k8SUtils.waitForDeploymentToBeDeleted(SPRING_CLOUD_CLIENT_CONFIG_IT_DEPLOYMENT_NAME, NAMESPACE);
|
||||
api.createNamespacedSecret(NAMESPACE, getConfigK8sClientItCSecret(), null, null, null, null);
|
||||
appsApi.createNamespacedDeployment(NAMESPACE, getConfigK8sClientItDeployment(), null, null, null, null);
|
||||
api.createNamespacedService(NAMESPACE, getConfigK8sClientItService(), null, null, null, null);
|
||||
private void configK8sClientIt(Phase phase) {
|
||||
V1Deployment deployment = (V1Deployment) util.yaml("deployment.yaml");
|
||||
V1Service service = (V1Service) util.yaml("service.yaml");
|
||||
V1Ingress ingress = (V1Ingress) util.yaml("ingress.yaml");
|
||||
V1Secret secret = (V1Secret) util.yaml("secret.yaml");
|
||||
|
||||
V1Ingress ingress = getConfigK8sClientItIngress();
|
||||
networkingApi.createNamespacedIngress(NAMESPACE, ingress, null, null, null, null);
|
||||
k8SUtils.waitForIngress(ingress.getMetadata().getName(), NAMESPACE);
|
||||
}
|
||||
|
||||
private static V1Deployment getConfigK8sClientItDeployment() throws Exception {
|
||||
V1Deployment deployment = (V1Deployment) K8SUtils.readYamlFromClasspath("deployment.yaml");
|
||||
String image = deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getImage() + ":"
|
||||
+ getPomVersion();
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setImage(image);
|
||||
return deployment;
|
||||
}
|
||||
|
||||
private static V1Service getConfigK8sClientItService() throws Exception {
|
||||
return (V1Service) K8SUtils.readYamlFromClasspath("service.yaml");
|
||||
}
|
||||
|
||||
private static V1Ingress getConfigK8sClientItIngress() throws Exception {
|
||||
return (V1Ingress) K8SUtils.readYamlFromClasspath("ingress.yaml");
|
||||
}
|
||||
|
||||
private static V1Secret getConfigK8sClientItCSecret() throws Exception {
|
||||
return (V1Secret) K8SUtils.readYamlFromClasspath("secret.yaml");
|
||||
if (phase.equals(Phase.CREATE)) {
|
||||
util.createAndWait(NAMESPACE, null, deployment, service, ingress, true);
|
||||
util.createAndWait(NAMESPACE, null, secret);
|
||||
}
|
||||
else if (phase.equals(Phase.DELETE)) {
|
||||
util.deleteAndWait(NAMESPACE, deployment, service, ingress);
|
||||
util.deleteAndWait(NAMESPACE, null, secret);
|
||||
}
|
||||
}
|
||||
|
||||
private WebClient.Builder builder() {
|
||||
|
||||
@@ -38,11 +38,6 @@
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.vintage</groupId>
|
||||
<artifactId>junit-vintage-engine</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-kubernetes-test-support</artifactId>
|
||||
|
||||
@@ -20,8 +20,6 @@ import java.time.Duration;
|
||||
|
||||
import com.github.tomakehurst.wiremock.client.VerificationException;
|
||||
import com.github.tomakehurst.wiremock.client.WireMock;
|
||||
import io.kubernetes.client.openapi.apis.AppsV1Api;
|
||||
import io.kubernetes.client.openapi.apis.CoreV1Api;
|
||||
import io.kubernetes.client.openapi.models.V1ConfigMap;
|
||||
import io.kubernetes.client.openapi.models.V1ConfigMapBuilder;
|
||||
import io.kubernetes.client.openapi.models.V1Deployment;
|
||||
@@ -34,30 +32,18 @@ import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.k3s.K3sContainer;
|
||||
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Commons;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Phase;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.native_client.Util;
|
||||
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.findAll;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.post;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.verify;
|
||||
import static org.awaitility.Awaitility.await;
|
||||
import static org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils.createApiClient;
|
||||
import static org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils.getPomVersion;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
class ActuatorRefreshIT {
|
||||
|
||||
private static final String SPRING_CLOUD_K8S_CONFIG_WATCHER_DEPLOYMENT_NAME = "spring-cloud-kubernetes-configuration-watcher-deployment";
|
||||
|
||||
private static final String SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME = "spring-cloud-kubernetes-configuration-watcher";
|
||||
|
||||
private String configWatcherConfigMapName;
|
||||
|
||||
private static final String WIREMOCK_HOST = "localhost";
|
||||
|
||||
private static final String WIREMOCK_PATH = "/";
|
||||
@@ -66,105 +52,83 @@ class ActuatorRefreshIT {
|
||||
|
||||
private static final String NAMESPACE = "default";
|
||||
|
||||
private static CoreV1Api api;
|
||||
|
||||
private static AppsV1Api appsApi;
|
||||
|
||||
private static K8SUtils k8SUtils;
|
||||
|
||||
private static final K3sContainer K3S = Commons.container();
|
||||
|
||||
private static Util util;
|
||||
|
||||
@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);
|
||||
createApiClient(K3S.getKubeConfigYaml());
|
||||
api = new CoreV1Api();
|
||||
appsApi = new AppsV1Api();
|
||||
k8SUtils = new K8SUtils(api, appsApi);
|
||||
k8SUtils.setUp(NAMESPACE);
|
||||
util = new Util(K3S);
|
||||
util.setUp(NAMESPACE);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void afterAll() throws Exception {
|
||||
Commons.cleanUp(SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME, K3S);
|
||||
k8SUtils.removeWiremockImage();
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void setup() throws Exception {
|
||||
deployConfigWatcher();
|
||||
k8SUtils.deployWiremock(NAMESPACE, true, K3S);
|
||||
void setup() {
|
||||
configWatcher(Phase.CREATE);
|
||||
util.wiremock(NAMESPACE, "/", Phase.CREATE);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void after() throws Exception {
|
||||
|
||||
appsApi.deleteCollectionNamespacedDeployment(NAMESPACE, null, null, null,
|
||||
"metadata.name=" + SPRING_CLOUD_K8S_CONFIG_WATCHER_DEPLOYMENT_NAME, null, null, null, null, null, null,
|
||||
null, null, null);
|
||||
api.deleteNamespacedService(SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME, NAMESPACE, null, null, null, null, null,
|
||||
null);
|
||||
|
||||
api.deleteNamespacedConfigMap(configWatcherConfigMapName, NAMESPACE, null, null, null, null, null, null);
|
||||
api.deleteNamespacedConfigMap("servicea-wiremock", NAMESPACE, null, null, null, null, null, null);
|
||||
k8SUtils.cleanUpWiremock(NAMESPACE);
|
||||
void after() {
|
||||
configWatcher(Phase.DELETE);
|
||||
util.wiremock(NAMESPACE, "/", Phase.DELETE);
|
||||
}
|
||||
|
||||
/*
|
||||
* this test loads uses 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: "servicea-wiremock", this in turn will trigger that
|
||||
* and deploy a new configmap: "service-wiremock", this in turn will trigger that
|
||||
* refresh that we capture and assert for.
|
||||
*/
|
||||
// curl <WIREMOCK_POD_IP>:8080/__admin/mappings
|
||||
@Test
|
||||
void testActuatorRefresh() throws Exception {
|
||||
void testActuatorRefresh() {
|
||||
WireMock.configureFor(WIREMOCK_HOST, WIREMOCK_PORT, WIREMOCK_PATH);
|
||||
await().timeout(Duration.ofSeconds(60)).ignoreException(VerificationException.class)
|
||||
.until(() -> stubFor(post(urlEqualTo("/actuator/refresh")).willReturn(aResponse().withStatus(200)))
|
||||
.until(() -> WireMock
|
||||
.stubFor(WireMock.post(WireMock.urlEqualTo("/actuator/refresh"))
|
||||
.willReturn(WireMock.aResponse().withBody("{}").withStatus(200)))
|
||||
.getResponse().wasConfigured());
|
||||
|
||||
// Create new configmap to trigger controller to signal app to refresh
|
||||
V1ConfigMap configMap = new V1ConfigMapBuilder().editOrNewMetadata().withName("servicea-wiremock")
|
||||
V1ConfigMap configMap = new V1ConfigMapBuilder().editOrNewMetadata().withName("service-wiremock")
|
||||
.addToLabels("spring.cloud.kubernetes.config", "true").endMetadata().addToData("foo", "bar").build();
|
||||
api.createNamespacedConfigMap(NAMESPACE, configMap, null, null, null, null);
|
||||
util.createAndWait(NAMESPACE, configMap, null);
|
||||
|
||||
// Wait a bit before we verify
|
||||
await().atMost(Duration.ofSeconds(30))
|
||||
.until(() -> !findAll(postRequestedFor(urlEqualTo("/actuator/refresh"))).isEmpty());
|
||||
await().atMost(Duration.ofSeconds(30)).until(
|
||||
() -> !WireMock.findAll(WireMock.postRequestedFor(WireMock.urlEqualTo("/actuator/refresh"))).isEmpty());
|
||||
|
||||
verify(postRequestedFor(urlEqualTo("/actuator/refresh")));
|
||||
WireMock.verify(WireMock.postRequestedFor(WireMock.urlEqualTo("/actuator/refresh")));
|
||||
util.deleteAndWait(NAMESPACE, configMap, null);
|
||||
}
|
||||
|
||||
private void deployConfigWatcher() throws Exception {
|
||||
V1ConfigMap configMap = getConfigWatcherConfigMap();
|
||||
configWatcherConfigMapName = configMap.getMetadata().getName();
|
||||
api.createNamespacedConfigMap(NAMESPACE, configMap, null, null, null, null);
|
||||
appsApi.createNamespacedDeployment(NAMESPACE, getConfigWatcherDeployment(), null, null, null, null);
|
||||
api.createNamespacedService(NAMESPACE, getConfigWatcherService(), null, null, null, null);
|
||||
private 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-http-deployment.yaml");
|
||||
V1Service service = (V1Service) util
|
||||
.yaml("config-watcher/spring-cloud-kubernetes-configuration-watcher-service.yaml");
|
||||
|
||||
// Check to make sure the controller deployment is ready
|
||||
k8SUtils.waitForDeployment(SPRING_CLOUD_K8S_CONFIG_WATCHER_DEPLOYMENT_NAME, NAMESPACE);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
private V1Deployment getConfigWatcherDeployment() throws Exception {
|
||||
V1Deployment deployment = (V1Deployment) K8SUtils.readYamlFromClasspath(
|
||||
"config-watcher/spring-cloud-kubernetes-configuration-watcher-http-deployment.yaml");
|
||||
String image = K8SUtils.getImageFromDeployment(deployment) + ":" + getPomVersion();
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setImage(image);
|
||||
return deployment;
|
||||
}
|
||||
|
||||
private V1Service getConfigWatcherService() throws Exception {
|
||||
return (V1Service) K8SUtils
|
||||
.readYamlFromClasspath("config-watcher/spring-cloud-kubernetes-configuration-watcher-service.yaml");
|
||||
}
|
||||
|
||||
private V1ConfigMap getConfigWatcherConfigMap() throws Exception {
|
||||
return (V1ConfigMap) K8SUtils
|
||||
.readYamlFromClasspath("config-watcher/spring-cloud-kubernetes-configuration-watcher-configmap.yaml");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,19 +18,15 @@ package org.springframework.cloud.kubernetes.configuration.watcher;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import io.kubernetes.client.openapi.apis.AppsV1Api;
|
||||
import io.kubernetes.client.openapi.apis.CoreV1Api;
|
||||
import io.kubernetes.client.openapi.apis.NetworkingV1Api;
|
||||
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.V1Ingress;
|
||||
import io.kubernetes.client.openapi.models.V1Service;
|
||||
import org.assertj.core.api.Assertions;
|
||||
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;
|
||||
@@ -40,14 +36,13 @@ import reactor.util.retry.Retry;
|
||||
import reactor.util.retry.RetryBackoffSpec;
|
||||
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Commons;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Phase;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.native_client.Util;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import static org.awaitility.Awaitility.await;
|
||||
import static org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils.createApiClient;
|
||||
import static org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils.getPomVersion;
|
||||
|
||||
/**
|
||||
* @author Kris Iyer
|
||||
@@ -56,32 +51,14 @@ class ActuatorRefreshKafkaIT {
|
||||
|
||||
private static final String CONFIG_WATCHER_IT_IMAGE = "spring-cloud-kubernetes-configuration-watcher-it";
|
||||
|
||||
private static final String SPRING_CLOUD_K8S_CONFIG_WATCHER_DEPLOYMENT_NAME = "spring-cloud-kubernetes-configuration-watcher-deployment";
|
||||
|
||||
private static final String SPRING_CLOUD_K8S_CONFIG_WATCHER_IT_DEPLOYMENT_NAME = "spring-cloud-kubernetes-configuration-watcher-it-deployment";
|
||||
|
||||
private static final String SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME = "spring-cloud-kubernetes-configuration-watcher";
|
||||
|
||||
private static final String NAMESPACE = "default";
|
||||
|
||||
private static final String KAFKA_BROKER = "kafka-broker";
|
||||
|
||||
private static final String KAFKA_SERVICE = "kafka";
|
||||
|
||||
private static final String ZOOKEEPER_SERVICE = "zookeeper";
|
||||
|
||||
private static final String ZOOKEEPER_DEPLOYMENT = "zookeeper";
|
||||
|
||||
private static CoreV1Api api;
|
||||
|
||||
private static AppsV1Api appsApi;
|
||||
|
||||
private static NetworkingV1Api networkingApi;
|
||||
|
||||
private static K8SUtils k8SUtils;
|
||||
|
||||
private static final K3sContainer K3S = Commons.container();
|
||||
|
||||
private static Util util;
|
||||
|
||||
@BeforeAll
|
||||
static void beforeAll() throws Exception {
|
||||
K3S.start();
|
||||
@@ -91,13 +68,8 @@ class ActuatorRefreshKafkaIT {
|
||||
|
||||
Commons.validateImage(CONFIG_WATCHER_IT_IMAGE, K3S);
|
||||
Commons.loadSpringCloudKubernetesImage(CONFIG_WATCHER_IT_IMAGE, K3S);
|
||||
|
||||
createApiClient(K3S.getKubeConfigYaml());
|
||||
api = new CoreV1Api();
|
||||
appsApi = new AppsV1Api();
|
||||
k8SUtils = new K8SUtils(api, appsApi);
|
||||
networkingApi = new NetworkingV1Api();
|
||||
k8SUtils.setUp(NAMESPACE);
|
||||
util = new Util(K3S);
|
||||
util.setUp(NAMESPACE);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
@@ -107,46 +79,28 @@ class ActuatorRefreshKafkaIT {
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void setup() throws Exception {
|
||||
|
||||
deployZookeeper();
|
||||
deployKafka();
|
||||
deployTestApp();
|
||||
deployConfigWatcher();
|
||||
|
||||
// Check to make sure the controller deployment is ready
|
||||
waitForDeployment(ZOOKEEPER_DEPLOYMENT);
|
||||
waitForDeployment(KAFKA_BROKER);
|
||||
waitForDeployment(SPRING_CLOUD_K8S_CONFIG_WATCHER_IT_DEPLOYMENT_NAME);
|
||||
waitForDeployment(SPRING_CLOUD_K8S_CONFIG_WATCHER_DEPLOYMENT_NAME);
|
||||
void setup() {
|
||||
util.zookeeper(NAMESPACE, Phase.CREATE);
|
||||
util.kafka(NAMESPACE, Phase.CREATE);
|
||||
testApp(Phase.CREATE);
|
||||
configWatcher(Phase.CREATE);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void after() throws Exception {
|
||||
|
||||
cleanUpKafka();
|
||||
cleanUpZookeeper();
|
||||
cleanUpServices();
|
||||
cleanUpDeployments();
|
||||
|
||||
networkingApi.deleteNamespacedIngress("it-ingress", NAMESPACE, null, null, null, null, null, null);
|
||||
|
||||
cleanUpConfigMaps();
|
||||
|
||||
// Check to make sure the controller deployment is deleted
|
||||
k8SUtils.waitForDeploymentToBeDeleted(KAFKA_BROKER, NAMESPACE);
|
||||
k8SUtils.waitForDeploymentToBeDeleted(ZOOKEEPER_DEPLOYMENT, NAMESPACE);
|
||||
k8SUtils.waitForDeploymentToBeDeleted(SPRING_CLOUD_K8S_CONFIG_WATCHER_DEPLOYMENT_NAME, NAMESPACE);
|
||||
k8SUtils.waitForDeploymentToBeDeleted(SPRING_CLOUD_K8S_CONFIG_WATCHER_IT_DEPLOYMENT_NAME, NAMESPACE);
|
||||
void after() {
|
||||
util.zookeeper(NAMESPACE, Phase.DELETE);
|
||||
util.kafka(NAMESPACE, Phase.DELETE);
|
||||
testApp(Phase.DELETE);
|
||||
configWatcher(Phase.DELETE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRefresh() throws Exception {
|
||||
void testRefresh() {
|
||||
// Create new configmap to trigger controller to signal app to refresh
|
||||
V1ConfigMap configMap = new V1ConfigMapBuilder().editOrNewMetadata().withName(CONFIG_WATCHER_IT_IMAGE)
|
||||
.addToLabels("spring.cloud.kubernetes.config", "true").endMetadata().addToData("foo", "hello world")
|
||||
.build();
|
||||
api.createNamespacedConfigMap(NAMESPACE, configMap, null, null, null, null);
|
||||
util.createAndWait(NAMESPACE, configMap, null);
|
||||
|
||||
WebClient.Builder builder = builder();
|
||||
WebClient serviceClient = builder.baseUrl("http://localhost:80/it").build();
|
||||
@@ -158,126 +112,42 @@ class ActuatorRefreshKafkaIT {
|
||||
return value[0];
|
||||
});
|
||||
|
||||
Assertions.assertThat(value[0]).isTrue();
|
||||
Assertions.assertTrue(value[0]);
|
||||
|
||||
util.deleteAndWait(NAMESPACE, configMap, null);
|
||||
}
|
||||
|
||||
private void waitForDeployment(String deploymentName) {
|
||||
await().pollInterval(Duration.ofSeconds(3)).atMost(600, TimeUnit.SECONDS)
|
||||
.until(() -> k8SUtils.isDeploymentReady(deploymentName, NAMESPACE));
|
||||
private void testApp(Phase phase) {
|
||||
V1Deployment deployment = (V1Deployment) util
|
||||
.yaml("app/spring-cloud-kubernetes-configuration-watcher-it-bus-kafka-deployment.yaml");
|
||||
V1Service service = (V1Service) util.yaml("app/spring-cloud-kubernetes-configuration-watcher-it-service.yaml");
|
||||
V1Ingress ingress = (V1Ingress) util.yaml("app/spring-cloud-kubernetes-configuration-watcher-it-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);
|
||||
}
|
||||
}
|
||||
|
||||
private void deployTestApp() throws Exception {
|
||||
appsApi.createNamespacedDeployment(NAMESPACE, getItDeployment(), null, null, null, null);
|
||||
api.createNamespacedService(NAMESPACE, getItAppService(), null, null, null, null);
|
||||
private void configWatcher(Phase phase) {
|
||||
V1Deployment deployment = (V1Deployment) util
|
||||
.yaml("app-watcher/spring-cloud-kubernetes-configuration-watcher-bus-kafka-deployment.yaml");
|
||||
V1Service service = (V1Service) util
|
||||
.yaml("config-watcher/spring-cloud-kubernetes-configuration-watcher-service.yaml");
|
||||
|
||||
V1Ingress ingress = getItIngress();
|
||||
networkingApi.createNamespacedIngress(NAMESPACE, ingress, null, null, null, null);
|
||||
k8SUtils.waitForIngress(ingress.getMetadata().getName(), NAMESPACE);
|
||||
}
|
||||
V1ConfigMap configMap = (V1ConfigMap) util
|
||||
.yaml("config-watcher/spring-cloud-kubernetes-configuration-watcher-configmap.yaml");
|
||||
|
||||
private void deployConfigWatcher() throws Exception {
|
||||
api.createNamespacedConfigMap(NAMESPACE, getConfigWatcherConfigMap(), null, null, null, null);
|
||||
appsApi.createNamespacedDeployment(NAMESPACE, getConfigWatcherDeployment(), null, null, null, null);
|
||||
api.createNamespacedService(NAMESPACE, getConfigWatcherService(), null, null, null, null);
|
||||
}
|
||||
|
||||
private void deployZookeeper() throws Exception {
|
||||
api.createNamespacedService(NAMESPACE, getZookeeperService(), null, null, null, null);
|
||||
V1Deployment deployment = getZookeeperDeployment();
|
||||
String[] image = K8SUtils.getImageFromDeployment(deployment).split(":");
|
||||
Commons.pullImage(image[0], image[1], K3S);
|
||||
Commons.loadImage(image[0], image[1], "zookeeper", K3S);
|
||||
appsApi.createNamespacedDeployment(NAMESPACE, deployment, null, null, null, null);
|
||||
}
|
||||
|
||||
private void deployKafka() throws Exception {
|
||||
api.createNamespacedService(NAMESPACE, getKafkaService(), null, null, null, null);
|
||||
V1Deployment deployment = getKafkaDeployment();
|
||||
String[] image = K8SUtils.getImageFromDeployment(deployment).split(":");
|
||||
Commons.pullImage(image[0], image[1], K3S);
|
||||
Commons.loadImage(image[0], image[1], "kafka", K3S);
|
||||
appsApi.createNamespacedDeployment(NAMESPACE, getKafkaDeployment(), null, null, null, null);
|
||||
}
|
||||
|
||||
private void cleanUpKafka() throws Exception {
|
||||
appsApi.deleteNamespacedDeployment(KAFKA_BROKER, NAMESPACE, null, null, null, null, null, null);
|
||||
api.deleteNamespacedService(KAFKA_SERVICE, NAMESPACE, null, null, null, null, null, null);
|
||||
}
|
||||
|
||||
private void cleanUpZookeeper() throws Exception {
|
||||
appsApi.deleteNamespacedDeployment(ZOOKEEPER_DEPLOYMENT, NAMESPACE, null, null, null, null, null, null);
|
||||
api.deleteNamespacedService(ZOOKEEPER_SERVICE, NAMESPACE, null, null, null, null, null, null);
|
||||
}
|
||||
|
||||
private V1Deployment getConfigWatcherDeployment() throws Exception {
|
||||
V1Deployment deployment = (V1Deployment) K8SUtils.readYamlFromClasspath(
|
||||
"app-watcher/spring-cloud-kubernetes-configuration-watcher-bus-kafka-deployment.yaml");
|
||||
String image = K8SUtils.getImageFromDeployment(deployment) + ":" + getPomVersion();
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setImage(image);
|
||||
return deployment;
|
||||
}
|
||||
|
||||
private V1Deployment getItDeployment() throws Exception {
|
||||
String urlString = "app/spring-cloud-kubernetes-configuration-watcher-it-bus-kafka-deployment.yaml";
|
||||
V1Deployment deployment = (V1Deployment) K8SUtils.readYamlFromClasspath(urlString);
|
||||
String image = K8SUtils.getImageFromDeployment(deployment) + ":" + getPomVersion();
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setImage(image);
|
||||
return deployment;
|
||||
}
|
||||
|
||||
private V1Service getConfigWatcherService() throws Exception {
|
||||
return (V1Service) K8SUtils
|
||||
.readYamlFromClasspath("config-watcher/spring-cloud-kubernetes-configuration-watcher-service.yaml");
|
||||
}
|
||||
|
||||
private V1ConfigMap getConfigWatcherConfigMap() throws Exception {
|
||||
return (V1ConfigMap) K8SUtils
|
||||
.readYamlFromClasspath("config-watcher/spring-cloud-kubernetes-configuration-watcher-configmap.yaml");
|
||||
}
|
||||
|
||||
private V1Service getItAppService() throws Exception {
|
||||
return (V1Service) K8SUtils
|
||||
.readYamlFromClasspath("app/spring-cloud-kubernetes-configuration-watcher-it-service.yaml");
|
||||
}
|
||||
|
||||
private V1Ingress getItIngress() throws Exception {
|
||||
return (V1Ingress) K8SUtils
|
||||
.readYamlFromClasspath("app/spring-cloud-kubernetes-configuration-watcher-it-ingress.yaml");
|
||||
}
|
||||
|
||||
private V1Deployment getKafkaDeployment() throws Exception {
|
||||
return (V1Deployment) K8SUtils.readYamlFromClasspath("kafka/kafka-deployment.yaml");
|
||||
}
|
||||
|
||||
private V1Service getKafkaService() throws Exception {
|
||||
return (V1Service) K8SUtils.readYamlFromClasspath("kafka/kafka-service.yaml");
|
||||
}
|
||||
|
||||
private V1Deployment getZookeeperDeployment() throws Exception {
|
||||
return (V1Deployment) K8SUtils.readYamlFromClasspath("zookeeper/zookeeper-deployment.yaml");
|
||||
}
|
||||
|
||||
private V1Service getZookeeperService() throws Exception {
|
||||
return (V1Service) K8SUtils.readYamlFromClasspath("zookeeper/zookeeper-service.yaml");
|
||||
}
|
||||
|
||||
private void cleanUpConfigMaps() throws Exception {
|
||||
api.deleteNamespacedConfigMap(SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME, NAMESPACE, null, null, null, null, null,
|
||||
null);
|
||||
api.deleteNamespacedConfigMap(CONFIG_WATCHER_IT_IMAGE, NAMESPACE, null, null, null, null, null, null);
|
||||
}
|
||||
|
||||
private void cleanUpDeployments() throws Exception {
|
||||
appsApi.deleteNamespacedDeployment(SPRING_CLOUD_K8S_CONFIG_WATCHER_DEPLOYMENT_NAME, NAMESPACE, null, null, null,
|
||||
null, null, null);
|
||||
appsApi.deleteNamespacedDeployment(SPRING_CLOUD_K8S_CONFIG_WATCHER_IT_DEPLOYMENT_NAME, NAMESPACE, null, null,
|
||||
null, null, null, null);
|
||||
}
|
||||
|
||||
private void cleanUpServices() throws Exception {
|
||||
api.deleteNamespacedService(CONFIG_WATCHER_IT_IMAGE, NAMESPACE, null, null, null, null, null, null);
|
||||
api.deleteNamespacedService(SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME, NAMESPACE, null, null, null, null, null,
|
||||
null);
|
||||
if (phase.equals(Phase.CREATE)) {
|
||||
util.createAndWait(NAMESPACE, null, deployment, service, null, true);
|
||||
util.createAndWait(NAMESPACE, configMap, null);
|
||||
}
|
||||
else if (phase.equals(Phase.DELETE)) {
|
||||
util.deleteAndWait(NAMESPACE, deployment, service, null);
|
||||
util.deleteAndWait(NAMESPACE, configMap, null);
|
||||
}
|
||||
}
|
||||
|
||||
private WebClient.Builder builder() {
|
||||
|
||||
@@ -18,20 +18,15 @@ package org.springframework.cloud.kubernetes.configuration.watcher;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import io.kubernetes.client.openapi.apis.AppsV1Api;
|
||||
import io.kubernetes.client.openapi.apis.CoreV1Api;
|
||||
import io.kubernetes.client.openapi.apis.NetworkingV1Api;
|
||||
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.V1Ingress;
|
||||
import io.kubernetes.client.openapi.models.V1ReplicationController;
|
||||
import io.kubernetes.client.openapi.models.V1Service;
|
||||
import org.assertj.core.api.Assertions;
|
||||
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;
|
||||
@@ -41,14 +36,13 @@ import reactor.util.retry.Retry;
|
||||
import reactor.util.retry.RetryBackoffSpec;
|
||||
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Commons;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Phase;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.native_client.Util;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import static org.awaitility.Awaitility.await;
|
||||
import static org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils.createApiClient;
|
||||
import static org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils.getPomVersion;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
@@ -57,26 +51,14 @@ class ActuatorRefreshRabbitMQIT {
|
||||
|
||||
private static final String CONFIG_WATCHER_IT_IMAGE = "spring-cloud-kubernetes-configuration-watcher-it";
|
||||
|
||||
private static final String SPRING_CLOUD_K8S_CONFIG_WATCHER_DEPLOYMENT_NAME = "spring-cloud-kubernetes-configuration-watcher-deployment";
|
||||
|
||||
private static final String SPRING_CLOUD_K8S_CONFIG_WATCHER_IT_DEPLOYMENT_NAME = "spring-cloud-kubernetes-configuration-watcher-it-deployment";
|
||||
|
||||
private static final String SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME = "spring-cloud-kubernetes-configuration-watcher";
|
||||
|
||||
private static final String NAMESPACE = "default";
|
||||
|
||||
private static final String RABBIT_MQ_CONTROLLER_NAME = "rabbitmq-controller";
|
||||
|
||||
private static CoreV1Api api;
|
||||
|
||||
private static AppsV1Api appsApi;
|
||||
|
||||
private static NetworkingV1Api networkingApi;
|
||||
|
||||
private static K8SUtils k8SUtils;
|
||||
|
||||
private static final K3sContainer K3S = Commons.container();
|
||||
|
||||
private static Util util;
|
||||
|
||||
@BeforeAll
|
||||
static void beforeAll() throws Exception {
|
||||
K3S.start();
|
||||
@@ -86,13 +68,8 @@ class ActuatorRefreshRabbitMQIT {
|
||||
|
||||
Commons.validateImage(CONFIG_WATCHER_IT_IMAGE, K3S);
|
||||
Commons.loadSpringCloudKubernetesImage(CONFIG_WATCHER_IT_IMAGE, K3S);
|
||||
|
||||
createApiClient(K3S.getKubeConfigYaml());
|
||||
api = new CoreV1Api();
|
||||
appsApi = new AppsV1Api();
|
||||
k8SUtils = new K8SUtils(api, appsApi);
|
||||
networkingApi = new NetworkingV1Api();
|
||||
k8SUtils.setUp(NAMESPACE);
|
||||
util = new Util(K3S);
|
||||
util.setUp(NAMESPACE);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
@@ -102,25 +79,26 @@ class ActuatorRefreshRabbitMQIT {
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void setup() throws Exception {
|
||||
void setup() {
|
||||
util.rabbitMq(NAMESPACE, Phase.CREATE);
|
||||
app(Phase.CREATE);
|
||||
configWatcher(Phase.CREATE);
|
||||
}
|
||||
|
||||
deployRabbitMQ();
|
||||
deployTestApp();
|
||||
deployConfigWatcher();
|
||||
|
||||
// Check to make sure the controller deployment is ready
|
||||
k8SUtils.waitForReplicationController(RABBIT_MQ_CONTROLLER_NAME, NAMESPACE);
|
||||
waitForDeployment(SPRING_CLOUD_K8S_CONFIG_WATCHER_IT_DEPLOYMENT_NAME);
|
||||
waitForDeployment(SPRING_CLOUD_K8S_CONFIG_WATCHER_DEPLOYMENT_NAME);
|
||||
@AfterEach
|
||||
void afterEach() {
|
||||
util.rabbitMq(NAMESPACE, Phase.DELETE);
|
||||
app(Phase.DELETE);
|
||||
configWatcher(Phase.DELETE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRefresh() throws Exception {
|
||||
void testRefresh() {
|
||||
// Create new configmap to trigger controller to signal app to refresh
|
||||
V1ConfigMap configMap = new V1ConfigMapBuilder().editOrNewMetadata().withName(CONFIG_WATCHER_IT_IMAGE)
|
||||
.addToLabels("spring.cloud.kubernetes.config", "true").endMetadata().addToData("foo", "hello world")
|
||||
.build();
|
||||
api.createNamespacedConfigMap(NAMESPACE, configMap, null, null, null, null);
|
||||
util.createAndWait(NAMESPACE, configMap, null);
|
||||
|
||||
WebClient.Builder builder = builder();
|
||||
WebClient serviceClient = builder.baseUrl("http://localhost:80/it").build();
|
||||
@@ -132,115 +110,40 @@ class ActuatorRefreshRabbitMQIT {
|
||||
return value[0];
|
||||
});
|
||||
|
||||
Assertions.assertThat(value[0]).isTrue();
|
||||
Assertions.assertTrue(value[0]);
|
||||
util.deleteAndWait(NAMESPACE, configMap, null);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void after() throws Exception {
|
||||
api.deleteNamespacedService("rabbitmq-service", NAMESPACE, null, null, null, null, null, null);
|
||||
api.deleteNamespacedService(CONFIG_WATCHER_IT_IMAGE, NAMESPACE, null, null, null, null, null, null);
|
||||
api.deleteNamespacedService(SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME, NAMESPACE, null, null, null, null, null,
|
||||
null);
|
||||
private void app(Phase phase) {
|
||||
V1Deployment deployment = (V1Deployment) util
|
||||
.yaml("app-watcher/spring-cloud-kubernetes-configuration-watcher-it-bus-amqp-deployment.yaml");
|
||||
V1Service service = (V1Service) util.yaml("app/spring-cloud-kubernetes-configuration-watcher-it-service.yaml");
|
||||
V1Ingress ingress = (V1Ingress) util.yaml("app/spring-cloud-kubernetes-configuration-watcher-it-ingress.yaml");
|
||||
|
||||
appsApi.deleteNamespacedDeployment(SPRING_CLOUD_K8S_CONFIG_WATCHER_DEPLOYMENT_NAME, NAMESPACE, null, null, null,
|
||||
null, null, null);
|
||||
appsApi.deleteNamespacedDeployment(SPRING_CLOUD_K8S_CONFIG_WATCHER_IT_DEPLOYMENT_NAME, NAMESPACE, null, null,
|
||||
null, null, null, null);
|
||||
|
||||
try {
|
||||
api.deleteNamespacedReplicationController(RABBIT_MQ_CONTROLLER_NAME, NAMESPACE, null, null, null, null,
|
||||
null, null);
|
||||
if (phase.equals(Phase.CREATE)) {
|
||||
util.createAndWait(NAMESPACE, null, deployment, service, ingress, true);
|
||||
}
|
||||
catch (Exception e) {
|
||||
// swallowing this exception, delete does actually happen, it's a problem
|
||||
// downstream from the k8s client; see:
|
||||
// https://github.com/kubernetes-client/java/issues/86#issuecomment-411234259
|
||||
else if (phase.equals(Phase.DELETE)) {
|
||||
util.deleteAndWait(NAMESPACE, deployment, service, ingress);
|
||||
}
|
||||
|
||||
networkingApi.deleteNamespacedIngress("it-ingress", NAMESPACE, null, null, null, null, null, null);
|
||||
|
||||
api.deleteNamespacedConfigMap(SPRING_CLOUD_K8S_CONFIG_WATCHER_APP_NAME, NAMESPACE, null, null, null, null, null,
|
||||
null);
|
||||
api.deleteNamespacedConfigMap(CONFIG_WATCHER_IT_IMAGE, NAMESPACE, null, null, null, null, null, null);
|
||||
|
||||
// Check to make sure the controller deployment is deleted
|
||||
k8SUtils.waitForDeploymentToBeDeleted(SPRING_CLOUD_K8S_CONFIG_WATCHER_DEPLOYMENT_NAME, NAMESPACE);
|
||||
k8SUtils.waitForDeploymentToBeDeleted(SPRING_CLOUD_K8S_CONFIG_WATCHER_IT_DEPLOYMENT_NAME, NAMESPACE);
|
||||
|
||||
}
|
||||
|
||||
private void deployTestApp() throws Exception {
|
||||
appsApi.createNamespacedDeployment(NAMESPACE, getItDeployment(), null, null, null, null);
|
||||
api.createNamespacedService(NAMESPACE, getItAppService(), null, null, null, null);
|
||||
private void configWatcher(Phase phase) {
|
||||
V1Deployment deployment = (V1Deployment) util
|
||||
.yaml("app-watcher/spring-cloud-kubernetes-configuration-watcher-bus-amqp-deployment.yaml");
|
||||
V1Service service = (V1Service) util
|
||||
.yaml("config-watcher/spring-cloud-kubernetes-configuration-watcher-service.yaml");
|
||||
V1ConfigMap configMap = (V1ConfigMap) util
|
||||
.yaml("config-watcher/spring-cloud-kubernetes-configuration-watcher-configmap.yaml");
|
||||
|
||||
V1Ingress ingress = getItIngress();
|
||||
networkingApi.createNamespacedIngress(NAMESPACE, ingress, null, null, null, null);
|
||||
k8SUtils.waitForIngress(ingress.getMetadata().getName(), NAMESPACE);
|
||||
}
|
||||
|
||||
private void deployConfigWatcher() throws Exception {
|
||||
api.createNamespacedConfigMap(NAMESPACE, getConfigWatcherConfigMap(), null, null, null, null);
|
||||
appsApi.createNamespacedDeployment(NAMESPACE, getConfigWatcherDeployment(), null, null, null, null);
|
||||
api.createNamespacedService(NAMESPACE, getConfigWatcherService(), null, null, null, null);
|
||||
}
|
||||
|
||||
private void deployRabbitMQ() throws Exception {
|
||||
api.createNamespacedService(NAMESPACE, getRabbitMQService(), null, null, null, null);
|
||||
String[] image = getRabbitMQReplicationController().getSpec().getTemplate().getSpec().getContainers().get(0)
|
||||
.getImage().split(":");
|
||||
Commons.pullImage(image[0], image[1], K3S);
|
||||
Commons.loadImage(image[0], image[1], "rabbitmq", K3S);
|
||||
api.createNamespacedReplicationController(NAMESPACE, getRabbitMQReplicationController(), null, null, null,
|
||||
null);
|
||||
}
|
||||
|
||||
private V1Deployment getConfigWatcherDeployment() throws Exception {
|
||||
V1Deployment deployment = (V1Deployment) K8SUtils.readYamlFromClasspath(
|
||||
"app-watcher/spring-cloud-kubernetes-configuration-watcher-bus-amqp-deployment.yaml");
|
||||
String image = K8SUtils.getImageFromDeployment(deployment) + ":" + getPomVersion();
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setImage(image);
|
||||
return deployment;
|
||||
}
|
||||
|
||||
private V1Deployment getItDeployment() throws Exception {
|
||||
String urlString = "app-watcher/spring-cloud-kubernetes-configuration-watcher-it-bus-amqp-deployment.yaml";
|
||||
V1Deployment deployment = (V1Deployment) K8SUtils.readYamlFromClasspath(urlString);
|
||||
String image = K8SUtils.getImageFromDeployment(deployment) + ":" + getPomVersion();
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setImage(image);
|
||||
return deployment;
|
||||
}
|
||||
|
||||
private V1Service getItAppService() throws Exception {
|
||||
return (V1Service) K8SUtils
|
||||
.readYamlFromClasspath("app/spring-cloud-kubernetes-configuration-watcher-it-service.yaml");
|
||||
}
|
||||
|
||||
private V1Service getConfigWatcherService() throws Exception {
|
||||
return (V1Service) K8SUtils
|
||||
.readYamlFromClasspath("config-watcher/spring-cloud-kubernetes-configuration-watcher-service.yaml");
|
||||
}
|
||||
|
||||
private V1ConfigMap getConfigWatcherConfigMap() throws Exception {
|
||||
return (V1ConfigMap) K8SUtils
|
||||
.readYamlFromClasspath("config-watcher/spring-cloud-kubernetes-configuration-watcher-configmap.yaml");
|
||||
}
|
||||
|
||||
private V1Ingress getItIngress() throws Exception {
|
||||
return (V1Ingress) K8SUtils
|
||||
.readYamlFromClasspath("app/spring-cloud-kubernetes-configuration-watcher-it-ingress.yaml");
|
||||
}
|
||||
|
||||
private V1ReplicationController getRabbitMQReplicationController() throws Exception {
|
||||
return (V1ReplicationController) K8SUtils.readYamlFromClasspath("rabbitmq/rabbitmq-controller.yaml");
|
||||
}
|
||||
|
||||
private V1Service getRabbitMQService() throws Exception {
|
||||
return (V1Service) K8SUtils.readYamlFromClasspath("rabbitmq/rabbitmq-service.yaml");
|
||||
}
|
||||
|
||||
private void waitForDeployment(String deploymentName) {
|
||||
await().pollInterval(Duration.ofSeconds(3)).atMost(600, TimeUnit.SECONDS)
|
||||
.until(() -> k8SUtils.isDeploymentReady(deploymentName, NAMESPACE));
|
||||
if (phase.equals(Phase.CREATE)) {
|
||||
util.createAndWait(NAMESPACE, null, deployment, service, null, true);
|
||||
util.createAndWait(NAMESPACE, configMap, null);
|
||||
}
|
||||
else if (phase.equals(Phase.DELETE)) {
|
||||
util.deleteAndWait(NAMESPACE, deployment, service, null);
|
||||
util.deleteAndWait(NAMESPACE, configMap, null);
|
||||
}
|
||||
}
|
||||
|
||||
private WebClient.Builder builder() {
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: kafka
|
||||
component: kafka-broker
|
||||
name: kafka-broker
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: kafka
|
||||
component: kafka-broker
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: kafka
|
||||
component: kafka-broker
|
||||
spec:
|
||||
# otherwise we will get an env var "KAFKA_PORT" (from service name: "kafka" and appended with "_PORT")
|
||||
# and this will cause this problem: https://github.com/confluentinc/cp-docker-images/blob/master/debian/kafka/include/etc/confluent/docker/configure#L58-L62
|
||||
# Another solution is to rename the service.
|
||||
enableServiceLinks: false
|
||||
containers:
|
||||
- name: kafka
|
||||
image: confluentinc/cp-kafka:7.2.1
|
||||
ports:
|
||||
- containerPort: 9092
|
||||
env:
|
||||
- name: KAFKA_LISTENERS
|
||||
value: "INTERNAL://0.0.0.0:9092,OUTSIDE://0.0.0.0:9094"
|
||||
|
||||
- name: KAFKA_LISTENER_SECURITY_PROTOCOL_MAP
|
||||
value: "INTERNAL:PLAINTEXT,OUTSIDE:PLAINTEXT"
|
||||
|
||||
- name: KAFKA_ADVERTISED_LISTENERS
|
||||
value: "INTERNAL://kafka:9092,OUTSIDE://localhost:9094"
|
||||
|
||||
- name: KAFKA_INTER_BROKER_LISTENER_NAME
|
||||
value: "INTERNAL"
|
||||
|
||||
- name: KAFKA_ADVERTISED_HOST_NAME
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: status.podIP
|
||||
|
||||
- name: KAFKA_ZOOKEEPER_CONNECT
|
||||
value: zookeeper:2181
|
||||
|
||||
# we have enabled auto creation of topics and when this happens there is a replication factor of 3
|
||||
# that is set automatically. Since we don't have that many, producers will fail.
|
||||
# This setting ensures that there is just one replication
|
||||
- name: KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR
|
||||
value: "1"
|
||||
@@ -1,16 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: kafka
|
||||
labels:
|
||||
app: kafka
|
||||
component: kafka-broker
|
||||
spec:
|
||||
ports:
|
||||
- port: 9092
|
||||
name: kafka-port
|
||||
targetPort: 9092
|
||||
protocol: TCP
|
||||
selector:
|
||||
app: kafka
|
||||
component: kafka-broker
|
||||
@@ -1,36 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: ReplicationController
|
||||
metadata:
|
||||
labels:
|
||||
component: rabbitmq
|
||||
name: rabbitmq-controller
|
||||
spec:
|
||||
replicas: 1
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: taskQueue
|
||||
component: rabbitmq
|
||||
spec:
|
||||
containers:
|
||||
- image: rabbitmq:3-management
|
||||
name: rabbitmq
|
||||
ports:
|
||||
- name: amqp
|
||||
containerPort: 5672
|
||||
- name: http-stats
|
||||
containerPort: 15672
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
port: 15672
|
||||
path: /api/healthchecks/node
|
||||
httpHeaders:
|
||||
- name: Authorization
|
||||
value: Basic Z3Vlc3Q6Z3Vlc3Q=
|
||||
# livenessProbe:
|
||||
# httpGet:
|
||||
# port: 15672
|
||||
# path: /api/healthchecks/node
|
||||
# httpHeaders:
|
||||
# - name: Authorization
|
||||
# value: Basic Z3Vlc3Q6Z3Vlc3Q=
|
||||
@@ -1,17 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
component: rabbitmq
|
||||
name: rabbitmq-service
|
||||
spec:
|
||||
ports:
|
||||
- port: 5672
|
||||
name: amqp
|
||||
targetPort: 5672
|
||||
- port: 15672
|
||||
name: http-stats
|
||||
targetPort: 15672
|
||||
selector:
|
||||
app: taskQueue
|
||||
component: rabbitmq
|
||||
@@ -1,31 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: kafka
|
||||
component: zookeeper
|
||||
name: zookeeper
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: kafka
|
||||
component: zookeeper
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: kafka
|
||||
component: zookeeper
|
||||
spec:
|
||||
containers:
|
||||
- name: zookeeper
|
||||
image: confluentinc/cp-zookeeper:7.2.1
|
||||
ports:
|
||||
- containerPort: 2181
|
||||
env:
|
||||
- name: ZOOKEEPER_ID
|
||||
value: "1"
|
||||
- name: ZOOKEEPER_SERVER_1
|
||||
value: zookeeper
|
||||
- name: ZOOKEEPER_CLIENT_PORT
|
||||
value: 2181
|
||||
@@ -1,16 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: zookeeper
|
||||
labels:
|
||||
app: kafka
|
||||
component: zookeeper
|
||||
spec:
|
||||
ports:
|
||||
- port: 2181
|
||||
name: zookeeper-port
|
||||
targetPort: 2181
|
||||
protocol: TCP
|
||||
selector:
|
||||
app: kafka
|
||||
component: zookeeper
|
||||
@@ -1,26 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
app: spring-cloud-kubernetes-core-k8s-client-it
|
||||
name: spring-cloud-kubernetes-core-k8s-client-it-deployment
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: spring-cloud-kubernetes-core-k8s-client-it
|
||||
strategy: {}
|
||||
template:
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
app: spring-cloud-kubernetes-core-k8s-client-it
|
||||
spec:
|
||||
serviceAccountName: spring-cloud-kubernetes-serviceaccount
|
||||
containers:
|
||||
- image: springcloud/spring-cloud-kubernetes-core-k8s-client-it:3.0.0-SNAPSHOT
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: spring-cloud-kubernetes-core-k8s-client-it
|
||||
resources: {}
|
||||
status: {}
|
||||
@@ -1,18 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
app: spring-cloud-kubernetes-core-k8s-client-it
|
||||
name: spring-cloud-kubernetes-core-k8s-client-it
|
||||
spec:
|
||||
ports:
|
||||
- name: 80-8080
|
||||
port: 80
|
||||
protocol: TCP
|
||||
targetPort: 8080
|
||||
selector:
|
||||
app: spring-cloud-kubernetes-core-k8s-client-it
|
||||
type: ClusterIP
|
||||
status:
|
||||
loadBalancer: {}
|
||||
@@ -1,19 +0,0 @@
|
||||
apiVersion: skaffold/v2alpha3
|
||||
kind: Config
|
||||
metadata:
|
||||
name: spring-cloud-kubernetes-core-k8s-client-it
|
||||
build:
|
||||
artifacts:
|
||||
- image: springcloud/spring-cloud-kubernetes-core-k8s-client-it
|
||||
custom:
|
||||
buildCommand: "../../mvnw clean install -Pskaffold"
|
||||
dependencies:
|
||||
paths:
|
||||
- src
|
||||
- pom.xml
|
||||
deploy:
|
||||
kubectl:
|
||||
manifests:
|
||||
- k8s/deployment-it.yaml
|
||||
- k8s/service-it.yaml
|
||||
- ../permissions.yaml
|
||||
@@ -20,9 +20,6 @@ import java.time.Duration;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import io.kubernetes.client.openapi.apis.AppsV1Api;
|
||||
import io.kubernetes.client.openapi.apis.CoreV1Api;
|
||||
import io.kubernetes.client.openapi.apis.NetworkingV1Api;
|
||||
import io.kubernetes.client.openapi.models.V1Deployment;
|
||||
import io.kubernetes.client.openapi.models.V1Ingress;
|
||||
import io.kubernetes.client.openapi.models.V1Service;
|
||||
@@ -35,65 +32,42 @@ import reactor.util.retry.Retry;
|
||||
import reactor.util.retry.RetryBackoffSpec;
|
||||
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Commons;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils;
|
||||
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.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
|
||||
import static org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils.createApiClient;
|
||||
import static org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils.getPomVersion;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
class ActuatorEndpointIT {
|
||||
|
||||
private static final String SPRING_CLOUD_K8S_CLIENT_IT_DEPLOYMENT_NAME = "spring-cloud-kubernetes-core-k8s-client-it-deployment";
|
||||
|
||||
private static final String K8S_CONFIG_CLIENT_IT_NAME = "spring-cloud-kubernetes-core-k8s-client-it-deployment";
|
||||
|
||||
private static final String K8S_CONFIG_CLIENT_IT_SERVICE_NAME = "spring-cloud-kubernetes-core-k8s-client-it";
|
||||
|
||||
private static final String NAMESPACE = "default";
|
||||
|
||||
private static CoreV1Api api;
|
||||
|
||||
private static AppsV1Api appsApi;
|
||||
|
||||
private static K8SUtils k8SUtils;
|
||||
|
||||
private static NetworkingV1Api networkingApi;
|
||||
|
||||
private static final K3sContainer K3S = Commons.container();
|
||||
|
||||
private static Util util;
|
||||
|
||||
@BeforeAll
|
||||
static void beforeAll() throws Exception {
|
||||
K3S.start();
|
||||
Commons.validateImage(K8S_CONFIG_CLIENT_IT_SERVICE_NAME, K3S);
|
||||
Commons.loadSpringCloudKubernetesImage(K8S_CONFIG_CLIENT_IT_SERVICE_NAME, K3S);
|
||||
createApiClient(K3S.getKubeConfigYaml());
|
||||
api = new CoreV1Api();
|
||||
appsApi = new AppsV1Api();
|
||||
networkingApi = new NetworkingV1Api();
|
||||
k8SUtils = new K8SUtils(api, appsApi);
|
||||
k8SUtils.setUp(NAMESPACE);
|
||||
|
||||
deployCoreK8sClientIt();
|
||||
|
||||
// Check to make sure the controller deployment is ready
|
||||
k8SUtils.waitForDeployment(SPRING_CLOUD_K8S_CLIENT_IT_DEPLOYMENT_NAME, NAMESPACE);
|
||||
util = new Util(K3S);
|
||||
util.setUp(NAMESPACE);
|
||||
coreK8sClientIt(Phase.CREATE);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void after() throws Exception {
|
||||
Commons.cleanUp(K8S_CONFIG_CLIENT_IT_SERVICE_NAME, K3S);
|
||||
appsApi.deleteCollectionNamespacedDeployment(NAMESPACE, null, null, null,
|
||||
"metadata.name=" + K8S_CONFIG_CLIENT_IT_NAME, null, null, null, null, null, null, null, null, null);
|
||||
api.deleteNamespacedService(K8S_CONFIG_CLIENT_IT_SERVICE_NAME, NAMESPACE, null, null, null, null, null, null);
|
||||
networkingApi.deleteNamespacedIngress("it-ingress", NAMESPACE, null, null, null, null, null, null);
|
||||
static void afterAll() {
|
||||
coreK8sClientIt(Phase.DELETE);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -152,30 +126,18 @@ class ActuatorEndpointIT {
|
||||
assertThat(kubernetes.containsKey("serviceAccount")).isTrue();
|
||||
}
|
||||
|
||||
private static void deployCoreK8sClientIt() throws Exception {
|
||||
appsApi.createNamespacedDeployment(NAMESPACE, getCoreK8sClientItDeployment(), null, null, null, null);
|
||||
api.createNamespacedService(NAMESPACE, getCoreK8sClientItService(), null, null, null, null);
|
||||
private static void coreK8sClientIt(Phase phase) {
|
||||
V1Deployment deployment = (V1Deployment) util
|
||||
.yaml("spring-cloud-kubernetes-core-k8s-client-it-deployment.yaml");
|
||||
V1Service service = (V1Service) util.yaml("spring-cloud-kubernetes-core-k8s-client-it-service.yaml");
|
||||
V1Ingress ingress = (V1Ingress) util.yaml("spring-cloud-kubernetes-core-k8s-client-it-ingress.yaml");
|
||||
|
||||
V1Ingress ingress = getCoreK8sClientItIngress();
|
||||
networkingApi.createNamespacedIngress(NAMESPACE, ingress, null, null, null, null);
|
||||
k8SUtils.waitForIngress(ingress.getMetadata().getName(), NAMESPACE);
|
||||
}
|
||||
|
||||
private static V1Deployment getCoreK8sClientItDeployment() throws Exception {
|
||||
V1Deployment deployment = (V1Deployment) K8SUtils
|
||||
.readYamlFromClasspath("spring-cloud-kubernetes-core-k8s-client-it-deployment.yaml");
|
||||
String image = deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getImage() + ":"
|
||||
+ getPomVersion();
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setImage(image);
|
||||
return deployment;
|
||||
}
|
||||
|
||||
private static V1Service getCoreK8sClientItService() throws Exception {
|
||||
return (V1Service) K8SUtils.readYamlFromClasspath("spring-cloud-kubernetes-core-k8s-client-it-service.yaml");
|
||||
}
|
||||
|
||||
private static V1Ingress getCoreK8sClientItIngress() throws Exception {
|
||||
return (V1Ingress) K8SUtils.readYamlFromClasspath("spring-cloud-kubernetes-core-k8s-client-it-ingress.yaml");
|
||||
if (phase.equals(Phase.CREATE)) {
|
||||
util.createAndWait(NAMESPACE, null, deployment, service, ingress, true);
|
||||
}
|
||||
else {
|
||||
util.deleteAndWait(NAMESPACE, deployment, service, ingress);
|
||||
}
|
||||
}
|
||||
|
||||
private WebClient.Builder builder() {
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
app: spring-cloud-kubernetes-discoveryclient-it
|
||||
name: spring-cloud-kubernetes-discoveryclient-it-deployment
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: spring-cloud-kubernetes-discoveryclient-it
|
||||
strategy: {}
|
||||
template:
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
app: spring-cloud-kubernetes-discoveryclient-it
|
||||
spec:
|
||||
serviceAccountName: spring-cloud-kubernetes-serviceaccount
|
||||
containers:
|
||||
- image: springcloud/spring-cloud-kubernetes-discoveryclient-it:3.0.0-SNAPSHOT
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: spring-cloud-kubernetes-discoveryclient-it
|
||||
resources: {}
|
||||
status: {}
|
||||
@@ -1,18 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
app: spring-cloud-kubernetes-discoveryclient-it
|
||||
name: spring-cloud-kubernetes-discoveryclient-it
|
||||
spec:
|
||||
ports:
|
||||
- name: 80-8080
|
||||
port: 80
|
||||
protocol: TCP
|
||||
targetPort: 8080
|
||||
selector:
|
||||
app: spring-cloud-kubernetes-discoveryclient-it
|
||||
type: ClusterIP
|
||||
status:
|
||||
loadBalancer: {}
|
||||
@@ -17,15 +17,10 @@
|
||||
package org.springframework.cloud.kubernetes.discoveryclient.it;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import io.kubernetes.client.openapi.ApiException;
|
||||
import io.kubernetes.client.openapi.apis.AppsV1Api;
|
||||
import io.kubernetes.client.openapi.apis.CoreV1Api;
|
||||
import io.kubernetes.client.openapi.apis.NetworkingV1Api;
|
||||
import io.kubernetes.client.openapi.apis.RbacAuthorizationV1Api;
|
||||
import io.kubernetes.client.openapi.models.V1ClusterRoleBinding;
|
||||
import io.kubernetes.client.openapi.models.V1Container;
|
||||
@@ -33,11 +28,7 @@ import io.kubernetes.client.openapi.models.V1Deployment;
|
||||
import io.kubernetes.client.openapi.models.V1EnvVar;
|
||||
import io.kubernetes.client.openapi.models.V1EnvVarBuilder;
|
||||
import io.kubernetes.client.openapi.models.V1Ingress;
|
||||
import io.kubernetes.client.openapi.models.V1Namespace;
|
||||
import io.kubernetes.client.openapi.models.V1ObjectMeta;
|
||||
import io.kubernetes.client.openapi.models.V1Service;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
@@ -49,7 +40,8 @@ import reactor.util.retry.RetryBackoffSpec;
|
||||
|
||||
import org.springframework.cloud.kubernetes.discovery.KubernetesServiceInstance;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Commons;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils;
|
||||
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;
|
||||
@@ -57,48 +49,28 @@ import org.springframework.http.client.reactive.ReactorClientHttpConnector;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils.createApiClient;
|
||||
import static org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils.getPomVersion;
|
||||
|
||||
/**
|
||||
* @author mbialkowski1
|
||||
*/
|
||||
class DiscoveryClientFilterNamespaceIT {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(DiscoveryClientFilterNamespaceIT.class);
|
||||
|
||||
private static final String DISCOVERY_SERVER_DEPLOYMENT_NAME = "spring-cloud-kubernetes-discoveryserver-deployment";
|
||||
|
||||
private static final String DISCOVERY_SERVER_APP_NAME = "spring-cloud-kubernetes-discoveryserver";
|
||||
|
||||
private static final String SPRING_CLOUD_K8S_DISCOVERY_CLIENT_DEPLOYMENT_NAME = "spring-cloud-kubernetes-discoveryclient-it-deployment";
|
||||
|
||||
private static final String SPRING_CLOUD_K8S_DISCOVERY_CLIENT_APP_NAME = "spring-cloud-kubernetes-discoveryclient-it";
|
||||
|
||||
private static final String MOCK_DEPLOYMENT_NAME = "wiremock-deployment";
|
||||
|
||||
private static final String MOCK_CLIENT_APP_NAME = "wiremock";
|
||||
|
||||
private static final String MOCK_IMAGE_NAME = "wiremock";
|
||||
|
||||
private static final String NAMESPACE = "default";
|
||||
|
||||
private static final String NAMESPACE_LEFT = "left-namespace-k8s-client";
|
||||
private static final String NAMESPACE_LEFT = "left";
|
||||
|
||||
private static final String NAMESPACE_RIGHT = "right-namespace-k8s-client";
|
||||
|
||||
private static CoreV1Api api;
|
||||
|
||||
private static AppsV1Api appsApi;
|
||||
|
||||
private static NetworkingV1Api networkingApi;
|
||||
|
||||
private static RbacAuthorizationV1Api authApi;
|
||||
|
||||
private static K8SUtils k8SUtils;
|
||||
private static final String NAMESPACE_RIGHT = "right";
|
||||
|
||||
private static final K3sContainer K3S = Commons.container();
|
||||
|
||||
private static Util util;
|
||||
|
||||
private static RbacAuthorizationV1Api rbacApi;
|
||||
|
||||
@BeforeAll
|
||||
static void beforeAll() throws Exception {
|
||||
K3S.start();
|
||||
@@ -109,97 +81,56 @@ class DiscoveryClientFilterNamespaceIT {
|
||||
Commons.validateImage(SPRING_CLOUD_K8S_DISCOVERY_CLIENT_APP_NAME, K3S);
|
||||
Commons.loadSpringCloudKubernetesImage(SPRING_CLOUD_K8S_DISCOVERY_CLIENT_APP_NAME, K3S);
|
||||
|
||||
String[] mockImage = K8SUtils.getImageFromDeployment(getMockServiceDeployment()).split(":");
|
||||
Commons.pullImage(mockImage[0], mockImage[1], K3S);
|
||||
Commons.loadImage(mockImage[0], mockImage[1], MOCK_IMAGE_NAME, K3S);
|
||||
util = new Util(K3S);
|
||||
rbacApi = new RbacAuthorizationV1Api();
|
||||
util.createNamespace(NAMESPACE_LEFT);
|
||||
util.createNamespace(NAMESPACE_RIGHT);
|
||||
util.setUp(NAMESPACE);
|
||||
|
||||
createApiClient(K3S.getKubeConfigYaml());
|
||||
api = new CoreV1Api();
|
||||
appsApi = new AppsV1Api();
|
||||
networkingApi = new NetworkingV1Api();
|
||||
authApi = new RbacAuthorizationV1Api();
|
||||
k8SUtils = new K8SUtils(api, appsApi);
|
||||
k8SUtils.setUp(NAMESPACE);
|
||||
|
||||
deployDiscoveryServer();
|
||||
|
||||
// Check to make sure the discovery server deployment is ready
|
||||
k8SUtils.waitForDeployment(DISCOVERY_SERVER_DEPLOYMENT_NAME, NAMESPACE);
|
||||
|
||||
// Check to see if endpoint is ready
|
||||
k8SUtils.waitForEndpointReady(DISCOVERY_SERVER_APP_NAME, NAMESPACE);
|
||||
V1ClusterRoleBinding clusterRole = (V1ClusterRoleBinding) util
|
||||
.yaml("namespace-filter/cluster-admin-serviceaccount-role.yaml");
|
||||
rbacApi.createClusterRoleBinding(clusterRole, null, null, null, null);
|
||||
discoveryServer(Phase.CREATE);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void afterAll() throws Exception {
|
||||
Commons.cleanUp(DISCOVERY_SERVER_APP_NAME, K3S);
|
||||
Commons.cleanUp(SPRING_CLOUD_K8S_DISCOVERY_CLIENT_APP_NAME, K3S);
|
||||
Commons.cleanUpDownloadedImage(MOCK_IMAGE_NAME);
|
||||
|
||||
appsApi.deleteCollectionNamespacedDeployment(NAMESPACE, null, null, null,
|
||||
"metadata.name=" + DISCOVERY_SERVER_DEPLOYMENT_NAME, null, null, null, null, null, null, null, null,
|
||||
null);
|
||||
|
||||
api.deleteNamespacedService(DISCOVERY_SERVER_APP_NAME, NAMESPACE, null, null, null, null, null, null);
|
||||
networkingApi.deleteNamespacedIngress("discoveryserver-ingress", NAMESPACE, null, null, null, null, null, null);
|
||||
discoveryServer(Phase.DELETE);
|
||||
util.deleteNamespace(NAMESPACE_LEFT);
|
||||
util.deleteNamespace(NAMESPACE_RIGHT);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void afterEach() throws ApiException {
|
||||
cleanup();
|
||||
void afterEach() {
|
||||
util.wiremock(NAMESPACE_LEFT, "/wiremock-" + NAMESPACE_LEFT, Phase.DELETE);
|
||||
util.wiremock(NAMESPACE_RIGHT, "/wiremock-" + NAMESPACE_RIGHT, Phase.DELETE);
|
||||
discoveryIt(Phase.DELETE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDiscoveryClient() throws Exception {
|
||||
deploySampleAppInNamespace(NAMESPACE_LEFT);
|
||||
deploySampleAppInNamespace(NAMESPACE_RIGHT);
|
||||
deployDiscoveryIt();
|
||||
void testDiscoveryClient() {
|
||||
util.wiremock(NAMESPACE_LEFT, "/wiremock-" + NAMESPACE_LEFT, Phase.CREATE);
|
||||
util.wiremock(NAMESPACE_RIGHT, "/wiremock-" + NAMESPACE_RIGHT, Phase.CREATE);
|
||||
discoveryIt(Phase.CREATE);
|
||||
|
||||
testLoadBalancer();
|
||||
testHealth();
|
||||
}
|
||||
|
||||
private void cleanup() throws ApiException {
|
||||
appsApi.deleteCollectionNamespacedDeployment(NAMESPACE, null, null, null,
|
||||
"metadata.name=" + SPRING_CLOUD_K8S_DISCOVERY_CLIENT_DEPLOYMENT_NAME, null, null, null, null, null,
|
||||
null, null, null, null);
|
||||
api.deleteNamespacedService(SPRING_CLOUD_K8S_DISCOVERY_CLIENT_APP_NAME, NAMESPACE, null, null, null, null, null,
|
||||
null);
|
||||
networkingApi.deleteNamespacedIngress("it-ingress", NAMESPACE, null, null, null, null, null, null);
|
||||
|
||||
appsApi.deleteCollectionNamespacedDeployment(NAMESPACE_LEFT, null, null, null,
|
||||
"metadata.name=" + MOCK_DEPLOYMENT_NAME, null, null, null, null, null, null, null, null, null);
|
||||
appsApi.deleteCollectionNamespacedDeployment(NAMESPACE_RIGHT, null, null, null,
|
||||
"metadata.name=" + MOCK_DEPLOYMENT_NAME, null, null, null, null, null, null, null, null, null);
|
||||
|
||||
api.deleteNamespacedService(MOCK_CLIENT_APP_NAME, NAMESPACE_LEFT, null, null, null, null, null, null);
|
||||
api.deleteNamespacedService(MOCK_CLIENT_APP_NAME, NAMESPACE_RIGHT, null, null, null, null, null, null);
|
||||
|
||||
networkingApi.deleteNamespacedIngress("wiremock-ingress", NAMESPACE_LEFT, null, null, null, null, null, null);
|
||||
networkingApi.deleteNamespacedIngress("wiremock-ingress", NAMESPACE_RIGHT, null, null, null, null, null, null);
|
||||
|
||||
authApi.deleteClusterRoleBinding("admin-default-k8s-client", null, null, null, null, null, null);
|
||||
|
||||
api.deleteNamespace(NAMESPACE_LEFT, null, null, null, null, null, null);
|
||||
api.deleteNamespace(NAMESPACE_RIGHT, null, null, null, null, null, null);
|
||||
|
||||
}
|
||||
|
||||
private void testLoadBalancer() {
|
||||
|
||||
// Check to make sure the controller deployment is ready
|
||||
k8SUtils.waitForDeployment(SPRING_CLOUD_K8S_DISCOVERY_CLIENT_DEPLOYMENT_NAME, NAMESPACE);
|
||||
WebClient.Builder builder = builder();
|
||||
WebClient serviceClient = builder.baseUrl("http://localhost:80/discoveryclient-it/services").build();
|
||||
|
||||
String[] result = serviceClient.method(HttpMethod.GET).retrieve().bodyToMono(String[].class)
|
||||
.retryWhen(retrySpec()).block();
|
||||
LOG.info("Services: " + Arrays.toString(result));
|
||||
assertThat(result).containsAnyOf("wiremock");
|
||||
assertThat(result).containsAnyOf("service-wiremock");
|
||||
|
||||
// ServiceInstance
|
||||
WebClient serviceInstanceClient = builder.baseUrl("http://localhost:80/discoveryclient-it/service/wiremock")
|
||||
.build();
|
||||
WebClient serviceInstanceClient = builder
|
||||
.baseUrl("http://localhost:80/discoveryclient-it/service/service-wiremock").build();
|
||||
List<KubernetesServiceInstance> serviceInstances = serviceInstanceClient.method(HttpMethod.GET).retrieve()
|
||||
.bodyToMono(new ParameterizedTypeReference<List<KubernetesServiceInstance>>() {
|
||||
}).retryWhen(retrySpec()).block();
|
||||
@@ -227,119 +158,48 @@ class DiscoveryClientFilterNamespaceIT {
|
||||
assertThat(discoveryComposite.get("status")).isEqualTo("UP");
|
||||
}
|
||||
|
||||
private void deployDiscoveryIt() throws Exception {
|
||||
appsApi.createNamespacedDeployment(NAMESPACE, getDiscoveryItDeployment(), null, null, null, null);
|
||||
api.createNamespacedService(NAMESPACE, getDiscoveryService(), null, null, null, null);
|
||||
private void discoveryIt(Phase phase) {
|
||||
|
||||
V1Deployment deployment = (V1Deployment) util
|
||||
.yaml("client/spring-cloud-kubernetes-discoveryclient-it-deployment.yaml");
|
||||
V1Service service = (V1Service) util.yaml("client/spring-cloud-kubernetes-discoveryclient-it-service.yaml");
|
||||
V1Ingress ingress = (V1Ingress) util.yaml("client/spring-cloud-kubernetes-discoveryclient-it-ingress.yaml");
|
||||
|
||||
if (phase.equals(Phase.CREATE)) {
|
||||
// add namespaces filter property for left namespace
|
||||
var env = new V1EnvVarBuilder().withName("SPRING_CLOUD_KUBERNETES_DISCOVERY_NAMESPACES_0")
|
||||
.withValue(NAMESPACE_LEFT).build();
|
||||
var container = deployment.getSpec().getTemplate().getSpec().getContainers().get(0);
|
||||
container.setEnv(List.of(env));
|
||||
|
||||
util.createAndWait(NAMESPACE, null, deployment, service, ingress, true);
|
||||
}
|
||||
else {
|
||||
util.deleteAndWait(NAMESPACE, deployment, service, ingress);
|
||||
}
|
||||
|
||||
V1Ingress ingress = getDiscoveryItIngress();
|
||||
networkingApi.createNamespacedIngress(NAMESPACE, ingress, null, null, null, null);
|
||||
k8SUtils.waitForIngress(ingress.getMetadata().getName(), NAMESPACE);
|
||||
}
|
||||
|
||||
private static V1Deployment getDiscoveryItDeployment() throws Exception {
|
||||
V1Deployment deployment = (V1Deployment) K8SUtils
|
||||
.readYamlFromClasspath("client/spring-cloud-kubernetes-discoveryclient-it-deployment.yaml");
|
||||
private static void discoveryServer(Phase phase) {
|
||||
|
||||
// add namespaces filter property for left namespace
|
||||
var env = new V1EnvVarBuilder().withName("SPRING_CLOUD_KUBERNETES_DISCOVERY_NAMESPACES_0")
|
||||
.withValue(NAMESPACE_LEFT).build();
|
||||
var container = deployment.getSpec().getTemplate().getSpec().getContainers().get(0);
|
||||
container.setEnv(List.of(env));
|
||||
V1Deployment deployment = (V1Deployment) util
|
||||
.yaml("server/spring-cloud-kubernetes-discoveryserver-deployment.yaml");
|
||||
V1Service service = (V1Service) util.yaml("server/spring-cloud-kubernetes-discoveryserver-service.yaml");
|
||||
V1Ingress ingress = (V1Ingress) util.yaml("server/spring-cloud-kubernetes-discoveryserver-ingress.yaml");
|
||||
|
||||
String image = deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getImage() + ":"
|
||||
+ getPomVersion();
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setImage(image);
|
||||
return deployment;
|
||||
}
|
||||
if (phase.equals(Phase.CREATE)) {
|
||||
// add namespaces filter property for left namespace
|
||||
// setup all-namespaces property
|
||||
V1EnvVar env = new V1EnvVarBuilder().withName("SPRING_CLOUD_KUBERNETES_DISCOVERY_ALL_NAMESPACES")
|
||||
.withValue("TRUE").build();
|
||||
V1Container container = deployment.getSpec().getTemplate().getSpec().getContainers().get(0);
|
||||
container.setEnv(List.of(env));
|
||||
|
||||
private static void deployDiscoveryServer() throws Exception {
|
||||
|
||||
V1ClusterRoleBinding clusterRoleBinding = getClusterRoleBinding();
|
||||
authApi.createClusterRoleBinding(clusterRoleBinding, null, null, null, null);
|
||||
|
||||
appsApi.createNamespacedDeployment(NAMESPACE, getDiscoveryServerDeployment(), null, null, null, null);
|
||||
api.createNamespacedService(NAMESPACE, getDiscoveryServerService(), null, null, null, null);
|
||||
|
||||
V1Ingress ingress = getDiscoveryServerIngress();
|
||||
networkingApi.createNamespacedIngress(NAMESPACE, ingress, null, null, null, null);
|
||||
k8SUtils.waitForIngress(ingress.getMetadata().getName(), NAMESPACE);
|
||||
}
|
||||
|
||||
private static void deploySampleAppInNamespace(final String namespace) throws Exception {
|
||||
|
||||
V1Namespace v1Namespace = new V1Namespace();
|
||||
V1ObjectMeta meta = new V1ObjectMeta();
|
||||
meta.setName(namespace);
|
||||
v1Namespace.setMetadata(meta);
|
||||
|
||||
api.createNamespace(v1Namespace, null, null, null, null);
|
||||
|
||||
V1Deployment deployment = getMockServiceDeployment();
|
||||
deployment.getMetadata().setNamespace(namespace);
|
||||
|
||||
appsApi.createNamespacedDeployment(namespace, deployment, null, null, null, null);
|
||||
V1Service service = getMockServiceService();
|
||||
service.getMetadata().setNamespace(namespace);
|
||||
api.createNamespacedService(namespace, service, null, null, null, null);
|
||||
V1Ingress ingress = getMockIngress();
|
||||
ingress.getMetadata().setNamespace(namespace);
|
||||
|
||||
ingress.getSpec().getRules().get(0).getHttp().getPaths().get(0).setPath("/wiremock-" + namespace);
|
||||
networkingApi.createNamespacedIngress(namespace, ingress, null, null, null, null);
|
||||
k8SUtils.waitForIngress(ingress.getMetadata().getName(), namespace);
|
||||
}
|
||||
|
||||
private static V1Deployment getDiscoveryServerDeployment() throws Exception {
|
||||
V1Deployment deployment = (V1Deployment) K8SUtils
|
||||
.readYamlFromClasspath("server/spring-cloud-kubernetes-discoveryserver-deployment.yaml");
|
||||
String image = deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getImage() + ":"
|
||||
+ getPomVersion();
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setImage(image);
|
||||
// setup all-namespaces property
|
||||
V1EnvVar env = new V1EnvVarBuilder().withName("SPRING_CLOUD_KUBERNETES_DISCOVERY_ALL_NAMESPACES")
|
||||
.withValue("TRUE").build();
|
||||
V1Container container = deployment.getSpec().getTemplate().getSpec().getContainers().get(0);
|
||||
container.setEnv(List.of(env));
|
||||
|
||||
return deployment;
|
||||
}
|
||||
|
||||
private static V1Ingress getDiscoveryServerIngress() throws Exception {
|
||||
return (V1Ingress) K8SUtils
|
||||
.readYamlFromClasspath("server/spring-cloud-kubernetes-discoveryserver-ingress.yaml");
|
||||
}
|
||||
|
||||
private static V1Service getDiscoveryServerService() throws Exception {
|
||||
return (V1Service) K8SUtils
|
||||
.readYamlFromClasspath("server/spring-cloud-kubernetes-discoveryserver-service.yaml");
|
||||
}
|
||||
|
||||
private static V1Ingress getDiscoveryItIngress() throws Exception {
|
||||
return (V1Ingress) K8SUtils
|
||||
.readYamlFromClasspath("client/spring-cloud-kubernetes-discoveryclient-it-ingress.yaml");
|
||||
}
|
||||
|
||||
private static V1Service getDiscoveryService() throws Exception {
|
||||
return (V1Service) K8SUtils
|
||||
.readYamlFromClasspath("client/spring-cloud-kubernetes-discoveryclient-it-service.yaml");
|
||||
}
|
||||
|
||||
private static V1ClusterRoleBinding getClusterRoleBinding() throws Exception {
|
||||
return (V1ClusterRoleBinding) K8SUtils
|
||||
.readYamlFromClasspath("namespace-filter/cluster-admin-serviceaccount-role.yaml");
|
||||
}
|
||||
|
||||
private static V1Deployment getMockServiceDeployment() throws Exception {
|
||||
return (V1Deployment) K8SUtils.readYamlFromClasspath("wiremock/discovery-wiremock-deployment.yaml");
|
||||
}
|
||||
|
||||
private static V1Service getMockServiceService() throws Exception {
|
||||
|
||||
return (V1Service) K8SUtils.readYamlFromClasspath("wiremock/discovery-wiremock-service.yaml");
|
||||
}
|
||||
|
||||
private static V1Ingress getMockIngress() throws Exception {
|
||||
return (V1Ingress) K8SUtils.readYamlFromClasspath("wiremock/discovery-wiremock-ingress.yaml");
|
||||
util.createAndWait(NAMESPACE, null, deployment, service, ingress, true);
|
||||
}
|
||||
else {
|
||||
util.deleteAndWait(NAMESPACE, deployment, service, ingress);
|
||||
}
|
||||
}
|
||||
|
||||
private WebClient.Builder builder() {
|
||||
|
||||
@@ -21,17 +21,10 @@ import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import io.kubernetes.client.openapi.ApiException;
|
||||
import io.kubernetes.client.openapi.apis.AppsV1Api;
|
||||
import io.kubernetes.client.openapi.apis.CoreV1Api;
|
||||
import io.kubernetes.client.openapi.apis.NetworkingV1Api;
|
||||
import io.kubernetes.client.openapi.models.V1Deployment;
|
||||
import io.kubernetes.client.openapi.models.V1Ingress;
|
||||
import io.kubernetes.client.openapi.models.V1Service;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.k3s.K3sContainer;
|
||||
@@ -40,7 +33,8 @@ import reactor.util.retry.Retry;
|
||||
import reactor.util.retry.RetryBackoffSpec;
|
||||
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Commons;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils;
|
||||
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;
|
||||
@@ -48,36 +42,22 @@ import org.springframework.http.client.reactive.ReactorClientHttpConnector;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils.createApiClient;
|
||||
import static org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils.getPomVersion;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
class DiscoveryClientIT {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(DiscoveryClientIT.class);
|
||||
|
||||
private static final String DISCOVERY_SERVER_DEPLOYMENT_NAME = "spring-cloud-kubernetes-discoveryserver-deployment";
|
||||
|
||||
private static final String DISCOVERY_SERVER_APP_NAME = "spring-cloud-kubernetes-discoveryserver";
|
||||
|
||||
private static final String SPRING_CLOUD_K8S_DISCOVERY_CLIENT_DEPLOYMENT_NAME = "spring-cloud-kubernetes-discoveryclient-it-deployment";
|
||||
|
||||
private static final String SPRING_CLOUD_K8S_DISCOVERY_CLIENT_APP_NAME = "spring-cloud-kubernetes-discoveryclient-it";
|
||||
|
||||
private static final String NAMESPACE = "default";
|
||||
|
||||
private static CoreV1Api api;
|
||||
|
||||
private static AppsV1Api appsApi;
|
||||
|
||||
private static NetworkingV1Api networkingApi;
|
||||
|
||||
private static K8SUtils k8SUtils;
|
||||
|
||||
private static final K3sContainer K3S = Commons.container();
|
||||
|
||||
private static Util util;
|
||||
|
||||
@BeforeAll
|
||||
static void beforeAll() throws Exception {
|
||||
K3S.start();
|
||||
@@ -87,21 +67,10 @@ class DiscoveryClientIT {
|
||||
|
||||
Commons.validateImage(SPRING_CLOUD_K8S_DISCOVERY_CLIENT_APP_NAME, K3S);
|
||||
Commons.loadSpringCloudKubernetesImage(SPRING_CLOUD_K8S_DISCOVERY_CLIENT_APP_NAME, K3S);
|
||||
util = new Util(K3S);
|
||||
util.setUp(NAMESPACE);
|
||||
discoveryServer(Phase.CREATE);
|
||||
|
||||
createApiClient(K3S.getKubeConfigYaml());
|
||||
api = new CoreV1Api();
|
||||
appsApi = new AppsV1Api();
|
||||
networkingApi = new NetworkingV1Api();
|
||||
k8SUtils = new K8SUtils(api, appsApi);
|
||||
k8SUtils.setUp(NAMESPACE);
|
||||
|
||||
deployDiscoveryServer();
|
||||
|
||||
// Check to make sure the discovery server deployment is ready
|
||||
k8SUtils.waitForDeployment(DISCOVERY_SERVER_DEPLOYMENT_NAME, NAMESPACE);
|
||||
|
||||
// Check to see if endpoint is ready
|
||||
k8SUtils.waitForEndpointReady(DISCOVERY_SERVER_APP_NAME, NAMESPACE);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
@@ -109,45 +78,23 @@ class DiscoveryClientIT {
|
||||
Commons.cleanUp(DISCOVERY_SERVER_APP_NAME, K3S);
|
||||
Commons.cleanUp(SPRING_CLOUD_K8S_DISCOVERY_CLIENT_APP_NAME, K3S);
|
||||
|
||||
appsApi.deleteCollectionNamespacedDeployment(NAMESPACE, null, null, null,
|
||||
"metadata.name=" + DISCOVERY_SERVER_DEPLOYMENT_NAME, null, null, null, null, null, null, null, null,
|
||||
null);
|
||||
|
||||
api.deleteNamespacedService(DISCOVERY_SERVER_APP_NAME, NAMESPACE, null, null, null, null, null, null);
|
||||
networkingApi.deleteNamespacedIngress("discoveryserver-ingress", NAMESPACE, null, null, null, null, null, null);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void afterEach() throws ApiException {
|
||||
cleanup();
|
||||
discoveryServer(Phase.DELETE);
|
||||
discoveryIt(Phase.DELETE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDiscoveryClient() throws Exception {
|
||||
deployDiscoveryIt();
|
||||
void testDiscoveryClient() {
|
||||
discoveryIt(Phase.CREATE);
|
||||
testLoadBalancer();
|
||||
testHealth();
|
||||
}
|
||||
|
||||
private void cleanup() throws ApiException {
|
||||
appsApi.deleteCollectionNamespacedDeployment(NAMESPACE, null, null, null,
|
||||
"metadata.name=" + SPRING_CLOUD_K8S_DISCOVERY_CLIENT_DEPLOYMENT_NAME, null, null, null, null, null,
|
||||
null, null, null, null);
|
||||
api.deleteNamespacedService(SPRING_CLOUD_K8S_DISCOVERY_CLIENT_APP_NAME, NAMESPACE, null, null, null, null, null,
|
||||
null);
|
||||
networkingApi.deleteNamespacedIngress("it-ingress", NAMESPACE, null, null, null, null, null, null);
|
||||
}
|
||||
|
||||
private void testLoadBalancer() {
|
||||
|
||||
// Check to make sure the controller deployment is ready
|
||||
k8SUtils.waitForDeployment(SPRING_CLOUD_K8S_DISCOVERY_CLIENT_DEPLOYMENT_NAME, NAMESPACE);
|
||||
WebClient.Builder builder = builder();
|
||||
WebClient serviceClient = builder.baseUrl("http://localhost:80/discoveryclient-it/services").build();
|
||||
|
||||
String[] result = serviceClient.method(HttpMethod.GET).retrieve().bodyToMono(String[].class)
|
||||
.retryWhen(retrySpec()).block();
|
||||
LOG.info("Services: " + Arrays.toString(result));
|
||||
assertThat(Arrays.stream(result).anyMatch("spring-cloud-kubernetes-discoveryserver"::equalsIgnoreCase))
|
||||
.isTrue();
|
||||
|
||||
@@ -170,60 +117,32 @@ class DiscoveryClientIT {
|
||||
assertThat(discoveryComposite.get("status")).isEqualTo("UP");
|
||||
}
|
||||
|
||||
private void deployDiscoveryIt() throws Exception {
|
||||
appsApi.createNamespacedDeployment(NAMESPACE, getDiscoveryItDeployment(), null, null, null, null);
|
||||
api.createNamespacedService(NAMESPACE, getDiscoveryService(), null, null, null, null);
|
||||
private static void discoveryIt(Phase phase) {
|
||||
V1Deployment deployment = (V1Deployment) util
|
||||
.yaml("client/spring-cloud-kubernetes-discoveryclient-it-deployment.yaml");
|
||||
V1Service service = (V1Service) util.yaml("client/spring-cloud-kubernetes-discoveryclient-it-service.yaml");
|
||||
V1Ingress ingress = (V1Ingress) util.yaml("client/spring-cloud-kubernetes-discoveryclient-it-ingress.yaml");
|
||||
|
||||
V1Ingress ingress = getDiscoveryItIngress();
|
||||
networkingApi.createNamespacedIngress(NAMESPACE, ingress, null, null, null, null);
|
||||
k8SUtils.waitForIngress(ingress.getMetadata().getName(), NAMESPACE);
|
||||
if (phase.equals(Phase.CREATE)) {
|
||||
util.createAndWait(NAMESPACE, null, deployment, service, ingress, true);
|
||||
}
|
||||
else {
|
||||
util.deleteAndWait(NAMESPACE, deployment, service, ingress);
|
||||
}
|
||||
}
|
||||
|
||||
private V1Deployment getDiscoveryItDeployment() throws Exception {
|
||||
V1Deployment deployment = (V1Deployment) k8SUtils
|
||||
.readYamlFromClasspath("client/spring-cloud-kubernetes-discoveryclient-it-deployment.yaml");
|
||||
String image = deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getImage() + ":"
|
||||
+ getPomVersion();
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setImage(image);
|
||||
return deployment;
|
||||
}
|
||||
private static void discoveryServer(Phase phase) {
|
||||
V1Deployment deployment = (V1Deployment) util
|
||||
.yaml("server/spring-cloud-kubernetes-discoveryserver-deployment.yaml");
|
||||
V1Service service = (V1Service) util.yaml("server/spring-cloud-kubernetes-discoveryserver-service.yaml");
|
||||
V1Ingress ingress = (V1Ingress) util.yaml("server/spring-cloud-kubernetes-discoveryserver-ingress.yaml");
|
||||
|
||||
private static void deployDiscoveryServer() throws Exception {
|
||||
appsApi.createNamespacedDeployment(NAMESPACE, getDiscoveryServerDeployment(), null, null, null, null);
|
||||
api.createNamespacedService(NAMESPACE, getDiscoveryServerService(), null, null, null, null);
|
||||
|
||||
V1Ingress ingress = getDiscoveryServerIngress();
|
||||
networkingApi.createNamespacedIngress(NAMESPACE, ingress, null, null, null, null);
|
||||
k8SUtils.waitForIngress(ingress.getMetadata().getName(), NAMESPACE);
|
||||
}
|
||||
|
||||
private static V1Deployment getDiscoveryServerDeployment() throws Exception {
|
||||
V1Deployment deployment = (V1Deployment) k8SUtils
|
||||
.readYamlFromClasspath("server/spring-cloud-kubernetes-discoveryserver-deployment.yaml");
|
||||
String image = deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getImage() + ":"
|
||||
+ getPomVersion();
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setImage(image);
|
||||
return deployment;
|
||||
}
|
||||
|
||||
private static V1Ingress getDiscoveryServerIngress() throws Exception {
|
||||
return (V1Ingress) K8SUtils
|
||||
.readYamlFromClasspath("server/spring-cloud-kubernetes-discoveryserver-ingress.yaml");
|
||||
}
|
||||
|
||||
private static V1Service getDiscoveryServerService() throws Exception {
|
||||
return (V1Service) K8SUtils
|
||||
.readYamlFromClasspath("server/spring-cloud-kubernetes-discoveryserver-service.yaml");
|
||||
}
|
||||
|
||||
private V1Ingress getDiscoveryItIngress() throws Exception {
|
||||
return (V1Ingress) K8SUtils
|
||||
.readYamlFromClasspath("client/spring-cloud-kubernetes-discoveryclient-it-ingress.yaml");
|
||||
}
|
||||
|
||||
private V1Service getDiscoveryService() throws Exception {
|
||||
return (V1Service) K8SUtils
|
||||
.readYamlFromClasspath("client/spring-cloud-kubernetes-discoveryclient-it-service.yaml");
|
||||
if (phase.equals(Phase.CREATE)) {
|
||||
util.createAndWait(NAMESPACE, null, deployment, service, ingress, true);
|
||||
}
|
||||
else {
|
||||
util.deleteAndWait(NAMESPACE, deployment, service, ingress);
|
||||
}
|
||||
}
|
||||
|
||||
private WebClient.Builder builder() {
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: wiremock-deployment
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: wiremock
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: wiremock
|
||||
spec:
|
||||
containers:
|
||||
- name: wiremock
|
||||
image: wiremock/wiremock:2.32.0
|
||||
imagePullPolicy: IfNotPresent
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
port: 8080
|
||||
path: /__admin/mappings
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
port: 8080
|
||||
path: /__admin/mappings
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
@@ -1,15 +0,0 @@
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: wiremock-ingress
|
||||
spec:
|
||||
rules:
|
||||
- http:
|
||||
paths:
|
||||
- path: /wiremock
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: wiremock
|
||||
port:
|
||||
number: 8080
|
||||
@@ -1,14 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app: wiremock
|
||||
name: wiremock
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 8080
|
||||
targetPort: 8080
|
||||
selector:
|
||||
app: wiremock
|
||||
type: ClusterIP
|
||||
@@ -24,10 +24,7 @@ import java.util.Objects;
|
||||
import io.fabric8.kubernetes.api.model.Service;
|
||||
import io.fabric8.kubernetes.api.model.apps.Deployment;
|
||||
import io.fabric8.kubernetes.api.model.networking.v1.Ingress;
|
||||
import io.fabric8.kubernetes.client.Config;
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
import io.fabric8.kubernetes.client.KubernetesClientBuilder;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@@ -39,8 +36,8 @@ 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.Fabric8Utils;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils;
|
||||
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;
|
||||
@@ -62,36 +59,23 @@ class Fabric8CatalogWatchIT {
|
||||
|
||||
private static KubernetesClient client;
|
||||
|
||||
private static String busyboxServiceName;
|
||||
|
||||
private static String busyboxDeploymentName;
|
||||
|
||||
private static String appDeploymentName;
|
||||
|
||||
private static String appServiceName;
|
||||
|
||||
private static String appIngressName;
|
||||
private static Util util;
|
||||
|
||||
@BeforeAll
|
||||
static void beforeAll() throws Exception {
|
||||
K3S.start();
|
||||
Config config = Config.fromKubeconfig(K3S.getKubeConfigYaml());
|
||||
client = new KubernetesClientBuilder().withConfig(config).build();
|
||||
util = new Util(K3S);
|
||||
client = util.client();
|
||||
|
||||
Commons.validateImage(APP_NAME, K3S);
|
||||
Commons.loadSpringCloudKubernetesImage(APP_NAME, K3S);
|
||||
|
||||
Fabric8Utils.setUp(client, "default");
|
||||
util.setUp(NAMESPACE);
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() throws Exception {
|
||||
deployBusyboxManifests();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void afterEach() {
|
||||
deleteApp();
|
||||
void beforeEach() {
|
||||
util.busybox(NAMESPACE, Phase.CREATE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -104,16 +88,18 @@ class Fabric8CatalogWatchIT {
|
||||
*/
|
||||
@Test
|
||||
void testCatalogWatchWithEndpoints() throws Exception {
|
||||
deployApp(false);
|
||||
app(false, Phase.CREATE);
|
||||
assertLogStatement("stateGenerator is of type: Fabric8EndpointsCatalogWatch");
|
||||
test();
|
||||
app(false, Phase.DELETE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCatalogWatchWithEndpointSlices() throws Exception {
|
||||
deployApp(true);
|
||||
app(true, Phase.CREATE);
|
||||
assertLogStatement("stateGenerator is of type: Fabric8EndpointSliceV1CatalogWatch");
|
||||
test();
|
||||
app(true, Phase.DELETE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -169,7 +155,7 @@ class Fabric8CatalogWatchIT {
|
||||
Assertions.assertEquals("default", resultOne.namespace());
|
||||
Assertions.assertEquals("default", resultTwo.namespace());
|
||||
|
||||
deleteBusyboxApp();
|
||||
util.busybox(NAMESPACE, Phase.DELETE);
|
||||
|
||||
// what we get after delete
|
||||
EndpointNameAndNamespace[] afterDelete = new EndpointNameAndNamespace[1];
|
||||
@@ -202,87 +188,26 @@ class Fabric8CatalogWatchIT {
|
||||
|
||||
}
|
||||
|
||||
private void deployBusyboxManifests() throws Exception {
|
||||
private static void app(boolean useEndpointSlices, Phase phase) {
|
||||
|
||||
Deployment deployment = client.apps().deployments().load(getBusyboxDeployment()).get();
|
||||
InputStream endpointsDeploymentStream = util.inputStream("app/watcher-endpoints-deployment.yaml");
|
||||
InputStream endpointSlicesDeploymentStream = util.inputStream("app/watcher-endpoint-slices-deployment.yaml");
|
||||
InputStream serviceStream = util.inputStream("app/watcher-service.yaml");
|
||||
InputStream ingressStream = util.inputStream("app/watcher-ingress.yaml");
|
||||
|
||||
String[] image = K8SUtils.getImageFromDeployment(deployment).split(":");
|
||||
Commons.pullImage(image[0], image[1], K3S);
|
||||
Commons.loadImage(image[0], image[1], "busybox", K3S);
|
||||
Deployment deployment = useEndpointSlices
|
||||
? client.apps().deployments().load(endpointSlicesDeploymentStream).get()
|
||||
: client.apps().deployments().load(endpointsDeploymentStream).get();
|
||||
Service service = client.services().load(serviceStream).get();
|
||||
Ingress ingress = client.network().v1().ingresses().load(ingressStream).get();
|
||||
|
||||
client.apps().deployments().inNamespace(NAMESPACE).resource(deployment).create();
|
||||
busyboxDeploymentName = deployment.getMetadata().getName();
|
||||
if (phase.equals(Phase.CREATE)) {
|
||||
util.createAndWait(Fabric8CatalogWatchIT.NAMESPACE, null, deployment, service, ingress, true);
|
||||
}
|
||||
else {
|
||||
util.deleteAndWait(Fabric8CatalogWatchIT.NAMESPACE, deployment, service, ingress);
|
||||
}
|
||||
|
||||
Service busyboxService = client.services().load(getBusyboxService()).get();
|
||||
busyboxServiceName = busyboxService.getMetadata().getName();
|
||||
client.services().inNamespace(NAMESPACE).resource(busyboxService).create();
|
||||
|
||||
Fabric8Utils.waitForDeployment(client, busyboxDeploymentName, NAMESPACE, 2, 600);
|
||||
|
||||
}
|
||||
|
||||
private static void deployApp(boolean useEndpointSlices) {
|
||||
|
||||
InputStream deployment = useEndpointSlices ? getEndpointSlicesAppDeployment() : getEndpointsAppDeployment();
|
||||
Deployment appDeployment = client.apps().deployments().load(deployment).get();
|
||||
|
||||
String version = K8SUtils.getPomVersion();
|
||||
String currentImage = appDeployment.getSpec().getTemplate().getSpec().getContainers().get(0).getImage();
|
||||
appDeployment.getSpec().getTemplate().getSpec().getContainers().get(0).setImage(currentImage + ":" + version);
|
||||
|
||||
client.apps().deployments().inNamespace(NAMESPACE).resource(appDeployment).create();
|
||||
appDeploymentName = appDeployment.getMetadata().getName();
|
||||
|
||||
Service appService = client.services().load(getAppService()).get();
|
||||
appServiceName = appService.getMetadata().getName();
|
||||
client.services().inNamespace(NAMESPACE).resource(appService).create();
|
||||
|
||||
Fabric8Utils.waitForDeployment(client, appDeploymentName, NAMESPACE, 2, 600);
|
||||
|
||||
Ingress appIngress = client.network().v1().ingresses().load(getAppIngress()).get();
|
||||
appIngressName = appIngress.getMetadata().getName();
|
||||
client.network().v1().ingresses().inNamespace(NAMESPACE).resource(appIngress).create();
|
||||
|
||||
Fabric8Utils.waitForIngress(client, appIngressName, NAMESPACE);
|
||||
|
||||
}
|
||||
|
||||
private void deleteBusyboxApp() {
|
||||
Fabric8Utils.deleteDeployment(client, NAMESPACE, busyboxDeploymentName);
|
||||
Fabric8Utils.deleteService(client, NAMESPACE, busyboxServiceName);
|
||||
}
|
||||
|
||||
private void deleteApp() {
|
||||
Fabric8Utils.deleteDeployment(client, NAMESPACE, appDeploymentName);
|
||||
Fabric8Utils.deleteService(client, NAMESPACE, appServiceName);
|
||||
Fabric8Utils.deleteIngress(client, NAMESPACE, appIngressName);
|
||||
}
|
||||
|
||||
private static InputStream getBusyboxService() {
|
||||
return Fabric8Utils.inputStream("busybox/service.yaml");
|
||||
}
|
||||
|
||||
private static InputStream getBusyboxDeployment() {
|
||||
return Fabric8Utils.inputStream("busybox/deployment.yaml");
|
||||
}
|
||||
|
||||
/**
|
||||
* deployment where support for endpoint slices is equal to false
|
||||
*/
|
||||
private static InputStream getEndpointsAppDeployment() {
|
||||
return Fabric8Utils.inputStream("app/watcher-endpoints-deployment.yaml");
|
||||
}
|
||||
|
||||
private static InputStream getEndpointSlicesAppDeployment() {
|
||||
return Fabric8Utils.inputStream("app/watcher-endpoint-slices-deployment.yaml");
|
||||
}
|
||||
|
||||
private static InputStream getAppIngress() {
|
||||
return Fabric8Utils.inputStream("app/watcher-ingress.yaml");
|
||||
}
|
||||
|
||||
private static InputStream getAppService() {
|
||||
return Fabric8Utils.inputStream("app/watcher-service.yaml");
|
||||
}
|
||||
|
||||
private WebClient.Builder builder() {
|
||||
|
||||
@@ -25,14 +25,11 @@ import java.util.Set;
|
||||
|
||||
import io.fabric8.kubernetes.api.model.EnvVar;
|
||||
import io.fabric8.kubernetes.api.model.EnvVarBuilder;
|
||||
import io.fabric8.kubernetes.api.model.NamespaceBuilder;
|
||||
import io.fabric8.kubernetes.api.model.Service;
|
||||
import io.fabric8.kubernetes.api.model.apps.Deployment;
|
||||
import io.fabric8.kubernetes.api.model.networking.v1.Ingress;
|
||||
import io.fabric8.kubernetes.client.Config;
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
import io.fabric8.kubernetes.client.KubernetesClientBuilder;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@@ -44,8 +41,8 @@ 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.Fabric8Utils;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils;
|
||||
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;
|
||||
@@ -71,46 +68,33 @@ class Fabric8CatalogWatchWithNamespacesIT {
|
||||
|
||||
private static KubernetesClient client;
|
||||
|
||||
private static String busyboxServiceNameA;
|
||||
|
||||
private static String busyboxServiceNameB;
|
||||
|
||||
private static String busyboxDeploymentNameA;
|
||||
|
||||
private static String busyboxDeploymentNameB;
|
||||
|
||||
private static String appDeploymentName;
|
||||
|
||||
private static String appServiceName;
|
||||
|
||||
private static String appIngressName;
|
||||
private static Util util;
|
||||
|
||||
@BeforeAll
|
||||
static void beforeAll() throws Exception {
|
||||
K3S.start();
|
||||
Config config = Config.fromKubeconfig(K3S.getKubeConfigYaml());
|
||||
client = new KubernetesClientBuilder().withConfig(config).build();
|
||||
util = new Util(K3S);
|
||||
client = util.client();
|
||||
|
||||
Commons.validateImage(APP_NAME, K3S);
|
||||
Commons.loadSpringCloudKubernetesImage(APP_NAME, K3S);
|
||||
|
||||
util.createNamespace(NAMESPACE_A);
|
||||
util.createNamespace(NAMESPACE_B);
|
||||
|
||||
util.setUpClusterWide(NAMESPACE_DEFAULT, Set.of(NAMESPACE_DEFAULT, NAMESPACE_A, NAMESPACE_B));
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() throws Exception {
|
||||
client.namespaces().resource(new NamespaceBuilder().withNewMetadata().withName(NAMESPACE_A).and().build())
|
||||
.create();
|
||||
client.namespaces().resource(new NamespaceBuilder().withNewMetadata().withName(NAMESPACE_B).and().build())
|
||||
.create();
|
||||
Fabric8Utils.setUpClusterWide(client, NAMESPACE_DEFAULT, Set.of(NAMESPACE_DEFAULT, NAMESPACE_A, NAMESPACE_B));
|
||||
deployBusyboxManifests();
|
||||
void beforeEach() {
|
||||
util.busybox(NAMESPACE_A, Phase.CREATE);
|
||||
util.busybox(NAMESPACE_B, Phase.CREATE);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void afterEach() {
|
||||
Fabric8Utils.cleanUpClusterWide(client, NAMESPACE_DEFAULT, Set.of(NAMESPACE_DEFAULT, NAMESPACE_A, NAMESPACE_B));
|
||||
Fabric8Utils.deleteNamespace(client, NAMESPACE_A);
|
||||
Fabric8Utils.deleteNamespace(client, NAMESPACE_B);
|
||||
deleteApp();
|
||||
@AfterAll
|
||||
static void afterAll() {
|
||||
util.deleteNamespace(NAMESPACE_A);
|
||||
util.deleteNamespace(NAMESPACE_B);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,16 +109,18 @@ class Fabric8CatalogWatchWithNamespacesIT {
|
||||
*/
|
||||
@Test
|
||||
void testCatalogWatchWithEndpoints() throws Exception {
|
||||
deployApp(false);
|
||||
app(false, Phase.CREATE);
|
||||
assertLogStatement("stateGenerator is of type: Fabric8EndpointsCatalogWatch");
|
||||
test();
|
||||
app(false, Phase.DELETE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCatalogWatchWithEndpointSlices() throws Exception {
|
||||
deployApp(true);
|
||||
app(true, Phase.CREATE);
|
||||
assertLogStatement("stateGenerator is of type: Fabric8EndpointSliceV1CatalogWatch");
|
||||
test();
|
||||
app(true, Phase.DELETE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -190,7 +176,8 @@ class Fabric8CatalogWatchWithNamespacesIT {
|
||||
Assertions.assertEquals(NAMESPACE_A, resultOne.namespace());
|
||||
Assertions.assertEquals(NAMESPACE_A, resultTwo.namespace());
|
||||
|
||||
deleteBusyboxApp();
|
||||
util.busybox(NAMESPACE_A, Phase.DELETE);
|
||||
util.busybox(NAMESPACE_B, Phase.DELETE);
|
||||
|
||||
// what we get after delete
|
||||
EndpointNameAndNamespace[] afterDelete = new EndpointNameAndNamespace[1];
|
||||
@@ -223,43 +210,19 @@ class Fabric8CatalogWatchWithNamespacesIT {
|
||||
|
||||
}
|
||||
|
||||
private void deployBusyboxManifests() throws Exception {
|
||||
private static void app(boolean useEndpointSlices, Phase phase) {
|
||||
|
||||
Deployment deployment = client.apps().deployments().load(getBusyboxDeployment()).get();
|
||||
InputStream endpointsDeploymentStream = util.inputStream("app/watcher-endpoints-deployment.yaml");
|
||||
InputStream endpointSlicesDeploymentStream = util.inputStream("app/watcher-endpoint-slices-deployment.yaml");
|
||||
InputStream serviceStream = util.inputStream("app/watcher-service.yaml");
|
||||
InputStream ingressStream = util.inputStream("app/watcher-ingress.yaml");
|
||||
|
||||
String[] image = K8SUtils.getImageFromDeployment(deployment).split(":");
|
||||
Commons.pullImage(image[0], image[1], K3S);
|
||||
Commons.loadImage(image[0], image[1], "busybox", K3S);
|
||||
|
||||
// namespace_a
|
||||
client.apps().deployments().inNamespace(NAMESPACE_A).resource(deployment).create();
|
||||
busyboxDeploymentNameA = deployment.getMetadata().getName();
|
||||
|
||||
Service busyboxServiceA = client.services().load(getBusyboxService()).get();
|
||||
busyboxServiceNameA = busyboxServiceA.getMetadata().getName();
|
||||
client.services().inNamespace(NAMESPACE_A).resource(busyboxServiceA).create();
|
||||
|
||||
Fabric8Utils.waitForDeployment(client, busyboxDeploymentNameA, NAMESPACE_A, 2, 600);
|
||||
|
||||
// namespace_b
|
||||
client.apps().deployments().inNamespace(NAMESPACE_B).resource(deployment).create();
|
||||
busyboxDeploymentNameB = deployment.getMetadata().getName();
|
||||
|
||||
Service busyboxServiceB = client.services().load(getBusyboxService()).get();
|
||||
busyboxServiceNameB = busyboxServiceB.getMetadata().getName();
|
||||
client.services().inNamespace(NAMESPACE_B).resource(busyboxServiceB).create();
|
||||
|
||||
Fabric8Utils.waitForDeployment(client, busyboxDeploymentNameB, NAMESPACE_B, 2, 600);
|
||||
|
||||
}
|
||||
|
||||
private static void deployApp(boolean useEndpointSlices) {
|
||||
|
||||
InputStream deployment = useEndpointSlices ? getEndpointSlicesAppDeployment() : getEndpointsAppDeployment();
|
||||
Deployment appDeployment = client.apps().deployments().load(deployment).get();
|
||||
Deployment deployment = useEndpointSlices
|
||||
? client.apps().deployments().load(endpointSlicesDeploymentStream).get()
|
||||
: client.apps().deployments().load(endpointsDeploymentStream).get();
|
||||
|
||||
List<EnvVar> envVars = new ArrayList<>(
|
||||
appDeployment.getSpec().getTemplate().getSpec().getContainers().get(0).getEnv());
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getEnv());
|
||||
EnvVar namespaceAEnvVar = new EnvVarBuilder().withName("SPRING_CLOUD_KUBERNETES_DISCOVERY_NAMESPACES_0")
|
||||
.withValue(NAMESPACE_A).build();
|
||||
EnvVar namespaceDefaultEnvVar = new EnvVarBuilder().withName("SPRING_CLOUD_KUBERNETES_DISCOVERY_NAMESPACES_1")
|
||||
@@ -267,70 +230,19 @@ class Fabric8CatalogWatchWithNamespacesIT {
|
||||
envVars.add(namespaceAEnvVar);
|
||||
envVars.add(namespaceDefaultEnvVar);
|
||||
|
||||
appDeployment.getSpec().getTemplate().getSpec().getContainers().get(0).setEnv(envVars);
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setEnv(envVars);
|
||||
|
||||
String version = K8SUtils.getPomVersion();
|
||||
String currentImage = appDeployment.getSpec().getTemplate().getSpec().getContainers().get(0).getImage();
|
||||
appDeployment.getSpec().getTemplate().getSpec().getContainers().get(0).setImage(currentImage + ":" + version);
|
||||
Service service = client.services().load(serviceStream).get();
|
||||
Ingress ingress = client.network().v1().ingresses().load(ingressStream).get();
|
||||
|
||||
client.apps().deployments().inNamespace(NAMESPACE_DEFAULT).resource(appDeployment).create();
|
||||
appDeploymentName = appDeployment.getMetadata().getName();
|
||||
if (phase.equals(Phase.CREATE)) {
|
||||
util.createAndWait(Fabric8CatalogWatchWithNamespacesIT.NAMESPACE_DEFAULT, null, deployment, service,
|
||||
ingress, true);
|
||||
}
|
||||
else {
|
||||
util.deleteAndWait(Fabric8CatalogWatchWithNamespacesIT.NAMESPACE_DEFAULT, deployment, service, ingress);
|
||||
}
|
||||
|
||||
Service appService = client.services().load(getAppService()).get();
|
||||
appServiceName = appService.getMetadata().getName();
|
||||
client.services().inNamespace(NAMESPACE_DEFAULT).resource(appService).create();
|
||||
|
||||
Fabric8Utils.waitForDeployment(client, appDeploymentName, NAMESPACE_DEFAULT, 2, 600);
|
||||
|
||||
Ingress appIngress = client.network().v1().ingresses().load(getAppIngress()).get();
|
||||
appIngressName = appIngress.getMetadata().getName();
|
||||
client.network().v1().ingresses().inNamespace(NAMESPACE_DEFAULT).resource(appIngress).create();
|
||||
|
||||
Fabric8Utils.waitForIngress(client, appIngressName, NAMESPACE_DEFAULT);
|
||||
|
||||
}
|
||||
|
||||
private void deleteBusyboxApp() {
|
||||
// namespacea
|
||||
Fabric8Utils.deleteDeployment(client, NAMESPACE_A, busyboxDeploymentNameA);
|
||||
Fabric8Utils.deleteService(client, NAMESPACE_A, busyboxServiceNameA);
|
||||
|
||||
// namespaceb
|
||||
Fabric8Utils.deleteDeployment(client, NAMESPACE_B, busyboxDeploymentNameB);
|
||||
Fabric8Utils.deleteService(client, NAMESPACE_B, busyboxServiceNameB);
|
||||
}
|
||||
|
||||
private void deleteApp() {
|
||||
Fabric8Utils.deleteDeployment(client, NAMESPACE_DEFAULT, appDeploymentName);
|
||||
Fabric8Utils.deleteService(client, NAMESPACE_DEFAULT, appServiceName);
|
||||
Fabric8Utils.deleteIngress(client, NAMESPACE_DEFAULT, appIngressName);
|
||||
}
|
||||
|
||||
private static InputStream getBusyboxService() {
|
||||
return Fabric8Utils.inputStream("busybox/service.yaml");
|
||||
}
|
||||
|
||||
private static InputStream getBusyboxDeployment() {
|
||||
return Fabric8Utils.inputStream("busybox/deployment.yaml");
|
||||
}
|
||||
|
||||
/**
|
||||
* deployment where support for endpoint slices is equal to false
|
||||
*/
|
||||
private static InputStream getEndpointsAppDeployment() {
|
||||
return Fabric8Utils.inputStream("app/watcher-endpoints-deployment.yaml");
|
||||
}
|
||||
|
||||
private static InputStream getEndpointSlicesAppDeployment() {
|
||||
return Fabric8Utils.inputStream("app/watcher-endpoint-slices-deployment.yaml");
|
||||
}
|
||||
|
||||
private static InputStream getAppIngress() {
|
||||
return Fabric8Utils.inputStream("app/watcher-ingress.yaml");
|
||||
}
|
||||
|
||||
private static InputStream getAppService() {
|
||||
return Fabric8Utils.inputStream("app/watcher-service.yaml");
|
||||
}
|
||||
|
||||
private WebClient.Builder builder() {
|
||||
|
||||
@@ -18,6 +18,8 @@ package org.springframework.cloud.kubernetes.fabric8.configmap.event.reload;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
@@ -26,14 +28,13 @@ import java.util.concurrent.locks.LockSupport;
|
||||
|
||||
import io.fabric8.kubernetes.api.model.ConfigMap;
|
||||
import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
|
||||
import io.fabric8.kubernetes.api.model.EnvVar;
|
||||
import io.fabric8.kubernetes.api.model.EnvVarBuilder;
|
||||
import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
|
||||
import io.fabric8.kubernetes.api.model.Service;
|
||||
import io.fabric8.kubernetes.api.model.apps.Deployment;
|
||||
import io.fabric8.kubernetes.api.model.networking.v1.Ingress;
|
||||
import io.fabric8.kubernetes.client.Config;
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
import io.fabric8.kubernetes.client.KubernetesClientBuilder;
|
||||
import io.fabric8.kubernetes.client.dsl.internal.HasMetadataOperation;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
@@ -44,14 +45,13 @@ import reactor.util.retry.Retry;
|
||||
import reactor.util.retry.RetryBackoffSpec;
|
||||
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Commons;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Fabric8Utils;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Phase;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.fabric8_client.Util;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import static org.awaitility.Awaitility.await;
|
||||
import static org.springframework.cloud.kubernetes.integration.tests.commons.Commons.processExecResult;
|
||||
|
||||
/**
|
||||
* @author wind57
|
||||
@@ -62,37 +62,30 @@ class ConfigMapEventReloadIT {
|
||||
|
||||
private static final String NAMESPACE = "default";
|
||||
|
||||
private static KubernetesClient client;
|
||||
|
||||
private static String deploymentName;
|
||||
|
||||
private static String serviceName;
|
||||
|
||||
private static String ingressName;
|
||||
|
||||
private static String leftConfigMapName;
|
||||
|
||||
private static String rightConfigMapName;
|
||||
|
||||
private static String rightWithLabelConfigMapName;
|
||||
|
||||
private static final K3sContainer K3S = Commons.container();
|
||||
|
||||
private static Util util;
|
||||
|
||||
private static KubernetesClient client;
|
||||
|
||||
@BeforeAll
|
||||
static void beforeAll() throws Exception {
|
||||
K3S.start();
|
||||
Commons.validateImage(IMAGE_NAME, K3S);
|
||||
Commons.loadSpringCloudKubernetesImage(IMAGE_NAME, K3S);
|
||||
Config config = Config.fromKubeconfig(K3S.getKubeConfigYaml());
|
||||
client = new KubernetesClientBuilder().withConfig(config).build();
|
||||
|
||||
createNamespaces();
|
||||
Fabric8Utils.setUpClusterWide(client, "default", Set.of("left", "right"));
|
||||
util = new Util(K3S);
|
||||
client = util.client();
|
||||
|
||||
util.createNamespace("left");
|
||||
util.createNamespace("right");
|
||||
util.setUpClusterWide(NAMESPACE, Set.of("left", "right"));
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void afterAll() throws Exception {
|
||||
deleteNamespaces();
|
||||
util.deleteNamespace("left");
|
||||
util.deleteNamespace("right");
|
||||
Commons.cleanUp(IMAGE_NAME, K3S);
|
||||
}
|
||||
|
||||
@@ -106,7 +99,7 @@ class ConfigMapEventReloadIT {
|
||||
*/
|
||||
@Test
|
||||
void testInformFromOneNamespaceEventNotTriggered() {
|
||||
deployManifests("one");
|
||||
manifests("one", Phase.CREATE);
|
||||
|
||||
WebClient webClient = builder().baseUrl("localhost/left").build();
|
||||
String result = webClient.method(HttpMethod.GET).retrieve().bodyToMono(String.class).retryWhen(retrySpec())
|
||||
@@ -125,7 +118,7 @@ class ConfigMapEventReloadIT {
|
||||
.withMetadata(new ObjectMetaBuilder().withNamespace("right").withName("right-configmap").build())
|
||||
.withData(Map.of("right.value", "right-after-change")).build();
|
||||
|
||||
replaceConfigMap(rightConfigMapAfterChange, "right-configmap");
|
||||
replaceConfigMap(rightConfigMapAfterChange);
|
||||
|
||||
// wait dummy for 5 seconds
|
||||
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(5));
|
||||
@@ -135,7 +128,7 @@ class ConfigMapEventReloadIT {
|
||||
// left configmap has not changed, no restart of app has happened
|
||||
Assertions.assertEquals("left-initial", result);
|
||||
|
||||
deleteManifests();
|
||||
manifests("one", Phase.DELETE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -148,7 +141,7 @@ class ConfigMapEventReloadIT {
|
||||
*/
|
||||
@Test
|
||||
void testInformFromOneNamespaceEventTriggered() {
|
||||
deployManifests("two");
|
||||
manifests("two", Phase.CREATE);
|
||||
|
||||
// read the value from the right-configmap
|
||||
WebClient webClient = builder().baseUrl("localhost/right").build();
|
||||
@@ -161,7 +154,7 @@ class ConfigMapEventReloadIT {
|
||||
.withMetadata(new ObjectMetaBuilder().withNamespace("right").withName("right-configmap").build())
|
||||
.withData(Map.of("right.value", "right-after-change")).build();
|
||||
|
||||
replaceConfigMap(rightConfigMapAfterChange, "right-configmap");
|
||||
replaceConfigMap(rightConfigMapAfterChange);
|
||||
|
||||
String[] resultAfterChange = new String[1];
|
||||
await().pollInterval(Duration.ofSeconds(3)).atMost(Duration.ofSeconds(90)).until(() -> {
|
||||
@@ -173,7 +166,7 @@ class ConfigMapEventReloadIT {
|
||||
});
|
||||
Assertions.assertEquals("right-after-change", resultAfterChange[0]);
|
||||
|
||||
deleteManifests();
|
||||
manifests("two", Phase.DELETE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -187,7 +180,7 @@ class ConfigMapEventReloadIT {
|
||||
*/
|
||||
@Test
|
||||
void testInform() {
|
||||
deployManifests("three");
|
||||
manifests("three", Phase.CREATE);
|
||||
|
||||
// read the initial value from the right-configmap
|
||||
WebClient rightWebClient = builder().baseUrl("localhost/right").build();
|
||||
@@ -206,7 +199,7 @@ class ConfigMapEventReloadIT {
|
||||
.withMetadata(new ObjectMetaBuilder().withNamespace("right").withName("right-configmap").build())
|
||||
.withData(Map.of("right.value", "right-after-change")).build();
|
||||
|
||||
replaceConfigMap(rightConfigMapAfterChange, "right-configmap");
|
||||
replaceConfigMap(rightConfigMapAfterChange);
|
||||
|
||||
// sleep for 5 seconds
|
||||
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(5));
|
||||
@@ -222,7 +215,7 @@ class ConfigMapEventReloadIT {
|
||||
new ObjectMetaBuilder().withNamespace("right").withName("right-configmap-with-label").build())
|
||||
.withData(Map.of("right.with.label.value", "right-with-label-after-change")).build();
|
||||
|
||||
replaceConfigMap(rightWithLabelConfigMapAfterChange, "right-configmap-with-label");
|
||||
replaceConfigMap(rightWithLabelConfigMapAfterChange);
|
||||
|
||||
// since we have changed a labeled configmap, app will restart and pick up the new
|
||||
// value
|
||||
@@ -242,111 +235,53 @@ class ConfigMapEventReloadIT {
|
||||
.block();
|
||||
Assertions.assertEquals("right-after-change", rightResult);
|
||||
|
||||
deleteManifests();
|
||||
manifests("three", Phase.DELETE);
|
||||
}
|
||||
|
||||
private static void createNamespaces() throws Exception {
|
||||
processExecResult(K3S.execInContainer("sh", "-c", "kubectl create namespace left"));
|
||||
processExecResult(K3S.execInContainer("sh", "-c", "kubectl create namespace right"));
|
||||
}
|
||||
private static void manifests(String activeProfile, Phase phase) {
|
||||
|
||||
private static void deleteNamespaces() throws Exception {
|
||||
processExecResult(K3S.execInContainer("sh", "-c", "kubectl delete namespace left"));
|
||||
processExecResult(K3S.execInContainer("sh", "-c", "kubectl delete namespace right"));
|
||||
}
|
||||
InputStream deploymentStream = util.inputStream("deployment.yaml");
|
||||
InputStream serviceStream = util.inputStream("service.yaml");
|
||||
InputStream ingressStream = util.inputStream("ingress.yaml");
|
||||
InputStream leftConfigMapStream = util.inputStream("left-configmap.yaml");
|
||||
InputStream rightConfigMapStream = util.inputStream("right-configmap.yaml");
|
||||
InputStream rightWithLabelConfigMapStream = util.inputStream("right-configmap-with-label.yaml");
|
||||
|
||||
private static void deployManifests(String deploymentRoot) {
|
||||
Deployment deployment = client.apps().deployments().load(deploymentStream).get();
|
||||
|
||||
try {
|
||||
List<EnvVar> envVars = new ArrayList<>(
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getEnv());
|
||||
EnvVar activeProfileProperty = new EnvVarBuilder().withName("SPRING_PROFILES_ACTIVE").withValue(activeProfile)
|
||||
.build();
|
||||
envVars.add(activeProfileProperty);
|
||||
|
||||
ConfigMap leftConfigMap = client.configMaps().load(leftConfigMap()).get();
|
||||
leftConfigMapName = leftConfigMap.getMetadata().getName();
|
||||
client.configMaps().create(leftConfigMap);
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setEnv(envVars);
|
||||
|
||||
ConfigMap rightConfigMap = client.configMaps().load(rightConfigMap()).get();
|
||||
rightConfigMapName = rightConfigMap.getMetadata().getName();
|
||||
client.configMaps().create(rightConfigMap);
|
||||
Service service = client.services().load(serviceStream).get();
|
||||
Ingress ingress = client.network().v1().ingresses().load(ingressStream).get();
|
||||
ConfigMap leftConfigMap = client.configMaps().load(leftConfigMapStream).get();
|
||||
ConfigMap rightConfigMap = client.configMaps().load(rightConfigMapStream).get();
|
||||
ConfigMap rightWithLabelConfigMap = client.configMaps().load(rightWithLabelConfigMapStream).get();
|
||||
|
||||
if ("three".equals(deploymentRoot)) {
|
||||
ConfigMap rightWithLabelConfigMap = client.configMaps().load(rightWithLabelConfigMap()).get();
|
||||
rightWithLabelConfigMapName = rightWithLabelConfigMap.getMetadata().getName();
|
||||
client.configMaps().create(rightWithLabelConfigMap);
|
||||
if (phase.equals(Phase.CREATE)) {
|
||||
util.createAndWait("left", leftConfigMap, null);
|
||||
util.createAndWait("right", rightConfigMap, null);
|
||||
if ("three".equals(activeProfile)) {
|
||||
util.createAndWait("right", rightWithLabelConfigMap, null);
|
||||
}
|
||||
|
||||
Deployment deployment = client.apps().deployments().load(getDeployment(deploymentRoot)).get();
|
||||
|
||||
String version = K8SUtils.getPomVersion();
|
||||
String currentImage = deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getImage();
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setImage(currentImage + ":" + version);
|
||||
|
||||
client.apps().deployments().inNamespace(NAMESPACE).create(deployment);
|
||||
deploymentName = deployment.getMetadata().getName();
|
||||
|
||||
Service service = client.services().load(getService()).get();
|
||||
serviceName = service.getMetadata().getName();
|
||||
client.services().inNamespace(NAMESPACE).create(service);
|
||||
|
||||
Ingress ingress = client.network().v1().ingresses().load(getIngress()).get();
|
||||
ingressName = ingress.getMetadata().getName();
|
||||
client.network().v1().ingresses().inNamespace(NAMESPACE).create(ingress);
|
||||
|
||||
Fabric8Utils.waitForDeployment(client,
|
||||
"spring-cloud-kubernetes-fabric8-client-configmap-deployment-event-reload", NAMESPACE, 2, 600);
|
||||
|
||||
util.createAndWait(NAMESPACE, null, deployment, service, ingress, true);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void deleteManifests() {
|
||||
|
||||
try {
|
||||
|
||||
client.configMaps().inNamespace("left").withName(leftConfigMapName).delete();
|
||||
Fabric8Utils.waitForConfigMapDelete(client, "left", leftConfigMapName);
|
||||
client.configMaps().inNamespace("right").withName(rightConfigMapName).delete();
|
||||
Fabric8Utils.waitForConfigMapDelete(client, "right", rightConfigMapName);
|
||||
if (rightWithLabelConfigMapName != null) {
|
||||
client.configMaps().inNamespace("right").withName(rightWithLabelConfigMapName).delete();
|
||||
Fabric8Utils.waitForConfigMapDelete(client, "right", rightWithLabelConfigMapName);
|
||||
else {
|
||||
util.deleteAndWait("left", leftConfigMap, null);
|
||||
util.deleteAndWait("right", rightConfigMap, null);
|
||||
if ("three".equals(activeProfile)) {
|
||||
util.deleteAndWait("right", rightWithLabelConfigMap, null);
|
||||
}
|
||||
client.apps().deployments().inNamespace(NAMESPACE).withName(deploymentName).delete();
|
||||
client.services().inNamespace(NAMESPACE).withName(serviceName).delete();
|
||||
client.network().v1().ingresses().inNamespace(NAMESPACE).withName(ingressName).delete();
|
||||
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
util.deleteAndWait(NAMESPACE, deployment, service, ingress);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static InputStream leftConfigMap() {
|
||||
return Fabric8Utils.inputStream("left-configmap.yaml");
|
||||
}
|
||||
|
||||
private static InputStream rightConfigMap() {
|
||||
return Fabric8Utils.inputStream("right-configmap.yaml");
|
||||
}
|
||||
|
||||
private static InputStream rightWithLabelConfigMap() {
|
||||
return Fabric8Utils.inputStream("right-configmap-with-label.yaml");
|
||||
}
|
||||
|
||||
private static InputStream getDeployment(String root) {
|
||||
return Fabric8Utils.inputStream(root + "/deployment.yaml");
|
||||
}
|
||||
|
||||
private static InputStream getService() {
|
||||
return Fabric8Utils.inputStream("service.yaml");
|
||||
}
|
||||
|
||||
private static InputStream getIngress() {
|
||||
return Fabric8Utils.inputStream("ingress.yaml");
|
||||
}
|
||||
|
||||
private WebClient.Builder builder() {
|
||||
return WebClient.builder().clientConnector(new ReactorClientHttpConnector(HttpClient.create()));
|
||||
}
|
||||
@@ -355,11 +290,8 @@ class ConfigMapEventReloadIT {
|
||||
return Retry.fixedDelay(120, Duration.ofSeconds(2)).filter(Objects::nonNull);
|
||||
}
|
||||
|
||||
// the weird cast comes from :
|
||||
// https://github.com/fabric8io/kubernetes-client/issues/2445
|
||||
@SuppressWarnings({ "unchecked", "raw" })
|
||||
private static void replaceConfigMap(ConfigMap configMap, String name) {
|
||||
((HasMetadataOperation) client.configMaps().inNamespace("right").withName(name)).createOrReplace(configMap);
|
||||
private static void replaceConfigMap(ConfigMap configMap) {
|
||||
client.configMaps().inNamespace("right").resource(configMap).createOrReplace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,6 +26,3 @@ spec:
|
||||
path: /actuator/health/liveness
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
env:
|
||||
- name: SPRING_PROFILES_ACTIVE
|
||||
value: two
|
||||
@@ -1,31 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: spring-cloud-kubernetes-fabric8-client-configmap-deployment-event-reload
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: spring-cloud-kubernetes-fabric8-client-configmap-event-reload
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: spring-cloud-kubernetes-fabric8-client-configmap-event-reload
|
||||
spec:
|
||||
serviceAccountName: spring-cloud-kubernetes-serviceaccount
|
||||
containers:
|
||||
- name: spring-cloud-kubernetes-fabric8-client-configmap-event-reload
|
||||
image: docker.io/springcloud/spring-cloud-kubernetes-fabric8-client-configmap-event-reload
|
||||
imagePullPolicy: IfNotPresent
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
port: 8080
|
||||
path: /actuator/health/readiness
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
port: 8080
|
||||
path: /actuator/health/liveness
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
env:
|
||||
- name: SPRING_PROFILES_ACTIVE
|
||||
value: one
|
||||
@@ -1,31 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: spring-cloud-kubernetes-fabric8-client-configmap-deployment-event-reload
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: spring-cloud-kubernetes-fabric8-client-configmap-event-reload
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: spring-cloud-kubernetes-fabric8-client-configmap-event-reload
|
||||
spec:
|
||||
serviceAccountName: spring-cloud-kubernetes-serviceaccount
|
||||
containers:
|
||||
- name: spring-cloud-kubernetes-fabric8-client-configmap-event-reload
|
||||
image: docker.io/springcloud/spring-cloud-kubernetes-fabric8-client-configmap-event-reload
|
||||
imagePullPolicy: IfNotPresent
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
port: 8080
|
||||
path: /actuator/health/readiness
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
port: 8080
|
||||
path: /actuator/health/liveness
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
env:
|
||||
- name: SPRING_PROFILES_ACTIVE
|
||||
value: three
|
||||
@@ -27,10 +27,7 @@ import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
|
||||
import io.fabric8.kubernetes.api.model.Service;
|
||||
import io.fabric8.kubernetes.api.model.apps.Deployment;
|
||||
import io.fabric8.kubernetes.api.model.networking.v1.Ingress;
|
||||
import io.fabric8.kubernetes.client.Config;
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
import io.fabric8.kubernetes.client.KubernetesClientBuilder;
|
||||
import io.fabric8.kubernetes.client.dsl.internal.HasMetadataOperation;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
@@ -41,8 +38,8 @@ import reactor.util.retry.Retry;
|
||||
import reactor.util.retry.RetryBackoffSpec;
|
||||
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Commons;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Fabric8Utils;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Phase;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.fabric8_client.Util;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
@@ -58,16 +55,10 @@ class ConfigMapPollingReloadIT {
|
||||
|
||||
private static final String NAMESPACE = "default";
|
||||
|
||||
private static Util util;
|
||||
|
||||
private static KubernetesClient client;
|
||||
|
||||
private static String deploymentName;
|
||||
|
||||
private static String serviceName;
|
||||
|
||||
private static String ingressName;
|
||||
|
||||
private static String configMapName;
|
||||
|
||||
private static final K3sContainer K3S = Commons.container();
|
||||
|
||||
@BeforeAll
|
||||
@@ -75,19 +66,18 @@ class ConfigMapPollingReloadIT {
|
||||
K3S.start();
|
||||
Commons.validateImage(IMAGE_NAME, K3S);
|
||||
Commons.loadSpringCloudKubernetesImage(IMAGE_NAME, K3S);
|
||||
Config config = Config.fromKubeconfig(K3S.getKubeConfigYaml());
|
||||
client = new KubernetesClientBuilder().withConfig(config).build();
|
||||
Fabric8Utils.setUp(client, NAMESPACE);
|
||||
deployManifests();
|
||||
util = new Util(K3S);
|
||||
client = util.client();
|
||||
util.setUp(NAMESPACE);
|
||||
manifests(Phase.CREATE);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void after() throws Exception {
|
||||
deleteManifests();
|
||||
manifests(Phase.DELETE);
|
||||
Commons.cleanUp(IMAGE_NAME, K3S);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "raw", "unchecked" })
|
||||
@Test
|
||||
void test() {
|
||||
WebClient webClient = builder().baseUrl("localhost/key").build();
|
||||
@@ -103,83 +93,36 @@ class ConfigMapPollingReloadIT {
|
||||
.withMetadata(new ObjectMetaBuilder().withNamespace("default").withName("poll-reload").build())
|
||||
.withData(Map.of("application.properties", "from.properties.key=after-change")).build();
|
||||
|
||||
// the weird cast comes from :
|
||||
// https://github.com/fabric8io/kubernetes-client/issues/2445
|
||||
((HasMetadataOperation) client.configMaps().inNamespace("default").withName("poll-reload")).resource(map)
|
||||
.createOrReplace();
|
||||
client.configMaps().inNamespace("default").resource(map).createOrReplace();
|
||||
|
||||
await().timeout(Duration.ofSeconds(60)).until(() -> webClient.method(HttpMethod.GET).retrieve()
|
||||
.bodyToMono(String.class).retryWhen(retrySpec()).block().equals("after-change"));
|
||||
|
||||
}
|
||||
|
||||
private static void deleteManifests() {
|
||||
private static void manifests(Phase phase) {
|
||||
|
||||
try {
|
||||
InputStream deploymentStream = util.inputStream("deployment.yaml");
|
||||
InputStream serviceStream = util.inputStream("service.yaml");
|
||||
InputStream ingressStream = util.inputStream("ingress.yaml");
|
||||
InputStream configMapStream = util.inputStream("configmap.yaml");
|
||||
|
||||
client.configMaps().inNamespace(NAMESPACE).withName(configMapName).delete();
|
||||
client.apps().deployments().inNamespace(NAMESPACE).withName(deploymentName).delete();
|
||||
client.services().inNamespace(NAMESPACE).withName(serviceName).delete();
|
||||
client.network().v1().ingresses().inNamespace(NAMESPACE).withName(ingressName).delete();
|
||||
Deployment deployment = client.apps().deployments().load(deploymentStream).get();
|
||||
Service service = client.services().load(serviceStream).get();
|
||||
Ingress ingress = client.network().v1().ingresses().load(ingressStream).get();
|
||||
ConfigMap configMap = client.configMaps().load(configMapStream).get();
|
||||
|
||||
if (phase.equals(Phase.CREATE)) {
|
||||
util.createAndWait(NAMESPACE, configMap, null);
|
||||
util.createAndWait(NAMESPACE, null, deployment, service, ingress, true);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
else {
|
||||
util.deleteAndWait(NAMESPACE, configMap, null);
|
||||
util.deleteAndWait(NAMESPACE, deployment, service, ingress);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void deployManifests() {
|
||||
|
||||
try {
|
||||
|
||||
ConfigMap configMap = client.configMaps().load(getConfigMap()).get();
|
||||
configMapName = configMap.getMetadata().getName();
|
||||
client.configMaps().resource(configMap).create();
|
||||
|
||||
Deployment deployment = client.apps().deployments().load(getDeployment()).get();
|
||||
|
||||
String version = K8SUtils.getPomVersion();
|
||||
String currentImage = deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getImage();
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setImage(currentImage + ":" + version);
|
||||
|
||||
client.apps().deployments().inNamespace(NAMESPACE).create(deployment);
|
||||
deploymentName = deployment.getMetadata().getName();
|
||||
|
||||
Service service = client.services().load(getService()).get();
|
||||
serviceName = service.getMetadata().getName();
|
||||
client.services().inNamespace(NAMESPACE).resource(service).create();
|
||||
|
||||
Ingress ingress = client.network().v1().ingresses().load(getIngress()).get();
|
||||
ingressName = ingress.getMetadata().getName();
|
||||
client.network().v1().ingresses().inNamespace(NAMESPACE).resource(ingress).create();
|
||||
|
||||
Fabric8Utils.waitForDeployment(client,
|
||||
"spring-cloud-kubernetes-fabric8-client-configmap-deployment-polling-reload", NAMESPACE, 2, 600);
|
||||
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static InputStream getService() {
|
||||
return Fabric8Utils.inputStream("service.yaml");
|
||||
}
|
||||
|
||||
private static InputStream getDeployment() {
|
||||
return Fabric8Utils.inputStream("deployment.yaml");
|
||||
}
|
||||
|
||||
private static InputStream getIngress() {
|
||||
return Fabric8Utils.inputStream("ingress.yaml");
|
||||
}
|
||||
|
||||
private static InputStream getConfigMap() {
|
||||
return Fabric8Utils.inputStream("configmap.yaml");
|
||||
}
|
||||
|
||||
private WebClient.Builder builder() {
|
||||
return WebClient.builder().clientConnector(new ReactorClientHttpConnector(HttpClient.create()));
|
||||
}
|
||||
|
||||
@@ -24,9 +24,7 @@ import io.fabric8.kubernetes.api.model.ConfigMap;
|
||||
import io.fabric8.kubernetes.api.model.Service;
|
||||
import io.fabric8.kubernetes.api.model.apps.Deployment;
|
||||
import io.fabric8.kubernetes.api.model.networking.v1.Ingress;
|
||||
import io.fabric8.kubernetes.client.Config;
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
import io.fabric8.kubernetes.client.KubernetesClientBuilder;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
@@ -37,8 +35,8 @@ import reactor.util.retry.Retry;
|
||||
import reactor.util.retry.RetryBackoffSpec;
|
||||
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Commons;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Fabric8Utils;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Phase;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.fabric8_client.Util;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
@@ -51,30 +49,26 @@ class Fabric8ConfigMapIT {
|
||||
|
||||
private static KubernetesClient client;
|
||||
|
||||
private static String deploymentName;
|
||||
|
||||
private static String serviceName;
|
||||
|
||||
private static String ingressName;
|
||||
|
||||
private static String configMapName;
|
||||
|
||||
private static final K3sContainer K3S = Commons.container();
|
||||
|
||||
private static Util util;
|
||||
|
||||
@BeforeAll
|
||||
static void beforeAll() throws Exception {
|
||||
K3S.start();
|
||||
util = new Util(K3S);
|
||||
client = util.client();
|
||||
|
||||
Commons.validateImage(IMAGE_NAME, K3S);
|
||||
Commons.loadSpringCloudKubernetesImage(IMAGE_NAME, K3S);
|
||||
Config config = Config.fromKubeconfig(K3S.getKubeConfigYaml());
|
||||
client = new KubernetesClientBuilder().withConfig(config).build();
|
||||
Fabric8Utils.setUp(client, NAMESPACE);
|
||||
deployManifests();
|
||||
|
||||
util.setUp(NAMESPACE);
|
||||
manifests(Phase.CREATE);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void after() throws Exception {
|
||||
deleteManifests();
|
||||
static void afterAll() throws Exception {
|
||||
manifests(Phase.DELETE);
|
||||
Commons.cleanUp(IMAGE_NAME, K3S);
|
||||
}
|
||||
|
||||
@@ -88,73 +82,29 @@ class Fabric8ConfigMapIT {
|
||||
Assertions.assertEquals("value1", result);
|
||||
}
|
||||
|
||||
private static void deleteManifests() {
|
||||
private static void manifests(Phase phase) {
|
||||
|
||||
try {
|
||||
InputStream deploymentStream = util.inputStream("fabric8-deployment.yaml");
|
||||
InputStream serviceStream = util.inputStream("fabric8-service.yaml");
|
||||
InputStream ingressStream = util.inputStream("fabric8-ingress.yaml");
|
||||
InputStream configMapStream = util.inputStream("fabric8-configmap.yaml");
|
||||
|
||||
client.configMaps().inNamespace(NAMESPACE).withName(configMapName).delete();
|
||||
client.apps().deployments().inNamespace(NAMESPACE).withName(deploymentName).delete();
|
||||
client.services().inNamespace(NAMESPACE).withName(serviceName).delete();
|
||||
client.network().v1().ingresses().inNamespace(NAMESPACE).withName(ingressName).delete();
|
||||
Deployment deployment = client.apps().deployments().load(deploymentStream).get();
|
||||
Service service = client.services().load(serviceStream).get();
|
||||
Ingress ingress = client.network().v1().ingresses().load(ingressStream).get();
|
||||
ConfigMap configMap = client.configMaps().load(configMapStream).get();
|
||||
|
||||
if (phase.equals(Phase.CREATE)) {
|
||||
util.createAndWait(NAMESPACE, configMap, null);
|
||||
util.createAndWait(NAMESPACE, null, deployment, service, ingress, true);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
else {
|
||||
util.deleteAndWait(NAMESPACE, configMap, null);
|
||||
util.deleteAndWait(NAMESPACE, deployment, service, ingress);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void deployManifests() {
|
||||
|
||||
try {
|
||||
|
||||
ConfigMap configMap = client.configMaps().load(getConfigMap()).get();
|
||||
configMapName = configMap.getMetadata().getName();
|
||||
client.configMaps().resource(configMap).create();
|
||||
|
||||
Deployment deployment = client.apps().deployments().load(getDeployment()).get();
|
||||
|
||||
String version = K8SUtils.getPomVersion();
|
||||
String currentImage = deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getImage();
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setImage(currentImage + ":" + version);
|
||||
|
||||
client.apps().deployments().inNamespace(NAMESPACE).resource(deployment).create();
|
||||
deploymentName = deployment.getMetadata().getName();
|
||||
|
||||
Service service = client.services().load(getService()).get();
|
||||
serviceName = service.getMetadata().getName();
|
||||
client.services().inNamespace(NAMESPACE).resource(service).create();
|
||||
|
||||
Ingress ingress = client.network().v1().ingresses().load(getIngress()).get();
|
||||
ingressName = ingress.getMetadata().getName();
|
||||
client.network().v1().ingresses().inNamespace(NAMESPACE).resource(ingress).create();
|
||||
|
||||
Fabric8Utils.waitForDeployment(client, "spring-cloud-kubernetes-fabric8-client-configmap-deployment",
|
||||
NAMESPACE, 2, 600);
|
||||
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static InputStream getService() {
|
||||
return Fabric8Utils.inputStream("fabric8-service.yaml");
|
||||
}
|
||||
|
||||
private static InputStream getDeployment() {
|
||||
return Fabric8Utils.inputStream("fabric8-deployment.yaml");
|
||||
}
|
||||
|
||||
private static InputStream getIngress() {
|
||||
return Fabric8Utils.inputStream("fabric8-ingress.yaml");
|
||||
}
|
||||
|
||||
private static InputStream getConfigMap() {
|
||||
return Fabric8Utils.inputStream("fabric8-configmap.yaml");
|
||||
}
|
||||
|
||||
private WebClient.Builder builder() {
|
||||
return WebClient.builder().clientConnector(new ReactorClientHttpConnector(HttpClient.create()));
|
||||
}
|
||||
|
||||
@@ -24,9 +24,7 @@ import java.util.Objects;
|
||||
import io.fabric8.kubernetes.api.model.Service;
|
||||
import io.fabric8.kubernetes.api.model.apps.Deployment;
|
||||
import io.fabric8.kubernetes.api.model.networking.v1.Ingress;
|
||||
import io.fabric8.kubernetes.client.Config;
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
import io.fabric8.kubernetes.client.KubernetesClientBuilder;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
@@ -37,8 +35,8 @@ import reactor.util.retry.Retry;
|
||||
import reactor.util.retry.RetryBackoffSpec;
|
||||
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Commons;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Fabric8Utils;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Phase;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.fabric8_client.Util;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
@@ -54,17 +52,7 @@ class Fabric8DiscoveryIT {
|
||||
|
||||
private static KubernetesClient client;
|
||||
|
||||
private static String deploymentName;
|
||||
|
||||
private static String serviceName;
|
||||
|
||||
private static String ingressName;
|
||||
|
||||
private static String mockServiceName;
|
||||
|
||||
private static String mockDeploymentName;
|
||||
|
||||
private static String mockDeploymentImage;
|
||||
private static Util util;
|
||||
|
||||
private static final K3sContainer K3S = Commons.container();
|
||||
|
||||
@@ -74,19 +62,20 @@ class Fabric8DiscoveryIT {
|
||||
Commons.validateImage(IMAGE_NAME, K3S);
|
||||
Commons.loadSpringCloudKubernetesImage(IMAGE_NAME, K3S);
|
||||
|
||||
Config config = Config.fromKubeconfig(K3S.getKubeConfigYaml());
|
||||
client = new KubernetesClientBuilder().withConfig(config).build();
|
||||
Fabric8Utils.setUp(client, NAMESPACE);
|
||||
util = new Util(K3S);
|
||||
client = util.client();
|
||||
|
||||
deployManifests();
|
||||
deployMockManifests();
|
||||
util.setUp(NAMESPACE);
|
||||
|
||||
manifests(Phase.CREATE);
|
||||
util.wiremock(NAMESPACE, "/wiremock", Phase.CREATE);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void after() throws Exception {
|
||||
deleteManifests();
|
||||
util.wiremock(NAMESPACE, "/wiremock", Phase.DELETE);
|
||||
manifests(Phase.DELETE);
|
||||
Commons.cleanUp(IMAGE_NAME, K3S);
|
||||
Commons.cleanUpDownloadedImage(mockDeploymentImage);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -100,103 +89,28 @@ class Fabric8DiscoveryIT {
|
||||
Assertions.assertEquals(result.size(), 3);
|
||||
Assertions.assertTrue(result.contains("kubernetes"));
|
||||
Assertions.assertTrue(result.contains("spring-cloud-kubernetes-fabric8-client-discovery"));
|
||||
Assertions.assertTrue(result.contains("wiremock"));
|
||||
Assertions.assertTrue(result.contains("service-wiremock"));
|
||||
}
|
||||
|
||||
private static void deleteManifests() {
|
||||
private static void manifests(Phase phase) {
|
||||
|
||||
try {
|
||||
InputStream deploymentStream = util.inputStream("fabric8-discovery-deployment.yaml");
|
||||
InputStream serviceStream = util.inputStream("fabric8-discovery-service.yaml");
|
||||
InputStream ingressStream = util.inputStream("fabric8-discovery-ingress.yaml");
|
||||
|
||||
client.apps().deployments().inNamespace(NAMESPACE).withName(deploymentName).delete();
|
||||
client.services().inNamespace(NAMESPACE).withName(serviceName).delete();
|
||||
client.network().v1().ingresses().inNamespace(NAMESPACE).withName(ingressName).delete();
|
||||
|
||||
client.services().inNamespace(NAMESPACE).withName(mockServiceName).delete();
|
||||
client.apps().deployments().inNamespace(NAMESPACE).withName(mockDeploymentName).delete();
|
||||
Deployment deployment = client.apps().deployments().load(deploymentStream).get();
|
||||
Service service = client.services().load(serviceStream).get();
|
||||
Ingress ingress = client.network().v1().ingresses().load(ingressStream).get();
|
||||
|
||||
if (phase.equals(Phase.CREATE)) {
|
||||
util.createAndWait(NAMESPACE, null, deployment, service, ingress, true);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
else {
|
||||
util.deleteAndWait(NAMESPACE, deployment, service, ingress);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void deployManifests() {
|
||||
|
||||
try {
|
||||
|
||||
Deployment deployment = client.apps().deployments().load(getDeployment()).get();
|
||||
|
||||
String version = K8SUtils.getPomVersion();
|
||||
String currentImage = deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getImage();
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setImage(currentImage + ":" + version);
|
||||
|
||||
client.apps().deployments().inNamespace(NAMESPACE).resource(deployment).create();
|
||||
deploymentName = deployment.getMetadata().getName();
|
||||
|
||||
Service service = client.services().load(getService()).get();
|
||||
serviceName = service.getMetadata().getName();
|
||||
client.services().inNamespace(NAMESPACE).resource(service).create();
|
||||
|
||||
Ingress ingress = client.network().v1().ingresses().load(getIngress()).get();
|
||||
ingressName = ingress.getMetadata().getName();
|
||||
client.network().v1().ingresses().inNamespace(NAMESPACE).resource(ingress).create();
|
||||
|
||||
Fabric8Utils.waitForDeployment(client, "spring-cloud-kubernetes-fabric8-client-discovery-deployment",
|
||||
NAMESPACE, 2, 600);
|
||||
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void deployMockManifests() {
|
||||
|
||||
try {
|
||||
|
||||
Deployment deployment = client.apps().deployments().load(getMockDeployment()).get();
|
||||
String[] image = K8SUtils.getImageFromDeployment(deployment).split(":");
|
||||
Commons.pullImage(image[0], image[1], K3S);
|
||||
Commons.loadImage(image[0], image[1], "wiremock", K3S);
|
||||
client.apps().deployments().inNamespace(NAMESPACE).resource(deployment).create();
|
||||
mockDeploymentName = deployment.getMetadata().getName();
|
||||
mockDeploymentImage = deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getImage();
|
||||
|
||||
Service service = client.services().load(getMockService()).get();
|
||||
mockServiceName = service.getMetadata().getName();
|
||||
client.services().inNamespace(NAMESPACE).resource(service).create();
|
||||
|
||||
Fabric8Utils.waitForDeployment(client, "wiremock-deployment", NAMESPACE, 2, 600);
|
||||
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static InputStream getService() {
|
||||
return Fabric8Utils.inputStream("fabric8-discovery-service.yaml");
|
||||
}
|
||||
|
||||
private static InputStream getDeployment() {
|
||||
return Fabric8Utils.inputStream("fabric8-discovery-deployment.yaml");
|
||||
}
|
||||
|
||||
private static InputStream getIngress() {
|
||||
return Fabric8Utils.inputStream("fabric8-discovery-ingress.yaml");
|
||||
}
|
||||
|
||||
private static InputStream getMockService() {
|
||||
return Fabric8Utils.inputStream("wiremock/wiremock-service.yaml");
|
||||
}
|
||||
|
||||
private static InputStream getMockDeployment() {
|
||||
return Fabric8Utils.inputStream("wiremock/wiremock-deployment.yaml");
|
||||
}
|
||||
|
||||
private WebClient.Builder builder() {
|
||||
return WebClient.builder().clientConnector(new ReactorClientHttpConnector(HttpClient.create()));
|
||||
}
|
||||
|
||||
@@ -18,19 +18,17 @@ package org.springframework.cloud.kubernetes.fabric8.configmap;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import io.fabric8.kubernetes.api.model.Endpoints;
|
||||
import io.fabric8.kubernetes.api.model.EnvVar;
|
||||
import io.fabric8.kubernetes.api.model.Namespace;
|
||||
import io.fabric8.kubernetes.api.model.ObjectMeta;
|
||||
import io.fabric8.kubernetes.api.model.EnvVarBuilder;
|
||||
import io.fabric8.kubernetes.api.model.Service;
|
||||
import io.fabric8.kubernetes.api.model.apps.Deployment;
|
||||
import io.fabric8.kubernetes.api.model.networking.v1.Ingress;
|
||||
import io.fabric8.kubernetes.client.Config;
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
import io.fabric8.kubernetes.client.KubernetesClientBuilder;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
@@ -41,8 +39,8 @@ import reactor.util.retry.Retry;
|
||||
import reactor.util.retry.RetryBackoffSpec;
|
||||
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Commons;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Fabric8Utils;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils;
|
||||
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.http.HttpMethod;
|
||||
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
|
||||
@@ -61,20 +59,10 @@ class Fabric8DiscoveryNamespaceFilterIT {
|
||||
|
||||
private static final String IMAGE_NAME = "spring-cloud-kubernetes-fabric8-client-discovery";
|
||||
|
||||
private static Util util;
|
||||
|
||||
private static KubernetesClient client;
|
||||
|
||||
private static String deploymentName;
|
||||
|
||||
private static String serviceName;
|
||||
|
||||
private static String ingressName;
|
||||
|
||||
private static String mockServiceName;
|
||||
|
||||
private static String mockDeploymentName;
|
||||
|
||||
private static String mockDeploymentImage;
|
||||
|
||||
private static final K3sContainer K3S = Commons.container();
|
||||
|
||||
@BeforeAll
|
||||
@@ -83,19 +71,25 @@ class Fabric8DiscoveryNamespaceFilterIT {
|
||||
Commons.validateImage(IMAGE_NAME, K3S);
|
||||
Commons.loadSpringCloudKubernetesImage(IMAGE_NAME, K3S);
|
||||
|
||||
Config config = Config.fromKubeconfig(K3S.getKubeConfigYaml());
|
||||
client = new KubernetesClientBuilder().withConfig(config).build();
|
||||
Fabric8Utils.setUp(client, NAMESPACE);
|
||||
util = new Util(K3S);
|
||||
client = util.client();
|
||||
util.setUp(NAMESPACE);
|
||||
|
||||
deployManifests();
|
||||
deployMockManifests();
|
||||
manifests(Phase.CREATE);
|
||||
util.createNamespace(NAMESPACE_LEFT);
|
||||
util.createNamespace(NAMESPACE_RIGHT);
|
||||
util.wiremock(NAMESPACE_LEFT, "/wiremock", Phase.CREATE);
|
||||
util.wiremock(NAMESPACE_RIGHT, "/wiremock", Phase.CREATE);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void after() throws Exception {
|
||||
deleteManifests();
|
||||
manifests(Phase.DELETE);
|
||||
util.wiremock(NAMESPACE_LEFT, "/wiremock", Phase.DELETE);
|
||||
util.wiremock(NAMESPACE_RIGHT, "/wiremock", Phase.DELETE);
|
||||
util.deleteNamespace(NAMESPACE_LEFT);
|
||||
util.deleteNamespace(NAMESPACE_RIGHT);
|
||||
Commons.cleanUp(IMAGE_NAME, K3S);
|
||||
Commons.cleanUpDownloadedImage(mockDeploymentImage);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -107,9 +101,9 @@ class Fabric8DiscoveryNamespaceFilterIT {
|
||||
.retryWhen(retrySpec()).block();
|
||||
|
||||
Assertions.assertEquals(services.size(), 1);
|
||||
Assertions.assertTrue(services.contains("wiremock"));
|
||||
Assertions.assertTrue(services.contains("service-wiremock"));
|
||||
|
||||
WebClient clientEndpoints = builder().baseUrl("localhost/endpoints/wiremock").build();
|
||||
WebClient clientEndpoints = builder().baseUrl("localhost/endpoints/service-wiremock").build();
|
||||
|
||||
List<Endpoints> endpoints = clientEndpoints.method(HttpMethod.GET).retrieve()
|
||||
.bodyToMono(new ParameterizedTypeReference<List<Endpoints>>() {
|
||||
@@ -120,127 +114,36 @@ class Fabric8DiscoveryNamespaceFilterIT {
|
||||
|
||||
}
|
||||
|
||||
private static void deleteManifests() {
|
||||
private static void manifests(Phase phase) {
|
||||
|
||||
try {
|
||||
InputStream deploymentStream = util.inputStream("fabric8-discovery-deployment.yaml");
|
||||
InputStream serviceStream = util.inputStream("fabric8-discovery-service.yaml");
|
||||
InputStream ingressStream = util.inputStream("fabric8-discovery-ingress.yaml");
|
||||
|
||||
client.apps().deployments().inNamespace(NAMESPACE).withName(deploymentName).delete();
|
||||
client.services().inNamespace(NAMESPACE).withName(serviceName).delete();
|
||||
client.network().v1().ingresses().inNamespace(NAMESPACE).withName(ingressName).delete();
|
||||
Deployment deployment = client.apps().deployments().load(deploymentStream).get();
|
||||
List<EnvVar> envVars = new ArrayList<>(
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getEnv());
|
||||
EnvVar activeProfileProperty = new EnvVarBuilder().withName("SPRING_CLOUD_KUBERNETES_DISCOVERY_NAMESPACES_0")
|
||||
.withValue(NAMESPACE_LEFT).build();
|
||||
envVars.add(activeProfileProperty);
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setEnv(envVars);
|
||||
|
||||
client.services().inNamespace(NAMESPACE_LEFT).withName(mockServiceName).delete();
|
||||
client.apps().deployments().inNamespace(NAMESPACE_LEFT).withName(mockDeploymentName).delete();
|
||||
|
||||
client.services().inNamespace(NAMESPACE_RIGHT).withName(mockServiceName).delete();
|
||||
client.apps().deployments().inNamespace(NAMESPACE_RIGHT).withName(mockDeploymentName).delete();
|
||||
|
||||
client.rbac().clusterRoleBindings().withName("admin-default").delete();
|
||||
client.namespaces().withName(NAMESPACE_LEFT).delete();
|
||||
client.namespaces().withName(NAMESPACE_RIGHT).delete();
|
||||
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void deployManifests() {
|
||||
|
||||
try {
|
||||
|
||||
Deployment deployment = client.apps().deployments().load(getDeployment()).get();
|
||||
|
||||
String version = K8SUtils.getPomVersion();
|
||||
String currentImage = deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getImage();
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setImage(currentImage + ":" + version);
|
||||
List<EnvVar> env = deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getEnv();
|
||||
env.add(new EnvVar("SPRING_CLOUD_KUBERNETES_DISCOVERY_NAMESPACES_0", NAMESPACE_LEFT, null));
|
||||
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setEnv(env);
|
||||
|
||||
client.apps().deployments().inNamespace(NAMESPACE).resource(deployment).create();
|
||||
deploymentName = deployment.getMetadata().getName();
|
||||
|
||||
Service service = client.services().load(getService()).get();
|
||||
serviceName = service.getMetadata().getName();
|
||||
client.services().inNamespace(NAMESPACE).resource(service).create();
|
||||
|
||||
Ingress ingress = client.network().v1().ingresses().load(getIngress()).get();
|
||||
ingressName = ingress.getMetadata().getName();
|
||||
client.network().v1().ingresses().inNamespace(NAMESPACE).resource(ingress).create();
|
||||
Service service = client.services().load(serviceStream).get();
|
||||
Ingress ingress = client.network().v1().ingresses().load(ingressStream).get();
|
||||
|
||||
if (phase.equals(Phase.CREATE)) {
|
||||
client.rbac().clusterRoleBindings().resource(client.rbac().clusterRoleBindings().load(getAdminRole()).get())
|
||||
.create();
|
||||
|
||||
Fabric8Utils.waitForDeployment(client, "spring-cloud-kubernetes-fabric8-client-discovery-deployment",
|
||||
NAMESPACE, 2, 600);
|
||||
|
||||
util.createAndWait(NAMESPACE, null, deployment, service, ingress, true);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
else {
|
||||
util.deleteAndWait(NAMESPACE, deployment, service, ingress);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void deployMockManifests() {
|
||||
|
||||
try {
|
||||
deployInMockInNamespace(NAMESPACE_LEFT);
|
||||
deployInMockInNamespace(NAMESPACE_RIGHT);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void deployInMockInNamespace(String namespace) throws Exception {
|
||||
|
||||
Namespace namespaceDef = new Namespace();
|
||||
ObjectMeta meta = new ObjectMeta();
|
||||
meta.setName(namespace);
|
||||
meta.setNamespace(namespace);
|
||||
namespaceDef.setMetadata(meta);
|
||||
client.namespaces().resource(namespaceDef).create();
|
||||
|
||||
Deployment deployment = client.apps().deployments().load(getMockDeployment()).get();
|
||||
String[] image = K8SUtils.getImageFromDeployment(deployment).split(":");
|
||||
Commons.pullImage(image[0], image[1], K3S);
|
||||
Commons.loadImage(image[0], image[1], "wiremock", K3S);
|
||||
client.apps().deployments().inNamespace(namespace).resource(deployment).create();
|
||||
mockDeploymentName = deployment.getMetadata().getName();
|
||||
mockDeploymentImage = deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getImage();
|
||||
|
||||
Service service = client.services().load(getMockService()).get();
|
||||
mockServiceName = service.getMetadata().getName();
|
||||
client.services().inNamespace(namespace).resource(service).create();
|
||||
|
||||
Fabric8Utils.waitForDeployment(client, "wiremock-deployment", namespace, 2, 600);
|
||||
}
|
||||
|
||||
private static InputStream getService() {
|
||||
return Fabric8Utils.inputStream("fabric8-discovery-service.yaml");
|
||||
}
|
||||
|
||||
private static InputStream getDeployment() {
|
||||
return Fabric8Utils.inputStream("fabric8-discovery-deployment.yaml");
|
||||
}
|
||||
|
||||
private static InputStream getAdminRole() {
|
||||
return Fabric8Utils.inputStream("namespace-filter/fabric8-cluster-admin-serviceaccount-role.yaml");
|
||||
}
|
||||
|
||||
private static InputStream getIngress() {
|
||||
return Fabric8Utils.inputStream("fabric8-discovery-ingress.yaml");
|
||||
}
|
||||
|
||||
private static InputStream getMockService() {
|
||||
return Fabric8Utils.inputStream("wiremock/wiremock-service.yaml");
|
||||
}
|
||||
|
||||
private static InputStream getMockDeployment() {
|
||||
return Fabric8Utils.inputStream("wiremock/wiremock-deployment.yaml");
|
||||
return util.inputStream("namespace-filter/fabric8-cluster-admin-serviceaccount-role.yaml");
|
||||
}
|
||||
|
||||
private WebClient.Builder builder() {
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: wiremock-deployment
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: wiremock
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: wiremock
|
||||
spec:
|
||||
containers:
|
||||
- name: wiremock
|
||||
image: wiremock/wiremock:2.32.0
|
||||
imagePullPolicy: IfNotPresent
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
port: 8080
|
||||
path: /__admin/mappings
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
port: 8080
|
||||
path: /__admin/mappings
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
@@ -1,14 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app: wiremock
|
||||
name: wiremock
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 8080
|
||||
targetPort: 8080
|
||||
selector:
|
||||
app: wiremock
|
||||
type: ClusterIP
|
||||
@@ -54,7 +54,7 @@ public class Fabric8ClientLoadbalancerApp {
|
||||
|
||||
@GetMapping("/servicea")
|
||||
public Mono<Map> greeting() {
|
||||
return builder().build().method(HttpMethod.GET).uri(URI.create("http://servicea-wiremock/__admin/mappings"))
|
||||
return builder().build().method(HttpMethod.GET).uri(URI.create("http://service-wiremock/__admin/mappings"))
|
||||
.retrieve().bodyToMono(Map.class);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,17 +18,20 @@ package org.springframework.cloud.kubernetes.client.loadbalancer.it;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import io.fabric8.kubernetes.api.model.EnvVar;
|
||||
import io.fabric8.kubernetes.api.model.EnvVarBuilder;
|
||||
import io.fabric8.kubernetes.api.model.Service;
|
||||
import io.fabric8.kubernetes.api.model.apps.Deployment;
|
||||
import io.fabric8.kubernetes.api.model.networking.v1.Ingress;
|
||||
import io.fabric8.kubernetes.client.Config;
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
import io.fabric8.kubernetes.client.KubernetesClientBuilder;
|
||||
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;
|
||||
@@ -38,14 +41,12 @@ import reactor.util.retry.Retry;
|
||||
import reactor.util.retry.RetryBackoffSpec;
|
||||
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Commons;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Fabric8Utils;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Phase;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.fabric8_client.Util;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author wind57
|
||||
*/
|
||||
@@ -57,17 +58,7 @@ public class Fabric8ClientLoadbalancerIT {
|
||||
|
||||
private static KubernetesClient client;
|
||||
|
||||
private static String deploymentName;
|
||||
|
||||
private static String serviceName;
|
||||
|
||||
private static String ingressName;
|
||||
|
||||
private static String mockServiceName;
|
||||
|
||||
private static String mockDeploymentName;
|
||||
|
||||
private static String mockIngressName;
|
||||
private static Util util;
|
||||
|
||||
private static final K3sContainer K3S = Commons.container();
|
||||
|
||||
@@ -77,9 +68,9 @@ public class Fabric8ClientLoadbalancerIT {
|
||||
Commons.validateImage(IMAGE_NAME, K3S);
|
||||
Commons.loadSpringCloudKubernetesImage(IMAGE_NAME, K3S);
|
||||
|
||||
Config config = Config.fromKubeconfig(K3S.getKubeConfigYaml());
|
||||
client = new KubernetesClientBuilder().withConfig(config).build();
|
||||
Fabric8Utils.setUp(client, NAMESPACE);
|
||||
util = new Util(K3S);
|
||||
client = util.client();
|
||||
util.setUp(NAMESPACE);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
@@ -89,18 +80,18 @@ public class Fabric8ClientLoadbalancerIT {
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
deployMockManifests();
|
||||
util.wiremock(NAMESPACE, "/", Phase.CREATE);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void after() {
|
||||
deleteManifests();
|
||||
void afterEach() {
|
||||
util.wiremock(NAMESPACE, "/", Phase.DELETE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLoadBalancerServiceMode() {
|
||||
|
||||
deployServiceManifests();
|
||||
manifests("SERVICE", Phase.CREATE);
|
||||
|
||||
WebClient client = builder().baseUrl("localhost/loadbalancer-it/servicea").build();
|
||||
|
||||
@@ -108,15 +99,17 @@ public class Fabric8ClientLoadbalancerIT {
|
||||
Map<String, String> mapResult = (Map<String, String>) client.method(HttpMethod.GET).retrieve()
|
||||
.bodyToMono(Map.class).retryWhen(retrySpec()).block();
|
||||
|
||||
assertThat(mapResult.containsKey("mappings")).isTrue();
|
||||
assertThat(mapResult.containsKey("meta")).isTrue();
|
||||
Assertions.assertTrue(mapResult.containsKey("mappings"));
|
||||
Assertions.assertTrue(mapResult.containsKey("meta"));
|
||||
|
||||
manifests("SERVICE", Phase.DELETE);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadBalancerPodMode() {
|
||||
|
||||
deployPodManifests();
|
||||
manifests("POD", Phase.CREATE);
|
||||
|
||||
WebClient client = builder().baseUrl("localhost/loadbalancer-it/servicea").build();
|
||||
|
||||
@@ -124,148 +117,42 @@ public class Fabric8ClientLoadbalancerIT {
|
||||
Map<String, String> mapResult = (Map<String, String>) client.method(HttpMethod.GET).retrieve()
|
||||
.bodyToMono(Map.class).retryWhen(retrySpec()).block();
|
||||
|
||||
assertThat(mapResult.containsKey("mappings")).isTrue();
|
||||
assertThat(mapResult.containsKey("meta")).isTrue();
|
||||
Assertions.assertTrue(mapResult.containsKey("mappings"));
|
||||
Assertions.assertTrue(mapResult.containsKey("meta"));
|
||||
|
||||
manifests("SERVICE", Phase.DELETE);
|
||||
|
||||
}
|
||||
|
||||
private static void deleteManifests() {
|
||||
private static void manifests(String type, Phase phase) {
|
||||
|
||||
try {
|
||||
InputStream deploymentStream = util
|
||||
.inputStream("spring-cloud-kubernetes-fabric8-client-loadbalancer-deployment.yaml");
|
||||
InputStream serviceStream = util
|
||||
.inputStream("spring-cloud-kubernetes-fabric8-client-loadbalancer-service.yaml");
|
||||
InputStream ingressStream = util
|
||||
.inputStream("spring-cloud-kubernetes-fabric8-client-loadbalancer-ingress.yaml");
|
||||
|
||||
client.apps().deployments().inNamespace(NAMESPACE).withName(deploymentName).delete();
|
||||
client.services().inNamespace(NAMESPACE).withName(serviceName).delete();
|
||||
client.network().v1().ingresses().inNamespace(NAMESPACE).withName(ingressName).delete();
|
||||
Deployment deployment = client.apps().deployments().load(deploymentStream).get();
|
||||
List<EnvVar> envVars = new ArrayList<>(
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getEnv());
|
||||
EnvVar activeProfileProperty = new EnvVarBuilder().withName("SPRING_CLOUD_KUBERNETES_LOADBALANCER_MODE")
|
||||
.withValue(type).build();
|
||||
envVars.add(activeProfileProperty);
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setEnv(envVars);
|
||||
|
||||
client.services().inNamespace(NAMESPACE).withName(mockServiceName).delete();
|
||||
client.apps().deployments().inNamespace(NAMESPACE).withName(mockDeploymentName).delete();
|
||||
client.network().v1().ingresses().inNamespace(NAMESPACE).withName(mockIngressName).delete();
|
||||
Service service = client.services().load(serviceStream).get();
|
||||
Ingress ingress = client.network().v1().ingresses().load(ingressStream).get();
|
||||
|
||||
if (phase.equals(Phase.CREATE)) {
|
||||
util.createAndWait(NAMESPACE, null, deployment, service, ingress, true);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
else {
|
||||
util.deleteAndWait(NAMESPACE, deployment, service, ingress);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void deployServiceManifests() {
|
||||
|
||||
try {
|
||||
|
||||
Deployment deployment = client.apps().deployments().load(getServiceDeployment()).get();
|
||||
|
||||
String version = K8SUtils.getPomVersion();
|
||||
String currentImage = deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getImage();
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setImage(currentImage + ":" + version);
|
||||
|
||||
client.apps().deployments().inNamespace(NAMESPACE).resource(deployment).create();
|
||||
deploymentName = deployment.getMetadata().getName();
|
||||
|
||||
Service service = client.services().load(getService()).get();
|
||||
serviceName = service.getMetadata().getName();
|
||||
client.services().inNamespace(NAMESPACE).resource(service).create();
|
||||
|
||||
Ingress ingress = client.network().v1().ingresses().load(getIngress()).get();
|
||||
ingressName = ingress.getMetadata().getName();
|
||||
client.network().v1().ingresses().inNamespace(NAMESPACE).resource(ingress).create();
|
||||
|
||||
Fabric8Utils.waitForDeployment(client, "spring-cloud-kubernetes-fabric8-client-loadbalancer-deployment",
|
||||
NAMESPACE, 2, 600);
|
||||
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void deployPodManifests() {
|
||||
|
||||
try {
|
||||
|
||||
Deployment deployment = client.apps().deployments().load(getPodDeployment()).get();
|
||||
|
||||
String version = K8SUtils.getPomVersion();
|
||||
String currentImage = deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getImage();
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setImage(currentImage + ":" + version);
|
||||
|
||||
client.apps().deployments().inNamespace(NAMESPACE).resource(deployment).create();
|
||||
deploymentName = deployment.getMetadata().getName();
|
||||
|
||||
Service service = client.services().load(getService()).get();
|
||||
serviceName = service.getMetadata().getName();
|
||||
client.services().inNamespace(NAMESPACE).resource(service).create();
|
||||
|
||||
Ingress ingress = client.network().v1().ingresses().load(getIngress()).get();
|
||||
ingressName = ingress.getMetadata().getName();
|
||||
client.network().v1().ingresses().inNamespace(NAMESPACE).resource(ingress).create();
|
||||
|
||||
Fabric8Utils.waitForDeployment(client, "spring-cloud-kubernetes-fabric8-client-loadbalancer-deployment",
|
||||
NAMESPACE, 2, 600);
|
||||
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void deployMockManifests() {
|
||||
|
||||
try {
|
||||
|
||||
Deployment deployment = client.apps().deployments().load(getMockDeployment()).get();
|
||||
String[] image = K8SUtils.getImageFromDeployment(deployment).split(":");
|
||||
Commons.pullImage(image[0], image[1], K3S);
|
||||
Commons.loadImage(image[0], image[1], "wiremock", K3S);
|
||||
client.apps().deployments().inNamespace(NAMESPACE).resource(deployment).create();
|
||||
mockDeploymentName = deployment.getMetadata().getName();
|
||||
|
||||
Service service = client.services().load(getMockService()).get();
|
||||
mockServiceName = service.getMetadata().getName();
|
||||
client.services().inNamespace(NAMESPACE).resource(service).create();
|
||||
|
||||
Ingress ingress = client.network().v1().ingresses().load(getMockIngress()).get();
|
||||
mockIngressName = ingress.getMetadata().getName();
|
||||
|
||||
Fabric8Utils.waitForDeployment(client, "servicea-wiremock-deployment", NAMESPACE, 2, 600);
|
||||
Fabric8Utils.waitForEndpoint(client, "servicea-wiremock", NAMESPACE, 2, 600);
|
||||
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static InputStream getIngress() {
|
||||
return Fabric8Utils.inputStream("spring-cloud-kubernetes-fabric8-client-loadbalancer-ingress.yaml");
|
||||
}
|
||||
|
||||
private static InputStream getService() {
|
||||
return Fabric8Utils.inputStream("spring-cloud-kubernetes-fabric8-client-loadbalancer-service.yaml");
|
||||
}
|
||||
|
||||
private static InputStream getPodDeployment() {
|
||||
return Fabric8Utils.inputStream("spring-cloud-kubernetes-fabric8-client-loadbalancer-pod-deployment.yaml");
|
||||
}
|
||||
|
||||
private static InputStream getServiceDeployment() {
|
||||
return Fabric8Utils.inputStream("spring-cloud-kubernetes-fabric8-client-loadbalancer-service-deployment.yaml");
|
||||
}
|
||||
|
||||
private static InputStream getMockIngress() {
|
||||
return Fabric8Utils.inputStream("wiremock/wiremock-ingress.yaml");
|
||||
}
|
||||
|
||||
private static InputStream getMockService() {
|
||||
return Fabric8Utils.inputStream("wiremock/wiremock-service.yaml");
|
||||
}
|
||||
|
||||
private static InputStream getMockDeployment() {
|
||||
return Fabric8Utils.inputStream("wiremock/wiremock-deployment.yaml");
|
||||
}
|
||||
|
||||
private WebClient.Builder builder() {
|
||||
return WebClient.builder().clientConnector(new ReactorClientHttpConnector(HttpClient.create()));
|
||||
}
|
||||
|
||||
@@ -14,9 +14,6 @@ spec:
|
||||
serviceAccountName: spring-cloud-kubernetes-serviceaccount
|
||||
containers:
|
||||
- name: spring-cloud-kubernetes-fabric8-client-loadbalancer
|
||||
env:
|
||||
- name: SPRING_CLOUD_KUBERNETES_LOADBALANCER_MODE
|
||||
value: POD
|
||||
image: docker.io/springcloud/spring-cloud-kubernetes-fabric8-client-loadbalancer
|
||||
imagePullPolicy: IfNotPresent
|
||||
readinessProbe:
|
||||
@@ -1,31 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: spring-cloud-kubernetes-fabric8-client-loadbalancer-deployment
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: spring-cloud-kubernetes-fabric8-client-loadbalancer
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: spring-cloud-kubernetes-fabric8-client-loadbalancer
|
||||
spec:
|
||||
serviceAccountName: spring-cloud-kubernetes-serviceaccount
|
||||
containers:
|
||||
- name: spring-cloud-kubernetes-fabric8-client-loadbalancer
|
||||
env:
|
||||
- name: SPRING_CLOUD_KUBERNETES_LOADBALANCER_MODE
|
||||
value: SERVICE
|
||||
image: docker.io/springcloud/spring-cloud-kubernetes-fabric8-client-loadbalancer
|
||||
imagePullPolicy: IfNotPresent
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
port: 8080
|
||||
path: /loadbalancer-it/actuator/health/readiness
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
port: 8080
|
||||
path: /loadbalancer-it/actuator/health/liveness
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
@@ -1,27 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: servicea-wiremock-deployment
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: servicea-wiremock
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: servicea-wiremock
|
||||
spec:
|
||||
containers:
|
||||
- name: servicea-wiremock
|
||||
image: wiremock/wiremock:2.32.0
|
||||
imagePullPolicy: IfNotPresent
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
port: 8080
|
||||
path: /__admin/mappings
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
port: 8080
|
||||
path: /__admin/mappings
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
@@ -1,17 +0,0 @@
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: wiremock-ingress
|
||||
namespace: default
|
||||
spec:
|
||||
rules:
|
||||
- http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: servicea-wiremock
|
||||
port:
|
||||
number: 8080
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app: servicea-wiremock
|
||||
name: servicea-wiremock
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 8080
|
||||
targetPort: 8080
|
||||
selector:
|
||||
app: servicea-wiremock
|
||||
type: ClusterIP
|
||||
@@ -28,10 +28,7 @@ import io.fabric8.kubernetes.api.model.SecretBuilder;
|
||||
import io.fabric8.kubernetes.api.model.Service;
|
||||
import io.fabric8.kubernetes.api.model.apps.Deployment;
|
||||
import io.fabric8.kubernetes.api.model.networking.v1.Ingress;
|
||||
import io.fabric8.kubernetes.client.Config;
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
import io.fabric8.kubernetes.client.KubernetesClientBuilder;
|
||||
import io.fabric8.kubernetes.client.dsl.internal.HasMetadataOperation;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
@@ -42,8 +39,8 @@ import reactor.util.retry.Retry;
|
||||
import reactor.util.retry.RetryBackoffSpec;
|
||||
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Commons;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Fabric8Utils;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Phase;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.fabric8_client.Util;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
@@ -61,13 +58,7 @@ class SecretsEventsReloadIT {
|
||||
|
||||
private static KubernetesClient client;
|
||||
|
||||
private static String deploymentName;
|
||||
|
||||
private static String serviceName;
|
||||
|
||||
private static String ingressName;
|
||||
|
||||
private static String secretName;
|
||||
private static Util util;
|
||||
|
||||
private static final K3sContainer K3S = Commons.container();
|
||||
|
||||
@@ -76,19 +67,19 @@ class SecretsEventsReloadIT {
|
||||
K3S.start();
|
||||
Commons.validateImage(IMAGE_NAME, K3S);
|
||||
Commons.loadSpringCloudKubernetesImage(IMAGE_NAME, K3S);
|
||||
Config config = Config.fromKubeconfig(K3S.getKubeConfigYaml());
|
||||
client = new KubernetesClientBuilder().withConfig(config).build();
|
||||
Fabric8Utils.setUp(client, NAMESPACE);
|
||||
deployManifests();
|
||||
|
||||
util = new Util(K3S);
|
||||
client = util.client();
|
||||
util.setUp(NAMESPACE);
|
||||
manifests(Phase.CREATE);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void after() throws Exception {
|
||||
deleteManifests();
|
||||
manifests(Phase.DELETE);
|
||||
Commons.cleanUp(IMAGE_NAME, K3S);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "raw", "unchecked" })
|
||||
@Test
|
||||
void test() {
|
||||
WebClient webClient = builder().baseUrl("localhost/key").build();
|
||||
@@ -106,83 +97,36 @@ class SecretsEventsReloadIT {
|
||||
Base64.getEncoder().encodeToString("from.properties.key=after-change".getBytes())))
|
||||
.build();
|
||||
|
||||
// the weird cast comes from :
|
||||
// https://github.com/fabric8io/kubernetes-client/issues/2445
|
||||
((HasMetadataOperation) client.secrets().inNamespace("default").withName("event-reload"))
|
||||
.createOrReplace(secret);
|
||||
client.secrets().inNamespace("default").resource(secret).createOrReplace();
|
||||
|
||||
await().timeout(Duration.ofSeconds(120)).until(() -> webClient.method(HttpMethod.GET).retrieve()
|
||||
.bodyToMono(String.class).retryWhen(retrySpec()).block().equals("after-change"));
|
||||
|
||||
}
|
||||
|
||||
private static void deleteManifests() {
|
||||
private static void manifests(Phase phase) {
|
||||
|
||||
try {
|
||||
InputStream deploymentStream = util.inputStream("deployment.yaml");
|
||||
InputStream serviceStream = util.inputStream("service.yaml");
|
||||
InputStream ingressStream = util.inputStream("ingress.yaml");
|
||||
InputStream secretStream = util.inputStream("secret.yaml");
|
||||
|
||||
client.secrets().inNamespace(NAMESPACE).withName(secretName).delete();
|
||||
client.apps().deployments().inNamespace(NAMESPACE).withName(deploymentName).delete();
|
||||
client.services().inNamespace(NAMESPACE).withName(serviceName).delete();
|
||||
client.network().v1().ingresses().inNamespace(NAMESPACE).withName(ingressName).delete();
|
||||
Deployment deployment = client.apps().deployments().load(deploymentStream).get();
|
||||
Service service = client.services().load(serviceStream).get();
|
||||
Ingress ingress = client.network().v1().ingresses().load(ingressStream).get();
|
||||
Secret secret = client.secrets().load(secretStream).get();
|
||||
|
||||
if (phase.equals(Phase.CREATE)) {
|
||||
util.createAndWait(NAMESPACE, null, secret);
|
||||
util.createAndWait(NAMESPACE, null, deployment, service, ingress, true);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
else {
|
||||
util.deleteAndWait(NAMESPACE, null, secret);
|
||||
util.deleteAndWait(NAMESPACE, deployment, service, ingress);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void deployManifests() {
|
||||
|
||||
try {
|
||||
|
||||
Secret configMap = client.secrets().load(getSecret()).get();
|
||||
secretName = configMap.getMetadata().getName();
|
||||
client.secrets().resource(configMap).create();
|
||||
|
||||
Deployment deployment = client.apps().deployments().load(getDeployment()).get();
|
||||
|
||||
String version = K8SUtils.getPomVersion();
|
||||
String currentImage = deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getImage();
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setImage(currentImage + ":" + version);
|
||||
|
||||
client.apps().deployments().inNamespace(NAMESPACE).resource(deployment).create();
|
||||
deploymentName = deployment.getMetadata().getName();
|
||||
|
||||
Service service = client.services().load(getService()).get();
|
||||
serviceName = service.getMetadata().getName();
|
||||
client.services().inNamespace(NAMESPACE).resource(service).create();
|
||||
|
||||
Ingress ingress = client.network().v1().ingresses().load(getIngress()).get();
|
||||
ingressName = ingress.getMetadata().getName();
|
||||
client.network().v1().ingresses().inNamespace(NAMESPACE).resource(ingress).create();
|
||||
|
||||
Fabric8Utils.waitForDeployment(client,
|
||||
"spring-cloud-kubernetes-fabric8-client-secrets-deployment-event-reload", NAMESPACE, 2, 600);
|
||||
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static InputStream getService() {
|
||||
return Fabric8Utils.inputStream("service.yaml");
|
||||
}
|
||||
|
||||
private static InputStream getDeployment() {
|
||||
return Fabric8Utils.inputStream("deployment.yaml");
|
||||
}
|
||||
|
||||
private static InputStream getIngress() {
|
||||
return Fabric8Utils.inputStream("ingress.yaml");
|
||||
}
|
||||
|
||||
private static InputStream getSecret() {
|
||||
return Fabric8Utils.inputStream("secret.yaml");
|
||||
}
|
||||
|
||||
private WebClient.Builder builder() {
|
||||
return WebClient.builder().clientConnector(new ReactorClientHttpConnector(HttpClient.create()));
|
||||
}
|
||||
|
||||
@@ -23,9 +23,7 @@ import java.util.Objects;
|
||||
import io.fabric8.kubernetes.api.model.Service;
|
||||
import io.fabric8.kubernetes.api.model.apps.Deployment;
|
||||
import io.fabric8.kubernetes.api.model.networking.v1.Ingress;
|
||||
import io.fabric8.kubernetes.client.Config;
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
import io.fabric8.kubernetes.client.KubernetesClientBuilder;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
@@ -36,8 +34,8 @@ import reactor.util.retry.Retry;
|
||||
import reactor.util.retry.RetryBackoffSpec;
|
||||
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Commons;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Fabric8Utils;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Phase;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.fabric8_client.Util;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
@@ -53,11 +51,7 @@ class SimpleCoreIT {
|
||||
|
||||
private static KubernetesClient client;
|
||||
|
||||
private static String deploymentName;
|
||||
|
||||
private static String serviceName;
|
||||
|
||||
private static String ingressName;
|
||||
private static Util util;
|
||||
|
||||
private static final K3sContainer K3S = Commons.container();
|
||||
|
||||
@@ -67,16 +61,16 @@ class SimpleCoreIT {
|
||||
Commons.validateImage(IMAGE_NAME, K3S);
|
||||
Commons.loadSpringCloudKubernetesImage(IMAGE_NAME, K3S);
|
||||
|
||||
Config config = Config.fromKubeconfig(K3S.getKubeConfigYaml());
|
||||
client = new KubernetesClientBuilder().withConfig(config).build();
|
||||
Fabric8Utils.setUp(client, NAMESPACE);
|
||||
util = new Util(K3S);
|
||||
client = util.client();
|
||||
util.setUp(NAMESPACE);
|
||||
|
||||
deployManifests();
|
||||
manifests(Phase.CREATE);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void after() throws Exception {
|
||||
deleteManifests();
|
||||
manifests(Phase.DELETE);
|
||||
Commons.cleanUp(IMAGE_NAME, K3S);
|
||||
}
|
||||
|
||||
@@ -91,64 +85,25 @@ class SimpleCoreIT {
|
||||
Assertions.assertEquals("Hello from k8s profile", result);
|
||||
}
|
||||
|
||||
private static void deleteManifests() {
|
||||
private static void manifests(Phase phase) {
|
||||
|
||||
try {
|
||||
InputStream deploymentStream = util.inputStream("simple-core-deployment.yaml");
|
||||
InputStream serviceStream = util.inputStream("simple-core-service.yaml");
|
||||
InputStream ingressStream = util.inputStream("simple-core-ingress.yaml");
|
||||
|
||||
client.apps().deployments().inNamespace(NAMESPACE).withName(deploymentName).delete();
|
||||
client.services().inNamespace(NAMESPACE).withName(serviceName).delete();
|
||||
client.network().v1().ingresses().inNamespace(NAMESPACE).withName(ingressName).delete();
|
||||
Deployment deployment = client.apps().deployments().load(deploymentStream).get();
|
||||
Service service = client.services().load(serviceStream).get();
|
||||
Ingress ingress = client.network().v1().ingresses().load(ingressStream).get();
|
||||
|
||||
if (phase.equals(Phase.CREATE)) {
|
||||
util.createAndWait(NAMESPACE, null, deployment, service, ingress, true);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
else {
|
||||
util.deleteAndWait(NAMESPACE, deployment, service, ingress);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void deployManifests() {
|
||||
|
||||
try {
|
||||
|
||||
Deployment deployment = client.apps().deployments().load(getDeployment()).get();
|
||||
|
||||
String version = K8SUtils.getPomVersion();
|
||||
String currentImage = deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getImage();
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setImage(currentImage + ":" + version);
|
||||
|
||||
client.apps().deployments().inNamespace(NAMESPACE).resource(deployment).create();
|
||||
deploymentName = deployment.getMetadata().getName();
|
||||
|
||||
Service service = client.services().load(getService()).get();
|
||||
serviceName = service.getMetadata().getName();
|
||||
client.services().inNamespace(NAMESPACE).resource(service).create();
|
||||
|
||||
Ingress ingress = client.network().v1().ingresses().load(getIngress()).get();
|
||||
ingressName = ingress.getMetadata().getName();
|
||||
client.network().v1().ingresses().inNamespace(NAMESPACE).resource(ingress).create();
|
||||
|
||||
Fabric8Utils.waitForDeployment(client, "spring-cloud-kubernetes-fabric8-client-simple-core-deployment",
|
||||
NAMESPACE, 2, 600);
|
||||
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static InputStream getService() {
|
||||
return Fabric8Utils.inputStream("simple-core-service.yaml");
|
||||
}
|
||||
|
||||
private static InputStream getDeployment() {
|
||||
return Fabric8Utils.inputStream("simple-core-deployment.yaml");
|
||||
}
|
||||
|
||||
private static InputStream getIngress() {
|
||||
return Fabric8Utils.inputStream("simple-core-ingress.yaml");
|
||||
}
|
||||
|
||||
private WebClient.Builder builder() {
|
||||
return WebClient.builder().clientConnector(new ReactorClientHttpConnector(HttpClient.create()));
|
||||
}
|
||||
|
||||
@@ -25,9 +25,7 @@ import java.util.Objects;
|
||||
import io.fabric8.kubernetes.api.model.Service;
|
||||
import io.fabric8.kubernetes.api.model.apps.Deployment;
|
||||
import io.fabric8.kubernetes.api.model.networking.v1.Ingress;
|
||||
import io.fabric8.kubernetes.client.Config;
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
import io.fabric8.kubernetes.client.KubernetesClientBuilder;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
@@ -38,8 +36,8 @@ import reactor.util.retry.Retry;
|
||||
import reactor.util.retry.RetryBackoffSpec;
|
||||
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Commons;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Fabric8Utils;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Phase;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.fabric8_client.Util;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
@@ -67,11 +65,7 @@ class Fabric8IstioIT {
|
||||
|
||||
private static KubernetesClient client;
|
||||
|
||||
private static String deploymentName;
|
||||
|
||||
private static String serviceName;
|
||||
|
||||
private static String ingressName;
|
||||
private static Util util;
|
||||
|
||||
private static K3sContainer K3S;
|
||||
|
||||
@@ -81,6 +75,8 @@ class Fabric8IstioIT {
|
||||
String absolutePath = new File(LOCAL_ISTIO_BIN_PATH).getAbsolutePath();
|
||||
K3S = Commons.container().withFileSystemBind(absolutePath, CONTAINER_ISTIO_BIN_PATH);
|
||||
K3S.start();
|
||||
util = new Util(K3S);
|
||||
client = util.client();
|
||||
Commons.validateImage(IMAGE_NAME, K3S);
|
||||
Commons.loadSpringCloudKubernetesImage(IMAGE_NAME, K3S);
|
||||
|
||||
@@ -93,21 +89,12 @@ class Fabric8IstioIT {
|
||||
processExecResult(
|
||||
K3S.execInContainer("sh", "-c", "kubectl label namespace istio-test istio-injection=enabled"));
|
||||
|
||||
// for Mac M1 with aarch64
|
||||
if (System.getProperty("os.arch").equals("aarch64")) {
|
||||
processExecResult(K3S.execInContainer("sh", "-c", CONTAINER_ISTIO_BIN_PATH + "istioctl"
|
||||
+ " --kubeconfig=/etc/rancher/k3s/k3s.yaml install --set hub=docker.io/querycapistio --set profile=minimal -y"));
|
||||
}
|
||||
else {
|
||||
processExecResult(K3S.execInContainer("sh", "-c", CONTAINER_ISTIO_BIN_PATH + "istioctl"
|
||||
+ " --kubeconfig=/etc/rancher/k3s/k3s.yaml install --set profile=minimal -y"));
|
||||
}
|
||||
processExecResult(K3S.execInContainer("sh", "-c", CONTAINER_ISTIO_BIN_PATH + "istioctl"
|
||||
+ " --kubeconfig=/etc/rancher/k3s/k3s.yaml install --set profile=minimal -y"));
|
||||
|
||||
Config config = Config.fromKubeconfig(K3S.getKubeConfigYaml());
|
||||
client = new KubernetesClientBuilder().withConfig(config).build();
|
||||
Fabric8Utils.setUpIstio(client, NAMESPACE);
|
||||
util.setUpIstio(NAMESPACE);
|
||||
|
||||
deployManifests();
|
||||
manifests(Phase.CREATE);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
@@ -117,7 +104,7 @@ class Fabric8IstioIT {
|
||||
|
||||
@AfterAll
|
||||
static void after() {
|
||||
deleteManifests();
|
||||
manifests(Phase.DELETE);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -132,67 +119,25 @@ class Fabric8IstioIT {
|
||||
Assertions.assertTrue(result.contains("istio"));
|
||||
}
|
||||
|
||||
private static void deleteManifests() {
|
||||
private static void manifests(Phase phase) {
|
||||
|
||||
try {
|
||||
InputStream deploymentStream = util.inputStream("istio-deployment.yaml");
|
||||
InputStream serviceStream = util.inputStream("istio-service.yaml");
|
||||
InputStream ingressStream = util.inputStream("istio-ingress.yaml");
|
||||
|
||||
client.apps().deployments().inNamespace(NAMESPACE).withName(deploymentName).delete();
|
||||
client.services().inNamespace(NAMESPACE).withName(serviceName).delete();
|
||||
client.network().v1().ingresses().inNamespace(NAMESPACE).withName(ingressName).delete();
|
||||
Deployment deployment = client.apps().deployments().load(deploymentStream).get();
|
||||
Service service = client.services().load(serviceStream).get();
|
||||
Ingress ingress = client.network().v1().ingresses().load(ingressStream).get();
|
||||
|
||||
if (phase.equals(Phase.CREATE)) {
|
||||
util.createAndWait(NAMESPACE, null, deployment, service, ingress, true);
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
else {
|
||||
util.deleteAndWait(NAMESPACE, deployment, service, ingress);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void deployManifests() {
|
||||
|
||||
try {
|
||||
|
||||
Deployment deployment = client.apps().deployments().load(getDeployment()).get();
|
||||
|
||||
String version = K8SUtils.getPomVersion();
|
||||
String currentImage = deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getImage();
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0).setImage(currentImage + ":" + version);
|
||||
|
||||
client.apps().deployments().inNamespace(NAMESPACE).resource(deployment).create();
|
||||
deploymentName = deployment.getMetadata().getName();
|
||||
|
||||
Service service = client.services().load(getService()).get();
|
||||
serviceName = service.getMetadata().getName();
|
||||
client.services().inNamespace(NAMESPACE).resource(service).create();
|
||||
|
||||
Ingress ingress = client.network().v1().ingresses().load(getIngress()).get();
|
||||
ingressName = ingress.getMetadata().getName();
|
||||
client.network().v1().ingresses().inNamespace(NAMESPACE).resource(ingress).create();
|
||||
|
||||
Fabric8Utils.waitForIngress(client, ingressName, NAMESPACE);
|
||||
Fabric8Utils.waitForDeployment(client, "spring-cloud-kubernetes-fabric8-istio-it-deployment", NAMESPACE, 2,
|
||||
600);
|
||||
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static InputStream getService() {
|
||||
return Fabric8Utils.inputStream("istio-service.yaml");
|
||||
}
|
||||
|
||||
private static InputStream getDeployment() {
|
||||
return Fabric8Utils.inputStream("istio-deployment.yaml");
|
||||
}
|
||||
|
||||
private static InputStream getIngress() {
|
||||
return Fabric8Utils.inputStream("istio-ingress.yaml");
|
||||
}
|
||||
|
||||
private WebClient.Builder builder() {
|
||||
return WebClient.builder().clientConnector(new ReactorClientHttpConnector(HttpClient.create()));
|
||||
}
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
package org.springframework.cloud.kubernetes.integration.tests.commons;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
@@ -32,7 +34,10 @@ import org.testcontainers.containers.Container;
|
||||
import org.testcontainers.k3s.K3sContainer;
|
||||
import org.testcontainers.utility.DockerImageName;
|
||||
|
||||
import static org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils.getPomVersion;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StreamUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* A few commons things that can be re-used across clients. This is meant to be used for
|
||||
@@ -46,6 +51,8 @@ public final class Commons {
|
||||
throw new AssertionError("No instance provided");
|
||||
}
|
||||
|
||||
private static final String KUBERNETES_VERSION_FILE = "META-INF/springcloudkubernetes-version.txt";
|
||||
|
||||
/**
|
||||
* Rancher version to use for test-containers.
|
||||
*/
|
||||
@@ -76,7 +83,7 @@ public final class Commons {
|
||||
}
|
||||
|
||||
public static void loadSpringCloudKubernetesImage(String project, K3sContainer container) throws Exception {
|
||||
loadImage("springcloud/" + project, getPomVersion(), project, container);
|
||||
loadImage("springcloud/" + project, pomVersion(), project, container);
|
||||
}
|
||||
|
||||
public static void loadImage(String image, String tag, String tarName, K3sContainer container) throws Exception {
|
||||
@@ -95,7 +102,7 @@ public final class Commons {
|
||||
}
|
||||
|
||||
public static void cleanUp(String image, K3sContainer container) throws Exception {
|
||||
container.execInContainer("crictl", "rmi", "docker.io/springcloud/" + image + ":" + getPomVersion());
|
||||
container.execInContainer("crictl", "rmi", "docker.io/springcloud/" + image + ":" + pomVersion());
|
||||
container.execInContainer("rm", TEMP_FOLDER + "/" + image + ".tar");
|
||||
}
|
||||
|
||||
@@ -132,6 +139,21 @@ public final class Commons {
|
||||
return execResult.getStdout();
|
||||
}
|
||||
|
||||
public static String pomVersion() {
|
||||
try (InputStream in = new ClassPathResource(KUBERNETES_VERSION_FILE).getInputStream()) {
|
||||
String version = StreamUtils.copyToString(in, StandardCharsets.UTF_8);
|
||||
if (StringUtils.hasText(version)) {
|
||||
version = version.trim();
|
||||
}
|
||||
return version;
|
||||
}
|
||||
catch (IOException e) {
|
||||
ReflectionUtils.rethrowRuntimeException(e);
|
||||
}
|
||||
// not reachable since exception rethrown at runtime
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A K3sContainer, but with fixed port mappings. This is needed because of the nature
|
||||
* of some integration tests.
|
||||
|
||||
@@ -1,297 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.kubernetes.integration.tests.commons;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import io.fabric8.kubernetes.api.model.ConfigMap;
|
||||
import io.fabric8.kubernetes.api.model.Endpoints;
|
||||
import io.fabric8.kubernetes.api.model.LoadBalancerIngress;
|
||||
import io.fabric8.kubernetes.api.model.Namespace;
|
||||
import io.fabric8.kubernetes.api.model.Pod;
|
||||
import io.fabric8.kubernetes.api.model.Service;
|
||||
import io.fabric8.kubernetes.api.model.ServiceAccount;
|
||||
import io.fabric8.kubernetes.api.model.apps.Deployment;
|
||||
import io.fabric8.kubernetes.api.model.networking.v1.Ingress;
|
||||
import io.fabric8.kubernetes.api.model.rbac.ClusterRole;
|
||||
import io.fabric8.kubernetes.api.model.rbac.Role;
|
||||
import io.fabric8.kubernetes.api.model.rbac.RoleBinding;
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import static org.awaitility.Awaitility.await;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
* @author wind57
|
||||
*/
|
||||
public final class Fabric8Utils {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(Fabric8Utils.class);
|
||||
|
||||
private Fabric8Utils() {
|
||||
throw new AssertionError("no instance provided");
|
||||
}
|
||||
|
||||
public static InputStream inputStream(String fileName) {
|
||||
return Fabric8Utils.class.getClassLoader().getResourceAsStream(fileName);
|
||||
}
|
||||
|
||||
public static void waitForDeployment(KubernetesClient client, String deploymentName, String namespace,
|
||||
int pollSeconds, int maxSeconds) {
|
||||
await().pollInterval(Duration.ofSeconds(pollSeconds)).atMost(maxSeconds, TimeUnit.SECONDS)
|
||||
.until(() -> isDeploymentReady(client, deploymentName, namespace));
|
||||
}
|
||||
|
||||
public static void waitForEndpoint(KubernetesClient client, String endpointName, String namespace, int pollSeconds,
|
||||
int maxSeconds) {
|
||||
await().pollInterval(Duration.ofSeconds(pollSeconds)).atMost(maxSeconds, TimeUnit.SECONDS)
|
||||
.until(() -> isEndpointReady(client, endpointName, namespace));
|
||||
}
|
||||
|
||||
private static boolean isDeploymentReady(KubernetesClient client, String deploymentName, String namespace) {
|
||||
|
||||
Deployment deployment = client.apps().deployments().inNamespace(namespace).withName(deploymentName).get();
|
||||
|
||||
Integer availableReplicas = deployment.getStatus().getAvailableReplicas();
|
||||
LOG.info("Available replicas for " + deploymentName + ": " + ((availableReplicas == null) ? 0 : 1));
|
||||
return availableReplicas != null && availableReplicas >= 1;
|
||||
}
|
||||
|
||||
private static boolean isEndpointReady(KubernetesClient client, String endpointName, String namespace) {
|
||||
|
||||
Endpoints endpoint = client.endpoints().inNamespace(namespace).withName(endpointName).get();
|
||||
|
||||
if (endpoint.getSubsets().isEmpty()) {
|
||||
fail("no endpoints for " + endpointName);
|
||||
}
|
||||
|
||||
return endpoint.getSubsets().get(0).getAddresses().size() >= 1;
|
||||
}
|
||||
|
||||
public static void setUp(KubernetesClient client, String namespace) throws Exception {
|
||||
InputStream serviceAccountAsStream = inputStream("setup/service-account.yaml");
|
||||
InputStream roleBindingAsStream = inputStream("setup/role-binding.yaml");
|
||||
InputStream roleAsStream = inputStream("setup/role.yaml");
|
||||
|
||||
innerSetup(client, namespace, serviceAccountAsStream, roleBindingAsStream, roleAsStream);
|
||||
}
|
||||
|
||||
public static void setUpClusterWide(KubernetesClient client, String serviceAccountNamespace,
|
||||
Set<String> namespaces) {
|
||||
InputStream clusterRoleBindingAsStream = inputStream("cluster/cluster-role.yaml");
|
||||
InputStream serviceAccountAsStream = inputStream("cluster/service-account.yaml");
|
||||
InputStream roleBindingAsStream = inputStream("cluster/role-binding.yaml");
|
||||
|
||||
ClusterRole clusterRole = client.rbac().clusterRoles().load(clusterRoleBindingAsStream).get();
|
||||
if (client.rbac().clusterRoles().withName(clusterRole.getMetadata().getName()).get() == null) {
|
||||
client.rbac().clusterRoles().resource(clusterRole).create();
|
||||
}
|
||||
|
||||
ServiceAccount serviceAccountFromStream = client.serviceAccounts().load(serviceAccountAsStream).get();
|
||||
serviceAccountFromStream.getMetadata().setNamespace(serviceAccountNamespace);
|
||||
if (client.serviceAccounts().inNamespace(serviceAccountNamespace)
|
||||
.withName(serviceAccountFromStream.getMetadata().getName()).get() == null) {
|
||||
client.serviceAccounts().inNamespace(serviceAccountNamespace).resource(serviceAccountFromStream).create();
|
||||
}
|
||||
|
||||
RoleBinding roleBindingFromStream = client.rbac().roleBindings().load(roleBindingAsStream).get();
|
||||
namespaces.forEach(namespace -> {
|
||||
roleBindingFromStream.getMetadata().setNamespace(namespace);
|
||||
|
||||
if (client.rbac().roleBindings().inNamespace(namespace)
|
||||
.withName(roleBindingFromStream.getMetadata().getName()).get() == null) {
|
||||
client.rbac().roleBindings().inNamespace(namespace).resource(roleBindingFromStream).create();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public static void cleanUpClusterWide(KubernetesClient client, String serviceAccountNamespace,
|
||||
Set<String> namespaces) {
|
||||
|
||||
InputStream clusterRoleBindingAsStream = inputStream("cluster/cluster-role.yaml");
|
||||
InputStream serviceAccountAsStream = inputStream("cluster/service-account.yaml");
|
||||
InputStream roleBindingAsStream = inputStream("cluster/role-binding.yaml");
|
||||
|
||||
ClusterRole clusterRole = client.rbac().clusterRoles().load(clusterRoleBindingAsStream).get();
|
||||
client.rbac().clusterRoles().withName(clusterRole.getMetadata().getName()).delete();
|
||||
|
||||
await().pollInterval(Duration.ofSeconds(1)).atMost(30, TimeUnit.SECONDS).until(() -> {
|
||||
ClusterRole innerClusterRole = client.rbac().clusterRoles().withName(clusterRole.getMetadata().getName())
|
||||
.get();
|
||||
return innerClusterRole == null;
|
||||
});
|
||||
|
||||
ServiceAccount serviceAccount = client.serviceAccounts().load(serviceAccountAsStream).get();
|
||||
client.serviceAccounts().inNamespace(serviceAccountNamespace).withName(serviceAccount.getMetadata().getName())
|
||||
.delete();
|
||||
await().pollInterval(Duration.ofSeconds(1)).atMost(30, TimeUnit.SECONDS).until(() -> {
|
||||
ServiceAccount innerServiceAccount = client.serviceAccounts().inNamespace(serviceAccountNamespace)
|
||||
.withName(serviceAccount.getMetadata().getName()).get();
|
||||
return innerServiceAccount == null;
|
||||
});
|
||||
|
||||
RoleBinding roleBinding = client.rbac().roleBindings().load(roleBindingAsStream).get();
|
||||
namespaces.forEach(namespace -> {
|
||||
client.rbac().roleBindings().inNamespace(namespace).withName(roleBinding.getMetadata().getName()).delete();
|
||||
|
||||
await().pollInterval(Duration.ofSeconds(1)).atMost(30, TimeUnit.SECONDS).until(() -> {
|
||||
RoleBinding innerRoleBinding = client.rbac().roleBindings().inNamespace(namespace)
|
||||
.withName(roleBinding.getMetadata().getName()).get();
|
||||
return innerRoleBinding == null;
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public static void setUpIstio(KubernetesClient client, String namespace) {
|
||||
InputStream serviceAccountAsStream = inputStream("istio/service-account.yaml");
|
||||
InputStream roleBindingAsStream = inputStream("istio/role-binding.yaml");
|
||||
InputStream roleAsStream = inputStream("istio/role.yaml");
|
||||
|
||||
innerSetup(client, namespace, serviceAccountAsStream, roleBindingAsStream, roleAsStream);
|
||||
}
|
||||
|
||||
public static void waitForIngress(KubernetesClient client, String ingressName, String namespace) {
|
||||
|
||||
try {
|
||||
await().pollInterval(Duration.ofSeconds(2)).atMost(180, TimeUnit.SECONDS).until(() -> {
|
||||
Ingress ingress = client.network().v1().ingresses().inNamespace(namespace).withName(ingressName).get();
|
||||
|
||||
if (ingress == null) {
|
||||
System.out.println("ingress : " + ingressName + " not ready yet present");
|
||||
return false;
|
||||
}
|
||||
|
||||
List<LoadBalancerIngress> loadBalancerIngress = ingress.getStatus().getLoadBalancer().getIngress();
|
||||
if (loadBalancerIngress == null || loadBalancerIngress.isEmpty()) {
|
||||
System.out.println(
|
||||
"ingress : " + ingressName + " not ready yet (loadbalancer ingress not yet present)");
|
||||
return false;
|
||||
}
|
||||
|
||||
String ip = loadBalancerIngress.get(0).getIp();
|
||||
if (ip == null) {
|
||||
System.out.println("ingress : " + ingressName + " not ready yet");
|
||||
return false;
|
||||
}
|
||||
|
||||
System.out.println("ingress : " + ingressName + " ready with ip : " + ip);
|
||||
return true;
|
||||
|
||||
});
|
||||
}
|
||||
catch (Exception e) {
|
||||
System.out.println("Error waiting for ingress");
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void waitForConfigMapDelete(KubernetesClient client, String namespace, String name) {
|
||||
await().pollInterval(Duration.ofSeconds(1)).atMost(30, TimeUnit.SECONDS).until(() -> {
|
||||
ConfigMap configMap = client.configMaps().inNamespace(namespace).withName(name).get();
|
||||
return configMap == null;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* delete a deployment and every pod by spec.select.matchLabels, waits until
|
||||
* everything is deleted.
|
||||
*/
|
||||
public static void deleteDeployment(KubernetesClient client, String namespace, String name) {
|
||||
|
||||
Deployment deployment = client.apps().deployments().inNamespace(namespace).withName(name).get();
|
||||
Map<String, String> matchLabels = deployment.getSpec().getSelector().getMatchLabels();
|
||||
|
||||
client.apps().deployments().inNamespace(namespace).resource(deployment).delete();
|
||||
|
||||
await().pollInterval(Duration.ofSeconds(1)).atMost(30, TimeUnit.SECONDS).until(() -> {
|
||||
Deployment inner = client.apps().deployments().inNamespace(namespace).withName(name).get();
|
||||
return inner == null;
|
||||
});
|
||||
|
||||
await().pollInterval(Duration.ofSeconds(1)).atMost(60, TimeUnit.SECONDS).until(() -> {
|
||||
List<Pod> podList = client.pods().inNamespace(namespace).withLabels(matchLabels).list().getItems();
|
||||
return podList == null || podList.isEmpty();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* delete the service and wait for it to be deleted.
|
||||
*/
|
||||
public static void deleteService(KubernetesClient client, String namespace, String name) {
|
||||
|
||||
client.services().inNamespace(namespace).withName(name).delete();
|
||||
|
||||
await().pollInterval(Duration.ofSeconds(1)).atMost(30, TimeUnit.SECONDS).until(() -> {
|
||||
Service service = client.services().inNamespace(namespace).withName(name).get();
|
||||
return service == null;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* delete ingress and wait for it to be deleted.
|
||||
*/
|
||||
public static void deleteIngress(KubernetesClient client, String namespace, String name) {
|
||||
client.network().v1().ingresses().inNamespace(namespace).withName(name).delete();
|
||||
|
||||
await().pollInterval(Duration.ofSeconds(1)).atMost(30, TimeUnit.SECONDS).until(() -> {
|
||||
Ingress ingress = client.network().v1().ingresses().inNamespace(namespace).withName(name).get();
|
||||
return ingress == null;
|
||||
});
|
||||
}
|
||||
|
||||
public static void deleteNamespace(KubernetesClient client, String name) {
|
||||
client.namespaces().withName(name).delete();
|
||||
|
||||
await().pollInterval(Duration.ofSeconds(1)).atMost(30, TimeUnit.SECONDS).until(() -> {
|
||||
Namespace namespace = client.namespaces().withName(name).get();
|
||||
return namespace == null;
|
||||
});
|
||||
}
|
||||
|
||||
private static void innerSetup(KubernetesClient client, String namespace, InputStream serviceAccountAsStream,
|
||||
InputStream roleBindingAsStream, InputStream roleAsStream) {
|
||||
ServiceAccount serviceAccountFromStream = client.serviceAccounts().load(serviceAccountAsStream).get();
|
||||
if (client.serviceAccounts().inNamespace(namespace).withName(serviceAccountFromStream.getMetadata().getName())
|
||||
.get() == null) {
|
||||
client.serviceAccounts().inNamespace(namespace).resource(serviceAccountFromStream).create();
|
||||
}
|
||||
|
||||
RoleBinding roleBindingFromStream = client.rbac().roleBindings().load(roleBindingAsStream).get();
|
||||
if (client.rbac().roleBindings().inNamespace(namespace).withName(roleBindingFromStream.getMetadata().getName())
|
||||
.get() == null) {
|
||||
client.rbac().roleBindings().inNamespace(namespace).resource(roleBindingFromStream).create();
|
||||
}
|
||||
|
||||
Role roleFromStream = client.rbac().roles().load(roleAsStream).get();
|
||||
if (client.rbac().roles().inNamespace(namespace).withName(roleFromStream.getMetadata().getName())
|
||||
.get() == null) {
|
||||
client.rbac().roles().inNamespace(namespace).resource(roleFromStream).create();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.integration.tests.commons;
|
||||
|
||||
/**
|
||||
* @author wind57
|
||||
*/
|
||||
public enum Phase {
|
||||
|
||||
/**
|
||||
* Apply the manifests.
|
||||
*/
|
||||
CREATE,
|
||||
|
||||
/**
|
||||
* Deleted the manifests.
|
||||
*/
|
||||
DELETE
|
||||
|
||||
}
|
||||
@@ -0,0 +1,400 @@
|
||||
/*
|
||||
* 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.integration.tests.commons.fabric8_client;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import io.fabric8.kubernetes.api.model.ConfigMap;
|
||||
import io.fabric8.kubernetes.api.model.LoadBalancerIngress;
|
||||
import io.fabric8.kubernetes.api.model.NamespaceBuilder;
|
||||
import io.fabric8.kubernetes.api.model.Pod;
|
||||
import io.fabric8.kubernetes.api.model.Secret;
|
||||
import io.fabric8.kubernetes.api.model.Service;
|
||||
import io.fabric8.kubernetes.api.model.ServiceAccount;
|
||||
import io.fabric8.kubernetes.api.model.apps.Deployment;
|
||||
import io.fabric8.kubernetes.api.model.networking.v1.Ingress;
|
||||
import io.fabric8.kubernetes.api.model.rbac.ClusterRole;
|
||||
import io.fabric8.kubernetes.api.model.rbac.Role;
|
||||
import io.fabric8.kubernetes.api.model.rbac.RoleBinding;
|
||||
import io.fabric8.kubernetes.client.Config;
|
||||
import io.fabric8.kubernetes.client.KubernetesClient;
|
||||
import io.fabric8.kubernetes.client.KubernetesClientBuilder;
|
||||
import jakarta.annotation.Nullable;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.testcontainers.k3s.K3sContainer;
|
||||
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Phase;
|
||||
|
||||
import static org.awaitility.Awaitility.await;
|
||||
import static org.springframework.cloud.kubernetes.integration.tests.commons.Commons.loadImage;
|
||||
import static org.springframework.cloud.kubernetes.integration.tests.commons.Commons.pomVersion;
|
||||
import static org.springframework.cloud.kubernetes.integration.tests.commons.Commons.pullImage;
|
||||
|
||||
/**
|
||||
* @author wind57
|
||||
*/
|
||||
public final class Util {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(Util.class);
|
||||
|
||||
private final K3sContainer container;
|
||||
|
||||
private final KubernetesClient client;
|
||||
|
||||
public Util(K3sContainer container) {
|
||||
this.container = container;
|
||||
this.client = new KubernetesClientBuilder().withConfig(Config.fromKubeconfig(container.getKubeConfigYaml()))
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the preferred method to use when creating a deployment alongside with a
|
||||
* service. It creates the given resources as-well as waits for them to be created.
|
||||
* The delay check is intentionally not taken as an argument, so that it stays as
|
||||
* tight as possible, providing reasonable defaults.
|
||||
*
|
||||
*/
|
||||
public void createAndWait(String namespace, String name, Deployment deployment, Service service,
|
||||
@Nullable Ingress ingress, boolean changeVersion) {
|
||||
try {
|
||||
|
||||
String imageFromDeployment = deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getImage();
|
||||
if (changeVersion) {
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0)
|
||||
.setImage(imageFromDeployment + ":" + pomVersion());
|
||||
}
|
||||
else {
|
||||
String[] image = imageFromDeployment.split(":", 2);
|
||||
pullImage(image[0], image[1], container);
|
||||
loadImage(image[0], image[1], name, container);
|
||||
}
|
||||
|
||||
client.apps().deployments().inNamespace(namespace).resource(deployment).create();
|
||||
client.services().inNamespace(namespace).resource(service).create();
|
||||
waitForDeployment(namespace, deployment);
|
||||
if (ingress != null) {
|
||||
client.network().v1().ingresses().inNamespace(namespace).resource(ingress).create();
|
||||
waitForIngress(namespace, ingress);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void busybox(String namespace, Phase phase) {
|
||||
InputStream deploymentStream = inputStream("busybox/deployment.yaml");
|
||||
InputStream serviceStream = inputStream("busybox/service.yaml");
|
||||
Deployment deployment = client.apps().deployments().load(deploymentStream).get();
|
||||
Service service = client.services().load(serviceStream).get();
|
||||
|
||||
if (phase.equals(Phase.CREATE)) {
|
||||
createAndWait(namespace, "busybox", deployment, service, null, false);
|
||||
}
|
||||
else if (phase.equals(Phase.DELETE)) {
|
||||
deleteAndWait(namespace, deployment, service, null);
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteAndWait(String namespace, Deployment deployment, Service service, @Nullable Ingress ingress) {
|
||||
try {
|
||||
client.apps().deployments().inNamespace(namespace).resource(deployment).delete();
|
||||
client.services().inNamespace(namespace).resource(service).delete();
|
||||
waitForDeploymentToBeDeleted(namespace, deployment);
|
||||
|
||||
if (ingress != null) {
|
||||
client.network().v1().ingresses().inNamespace(namespace).resource(ingress).delete();
|
||||
waitForIngressToBeDeleted(namespace, ingress);
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void setUp(String namespace) throws Exception {
|
||||
InputStream serviceAccountAsStream = inputStream("setup/service-account.yaml");
|
||||
InputStream roleBindingAsStream = inputStream("setup/role-binding.yaml");
|
||||
InputStream roleAsStream = inputStream("setup/role.yaml");
|
||||
|
||||
innerSetup(namespace, serviceAccountAsStream, roleBindingAsStream, roleAsStream);
|
||||
}
|
||||
|
||||
public InputStream inputStream(String fileName) {
|
||||
return Util.class.getClassLoader().getResourceAsStream(fileName);
|
||||
}
|
||||
|
||||
public void createNamespace(String name) {
|
||||
try {
|
||||
client.namespaces().resource(new NamespaceBuilder().withNewMetadata().withName(name).and().build())
|
||||
.create();
|
||||
|
||||
await().pollInterval(Duration.ofSeconds(1)).atMost(30, TimeUnit.SECONDS).until(() -> client.namespaces()
|
||||
.list().getItems().stream().anyMatch(x -> x.getMetadata().getName().equals(name)));
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteNamespace(String name) {
|
||||
try {
|
||||
client.namespaces().resource(new NamespaceBuilder().withNewMetadata().withName(name).and().build())
|
||||
.delete();
|
||||
|
||||
await().pollInterval(Duration.ofSeconds(1)).atMost(30, TimeUnit.SECONDS).until(() -> client.namespaces()
|
||||
.list().getItems().stream().noneMatch(x -> x.getMetadata().getName().equals(name)));
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void setUpClusterWide(String serviceAccountNamespace, Set<String> namespaces) {
|
||||
InputStream clusterRoleBindingAsStream = inputStream("cluster/cluster-role.yaml");
|
||||
InputStream serviceAccountAsStream = inputStream("cluster/service-account.yaml");
|
||||
InputStream roleBindingAsStream = inputStream("cluster/role-binding.yaml");
|
||||
|
||||
ClusterRole clusterRole = client.rbac().clusterRoles().load(clusterRoleBindingAsStream).get();
|
||||
if (client.rbac().clusterRoles().withName(clusterRole.getMetadata().getName()).get() == null) {
|
||||
client.rbac().clusterRoles().resource(clusterRole).create();
|
||||
}
|
||||
|
||||
ServiceAccount serviceAccountFromStream = client.serviceAccounts().load(serviceAccountAsStream).get();
|
||||
serviceAccountFromStream.getMetadata().setNamespace(serviceAccountNamespace);
|
||||
if (client.serviceAccounts().inNamespace(serviceAccountNamespace)
|
||||
.withName(serviceAccountFromStream.getMetadata().getName()).get() == null) {
|
||||
client.serviceAccounts().inNamespace(serviceAccountNamespace).resource(serviceAccountFromStream).create();
|
||||
}
|
||||
|
||||
RoleBinding roleBindingFromStream = client.rbac().roleBindings().load(roleBindingAsStream).get();
|
||||
namespaces.forEach(namespace -> {
|
||||
roleBindingFromStream.getMetadata().setNamespace(namespace);
|
||||
|
||||
if (client.rbac().roleBindings().inNamespace(namespace)
|
||||
.withName(roleBindingFromStream.getMetadata().getName()).get() == null) {
|
||||
client.rbac().roleBindings().inNamespace(namespace).resource(roleBindingFromStream).create();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public void createAndWait(String namespace, @Nullable ConfigMap configMap, @Nullable Secret secret) {
|
||||
if (configMap != null) {
|
||||
client.configMaps().resource(configMap).create();
|
||||
waitForConfigMap(namespace, configMap, Phase.CREATE);
|
||||
}
|
||||
|
||||
if (secret != null) {
|
||||
client.secrets().resource(secret).create();
|
||||
waitForSecret(namespace, secret, Phase.CREATE);
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteAndWait(String namespace, @Nullable ConfigMap configMap, @Nullable Secret secret) {
|
||||
if (configMap != null) {
|
||||
client.configMaps().resource(configMap).delete();
|
||||
waitForConfigMap(namespace, configMap, Phase.DELETE);
|
||||
}
|
||||
|
||||
if (secret != null) {
|
||||
client.secrets().resource(secret).delete();
|
||||
waitForSecret(namespace, secret, Phase.DELETE);
|
||||
}
|
||||
}
|
||||
|
||||
public void setUpIstio(String namespace) {
|
||||
InputStream serviceAccountAsStream = inputStream("istio/service-account.yaml");
|
||||
InputStream roleBindingAsStream = inputStream("istio/role-binding.yaml");
|
||||
InputStream roleAsStream = inputStream("istio/role.yaml");
|
||||
|
||||
innerSetup(namespace, serviceAccountAsStream, roleBindingAsStream, roleAsStream);
|
||||
}
|
||||
|
||||
private void waitForConfigMap(String namespace, ConfigMap configMap, Phase phase) {
|
||||
String configMapName = configMapName(configMap);
|
||||
await().pollInterval(Duration.ofSeconds(1)).atMost(600, TimeUnit.SECONDS).until(() -> {
|
||||
int size = (int) client.configMaps().inNamespace(namespace).list().getItems().stream()
|
||||
.filter(x -> x.getMetadata().getName().equals(configMapName)).count();
|
||||
if (size == 0) {
|
||||
return !phase.equals(Phase.CREATE);
|
||||
}
|
||||
return phase.equals(Phase.CREATE);
|
||||
});
|
||||
}
|
||||
|
||||
public void wiremock(String namespace, String path, Phase phase) {
|
||||
InputStream deploymentStream = inputStream("wiremock/wiremock-deployment.yaml");
|
||||
InputStream serviceStream = inputStream("wiremock/wiremock-service.yaml");
|
||||
InputStream ingressStream = inputStream("wiremock/wiremock-ingress.yaml");
|
||||
|
||||
Deployment deployment = client.apps().deployments().load(deploymentStream).get();
|
||||
Service service = client.services().load(serviceStream).get();
|
||||
Ingress ingress = client.network().v1().ingresses().load(ingressStream).get();
|
||||
|
||||
if (phase.equals(Phase.CREATE)) {
|
||||
deployment.getMetadata().setNamespace(namespace);
|
||||
service.getMetadata().setNamespace(namespace);
|
||||
ingress.getMetadata().setNamespace(namespace);
|
||||
ingress.getSpec().getRules().get(0).getHttp().getPaths().get(0).setPath(path);
|
||||
createAndWait(namespace, "wiremock", deployment, service, ingress, false);
|
||||
}
|
||||
else {
|
||||
deleteAndWait(namespace, deployment, service, ingress);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void waitForSecret(String namespace, Secret secret, Phase phase) {
|
||||
String secretName = secretName(secret);
|
||||
await().pollInterval(Duration.ofSeconds(1)).atMost(600, TimeUnit.SECONDS).until(() -> {
|
||||
int size = (int) client.secrets().inNamespace(namespace).list().getItems().stream()
|
||||
.filter(x -> x.getMetadata().getName().equals(secretName)).count();
|
||||
if (size == 0) {
|
||||
return !phase.equals(Phase.CREATE);
|
||||
}
|
||||
return phase.equals(Phase.CREATE);
|
||||
});
|
||||
}
|
||||
|
||||
private void waitForIngressToBeDeleted(String namespace, Ingress ingress) {
|
||||
String ingressName = ingressName(ingress);
|
||||
await().pollInterval(Duration.ofSeconds(1)).atMost(30, TimeUnit.SECONDS).until(() -> {
|
||||
Ingress inner = client.network().v1().ingresses().inNamespace(namespace).withName(ingressName).get();
|
||||
return inner == null;
|
||||
});
|
||||
}
|
||||
|
||||
private void waitForDeploymentToBeDeleted(String namespace, Deployment deployment) {
|
||||
|
||||
String deploymentName = deploymentName(deployment);
|
||||
|
||||
Map<String, String> matchLabels = deployment.getSpec().getSelector().getMatchLabels();
|
||||
|
||||
await().pollInterval(Duration.ofSeconds(1)).atMost(30, TimeUnit.SECONDS).until(() -> {
|
||||
Deployment inner = client.apps().deployments().inNamespace(namespace).withName(deploymentName).get();
|
||||
return inner == null;
|
||||
});
|
||||
|
||||
await().pollInterval(Duration.ofSeconds(1)).atMost(60, TimeUnit.SECONDS).until(() -> {
|
||||
List<Pod> podList = client.pods().inNamespace(namespace).withLabels(matchLabels).list().getItems();
|
||||
return podList == null || podList.isEmpty();
|
||||
});
|
||||
}
|
||||
|
||||
private void waitForDeployment(String namespace, Deployment deployment) {
|
||||
String deploymentName = deploymentName(deployment);
|
||||
await().pollInterval(Duration.ofSeconds(2)).atMost(600, TimeUnit.SECONDS)
|
||||
.until(() -> isDeploymentReady(namespace, deploymentName));
|
||||
}
|
||||
|
||||
private boolean isDeploymentReady(String namespace, String deploymentName) {
|
||||
|
||||
Deployment deployment = client.apps().deployments().inNamespace(namespace).withName(deploymentName).get();
|
||||
|
||||
Integer availableReplicas = deployment.getStatus().getAvailableReplicas();
|
||||
LOG.info("Available replicas for " + deploymentName + ": " + ((availableReplicas == null) ? 0 : 1));
|
||||
return availableReplicas != null && availableReplicas >= 1;
|
||||
}
|
||||
|
||||
public void waitForIngress(String namespace, Ingress ingress) {
|
||||
|
||||
String ingressName = ingressName(ingress);
|
||||
|
||||
try {
|
||||
await().pollInterval(Duration.ofSeconds(2)).atMost(180, TimeUnit.SECONDS).until(() -> {
|
||||
Ingress inner = client.network().v1().ingresses().inNamespace(namespace).withName(ingressName).get();
|
||||
|
||||
if (inner == null) {
|
||||
LOG.info("ingress : " + ingressName + " not ready yet present");
|
||||
return false;
|
||||
}
|
||||
|
||||
List<LoadBalancerIngress> loadBalancerIngress = inner.getStatus().getLoadBalancer().getIngress();
|
||||
if (loadBalancerIngress == null || loadBalancerIngress.isEmpty()) {
|
||||
LOG.info("ingress : " + ingressName + " not ready yet (loadbalancer ingress not yet present)");
|
||||
return false;
|
||||
}
|
||||
|
||||
String ip = loadBalancerIngress.get(0).getIp();
|
||||
if (ip == null) {
|
||||
LOG.info("ingress : " + ingressName + " not ready yet");
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG.info("ingress : " + ingressName + " ready with ip : " + ip);
|
||||
return true;
|
||||
|
||||
});
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.error("Error waiting for ingress");
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void innerSetup(String namespace, InputStream serviceAccountAsStream, InputStream roleBindingAsStream,
|
||||
InputStream roleAsStream) {
|
||||
ServiceAccount serviceAccountFromStream = client.serviceAccounts().load(serviceAccountAsStream).get();
|
||||
if (client.serviceAccounts().inNamespace(namespace).withName(serviceAccountFromStream.getMetadata().getName())
|
||||
.get() == null) {
|
||||
client.serviceAccounts().inNamespace(namespace).resource(serviceAccountFromStream).create();
|
||||
}
|
||||
|
||||
RoleBinding roleBindingFromStream = client.rbac().roleBindings().load(roleBindingAsStream).get();
|
||||
if (client.rbac().roleBindings().inNamespace(namespace).withName(roleBindingFromStream.getMetadata().getName())
|
||||
.get() == null) {
|
||||
client.rbac().roleBindings().inNamespace(namespace).resource(roleBindingFromStream).create();
|
||||
}
|
||||
|
||||
Role roleFromStream = client.rbac().roles().load(roleAsStream).get();
|
||||
if (client.rbac().roles().inNamespace(namespace).withName(roleFromStream.getMetadata().getName())
|
||||
.get() == null) {
|
||||
client.rbac().roles().inNamespace(namespace).resource(roleFromStream).create();
|
||||
}
|
||||
}
|
||||
|
||||
private String deploymentName(Deployment deployment) {
|
||||
return deployment.getMetadata().getName();
|
||||
}
|
||||
|
||||
private String ingressName(Ingress ingress) {
|
||||
return ingress.getMetadata().getName();
|
||||
}
|
||||
|
||||
private String configMapName(ConfigMap configMap) {
|
||||
return configMap.getMetadata().getName();
|
||||
}
|
||||
|
||||
private String secretName(Secret secret) {
|
||||
return secret.getMetadata().getName();
|
||||
}
|
||||
|
||||
public KubernetesClient client() {
|
||||
return client;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,517 @@
|
||||
/*
|
||||
* 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.integration.tests.commons.native_client;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.StringReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import io.kubernetes.client.openapi.ApiClient;
|
||||
import io.kubernetes.client.openapi.ApiException;
|
||||
import io.kubernetes.client.openapi.Configuration;
|
||||
import io.kubernetes.client.openapi.apis.AppsV1Api;
|
||||
import io.kubernetes.client.openapi.apis.CoreV1Api;
|
||||
import io.kubernetes.client.openapi.apis.NetworkingV1Api;
|
||||
import io.kubernetes.client.openapi.apis.RbacAuthorizationV1Api;
|
||||
import io.kubernetes.client.openapi.models.V1ClusterRole;
|
||||
import io.kubernetes.client.openapi.models.V1ConfigMap;
|
||||
import io.kubernetes.client.openapi.models.V1Deployment;
|
||||
import io.kubernetes.client.openapi.models.V1DeploymentList;
|
||||
import io.kubernetes.client.openapi.models.V1Ingress;
|
||||
import io.kubernetes.client.openapi.models.V1LoadBalancerIngress;
|
||||
import io.kubernetes.client.openapi.models.V1LoadBalancerStatus;
|
||||
import io.kubernetes.client.openapi.models.V1NamespaceBuilder;
|
||||
import io.kubernetes.client.openapi.models.V1Role;
|
||||
import io.kubernetes.client.openapi.models.V1RoleBinding;
|
||||
import io.kubernetes.client.openapi.models.V1Secret;
|
||||
import io.kubernetes.client.openapi.models.V1Service;
|
||||
import io.kubernetes.client.openapi.models.V1ServiceAccount;
|
||||
import io.kubernetes.client.util.Config;
|
||||
import io.kubernetes.client.util.Yaml;
|
||||
import jakarta.annotation.Nullable;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.testcontainers.k3s.K3sContainer;
|
||||
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.Phase;
|
||||
|
||||
import static org.awaitility.Awaitility.await;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.springframework.cloud.kubernetes.integration.tests.commons.Commons.loadImage;
|
||||
import static org.springframework.cloud.kubernetes.integration.tests.commons.Commons.pomVersion;
|
||||
import static org.springframework.cloud.kubernetes.integration.tests.commons.Commons.pullImage;
|
||||
|
||||
/**
|
||||
* @author wind57
|
||||
*/
|
||||
public final class Util {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(Util.class);
|
||||
|
||||
private final CoreV1Api coreV1Api;
|
||||
|
||||
private final AppsV1Api appsV1Api;
|
||||
|
||||
private final NetworkingV1Api networkingV1Api;
|
||||
|
||||
private final RbacAuthorizationV1Api rbacApi;
|
||||
|
||||
private final K3sContainer container;
|
||||
|
||||
public Util(K3sContainer container) {
|
||||
|
||||
ApiClient client;
|
||||
try {
|
||||
client = Config.fromConfig(new StringReader(container.getKubeConfigYaml()));
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
client.setHttpClient(client.getHttpClient().newBuilder().readTimeout(Duration.ofSeconds(15)).build());
|
||||
client.setDebugging(false);
|
||||
Configuration.setDefaultApiClient(client);
|
||||
|
||||
this.container = container;
|
||||
this.coreV1Api = new CoreV1Api();
|
||||
this.appsV1Api = new AppsV1Api();
|
||||
this.networkingV1Api = new NetworkingV1Api();
|
||||
rbacApi = new RbacAuthorizationV1Api();
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the preferred method to use when creating a deployment alongside with a
|
||||
* service. It creates the given resources as-well as waits for them to be created.
|
||||
* The delay check is intentionally not taken as an argument, so that it stays as
|
||||
* tight as possible, providing reasonable defaults.
|
||||
*
|
||||
*/
|
||||
public void createAndWait(String namespace, String name, V1Deployment deployment, V1Service service,
|
||||
@Nullable V1Ingress ingress, boolean changeVersion) {
|
||||
try {
|
||||
|
||||
String imageFromDeployment = deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getImage();
|
||||
if (changeVersion) {
|
||||
deployment.getSpec().getTemplate().getSpec().getContainers().get(0)
|
||||
.setImage(imageFromDeployment + ":" + pomVersion());
|
||||
}
|
||||
else {
|
||||
String[] image = imageFromDeployment.split(":", 2);
|
||||
pullImage(image[0], image[1], container);
|
||||
loadImage(image[0], image[1], name, container);
|
||||
}
|
||||
|
||||
appsV1Api.createNamespacedDeployment(namespace, deployment, null, null, null, null);
|
||||
coreV1Api.createNamespacedService(namespace, service, null, null, null, null);
|
||||
waitForDeployment(namespace, deployment);
|
||||
if (ingress != null) {
|
||||
networkingV1Api.createNamespacedIngress(namespace, ingress, null, null, null, null);
|
||||
waitForIngress(namespace, ingress);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void createAndWait(String namespace, @Nullable V1ConfigMap configMap, @Nullable V1Secret secret) {
|
||||
try {
|
||||
if (configMap != null) {
|
||||
coreV1Api.createNamespacedConfigMap(namespace, configMap, null, null, null, null);
|
||||
waitForConfigMap(namespace, configMap, Phase.CREATE);
|
||||
}
|
||||
|
||||
if (secret != null) {
|
||||
coreV1Api.createNamespacedSecret(namespace, secret, null, null, null, null);
|
||||
waitForSecret(namespace, secret, Phase.CREATE);
|
||||
}
|
||||
|
||||
}
|
||||
catch (ApiException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteAndWait(String namespace, @Nullable V1ConfigMap configMap, @Nullable V1Secret secret) {
|
||||
try {
|
||||
if (configMap != null) {
|
||||
String configMapName = configMapName(configMap);
|
||||
coreV1Api.deleteNamespacedConfigMap(configMapName, namespace, null, null, null, null, null, null);
|
||||
waitForConfigMap(namespace, configMap, Phase.DELETE);
|
||||
}
|
||||
|
||||
if (secret != null) {
|
||||
String secretName = secretName(secret);
|
||||
coreV1Api.deleteNamespacedSecret(secretName, namespace, null, null, null, null, null, null);
|
||||
waitForSecret(namespace, secret, Phase.DELETE);
|
||||
}
|
||||
|
||||
}
|
||||
catch (ApiException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void createNamespace(String name) {
|
||||
try {
|
||||
coreV1Api.createNamespace(new V1NamespaceBuilder().withNewMetadata().withName(name).and().build(), null,
|
||||
null, null, null);
|
||||
}
|
||||
catch (ApiException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteAndWait(String namespace, V1Deployment deployment, V1Service service,
|
||||
@Nullable V1Ingress ingress) {
|
||||
String deploymentName = deploymentName(deployment);
|
||||
String serviceName = serviceName(service);
|
||||
try {
|
||||
appsV1Api.deleteNamespacedDeployment(deploymentName, namespace, null, null, null, null, null, null);
|
||||
coreV1Api.deleteNamespacedService(serviceName, namespace, null, null, null, null, null, null);
|
||||
waitForDeploymentToBeDeleted(deploymentName, namespace);
|
||||
|
||||
if (ingress != null) {
|
||||
String ingressName = ingressName(ingress);
|
||||
networkingV1Api.deleteNamespacedIngress(ingressName, namespace, null, null, null, null, null, null);
|
||||
waitForIngressToBeDeleted(ingressName, namespace);
|
||||
}
|
||||
|
||||
}
|
||||
catch (ApiException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void busybox(String namespace, Phase phase) {
|
||||
V1Deployment deployment = (V1Deployment) yaml("busybox/deployment.yaml");
|
||||
V1Service service = (V1Service) yaml("busybox/service.yaml");
|
||||
if (phase.equals(Phase.CREATE)) {
|
||||
createAndWait(namespace, "busybox", deployment, service, null, false);
|
||||
}
|
||||
else if (phase.equals(Phase.DELETE)) {
|
||||
deleteAndWait(namespace, deployment, service, null);
|
||||
}
|
||||
}
|
||||
|
||||
public void kafka(String namespace, Phase phase) {
|
||||
V1Deployment deployment = (V1Deployment) yaml("kafka/kafka-deployment.yaml");
|
||||
V1Service service = (V1Service) yaml("kafka/kafka-service.yaml");
|
||||
|
||||
if (phase.equals(Phase.CREATE)) {
|
||||
createAndWait(namespace, "kafka", deployment, service, null, false);
|
||||
}
|
||||
else if (phase.equals(Phase.DELETE)) {
|
||||
deleteAndWait(namespace, deployment, service, null);
|
||||
}
|
||||
}
|
||||
|
||||
public void rabbitMq(String namespace, Phase phase) {
|
||||
V1Deployment deployment = (V1Deployment) yaml("rabbitmq/rabbitmq-deployment.yaml");
|
||||
V1Service service = (V1Service) yaml("rabbitmq/rabbitmq-service.yaml");
|
||||
|
||||
if (phase.equals(Phase.CREATE)) {
|
||||
createAndWait(namespace, "rabbitmq", deployment, service, null, false);
|
||||
}
|
||||
else if (phase.equals(Phase.DELETE)) {
|
||||
deleteAndWait(namespace, deployment, service, null);
|
||||
}
|
||||
}
|
||||
|
||||
public void zookeeper(String namespace, Phase phase) {
|
||||
V1Deployment deployment = (V1Deployment) yaml("zookeeper/zookeeper-deployment.yaml");
|
||||
V1Service service = (V1Service) yaml("zookeeper/zookeeper-service.yaml");
|
||||
|
||||
if (phase.equals(Phase.CREATE)) {
|
||||
createAndWait(namespace, "zookeeper", deployment, service, null, false);
|
||||
}
|
||||
else if (phase.equals(Phase.DELETE)) {
|
||||
deleteAndWait(namespace, deployment, service, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* reads a yaml from classpath, fails if not found.
|
||||
*/
|
||||
public Object yaml(String fileName) {
|
||||
ClassLoader classLoader = Util.class.getClassLoader();
|
||||
String file = new BufferedReader(new InputStreamReader(classLoader.getResourceAsStream(fileName))).lines()
|
||||
.collect(Collectors.joining("\n"));
|
||||
try {
|
||||
return Yaml.load(file);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void setUp(String namespace) {
|
||||
|
||||
try {
|
||||
V1ServiceAccount serviceAccount = (V1ServiceAccount) yaml("setup/service-account.yaml");
|
||||
CheckedSupplier<V1ServiceAccount> accountSupplier = () -> coreV1Api
|
||||
.readNamespacedServiceAccount(serviceAccount.getMetadata().getName(), namespace, null);
|
||||
CheckedSupplier<V1ServiceAccount> accountDefaulter = () -> coreV1Api
|
||||
.createNamespacedServiceAccount(namespace, serviceAccount, null, null, null, null);
|
||||
notExistsHandler(accountSupplier, accountDefaulter);
|
||||
|
||||
V1RoleBinding roleBinding = (V1RoleBinding) yaml("setup/role-binding.yaml");
|
||||
notExistsHandler(
|
||||
() -> rbacApi.readNamespacedRoleBinding(roleBinding.getMetadata().getName(), namespace, null),
|
||||
() -> rbacApi.createNamespacedRoleBinding(namespace, roleBinding, null, null, null, null));
|
||||
|
||||
V1Role role = (V1Role) yaml("setup/role.yaml");
|
||||
notExistsHandler(() -> rbacApi.readNamespacedRole(role.getMetadata().getName(), namespace, null),
|
||||
() -> rbacApi.createNamespacedRole(namespace, role, null, null, null, null));
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void setUpClusterWide(String serviceAccountNamespace, Set<String> namespaces) {
|
||||
|
||||
try {
|
||||
V1ServiceAccount serviceAccount = (V1ServiceAccount) yaml("cluster/service-account.yaml");
|
||||
CheckedSupplier<V1ServiceAccount> accountSupplier = () -> coreV1Api.readNamespacedServiceAccount(
|
||||
serviceAccount.getMetadata().getName(), serviceAccountNamespace, null);
|
||||
CheckedSupplier<V1ServiceAccount> accountDefaulter = () -> coreV1Api
|
||||
.createNamespacedServiceAccount(serviceAccountNamespace, serviceAccount, null, null, null, null);
|
||||
notExistsHandler(accountSupplier, accountDefaulter);
|
||||
|
||||
V1ClusterRole clusterRole = (V1ClusterRole) yaml("cluster/cluster-role.yaml");
|
||||
notExistsHandler(() -> rbacApi.readClusterRole(clusterRole.getMetadata().getName(), null),
|
||||
() -> rbacApi.createClusterRole(clusterRole, null, null, null, null));
|
||||
|
||||
V1RoleBinding roleBinding = (V1RoleBinding) yaml("cluster/role-binding.yaml");
|
||||
namespaces.forEach(namespace -> {
|
||||
roleBinding.getMetadata().setNamespace(namespace);
|
||||
try {
|
||||
notExistsHandler(
|
||||
() -> rbacApi.readNamespacedRoleBinding(roleBinding.getMetadata().getName(), namespace,
|
||||
null),
|
||||
() -> rbacApi.createNamespacedRoleBinding(namespace, roleBinding, null, null, null, null));
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void deleteNamespace(String name) {
|
||||
try {
|
||||
coreV1Api.deleteNamespace(name, null, null, null, null, null, null);
|
||||
}
|
||||
catch (ApiException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
await().pollInterval(Duration.ofSeconds(1)).atMost(30, TimeUnit.SECONDS)
|
||||
.until(() -> coreV1Api.listNamespace(null, null, null, null, null, null, null, null, null, null)
|
||||
.getItems().stream().noneMatch(x -> x.getMetadata().getName().equals(name)));
|
||||
}
|
||||
|
||||
public void wiremock(String namespace, String path, Phase phase) {
|
||||
V1Deployment deployment = (V1Deployment) yaml("wiremock/wiremock-deployment.yaml");
|
||||
V1Service service = (V1Service) yaml("wiremock/wiremock-service.yaml");
|
||||
V1Ingress ingress = (V1Ingress) yaml("wiremock/wiremock-ingress.yaml");
|
||||
|
||||
if (phase.equals(Phase.CREATE)) {
|
||||
deployment.getMetadata().setNamespace(namespace);
|
||||
service.getMetadata().setNamespace(namespace);
|
||||
ingress.getMetadata().setNamespace(namespace);
|
||||
ingress.getSpec().getRules().get(0).getHttp().getPaths().get(0).setPath(path);
|
||||
createAndWait(namespace, "wiremock", deployment, service, ingress, false);
|
||||
}
|
||||
else {
|
||||
deleteAndWait(namespace, deployment, service, ingress);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private String deploymentName(V1Deployment deployment) {
|
||||
return deployment.getMetadata().getName();
|
||||
}
|
||||
|
||||
private String serviceName(V1Service service) {
|
||||
return service.getMetadata().getName();
|
||||
}
|
||||
|
||||
private String ingressName(V1Ingress ingress) {
|
||||
return ingress.getMetadata().getName();
|
||||
}
|
||||
|
||||
private String configMapName(V1ConfigMap configMap) {
|
||||
return configMap.getMetadata().getName();
|
||||
}
|
||||
|
||||
private String secretName(V1Secret secret) {
|
||||
return secret.getMetadata().getName();
|
||||
}
|
||||
|
||||
private void waitForDeployment(String namespace, V1Deployment deployment) {
|
||||
String deploymentName = deploymentName(deployment);
|
||||
await().pollInterval(Duration.ofSeconds(1)).atMost(600, TimeUnit.SECONDS)
|
||||
.until(() -> isDeploymentReady(deploymentName, namespace));
|
||||
}
|
||||
|
||||
private void waitForConfigMap(String namespace, V1ConfigMap configMap, Phase phase) {
|
||||
String configMapName = configMapName(configMap);
|
||||
await().pollInterval(Duration.ofSeconds(1)).atMost(600, TimeUnit.SECONDS).until(() -> {
|
||||
try {
|
||||
coreV1Api.readNamespacedConfigMap(configMapName, namespace, null);
|
||||
return phase.equals(Phase.CREATE);
|
||||
}
|
||||
catch (ApiException e) {
|
||||
if (e.getCode() == HttpURLConnection.HTTP_NOT_FOUND) {
|
||||
return !phase.equals(Phase.CREATE);
|
||||
|
||||
}
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void waitForSecret(String namespace, V1Secret secret, Phase phase) {
|
||||
String secretName = secretName(secret);
|
||||
await().pollInterval(Duration.ofSeconds(1)).atMost(600, TimeUnit.SECONDS).until(() -> {
|
||||
try {
|
||||
coreV1Api.readNamespacedSecret(secretName, namespace, null);
|
||||
return phase.equals(Phase.CREATE);
|
||||
}
|
||||
catch (ApiException e) {
|
||||
if (e.getCode() == HttpURLConnection.HTTP_NOT_FOUND) {
|
||||
return !phase.equals(Phase.CREATE);
|
||||
}
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void waitForIngress(String namespace, V1Ingress ingress) {
|
||||
String ingressName = ingressName(ingress);
|
||||
await().timeout(Duration.ofSeconds(90)).pollInterval(Duration.ofSeconds(3)).until(() -> {
|
||||
try {
|
||||
V1LoadBalancerStatus status = networkingV1Api.readNamespacedIngress(ingressName, namespace, null)
|
||||
.getStatus().getLoadBalancer();
|
||||
|
||||
if (status == null) {
|
||||
LOG.info("ingress : " + ingressName + " not ready yet (loadbalancer not yet present)");
|
||||
return false;
|
||||
}
|
||||
|
||||
List<V1LoadBalancerIngress> loadBalancerIngress = status.getIngress();
|
||||
if (loadBalancerIngress == null) {
|
||||
LOG.info("ingress : " + ingressName + " not ready yet (loadbalancer ingress not yet present)");
|
||||
return false;
|
||||
}
|
||||
|
||||
String ip = loadBalancerIngress.get(0).getIp();
|
||||
if (ip == null) {
|
||||
LOG.info("ingress : " + ingressName + " not ready yet");
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG.info("ingress : " + ingressName + " ready with ip : " + ip);
|
||||
return true;
|
||||
}
|
||||
catch (ApiException e) {
|
||||
if (e.getCode() == HttpURLConnection.HTTP_NOT_FOUND) {
|
||||
return false;
|
||||
}
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void waitForDeploymentToBeDeleted(String deploymentName, String namespace) {
|
||||
await().timeout(Duration.ofSeconds(90)).until(() -> {
|
||||
try {
|
||||
appsV1Api.readNamespacedDeployment(deploymentName, namespace, null);
|
||||
return false;
|
||||
}
|
||||
catch (ApiException e) {
|
||||
if (e.getCode() == HttpURLConnection.HTTP_NOT_FOUND) {
|
||||
return true;
|
||||
}
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void waitForIngressToBeDeleted(String ingressName, String namespace) {
|
||||
await().timeout(Duration.ofSeconds(90)).until(() -> {
|
||||
try {
|
||||
networkingV1Api.readNamespacedIngress(ingressName, namespace, null);
|
||||
return false;
|
||||
}
|
||||
catch (ApiException e) {
|
||||
if (e.getCode() == HttpURLConnection.HTTP_NOT_FOUND) {
|
||||
return true;
|
||||
}
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private boolean isDeploymentReady(String deploymentName, String namespace) throws ApiException {
|
||||
V1DeploymentList deployments = appsV1Api.listNamespacedDeployment(namespace, null, null, null,
|
||||
"metadata.name=" + deploymentName, null, null, null, null, null, null);
|
||||
if (deployments.getItems().size() < 1) {
|
||||
fail("No deployments with the name " + deploymentName);
|
||||
}
|
||||
V1Deployment deployment = deployments.getItems().get(0);
|
||||
Integer availableReplicas = deployment.getStatus().getAvailableReplicas();
|
||||
LOG.info("Available replicas for " + deploymentName + ": "
|
||||
+ (availableReplicas == null ? 0 : availableReplicas));
|
||||
return availableReplicas != null && availableReplicas >= 1;
|
||||
}
|
||||
|
||||
private static <T> void notExistsHandler(CheckedSupplier<T> callee, CheckedSupplier<T> defaulter) throws Exception {
|
||||
try {
|
||||
callee.get();
|
||||
}
|
||||
catch (Exception exception) {
|
||||
if (exception instanceof ApiException apiException) {
|
||||
if (apiException.getCode() == 404) {
|
||||
defaulter.get();
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new RuntimeException(exception);
|
||||
}
|
||||
}
|
||||
|
||||
private interface CheckedSupplier<T> {
|
||||
|
||||
T get() throws Exception;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: rabbitmq
|
||||
labels:
|
||||
app: taskqueue
|
||||
component: rabbitmq
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: taskqueue
|
||||
component: rabbitmq
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: taskqueue
|
||||
component: rabbitmq
|
||||
spec:
|
||||
containers:
|
||||
- name: taskqueue
|
||||
image: rabbitmq:3-management
|
||||
imagePullPolicy: IfNotPresent
|
||||
|
||||
|
||||
@@ -13,5 +13,5 @@ spec:
|
||||
name: http-stats
|
||||
targetPort: 15672
|
||||
selector:
|
||||
app: taskQueue
|
||||
app: taskqueue
|
||||
component: rabbitmq
|
||||
@@ -1,19 +1,19 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: servicea-wiremock-deployment
|
||||
name: service-wiremock-deployment
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: servicea-wiremock
|
||||
app: service-wiremock
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: servicea-wiremock
|
||||
app: service-wiremock
|
||||
spec:
|
||||
containers:
|
||||
- name: servicea-wiremock
|
||||
image: wiremock/wiremock:2.32.0
|
||||
- name: service-wiremock
|
||||
image: wiremock/wiremock:2.35.0
|
||||
args: ["--verbose"]
|
||||
imagePullPolicy: IfNotPresent
|
||||
readinessProbe:
|
||||
|
||||
@@ -11,7 +11,7 @@ spec:
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: servicea-wiremock
|
||||
name: service-wiremock
|
||||
port:
|
||||
number: 8080
|
||||
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: wiremock-ingress
|
||||
namespace: default
|
||||
spec:
|
||||
rules:
|
||||
- http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: servicea-wiremock
|
||||
port:
|
||||
number: 8080
|
||||
|
||||
@@ -2,13 +2,13 @@ apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app: servicea-wiremock
|
||||
name: servicea-wiremock
|
||||
app: service-wiremock
|
||||
name: service-wiremock
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 8080
|
||||
targetPort: 8080
|
||||
selector:
|
||||
app: servicea-wiremock
|
||||
app: service-wiremock
|
||||
type: ClusterIP
|
||||
|
||||
Reference in New Issue
Block a user