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 java.util.UUID;
25 import java.util.stream.Collectors;
26 import javax.validation.Valid;
27 import javax.ws.rs.core.Response;
28 import javax.ws.rs.core.Response.Status;
29 import lombok.AllArgsConstructor;
30 import org.onap.policy.clamp.acm.runtime.participants.AcmParticipantProvider;
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.AutomationCompositions;
35 import org.onap.policy.clamp.models.acm.concepts.DeployState;
36 import org.onap.policy.clamp.models.acm.concepts.LockState;
37 import org.onap.policy.clamp.models.acm.concepts.NodeTemplateState;
38 import org.onap.policy.clamp.models.acm.concepts.StateChangeResult;
39 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.AcInstanceStateUpdate;
40 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.InstantiationResponse;
41 import org.onap.policy.clamp.models.acm.persistence.provider.AcDefinitionProvider;
42 import org.onap.policy.clamp.models.acm.persistence.provider.AcInstanceStateResolver;
43 import org.onap.policy.clamp.models.acm.persistence.provider.AutomationCompositionProvider;
44 import org.onap.policy.clamp.models.acm.utils.AcmUtils;
45 import org.onap.policy.common.parameters.BeanValidationResult;
46 import org.onap.policy.common.parameters.ObjectValidationResult;
47 import org.onap.policy.common.parameters.ValidationStatus;
48 import org.onap.policy.models.base.PfModelRuntimeException;
49 import org.springframework.stereotype.Service;
50 import org.springframework.transaction.annotation.Transactional;
53 * This class is dedicated to the Instantiation of Commissioned automation composition.
58 public class AutomationCompositionInstantiationProvider {
59 private static final String DO_NOT_MATCH = " do not match with ";
61 private final AutomationCompositionProvider automationCompositionProvider;
62 private final AcDefinitionProvider acDefinitionProvider;
63 private final AcInstanceStateResolver acInstanceStateResolver;
64 private final SupervisionAcHandler supervisionAcHandler;
65 private final AcmParticipantProvider acmParticipantProvider;
68 * Create automation composition.
70 * @param compositionId The UUID of the automation composition definition
71 * @param automationComposition the automation composition
72 * @return the result of the instantiation operation
74 public InstantiationResponse createAutomationComposition(UUID compositionId,
75 AutomationComposition automationComposition) {
76 if (!compositionId.equals(automationComposition.getCompositionId())) {
77 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
78 automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
80 var checkAutomationCompositionOpt =
81 automationCompositionProvider.findAutomationComposition(automationComposition.getKey().asIdentifier());
82 if (checkAutomationCompositionOpt.isPresent()) {
83 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
84 automationComposition.getKey().asIdentifier() + " already defined");
87 var validationResult = validateAutomationComposition(automationComposition);
88 if (!validationResult.isValid()) {
89 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, validationResult.getResult());
91 automationComposition = automationCompositionProvider.createAutomationComposition(automationComposition);
93 var response = new InstantiationResponse();
94 response.setInstanceId(automationComposition.getInstanceId());
95 response.setAffectedAutomationComposition(automationComposition.getKey().asIdentifier());
101 * Update automation composition.
103 * @param compositionId The UUID of the automation composition definition
104 * @param automationComposition the automation composition
105 * @return the result of the update
107 public InstantiationResponse updateAutomationComposition(UUID compositionId,
108 AutomationComposition automationComposition) {
109 var response = new InstantiationResponse();
110 var instanceId = automationComposition.getInstanceId();
111 var acToUpdate = automationCompositionProvider.getAutomationComposition(instanceId);
112 if (!compositionId.equals(acToUpdate.getCompositionId())) {
113 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
114 automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
116 if (DeployState.UNDEPLOYED.equals(acToUpdate.getDeployState())) {
117 acToUpdate.setElements(automationComposition.getElements());
118 acToUpdate.setName(automationComposition.getName());
119 acToUpdate.setVersion(automationComposition.getVersion());
120 acToUpdate.setDescription(automationComposition.getDescription());
121 acToUpdate.setDerivedFrom(automationComposition.getDerivedFrom());
122 var validationResult = validateAutomationComposition(acToUpdate);
123 if (!validationResult.isValid()) {
124 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, validationResult.getResult());
126 automationComposition = automationCompositionProvider.updateAutomationComposition(acToUpdate);
127 response.setInstanceId(instanceId);
128 response.setAffectedAutomationComposition(automationComposition.getKey().asIdentifier());
131 } else if ((DeployState.DEPLOYED.equals(acToUpdate.getDeployState())
132 || DeployState.UPDATING.equals(acToUpdate.getDeployState()))
133 && LockState.LOCKED.equals(acToUpdate.getLockState())) {
134 return updateDeployedAutomationComposition(compositionId, automationComposition, acToUpdate);
136 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
137 "Not allowed to update in the state " + acToUpdate.getDeployState());
141 * Update deployed AC Element properties.
143 * @param compositionId The UUID of the automation composition definition
144 * @param automationComposition the automation composition
145 * @param acToBeUpdated the composition to be updated
146 * @return the result of the update
148 public InstantiationResponse updateDeployedAutomationComposition(UUID compositionId,
149 AutomationComposition automationComposition, AutomationComposition acToBeUpdated) {
151 // Iterate and update the element property values
152 for (var dbAcElement : acToBeUpdated.getElements().entrySet()) {
153 var elementId = dbAcElement.getKey();
154 if (automationComposition.getElements().containsKey(elementId)) {
155 dbAcElement.getValue().getProperties()
156 .putAll(automationComposition.getElements().get(elementId).getProperties());
159 if (automationComposition.getRestarting() != null) {
160 throw new PfModelRuntimeException(Status.BAD_REQUEST, "There is a restarting process, Update not allowed");
162 var validationResult = validateAutomationComposition(acToBeUpdated);
163 if (!validationResult.isValid()) {
164 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, validationResult.getResult());
167 // Publish property update event to the participants
168 supervisionAcHandler.update(acToBeUpdated);
170 automationComposition = automationCompositionProvider.updateAutomationComposition(acToBeUpdated);
171 var response = new InstantiationResponse();
172 var instanceId = automationComposition.getInstanceId();
173 response.setInstanceId(instanceId);
174 response.setAffectedAutomationComposition(automationComposition.getKey().asIdentifier());
179 * Validate AutomationComposition.
181 * @param automationComposition AutomationComposition to validate
182 * @return the result of validation
184 private BeanValidationResult validateAutomationComposition(AutomationComposition automationComposition) {
186 var result = new BeanValidationResult("AutomationComposition", automationComposition);
187 var acDefinitionOpt = acDefinitionProvider.findAcDefinition(automationComposition.getCompositionId());
188 if (acDefinitionOpt.isEmpty()) {
189 result.addResult(new ObjectValidationResult("ServiceTemplate", "", ValidationStatus.INVALID,
190 "Commissioned automation composition definition not found"));
193 if (!AcTypeState.PRIMED.equals(acDefinitionOpt.get().getState())) {
194 result.addResult(new ObjectValidationResult("ServiceTemplate.state", acDefinitionOpt.get().getState(),
195 ValidationStatus.INVALID, "Commissioned automation composition definition not primed"));
198 if (acDefinitionOpt.get().getRestarting() != null) {
200 new ObjectValidationResult("ServiceTemplate.restarting", acDefinitionOpt.get().getRestarting(),
201 ValidationStatus.INVALID, "There is a restarting process in composition"));
204 var participantIds = acDefinitionOpt.get().getElementStateMap().values().stream()
205 .map(NodeTemplateState::getParticipantId).collect(Collectors.toSet());
207 acmParticipantProvider.verifyParticipantState(participantIds);
209 result.addResult(AcmUtils.validateAutomationComposition(automationComposition,
210 acDefinitionOpt.get().getServiceTemplate()));
212 if (result.isValid()) {
213 for (var element : automationComposition.getElements().values()) {
214 var name = element.getDefinition().getName();
215 var participantId = acDefinitionOpt.get().getElementStateMap().get(name).getParticipantId();
216 element.setParticipantId(participantId);
224 * Get Automation Composition.
226 * @param compositionId The UUID of the automation composition definition
227 * @param instanceId The UUID of the automation composition instance
228 * @return the Automation Composition
230 @Transactional(readOnly = true)
231 public AutomationComposition getAutomationComposition(UUID compositionId, UUID instanceId) {
232 var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
233 if (!automationComposition.getCompositionId().equals(compositionId)) {
234 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
235 automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
237 return automationComposition;
241 * Delete the automation composition with the given name and version.
243 * @param compositionId The UUID of the automation composition definition
244 * @param instanceId The UUID of the automation composition instance
245 * @return the result of the deletion
247 public InstantiationResponse deleteAutomationComposition(UUID compositionId, UUID instanceId) {
248 var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
249 if (!compositionId.equals(automationComposition.getCompositionId())) {
250 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
251 automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
253 if (!DeployState.UNDEPLOYED.equals(automationComposition.getDeployState())
254 && !DeployState.DELETING.equals(automationComposition.getDeployState())) {
255 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
256 "Automation composition state is still " + automationComposition.getDeployState());
258 if (DeployState.DELETING.equals(automationComposition.getDeployState())
259 && StateChangeResult.NO_ERROR.equals(automationComposition.getStateChangeResult())) {
260 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
261 "Automation composition state is still " + automationComposition.getDeployState());
263 if (automationComposition.getRestarting() != null) {
264 throw new PfModelRuntimeException(Status.BAD_REQUEST, "There is a restarting process, Delete not allowed");
266 var acDefinition = acDefinitionProvider.getAcDefinition(automationComposition.getCompositionId());
267 if (acDefinition != null) {
268 var participantIds = acDefinition.getElementStateMap().values().stream()
269 .map(NodeTemplateState::getParticipantId).collect(Collectors.toSet());
270 acmParticipantProvider.verifyParticipantState(participantIds);
272 supervisionAcHandler.delete(automationComposition, acDefinition);
273 var response = new InstantiationResponse();
274 response.setInstanceId(automationComposition.getInstanceId());
275 response.setAffectedAutomationComposition(automationComposition.getKey().asIdentifier());
280 * Get the requested automation compositions.
282 * @param name the name of the automation composition to get, null for all automation compositions
283 * @param version the version of the automation composition to get, null for all automation compositions
284 * @return the automation compositions
286 @Transactional(readOnly = true)
287 public AutomationCompositions getAutomationCompositions(UUID compositionId, String name, String version) {
288 var automationCompositions = new AutomationCompositions();
289 automationCompositions.setAutomationCompositionList(
290 automationCompositionProvider.getAutomationCompositions(compositionId, name, version));
292 return automationCompositions;
296 * Handle Composition Instance State.
298 * @param compositionId the compositionId
299 * @param instanceId the instanceId
300 * @param acInstanceStateUpdate the AcInstanceStateUpdate
302 public void compositionInstanceState(UUID compositionId, UUID instanceId,
303 @Valid AcInstanceStateUpdate acInstanceStateUpdate) {
304 var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
305 if (!compositionId.equals(automationComposition.getCompositionId())) {
306 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
307 automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
309 var acDefinition = acDefinitionProvider.getAcDefinition(automationComposition.getCompositionId());
311 var participantIds = acDefinition.getElementStateMap().values().stream()
312 .map(NodeTemplateState::getParticipantId).collect(Collectors.toSet());
314 acmParticipantProvider.verifyParticipantState(participantIds);
315 var result = acInstanceStateResolver.resolve(acInstanceStateUpdate.getDeployOrder(),
316 acInstanceStateUpdate.getLockOrder(), automationComposition.getDeployState(),
317 automationComposition.getLockState(), automationComposition.getStateChangeResult());
320 supervisionAcHandler.deploy(automationComposition, acDefinition);
324 supervisionAcHandler.undeploy(automationComposition, acDefinition);
328 supervisionAcHandler.lock(automationComposition, acDefinition);
332 supervisionAcHandler.unlock(automationComposition, acDefinition);
336 throw new PfModelRuntimeException(Status.BAD_REQUEST, "Not valid " + acInstanceStateUpdate);