Esempio n. 1
0
def exec_workflow(
    steps: List[WorkflowStep], workers: WorkerFactory, rundir: str,
    result: RunResult
) -> RunResult:
    """Execute steps in a serial workflow.

    The workflow arguments are part of the execution context that is contained
    in the :class:`flowserv.controller.serial.workflow.result.RunResult`. The
    result object is used to maintain the results for executed workflow steps.

    Executes workflow steps in sequence. Terminates early if the execution
    of a workflow step returns a non-zero value. Uses the given worker
    factory to create workers for steps that are of class
    :class:`flowserv.model.workflow.step.ContainerStep`.

    Parameters
    ----------
    steps: list of flowserv.model.workflow.step.WorkflowStep
        Steps in the serial workflow that are executed in the given context.
    workers: flowserv.controller.worker.factory.WorkerFactory, default=None
        Factory for :class:`flowserv.model.workflow.step.ContainerStep` steps.
    rundir: str, default=None
        Working directory for all executed workflow steps.
    result: flowserv.controller.worker.result.RunResult
        Collector for results from executed workflow steps. Contains the context
        within which the workflow is executed.

    Returns
    -------
    flowserv.controller.worker.result.RunResult
    """
    for step in steps:
        if step.is_function_step():
            r = exec_func(step=step, context=result.context, rundir=rundir)
        else:
            worker = workers.get(step.image)
            r = worker.exec(
                step=step,
                arguments=result.context,
                rundir=rundir
            )
        result.add(r)
        # Terminate if the step execution was not successful.
        if r.returncode != 0:
            break
    return result
Esempio n. 2
0
def exec_workflow(steps: List[WorkflowStep], workers: WorkerPool,
                  volumes: VolumeManager, result: RunResult) -> RunResult:
    """Execute steps in a serial workflow.

    The workflow arguments are part of the execution context that is contained
    in the :class:`flowserv.controller.serial.workflow.result.RunResult`. The
    result object is used to maintain the results for executed workflow steps.

    Executes workflow steps in sequence. Terminates early if the execution
    of a workflow step returns a non-zero value. Uses the given worker
    factory to create workers for steps that are of class
    :class:`flowserv.model.workflow.step.ContainerStep`.

    Parameters
    ----------
    steps: list of flowserv.model.workflow.step.WorkflowStep
        Steps in the serial workflow that are executed in the given context.
    workers: flowserv.controller.worker.manager.WorkerPool, default=None
        Factory for :class:`flowserv.model.workflow.step.ContainerStep` steps.
    volumes: flowserv.volume.manager.VolumeManager
        Manager for storage volumes that are used by the different workers.
    result: flowserv.controller.serial.workflow.result.RunResult
        Collector for results from executed workflow steps. Contains the context
        within which the workflow is executed.

    Returns
    -------
    flowserv.controller.worker.result.RunResult
    """
    for step in steps:
        # Get the worker that is responsible for executing the workflow step.
        worker = workers.get(step)
        # Prepare the volume store that is associated with the worker.
        store = volumes.get(worker.volume)
        volumes.prepare(store=store, inputs=step.inputs, outputs=step.outputs)
        # Execute the workflow step and add the result to the overall workflow
        # result. Terminate if the step execution was not successful.
        r = worker.exec(step=step, context=result.context, store=store)
        result.add(r)
        if r.returncode != 0:
            break
        # Update volume manager with output files for the workflow step.
        volumes.update(store=store, files=step.outputs)
    return result
Esempio n. 3
0
def test_successful_run_result():
    """Test results of a successful workflow run."""
    r = RunResult(arguments={'a': 1})
    r.add(ExecResult(step=ContainerStep(identifier='s1', image='test1'), returncode=0, stdout=['o1']))
    r.context['a'] = 2
    r.add(ExecResult(step=ContainerStep(identifier='s2', image='test2'), returncode=0, stdout=['o2', 'o3']))
    r.context['b'] = 1
    assert r.exception is None
    assert r.returncode == 0
    r.raise_for_status()
    assert r.stdout == ['o1', 'o2', 'o3']
    assert r.stderr == []
    assert r.get('a') == 2
    assert r.get('b') == 1
    result = r.steps[0]
    assert result.step.image == 'test1'
    assert result.stdout == ['o1']
    result = r.steps[1]
    assert result.step.image == 'test2'
    assert result.stdout == ['o2', 'o3']
Esempio n. 4
0
def test_error_run_result():
    """Test results of an erroneous workflow run."""
    r = RunResult(arguments={})
    r.add(ExecResult(step=ContainerStep(identifier='s1', image='test'), returncode=0))
    assert r.exception is None
    assert r.returncode == 0
    r.add(ExecResult(step=ContainerStep(identifier='s2', image='test'), returncode=1, stderr=['e1', 'e2'], exception=ValueError()))  # noqa: E501
    with pytest.raises(ValueError):
        r.raise_for_status()
    assert r.exception is not None
    assert r.returncode == 1
    assert r.stdout == []
    assert r.stderr == ['e1', 'e2']
    r = RunResult(arguments={})
    r.add(ExecResult(step=ContainerStep(identifier='s3', image='test'), returncode=1, stderr=['e1', 'e2']))
    with pytest.raises(err.FlowservError):
        r.raise_for_status()