From dfd1e716f8e840f7caaf42e14572d18c8acc9d38 Mon Sep 17 00:00:00 2001 From: rameshiyer27 Date: Wed, 7 Jul 2021 20:37:54 +0100 Subject: Support override parameters for k8s-participant Add support for helm chart override parameters in TOSCA. Add support for monitoring Pod status after deployment. Note: ONAP Helm charts from OOM repository needs a global master password to be provided along with the helm command. Looking for suggestions here to avoid passing clear text password in TOSCA (KubernetesHelm.yaml). Thanks Issue-ID: POLICY-3433 Signed-off-by: zrrmmua Change-Id: Ibcbe79d07caa9bff12de341c3d88c36a144796bc --- .../handler/ControlLoopElementHandlerTest.java | 6 +- .../helm/HelmClientTest.java | 17 +++- .../helm/PodStatusValidatorTest.java | 108 +++++++++++++++++++++ .../rest/ChartControllerTest.java | 21 ++-- .../service/ChartServiceTest.java | 6 +- .../service/ChartStoreTest.java | 34 ++++--- 6 files changed, 159 insertions(+), 33 deletions(-) create mode 100644 participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/helm/PodStatusValidatorTest.java (limited to 'participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes') diff --git a/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/handler/ControlLoopElementHandlerTest.java b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/handler/ControlLoopElementHandlerTest.java index f3d27a63c..f8381ee7f 100644 --- a/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/handler/ControlLoopElementHandlerTest.java +++ b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/handler/ControlLoopElementHandlerTest.java @@ -22,6 +22,8 @@ package org.onap.policy.clamp.controlloop.participant.kubernetes.handler; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doThrow; @@ -35,6 +37,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; +import org.mockito.Spy; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElement; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopOrderedState; import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopState; @@ -64,6 +67,7 @@ class ControlLoopElementHandlerTest { @InjectMocks + @Spy private ControlLoopElementHandler controlLoopElementHandler = new ControlLoopElementHandler(); @Mock @@ -107,7 +111,7 @@ class ControlLoopElementHandlerTest { @Test void test_ControlLoopElementUpdate() throws PfModelException, IOException, ServiceException { - + doNothing().when(controlLoopElementHandler).checkPodStatus(any(), anyInt(), anyInt()); UUID elementId1 = UUID.randomUUID(); ControlLoopElement element = new ControlLoopElement(); element.setId(elementId1); diff --git a/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/helm/HelmClientTest.java b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/helm/HelmClientTest.java index 5f8b7dc78..370bfa6ce 100644 --- a/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/helm/HelmClientTest.java +++ b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/helm/HelmClientTest.java @@ -33,6 +33,7 @@ import java.io.File; import java.io.IOException; import java.nio.file.Path; import java.util.List; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -49,6 +50,7 @@ import org.onap.policy.common.utils.coder.Coder; import org.onap.policy.common.utils.coder.CoderException; import org.onap.policy.common.utils.coder.StandardCoder; import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.util.FileSystemUtils; @ExtendWith(SpringExtension.class) @@ -74,6 +76,12 @@ class HelmClientTest { mockedClient = mockStatic(HelmClient.class); } + @AfterAll + public static void close() throws IOException { + mockedClient.close(); + FileSystemUtils.deleteRecursively(Path.of("target/tmp")); + } + @Test void test_installChart() throws IOException { mockedClient.when(() -> HelmClient.executeCommand(any())) @@ -85,21 +93,22 @@ class HelmClientTest { @Test void test_findChartRepository() throws IOException, ServiceException { + String tmpPath = "target/tmp/dummyChart/1.0/"; mockedClient.when(() -> HelmClient.executeCommand(Mockito.any())) .thenReturn("nginx-stable/nginx-ingress\t0.9.3\t1.11.3" + " \tNGINX Ingress Controller"); String configuredRepo = helmClient.findChartRepository(charts.get(1)); - assertThat(configuredRepo).isEqualTo("nginx-stable"); - doReturn(Path.of("/target/tmp/dummyChart/1.0")).when(chartStore).getAppPath(charts.get(1).getChartName(), - charts.get(1).getVersion()); + File tmpFile = new File(tmpPath + charts.get(1).getChartId().getName()); + tmpFile.mkdirs(); + doReturn(Path.of(tmpPath)).when(chartStore).getAppPath(charts.get(1).getChartId()); doReturn(null).when(helmClient).verifyConfiguredRepo(charts.get(1)); String localRepoName = helmClient.findChartRepository(charts.get(1)); assertNotNull(localRepoName); - assertThat(localRepoName).endsWith(charts.get(0).getVersion()); + assertThat(localRepoName).endsWith(charts.get(0).getChartId().getVersion()); } @Test diff --git a/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/helm/PodStatusValidatorTest.java b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/helm/PodStatusValidatorTest.java new file mode 100644 index 000000000..f72a53403 --- /dev/null +++ b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/helm/PodStatusValidatorTest.java @@ -0,0 +1,108 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation. + * ================================================================================ + * 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 + * + * http://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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.clamp.controlloop.participant.kubernetes.helm; + + + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mockStatic; + +import java.io.File; +import java.util.List; +import java.util.Map; +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.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.MockedStatic; +import org.onap.policy.clamp.controlloop.participant.kubernetes.exception.ServiceException; +import org.onap.policy.clamp.controlloop.participant.kubernetes.handler.ControlLoopElementHandler; +import org.onap.policy.clamp.controlloop.participant.kubernetes.models.ChartInfo; +import org.onap.policy.clamp.controlloop.participant.kubernetes.models.ChartList; +import org.onap.policy.common.utils.coder.Coder; +import org.onap.policy.common.utils.coder.CoderException; +import org.onap.policy.common.utils.coder.StandardCoder; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +class PodStatusValidatorTest { + + + private static final Coder CODER = new StandardCoder(); + private static final String CHART_INFO_YAML = "src/test/resources/ChartList.json"; + private static List charts; + private static int timeout = 60; + private static int statusCheckInterval = 30; + + + @InjectMocks + private static PodStatusValidator podStatusValidator; + + private static MockedStatic mockedClient; + + + @BeforeAll + static void init() throws CoderException { + charts = CODER.decode(new File(CHART_INFO_YAML), ChartList.class).getCharts(); + mockedClient = mockStatic(HelmClient.class); + podStatusValidator = new PodStatusValidator(charts.get(0), timeout, statusCheckInterval); + } + + @AfterEach + void clearPodStatusMap() { + ControlLoopElementHandler.getPodStatusMap().clear(); + } + + @AfterAll + public static void close() { + mockedClient.close(); + } + + + @Test + void test_RunningPodState() { + String runningPod = "NAME\tREADY\tSTATUS\tRESTARTS\tAGE\r\nHelloWorld-54777df9f8-qpzqr\t1/1\tRunning\t0\t9h"; + mockedClient.when(() -> HelmClient.executeCommand(any())) + .thenReturn(runningPod); + assertDoesNotThrow(() -> podStatusValidator.run()); + assertThat(ControlLoopElementHandler.getPodStatusMap()).hasSize(1); + assertThat(ControlLoopElementHandler.getPodStatusMap()).containsKey(charts.get(0).getReleaseName()); + assertThat(ControlLoopElementHandler.getPodStatusMap()) + .containsValue(Map.of("HelloWorld-54777df9f8-qpzqr", "Running")); + } + + + @Test + void test_InvalidPodState() { + String invalidPod = "NAME\tREADY\tSTATUS\tRESTARTS\tAGE\nhellofromdocker-54777df9f8-qpzqr\t1/1\tInit\t0\t9h"; + mockedClient.when(() -> HelmClient.executeCommand(any())) + .thenReturn(invalidPod); + assertThatThrownBy(() -> podStatusValidator.run()) + .isInstanceOf(ServiceException.class).hasMessage("Error verifying the status of the pod. Exiting"); + assertThat(ControlLoopElementHandler.getPodStatusMap()).isEmpty(); + } + +} diff --git a/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/rest/ChartControllerTest.java b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/rest/ChartControllerTest.java index 1a1bdae5b..a28fd9ebe 100644 --- a/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/rest/ChartControllerTest.java +++ b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/rest/ChartControllerTest.java @@ -93,7 +93,7 @@ class ChartControllerTest { @BeforeEach void mockServiceClass() { when(chartService.getAllCharts()).thenReturn(charts); - when(chartService.getChart(charts.get(0).getChartName(), charts.get(0).getVersion())) + when(chartService.getChart(charts.get(0).getChartId().getName(), charts.get(0).getChartId().getVersion())) .thenReturn(charts.get(0)); this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build(); @@ -110,7 +110,7 @@ class ChartControllerTest { mockMvc.perform(requestBuilder).andExpect(status().isOk()) .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.charts.[0].chartName", is("HelloWorld"))); + .andExpect(jsonPath("$.charts.[0].chartId.name", is("HelloWorld"))); } /** @@ -125,7 +125,7 @@ class ChartControllerTest { doNothing().when(chartService).installChart(charts.get(0)); requestBuilder = MockMvcRequestBuilders.post(INSTALL_CHART_URL).accept(MediaType.APPLICATION_JSON_VALUE) - .content(getInstallationJson(charts.get(0).getChartName(), charts.get(0).getVersion())) + .content(getInstallationJson(charts.get(0).getChartId().getName(), charts.get(0).getChartId().getVersion())) .contentType(MediaType.APPLICATION_JSON_VALUE); mockMvc.perform(requestBuilder).andExpect(status().isCreated()); @@ -149,9 +149,9 @@ class ChartControllerTest { //Mocking successful scenario for void uninstall method doNothing().when(chartService).uninstallChart(charts.get(0)); - requestBuilder = MockMvcRequestBuilders.delete(UNINSTALL_CHART_URL + charts.get(0).getChartName() - + "/" + charts.get(0).getVersion()).accept(MediaType.APPLICATION_JSON_VALUE) - .contentType(MediaType.APPLICATION_JSON_VALUE); + requestBuilder = MockMvcRequestBuilders.delete(UNINSTALL_CHART_URL + charts.get(0) + .getChartId().getName() + "/" + charts.get(0).getChartId().getVersion()) + .accept(MediaType.APPLICATION_JSON_VALUE).contentType(MediaType.APPLICATION_JSON_VALUE); mockMvc.perform(requestBuilder).andExpect(status().isNoContent()); @@ -196,8 +196,9 @@ class ChartControllerTest { //Mocking successful scenario for void uninstall method doNothing().when(chartService).deleteChart(charts.get(0)); - requestBuilder = MockMvcRequestBuilders.delete(DEFAULT_CHART_URL + "/" + charts.get(0).getChartName() - + "/" + charts.get(0).getVersion()).accept(MediaType.APPLICATION_JSON_VALUE) + requestBuilder = MockMvcRequestBuilders.delete(DEFAULT_CHART_URL + "/" + charts.get(0) + .getChartId().getName() + "/" + charts.get(0).getChartId().getVersion()) + .accept(MediaType.APPLICATION_JSON_VALUE) .contentType(MediaType.APPLICATION_JSON_VALUE); mockMvc.perform(requestBuilder).andExpect(status().isNoContent()); @@ -219,8 +220,8 @@ class ChartControllerTest { private String getChartInfoJson() { JSONObject jsonObj = new JSONObject(); - jsonObj.put("chartName", charts.get(0).getChartName()); - jsonObj.put("version", charts.get(0).getVersion()); + jsonObj.put("chartName", charts.get(0).getChartId().getName()); + jsonObj.put("version", charts.get(0).getChartId().getVersion()); jsonObj.put("namespace", charts.get(0).getNamespace()); jsonObj.put("repository", charts.get(0).getRepository()); jsonObj.put("releaseName", charts.get(0).getReleaseName()); diff --git a/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/service/ChartServiceTest.java b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/service/ChartServiceTest.java index 957a69a08..8e7943410 100644 --- a/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/service/ChartServiceTest.java +++ b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/service/ChartServiceTest.java @@ -88,8 +88,8 @@ class ChartServiceTest { assertNull(chartService.getChart("dummyName", "dummyversion")); doReturn(charts.get(0)).when(chartStore).getChart(any(), any()); - ChartInfo chart = chartService.getChart(charts.get(0).getChartName(), - charts.get(0).getVersion()); + ChartInfo chart = chartService.getChart(charts.get(0).getChartId().getName(), + charts.get(0).getChartId().getVersion()); assertNotNull(chart); assertThat(chart.getNamespace()).isEqualTo(charts.get(0).getNamespace()); } @@ -107,7 +107,7 @@ class ChartServiceTest { ChartInfo chart = chartService.saveChart(charts.get(0), mockChartFile, mockOverrideFile); assertNotNull(chart); - assertThat(chart.getChartName()).isEqualTo(charts.get(0).getChartName()); + assertThat(chart.getChartId().getName()).isEqualTo(charts.get(0).getChartId().getName()); } diff --git a/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/service/ChartStoreTest.java b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/service/ChartStoreTest.java index 2d05a7a0e..eb4e7a173 100644 --- a/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/service/ChartStoreTest.java +++ b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/service/ChartStoreTest.java @@ -46,6 +46,7 @@ import org.onap.policy.clamp.controlloop.participant.kubernetes.parameters.Parti import org.onap.policy.common.utils.coder.Coder; import org.onap.policy.common.utils.coder.CoderException; import org.onap.policy.common.utils.coder.StandardCoder; +import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; import org.springframework.mock.web.MockMultipartFile; import org.springframework.util.FileSystemUtils; @@ -88,7 +89,7 @@ class ChartStoreTest { void test_getHelmChartFile() { File file = chartStore.getHelmChartFile(charts.get(0)); assertNotNull(file); - assertThat(file.getPath()).endsWith(charts.get(0).getChartName()); + assertThat(file.getPath()).endsWith(charts.get(0).getChartId().getName()); } @Test @@ -103,10 +104,10 @@ class ChartStoreTest { MockMultipartFile mockChartFile = new MockMultipartFile("chart", "dummy".getBytes()); MockMultipartFile mockOverrideFile = new MockMultipartFile("override", "dummy".getBytes()); ChartInfo testChart = charts.get(0); - testChart.setChartName("testChart"); + testChart.setChartId(new ToscaConceptIdentifier("testChart", "1.0.0")); ChartInfo result = chartStore.saveChart(charts.get(0), mockChartFile, mockOverrideFile); - assertThat(result.getChartName()).isEqualTo("testChart"); + assertThat(result.getChartId().getName()).isEqualTo("testChart"); assertThat(chartStore.getLocalChartMap()).hasSize(1); assertThatThrownBy(() -> chartStore.saveChart(charts.get(0), mockChartFile, mockOverrideFile)) @@ -116,11 +117,12 @@ class ChartStoreTest { @Test void test_getChart() { - assertNull(chartStore.getChart(charts.get(0).getChartName(), charts.get(0).getVersion())); - chartStore.getLocalChartMap().put(charts.get(0).getChartName() + "_" + charts.get(0).getVersion(), - charts.get(0)); - ChartInfo chart = chartStore.getChart(charts.get(0).getChartName(), charts.get(0).getVersion()); - assertThat(chart.getChartName()).isEqualTo(charts.get(0).getChartName()); + assertNull(chartStore.getChart(charts.get(0).getChartId().getName(), charts.get(0).getChartId().getVersion())); + chartStore.getLocalChartMap().put(charts.get(0).getChartId().getName() + "_" + charts.get(0).getChartId() + .getVersion(), charts.get(0)); + ChartInfo chart = chartStore.getChart(charts.get(0).getChartId().getName(), + charts.get(0).getChartId().getVersion()); + assertThat(chart.getChartId().getName()).isEqualTo(charts.get(0).getChartId().getName()); } @Test @@ -129,7 +131,8 @@ class ChartStoreTest { assertThat(chartStore.getAllCharts()).isEmpty(); for (ChartInfo chart : charts) { - chartStore.getLocalChartMap().put(chart.getChartName() + "_" + chart.getVersion(), chart); + chartStore.getLocalChartMap().put(chart.getChartId().getName() + "_" + chart.getChartId().getVersion(), + chart); } List retrievedChartList = chartStore.getAllCharts(); assertThat(retrievedChartList).isNotEmpty(); @@ -138,8 +141,8 @@ class ChartStoreTest { @Test void test_deleteChart() { - chartStore.getLocalChartMap().put(charts.get(0).getChartName() + "_" + charts.get(0).getVersion(), - charts.get(0)); + chartStore.getLocalChartMap().put(charts.get(0).getChartId().getName() + "_" + charts.get(0).getChartId() + .getVersion(), charts.get(0)); assertThat(chartStore.getLocalChartMap()).hasSize(1); chartStore.deleteChart(charts.get(0)); assertThat(chartStore.getLocalChartMap()).isEmpty(); @@ -147,9 +150,9 @@ class ChartStoreTest { @Test void test_getAppPath() { - Path path = chartStore.getAppPath(charts.get(0).getChartName(), charts.get(0).getVersion()); + Path path = chartStore.getAppPath(charts.get(0).getChartId()); assertNotNull(path); - assertThat(path.toString()).endsWith(charts.get(0).getVersion()); + assertThat(path.toString()).endsWith(charts.get(0).getChartId().getVersion()); assertThat(path.toString()).startsWith("target"); } @@ -158,13 +161,14 @@ class ChartStoreTest { MockMultipartFile mockChartFile = new MockMultipartFile("HelmChartFile", "dummyData".getBytes()); MockMultipartFile mockOverrideFile = new MockMultipartFile("overrideFile.yaml", "dummyData".getBytes()); ChartInfo testChart = charts.get(0); - testChart.setChartName("dummyChart"); + testChart.setChartId(new ToscaConceptIdentifier("dummyChart", "1.0.0")); //Creating a dummy chart in local dir. chartStore.saveChart(charts.get(0), mockChartFile, mockOverrideFile); //Instantiating a new chartStore object with pre available chart in local. ChartStore chartStore2 = new ChartStore(parameters); - assertThat(chartStore2.getLocalChartMap()).hasSize(1).containsKey("dummyChart_" + charts.get(0).getVersion()); + assertThat(chartStore2.getLocalChartMap()).hasSize(1).containsKey("dummyChart_" + charts.get(0).getChartId() + .getVersion()); } } -- cgit 1.2.3-korg