0daf6e45bdcea5d230913face06440088c7c3222
[policy/clamp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2021-2025 OpenInfra Foundation Europe. All rights reserved.
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 org.onap.policy.clamp.acm.participant.intermediary.api.CompositionElementDto;
31 import org.onap.policy.clamp.acm.participant.intermediary.api.InstanceElementDto;
32 import org.onap.policy.clamp.acm.participant.intermediary.api.ParticipantIntermediaryApi;
33 import org.onap.policy.clamp.acm.participant.intermediary.api.impl.AcElementListenerV3;
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.acm.participant.policy.concepts.DeploymentSubGroup;
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.common.utils.coder.Coder;
40 import org.onap.policy.common.utils.coder.CoderException;
41 import org.onap.policy.common.utils.coder.StandardCoder;
42 import org.onap.policy.models.base.PfModelException;
43 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
44 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47 import org.springframework.stereotype.Component;
48 import org.springframework.web.reactive.function.client.WebClientResponseException;
49
50 /**
51  * This class handles implementation of automationCompositionElement updates.
52  */
53 @Component
54 public class AutomationCompositionElementHandler extends AcElementListenerV3 {
55
56     private static final Logger LOGGER = LoggerFactory.getLogger(AutomationCompositionElementHandler.class);
57     private static final Coder CODER = new StandardCoder();
58
59     private final PolicyApiHttpClient apiHttpClient;
60     private final PolicyPapHttpClient papHttpClient;
61
62     /**
63      * Constructor.
64      *
65      * @param apiHttpClient the PolicyApi Http Client
66      * @param papHttpClient the Policy Pap Http Client
67      * @param intermediaryApi the Participant Intermediary Api
68      */
69     public AutomationCompositionElementHandler(PolicyApiHttpClient apiHttpClient, PolicyPapHttpClient papHttpClient,
70         ParticipantIntermediaryApi intermediaryApi) {
71         super(intermediaryApi);
72         this.apiHttpClient = apiHttpClient;
73         this.papHttpClient = papHttpClient;
74     }
75
76     /**
77      * Callback method to handle a automation composition element state change.
78      *
79      * @param compositionElement the information of the Automation Composition Definition Element
80      * @param instanceElement the information of the Automation Composition Instance Element
81      * @throws PfModelException in case of a model exception
82      */
83     @Override
84     public void undeploy(CompositionElementDto compositionElement, InstanceElementDto instanceElement)
85             throws PfModelException {
86         var automationCompositionDefinition = getToscaServiceTemplate(instanceElement.inProperties());
87         if (automationCompositionDefinition.getToscaTopologyTemplate() == null) {
88             LOGGER.debug("No policies to undeploy to {}", instanceElement.elementId());
89             intermediaryApi.updateAutomationCompositionElementState(instanceElement.instanceId(),
90                     instanceElement.elementId(), DeployState.UNDEPLOYED, null, StateChangeResult.NO_ERROR,
91                     "Undeployed");
92             return;
93         }
94         var policyList = getPolicyList(automationCompositionDefinition);
95         undeployPolicies(policyList, instanceElement.elementId());
96         var policyTypeList = getPolicyTypeList(automationCompositionDefinition);
97         deletePolicyData(policyTypeList, policyList);
98         intermediaryApi.updateAutomationCompositionElementState(instanceElement.instanceId(),
99                 instanceElement.elementId(), DeployState.UNDEPLOYED, null, StateChangeResult.NO_ERROR,
100                 "Undeployed");
101     }
102
103     private void deletePolicyData(List<ToscaConceptIdentifier> policyTypeList,
104             List<ToscaConceptIdentifier> policyList) {
105         // Delete all policies of this automationComposition from policy framework
106         for (var policy : policyList) {
107             apiHttpClient.deletePolicy(policy.getName(), policy.getVersion());
108         }
109         // Delete all policy types of this automation composition from policy framework
110         for (var policyType : policyTypeList) {
111             apiHttpClient.deletePolicyType(policyType.getName(), policyType.getVersion());
112         }
113     }
114
115     private void deployPolicies(List<ToscaConceptIdentifier> policyList, UUID automationCompositionId,
116             UUID automationCompositionElementId) throws PfModelException {
117         var deployFailure = false;
118         // Deploy all policies of this automationComposition from Policy Framework
119         if (!policyList.isEmpty()) {
120             for (var policy : policyList) {
121                 try {
122                     papHttpClient.handlePolicyDeployOrUndeploy(policy.getName(), policy.getVersion(),
123                             DeploymentSubGroup.Action.POST);
124                 } catch (WebClientResponseException e) {
125                     LOGGER.error(e.getMessage(), e);
126                     deployFailure = true;
127                 }
128             }
129             LOGGER.info("Policies deployed to {} successfully", automationCompositionElementId);
130         } else {
131             LOGGER.debug("No policies to deploy to {}", automationCompositionElementId);
132         }
133         if (!deployFailure) {
134             // Update the AC element state
135             intermediaryApi.sendAcElementInfo(automationCompositionId, automationCompositionElementId, "IDLE",
136                     "ENABLED", Map.of());
137             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId,
138                     automationCompositionElementId, DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Deployed");
139         } else {
140             throw new PfModelException(Status.BAD_REQUEST, "Deploy of Policy failed.");
141         }
142     }
143
144     private void undeployPolicies(List<ToscaConceptIdentifier> policyList, UUID automationCompositionElementId) {
145         // Undeploy all policies of this automation composition from Policy Framework
146         if (!policyList.isEmpty()) {
147             for (var policy : policyList) {
148                 papHttpClient.handlePolicyDeployOrUndeploy(policy.getName(), policy.getVersion(),
149                         DeploymentSubGroup.Action.DELETE);
150             }
151             LOGGER.debug("Undeployed policies from {} successfully", automationCompositionElementId);
152         } else {
153             LOGGER.debug("No policies are deployed to {}", automationCompositionElementId);
154         }
155     }
156
157     /**
158      * Callback method to handle an update on automation composition element.
159      *
160      * @param compositionElement the information of the Automation Composition Definition Element
161      * @param instanceElement the information of the Automation Composition Instance Element
162      * @throws PfModelException from Policy framework
163      */
164     @Override
165     public void deploy(CompositionElementDto compositionElement, InstanceElementDto instanceElement)
166             throws PfModelException {
167         var createPolicyTypeResp = true;
168         var createPolicyResp = true;
169
170         var automationCompositionDefinition = getToscaServiceTemplate(instanceElement.inProperties());
171         if (automationCompositionDefinition.getToscaTopologyTemplate() == null) {
172             intermediaryApi.updateAutomationCompositionElementState(instanceElement.instanceId(),
173                     instanceElement.elementId(), DeployState.UNDEPLOYED, null, StateChangeResult.FAILED,
174                     "ToscaTopologyTemplate not defined");
175             return;
176         }
177         if (automationCompositionDefinition.getPolicyTypes() != null) {
178             LOGGER.info("Found Policy Types in automation composition definition: {} , Creating Policy Types",
179                     automationCompositionDefinition.getName());
180             try {
181                 apiHttpClient.createPolicyType(automationCompositionDefinition);
182             } catch (WebClientResponseException e) {
183                 LOGGER.error(e.getMessage(), e);
184                 createPolicyTypeResp = false;
185             }
186         }
187         if (automationCompositionDefinition.getToscaTopologyTemplate().getPolicies() != null) {
188             LOGGER.info("Found Policies in automation composition definition: {} , Creating Policies",
189                     automationCompositionDefinition.getName());
190             try {
191                 apiHttpClient.createPolicy(automationCompositionDefinition);
192             } catch (WebClientResponseException e) {
193                 LOGGER.error(e.getMessage(), e);
194                 createPolicyResp = false;
195             }
196         }
197         if (createPolicyTypeResp && createPolicyResp) {
198             LOGGER.info(
199                     "PolicyTypes/Policies for the automation composition element : {} are created " + "successfully",
200                     instanceElement.elementId());
201             var policyList = getPolicyList(automationCompositionDefinition);
202             deployPolicies(policyList, instanceElement.instanceId(), instanceElement.elementId());
203         } else {
204             intermediaryApi.updateAutomationCompositionElementState(instanceElement.instanceId(),
205                     instanceElement.elementId(), DeployState.UNDEPLOYED, null, StateChangeResult.FAILED,
206                     "Creation of PolicyTypes/Policies failed. Policies will not be deployed.");
207         }
208     }
209
210     private List<ToscaConceptIdentifier> getPolicyTypeList(ToscaServiceTemplate serviceTemplate) {
211         List<ToscaConceptIdentifier> policyTypeList = new ArrayList<>();
212         if (serviceTemplate.getPolicyTypes() != null) {
213             for (var policyType : serviceTemplate.getPolicyTypes().values()) {
214                 policyTypeList.add(policyType.getKey().asIdentifier());
215             }
216         }
217
218         return policyTypeList;
219     }
220
221     private List<ToscaConceptIdentifier> getPolicyList(ToscaServiceTemplate serviceTemplate) {
222         List<ToscaConceptIdentifier> policyList = new ArrayList<>();
223         if (serviceTemplate.getToscaTopologyTemplate().getPolicies() != null) {
224             for (var gotPolicyMap : serviceTemplate.getToscaTopologyTemplate().getPolicies()) {
225                 for (var policy : gotPolicyMap.values()) {
226                     policyList.add(policy.getKey().asIdentifier());
227                 }
228             }
229         }
230
231         return policyList;
232     }
233
234     private ToscaServiceTemplate getToscaServiceTemplate(Map<String, Object> properties) throws PfModelException {
235         try {
236             return  CODER.convert(properties, ToscaServiceTemplate.class);
237         } catch (CoderException e) {
238             throw new PfModelException(Status.BAD_REQUEST, e.getMessage());
239         }
240     }
241 }