ae906e1efa65718cfa9ae23ef76558ec5680acd3
[policy/clamp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2021-2024 Nordix Foundation.
4  * ================================================================================
5  * Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  * SPDX-License-Identifier: Apache-2.0
20  * ============LICENSE_END=========================================================
21  */
22
23 package org.onap.policy.clamp.acm.participant.policy.main.handler;
24
25 import jakarta.ws.rs.core.Response.Status;
26 import java.util.ArrayList;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.UUID;
30 import java.util.concurrent.ConcurrentHashMap;
31 import org.apache.http.HttpStatus;
32 import org.onap.policy.clamp.acm.participant.intermediary.api.ParticipantIntermediaryApi;
33 import org.onap.policy.clamp.acm.participant.intermediary.api.impl.AcElementListenerV1;
34 import org.onap.policy.clamp.acm.participant.policy.client.PolicyApiHttpClient;
35 import org.onap.policy.clamp.acm.participant.policy.client.PolicyPapHttpClient;
36 import org.onap.policy.clamp.models.acm.concepts.AcElementDeploy;
37 import org.onap.policy.clamp.models.acm.concepts.DeployState;
38 import org.onap.policy.clamp.models.acm.concepts.StateChangeResult;
39 import org.onap.policy.models.base.PfModelException;
40 import org.onap.policy.models.pdp.concepts.DeploymentSubGroup;
41 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
42 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45 import org.springframework.stereotype.Component;
46
47 /**
48  * This class handles implementation of automationCompositionElement updates.
49  */
50 @Component
51 public class AutomationCompositionElementHandler extends AcElementListenerV1 {
52
53     private static final Logger LOGGER = LoggerFactory.getLogger(AutomationCompositionElementHandler.class);
54
55     private final Map<UUID, ToscaServiceTemplate> serviceTemplateMap = new ConcurrentHashMap<>();
56
57     private final PolicyApiHttpClient apiHttpClient;
58     private final PolicyPapHttpClient papHttpClient;
59
60     /**
61      * Constructor.
62      *
63      * @param apiHttpClient the PolicyApi Http Client
64      * @param papHttpClient the Policy Pap Http Client
65      * @param intermediaryApi the Participant Intermediary Api
66      */
67     public AutomationCompositionElementHandler(PolicyApiHttpClient apiHttpClient, PolicyPapHttpClient papHttpClient,
68         ParticipantIntermediaryApi intermediaryApi) {
69         super(intermediaryApi);
70         this.apiHttpClient = apiHttpClient;
71         this.papHttpClient = papHttpClient;
72     }
73
74     /**
75      * Callback method to handle a automation composition element state change.
76      *
77      * @param automationCompositionId the ID of the automation composition
78      * @param automationCompositionElementId the ID of the automation composition element
79      */
80     @Override
81     public void undeploy(UUID automationCompositionId, UUID automationCompositionElementId) throws PfModelException {
82         var automationCompositionDefinition = serviceTemplateMap.get(automationCompositionElementId);
83         if (automationCompositionDefinition == null) {
84             LOGGER.debug("No policies to undeploy to {}", automationCompositionElementId);
85             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId,
86                     automationCompositionElementId, DeployState.UNDEPLOYED, null, StateChangeResult.NO_ERROR,
87                     "Undeployed");
88             return;
89         }
90         var policyList = getPolicyList(automationCompositionDefinition);
91         undeployPolicies(policyList, automationCompositionElementId);
92         var policyTypeList = getPolicyTypeList(automationCompositionDefinition);
93         deletePolicyData(policyTypeList, policyList);
94         serviceTemplateMap.remove(automationCompositionElementId);
95         intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, automationCompositionElementId,
96                 DeployState.UNDEPLOYED, null, StateChangeResult.NO_ERROR, "Undeployed");
97     }
98
99     private void deletePolicyData(List<ToscaConceptIdentifier> policyTypeList,
100             List<ToscaConceptIdentifier> policyList) {
101         // Delete all policies of this automationComposition from policy framework
102         for (var policy : policyList) {
103             apiHttpClient.deletePolicy(policy.getName(), policy.getVersion());
104         }
105         // Delete all policy types of this automation composition from policy framework
106         for (var policyType : policyTypeList) {
107             apiHttpClient.deletePolicyType(policyType.getName(), policyType.getVersion());
108         }
109     }
110
111     private void deployPolicies(List<ToscaConceptIdentifier> policyList, UUID automationCompositionId,
112             UUID automationCompositionElementId) throws PfModelException {
113         var deployFailure = false;
114         // Deploy all policies of this automationComposition from Policy Framework
115         if (!policyList.isEmpty()) {
116             for (var policy : policyList) {
117                 var deployPolicyResp = papHttpClient.handlePolicyDeployOrUndeploy(policy.getName(), policy.getVersion(),
118                         DeploymentSubGroup.Action.POST).getStatus();
119                 if (deployPolicyResp != HttpStatus.SC_ACCEPTED) {
120                     deployFailure = true;
121                 }
122             }
123             LOGGER.info("Policies deployed to {} successfully", automationCompositionElementId);
124         } else {
125             LOGGER.debug("No policies to deploy to {}", automationCompositionElementId);
126         }
127         if (!deployFailure) {
128             // Update the AC element state
129             intermediaryApi.sendAcElementInfo(automationCompositionId, automationCompositionElementId, "IDLE",
130                     "ENABLED", Map.of());
131             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId,
132                     automationCompositionElementId, DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Deployed");
133         } else {
134             throw new PfModelException(Status.BAD_REQUEST, "Deploy of Policy failed.");
135         }
136     }
137
138     private void undeployPolicies(List<ToscaConceptIdentifier> policyList, UUID automationCompositionElementId) {
139         // Undeploy all policies of this automation composition from Policy Framework
140         if (!policyList.isEmpty()) {
141             for (var policy : policyList) {
142                 papHttpClient.handlePolicyDeployOrUndeploy(policy.getName(), policy.getVersion(),
143                         DeploymentSubGroup.Action.DELETE);
144             }
145             LOGGER.debug("Undeployed policies from {} successfully", automationCompositionElementId);
146         } else {
147             LOGGER.debug("No policies are deployed to {}", automationCompositionElementId);
148         }
149     }
150
151     /**
152      * Callback method to handle an update on automation composition element.
153      *
154      * @param automationCompositionId the automationComposition Id
155      * @param element the information on the automation composition element
156      * @param properties properties Map
157      * @throws PfModelException in case of an exception
158      */
159     @Override
160     public void deploy(UUID automationCompositionId, AcElementDeploy element, Map<String, Object> properties)
161             throws PfModelException {
162         var createPolicyTypeResp = HttpStatus.SC_OK;
163         var createPolicyResp = HttpStatus.SC_OK;
164
165         var automationCompositionDefinition = element.getToscaServiceTemplateFragment();
166         if (automationCompositionDefinition.getToscaTopologyTemplate() == null) {
167             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, element.getId(),
168                     DeployState.UNDEPLOYED, null, StateChangeResult.FAILED, "ToscaTopologyTemplate not defined");
169             return;
170         }
171         serviceTemplateMap.put(element.getId(), automationCompositionDefinition);
172         if (automationCompositionDefinition.getPolicyTypes() != null) {
173             LOGGER.info("Found Policy Types in automation composition definition: {} , Creating Policy Types",
174                     automationCompositionDefinition.getName());
175             try (var response = apiHttpClient.createPolicyType(automationCompositionDefinition)) {
176                 createPolicyTypeResp = response.getStatus();
177             }
178         }
179         if (automationCompositionDefinition.getToscaTopologyTemplate().getPolicies() != null) {
180             LOGGER.info("Found Policies in automation composition definition: {} , Creating Policies",
181                     automationCompositionDefinition.getName());
182             try (var response = apiHttpClient.createPolicy(automationCompositionDefinition)) {
183                 createPolicyResp = response.getStatus();
184             }
185         }
186         if (createPolicyTypeResp == HttpStatus.SC_OK && createPolicyResp == HttpStatus.SC_OK) {
187             LOGGER.info(
188                     "PolicyTypes/Policies for the automation composition element : {} are created " + "successfully",
189                     element.getId());
190             var policyList = getPolicyList(automationCompositionDefinition);
191             deployPolicies(policyList, automationCompositionId, element.getId());
192         } else {
193             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, element.getId(),
194                     DeployState.UNDEPLOYED, null, StateChangeResult.FAILED,
195                     "Creation of PolicyTypes/Policies failed. Policies will not be deployed.");
196         }
197     }
198
199     private List<ToscaConceptIdentifier> getPolicyTypeList(ToscaServiceTemplate serviceTemplate) {
200         List<ToscaConceptIdentifier> policyTypeList = new ArrayList<>();
201         if (serviceTemplate.getPolicyTypes() != null) {
202             for (var policyType : serviceTemplate.getPolicyTypes().values()) {
203                 policyTypeList.add(policyType.getKey().asIdentifier());
204             }
205         }
206
207         return policyTypeList;
208     }
209
210     private List<ToscaConceptIdentifier> getPolicyList(ToscaServiceTemplate serviceTemplate) {
211         List<ToscaConceptIdentifier> policyList = new ArrayList<>();
212         if (serviceTemplate.getToscaTopologyTemplate().getPolicies() != null) {
213             for (var gotPolicyMap : serviceTemplate.getToscaTopologyTemplate().getPolicies()) {
214                 for (var policy : gotPolicyMap.values()) {
215                     policyList.add(policy.getKey().asIdentifier());
216                 }
217             }
218         }
219
220         return policyList;
221     }
222 }