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