Data Rendering¶
DRP uses Go's text/template package to render task scripts and configuration files before they are delivered to the machine runner. Rendering happens in two phases: first, DRP resolves the template on the server side using machine state and parameters; then, the rendered script is handed to the runner (agent on the target machine or a server-side context) for execution. Understanding the rendering context and available functions is essential for writing tasks that adapt to per-machine configuration.
Two-Phase Execution¶
Phase 1 — Server-side rendering: DRP fetches the task's template Contents, evaluates all {{ }} expressions against the current machine state, and produces a plain script or configuration file. No code is executed during this phase — only template expressions are evaluated.
Phase 2 — Runner-side execution: The rendered script is sent to the runner agent on the machine (or in the configured context). The agent writes the script to disk, sets it executable, and runs it. Output and exit codes are captured back to DRP as job log entries.
This separation means that any DRP API calls, parameter lookups, or conditional logic written in template syntax happens before the script reaches the machine. The machine itself only sees the final rendered output.
Template Context¶
Every template is evaluated with a root context object (.) that exposes the following top-level fields:
| Field | Type | Description |
|---|---|---|
.Machine |
Machine object | The full machine model for the target machine |
.Env |
BootEnv object | The current boot environment |
.Task |
Task object | The current task being rendered |
.Stage |
Stage object | The current stage |
.Job |
Job object | The current job |
.Param "name" |
any | Resolved parameter value (machine → profiles → global) |
.ParamExists "name" |
bool | True if the parameter is set anywhere in the resolution chain |
Accessing a machine field directly:
Accessing a resolved parameter (recommended over .Machine.Params for proper profile resolution):
Common Template Functions¶
DRP extends the standard Go template function set with several helpers:
{{ .Param "my-param" }} # Get a parameter value
{{ .ParamExists "my-param" }} # Check if parameter exists
{{ .Machine.Params.SomeKey }} # Access raw machine params (no profile resolution)
DRP templates include the full Sprig function library. Use the dig function to safely navigate nested maps with a default value rather than risking a nil dereference:
{{/* Safely retrieve a nested key with a default */}}
{{ dig "network" "gateway" "192.168.1.1" (.Param "site/network-config") }}
Standard Go template functions are also available: range, if, with, index, len, printf, and, or, not, and all text/template built-ins.
Example: Rendering Machine-Specific Configuration¶
The following task template renders an NTP configuration file using parameters resolved for the target machine:
#!/bin/bash
# Rendered by DRP for machine: {{ .Machine.Name }}
# This script configures NTP on the target machine.
cat > /etc/chrony.conf <<EOF
{{ range (.Param "ntp/servers") -}}
server {{ . }} iburst
{{ end -}}
driftfile /var/lib/chrony/drift
EOF
systemctl enable chronyd
systemctl restart chronyd
The range loop iterates over the ntp/servers parameter (a list of strings). The - after {{ and before }} trims surrounding whitespace from the rendered output.
Conditional Rendering Based on Parameters¶
Use if and with to conditionally include configuration:
#!/bin/bash
# Configure DNS search domain if set
{{ if .ParamExists "dns/search-domain" -}}
echo "search {{ .Param "dns/search-domain" }}" >> /etc/resolv.conf
{{ end -}}
{{ range (.Param "dns/servers") -}}
echo "nameserver {{ . }}" >> /etc/resolv.conf
{{ end -}}
Troubleshooting Rendering¶
When a template fails to render, the error is captured in the job log with a line number referencing the template source. Common issues:
- Missing required parameter: The template references
.Param "name"but the parameter is not set on the machine or any attached profile. Checkdrpcli machines show <uuid> | jq .Paramsand verify the parameter is present. - Type mismatch: A template expects a list (
range) but the parameter is a string. Check the parameter schema withdrpcli params show <name>. - Nil dereference: Accessing a sub-field on a nil value (e.g.,
.Machine.Params.SomeKeywhenSomeKeyis not set) causes a render failure. Use{{ if .ParamExists "key" }}guards.
To test rendering without running the task, create a job and inspect the rendered actions:
# Create a job for the machine's current task
JOB=$(drpcli jobs create <machine-uuid> | jq -r .UUID)
# See the rendered scripts that would execute
drpcli jobs actions $JOB