0f230c0a441fd67481d3f37760aa89d237d3f629
[policy/clamp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2021-2024 Nordix Foundation.
4  *  Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
5  * ================================================================================
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * SPDX-License-Identifier: Apache-2.0
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.onap.policy.clamp.acm.participant.intermediary.handler;
23
24 import java.util.List;
25 import java.util.UUID;
26 import lombok.RequiredArgsConstructor;
27 import org.onap.policy.clamp.acm.participant.intermediary.api.InstanceElementDto;
28 import org.onap.policy.clamp.acm.participant.intermediary.comm.ParticipantMessagePublisher;
29 import org.onap.policy.clamp.models.acm.concepts.AcElementDeploy;
30 import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
31 import org.onap.policy.clamp.models.acm.concepts.DeployState;
32 import org.onap.policy.clamp.models.acm.concepts.ParticipantDeploy;
33 import org.onap.policy.clamp.models.acm.concepts.ParticipantUtils;
34 import org.onap.policy.clamp.models.acm.concepts.StateChangeResult;
35 import org.onap.policy.clamp.models.acm.concepts.SubState;
36 import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionDeploy;
37 import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionDeployAck;
38 import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionMigration;
39 import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionStateChange;
40 import org.onap.policy.clamp.models.acm.messages.kafka.participant.ParticipantMessageType;
41 import org.onap.policy.clamp.models.acm.messages.kafka.participant.PropertiesUpdate;
42 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.DeployOrder;
43 import org.onap.policy.clamp.models.acm.utils.AcmUtils;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46 import org.springframework.stereotype.Component;
47
48 /*
49  * This class is responsible for managing the state of all automation compositions in the participant.
50  */
51 @Component
52 @RequiredArgsConstructor
53 public class AutomationCompositionHandler {
54     private static final Logger LOGGER = LoggerFactory.getLogger(AutomationCompositionHandler.class);
55
56     private final CacheProvider cacheProvider;
57     private final ParticipantMessagePublisher publisher;
58     private final ThreadHandler listener;
59
60     /**
61      * Handle a automation composition state change message.
62      *
63      * @param stateChangeMsg the state change message
64      */
65     public void handleAutomationCompositionStateChange(AutomationCompositionStateChange stateChangeMsg) {
66         if (stateChangeMsg.getAutomationCompositionId() == null) {
67             return;
68         }
69
70         var automationComposition = cacheProvider.getAutomationComposition(stateChangeMsg.getAutomationCompositionId());
71
72         if (automationComposition == null) {
73             if (DeployOrder.DELETE.equals(stateChangeMsg.getDeployOrderedState())) {
74                 var automationCompositionAck = new AutomationCompositionDeployAck(
75                         ParticipantMessageType.AUTOMATION_COMPOSITION_STATECHANGE_ACK);
76                 automationCompositionAck.setParticipantId(cacheProvider.getParticipantId());
77                 automationCompositionAck.setReplicaId(cacheProvider.getReplicaId());
78                 automationCompositionAck.setMessage("Already deleted or never used");
79                 automationCompositionAck.setResult(true);
80                 automationCompositionAck.setStateChangeResult(StateChangeResult.NO_ERROR);
81                 automationCompositionAck.setResponseTo(stateChangeMsg.getMessageId());
82                 automationCompositionAck.setAutomationCompositionId(stateChangeMsg.getAutomationCompositionId());
83                 publisher.sendAutomationCompositionAck(automationCompositionAck);
84             } else {
85                 LOGGER.debug("Automation composition {} does not use this participant",
86                         stateChangeMsg.getAutomationCompositionId());
87             }
88             return;
89         }
90
91         switch (stateChangeMsg.getDeployOrderedState()) {
92             case UNDEPLOY -> handleUndeployState(stateChangeMsg.getMessageId(), automationComposition,
93                     stateChangeMsg.getStartPhase());
94             case DELETE -> handleDeleteState(stateChangeMsg.getMessageId(), automationComposition,
95                     stateChangeMsg.getStartPhase());
96             default ->
97                     LOGGER.error("StateChange message has no state, state is null {}", automationComposition.getKey());
98         }
99     }
100
101     /**
102      * Handle a automation composition properties update message.
103      *
104      * @param updateMsg the properties update message
105      */
106     public void handleAcPropertyUpdate(PropertiesUpdate updateMsg) {
107
108         if (updateMsg.getParticipantUpdatesList().isEmpty()) {
109             LOGGER.warn("No AutomationCompositionElement updates in message {}",
110                     updateMsg.getAutomationCompositionId());
111             return;
112         }
113
114         for (var participantDeploy : updateMsg.getParticipantUpdatesList()) {
115             if (cacheProvider.getParticipantId().equals(participantDeploy.getParticipantId())) {
116                 var automationComposition = cacheProvider.getAutomationComposition(
117                         updateMsg.getAutomationCompositionId());
118                 automationComposition.setDeployState(DeployState.UPDATING);
119                 var acCopy = new AutomationComposition(automationComposition);
120                 updateExistingElementsOnThisParticipant(updateMsg.getAutomationCompositionId(), participantDeploy,
121                         DeployState.UPDATING);
122
123                 callParticipantUpdateProperty(updateMsg.getMessageId(), participantDeploy.getAcElementList(), acCopy);
124             }
125         }
126     }
127
128     /**
129      * Handle a automation composition Deploy message.
130      *
131      * @param deployMsg the Deploy message
132      */
133     public void handleAutomationCompositionDeploy(AutomationCompositionDeploy deployMsg) {
134
135         if (deployMsg.getParticipantUpdatesList().isEmpty()) {
136             LOGGER.warn("No AutomationCompositionElement deploy in message {}", deployMsg.getAutomationCompositionId());
137             return;
138         }
139
140         for (var participantDeploy : deployMsg.getParticipantUpdatesList()) {
141             if (cacheProvider.getParticipantId().equals(participantDeploy.getParticipantId())) {
142                 if (deployMsg.isFirstStartPhase()) {
143                     cacheProvider.initializeAutomationComposition(deployMsg.getCompositionId(),
144                             deployMsg.getAutomationCompositionId(), participantDeploy);
145                 }
146                 callParticipanDeploy(deployMsg.getMessageId(), participantDeploy.getAcElementList(),
147                         deployMsg.getStartPhase(), deployMsg.getAutomationCompositionId());
148             }
149         }
150     }
151
152     private void callParticipanDeploy(UUID messageId, List<AcElementDeploy> acElementDeployList,
153             Integer startPhaseMsg, UUID instanceId) {
154         var automationComposition = cacheProvider.getAutomationComposition(instanceId);
155         automationComposition.setDeployState(DeployState.DEPLOYING);
156         for (var elementDeploy : acElementDeployList) {
157             var element = automationComposition.getElements().get(elementDeploy.getId());
158             var compositionInProperties = cacheProvider
159                 .getCommonProperties(automationComposition.getCompositionId(), element.getDefinition());
160             int startPhase = ParticipantUtils.findStartPhase(compositionInProperties);
161             if (startPhaseMsg.equals(startPhase)) {
162                 var compositionElement = cacheProvider.createCompositionElementDto(
163                         automationComposition.getCompositionId(), element, compositionInProperties);
164                 var instanceElement = new InstanceElementDto(instanceId, elementDeploy.getId(),
165                     elementDeploy.getToscaServiceTemplateFragment(),
166                     elementDeploy.getProperties(), element.getOutProperties());
167                 listener.deploy(messageId, compositionElement, instanceElement);
168             }
169         }
170     }
171
172     private void callParticipantUpdateProperty(UUID messageId, List<AcElementDeploy> acElements,
173         AutomationComposition acCopy) {
174         var instanceElementDtoMap = cacheProvider.getInstanceElementDtoMap(acCopy);
175         var instanceElementDtoMapUpdated = cacheProvider.getInstanceElementDtoMap(
176             cacheProvider.getAutomationComposition(acCopy.getInstanceId()));
177         var compositionElementDtoMap = cacheProvider.getCompositionElementDtoMap(acCopy);
178         for (var acElement : acElements) {
179             listener.update(messageId, compositionElementDtoMap.get(acElement.getId()),
180                 instanceElementDtoMap.get(acElement.getId()), instanceElementDtoMapUpdated.get(acElement.getId()));
181         }
182     }
183
184     private void updateExistingElementsOnThisParticipant(UUID instanceId, ParticipantDeploy participantDeploy,
185         DeployState deployState) {
186         var acElementList = cacheProvider.getAutomationComposition(instanceId).getElements();
187         for (var element : participantDeploy.getAcElementList()) {
188             var acElement = acElementList.get(element.getId());
189             AcmUtils.recursiveMerge(acElement.getProperties(), element.getProperties());
190             acElement.setDeployState(deployState);
191             acElement.setSubState(SubState.NONE);
192             acElement.setDefinition(element.getDefinition());
193         }
194     }
195
196     /**
197      * Method to handle when the new state from participant is UNINITIALISED state.
198      *
199      * @param messageId the messageId
200      * @param automationComposition participant response
201      * @param startPhaseMsg startPhase from message
202      */
203     private void handleUndeployState(UUID messageId, final AutomationComposition automationComposition,
204             Integer startPhaseMsg) {
205         automationComposition.setCompositionTargetId(null);
206         automationComposition.setDeployState(DeployState.UNDEPLOYING);
207         var serviceTemplateFragment = cacheProvider
208                 .getServiceTemplateFragmentMap().get(automationComposition.getCompositionId());
209         for (var element : automationComposition.getElements().values()) {
210             var compositionInProperties = cacheProvider
211                 .getCommonProperties(automationComposition.getCompositionId(), element.getDefinition());
212             int startPhase = ParticipantUtils.findStartPhase(compositionInProperties);
213             if (startPhaseMsg.equals(startPhase)) {
214                 element.setDeployState(DeployState.UNDEPLOYING);
215                 var compositionElement = cacheProvider.createCompositionElementDto(
216                         automationComposition.getCompositionId(), element, compositionInProperties);
217                 var instanceElement = new InstanceElementDto(automationComposition.getInstanceId(), element.getId(),
218                         serviceTemplateFragment, element.getProperties(), element.getOutProperties());
219                 listener.undeploy(messageId, compositionElement, instanceElement);
220             }
221         }
222     }
223
224     private void handleDeleteState(UUID messageId, final AutomationComposition automationComposition,
225             Integer startPhaseMsg) {
226         automationComposition.setDeployState(DeployState.DELETING);
227         var serviceTemplateFragment = cacheProvider
228                 .getServiceTemplateFragmentMap().get(automationComposition.getCompositionId());
229         for (var element : automationComposition.getElements().values()) {
230             var compositionInProperties = cacheProvider
231                 .getCommonProperties(automationComposition.getCompositionId(), element.getDefinition());
232             int startPhase = ParticipantUtils.findStartPhase(compositionInProperties);
233             if (startPhaseMsg.equals(startPhase)) {
234                 element.setDeployState(DeployState.DELETING);
235                 element.setSubState(SubState.NONE);
236                 var compositionElement = cacheProvider.createCompositionElementDto(
237                         automationComposition.getCompositionId(), element, compositionInProperties);
238                 var instanceElement = new InstanceElementDto(automationComposition.getInstanceId(), element.getId(),
239                         serviceTemplateFragment, element.getProperties(), element.getOutProperties());
240                 listener.delete(messageId, compositionElement, instanceElement);
241             }
242         }
243     }
244
245     /**
246      * Handles AutomationComposition Migration.
247      *
248      * @param migrationMsg the AutomationCompositionMigration
249      */
250     public void handleAutomationCompositionMigration(AutomationCompositionMigration migrationMsg) {
251         if (migrationMsg.getAutomationCompositionId() == null || migrationMsg.getCompositionTargetId() == null) {
252             return;
253         }
254
255         var automationComposition = cacheProvider.getAutomationComposition(migrationMsg.getAutomationCompositionId());
256         if (automationComposition == null) {
257             LOGGER.debug("Automation composition {} does not use this participant",
258                     migrationMsg.getAutomationCompositionId());
259             return;
260         }
261         var acCopy = new AutomationComposition(automationComposition);
262         automationComposition.setCompositionTargetId(migrationMsg.getCompositionTargetId());
263         automationComposition.setDeployState(DeployState.MIGRATING);
264         for (var participantDeploy : migrationMsg.getParticipantUpdatesList()) {
265             if (cacheProvider.getParticipantId().equals(participantDeploy.getParticipantId())) {
266
267                 updateExistingElementsOnThisParticipant(migrationMsg.getAutomationCompositionId(), participantDeploy,
268                     DeployState.MIGRATING);
269
270                 callParticipantMigrate(migrationMsg.getMessageId(), participantDeploy.getAcElementList(),
271                     acCopy, migrationMsg.getCompositionTargetId());
272             }
273         }
274     }
275
276     private void callParticipantMigrate(UUID messageId, List<AcElementDeploy> acElements,
277             AutomationComposition acCopy, UUID compositionTargetId) {
278         var compositionElementMap = cacheProvider.getCompositionElementDtoMap(acCopy);
279         var instanceElementMap = cacheProvider.getInstanceElementDtoMap(acCopy);
280         var automationComposition = cacheProvider.getAutomationComposition(acCopy.getInstanceId());
281         var compositionElementTargetMap = cacheProvider.getCompositionElementDtoMap(automationComposition,
282             compositionTargetId);
283         var instanceElementMigrateMap = cacheProvider.getInstanceElementDtoMap(automationComposition);
284
285         for (var acElement : acElements) {
286             listener.migrate(messageId, compositionElementMap.get(acElement.getId()),
287                 compositionElementTargetMap.get(acElement.getId()),
288                 instanceElementMap.get(acElement.getId()), instanceElementMigrateMap.get(acElement.getId()));
289         }
290     }
291 }