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 result.addResult(automationCompositionProvider.validateElementIds(automationComposition));
242 if (result.isValid()) {
243 for (var element : automationComposition.getElements().values()) {
244 var name = element.getDefinition().getName();
245 var participantId = acDefinitionOpt.get().getElementStateMap().get(name).getParticipantId();
246 element.setParticipantId(participantId);
254 * Get Automation Composition.
256 * @param compositionId The UUID of the automation composition definition
257 * @param instanceId The UUID of the automation composition instance
258 * @return the Automation Composition
260 @Transactional(readOnly = true)
261 public AutomationComposition getAutomationComposition(@NonNull UUID compositionId, UUID instanceId) {
262 var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
263 if (!compositionId.equals(automationComposition.getCompositionId())
264 && !compositionId.equals(automationComposition.getCompositionTargetId())) {
265 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
266 automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
268 return automationComposition;
272 * Delete the automation composition with the given name and version.
274 * @param compositionId The UUID of the automation composition definition
275 * @param instanceId The UUID of the automation composition instance
276 * @return the result of the deletion
278 public InstantiationResponse deleteAutomationComposition(UUID compositionId, UUID instanceId) {
279 var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
280 if (!compositionId.equals(automationComposition.getCompositionId())) {
281 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
282 automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
284 if (!DeployState.UNDEPLOYED.equals(automationComposition.getDeployState())
285 && !DeployState.DELETING.equals(automationComposition.getDeployState())) {
286 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
287 "Automation composition state is still " + automationComposition.getDeployState());
289 if (DeployState.DELETING.equals(automationComposition.getDeployState())
290 && StateChangeResult.NO_ERROR.equals(automationComposition.getStateChangeResult())) {
291 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
292 "Automation composition state is still " + automationComposition.getDeployState());
294 if (automationComposition.getRestarting() != null) {
295 throw new PfModelRuntimeException(Status.BAD_REQUEST, "There is a restarting process, Delete not allowed");
297 var acDefinition = acDefinitionProvider.getAcDefinition(automationComposition.getCompositionId());
298 var participantIds = acDefinition.getElementStateMap().values().stream()
299 .map(NodeTemplateState::getParticipantId).collect(Collectors.toSet());
300 acmParticipantProvider.verifyParticipantState(participantIds);
301 supervisionAcHandler.delete(automationComposition, acDefinition);
302 var response = new InstantiationResponse();
303 response.setInstanceId(automationComposition.getInstanceId());
304 response.setAffectedAutomationComposition(automationComposition.getKey().asIdentifier());
309 * Get the requested automation compositions.
311 * @param name the name of the automation composition to get, null for all automation compositions
312 * @param version the version of the automation composition to get, null for all automation compositions
313 * @return the automation compositions
315 @Transactional(readOnly = true)
316 public AutomationCompositions getAutomationCompositions(UUID compositionId, String name, String version) {
317 var automationCompositions = new AutomationCompositions();
318 automationCompositions.setAutomationCompositionList(
319 automationCompositionProvider.getAutomationCompositions(compositionId, name, version));
321 return automationCompositions;
325 * Handle Composition Instance State.
327 * @param compositionId the compositionId
328 * @param instanceId the instanceId
329 * @param acInstanceStateUpdate the AcInstanceStateUpdate
331 public void compositionInstanceState(UUID compositionId, UUID instanceId,
332 @Valid AcInstanceStateUpdate acInstanceStateUpdate) {
333 var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
334 if (!compositionId.equals(automationComposition.getCompositionId())) {
335 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
336 automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
338 var acDefinition = acDefinitionProvider.getAcDefinition(automationComposition.getCompositionId());
340 var participantIds = acDefinition.getElementStateMap().values().stream()
341 .map(NodeTemplateState::getParticipantId).collect(Collectors.toSet());
343 acmParticipantProvider.verifyParticipantState(participantIds);
344 var result = acInstanceStateResolver.resolve(acInstanceStateUpdate.getDeployOrder(),
345 acInstanceStateUpdate.getLockOrder(), automationComposition.getDeployState(),
346 automationComposition.getLockState(), automationComposition.getStateChangeResult());
349 supervisionAcHandler.deploy(automationComposition, acDefinition);
353 supervisionAcHandler.undeploy(automationComposition, acDefinition);
357 supervisionAcHandler.lock(automationComposition, acDefinition);
361 supervisionAcHandler.unlock(automationComposition, acDefinition);
365 throw new PfModelRuntimeException(Status.BAD_REQUEST, "Not valid " + acInstanceStateUpdate);