There are two main operations mode for foreach:

  1. In the steps section.
  2. In the action section.

When you enter a foreach context, you can use {{ foreach.value }} to use the specific value. Let’s review how to use foreach.

Steps section

Using foreach in steps, let you run a step for each result of a previous step. In other words:

  1. Run some step.
  2. For each result of the previous step, run another step.

For example, in this alert, we:

  1. Get all node id’s (get-node-ids step).
  2. For each node, get the data for result id (get-filesystems-by-node-id step).
    # Get all nodes ids
    - name: get-node-ids
        type: postgres
        config: "{{ providers.postgres-server }}"
          query: "select distinct(node_id) from filesystem;"
    # For each node id, get the filesystem status and find filesystems in node that are not balanced
    - name: get-filesystems-by-node-id
      foreach: "{{ steps.get-node-ids.results }}"
        type: postgres
        config: "{{ providers.postgres-server }}"
          query: "select * from filesystem where node_id = '{{ foreach.value[0] }}';"

In this case, foreach.value contains a row from the database, and foreach.value[0] is the first column of this row.

Actions section

Now, let’s see how foreach can be used in the actions section.

In the following example, we are using foreach twice:

  1. foreach: "{{ steps.get-filesystems-by-node-id.results }}" - iterate over the results of get-filesystems-by-node-id results
  2. {{#foreach.stddev}} - using mustache syntax, we iterate over foreach.stddev results.

Wait, but what’s foreach.stddev?

tldr: conditions can extend foreach with other attributes, to support more context.

Due to the fact that conditions work on foreach.value, we can extend foreach with other attributes. For example, the threshold condition extends foreach with level, so you can use foreach.level, and stddev condition extends foreach with stddev attribute.

    - name: push-alert-to-postgres
      # Run on get-filesystems-by-node-id results.
      # Notice each result is a list of filesystems in node
      foreach: "{{ steps.get-filesystems-by-node-id.results }}"
      # Alert on nodes that have filesystems that away from the standard deviation
        - name: stddev-condition
          type: stddev
          # foreach.value contain a list of rows from the database
          value:  "{{ foreach.value }}"
          pivot_column: 8 # 8th column is the filesystem usage percentage
          compare_to: 1

        type: postgres
        config: "{{ providers.postgres-server }}"
          query: >
            INSERT INTO alert (alert_level, alert_message)
            VALUES ('major', 'The node {{ foreach.value[0][4] }} has filesystems that are not balanced:
                    - Filesystem {{ value[0] }} is {{stddev}} away from the standard deviation