Example #1
0
    def _handle_workflow_return_value(self, wf_ex_db):
        if wf_ex_db.status in wf_statuses.COMPLETED_STATUSES:
            status = wf_ex_db.status
            result = {'output': wf_ex_db.output or None}

            if wf_ex_db.status in wf_statuses.ABENDED_STATUSES:
                result['errors'] = wf_ex_db.errors

            for wf_ex_error in wf_ex_db.errors:
                msg = 'Workflow execution completed with errors.'
                wf_svc.update_progress(wf_ex_db,
                                       '%s %s' % (msg, str(wf_ex_error)),
                                       log=False)
                LOG.error('[%s] %s',
                          str(self.execution.id),
                          msg,
                          extra=wf_ex_error)

            return (status, result, self.context)

        # Set return values.
        status = ac_const.LIVEACTION_STATUS_RUNNING
        partial_results = {}
        ctx = self._construct_context(wf_ex_db)

        return (status, partial_results, ctx)
Example #2
0
    def handle_action_execution(self, ac_ex_db):
        # Exit if action execution is not executed under an orquesta workflow.
        if not wf_svc.is_action_execution_under_workflow_context(ac_ex_db):
            return

        # Get related record identifiers.
        wf_ex_id = ac_ex_db.context["orquesta"]["workflow_execution_id"]
        task_ex_id = ac_ex_db.context["orquesta"]["task_execution_id"]

        # Get execution records for logging purposes.
        wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_id)
        task_ex_db = wf_db_access.TaskExecution.get_by_id(task_ex_id)

        msg = 'Action execution "%s" for task "%s" is updated and in "%s" state.' % (
            str(ac_ex_db.id),
            task_ex_db.task_id,
            ac_ex_db.status,
        )
        wf_svc.update_progress(wf_ex_db, msg)

        # Skip if task execution is already in completed state.
        if task_ex_db.status in statuses.COMPLETED_STATUSES:
            msg = (
                'Action execution "%s" for task "%s", route "%s", is not processed '
                'because task execution "%s" is already in completed state "%s".'
                % (
                    str(ac_ex_db.id),
                    task_ex_db.task_id,
                    str(task_ex_db.task_route),
                    str(task_ex_db.id),
                    task_ex_db.status,
                )
            )
            wf_svc.update_progress(wf_ex_db, msg)
            return

        # Process pending request on the action execution.
        if ac_ex_db.status == ac_const.LIVEACTION_STATUS_PENDING:
            wf_svc.handle_action_execution_pending(ac_ex_db)
            return

        # Process pause request on the action execution.
        if ac_ex_db.status == ac_const.LIVEACTION_STATUS_PAUSED:
            wf_svc.handle_action_execution_pause(ac_ex_db)
            return

        # Exit if action execution has not completed yet.
        if ac_ex_db.status not in ac_const.LIVEACTION_COMPLETED_STATES:
            return

        # Apply post run policies.
        lv_ac_db = lv_db_access.LiveAction.get_by_id(ac_ex_db.liveaction["id"])
        pc_svc.apply_post_run_policies(lv_ac_db)

        # Process completion of the action execution.
        wf_svc.handle_action_execution_completion(ac_ex_db)
Example #3
0
    def cancel(self):
        result = None
        wf_ex_db = None

        # Try to cancel the target workflow execution.
        try:
            wf_ex_db = wf_svc.request_cancellation(self.execution)
        # If workflow execution is not found because the action execution is cancelled
        # before the workflow execution is created or if the workflow execution is
        # already completed, then ignore the exception and proceed with cancellation.
        except (
                wf_svc_exc.WorkflowExecutionNotFoundException,
                wf_svc_exc.WorkflowExecutionIsCompletedException,
        ):
            pass
        # If there is an unknown exception, then log the error. Continue with the
        # cancelation sequence below to cancel children and determine final status.
        # If we rethrow the exception here, the workflow will be stuck in a canceling
        # state with no options for user to clean up. It is safer to continue with
        # the cancel then to revert back to some other statuses because the workflow
        # execution will be in an unknown state.
        except Exception:
            _, ex, tb = sys.exc_info()
            msg = "Error encountered when canceling workflow execution."
            LOG.exception("[%s] %s", str(self.execution.id), msg)
            msg = "Error encountered when canceling workflow execution. %s"
            wf_svc.update_progress(wf_ex_db, msg % str(ex), log=False)
            result = {
                "error": msg % str(ex),
                "traceback": "".join(traceback.format_tb(tb, 20)),
            }

        # Request cancellation of tasks that are workflows and still running.
        for child_ex_id in self.execution.children:
            child_ex = ex_db_access.ActionExecution.get(id=child_ex_id)
            if self.task_cancelable(child_ex):
                ac_svc.request_cancellation(
                    lv_db_access.LiveAction.get(id=child_ex.liveaction["id"]),
                    self.context.get("user", None),
                )

        status = (ac_const.LIVEACTION_STATUS_CANCELING
                  if ac_svc.is_children_active(self.liveaction.id) else
                  ac_const.LIVEACTION_STATUS_CANCELED)

        return (
            status,
            result if result else self.liveaction.result,
            self.liveaction.context,
        )
Example #4
0
    def fail_workflow_execution(self, message, exception):
        # Prepare attributes based on message type.
        if isinstance(message, wf_db_models.WorkflowExecutionDB):
            msg_type = 'workflow'
            wf_ex_db = message
            wf_ex_id = str(wf_ex_db.id)
            task = None
        else:
            msg_type = 'task'
            ac_ex_db = message
            wf_ex_id = ac_ex_db.context['orquesta']['workflow_execution_id']
            task_ex_id = ac_ex_db.context['orquesta']['task_execution_id']
            wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_id)
            task_ex_db = wf_db_access.TaskExecution.get_by_id(task_ex_id)
            task = {'id': task_ex_db.task_id, 'route': task_ex_db.task_route}

        # Log the error.
        msg = 'Unknown error while processing %s execution. %s: %s'
        wf_svc.update_progress(
            wf_ex_db,
            msg % (msg_type, exception.__class__.__name__, str(exception)),
            severity='error')

        # Fail the task execution so it's marked correctly in the
        # conductor state to allow for task rerun if needed.
        if isinstance(message, ex_db_models.ActionExecutionDB):
            msg = 'Unknown error while processing %s execution. Failing task execution "%s".'
            wf_svc.update_progress(wf_ex_db,
                                   msg % (msg_type, task_ex_id),
                                   severity='error')
            wf_svc.update_task_execution(task_ex_id,
                                         ac_const.LIVEACTION_STATUS_FAILED)
            wf_svc.update_task_state(task_ex_id,
                                     ac_const.LIVEACTION_STATUS_FAILED)

        # Fail the workflow execution.
        msg = 'Unknown error while processing %s execution. Failing workflow execution "%s".'
        wf_svc.update_progress(wf_ex_db,
                               msg % (msg_type, wf_ex_id),
                               severity='error')
        wf_svc.fail_workflow_execution(wf_ex_id, exception, task=task)
Example #5
0
 def handle_workflow_execution(self, wf_ex_db):
     # Request the next set of tasks to execute.
     wf_svc.update_progress(wf_ex_db,
                            'Processing request for workflow execution.')
     wf_svc.request_next_tasks(wf_ex_db)