Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Brief introduction

Example of scenario with a deployed instance with two element:

  • user call undeploy command
  • first instance element success with UNDEPLOYED state
  • second instance element fail with DEPLOYED state
  • user call undeploy command again
  • first instance element does not know that the element is already UNDEPLOYED

Add support for the participant to understand what was the last state.

...

Allowed state from the participant perspective

Action

state

stChResult

Description

Prime

PRIMED

NO_ERROR

Prime is completed

COMMISSIONED

FAILED

Prime is failed

Deprime

COMMISSIONED

NO_ERROR

Deprime is completed

PRIMED

FAILED

Deprime is failed


Action

deployState

lockState

stChResult

Description

Deploy

DEPLOYED


NO_ERROR

Deploy is completed

UNDEPLOYED


FAILED

Deploy is failed

Undeploy

UNDEPLOYED


NO_ERROR

Undeploy is completed

DEPLOYED


FAILED

Undeploy is failed

Lock


LOCKED

NO_ERROR

Lock is completed


UNLOCKED

FAILED

Lock is failed

Unlock


UNLOCKED

NO_ERROR

Unlock is completed


LOCKED

FAILED

Unlock is failed

Update

DEPLOYED


NO_ERROR

Update is completed

DEPLOYED


FAILED

Update is failed

Migrate

DEPLOYED


NO_ERROR

Migrate is completed

DEPLOYED


FAILED

Migrate is failed

Delete

DELETED


NO_ERROR

Delete is completed

UNDEPLOYED


FAILED

Delete is failed

Handle states and failure scenarios from the participant perspective

It is important to make distinction between the state of the instance/element

...

flow, and the state of the application/configuration involved.
A deployed element means that a participant has completed a deploy action, and should not be confused with a deployed application.

There are scenarios where it make sense when a process is failed, all elements should be repeat fully, by in other scenarios could de different, it depend of the context. Anyway a participant could implement idempotent operations.  

The responsibility to know what it needs to be done is delegated to the participant.

When a participant cannot implement idempotent operations, in order to cover the scenario with failed process with more than one element involved, it has to know what was the previous state.

Solutions

A simple solution from participant side is that it can use "useState" and "operationalState" to save information related to the deployment process.

"useState", "operationalState" and "outProperties" are controlled by the participant side, and saved into ACM-r Db by status message (by sendAcElementInfo method).

To support the participant implementation we can add "useState" and "operationalState" into the InstanceElementDto:

Code Block
languagejava
public record InstanceElementDto(UUID instanceId, UUID elementId, ToscaServiceTemplate toscaServiceTemplateFragment,
                                 Map<String, Object> inProperties, Map<String, Object> outProperties, String operationalState, String useState) {
}

The examples below are suggestions, there are al lot possibility how these parameters can be used.

  • Below a suggestion with operationalState:

Example with two elements:

  1. an instance is deployed, so the two elements are DEPLOYED

  2. user calls undeploy command (ACM-R sets all element as DEPLOYING)

  3. participant executes the first instance element with success and sends UNDEPLOYED state

  4. participant executes the second instance element with fail and sends DEPLOYED state

  5. user calls undeploy command again (ACM-R sets all element as DEPLOYING)

  6. participant does not know that the application related to the first element is already UNDEPLOYED when the flow state is UNDEPLOYING

There are some contexts in a failure scenario that the participant need to know the state of the deployed application. From participant side, using “outProperties” it could be possible to handle custom states that better suit whit the context.

Solutions

Example of a participant that deploy/undeploy applications.
The following Java code shows how to implement deploy and undeploy that avoid to repeat the action already executed.

Code Block
languagejava
    @Override
    public void deploy(CompositionElementDto compositionElement, InstanceElementDto instanceElement)
            throws PfModelException {

        if ("DEPLOYED".equals(instanceElement.operationalStateoutProperties().get("state"))) {
             // deploy process already done
            intermediaryApi.updateAutomationCompositionElementState(instanceElement.instanceId(), instanceElement.elementId,
                    (), DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Already Deployed");
            return;
           }
         
        // deployment process
        .......................................
        .......................................
        // end of the deployment process
        
        if (isDeploySuccess()) {
            instanceElement.outProperties().put("state", "DEPLOYED");
            intermediaryApi.sendAcElementInfo(instanceElement.instanceId(), instanceElement.elementId(), null, null, instanceElement.outProperties());
 
             ""intermediaryApi.updateAutomationCompositionElementState(instanceElement.instanceId(), instanceElement.elementId(), DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "DEPLOYED",Deployed");
        } else {
            instanceElement.outProperties().put("state", "UNDEPLOYED");
            intermediaryApi.updateAutomationCompositionElementStatesendAcElementInfo(instanceElement.instanceId(), instanceElement.elementId(), null, null, instanceElement.outProperties());
 
            intermediaryApi.updateAutomationCompositionElementState(instanceElement.instanceId(),     instanceElement.elementId(), DeployState.DEPLOYEDUNDEPLOYED, null, StateChangeResult.NO_ERRORFAILED, "DeployedDeploy failed!");
        } 
    }


    @Override
    public void undeploy(CompositionElementDto compositionElement, InstanceElementDto instanceElement)
            throws PfModelException {

        if ("UNDEPLOYEDDEPLOYED".equals(instanceElement.operationalState(outProperties().get("state"))) {
                 // undeploy process already done

            intermediaryApi.updateAutomationCompositionElementState(instanceElement.instanceId(), instanceElement.elementId(),
                    DeployState.UNDEPLOYED, null, StateChangeResult.NO_ERROR, "Already Undeployed");
            return;
        }

        // undeployment process
        .......................................
        .......................................
        // end of the undeployment process        
        
        if (isUndeploySuccess()) {
             instanceElement.outProperties().put("state", "UNDEPLOYED");
            intermediaryApi.sendAcElementInfo(instanceElement.instanceId(), instanceElement.elementId(), null, null, instanceElement.outProperties());

            ""intermediaryApi.updateAutomationCompositionElementState(instanceElement.instanceId(), instanceElement.elementId(), DeployState.UNDEPLOYED, null, StateChangeResult.NO_ERROR, "UNDEPLOYED",Undeployed");
        } else {
            instanceElement.outProperties().put("state", "DEPLOYED");
            intermediaryApi.updateAutomationCompositionElementStatesendAcElementInfo(instanceElement.instanceId(), instanceElement.elementId(), null, null, instanceElement.outProperties());

            intermediaryApi.updateAutomationCompositionElementState(instanceElement.instanceId(), instanceElement.elementId(), DeployState.UNDEPLOYEDDEPLOYED, null, StateChangeResult.NO_ERRORFAILED, "UndeployedUndeploy failed!");
        }
     }

...

}


Example of a participant that make configurations.
The following Java code shows how to implement deploy and undeploy that needs a clean up and repeat the action. The state of the configuration will saved in outProperties.

Code Block
languagejava
    @Override
    public void deploy(CompositionElementDto compositionElement, InstanceElementDto instanceElement) throws PfModelException {

        throwsvar PfModelExceptionstate {
= instanceElement.outProperties().get("state");
        if ("DEPLOYED".equals(instanceElement.operationalState(state))) {
             // deployclean processup alreadydeployment
done        
    intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,   } else if ("DEPLOYING".equals(state) || "UNDEPLOYING".equals(state)) {
           DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Already Deployed");
 // check and clean up

         }
return;
        }

         // deployment process
          instanceElement.......................................
        .......................................
        intermediaryApioutProperties().put("state", "DEPLOYING");
        intermediaryApi.sendAcElementInfo(instanceElement.instanceId(), instanceElement.elementId(),                 "Step 1", "DEPLOYING"null, null, instanceElement.outProperties()); 
            .......................................
        .......................................
        intermediaryApi.sendAcElementInfo(instanceElement.instanceId(), instanceElement.elementId(),
                "Step 2", "DEPLOYING", instanceElement.outProperties());
        .......................................
        .......................................
        // end of the deployment process        
        
         if (isDeploySuccess()) {
            instanceElement.outProperties().put("state", "DEPLOYED");
            intermediaryApi.sendAcElementInfo(instanceElement.instanceId(), instanceElement.elementId(), null, null, instanceElement.outProperties());
 
             ""intermediaryApi.updateAutomationCompositionElementState(instanceElement.instanceId(), instanceElement.elementId(), DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "DEPLOYED",Deployed");
        } else {
            instanceElement.outProperties().put("state", "UNDEPLOYED");
            intermediaryApi.updateAutomationCompositionElementStatesendAcElementInfo(instanceElement.instanceId(), instanceElement.elementId(), null, null, instanceElement.outProperties());
 
            intermediaryApi.updateAutomationCompositionElementState(instanceElement.instanceId(),     instanceElement.elementId(), DeployState.DEPLOYEDUNDEPLOYED, null, StateChangeResult.NO_ERRORFAILED, "DeployedDeploy failed!");
        } 
     }


    @Override
    public void undeploy(CompositionElementDto compositionElement, InstanceElementDto instanceElement) throws PfModelException {

         throwsvar PfModelExceptionstate {
= instanceElement.outProperties().get("state");
        if ("UNDEPLOYED".equals(instanceElement.operationalState(state))) {
            // undeployclean processup alreadyundeployment
done        
     intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,  } else if ("DEPLOYING".equals(state) || "UNDEPLOYING".equals(state)) {
            DeployState.UNDEPLOYED, null, StateChangeResult.NO_ERROR, "Already Undeployed");// check and clean up

        }
 
return;
        }

        // undeployment process
 
      .......................................   instanceElement.outProperties().put("state", "UNDEPLOYING");
    .......................................         intermediaryApiintermediaryApi.sendAcElementInfo(instanceElement.instanceId(), instanceElement.elementId(),                 "Step 1", "UNDEPLOYING"null, null, instanceElement.outProperties()); 

          .......................................
        .......................................
        intermediaryApi.sendAcElementInfo(instanceElement.instanceId(), instanceElement.elementId(),
                "Step 2", "UNDEPLOYING", instanceElement.outProperties());
        .......................................
        .......................................
        // end of the undeployment process        
        
         if (isUndeploySuccess()) {
            instanceElement.outProperties().put("state", "UNDEPLOYED");
            intermediaryApi.sendAcElementInfo(instanceElement.instanceId(), instanceElement.elementId(), null, null, instanceElement.outProperties());

            ""intermediaryApi.updateAutomationCompositionElementState(instanceElement.instanceId(), instanceElement.elementId(), DeployState.UNDEPLOYED, null, StateChangeResult.NO_ERROR, "UNDEPLOYED",Undeployed");
        } else {
            instanceElement.outProperties().put("state", "DEPLOYED");
            intermediaryApi.updateAutomationCompositionElementStatesendAcElementInfo(instanceElement.instanceId(), instanceElement.elementId(), null, null, instanceElement.outProperties());

            intermediaryApi.updateAutomationCompositionElementState(instanceElement.instanceId(), instanceElement.elementId(), DeployState.UNDEPLOYEDDEPLOYED, null, StateChangeResult.NO_ERRORFAILED, "UndeployedUndeploy failed!");
         }
    }


Final consideration: In all suggestions shown before we have used labels as "DEPLOY", "UNDEPLOY", "DEPLOYING", "UNDEPLOYING" but the developer can change them as better suit with the context of the participant.