When Expressions

The when: attribute on resources and modules controls conditional execution. Expressions evaluate to true or false — the resource is skipped when false.

Syntax

When expressions support boolean logic and function calls:

when: "os_family('debian')"
when: "!is_container"
when: "os_family('debian') && arch('amd64')"
when: "file_exists('/opt/app') || dir_exists('/opt/app')"
when: "os_family('redhat') && !version_ge('9')"

Operators

Operator Description Example
&& Logical AND os_family('debian') && arch('amd64')
|| Logical OR file_exists('/a') || file_exists('/b')
! Logical NOT !is_container
( ) Grouping (os_family('debian') || os_family('redhat')) && arch('amd64')

Builtin Functions (16)

All builtins are evaluated on the agent using local system state and traits.

Filesystem

Function Args Description
file_exists(path) 1 True if path is a regular file
dir_exists(path) 1 True if path is a directory
- name: migrate-data
  type: exec
  command: "/opt/app/migrate.sh"
  when: "file_exists('/opt/app/migrate.sh')"

Process

Function Args Description
process_running(name) 1 True if a process with this name exists
command_succeeds(cmd) 1 True if the command exits 0
- name: stop-old-service
  type: exec
  command: "systemctl stop legacy-app"
  when: "process_running('legacy-app')"

Time

Function Args Description
hour_range(start, end) 2 True if current local hour is within [start, end)
minute_range(start, end) 2 True if current local minute is within [start, end)
day_of_week(day) 1 True if current day matches (e.g., monday, friday)
day_of_month(day) 1 True if current day-of-month matches (1-31)
- name: maintenance-cleanup
  type: exec
  command: "/opt/cleanup.sh"
  when: "hour_range('2', '5') && day_of_week('sunday')"

- name: staggered-task
  type: exec
  command: "/opt/rotate-logs.sh"
  when: "minute_range('0', '15')"

OS / Traits

Function Args Description
os_family(family) 1 True if os.family trait matches (case-insensitive)
distro(name) 1 True if os.distro trait matches (case-insensitive)
arch(arch) 1 True if os.arch trait matches
version_ge(version) 1 True if os.version trait is >= the given version
has_display() 0 True if a display server is available (X11, Wayland, Quartz, or Windows)
- name: apt-package
  type: package
  package: nginx
  when: "os_family('debian')"

- name: yum-package
  type: package
  package: nginx
  when: "os_family('redhat')"

- name: install-gui-app
  type: source_package
  url: "https://example.com/app-{{ .Traits.os.arch }}.deb"
  target_path: /tmp/app-install
  when: "has_display() and os_family('debian')"

System

Function Args Description
flag_set(flag) 1 True if /var/lib/vigo/flags/<flag> exists
in_group(group) 1 True if the system group exists
- name: enable-feature
  type: exec
  command: "/opt/app/enable-beta.sh"
  when: "flag_set('beta-features')"

Flags are a simple feature-gate mechanism. Create a flag:

mkdir -p /var/lib/vigo/flags
touch /var/lib/vigo/flags/beta-features

Network

Function Args Description
port_listening(port) 1 True if the given TCP port is in LISTEN state (from ports trait)
- name: haproxy-backend
  type: file
  target_path: /etc/haproxy/haproxy.cfg
  content: "..."
  when: "port_listening(8080)"

Trigger Guard: changed

The special keyword changed in a when: expression makes a resource only execute when triggered by notify, subscribes, or watch_secret. It is skipped on normal check-ins.

- name: restart-app
  type: exec
  command: "systemctl restart myapp"
  subscribes: [app-config]
  when: "changed"

changed can be combined with other expressions:

when: "changed && os_family('debian')"

This is the standard way to create a resource that only runs in reaction to another resource changing, similar to Puppet's refreshonly or Ansible's handler model.

Variables in When

When expressions can reference variables that resolve to boolean names. The server resolves variable names at check-in time:

vars:
  is_debian:
    trait: os.family
    in: [debian]
  has_enough_ram:
    trait: hardware.memory_mb
    gte: 4096

resources:
  - name: heavy-service
    type: service
    service: analytics
    when: "is_debian && has_enough_ram"

Conditional vars (those with a trait: field) are resolved by the server and substituted as true/false before the expression reaches the agent. Builtin function calls are passed through to the agent for local evaluation.

Evaluation Model

When expressions are evaluated in two phases:

When Expression Evaluation

If the expression is fully resolved after variable substitution (e.g., true && true), the server can filter the resource before sending it to the agent.

If the expression contains builtin function calls, it's passed to the agent for local evaluation.

Module-Level When

Apply a when: to an entire module reference:

# In a role definition
modules:
  - name: monitoring
    when: "!is_container"

Or in nodes.vgo:

envoys:
  - match: "*"
    modules:
      - name: monitoring
        when: "!is_container"

Role-Level When

Apply a when: to an entire role definition. All modules inherit the condition:

- name: cis-ubuntu
  when: "distro('ubuntu')"
  modules: [cis-ubuntu-access, cis-ubuntu-network, cis-ubuntu-logging]

Role Case

Use case: for roles that need different modules per platform:

- name: remote-access
  case:
    - when: "os_family('linux')"
      modules: [x11vnc, xrdp]
    - when: "os_family('windows')"
      modules: [tightvnc]

All matching cases contribute modules. A module with its own when: keeps it regardless of the case condition.

Inheritance Precedence

  1. Module's own when: (highest priority)
  2. Case when:
  3. Role definition when:
  4. Role ref when: (at the node entry)

Related

  • Resource Language — conditional_block for grouping
  • Config Format — Conditional vars
  • Trait Collectors — Available trait data for expressions