fix(tf/ceph): stop writing rendered inventories via local_file (#155)

local_file stored the destination path in shared remote state, derived from
get_repo_root(). git worktrees each resolve get_repo_root() to their own root,
so state became bound to whichever worktree last applied. Any apply from a
different checkout then force-replaced every rendered file and rebound state.

The module now emits inventory and secrets content as a render output instead
of local_file resources. ansible/ceph/scripts/render-inventories.sh reads that
output and writes the files using a path derived from its own location, so no
checkout-specific path ever enters state.

Also exclude painbox from the managed clusters (in active use by Zack); its
spec moves to clusters.example.tfvars and its 1Password items are left alone.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Andy Molenda
2026-06-24 08:15:46 -07:00
committed by GitHub
co-authored by Claude Opus 4.8
parent 03e2802c06
commit 83dab28c91
10 changed files with 166 additions and 117 deletions
+2 -2
View File
@@ -18,7 +18,7 @@ set -euo pipefail
if [ ! -f "$CEPH_ENV" ]; then
echo "ansible-play.sh: inventory not found: $CEPH_ENV" >&2
echo " Hint: has 'tofu apply' been run in tf/deployment/<env>/ceph/?" >&2
echo " Hint: render it — 'terragrunt apply' in tf/deployment/<env>/ceph/, then scripts/render-inventories.sh <env>." >&2
exit 1
fi
@@ -27,7 +27,7 @@ TEMPLATE="$CEPH_ENV_DIR/secrets.yml.tpl"
if [ ! -f "$TEMPLATE" ]; then
echo "ansible-play.sh: secrets template not found: $TEMPLATE" >&2
echo " Hint: has 'tofu apply' been run in tf/deployment/<env>/ceph/?" >&2
echo " Hint: render it — 'terragrunt apply' in tf/deployment/<env>/ceph/, then scripts/render-inventories.sh <env>." >&2
exit 1
fi
+56
View File
@@ -0,0 +1,56 @@
#!/usr/bin/env bash
# render-inventories.sh — write the TF-rendered Ansible inventories + secrets
# templates into THIS checkout, from the dev/ceph stack's `render` output.
#
# WHY a wrapper instead of tofu `local_file`: local_file records the destination
# path in state. With a shared remote backend that path is checkout-specific, so
# it coupled state to whichever git worktree last applied (get_repo_root()
# resolves per-worktree) — every apply elsewhere then force-replaced the files
# and rebound state. Reading the content from a TF *output* and writing it here,
# with the path derived from THIS script's own location, keeps checkout-specific
# paths out of shared state entirely.
#
# Prereq: `terragrunt apply` has been run for the stack (so the `render` output
# reflects the current cluster spec). This script is read-only against state.
#
# Usage (from anywhere):
# ansible/ceph/scripts/render-inventories.sh [env] # env defaults to dev
set -euo pipefail
ENVIRONMENT="${1:-dev}"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ANSIBLE_CEPH="$(cd "$SCRIPT_DIR/.." && pwd)" # ansible/ceph
REPO_ROOT="$(cd "$ANSIBLE_CEPH/../.." && pwd)" # repo root of THIS checkout
STACK_DIR="$REPO_ROOT/tf/deployment/${ENVIRONMENT}/ceph"
INV_ROOT="$ANSIBLE_CEPH/inventories"
[ -d "$STACK_DIR" ] || {
echo "render-inventories: stack not found: $STACK_DIR" >&2
exit 1
}
# The `render` output is non-sensitive (inventory text + op:// references — no
# raw secrets). Reading state needs the S3 backend creds, so go through the
# op-run wrapper which injects them from tf/.env.
JSON="$(cd "$STACK_DIR" && OP_ENV_FILE="$REPO_ROOT/tf/.env" "$REPO_ROOT/tf/op-run.sh" terragrunt output -json render)"
# JSON travels via env (RENDER_JSON); the heredoc owns python's stdin (the
# program), so we can't also pipe the data in.
RENDER_JSON="$JSON" python3 - "$INV_ROOT" <<'PY'
import json, os, sys
inv_root = sys.argv[1]
data = json.loads(os.environ["RENDER_JSON"])
for cluster, spec in data.items():
d = os.path.join(inv_root, spec["dirname"])
os.makedirs(d, exist_ok=True)
for fname, content in spec["files"].items():
p = os.path.join(d, fname)
with open(p, "w") as fh:
fh.write(content)
os.chmod(p, 0o644)
print(f"wrote {p}")
PY
echo "render-inventories: done (${ENVIRONMENT})."