Exemplo n.º 1
0
def prepare_tasks(tasks, context, workbook):
    results = []

    for task in tasks:
        # TODO(rakhmerov): Inbound context should be a merge of
        # outbound contexts of task dependencies, if any.
        action_params = evaluate_task_parameters(task, context)

        db_api.task_update(task['id'],
                           {'state': states.RUNNING,
                            'in_context': context,
                            'parameters': action_params})

        # Get action name. Unwrap ad-hoc and reevaluate params if
        # necessary.
        action_name = wb_task.TaskSpec(task['task_spec'])\
            .get_full_action_name()

        openstack_ctx = context.get('openstack')

        if not a_f.get_action_class(action_name):
            # If action is not found in registered actions try to find
            # ad-hoc action definition.
            if openstack_ctx is not None:
                action_params.update({'openstack': openstack_ctx})

            action = a_f.resolve_adhoc_action_name(workbook, action_name)

            if not action:
                msg = 'Unknown action [workbook=%s, action=%s]' % \
                      (workbook, action_name)
                raise exc.ActionException(msg)

            action_params = a_f.convert_adhoc_action_params(workbook,
                                                            action_name,
                                                            action_params)
            action_name = action

        if _has_action_context_param(a_f.get_action_class(action_name)):
            action_params[_ACTION_CTX_PARAM] = \
                _get_action_context(task, openstack_ctx)

        results.append((task['id'], action_name, action_params))

    return results
Exemplo n.º 2
0
    def handle_task(self, cntx, task_id, action_name, params={}):
        """Handle the execution of the workbook task.

        :param task_id: task identifier
        :type task_id: str
        :param action_name: a name of the action to run
        :type action_name: str
        :param params: a dict of action parameters
        """

        action_cls = a_f.get_action_class(action_name)

        # TODO(dzimine): on failure, convey failure details back
        try:
            action = action_cls(**params)
        except Exception as e:
            raise exc.ActionException("Failed to create action"
                                      "[action_name=%s, params=%s]: %s" %
                                      (action_name, params, e))

        if action.is_sync():
            try:
                state, result = states.SUCCESS, action.run()
            except exc.ActionException as ex:
                self._log_action_exception("Action failed", task_id,
                                           action_name, params, ex)
                state, result = states.ERROR, None

            self.engine.convey_task_result(task_id, state, result)
        else:
            try:
                action.run()
            except exc.ActionException as ex:
                self._log_action_exception("Action failed", task_id,
                                           action_name, params, ex)
                self.engine.convey_task_result(task_id, states.ERROR, None)
Exemplo n.º 3
0
    def convey_task_result(self, cntx, **kwargs):
        """Conveys task result to Mistral Engine.

        This method should be used by clients of Mistral Engine to update
        state of a task once task action has been performed. One of the
        clients of this method is Mistral REST API server that receives
        task result from the outside action handlers.

        Note: calling this method serves an event notifying Mistral that
        it possibly needs to move the workflow on, i.e. run other workflow
        tasks for which all dependencies are satisfied.

        :param cntx: a request context dict
        :type cntx: dict
        :param kwargs: a dict of method arguments
        :type kwargs: dict
        :return: Task.
        """
        task_id = kwargs.get('task_id')
        state = kwargs.get('state')
        result = kwargs.get('result')

        db_api.start_tx()

        try:
            # TODO(rakhmerov): validate state transition
            task = db_api.task_get(task_id)
            workbook = self._get_workbook(task['workbook_name'])

            wf_trace_msg = "Task '%s' [%s -> %s" % \
                           (task['name'], task['state'], state)

            wf_trace_msg += ']' if state == states.ERROR \
                else ", result = %s]" % result
            WORKFLOW_TRACE.info(wf_trace_msg)

            action_name = wb_task.TaskSpec(task['task_spec'])\
                .get_full_action_name()

            if not a_f.get_action_class(action_name):
                action = a_f.resolve_adhoc_action_name(workbook, action_name)

                if not action:
                    msg = 'Unknown action [workbook=%s, action=%s]' % \
                          (workbook, action_name)
                    raise exc.ActionException(msg)

                result = a_f.convert_adhoc_action_result(workbook,
                                                         action_name,
                                                         result)

            task_output = data_flow.get_task_output(task, result)

            # Update task state.
            task, context = self._update_task(workbook, task, state,
                                              task_output)

            execution = db_api.execution_get(task['execution_id'])

            self._create_next_tasks(task, workbook)

            # Determine what tasks need to be started.
            tasks = db_api.tasks_get(execution_id=task['execution_id'])

            new_exec_state = self._determine_execution_state(execution, tasks)

            if execution['state'] != new_exec_state:
                wf_trace_msg = \
                    "Execution '%s' [%s -> %s]" % \
                    (execution['id'], execution['state'], new_exec_state)
                WORKFLOW_TRACE.info(wf_trace_msg)

                execution = db_api.execution_update(execution['id'], {
                    "state": new_exec_state
                })

                LOG.info("Changed execution state: %s" % execution)

            # Create a list of tasks that can be executed immediately (have
            # their requirements satisfied) along with the list of tasks that
            # require some delay before they'll be executed.
            tasks_to_start, delayed_tasks = workflow.find_resolved_tasks(tasks)

            # Populate context with special variables such as `openstack` and
            # `__execution`.
            self._add_variables_to_data_flow_context(context, execution)

            # Update task with new context and params.
            executables = data_flow.prepare_tasks(tasks_to_start,
                                                  context,
                                                  workbook)

            db_api.commit_tx()
        except Exception as e:
            msg = "Failed to create necessary DB objects: %s" % e
            LOG.exception(msg)
            raise exc.EngineException(msg)
        finally:
            db_api.end_tx()

        if states.is_stopped_or_finished(execution['state']):
            return task

        for task in delayed_tasks:
            self._schedule_run(workbook, task, context)

        for task_id, action_name, action_params in executables:
            self._run_task(task_id, action_name, action_params)

        return task
Exemplo n.º 4
0
 def test_get_action_class(self):
     self.assertEqual(std.EchoAction, a_f.get_action_class("std.echo"))
     self.assertEqual(std.HTTPAction, a_f.get_action_class("std.http"))
     self.assertEqual(std.SendEmailAction,
                      a_f.get_action_class("std.email"))
Exemplo n.º 5
0
 def test_get_action_class_failure(self):
     self.assertEqual(std.EchoAction, a_f.get_action_class("echo"))
Exemplo n.º 6
0
 def test_get_action_class(self):
     self.assertEqual(std.EchoAction, a_f.get_action_class("std.echo"))
     self.assertEqual(std.HTTPAction, a_f.get_action_class("std.http"))
     self.assertEqual(std.SendEmailAction,
                      a_f.get_action_class("std.email"))