Command line¶
sadame has nine commands: plan, apply and drift run a recipe,
validate checks one without any machine, hosts shows which machines a
selection reaches and facts what recipes see on them, init starts a
project, report turns JSON reports into Markdown or JUnit, and lsp
serves editors. Each takes the same
target and output options, so a command line that plans a change also
applies it after replacing plan with apply. This page lists every
command, option, environment variable and file; the
exit codes have their own page.
Minimal example¶
sadame plan examples/01-hello # on this machine: what would change
sadame apply examples/01-hello # make the change
sadame --help prints the same reference in short:
$ sadame --help
Usage: sadame COMMAND [RECIPE] [options]
sadame init [DIRECTORY] [--ci github|gitlab]
sadame report FILE [--format markdown|junit]
sadame lsp
Commands:
init Start a project: recipe.rb, vars.rb, hosts.rb, a template, and
with --ci a daily drift check for GitHub Actions or GitLab CI.
plan Show what apply would change, as a diff. Changes nothing.
apply Make the hosts match the recipe.
drift Like plan, but exit 1 when a host differs from the recipe.
validate Check the recipe for every selected host without connecting.
hosts Show the selected hosts with their connection options and vars.
facts Show the facts recipes see on each host: CPUs, memory, addresses.
report Turn the --json output of plan, apply or drift into Markdown
(for a CI summary page) or JUnit XML (for test reports).
lsp Run a language server for editors, on stdin and stdout.
RECIPE is a recipe file or a directory containing recipe.rb
(default: ./recipe.rb). vars.rb and hosts.rb next to it are loaded if
present; hosts and facts only use those. Without -h, -g or --limit,
sadame runs on this machine.
Targets:
-h, --host [USER@]HOST[:PORT],... Run on these hosts over SSH
-g, --group GROUP,... Run on the hosts of these groups
--limit GLOB Only hosts whose name matches, e.g. "web*"
--inventory PATH Use this inventory instead of ./hosts.rb
--sudo Run sadame with sudo on every target
--forks N Work on at most N hosts at once (default: all)
--serial N|N% Run in batches of N hosts (or N% of them), one
batch after another; stop when a batch fails
Options:
--platform NAME validate as on debian, ubuntu, rocky, alpine or arch
(default: debian)
--tags T,... Only resources with one of these tags (plan, apply, drift)
--skip-tags T,... Leave out resources with one of these tags
--var KEY=VALUE Set vars[:KEY]; repeatable, overrides everything else
--vars-file PATH Load more vars from a Ruby file (local runs)
--json Print a JSON report instead of text
--format FORMAT report: markdown (default) or junit
--ci SYSTEM init: also write a drift check for github or gitlab
--color Always use colors
--no-color Never use colors (also: NO_COLOR environment variable)
--host-name NAME host_name in recipes and reports for local runs (default: local)
--host-groups G,... host_groups in recipes for local runs
--version Print the version
--help Print this help
Exit status:
0 success; for drift, every host matches the recipe
1 apply failed, or drift found differences
2 usage or recipe error, the state of a resource could not be read,
or a host could not be reached
Synopsis¶
sadame COMMAND [RECIPE] [options]
Options may come before or after the command and the recipe.
Commands¶
| Command | Changes machines | What it does |
|---|---|---|
plan |
no | Reads the current state of every resource and prints what apply would change, as a diff. |
apply |
yes | Changes what differs from the recipe, in order, then runs notifications. |
drift |
no | Same comparison as plan; exits 1 when anything differs. For scripts and CI. |
validate |
no | Evaluates the recipe for each selected host, with its vars, against a stand-in machine, and renders the templates: finds what would make plan fail, without connecting to anything. Exits 2 when a host's recipe has an error. |
hosts |
no | Prints the selected hosts, their connection options and vars, and where each var came from. Connects to nothing. |
facts |
no | Prints the facts recipes see: of this machine, or with -h, -g or --limit, of each selected host over SSH. Runs no recipe. |
init |
no | Writes recipe.rb, vars.rb, hosts.rb and templates/motd.erb into a directory (. by default); with --ci, also a daily drift check. Writes nothing if one of its files exists. |
report |
no | Reads the --json output of plan, apply or drift from a file and prints it as Markdown or JUnit XML; see Drift in CI. |
lsp |
no | A language server on stdin and stdout, which editors start; see Editor support. |
plan, apply and drift are explained together in
plan, apply, drift.
The recipe argument¶
| Given | sadame runs |
|---|---|
| nothing | ./recipe.rb |
a file, such as site.rb |
that file |
a directory, such as examples/01-hello |
recipe.rb in that directory |
vars.rb and hosts.rb in the recipe's directory are loaded when they
exist. Templates and files are looked up next to the recipe, then in its
templates/ and files/ directories. hosts and facts do not need a
recipe; given one, or a directory, they use the hosts.rb and vars.rb
next to it.
Targets¶
Without any of these options, sadame runs on the machine it is started on. With any of them, it runs on the selected hosts over SSH, copying itself and the recipe there first (see Remote hosts).
| Option | Value | Effect |
|---|---|---|
-h, --host |
[USER@]HOST[:PORT], comma-separated |
These hosts. A name from the inventory keeps its settings; the user and port given here win. |
-g, --group |
group names, comma-separated | The hosts of these groups in the inventory. |
--limit |
glob, such as "web*" |
Only the selected hosts whose name matches (* any characters, ? one). Alone, it filters every host of the inventory. |
--inventory |
path | Use this inventory instead of hosts.rb next to the recipe. |
--sudo |
Run sadame with sudo on every target, whatever the inventory says. Needs passwordless sudo. Only with remote targets. | |
--forks |
number | Work on at most this many hosts at once (default: every selected host). Only with remote targets. |
--serial |
number, or percentage such as 25% |
Run the hosts in batches of this size, one batch after another, in the order they were selected. When a host of a batch fails or cannot be reached, the hosts of later batches are skipped. Only with remote targets. |
-h and -g add up: -g db -h web1.example.com selects both.
--limit narrows the result. Selection rules and vars precedence are in
Inventory.
Options¶
| Option | Effect |
|---|---|
--tags T,... |
plan, apply, drift: only resources with one of these tags. |
--skip-tags T,... |
plan, apply, drift: leave out resources with one of these tags. |
--platform NAME |
validate: evaluate as on debian (the default), ubuntu, rocky, alpine or arch. |
--format FORMAT |
report: markdown (the default) or junit. |
--ci SYSTEM |
init: also write a daily drift check for github (.github/workflows/sadame-drift.yml) or gitlab (.gitlab/sadame-drift.yml), in the current directory. |
--var KEY=VALUE |
Sets vars[:KEY]. Repeatable. Wins over every other source of vars. Whole numbers become Integers, true and false booleans; everything else stays a String. |
--vars-file PATH |
Loads more vars from a Ruby file that returns a Hash. Local runs only. |
--json |
Prints one JSON document instead of text; see JSON output. |
--color |
Always use colors, even when the output is not a terminal. |
--no-color |
Never use colors. |
--host-name NAME |
host_name in recipes and reports for local runs (default local). |
--host-groups G,... |
host_groups in recipes for local runs. |
--version |
Prints the version. |
--help |
Prints the help above. |
$ sadame --version
sadame 0.5.1
validate¶
validate evaluates the recipe the way plan does, but against a machine
that is not there: the platform given with --platform, made-up
facts (2 CPUs, 2048 MB, 192.0.2.10), and a shell
that refuses to run anything. It finds Ruby errors, misspelled resources and
options, notifications to resources that are not declared, missing
templates and files, and template errors, for every selected host with its
own name, groups and vars:
$ sadame validate examples/08-multi-role-inventory/site.rb -g all --platform ubuntu
sadame 0.5.1 validate examples/08-multi-role-inventory/site.rb, as on Ubuntu 24.04 LTS
web1.example.com ok 6 resources
web2.example.com ok 6 resources
db1.example.com ok 6 resources
validate on 3 hosts: 3 ok.
An error names the file and line:
$ sadame validate
sadame 0.5.1 validate recipe.rb, as on Debian GNU/Linux 12 (bookworm)
local error templates/app.conf.erb:3: undefined method 'port' for Sadame::Template::Scope
validate on 1 host: 0 ok, 1 error.
$ echo $?
2
What it cannot find is what depends on the machine: a package name that
does not exist there, a service that is not installed, a file a line
resource expects. plan finds those.
Environment variables¶
| Variable | Effect |
|---|---|
NO_COLOR |
When set and not empty, no colors, as with --no-color. |
SADAME_BINARY_DIR |
Push mode: copy sadame-OS-ARCH from this directory to targets, instead of the running binary or a download. Used with binaries built from source. |
SADAME_DOWNLOAD_URL |
Push mode: download target binaries and SHA256SUMS from this URL instead of the GitHub release of the running version. |
TMPDIR |
Where sadame keeps the error output of the commands it runs while they run (default /tmp). |
Every command sadame runs, on the machine itself or on a target, runs with
LC_ALL=C.UTF-8, so its output is in English whatever the system's
language (see exec).
Files¶
| Path | On | What |
|---|---|---|
recipe.rb, vars.rb, hosts.rb |
your machine | The recipe, its default vars, the inventory. |
templates/, files/ |
your machine | Templates and files next to the recipe. |
~/.sadame/dist/VERSION/ |
your machine | Target binaries downloaded for push mode. |
~/.sadame/bin/SHA256/sadame |
each target | The copied binary, kept between runs and reused while its checksum matches. |
Nothing else is left on a target; the copied recipe is removed after each run. Details in What is copied where.
Scenarios¶
Preview a var change on one group. --var wins over hosts.rb, so a
change can be tried without editing anything:
sadame plan site.rb -g db --var backup_hour=4
Roll out to part of a group first. Apply to the first web server, look at it, then apply to the rest:
sadame apply site.rb -g web --limit "web1*"
sadame apply site.rb -g web
Roll out one server at a time. With --serial 1, a change that breaks
the first server stops before it reaches the second; --serial 25% keeps
three quarters of the group untouched while the first quarter changes:
sadame apply site.rb -g web --serial 1
Check one machine that is not in the inventory. -h takes a full
address, so a one-off check needs no hosts.rb:
sadame drift examples/07-hardening-baseline -h admin@203.0.113.10:2222 --sudo
Common mistakes¶
-hfor help.-his--hostand needs a value; use--help.-
Misspelled options. sadame stops with exit status
2instead of guessing:$ sadame plan examples/01-hello --colour sadame: unknown option --colour Run 'sadame --help' for usage. $ echo $? 2 -
--sudoon a local run. It applies to remote targets only; runsudo sadame ...on the machine itself. - Expecting a list from
--var.--var workers=8gives the Integer8, but--var ports=80,443gives the String"80,443", which the recipe has to split.