Search in sources :

Example 6 with Step

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;
}
Also used : Stat(org.apache.zookeeper.data.Stat) WorkflowStepData(com.emc.storageos.db.client.model.WorkflowStepData) DataObject(com.emc.storageos.db.client.model.DataObject) Step(com.emc.storageos.workflow.Workflow.Step) InternalException(com.emc.storageos.svcs.errorhandling.resources.InternalException) DatabaseException(com.emc.storageos.db.exceptions.DatabaseException) DeviceControllerException(com.emc.storageos.exceptions.DeviceControllerException) ControllerException(com.emc.storageos.volumecontroller.ControllerException) LockRetryException(com.emc.storageos.locking.LockRetryException)

Example 7 with Step

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);
        }
    }
}
Also used : InterProcessLock(org.apache.curator.framework.recipes.locks.InterProcessLock) StepStatus(com.emc.storageos.workflow.Workflow.StepStatus) Step(com.emc.storageos.workflow.Workflow.Step) InternalException(com.emc.storageos.svcs.errorhandling.resources.InternalException) DatabaseException(com.emc.storageos.db.exceptions.DatabaseException) DeviceControllerException(com.emc.storageos.exceptions.DeviceControllerException) ControllerException(com.emc.storageos.volumecontroller.ControllerException) LockRetryException(com.emc.storageos.locking.LockRetryException)

Example 8 with Step

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;
}
Also used : Step(com.emc.storageos.workflow.Workflow.Step) StepStatus(com.emc.storageos.workflow.Workflow.StepStatus)

Example 9 with Step

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);
            }
        }
    }
}
Also used : Step(com.emc.storageos.workflow.Workflow.Step) URI(java.net.URI)

Example 10 with Step

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);
}
Also used : Step(com.emc.storageos.workflow.Workflow.Step) InternalException(com.emc.storageos.svcs.errorhandling.resources.InternalException) DatabaseException(com.emc.storageos.db.exceptions.DatabaseException) DeviceControllerException(com.emc.storageos.exceptions.DeviceControllerException) ControllerException(com.emc.storageos.volumecontroller.ControllerException) LockRetryException(com.emc.storageos.locking.LockRetryException) HashSet(java.util.HashSet)

Aggregations

Step (com.emc.storageos.workflow.Workflow.Step)12 DatabaseException (com.emc.storageos.db.exceptions.DatabaseException)5 DeviceControllerException (com.emc.storageos.exceptions.DeviceControllerException)5 LockRetryException (com.emc.storageos.locking.LockRetryException)5 InternalException (com.emc.storageos.svcs.errorhandling.resources.InternalException)5 ControllerException (com.emc.storageos.volumecontroller.ControllerException)5 StepStatus (com.emc.storageos.workflow.Workflow.StepStatus)4 HashSet (java.util.HashSet)4 DataObject (com.emc.storageos.db.client.model.DataObject)2 InterProcessLock (org.apache.curator.framework.recipes.locks.InterProcessLock)2 URIQueryResultList (com.emc.storageos.db.client.constraint.URIQueryResultList)1 WorkflowStepData (com.emc.storageos.db.client.model.WorkflowStepData)1 StepState (com.emc.storageos.workflow.Workflow.StepState)1 URI (java.net.URI)1 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 List (java.util.List)1 Set (java.util.Set)1 Stat (org.apache.zookeeper.data.Stat)1