Exemplo n.º 1
0
def get_controller(wf_ex, wf_spec=None):
    """Gets a workflow controller instance by given workflow execution object.

    :param wf_ex: Workflow execution object.
    :param wf_spec: Workflow specification object. If passed, the method works
        faster.
    :returns: Workflow controller class.
    """

    if not wf_spec:
        wf_spec = spec_parser.get_workflow_spec_by_execution_id(wf_ex.id)

    wf_type = wf_spec.get_type()

    ctrl_cls = None

    for cls in u.iter_subclasses(WorkflowController):
        if cls.__workflow_type__ == wf_type:
            ctrl_cls = cls
            break

    if not ctrl_cls:
        raise exc.MistralError(
            'Failed to find a workflow controller [type=%s]' % wf_type)

    return ctrl_cls(wf_ex, wf_spec)
Exemplo n.º 2
0
def _build_task_from_command(cmd):
    if isinstance(cmd, wf_cmds.RunExistingTask):
        task = _create_task(cmd.wf_ex,
                            cmd.wf_spec,
                            spec_parser.get_task_spec(cmd.task_ex.spec),
                            cmd.ctx,
                            task_ex=cmd.task_ex,
                            unique_key=cmd.task_ex.unique_key,
                            waiting=cmd.task_ex.state == states.WAITING,
                            triggered_by=cmd.triggered_by)

        if cmd.reset:
            task.reset()

        return task

    if isinstance(cmd, wf_cmds.RunTask):
        task = _create_task(cmd.wf_ex,
                            cmd.wf_spec,
                            cmd.task_spec,
                            cmd.ctx,
                            unique_key=cmd.unique_key,
                            waiting=cmd.is_waiting(),
                            triggered_by=cmd.triggered_by)

        return task

    raise exc.MistralError('Unsupported workflow command: %s' % cmd)
Exemplo n.º 3
0
    def _run_existing(self):
        if self.waiting:
            return

        # Explicitly change task state to RUNNING.
        # Throw exception if the existing task already succeeded.
        if self.task_ex.state == states.SUCCESS:
            raise exc.MistralError(
                'Rerunning succeeded tasks is not supported.')

        # Record the current task state.
        old_task_state = self.task_ex.state

        self.set_state(states.RUNNING, None, processed=False)

        # Publish event.
        self.notify(old_task_state, self.task_ex.state)

        if self.rerun:
            self.save_started_time()
            self.save_finished_time(value=None)
            self._before_task_start()

            # Policies could possibly change task state.
            if self.task_ex.state != states.RUNNING:
                return

        self._update_inbound_context()
        self._update_triggered_by()
        self._reset_actions()
        self._schedule_actions()
Exemplo n.º 4
0
    def __init__(self):
        config_file = CONF.event_engine.event_definitions_cfg_file
        definition_cfg = []

        if os.path.exists(config_file):
            with open(config_file) as cf:
                config = cf.read()

            try:
                definition_cfg = safe_yaml.load(config)
            except safe_yaml.YAMLError as err:
                if hasattr(err, 'problem_mark'):
                    mark = err.problem_mark
                    errmsg = (
                        "Invalid YAML syntax in Definitions file "
                        "%(file)s at line: %(line)s, column: %(column)s." %
                        dict(file=config_file,
                             line=mark.line + 1,
                             column=mark.column + 1))
                else:
                    errmsg = ("YAML error reading Definitions file %s" %
                              CONF.event_engine.event_definitions_cfg_file)

                LOG.error(errmsg)

                raise exceptions.MistralError(
                    'Invalid event definition configuration file. %s' %
                    config_file)

        self.definitions = [
            EventDefinition(event_def)
            for event_def in reversed(definition_cfg)
        ]
Exemplo n.º 5
0
    def _run_existing(self):
        if self.waiting:
            return

        # Explicitly change task state to RUNNING.
        # Throw exception if the existing task already succeeded.
        if self.task_ex.state == states.SUCCESS:
            raise exc.MistralError(
                'Rerunning succeeded tasks is not supported.'
            )

        self.set_state(states.RUNNING, None, processed=False)

        # Get the manual input data when action is rerun, otherwise
        # the manual output data when action is used for pass.
        self._task_action = getattr(self.task_ex, "_manual_action", None)
        self._task_input = getattr(self.task_ex, "_manual_input", None)
        self._task_output = getattr(self.task_ex, "_manual_output", None)

        # Add Kafka log trace
        if self._task_action:
            etype = kfk_etypes.TASK_REDO
            if self._task_action == 'pass':
                etype = kfk_etypes.TASK_PASS
            kfk_trace.log(etype, None, states.RUNNING,
                        self.wf_ex.workflow_id, self.wf_ex.id,
                        self.task_ex.id, self.task_ex.name,
                        self._task_input, self._task_output, self.triggered_by)

        self._update_inbound_context()
        self._update_triggered_by()
        self._reset_actions()
        self._schedule_actions()
Exemplo n.º 6
0
def dispatch_workflow_commands(wf_ex, wf_cmds):
    # TODO(rakhmerov): I don't like these imports but otherwise we have
    # import cycles.
    from mistral.engine import task_handler
    from mistral.engine import workflow_handler as wf_handler

    if not wf_cmds:
        return

    for cmd in wf_cmds:
        if isinstance(cmd, (commands.RunTask, commands.RunExistingTask)):
            task_handler.run_task(cmd)
        elif isinstance(cmd, commands.SetWorkflowState):
            # TODO(rakhmerov): Make just a single call to workflow_handler
            if states.is_completed(cmd.new_state):
                wf_handler.stop_workflow(cmd.wf_ex, cmd.new_state, cmd.msg)
            else:
                wf_handler.set_workflow_state(wf_ex, cmd.new_state, cmd.msg)
        elif isinstance(cmd, commands.Noop):
            # Do nothing.
            pass
        else:
            raise exc.MistralError('Unsupported workflow command: %s' % cmd)

        if wf_ex.state != states.RUNNING:
            break
Exemplo n.º 7
0
def set_workflow_state(wf_ex, state, msg=None):
    if states.is_completed(state):
        stop_workflow(wf_ex, state, msg)
    elif states.is_paused(state):
        pause_workflow(wf_ex, msg)
    else:
        raise exc.MistralError('Invalid workflow state [wf_ex=%s, state=%s]' %
                               (wf_ex, state))
Exemplo n.º 8
0
def set_workflow_state(wf_ex, state, msg=None):
    if states.is_completed(state):
        stop_workflow(wf_ex, state, msg)
    elif states.is_paused(state):
        pause_workflow(wf_ex, msg)
    else:
        raise exc.MistralError(
            'Invalid workflow execution state [wf_ex_id=%s, wf_name=%s, '
            'state=%s]' % (wf_ex.id, wf_ex.name, state))
Exemplo n.º 9
0
    def _run_existing(self):
        if self.waiting:
            return

        # Explicitly change task state to RUNNING.
        # Throw exception if the existing task already succeeded.
        if self.task_ex.state == states.SUCCESS:
            raise exc.MistralError(
                'Rerunning succeeded tasks is not supported.')

        self.set_state(states.RUNNING, None, processed=False)

        self._update_inbound_context()
        self._reset_actions()
        self._schedule_actions()
Exemplo n.º 10
0
    def test_resume_fails(self):
        # Start and pause workflow.
        wb_service.create_workbook_v2(WORKBOOK_DIFFERENT_TASK_STATES)

        wf_ex = self.engine.start_workflow('wb.wf1', {})

        self.await_workflow_paused(wf_ex.id)

        wf_ex = db_api.get_workflow_execution(wf_ex.id)

        self.assertEqual(states.PAUSED, wf_ex.state)

        # Simulate failure and check if it is handled.
        err = exc.MistralError('foo')

        with mock.patch.object(db_api, 'acquire_lock', side_effect=err):

            self.assertRaises(exc.MistralError, self.engine.resume_workflow,
                              wf_ex.id)
Exemplo n.º 11
0
def _build_task_from_command(cmd):
    if isinstance(cmd, wf_cmds.RunExistingTask):
        task = _create_task(cmd.wf_ex,
                            spec_parser.get_task_spec(cmd.task_ex.spec),
                            cmd.ctx, cmd.task_ex)

        if cmd.reset:
            task.reset()

        return task

    if isinstance(cmd, wf_cmds.RunTask):
        task = _create_task(cmd.wf_ex, cmd.task_spec, cmd.ctx)

        if cmd.is_waiting():
            task.defer()

        return task

    raise exc.MistralError('Unsupported workflow command: %s' % cmd)
Exemplo n.º 12
0
def _process_commands(wf_ex, cmds):
    if not cmds:
        return

    from mistral.engine import task_handler
    from mistral.engine import workflow_handler as wf_handler

    for cmd in _rearrange_commands(cmds):
        if states.is_completed(wf_ex.state):
            break

        if wf_ex.state == states.PAUSED:
            # Save all commands after 'pause' to the backlog so that
            # they can be processed after the workflow is resumed.
            _save_command_to_backlog(wf_ex, cmd)

            continue

        if isinstance(cmd, (commands.RunTask, commands.RunExistingTask)):
            task_handler.run_task(cmd)
        elif isinstance(cmd, commands.SetWorkflowState):
            wf_handler.set_workflow_state(wf_ex, cmd.new_state, cmd.msg)
        else:
            raise exc.MistralError('Unsupported workflow command: %s' % cmd)
Exemplo n.º 13
0
 def _raise_immutable_error():
     raise exc.MistralError('Context view is immutable.')
Exemplo n.º 14
0
 def call(self, fn, *args, **kwargs):
     try:
         return super(MistralRetrying, self).call(fn, *args, **kwargs)
     except tenacity.RetryError:
         raise exc.MistralError("The service is temporarily unavailable")
Exemplo n.º 15
0
def _validate_config():
    if not CONF.yaql.convert_output_data and CONF.yaql.convert_input_data:
        raise exc.MistralError(
            "The config property 'yaql.convert_output_data' is set to False "
            "so 'yaql.convert_input_data' must also be set to False.")