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 org.onap.policy.clamp.acm.runtime.main.parameters.AcRuntimeParameterGroup;
31 import org.onap.policy.clamp.acm.runtime.participants.AcmParticipantProvider;
32 import org.onap.policy.clamp.acm.runtime.supervision.SupervisionAcHandler;
33 import org.onap.policy.clamp.models.acm.concepts.AcTypeState;
34 import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
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.concepts.NodeTemplateState;
39 import org.onap.policy.clamp.models.acm.concepts.StateChangeResult;
40 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.AcInstanceStateUpdate;
41 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.InstantiationResponse;
42 import org.onap.policy.clamp.models.acm.persistence.provider.AcDefinitionProvider;
43 import org.onap.policy.clamp.models.acm.persistence.provider.AcInstanceStateResolver;
44 import org.onap.policy.clamp.models.acm.persistence.provider.AutomationCompositionProvider;
45 import org.onap.policy.clamp.models.acm.utils.AcmUtils;
46 import org.onap.policy.common.parameters.BeanValidationResult;
47 import org.onap.policy.common.parameters.ObjectValidationResult;
48 import org.onap.policy.common.parameters.ValidationStatus;
49 import org.onap.policy.models.base.PfModelRuntimeException;
50 import org.springframework.stereotype.Service;
51 import org.springframework.transaction.annotation.Transactional;
54 * This class is dedicated to the Instantiation of Commissioned automation composition.
59 public class AutomationCompositionInstantiationProvider {
60 private static final String DO_NOT_MATCH = " do not match with ";
62 private final AutomationCompositionProvider automationCompositionProvider;
63 private final AcDefinitionProvider acDefinitionProvider;
64 private final AcInstanceStateResolver acInstanceStateResolver;
65 private final SupervisionAcHandler supervisionAcHandler;
66 private final AcmParticipantProvider acmParticipantProvider;
67 private final AcRuntimeParameterGroup acRuntimeParameterGroup;
70 * Create automation composition.
72 * @param compositionId The UUID of the automation composition definition
73 * @param automationComposition the automation composition
74 * @return the result of the instantiation operation
76 public InstantiationResponse createAutomationComposition(UUID compositionId,
77 AutomationComposition automationComposition) {
78 if (!compositionId.equals(automationComposition.getCompositionId())) {
79 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
80 automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
82 var checkAutomationCompositionOpt =
83 automationCompositionProvider.findAutomationComposition(automationComposition.getKey().asIdentifier());
84 if (checkAutomationCompositionOpt.isPresent()) {
85 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
86 automationComposition.getKey().asIdentifier() + " already defined");
89 var validationResult = validateAutomationComposition(automationComposition);
90 if (!validationResult.isValid()) {
91 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, validationResult.getResult());
93 automationComposition = automationCompositionProvider.createAutomationComposition(automationComposition);
95 var response = new InstantiationResponse();
96 response.setInstanceId(automationComposition.getInstanceId());
97 response.setAffectedAutomationComposition(automationComposition.getKey().asIdentifier());
103 * Update automation composition.
105 * @param compositionId The UUID of the automation composition definition
106 * @param automationComposition the automation composition
107 * @return the result of the update
109 public InstantiationResponse updateAutomationComposition(UUID compositionId,
110 AutomationComposition automationComposition) {
111 var response = new InstantiationResponse();
112 var instanceId = automationComposition.getInstanceId();
113 var acToUpdate = automationCompositionProvider.getAutomationComposition(instanceId);
114 if (!compositionId.equals(acToUpdate.getCompositionId())) {
115 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
116 automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
118 if (DeployState.UNDEPLOYED.equals(acToUpdate.getDeployState())) {
119 acToUpdate.setElements(automationComposition.getElements());
120 acToUpdate.setName(automationComposition.getName());
121 acToUpdate.setVersion(automationComposition.getVersion());
122 acToUpdate.setDescription(automationComposition.getDescription());
123 acToUpdate.setDerivedFrom(automationComposition.getDerivedFrom());
124 var validationResult = validateAutomationComposition(acToUpdate);
125 if (!validationResult.isValid()) {
126 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, validationResult.getResult());
128 automationComposition = automationCompositionProvider.updateAutomationComposition(acToUpdate);
129 response.setInstanceId(instanceId);
130 response.setAffectedAutomationComposition(automationComposition.getKey().asIdentifier());
133 } else if ((DeployState.DEPLOYED.equals(acToUpdate.getDeployState())
134 || DeployState.UPDATING.equals(acToUpdate.getDeployState()))
135 && LockState.LOCKED.equals(acToUpdate.getLockState())) {
136 return updateDeployedAutomationComposition(compositionId, automationComposition, acToUpdate);
138 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
139 "Not allowed to update in the state " + acToUpdate.getDeployState());
143 * Update deployed AC Element properties.
145 * @param compositionId The UUID of the automation composition definition
146 * @param automationComposition the automation composition
147 * @param acToBeUpdated the composition to be updated
148 * @return the result of the update
150 public InstantiationResponse updateDeployedAutomationComposition(UUID compositionId,
151 AutomationComposition automationComposition, AutomationComposition acToBeUpdated) {
153 // Iterate and update the element property values
154 for (var dbAcElement : acToBeUpdated.getElements().entrySet()) {
155 var elementId = dbAcElement.getKey();
156 if (automationComposition.getElements().containsKey(elementId)) {
157 dbAcElement.getValue().getProperties()
158 .putAll(automationComposition.getElements().get(elementId).getProperties());
161 if (automationComposition.getRestarting() != null) {
162 throw new PfModelRuntimeException(Status.BAD_REQUEST, "There is a restarting process, Update not allowed");
164 var validationResult = validateAutomationComposition(acToBeUpdated);
165 if (!validationResult.isValid()) {
166 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, validationResult.getResult());
169 // Publish property update event to the participants
170 supervisionAcHandler.update(acToBeUpdated);
172 automationComposition = automationCompositionProvider.updateAutomationComposition(acToBeUpdated);
173 var response = new InstantiationResponse();
174 var instanceId = automationComposition.getInstanceId();
175 response.setInstanceId(instanceId);
176 response.setAffectedAutomationComposition(automationComposition.getKey().asIdentifier());
181 * Validate AutomationComposition.
183 * @param automationComposition AutomationComposition to validate
184 * @return the result of validation
186 private BeanValidationResult validateAutomationComposition(AutomationComposition automationComposition) {
188 var result = new BeanValidationResult("AutomationComposition", automationComposition);
189 var acDefinitionOpt = acDefinitionProvider.findAcDefinition(automationComposition.getCompositionId());
190 if (acDefinitionOpt.isEmpty()) {
191 result.addResult(new ObjectValidationResult("ServiceTemplate", "", ValidationStatus.INVALID,
192 "Commissioned automation composition definition not found"));
195 if (!AcTypeState.PRIMED.equals(acDefinitionOpt.get().getState())) {
196 result.addResult(new ObjectValidationResult("ServiceTemplate.state", acDefinitionOpt.get().getState(),
197 ValidationStatus.INVALID, "Commissioned automation composition definition not primed"));
200 if (acDefinitionOpt.get().getRestarting() != null) {
202 new ObjectValidationResult("ServiceTemplate.restarting", acDefinitionOpt.get().getRestarting(),
203 ValidationStatus.INVALID, "There is a restarting process in composition"));
206 var participantIds = acDefinitionOpt.get().getElementStateMap().values().stream()
207 .map(NodeTemplateState::getParticipantId).collect(Collectors.toSet());
209 acmParticipantProvider.verifyParticipantState(participantIds);
211 result.addResult(AcmUtils.validateAutomationComposition(automationComposition,
212 acDefinitionOpt.get().getServiceTemplate(),
213 acRuntimeParameterGroup.getAcmParameters().getToscaCompositionName()));
215 if (result.isValid()) {
216 for (var element : automationComposition.getElements().values()) {
217 var name = element.getDefinition().getName();
218 var participantId = acDefinitionOpt.get().getElementStateMap().get(name).getParticipantId();
219 element.setParticipantId(participantId);
227 * Get Automation Composition.
229 * @param compositionId The UUID of the automation composition definition
230 * @param instanceId The UUID of the automation composition instance
231 * @return the Automation Composition
233 @Transactional(readOnly = true)
234 public AutomationComposition getAutomationComposition(UUID compositionId, UUID instanceId) {
235 var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
236 if (!automationComposition.getCompositionId().equals(compositionId)) {
237 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
238 automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
240 return automationComposition;
244 * Delete the automation composition with the given name and version.
246 * @param compositionId The UUID of the automation composition definition
247 * @param instanceId The UUID of the automation composition instance
248 * @return the result of the deletion
250 public InstantiationResponse deleteAutomationComposition(UUID compositionId, UUID instanceId) {
251 var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
252 if (!compositionId.equals(automationComposition.getCompositionId())) {
253 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
254 automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
256 if (!DeployState.UNDEPLOYED.equals(automationComposition.getDeployState())
257 && !DeployState.DELETING.equals(automationComposition.getDeployState())) {
258 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
259 "Automation composition state is still " + automationComposition.getDeployState());
261 if (DeployState.DELETING.equals(automationComposition.getDeployState())
262 && StateChangeResult.NO_ERROR.equals(automationComposition.getStateChangeResult())) {
263 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
264 "Automation composition state is still " + automationComposition.getDeployState());
266 if (automationComposition.getRestarting() != null) {
267 throw new PfModelRuntimeException(Status.BAD_REQUEST, "There is a restarting process, Delete not allowed");
269 var acDefinition = acDefinitionProvider.getAcDefinition(automationComposition.getCompositionId());
270 if (acDefinition != null) {
271 var participantIds = acDefinition.getElementStateMap().values().stream()
272 .map(NodeTemplateState::getParticipantId).collect(Collectors.toSet());
273 acmParticipantProvider.verifyParticipantState(participantIds);
275 supervisionAcHandler.delete(automationComposition, acDefinition);
276 var response = new InstantiationResponse();
277 response.setInstanceId(automationComposition.getInstanceId());
278 response.setAffectedAutomationComposition(automationComposition.getKey().asIdentifier());
283 * Get the requested automation compositions.
285 * @param name the name of the automation composition to get, null for all automation compositions
286 * @param version the version of the automation composition to get, null for all automation compositions
287 * @return the automation compositions
289 @Transactional(readOnly = true)
290 public AutomationCompositions getAutomationCompositions(UUID compositionId, String name, String version) {
291 var automationCompositions = new AutomationCompositions();
292 automationCompositions.setAutomationCompositionList(
293 automationCompositionProvider.getAutomationCompositions(compositionId, name, version));
295 return automationCompositions;
299 * Handle Composition Instance State.
301 * @param compositionId the compositionId
302 * @param instanceId the instanceId
303 * @param acInstanceStateUpdate the AcInstanceStateUpdate
305 public void compositionInstanceState(UUID compositionId, UUID instanceId,
306 @Valid AcInstanceStateUpdate acInstanceStateUpdate) {
307 var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
308 if (!compositionId.equals(automationComposition.getCompositionId())) {
309 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
310 automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
312 var acDefinition = acDefinitionProvider.getAcDefinition(automationComposition.getCompositionId());
314 var participantIds = acDefinition.getElementStateMap().values().stream()
315 .map(NodeTemplateState::getParticipantId).collect(Collectors.toSet());
317 acmParticipantProvider.verifyParticipantState(participantIds);
318 var result = acInstanceStateResolver.resolve(acInstanceStateUpdate.getDeployOrder(),
319 acInstanceStateUpdate.getLockOrder(), automationComposition.getDeployState(),
320 automationComposition.getLockState(), automationComposition.getStateChangeResult());
323 supervisionAcHandler.deploy(automationComposition, acDefinition);
327 supervisionAcHandler.undeploy(automationComposition, acDefinition);
331 supervisionAcHandler.lock(automationComposition, acDefinition);
335 supervisionAcHandler.unlock(automationComposition, acDefinition);
339 throw new PfModelRuntimeException(Status.BAD_REQUEST, "Not valid " + acInstanceStateUpdate);