--- name: felhom-build-deploy description: Build, deploy, publish, or verify ANY Felhom artifact — felhom-controller image (guest 9201 bootstrap deploy), felhom-agent binary (felhom-pve), felhom-hub (GitOps/ArgoCD), the felhom.eu website (git-sync), or the app catalog. Use whenever the task says build, deploy, ship, release, publish, bump version, restart the controller/agent/hub, or verify what version is live. Contains the exact verified commands and the gotchas that silently break deploys. --- # Felhom build & deploy runbooks All repos live in `E:\git\` (Git Bash: `/e/git/`). Trunk-based: commit+push to `main` first, always. Update the repo's `CHANGELOG.md` (+ `REUSE.md` if a shared helper changed) in the same commit. ## Session invariants (set once, every session) ```bash SSH=/c/Windows/System32/OpenSSH/ssh.exe # Git Bash's /usr/bin/ssh can't reach the Windows agent — fails silently export MSYS_NO_PATHCONV=1 # before any ssh felhom-pve command with absolute paths (pct etc.) ``` | Host | Access | Role | |---|---|---| | Build server (k3s) | `$SSH kisfenyo@192.168.0.180` | build+push images/binaries (`~/build/felhom-{controller,hub,agent}`), `sudo kubectl` | | Demo Proxmox host | `$SSH felhom-pve` (root@192.168.0.162) | agent deploy, `pct` into guests | | Demo guest 9201 | via `pct exec 9201 -- bash -c '...'` on felhom-pve | the live controller | | felhotest (legacy) | `$SSH -p 33022 kisfenyo@router.abonet.hu` | OLD /opt/docker compose mechanism — not the 9201 flow | Version bumps are ldflags-only (`-X main.version` / `-X main.Version`) — build scripts inject them; no source edit. ## Controller (felhom-controller → guest 9201) 9201 is golden/bootstrap-managed — **NO compose file**. `felhom-controller-bootstrap.service` docker-runs the tag written in `/etc/felhom-controller-image` (anonymous Gitea pull). Data volume + encryption key persist. ```bash # 1. commit+push the repo # 2. build+push image (build.sh does NOT git-pull — the explicit pull is load-bearing) $SSH kisfenyo@192.168.0.180 "cd ~/build/felhom-controller && git -C ~/git/felhom-controller pull && ./build.sh --push" # 3. deploy in the guest $SSH felhom-pve "pct exec 9201 -- bash -c 'docker pull gitea.dooplex.hu/admin/felhom-controller: && echo gitea.dooplex.hu/admin/felhom-controller: > /etc/felhom-controller-image && systemctl restart felhom-controller-bootstrap.service'" # 4. verify $SSH felhom-pve "pct exec 9201 -- docker ps --filter name=felhom-controller --format '{{.Image}} {{.Status}}'" ``` Check current live version first: same `docker ps` command, or `cat /etc/felhom-controller-image`. ## Agent (felhom-agent → felhom-pve) Runs as the NON-ROOT `felhom-agent` user: `/usr/local/bin/felhom-agent --config /etc/felhom-agent/agent.json` (systemd `felhom-agent.service`). Sudoers allowlist at `/etc/sudoers.d/felhom-agent`. ```bash # build on 180 (pull first!) $SSH kisfenyo@192.168.0.180 "cd ~/git/felhom-agent && git pull && go build -ldflags '-X main.version=' -o /tmp/felhom-agent- ./cmd/felhom-agent" # fetch to local, then push to the PVE host (Windows scp needs cygpath -w for the LOCAL path) scp kisfenyo@192.168.0.180:/tmp/felhom-agent- "$(cygpath -w /tmp/felhom-agent-)" scp "$(cygpath -w /tmp/felhom-agent-)" felhom-pve:/tmp/ # install with backup + restart $SSH felhom-pve "cp /usr/local/bin/felhom-agent /usr/local/bin/felhom-agent.bak-\$(/usr/local/bin/felhom-agent --version | awk '{print \$2}') && install -m0755 /tmp/felhom-agent- /usr/local/bin/felhom-agent && systemctl restart felhom-agent && sleep 3 && /usr/local/bin/felhom-agent --version && journalctl -u felhom-agent -n 20 --no-pager" ``` **Ship the sudoers + guarded-mkfs wrapper WITH the binary whenever `configs/` changed** — several Go guards exist only if the deployed sudoers/wrapper match the binary (globs must match `stageTemp` patterns). Beware CRLF when scp-ing config files through Windows. After restart, check the journal for a clean `ReassertGuestBinds` and no capability-probe degradations. Publish to Gitea (so Day-0 self-install can fetch it): `scripts/publish-agent.sh ` with `REGISTRY_*` creds. The hub's Day-0 artifact manifest must then vouch the new version — that UI is operator-password-gated (CC cannot); flag it as an operator follow-up. ## Hub (felhom.eu/hub → k3s, GitOps via ArgoCD app `felhom`) **The manifest is the truth.** A code push + image build deploys NOTHING until `manifests/hub.yaml`'s `image:` tag changes in git AND the app is synced (auto-sync is OFF). Never `kubectl set image` (reverted on next sync), never `:latest`. The live image can lag the CHANGELOG — reconcile via the manifest. ```bash # 1. commit+push code 2. build+push image $SSH kisfenyo@192.168.0.180 "cd ~/build/felhom-hub && ./build.sh --push" # 3. bump manifests/hub.yaml image tag → , commit, push # 4. hard-refresh + sync (argocd CLI on 180 is not logged in — drive the Application CR) $SSH kisfenyo@192.168.0.180 "sudo kubectl -n argocd annotate application felhom argocd.argoproj.io/refresh=hard --overwrite; sleep 8; sudo kubectl -n argocd get application felhom -o jsonpath='{.status.sync.status} {.status.sync.revision}{\"\n\"}'" $SSH kisfenyo@192.168.0.180 "sudo kubectl -n argocd patch application felhom --type merge -p '{\"operation\":{\"initiatedBy\":{\"username\":\"cc\"},\"sync\":{\"syncStrategy\":{\"apply\":{}}}}}'" # 5. verify: Synced/Healthy + rollout + image tag + startup log $SSH kisfenyo@192.168.0.180 "sudo kubectl -n argocd get application felhom -o jsonpath='sync={.status.sync.status} health={.status.health.status}{\"\n\"}'; sudo kubectl -n felhom-system rollout status deploy/hub --timeout=90s; sudo kubectl -n felhom-system get deploy hub -o jsonpath='{.spec.template.spec.containers[0].image}'; echo; sudo kubectl -n felhom-system logs -l app=hub --tail 10" ``` Green gate before any hub commit: `go build ./... && go vet ./... && go test ./...` in `hub/`. ## Website (felhom.eu/website) Push to `main` = deployed (git-sync sidecar, live in ~1–2 min). **Run `python scripts/site_gates.py` first, after ANY website change** (BOM, emoji, nav parity, cache-bust `?v=N` — bump it when css/svg change). New pages must be added to the script's `PAGES` list. Emergency edits: https://files.felhom.eu. ## App catalog (app-catalog-felhom.eu) Push to `main` = deploy: the controller's git-sync picks it up within 15 min, or trigger via the dashboard "Sablonok frissítése" button / `POST /api/sync` (30s debounce). Only `docker-compose.yml` + `.felhom.yml` sync; deployed `app.yaml` is never overwritten. Conventions: `/REUSE.md`. ## Other k8s manifests (felhom.eu/manifests) Same GitOps rule as the hub: edit in git, push, deliberate ArgoCD sync of app `felhom`. Never `kubectl apply` directly. Secrets: out-of-band `kubectl create secret` + `secretKeyRef` — never inline `stringData` (see felhom.eu/REUSE.md §3).