コード例 #1
0
ファイル: test_run_action.py プロジェクト: rocky11030/mistral
    def test_run_action_async(self):
        action_ex = self.engine.start_action('std.async_noop', {})

        is_action_ex_running = (lambda: db_api.get_action_execution(
            action_ex.id).state == states.RUNNING)

        self._await(is_action_ex_running)

        action_ex = db_api.get_action_execution(action_ex.id)

        self.assertEqual(states.RUNNING, action_ex.state)
コード例 #2
0
ファイル: test_run_action.py プロジェクト: rocky11030/mistral
    def test_run_action_async_invoke_failure(self):
        action_ex = self.engine.start_action('std.async_noop', {})

        is_action_ex_error = (lambda: db_api.get_action_execution(action_ex.id)
                              .state == states.ERROR)

        self._await(is_action_ex_error)

        action_ex = db_api.get_action_execution(action_ex.id)

        self.assertEqual(states.ERROR, action_ex.state)
        self.assertIn('Invoke failed.', action_ex.output.get('result', ''))
コード例 #3
0
    def on_action_complete(self, action_ex_id, result):
        wf_ex_id = None

        try:
            with db_api.transaction():
                action_ex = db_api.get_action_execution(action_ex_id)

                # In case of single action execution there is no
                # assigned task execution.
                if not action_ex.task_execution:
                    return action_handler.store_action_result(
                        action_ex, result).get_clone()

                wf_ex_id = action_ex.task_execution.workflow_execution_id
                wf_ex = wf_handler.lock_workflow_execution(wf_ex_id)

                task_ex = task_handler.on_action_complete(action_ex, result)

                # If workflow is on pause or completed then there's no
                # need to continue workflow.
                if states.is_paused_or_completed(wf_ex.state):
                    return action_ex.get_clone()

            prev_task_state = task_ex.state

            # Separate the task transition in a separate transaction. The task
            # has already completed for better or worst. The task state should
            # not be affected by errors during transition on conditions such as
            # on-success and on-error.
            with db_api.transaction():
                wf_ex = wf_handler.lock_workflow_execution(wf_ex_id)
                action_ex = db_api.get_action_execution(action_ex_id)
                task_ex = action_ex.task_execution

                self._on_task_state_change(task_ex,
                                           wf_ex,
                                           task_state=prev_task_state)

                return action_ex.get_clone()
        except Exception as e:
            # TODO(dzimine): try to find out which command caused failure.
            # TODO(rakhmerov): Need to refactor logging in a more elegant way.
            LOG.error(
                "Failed to handle action execution result [id=%s]: %s\n%s",
                action_ex_id, e, traceback.format_exc())

            # If an exception was thrown after we got the wf_ex_id
            if wf_ex_id:
                self._fail_workflow(wf_ex_id, e)

            raise e
コード例 #4
0
ファイル: test_run_action.py プロジェクト: rocky11030/mistral
    def test_run_action_save_result(self):
        # Start action.
        action_ex = self.engine.start_action('std.echo', {'output': 'Hello!'},
                                             save_result=True)

        is_action_ex_success = (lambda: db_api.get_action_execution(
            action_ex.id).state == states.SUCCESS)

        self._await(is_action_ex_success)

        action_ex = db_api.get_action_execution(action_ex.id)

        self.assertEqual(states.SUCCESS, action_ex.state)
        self.assertEqual({'result': 'Hello!'}, action_ex.output)
コード例 #5
0
    def delete(self, id):
        """Delete the specified action_execution.

        :param id: UUID of action execution to delete
        """
        acl.enforce('action_executions:delete', context.ctx())

        LOG.debug("Delete action_execution [id=%s]", id)

        if not cfg.CONF.api.allow_action_execution_deletion:
            raise exc.NotAllowedException("Action execution deletion is not "
                                          "allowed.")

        with db_api.transaction():
            action_ex = db_api.get_action_execution(id)

            if action_ex.task_execution_id:
                raise exc.NotAllowedException(
                    "Only ad-hoc action execution can be deleted.")

            if not states.is_completed(action_ex.state):
                raise exc.NotAllowedException(
                    "Only completed action execution can be deleted.")

            return db_api.delete_action_execution(id)
コード例 #6
0
    def _fail_workflow(wf_ex_id, err, action_ex_id=None):
        """Private helper to fail workflow on exceptions."""
        err_msg = str(err)

        with db_api.transaction():
            wf_ex = db_api.load_workflow_execution(wf_ex_id)

            if wf_ex is None:
                LOG.error(
                    "Cant fail workflow execution with id='%s': not found.",
                    wf_ex_id)
                return

            wf_handler.set_execution_state(wf_ex, states.ERROR, err_msg)

            if action_ex_id:
                # Note(dzimine): Don't call self.engine_client:
                # 1) to avoid computing and triggering next tasks
                # 2) to avoid a loop in case of error in transport
                action_ex = db_api.get_action_execution(action_ex_id)

                task_handler.on_action_complete(action_ex,
                                                wf_utils.Result(error=err_msg))

            return wf_ex
コード例 #7
0
    def test_report_running_actions(self):
        wf_input = {'param1': 'Hey', 'param2': 'Hi'}

        # Start workflow.
        wf_ex = self.engine.start_workflow('wb.wf',
                                           '',
                                           wf_input=wf_input,
                                           description='my execution',
                                           task_name='task2')

        with db_api.transaction():
            wf_ex = db_api.get_workflow_execution(wf_ex.id)

            task_execs = wf_ex.task_executions

        self.assertEqual(1, len(task_execs))

        task_ex = task_execs[0]

        action_execs = db_api.get_action_executions(
            task_execution_id=task_ex.id)

        task_action_ex = action_execs[0]

        self.engine.report_running_actions([])
        self.engine.report_running_actions([None, None])
        self.engine.report_running_actions([None, task_action_ex.id])

        task_action_ex = db_api.get_action_execution(task_action_ex.id)

        self.assertIsNotNone(task_action_ex.last_heartbeat)
コード例 #8
0
ファイル: task_handler.py プロジェクト: saadkhan44/mistral
def _scheduled_on_action_update(action_ex_id, wf_action):
    with db_api.transaction():
        if wf_action:
            action_ex = db_api.get_workflow_execution(action_ex_id)
        else:
            action_ex = db_api.get_action_execution(action_ex_id)

        _on_action_update(action_ex)
コード例 #9
0
    def test_run_action_async(self):
        action_ex = self.engine.start_action('std.async_noop', {})

        self.await_action_state(action_ex.id, states.RUNNING)

        action_ex = db_api.get_action_execution(action_ex.id)

        self.assertEqual(states.RUNNING, action_ex.state)
コード例 #10
0
    def test_run_action_async_invoke_with_error(self):
        action_ex = self.engine.start_action('std.async_noop', {})

        self.await_action_error(action_ex.id)

        action_ex = db_api.get_action_execution(action_ex.id)

        self.assertEqual(states.ERROR, action_ex.state)
        self.assertIn('Invoke erred.', action_ex.output.get('result', ''))
コード例 #11
0
ファイル: action_handler.py プロジェクト: kantorv/mistral
def run_existing_action(action_ex_id, target):
    action_ex = db_api.get_action_execution(action_ex_id)
    action_def = db_api.get_action_definition(action_ex.name)

    return run_action(
        action_def,
        action_ex.input,
        action_ex_id,
        target
    )
コード例 #12
0
def _run_existing_action(action_ex_id, target):
    action_ex = db_api.get_action_execution(action_ex_id)
    action_def = db_api.get_action_definition(action_ex.name)

    result = rpc.get_executor_client().run_action(action_ex_id,
                                                  action_def.action_class,
                                                  action_def.attributes or {},
                                                  action_ex.input, target)

    return _get_action_output(result) if result else None
コード例 #13
0
    def on_action_complete(self, action_ex_id, result, wf_action=False):
        with db_api.transaction():
            if wf_action:
                action_ex = db_api.get_workflow_execution(action_ex_id)
            else:
                action_ex = db_api.get_action_execution(action_ex_id)

            action_handler.on_action_complete(action_ex, result)

            return action_ex.get_clone()
コード例 #14
0
    def on_action_update(self, action_ex_id, state, wf_action=False,
                         async_=False):
        with db_api.transaction():
            if wf_action:
                action_ex = db_api.get_workflow_execution(action_ex_id)
            else:
                action_ex = db_api.get_action_execution(action_ex_id)

            action_handler.on_action_update(action_ex, state)

            return action_ex.get_clone()
コード例 #15
0
    def test_run_action_save_result_and_run_sync(self):
        # Start action.
        action_ex = self.engine.start_action('std.echo', {'output': 'Hello!'},
                                             save_result=True,
                                             run_sync=True)

        self.assertEqual('Hello!', action_ex.output['result'])
        self.assertEqual(states.SUCCESS, action_ex.state)

        db_action_ex = db_api.get_action_execution(action_ex.id)
        self.assertEqual(states.SUCCESS, db_action_ex.state)
        self.assertEqual({'result': 'Hello!'}, db_action_ex.output)
コード例 #16
0
    def test_run_action_save_result(self):
        # Start action.
        action_ex = self.engine.start_action('std.echo', {'output': 'Hello!'},
                                             save_result=True)

        self.await_action_success(action_ex.id)

        with db_api.transaction():
            action_ex = db_api.get_action_execution(action_ex.id)

            self.assertEqual(states.SUCCESS, action_ex.state)
            self.assertEqual({'result': 'Hello!'}, action_ex.output)
コード例 #17
0
ファイル: default_engine.py プロジェクト: xavierhardy/mistral
    def on_action_complete(self, action_ex_id, result):
        with db_api.transaction():
            action_ex = db_api.get_action_execution(action_ex_id)

            task_ex = action_ex.task_execution

            if task_ex:
                wf_handler.lock_workflow_execution(
                    task_ex.workflow_execution_id)

            action_handler.on_action_complete(action_ex, result)

            return action_ex.get_clone()
コード例 #18
0
ファイル: actions.py プロジェクト: anilyadav/mistral
def _run_existing_action(action_ex_id, target):
    action_ex = db_api.get_action_execution(action_ex_id)
    action_def = db_api.get_action_definition(action_ex.name)

    result = rpc.get_executor_client().run_action(
        action_ex_id,
        action_def.action_class,
        action_def.attributes or {},
        action_ex.input,
        target,
        safe_rerun=action_ex.runtime_context.get('safe_rerun', False))

    return _get_action_output(result) if result else None
コード例 #19
0
    def on_action_complete(self, action_ex_id, result, wf_action=False,
                           async_=False):
        with db_api.transaction():
            if wf_action:
                action_ex = db_api.get_workflow_execution(action_ex_id)

                # If result is None it means that it's a normal subworkflow
                # output and we just need to fetch it from the model.
                # This is just an optimization to not send data over RPC
                if result is None:
                    result = ml_actions.Result(data=action_ex.output)
            else:
                action_ex = db_api.get_action_execution(action_ex_id)

            action_handler.on_action_complete(action_ex, result)

            return action_ex.get_clone()
コード例 #20
0
    def on_action_complete(self, action_ex_id, result):
        wf_ex_id = None

        try:
            with db_api.transaction():
                action_ex = db_api.get_action_execution(action_ex_id)

                # In case of single action execution there is no
                # assigned task execution.
                if not action_ex.task_execution:
                    return action_handler.store_action_result(
                        action_ex,
                        result
                    ).get_clone()

                wf_ex_id = action_ex.task_execution.workflow_execution_id
                wf_ex = wf_handler.lock_workflow_execution(wf_ex_id)

                wf_spec = spec_parser.get_workflow_spec(wf_ex.spec)

                task_ex = task_handler.on_action_complete(
                    action_ex,
                    wf_spec,
                    result
                )

                # If workflow is on pause or completed then there's no
                # need to continue workflow.
                if states.is_paused_or_completed(wf_ex.state):
                    return action_ex.get_clone()

                self._on_task_state_change(task_ex, wf_ex, wf_spec)

                return action_ex.get_clone()
        except Exception as e:
            # TODO(rakhmerov): Need to refactor logging in a more elegant way.
            LOG.error(
                'Failed to handle action execution result [id=%s]: %s\n%s',
                action_ex_id, e, traceback.format_exc()
            )

            # If an exception was thrown after we got the wf_ex_id
            if wf_ex_id:
                self._fail_workflow(wf_ex_id, e)

            raise e
コード例 #21
0
    def test_adhoc_async_action(self):
        wb_text = """---
        version: '2.0'

        name: my_wb1

        actions:
          my_action:
            input:
              - my_param

            base: std.async_noop
            output: (((<% $ %>)))

        workflows:
          my_wf:
            tasks:
              task1:
                action: my_action my_param="asdfasdf"
        """

        wb_service.create_workbook_v2(wb_text)

        wf_ex = self.engine.start_workflow('my_wb1.my_wf')

        self.await_workflow_running(wf_ex.id, timeout=4)

        with db_api.transaction(read_only=True):
            wf_ex = db_api.get_workflow_execution(wf_ex.id)
            wf_ex_id = wf_ex.id

            a_ex_id = wf_ex.task_executions[0].action_executions[0].id

        self.engine.on_action_complete(a_ex_id, ml_actions.Result(data='Hi!'))

        self.await_action_success(a_ex_id)
        self.await_workflow_success(wf_ex_id)

        with db_api.transaction(read_only=True):
            a_ex = db_api.get_action_execution(a_ex_id)

            self.assertEqual('(((Hi!)))', a_ex.output.get('result'))
コード例 #22
0
    def delete(self, id):
        """Delete the specified action_execution."""

        LOG.info("Delete action_execution [id=%s]" % id)

        if not cfg.CONF.api.allow_action_execution_deletion:
            raise exc.NotAllowedException("Action execution deletion is not "
                                          "allowed.")

        action_ex = db_api.get_action_execution(id)

        if action_ex.task_execution_id:
            raise exc.NotAllowedException("Only ad-hoc action execution can "
                                          "be deleted.")

        if not states.is_completed(action_ex.state):
            raise exc.NotAllowedException("Only completed action execution "
                                          "can be deleted.")

        return db_api.delete_action_execution(id)
コード例 #23
0
    def on_action_complete(self, action_ex_id, result):
        wf_ex_id = None

        try:
            with db_api.transaction():
                action_ex = db_api.get_action_execution(action_ex_id)

                # In case of single action execution there is no
                # assigned task execution.
                if not action_ex.task_execution:
                    return action_handler.store_action_result(
                        action_ex, result).get_clone()

                wf_ex_id = action_ex.task_execution.workflow_execution_id

                # Must be before loading the object itself (see method doc).
                self._lock_workflow_execution(wf_ex_id)

                wf_ex = action_ex.task_execution.workflow_execution

                task_ex = task_handler.on_action_complete(action_ex, result)

                # If workflow is on pause or completed then there's no
                # need to continue workflow.
                if states.is_paused_or_completed(wf_ex.state):
                    return action_ex

                self._on_task_state_change(task_ex, wf_ex, action_ex)

                return action_ex.get_clone()
        except Exception as e:
            # TODO(dzimine): try to find out which command caused failure.
            # TODO(rakhmerov): Need to refactor logging in a more elegant way.
            LOG.error(
                "Failed to handle action execution result [id=%s]: %s\n%s",
                action_ex_id, e, traceback.format_exc())
            self._fail_workflow(wf_ex_id, e)
            raise e
コード例 #24
0
    def test_run_action_with_namespace(self):
        namespace = 'test_ns'

        action_text = """---
        version: '2.0'

        concat1:
          base: std.echo
          base-input:
            output: <% $.left %><% $.right %>
          input:
            - left
            - right

        concat2:
          base: concat1
          base-input:
            left: <% $.left %><% $.center %>
            right: <% $.right %>
          input:
            - left
            - center
            - right
        """

        actions.create_actions(action_text, namespace=namespace)

        self.assertRaises(exc.InvalidActionException,
                          self.engine.start_action,
                          'concat1', {
                              'left': 'Hello, ',
                              'right': 'John Doe!'
                          },
                          save_result=True,
                          namespace='')

        action_ex = self.engine.start_action('concat1', {
            'left': 'Hello, ',
            'right': 'John Doe!'
        },
                                             save_result=True,
                                             namespace=namespace)

        self.assertEqual(namespace, action_ex.workflow_namespace)

        self.await_action_success(action_ex.id)

        with db_api.transaction():
            action_ex = db_api.get_action_execution(action_ex.id)

            self.assertEqual(states.SUCCESS, action_ex.state)
            self.assertEqual({'result': u'Hello, John Doe!'}, action_ex.output)

        action_ex = self.engine.start_action('concat2', {
            'left': 'Hello, ',
            'center': 'John',
            'right': ' Doe!'
        },
                                             save_result=True,
                                             namespace=namespace)

        self.assertEqual(namespace, action_ex.workflow_namespace)

        self.await_action_success(action_ex.id)

        with db_api.transaction():
            action_ex = db_api.get_action_execution(action_ex.id)

            self.assertEqual(states.SUCCESS, action_ex.state)
            self.assertEqual('Hello, John Doe!', action_ex.output['result'])
コード例 #25
0
    def _action_result_equals(action_ex_id, output):
        with db_api.transaction():
            a_ex = db_api.get_action_execution(action_ex_id)

            return a_ex.output == output
コード例 #26
0
ファイル: base.py プロジェクト: wookiist/mistral
 def is_action_in_state(self, ex_id, state):
     return db_api.get_action_execution(ex_id).state == state
コード例 #27
0
class DefaultEngine(base.Engine):
    @action_queue.process
    @u.log_exec(LOG)
    @profiler.trace('engine-start-workflow')
    def start_workflow(self,
                       wf_identifier,
                       wf_input,
                       description='',
                       **params):

        with db_api.transaction():
            wf_ex = wf_handler.start_workflow(wf_identifier, wf_input,
                                              description, params)

            return wf_ex.get_clone()

    @action_queue.process
    @u.log_exec(LOG)
    def start_action(self,
                     action_name,
                     action_input,
                     description=None,
                     **params):
        with db_api.transaction():
            action = action_handler.build_action_by_name(action_name)

            action.validate_input(action_input)

            sync = params.get('run_sync')
            save = params.get('save_result')
            target = params.get('target')

            is_action_sync = action.is_sync(action_input)

            if sync and not is_action_sync:
                raise exceptions.InputException(
                    "Action does not support synchronous execution.")

            if not sync and (save or not is_action_sync):
                action.schedule(action_input, target)

                return action.action_ex.get_clone()

            output = action.run(action_input, target, save=False)

            state = states.SUCCESS if output.is_success() else states.ERROR

            if not save:
                # Action execution is not created but we need to return similar
                # object to a client anyway.
                return db_models.ActionExecution(name=action_name,
                                                 description=description,
                                                 input=action_input,
                                                 output=output.to_dict(),
                                                 state=state)

            action_ex_id = u.generate_unicode_uuid()

            values = {
                'id': action_ex_id,
                'name': action_name,
                'description': description,
                'input': action_input,
                'output': output.to_dict(),
                'state': state,
            }

            return db_api.create_action_execution(values)

    @db_utils.retry_on_deadlock
    @action_queue.process
    @u.log_exec(LOG)
    @profiler.trace('engine-on-action-complete')
    def on_action_complete(self,
                           action_ex_id,
                           result,
                           wf_action=False,
                           async=False):
        with db_api.transaction():
            if wf_action:
                action_ex = db_api.get_workflow_execution(action_ex_id)
            else:
                action_ex = db_api.get_action_execution(action_ex_id)

            action_handler.on_action_complete(action_ex, result)

            return action_ex.get_clone()
コード例 #28
0
def _get_action_execution(id):
    with db_api.transaction():
        return _get_action_execution_resource(db_api.get_action_execution(id))
コード例 #29
0
def _get_action_execution(id):
    action_ex = db_api.get_action_execution(id)

    return _get_action_execution_resource(action_ex)