docs: plan — relocate platform IaC to fxhnt, archive foxhunt (Phase 2D), inline+gated

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
jgrusewski
2026-06-21 18:14:58 +02:00
parent b017daf04b
commit ffc83da643

View File

@@ -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/<module>` 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 <noreply@anthropic.com>"
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