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 elements:

  • 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 repeat the action, but in other scenarios it could be different, it depends on 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 "outProperties" to save information related to the deployment process.

"outProperties" is controlled by the participant side, and saved into ACM-r Db by status message (by sendAcElementInfo method). Each participant replica will be synchronized as well.

The examples below are suggestions.

...

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.outProperties().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");
        } else {
            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.FAILED, "Deploy failed!");
        } 
    }


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

        if ("DEPLOYED".equals(instanceElement.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");
        } else {
            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.FAILED, "Undeploy 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 {

        var state = instanceElement.outProperties().get("state");
        if ("DEPLOYED".equals(state)) {
            // clean up deployment
        
        } else if ("DEPLOYING".equals(state) || "UNDEPLOYING".equals(state)) {
            // check and clean up

        }

        // deployment process
        instanceElement.outProperties().put("state", "DEPLOYING");
        intermediaryApi.sendAcElementInfo(instanceElement.instanceId(), instanceElement.elementId(), null, null, 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");
        } else {
            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.FAILED, "Deploy failed!");
        } 
     }


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

         var state = instanceElement.outProperties().get("state");
        if ("UNDEPLOYED".equals(state)) {
            // clean up undeployment
        
        } else if ("DEPLOYING".equals(state) || "UNDEPLOYING".equals(state)) {
            // check and clean up

        }
 
        // undeployment process
 
        instanceElement.outProperties().put("state", "UNDEPLOYING");
        intermediaryApi.sendAcElementInfo(instanceElement.instanceId(), instanceElement.elementId(), null, null, 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");
        } else {
            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.FAILED, "Undeploy 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.