Skip to main content

RUN A GUARDED COMMAND ACROSS TAGGED SSH HOSTS

This guide shows you how to run a check such as test -f on every host with a given tag, so that exit 0 and exit 1 are both recorded as answers instead of failures.

Prerequisites

  • swamp auth login completed
  • SSH access to the target hosts with a key available to ssh-agent or an identity file

Pull the extension

swamp extension pull @swamp/ssh

You will see output like:

INF extension·pull: Pulling "@swamp/ssh"@"2026.10.13.1"
INF extension·pull: Identity verified: "@swamp/ssh"@"2026.10.13.1"
INF extension·pull: Pulled "@swamp/ssh"@"2026.10.13.1"
INF extension·pull: Extracted 14 files:

Declare the fleet

Create a @swamp/ssh behavior named prod-fleet (see Create and Run a Behavior). Tag the hosts you want to check, here with nginx:

globalArguments:
  name: prod-fleet
  transport:
    kind: ssh
    user: ops
    port: 22
    auth:
      kind: key
    connectTimeoutSec: 10
    extraOptions: []
    controlMaster:
      enabled: true
      persistSec: 600
  hosts:
    - name: web-1
      address: 10.0.0.11
      tags: [nginx, prod]
      attrs: {}
    - name: web-2
      address: 10.0.0.12
      tags: [nginx, prod]
      attrs: {}
    - name: db-1
      address: 10.0.0.21
      tags: [db, prod]
      attrs: {}

Check which hosts the selector matches

Resolve the selector before you run anything on the hosts:

swamp behavior run prod-fleet resolve --input hosts=tag:nginx

This command does not connect to any host. It writes a selection resource with the matched hosts and a count. A selector that matches nothing returns count: 0 and does not raise an error, so check the count before you continue.

Run the guarded command

Pass okExitCodes to set which exit codes count as success:

swamp behavior run prod-fleet exec \
  --input hosts=tag:nginx \
  --input 'command=test -f /etc/nginx/nginx.conf' \
  --input 'okExitCodes:json=[0,1]'

This command runs test -f on each matched host in parallel and writes one run-exec-<host> resource per host with the exit code it returned. A host without the file records exitCode 1 and the run still succeeds.

The array replaces the default [0] rather than adding to it. [1] alone would make exit 0 a failure. Keep the list explicit instead of passing any: OpenSSH reports its own errors, such as an unreachable host or a rejected key, as exit 255, and those must still fail the host. Spawn errors, timeouts and signal kills fail the host whatever okExitCodes says.

Target named hosts instead of a tag

To run the same check on specific hosts, pass a JSON list of host names:

swamp behavior run prod-fleet exec \
  --input 'hosts:json=["web-1"]' \
  --input 'command=test -f /etc/nginx/nginx.conf' \
  --input 'okExitCodes:json=[0,1]'

This command runs the check on web-1 only and writes run-exec-web-1.

Read the results

Each run-exec-<host> resource is tagged with fleet, host, method and exitCode. Query them by tag to see which hosts returned 0 and which returned 1. See Query and Manage Data for query syntax, and CEL Expressions for writing cel: selectors.