How to write runtime hooks¶
This guide shows how to write each of the five runtime hooks an SDK can ship, with a synthesized SDK that exercises the contract differences: which user the hook runs as, which working directory it starts in, and which environment variables it can rely on.
Workshop runs each hook as a bash script
with errexit and pipefail set,
so any non-zero exit aborts the hook.
Where it differs is the privilege, working directory, and extra environment.
Prerequisites¶
You need a working SDKcraft installation
and a workshop you can launch and refresh
on a host with Workshop installed.
The examples use a synthesized SDK named dotfiles-sdk.
If you don’t have an SDK yet,
Craft SDKs with SDKcraft walks through scaffolding one with
sdkcraft init.
Lay out the hooks directory¶
SDKcraft picks up any executable file in the SDK’s hooks/ directory
whose name matches one of the five hook names.
Hooks are not listed in sdkcraft.yaml;
SDKcraft enumerates them automatically when packing.
A complete hook tree looks like this:
$ ls hooks/
check-health
restore-state
save-state
setup-base
setup-project
Each file is a bash script; mark it executable (sdkcraft init already does this for the scaffolded ones).
Write setup-base¶
setup-base runs as root,
before the project directory is mounted
and before plugs and slots are connected.
It runs when the SDK is installed
and again when its revision changes;
a refresh that leaves the SDK intact skips it.
The working directory is the SDK’s own hooks/ directory.
Use it for system-wide preparation
that other SDKs in the workshop may want to rely on:
cat <<PROFILE >/etc/profile.d/dotfiles.sh
export DOTFILES_SDK="$SDK"
PROFILE
$SDK always points at the SDK installation directory in the workshop,
so hooks can reference files the SDK shipped
without hardcoding a path.
Write setup-project¶
setup-project runs as the workshop user,
not root,
with the working directory set to /project/.
It also has $HOME, $XDG_RUNTIME_DIR,
and $DBUS_SESSION_BUS_ADDRESS available,
so it can touch the user’s home tree
and talk to user-session services.
Use it for per-project initialization:
id -u >"$HOME/.dotfiles-uid"
install -m 0644 -t "$HOME" "$SDK/skel/.bash_aliases"
The hook runs after auto-connect has finished,
so any mounts the SDK plugged into are visible at this point,
as well as the project directory itself,
and the home directory is writable by the workshop user.
Write check-health¶
check-health runs as root
from the SDK’s hooks/ directory.
It is meant to be quick:
each attempt has five seconds
to report its result through workshopctl set-health
and exit.
A hook that runs past that window,
or exits without reporting a status,
moves the SDK’s health to error.
Call workshopctl set-health okay
when everything is in order;
otherwise, set error with a short message:
if ! sudo -u workshop --login bash -c 'test -f "$HOME/.dotfiles-uid"'; then
workshopctl set-health error "setup-project marker missing"
exit 0
fi
workshopctl set-health okay
Because check-health runs as root,
use sudo -u workshop whenever the check needs the workshop user’s
shell, environment, or file ownership.
Persist state with save-state and restore-state¶
When a workshop refreshes an SDK to a new revision,
anything that lives outside a connected plug
disappears unless the SDK explicitly preserves it.
save-state and restore-state
solve that case.
Both hooks run as root
from the SDK’s hooks/ directory
and have $SDK_STATE_DIR available,
pointing at a directory that survives the refresh.
save-state runs from the old SDK revision
before the swap.
Write whatever needs to outlive the revision
into $SDK_STATE_DIR:
if [ -f /home/workshop/.dotfiles-uid ]; then
cp /home/workshop/.dotfiles-uid "$SDK_STATE_DIR/"
fi
restore-state runs from the new SDK revision
after the swap and after setup-project has finished
for every SDK in the workshop:
if [ -f "$SDK_STATE_DIR/.dotfiles-uid" ]; then
install -m 0644 -o 1000 -g 1000 \
"$SDK_STATE_DIR/.dotfiles-uid" \
/home/workshop/.dotfiles-restored-uid
fi
Keep the hook idempotent and tolerant of missing input,
since the new revision may be installed onto a workshop
that was originally launched without save-state.
Verify the hooks¶
Build and install the SDK into a workshop with sdkcraft try:
$ sdkcraft try
SDKcraft lints every hook with ShellCheck while packing, so a shell error in a hook fails the build at this step.
List the SDK in a workshop definition with the try- prefix
and launch the workshop:
name: dev
base: ubuntu@22.04
sdks:
- name: try-dotfiles-sdk
$ workshop launch dev
At this point setup-base, setup-project,
and check-health have all run.
Confirm:
$ workshop exec dev -- cat /etc/profile.d/dotfiles.sh
export DOTFILES_SDK="/var/lib/workshop/sdk/dotfiles-sdk"
$ workshop exec dev -- cat /home/workshop/.dotfiles-uid
1000
$ workshop info dev
name: dev
base: ubuntu@22.04
project: /home/user/workshop/dev
status: ready
save-state and restore-state only run
when workshop refresh has work to do:
a new SDK revision to swap in,
an added or removed SDK,
or a change to the workshop definition.
A bare workshop refresh dev against an unchanged workshop
is a no-op and skips every hook.
To exercise the state hooks,
edit the workshop definition so the refresh has something to apply,
for example by adding a mount,
and run workshop refresh for the workshop.
After the refresh,
.dotfiles-restored-uid exists in the workshop user’s home,
confirming that save-state wrote into $SDK_STATE_DIR
and restore-state read it back.
See also¶
Explanation:
Reference:
Tutorial: