From d16ea64164f132919250feefbd508a8c431c9dba Mon Sep 17 00:00:00 2001 From: David Turanski Date: Wed, 12 Jan 2022 12:39:15 -0500 Subject: [PATCH] Implement KubernetesActuatorTemplate --- pom.xml | 17 ++ .../KubernetesActuatorTemplate.java | 38 ++++ .../KubernetesAppInstanceStatus.java | 15 +- .../KubernetesAutoConfiguration.java | 13 ++ .../KubernetesActuatorTemplateTests.java | 172 ++++++++++++++++++ .../KubernetesAppDeployerIntegrationIT.java | 138 +++++--------- .../KubernetesAppDeployerTests.java | 105 ++++++----- .../resources/actuator-binding-input.json | 97 ++++++++++ src/test/resources/actuator-bindings.json | 100 ++++++++++ src/test/resources/actuator-info.json | 7 + 10 files changed, 564 insertions(+), 138 deletions(-) create mode 100644 src/main/java/org/springframework/cloud/deployer/spi/kubernetes/KubernetesActuatorTemplate.java create mode 100644 src/test/java/org/springframework/cloud/deployer/spi/kubernetes/KubernetesActuatorTemplateTests.java create mode 100644 src/test/resources/actuator-binding-input.json create mode 100644 src/test/resources/actuator-bindings.json create mode 100644 src/test/resources/actuator-info.json diff --git a/pom.xml b/pom.xml index 217d83a9..7140f654 100644 --- a/pom.xml +++ b/pom.xml @@ -22,6 +22,7 @@ 0.9.0 3.8.0 2.0.2 + 3.14.9 @@ -40,6 +41,10 @@ org.springframework.boot spring-boot-autoconfigure + + org.springframework + spring-web + io.fabric8 kubernetes-client @@ -78,6 +83,18 @@ 2.23.4 test + + com.squareup.okhttp3 + okhttp + ${okhttp.version} + test + + + com.squareup.okhttp3 + mockwebserver + ${okhttp.version} + test + diff --git a/src/main/java/org/springframework/cloud/deployer/spi/kubernetes/KubernetesActuatorTemplate.java b/src/main/java/org/springframework/cloud/deployer/spi/kubernetes/KubernetesActuatorTemplate.java new file mode 100644 index 00000000..e0522d17 --- /dev/null +++ b/src/main/java/org/springframework/cloud/deployer/spi/kubernetes/KubernetesActuatorTemplate.java @@ -0,0 +1,38 @@ +/* + * Copyright 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.deployer.spi.kubernetes; + +import org.springframework.cloud.deployer.spi.app.AbstractActuatorTemplate; +import org.springframework.cloud.deployer.spi.app.AppDeployer; +import org.springframework.cloud.deployer.spi.app.AppInstanceStatus; +import org.springframework.web.client.RestTemplate; + +/** + * @author David Turanski + */ + +public class KubernetesActuatorTemplate extends AbstractActuatorTemplate { + + public KubernetesActuatorTemplate(RestTemplate restTemplate, AppDeployer appDeployer) { + super(restTemplate, appDeployer); + } + + protected String actuatorUrlForInstance(AppInstanceStatus appInstanceStatus) { + return String.format("http://%s:%d/actuator", appInstanceStatus.getAttributes().get("pod.ip"), + Integer.valueOf(appInstanceStatus.getAttributes().get("actuator.port"))); + } +} diff --git a/src/main/java/org/springframework/cloud/deployer/spi/kubernetes/KubernetesAppInstanceStatus.java b/src/main/java/org/springframework/cloud/deployer/spi/kubernetes/KubernetesAppInstanceStatus.java index 149fa39f..205add6e 100644 --- a/src/main/java/org/springframework/cloud/deployer/spi/kubernetes/KubernetesAppInstanceStatus.java +++ b/src/main/java/org/springframework/cloud/deployer/spi/kubernetes/KubernetesAppInstanceStatus.java @@ -1,5 +1,5 @@ /* - * Copyright 2015-2019 the original author or authors. + * Copyright 2015-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. @@ -20,7 +20,9 @@ import java.util.List; import java.util.Map; +import io.fabric8.kubernetes.api.model.Container; import io.fabric8.kubernetes.api.model.ContainerStatus; +import io.fabric8.kubernetes.api.model.IntOrString; import io.fabric8.kubernetes.api.model.Pod; import io.fabric8.kubernetes.api.model.Service; import io.fabric8.kubernetes.api.model.ServicePort; @@ -127,6 +129,7 @@ public Map getAttributes() { result.put("pod.name", pod.getMetadata().getName()); result.put("pod.startTime", pod.getStatus().getStartTime()); result.put("pod.ip", pod.getStatus().getPodIP()); + result.put("actuator.port", determineActuatorPort(pod)); result.put("host.ip", pod.getStatus().getHostIP()); result.put("phase", pod.getStatus().getPhase()); result.put(AbstractKubernetesDeployer.SPRING_APP_KEY.replace('-', '.'), @@ -175,6 +178,16 @@ public Map getAttributes() { } return result; } + + private String determineActuatorPort(Pod pod) { + return pod.getSpec().getContainers().stream().filter( (Container container) -> + container.getLivenessProbe() != null && + container.getLivenessProbe().getHttpGet() != null && + container.getLivenessProbe().getHttpGet().getPath().startsWith("/actuator")) + .findFirst() + .map(container -> container.getLivenessProbe().getHttpGet().getPort().getStrVal()) + .orElse(new IntOrString("unknown").getStrVal()); + } } diff --git a/src/main/java/org/springframework/cloud/deployer/spi/kubernetes/KubernetesAutoConfiguration.java b/src/main/java/org/springframework/cloud/deployer/spi/kubernetes/KubernetesAutoConfiguration.java index 930159c2..1e1b312c 100644 --- a/src/main/java/org/springframework/cloud/deployer/spi/kubernetes/KubernetesAutoConfiguration.java +++ b/src/main/java/org/springframework/cloud/deployer/spi/kubernetes/KubernetesAutoConfiguration.java @@ -22,11 +22,13 @@ import org.springframework.boot.autoconfigure.AutoConfigureOrder; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cloud.deployer.spi.app.ActuatorOperations; import org.springframework.cloud.deployer.spi.app.AppDeployer; import org.springframework.cloud.deployer.spi.task.TaskLauncher; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; +import org.springframework.web.client.RestTemplate; /** * Spring Bean configuration for the {@link KubernetesAppDeployer}. @@ -72,4 +74,15 @@ public ContainerFactory containerFactory() { return new DefaultContainerFactory(deployerProperties); } + @Bean + ActuatorOperations actuatorSupport(RestTemplate actuatorRestTemplate, AppDeployer appDeployer) { + return new KubernetesActuatorTemplate(actuatorRestTemplate, appDeployer); + } + + @Bean + RestTemplate actuatorRestTemplate() { + //TODO: Configure security + return new RestTemplate(); + } + } diff --git a/src/test/java/org/springframework/cloud/deployer/spi/kubernetes/KubernetesActuatorTemplateTests.java b/src/test/java/org/springframework/cloud/deployer/spi/kubernetes/KubernetesActuatorTemplateTests.java new file mode 100644 index 00000000..079d505c --- /dev/null +++ b/src/test/java/org/springframework/cloud/deployer/spi/kubernetes/KubernetesActuatorTemplateTests.java @@ -0,0 +1,172 @@ +/* + * Copyright 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.deployer.spi.kubernetes; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import okhttp3.mockwebserver.Dispatcher; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import okhttp3.mockwebserver.RecordedRequest; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import org.springframework.cloud.deployer.spi.app.ActuatorOperations; +import org.springframework.cloud.deployer.spi.app.AppDeployer; +import org.springframework.cloud.deployer.spi.app.AppInstanceStatus; +import org.springframework.cloud.deployer.spi.app.AppStatus; +import org.springframework.cloud.deployer.spi.app.DeploymentState; +import org.springframework.core.io.ClassPathResource; +import org.springframework.http.HttpStatus; +import org.springframework.util.StreamUtils; +import org.springframework.util.StringUtils; +import org.springframework.web.client.RestTemplate; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class KubernetesActuatorTemplateTests { + private static MockWebServer mockActuator; + + private final AppDeployer appDeployer = mock(AppDeployer.class); + + private final ActuatorOperations actuatorOperations = new KubernetesActuatorTemplate(new RestTemplate(), appDeployer); + + private AppInstanceStatus appInstanceStatus; + + @BeforeAll + static void setupMockServer() throws IOException { + mockActuator = new MockWebServer(); + mockActuator.start(); + mockActuator.setDispatcher(new Dispatcher() { + @Override + public MockResponse dispatch(RecordedRequest recordedRequest) throws InterruptedException { + switch (recordedRequest.getPath()) { + case "/actuator/info": + return new MockResponse().setBody(resourceAsString("actuator-info.json")) + .addHeader("Content-Type", "application/json").setResponseCode(200); + case "/actuator/health": + return new MockResponse().setBody("\"status\":\"UP\"}") + .addHeader("Content-Type", "application/json").setResponseCode(200); + case "/actuator/bindings": + return new MockResponse().setBody(resourceAsString("actuator-bindings.json")) + .addHeader("Content-Type", "application/json").setResponseCode(200); + case "/actuator/bindings/input": + if (recordedRequest.getMethod().equals("GET")) { + return new MockResponse().setBody(resourceAsString("actuator-binding-input.json")) + .addHeader("Content-Type", "application/json") + .setResponseCode(200); + } + else if (recordedRequest.getMethod().equals("POST")) { + if (!StringUtils.hasText(recordedRequest.getBody().toString())) { + return new MockResponse().setResponseCode(HttpStatus.BAD_REQUEST.value()); + } + else { + return new MockResponse().setBody(recordedRequest.getBody()) + .addHeader("Content-Type", "application/json").setResponseCode(200); + } + } + else { + return new MockResponse().setResponseCode(HttpStatus.BAD_REQUEST.value()); + } + default: + return new MockResponse().setResponseCode(HttpStatus.NOT_FOUND.value()); + } + } + }); + } + + @AfterAll + static void tearDown() throws IOException { + mockActuator.shutdown(); + } + + @BeforeEach + void setUp() { + appInstanceStatus = mock(AppInstanceStatus.class); + Map attributes = new HashMap<>(); + attributes.put("pod.ip", "127.0.0.1"); + attributes.put("actuator.port", String.valueOf(mockActuator.getPort())); + attributes.put("guid", "test-application-0"); + when(appInstanceStatus.getAttributes()).thenReturn(attributes); + when(appInstanceStatus.getState()).thenReturn(DeploymentState.deployed); + AppStatus appStatus = AppStatus.of("test-application-id") + .with(appInstanceStatus) + .build(); + when(appDeployer.status(anyString())).thenReturn(appStatus); + } + + @Test + void actuatorInfo() { + Map info = actuatorOperations + .getFromActuator("test-application-id", "test-application-0", "/info", Map.class); + + assertThat(((Map) (info.get("app"))).get("name")).isEqualTo("log-sink-rabbit"); + } + + @Test + void actuatorBindings() { + List bindings = actuatorOperations + .getFromActuator("test-application-id", "test-application-0", "/bindings", List.class); + + assertThat(((Map) (bindings.get(0))).get("bindingName")).isEqualTo("input"); + } + + @Test + void actuatorBindingInput() { + Map binding = actuatorOperations + .getFromActuator("test-application-id", "test-application-0", "/bindings/input", Map.class); + assertThat(binding.get("bindingName")).isEqualTo("input"); + } + + @Test + void actuatorPostBindingInput() { + Map state = actuatorOperations + .postToActuator("test-application-id", "test-application-0", "/bindings/input", + Collections.singletonMap("state", "STOPPED"), Map.class); + assertThat(state.get("state")).isEqualTo("STOPPED"); + } + + @Test + void noInstanceDeployed() { + when(appInstanceStatus.getState()).thenReturn(DeploymentState.failed); + assertThatThrownBy(() -> { + actuatorOperations + .getFromActuator("test-application-id", "test-application-0", "/info", Map.class); + + }).isInstanceOf(IllegalStateException.class).hasMessageContaining("not deployed"); + } + + private static String resourceAsString(String path) { + try { + return StreamUtils.copyToString(new ClassPathResource(path).getInputStream(), StandardCharsets.UTF_8); + } + catch (IOException e) { + throw new RuntimeException(e.getMessage(), e); + } + } +} diff --git a/src/test/java/org/springframework/cloud/deployer/spi/kubernetes/KubernetesAppDeployerIntegrationIT.java b/src/test/java/org/springframework/cloud/deployer/spi/kubernetes/KubernetesAppDeployerIntegrationIT.java index efceebea..55031aef 100644 --- a/src/test/java/org/springframework/cloud/deployer/spi/kubernetes/KubernetesAppDeployerIntegrationIT.java +++ b/src/test/java/org/springframework/cloud/deployer/spi/kubernetes/KubernetesAppDeployerIntegrationIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2021 the original author or authors. + * Copyright 2016-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. @@ -128,11 +128,7 @@ public void setup() { @Test public void testScaleStatefulSet() { log.info("Testing {}...", "ScaleStatefulSet"); - KubernetesDeployerProperties deployProperties = new KubernetesDeployerProperties(); - - ContainerFactory containerFactory = new DefaultContainerFactory(deployProperties); - KubernetesAppDeployer appDeployer = new KubernetesAppDeployer(deployProperties, kubernetesClient, - containerFactory); + KubernetesAppDeployer appDeployer = kubernetesAppDeployer(); AppDefinition definition = new AppDefinition(randomName(), null); Resource resource = testApplication(); @@ -193,11 +189,7 @@ public void testScaleStatefulSet() { @Test public void testScaleDeployment() { log.info("Testing {}...", "ScaleDeployment"); - KubernetesDeployerProperties deployProperties = new KubernetesDeployerProperties(); - - ContainerFactory containerFactory = new DefaultContainerFactory(deployProperties); - KubernetesAppDeployer appDeployer = new KubernetesAppDeployer(deployProperties, kubernetesClient, - containerFactory); + KubernetesAppDeployer appDeployer = kubernetesAppDeployer(); AppDefinition definition = new AppDefinition(randomName(), null); Resource resource = testApplication(); @@ -253,9 +245,7 @@ public void testFailedDeploymentWithLoadBalancer() { deployProperties.setLivenessHttpProbePeriod(10); deployProperties.setMaxTerminatedErrorRestarts(1); deployProperties.setMaxCrashLoopBackOffRestarts(1); - ContainerFactory containerFactory = new DefaultContainerFactory(deployProperties); - KubernetesAppDeployer lbAppDeployer = new KubernetesAppDeployer(deployProperties, kubernetesClient, - containerFactory); + KubernetesAppDeployer lbAppDeployer = kubernetesAppDeployer(deployProperties); AppDefinition definition = new AppDefinition(randomName(), null); Resource resource = testApplication(); @@ -292,9 +282,7 @@ public void testGoodDeploymentWithLoadBalancer() { KubernetesDeployerProperties deployProperties = new KubernetesDeployerProperties(); deployProperties.setCreateLoadBalancer(true); deployProperties.setMinutesToWaitForLoadBalancer(1); - ContainerFactory containerFactory = new DefaultContainerFactory(deployProperties); - KubernetesAppDeployer lbAppDeployer = new KubernetesAppDeployer(deployProperties, kubernetesClient, - containerFactory); + KubernetesAppDeployer lbAppDeployer = kubernetesAppDeployer(deployProperties); AppDefinition definition = new AppDefinition(randomName(), null); Resource resource = testApplication(); @@ -327,9 +315,7 @@ public void testDeploymentWithLoadBalancerHasUrlAndAnnotation() { KubernetesDeployerProperties deployProperties = new KubernetesDeployerProperties(); deployProperties.setCreateLoadBalancer(true); deployProperties.setMinutesToWaitForLoadBalancer(1); - ContainerFactory containerFactory = new DefaultContainerFactory(deployProperties); - KubernetesAppDeployer lbAppDeployer = new KubernetesAppDeployer(deployProperties, kubernetesClient, - containerFactory); + KubernetesAppDeployer lbAppDeployer = kubernetesAppDeployer(deployProperties); AppDefinition definition = new AppDefinition(randomName(), null); Resource resource = testApplication(); @@ -379,10 +365,7 @@ public void testDeploymentWithLoadBalancerHasUrlAndAnnotation() { @Test public void testDeploymentWithPodAnnotation() { log.info("Testing {}...", "DeploymentWithPodAnnotation"); - KubernetesDeployerProperties deployProperties = new KubernetesDeployerProperties(); - ContainerFactory containerFactory = new DefaultContainerFactory(deployProperties); - KubernetesAppDeployer appDeployer = new KubernetesAppDeployer(deployProperties, kubernetesClient, - containerFactory); + KubernetesAppDeployer appDeployer = kubernetesAppDeployer(); AppDefinition definition = new AppDefinition(randomName(), null); Resource resource = testApplication(); @@ -442,9 +425,7 @@ public void testDeploymentWithMountedHostPathVolume() throws IOException { .build())); deployProperties.setVolumeMounts(Collections.singletonList(new VolumeMount(hostPathVolumeSource.getPath(), null, mountName, false, null, null))); - ContainerFactory containerFactory = new DefaultContainerFactory(deployProperties); - KubernetesAppDeployer lbAppDeployer = new KubernetesAppDeployer(deployProperties, kubernetesClient, - containerFactory); + KubernetesAppDeployer lbAppDeployer = kubernetesAppDeployer(deployProperties); AppDefinition definition = new AppDefinition(randomName(), Collections.singletonMap("logging.file", containerPath + subPath)); @@ -583,9 +564,7 @@ public void testDeploymentWithGroupAndIndex() throws IOException { KubernetesDeployerProperties deployProperties = new KubernetesDeployerProperties(); deployProperties.setCreateLoadBalancer(true); deployProperties.setMinutesToWaitForLoadBalancer(1); - ContainerFactory containerFactory = new DefaultContainerFactory(deployProperties); - KubernetesAppDeployer testAppDeployer = new KubernetesAppDeployer(deployProperties, kubernetesClient, - containerFactory); + KubernetesAppDeployer testAppDeployer = kubernetesAppDeployer(deployProperties); Map appProperties = new HashMap<>(); appProperties.put("security.basic.enabled", "false"); @@ -642,8 +621,7 @@ public void testDeploymentServiceAccountName() { deployProperties.setDeploymentServiceAccountName(serviceAccountName); ContainerFactory containerFactory = new DefaultContainerFactory(deployProperties); - KubernetesAppDeployer appDeployer = new KubernetesAppDeployer(deployProperties, kubernetesClient, - containerFactory); + KubernetesAppDeployer appDeployer = kubernetesAppDeployer(deployProperties); AppDefinition definition = new AppDefinition(randomName(), null); AppDeploymentRequest request = new AppDeploymentRequest(definition, testApplication()); @@ -678,8 +656,7 @@ public void testCreateStatefulSet() throws Exception { AppDefinition definition = new AppDefinition(randomName(), null); AppDeploymentRequest appDeploymentRequest = new AppDeploymentRequest(definition, testApplication(), props); - KubernetesAppDeployer deployer = new KubernetesAppDeployer(new KubernetesDeployerProperties(), - kubernetesClient); + KubernetesAppDeployer deployer = kubernetesAppDeployer(); log.info("Deploying {}...", appDeploymentRequest.getDefinition().getName()); String deploymentId = deployer.deploy(appDeploymentRequest); @@ -764,8 +741,7 @@ public void testCreateStatefulSetInitContainerImageNamePropOverride() throws Exc AppDefinition definition = new AppDefinition(randomName(), null); AppDeploymentRequest appDeploymentRequest = new AppDeploymentRequest(definition, testApplication(), props); - KubernetesAppDeployer deployer = new KubernetesAppDeployer(new KubernetesDeployerProperties(), - kubernetesClient); + KubernetesAppDeployer deployer = kubernetesAppDeployer(); log.info("Deploying {}...", appDeploymentRequest.getDefinition().getName()); String deploymentId = deployer.deploy(appDeploymentRequest); @@ -816,7 +792,7 @@ public void createStatefulSetInitContainerImageNameGlobalOverride() throws Excep KubernetesDeployerProperties kubernetesDeployerProperties = new KubernetesDeployerProperties(); kubernetesDeployerProperties.setStatefulSetInitContainerImageName(imageName); - KubernetesAppDeployer deployer = new KubernetesAppDeployer(kubernetesDeployerProperties, kubernetesClient); + KubernetesAppDeployer deployer = kubernetesAppDeployer(kubernetesDeployerProperties); log.info("Deploying {}...", appDeploymentRequest.getDefinition().getName()); String deploymentId = deployer.deploy(appDeploymentRequest); @@ -864,8 +840,7 @@ public void createStatefulSetWithOverridingRequest() throws Exception { AppDefinition definition = new AppDefinition(randomName(), null); AppDeploymentRequest appDeploymentRequest = new AppDeploymentRequest(definition, testApplication(), props); - KubernetesAppDeployer deployer = new KubernetesAppDeployer(new KubernetesDeployerProperties(), - kubernetesClient); + KubernetesAppDeployer deployer = kubernetesAppDeployer(); log.info("Deploying {}...", appDeploymentRequest.getDefinition().getName()); String deploymentId = deployer.deploy(appDeploymentRequest); @@ -933,8 +908,7 @@ public void createStatefulSetWithPVCDefaultName() throws Exception { AppDefinition definition = new AppDefinition(randomName(), null); AppDeploymentRequest appDeploymentRequest = new AppDeploymentRequest(definition, testApplication(), props); - KubernetesAppDeployer deployer = new KubernetesAppDeployer(new KubernetesDeployerProperties(), - kubernetesClient); + KubernetesAppDeployer deployer = kubernetesAppDeployer(); log.info("Deploying {}...", appDeploymentRequest.getDefinition().getName()); String deploymentId = deployer.deploy(appDeploymentRequest); @@ -969,11 +943,8 @@ public void createStatefulSetWithPVCDefaultName() throws Exception { @Test public void testStatefulSetPodAnnotations() { log.info("Testing {}...", "StatefulSetPodAnnotations"); - KubernetesDeployerProperties deployProperties = new KubernetesDeployerProperties(); - ContainerFactory containerFactory = new DefaultContainerFactory(deployProperties); - KubernetesAppDeployer appDeployer = new KubernetesAppDeployer(deployProperties, kubernetesClient, - containerFactory); + KubernetesAppDeployer appDeployer = kubernetesAppDeployer(); AppDefinition definition = new AppDefinition(randomName(), null); Resource resource = testApplication(); @@ -1022,8 +993,7 @@ public void testDeploymentLabels() { AppDefinition definition = new AppDefinition(randomName(), null); AppDeploymentRequest appDeploymentRequest = new AppDeploymentRequest(definition, testApplication(), props); - KubernetesAppDeployer deployer = new KubernetesAppDeployer(new KubernetesDeployerProperties(), - kubernetesClient); + KubernetesAppDeployer deployer = kubernetesAppDeployer(); log.info("Deploying {}...", appDeploymentRequest.getDefinition().getName()); @@ -1068,8 +1038,7 @@ public void testDeploymentLabelsStatefulSet() { AppDefinition definition = new AppDefinition(randomName(), null); AppDeploymentRequest appDeploymentRequest = new AppDeploymentRequest(definition, testApplication(), props); - KubernetesAppDeployer deployer = new KubernetesAppDeployer(new KubernetesDeployerProperties(), - kubernetesClient); + KubernetesAppDeployer deployer = kubernetesAppDeployer(); log.info("Deploying {}...", appDeploymentRequest.getDefinition().getName()); @@ -1126,8 +1095,7 @@ public void testCleanupOnDeployFailure() throws InterruptedException { kubernetesDeployerProperties.setLimits(resources); - KubernetesAppDeployer deployer = new KubernetesAppDeployer(kubernetesDeployerProperties, - kubernetesClient); + KubernetesAppDeployer deployer = kubernetesAppDeployer(kubernetesDeployerProperties); log.info("Deploying {}...", appDeploymentRequest.getDefinition().getName()); @@ -1150,7 +1118,7 @@ public void testCleanupOnDeployFailure() throws InterruptedException { log.info("Got expected not not deployed exception on undeployment: " + e.getMessage()); } - deployer = new KubernetesAppDeployer(new KubernetesDeployerProperties(), kubernetesClient); + deployer = kubernetesAppDeployer(); log.info("Deploying {}... again", deploymentId); @@ -1176,10 +1144,7 @@ public void testCleanupOnDeployFailure() throws InterruptedException { public void testMultipleContainersInPod() { log.info("Testing {}...", "MultipleContainersInPod"); - KubernetesDeployerProperties deployProperties = new KubernetesDeployerProperties(); - - KubernetesAppDeployer kubernetesAppDeployer = Mockito.spy(new KubernetesAppDeployer(deployProperties, - kubernetesClient, new DefaultContainerFactory(deployProperties))); + KubernetesAppDeployer kubernetesAppDeployer = Mockito.spy(kubernetesAppDeployer()); AppDefinition definition = new AppDefinition(randomName(), Collections.singletonMap("server.port", "9090")); Resource resource = testApplication(); @@ -1220,7 +1185,7 @@ public void testMultipleContainersInPod() { @Test public void testDefaultServicePort() { log.info("Testing {}...", "DefaultServicePort"); - KubernetesAppDeployer kubernetesAppDeployer = new KubernetesAppDeployer(new KubernetesDeployerProperties(), kubernetesClient); + KubernetesAppDeployer kubernetesAppDeployer = kubernetesAppDeployer(); AppDefinition definition = new AppDefinition(randomName(), null); Resource resource = testApplication(); @@ -1255,7 +1220,7 @@ public void testDefaultServicePort() { @Test public void testDefaultServicePortOverride() { log.info("Testing {}...", "DefaultServicePortOverride"); - KubernetesAppDeployer kubernetesAppDeployer = new KubernetesAppDeployer(new KubernetesDeployerProperties(), kubernetesClient); + KubernetesAppDeployer kubernetesAppDeployer = kubernetesAppDeployer(); AppDefinition definition = new AppDefinition(randomName(), Collections.singletonMap("server.port", "9090")); Resource resource = testApplication(); @@ -1290,7 +1255,7 @@ public void testDefaultServicePortOverride() { @Test public void testServiceWithMultiplePorts() { log.info("Testing {}...", "ServiceWithMultiplePorts"); - KubernetesAppDeployer kubernetesAppDeployer = new KubernetesAppDeployer(new KubernetesDeployerProperties(), kubernetesClient); + KubernetesAppDeployer kubernetesAppDeployer = kubernetesAppDeployer(); AppDefinition definition = new AppDefinition(randomName(), null); Resource resource = testApplication(); @@ -1328,8 +1293,7 @@ public void testServiceWithMultiplePorts() { @Test public void testCreateInitContainer() { log.info("Testing {}...", "CreateInitContainer"); - KubernetesAppDeployer kubernetesAppDeployer = new KubernetesAppDeployer(new KubernetesDeployerProperties(), - kubernetesClient); + KubernetesAppDeployer kubernetesAppDeployer = kubernetesAppDeployer(); Map props = Collections.singletonMap("spring.cloud.deployer.kubernetes.initContainer", "{containerName: 'test', imageName: 'busybox:latest', commands: ['sh', '-c', 'echo hello']}"); @@ -1374,8 +1338,7 @@ public void testCreateInitContainer() { @Test public void testCreateInitContainerWithEnvVariables() { log.info("Testing {}...", "CreateInitContainer"); - KubernetesAppDeployer kubernetesAppDeployer = new KubernetesAppDeployer(new KubernetesDeployerProperties(), - kubernetesClient); + KubernetesAppDeployer kubernetesAppDeployer = kubernetesAppDeployer(); Map props = Collections.singletonMap("spring.cloud.deployer.kubernetes.initContainer", "{containerName: 'test', imageName: 'busybox:latest', commands: ['sh', '-c', 'echo hello'], environmentVariables: ['KEY1=VAL1', 'KEY2=VAL2']}"); @@ -1419,8 +1382,7 @@ public void testCreateInitContainerWithEnvVariables() { @Test public void testCreateInitContainerWithVolumeMounts() { log.info("Testing {}...", "CreateInitContainerWithVolumeMounts"); - KubernetesAppDeployer kubernetesAppDeployer = new KubernetesAppDeployer(new KubernetesDeployerProperties(), - kubernetesClient); + KubernetesAppDeployer kubernetesAppDeployer =kubernetesAppDeployer(); Map props = Stream.of(new String[][]{ { @@ -1489,8 +1451,7 @@ public void testCreateInitContainerWithVolumeMounts() { @Test public void testCreateAdditionalContainers() { log.info("Testing {}...", "CreateAdditionalContainers"); - KubernetesAppDeployer kubernetesAppDeployer = new KubernetesAppDeployer(new KubernetesDeployerProperties(), - kubernetesClient); + KubernetesAppDeployer kubernetesAppDeployer = kubernetesAppDeployer(); Map props = Stream.of(new String[][]{ { @@ -1578,8 +1539,8 @@ public void testCreateAdditionalContainersOverride() { container2.setCommand(Arrays.asList("sh", "-c", "echo hello-from-original-properties")); KubernetesDeployerProperties kubernetesDeployerProperties = new KubernetesDeployerProperties(); kubernetesDeployerProperties.setAdditionalContainers(Arrays.asList(container1, container2)); - KubernetesAppDeployer kubernetesAppDeployer = new KubernetesAppDeployer(kubernetesDeployerProperties, - kubernetesClient); + KubernetesAppDeployer kubernetesAppDeployer = kubernetesAppDeployer(kubernetesDeployerProperties); + Map props = Stream.of(new String[][]{ { @@ -1671,8 +1632,7 @@ public void testCreateAdditionalContainersOverride() { @Test public void testUnknownStatusOnPendingResources() throws InterruptedException { log.info("Testing {}...", "UnknownStatusOnPendingResources"); - KubernetesAppDeployer kubernetesAppDeployer = new KubernetesAppDeployer(new KubernetesDeployerProperties(), - kubernetesClient); + KubernetesAppDeployer kubernetesAppDeployer = kubernetesAppDeployer(); AppDefinition definition = new AppDefinition(randomName(), null); Resource resource = testApplication(); @@ -1733,7 +1693,7 @@ public void testSecretRef() throws InterruptedException { KubernetesDeployerProperties kubernetesDeployerProperties = new KubernetesDeployerProperties(); kubernetesDeployerProperties.setSecretRefs(Collections.singletonList(secret.getMetadata().getName())); - KubernetesAppDeployer kubernetesAppDeployer = new KubernetesAppDeployer(kubernetesDeployerProperties, kubernetesClient); + KubernetesAppDeployer kubernetesAppDeployer = kubernetesAppDeployer(kubernetesDeployerProperties); AppDefinition definition = new AppDefinition(randomName(), null); Resource resource = testApplication(); @@ -1785,8 +1745,7 @@ public void testSecretRefFromDeployerProperty() throws InterruptedException { Secret secret = randomSecret(); - KubernetesAppDeployer kubernetesAppDeployer = new KubernetesAppDeployer(new KubernetesDeployerProperties(), - kubernetesClient); + KubernetesAppDeployer kubernetesAppDeployer = kubernetesAppDeployer(); Map props = new HashMap<>(); props.put("spring.cloud.deployer.kubernetes.secretRefs", secret.getMetadata().getName()); @@ -1845,8 +1804,7 @@ public void testSecretRefFromDeployerPropertyOverride() throws IOException, Inte KubernetesDeployerProperties kubernetesDeployerProperties = new KubernetesDeployerProperties(); kubernetesDeployerProperties.setSecretRefs(Collections.singletonList(propertySecret.getMetadata().getName())); - KubernetesAppDeployer kubernetesAppDeployer = new KubernetesAppDeployer(kubernetesDeployerProperties, - kubernetesClient); + KubernetesAppDeployer kubernetesAppDeployer =kubernetesAppDeployer(kubernetesDeployerProperties); Map props = new HashMap<>(); props.put("spring.cloud.deployer.kubernetes.secretRefs", deployerPropertySecret.getMetadata().getName()); @@ -1913,8 +1871,7 @@ public void testSecretRefFromPropertyMultiple() throws InterruptedException { KubernetesDeployerProperties kubernetesDeployerProperties = new KubernetesDeployerProperties(); kubernetesDeployerProperties.setSecretRefs(secrets); - KubernetesAppDeployer kubernetesAppDeployer = new KubernetesAppDeployer(kubernetesDeployerProperties, - kubernetesClient); + KubernetesAppDeployer kubernetesAppDeployer = kubernetesAppDeployer(kubernetesDeployerProperties); AppDefinition definition = new AppDefinition(randomName(), null); Resource resource = testApplication(); @@ -1979,8 +1936,7 @@ public void testSecretRefFromDeploymentPropertyMultiple() throws InterruptedExce props.put("spring.cloud.deployer.kubernetes.secretRefs", "[" + secret1.getMetadata().getName() + "," + secret2.getMetadata().getName() + "]"); - KubernetesAppDeployer kubernetesAppDeployer = new KubernetesAppDeployer(new KubernetesDeployerProperties(), - kubernetesClient); + KubernetesAppDeployer kubernetesAppDeployer = kubernetesAppDeployer(); AppDefinition definition = new AppDefinition(randomName(), null); Resource resource = testApplication(); @@ -2043,7 +1999,7 @@ public void testConfigMapRef() throws InterruptedException { KubernetesDeployerProperties kubernetesDeployerProperties = new KubernetesDeployerProperties(); kubernetesDeployerProperties.setConfigMapRefs(Collections.singletonList(configMap.getMetadata().getName())); - KubernetesAppDeployer kubernetesAppDeployer = new KubernetesAppDeployer(kubernetesDeployerProperties, kubernetesClient); + KubernetesAppDeployer kubernetesAppDeployer = kubernetesAppDeployer(kubernetesDeployerProperties); AppDefinition definition = new AppDefinition(randomName(), null); Resource resource = testApplication(); @@ -2094,8 +2050,7 @@ public void testConfigMapRefFromDeployerProperty() throws InterruptedException { ConfigMap configMap = randomConfigMap(); - KubernetesAppDeployer kubernetesAppDeployer = new KubernetesAppDeployer(new KubernetesDeployerProperties(), - kubernetesClient); + KubernetesAppDeployer kubernetesAppDeployer = kubernetesAppDeployer(); Map props = new HashMap<>(); props.put("spring.cloud.deployer.kubernetes.config-map-refs", configMap.getMetadata().getName()); @@ -2153,8 +2108,7 @@ public void testConfigMapRefFromDeployerPropertyOverride() throws IOException, I KubernetesDeployerProperties kubernetesDeployerProperties = new KubernetesDeployerProperties(); kubernetesDeployerProperties.setConfigMapRefs(Collections.singletonList(propertyConfigMap.getMetadata().getName())); - KubernetesAppDeployer kubernetesAppDeployer = new KubernetesAppDeployer(kubernetesDeployerProperties, - kubernetesClient); + KubernetesAppDeployer kubernetesAppDeployer = kubernetesAppDeployer(kubernetesDeployerProperties); Map props = new HashMap<>(); props.put("spring.cloud.deployer.kubernetes.configMapRefs", deployerPropertyConfigMap.getMetadata().getName()); @@ -2220,8 +2174,7 @@ public void testConfigMapRefFromPropertyMultiple() throws InterruptedException { KubernetesDeployerProperties kubernetesDeployerProperties = new KubernetesDeployerProperties(); kubernetesDeployerProperties.setConfigMapRefs(configMaps); - KubernetesAppDeployer kubernetesAppDeployer = new KubernetesAppDeployer(kubernetesDeployerProperties, - kubernetesClient); + KubernetesAppDeployer kubernetesAppDeployer = kubernetesAppDeployer(kubernetesDeployerProperties); AppDefinition definition = new AppDefinition(randomName(), null); Resource resource = testApplication(); @@ -2285,8 +2238,7 @@ public void testConfigMapRefFromDeploymentPropertyMultiple() throws InterruptedE props.put("spring.cloud.deployer.kubernetes.configMapRefs", "[" + configMap1.getMetadata().getName() + "," + configMap2.getMetadata().getName() + "]"); - KubernetesAppDeployer kubernetesAppDeployer = new KubernetesAppDeployer(new KubernetesDeployerProperties(), - kubernetesClient); + KubernetesAppDeployer kubernetesAppDeployer = kubernetesAppDeployer(); AppDefinition definition = new AppDefinition(randomName(), null); Resource resource = testApplication(); @@ -2433,4 +2385,12 @@ private ConfigMap randomConfigMap() { return kubernetesClient.configMaps().create(configMap); } + + private KubernetesAppDeployer kubernetesAppDeployer() { + return kubernetesAppDeployer(new KubernetesDeployerProperties()); + } + private KubernetesAppDeployer kubernetesAppDeployer(KubernetesDeployerProperties kubernetesDeployerProperties) { + return new KubernetesAppDeployer(kubernetesDeployerProperties, this.kubernetesClient, + new DefaultContainerFactory(kubernetesDeployerProperties)); + } } diff --git a/src/test/java/org/springframework/cloud/deployer/spi/kubernetes/KubernetesAppDeployerTests.java b/src/test/java/org/springframework/cloud/deployer/spi/kubernetes/KubernetesAppDeployerTests.java index 233132ae..ceb4f59b 100644 --- a/src/test/java/org/springframework/cloud/deployer/spi/kubernetes/KubernetesAppDeployerTests.java +++ b/src/test/java/org/springframework/cloud/deployer/spi/kubernetes/KubernetesAppDeployerTests.java @@ -91,7 +91,7 @@ public void deployWithVolumesOnly() throws Exception { AppDeploymentRequest appDeploymentRequest = new AppDeploymentRequest(definition, getResource(), new HashMap<>()); - deployer = new KubernetesAppDeployer(bindDeployerProperties(), null); + deployer =k8sAppDeployer(bindDeployerProperties()); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); assertThat(podSpec.getVolumes()).isEmpty(); @@ -105,7 +105,7 @@ public void deployWithVolumesAndVolumeMounts() throws Exception { + "{name: 'testnfs', mountPath: '/test/nfs', readOnly: 'true'}" + "]"); AppDeploymentRequest appDeploymentRequest = new AppDeploymentRequest(definition, getResource(), props); - deployer = new KubernetesAppDeployer(bindDeployerProperties(), null); + deployer = k8sAppDeployer(); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); assertThat(podSpec.getVolumes()).containsOnly( @@ -124,7 +124,7 @@ public void deployWithVolumesAndVolumeMounts() throws Exception { + "{name: 'testnfs', mountPath: '/test/nfs', readOnly: 'true'}" + "]"); appDeploymentRequest = new AppDeploymentRequest(definition, getResource(), props); - deployer = new KubernetesAppDeployer(bindDeployerProperties(), null); + deployer = k8sAppDeployer(); podSpec = deployer.createPodSpec(appDeploymentRequest); HostPathVolumeSource hostPathVolumeSource = new HostPathVolumeSourceBuilder() @@ -144,7 +144,7 @@ public void deployWithNodeSelectorGlobalProperty() throws Exception { KubernetesDeployerProperties kubernetesDeployerProperties = new KubernetesDeployerProperties(); kubernetesDeployerProperties.setNodeSelector("disktype:ssd, os:qnx"); - deployer = new KubernetesAppDeployer(kubernetesDeployerProperties, null); + deployer = k8sAppDeployer(kubernetesDeployerProperties); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); assertThat(podSpec.getNodeSelector()).containsOnly(entry("disktype", "ssd"), entry("os", "qnx")); @@ -157,7 +157,7 @@ public void deployWithNodeSelectorDeploymentProperty() throws Exception { props.put(KubernetesDeployerProperties.KUBERNETES_DEPLOYMENT_NODE_SELECTOR, "disktype:ssd, os: linux"); AppDeploymentRequest appDeploymentRequest = new AppDeploymentRequest(definition, getResource(), props); - deployer = new KubernetesAppDeployer(bindDeployerProperties(), null); + deployer = k8sAppDeployer(); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); assertThat(podSpec.getNodeSelector()).containsOnly(entry("disktype", "ssd"), entry("os", "linux")); @@ -173,7 +173,7 @@ public void deployWithNodeSelectorDeploymentPropertyGlobalOverride() throws Exce KubernetesDeployerProperties kubernetesDeployerProperties = new KubernetesDeployerProperties(); kubernetesDeployerProperties.setNodeSelector("disktype:ssd, os:qnx"); - deployer = new KubernetesAppDeployer(kubernetesDeployerProperties, null); + deployer = k8sAppDeployer(kubernetesDeployerProperties); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); assertThat(podSpec.getNodeSelector()).containsOnly(entry("disktype", "ssd"), entry("os", "openbsd")); @@ -188,7 +188,7 @@ public void deployWithEnvironmentWithCommaDelimitedValue() throws Exception { AppDeploymentRequest appDeploymentRequest = new AppDeploymentRequest(definition, getResource(), props); - deployer = new KubernetesAppDeployer(bindDeployerProperties(), null); + deployer = k8sAppDeployer(); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); assertThat(podSpec.getContainers().get(0).getEnv()) @@ -210,7 +210,7 @@ public void deployWithEnvironmentWithSingleCommaDelimitedValue() throws Exceptio AppDeploymentRequest appDeploymentRequest = new AppDeploymentRequest(definition, getResource(), props); - deployer = new KubernetesAppDeployer(bindDeployerProperties(), null); + deployer = k8sAppDeployer(); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); assertThat(podSpec.getContainers().get(0).getEnv()) @@ -226,7 +226,7 @@ public void deployWithEnvironmentWithMultipleCommaDelimitedValue() throws Except AppDeploymentRequest appDeploymentRequest = new AppDeploymentRequest(definition, getResource(), props); - deployer = new KubernetesAppDeployer(bindDeployerProperties(), null); + deployer = k8sAppDeployer(); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); assertThat(podSpec.getContainers().get(0).getEnv()) @@ -244,7 +244,7 @@ public void deployWithImagePullSecretDeploymentProperty() { AppDeploymentRequest appDeploymentRequest = new AppDeploymentRequest(definition, getResource(), props); - deployer = new KubernetesAppDeployer(new KubernetesDeployerProperties(), null); + deployer = k8sAppDeployer(new KubernetesDeployerProperties()); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); assertThat(podSpec.getImagePullSecrets().size()).isEqualTo(1); @@ -260,7 +260,7 @@ public void deployWithImagePullSecretDeployerProperty() { KubernetesDeployerProperties kubernetesDeployerProperties = new KubernetesDeployerProperties(); kubernetesDeployerProperties.setImagePullSecret("regcred"); - deployer = new KubernetesAppDeployer(kubernetesDeployerProperties, null); + deployer = k8sAppDeployer(kubernetesDeployerProperties); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); assertThat(podSpec.getImagePullSecrets().size()).isEqualTo(1); @@ -276,7 +276,7 @@ public void deployWithImagePullSecretsDeploymentProperty() { AppDeploymentRequest appDeploymentRequest = new AppDeploymentRequest(definition, getResource(), props); - deployer = new KubernetesAppDeployer(new KubernetesDeployerProperties(), null); + deployer = k8sAppDeployer(new KubernetesDeployerProperties()); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); assertThat(podSpec.getImagePullSecrets().size()).isEqualTo(2); @@ -293,7 +293,7 @@ public void deployWithImagePullSecretsDeployerProperty() { KubernetesDeployerProperties kubernetesDeployerProperties = new KubernetesDeployerProperties(); kubernetesDeployerProperties.setImagePullSecrets(Arrays.asList("regcredone","regcredtwo")); - deployer = new KubernetesAppDeployer(kubernetesDeployerProperties, null); + deployer = k8sAppDeployer(kubernetesDeployerProperties); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); assertThat(podSpec.getImagePullSecrets().size()).isEqualTo(2); @@ -310,7 +310,7 @@ public void deployWithDeploymentServiceAccountNameDeploymentProperties() { AppDeploymentRequest appDeploymentRequest = new AppDeploymentRequest(definition, getResource(), props); - deployer = new KubernetesAppDeployer(new KubernetesDeployerProperties(), null); + deployer = k8sAppDeployer(new KubernetesDeployerProperties()); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); assertThat(podSpec.getServiceAccountName()).isNotNull(); @@ -326,7 +326,7 @@ public void deployWithDeploymentServiceAccountNameDeployerProperty() { KubernetesDeployerProperties kubernetesDeployerProperties = new KubernetesDeployerProperties(); kubernetesDeployerProperties.setDeploymentServiceAccountName("myserviceaccount"); - deployer = new KubernetesAppDeployer(kubernetesDeployerProperties, null); + deployer = k8sAppDeployer(kubernetesDeployerProperties); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); assertThat(podSpec.getServiceAccountName()).isNotNull(); @@ -345,7 +345,7 @@ public void deployWithDeploymentServiceAccountNameDeploymentPropertyOverride() { KubernetesDeployerProperties kubernetesDeployerProperties = new KubernetesDeployerProperties(); kubernetesDeployerProperties.setDeploymentServiceAccountName("defaultsan"); - deployer = new KubernetesAppDeployer(kubernetesDeployerProperties, null); + deployer = k8sAppDeployer(kubernetesDeployerProperties); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); assertThat(podSpec.getServiceAccountName()).isNotNull(); @@ -358,7 +358,7 @@ public void deployWithTolerations() throws Exception { AppDeploymentRequest appDeploymentRequest = new AppDeploymentRequest(definition, getResource(), new HashMap<>()); - deployer = new KubernetesAppDeployer(bindDeployerProperties(), null); + deployer = k8sAppDeployer(); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); assertThat(podSpec.getTolerations()).isNotEmpty(); @@ -375,7 +375,7 @@ public void deployWithGlobalTolerations() { AppDeploymentRequest appDeploymentRequest = new AppDeploymentRequest(definition, getResource(), props); - deployer = new KubernetesAppDeployer(new KubernetesDeployerProperties(), null); + deployer = k8sAppDeployer(new KubernetesDeployerProperties()); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); assertThat(podSpec.getTolerations()).isNotNull(); @@ -405,7 +405,7 @@ public void deployWithTolerationPropertyOverride() { KubernetesDeployerProperties kubernetesDeployerProperties = new KubernetesDeployerProperties(); kubernetesDeployerProperties.getTolerations().add(toleration); - deployer = new KubernetesAppDeployer(kubernetesDeployerProperties, null); + deployer = k8sAppDeployer(kubernetesDeployerProperties); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); assertThat(podSpec.getTolerations()).isNotNull(); @@ -434,7 +434,7 @@ public void deployWithDuplicateTolerationKeyPropertyOverride() { KubernetesDeployerProperties kubernetesDeployerProperties = new KubernetesDeployerProperties(); kubernetesDeployerProperties.getTolerations().add(toleration); - deployer = new KubernetesAppDeployer(kubernetesDeployerProperties, null); + deployer = k8sAppDeployer(kubernetesDeployerProperties); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); assertThat(podSpec.getTolerations()).isNotNull(); @@ -468,7 +468,7 @@ public void deployWithDuplicateGlobalToleration() { kubernetesDeployerProperties.getTolerations().add(toleration2); - deployer = new KubernetesAppDeployer(kubernetesDeployerProperties, null); + deployer = k8sAppDeployer(kubernetesDeployerProperties); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); assertThat(podSpec.getTolerations()).isNotNull(); @@ -529,7 +529,7 @@ public void testSecretKeyRef() { AppDefinition definition = new AppDefinition("app-test", null); AppDeploymentRequest appDeploymentRequest = new AppDeploymentRequest(definition, getResource(), props); - deployer = new KubernetesAppDeployer(new KubernetesDeployerProperties(), null); + deployer =k8sAppDeployer(new KubernetesDeployerProperties()); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); List envVars = podSpec.getContainers().get(0).getEnv(); @@ -553,7 +553,7 @@ public void testSecretKeyRefMultiple() { AppDefinition definition = new AppDefinition("app-test", null); AppDeploymentRequest appDeploymentRequest = new AppDeploymentRequest(definition, getResource(), props); - deployer = new KubernetesAppDeployer(new KubernetesDeployerProperties(), null); + deployer = k8sAppDeployer(new KubernetesDeployerProperties()); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); List envVars = podSpec.getContainers().get(0).getEnv(); @@ -585,7 +585,7 @@ public void testSecretKeyRefGlobal() { secretKeyRef.setDataKey("passwordGlobal"); kubernetesDeployerProperties.setSecretKeyRefs(Collections.singletonList(secretKeyRef)); - deployer = new KubernetesAppDeployer(kubernetesDeployerProperties, null); + deployer = k8sAppDeployer(kubernetesDeployerProperties); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); List envVars = podSpec.getContainers().get(0).getEnv(); @@ -627,7 +627,7 @@ public void testSecretKeyRefPropertyOverride() { kubernetesDeployerProperties.setSecretKeyRefs(globalSecretKeyRefs); - deployer = new KubernetesAppDeployer(kubernetesDeployerProperties, null); + deployer = k8sAppDeployer(kubernetesDeployerProperties); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); List envVars = podSpec.getContainers().get(0).getEnv(); @@ -661,7 +661,7 @@ public void testSecretKeyRefGlobalFromYaml() throws Exception { AppDefinition definition = new AppDefinition("app-test", null); AppDeploymentRequest appDeploymentRequest = new AppDeploymentRequest(definition, getResource(), null); - deployer = new KubernetesAppDeployer(bindDeployerProperties(), null); + deployer = k8sAppDeployer(); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); List envVars = podSpec.getContainers().get(0).getEnv(); @@ -684,7 +684,7 @@ public void testConfigMapKeyRef() { AppDefinition definition = new AppDefinition("app-test", null); AppDeploymentRequest appDeploymentRequest = new AppDeploymentRequest(definition, getResource(), props); - deployer = new KubernetesAppDeployer(new KubernetesDeployerProperties(), null); + deployer = k8sAppDeployer(new KubernetesDeployerProperties()); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); List envVars = podSpec.getContainers().get(0).getEnv(); @@ -708,7 +708,7 @@ public void testConfigMapKeyRefMultiple() { AppDefinition definition = new AppDefinition("app-test", null); AppDeploymentRequest appDeploymentRequest = new AppDeploymentRequest(definition, getResource(), props); - deployer = new KubernetesAppDeployer(new KubernetesDeployerProperties(), null); + deployer = k8sAppDeployer(new KubernetesDeployerProperties()); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); List envVars = podSpec.getContainers().get(0).getEnv(); @@ -740,7 +740,7 @@ public void testConfigMapKeyRefGlobal() { configMapKeyRef.setDataKey("envGlobal"); kubernetesDeployerProperties.setConfigMapKeyRefs(Collections.singletonList(configMapKeyRef)); - deployer = new KubernetesAppDeployer(kubernetesDeployerProperties, null); + deployer = k8sAppDeployer(kubernetesDeployerProperties); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); List envVars = podSpec.getContainers().get(0).getEnv(); @@ -782,7 +782,7 @@ public void testConfigMapKeyRefPropertyOverride() { kubernetesDeployerProperties.setConfigMapKeyRefs(globalConfigMapKeyRefs); - deployer = new KubernetesAppDeployer(kubernetesDeployerProperties, null); + deployer = k8sAppDeployer(kubernetesDeployerProperties); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); List envVars = podSpec.getContainers().get(0).getEnv(); @@ -816,7 +816,7 @@ public void testConfigMapKeyRefGlobalFromYaml() throws Exception { AppDefinition definition = new AppDefinition("app-test", null); AppDeploymentRequest appDeploymentRequest = new AppDeploymentRequest(definition, getResource(), null); - deployer = new KubernetesAppDeployer(bindDeployerProperties(), null); + deployer = k8sAppDeployer(); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); List envVars = podSpec.getContainers().get(0).getEnv(); @@ -853,7 +853,7 @@ public void testNodeAffinityProperty() { AppDefinition definition = new AppDefinition("app-test", null); AppDeploymentRequest appDeploymentRequest = new AppDeploymentRequest(definition, getResource(), props); - deployer = new KubernetesAppDeployer(new KubernetesDeployerProperties(), null); + deployer = k8sAppDeployer(new KubernetesDeployerProperties()); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); NodeAffinity nodeAffinity = podSpec.getAffinity().getNodeAffinity(); @@ -888,7 +888,7 @@ public void testPodAffinityProperty() { AppDefinition definition = new AppDefinition("app-test", null); AppDeploymentRequest appDeploymentRequest = new AppDeploymentRequest(definition, getResource(), props); - deployer = new KubernetesAppDeployer(new KubernetesDeployerProperties(), null); + deployer = k8sAppDeployer(new KubernetesDeployerProperties()); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); PodAffinity podAffinity = podSpec.getAffinity().getPodAffinity(); @@ -923,7 +923,7 @@ public void testPodAntiAffinityProperty() { AppDefinition definition = new AppDefinition("app-test", null); AppDeploymentRequest appDeploymentRequest = new AppDeploymentRequest(definition, getResource(), props); - deployer = new KubernetesAppDeployer(new KubernetesDeployerProperties(), null); + deployer = k8sAppDeployer(new KubernetesDeployerProperties()); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); PodAntiAffinity podAntiAffinity = podSpec.getAffinity().getPodAntiAffinity(); @@ -963,7 +963,7 @@ public void testNodeAffinityGlobalProperty() { kubernetesDeployerProperties.setNodeAffinity(nodeAffinity); - deployer = new KubernetesAppDeployer(kubernetesDeployerProperties, null); + deployer = k8sAppDeployer(kubernetesDeployerProperties); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); NodeAffinity nodeAffinityTest = podSpec.getAffinity().getNodeAffinity(); @@ -1003,7 +1003,7 @@ public void testPodAffinityGlobalProperty() { kubernetesDeployerProperties.setPodAffinity(podAffinity); - deployer = new KubernetesAppDeployer(kubernetesDeployerProperties, null); + deployer = k8sAppDeployer(kubernetesDeployerProperties); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); PodAffinity podAffinityTest = podSpec.getAffinity().getPodAffinity(); @@ -1043,7 +1043,7 @@ public void testPodAntiAffinityGlobalProperty() { kubernetesDeployerProperties.setPodAntiAffinity(podAntiAffinity); - deployer = new KubernetesAppDeployer(kubernetesDeployerProperties, null); + deployer = k8sAppDeployer(kubernetesDeployerProperties); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); PodAntiAffinity podAntiAffinityTest = podSpec.getAffinity().getPodAntiAffinity(); @@ -1057,7 +1057,7 @@ public void testNodeAffinityFromYaml() throws Exception { AppDefinition definition = new AppDefinition("app-test", null); AppDeploymentRequest appDeploymentRequest = new AppDeploymentRequest(definition, getResource(), null); - deployer = new KubernetesAppDeployer(bindDeployerProperties(), null); + deployer = k8sAppDeployer(); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); NodeAffinity nodeAffinity = podSpec.getAffinity().getNodeAffinity(); @@ -1071,7 +1071,7 @@ public void testPodAffinityFromYaml() throws Exception { AppDefinition definition = new AppDefinition("app-test", null); AppDeploymentRequest appDeploymentRequest = new AppDeploymentRequest(definition, getResource(), null); - deployer = new KubernetesAppDeployer(bindDeployerProperties(), null); + deployer = k8sAppDeployer(); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); PodAffinity podAffinity = podSpec.getAffinity().getPodAffinity(); @@ -1085,7 +1085,7 @@ public void testPodAntiAffinityFromYaml() throws Exception { AppDefinition definition = new AppDefinition("app-test", null); AppDeploymentRequest appDeploymentRequest = new AppDeploymentRequest(definition, getResource(), null); - deployer = new KubernetesAppDeployer(bindDeployerProperties(), null); + deployer = k8sAppDeployer(); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); PodAntiAffinity podAntiAffinity = podSpec.getAffinity().getPodAntiAffinity(); @@ -1135,7 +1135,7 @@ public void testNodeAffinityPropertyOverrideGlobal() { kubernetesDeployerProperties.setNodeAffinity(nodeAffinity); - deployer = new KubernetesAppDeployer(kubernetesDeployerProperties, null); + deployer = k8sAppDeployer(kubernetesDeployerProperties); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); NodeAffinity nodeAffinityTest = podSpec.getAffinity().getNodeAffinity(); @@ -1187,7 +1187,7 @@ public void testPodAffinityPropertyOverrideGlobal() { kubernetesDeployerProperties.setPodAffinity(podAffinity); - deployer = new KubernetesAppDeployer(kubernetesDeployerProperties, null); + deployer = k8sAppDeployer(kubernetesDeployerProperties); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); PodAffinity podAffinityTest = podSpec.getAffinity().getPodAffinity(); @@ -1239,7 +1239,7 @@ public void testPodAntiAffinityPropertyOverrideGlobal() { kubernetesDeployerProperties.setPodAntiAffinity(podAntiAffinity); - deployer = new KubernetesAppDeployer(kubernetesDeployerProperties, null); + deployer = k8sAppDeployer(kubernetesDeployerProperties); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); PodAntiAffinity podAntiAffinityTest = podSpec.getAffinity().getPodAntiAffinity(); @@ -1487,7 +1487,7 @@ private void assertThatDeployerCreatesPodSpecWithContainerSecurityContext( private PodSpec deployerCreatesPodSpec(KubernetesDeployerProperties globalDeployerProperties, Map deploymentProperties) { AppDefinition definition = new AppDefinition("app-test", null); AppDeploymentRequest appDeploymentRequest = new AppDeploymentRequest(definition, getResource(), deploymentProperties); - KubernetesAppDeployer deployer = new KubernetesAppDeployer(globalDeployerProperties, null); + KubernetesAppDeployer deployer = k8sAppDeployer(globalDeployerProperties); return deployer.createPodSpec(appDeploymentRequest); } @@ -1499,7 +1499,7 @@ public void testWithLifecyclePostStart() { AppDefinition definition = new AppDefinition("app-test", null); AppDeploymentRequest appDeploymentRequest = new AppDeploymentRequest(definition, getResource(), props); KubernetesDeployerProperties kubernetesDeployerProperties = new KubernetesDeployerProperties(); - deployer = new KubernetesAppDeployer(kubernetesDeployerProperties, null); + deployer = k8sAppDeployer(kubernetesDeployerProperties); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); assertThat(podSpec.getContainers().get(0).getLifecycle().getPostStart().getExec().getCommand()) .containsExactlyInAnyOrder("/bin/sh","-c","echo Hello from the postStart handler > /usr/share/message"); @@ -1513,7 +1513,7 @@ public void testWithLifecyclePreStop() { AppDefinition definition = new AppDefinition("app-test", null); AppDeploymentRequest appDeploymentRequest = new AppDeploymentRequest(definition, getResource(), props); KubernetesDeployerProperties kubernetesDeployerProperties = new KubernetesDeployerProperties(); - deployer = new KubernetesAppDeployer(kubernetesDeployerProperties, null); + deployer = k8sAppDeployer(kubernetesDeployerProperties); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); assertThat(podSpec.getContainers().get(0).getLifecycle().getPreStop().getExec().getCommand()) .containsExactlyInAnyOrder( @@ -1552,7 +1552,7 @@ List getCommand() { } }); kubernetesDeployerProperties.setLifecycle(lifecycle); - deployer = new KubernetesAppDeployer(kubernetesDeployerProperties, null); + deployer = k8sAppDeployer(kubernetesDeployerProperties); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); assertThat(podSpec.getContainers().get(0).getLifecycle().getPostStart().getExec().getCommand()) .containsExactlyInAnyOrder( @@ -1593,7 +1593,7 @@ List getCommand() { } }); kubernetesDeployerProperties.setLifecycle(lifecycle); - deployer = new KubernetesAppDeployer(kubernetesDeployerProperties, null); + deployer = k8sAppDeployer(kubernetesDeployerProperties); PodSpec podSpec = deployer.createPodSpec(appDeploymentRequest); assertThat(podSpec.getContainers().get(0).getLifecycle().getPreStop().getExec().getCommand()) .containsExactlyInAnyOrder( @@ -1621,4 +1621,13 @@ private KubernetesDeployerProperties bindDeployerProperties() throws Exception { MapConfigurationPropertySource source = new MapConfigurationPropertySource(yaml); return new Binder(source).bind("", Bindable.of(KubernetesDeployerProperties.class)).get(); } + + protected KubernetesAppDeployer k8sAppDeployer() throws Exception { + return k8sAppDeployer(bindDeployerProperties()); + } + + protected KubernetesAppDeployer k8sAppDeployer(KubernetesDeployerProperties kubernetesDeployerProperties) { + return new KubernetesAppDeployer(kubernetesDeployerProperties, null); + } + } diff --git a/src/test/resources/actuator-binding-input.json b/src/test/resources/actuator-binding-input.json new file mode 100644 index 00000000..895f71eb --- /dev/null +++ b/src/test/resources/actuator-binding-input.json @@ -0,0 +1,97 @@ +{ + "bindingName": "input", + "name": "tiktok.time", + "group": "tiktok", + "pausable": false, + "state": "running", + "paused": false, + "input": true, + "extendedInfo": { + "bindingDestination": "RabbitConsumerDestination{queue=tiktok.time.tiktok, binding=Binding [destination=tiktok.time.tiktok, exchange=tiktok.time, routingKey=#, arguments={}]}", + "ExtendedConsumerProperties": { + "autoStartup": true, + "concurrency": 1, + "instanceCount": 2, + "maxAttempts": 3, + "backOffInitialInterval": 1000, + "backOffMaxInterval": 10000, + "backOffMultiplier": 2, + "defaultRetryable": true, + "extension": { + "exchangeType": "topic", + "declareExchange": true, + "exchangeDurable": true, + "exchangeAutoDelete": false, + "delayedExchange": false, + "queueNameGroupOnly": false, + "bindQueue": true, + "bindingRoutingKey": null, + "bindingRoutingKeyDelimiter": null, + "ttl": null, + "expires": null, + "maxLength": null, + "maxLengthBytes": null, + "maxPriority": null, + "deadLetterQueueName": null, + "deadLetterExchange": null, + "deadLetterExchangeType": "direct", + "declareDlx": true, + "deadLetterRoutingKey": null, + "dlqTtl": null, + "dlqExpires": null, + "dlqMaxLength": null, + "dlqMaxLengthBytes": null, + "dlqMaxPriority": null, + "dlqDeadLetterExchange": null, + "dlqDeadLetterRoutingKey": null, + "autoBindDlq": false, + "prefix": "", + "lazy": false, + "dlqLazy": false, + "overflowBehavior": null, + "dlqOverflowBehavior": null, + "queueBindingArguments": {}, + "dlqBindingArguments": {}, + "quorum": { + "enabled": false, + "initialGroupSize": null, + "deliveryLimit": null + }, + "dlqQuorum": { + "enabled": false, + "initialGroupSize": null, + "deliveryLimit": null + }, + "singleActiveConsumer": false, + "dlqSingleActiveConsumer": false, + "transacted": false, + "acknowledgeMode": "AUTO", + "maxConcurrency": 1, + "prefetch": 1, + "batchSize": 1, + "durableSubscription": true, + "republishToDlq": true, + "republishDeliveyMode": "PERSISTENT", + "requeueRejected": false, + "headerPatterns": [ + "*" + ], + "recoveryInterval": 5000, + "exclusive": false, + "missingQueuesFatal": false, + "queueDeclarationRetries": null, + "failedDeclarationRetryInterval": null, + "consumerTagPrefix": null, + "frameMaxHeadroom": 20000, + "containerType": "SIMPLE", + "anonymousGroupPrefix": "anonymous.", + "enableBatching": false, + "receiveTimeout": null, + "requestHeaderPatterns": [ + "*" + ], + "txSize": 1 + } + } + } +} \ No newline at end of file diff --git a/src/test/resources/actuator-bindings.json b/src/test/resources/actuator-bindings.json new file mode 100644 index 00000000..f225ef65 --- /dev/null +++ b/src/test/resources/actuator-bindings.json @@ -0,0 +1,100 @@ +[ + { + "bindingName": "input", + "name": "tiktok.time", + "group": "tiktok", + "pausable": false, + "state": "running", + "paused": false, + "extendedInfo": { + "bindingDestination": "RabbitConsumerDestination{queue=tiktok.time.tiktok, binding=Binding [destination=tiktok.time.tiktok, exchange=tiktok.time, routingKey=#, arguments={}]}", + "ExtendedConsumerProperties": { + "autoStartup": true, + "concurrency": 1, + "instanceCount": 2, + "instanceIndex": 1, + "maxAttempts": 3, + "backOffInitialInterval": 1000, + "backOffMaxInterval": 10000, + "backOffMultiplier": 2, + "defaultRetryable": true, + "extension": { + "exchangeType": "topic", + "declareExchange": true, + "exchangeDurable": true, + "exchangeAutoDelete": false, + "delayedExchange": false, + "queueNameGroupOnly": false, + "bindQueue": true, + "bindingRoutingKey": null, + "bindingRoutingKeyDelimiter": null, + "ttl": null, + "expires": null, + "maxLength": null, + "maxLengthBytes": null, + "maxPriority": null, + "deadLetterQueueName": null, + "deadLetterExchange": null, + "deadLetterExchangeType": "direct", + "declareDlx": true, + "deadLetterRoutingKey": null, + "dlqTtl": null, + "dlqExpires": null, + "dlqMaxLength": null, + "dlqMaxLengthBytes": null, + "dlqMaxPriority": null, + "dlqDeadLetterExchange": null, + "dlqDeadLetterRoutingKey": null, + "autoBindDlq": false, + "prefix": "", + "lazy": false, + "dlqLazy": false, + "overflowBehavior": null, + "dlqOverflowBehavior": null, + "queueBindingArguments": {}, + "dlqBindingArguments": {}, + "quorum": { + "enabled": false, + "initialGroupSize": null, + "deliveryLimit": null + }, + "dlqQuorum": { + "enabled": false, + "initialGroupSize": null, + "deliveryLimit": null + }, + "singleActiveConsumer": false, + "dlqSingleActiveConsumer": false, + "transacted": false, + "acknowledgeMode": "AUTO", + "maxConcurrency": 1, + "prefetch": 1, + "batchSize": 1, + "durableSubscription": true, + "republishToDlq": true, + "republishDeliveyMode": "PERSISTENT", + "requeueRejected": false, + "headerPatterns": [ + "*" + ], + "recoveryInterval": 5000, + "exclusive": false, + "missingQueuesFatal": false, + "queueDeclarationRetries": null, + "failedDeclarationRetryInterval": null, + "consumerTagPrefix": null, + "frameMaxHeadroom": 20000, + "containerType": "SIMPLE", + "anonymousGroupPrefix": "anonymous.", + "enableBatching": false, + "receiveTimeout": null, + "requestHeaderPatterns": [ + "*" + ], + "txSize": 1 + } + } + }, + "input": true + } +] \ No newline at end of file diff --git a/src/test/resources/actuator-info.json b/src/test/resources/actuator-info.json new file mode 100644 index 00000000..e8e2cf61 --- /dev/null +++ b/src/test/resources/actuator-info.json @@ -0,0 +1,7 @@ +{ + "app": { + "description": "Spring Cloud Stream Log Sink Rabbit Binder Application", + "version": "3.1.1", + "name": "log-sink-rabbit" + } +} \ No newline at end of file