Warning
This documentation is actively being updated as the project evolves and may not be complete in all areas.
Hooks¶
Jumpstarter supports lifecycle hooks that execute shell scripts automatically before or after a lease.
A beforeLease hook runs after a lease is assigned but
before drivers are available to the client, and an afterLease hook runs after
the session ends but before the lease is released. Hooks are optional and
configured in the Exporter YAML configuration file.
Hooks execute on the exporter host using a configurable interpreter (defaulting
to /bin/sh) and can use the j CLI to interact with drivers locally on the
exporter. The exec field lets you choose a different interpreter such as
/bin/bash or python3. The script field accepts either an inline script
or a path to a script file on disk. Common use cases include powering on
devices, validating hardware state, flashing firmware, and cleaning up after
tests.
How Hooks Work¶
The following diagram shows the full lifecycle of a lease with both hooks configured:
---
config:
theme: base
themeVariables:
lineColor: '#3d94ff'
primaryBorderColor: '#e5e5e5'
primaryColor: '#f8f8f8'
primaryTextColor: '#000'
secondaryColor: '#f8f8f8'
tertiaryColor: '#fff'
---
sequenceDiagram
participant Controller
participant Exporter
participant Hook as Hook Script
participant Client
Client->>Controller: Request lease
Controller->>Exporter: Assign lease
Exporter->>Exporter: Status: BEFORE_LEASE_HOOK
Exporter->>Hook: Execute beforeLease script
Note over Hook: j power on
Hook-->>Exporter: Exit code 0
Exporter->>Exporter: Status: LEASE_READY
Exporter->>Client: Drivers available
Client->>Exporter: Use drivers...
Client->>Exporter: End session
Exporter->>Exporter: Status: AFTER_LEASE_HOOK
Exporter->>Hook: Execute afterLease script
Note over Hook: j power off
Hook-->>Exporter: Exit code 0
Exporter->>Exporter: Status: AVAILABLE
Exporter->>Controller: Release lease
The exporter transitions through these states during a lease:
Lease assigned – The controller assigns a lease to the exporter.
BEFORE_LEASE_HOOK– ThebeforeLeasescript runs. Driver access is blocked until the hook completes successfully.LEASE_READY– The hook succeeded and the client can now access drivers.Client session – The client uses drivers normally.
Session ends – The client disconnects or the lease is released.
AFTER_LEASE_HOOK– TheafterLeasescript runs. The session remains open sojcommands can still interact with drivers.AVAILABLE– The hook completed and the lease is released. The exporter is ready for the next lease.
Note
If no hooks are configured, the exporter transitions directly from lease
assignment to LEASE_READY and from session end to AVAILABLE.
Configuration¶
Hooks are configured in the hooks section of the exporter config file:
apiVersion: jumpstarter.dev/v1alpha1
kind: ExporterConfig
metadata:
namespace: default
name: demo
endpoint: grpc.jumpstarter.example.com:443
token: xxxxx
export:
power:
type: jumpstarter_driver_yepkit.driver.Ykush
config:
serial: "YK25838"
port: "1"
hooks:
beforeLease:
script: |
j power on
sleep 5
timeout: 60
onFailure: endLease
afterLease:
script: |
j power off
timeout: 30
onFailure: warn
Field Reference¶
Field |
Type |
Default |
Description |
|---|---|---|---|
|
object |
(none) |
Hook that runs after lease assignment, before drivers are available |
|
object |
(none) |
Hook that runs after the session ends, before the lease is released |
|
string |
(auto) |
Interpreter used to execute the script. Auto-detected from file extension when not set ( |
|
string |
(required) |
Inline script or path to a script file (auto-detected) |
|
integer |
|
Maximum execution time in seconds |
|
string |
|
Action on failure: |
Script Modes¶
The script field supports two modes, detected automatically:
Inline script (default): When the value contains multiple lines or does not point to an existing file, it is passed to the interpreter with the
-cflag (e.g./bin/sh -c "echo hello").Script file: When the value is a single line that matches an existing file on disk, the interpreter runs the file directly (e.g.
/bin/bash /opt/hooks/setup.sh).
When exec is not set and the script is a file, the interpreter is
auto-detected from the file extension:
Extension |
Interpreter |
Notes |
|---|---|---|
|
Exporter’s Python ( |
Has access to all installed packages including the Jumpstarter client library |
|
|
POSIX shell |
(other) |
|
Fallback for unrecognized extensions |
Set exec explicitly to override auto-detection (e.g. exec: /bin/bash for
a .sh file that needs bash features).
Environment Variables¶
Hook scripts receive a pre-configured environment that enables the j CLI to
communicate with the exporter session:
Variable |
Description |
|---|---|
|
Unix socket path for |
|
Name of the current lease assigned by the controller |
|
Name of the client holding the lease |
|
Set to |
These variables are set automatically. The hook uses a dedicated Unix socket separate from the client connection to avoid protocol interference.
The hook environment is also configured to signal noninteractive mode. Even though hooks run in a PTY (for line-buffered output), they are not interactive sessions. The following variables are set to prevent programs from displaying prompts or interactive UI:
Variable |
Value |
Purpose |
|---|---|---|
|
|
Disables colors, cursor movement, and terminal UI |
|
|
Prevents |
|
|
Prevents git from prompting for credentials |
Additionally, PS1 is removed from the environment so the shell does not
emit a prompt.
Logging¶
Hook output is streamed to the client in real time. Every line written to
stdout or stderr by the hook script is captured and forwarded to the client
through the exporter’s log stream. The beforeLease hook output is tagged
with the BEFORE_LEASE_HOOK log source, and afterLease output is tagged
with AFTER_LEASE_HOOK.
Hooks run inside a pseudo-terminal (PTY) to force line buffering, so output
appears on the client as each line is written rather than being held in a
block buffer. This means echo statements, j CLI output, and any other
text written to the terminal will be visible immediately.
Note
Because hooks use a PTY, programs that detect terminal mode (such as
grep --color=auto) will behave as though running interactively.
Failure Handling¶
The onFailure field controls what happens when a hook script exits with a
non-zero exit code or exceeds its timeout. A hook is considered failed when the
shell process returns a non-zero exit code or when execution exceeds the
configured timeout.
warn¶
The default mode. The failure is logged as a warning and the lease lifecycle continues as if the hook succeeded:
beforeLease: Drivers are unblocked and the client can connect normally. The exporter status transitions toLEASE_READY.afterLease: The exporter returns toAVAILABLEand the lease is released normally.
This is useful for hooks that perform best-effort actions where failure should not disrupt the workflow.
endLease¶
The lease is ended and the client is notified of the failure:
beforeLease: The exporter status transitions toBEFORE_LEASE_HOOK_FAILED. The client discovers the failure through status polling and the lease is released. The interactive shell is skipped.afterLease: The exporter status transitions toAFTER_LEASE_HOOK_FAILED. Since the session has already ended, this primarily serves as a signal to the client that cleanup did not complete successfully. The exporter remains available for new leases.
This is the recommended mode for beforeLease validation hooks where you want
the client to know immediately that the device is not ready.
exit¶
The exporter shuts down entirely with exit code 1 (Failure):
beforeLease: The exporter status transitions toBEFORE_LEASE_HOOK_FAILED. The exporter then shuts down, going offline. The shutdown is deferred until the client has had a chance to observe the failure status.afterLease: The exporter status transitions toAFTER_LEASE_HOOK_FAILEDand the exporter shuts down immediately.
The exit code 1 signals to service managers such as systemd that the shutdown
was intentional. If your systemd unit uses Restart=always, you should
configure RestartPreventExitStatus=1 to prevent automatic restarts after an
exit failure.
Warning
The exit failure mode is a drastic action intended for critical failures
where the device may be in an unusable state. It takes the exporter offline
until manually restarted. Use endLease for most validation scenarios and
reserve exit for critical failures.
Timeout Behavior¶
When a hook exceeds its timeout, the process is terminated with SIGTERM
followed by SIGKILL if the process does not exit within a few seconds. The
resulting failure is then handled according to the onFailure setting, exactly
as if the script had exited with a non-zero exit code.
Use Cases¶
Device Initialization¶
Power on the device and wait until it is reachable over SSH before the client connects:
hooks:
beforeLease:
script: |
echo "Powering on device..."
j power on
echo "Waiting for SSH to become available..."
for i in $(seq 1 30); do
if j ssh -o ConnectTimeout=2 -- echo "Device ready"; then
exit 0
fi
sleep 1
done
echo "Device did not become reachable"
exit 1
timeout: 120
onFailure: endLease
Note that the j ssh command does not have a built-in connection timeout, so
each attempt uses the system SSH default (typically ~30 seconds). Passing
-o ConnectTimeout=2 keeps each retry attempt short so the loop can complete
within the hook’s timeout.
Device Cleanup¶
Power off the device after each lease to ensure a clean environment for the next user:
hooks:
afterLease:
script: |
echo "Cleaning up..."
j power off
timeout: 30
onFailure: warn
Firmware Flashing¶
Flash known-good firmware before each test session to guarantee a consistent starting state:
hooks:
beforeLease:
script: |
echo "Flashing firmware..."
j storage write --image /var/lib/jumpstarter/images/firmware.bin
j power cycle
sleep 10
timeout: 180
onFailure: endLease
Using Bash¶
Set exec: /bin/bash to use bash-specific features such as [[ ]] tests,
arrays, and process substitution:
hooks:
beforeLease:
exec: /bin/bash
script: |
echo "Checking device readiness..."
[[ -f /dev/ttyUSB0 ]] || { echo "Serial device missing"; exit 1; }
j power on
timeout: 60
onFailure: endLease
Using Python¶
Point script to a .py file. The exporter auto-detects the .py
extension and runs it with its own Python interpreter, so the hook has
access to all installed packages including the Jumpstarter client library.
Python hooks can use the driver client APIs directly by importing
jumpstarter.utils.env.env, which connects to the local exporter session
via the JUMPSTARTER_HOST socket automatically.
Exporter config:
hooks:
beforeLease:
script: /opt/jumpstarter/hooks/prepare_device.py
timeout: 60
onFailure: endLease
/opt/jumpstarter/hooks/prepare_device.py:
import os
from jumpstarter.utils.env import env
lease = os.environ["LEASE_NAME"]
print(f"Preparing device for lease {lease}")
with env() as client:
client.power.on()
print("Power on complete")
The env() context manager returns a DriverClient whose attributes
correspond to the exported drivers (e.g. client.power, client.storage).
This is the same API used by the j CLI and by test scripts connecting to
an exporter.
Using a Script File¶
Point script to an existing file on disk instead of writing the script
inline. The interpreter runs the file directly:
hooks:
beforeLease:
exec: /bin/bash
script: /opt/jumpstarter/hooks/prepare_device.sh
timeout: 120
onFailure: endLease
Best Practices¶
Keep hook scripts short and focused on a single concern (initialization or cleanup).
Set an appropriate
timeoutfor each hook. The default of 120 seconds may be too generous for simple scripts and too short for firmware flashing.Use
onFailure: endLeaseforbeforeLeasevalidation so clients get immediate feedback when a device is not ready.Use
onFailure: warnforafterLeasecleanup unless leaving the device in a bad state poses a safety risk.Reserve
onFailure: exitfor critical failures that require manual intervention.Hook output is streamed to the client in real time. Include informative
echostatements for observability.The interpreter is auto-detected from the file extension (
.pyuses the exporter’s Python,.shuses/bin/sh). Setexecexplicitly to override (e.g.exec: /bin/bashfor bash-specific syntax).The
jCLI is available in hook scripts becauseJUMPSTARTER_HOSTis set automatically. No additional configuration is needed.