exec¶
exec runs a shell command. It is the escape hatch for anything the other
resources do not cover: issuing a certificate, running an installer,
installing from the AUR. A command has no state sadame can read, so to stay
idempotent an exec needs a guard that says when the work is already done.
Guards are evaluated during plan as well as apply; the command itself
only runs during apply.
Minimal example¶
exec "tar -czf /var/backups/etc.tar.gz /etc", creates: "/var/backups/etc.tar.gz"
Options¶
| Option | Type | Default | Description |
|---|---|---|---|
command |
String | the resource name | Command to run, when you want the name to be a short label. |
creates |
String | none | Skip when this path exists. |
not_if |
String | none | Skip when this command exits 0. |
only_if |
String | none | Skip unless this command exits 0. |
cwd |
String | inherited | Working directory for the command and its guards. |
env |
Hash of String to String | none | Environment variables for the command and its guards. |
action |
:run or :nothing |
:run |
:nothing never runs the command on its own, only when another resource notifies it. |
notifies |
[:action, "type[name]"], optionally with :immediately, or a list of them |
none | Actions to run on other resources when this command runs. See Notifications. |
subscribes |
[:action, "type[name]"], optionally with :immediately, or a list of them |
none | Actions to run on this resource when another one changes. |
tags |
Symbol, String, or an Array of them | none | Tags for running part of a recipe with --tags and --skip-tags. See Tags. |
The command runs when every guard you gave agrees: the creates path is
missing, not_if exits non-zero, and only_if exits 0. Guards are checked
in that order and checking stops at the first one that says skip. Without
any guard, the command runs on every apply.
Commands and guards run with /bin/sh and standard input closed. A command
that exits non-zero fails the resource: apply prints the exit status and
the command's error output, marks the resource failed, and skips the
resources after it.
Every command sadame runs, including yours, runs in the C.UTF-8 locale
(LC_ALL=C.UTF-8, LANGUAGE unset), so programs answer in English
whatever the language of the machine or of the SSH session: a guard such as
not_if: "ufw status | grep -q 'Status: active'" matches on every system.
Set LC_ALL inside the command if it needs another locale.
Other resources can trigger the command with
notifies: [:run, "exec[NAME]"]. Combined with action: :nothing, that
gives a command that runs only when something else changed, such as
systemctl daemon-reload after a unit file changed; see
Notifications.
Scenarios¶
directory "/opt/demo"
# creates: skip when the path exists.
exec "tar -czf /opt/demo/etc-backup.tar.gz -C /etc hostname hosts",
creates: "/opt/demo/etc-backup.tar.gz"
# not_if: skip when the command succeeds.
exec "echo 'EDITOR=vim' >> /etc/environment",
not_if: "grep -qs '^EDITOR=vim$' /etc/environment"
# only_if: run only when the command succeeds. Here: only on hosts with git,
# and only until the setting is in place.
exec "git config --system init.defaultBranch main",
only_if: "command -v git",
not_if: "git config --system --get init.defaultBranch"
# cwd: and env: set the working directory and environment.
exec "echo \"built by $BUILDER\" > build-info.txt",
cwd: "/opt/demo",
env: { "BUILDER" => "sadame" },
creates: "/opt/demo/build-info.txt"
Plan explains why each command will run¶
$ sudo sadame plan examples/resources/exec
sadame 0.5.1 plan on local (Debian GNU/Linux 12 (bookworm))
+ directory[/opt/demo]
state: absent -> present
! exec[tar -czf /opt/demo/etc-backup.tar.gz -C /etc hostname hosts]
command: tar -czf /opt/demo/etc-backup.tar.gz -C /etc hostname hosts
(/opt/demo/etc-backup.tar.gz does not exist)
! exec[echo 'EDITOR=vim' >> /etc/environment]
command: echo 'EDITOR=vim' >> /etc/environment
(not_if exited non-zero)
! exec[echo "built by $BUILDER" > build-info.txt]
command: echo "built by $BUILDER" > build-info.txt
(/opt/demo/build-info.txt does not exist)
Plan: 1 to create, 0 to update, 0 to remove, 3 to run, 1 unchanged.
The git config command is not listed: this machine has no git, so its
only_if guard skips it.
After apply, the guards hold¶
$ sudo sadame apply examples/resources/exec
sadame 0.5.1 apply on local (Debian GNU/Linux 12 (bookworm))
changed directory[/opt/demo]
state: absent -> present
changed exec[tar -czf /opt/demo/etc-backup.tar.gz -C /etc hostname hosts]
command: tar -czf /opt/demo/etc-backup.tar.gz -C /etc hostname hosts
(/opt/demo/etc-backup.tar.gz does not exist)
changed exec[echo 'EDITOR=vim' >> /etc/environment]
command: echo 'EDITOR=vim' >> /etc/environment
(not_if exited non-zero)
unchanged exec[git config --system init.defaultBranch main]
changed exec[echo "built by $BUILDER" > build-info.txt]
command: echo "built by $BUILDER" > build-info.txt
(/opt/demo/build-info.txt does not exist)
Summary
changed 4 directory[/opt/demo]
exec[tar -czf /opt/demo/etc-backup.tar.gz -C /etc hostname hosts]
exec[echo 'EDITOR=vim' >> /etc/environment]
exec[echo "built by $BUILDER" > build-info.txt]
unchanged 1
failed 0
skipped 0
notified 0
Finished in 0.19s.
$ sudo sadame plan examples/resources/exec
sadame 0.5.1 plan on local (Debian GNU/Linux 12 (bookworm))
Plan: 0 to create, 0 to update, 0 to remove, 0 to run, 5 unchanged.
$ cat /opt/demo/build-info.txt
built by sadame
Common mistakes¶
- No guard. An
execwithoutcreates,not_iforonly_ifruns on every apply, plan always lists it with "(no guard, runs on every apply)", anddriftalways reports it. Add a guard, or useaction: :nothingif it should only run when notified. - Guards with side effects. Guards run during
plan. A guard such asnot_if: "mkdir /x"changes the machine when you only asked to look. - Interactive commands. Standard input is closed, so a command that
prompts reads end-of-file and usually fails. Pass the tool's
non-interactive flag (
-y,--noconfirm). - A guard that never becomes true. If the command does not create what the guard checks for, it runs every time. Check the exact path or setting the command produces.
See also¶
- package for installing AUR packages with
exec. - Recipe basics for using
varsin commands.