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.persistence.provider.ProviderUtils;
55 import org.onap.policy.clamp.models.acm.utils.AcmUtils;
56 import org.onap.policy.common.parameters.BeanValidationResult;
57 import org.onap.policy.models.base.PfModelRuntimeException;
58 import org.slf4j.Logger;
59 import org.slf4j.LoggerFactory;
60 import org.springframework.data.domain.Pageable;
61 import org.springframework.data.domain.Sort;
62 import org.springframework.stereotype.Service;
63 import org.springframework.transaction.annotation.Transactional;
66 * This class is dedicated to the Instantiation of Commissioned automation composition.
70 @RequiredArgsConstructor
71 public class AutomationCompositionInstantiationProvider {
72 private static final String DO_NOT_MATCH = " do not match with ";
73 private static final String ELEMENT_ID_NOT_PRESENT = "Element id not present ";
74 private static final String NOT_VALID_ORDER =
75 "Not valid order %s; DeployState: %s; LockState: %s; SubState: %s; StateChangeResult: %s";
77 private static final Logger LOGGER = LoggerFactory.getLogger(AutomationCompositionInstantiationProvider.class);
79 private final AutomationCompositionProvider automationCompositionProvider;
80 private final AcDefinitionProvider acDefinitionProvider;
81 private final AcInstanceStateResolver acInstanceStateResolver;
82 private final SupervisionAcHandler supervisionAcHandler;
83 private final ParticipantProvider participantProvider;
84 private final AcRuntimeParameterGroup acRuntimeParameterGroup;
85 private final EncryptionUtils encryptionUtils;
88 * Create automation composition.
90 * @param compositionId The UUID of the automation composition definition
91 * @param automationComposition the automation composition
92 * @return the result of the instantiation operation
94 public InstantiationResponse createAutomationComposition(UUID compositionId,
95 AutomationComposition automationComposition) {
96 AutomationCompositionProvider.validateInstanceEndpoint(compositionId, automationComposition);
97 automationCompositionProvider.validateNameVersion(automationComposition.getKey().asIdentifier());
99 var acDefinition = acDefinitionProvider.getAcDefinition(compositionId);
100 AcDefinitionProvider.checkPrimedComposition(acDefinition);
101 var validationResult = validateAutomationComposition(automationComposition, acDefinition);
102 if (!validationResult.isValid()) {
103 throw new PfModelRuntimeException(Status.BAD_REQUEST, validationResult.getResult());
105 encryptInstanceProperties(automationComposition, compositionId);
106 automationComposition = automationCompositionProvider.createAutomationComposition(automationComposition);
108 return createInstantiationResponse(automationComposition);
111 private InstantiationResponse createInstantiationResponse(AutomationComposition automationComposition) {
112 var response = new InstantiationResponse();
113 response.setInstanceId(automationComposition.getInstanceId());
114 response.setAffectedAutomationComposition(automationComposition.getKey().asIdentifier());
119 * Update automation composition.
121 * @param compositionId The UUID of the automation composition definition
122 * @param automationComposition the automation composition
123 * @return the result of the update
125 public InstantiationResponse updateAutomationComposition(UUID compositionId,
126 AutomationComposition automationComposition) {
127 var instanceId = automationComposition.getInstanceId();
128 var acToUpdate = automationCompositionProvider.getAutomationComposition(instanceId);
129 AutomationCompositionProvider.validateInstanceEndpoint(compositionId, acToUpdate);
130 var acDefinition = acDefinitionProvider.getAcDefinition(compositionId);
131 AcDefinitionProvider.checkPrimedComposition(acDefinition);
132 if (DeployState.UNDEPLOYED.equals(acToUpdate.getDeployState())) {
133 acToUpdate.setElements(automationComposition.getElements());
134 acToUpdate.setName(automationComposition.getName());
135 acToUpdate.setVersion(automationComposition.getVersion());
136 acToUpdate.setDescription(automationComposition.getDescription());
137 acToUpdate.setDerivedFrom(automationComposition.getDerivedFrom());
138 var validationResult = validateAutomationComposition(acToUpdate, acDefinition);
139 if (!validationResult.isValid()) {
140 throw new PfModelRuntimeException(Status.BAD_REQUEST, validationResult.getResult());
142 encryptInstanceProperties(acToUpdate, compositionId);
143 automationComposition = automationCompositionProvider.updateAutomationComposition(acToUpdate);
144 return createInstantiationResponse(automationComposition);
148 var deployOrder = DeployOrder.UPDATE;
149 var subOrder = SubOrder.NONE;
151 if (automationComposition.getCompositionTargetId() != null) {
153 if (Boolean.TRUE.equals(automationComposition.getPrecheck())) {
154 subOrder = SubOrder.MIGRATE_PRECHECK;
155 deployOrder = DeployOrder.NONE;
157 deployOrder = DeployOrder.MIGRATE;
160 var result = acInstanceStateResolver.resolve(deployOrder, LockOrder.NONE, subOrder,
161 acToUpdate.getDeployState(), acToUpdate.getLockState(), acToUpdate.getSubState(),
162 acToUpdate.getStateChangeResult());
163 return switch (result) {
164 case "UPDATE" -> updateDeployedAutomationComposition(automationComposition, acToUpdate, acDefinition);
166 case "MIGRATE" -> migrateAutomationComposition(automationComposition, acToUpdate, acDefinition);
168 case "MIGRATE_PRECHECK" -> migratePrecheckAc(automationComposition, acToUpdate, acDefinition);
170 default -> throw new PfModelRuntimeException(Status.BAD_REQUEST,
171 "Not allowed to " + deployOrder + " in the state " + acToUpdate.getDeployState());
176 * Update deployed AC Element properties.
178 * @param automationComposition the automation composition
179 * @param acToBeUpdated the composition to be updated
180 * @return the result of the update
182 private InstantiationResponse updateDeployedAutomationComposition(
183 AutomationComposition automationComposition, AutomationComposition acToBeUpdated,
184 AutomationCompositionDefinition acDefinition) {
185 // save copy in case of a rollback
186 automationCompositionProvider.copyAcElementsBeforeUpdate(acToBeUpdated);
188 // Iterate and update the element property values
189 for (var element : automationComposition.getElements().entrySet()) {
190 var elementId = element.getKey();
191 var dbAcElement = acToBeUpdated.getElements().get(elementId);
192 if (dbAcElement == null) {
193 throw new PfModelRuntimeException(Status.BAD_REQUEST, ELEMENT_ID_NOT_PRESENT + elementId);
195 AcmUtils.recursiveMerge(dbAcElement.getProperties(), element.getValue().getProperties());
198 var validationResult = validateAutomationComposition(acToBeUpdated, acDefinition);
199 if (!validationResult.isValid()) {
200 throw new PfModelRuntimeException(Status.BAD_REQUEST, validationResult.getResult());
202 updateAcForProperties(acToBeUpdated);
204 var acToPublish = new AutomationComposition(acToBeUpdated);
205 encryptInstanceProperties(acToBeUpdated, acToBeUpdated.getCompositionId());
207 automationComposition = automationCompositionProvider.updateAutomationComposition(acToBeUpdated);
208 // Publish property update event to the participants
209 supervisionAcHandler.update(acToPublish, acDefinition.getRevisionId());
210 return createInstantiationResponse(automationComposition);
213 private InstantiationResponse migrateAutomationComposition(
214 AutomationComposition automationComposition, AutomationComposition acToBeUpdated,
215 AutomationCompositionDefinition acDefinition) {
217 if (!DeployState.DEPLOYED.equals(acToBeUpdated.getDeployState())) {
218 throw new PfModelRuntimeException(Status.BAD_REQUEST,
219 "Not allowed to migrate in the state " + acToBeUpdated.getDeployState());
221 // make copy for rollback
222 automationCompositionProvider.copyAcElementsBeforeUpdate(acToBeUpdated);
224 var acDefinitionTarget = acDefinitionProvider.getAcDefinition(automationComposition.getCompositionTargetId());
225 AcDefinitionProvider.checkPrimedComposition(acDefinitionTarget);
226 // Iterate and update the element property values
227 var elementsRemoved = updateElementsProperties(automationComposition, acToBeUpdated, acDefinitionTarget);
229 updateAcForMigration(acToBeUpdated, acDefinitionTarget, DeployState.MIGRATING);
231 var acToPublish = new AutomationComposition(acToBeUpdated);
232 encryptInstanceProperties(acToBeUpdated, acToBeUpdated.getCompositionTargetId());
234 var ac = automationCompositionProvider.updateAutomationComposition(acToBeUpdated);
235 elementsRemoved.forEach(automationCompositionProvider::deleteAutomationCompositionElement);
237 // Publish migrate event to the participants
238 supervisionAcHandler.migrate(acToPublish, acDefinition.getRevisionId(), acDefinitionTarget.getRevisionId());
239 return createInstantiationResponse(ac);
242 private void updateAcForMigration(AutomationComposition acToBeUpdated,
243 AutomationCompositionDefinition acDefinition, DeployState deployState) {
244 AcmUtils.setCascadedState(acToBeUpdated, deployState, LockState.LOCKED);
245 acToBeUpdated.setStateChangeResult(StateChangeResult.NO_ERROR);
246 var stage = ParticipantUtils.getFirstStage(acToBeUpdated, acDefinition.getServiceTemplate());
247 acToBeUpdated.setPhase(stage);
250 private void updateAcForProperties(AutomationComposition acToBeUpdated) {
251 AcmUtils.setCascadedState(acToBeUpdated, DeployState.UPDATING, acToBeUpdated.getLockState());
252 acToBeUpdated.setStateChangeResult(StateChangeResult.NO_ERROR);
255 private List<UUID> getElementRemoved(AutomationComposition acFromDb, AutomationComposition acFromMigration) {
256 return acFromDb.getElements().keySet().stream()
257 .filter(id -> acFromMigration.getElements().get(id) == null).toList();
261 private InstantiationResponse migratePrecheckAc(
262 AutomationComposition automationComposition, AutomationComposition acToBeUpdated,
263 AutomationCompositionDefinition acDefinition) {
265 acToBeUpdated.setPrecheck(true);
266 var copyAc = new AutomationComposition(acToBeUpdated);
267 var acDefinitionTarget = acDefinitionProvider.getAcDefinition(automationComposition.getCompositionTargetId());
268 AcDefinitionProvider.checkPrimedComposition(acDefinitionTarget);
269 // Iterate and update the element property values
270 updateElementsProperties(automationComposition, copyAc, acDefinitionTarget);
272 // Publish migrate event to the participants
273 supervisionAcHandler.migratePrecheck(copyAc, acDefinition.getRevisionId(), acDefinitionTarget.getRevisionId());
275 AcmUtils.setCascadedState(acToBeUpdated, DeployState.DEPLOYED, LockState.LOCKED,
276 SubState.MIGRATION_PRECHECKING);
277 acToBeUpdated.setStateChangeResult(StateChangeResult.NO_ERROR);
279 return createInstantiationResponse(automationCompositionProvider.updateAutomationComposition(acToBeUpdated));
283 * Validate AutomationComposition.
285 * @param automationComposition AutomationComposition to validate
286 * @param acDefinition the Composition Definition
287 * @return the result of validation
289 private BeanValidationResult validateAutomationComposition(AutomationComposition automationComposition,
290 AutomationCompositionDefinition acDefinition) {
291 var result = new BeanValidationResult("AutomationComposition", automationComposition);
292 participantProvider.checkRegisteredParticipant(acDefinition);
293 result.addResult(AcmUtils.validateAutomationComposition(automationComposition,
294 acDefinition.getServiceTemplate(),
295 acRuntimeParameterGroup.getAcmParameters().getToscaCompositionName()));
297 result.addResult(automationCompositionProvider.validateElementIds(automationComposition));
299 if (result.isValid()) {
300 for (var element : automationComposition.getElements().values()) {
301 var name = element.getDefinition().getName();
302 var participantId = acDefinition.getElementStateMap().get(name).getParticipantId();
303 element.setParticipantId(participantId);
311 private void encryptInstanceProperties(AutomationComposition automationComposition, UUID compositionId) {
312 if (encryptionUtils.encryptionEnabled()) {
313 var acDefinitionOpt = acDefinitionProvider.findAcDefinition(compositionId);
314 acDefinitionOpt.ifPresent(acDefinition
315 -> encryptionUtils.findAndEncryptSensitiveData(acDefinition, automationComposition));
320 * Get Automation Composition.
322 * @param compositionId The UUID of the automation composition definition
323 * @param instanceId The UUID of the automation composition instance
324 * @return the Automation Composition
326 @Transactional(readOnly = true)
327 public AutomationComposition getAutomationComposition(@NonNull UUID compositionId, UUID instanceId) {
328 var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
329 if (!compositionId.equals(automationComposition.getCompositionId())
330 && !compositionId.equals(automationComposition.getCompositionTargetId())) {
331 throw new PfModelRuntimeException(Status.BAD_REQUEST,
332 automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
334 return automationComposition;
338 * Delete the automation composition with the given name and version.
340 * @param compositionId The UUID of the automation composition definition
341 * @param instanceId The UUID of the automation composition instance
342 * @return the result of the deletion
344 public InstantiationResponse deleteAutomationComposition(UUID compositionId, UUID instanceId) {
345 var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
346 var acDefinition = getAcDefinition(compositionId, automationComposition);
347 var result = acInstanceStateResolver.resolve(DeployOrder.DELETE,
349 automationComposition.getDeployState(), automationComposition.getLockState(),
350 automationComposition.getSubState(), automationComposition.getStateChangeResult());
351 if (!DeployOrder.DELETE.name().equals(result)) {
352 var msg = String.format(NOT_VALID_ORDER, DeployOrder.DELETE,
353 automationComposition.getDeployState(), automationComposition.getLockState(),
354 automationComposition.getSubState(), automationComposition.getStateChangeResult());
355 throw new PfModelRuntimeException(Status.BAD_REQUEST, msg);
357 supervisionAcHandler.delete(automationComposition, acDefinition);
358 return createInstantiationResponse(automationComposition);
362 * Get the requested automation compositions.
364 * @param name the name of the automation composition to get, null for all automation compositions
365 * @param version the version of the automation composition to get, null for all automation compositions
366 * @param pageable the Pageable
367 * @return the automation compositions
369 @Transactional(readOnly = true)
370 public AutomationCompositions getAutomationCompositions(@NonNull final UUID compositionId,
371 final String name, final String version,
372 @NonNull final Pageable pageable) {
373 var automationCompositions = new AutomationCompositions();
374 automationCompositions.setAutomationCompositionList(
375 automationCompositionProvider.getAutomationCompositions(compositionId, name, version, pageable));
377 return automationCompositions;
381 * Handle Composition Instance State.
383 * @param compositionId the compositionId
384 * @param instanceId the instanceId
385 * @param acInstanceStateUpdate the AcInstanceStateUpdate
387 public void compositionInstanceState(UUID compositionId, UUID instanceId,
388 @Valid AcInstanceStateUpdate acInstanceStateUpdate) {
389 var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
390 var acDefinition = getAcDefinition(compositionId, automationComposition);
391 var result = acInstanceStateResolver.resolve(acInstanceStateUpdate.getDeployOrder(),
392 acInstanceStateUpdate.getLockOrder(), acInstanceStateUpdate.getSubOrder(),
393 automationComposition.getDeployState(), automationComposition.getLockState(),
394 automationComposition.getSubState(), automationComposition.getStateChangeResult());
397 supervisionAcHandler.deploy(automationComposition, acDefinition);
401 supervisionAcHandler.undeploy(automationComposition, acDefinition);
405 supervisionAcHandler.lock(automationComposition, acDefinition);
409 supervisionAcHandler.unlock(automationComposition, acDefinition);
413 supervisionAcHandler.prepare(automationComposition, acDefinition);
417 supervisionAcHandler.review(automationComposition, acDefinition);
421 var msg = String.format(NOT_VALID_ORDER, acInstanceStateUpdate,
422 automationComposition.getDeployState(), automationComposition.getLockState(),
423 automationComposition.getSubState(), automationComposition.getStateChangeResult());
424 throw new PfModelRuntimeException(Status.BAD_REQUEST, msg);
429 * Rollback AC Instance.
431 * @param compositionId The UUID of the automation composition definition
432 * @param instanceId The UUID of the automation composition instance
434 public void rollback(UUID compositionId, UUID instanceId) {
435 var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
436 AutomationCompositionProvider.validateInstanceEndpoint(compositionId, automationComposition);
438 if (!DeployOrder.MIGRATION_REVERT.name().equals(acInstanceStateResolver.resolve(
439 DeployOrder.MIGRATION_REVERT, LockOrder.NONE,
440 SubOrder.NONE, automationComposition.getDeployState(), automationComposition.getLockState(),
441 automationComposition.getSubState(), automationComposition.getStateChangeResult()))) {
442 throw new PfModelRuntimeException(Status.BAD_REQUEST, "Invalid state for rollback");
445 var automationCompositionToRollback =
446 automationCompositionProvider.getAutomationCompositionRollback(instanceId);
447 var acToBeUpdated = new AutomationComposition(automationComposition);
448 acToBeUpdated.setCompositionTargetId(automationCompositionToRollback.getCompositionId());
449 acToBeUpdated.setElements(automationCompositionToRollback.getElements().values().stream()
450 .collect(Collectors.toMap(AutomationCompositionElement::getId, AutomationCompositionElement::new)));
452 var acDefinitionTarget = acDefinitionProvider.getAcDefinition(acToBeUpdated.getCompositionTargetId());
453 var validationResult = validateAutomationComposition(acToBeUpdated, acDefinitionTarget);
454 if (!validationResult.isValid()) {
455 throw new PfModelRuntimeException(Status.BAD_REQUEST, validationResult.getResult());
458 updateAcForMigration(acToBeUpdated, acDefinitionTarget, DeployState.MIGRATION_REVERTING);
459 var elementsRemoved = getElementRemoved(automationComposition, acToBeUpdated);
460 automationCompositionProvider.updateAutomationComposition(acToBeUpdated);
461 elementsRemoved.forEach(automationCompositionProvider::deleteAutomationCompositionElement);
462 var acDefinition = acDefinitionProvider.getAcDefinition(acToBeUpdated.getCompositionId());
463 supervisionAcHandler.migrate(acToBeUpdated, acDefinition.getRevisionId(), acDefinitionTarget.getRevisionId());
466 private List<UUID> updateElementsProperties(AutomationComposition automationComposition,
467 AutomationComposition acToBeUpdated, AutomationCompositionDefinition acDefinitionTarget) {
468 for (var element : automationComposition.getElements().entrySet()) {
469 var elementId = element.getKey();
470 var dbAcElement = acToBeUpdated.getElements().get(elementId);
471 // Add additional elements if present for migration
472 if (dbAcElement == null) {
473 LOGGER.info("New Ac element {} added in Migration", elementId);
474 acToBeUpdated.getElements().put(elementId, element.getValue());
476 AcmUtils.recursiveMerge(dbAcElement.getProperties(), element.getValue().getProperties());
477 var newDefinition = element.getValue().getDefinition().asConceptKey();
478 var dbElementDefinition = dbAcElement.getDefinition().asConceptKey();
479 AutomationCompositionProvider.checkCompatibility(
480 newDefinition, dbElementDefinition, automationComposition.getInstanceId());
481 dbAcElement.setDefinition(element.getValue().getDefinition());
484 // Remove element which is not present in the new Ac instance
485 var elementsRemoved = getElementRemoved(acToBeUpdated, automationComposition);
486 elementsRemoved.forEach(uuid -> acToBeUpdated.getElements().remove(uuid));
488 var validationResult = validateAutomationComposition(acToBeUpdated, acDefinitionTarget);
489 if (!validationResult.isValid()) {
490 throw new PfModelRuntimeException(Status.BAD_REQUEST, validationResult.getResult());
492 acToBeUpdated.setCompositionTargetId(automationComposition.getCompositionTargetId());
493 return elementsRemoved;
496 private AutomationCompositionDefinition getAcDefinition(UUID compositionId,
497 AutomationComposition automationComposition) {
498 AutomationCompositionProvider.validateInstanceEndpoint(compositionId, automationComposition);
499 var acDefinition = acDefinitionProvider.getAcDefinition(automationComposition.getCompositionId());
500 participantProvider.checkRegisteredParticipant(acDefinition);
505 * Retrieves a list of AutomationComposition instances filtered by the specified state change results
506 * and deployment states. The result can be paginated and sorted based on the provided parameters.
508 * @param stateChangeResults a list of StateChangeResult values to filter the AutomationComposition instances
509 * @param deployStates a list of DeployState values to filter the AutomationComposition instances
510 * @param pageable the pagination information including page size and page number
511 * @return a list of AutomationComposition instances that match the specified filters
513 public AutomationCompositions getAcInstancesByStateResultDeployState(
514 final String stateChangeResults, final String deployStates,
515 final Pageable pageable) {
517 List<StateChangeResult> stateChangeResultList = new ArrayList<>();
518 if (stateChangeResults != null) {
519 Arrays.stream(stateChangeResults.split(","))
520 .forEach(stateChangeResult -> stateChangeResultList.add(StateChangeResult.valueOf(stateChangeResult)));
523 List<DeployState> deployStateList = new ArrayList<>();
524 if (deployStates != null) {
525 Arrays.stream(deployStates.split(","))
526 .forEach(deployState -> deployStateList.add(DeployState.valueOf(deployState)));
529 var instances = automationCompositionProvider.getAcInstancesByStateResultDeployState(stateChangeResultList,
530 deployStateList, pageable);
531 return new AutomationCompositions(instances);