4e9ca3d6b1281d0ace06ec387df33818551beebb
[policy/clamp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * Copyright (C) 2021-2025 OpenInfra Foundation Europe. All rights reserved.
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 jakarta.validation.Valid;
25 import jakarta.ws.rs.core.Response.Status;
26 import java.util.List;
27 import java.util.UUID;
28 import java.util.stream.Collectors;
29 import lombok.NonNull;
30 import lombok.RequiredArgsConstructor;
31 import org.onap.policy.clamp.acm.runtime.main.parameters.AcRuntimeParameterGroup;
32 import org.onap.policy.clamp.acm.runtime.main.utils.EncryptionUtils;
33 import org.onap.policy.clamp.acm.runtime.supervision.SupervisionAcHandler;
34 import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
35 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionDefinition;
36 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElement;
37 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositions;
38 import org.onap.policy.clamp.models.acm.concepts.DeployState;
39 import org.onap.policy.clamp.models.acm.concepts.LockState;
40 import org.onap.policy.clamp.models.acm.concepts.ParticipantUtils;
41 import org.onap.policy.clamp.models.acm.concepts.StateChangeResult;
42 import org.onap.policy.clamp.models.acm.concepts.SubState;
43 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.AcInstanceStateUpdate;
44 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.DeployOrder;
45 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.InstantiationResponse;
46 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.LockOrder;
47 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.SubOrder;
48 import org.onap.policy.clamp.models.acm.persistence.provider.AcDefinitionProvider;
49 import org.onap.policy.clamp.models.acm.persistence.provider.AcInstanceStateResolver;
50 import org.onap.policy.clamp.models.acm.persistence.provider.AutomationCompositionProvider;
51 import org.onap.policy.clamp.models.acm.persistence.provider.ParticipantProvider;
52 import org.onap.policy.clamp.models.acm.utils.AcmUtils;
53 import org.onap.policy.common.parameters.BeanValidationResult;
54 import org.onap.policy.models.base.PfModelRuntimeException;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
57 import org.springframework.data.domain.Pageable;
58 import org.springframework.stereotype.Service;
59 import org.springframework.transaction.annotation.Transactional;
60
61 /**
62  * This class is dedicated to the Instantiation of Commissioned automation composition.
63  */
64 @Service
65 @Transactional
66 @RequiredArgsConstructor
67 public class AutomationCompositionInstantiationProvider {
68     private static final String DO_NOT_MATCH = " do not match with ";
69     private static final String ELEMENT_ID_NOT_PRESENT = "Element id not present ";
70     private static final String NOT_VALID_ORDER =
71         "Not valid order %s; DeployState: %s; LockState: %s; SubState: %s; StateChangeResult: %s";
72
73     private static final Logger LOGGER = LoggerFactory.getLogger(AutomationCompositionInstantiationProvider.class);
74
75     private final AutomationCompositionProvider automationCompositionProvider;
76     private final AcDefinitionProvider acDefinitionProvider;
77     private final AcInstanceStateResolver acInstanceStateResolver;
78     private final SupervisionAcHandler supervisionAcHandler;
79     private final ParticipantProvider participantProvider;
80     private final AcRuntimeParameterGroup acRuntimeParameterGroup;
81     private final EncryptionUtils encryptionUtils;
82
83     /**
84      * Create automation composition.
85      *
86      * @param compositionId         The UUID of the automation composition definition
87      * @param automationComposition the automation composition
88      * @return the result of the instantiation operation
89      */
90     public InstantiationResponse createAutomationComposition(UUID compositionId,
91                                                              AutomationComposition automationComposition) {
92         AutomationCompositionProvider.validateInstanceEndpoint(compositionId, automationComposition);
93         automationCompositionProvider.validateNameVersion(automationComposition.getKey().asIdentifier());
94
95         var acDefinition = acDefinitionProvider.getAcDefinition(compositionId);
96         AcDefinitionProvider.checkPrimedComposition(acDefinition);
97         var validationResult = validateAutomationComposition(automationComposition, acDefinition);
98         if (!validationResult.isValid()) {
99             throw new PfModelRuntimeException(Status.BAD_REQUEST, validationResult.getResult());
100         }
101         encryptInstanceProperties(automationComposition, compositionId);
102         automationComposition = automationCompositionProvider.createAutomationComposition(automationComposition);
103
104         return createInstantiationResponse(automationComposition);
105     }
106
107     private InstantiationResponse createInstantiationResponse(AutomationComposition automationComposition) {
108         var response = new InstantiationResponse();
109         response.setInstanceId(automationComposition.getInstanceId());
110         response.setAffectedAutomationComposition(automationComposition.getKey().asIdentifier());
111         return response;
112     }
113
114     /**
115      * Update automation composition.
116      *
117      * @param compositionId         The UUID of the automation composition definition
118      * @param automationComposition the automation composition
119      * @return the result of the update
120      */
121     public InstantiationResponse updateAutomationComposition(UUID compositionId,
122                                                              AutomationComposition automationComposition) {
123         var instanceId = automationComposition.getInstanceId();
124         var acToUpdate = automationCompositionProvider.getAutomationComposition(instanceId);
125         AutomationCompositionProvider.validateInstanceEndpoint(compositionId, acToUpdate);
126         var acDefinition = acDefinitionProvider.getAcDefinition(compositionId);
127         AcDefinitionProvider.checkPrimedComposition(acDefinition);
128         if (DeployState.UNDEPLOYED.equals(acToUpdate.getDeployState())) {
129             acToUpdate.setElements(automationComposition.getElements());
130             acToUpdate.setName(automationComposition.getName());
131             acToUpdate.setVersion(automationComposition.getVersion());
132             acToUpdate.setDescription(automationComposition.getDescription());
133             acToUpdate.setDerivedFrom(automationComposition.getDerivedFrom());
134             var validationResult = validateAutomationComposition(acToUpdate, acDefinition);
135             if (!validationResult.isValid()) {
136                 throw new PfModelRuntimeException(Status.BAD_REQUEST, validationResult.getResult());
137             }
138             encryptInstanceProperties(acToUpdate, compositionId);
139             automationComposition = automationCompositionProvider.updateAutomationComposition(acToUpdate);
140             return createInstantiationResponse(automationComposition);
141
142         }
143
144         var deployOrder = DeployOrder.UPDATE;
145         var subOrder = SubOrder.NONE;
146
147         if (automationComposition.getCompositionTargetId() != null) {
148
149             if (Boolean.TRUE.equals(automationComposition.getPrecheck())) {
150                 subOrder = SubOrder.MIGRATE_PRECHECK;
151                 deployOrder = DeployOrder.NONE;
152             } else {
153                 deployOrder = DeployOrder.MIGRATE;
154             }
155         }
156         var result = acInstanceStateResolver.resolve(deployOrder, LockOrder.NONE, subOrder,
157             acToUpdate.getDeployState(), acToUpdate.getLockState(), acToUpdate.getSubState(),
158             acToUpdate.getStateChangeResult());
159         return switch (result) {
160             case "UPDATE" -> updateDeployedAutomationComposition(automationComposition, acToUpdate, acDefinition);
161
162             case "MIGRATE" -> migrateAutomationComposition(automationComposition, acToUpdate, acDefinition);
163
164             case "MIGRATE_PRECHECK" -> migratePrecheckAc(automationComposition, acToUpdate, acDefinition);
165
166             default -> throw new PfModelRuntimeException(Status.BAD_REQUEST,
167                 "Not allowed to " + deployOrder + " in the state " + acToUpdate.getDeployState());
168         };
169     }
170
171     /**
172      * Update deployed AC Element properties.
173      *
174      * @param automationComposition the automation composition
175      * @param acToBeUpdated         the composition to be updated
176      * @return the result of the update
177      */
178     private InstantiationResponse updateDeployedAutomationComposition(
179             AutomationComposition automationComposition, AutomationComposition acToBeUpdated,
180             AutomationCompositionDefinition acDefinition) {
181         // save copy in case of a rollback
182         automationCompositionProvider.copyAcElementsBeforeUpdate(acToBeUpdated);
183
184         // Iterate and update the element property values
185         for (var element : automationComposition.getElements().entrySet()) {
186             var elementId = element.getKey();
187             var dbAcElement = acToBeUpdated.getElements().get(elementId);
188             if (dbAcElement == null) {
189                 throw new PfModelRuntimeException(Status.BAD_REQUEST, ELEMENT_ID_NOT_PRESENT + elementId);
190             }
191             AcmUtils.recursiveMerge(dbAcElement.getProperties(), element.getValue().getProperties());
192         }
193
194         var validationResult = validateAutomationComposition(acToBeUpdated, acDefinition);
195         if (!validationResult.isValid()) {
196             throw new PfModelRuntimeException(Status.BAD_REQUEST, validationResult.getResult());
197         }
198         updateAcForProperties(acToBeUpdated);
199
200         var acToPublish = new AutomationComposition(acToBeUpdated);
201         encryptInstanceProperties(acToBeUpdated, acToBeUpdated.getCompositionId());
202
203         automationComposition = automationCompositionProvider.updateAutomationComposition(acToBeUpdated);
204         // Publish property update event to the participants
205         supervisionAcHandler.update(acToPublish, acDefinition.getRevisionId());
206         return createInstantiationResponse(automationComposition);
207     }
208
209     private InstantiationResponse migrateAutomationComposition(
210             AutomationComposition automationComposition, AutomationComposition acToBeUpdated,
211             AutomationCompositionDefinition acDefinition) {
212
213         if (!DeployState.DEPLOYED.equals(acToBeUpdated.getDeployState())) {
214             throw new PfModelRuntimeException(Status.BAD_REQUEST,
215                 "Not allowed to migrate in the state " + acToBeUpdated.getDeployState());
216         }
217         // make copy for rollback
218         automationCompositionProvider.copyAcElementsBeforeUpdate(acToBeUpdated);
219
220         var acDefinitionTarget = acDefinitionProvider.getAcDefinition(automationComposition.getCompositionTargetId());
221         AcDefinitionProvider.checkPrimedComposition(acDefinitionTarget);
222         // Iterate and update the element property values
223         var elementsRemoved = updateElementsProperties(automationComposition, acToBeUpdated, acDefinitionTarget);
224
225         updateAcForMigration(acToBeUpdated, acDefinitionTarget, DeployState.MIGRATING);
226
227         var acToPublish = new AutomationComposition(acToBeUpdated);
228         encryptInstanceProperties(acToBeUpdated, acToBeUpdated.getCompositionTargetId());
229
230         var ac = automationCompositionProvider.updateAutomationComposition(acToBeUpdated);
231         elementsRemoved.forEach(automationCompositionProvider::deleteAutomationCompositionElement);
232
233         // Publish migrate event to the participants
234         supervisionAcHandler.migrate(acToPublish, acDefinition.getRevisionId(), acDefinitionTarget.getRevisionId());
235         return createInstantiationResponse(ac);
236     }
237
238     private void updateAcForMigration(AutomationComposition acToBeUpdated,
239                                       AutomationCompositionDefinition acDefinition, DeployState deployState) {
240         AcmUtils.setCascadedState(acToBeUpdated, deployState, LockState.LOCKED);
241         acToBeUpdated.setStateChangeResult(StateChangeResult.NO_ERROR);
242         var stage = ParticipantUtils.getFirstStage(acToBeUpdated, acDefinition.getServiceTemplate());
243         acToBeUpdated.setPhase(stage);
244     }
245
246     private void updateAcForProperties(AutomationComposition acToBeUpdated) {
247         AcmUtils.setCascadedState(acToBeUpdated, DeployState.UPDATING, acToBeUpdated.getLockState());
248         acToBeUpdated.setStateChangeResult(StateChangeResult.NO_ERROR);
249     }
250
251     private List<UUID> getElementRemoved(AutomationComposition acFromDb, AutomationComposition acFromMigration) {
252         return acFromDb.getElements().keySet().stream()
253             .filter(id -> acFromMigration.getElements().get(id) == null).toList();
254     }
255
256
257     private InstantiationResponse migratePrecheckAc(
258             AutomationComposition automationComposition, AutomationComposition acToBeUpdated,
259             AutomationCompositionDefinition acDefinition) {
260
261         acToBeUpdated.setPrecheck(true);
262         var copyAc = new AutomationComposition(acToBeUpdated);
263         var acDefinitionTarget = acDefinitionProvider.getAcDefinition(automationComposition.getCompositionTargetId());
264         AcDefinitionProvider.checkPrimedComposition(acDefinitionTarget);
265         // Iterate and update the element property values
266         updateElementsProperties(automationComposition, copyAc, acDefinitionTarget);
267
268         // Publish migrate event to the participants
269         supervisionAcHandler.migratePrecheck(copyAc, acDefinition.getRevisionId(), acDefinitionTarget.getRevisionId());
270
271         AcmUtils.setCascadedState(acToBeUpdated, DeployState.DEPLOYED, LockState.LOCKED,
272             SubState.MIGRATION_PRECHECKING);
273         acToBeUpdated.setStateChangeResult(StateChangeResult.NO_ERROR);
274
275         return createInstantiationResponse(automationCompositionProvider.updateAutomationComposition(acToBeUpdated));
276     }
277
278     /**
279      * Validate AutomationComposition.
280      *
281      * @param automationComposition AutomationComposition to validate
282      * @param acDefinition         the Composition Definition
283      * @return the result of validation
284      */
285     private BeanValidationResult validateAutomationComposition(AutomationComposition automationComposition,
286             AutomationCompositionDefinition acDefinition) {
287         var result = new BeanValidationResult("AutomationComposition", automationComposition);
288         participantProvider.checkRegisteredParticipant(acDefinition);
289         result.addResult(AcmUtils.validateAutomationComposition(automationComposition,
290                 acDefinition.getServiceTemplate(),
291             acRuntimeParameterGroup.getAcmParameters().getToscaCompositionName()));
292
293         result.addResult(automationCompositionProvider.validateElementIds(automationComposition));
294
295         if (result.isValid()) {
296             for (var element : automationComposition.getElements().values()) {
297                 var name = element.getDefinition().getName();
298                 var participantId = acDefinition.getElementStateMap().get(name).getParticipantId();
299                 element.setParticipantId(participantId);
300             }
301         }
302
303         return result;
304     }
305
306
307     private void encryptInstanceProperties(AutomationComposition automationComposition, UUID compositionId) {
308         if (encryptionUtils.encryptionEnabled()) {
309             var acDefinitionOpt = acDefinitionProvider.findAcDefinition(compositionId);
310             acDefinitionOpt.ifPresent(acDefinition
311                 -> encryptionUtils.findAndEncryptSensitiveData(acDefinition, automationComposition));
312         }
313     }
314
315     /**
316      * Get Automation Composition.
317      *
318      * @param compositionId The UUID of the automation composition definition
319      * @param instanceId    The UUID of the automation composition instance
320      * @return the Automation Composition
321      */
322     @Transactional(readOnly = true)
323     public AutomationComposition getAutomationComposition(@NonNull UUID compositionId, UUID instanceId) {
324         var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
325         if (!compositionId.equals(automationComposition.getCompositionId())
326             && !compositionId.equals(automationComposition.getCompositionTargetId())) {
327             throw new PfModelRuntimeException(Status.BAD_REQUEST,
328                 automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
329         }
330         return automationComposition;
331     }
332
333     /**
334      * Delete the automation composition with the given name and version.
335      *
336      * @param compositionId The UUID of the automation composition definition
337      * @param instanceId    The UUID of the automation composition instance
338      * @return the result of the deletion
339      */
340     public InstantiationResponse deleteAutomationComposition(UUID compositionId, UUID instanceId) {
341         var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
342         var acDefinition = getAcDefinition(compositionId, automationComposition);
343         var result = acInstanceStateResolver.resolve(DeployOrder.DELETE,
344             null, null,
345             automationComposition.getDeployState(), automationComposition.getLockState(),
346             automationComposition.getSubState(), automationComposition.getStateChangeResult());
347         if (!DeployOrder.DELETE.name().equals(result)) {
348             var msg = String.format(NOT_VALID_ORDER, DeployOrder.DELETE,
349                 automationComposition.getDeployState(), automationComposition.getLockState(),
350                 automationComposition.getSubState(), automationComposition.getStateChangeResult());
351             throw new PfModelRuntimeException(Status.BAD_REQUEST, msg);
352         }
353         supervisionAcHandler.delete(automationComposition, acDefinition);
354         return createInstantiationResponse(automationComposition);
355     }
356
357     /**
358      * Get the requested automation compositions.
359      *
360      * @param name     the name of the automation composition to get, null for all automation compositions
361      * @param version  the version of the automation composition to get, null for all automation compositions
362      * @param pageable the Pageable
363      * @return the automation compositions
364      */
365     @Transactional(readOnly = true)
366     public AutomationCompositions getAutomationCompositions(@NonNull final UUID compositionId,
367                                                             final String name, final String version,
368                                                             @NonNull final Pageable pageable) {
369         var automationCompositions = new AutomationCompositions();
370         automationCompositions.setAutomationCompositionList(
371             automationCompositionProvider.getAutomationCompositions(compositionId, name, version, pageable));
372
373         return automationCompositions;
374     }
375
376     /**
377      * Handle Composition Instance State.
378      *
379      * @param compositionId         the compositionId
380      * @param instanceId            the instanceId
381      * @param acInstanceStateUpdate the AcInstanceStateUpdate
382      */
383     public void compositionInstanceState(UUID compositionId, UUID instanceId,
384                                          @Valid AcInstanceStateUpdate acInstanceStateUpdate) {
385         var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
386         var acDefinition = getAcDefinition(compositionId, automationComposition);
387         var result = acInstanceStateResolver.resolve(acInstanceStateUpdate.getDeployOrder(),
388             acInstanceStateUpdate.getLockOrder(), acInstanceStateUpdate.getSubOrder(),
389             automationComposition.getDeployState(), automationComposition.getLockState(),
390             automationComposition.getSubState(), automationComposition.getStateChangeResult());
391         switch (result) {
392             case "DEPLOY":
393                 supervisionAcHandler.deploy(automationComposition, acDefinition);
394                 break;
395
396             case "UNDEPLOY":
397                 supervisionAcHandler.undeploy(automationComposition, acDefinition);
398                 break;
399
400             case "LOCK":
401                 supervisionAcHandler.lock(automationComposition, acDefinition);
402                 break;
403
404             case "UNLOCK":
405                 supervisionAcHandler.unlock(automationComposition, acDefinition);
406                 break;
407
408             case "PREPARE":
409                 supervisionAcHandler.prepare(automationComposition, acDefinition);
410                 break;
411
412             case "REVIEW":
413                 supervisionAcHandler.review(automationComposition, acDefinition);
414                 break;
415
416             default:
417                 var msg = String.format(NOT_VALID_ORDER, acInstanceStateUpdate,
418                     automationComposition.getDeployState(), automationComposition.getLockState(),
419                     automationComposition.getSubState(), automationComposition.getStateChangeResult());
420                 throw new PfModelRuntimeException(Status.BAD_REQUEST, msg);
421         }
422     }
423
424     /**
425      * Rollback AC Instance.
426      *
427      * @param compositionId The UUID of the automation composition definition
428      * @param instanceId    The UUID of the automation composition instance
429      */
430     public void rollback(UUID compositionId, UUID instanceId) {
431         var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
432         AutomationCompositionProvider.validateInstanceEndpoint(compositionId, automationComposition);
433
434         if (!DeployOrder.MIGRATION_REVERT.name().equals(acInstanceStateResolver.resolve(
435                 DeployOrder.MIGRATION_REVERT, LockOrder.NONE,
436                 SubOrder.NONE, automationComposition.getDeployState(), automationComposition.getLockState(),
437                 automationComposition.getSubState(), automationComposition.getStateChangeResult()))) {
438             throw new PfModelRuntimeException(Status.BAD_REQUEST, "Invalid state for rollback");
439         }
440
441         var automationCompositionToRollback =
442             automationCompositionProvider.getAutomationCompositionRollback(instanceId);
443         var acToBeUpdated = new AutomationComposition(automationComposition);
444         acToBeUpdated.setCompositionTargetId(automationCompositionToRollback.getCompositionId());
445         acToBeUpdated.setElements(automationCompositionToRollback.getElements().values().stream()
446                 .collect(Collectors.toMap(AutomationCompositionElement::getId, AutomationCompositionElement::new)));
447
448         var acDefinitionTarget = acDefinitionProvider.getAcDefinition(acToBeUpdated.getCompositionTargetId());
449         var validationResult = validateAutomationComposition(acToBeUpdated, acDefinitionTarget);
450         if (!validationResult.isValid()) {
451             throw new PfModelRuntimeException(Status.BAD_REQUEST, validationResult.getResult());
452         }
453
454         updateAcForMigration(acToBeUpdated, acDefinitionTarget, DeployState.MIGRATION_REVERTING);
455         var elementsRemoved = getElementRemoved(automationComposition, acToBeUpdated);
456         automationCompositionProvider.updateAutomationComposition(acToBeUpdated);
457         elementsRemoved.forEach(automationCompositionProvider::deleteAutomationCompositionElement);
458         var acDefinition = acDefinitionProvider.getAcDefinition(acToBeUpdated.getCompositionId());
459         supervisionAcHandler.migrate(acToBeUpdated, acDefinition.getRevisionId(), acDefinitionTarget.getRevisionId());
460     }
461
462     private List<UUID> updateElementsProperties(AutomationComposition automationComposition,
463             AutomationComposition acToBeUpdated, AutomationCompositionDefinition acDefinitionTarget) {
464         for (var element : automationComposition.getElements().entrySet()) {
465             var elementId = element.getKey();
466             var dbAcElement = acToBeUpdated.getElements().get(elementId);
467             // Add additional elements if present for migration
468             if (dbAcElement == null) {
469                 LOGGER.info("New Ac element {} added in Migration", elementId);
470                 acToBeUpdated.getElements().put(elementId, element.getValue());
471             } else {
472                 AcmUtils.recursiveMerge(dbAcElement.getProperties(), element.getValue().getProperties());
473                 var newDefinition = element.getValue().getDefinition().asConceptKey();
474                 var dbElementDefinition = dbAcElement.getDefinition().asConceptKey();
475                 AutomationCompositionProvider.checkCompatibility(
476                         newDefinition, dbElementDefinition, automationComposition.getInstanceId());
477                 dbAcElement.setDefinition(element.getValue().getDefinition());
478             }
479         }
480         // Remove element which is not present in the new Ac instance
481         var elementsRemoved = getElementRemoved(acToBeUpdated, automationComposition);
482         elementsRemoved.forEach(uuid -> acToBeUpdated.getElements().remove(uuid));
483
484         var validationResult = validateAutomationComposition(acToBeUpdated, acDefinitionTarget);
485         if (!validationResult.isValid()) {
486             throw new PfModelRuntimeException(Status.BAD_REQUEST, validationResult.getResult());
487         }
488         acToBeUpdated.setCompositionTargetId(automationComposition.getCompositionTargetId());
489         return elementsRemoved;
490     }
491
492     private AutomationCompositionDefinition getAcDefinition(UUID compositionId,
493                                                             AutomationComposition automationComposition) {
494         AutomationCompositionProvider.validateInstanceEndpoint(compositionId, automationComposition);
495         var acDefinition = acDefinitionProvider.getAcDefinition(automationComposition.getCompositionId());
496         participantProvider.checkRegisteredParticipant(acDefinition);
497         return acDefinition;
498     }
499 }