test: cover machine template registry
This commit is contained in:
parent
587a44617b
commit
88e59b6ec8
5 changed files with 106 additions and 8 deletions
28
README.md
28
README.md
|
|
@ -401,6 +401,34 @@ unattended VM-host appliance) — and `workstation` is the machine at the keyboa
|
|||
end of all the SSH connections: `root-door=closed`, `join=login`, entering the
|
||||
tailnet as *your* device rather than the fleet's.
|
||||
|
||||
### Machine-role templates
|
||||
|
||||
Machine presets can also live in the
|
||||
[heavy-duty/rig-templates](https://github.com/heavy-duty/rig-templates)
|
||||
registry. A `*-server` directory is a fleet-machine definition; the exact
|
||||
name `workstation` is the deliberate suffix-less exception. Its
|
||||
`template.env` contains exactly the three traits bootstrap's built-in table
|
||||
uses:
|
||||
|
||||
```dotenv
|
||||
ROOT_DOOR="open" # open|closed
|
||||
HOST="no" # yes|no
|
||||
JOIN="authkey" # authkey|login
|
||||
```
|
||||
|
||||
An `install.sh` is optional. When present, bootstrap runs it as root,
|
||||
non-interactively, from the definition directory with `RIG_ROLE` set, after
|
||||
the tailnet join, host setup, role marker prerequisites, and operator
|
||||
convergence. A nonzero exit fails bootstrap and names the role and registry
|
||||
source. The definition owns idempotence, just as bootstrap does.
|
||||
|
||||
Built-in roles and `custom` take precedence over registry names. Any other
|
||||
non-tenant role is looked up in the resolved registry; the same three source
|
||||
knobs below apply, including `RIG_TEMPLATES_DIR` for an offline local
|
||||
definition. Pin reviewed registry content into rig's tree before using it on
|
||||
fleet machines: an optional machine `install.sh` executes as root on metal,
|
||||
and an override is the operator explicitly choosing a different trust root.
|
||||
|
||||
### `rig bootstrap <role>-box` — the box tenants
|
||||
|
||||
Run as root, **inside** a [box](https://github.com/heavy-duty/box)-minted
|
||||
|
|
|
|||
1
changelog.d/152.md
Normal file
1
changelog.d/152.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
Machine-role templates can declare bootstrap traits and an optional final root install hook (#152)
|
||||
|
|
@ -144,7 +144,8 @@ case "$ROLE" in
|
|||
templates_resolve || exit 2
|
||||
trap '[ -n "$TEMPLATES_TMP" ] && rm -rf "$TEMPLATES_TMP"' EXIT
|
||||
MACHINE_TEMPLATE_DIR="$REGISTRY_DIR/$ROLE"
|
||||
if [ "$(template_family "$ROLE" 2>/dev/null || true)" != "machine" ] \
|
||||
if { [ "$ROLE" != "workstation" ] && [[ ! "$ROLE" =~ ^[a-z][a-z0-9-]*-server$ ]]; } \
|
||||
|| [ "$(template_family "$ROLE" 2>/dev/null || true)" != "machine" ] \
|
||||
|| [ ! -f "$MACHINE_TEMPLATE_DIR/template.env" ]; then
|
||||
MACHINE_ROLES="$(templates_machine_roles "$REGISTRY_DIR" | paste -sd'|' -)"
|
||||
[ -n "$MACHINE_ROLES" ] || MACHINE_ROLES="none"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#!/usr/bin/env bash
|
||||
# rig template-lint <role-dir>... — is this a valid tenant-role definition?
|
||||
# rig template-lint <role-dir>... — is this a valid role definition?
|
||||
#
|
||||
# rig defines what a valid template is (the schema lives in
|
||||
# lib/templates.sh, beside the mint-time parser that enforces it); the
|
||||
|
|
@ -23,12 +23,15 @@ usage() {
|
|||
cat <<'EOF'
|
||||
usage: rig template-lint <role-dir>...
|
||||
|
||||
Validate tenant-role definitions (the heavy-duty/rig-templates shape):
|
||||
each <role-dir> must carry a family-suffixed name (rig#76), a template.env
|
||||
that parses against the allowlist (KEY="value" only — the file is data,
|
||||
never sourced), an install.sh with a shebang, and a non-blank creds.md.
|
||||
Every refusal names the failing key or file. Exits non-zero if any
|
||||
definition fails; nothing is written.
|
||||
Validate role definitions (the heavy-duty/rig-templates shape).
|
||||
|
||||
Tenant roles use a *-box directory, tenant template.env schema, a shebang
|
||||
install.sh, and non-blank creds.md. Machine roles use a *-server directory
|
||||
(or exact name workstation), the ROOT_DOOR/HOST/JOIN schema, no creds.md,
|
||||
and an optional install.sh which must be non-empty and carry a shebang.
|
||||
template.env is parsed as KEY="value" data and never sourced. Every refusal
|
||||
names the failing key or file. Exits non-zero if any definition fails;
|
||||
nothing is written.
|
||||
EOF
|
||||
}
|
||||
|
||||
|
|
|
|||
65
test/cli.sh
65
test/cli.sh
|
|
@ -613,6 +613,25 @@ mkdir -p "$TPL_FIX/badnode-box"
|
|||
printf 'USER="x"\nCONTEXT_PATH=".x/A.md"\nCLI_NAME="x"\nPATH_LINE="p"\nNEEDS_NODE="maybe"\n' > "$TPL_FIX/badnode-box/template.env"
|
||||
mkdir -p "$TPL_FIX/badapt-box"
|
||||
printf 'USER="x"\nCONTEXT_PATH=".x/A.md"\nCLI_NAME="x"\nPATH_LINE="p"\nAPT_EXTRAS="zsh -o"\n' > "$TPL_FIX/badapt-box/template.env"
|
||||
mkdir -p "$TPL_FIX/scratch-server"
|
||||
printf 'ROOT_DOOR="closed"\nHOST="no"\nJOIN="login"\n' > "$TPL_FIX/scratch-server/template.env"
|
||||
mkdir -p "$TPL_FIX/workstation"
|
||||
printf 'ROOT_DOOR="closed"\nHOST="yes"\nJOIN="login"\n' > "$TPL_FIX/workstation/template.env"
|
||||
mkdir -p "$TPL_FIX/hooked-server"
|
||||
printf 'ROOT_DOOR="open"\nHOST="no"\nJOIN="authkey"\n' > "$TPL_FIX/hooked-server/template.env"
|
||||
printf '#!/usr/bin/env bash\nexit 1\n' > "$TPL_FIX/hooked-server/install.sh"
|
||||
mkdir -p "$TPL_FIX/baddoor-server"
|
||||
printf 'ROOT_DOOR="ajar"\nHOST="no"\nJOIN="authkey"\n' > "$TPL_FIX/baddoor-server/template.env"
|
||||
mkdir -p "$TPL_FIX/tenantkeys-server"
|
||||
cp "$TPL_FIX/scratch-box/template.env" "$TPL_FIX/tenantkeys-server/template.env"
|
||||
mkdir -p "$TPL_FIX/machinekeys-box"
|
||||
cp "$TPL_FIX/scratch-server/template.env" "$TPL_FIX/machinekeys-box/template.env"
|
||||
mkdir -p "$TPL_FIX/creds-server"
|
||||
cp "$TPL_FIX/scratch-server/template.env" "$TPL_FIX/creds-server/template.env"
|
||||
printf 'not used\n' > "$TPL_FIX/creds-server/creds.md"
|
||||
mkdir -p "$TPL_FIX/noshebang-server"
|
||||
cp "$TPL_FIX/scratch-server/template.env" "$TPL_FIX/noshebang-server/template.env"
|
||||
printf 'exit 0\n' > "$TPL_FIX/noshebang-server/install.sh"
|
||||
|
||||
# THE HARD CUT, tenant half (#76). The pre-rename names are gone and must fail
|
||||
# as UNKNOWN — asserted per name, because an alias left in for one tenant is the
|
||||
|
|
@ -653,6 +672,28 @@ check "bootstrap: tenant roles dispatch through bootstrap.sh" 0 "Box TENANT role
|
|||
check "bootstrap: an unheard-of '-box' role still dispatches (zero code changes)" 0 "Box TENANT roles" \
|
||||
"$ROOT/commands/bootstrap.sh" scratch-box --help
|
||||
|
||||
# Machine roles use the same resolved registry but remain table-compatible:
|
||||
# loading happens before flag parsing, so an explicit flag overrides the
|
||||
# definition exactly as it overrides a built-in row.
|
||||
check "machine template: traits load from the local registry" 2 "join=login" \
|
||||
env RIG_TEMPLATES_DIR="$TPL_FIX" TS_AUTHKEY=x \
|
||||
"$ROOT/commands/bootstrap.sh" scratch-server --no-users
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
check "machine template: a flag overrides the loaded trait" 1 "must run as root" \
|
||||
env RIG_TEMPLATES_DIR="$TPL_FIX" TS_AUTHKEY=x \
|
||||
"$ROOT/commands/bootstrap.sh" scratch-server --no-users --join authkey
|
||||
fi
|
||||
check "machine template: invalid ROOT_DOOR is refused by key" 2 "ROOT_DOOR" \
|
||||
env RIG_TEMPLATES_DIR="$TPL_FIX" \
|
||||
"$ROOT/commands/bootstrap.sh" baddoor-server --no-users
|
||||
check "machine template: unknown role lists machine definitions" 2 "scratch-server" \
|
||||
env RIG_TEMPLATES_DIR="$TPL_FIX" "$ROOT/commands/bootstrap.sh" absent-server
|
||||
check "machine template: unknown role names the resolved source" 2 "RIG_TEMPLATES_DIR" \
|
||||
env RIG_TEMPLATES_DIR="$TPL_FIX" "$ROOT/commands/bootstrap.sh" absent-server
|
||||
check "machine template: a registry role cannot shadow a built-in" 2 "unset TS_AUTHKEY" \
|
||||
env RIG_TEMPLATES_DIR="$TPL_FIX" TS_AUTHKEY=x \
|
||||
"$ROOT/commands/bootstrap.sh" workstation --no-users
|
||||
|
||||
# The tenant marker guard (#83), against marker FIXTURES (never the harness
|
||||
# machine's real /etc/rig/role): converging a tenant onto a machine-role box or a
|
||||
# VM host (host=yes) refuses for every tenant — and names the staging PAIR,
|
||||
|
|
@ -844,6 +885,30 @@ cp "$TPL_FIX/scratch-box/template.env" "$TPL_FIX/scratch-box/creds.md" "$TPL_FIX
|
|||
printf 'exit 0\n' > "$TPL_FIX/noshebang-box/install.sh"
|
||||
check "template-lint: an install.sh without a shebang is refused" 1 "no shebang" \
|
||||
"$ROOT/commands/template-lint.sh" "$TPL_FIX/noshebang-box"
|
||||
check "template-lint: a traits-only machine definition passes" 0 "OK: " \
|
||||
"$ROOT/commands/template-lint.sh" "$TPL_FIX/scratch-server"
|
||||
check "template-lint: workstation is the machine-family carve-out" 0 "OK: " \
|
||||
"$ROOT/commands/template-lint.sh" "$TPL_FIX/workstation"
|
||||
check "template-lint: machine roles refuse tenant keys" 1 "unknown key: USER" \
|
||||
"$ROOT/commands/template-lint.sh" "$TPL_FIX/tenantkeys-server"
|
||||
check "template-lint: tenant roles refuse machine keys" 1 "unknown key: ROOT_DOOR" \
|
||||
"$ROOT/commands/template-lint.sh" "$TPL_FIX/machinekeys-box"
|
||||
check "template-lint: machine roles refuse creds.md" 1 "creds.md is not allowed" \
|
||||
"$ROOT/commands/template-lint.sh" "$TPL_FIX/creds-server"
|
||||
check "template-lint: machine install.sh requires a shebang" 1 "no shebang" \
|
||||
"$ROOT/commands/template-lint.sh" "$TPL_FIX/noshebang-server"
|
||||
# The install is deliberately after the users phase and its wrapper names both
|
||||
# role and source. Dynamic execution belongs to the root integration path; the
|
||||
# non-root offline harness pins the safety ordering and failure contract.
|
||||
machine_hook_at="$(grep -n 'running install hook for' "$ROOT/commands/bootstrap.sh" | head -n1 | cut -d: -f1)"
|
||||
check "machine template: install hook is bootstrap's last convergence phase" 0 "" \
|
||||
test "${users_apply_at:-999999}" -lt "${machine_hook_at:-0}"
|
||||
# shellcheck disable=SC2016
|
||||
check "machine template: install failure names role and source" 0 "" \
|
||||
grep -qF 'install hook failed for role $ROLE from $(templates_source_desc)' "$ROOT/commands/bootstrap.sh"
|
||||
# shellcheck disable=SC2016
|
||||
check "machine template: install runs from its definition with RIG_ROLE" 0 "" \
|
||||
grep -qF 'cd "$MACHINE_TEMPLATE_DIR" && RIG_ROLE="$ROLE" ./install.sh' "$ROOT/commands/bootstrap.sh"
|
||||
rm -rf "$TPL_FIX" "$TPL_WORK"
|
||||
|
||||
# Creds-free BY CONSTRUCTION, provable by absence (box#69's grep-refusal
|
||||
|
|
|
|||
Loading…
Reference in a new issue