93a9ee70f300d3b558e21e392e34ec0d33a84c7f
[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.sim.main.handler;
22
23 import java.util.ArrayList;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.UUID;
27 import lombok.Getter;
28 import lombok.RequiredArgsConstructor;
29 import lombok.Setter;
30 import org.onap.policy.clamp.acm.participant.intermediary.api.CompositionDto;
31 import org.onap.policy.clamp.acm.participant.intermediary.api.ParticipantIntermediaryApi;
32 import org.onap.policy.clamp.acm.participant.sim.model.InternalData;
33 import org.onap.policy.clamp.acm.participant.sim.model.InternalDatas;
34 import org.onap.policy.clamp.acm.participant.sim.model.SimConfig;
35 import org.onap.policy.clamp.models.acm.concepts.AcTypeState;
36 import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
37 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositions;
38 import org.onap.policy.clamp.models.acm.concepts.DeployState;
39 import org.onap.policy.clamp.models.acm.concepts.LockState;
40 import org.onap.policy.clamp.models.acm.concepts.ParticipantUtils;
41 import org.onap.policy.clamp.models.acm.concepts.StateChangeResult;
42 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45 import org.springframework.stereotype.Service;
46
47 /**
48  * This class handles implementation of Simulator Service.
49  */
50 @Service
51 @RequiredArgsConstructor
52 public class SimulatorService {
53
54     private final ParticipantIntermediaryApi intermediaryApi;
55
56     private static final Logger LOGGER = LoggerFactory.getLogger(SimulatorService.class);
57     private static final String INTERNAL_STATE = "InternalState";
58     private static final String MIGRATION_PROPERTY = "stage";
59     private static final String PREPARE_PROPERTY = "prepareStage";
60
61     @Getter
62     @Setter
63     private SimConfig config = new SimConfig();
64
65     /**
66      * Get AutomationComposition.
67      *
68      * @return the AutomationCompositions
69      */
70     public AutomationCompositions getAutomationCompositions() {
71         var result = new AutomationCompositions();
72         result.setAutomationCompositionList(new ArrayList<>(intermediaryApi.getAutomationCompositions().values()));
73         return result;
74     }
75
76     public AutomationComposition getAutomationComposition(UUID instanceId) {
77         return intermediaryApi.getAutomationComposition(instanceId);
78     }
79
80     /**
81      * Set OutProperties.
82      *
83      * @param instanceId the automationComposition Id
84      * @param elementId the automationComposition Element Id
85      * @param useState the useState
86      * @param operationalState the operationalState
87      * @param outProperties the outProperties
88      */
89     public void setOutProperties(UUID instanceId, UUID elementId, String useState, String operationalState,
90                                  Map<String, Object> outProperties) {
91         intermediaryApi.sendAcElementInfo(instanceId, elementId, useState, operationalState,
92                 outProperties);
93     }
94
95     /**
96      * Get Instance Data List.
97      *
98      * @return the InternalDatas
99      */
100     public InternalDatas getDataList() {
101         var result = new InternalDatas();
102         var map = intermediaryApi.getAutomationCompositions();
103         for (var instance : map.values()) {
104             for (var element : instance.getElements().values()) {
105                 var data = new InternalData();
106                 data.setCompositionId(instance.getCompositionId());
107                 data.setAutomationCompositionId(instance.getInstanceId());
108                 data.setAutomationCompositionElementId(element.getId());
109                 data.setIntProperties(element.getProperties());
110                 data.setOperationalState(element.getOperationalState());
111                 data.setUseState(element.getUseState());
112                 data.setOutProperties(element.getOutProperties());
113                 result.getList().add(data);
114             }
115         }
116         return result;
117     }
118
119     /**
120      * Get Composition Data List.
121      *
122      * @return the InternalDatas
123      */
124     public InternalDatas getCompositionDataList() {
125         var acElementsDefinitions = intermediaryApi.getAcElementsDefinitions();
126         var internalDatas = new InternalDatas();
127         for (var entry : acElementsDefinitions.entrySet()) {
128             for (var acElementsDefinition : entry.getValue().values()) {
129                 var internalData = new InternalData();
130                 internalData.setCompositionId(entry.getKey());
131                 internalData.setCompositionDefinitionElementId(acElementsDefinition.getAcElementDefinitionId());
132                 internalData.setIntProperties(
133                         acElementsDefinition.getAutomationCompositionElementToscaNodeTemplate().getProperties());
134                 internalData.setOutProperties(acElementsDefinition.getOutProperties());
135                 internalDatas.getList().add(internalData);
136             }
137         }
138         return internalDatas;
139     }
140
141     public void setCompositionOutProperties(UUID compositionId, ToscaConceptIdentifier compositionDefinitionElementId,
142                                             Map<String, Object> outProperties) {
143         intermediaryApi.sendAcDefinitionInfo(compositionId, compositionDefinitionElementId, outProperties);
144
145     }
146
147     protected boolean execution(int timeMs, String msg, UUID elementId) {
148         long endTime = System.currentTimeMillis() + timeMs;
149         while (System.currentTimeMillis() < endTime) {
150             try {
151                 if (Thread.currentThread().isInterrupted()) {
152                     LOGGER.debug(msg, elementId);
153                     return false;
154                 }
155                 Thread.sleep(10L);
156             } catch (InterruptedException e) {
157                 LOGGER.debug(msg, elementId);
158                 Thread.currentThread().interrupt();
159                 return false;
160             }
161         }
162         return true;
163     }
164
165     /**
166      * Handle a deploy on a automation composition element.
167      *
168      * @param instanceId the instanceId
169      * @param elementId the elementId
170      * @param outProperties the outProperties
171      */
172     public void deploy(UUID instanceId, UUID elementId, Map<String, Object> outProperties) {
173         if (!execution(getConfig().getDeployTimerMs(),
174                 "Current Thread deploy is Interrupted during execution {}", elementId)) {
175             return;
176         }
177
178         if (getConfig().isDeploySuccess()) {
179             outProperties.put(INTERNAL_STATE, DeployState.DEPLOYED.name());
180             intermediaryApi.sendAcElementInfo(instanceId, elementId, null, null, outProperties);
181
182             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
183                     DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Deployed");
184         } else {
185             outProperties.put(INTERNAL_STATE, DeployState.UNDEPLOYED.name());
186             intermediaryApi.sendAcElementInfo(instanceId, elementId, null, null, outProperties);
187
188             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
189                     DeployState.UNDEPLOYED, null, StateChangeResult.FAILED, "Deploy failed!");
190         }
191     }
192
193     /**
194      * Handle an udeploy on a automation composition element.
195      *
196      * @param instanceId the instanceId
197      * @param elementId the elementId
198      * @param outProperties the outProperties
199      */
200     public void undeploy(UUID instanceId, UUID elementId, Map<String, Object> outProperties) {
201         if (!execution(getConfig().getUndeployTimerMs(),
202                 "Current Thread undeploy is Interrupted during execution {}", elementId)) {
203             return;
204         }
205
206         if (getConfig().isUndeploySuccess()) {
207             outProperties.put(INTERNAL_STATE, DeployState.UNDEPLOYED.name());
208             intermediaryApi.sendAcElementInfo(instanceId, elementId, null, null, outProperties);
209
210             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
211                     DeployState.UNDEPLOYED, null, StateChangeResult.NO_ERROR, "Undeployed");
212         } else {
213             outProperties.put(INTERNAL_STATE, DeployState.DEPLOYED.name());
214             intermediaryApi.sendAcElementInfo(instanceId, elementId, null, null, outProperties);
215
216             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
217                     DeployState.DEPLOYED, null, StateChangeResult.FAILED, "Undeploy failed!");
218         }
219     }
220
221     /**
222      * Handle a lock on a automation composition element.
223      *
224      * @param instanceId the instanceId
225      * @param elementId the elementId
226      */
227     public void lock(UUID instanceId, UUID elementId) {
228         if (!execution(getConfig().getLockTimerMs(),
229                 "Current Thread lock is Interrupted during execution {}", elementId)) {
230             return;
231         }
232
233         if (getConfig().isLockSuccess()) {
234             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
235                     null, LockState.LOCKED, StateChangeResult.NO_ERROR, "Locked");
236         } else {
237             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
238                     null, LockState.UNLOCKED, StateChangeResult.FAILED, "Lock failed!");
239         }
240     }
241
242     /**
243      * Handle an unlock on a automation composition element.
244      *
245      * @param instanceId the instanceId
246      * @param elementId the elementId
247      */
248     public void unlock(UUID instanceId, UUID elementId) {
249         if (!execution(getConfig().getUnlockTimerMs(),
250                 "Current Thread unlock is Interrupted during execution {}", elementId)) {
251             return;
252         }
253
254         if (getConfig().isUnlockSuccess()) {
255             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
256                     null, LockState.UNLOCKED, StateChangeResult.NO_ERROR, "Unlocked");
257         } else {
258             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
259                     null, LockState.LOCKED, StateChangeResult.FAILED, "Unlock failed!");
260         }
261     }
262
263     /**
264      * Handle a delete on a automation composition element.
265      *
266      * @param instanceId the instanceId
267      * @param elementId the elementId
268      */
269     public void delete(UUID instanceId, UUID elementId) {
270         if (!execution(getConfig().getDeleteTimerMs(),
271                 "Current Thread delete is Interrupted during execution {}", elementId)) {
272             return;
273         }
274
275         if (getConfig().isDeleteSuccess()) {
276             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
277                     DeployState.DELETED, null, StateChangeResult.NO_ERROR, "Deleted");
278         } else {
279             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
280                     DeployState.UNDEPLOYED, null, StateChangeResult.FAILED, "Delete failed!");
281         }
282     }
283
284     /**
285      * Handle an update on a automation composition element.
286      *
287      * @param instanceId the instanceId
288      * @param elementId the elementId
289      */
290     public void update(UUID instanceId, UUID elementId) {
291         if (!execution(getConfig().getUpdateTimerMs(),
292                 "Current Thread update is Interrupted during execution {}", elementId)) {
293             return;
294         }
295
296         if (getConfig().isUpdateSuccess()) {
297             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
298                     DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Updated");
299         } else {
300             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
301                     DeployState.DEPLOYED, null, StateChangeResult.FAILED, "Update failed!");
302         }
303     }
304
305     /**
306      * Handle a prime on a automation composition definition.
307      *
308      * @param composition the information of the Automation Composition Definition
309      */
310     public void prime(CompositionDto composition) {
311         if (!execution(getConfig().getPrimeTimerMs(),
312                 "Current Thread prime is Interrupted during execution {}", composition.compositionId())) {
313             return;
314         }
315
316         if (getConfig().isPrimeSuccess()) {
317             sendOutProperties(composition, AcTypeState.PRIMED.name());
318             intermediaryApi.updateCompositionState(composition.compositionId(), AcTypeState.PRIMED,
319                     StateChangeResult.NO_ERROR, "Primed");
320         } else {
321             sendOutProperties(composition, AcTypeState.COMMISSIONED.name());
322             intermediaryApi.updateCompositionState(composition.compositionId(), AcTypeState.COMMISSIONED,
323                     StateChangeResult.FAILED, "Prime failed!");
324         }
325     }
326
327     private void sendOutProperties(CompositionDto composition, String data) {
328         for (var elementEntry : composition.outPropertiesMap().entrySet()) {
329             elementEntry.getValue().put(INTERNAL_STATE, data);
330             intermediaryApi.sendAcDefinitionInfo(
331                     composition.compositionId(), elementEntry.getKey(), elementEntry.getValue());
332         }
333     }
334
335     /**
336      * Handle a deprime on a automation composition definition.
337      *
338      * @param composition the information of the Automation Composition Definition
339      */
340     public void deprime(CompositionDto composition) {
341         if (!execution(getConfig().getDeprimeTimerMs(),
342                 "Current Thread deprime is Interrupted during execution {}", composition.compositionId())) {
343             return;
344         }
345
346         if (getConfig().isDeprimeSuccess()) {
347             sendOutProperties(composition, AcTypeState.COMMISSIONED.name());
348             intermediaryApi.updateCompositionState(composition.compositionId(), AcTypeState.COMMISSIONED,
349                     StateChangeResult.NO_ERROR, "Deprimed");
350         } else {
351             sendOutProperties(composition, AcTypeState.PRIMED.name());
352             intermediaryApi.updateCompositionState(composition.compositionId(), AcTypeState.PRIMED,
353                     StateChangeResult.FAILED, "Deprime failed!");
354         }
355     }
356
357     /**
358      * Handle a migrate on a automation composition element.
359      *
360      * @param instanceId the instanceId
361      * @param elementId the elementId
362      * @param stage the stage
363      * @param compositionInProperties in Properties from composition definition element
364      * @param instanceOutProperties in Properties from instance element
365      */
366     public void migrate(UUID instanceId, UUID elementId, int stage, Map<String, Object> compositionInProperties,
367             Map<String, Object> instanceOutProperties) {
368         if (!execution(getConfig().getMigrateTimerMs(),
369                 "Current Thread migrate is Interrupted during execution {}", elementId)) {
370             return;
371         }
372
373         if (config.isMigrateSuccess()) {
374             var stageSet = ParticipantUtils.findStageSetMigrate(compositionInProperties);
375             var nextStage = 1000;
376             for (var s : stageSet) {
377                 if (s > stage) {
378                     nextStage = Math.min(s, nextStage);
379                 }
380             }
381             instanceOutProperties.putIfAbsent(MIGRATION_PROPERTY, new ArrayList<>());
382             @SuppressWarnings("unchecked")
383             var stageList = (List<Integer>) instanceOutProperties.get(MIGRATION_PROPERTY);
384             stageList.add(stage);
385             intermediaryApi.sendAcElementInfo(instanceId, elementId, null, null, instanceOutProperties);
386             if (nextStage == 1000) {
387                 intermediaryApi.updateAutomationCompositionElementState(
388                         instanceId, elementId,
389                         DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Migrated");
390             } else {
391                 intermediaryApi.updateAutomationCompositionElementStage(
392                         instanceId, elementId,
393                         StateChangeResult.NO_ERROR, nextStage, "stage " + stage + " Migrated");
394             }
395         } else {
396             intermediaryApi.updateAutomationCompositionElementState(
397                     instanceId, elementId,
398                     DeployState.DEPLOYED, null, StateChangeResult.FAILED, "Migrate failed!");
399         }
400     }
401
402     /**
403      * Handle a Migrate Precheck on a automation composition element.
404      *
405      * @param instanceId the instanceId
406      * @param elementId the elementId
407      */
408     public void migratePrecheck(UUID instanceId, UUID elementId) {
409         if (!execution(config.getMigratePrecheckTimerMs(),
410                 "Current Thread migrate precheck is Interrupted during execution {}", elementId)) {
411             return;
412         }
413
414         if (config.isMigratePrecheck()) {
415             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
416                     DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Migration precheck completed");
417         } else {
418             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
419                     DeployState.DEPLOYED, null, StateChangeResult.FAILED, "Migration precheck failed");
420         }
421     }
422
423     /**
424      * Handle a Prepare on a automation composition element.
425      *
426      * @param instanceId the instanceId
427      * @param elementId the elementId
428      * @param stage the stage
429      * @param compositionInProperties in Properties from composition definition element
430      * @param instanceOutProperties in Properties from instance element
431      */
432     public void prepare(UUID instanceId, UUID elementId, int stage, Map<String, Object> compositionInProperties,
433             Map<String, Object> instanceOutProperties) {
434         if (!execution(config.getPrepareTimerMs(),
435                 "Current Thread prepare is Interrupted during execution {}", elementId)) {
436             return;
437         }
438
439         if (config.isPrepare()) {
440             var stageSet = ParticipantUtils.findStageSetPrepare(compositionInProperties);
441             var nextStage = 1000;
442             for (var s : stageSet) {
443                 if (s > stage) {
444                     nextStage = Math.min(s, nextStage);
445                 }
446             }
447             instanceOutProperties.putIfAbsent(PREPARE_PROPERTY, new ArrayList<>());
448             @SuppressWarnings("unchecked")
449             var stageList = (List<Integer>) instanceOutProperties.get(PREPARE_PROPERTY);
450             stageList.add(stage);
451             intermediaryApi.sendAcElementInfo(instanceId, elementId, null, null, instanceOutProperties);
452             if (nextStage == 1000) {
453                 intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
454                         DeployState.UNDEPLOYED, null, StateChangeResult.NO_ERROR, "Prepare completed");
455             } else {
456                 intermediaryApi.updateAutomationCompositionElementStage(
457                         instanceId, elementId,
458                         StateChangeResult.NO_ERROR, nextStage, "stage " + stage + " Prepared");
459             }
460         } else {
461             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
462                     DeployState.UNDEPLOYED, null, StateChangeResult.FAILED, "Prepare failed");
463         }
464     }
465
466     /**
467      * Handle a Review on a automation composition element.
468      *
469      * @param instanceId the instanceId
470      * @param elementId the elementId
471      */
472     public void review(UUID instanceId, UUID elementId) {
473         if (!execution(config.getReviewTimerMs(),
474                 "Current Thread review is Interrupted during execution {}", elementId)) {
475             return;
476         }
477
478         if (config.isReview()) {
479             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
480                     DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Review completed");
481         } else {
482             intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
483                     DeployState.DEPLOYED, null, StateChangeResult.FAILED, "Review failed");
484         }
485     }
486 }