use of com.emc.storageos.workflow.Workflow.Step in project coprhd-controller by CoprHD.
the class WorkflowService method loadStepData.
/**
* Retrieve step data for a class.
*
* @param workflowURI -- required workflow URI
* @param key - optional string key
* @param stepId -- The step identifier (optional).
* @return -- A Java serializable object, or null if no data found.
* @throws Exception
*/
public Object loadStepData(URI workflowURI, String key, String stepId) {
try {
Workflow workflow = loadWorkflowFromUri(workflowURI);
if (workflow == null) {
Exception ex = WorkflowException.exceptions.workflowNotFound(stepId);
_log.error("Can't load step state for step: " + stepId, ex);
return null;
}
String path = getZKStepDataPath(stepId);
Stat stat = _dataManager.checkExists(path);
if (stat != null) {
// Legacy path for old workflows
Object data = _dataManager.getData(path, false);
_log.info(String.format("Loaded WorkflowStepData for %s %s %s", workflowURI, stepId, key));
return data;
}
Object data = null;
WorkflowStepData stepData = getWorkflowStepData(workflow.getWorkflowURI(), stepId, key);
if (stepData == null) {
// If we were not able to find step data, it could be that the step we are trying to load is a rollback
// step. Rollback step ids are only determined during rollback execution and therefore step data
// for these steps may not be stored in the database yet. In this case we need to determine if the rollback
// step has a founding step (primary execution step) that we can load from the database. The founding
// step data can be used to form a context of executed step operations.
Map<String, Step> stepMap = workflow.getStepMap();
if (stepMap != null) {
Step workflowStep = stepMap.get(stepId);
if (workflowStep != null && workflowStep.isRollbackStep() && workflowStep.foundingStepId != null) {
_log.info(String.format("Step data for rollback step %s does not exist. Attempting to load step data for founding step %s", stepId, workflowStep.foundingStepId));
stepData = getWorkflowStepData(workflow.getWorkflowURI(), workflowStep.foundingStepId, key);
}
}
}
if (stepData != null) {
data = GenericSerializer.deserialize(stepData.getData());
_log.info(String.format("Loaded WorkflowStepData for %s %s %s", workflowURI, stepId, key));
} else {
_log.info(String.format("No WorkflowStepData found for %s %s %s", workflowURI, stepId, key));
}
return data;
} catch (Exception ex) {
_log.error("Can't load step data for step: " + stepId);
}
return null;
}
use of com.emc.storageos.workflow.Workflow.Step in project coprhd-controller by CoprHD.
the class WorkflowService method updateStepStatus.
/**
* Given a ZK path to a Callback node, get the data which is a StatusUpdateMessage
* and update the appropriate step status.
*
* @param stepId
* -- The Step Id of the step.
* @param state
* @param code
* @param message
* @param automaticRollback
* whether to rollback in case of error at the end of workflow
* @throws WorkflowException
*/
private void updateStepStatus(String stepId, StepState state, ServiceCode code, String message, boolean automaticRollback) throws WorkflowException {
// String path = getZKCallbackPath(stepId);
String workflowPath = getZKStep2WorkflowPath(stepId);
Workflow workflow = null;
boolean workflowDeleted = false;
InterProcessLock lock = null;
try {
// Get the workflow path from ZK
workflowPath = (String) _dataManager.getData(workflowPath, false);
// It is not an error to try and update using a non-existent stepId
if (workflowPath == null) {
return;
}
// Load the Workflow state from ZK
workflow = (Workflow) _dataManager.getData(workflowPath, false);
if (workflow == null) {
WorkflowException ex = WorkflowException.exceptions.workflowNotFound(workflowPath);
_log.info("Workflow not found: " + workflowPath, ex);
throw ex;
}
// Lock the Workflow
lock = lockWorkflow(workflow);
// Load the entire workflow state including the steps
workflow = loadWorkflow(workflow);
if (workflow == null) {
WorkflowException ex = WorkflowException.exceptions.workflowNotFound(workflowPath);
_log.info("Workflow not found: " + workflowPath, ex);
throw ex;
}
synchronized (workflow) {
// Update the StepState structure
StepStatus status = workflow.getStepStatus(stepId);
// something else. There is an exception as WorkflowService calls this for SUSPENDED_NO_ERROR.
if (status.isTerminalState() && !(status.state == StepState.SUSPENDED_NO_ERROR || status.state == StepState.CANCELLED)) {
WorkflowException ex = WorkflowException.exceptions.workflowStepInTerminalState(stepId, status.state.name(), state.name());
_log.error(String.format("Step %s is already in terminal state %s, trying to change to %s which will be ignored", stepId, status.state.toString(), state.toString()), ex);
// are called out of a completer called from the WorkflowService.doWorkflowEndProcessing
return;
}
// If an error is reported, and we're supposed to suspend on error, suspend
// Don't put a workflow in suspended state if we're already in rollback.
Step step = workflow.getStepMap().get(stepId);
if (StepState.ERROR == state && workflow.isSuspendOnError() && !step.isRollbackStep()) {
state = StepState.SUSPENDED_ERROR;
step.suspendStep = false;
}
// SUSPENDED_ERROR step to ERROR
if (step.isRollbackStep()) {
if (step.foundingStepId != null) {
if (workflow.getStepMap().get(step.foundingStepId) != null) {
Step foundingStep = workflow.getStepMap().get(step.foundingStepId);
StepStatus foundingStatus = workflow.getStepStatus(step.foundingStepId);
if (StepState.SUSPENDED_ERROR.equals(foundingStatus.state)) {
foundingStatus.updateState(StepState.ERROR, code, message);
persistWorkflowStep(workflow, foundingStep);
}
}
}
}
_log.info(String.format("Updating workflow step: %s state %s : %s", stepId, state, message));
status.updateState(state, code, message);
// Persist the updated step state
persistWorkflowStep(workflow, step);
// to initiate a totally separate rollback.
try {
if (workflow.allStatesTerminal() && !workflow.isRollbackState() && (workflow._childWorkflows == null || workflow._childWorkflows.isEmpty())) {
InvokeTestFailure.internalOnlyInvokeTestFailure(InvokeTestFailure.ARTIFICIAL_FAILURE_004);
}
} catch (NullPointerException npe) {
// Overwrite the status of the final state
_log.error("Overwriting the state of the final step of a workflow due to artificial failure request", npe);
StepStatus ss = workflow.getStepStatus(stepId);
ss.state = StepState.ERROR;
ss.description = "Artificially thrown exception: " + InvokeTestFailure.ARTIFICIAL_FAILURE_004;
ss.message = "The final step in the workflow was successful, but an artificial failure request is configured to fail the final step to invoke full rollback.";
workflow.getStepStatusMap().put(stepId, ss);
_log.info(String.format("Updating workflow step: %s state %s : %s", stepId, state, ss.message));
WorkflowException ex = WorkflowException.exceptions.workflowInvokedFailure(ss.description);
status.updateState(ss.state, ex.getServiceCode(), ss.message);
step.status = ss;
// Persist the updated step state
persistWorkflowStep(workflow, step);
}
if (status.isTerminalState()) {
// release any step level locks held.
boolean releasedLocks = _ownerLocker.releaseLocks(stepId);
if (!releasedLocks) {
_log.info("Unable to release StepLocks for step: " + stepId);
}
// Check for any blocked steps and unblock them
checkBlockedSteps(workflow, stepId);
}
// Check to see if the workflow might be finished, or need a rollback.
if (workflow.allStatesTerminal()) {
workflowDeleted = doWorkflowEndProcessing(workflow, automaticRollback, lock);
if (workflowDeleted) {
// lock is released by end processing if the workflow is deleted
lock = null;
}
}
}
} catch (Exception ex) {
String exMsg = "Exception processing updateStepStatus stepId: " + stepId + ": " + ex.getMessage();
_log.error(exMsg, ex);
throw new WorkflowException(exMsg, ex);
} finally {
unlockWorkflow(workflow, lock);
if (workflowDeleted) {
deleteWorkflowLock(workflow);
}
}
}
use of com.emc.storageos.workflow.Workflow.Step in project coprhd-controller by CoprHD.
the class WorkflowService method determineIfRollbackCompleted.
/**
* Returns true if all the Rollback StepStates are SUCCESS.
* Returns false if no Rollback was never initiated or some rollback states did not complete.
*
* @param workflow
* URI
* @return true iff all the Rollback StepStates are SUCCESS.
*/
private boolean determineIfRollbackCompleted(Workflow workflow) {
// If haven't initiated rollback, then return false.
if (workflow.isRollbackState() == false) {
return false;
}
boolean rollbackComplete = true;
Map<String, Step> stepMap = workflow.getStepMap();
for (Step step : stepMap.values()) {
// Do not consider non-rollback steps
if (!step.isRollbackStep()) {
continue;
}
StepStatus status = workflow.getStepStatus(step.stepId);
if (status.isTerminalState() == false || status.state != StepState.SUCCESS) {
_log.info(String.format("Rollback step %s not successful, state %s", step.stepId, status.state.name()));
rollbackComplete = false;
}
}
return rollbackComplete;
}
use of com.emc.storageos.workflow.Workflow.Step in project coprhd-controller by CoprHD.
the class WorkflowService method suspendStepsMatchingProperty.
/**
* Marks steps as suspend-able when they are encountered and unblocked.
* workflow_suspend_on_class_method, such as "MaskingWorkflowEntryPoints.doExportGroupAddVolumes"
*
* @param workflow
* workflow to scan
*/
private void suspendStepsMatchingProperty(Workflow workflow) {
// Load the current workflow property to suspend on class/method
String suspendOn = _coordinator.getPropertyInfo().getProperty(WORKFLOW_SUSPEND_ON_CLASS_METHOD_PROPERTY);
// If unit testing, get this value from the unit tester.
if (_suspendClassMethodTestOnly != null) {
suspendOn = _suspendClassMethodTestOnly;
}
String suspendClass = null;
String suspendMethod = null;
if (suspendOn != null && !suspendOn.trim().isEmpty()) {
_log.info("suspend on class/method is SET to: " + suspendOn);
if (suspendOn.contains(".")) {
suspendClass = suspendOn.substring(0, suspendOn.indexOf("."));
suspendMethod = suspendOn.substring(suspendOn.indexOf(".") + 1);
} else {
suspendClass = suspendOn;
suspendMethod = "*";
}
// Scan all steps for class and methods that should be set to the suspended state.
for (Step step : workflow.getStepMap().values()) {
boolean suspendStep = false;
// If suspend class and method are true, everything suspends all of the time.
if (suspendClass.equals("*") && suspendMethod.equals("*")) {
suspendStep = true;
} else if (step.controllerName.endsWith(suspendClass) && (step.executeMethod.methodName.equals(suspendMethod) || suspendMethod.equals("*"))) {
suspendStep = true;
} else if (suspendClass.equals("*") && step.executeMethod.methodName.equals(suspendMethod)) {
suspendStep = true;
}
if (suspendStep) {
logStep(workflow, step);
if (workflow.getSuspendSteps() == null) {
workflow.setSuspendSteps(new HashSet<URI>());
}
_log.info("Adding step " + step.description + " to workflow list of steps to suspend: " + workflow._workflowURI.toString());
workflow.getSuspendSteps().add(step.workflowStepURI);
}
}
}
}
use of com.emc.storageos.workflow.Workflow.Step in project coprhd-controller by CoprHD.
the class WorkflowService method checkBlockedSteps.
/**
* Checks the workflow for any BLOCKED steps that have become unblocked,
* and dispatches them or cancels them if necessary.
*
* @param workflow
* -- The Workflow to be checked.
* @param fromStepId
* -- The Step that has changed state.
*/
private void checkBlockedSteps(Workflow workflow, String fromStepId) {
boolean again;
Set<String> suspendedSteps = new HashSet<String>();
do {
// only loop again if made change
again = false;
for (Step step : workflow.getStepMap().values()) {
if (step.status.state != StepState.BLOCKED) {
continue;
}
try {
try {
if (!isBlocked(workflow, step)) {
again = true;
if (isStepMarkedForSuspend(workflow, step)) {
changeStepToSuspendedNoErrorState(workflow, suspendedSteps, step);
} else {
step.status.updateState(StepState.QUEUED, null, "Unblocked by step: " + fromStepId);
persistWorkflowStep(workflow, step);
_log.info(String.format("Step %s has been unblocked by step %s", step.stepId, fromStepId));
dispatchStep(step, workflow._nested);
}
}
} catch (CancelledException ex) {
again = true;
// If we got a CancelledException, this step needs to be cancelled.
step.status.updateState(StepState.CANCELLED, null, "Cancelled by step: " + fromStepId);
_log.info(String.format("Step %s has been cancelled by step %s", step.stepId, fromStepId));
persistWorkflowStep(workflow, step);
}
} catch (Exception ex) {
_log.error("Exception" + ex.getMessage());
}
}
} while (again == true);
}
Aggregations