# pipeline

ordered stages that apply steps to hosts

A pipeline is an ordered list of stages. Each stage applies its steps to a set of hosts.

## Files

A pipeline is a file in pipelines/, such as pipelines/site.yaml, or a key in pipelines of winch.yaml. winch plan site and winch apply site run it.

## One stage or many

Most pipelines run the same steps on every host. Such a pipeline holds the steps directly. It is one stage with the name of the pipeline. A pipeline whose hosts have different roles, or that must finish on some hosts before it starts on others, has stages.

## Order

Stages run in order. A stage starts when the previous stage finished on all its hosts. Inside a stage, each host runs its steps in order, without waiting for other hosts. A stage that matches no host is skipped. --stages runs only some stages, and --hosts only some hosts.

## Steps of a stage

A step in a stage can use a module directly. It cannot use template, source, or the key of repo: those read the files of a recipe.

## Failures

A failed host takes no part in later stages. The other hosts go on. A new run is the resume: steps that already succeeded check as ok.

## Keys

| Key | Type | Default | Meaning |
| --- | --- | --- | --- |
| [`stages`](#pipeline.stages) | list of maps | - | stages in run order |
| [`stages.name`](#pipeline.stages.name) | string | required | unique in the pipeline |
| [`stages.hosts`](#pipeline.stages.hosts) | string | all | host pattern |
| [`stages.parallelism`](#pipeline.stages.parallelism) | integer | - | maximum hosts at the same time |
| [`stages.health`](#pipeline.stages.health) | map | - | check after a host changed in the stage |
| [`stages.health.command`](#pipeline.stages.health.command) | string | required | must exit 0 |
| [`stages.health.stable`](#pipeline.stages.health.stable) | integer | 0 | seconds the command keeps passing |
| [`stages.health.timeout`](#pipeline.stages.health.timeout) | integer | 60 | seconds the gate has to pass |
| [`stages.steps`](#pipeline.stages.steps) | list of steps | required | recipe steps and module steps, in order |
| [`stages.handlers`](#pipeline.stages.handlers) | map of lists of steps | - | handlers of the stage |
| [`hosts`](#pipeline.hosts) | string | all | host pattern of a pipeline without stages |
| [`parallelism`](#pipeline.parallelism) | integer | - | maximum hosts at the same time |
| [`health`](#pipeline.health) | map | - | check after a host changed in the stage |
| [`health.command`](#pipeline.health.command) | string | required | must exit 0 |
| [`health.stable`](#pipeline.health.stable) | integer | 0 | seconds the command keeps passing |
| [`health.timeout`](#pipeline.health.timeout) | integer | 60 | seconds the gate has to pass |
| [`steps`](#pipeline.steps) | list of steps | - | steps of a pipeline without stages |
| [`handlers`](#pipeline.handlers) | map of lists of steps | - | handlers of a pipeline without stages |

### `pipeline.stages` {#pipeline.stages}

list of maps

Stages in run order. A stage starts when the previous stage finished on all its hosts. A pipeline with stages has no other key.

### `pipeline.stages.name` {#pipeline.stages.name}

string, required

Unique in the pipeline. It follows the rule of host names. --stages selects stages by name.

### `pipeline.stages.hosts` {#pipeline.stages.hosts}

string, default all

Host pattern. Run winch doc inventory for the patterns.

### `pipeline.stages.parallelism` {#pipeline.stages.parallelism}

integer

Maximum hosts at the same time. Hosts start in inventory order. The next host starts when a host finishes the stage and its health gate passes. A failure stops new hosts from starting. Running hosts finish the stage.

### `pipeline.stages.health` {#pipeline.stages.health}

map

Check after a host changed in the stage. The gate runs on a host after it finishes the stage, when the stage has a change on that host. The plan marks it with \* and does not run it. A gate that fails stays pending on the host, and the next apply runs it.

### `pipeline.stages.health.command` {#pipeline.stages.health.command}

string, required

Must exit 0. winch runs it on the host once per second until it exits 0, then keeps running it for stable seconds. A failed run starts the wait again. An exit of 126 or 127, when sh cannot find or run the command, fails the gate at once.

### `pipeline.stages.health.stable` {#pipeline.stages.health.stable}

integer, default 0

Seconds the command keeps passing. It is less than timeout.

### `pipeline.stages.health.timeout` {#pipeline.stages.health.timeout}

integer, default 60

Seconds the gate has to pass. Then the host fails, and the error shows the end of the last output.

### `pipeline.stages.steps` {#pipeline.stages.steps}

list of steps, required

Recipe steps and module steps, in order.

### `pipeline.stages.handlers` {#pipeline.stages.handlers}

map of lists of steps

Handlers of the stage, as in a recipe. A module step of the stage notifies them.

### `pipeline.hosts` {#pipeline.hosts}

string, default all

Host pattern of a pipeline without stages. Run winch doc inventory for the patterns.

### `pipeline.parallelism` {#pipeline.parallelism}

integer

Maximum hosts at the same time. Hosts start in inventory order. The next host starts when a host finishes the stage and its health gate passes. A failure stops new hosts from starting. Running hosts finish the stage.

### `pipeline.health` {#pipeline.health}

map

Check after a host changed in the stage. The gate runs on a host after it finishes the stage, when the stage has a change on that host. The plan marks it with \* and does not run it. A gate that fails stays pending on the host, and the next apply runs it.

### `pipeline.health.command` {#pipeline.health.command}

string, required

Must exit 0. winch runs it on the host once per second until it exits 0, then keeps running it for stable seconds. A failed run starts the wait again. An exit of 126 or 127, when sh cannot find or run the command, fails the gate at once.

### `pipeline.health.stable` {#pipeline.health.stable}

integer, default 0

Seconds the command keeps passing. It is less than timeout.

### `pipeline.health.timeout` {#pipeline.health.timeout}

integer, default 60

Seconds the gate has to pass. Then the host fails, and the error shows the end of the last output.

### `pipeline.steps` {#pipeline.steps}

list of steps

Steps of a pipeline without stages: recipe steps and module steps, in order.

### `pipeline.handlers` {#pipeline.handlers}

map of lists of steps

Handlers of a pipeline without stages, as in a recipe. A module step of the stage notifies them.

## Example

```
# pipelines/site.yaml
stages:
  - name: base
    hosts: all
    parallelism: 1
    steps:
      - timezone:
          name: Etc/UTC
  - name: web
    hosts: web
    health:
      command: systemctl is-active nginx
      stable: 10
      timeout: 120
    steps:
      - recipe: nginx

# winch.yaml
name: acme
inventories:
  production:
    hosts:
      web1.acme.com: {}
      web2.acme.com: {}
    groups:
      web:
        hosts: [web1.acme.com, web2.acme.com]
recipes:
  nginx:
    steps:
      - pkg:
          name: nginx
```
