The deployment shipped its payload but not the thing that installs it.54a5c09added README, knot.conf, knsctl, zone.tmpl, secrets.conf.example, the aliases and the MOTD -- but no deploy.sh, no cloud-init.yml, and no entry in automations.sh's DEPLOYMENTS. `git log --all` confirms deploy.sh was never committed and it is not gitignored, yet README.md:96 and :100 tell the operator to run it. So the documented install path did not exist. Alpine only, native, matching the README: Knot binds :53 directly, needs real client addresses for RRL and cookies, and keeps its DNSSEC key store on the host filesystem. The RHEL packaging needs EPEL, which nothing here sets up, so anything that is not Alpine dies with a clear message rather than half-installing somewhere untested. Three decisions worth recording: The include chain is stubbed. knot.conf include:s seven files the `dns` repo owns; Knot treats a missing include as a config error, so a node the pipeline has never delivered to would fail conf-check and never start. deploy.sh writes a placeholder for each one that is ABSENT -- never over a delivered file -- so the node comes up healthy serving no zones until the pipeline lands. TSIG is generated on a primary and required on a secondary. The keys must match byte for byte, so a secondary that generated its own would authenticate nothing; it now refuses to deploy without TSIG_AUTHORITIVE and TSIG_ADMIN. A primary generates both and prints them once. An existing secrets.conf is never rewritten, so a re-run cannot rotate a key out from under a running estate. PRIMARY_ADDR seeds a minimal remotes.conf on a secondary so it can bootstrap by AXFR before the pipeline runs -- written only when remotes.conf was absent, verified by re-running against a delivered file and confirming it is left untouched. Re-runs apply changes rather than freezing at first deploy, per the pattern this repo just adopted elsewhere: knot.conf is re-rendered from .env every run, env-presence is captured before the ":=" defaults, and values passed to a re-run are written back to .env with the awk-based set_env from947c899-- which matters here because a TSIG secret can contain the characters that broke the sed-based one. Two bugs caught while testing this, before it shipped: - the secrets.conf renderer used `++n` as a gsub argument, which awk evaluates on every line, not just matching ones -- both keys would have received the SAME secret, making the read-only admin key identical to the replication key. Increments on a matching line only now. - the MOTD is a pre-drawn box, so substituting values of a different width than their @TOKEN@ shifted the right border on every login. Values are now padded to the token's span, measured over an ASCII-only region so it holds under busybox awk in the C locale; an over-long value overflows rather than being truncated. Verified: knot.conf renders identity/NSID/listen and leaves the control socket alone; all seven stubs are created on a fresh node and skipped on a re-run; the remotes.conf seed fires only for a fresh secondary; .env seeds every runtime key; the MOTD renders with no leftover tokens and an aligned border. Not verified: apk, knotc and the service start, which need an actual Alpine host. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
46 lines
1017 B
Bash
46 lines
1017 B
Bash
#!/usr/bin/env bash
|
|
#
|
|
# build.sh -- (re)embed knot.conf, secrets.conf.example, knsctl, zone.tmpl,
|
|
# knotdns-aliases.sh, knot-dns.motd and .env.example into deploy.sh as a
|
|
# base64-encoded tar.gz payload after __ARCHIVE_BELOW__. Idempotent: strips any
|
|
# existing payload first.
|
|
|
|
set -euo pipefail
|
|
|
|
DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
|
SCRIPT="$DIR/deploy.sh"
|
|
MARKER="__ARCHIVE_BELOW__"
|
|
|
|
FILES=(
|
|
knot.conf
|
|
secrets.conf.example
|
|
knsctl
|
|
zone.tmpl
|
|
knotdns-aliases.sh
|
|
knot-dns.motd
|
|
.env.example
|
|
)
|
|
|
|
[[ -f "$SCRIPT" ]] || { echo "deploy.sh not found at $SCRIPT" >&2; exit 1; }
|
|
for f in "${FILES[@]}"; do
|
|
[[ -f "$DIR/$f" ]] || { echo "Missing $DIR/$f" >&2; exit 1; }
|
|
done
|
|
|
|
PAYLOAD=$(tar -czf - -C "$DIR" "${FILES[@]}" | base64)
|
|
|
|
TMP=$(mktemp)
|
|
trap 'rm -f "$TMP"' EXIT
|
|
|
|
sed "/^${MARKER}\$/,\$d" "$SCRIPT" > "$TMP"
|
|
{
|
|
echo "$MARKER"
|
|
echo "$PAYLOAD"
|
|
} >> "$TMP"
|
|
|
|
mv "$TMP" "$SCRIPT"
|
|
chmod +x "$SCRIPT"
|
|
trap - EXIT
|
|
|
|
size=$(wc -c < "$SCRIPT")
|
|
echo "Built $SCRIPT (${size} bytes)"
|