Exit codes¶
Every sadame command ends with an exit status a script can act on: 0
when it did what was asked, 1 when apply failed or drift found a
difference, and 2 when sadame could not do its job at all: a wrong
command line, a broken recipe, a state it could not read, a host it could
not reach. 2 never means "the machine differs"; a CI job can tell "the
servers drifted" from "the check itself is broken".
Minimal example¶
sadame drift site.rb -g all
case $? in
0) echo "every host matches" ;;
1) echo "drift: run apply, or update the recipe" ;;
*) echo "the check could not run" ; exit 2 ;;
esac
By command¶
| Status | plan |
apply |
drift |
hosts |
|---|---|---|---|---|
0 |
plan computed, with or without changes | every resource and notification succeeded | every host matches the recipe | hosts listed |
1 |
not used | a resource or a notification failed | a host differs from the recipe | not used |
2 |
usage or recipe error, a state could not be read, a host could not be reached | usage or recipe error, a host could not be reached | usage or recipe error, a state could not be read, a host could not be reached | usage or inventory error |
plan exits 0 even when there are changes: it answers "what would
change", not "is anything different". Use drift for that question.
Several hosts¶
With remote targets, each host gets a result, and the run exits with the highest status among them:
| Host result | Meaning | Status |
|---|---|---|
ok |
sadame finished on the host with status 0 | 0 |
drift |
drift found a difference on the host |
1 |
failed |
apply had a failed resource on the host |
1 |
error |
sadame could not run on the host, or exited with 2 there | 2 |
unreachable |
ssh could not connect | 2 |
One host that drifted makes the whole run exit 1:
$ sadame drift site.rb --limit 'web*'
[web2.example.com] sadame 0.5.1 drift on web2.example.com (Debian GNU/Linux 12 (bookworm))
[web2.example.com]
[web1.example.com] sadame 0.5.1 drift on web1.example.com (Debian GNU/Linux 12 (bookworm))
[web1.example.com]
[web2.example.com] ~ file[/etc/demo-app/web.conf]
[web2.example.com] --- /etc/demo-app/web.conf
[web2.example.com] +++ /etc/demo-app/web.conf (desired)
[web2.example.com] @@ -1,3 +1,3 @@
[web2.example.com] # Managed by sadame.
[web2.example.com] environment = production
[web2.example.com] -workers = 12
[web2.example.com] +workers = 8
[web2.example.com]
[web1.example.com] No drift: 6 resources match the recipe.
[web2.example.com] Drift: 1 of 6 resources differs from the recipe.
Hosts
web1.example.com ok
web2.example.com drift
drift on 2 hosts: 1 ok, 1 drift. Finished in 0.22s.
$ echo $?
1
One host that cannot be reached makes it exit 2, and the other hosts
still run:
$ sadame plan site.rb -g db -h deploy@db2.example.com
[db1.example.com] sadame 0.5.1 plan on db1.example.com (Debian GNU/Linux 12 (bookworm))
[db1.example.com]
[db1.example.com] Plan: 0 to create, 0 to update, 0 to remove, 0 to run, 6 unchanged.
Hosts
db1.example.com ok
db2.example.com unreachable connect failed: ssh: Could not resolve hostname db2.example.com: Name or service not known
plan on 2 hosts: 1 ok, 1 unreachable. Finished in 0.22s.
$ echo $?
2
Scenarios¶
Fail a scheduled CI job only on drift. Treat 1 and 2 differently,
so a broken check does not look like drift (and drift does not look like a
broken check). Drift in CI has complete
GitHub Actions and GitLab CI pipelines.
Gate a deployment on a clean apply. In a shell script, set -e stops
at the first failing host's exit status:
set -e
sadame apply site.rb -g db
sadame apply site.rb -g web
Read the status per host. --json reports each host's result and exit
status, for when one number for the whole run is not enough (see
JSON output).
Common mistakes¶
- Checking
plan's status for changes. It is0either way; usedrift. - Treating every non-zero status as drift.
2means the check did not complete; the servers may be fine. - Unguarded
execresources. Anexecwithoutcreates:,not_if:oronly_if:always differs, sodriftalways exits1.