Search in sources :

Example 6 with StepStatus

use of com.emc.storageos.workflow.Workflow.StepStatus in project coprhd-controller by CoprHD.

the class WorkflowService method printStepStatuses.

private void printStepStatuses(Collection<StepStatus> stepStatuses) {
    for (StepStatus status : stepStatuses) {
        Date startTime = status.startTime;
        Date endTime = status.endTime;
        if (startTime != null && endTime != null) {
            _log.info(String.format("Step: %s (%s) state: %s message: %s started: %s completed: %s elapsed: %d ms", status.stepId, status.description, status.state, status.message, status.startTime, status.endTime, (status.endTime.getTime() - status.startTime.getTime())));
        } else {
            _log.info(String.format("Step: %s (%s) state: %s message: %s ", status.stepId, status.description, status.state, status.message));
        }
    }
}
Also used : StepStatus(com.emc.storageos.workflow.Workflow.StepStatus) Date(java.util.Date)

Example 7 with StepStatus

use of com.emc.storageos.workflow.Workflow.StepStatus 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 8 with StepStatus

use of com.emc.storageos.workflow.Workflow.StepStatus in project coprhd-controller by CoprHD.

the class WorkflowService method doWorkflowEndProcessing.

/**
 * End of Workflow processing that used to be in WorkflowExecutor.
 * Initiates rollback if necessary, does final task completer.
 *
 * @param workflow
 * @param automaticRollback
 * @param workflowLock
 *            -- released only if workflow is deleted
 * @return deleted
 * @throws DeviceControllerException
 */
private boolean doWorkflowEndProcessing(Workflow workflow, boolean automaticRollback, InterProcessLock workflowLock) throws DeviceControllerException {
    Map<String, StepStatus> statusMap = workflow.getStepStatusMap();
    // Print out the status of each step into the log.
    printStepStatuses(statusMap.values());
    // Get the WorkflowState
    WorkflowState state = workflow.getWorkflowStateFromSteps();
    // Clear the suspend step so we will execute if resumed.
    if (statusMap != null && workflow.getSuspendSteps() != null) {
        for (Map.Entry<String, StepStatus> statusEntry : statusMap.entrySet()) {
            if (statusEntry.getValue() != null && statusEntry.getValue().state != null && (statusEntry.getValue().state == StepState.SUSPENDED_ERROR || statusEntry.getValue().state == StepState.SUSPENDED_NO_ERROR)) {
                _log.info("Removing step " + statusEntry.getValue().description + " from the suspended steps list in workflow " + workflow._workflowURI.toString());
                URI suspendStepURI = workflow.getStepMap().get(statusEntry.getKey()).workflowStepURI;
                workflow.getSuspendSteps().remove(suspendStepURI);
                persistWorkflow(workflow);
            }
        }
    }
    // Get composite status and status message
    if (workflow._successMessage == null) {
        workflow._successMessage = String.format("Operation %s for task %s completed successfully", workflow._orchMethod, workflow._orchTaskId);
    }
    String[] errorMessage = new String[] { workflow._successMessage };
    _log.info(String.format("Workflow %s overall state: %s (%s)", workflow.getOrchTaskId(), state, errorMessage[0]));
    ServiceError error = Workflow.getOverallServiceError(statusMap);
    // Check for user requested terminate
    if (state == WorkflowState.ERROR && error == null && workflow.isRollingBackFromSuspend()) {
        WorkflowException exception = WorkflowException.exceptions.workflowTerminatedByRequest();
        error = ServiceError.buildServiceError(exception.getServiceCode(), exception.getLocalizedMessage());
    }
    // Initiate rollback if needed.
    if (automaticRollback && !workflow.isRollbackState() && (state == WorkflowState.ERROR || state == WorkflowState.SUSPENDED_ERROR)) {
        if (workflow.isSuspendOnError()) {
            _log.info(String.format("Suspending workflow %s on error, no rollback initiation", workflow.getWorkflowURI()));
            state = WorkflowState.SUSPENDED_ERROR;
        } else if (initiateRollback(workflow)) {
            // Return now, wait until the rollback completions come here again.
            workflow.setWorkflowState(WorkflowState.ROLLING_BACK);
            persistWorkflow(workflow);
            logWorkflow(workflow, true);
            _log.info(String.format("Rollback initiated workflow %s", workflow.getWorkflowURI()));
            return false;
        }
    }
    // Save the updated workflow state
    workflow.setWorkflowState(state);
    persistWorkflow(workflow);
    logWorkflow(workflow, true);
    try {
        // Check if rollback completed.
        if (workflow.isRollbackState()) {
            if (workflow._rollbackHandler != null) {
                workflow._rollbackHandler.rollbackComplete(workflow, workflow._rollbackHandlerArgs);
            }
        }
        // Check for workflow completer callback.
        if (workflow._callbackHandler != null) {
            workflow._callbackHandler.workflowComplete(workflow, workflow._callbackHandlerArgs);
        }
        // Throw task completer if supplied.
        if (workflow._taskCompleter != null) {
            switch(state) {
                case ERROR:
                    workflow._taskCompleter.error(_dbClient, _locker, error);
                    break;
                case SUCCESS:
                    workflow._taskCompleter.ready(_dbClient, _locker);
                    break;
                case SUSPENDED_ERROR:
                    workflow._taskCompleter.suspendedError(_dbClient, _locker, error);
                    break;
                case SUSPENDED_NO_ERROR:
                    workflow._taskCompleter.suspendedNoError(_dbClient, _locker);
                    break;
                default:
                    break;
            }
        }
    } finally {
        logWorkflow(workflow, true);
        // Release the Workflow's locks, if any.
        boolean removed = _ownerLocker.releaseLocks(workflow.getWorkflowURI().toString());
        if (!removed) {
            _log.error("Unable to release workflow locks for: " + workflow.getWorkflowURI().toString());
        }
        // Remove the workflow from ZK unless it is suspended (either for an error, or no error)
        if (workflow.getWorkflowState() != WorkflowState.SUSPENDED_ERROR && workflow.getWorkflowState() != WorkflowState.SUSPENDED_NO_ERROR) {
            removed = false;
            if (!workflow._nested) {
                // Remove the workflow from ZK unless it is suspended (either for an error, or no error)
                unlockWorkflow(workflow, workflowLock);
                destroyWorkflow(workflow);
                return true;
            } else {
                if (isExistingWorkflow(workflow)) {
                    _log.info(String.format("Workflow %s is nested, destruction deferred until parent destroys", workflow.getWorkflowURI()));
                }
                logWorkflow(workflow, true);
            }
        }
    }
    return false;
}
Also used : ServiceError(com.emc.storageos.svcs.errorhandling.model.ServiceError) StepStatus(com.emc.storageos.workflow.Workflow.StepStatus) Map(java.util.Map) HashMap(java.util.HashMap) URI(java.net.URI)

Example 9 with StepStatus

use of com.emc.storageos.workflow.Workflow.StepStatus in project coprhd-controller by CoprHD.

the class WorkflowService method initiateRollback.

/**
 * Initiate a rollback of the entire workflow.
 *
 * @param workflow
 *            - The workflow to be rolled back.
 * @return true if rollback initiated, false if suspended.
 */
public boolean initiateRollback(Workflow workflow) throws WorkflowException {
    // Verify all existing steps are in a terminal state.
    Map<String, StepStatus> statusMap = workflow.getAllStepStatus();
    for (StepStatus status : statusMap.values()) {
        if (false == status.isTerminalState()) {
            throw new WorkflowException("Step: " + status.stepId + " is not in a terminal state: " + status.state);
        }
    }
    // Make sure all non-cancelled nodes have a rollback method.
    // TODO: handle null rollback methods better.
    boolean norollback = false;
    for (Step step : workflow.getStepMap().values()) {
        // Suspended no error steps have not run, treat them as cancelled
        if (step.status.state == StepState.SUSPENDED_NO_ERROR) {
            step.status.updateState(StepState.CANCELLED, ServiceCode.WORKFLOW_STEP_CANCELLED, "Step cancelled because rollback was initiated");
            persistWorkflowStep(workflow, step);
            continue;
        }
        if (step.status.state != StepState.CANCELLED && step.rollbackMethod == null) {
            _log.error(String.format("Cannot rollback step %s because it does not have a rollback method", step.stepId));
            norollback = true;
        }
    }
    if (norollback) {
        return false;
    }
    _log.info("Generating rollback steps for workflow: " + workflow.getWorkflowURI());
    // Going to try and initiate the rollback.
    if (workflow._rollbackHandler != null) {
        workflow._rollbackHandler.initiatingRollback(workflow, workflow._rollbackHandlerArgs);
    }
    // Determine the steps that need to be rolled back.
    // Maps step original stepId to rollback Step.
    Map<String, Step> rollbackStepMap = new HashMap<String, Step>();
    // Contains dependencies for the rollback Steps organized into Step Groups..
    Map<String, Set<String>> rollbackStepGroupMap = new HashMap<String, Set<String>>();
    // Map of step ids or stepGroups names to execution step ids having a dependence on this step/group
    Map<String, List<String>> dependenceMap = new HashMap<String, List<String>>();
    for (Step step : workflow.getStepMap().values()) {
        // Don't process cancelled nodes, they don't need to be rolled back.
        if (step.status.state == StepState.CANCELLED) {
            continue;
        }
        // If we have a dependence, put it in the dependence map
        if (step.waitFor != null) {
            if (dependenceMap.get(step.waitFor) == null) {
                dependenceMap.put(step.waitFor, new ArrayList<String>());
            }
            // Step is dependent on the indicated waitFor
            dependenceMap.get(step.waitFor).add(step.stepId);
        }
        // Compute the corresponding rollback node.
        Step rb = step.generateRollbackStep();
        rollbackStepMap.put(step.stepId, rb);
    }
    // or it can be dependent on the stepGroup containing es1.
    for (Step executeStep : workflow.getStepMap().values()) {
        if (executeStep.status.state == StepState.CANCELLED) {
            continue;
        }
        Step rollbackStep = rollbackStepMap.get(executeStep.stepId);
        String stepGroupKey = "_rollback_" + rollbackStep.stepId;
        rollbackStepGroupMap.put(stepGroupKey, new HashSet<String>());
        // rollback nodes corresponding to the direct dependents of executeStep
        List<String> dependentList = dependenceMap.get(executeStep.stepId);
        if (dependentList != null) {
            for (String dependentId : dependentList) {
                Step dependentRollbackStep = rollbackStepMap.get(dependentId);
                if (dependentRollbackStep == null) {
                    continue;
                }
                rollbackStepGroupMap.get(stepGroupKey).add(dependentRollbackStep.stepId);
            }
        }
        // rollback nodes corresponding to the dependents in the executeStep's stepGroup
        dependentList = dependenceMap.get(executeStep.stepGroup);
        if (dependentList != null) {
            for (String dependentId : dependentList) {
                Step dependentRollbackStep = rollbackStepMap.get(dependentId);
                if (dependentRollbackStep == null) {
                    continue;
                }
                rollbackStepGroupMap.get(stepGroupKey).add(dependentRollbackStep.stepId);
            }
        }
        // If we have dependencies, then set the waitFor to point to our group.
        if (false == rollbackStepGroupMap.get(stepGroupKey).isEmpty()) {
            rollbackStep.waitFor = stepGroupKey;
        }
    }
    // Print what is being added.
    for (Step step : rollbackStepMap.values()) {
        _log.info(String.format("Adding rollback node %s (%s) waitFor: %s", step.stepId, step.description, step.waitFor));
    }
    for (String key : rollbackStepGroupMap.keySet()) {
        _log.info(String.format("Adding group %s members %s", key, rollbackStepGroupMap.get(key)));
    }
    // Add all the rollback Steps and new dependence Groups
    for (Step rollbackStep : rollbackStepMap.values()) {
        StepStatus status = new StepStatus();
        status.stepId = rollbackStep.stepId;
        status.state = StepState.CREATED;
        status.description = rollbackStep.description;
        rollbackStep.status = status;
        workflow.getStepMap().put(rollbackStep.stepId, rollbackStep);
        workflow.getStepStatusMap().put(rollbackStep.stepId, status);
    }
    workflow.getStepGroupMap().putAll(rollbackStepGroupMap);
    workflow.setRollbackState(true);
    workflow.setWorkflowState(WorkflowState.ROLLING_BACK);
    // Persist the workflow since we added the rollback groups
    persistWorkflow(workflow);
    logWorkflow(workflow, true);
    // Now queue all the new steps.
    for (Step step : rollbackStepMap.values()) {
        queueWorkflowStep(workflow, step);
    }
    return true;
}
Also used : Set(java.util.Set) HashSet(java.util.HashSet) HashMap(java.util.HashMap) StepStatus(com.emc.storageos.workflow.Workflow.StepStatus) Step(com.emc.storageos.workflow.Workflow.Step) List(java.util.List) ArrayList(java.util.ArrayList) URIQueryResultList(com.emc.storageos.db.client.constraint.URIQueryResultList)

Example 10 with StepStatus

use of com.emc.storageos.workflow.Workflow.StepStatus in project coprhd-controller by CoprHD.

the class WorkflowService method isBlocked.

/**
 * Determine if a workflow step is blocked. A step is blocked if it has a waitFor clause
 * pointing to a step or step group that is not in the SUCCESS state.
 * If a pre-requisite step has errored or been cancelled, a CancelledException is thrown.
 *
 * @param workflow
 *            Workflow containing the Step
 * @param step
 *            Step checked.
 * @return true if the step is blocked waiting on a pre-requiste step to complete, false if runnable now.
 * @throws CancelledException
 *             if a prerequisite step has had an error or has been cancelled
 *             or if this step (or all steps) should be cancelled because of suspend request.
 */
boolean isBlocked(Workflow workflow, Step step) throws WorkflowException, CancelledException {
    // The step cannot be blocked if waitFor is null (which means not specified)
    if (step.waitFor == null) {
        return false;
    }
    Map<String, StepStatus> statusMap = new HashMap<String, StepStatus>();
    try {
        StepStatus status = workflow.getStepStatus(step.waitFor);
        statusMap.put(step.waitFor, status);
    } catch (WorkflowException ex1) {
        try {
            statusMap = workflow.getStepGroupStatus(step.waitFor);
        } catch (WorkflowException ex2) {
            throw new WorkflowException(String.format("Workflow step %s waitFor %s invalid, must be stepId or stepGroup name", step.stepId, step.waitFor));
        }
    }
    String[] errorMessage = new String[1];
    StepState state = Workflow.getOverallState(statusMap, errorMessage);
    switch(state) {
        case SUSPENDED_NO_ERROR:
        case SUSPENDED_ERROR:
        case CANCELLED:
            throw new CancelledException();
        case ERROR:
            if ((workflow.getRollbackContOnError()) && (workflow.isRollbackState())) {
                _log.info("Allowing rollback to continue despite failure in previous rollback step.");
                return false;
            }
            throw new CancelledException();
        case SUCCESS:
            return false;
        case CREATED:
        case BLOCKED:
        case QUEUED:
        case EXECUTING:
        default:
            return true;
    }
}
Also used : StepState(com.emc.storageos.workflow.Workflow.StepState) HashMap(java.util.HashMap) StepStatus(com.emc.storageos.workflow.Workflow.StepStatus)

Aggregations

StepStatus (com.emc.storageos.workflow.Workflow.StepStatus)11 DatabaseException (com.emc.storageos.db.exceptions.DatabaseException)5 DeviceControllerException (com.emc.storageos.exceptions.DeviceControllerException)4 LockRetryException (com.emc.storageos.locking.LockRetryException)4 InternalException (com.emc.storageos.svcs.errorhandling.resources.InternalException)4 ControllerException (com.emc.storageos.volumecontroller.ControllerException)4 Step (com.emc.storageos.workflow.Workflow.Step)4 ArrayList (java.util.ArrayList)3 HashMap (java.util.HashMap)3 Task (com.emc.storageos.db.client.model.Task)2 URI (java.net.URI)2 HashSet (java.util.HashSet)2 URIQueryResultList (com.emc.storageos.db.client.constraint.URIQueryResultList)1 DataObject (com.emc.storageos.db.client.model.DataObject)1 ServiceCoded (com.emc.storageos.svcs.errorhandling.model.ServiceCoded)1 ServiceError (com.emc.storageos.svcs.errorhandling.model.ServiceError)1 StepState (com.emc.storageos.workflow.Workflow.StepState)1 Date (java.util.Date)1 List (java.util.List)1 Map (java.util.Map)1