diff options
4 files changed, 77 insertions, 56 deletions
diff --git a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/acm/participant/kubernetes/handler/AutomationCompositionElementHandler.java b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/acm/participant/kubernetes/handler/AutomationCompositionElementHandler.java index 7050dfd47..7385a1f3b 100644 --- a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/acm/participant/kubernetes/handler/AutomationCompositionElementHandler.java +++ b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/acm/participant/kubernetes/handler/AutomationCompositionElementHandler.java @@ -27,10 +27,8 @@ import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; import lombok.AccessLevel; import lombok.Getter; import org.onap.policy.clamp.acm.participant.intermediary.api.AutomationCompositionElementListener; @@ -39,6 +37,7 @@ import org.onap.policy.clamp.acm.participant.kubernetes.exception.ServiceExcepti import org.onap.policy.clamp.acm.participant.kubernetes.helm.PodStatusValidator; import org.onap.policy.clamp.acm.participant.kubernetes.models.ChartInfo; import org.onap.policy.clamp.acm.participant.kubernetes.service.ChartService; +import org.onap.policy.clamp.common.acm.exception.AutomationCompositionException; import org.onap.policy.clamp.models.acm.concepts.AcElementDeploy; import org.onap.policy.clamp.models.acm.concepts.AcTypeState; import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElementDefinition; @@ -61,8 +60,6 @@ import org.springframework.stereotype.Component; public class AutomationCompositionElementHandler implements AutomationCompositionElementListener { private static final Logger LOGGER = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - private ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); - // Map of helm installation and the status of corresponding pods @Getter private static Map<String, Map<String, String>> podStatusMap = new ConcurrentHashMap<>(); @@ -118,26 +115,47 @@ public class AutomationCompositionElementHandler implements AutomationCompositio @Override public synchronized void deploy(UUID automationCompositionId, AcElementDeploy element, Map<String, Object> properties) throws PfModelException { - @SuppressWarnings("unchecked") - var chartData = (Map<String, Object>) properties.get("chart"); - LOGGER.info("Installation request received for the Helm Chart {} ", chartData); try { - var chartInfo = CODER.convert(chartData, ChartInfo.class); + var chartInfo = getChartInfo(properties); if (chartService.installChart(chartInfo)) { chartMap.put(element.getId(), chartInfo); - var config = CODER.convert(properties, ThreadConfig.class); + var config = getThreadConfig(properties); checkPodStatus(automationCompositionId, element.getId(), chartInfo, config.uninitializedToPassiveTimeout, config.podStatusCheckInterval); + } else { + intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, element.getId(), + DeployState.UNDEPLOYED, null, StateChangeResult.FAILED, "Chart not installed"); } - } catch (ServiceException | CoderException | IOException e) { - LOGGER.warn("Installation of Helm chart failed", e); + } catch (ServiceException | IOException e) { + throw new PfModelException(Response.Status.BAD_REQUEST, "Installation of Helm chart failed ", e); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new PfModelException(Response.Status.BAD_REQUEST, "Error invoking ExecutorService ", e); - } catch (ExecutionException e) { - throw new PfModelException(Response.Status.BAD_REQUEST, "Error retrieving pod status result ", e); + } catch (AutomationCompositionException e) { + intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, element.getId(), + DeployState.UNDEPLOYED, null, StateChangeResult.FAILED, e.getMessage()); + } + } + + private ThreadConfig getThreadConfig(Map<String, Object> properties) throws AutomationCompositionException { + try { + return CODER.convert(properties, ThreadConfig.class); + } catch (CoderException e) { + throw new AutomationCompositionException(Status.BAD_REQUEST, "Error extracting ThreadConfig ", e); + } + } + + private ChartInfo getChartInfo(Map<String, Object> properties) throws AutomationCompositionException { + @SuppressWarnings("unchecked") + var chartData = (Map<String, Object>) properties.get("chart"); + + LOGGER.info("Installation request received for the Helm Chart {} ", chartData); + try { + return CODER.convert(chartData, ChartInfo.class); + } catch (CoderException e) { + throw new AutomationCompositionException(Status.BAD_REQUEST, "Error extracting ChartInfo ", e); } } @@ -145,16 +163,17 @@ public class AutomationCompositionElementHandler implements AutomationCompositio * Invoke a new thread to check the status of deployed pods. * * @param chart ChartInfo + * @throws ServiceException in case of an exception */ public void checkPodStatus(UUID automationCompositionId, UUID elementId, ChartInfo chart, int timeout, - int podStatusCheckInterval) throws ExecutionException, InterruptedException { - // Invoke runnable thread to check pod status - var result = executor.submit(new PodStatusValidator(chart, timeout, podStatusCheckInterval), "Done"); - if (!result.get().isEmpty()) { - LOGGER.info("Pod Status Validator Completed: {}", result.isDone()); - intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, elementId, - DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Deployed"); - } + int podStatusCheckInterval) throws InterruptedException, ServiceException { + + var result = new PodStatusValidator(chart, timeout, podStatusCheckInterval); + result.run(); + LOGGER.info("Pod Status Validator Completed"); + intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, elementId, + DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Deployed"); + } @Override 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 89eb284eb..0a1424134 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 @@ -25,7 +25,6 @@ import java.lang.invoke.MethodHandles; import java.nio.charset.StandardCharsets; 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; @@ -35,7 +34,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class PodStatusValidator implements Runnable { +public class PodStatusValidator { private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); @@ -50,6 +49,7 @@ public class PodStatusValidator implements Runnable { /** * Constructor for PodStatusValidator. + * * @param chart chartInfo * @param timeout timeout for the thread to exit * @param statusCheckInterval Interval to check pod status @@ -60,15 +60,18 @@ public class PodStatusValidator implements Runnable { this.statusCheckInterval = statusCheckInterval; } - - @SneakyThrows - @Override - public void run() { + /** + * Run the execution. + * + * @throws InterruptedException in case of an exception + * @throws ServiceException in case of an exception + */ + public void run() throws InterruptedException, ServiceException { logger.info("Polling the status of deployed pods for the chart {}", chart.getChartId().getName()); try { verifyPodStatus(); - } catch (ServiceException | IOException e) { + } catch (IOException e) { throw new ServiceException("Error verifying the status of the pod. Exiting", e); } } diff --git a/participant/participant-impl/participant-impl-kubernetes/src/test/java/org/onap/policy/clamp/acm/participant/kubernetes/handler/AutomationCompositionElementHandlerTest.java b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org/onap/policy/clamp/acm/participant/kubernetes/handler/AutomationCompositionElementHandlerTest.java index d9702abc5..6b24c0f8a 100644 --- a/participant/participant-impl/participant-impl-kubernetes/src/test/java/org/onap/policy/clamp/acm/participant/kubernetes/handler/AutomationCompositionElementHandlerTest.java +++ b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org/onap/policy/clamp/acm/participant/kubernetes/handler/AutomationCompositionElementHandlerTest.java @@ -23,6 +23,7 @@ package org.onap.policy.clamp.acm.participant.kubernetes.handler; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.doNothing; @@ -68,17 +69,17 @@ class AutomationCompositionElementHandlerTest { private static final Coder CODER = new StandardCoder(); private static final String CHART_INFO_YAML = "src/test/resources/ChartList.json"; private static final String KEY_NAME = - "org.onap.domain.database.HelloWorld_K8SMicroserviceAutomationCompositionElement"; + "org.onap.domain.database.HelloWorld_K8SMicroserviceAutomationCompositionElement"; private static List<ChartInfo> charts; private static ToscaServiceTemplate toscaServiceTemplate; private static final String K8S_AUTOMATION_COMPOSITION_ELEMENT = - "org.onap.domain.database.PMSH_K8SMicroserviceAutomationCompositionElement"; + "org.onap.domain.database.PMSH_K8SMicroserviceAutomationCompositionElement"; private final CommonTestData commonTestData = new CommonTestData(); @InjectMocks @Spy private AutomationCompositionElementHandler automationCompositionElementHandler = - new AutomationCompositionElementHandler(); + new AutomationCompositionElementHandler(); @Mock private ChartService chartService; @@ -107,19 +108,18 @@ class AutomationCompositionElementHandlerTest { doNothing().when(chartService).uninstallChart(charts.get(0)); - automationCompositionElementHandler.undeploy( - commonTestData.getAutomationCompositionId(), automationCompositionElementId1); + automationCompositionElementHandler.undeploy(commonTestData.getAutomationCompositionId(), + automationCompositionElementId1); doThrow(new ServiceException("Error uninstalling the chart")).when(chartService).uninstallChart(charts.get(0)); - assertDoesNotThrow(() -> automationCompositionElementHandler.undeploy( - commonTestData.getAutomationCompositionId(), automationCompositionElementId1)); + assertDoesNotThrow(() -> automationCompositionElementHandler + .undeploy(commonTestData.getAutomationCompositionId(), automationCompositionElementId1)); } @Test - void test_AutomationCompositionElementUpdate() throws PfModelException, IOException, ServiceException, - ExecutionException, InterruptedException { - doReturn(true).when(chartService).installChart(any()); + void test_AutomationCompositionElementUpdate() + throws PfModelException, IOException, ServiceException, ExecutionException, InterruptedException { doNothing().when(automationCompositionElementHandler).checkPodStatus(any(), any(), any(), anyInt(), anyInt()); var elementId1 = UUID.randomUUID(); var element = new AcElementDeploy(); @@ -127,11 +127,15 @@ class AutomationCompositionElementHandlerTest { element.setDefinition(new ToscaConceptIdentifier(KEY_NAME, "1.0.1")); element.setOrderedState(DeployOrder.DEPLOY); - var nodeTemplatesMap = - toscaServiceTemplate.getToscaTopologyTemplate().getNodeTemplates(); - automationCompositionElementHandler.deploy( - commonTestData.getAutomationCompositionId(), element, - nodeTemplatesMap.get(K8S_AUTOMATION_COMPOSITION_ELEMENT).getProperties()); + var nodeTemplatesMap = toscaServiceTemplate.getToscaTopologyTemplate().getNodeTemplates(); + + doReturn(false).when(chartService).installChart(any()); + assertDoesNotThrow(() -> automationCompositionElementHandler.deploy(commonTestData.getAutomationCompositionId(), + element, nodeTemplatesMap.get(K8S_AUTOMATION_COMPOSITION_ELEMENT).getProperties())); + + doReturn(true).when(chartService).installChart(any()); + automationCompositionElementHandler.deploy(commonTestData.getAutomationCompositionId(), element, + nodeTemplatesMap.get(K8S_AUTOMATION_COMPOSITION_ELEMENT).getProperties()); assertThat(automationCompositionElementHandler.getChartMap()).hasSize(1).containsKey(elementId1); @@ -139,24 +143,20 @@ class AutomationCompositionElementHandlerTest { var elementId2 = UUID.randomUUID(); element.setId(elementId2); - automationCompositionElementHandler.deploy( - commonTestData.getAutomationCompositionId(), element, - nodeTemplatesMap.get(K8S_AUTOMATION_COMPOSITION_ELEMENT).getProperties()); + assertThrows(PfModelException.class, + () -> automationCompositionElementHandler.deploy(commonTestData.getAutomationCompositionId(), element, + nodeTemplatesMap.get(K8S_AUTOMATION_COMPOSITION_ELEMENT).getProperties())); assertThat(automationCompositionElementHandler.getChartMap().containsKey(elementId2)).isFalse(); } @Test void test_checkPodStatus() throws ExecutionException, InterruptedException { - doReturn(result).when(executor).submit(any(Runnable.class), any()); - doReturn("Done").when(result).get(); - doReturn(true).when(result).isDone(); var chartInfo = charts.get(0); var automationCompositionId = UUID.randomUUID(); var element = new AutomationCompositionElement(); - assertDoesNotThrow( - () -> automationCompositionElementHandler.checkPodStatus(automationCompositionId, - element.getId(), chartInfo, 1, 1)); + assertThrows(ServiceException.class, () -> automationCompositionElementHandler + .checkPodStatus(automationCompositionId, element.getId(), chartInfo, 1, 1)); } @Test 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 6cec6056d..91aff830f 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 @@ -22,8 +22,8 @@ package org.onap.policy.clamp.acm.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.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; @@ -92,8 +92,7 @@ class PodStatusValidatorTest { void test_InvalidPodState() throws ServiceException { String invalidPod = "NAME\tREADY\tSTATUS\tRESTARTS\tAGE\nhellofromdocker-54777df9f8-qpzqr\t1/1\tInit\t0\t9h"; doReturn(invalidPod).when(client).executeCommand(any()); - assertThatThrownBy(() -> podStatusValidator.run()) - .isInstanceOf(ServiceException.class).hasMessage("Error verifying the status of the pod. Exiting"); + assertThrows(ServiceException.class, () -> podStatusValidator.run()); assertThat(AutomationCompositionElementHandler.getPodStatusMap()).isEmpty(); } |