787547860f9ed66e97576a6ddb013cba29c0c29c
[policy/clamp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * Copyright (C) 2021-2023 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.runtime.instantiation;
23
24
25 import java.util.Map;
26 import java.util.UUID;
27 import javax.validation.Valid;
28 import javax.ws.rs.core.Response;
29 import javax.ws.rs.core.Response.Status;
30 import lombok.AllArgsConstructor;
31 import org.onap.policy.clamp.acm.runtime.supervision.SupervisionAcHandler;
32 import org.onap.policy.clamp.models.acm.concepts.AcTypeState;
33 import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
34 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElement;
35 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositions;
36 import org.onap.policy.clamp.models.acm.concepts.DeployState;
37 import org.onap.policy.clamp.models.acm.concepts.LockState;
38 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.AcInstanceStateUpdate;
39 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.InstantiationResponse;
40 import org.onap.policy.clamp.models.acm.persistence.provider.AcDefinitionProvider;
41 import org.onap.policy.clamp.models.acm.persistence.provider.AcInstanceStateResolver;
42 import org.onap.policy.clamp.models.acm.persistence.provider.AutomationCompositionProvider;
43 import org.onap.policy.clamp.models.acm.utils.AcmUtils;
44 import org.onap.policy.common.parameters.BeanValidationResult;
45 import org.onap.policy.common.parameters.ObjectValidationResult;
46 import org.onap.policy.common.parameters.ValidationStatus;
47 import org.onap.policy.models.base.PfModelRuntimeException;
48 import org.springframework.stereotype.Service;
49 import org.springframework.transaction.annotation.Transactional;
50
51 /**
52  * This class is dedicated to the Instantiation of Commissioned automation composition.
53  */
54 @Service
55 @Transactional
56 @AllArgsConstructor
57 public class AutomationCompositionInstantiationProvider {
58     private static final String DO_NOT_MATCH = " do not match with ";
59
60     private final AutomationCompositionProvider automationCompositionProvider;
61     private final AcDefinitionProvider acDefinitionProvider;
62     private final AcInstanceStateResolver acInstanceStateResolver;
63     private final SupervisionAcHandler supervisionAcHandler;
64
65     /**
66      * Create automation composition.
67      *
68      * @param compositionId The UUID of the automation composition definition
69      * @param automationComposition the automation composition
70      * @return the result of the instantiation operation
71      */
72     public InstantiationResponse createAutomationComposition(UUID compositionId,
73             AutomationComposition automationComposition) {
74         if (!compositionId.equals(automationComposition.getCompositionId())) {
75             throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
76                     automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
77         }
78         var checkAutomationCompositionOpt =
79                 automationCompositionProvider.findAutomationComposition(automationComposition.getKey().asIdentifier());
80         if (checkAutomationCompositionOpt.isPresent()) {
81             throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
82                     automationComposition.getKey().asIdentifier() + " already defined");
83         }
84
85         var validationResult = validateAutomationComposition(automationComposition);
86         if (!validationResult.isValid()) {
87             throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, validationResult.getResult());
88         }
89         automationComposition = automationCompositionProvider.createAutomationComposition(automationComposition);
90
91         var response = new InstantiationResponse();
92         response.setInstanceId(automationComposition.getInstanceId());
93         response.setAffectedAutomationComposition(automationComposition.getKey().asIdentifier());
94
95         return response;
96     }
97
98     /**
99      * Update automation composition.
100      *
101      * @param compositionId The UUID of the automation composition definition
102      * @param automationComposition the automation composition
103      * @return the result of the update
104      */
105     public InstantiationResponse updateAutomationComposition(UUID compositionId,
106             AutomationComposition automationComposition) {
107         var response = new InstantiationResponse();
108         var instanceId = automationComposition.getInstanceId();
109         var acToUpdate = automationCompositionProvider.getAutomationComposition(instanceId);
110         if (!compositionId.equals(acToUpdate.getCompositionId())) {
111             throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
112                     automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
113         }
114         if (DeployState.UNDEPLOYED.equals(acToUpdate.getDeployState())) {
115             acToUpdate.setElements(automationComposition.getElements());
116             acToUpdate.setName(automationComposition.getName());
117             acToUpdate.setVersion(automationComposition.getVersion());
118             acToUpdate.setDescription(automationComposition.getDescription());
119             acToUpdate.setDerivedFrom(automationComposition.getDerivedFrom());
120             var validationResult = validateAutomationComposition(acToUpdate);
121             if (!validationResult.isValid()) {
122                 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, validationResult.getResult());
123             }
124             automationComposition = automationCompositionProvider.updateAutomationComposition(acToUpdate);
125             response.setInstanceId(instanceId);
126             response.setAffectedAutomationComposition(automationComposition.getKey().asIdentifier());
127             return response;
128
129         } else if (DeployState.DEPLOYED.equals(acToUpdate.getDeployState())
130                 && LockState.LOCKED.equals(acToUpdate.getLockState())) {
131             return updateDeployedAutomationComposition(compositionId, automationComposition, acToUpdate);
132         }
133         throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
134                     "Not allowed to update in the state " + acToUpdate.getDeployState());
135     }
136
137     /**
138      * Update deployed AC Element properties.
139      *
140      * @param compositionId The UUID of the automation composition definition
141      * @param automationComposition the automation composition
142      * @param acToBeUpdated the composition to be updated
143      * @return the result of the update
144      */
145     public InstantiationResponse updateDeployedAutomationComposition(UUID compositionId,
146                                                                      AutomationComposition automationComposition,
147                                                                      AutomationComposition acToBeUpdated) {
148
149         // Iterate and update the element property values
150         for (Map.Entry<UUID, AutomationCompositionElement> dbAcElement : acToBeUpdated.getElements().entrySet()) {
151             var elementId = dbAcElement.getKey();
152             if (automationComposition.getElements().containsKey(elementId)) {
153                 dbAcElement.getValue().getProperties().putAll(automationComposition.getElements().get(elementId)
154                         .getProperties());
155             }
156         }
157         // Publish property update event to the participants
158         supervisionAcHandler.update(acToBeUpdated);
159
160         var validationResult = validateAutomationComposition(acToBeUpdated);
161         if (!validationResult.isValid()) {
162             throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, validationResult.getResult());
163         }
164         automationComposition = automationCompositionProvider.updateAutomationComposition(acToBeUpdated);
165         var response = new InstantiationResponse();
166         var instanceId = automationComposition.getInstanceId();
167         response.setInstanceId(instanceId);
168         response.setAffectedAutomationComposition(automationComposition.getKey().asIdentifier());
169         return response;
170     }
171
172
173     /**
174      * Validate AutomationComposition.
175      *
176      * @param automationComposition AutomationComposition to validate
177      * @return the result of validation
178      */
179     private BeanValidationResult validateAutomationComposition(AutomationComposition automationComposition) {
180
181         var result = new BeanValidationResult("AutomationComposition", automationComposition);
182         var acDefinitionOpt = acDefinitionProvider.findAcDefinition(automationComposition.getCompositionId());
183         if (acDefinitionOpt.isEmpty()) {
184             result.addResult(new ObjectValidationResult("ServiceTemplate", "", ValidationStatus.INVALID,
185                     "Commissioned automation composition definition not found"));
186             return result;
187         }
188         if (!AcTypeState.PRIMED.equals(acDefinitionOpt.get().getState())) {
189             result.addResult(new ObjectValidationResult("ServiceTemplate", acDefinitionOpt.get().getState(),
190                     ValidationStatus.INVALID, "Commissioned automation composition definition not primed"));
191             return result;
192         }
193         result.addResult(AcmUtils.validateAutomationComposition(automationComposition,
194                 acDefinitionOpt.get().getServiceTemplate()));
195
196         if (result.isValid()) {
197             for (var element : automationComposition.getElements().values()) {
198                 var name = element.getDefinition().getName();
199                 var participantId = acDefinitionOpt.get().getElementStateMap().get(name).getParticipantId();
200                 element.setParticipantId(participantId);
201             }
202         }
203
204         return result;
205     }
206
207     /**
208      * Get Automation Composition.
209      *
210      * @param compositionId The UUID of the automation composition definition
211      * @param instanceId The UUID of the automation composition instance
212      * @return the Automation Composition
213      */
214     @Transactional(readOnly = true)
215     public AutomationComposition getAutomationComposition(UUID compositionId, UUID instanceId) {
216         var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
217         if (!automationComposition.getCompositionId().equals(compositionId)) {
218             throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
219                     automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
220         }
221         return automationComposition;
222     }
223
224     /**
225      * Delete the automation composition with the given name and version.
226      *
227      * @param compositionId The UUID of the automation composition definition
228      * @param instanceId The UUID of the automation composition instance
229      * @return the result of the deletion
230      */
231     public InstantiationResponse deleteAutomationComposition(UUID compositionId, UUID instanceId) {
232         var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
233         if (!compositionId.equals(automationComposition.getCompositionId())) {
234             throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
235                     automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
236         }
237         if (!DeployState.UNDEPLOYED.equals(automationComposition.getDeployState())) {
238             throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
239                     "Automation composition state is still " + automationComposition.getDeployState());
240         }
241         var response = new InstantiationResponse();
242         var acDefinition = acDefinitionProvider.getAcDefinition(automationComposition.getCompositionId());
243         supervisionAcHandler.delete(automationComposition, acDefinition);
244         response.setInstanceId(automationComposition.getInstanceId());
245         response.setAffectedAutomationComposition(automationComposition.getKey().asIdentifier());
246         return response;
247     }
248
249     /**
250      * Get the requested automation compositions.
251      *
252      * @param name the name of the automation composition to get, null for all automation compositions
253      * @param version the version of the automation composition to get, null for all automation compositions
254      * @return the automation compositions
255      */
256     @Transactional(readOnly = true)
257     public AutomationCompositions getAutomationCompositions(UUID compositionId, String name, String version) {
258         var automationCompositions = new AutomationCompositions();
259         automationCompositions.setAutomationCompositionList(
260                 automationCompositionProvider.getAutomationCompositions(compositionId, name, version));
261
262         return automationCompositions;
263     }
264
265     /**
266      * Handle Composition Instance State.
267      *
268      * @param compositionId the compositionId
269      * @param instanceId the instanceId
270      * @param acInstanceStateUpdate the AcInstanceStateUpdate
271      */
272     public void compositionInstanceState(UUID compositionId, UUID instanceId,
273             @Valid AcInstanceStateUpdate acInstanceStateUpdate) {
274         var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
275         if (!compositionId.equals(automationComposition.getCompositionId())) {
276             throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
277                     automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
278         }
279         var acDefinition = acDefinitionProvider.getAcDefinition(automationComposition.getCompositionId());
280         var result = acInstanceStateResolver.resolve(acInstanceStateUpdate.getDeployOrder(),
281                 acInstanceStateUpdate.getLockOrder(), automationComposition.getDeployState(),
282                 automationComposition.getLockState());
283         switch (result) {
284             case "DEPLOY":
285                 supervisionAcHandler.deploy(automationComposition, acDefinition);
286                 break;
287
288             case "UNDEPLOY":
289                 supervisionAcHandler.undeploy(automationComposition, acDefinition);
290                 break;
291
292             case "LOCK":
293                 supervisionAcHandler.lock(automationComposition, acDefinition);
294                 break;
295
296             case "UNLOCK":
297                 supervisionAcHandler.unlock(automationComposition, acDefinition);
298                 break;
299
300             default:
301                 throw new PfModelRuntimeException(Status.BAD_REQUEST, "Not valid " + acInstanceStateUpdate);
302         }
303     }
304 }