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
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.Status;
26 import java.util.ArrayList;
27 import java.util.Arrays;
28 import java.util.List;
29 import java.util.UUID;
30 import java.util.stream.Collectors;
31 import lombok.NonNull;
32 import lombok.RequiredArgsConstructor;
33 import org.onap.policy.clamp.acm.runtime.main.parameters.AcRuntimeParameterGroup;
34 import org.onap.policy.clamp.acm.runtime.main.utils.EncryptionUtils;
35 import org.onap.policy.clamp.acm.runtime.supervision.SupervisionAcHandler;
36 import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
37 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionDefinition;
38 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElement;
39 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositions;
40 import org.onap.policy.clamp.models.acm.concepts.DeployState;
41 import org.onap.policy.clamp.models.acm.concepts.LockState;
42 import org.onap.policy.clamp.models.acm.concepts.ParticipantUtils;
43 import org.onap.policy.clamp.models.acm.concepts.StateChangeResult;
44 import org.onap.policy.clamp.models.acm.concepts.SubState;
45 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.AcInstanceStateUpdate;
46 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.DeployOrder;
47 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.InstantiationResponse;
48 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.LockOrder;
49 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.SubOrder;
50 import org.onap.policy.clamp.models.acm.persistence.provider.AcDefinitionProvider;
51 import org.onap.policy.clamp.models.acm.persistence.provider.AcInstanceStateResolver;
52 import org.onap.policy.clamp.models.acm.persistence.provider.AutomationCompositionProvider;
53 import org.onap.policy.clamp.models.acm.persistence.provider.ParticipantProvider;
54 import org.onap.policy.clamp.models.acm.utils.AcmUtils;
55 import org.onap.policy.common.parameters.BeanValidationResult;
56 import org.onap.policy.models.base.PfModelRuntimeException;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
59 import org.springframework.data.domain.Pageable;
60 import org.springframework.stereotype.Service;
61 import org.springframework.transaction.annotation.Transactional;
64 * This class is dedicated to the Instantiation of Commissioned automation composition.
68 @RequiredArgsConstructor
69 public class AutomationCompositionInstantiationProvider {
70 private static final String DO_NOT_MATCH = " do not match with ";
71 private static final String ELEMENT_ID_NOT_PRESENT = "Element id not present ";
72 private static final String NOT_VALID_ORDER =
73 "Not valid order %s; DeployState: %s; LockState: %s; SubState: %s; StateChangeResult: %s";
75 private static final Logger LOGGER = LoggerFactory.getLogger(AutomationCompositionInstantiationProvider.class);
77 private final AutomationCompositionProvider automationCompositionProvider;
78 private final AcDefinitionProvider acDefinitionProvider;
79 private final AcInstanceStateResolver acInstanceStateResolver;
80 private final SupervisionAcHandler supervisionAcHandler;
81 private final ParticipantProvider participantProvider;
82 private final AcRuntimeParameterGroup acRuntimeParameterGroup;
83 private final EncryptionUtils encryptionUtils;
86 * Create automation composition.
88 * @param compositionId The UUID of the automation composition definition
89 * @param automationComposition the automation composition
90 * @return the result of the instantiation operation
92 public InstantiationResponse createAutomationComposition(UUID compositionId,
93 AutomationComposition automationComposition) {
94 AutomationCompositionProvider.validateInstanceEndpoint(compositionId, automationComposition);
95 automationCompositionProvider.validateNameVersion(automationComposition.getKey().asIdentifier());
97 var acDefinition = acDefinitionProvider.getAcDefinition(compositionId);
98 AcDefinitionProvider.checkPrimedComposition(acDefinition);
99 var validationResult = validateAutomationComposition(automationComposition, acDefinition);
100 if (!validationResult.isValid()) {
101 throw new PfModelRuntimeException(Status.BAD_REQUEST, validationResult.getResult());
103 encryptInstanceProperties(automationComposition, compositionId);
104 automationComposition = automationCompositionProvider.createAutomationComposition(automationComposition);
106 return createInstantiationResponse(automationComposition);
109 private InstantiationResponse createInstantiationResponse(AutomationComposition automationComposition) {
110 var response = new InstantiationResponse();
111 response.setInstanceId(automationComposition.getInstanceId());
112 response.setAffectedAutomationComposition(automationComposition.getKey().asIdentifier());
117 * Update automation composition.
119 * @param compositionId The UUID of the automation composition definition
120 * @param automationComposition the automation composition
121 * @return the result of the update
123 public InstantiationResponse updateAutomationComposition(UUID compositionId,
124 AutomationComposition automationComposition) {
125 var instanceId = automationComposition.getInstanceId();
126 var acToUpdate = automationCompositionProvider.getAutomationComposition(instanceId);
127 AutomationCompositionProvider.validateInstanceEndpoint(compositionId, acToUpdate);
128 var acDefinition = acDefinitionProvider.getAcDefinition(compositionId);
129 AcDefinitionProvider.checkPrimedComposition(acDefinition);
130 if (DeployState.UNDEPLOYED.equals(acToUpdate.getDeployState())) {
131 acToUpdate.setElements(automationComposition.getElements());
132 acToUpdate.setName(automationComposition.getName());
133 acToUpdate.setVersion(automationComposition.getVersion());
134 acToUpdate.setDescription(automationComposition.getDescription());
135 acToUpdate.setDerivedFrom(automationComposition.getDerivedFrom());
136 var validationResult = validateAutomationComposition(acToUpdate, acDefinition);
137 if (!validationResult.isValid()) {
138 throw new PfModelRuntimeException(Status.BAD_REQUEST, validationResult.getResult());
140 encryptInstanceProperties(acToUpdate, compositionId);
141 automationComposition = automationCompositionProvider.updateAutomationComposition(acToUpdate);
142 return createInstantiationResponse(automationComposition);
146 var deployOrder = DeployOrder.UPDATE;
147 var subOrder = SubOrder.NONE;
149 if (automationComposition.getCompositionTargetId() != null) {
151 if (Boolean.TRUE.equals(automationComposition.getPrecheck())) {
152 subOrder = SubOrder.MIGRATE_PRECHECK;
153 deployOrder = DeployOrder.NONE;
155 deployOrder = DeployOrder.MIGRATE;
158 var result = acInstanceStateResolver.resolve(deployOrder, LockOrder.NONE, subOrder,
159 acToUpdate.getDeployState(), acToUpdate.getLockState(), acToUpdate.getSubState(),
160 acToUpdate.getStateChangeResult());
161 return switch (result) {
162 case "UPDATE" -> updateDeployedAutomationComposition(automationComposition, acToUpdate, acDefinition);
164 case "MIGRATE" -> migrateAutomationComposition(automationComposition, acToUpdate, acDefinition);
166 case "MIGRATE_PRECHECK" -> migratePrecheckAc(automationComposition, acToUpdate, acDefinition);
168 default -> throw new PfModelRuntimeException(Status.BAD_REQUEST,
169 "Not allowed to " + deployOrder + " in the state " + acToUpdate.getDeployState());
174 * Update deployed AC Element properties.
176 * @param automationComposition the automation composition
177 * @param acToBeUpdated the composition to be updated
178 * @return the result of the update
180 private InstantiationResponse updateDeployedAutomationComposition(
181 AutomationComposition automationComposition, AutomationComposition acToBeUpdated,
182 AutomationCompositionDefinition acDefinition) {
183 // save copy in case of a rollback
184 automationCompositionProvider.copyAcElementsBeforeUpdate(acToBeUpdated);
186 // Iterate and update the element property values
187 for (var element : automationComposition.getElements().entrySet()) {
188 var elementId = element.getKey();
189 var dbAcElement = acToBeUpdated.getElements().get(elementId);
190 if (dbAcElement == null) {
191 throw new PfModelRuntimeException(Status.BAD_REQUEST, ELEMENT_ID_NOT_PRESENT + elementId);
193 AcmUtils.recursiveMerge(dbAcElement.getProperties(), element.getValue().getProperties());
196 var validationResult = validateAutomationComposition(acToBeUpdated, acDefinition);
197 if (!validationResult.isValid()) {
198 throw new PfModelRuntimeException(Status.BAD_REQUEST, validationResult.getResult());
200 updateAcForProperties(acToBeUpdated);
202 var acToPublish = new AutomationComposition(acToBeUpdated);
203 encryptInstanceProperties(acToBeUpdated, acToBeUpdated.getCompositionId());
205 automationComposition = automationCompositionProvider.updateAutomationComposition(acToBeUpdated);
206 // Publish property update event to the participants
207 supervisionAcHandler.update(acToPublish, acDefinition.getRevisionId());
208 return createInstantiationResponse(automationComposition);
211 private InstantiationResponse migrateAutomationComposition(
212 AutomationComposition automationComposition, AutomationComposition acToBeUpdated,
213 AutomationCompositionDefinition acDefinition) {
215 if (!DeployState.DEPLOYED.equals(acToBeUpdated.getDeployState())) {
216 throw new PfModelRuntimeException(Status.BAD_REQUEST,
217 "Not allowed to migrate in the state " + acToBeUpdated.getDeployState());
219 // make copy for rollback
220 automationCompositionProvider.copyAcElementsBeforeUpdate(acToBeUpdated);
222 var acDefinitionTarget = acDefinitionProvider.getAcDefinition(automationComposition.getCompositionTargetId());
223 AcDefinitionProvider.checkPrimedComposition(acDefinitionTarget);
224 // Iterate and update the element property values
225 var elementsRemoved = updateElementsProperties(automationComposition, acToBeUpdated, acDefinitionTarget);
227 updateAcForMigration(acToBeUpdated, acDefinitionTarget, DeployState.MIGRATING);
229 var acToPublish = new AutomationComposition(acToBeUpdated);
230 encryptInstanceProperties(acToBeUpdated, acToBeUpdated.getCompositionTargetId());
232 var ac = automationCompositionProvider.updateAutomationComposition(acToBeUpdated);
233 for (var element : elementsRemoved) {
234 automationCompositionProvider.deleteAutomationCompositionElement(element.getId());
237 // Publish migrate event to the participants
238 supervisionAcHandler.migrate(acToPublish, acDefinition.getRevisionId(), acDefinitionTarget.getRevisionId(),
240 return createInstantiationResponse(ac);
243 private void updateAcForMigration(AutomationComposition acToBeUpdated,
244 AutomationCompositionDefinition acDefinition, DeployState deployState) {
245 AcmUtils.setCascadedState(acToBeUpdated, deployState, LockState.LOCKED);
246 acToBeUpdated.setStateChangeResult(StateChangeResult.NO_ERROR);
247 var stage = ParticipantUtils.getFirstStage(acToBeUpdated, acDefinition.getServiceTemplate());
248 acToBeUpdated.setPhase(stage);
251 private void updateAcForProperties(AutomationComposition acToBeUpdated) {
252 AcmUtils.setCascadedState(acToBeUpdated, DeployState.UPDATING, acToBeUpdated.getLockState());
253 acToBeUpdated.setStateChangeResult(StateChangeResult.NO_ERROR);
256 private List<AutomationCompositionElement> getElementRemoved(AutomationComposition acFromDb,
257 AutomationComposition acFromMigration) {
258 return acFromDb.getElements().values().stream()
259 .filter(element -> acFromMigration.getElements().get(element.getId()) == null).toList();
263 private InstantiationResponse migratePrecheckAc(
264 AutomationComposition automationComposition, AutomationComposition acToBeUpdated,
265 AutomationCompositionDefinition acDefinition) {
267 acToBeUpdated.setPrecheck(true);
268 var copyAc = new AutomationComposition(acToBeUpdated);
269 var acDefinitionTarget = acDefinitionProvider.getAcDefinition(automationComposition.getCompositionTargetId());
270 AcDefinitionProvider.checkPrimedComposition(acDefinitionTarget);
271 // Iterate and update the element property values
272 var removedElements = updateElementsProperties(automationComposition, copyAc, acDefinitionTarget);
274 // Publish migrate event to the participants
275 supervisionAcHandler.migratePrecheck(copyAc, acDefinition.getRevisionId(), acDefinitionTarget.getRevisionId(),
278 AcmUtils.setCascadedState(acToBeUpdated, DeployState.DEPLOYED, LockState.LOCKED,
279 SubState.MIGRATION_PRECHECKING);
280 acToBeUpdated.setStateChangeResult(StateChangeResult.NO_ERROR);
282 return createInstantiationResponse(automationCompositionProvider.updateAutomationComposition(acToBeUpdated));
286 * Validate AutomationComposition.
288 * @param automationComposition AutomationComposition to validate
289 * @param acDefinition the Composition Definition
290 * @return the result of validation
292 private BeanValidationResult validateAutomationComposition(AutomationComposition automationComposition,
293 AutomationCompositionDefinition acDefinition) {
294 var result = new BeanValidationResult("AutomationComposition", automationComposition);
295 participantProvider.checkRegisteredParticipant(acDefinition);
296 result.addResult(AcmUtils.validateAutomationComposition(automationComposition,
297 acDefinition.getServiceTemplate(),
298 acRuntimeParameterGroup.getAcmParameters().getToscaCompositionName()));
300 result.addResult(automationCompositionProvider.validateElementIds(automationComposition));
302 if (result.isValid()) {
303 for (var element : automationComposition.getElements().values()) {
304 var name = element.getDefinition().getName();
305 var participantId = acDefinition.getElementStateMap().get(name).getParticipantId();
306 element.setParticipantId(participantId);
314 private void encryptInstanceProperties(AutomationComposition automationComposition, UUID compositionId) {
315 if (encryptionUtils.encryptionEnabled()) {
316 var acDefinitionOpt = acDefinitionProvider.findAcDefinition(compositionId);
317 acDefinitionOpt.ifPresent(acDefinition
318 -> encryptionUtils.findAndEncryptSensitiveData(acDefinition, automationComposition));
323 * Get Automation Composition.
325 * @param compositionId The UUID of the automation composition definition
326 * @param instanceId The UUID of the automation composition instance
327 * @return the Automation Composition
329 @Transactional(readOnly = true)
330 public AutomationComposition getAutomationComposition(@NonNull UUID compositionId, UUID instanceId) {
331 var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
332 if (!compositionId.equals(automationComposition.getCompositionId())
333 && !compositionId.equals(automationComposition.getCompositionTargetId())) {
334 throw new PfModelRuntimeException(Status.BAD_REQUEST,
335 automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
337 return automationComposition;
341 * Delete the automation composition with the given name and version.
343 * @param compositionId The UUID of the automation composition definition
344 * @param instanceId The UUID of the automation composition instance
345 * @return the result of the deletion
347 public InstantiationResponse deleteAutomationComposition(UUID compositionId, UUID instanceId) {
348 var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
349 var acDefinition = getAcDefinition(compositionId, automationComposition);
350 var result = acInstanceStateResolver.resolve(DeployOrder.DELETE,
352 automationComposition.getDeployState(), automationComposition.getLockState(),
353 automationComposition.getSubState(), automationComposition.getStateChangeResult());
354 if (!DeployOrder.DELETE.name().equals(result)) {
355 var msg = String.format(NOT_VALID_ORDER, DeployOrder.DELETE,
356 automationComposition.getDeployState(), automationComposition.getLockState(),
357 automationComposition.getSubState(), automationComposition.getStateChangeResult());
358 throw new PfModelRuntimeException(Status.BAD_REQUEST, msg);
360 supervisionAcHandler.delete(automationComposition, acDefinition);
361 return createInstantiationResponse(automationComposition);
365 * Get the requested automation compositions.
367 * @param name the name of the automation composition to get, null for all automation compositions
368 * @param version the version of the automation composition to get, null for all automation compositions
369 * @param pageable the Pageable
370 * @return the automation compositions
372 @Transactional(readOnly = true)
373 public AutomationCompositions getAutomationCompositions(@NonNull final UUID compositionId,
374 final String name, final String version,
375 @NonNull final Pageable pageable) {
376 var automationCompositions = new AutomationCompositions();
377 automationCompositions.setAutomationCompositionList(
378 automationCompositionProvider.getAutomationCompositions(compositionId, name, version, pageable));
380 return automationCompositions;
384 * Handle Composition Instance State.
386 * @param compositionId the compositionId
387 * @param instanceId the instanceId
388 * @param acInstanceStateUpdate the AcInstanceStateUpdate
390 public void compositionInstanceState(UUID compositionId, UUID instanceId,
391 @Valid AcInstanceStateUpdate acInstanceStateUpdate) {
392 var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
393 var acDefinition = getAcDefinition(compositionId, automationComposition);
394 var result = acInstanceStateResolver.resolve(acInstanceStateUpdate.getDeployOrder(),
395 acInstanceStateUpdate.getLockOrder(), acInstanceStateUpdate.getSubOrder(),
396 automationComposition.getDeployState(), automationComposition.getLockState(),
397 automationComposition.getSubState(), automationComposition.getStateChangeResult());
400 supervisionAcHandler.deploy(automationComposition, acDefinition);
404 supervisionAcHandler.undeploy(automationComposition, acDefinition);
408 supervisionAcHandler.lock(automationComposition, acDefinition);
412 supervisionAcHandler.unlock(automationComposition, acDefinition);
416 supervisionAcHandler.prepare(automationComposition, acDefinition);
420 supervisionAcHandler.review(automationComposition, acDefinition);
424 var msg = String.format(NOT_VALID_ORDER, acInstanceStateUpdate,
425 automationComposition.getDeployState(), automationComposition.getLockState(),
426 automationComposition.getSubState(), automationComposition.getStateChangeResult());
427 throw new PfModelRuntimeException(Status.BAD_REQUEST, msg);
432 * Rollback AC Instance.
434 * @param compositionId The UUID of the automation composition definition
435 * @param instanceId The UUID of the automation composition instance
437 public void rollback(UUID compositionId, UUID instanceId) {
438 var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
439 AutomationCompositionProvider.validateInstanceEndpoint(compositionId, automationComposition);
441 if (!DeployOrder.MIGRATION_REVERT.name().equals(acInstanceStateResolver.resolve(
442 DeployOrder.MIGRATION_REVERT, LockOrder.NONE,
443 SubOrder.NONE, automationComposition.getDeployState(), automationComposition.getLockState(),
444 automationComposition.getSubState(), automationComposition.getStateChangeResult()))) {
445 throw new PfModelRuntimeException(Status.BAD_REQUEST, "Invalid state for rollback");
448 var automationCompositionToRollback =
449 automationCompositionProvider.getAutomationCompositionRollback(instanceId);
450 var acToBeUpdated = new AutomationComposition(automationComposition);
451 acToBeUpdated.setCompositionTargetId(automationCompositionToRollback.getCompositionId());
452 acToBeUpdated.setElements(automationCompositionToRollback.getElements().values().stream()
453 .collect(Collectors.toMap(AutomationCompositionElement::getId, AutomationCompositionElement::new)));
455 var acDefinitionTarget = acDefinitionProvider.getAcDefinition(acToBeUpdated.getCompositionTargetId());
456 var validationResult = validateAutomationComposition(acToBeUpdated, acDefinitionTarget);
457 if (!validationResult.isValid()) {
458 throw new PfModelRuntimeException(Status.BAD_REQUEST, validationResult.getResult());
461 updateAcForMigration(acToBeUpdated, acDefinitionTarget, DeployState.MIGRATION_REVERTING);
462 var elementsRemoved = getElementRemoved(automationComposition, acToBeUpdated);
463 automationCompositionProvider.updateAutomationComposition(acToBeUpdated);
464 for (var element : elementsRemoved) {
465 automationCompositionProvider.deleteAutomationCompositionElement(element.getId());
467 var acDefinition = acDefinitionProvider.getAcDefinition(acToBeUpdated.getCompositionId());
468 supervisionAcHandler.migrate(acToBeUpdated, acDefinition.getRevisionId(), acDefinitionTarget.getRevisionId(),
472 private List<AutomationCompositionElement> updateElementsProperties(AutomationComposition automationComposition,
473 AutomationComposition acToBeUpdated, AutomationCompositionDefinition acDefinitionTarget) {
474 for (var element : automationComposition.getElements().entrySet()) {
475 var elementId = element.getKey();
476 var dbAcElement = acToBeUpdated.getElements().get(elementId);
477 // Add additional elements if present for migration
478 if (dbAcElement == null) {
479 LOGGER.info("New Ac element {} added in Migration", elementId);
480 acToBeUpdated.getElements().put(elementId, element.getValue());
482 AcmUtils.recursiveMerge(dbAcElement.getProperties(), element.getValue().getProperties());
483 var newDefinition = element.getValue().getDefinition().asConceptKey();
484 var dbElementDefinition = dbAcElement.getDefinition().asConceptKey();
485 AutomationCompositionProvider.checkCompatibility(
486 newDefinition, dbElementDefinition, automationComposition.getInstanceId());
487 dbAcElement.setDefinition(element.getValue().getDefinition());
490 // Remove element which is not present in the new Ac instance
491 var elementsRemoved = getElementRemoved(acToBeUpdated, automationComposition);
492 elementsRemoved.forEach(element -> acToBeUpdated.getElements().remove(element.getId()));
494 var validationResult = validateAutomationComposition(acToBeUpdated, acDefinitionTarget);
495 if (!validationResult.isValid()) {
496 throw new PfModelRuntimeException(Status.BAD_REQUEST, validationResult.getResult());
498 acToBeUpdated.setCompositionTargetId(automationComposition.getCompositionTargetId());
499 return elementsRemoved;
502 private AutomationCompositionDefinition getAcDefinition(UUID compositionId,
503 AutomationComposition automationComposition) {
504 AutomationCompositionProvider.validateInstanceEndpoint(compositionId, automationComposition);
505 var acDefinition = acDefinitionProvider.getAcDefinition(automationComposition.getCompositionId());
506 participantProvider.checkRegisteredParticipant(acDefinition);
511 * Retrieves a list of AutomationComposition instances filtered by the specified state change results
512 * and deployment states. The result can be paginated and sorted based on the provided parameters.
514 * @param stateChangeResults a list of StateChangeResult values to filter the AutomationComposition instances
515 * @param deployStates a list of DeployState values to filter the AutomationComposition instances
516 * @param pageable the pagination information including page size and page number
517 * @return a list of AutomationComposition instances that match the specified filters
519 public AutomationCompositions getAcInstancesByStateResultDeployState(
520 final String stateChangeResults, final String deployStates,
521 final Pageable pageable) {
523 List<StateChangeResult> stateChangeResultList = new ArrayList<>();
524 if (stateChangeResults != null) {
525 Arrays.stream(stateChangeResults.split(","))
526 .forEach(stateChangeResult -> stateChangeResultList.add(StateChangeResult.valueOf(stateChangeResult)));
529 List<DeployState> deployStateList = new ArrayList<>();
530 if (deployStates != null) {
531 Arrays.stream(deployStates.split(","))
532 .forEach(deployState -> deployStateList.add(DeployState.valueOf(deployState)));
535 var instances = automationCompositionProvider.getAcInstancesByStateResultDeployState(stateChangeResultList,
536 deployStateList, pageable);
537 return new AutomationCompositions(instances);