From 6d530dbc21e2965bc49d03540ea7a3f4bf37d69e Mon Sep 17 00:00:00 2001 From: FrancescoFioraEst Date: Fri, 17 Feb 2023 14:17:24 +0000 Subject: Fix UNDEPLOY transition in policyParticipant in ACM Fix UNDEPLOY transition in policyParticipant when there are more then one service template defined Issue-ID: POLICY-4561 Change-Id: Ib05b995a215d9f5f62c69f7058db128474f48dab Signed-off-by: FrancescoFioraEst --- .../policy/client/PolicyApiHttpClient.java | 6 +- .../AutomationCompositionElementHandler.java | 141 ++++++++++++--------- .../AutomationCompositionElementHandlerTest.java | 79 ++++++++---- 3 files changed, 139 insertions(+), 87 deletions(-) (limited to 'participant/participant-impl/participant-impl-policy') diff --git a/participant/participant-impl/participant-impl-policy/src/main/java/org/onap/policy/clamp/acm/participant/policy/client/PolicyApiHttpClient.java b/participant/participant-impl/participant-impl-policy/src/main/java/org/onap/policy/clamp/acm/participant/policy/client/PolicyApiHttpClient.java index a86576eed..bf1d24a74 100644 --- a/participant/participant-impl/participant-impl-policy/src/main/java/org/onap/policy/clamp/acm/participant/policy/client/PolicyApiHttpClient.java +++ b/participant/participant-impl/participant-impl-policy/src/main/java/org/onap/policy/clamp/acm/participant/policy/client/PolicyApiHttpClient.java @@ -1,6 +1,6 @@ /*- * ============LICENSE_START======================================================= - * Copyright (C) 2021 Nordix Foundation. + * Copyright (C) 2021,2023 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,7 +24,6 @@ import javax.ws.rs.client.Entity; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.onap.policy.clamp.acm.participant.policy.main.parameters.ParticipantPolicyParameters; -import org.onap.policy.models.base.PfModelException; import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate; import org.springframework.stereotype.Component; @@ -47,9 +46,8 @@ public class PolicyApiHttpClient extends AbstractHttpClient { * * @param toscaServiceTemplate the whole ToscaServiceTemplate * @return Response - * @throws PfModelException on errors creating the policy type */ - public Response createPolicyType(ToscaServiceTemplate toscaServiceTemplate) throws PfModelException { + public Response createPolicyType(ToscaServiceTemplate toscaServiceTemplate) { return executePost(POLICY_URI + "policytypes", Entity.entity(toscaServiceTemplate, MediaType.APPLICATION_JSON)); } diff --git a/participant/participant-impl/participant-impl-policy/src/main/java/org/onap/policy/clamp/acm/participant/policy/main/handler/AutomationCompositionElementHandler.java b/participant/participant-impl/participant-impl-policy/src/main/java/org/onap/policy/clamp/acm/participant/policy/main/handler/AutomationCompositionElementHandler.java index 0b03e236f..3e740192b 100644 --- a/participant/participant-impl/participant-impl-policy/src/main/java/org/onap/policy/clamp/acm/participant/policy/main/handler/AutomationCompositionElementHandler.java +++ b/participant/participant-impl/participant-impl-policy/src/main/java/org/onap/policy/clamp/acm/participant/policy/main/handler/AutomationCompositionElementHandler.java @@ -22,9 +22,13 @@ package org.onap.policy.clamp.acm.participant.policy.main.handler; +import java.util.ArrayList; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import java.util.UUID; +import javax.ws.rs.core.Response.Status; +import lombok.RequiredArgsConstructor; import lombok.Setter; import org.apache.http.HttpStatus; import org.onap.policy.clamp.acm.participant.intermediary.api.AutomationCompositionElementListener; @@ -35,9 +39,9 @@ import org.onap.policy.clamp.models.acm.concepts.AcElementDeploy; import org.onap.policy.clamp.models.acm.concepts.DeployState; import org.onap.policy.clamp.models.acm.concepts.LockState; import org.onap.policy.models.base.PfModelException; -import org.onap.policy.models.base.PfModelRuntimeException; import org.onap.policy.models.pdp.concepts.DeploymentSubGroup; -import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy; +import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; +import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @@ -46,11 +50,12 @@ import org.springframework.stereotype.Component; * This class handles implementation of automationCompositionElement updates. */ @Component +@RequiredArgsConstructor public class AutomationCompositionElementHandler implements AutomationCompositionElementListener { private static final Logger LOGGER = LoggerFactory.getLogger(AutomationCompositionElementHandler.class); - private final Map policyTypeMap = new LinkedHashMap<>(); - private final Map policyMap = new LinkedHashMap<>(); + + private final Map serviceTemplateMap = new LinkedHashMap<>(); private final PolicyApiHttpClient apiHttpClient; private final PolicyPapHttpClient papHttpClient; @@ -58,17 +63,6 @@ public class AutomationCompositionElementHandler implements AutomationCompositio @Setter private ParticipantIntermediaryApi intermediaryApi; - /** - * constructor. - * - * @param apiHttpClient the Policy Api Http Client - * @param papHttpClient the Policy Pap Http Client - */ - public AutomationCompositionElementHandler(PolicyApiHttpClient apiHttpClient, PolicyPapHttpClient papHttpClient) { - this.papHttpClient = papHttpClient; - this.apiHttpClient = apiHttpClient; - } - /** * Callback method to handle a automation composition element state change. * @@ -76,36 +70,42 @@ public class AutomationCompositionElementHandler implements AutomationCompositio * @param automationCompositionElementId the ID of the automation composition element */ @Override - public void undeploy(UUID automationCompositionId, UUID automationCompositionElementId) { - try { - undeployPolicies(automationCompositionElementId); - deletePolicyData(automationCompositionId, automationCompositionElementId); + public void undeploy(UUID automationCompositionId, UUID automationCompositionElementId) throws PfModelException { + var automationCompositionDefinition = serviceTemplateMap.get(automationCompositionElementId); + if (automationCompositionDefinition == null) { + LOGGER.debug("No policies to undeploy to {}", automationCompositionElementId); intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, automationCompositionElementId, DeployState.UNDEPLOYED, LockState.NONE); - } catch (PfModelRuntimeException e) { - LOGGER.error("Undeploying/Deleting policy failed {}", automationCompositionElementId, e); + return; } + var policyList = getPolicyList(automationCompositionDefinition); + undeployPolicies(policyList, automationCompositionElementId); + var policyTypeList = getPolicyTypeList(automationCompositionDefinition); + deletePolicyData(policyTypeList, policyList); + serviceTemplateMap.remove(automationCompositionElementId); + intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, + automationCompositionElementId, DeployState.UNDEPLOYED, LockState.NONE); } - private void deletePolicyData(UUID automationCompositionId, UUID automationCompositionElementId) { + private void deletePolicyData(List policyTypeList, + List policyList) { // Delete all policies of this automationComposition from policy framework - for (var policy : policyMap.entrySet()) { - apiHttpClient.deletePolicy(policy.getKey(), policy.getValue()); + for (var policy : policyList) { + apiHttpClient.deletePolicy(policy.getName(), policy.getVersion()); } - policyMap.clear(); // Delete all policy types of this automation composition from policy framework - for (var policyType : policyTypeMap.entrySet()) { - apiHttpClient.deletePolicyType(policyType.getKey(), policyType.getValue()); + for (var policyType : policyTypeList) { + apiHttpClient.deletePolicyType(policyType.getName(), policyType.getVersion()); } - policyTypeMap.clear(); } - private void deployPolicies(UUID automationCompositionId, UUID automationCompositionElementId) { + private void deployPolicies(List policyList, UUID automationCompositionId, + UUID automationCompositionElementId) throws PfModelException { var deployFailure = false; // Deploy all policies of this automationComposition from Policy Framework - if (!policyMap.entrySet().isEmpty()) { - for (var policy : policyMap.entrySet()) { - var deployPolicyResp = papHttpClient.handlePolicyDeployOrUndeploy(policy.getKey(), policy.getValue(), + if (!policyList.isEmpty()) { + for (var policy : policyList) { + var deployPolicyResp = papHttpClient.handlePolicyDeployOrUndeploy(policy.getName(), policy.getVersion(), DeploymentSubGroup.Action.POST).getStatus(); if (deployPolicyResp != HttpStatus.SC_ACCEPTED) { deployFailure = true; @@ -119,14 +119,16 @@ public class AutomationCompositionElementHandler implements AutomationCompositio // Update the AC element state intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, automationCompositionElementId, DeployState.DEPLOYED, LockState.LOCKED); + } else { + throw new PfModelException(Status.BAD_REQUEST, "Deploy of Policy failed."); } } - private void undeployPolicies(UUID automationCompositionElementId) { + private void undeployPolicies(List policyList, UUID automationCompositionElementId) { // Undeploy all policies of this automation composition from Policy Framework - if (!policyMap.entrySet().isEmpty()) { - for (var policy : policyMap.entrySet()) { - papHttpClient.handlePolicyDeployOrUndeploy(policy.getKey(), policy.getValue(), + if (!policyList.isEmpty()) { + for (var policy : policyList) { + papHttpClient.handlePolicyDeployOrUndeploy(policy.getName(), policy.getVersion(), DeploymentSubGroup.Action.DELETE); } LOGGER.debug("Undeployed policies from {} successfully", automationCompositionElementId); @@ -150,32 +152,53 @@ public class AutomationCompositionElementHandler implements AutomationCompositio var createPolicyResp = HttpStatus.SC_OK; var automationCompositionDefinition = element.getToscaServiceTemplateFragment(); - if (automationCompositionDefinition.getToscaTopologyTemplate() != null) { - if (automationCompositionDefinition.getPolicyTypes() != null) { - for (var policyType : automationCompositionDefinition.getPolicyTypes().values()) { - policyTypeMap.put(policyType.getName(), policyType.getVersion()); - } - LOGGER.info("Found Policy Types in automation composition definition: {} , Creating Policy Types", - automationCompositionDefinition.getName()); - createPolicyTypeResp = apiHttpClient.createPolicyType(automationCompositionDefinition).getStatus(); + if (automationCompositionDefinition.getToscaTopologyTemplate() == null) { + throw new PfModelException(Status.BAD_REQUEST, "ToscaTopologyTemplate not defined"); + } + serviceTemplateMap.put(element.getId(), automationCompositionDefinition); + if (automationCompositionDefinition.getPolicyTypes() != null) { + LOGGER.info("Found Policy Types in automation composition definition: {} , Creating Policy Types", + automationCompositionDefinition.getName()); + createPolicyTypeResp = apiHttpClient.createPolicyType(automationCompositionDefinition).getStatus(); + } + if (automationCompositionDefinition.getToscaTopologyTemplate().getPolicies() != null) { + LOGGER.info("Found Policies in automation composition definition: {} , Creating Policies", + automationCompositionDefinition.getName()); + createPolicyResp = apiHttpClient.createPolicy(automationCompositionDefinition).getStatus(); + } + if (createPolicyTypeResp == HttpStatus.SC_OK && createPolicyResp == HttpStatus.SC_OK) { + LOGGER.info( + "PolicyTypes/Policies for the automation composition element : {} are created " + "successfully", + element.getId()); + var policyList = getPolicyList(automationCompositionDefinition); + deployPolicies(policyList, automationCompositionId, element.getId()); + } else { + throw new PfModelException(Status.BAD_REQUEST, + "Creation of PolicyTypes/Policies failed. Policies will not be deployed."); + } + } + + private List getPolicyTypeList(ToscaServiceTemplate serviceTemplate) { + List policyTypeList = new ArrayList<>(); + if (serviceTemplate.getPolicyTypes() != null) { + for (var policyType : serviceTemplate.getPolicyTypes().values()) { + policyTypeList.add(policyType.getKey().asIdentifier()); } - if (automationCompositionDefinition.getToscaTopologyTemplate().getPolicies() != null) { - for (var gotPolicyMap : automationCompositionDefinition.getToscaTopologyTemplate().getPolicies()) { - for (ToscaPolicy policy : gotPolicyMap.values()) { - policyMap.put(policy.getName(), policy.getVersion()); - } + } + + return policyTypeList; + } + + private List getPolicyList(ToscaServiceTemplate serviceTemplate) { + List policyList = new ArrayList<>(); + if (serviceTemplate.getToscaTopologyTemplate().getPolicies() != null) { + for (var gotPolicyMap : serviceTemplate.getToscaTopologyTemplate().getPolicies()) { + for (var policy : gotPolicyMap.values()) { + policyList.add(policy.getKey().asIdentifier()); } - LOGGER.info("Found Policies in automation composition definition: {} , Creating Policies", - automationCompositionDefinition.getName()); - createPolicyResp = apiHttpClient.createPolicy(automationCompositionDefinition).getStatus(); - } - if (createPolicyTypeResp == HttpStatus.SC_OK && createPolicyResp == HttpStatus.SC_OK) { - LOGGER.info("PolicyTypes/Policies for the automation composition element : {} are created " - + "successfully", element.getId()); - deployPolicies(automationCompositionId, element.getId()); - } else { - LOGGER.error("Creation of PolicyTypes/Policies failed. Policies will not be deployed."); } } + + return policyList; } } diff --git a/participant/participant-impl/participant-impl-policy/src/test/java/org/onap/policy/clamp/acm/participant/policy/main/handler/AutomationCompositionElementHandlerTest.java b/participant/participant-impl/participant-impl-policy/src/test/java/org/onap/policy/clamp/acm/participant/policy/main/handler/AutomationCompositionElementHandlerTest.java index e0b4a69c2..47c279988 100644 --- a/participant/participant-impl/participant-impl-policy/src/test/java/org/onap/policy/clamp/acm/participant/policy/main/handler/AutomationCompositionElementHandlerTest.java +++ b/participant/participant-impl/participant-impl-policy/src/test/java/org/onap/policy/clamp/acm/participant/policy/main/handler/AutomationCompositionElementHandlerTest.java @@ -20,20 +20,23 @@ package org.onap.policy.clamp.acm.participant.policy.main.handler; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; import java.util.List; import java.util.Map; import java.util.UUID; import javax.ws.rs.core.Response; import org.junit.jupiter.api.Test; -import org.mockito.Mockito; import org.onap.policy.clamp.acm.participant.intermediary.api.ParticipantIntermediaryApi; import org.onap.policy.clamp.acm.participant.policy.client.PolicyApiHttpClient; import org.onap.policy.clamp.acm.participant.policy.client.PolicyPapHttpClient; import org.onap.policy.clamp.models.acm.concepts.AcElementDeploy; +import org.onap.policy.clamp.models.acm.concepts.DeployState; +import org.onap.policy.clamp.models.acm.concepts.LockState; import org.onap.policy.clamp.models.acm.messages.rest.instantiation.DeployOrder; import org.onap.policy.models.base.PfModelException; import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; @@ -50,21 +53,16 @@ class AutomationCompositionElementHandlerTest { public static final UUID AC_ID = UUID.randomUUID(); private static final ToscaConceptIdentifier DEFINITION = new ToscaConceptIdentifier(ID_NAME, ID_VERSION); - private PolicyApiHttpClient api = Mockito.mock(PolicyApiHttpClient.class); - private PolicyPapHttpClient pap = Mockito.mock(PolicyPapHttpClient.class); - @Test - void testHandlerDoesNotThrowExceptions() { - var handler = getTestingHandler(); - - assertDoesNotThrow(() -> handler.undeploy(AC_ID, automationCompositionElementId)); - } - - private AutomationCompositionElementHandler getTestingHandler() { - var handler = new AutomationCompositionElementHandler(api, pap); - var intermediaryApi = Mockito.mock(ParticipantIntermediaryApi.class); + void testHandlerUndeploy() throws PfModelException { + var handler = new AutomationCompositionElementHandler(mock(PolicyApiHttpClient.class), + mock(PolicyPapHttpClient.class)); + var intermediaryApi = mock(ParticipantIntermediaryApi.class); handler.setIntermediaryApi(intermediaryApi); - return handler; + + handler.undeploy(AC_ID, automationCompositionElementId); + verify(intermediaryApi).updateAutomationCompositionElementState(AC_ID, automationCompositionElementId, + DeployState.UNDEPLOYED, LockState.NONE); } private AcElementDeploy getTestingAcElement() { @@ -81,25 +79,58 @@ class AutomationCompositionElementHandlerTest { } @Test - void testAcElementUpdate() throws PfModelException { + void testDeploy() throws PfModelException { // Mock success scenario for policy creation and deployment + var api = mock(PolicyApiHttpClient.class); doReturn(Response.ok().build()).when(api).createPolicyType(any()); doReturn(Response.ok().build()).when(api).createPolicy(any()); + + var pap = mock(PolicyPapHttpClient.class); + doReturn(Response.accepted().build()).when(pap).handlePolicyDeployOrUndeploy(any(), any(), any()); + + var handler = new AutomationCompositionElementHandler(api, pap); + var intermediaryApi = mock(ParticipantIntermediaryApi.class); + handler.setIntermediaryApi(intermediaryApi); + + handler.deploy(AC_ID, getTestingAcElement(), Map.of()); + handler.undeploy(AC_ID, automationCompositionElementId); + verify(intermediaryApi).updateAutomationCompositionElementState(AC_ID, automationCompositionElementId, + DeployState.UNDEPLOYED, LockState.NONE); + } + + @Test + void testApiException() throws PfModelException { + var api = mock(PolicyApiHttpClient.class); + doReturn(Response.serverError().build()).when(api).createPolicyType(any()); + doReturn(Response.ok().build()).when(api).createPolicy(any()); + + var pap = mock(PolicyPapHttpClient.class); doReturn(Response.accepted().build()).when(pap).handlePolicyDeployOrUndeploy(any(), any(), any()); - var handler = getTestingHandler(); + var handler = new AutomationCompositionElementHandler(api, pap); + var intermediaryApi = mock(ParticipantIntermediaryApi.class); + handler.setIntermediaryApi(intermediaryApi); var element = getTestingAcElement(); - assertDoesNotThrow(() -> handler.deploy(AC_ID, element, Map.of())); + // Mock failure in policy type creation + assertThatThrownBy(() -> handler.deploy(AC_ID, element, Map.of())) + .hasMessageMatching("Creation of PolicyTypes/Policies failed. Policies will not be deployed."); + } - assertDoesNotThrow(() -> handler.undeploy(AC_ID, automationCompositionElementId)); + @Test + void testDeployPapException() throws PfModelException { + var api = mock(PolicyApiHttpClient.class); + doReturn(Response.ok().build()).when(api).createPolicyType(any()); + doReturn(Response.ok().build()).when(api).createPolicy(any()); - // Mock failure in policy deployment + var pap = mock(PolicyPapHttpClient.class); doReturn(Response.serverError().build()).when(pap).handlePolicyDeployOrUndeploy(any(), any(), any()); - assertDoesNotThrow(() -> handler.deploy(AC_ID, element, Map.of())); - // Mock failure in policy type creation - doReturn(Response.serverError().build()).when(api).createPolicyType(any()); - assertDoesNotThrow(() -> handler.deploy(AC_ID, element, Map.of())); + var handler = new AutomationCompositionElementHandler(api, pap); + var intermediaryApi = mock(ParticipantIntermediaryApi.class); + handler.setIntermediaryApi(intermediaryApi); + var element = getTestingAcElement(); + assertThatThrownBy(() -> handler.deploy(AC_ID, element, Map.of())) + .hasMessageMatching("Deploy of Policy failed."); } } -- cgit 1.2.3-korg