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" or "operationalState" to save information related to the deployment process.
Into the participant implementation it can send the completition of the process by sendAcElementInfo method.
...
Example with two elements:
an instance is deployed, so the two elements are DEPLOYED
user calls undeploy command (ACM-R sets all element as DEPLOYING)
participant executes the first instance element with success and sends UNDEPLOYED state
participant executes the second instance element with fail and sends DEPLOYED state
user calls undeploy command again (ACM-R sets all element as DEPLOYING)
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 | ||
---|---|---|
| ||
@Override public recordvoid InstanceElementDtodeploy(UUIDCompositionElementDto instanceIdcompositionElement, UUIDInstanceElementDto elementId,instanceElement) ToscaServiceTemplatethrows toscaServiceTemplateFragment,PfModelException { if ("DEPLOYED".equals(instanceElement.outProperties().get("state"))) { // deploy process already done Map<String, Object> inProperties, Map<String, Object> outProperties, String operationalState, String useState) { } |
Below an example with operationalState where the process should not be repeated:
Code Block | ||
---|---|---|
| ||
@Override public void deploy(CompositionElementDto compositionElement, InstanceElementDto instanceElement) intermediaryApi.updateAutomationCompositionElementState(instanceElement.instanceId(), instanceElement.elementId(), DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Already Deployed"); return; } // deployment process ....................................... ....................................... // end of the deployment process throws PfModelExceptionif (isDeploySuccess()) { if instanceElement.outProperties().put("state", "DEPLOYED".equals); intermediaryApi.sendAcElementInfo(instanceElement.instanceId(), instanceElement.elementId(), null, null, instanceElement.outProperties()); intermediaryApi.updateAutomationCompositionElementState(instanceElement.operationalStateinstanceId(), instanceElement.elementId(), DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Deployed"); } else { instanceElement.outProperties().put("state", "UNDEPLOYED"); // deploy process already done intermediaryApi.sendAcElementInfo(instanceElement.instanceId(), instanceElement.elementId(), null, null, instanceElement.outProperties()); intermediaryApi 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.DEPLOYEDUNDEPLOYED, null, StateChangeResult.NO_ERROR, "Already DeployedUndeployed"); return; } // deploymentundeployment process ....................................... ....................................... // end of the deploymentundeployment 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, "DEPLOYED",Undeployed"); } else { instanceElement.outProperties().put("state", "DEPLOYED"); intermediaryApi.updateAutomationCompositionElementStatesendAcElementInfo(instanceElement.instanceId(), instanceElement.elementId(), null, null, instanceElement.outProperties()); intermediaryApi.updateAutomationCompositionElementState(instanceElement.instanceId(), instanceElement.elementId(), DeployState.DEPLOYED, null, StateChangeResult.NO_ERRORFAILED, "DeployedUndeploy 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 | ||
---|---|---|
| ||
@Override public void undeploydeploy(CompositionElementDto compositionElement, InstanceElementDto instanceElement) throws PfModelException { throws PfModelException {var state = instanceElement.outProperties().get("state"); if ("DEPLOYED".equals(state)) { // clean up deployment } else if ("UNDEPLOYEDDEPLOYING".equals(instanceElement.operationalState(state) || "UNDEPLOYING".equals(state))) { // undeploycheck and clean up } // deployment process already done instanceElement.outProperties().put("state", "DEPLOYING"); intermediaryApi.updateAutomationCompositionElementStatesendAcElementInfo(instanceElement.instanceId(), instanceElement.elementId(), null, null, instanceElement.outProperties()); DeployState.UNDEPLOYED....................................... ....................................... ....................................... // 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, "Already Undeployed"Deployed"); } else { instanceElement.outProperties().put("state", "UNDEPLOYED"); intermediaryApi.sendAcElementInfo(instanceElement.instanceId(), instanceElement.elementId(), null, returnnull, 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",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!"); } } |