From ffc83da6439ab76da19f2769a8ad9d34ee5f66a7 Mon Sep 17 00:00:00 2001 From: jgrusewski Date: Sun, 21 Jun 2026 18:14:58 +0200 Subject: [PATCH] =?UTF-8?q?docs:=20plan=20=E2=80=94=20relocate=20platform?= =?UTF-8?q?=20IaC=20to=20fxhnt,=20archive=20foxhunt=20(Phase=202D),=20inli?= =?UTF-8?q?ne+gated?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 --- .../plans/2026-06-21-relocate-iac-to-fxhnt.md | 206 ++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 docs/superpowers/plans/2026-06-21-relocate-iac-to-fxhnt.md diff --git a/docs/superpowers/plans/2026-06-21-relocate-iac-to-fxhnt.md b/docs/superpowers/plans/2026-06-21-relocate-iac-to-fxhnt.md new file mode 100644 index 000000000..78cb4d35a --- /dev/null +++ b/docs/superpowers/plans/2026-06-21-relocate-iac-to-fxhnt.md @@ -0,0 +1,206 @@ +# Relocate Platform IaC foxhunt → fxhnt + Archive foxhunt — Implementation Plan (Phase 2D) + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans (INLINE, with checkpoints). +> Spans TWO repos + a production Terraform state gate; the `terragrunt plan = No changes` check is the +> safety pin. Steps use checkbox (`- [ ]`) syntax. + +**Goal:** Move active platform IaC (terraform `live`+`modules`, platform k8s manifests) from `foxhunt` +into `fxhnt`, preserving TF state keys (no migration), then archive `foxhunt`. + +**Architecture:** Copy into fxhnt preserving the `live/production/` structure → state keys stay +identical → `terragrunt plan = No changes` proves it. Then `git rm` from foxhunt, commit/push both, +archive foxhunt. Cluster untouched throughout (source-of-truth move only). + +**Tech Stack:** terragrunt + OpenTofu (Scaleway s3 backend), kubectl manifests, git, Gitea. + +**Repos:** source `~/Work/foxhunt`, dest `~/Work/fxhnt`. **Spec:** +`docs/superpowers/specs/2026-06-21-relocate-iac-to-fxhnt-design.md` + +--- + +## Shared env (terragrunt steps) +```bash +export TG_TF_PATH=tofu TERRAGRUNT_TFPATH=tofu +export SCW_ACCESS_KEY=$(kubectl get secret scaleway-credentials -n foxhunt -o jsonpath='{.data.access-key}'|base64 -d) +export SCW_SECRET_KEY=$(kubectl get secret scaleway-credentials -n foxhunt -o jsonpath='{.data.secret-key}'|base64 -d) +export SCW_DEFAULT_PROJECT_ID=$(kubectl get secret scaleway-credentials -n foxhunt -o jsonpath='{.data.project-id}'|base64 -d) +export SCW_DEFAULT_REGION=fr-par SCW_DEFAULT_ZONE=fr-par-2 +export AWS_ACCESS_KEY_ID="$SCW_ACCESS_KEY" AWS_SECRET_ACCESS_KEY="$SCW_SECRET_KEY" AWS_REGION=fr-par +``` + +--- + +## Task 0: Branches +```bash +cd /home/jgrusewski/Work/fxhnt && git checkout master && git checkout -b chore/relocate-iac +cd /home/jgrusewski/Work/foxhunt && git checkout main && git checkout -b chore/relocate-iac-remove +``` + +--- + +## Task 1: Collision pre-flight (must be empty) +```bash +cd /home/jgrusewski/Work/foxhunt +for d in k8s/network-policies k8s/services k8s/jobs k8s/storage; do + echo "--- $d ---"; comm -12 <(ls infra/$d 2>/dev/null|sort) <(ls ~/Work/fxhnt/infra/$d 2>/dev/null|sort) +done +``` +Expected: no filenames printed. **STOP + resolve if any collision appears.** + +--- + +## Task 2: Copy Terraform (live + modules) into fxhnt, structure preserved + +- [ ] **Step 1: rsync source files (exclude generated/cached, keep .terraform.lock.hcl)** +```bash +cd /home/jgrusewski/Work/foxhunt +rsync -a --exclude '.terraform/' --exclude 'backend.tf' --exclude 'provider.tf' --exclude '*.tfstate*' \ + infra/live infra/modules /home/jgrusewski/Work/fxhnt/infra/ +find /home/jgrusewski/Work/fxhnt/infra/live /home/jgrusewski/Work/fxhnt/infra/modules -name '*.hcl' -o -name '*.tf' | sort +``` +Expected: `fxhnt/infra/live/production/{root.hcl,kapsule,public-gateway,dns,block-storage}` + +`fxhnt/infra/modules/{kapsule,public-gateway,dns,block-storage}` present. + +- [ ] **Step 2: Ensure fxhnt .gitignore covers terragrunt-generated files** +```bash +cd /home/jgrusewski/Work/fxhnt +grep -qE '^backend\.tf' .gitignore || printf '\n# terragrunt-generated\n**/.terraform/\n**/backend.tf\n**/provider.tf\n*.tfstate\n*.tfstate.*\n' >> .gitignore +tail -7 .gitignore +``` + +- [ ] **Step 3: GATE — terragrunt plan = No changes for all 4 modules (from fxhnt)** +```bash +cd /home/jgrusewski/Work/fxhnt +for m in kapsule public-gateway dns block-storage; do + echo "=== $m ===" + ( cd infra/live/production/$m && terragrunt init -reconfigure -input=false -no-color >/dev/null 2>&1 && \ + terragrunt plan -input=false -no-color 2>&1 | sed 's/.*tofu: //' | grep -iE "No changes|^Plan:|Error" | head -1 ) +done +``` +Expected: every module prints `No changes.` — proves state keys are unchanged (no migration). **STOP if any +module shows a plan diff or Error** (structure not preserved → do not proceed). + +--- + +## Task 3: Copy platform k8s manifests + the one platform script into fxhnt + +- [ ] **Step 1: rsync platform k8s dirs (everything except gpu-taint.yaml) + namespace.yaml** +```bash +cd /home/jgrusewski/Work/foxhunt +for d in argo cert-manager databases dns gitea gitlab jobs mattermost minio monitoring network-policies secrets services stalwart tailscale training storage; do + rsync -a "infra/k8s/$d" /home/jgrusewski/Work/fxhnt/infra/k8s/ +done +cp infra/k8s/namespace.yaml /home/jgrusewski/Work/fxhnt/infra/k8s/ +mkdir -p /home/jgrusewski/Work/fxhnt/infra/scripts && cp infra/scripts/generate-minio-tls.sh /home/jgrusewski/Work/fxhnt/infra/scripts/ +echo "=== fxhnt infra/k8s now ==="; ls /home/jgrusewski/Work/fxhnt/infra/k8s/ +``` +Expected: fxhnt/infra/k8s/ now contains the platform dirs (merged with fxhnt's existing +jobs/network-policies/services/storage/orchestration) + namespace.yaml. `gpu-taint.yaml` NOT copied. + +- [ ] **Step 2: Sanity — no remaining hardcoded foxhunt-repo paths in moved manifests** +```bash +cd /home/jgrusewski/Work/fxhnt +grep -rIn "Work/foxhunt\|foxhunt/infra\|root/foxhunt" infra/k8s/ infra/live/ infra/modules/ 2>/dev/null | grep -v "foxhunt.svc.cluster.local\|namespace: foxhunt\|name: foxhunt\|cluster_name\|foxhunt-tfstate\|foxhunt-gitlab\|foxhunt-training\|foxhunt-backups\|foxhunt-sccache\|foxhunt-binaries\|foxhunt-agent" | head +echo "(above should be empty — 'foxhunt' as the k8s namespace / SCW resource names is expected + correct)" +``` +Expected: empty (the namespace `foxhunt` + Scaleway resource names legitimately stay). + +--- + +## Task 4: Verify cluster unaffected + cockpit still deploys from fxhnt + +- [ ] **Step 1: terragrunt still clean from fxhnt + platform health** +```bash +cd /home/jgrusewski/Work/fxhnt +curl -sk -m 10 -o /dev/null -w "dashboard.fxhnt.ai: %{http_code}\n" https://dashboard.fxhnt.ai +curl -sk -m 10 https://git.fxhnt.ai/api/healthz 2>/dev/null | grep -o '"status": "pass"' +``` +Expected: dashboard 200; gitea pass. (No cluster change was made — this confirms nothing regressed.) + +--- + +## Task 5: Commit fxhnt (additions) + push + +- [ ] **Step 1** +```bash +cd /home/jgrusewski/Work/fxhnt +git add infra/ .gitignore +git commit -m "feat(infra): adopt platform IaC from foxhunt — terraform live+modules + k8s manifests (Phase 2D) + +fxhnt is now the single home for platform IaC. Terraform state keys unchanged +(live/production structure preserved) — terragrunt plan = No changes, no migration. +Includes k8s platform manifests (cert-manager, databases, dns, gitea, minio, monitoring, +network-policies, tailscale, stalwart, mattermost, services, storage, jobs, training, +secrets, argo, gitlab proxy) + generate-minio-tls.sh. + +Co-Authored-By: Claude Opus 4.8 " +GIT_SSH_COMMAND="ssh -o StrictHostKeyChecking=accept-new" git push origin chore/relocate-iac 2>&1 | tail -2 +``` + +--- + +## Task 6: Remove the moved paths from foxhunt + commit + push + +- [ ] **Step 1: git rm the relocated IaC from foxhunt (keep gpu-taint.yaml, docker, Rust scripts)** +```bash +cd /home/jgrusewski/Work/foxhunt +git rm -r -q infra/live infra/modules +for d in argo cert-manager databases dns gitea gitlab jobs mattermost minio monitoring network-policies secrets services stalwart tailscale training storage; do git rm -r -q "infra/k8s/$d"; done +git rm -q infra/k8s/namespace.yaml infra/scripts/generate-minio-tls.sh +echo "=== foxhunt infra/ remnant (Rust-only) ==="; find infra -maxdepth 2 | sort | head -30 +``` +Expected: `infra/k8s/gpu-taint.yaml` + `infra/docker/*` + `infra/scripts/{build-and-push,harden,smoke-test,train,...}` remain; live/modules + platform k8s gone. + +- [ ] **Step 2: Commit + push foxhunt** +```bash +cd /home/jgrusewski/Work/foxhunt +git commit -q -m "chore(infra): relocate platform IaC to fxhnt (Phase 2D) + +Platform terraform (live+modules) + k8s manifests moved to the fxhnt repo (now the IaC +home). Rust-only remnants kept here (docker build images, gpu-taint, Rust scripts). +foxhunt is being archived; history retained. See fxhnt for live platform IaC." +GIT_SSH_COMMAND="ssh -o StrictHostKeyChecking=accept-new" git push origin chore/relocate-iac-remove 2>&1 | tail -2 +``` + +--- + +## Task 7: Merge both branches, then archive foxhunt + +- [ ] **Step 1: Merge fxhnt branch → master + push** +```bash +cd /home/jgrusewski/Work/fxhnt +git checkout master && git merge --no-ff chore/relocate-iac -m "Merge: adopt platform IaC from foxhunt (Phase 2D)" 2>&1 | tail -2 +git branch -d chore/relocate-iac +GIT_SSH_COMMAND="ssh -o StrictHostKeyChecking=accept-new" git push origin master 2>&1 | tail -1 +``` + +- [ ] **Step 2: Merge foxhunt branch → main + push** +```bash +cd /home/jgrusewski/Work/foxhunt +git checkout main && git merge --no-ff chore/relocate-iac-remove -m "Merge: relocate platform IaC to fxhnt (Phase 2D)" 2>&1 | tail -2 +git branch -d chore/relocate-iac-remove +GIT_SSH_COMMAND="ssh -o StrictHostKeyChecking=accept-new" git push origin main 2>&1 | tail -1 +``` + +- [ ] **Step 3: Final re-verify terragrunt from fxhnt (post-merge) + archive foxhunt in Gitea** +```bash +cd /home/jgrusewski/Work/fxhnt +( cd infra/live/production/kapsule && terragrunt plan -input=false -no-color 2>&1 | sed 's/.*tofu: //' | grep -iE "No changes|^Plan:" | head -1 ) +GA=gitadmin; GP=$(kubectl get secret gitea-admin -n foxhunt -o jsonpath='{.data.password}'|base64 -d) +curl -sk -u "$GA:$GP" -X PATCH "https://git.fxhnt.ai/api/v1/repos/$GA/foxhunt" -H 'Content-Type: application/json' -d '{"archived":true}' -o /dev/null -w "archive foxhunt: %{http_code}\n" +``` +Expected: kapsule `No changes`; `archive foxhunt: 200`. + +--- + +## Rollback +- Before Task 6 (foxhunt rm): just delete `fxhnt/infra/{live,modules}` + the copied k8s dirs; nothing lost + (foxhunt still authoritative). +- After: both repos retain history; un-archive foxhunt + `git revert` if needed. TF state never moved. + +## Acceptance criteria (from spec) +- `fxhnt/infra/{live,modules}` present; `terragrunt plan = No changes` all 4 modules from fxhnt. ✅ T2, T7 +- Platform k8s manifests + generate-minio-tls.sh in fxhnt; no collisions lost. ✅ T1, T3 +- Moved paths `git rm`'d from foxhunt; both repos committed + pushed. ✅ T5, T6, T7 +- dashboard 200 + cockpit deploy unaffected. ✅ T4 +- foxhunt archived in Gitea; Rust code + history intact. ✅ T7