1dbf2c935f1d8cca3b8b11d86c58c294d2d4feb6
[policy/clamp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2024 Nordix Foundation.
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.models.acm.concepts.AcElementDeploy;
31 import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
32 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElement;
33 import org.onap.policy.clamp.models.acm.concepts.DeployState;
34 import org.onap.policy.clamp.models.acm.concepts.SubState;
35 import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionMigration;
36 import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionPrepare;
37 import org.onap.policy.clamp.models.acm.utils.AcmUtils;
38 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41 import org.springframework.stereotype.Component;
42
43 @Component
44 @RequiredArgsConstructor
45 public class AcSubStateHandler {
46
47     private static final Logger LOGGER = LoggerFactory.getLogger(AcSubStateHandler.class);
48
49     private final CacheProvider cacheProvider;
50     private final ThreadHandler listener;
51
52     /**
53      * Handles AutomationComposition Migration Precheck.
54      *
55      * @param migrationMsg the AutomationCompositionMigration
56      */
57     public void handleAcMigrationPrecheck(AutomationCompositionMigration migrationMsg) {
58         if (migrationMsg.getAutomationCompositionId() == null || migrationMsg.getCompositionTargetId() == null) {
59             return;
60         }
61
62         var automationComposition = cacheProvider.getAutomationComposition(migrationMsg.getAutomationCompositionId());
63         if (automationComposition == null) {
64             LOGGER.debug("Automation composition {} does not use this participant",
65                     migrationMsg.getAutomationCompositionId());
66             return;
67         }
68         automationComposition.setSubState(SubState.MIGRATION_PRECHECKING);
69         for (var participantDeploy : migrationMsg.getParticipantUpdatesList()) {
70             if (cacheProvider.getParticipantId().equals(participantDeploy.getParticipantId())) {
71
72                 callParticipantMigratePrecheck(migrationMsg.getMessageId(), participantDeploy.getAcElementList(),
73                     automationComposition, migrationMsg.getCompositionTargetId());
74             }
75         }
76     }
77
78     private void callParticipantMigratePrecheck(UUID messageId, List<AcElementDeploy> acElements,
79             AutomationComposition automationComposition, UUID compositionTargetId) {
80         var compositionElementMap = cacheProvider.getCompositionElementDtoMap(automationComposition);
81         var instanceElementMap = cacheProvider.getInstanceElementDtoMap(automationComposition);
82         var acElementList = automationComposition.getElements();
83         for (var acElement : acElements) {
84             var element = acElementList.get(acElement.getId());
85             if (element != null) {
86                 element.setSubState(SubState.MIGRATION_PRECHECKING);
87             }
88         }
89         var acCopyMigrateTo = new AutomationComposition(automationComposition);
90         var acElementCopyList = acCopyMigrateTo.getElements();
91         for (var acElement : acElements) {
92             var element = acElementCopyList.get(acElement.getId());
93             if (element != null) {
94                 AcmUtils.recursiveMerge(element.getProperties(), acElement.getProperties());
95                 element.setDefinition(acElement.getDefinition());
96             } else {
97                 element = CacheProvider.createAutomationCompositionElement(acElement);
98                 element.setSubState(SubState.MIGRATION_PRECHECKING);
99                 acElementCopyList.put(element.getId(), element);
100             }
101         }
102         var toDelete = acElementCopyList.values().stream()
103                 .filter(el -> !SubState.MIGRATION_PRECHECKING.equals(el.getSubState()))
104                 .map(AutomationCompositionElement::getId)
105                 .toList();
106         toDelete.forEach(acElementCopyList::remove);
107
108         var compositionElementTargetMap = cacheProvider.getCompositionElementDtoMap(acCopyMigrateTo,
109             compositionTargetId);
110         var instanceElementMigrateMap = cacheProvider.getInstanceElementDtoMap(acCopyMigrateTo);
111
112         for (var acElement : acElements) {
113             var compositionElement = compositionElementMap.get(acElement.getId());
114             var compositionElementTarget = compositionElementTargetMap.get(acElement.getId());
115             var instanceElement = instanceElementMap.get(acElement.getId());
116             var instanceElementMigrate = instanceElementMigrateMap.get(acElement.getId());
117
118             if (instanceElement == null) {
119                 // new element scenario
120                 compositionElement = new CompositionElementDto(automationComposition.getCompositionId(),
121                         acElement.getDefinition(), Map.of(), Map.of(), ElementState.NOT_PRESENT);
122                 instanceElement = new InstanceElementDto(automationComposition.getInstanceId(), acElement.getId(),
123                         new ToscaServiceTemplate(), Map.of(), Map.of(), ElementState.NOT_PRESENT);
124                 compositionElementTarget = CacheProvider.changeStateToNew(compositionElementTarget);
125                 instanceElementMigrate = CacheProvider.changeStateToNew(instanceElementMigrate);
126             }
127
128             listener.migratePrecheck(messageId, compositionElement, compositionElementTarget,
129                     instanceElement, instanceElementMigrate);
130         }
131
132         for (var elementId : toDelete) {
133             var compositionDtoTarget =
134                     new CompositionElementDto(compositionTargetId,
135                             automationComposition.getElements().get(elementId).getDefinition(),
136                             Map.of(), Map.of(), ElementState.REMOVED);
137             var instanceDtoTarget =
138                     new InstanceElementDto(automationComposition.getInstanceId(), elementId,
139                             null, Map.of(), Map.of(), ElementState.REMOVED);
140
141             listener.migratePrecheck(messageId, compositionElementMap.get(elementId), compositionDtoTarget,
142                     instanceElementMap.get(elementId), instanceDtoTarget);
143         }
144     }
145
146     /**
147      * Handle AutomationComposition Prepare message.
148      *
149      * @param acPrepareMsg the AutomationCompositionPrepare message
150      */
151     public void handleAcPrepare(AutomationCompositionPrepare acPrepareMsg) {
152         if (acPrepareMsg.isPreDeploy()) {
153             for (var participantPrepare : acPrepareMsg.getParticipantList()) {
154                 if (cacheProvider.getParticipantId().equals(participantPrepare.getParticipantId())) {
155                     cacheProvider.initializeAutomationComposition(acPrepareMsg.getCompositionId(),
156                         acPrepareMsg.getAutomationCompositionId(), participantPrepare, DeployState.UNDEPLOYED,
157                         SubState.PREPARING);
158                     callParticipanPrepare(acPrepareMsg.getMessageId(), participantPrepare.getAcElementList(),
159                         acPrepareMsg.getAutomationCompositionId());
160                 }
161             }
162         } else {
163             var automationComposition =
164                 cacheProvider.getAutomationComposition(acPrepareMsg.getAutomationCompositionId());
165             automationComposition.setSubState(SubState.REVIEWING);
166             callParticipanReview(acPrepareMsg.getMessageId(), automationComposition);
167         }
168     }
169
170     private void callParticipanPrepare(UUID messageId, List<AcElementDeploy> acElementList, UUID instanceId) {
171         var automationComposition = cacheProvider.getAutomationComposition(instanceId);
172         for (var elementDeploy : acElementList) {
173             var element = automationComposition.getElements().get(elementDeploy.getId());
174             var compositionInProperties = cacheProvider
175                 .getCommonProperties(automationComposition.getCompositionId(), element.getDefinition());
176             var compositionElement = cacheProvider.createCompositionElementDto(automationComposition.getCompositionId(),
177                 element, compositionInProperties);
178             var instanceElement = new InstanceElementDto(instanceId, elementDeploy.getId(),
179                 elementDeploy.getToscaServiceTemplateFragment(),
180                 elementDeploy.getProperties(), element.getOutProperties());
181             listener.prepare(messageId, compositionElement, instanceElement);
182         }
183     }
184
185     private void callParticipanReview(UUID messageId, AutomationComposition automationComposition) {
186         for (var element : automationComposition.getElements().values()) {
187             var compositionInProperties = cacheProvider
188                 .getCommonProperties(automationComposition.getCompositionId(), element.getDefinition());
189             element.setSubState(SubState.REVIEWING);
190             var compositionElement = cacheProvider.createCompositionElementDto(automationComposition.getCompositionId(),
191                 element, compositionInProperties);
192             var instanceElement = new InstanceElementDto(automationComposition.getInstanceId(), element.getId(),
193                 null, element.getProperties(), element.getOutProperties());
194             listener.review(messageId, compositionElement, instanceElement);
195         }
196     }
197 }