5a3bc6328d4ade313cb3df3f3ef93860a627862a
[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 org.apache.http.HttpStatus;
31 import org.onap.policy.clamp.acm.participant.intermediary.api.CompositionElementDto;
32 import org.onap.policy.clamp.acm.participant.intermediary.api.InstanceElementDto;
33 import org.onap.policy.clamp.acm.participant.intermediary.api.ParticipantIntermediaryApi;
34 import org.onap.policy.clamp.acm.participant.intermediary.api.impl.AcElementListenerV2;
35 import org.onap.policy.clamp.acm.participant.policy.client.PolicyApiHttpClient;
36 import org.onap.policy.clamp.acm.participant.policy.client.PolicyPapHttpClient;
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 AcElementListenerV2 {
52
53     private static final Logger LOGGER = LoggerFactory.getLogger(AutomationCompositionElementHandler.class);
54
55     private final PolicyApiHttpClient apiHttpClient;
56     private final PolicyPapHttpClient papHttpClient;
57
58     /**
59      * Constructor.
60      *
61      * @param apiHttpClient the PolicyApi Http Client
62      * @param papHttpClient the Policy Pap Http Client
63      * @param intermediaryApi the Participant Intermediary Api
64      */
65     public AutomationCompositionElementHandler(PolicyApiHttpClient apiHttpClient, PolicyPapHttpClient papHttpClient,
66         ParticipantIntermediaryApi intermediaryApi) {
67         super(intermediaryApi);
68         this.apiHttpClient = apiHttpClient;
69         this.papHttpClient = papHttpClient;
70     }
71
72     /**
73      * Callback method to handle a automation composition element state change.
74      *
75      * @param compositionElement the information of the Automation Composition Definition Element
76      * @param instanceElement the information of the Automation Composition Instance Element
77      * @throws PfModelException in case of a model exception
78      */
79     @Override
80     public void undeploy(CompositionElementDto compositionElement, InstanceElementDto instanceElement)
81             throws PfModelException {
82         var automationCompositionDefinition = instanceElement.toscaServiceTemplateFragment();
83         if (automationCompositionDefinition.getToscaTopologyTemplate() == null) {
84             LOGGER.debug("No policies to undeploy to {}", instanceElement.elementId());
85             intermediaryApi.updateAutomationCompositionElementState(instanceElement.instanceId(),
86                     instanceElement.elementId(), DeployState.UNDEPLOYED, null, StateChangeResult.NO_ERROR,
87                     "Undeployed");
88             return;
89         }
90         var policyList = getPolicyList(automationCompositionDefinition);
91         undeployPolicies(policyList, instanceElement.elementId());
92         var policyTypeList = getPolicyTypeList(automationCompositionDefinition);
93         deletePolicyData(policyTypeList, policyList);
94         intermediaryApi.updateAutomationCompositionElementState(instanceElement.instanceId(),
95                 instanceElement.elementId(), DeployState.UNDEPLOYED, null, StateChangeResult.NO_ERROR,
96                 "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 compositionElement the information of the Automation Composition Definition Element
155      * @param instanceElement the information of the Automation Composition Instance Element
156      * @throws PfModelException from Policy framework
157      */
158     @Override
159     public void deploy(CompositionElementDto compositionElement, InstanceElementDto instanceElement)
160             throws PfModelException {
161         var createPolicyTypeResp = HttpStatus.SC_OK;
162         var createPolicyResp = HttpStatus.SC_OK;
163
164         var automationCompositionDefinition = instanceElement.toscaServiceTemplateFragment();
165         if (automationCompositionDefinition.getToscaTopologyTemplate() == null) {
166             intermediaryApi.updateAutomationCompositionElementState(instanceElement.instanceId(),
167                     instanceElement.elementId(), DeployState.UNDEPLOYED, null, StateChangeResult.FAILED,
168                     "ToscaTopologyTemplate not defined");
169             return;
170         }
171         if (automationCompositionDefinition.getPolicyTypes() != null) {
172             LOGGER.info("Found Policy Types in automation composition definition: {} , Creating Policy Types",
173                     automationCompositionDefinition.getName());
174             try (var response = apiHttpClient.createPolicyType(automationCompositionDefinition)) {
175                 createPolicyTypeResp = response.getStatus();
176             }
177         }
178         if (automationCompositionDefinition.getToscaTopologyTemplate().getPolicies() != null) {
179             LOGGER.info("Found Policies in automation composition definition: {} , Creating Policies",
180                     automationCompositionDefinition.getName());
181             try (var response = apiHttpClient.createPolicy(automationCompositionDefinition)) {
182                 createPolicyResp = response.getStatus();
183             }
184         }
185         if (isSuccess(createPolicyTypeResp) && isSuccess(createPolicyResp)) {
186             LOGGER.info(
187                     "PolicyTypes/Policies for the automation composition element : {} are created " + "successfully",
188                     instanceElement.elementId());
189             var policyList = getPolicyList(automationCompositionDefinition);
190             deployPolicies(policyList, instanceElement.instanceId(), instanceElement.elementId());
191         } else {
192             intermediaryApi.updateAutomationCompositionElementState(instanceElement.instanceId(),
193                     instanceElement.elementId(), DeployState.UNDEPLOYED, null, StateChangeResult.FAILED,
194                     "Creation of PolicyTypes/Policies failed. Policies will not be deployed.");
195         }
196     }
197
198     private boolean isSuccess(int status) {
199         return status == HttpStatus.SC_OK || status == HttpStatus.SC_CREATED;
200     }
201
202     private List<ToscaConceptIdentifier> getPolicyTypeList(ToscaServiceTemplate serviceTemplate) {
203         List<ToscaConceptIdentifier> policyTypeList = new ArrayList<>();
204         if (serviceTemplate.getPolicyTypes() != null) {
205             for (var policyType : serviceTemplate.getPolicyTypes().values()) {
206                 policyTypeList.add(policyType.getKey().asIdentifier());
207             }
208         }
209
210         return policyTypeList;
211     }
212
213     private List<ToscaConceptIdentifier> getPolicyList(ToscaServiceTemplate serviceTemplate) {
214         List<ToscaConceptIdentifier> policyList = new ArrayList<>();
215         if (serviceTemplate.getToscaTopologyTemplate().getPolicies() != null) {
216             for (var gotPolicyMap : serviceTemplate.getToscaTopologyTemplate().getPolicies()) {
217                 for (var policy : gotPolicyMap.values()) {
218                     policyList.add(policy.getKey().asIdentifier());
219                 }
220             }
221         }
222
223         return policyList;
224     }
225 }