From a368937411e8767bc19f50a7968567fb68a6dfeb Mon Sep 17 00:00:00 2001 From: FrancescoFioraEst Date: Tue, 13 Sep 2022 15:54:10 +0100 Subject: Fix PodStatus Validator failing in K8sParticipant Fix PodStatus Validator failing in K8sParticipant using service template for Test and Verification of ACM State Management. Issue-ID: POLICY-4355 Change-Id: I63f8ed2c4991422dd43749151387ff54ba7d6071 Signed-off-by: FrancescoFioraEst --- .../kubernetes/helm/PodStatusValidator.java | 65 ++++++++++++---------- .../participant/kubernetes/models/ChartInfo.java | 2 + .../kubernetes/helm/PodStatusValidatorTest.java | 26 ++++++--- .../src/test/resources/ChartList.json | 13 +++++ 4 files changed, 68 insertions(+), 38 deletions(-) (limited to 'participant/participant-impl') diff --git a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/acm/participant/kubernetes/helm/PodStatusValidator.java b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/acm/participant/kubernetes/helm/PodStatusValidator.java index 8267bda13..67bdc0b40 100644 --- a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/acm/participant/kubernetes/helm/PodStatusValidator.java +++ b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/acm/participant/kubernetes/helm/PodStatusValidator.java @@ -1,6 +1,6 @@ /*- * ========================LICENSE_START================================= - * Copyright (C) 2021 Nordix Foundation. All rights reserved. + * Copyright (C) 2021-2022 Nordix Foundation. All rights reserved. * ====================================================================== * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,6 +27,7 @@ import java.util.HashMap; import java.util.Map; import lombok.SneakyThrows; import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; import org.onap.policy.clamp.acm.participant.kubernetes.exception.ServiceException; import org.onap.policy.clamp.acm.participant.kubernetes.handler.AutomationCompositionElementHandler; import org.onap.policy.clamp.acm.participant.kubernetes.models.ChartInfo; @@ -62,58 +63,64 @@ public class PodStatusValidator implements Runnable { @Override public void run() { logger.info("Polling the status of deployed pods for the chart {}", chart.getChartId().getName()); - Map podStatusMap; - String output = null; + + try { + verifyPodStatus(); + } catch (ServiceException | IOException e) { + throw new ServiceException("Error verifying the status of the pod. Exiting", e); + } + } + + private void verifyPodStatus() throws ServiceException, IOException, InterruptedException { var isVerified = false; long endTime = System.currentTimeMillis() + (timeout * 1000L); while (!isVerified && System.currentTimeMillis() < endTime) { - try { - output = HelmClient.executeCommand(verifyPodStatusCommand(chart)); - podStatusMap = mapPodStatus(output); - isVerified = podStatusMap.values() - .stream() - .allMatch("Running"::equals); - if (! isVerified) { - logger.info("Waiting for the pods to be active for the chart {}", chart.getChartId().getName()); - podStatusMap.forEach((key, value) -> logger.info("Pod: {} , state: {}", key, value)); - AutomationCompositionElementHandler.getPodStatusMap().put(chart.getReleaseName(), podStatusMap); - // Recheck status of pods in specific intervals. - Thread.sleep(statusCheckInterval * 1000L); - } else { - logger.info("All pods are in running state for the helm chart {}", chart.getChartId().getName()); - AutomationCompositionElementHandler.getPodStatusMap().put(chart.getReleaseName(), podStatusMap); - } - } catch (ServiceException | IOException e) { - throw new ServiceException("Error verifying the status of the pod. Exiting", e); + var output = HelmClient.executeCommand(verifyPodStatusCommand(chart)); + var podStatusMap = mapPodStatus(output); + isVerified = !podStatusMap.isEmpty() + && podStatusMap.values().stream().allMatch("Running"::equals); + if (!isVerified) { + logger.info("Waiting for the pods to be active for the chart {}", chart.getChartId().getName()); + podStatusMap.forEach((key, value) -> logger.info("Pod: {} , state: {}", key, value)); + // Recheck status of pods in specific intervals. + Thread.sleep(statusCheckInterval * 1000L); + } else { + logger.info("All pods are in running state for the helm chart {}", chart.getChartId().getName()); + AutomationCompositionElementHandler.getPodStatusMap().put(chart.getReleaseName(), podStatusMap); } } + if (!isVerified) { + throw new ServiceException("Time out Exception verifying the status of the pod"); + } } private ProcessBuilder verifyPodStatusCommand(ChartInfo chart) { - String cmd = "kubectl get pods --namespace " + chart.getNamespace() + " | grep " - + chart.getChartId().getName(); + String cmd = "kubectl get pods --namespace " + chart.getNamespace() + " | grep " + getPodName(); return new ProcessBuilder("sh", "-c", cmd); } + private String getPodName() { + return StringUtils.isNotEmpty(chart.getPodName()) ? chart.getPodName() : chart.getChartId().getName(); + } - private Map mapPodStatus(String output) throws IOException, ServiceException { + private Map mapPodStatus(String output) throws IOException { Map podStatusMap = new HashMap<>(); + var podName = getPodName(); try (var reader = new BufferedReader(new InputStreamReader(IOUtils.toInputStream(output, StandardCharsets.UTF_8)))) { var line = reader.readLine(); while (line != null) { - if (line.contains(chart.getChartId().getName())) { + if (line.contains(podName)) { var result = line.split("\\s+"); podStatusMap.put(result[0], result[2]); } line = reader.readLine(); } } - if (!podStatusMap.isEmpty()) { - return podStatusMap; - } else { - throw new ServiceException("Status of Pod is empty"); + if (podStatusMap.isEmpty()) { + logger.warn("Status of Pod {} is empty", podName); } + return podStatusMap; } } diff --git a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/acm/participant/kubernetes/models/ChartInfo.java b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/acm/participant/kubernetes/models/ChartInfo.java index b925e782d..e2c4c2e11 100644 --- a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/acm/participant/kubernetes/models/ChartInfo.java +++ b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/acm/participant/kubernetes/models/ChartInfo.java @@ -34,6 +34,8 @@ public class ChartInfo { @NonNull private ToscaConceptIdentifier chartId; + private String podName; + @NonNull private String namespace; diff --git a/participant/participant-impl/participant-impl-kubernetes/src/test/java/org/onap/policy/clamp/acm/participant/kubernetes/helm/PodStatusValidatorTest.java b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org/onap/policy/clamp/acm/participant/kubernetes/helm/PodStatusValidatorTest.java index fbddf8b28..962744db7 100644 --- a/participant/participant-impl/participant-impl-kubernetes/src/test/java/org/onap/policy/clamp/acm/participant/kubernetes/helm/PodStatusValidatorTest.java +++ b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org/onap/policy/clamp/acm/participant/kubernetes/helm/PodStatusValidatorTest.java @@ -35,7 +35,6 @@ 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.acm.participant.kubernetes.exception.ServiceException; import org.onap.policy.clamp.acm.participant.kubernetes.handler.AutomationCompositionElementHandler; @@ -51,20 +50,16 @@ class PodStatusValidatorTest { private static final Coder CODER = new StandardCoder(); private static final String CHART_INFO_YAML = "src/test/resources/ChartList.json"; + private static int TIMEOUT = 2; + private static int STATUS_CHECK_INTERVAL = 1; private static List charts; - @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); - int timeout = 60; - int statusCheckInterval = 30; - podStatusValidator = new PodStatusValidator(charts.get(0), timeout, statusCheckInterval); } @AfterEach @@ -77,12 +72,12 @@ class PodStatusValidatorTest { 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); + var podStatusValidator = new PodStatusValidator(charts.get(0), TIMEOUT, STATUS_CHECK_INTERVAL); assertDoesNotThrow(() -> podStatusValidator.run()); assertThat(AutomationCompositionElementHandler.getPodStatusMap()).hasSize(1); assertThat(AutomationCompositionElementHandler.getPodStatusMap()).containsKey(charts.get(0).getReleaseName()); @@ -90,15 +85,28 @@ class PodStatusValidatorTest { .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); + var podStatusValidator = new PodStatusValidator(charts.get(1), TIMEOUT, STATUS_CHECK_INTERVAL); assertThatThrownBy(() -> podStatusValidator.run()) .isInstanceOf(ServiceException.class).hasMessage("Error verifying the status of the pod. Exiting"); assertThat(AutomationCompositionElementHandler.getPodStatusMap()).isEmpty(); } + // Use case scenario: Hard coded pod name + @Test + void test_RunningPodStateWhitPodName() { + String runningPod = "NAME\tREADY\tSTATUS\tRESTARTS\tAGE\r\nhelloallworld-54777df9f8-qpzqr\t1/1\tRunning\t0\t9h"; + mockedClient.when(() -> HelmClient.executeCommand(any())) + .thenReturn(runningPod); + var podStatusValidator = new PodStatusValidator(charts.get(2), TIMEOUT, STATUS_CHECK_INTERVAL); + assertDoesNotThrow(() -> podStatusValidator.run()); + assertThat(AutomationCompositionElementHandler.getPodStatusMap()).hasSize(1); + assertThat(AutomationCompositionElementHandler.getPodStatusMap()).containsKey(charts.get(2).getReleaseName()); + assertThat(AutomationCompositionElementHandler.getPodStatusMap()) + .containsValue(Map.of("helloallworld-54777df9f8-qpzqr", "Running")); + } } diff --git a/participant/participant-impl/participant-impl-kubernetes/src/test/resources/ChartList.json b/participant/participant-impl/participant-impl-kubernetes/src/test/resources/ChartList.json index d4cd5de47..f58049640 100644 --- a/participant/participant-impl/participant-impl-kubernetes/src/test/resources/ChartList.json +++ b/participant/participant-impl/participant-impl-kubernetes/src/test/resources/ChartList.json @@ -19,6 +19,19 @@ }, "namespace" : "onap", "releaseName" : "nginxapp" + }, + { + "chartId" : { + "name" : "HelloWorld", + "version" : "1.2" + }, + "namespace" : "onap", + "repository" : { + "repoName": "chartMuseum", + "address" : "https://localhost:8080" + }, + "releaseName" : "helloworld", + "podName" : "helloallworld" } ] } -- cgit 1.2.3-korg