aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrancescoFioraEst <francesco.fiora@est.tech>2022-09-13 15:54:10 +0100
committerFrancescoFioraEst <francesco.fiora@est.tech>2022-09-20 10:00:49 +0100
commita368937411e8767bc19f50a7968567fb68a6dfeb (patch)
tree9c826430c8ecf6e0843aca26341b7af68cc4416e
parent18a13eaef5fc51556b0985c61e271dfc5a3a4a29 (diff)
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 <francesco.fiora@est.tech>
-rw-r--r--examples/src/main/resources/clamp/acm/acelement-helm/acelement/resources/config/application.yaml2
-rw-r--r--examples/src/main/resources/clamp/acm/acelement-helm/acelement/resources/config/logback.xml206
-rw-r--r--participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/acm/participant/kubernetes/helm/PodStatusValidator.java65
-rw-r--r--participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/acm/participant/kubernetes/models/ChartInfo.java2
-rw-r--r--participant/participant-impl/participant-impl-kubernetes/src/test/java/org/onap/policy/clamp/acm/participant/kubernetes/helm/PodStatusValidatorTest.java26
-rw-r--r--participant/participant-impl/participant-impl-kubernetes/src/test/resources/ChartList.json13
6 files changed, 276 insertions, 38 deletions
diff --git a/examples/src/main/resources/clamp/acm/acelement-helm/acelement/resources/config/application.yaml b/examples/src/main/resources/clamp/acm/acelement-helm/acelement/resources/config/application.yaml
index 98d3b6461..d6aa5d951 100644
--- a/examples/src/main/resources/clamp/acm/acelement-helm/acelement/resources/config/application.yaml
+++ b/examples/src/main/resources/clamp/acm/acelement-helm/acelement/resources/config/application.yaml
@@ -6,6 +6,8 @@ spring:
server:
port: ${PORT}
+ ssl:
+ enabled: false
error:
path: /error
diff --git a/examples/src/main/resources/clamp/acm/acelement-helm/acelement/resources/config/logback.xml b/examples/src/main/resources/clamp/acm/acelement-helm/acelement/resources/config/logback.xml
new file mode 100644
index 000000000..d013c0909
--- /dev/null
+++ b/examples/src/main/resources/clamp/acm/acelement-helm/acelement/resources/config/logback.xml
@@ -0,0 +1,206 @@
+<!--
+ ============LICENSE_START=======================================================
+ policy-clamp
+ ================================================================================
+ Copyright (C) 2022 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.
+ ============LICENSE_END=========================================================
+ -->
+
+<configuration scan="true" scanPeriod="30 seconds" debug="false">
+
+ <property name="logDir" value="${POLICY_LOGS}" />
+
+ <property name="errorLog" value="error" />
+ <property name="debugLog" value="debug" />
+ <property name="networkLog" value="network" />
+
+ <property name="metricLog" value="metric" />
+ <property name="transactionLog" value="audit" />
+
+ <property name="debugPattern"
+ value="[%d{yyyy-MM-dd'T'HH:mm:ss.SSS+00:00, UTC}|%level|%logger{0}|%thread] %msg%n" />
+ <property name="errorPattern" value="${debugPattern}" />
+ <property name="networkPattern"
+ value="[%d{yyyy-MM-dd'T'HH:mm:ss.SSS+00:00, UTC}|%t]%m%n" />
+
+ <property
+ name="mpPreamble"
+ value="%X{RequestID}|%X{InvocationID}|%X{ServiceName}|%X{PartnerName}" />
+
+ <property
+ name="mpTime"
+ value="%X{BeginTimestamp}|%X{EndTimestamp}|%X{ElapsedTime}" />
+
+ <property
+ name="mpLine1"
+ value="%X{ServiceInstanceID}|%X{VirtualServerName}|%X{StatusCode}|%X{ResponseCode}|%X{ResponseDescription}" />
+
+ <property
+ name="mpLine2"
+ value="%X{InstanceUUID}|%X{Severity}|%X{TargetEntity}|%X{TargetServiceName}|%X{Server}|%X{ServerIPAddress}" />
+
+ <property
+ name="mpLine3"
+ value="%X{ServerFQDN}|%X{ClientIPAddress}|%X{ProcessKey}|%X{RemoteHost}|%X{AlertSeverity}" />
+
+ <property
+ name="mpLine4"
+ value="%X{TargetVirtualEntity}|%level|%thread| %msg%n" />
+
+
+ <property name="metricPattern"
+ value="{$mpPreamble}|{$mpTime}|{$mpLine1}|{$mpLine2}|{$mpLine3}|$mpLine4" />
+
+ <property name="transactionPattern" value="${metricPattern}" />
+
+ <appender name="ErrorOut"
+ class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>${logDir}/${errorLog}.log</file>
+ <rollingPolicy
+ class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+ <fileNamePattern>${logDir}/${errorLog}.%d{yyyy-MM-dd}.%i.log.zip
+ </fileNamePattern>
+ <maxFileSize>50MB</maxFileSize>
+ <maxHistory>30</maxHistory>
+ <totalSizeCap>10GB</totalSizeCap>
+ </rollingPolicy>
+ <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+ <level>WARN</level>
+ </filter>
+ <encoder>
+ <pattern>${errorPattern}</pattern>
+ </encoder>
+ </appender>
+
+ <appender name="AsyncErrorOut"
+ class="ch.qos.logback.classic.AsyncAppender">
+ <appender-ref ref="ErrorOut" />
+ </appender>
+
+ <appender name="DebugOut"
+ class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>${logDir}/${debugLog}.log</file>
+ <rollingPolicy
+ class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+ <fileNamePattern>${logDir}/${debugLog}.%d{yyyy-MM-dd}.%i.log.zip
+ </fileNamePattern>
+ <maxFileSize>50MB</maxFileSize>
+ <maxHistory>30</maxHistory>
+ <totalSizeCap>10GB</totalSizeCap>
+ </rollingPolicy>
+ <encoder>
+ <pattern>${debugPattern}</pattern>
+ </encoder>
+ </appender>
+
+ <appender name="AsyncDebugOut"
+ class="ch.qos.logback.classic.AsyncAppender">
+ <appender-ref ref="DebugOut" />
+ </appender>
+
+ <appender name="NetworkOut"
+ class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>${logDir}/${networkLog}.log</file>
+ <rollingPolicy
+ class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+ <fileNamePattern>${logDir}/${networkLog}.%d{yyyy-MM-dd}.%i.log.zip
+ </fileNamePattern>
+ <maxFileSize>50MB</maxFileSize>
+ <maxHistory>30</maxHistory>
+ <totalSizeCap>10GB</totalSizeCap>
+ </rollingPolicy>
+ <encoder>
+ <pattern>${networkPattern}</pattern>
+ </encoder>
+ </appender>
+
+ <appender name="AsyncNetworkOut"
+ class="ch.qos.logback.classic.AsyncAppender">
+ <appender-ref ref="NetworkOut" />
+ </appender>
+
+ <appender name="MetricOut"
+ class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>${logDir}/${metricLog}.log</file>
+ <rollingPolicy
+ class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+ <fileNamePattern>${logDir}/${metricLog}.%d{yyyy-MM-dd}.%i.log.zip
+ </fileNamePattern>
+ <maxFileSize>50MB</maxFileSize>
+ <maxHistory>30</maxHistory>
+ <totalSizeCap>10GB</totalSizeCap>
+ </rollingPolicy>
+ <encoder>
+ <pattern>${metricPattern}</pattern>
+ </encoder>
+ </appender>
+
+ <appender name="AsyncMetricOut"
+ class="ch.qos.logback.classic.AsyncAppender">
+ <appender-ref ref="MetricOut" />
+ </appender>
+
+ <appender name="TransactionOut"
+ class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>${logDir}/${transactionLog}.log</file>
+ <rollingPolicy
+ class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+ <fileNamePattern>${logDir}/${transactionLog}.%d{yyyy-MM-dd}.%i.log.zip
+ </fileNamePattern>
+ <maxFileSize>50MB</maxFileSize>
+ <maxHistory>30</maxHistory>
+ <totalSizeCap>10GB</totalSizeCap>
+ </rollingPolicy>
+ <encoder>
+ <pattern>${transactionPattern}</pattern>
+ </encoder>
+ </appender>
+
+ <appender name="AsyncTransactionOut"
+ class="ch.qos.logback.classic.AsyncAppender">
+ <appender-ref ref="TransactionOut" />
+ </appender>
+
+ <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder>
+ <Pattern>[%d{yyyy-MM-dd'T'HH:mm:ss.SSS+00:00, UTC}|%level|%logger{0}|%thread] %msg%n</Pattern>
+ </encoder>
+ </appender>
+
+ <appender name="AsyncStdOut" class="ch.qos.logback.classic.AsyncAppender">
+ <appender-ref ref="STDOUT" />
+ </appender>
+
+ <logger name="network" level="INFO" additivity="false">
+ <appender-ref ref="AsyncNetworkOut" />
+ <appender-ref ref="AsyncStdOut" />
+ </logger>
+
+ <logger name="org.eclipse.jetty.server.RequestLog" level="info" additivity="false">
+ <appender-ref ref="AsyncNetworkOut" />
+ <appender-ref ref="AsyncStdOut" />
+ </logger>
+
+ <logger name="org.eclipse.jetty" level="ERROR" />
+
+ <root level="INFO">
+ <appender-ref ref="AsyncDebugOut" />
+ <appender-ref ref="AsyncErrorOut" />
+ <appender-ref ref="AsyncMetricOut" />
+ <appender-ref ref="AsyncTransactionOut" />
+ <appender-ref ref="AsyncStdOut" />
+ </root>
+
+</configuration>
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<String, String> 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<String, String> mapPodStatus(String output) throws IOException, ServiceException {
+ private Map<String, String> mapPodStatus(String output) throws IOException {
Map<String, String> 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<ChartInfo> charts;
- @InjectMocks
- private static PodStatusValidator podStatusValidator;
-
private static MockedStatic<HelmClient> 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"
}
]
}