Bash Task Authoring¶
Shebang and Prelude¶
- Always start with
#!/usr/bin/env bash - Include
{{ template "prelude.tmpl" . }}— this is the standard prelude (NOTsetup.tmplwhich is deprecated) - prelude.tmpl provides:
set -e -o pipefail -o errexit,shopt -s nullglob extglob globstar, DEBIAN_FRONTEND=noninteractive, LC_ALL=C, PS4 debug formatting - Environment vars set by prelude: RS_MC_ROLE, RS_MC_TYPE, RS_MC_NAME
- Debug support: if
rs-debug-enableparam is true,set -xis activated (unlesssecurity/debug-blockoverrides) - Exit helpers:
__exit(),exit_incomplete(),exit_reboot(),exit_shutdown(),exit_stop(),exit_incomplete_reboot(),exit_incomplete_shutdown() job_fail()for fatal errors (prints message and exits 1);job_error()for non-fatal error loggingxiterr()— deprecated, usejob_failinstead- Architecture detection:
$arch(amd64/arm64/ppc64le) - OS detection:
$OS_TYPE,$OS_VER,$OS_FAMILY,$OS_NAME,$osfamily,$osversion - Package management:
install(),install_lookup(),clean_pkg()— cross-distro package installation - Service management:
service()— handles systemd, sysv, upstart - Path management:
fixup_path() - Parameter helpers:
get_param "name",set_param "name" "value" - jq/drpjq symlinks created automatically
Environment Variables¶
$RS_UUID— Current machine UUID (set by agent)$RS_TOKEN— Authentication token (set by agent)$RS_ENDPOINT— DRP API endpoint URL (set by agent)$RS_MC_ROLE— Machine role from metadata (set by prelude)$RS_MC_TYPE— Machine type parameter (set by prelude)$RS_MC_NAME— Machine name (set by prelude)$RS_WORKORDER_UUID— Work order UUID (when running in work order context)$RS_TASK— Current task name$RS_TASK_DIR— Task working directory$RS_DEBUG_ENABLE— Set to "true" when debugging enabled
Error Handling Patterns¶
- prelude.tmpl already sets
set -e -o pipefail— any command failure exits - For commands that may legitimately fail:
command || true - For custom error messages:
command || job_fail "Failed to do X" job_fatalandxiterrare deprecated — usejob_failinstead-
Trap pattern for cleanup:
Common Patterns¶
- Machine update:
drpcli machines update $RS_UUID '{"Description": "configured"}' - Profile param set:
drpcli profiles set $PROFILE param "key" to "value" - Runtime param read:
get_param "param-name"(simple, no--decode/--compose) ordrpcli machines get $RS_UUID param "param-name"(full API; returns JSON — use| jq -r .for raw strings) - JSON parsing with jq:
VALUE=$(drpcli machines show $RS_UUID | jq -r '.Address') - Package install:
install curl wget jq(uses prelude's cross-distro installer) -
Conditional param:
-
Posting events:
Complete Example¶
The following shows a full task YAML with all best practices:
---
Name: "example-configure-service"
Description: "Install and configure an example service"
Documentation: |
Installs the example-svc package and configures it based on
DRP parameters. Idempotent: skips installation if already present.
Requires the `example/config-url` parameter to be set.
RequiredParams:
- example/config-url
OptionalParams:
- example/service-port # Defined with default: 8080
- rs-debug-enable
Meta:
icon: "cogs"
color: "blue"
title: "Example Content"
feature-flags: "sane-exit-codes"
Templates:
- Name: "example-configure-service.sh"
Meta:
OS: "linux"
Contents: |
#!/usr/bin/env bash
{{ template "prelude.tmpl" . }}
CONFIG_URL="{{ .Param "example/config-url" }}"
# example/service-port has a default of 8080 in its param definition,
# so no ParamExists check is needed here.
PORT="{{ .Param "example/service-port" }}"
# Idempotency check
if command -v example-svc &>/dev/null; then
job_info "example-svc already installed, checking config..."
else
job_info "Installing example-svc..."
install example-svc
fi
# Configure the service
job_info "Configuring example-svc with URL=$CONFIG_URL port=$PORT"
cat > /etc/example-svc/config.yaml <<CONF
url: $CONFIG_URL
port: $PORT
CONF
# Enable and start
service example-svc enable
service example-svc restart
# job_success prints the message and exits 0
job_success "example-svc configured and running on port $PORT"