f00c87b1f5ddbc3082dab1317673f22c462b4075
[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
63         var automationComposition = cacheProvider.getAutomationComposition(migrationMsg.getAutomationCompositionId());
64         if (automationComposition == null) {
65             LOGGER.debug("Automation composition {} does not use this participant",
66                     migrationMsg.getAutomationCompositionId());
67             return;
68         }
69         automationComposition.setSubState(SubState.MIGRATION_PRECHECKING);
70         for (var participantDeploy : migrationMsg.getParticipantUpdatesList()) {
71             if (cacheProvider.getParticipantId().equals(participantDeploy.getParticipantId())) {
72
73                 callParticipantMigratePrecheck(migrationMsg.getMessageId(), participantDeploy.getAcElementList(),
74                     automationComposition, migrationMsg.getCompositionTargetId());
75             }
76         }
77     }
78
79     private void callParticipantMigratePrecheck(UUID messageId, List<AcElementDeploy> acElements,
80             AutomationComposition automationComposition, UUID compositionTargetId) {
81         var compositionElementMap = cacheProvider.getCompositionElementDtoMap(automationComposition);
82         var instanceElementMap = cacheProvider.getInstanceElementDtoMap(automationComposition);
83         var acElementList = automationComposition.getElements();
84         for (var acElement : acElements) {
85             var element = acElementList.get(acElement.getId());
86             if (element != null) {
87                 element.setSubState(SubState.MIGRATION_PRECHECKING);
88             }
89         }
90         var acCopyMigrateTo = new AutomationComposition(automationComposition);
91         var acElementCopyList = acCopyMigrateTo.getElements();
92         for (var acElement : acElements) {
93             var element = acElementCopyList.get(acElement.getId());
94             if (element != null) {
95                 AcmUtils.recursiveMerge(element.getProperties(), acElement.getProperties());
96                 element.setDefinition(acElement.getDefinition());
97             } else {
98                 element = CacheProvider.createAutomationCompositionElement(acElement);
99                 element.setSubState(SubState.MIGRATION_PRECHECKING);
100                 acElementCopyList.put(element.getId(), element);
101             }
102         }
103         var toDelete = acElementCopyList.values().stream()
104                 .filter(el -> !SubState.MIGRATION_PRECHECKING.equals(el.getSubState()))
105                 .map(AutomationCompositionElement::getId)
106                 .toList();
107         toDelete.forEach(acElementCopyList::remove);
108
109         var compositionElementTargetMap = cacheProvider.getCompositionElementDtoMap(acCopyMigrateTo,
110             compositionTargetId);
111         var instanceElementMigrateMap = cacheProvider.getInstanceElementDtoMap(acCopyMigrateTo);
112
113         for (var acElement : acElements) {
114             var compositionElement = compositionElementMap.get(acElement.getId());
115             var compositionElementTarget = compositionElementTargetMap.get(acElement.getId());
116             var instanceElement = instanceElementMap.get(acElement.getId());
117             var instanceElementMigrate = instanceElementMigrateMap.get(acElement.getId());
118
119             if (instanceElement == null) {
120                 // new element scenario
121                 compositionElement = new CompositionElementDto(automationComposition.getCompositionId(),
122                         acElement.getDefinition(), Map.of(), Map.of(), ElementState.NOT_PRESENT);
123                 instanceElement = new InstanceElementDto(automationComposition.getInstanceId(), acElement.getId(),
124                         Map.of(), Map.of(), ElementState.NOT_PRESENT);
125                 compositionElementTarget = CacheProvider.changeStateToNew(compositionElementTarget);
126                 instanceElementMigrate = CacheProvider.changeStateToNew(instanceElementMigrate);
127             }
128
129             listener.migratePrecheck(messageId, compositionElement, compositionElementTarget,
130                     instanceElement, instanceElementMigrate);
131         }
132
133         for (var elementId : toDelete) {
134             var compositionDtoTarget =
135                     new CompositionElementDto(compositionTargetId,
136                             automationComposition.getElements().get(elementId).getDefinition(),
137                             Map.of(), Map.of(), ElementState.REMOVED);
138             var instanceDtoTarget =
139                     new InstanceElementDto(automationComposition.getInstanceId(), elementId,
140                             Map.of(), Map.of(), ElementState.REMOVED);
141
142             listener.migratePrecheck(messageId, compositionElementMap.get(elementId), compositionDtoTarget,
143                     instanceElementMap.get(elementId), instanceDtoTarget);
144         }
145     }
146
147     /**
148      * Handle AutomationComposition Prepare message.
149      *
150      * @param acPrepareMsg the AutomationCompositionPrepare message
151      */
152     public void handleAcPrepare(AutomationCompositionPrepare acPrepareMsg) {
153         if (acPrepareMsg.isPreDeploy()) {
154             for (var participantPrepare : acPrepareMsg.getParticipantList()) {
155                 if (cacheProvider.getParticipantId().equals(participantPrepare.getParticipantId())) {
156                     cacheProvider.initializeAutomationComposition(acPrepareMsg.getCompositionId(),
157                         acPrepareMsg.getAutomationCompositionId(), participantPrepare, DeployState.UNDEPLOYED,
158                         SubState.PREPARING, acPrepareMsg.getRevisionIdInstance());
159                     callParticipanPrepare(acPrepareMsg.getMessageId(), participantPrepare.getAcElementList(),
160                         acPrepareMsg.getStage(), acPrepareMsg.getAutomationCompositionId());
161                 }
162             }
163         } else {
164             var automationComposition =
165                 cacheProvider.getAutomationComposition(acPrepareMsg.getAutomationCompositionId());
166             automationComposition.setSubState(SubState.REVIEWING);
167             callParticipanReview(acPrepareMsg.getMessageId(), automationComposition);
168         }
169     }
170
171     private void callParticipanPrepare(UUID messageId, List<AcElementDeploy> acElementList, Integer stageMsg,
172             UUID instanceId) {
173         var automationComposition = cacheProvider.getAutomationComposition(instanceId);
174         for (var elementDeploy : acElementList) {
175             var element = automationComposition.getElements().get(elementDeploy.getId());
176             var compositionInProperties = cacheProvider
177                 .getCommonProperties(automationComposition.getCompositionId(), element.getDefinition());
178             var compositionElement = cacheProvider.createCompositionElementDto(automationComposition.getCompositionId(),
179                 element);
180             var stageSet = ParticipantUtils.findStageSetPrepare(compositionInProperties);
181             if (stageSet.contains(stageMsg)) {
182                 var instanceElement =
183                         new InstanceElementDto(instanceId, elementDeploy.getId(), elementDeploy.getProperties(),
184                                 element.getOutProperties());
185                 listener.prepare(messageId, compositionElement, instanceElement, stageMsg);
186             }
187         }
188     }
189
190     private void callParticipanReview(UUID messageId, AutomationComposition automationComposition) {
191         for (var element : automationComposition.getElements().values()) {
192             element.setSubState(SubState.REVIEWING);
193             var compositionElement = cacheProvider.createCompositionElementDto(automationComposition.getCompositionId(),
194                 element);
195             var instanceElement = new InstanceElementDto(automationComposition.getInstanceId(), element.getId(),
196                 element.getProperties(), element.getOutProperties());
197             listener.review(messageId, compositionElement, instanceElement);
198         }
199     }
200 }