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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * SPDX-License-Identifier: Apache-2.0
19 * ============LICENSE_END=========================================================
22 package org.onap.policy.clamp.acm.runtime.instantiation;
24 import jakarta.validation.Valid;
25 import jakarta.ws.rs.core.Response;
26 import jakarta.ws.rs.core.Response.Status;
27 import java.util.UUID;
28 import java.util.stream.Collectors;
29 import lombok.AllArgsConstructor;
30 import lombok.NonNull;
31 import org.onap.policy.clamp.acm.runtime.main.parameters.AcRuntimeParameterGroup;
32 import org.onap.policy.clamp.acm.runtime.participants.AcmParticipantProvider;
33 import org.onap.policy.clamp.acm.runtime.supervision.SupervisionAcHandler;
34 import org.onap.policy.clamp.models.acm.concepts.AcTypeState;
35 import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
36 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositions;
37 import org.onap.policy.clamp.models.acm.concepts.DeployState;
38 import org.onap.policy.clamp.models.acm.concepts.LockState;
39 import org.onap.policy.clamp.models.acm.concepts.NodeTemplateState;
40 import org.onap.policy.clamp.models.acm.concepts.StateChangeResult;
41 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.AcInstanceStateUpdate;
42 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.InstantiationResponse;
43 import org.onap.policy.clamp.models.acm.persistence.provider.AcDefinitionProvider;
44 import org.onap.policy.clamp.models.acm.persistence.provider.AcInstanceStateResolver;
45 import org.onap.policy.clamp.models.acm.persistence.provider.AutomationCompositionProvider;
46 import org.onap.policy.clamp.models.acm.utils.AcmUtils;
47 import org.onap.policy.common.parameters.BeanValidationResult;
48 import org.onap.policy.common.parameters.ObjectValidationResult;
49 import org.onap.policy.common.parameters.ValidationStatus;
50 import org.onap.policy.models.base.PfModelRuntimeException;
51 import org.springframework.stereotype.Service;
52 import org.springframework.transaction.annotation.Transactional;
55 * This class is dedicated to the Instantiation of Commissioned automation composition.
60 public class AutomationCompositionInstantiationProvider {
61 private static final String DO_NOT_MATCH = " do not match with ";
63 private final AutomationCompositionProvider automationCompositionProvider;
64 private final AcDefinitionProvider acDefinitionProvider;
65 private final AcInstanceStateResolver acInstanceStateResolver;
66 private final SupervisionAcHandler supervisionAcHandler;
67 private final AcmParticipantProvider acmParticipantProvider;
68 private final AcRuntimeParameterGroup acRuntimeParameterGroup;
71 * Create automation composition.
73 * @param compositionId The UUID of the automation composition definition
74 * @param automationComposition the automation composition
75 * @return the result of the instantiation operation
77 public InstantiationResponse createAutomationComposition(UUID compositionId,
78 AutomationComposition automationComposition) {
79 if (!compositionId.equals(automationComposition.getCompositionId())) {
80 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
81 automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
83 var checkAutomationCompositionOpt =
84 automationCompositionProvider.findAutomationComposition(automationComposition.getKey().asIdentifier());
85 if (checkAutomationCompositionOpt.isPresent()) {
86 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
87 automationComposition.getKey().asIdentifier() + " already defined");
90 var validationResult = validateAutomationComposition(automationComposition);
91 if (!validationResult.isValid()) {
92 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, validationResult.getResult());
94 automationComposition = automationCompositionProvider.createAutomationComposition(automationComposition);
96 var response = new InstantiationResponse();
97 response.setInstanceId(automationComposition.getInstanceId());
98 response.setAffectedAutomationComposition(automationComposition.getKey().asIdentifier());
104 * Update automation composition.
106 * @param compositionId The UUID of the automation composition definition
107 * @param automationComposition the automation composition
108 * @return the result of the update
110 public InstantiationResponse updateAutomationComposition(UUID compositionId,
111 AutomationComposition automationComposition) {
112 var response = new InstantiationResponse();
113 var instanceId = automationComposition.getInstanceId();
114 var acToUpdate = automationCompositionProvider.getAutomationComposition(instanceId);
115 if (!compositionId.equals(acToUpdate.getCompositionId())) {
116 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
117 automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
119 if (DeployState.UNDEPLOYED.equals(acToUpdate.getDeployState())) {
120 acToUpdate.setElements(automationComposition.getElements());
121 acToUpdate.setName(automationComposition.getName());
122 acToUpdate.setVersion(automationComposition.getVersion());
123 acToUpdate.setDescription(automationComposition.getDescription());
124 acToUpdate.setDerivedFrom(automationComposition.getDerivedFrom());
125 var validationResult = validateAutomationComposition(acToUpdate);
126 if (!validationResult.isValid()) {
127 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, validationResult.getResult());
129 automationComposition = automationCompositionProvider.updateAutomationComposition(acToUpdate);
130 response.setInstanceId(instanceId);
131 response.setAffectedAutomationComposition(automationComposition.getKey().asIdentifier());
134 } else if ((DeployState.DEPLOYED.equals(acToUpdate.getDeployState())
135 || DeployState.UPDATING.equals(acToUpdate.getDeployState()))
136 && LockState.LOCKED.equals(acToUpdate.getLockState())) {
137 return updateDeployedAutomationComposition(compositionId, automationComposition, acToUpdate);
139 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
140 "Not allowed to update in the state " + acToUpdate.getDeployState());
144 * Update deployed AC Element properties.
146 * @param compositionId The UUID of the automation composition definition
147 * @param automationComposition the automation composition
148 * @param acToBeUpdated the composition to be updated
149 * @return the result of the update
151 public InstantiationResponse updateDeployedAutomationComposition(UUID compositionId,
152 AutomationComposition automationComposition, AutomationComposition acToBeUpdated) {
154 if (automationComposition.getCompositionTargetId() != null
155 && !DeployState.DEPLOYED.equals(acToBeUpdated.getDeployState())) {
156 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
157 "Not allowed to migrate in the state " + acToBeUpdated.getDeployState());
160 // Iterate and update the element property values
161 for (var dbAcElement : acToBeUpdated.getElements().entrySet()) {
162 var elementId = dbAcElement.getKey();
163 if (automationComposition.getElements().containsKey(elementId)) {
164 dbAcElement.getValue().getProperties()
165 .putAll(automationComposition.getElements().get(elementId).getProperties());
168 if (automationComposition.getRestarting() != null) {
169 throw new PfModelRuntimeException(Status.BAD_REQUEST, "There is a restarting process, Update not allowed");
172 if (automationComposition.getCompositionTargetId() != null) {
173 var validationResult =
174 validateAutomationComposition(acToBeUpdated, automationComposition.getCompositionTargetId());
175 if (!validationResult.isValid()) {
176 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, validationResult.getResult());
178 acToBeUpdated.setCompositionTargetId(automationComposition.getCompositionTargetId());
180 // Publish migrate event to the participants
181 supervisionAcHandler.migrate(acToBeUpdated, automationComposition.getCompositionTargetId());
183 var validationResult = validateAutomationComposition(acToBeUpdated);
184 if (!validationResult.isValid()) {
185 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, validationResult.getResult());
187 // Publish property update event to the participants
188 supervisionAcHandler.update(acToBeUpdated);
191 automationComposition = automationCompositionProvider.updateAutomationComposition(acToBeUpdated);
192 var response = new InstantiationResponse();
193 var instanceId = automationComposition.getInstanceId();
194 response.setInstanceId(instanceId);
195 response.setAffectedAutomationComposition(automationComposition.getKey().asIdentifier());
199 private BeanValidationResult validateAutomationComposition(AutomationComposition automationComposition) {
200 return validateAutomationComposition(automationComposition, automationComposition.getCompositionId());
204 * Validate AutomationComposition.
206 * @param automationComposition AutomationComposition to validate
207 * @param compositionId the composition id
208 * @return the result of validation
210 private BeanValidationResult validateAutomationComposition(AutomationComposition automationComposition,
211 UUID compositionId) {
213 var result = new BeanValidationResult("AutomationComposition", automationComposition);
214 var acDefinitionOpt = acDefinitionProvider.findAcDefinition(compositionId);
215 if (acDefinitionOpt.isEmpty()) {
216 result.addResult(new ObjectValidationResult("ServiceTemplate", compositionId, ValidationStatus.INVALID,
217 "Commissioned automation composition definition not found"));
220 if (!AcTypeState.PRIMED.equals(acDefinitionOpt.get().getState())) {
221 result.addResult(new ObjectValidationResult("ServiceTemplate.state", acDefinitionOpt.get().getState(),
222 ValidationStatus.INVALID, "Commissioned automation composition definition not primed"));
225 if (acDefinitionOpt.get().getRestarting() != null) {
227 new ObjectValidationResult("ServiceTemplate.restarting", acDefinitionOpt.get().getRestarting(),
228 ValidationStatus.INVALID, "There is a restarting process in composition"));
231 var participantIds = acDefinitionOpt.get().getElementStateMap().values().stream()
232 .map(NodeTemplateState::getParticipantId).collect(Collectors.toSet());
234 acmParticipantProvider.verifyParticipantState(participantIds);
236 result.addResult(AcmUtils.validateAutomationComposition(automationComposition,
237 acDefinitionOpt.get().getServiceTemplate(),
238 acRuntimeParameterGroup.getAcmParameters().getToscaCompositionName()));
240 if (result.isValid()) {
241 for (var element : automationComposition.getElements().values()) {
242 var name = element.getDefinition().getName();
243 var participantId = acDefinitionOpt.get().getElementStateMap().get(name).getParticipantId();
244 element.setParticipantId(participantId);
252 * Get Automation Composition.
254 * @param compositionId The UUID of the automation composition definition
255 * @param instanceId The UUID of the automation composition instance
256 * @return the Automation Composition
258 @Transactional(readOnly = true)
259 public AutomationComposition getAutomationComposition(@NonNull UUID compositionId, UUID instanceId) {
260 var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
261 if (!compositionId.equals(automationComposition.getCompositionId())
262 && !compositionId.equals(automationComposition.getCompositionTargetId())) {
263 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
264 automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
266 return automationComposition;
270 * Delete the automation composition with the given name and version.
272 * @param compositionId The UUID of the automation composition definition
273 * @param instanceId The UUID of the automation composition instance
274 * @return the result of the deletion
276 public InstantiationResponse deleteAutomationComposition(UUID compositionId, UUID instanceId) {
277 var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
278 if (!compositionId.equals(automationComposition.getCompositionId())) {
279 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
280 automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
282 if (!DeployState.UNDEPLOYED.equals(automationComposition.getDeployState())
283 && !DeployState.DELETING.equals(automationComposition.getDeployState())) {
284 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
285 "Automation composition state is still " + automationComposition.getDeployState());
287 if (DeployState.DELETING.equals(automationComposition.getDeployState())
288 && StateChangeResult.NO_ERROR.equals(automationComposition.getStateChangeResult())) {
289 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
290 "Automation composition state is still " + automationComposition.getDeployState());
292 if (automationComposition.getRestarting() != null) {
293 throw new PfModelRuntimeException(Status.BAD_REQUEST, "There is a restarting process, Delete not allowed");
295 var acDefinition = acDefinitionProvider.getAcDefinition(automationComposition.getCompositionId());
296 var participantIds = acDefinition.getElementStateMap().values().stream()
297 .map(NodeTemplateState::getParticipantId).collect(Collectors.toSet());
298 acmParticipantProvider.verifyParticipantState(participantIds);
299 supervisionAcHandler.delete(automationComposition, acDefinition);
300 var response = new InstantiationResponse();
301 response.setInstanceId(automationComposition.getInstanceId());
302 response.setAffectedAutomationComposition(automationComposition.getKey().asIdentifier());
307 * Get the requested automation compositions.
309 * @param name the name of the automation composition to get, null for all automation compositions
310 * @param version the version of the automation composition to get, null for all automation compositions
311 * @return the automation compositions
313 @Transactional(readOnly = true)
314 public AutomationCompositions getAutomationCompositions(UUID compositionId, String name, String version) {
315 var automationCompositions = new AutomationCompositions();
316 automationCompositions.setAutomationCompositionList(
317 automationCompositionProvider.getAutomationCompositions(compositionId, name, version));
319 return automationCompositions;
323 * Handle Composition Instance State.
325 * @param compositionId the compositionId
326 * @param instanceId the instanceId
327 * @param acInstanceStateUpdate the AcInstanceStateUpdate
329 public void compositionInstanceState(UUID compositionId, UUID instanceId,
330 @Valid AcInstanceStateUpdate acInstanceStateUpdate) {
331 var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
332 if (!compositionId.equals(automationComposition.getCompositionId())) {
333 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
334 automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
336 var acDefinition = acDefinitionProvider.getAcDefinition(automationComposition.getCompositionId());
338 var participantIds = acDefinition.getElementStateMap().values().stream()
339 .map(NodeTemplateState::getParticipantId).collect(Collectors.toSet());
341 acmParticipantProvider.verifyParticipantState(participantIds);
342 var result = acInstanceStateResolver.resolve(acInstanceStateUpdate.getDeployOrder(),
343 acInstanceStateUpdate.getLockOrder(), automationComposition.getDeployState(),
344 automationComposition.getLockState(), automationComposition.getStateChangeResult());
347 supervisionAcHandler.deploy(automationComposition, acDefinition);
351 supervisionAcHandler.undeploy(automationComposition, acDefinition);
355 supervisionAcHandler.lock(automationComposition, acDefinition);
359 supervisionAcHandler.unlock(automationComposition, acDefinition);
363 throw new PfModelRuntimeException(Status.BAD_REQUEST, "Not valid " + acInstanceStateUpdate);