20b2a2438fd9feb1c14f26926ecc7c52897ff317
[policy/clamp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2024-2025 OpenInfra Foundation Europe. All rights reserved.
4  * ================================================================================
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * SPDX-License-Identifier: Apache-2.0
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.policy.clamp.acm.participant.intermediary.handler;
22
23 import java.util.List;
24 import java.util.Map;
25 import java.util.UUID;
26 import lombok.RequiredArgsConstructor;
27 import org.onap.policy.clamp.acm.participant.intermediary.api.CompositionElementDto;
28 import org.onap.policy.clamp.acm.participant.intermediary.api.ElementState;
29 import org.onap.policy.clamp.acm.participant.intermediary.api.InstanceElementDto;
30 import org.onap.policy.clamp.acm.participant.intermediary.handler.cache.CacheProvider;
31 import org.onap.policy.clamp.models.acm.concepts.AcElementDeploy;
32 import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
33 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElement;
34 import org.onap.policy.clamp.models.acm.concepts.DeployState;
35 import org.onap.policy.clamp.models.acm.concepts.ParticipantUtils;
36 import org.onap.policy.clamp.models.acm.concepts.SubState;
37 import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionMigration;
38 import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionPrepare;
39 import org.onap.policy.clamp.models.acm.utils.AcmUtils;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42 import org.springframework.stereotype.Component;
43
44 @Component
45 @RequiredArgsConstructor
46 public class AcSubStateHandler {
47
48     private static final Logger LOGGER = LoggerFactory.getLogger(AcSubStateHandler.class);
49
50     private final CacheProvider cacheProvider;
51     private final ThreadHandler listener;
52
53     /**
54      * Handles AutomationComposition Migration Precheck.
55      *
56      * @param migrationMsg the AutomationCompositionMigration
57      */
58     public void handleAcMigrationPrecheck(AutomationCompositionMigration migrationMsg) {
59         if (migrationMsg.getAutomationCompositionId() == null || migrationMsg.getCompositionTargetId() == null) {
60             return;
61         }
62         var acTargetDefinition = cacheProvider.getAcElementsDefinitions().get(migrationMsg.getCompositionTargetId());
63         var automationComposition = cacheProvider.getAutomationComposition(migrationMsg.getAutomationCompositionId());
64         if (automationComposition == null) {
65             if (acTargetDefinition == null) {
66                 LOGGER.warn("Automation composition {} does not use this participant",
67                         migrationMsg.getAutomationCompositionId());
68                 return;
69             }
70         } else {
71             LOGGER.info("Migration Precheck invoked on an existing participant for the instance {}",
72                     migrationMsg.getAutomationCompositionId());
73         }
74         for (var participantDeploy : migrationMsg.getParticipantUpdatesList()) {
75             if (cacheProvider.getParticipantId().equals(participantDeploy.getParticipantId())) {
76                 if (automationComposition == null) { // New element with new participant
77                     automationComposition = cacheProvider.createAcInstance(migrationMsg.getCompositionId(),
78                             migrationMsg.getCompositionTargetId(), migrationMsg.getAutomationCompositionId(),
79                             participantDeploy, DeployState.MIGRATING, SubState.MIGRATION_PRECHECKING,
80                             migrationMsg.getRevisionIdInstance());
81                     LOGGER.info("New participant with new element type added for Migration Precheck");
82                 }
83
84                 callParticipantMigratePrecheck(migrationMsg.getMessageId(), participantDeploy.getAcElementList(),
85                     automationComposition, migrationMsg.getCompositionTargetId());
86             }
87         }
88     }
89
90     private void callParticipantMigratePrecheck(UUID messageId, List<AcElementDeploy> acElements,
91             AutomationComposition automationComposition, UUID compositionTargetId) {
92         var compositionElementMap = cacheProvider.getCompositionElementDtoMap(automationComposition);
93         var instanceElementMap = cacheProvider.getInstanceElementDtoMap(automationComposition);
94         var acElementList = automationComposition.getElements();
95         for (var acElement : acElements) {
96             var element = acElementList.get(acElement.getId());
97             if (element != null) {
98                 element.setSubState(SubState.MIGRATION_PRECHECKING);
99             }
100         }
101         var acCopyMigrateTo = new AutomationComposition(automationComposition);
102         var acElementCopyList = acCopyMigrateTo.getElements();
103         for (var acElement : acElements) {
104             var element = acElementCopyList.get(acElement.getId());
105             if (element != null) {
106                 AcmUtils.recursiveMerge(element.getProperties(), acElement.getProperties());
107                 element.setDefinition(acElement.getDefinition());
108             } else {
109                 element = CacheProvider.createAutomationCompositionElement(acElement);
110                 element.setSubState(SubState.MIGRATION_PRECHECKING);
111                 acElementCopyList.put(element.getId(), element);
112             }
113         }
114         var toDelete = acElementCopyList.values().stream()
115                 .filter(el -> !SubState.MIGRATION_PRECHECKING.equals(el.getSubState()))
116                 .map(AutomationCompositionElement::getId)
117                 .toList();
118         toDelete.forEach(acElementCopyList::remove);
119
120         var compositionElementTargetMap = cacheProvider.getCompositionElementDtoMap(acCopyMigrateTo,
121             compositionTargetId);
122         var instanceElementMigrateMap = cacheProvider.getInstanceElementDtoMap(acCopyMigrateTo);
123
124         for (var acElement : acElements) {
125             var compositionElement = compositionElementMap.get(acElement.getId());
126             var compositionElementTarget = compositionElementTargetMap.get(acElement.getId());
127             var instanceElement = instanceElementMap.get(acElement.getId());
128             var instanceElementMigrate = instanceElementMigrateMap.get(acElement.getId());
129
130             if (instanceElement == null) {
131                 // new element scenario
132                 compositionElement = new CompositionElementDto(automationComposition.getCompositionId(),
133                         acElement.getDefinition(), Map.of(), Map.of(), ElementState.NOT_PRESENT);
134                 instanceElement = new InstanceElementDto(automationComposition.getInstanceId(), acElement.getId(),
135                         Map.of(), Map.of(), ElementState.NOT_PRESENT);
136                 compositionElementTarget = CacheProvider.changeStateToNew(compositionElementTarget);
137                 instanceElementMigrate = CacheProvider.changeStateToNew(instanceElementMigrate);
138             }
139
140             listener.migratePrecheck(messageId, compositionElement, compositionElementTarget,
141                     instanceElement, instanceElementMigrate);
142         }
143
144         for (var elementId : toDelete) {
145             var compositionDtoTarget =
146                     new CompositionElementDto(compositionTargetId,
147                             automationComposition.getElements().get(elementId).getDefinition(),
148                             Map.of(), Map.of(), ElementState.REMOVED);
149             var instanceDtoTarget =
150                     new InstanceElementDto(automationComposition.getInstanceId(), elementId,
151                             Map.of(), Map.of(), ElementState.REMOVED);
152
153             listener.migratePrecheck(messageId, compositionElementMap.get(elementId), compositionDtoTarget,
154                     instanceElementMap.get(elementId), instanceDtoTarget);
155         }
156     }
157
158     /**
159      * Handle AutomationComposition Prepare message.
160      *
161      * @param acPrepareMsg the AutomationCompositionPrepare message
162      */
163     public void handleAcPrepare(AutomationCompositionPrepare acPrepareMsg) {
164         if (acPrepareMsg.isPreDeploy()) {
165             for (var participantPrepare : acPrepareMsg.getParticipantList()) {
166                 if (cacheProvider.getParticipantId().equals(participantPrepare.getParticipantId())) {
167                     cacheProvider.initializeAutomationComposition(acPrepareMsg.getCompositionId(), null,
168                         acPrepareMsg.getAutomationCompositionId(), participantPrepare, DeployState.UNDEPLOYED,
169                         SubState.PREPARING, acPrepareMsg.getRevisionIdInstance());
170                     callParticipanPrepare(acPrepareMsg.getMessageId(), participantPrepare.getAcElementList(),
171                         acPrepareMsg.getStage(), acPrepareMsg.getAutomationCompositionId());
172                 }
173             }
174         } else {
175             var automationComposition =
176                 cacheProvider.getAutomationComposition(acPrepareMsg.getAutomationCompositionId());
177             automationComposition.setSubState(SubState.REVIEWING);
178             callParticipanReview(acPrepareMsg.getMessageId(), automationComposition);
179         }
180     }
181
182     private void callParticipanPrepare(UUID messageId, List<AcElementDeploy> acElementList, Integer stageMsg,
183             UUID instanceId) {
184         var automationComposition = cacheProvider.getAutomationComposition(instanceId);
185         for (var elementDeploy : acElementList) {
186             var element = automationComposition.getElements().get(elementDeploy.getId());
187             var compositionInProperties = cacheProvider
188                 .getCommonProperties(automationComposition.getCompositionId(), element.getDefinition());
189             var compositionElement = cacheProvider.createCompositionElementDto(automationComposition.getCompositionId(),
190                 element);
191             var stageSet = ParticipantUtils.findStageSetPrepare(compositionInProperties);
192             if (stageSet.contains(stageMsg)) {
193                 var instanceElement =
194                         new InstanceElementDto(instanceId, elementDeploy.getId(), elementDeploy.getProperties(),
195                                 element.getOutProperties());
196                 listener.prepare(messageId, compositionElement, instanceElement, stageMsg);
197             }
198         }
199     }
200
201     private void callParticipanReview(UUID messageId, AutomationComposition automationComposition) {
202         for (var element : automationComposition.getElements().values()) {
203             element.setSubState(SubState.REVIEWING);
204             var compositionElement = cacheProvider.createCompositionElementDto(automationComposition.getCompositionId(),
205                 element);
206             var instanceElement = new InstanceElementDto(automationComposition.getInstanceId(), element.getId(),
207                 element.getProperties(), element.getOutProperties());
208             listener.review(messageId, compositionElement, instanceElement);
209         }
210     }
211 }