docs: v0.83.0 REPORT/CONTEXT/README — scoped Traefik serversTransport for self-signed HTTPS backends
This commit is contained in:
@@ -1,62 +1,67 @@
|
||||
# REPORT — FileBrowser no-op recreate fix (F2) + drop restic binary (F1)
|
||||
# REPORT — Traefik scoped serversTransport for self-signed HTTPS backends (crafty 502 fix)
|
||||
|
||||
**Repo:** `felhom-controller` · **Version:** `v0.81.0` → **`v0.82.0`** · **Date:** 2026-06-24
|
||||
**Baseline:** `main` @ `036a6078b` (CHANGELOG top `v0.81.0`), trunk-based, no branches.
|
||||
**Repo:** `felhom-controller` · **Version:** `v0.82.0` → **`v0.83.0`** · **Date:** 2026-06-26
|
||||
**Commit:** `2d6df0f` · **Paired catalog commit:** `app-catalog-felhom.eu` `1216a8a`
|
||||
**Deployed:** guest 9201 (`demo-felhom`) on `felhom-pve`, golden/bootstrap mechanism.
|
||||
|
||||
Two findings from `TEST-REPORT-stable-path-sysdrive-restart-2026-06-23.md`, both validated at source.
|
||||
## Problem
|
||||
The crafty-controller healthcheck fix (catalog `68ce009`) un-withheld its Traefik route, exposing a
|
||||
pre-existing **502**: Traefik proxied **HTTP** to Crafty's **HTTPS-only** self-signed backend on `:8443`.
|
||||
Crafty is the only catalog app with an HTTPS backend (all others serve plain HTTP, so Traefik's default
|
||||
HTTP transport works for them). In Traefik v3 `insecureSkipVerify` cannot be set via Docker labels — it
|
||||
must live in static/file config — so the fix necessarily touched the controller (which generates the
|
||||
Traefik config), not just the catalog.
|
||||
|
||||
## F2 — gate the FileBrowser recreate on an actual change
|
||||
## Fix (Option B — scoped; verification stays ON by default)
|
||||
A **named** serversTransport, opted into per-service — no global `insecureSkipVerify`.
|
||||
|
||||
**Root cause:** `syncFileBrowserMounts` (`internal/web/handlers.go`) ran
|
||||
`docker compose up -d --force-recreate --remove-orphans` **unconditionally**. The existing
|
||||
`sourcesChanged` flag gated only the restore-mode DB reset (`down -v`); the force-recreate fired on
|
||||
every controller restart and every storage sync even when `config.yaml`/compose were byte-identical —
|
||||
bouncing the customer's file-access UI, contradicting the "Vezérlő újraindítása → apps keep running"
|
||||
promise (the 3.4 reproduction in the test report).
|
||||
- `internal/infra/infra.go` — new pure `RenderServersTransports()` + exported const
|
||||
`ServersTransportInsecure = "insecure-skip-verify"`. Emits:
|
||||
```yaml
|
||||
http:
|
||||
serversTransports:
|
||||
insecure-skip-verify:
|
||||
insecureSkipVerify: true
|
||||
```
|
||||
- `internal/stacks/infra.go` — new `ensureServersTransports(traefikDir)` writes
|
||||
`dynamic/serverstransports.yml` (0644) idempotently (write-only-on-change, like `wireController`, so the
|
||||
traefik file-watcher doesn't reload each self-heal tick). Called from `EnsureBaseStack` **outside**
|
||||
`ensureTraefik` (which early-returns when traefik is already running) so an established node still
|
||||
materializes the file on the next self-heal tick / restart; the file-provider `watch: true` hot-loads it
|
||||
(no traefik restart).
|
||||
- Catalog (`1216a8a`): crafty service gains `loadbalancer.server.scheme=https` +
|
||||
`loadbalancer.serverstransport=insecure-skip-verify@file`.
|
||||
- Tests: `TestServersTransports` (named transport + insecureSkipVerify + valid YAML) and the new render
|
||||
added to the YAML-parse / no-`:latest` matrix. `go test ./internal/infra/... ./internal/stacks/...` green.
|
||||
|
||||
**Fix:**
|
||||
- Capture `oldConfig`/`oldCompose` from disk **before** the writes.
|
||||
- Re-read `finalConfig`/`finalCompose` **after** the writes — so the integrations'
|
||||
`ReapplyConfigForTarget("filebrowser")` edits to `config.yaml` are included in the comparison.
|
||||
- New pure helper `fbNeedsRecreate(oldCfg, newCfg, oldCompose, newCompose) bool` (byte-equality on
|
||||
both files) drives the decision. `changed` → `up -d --force-recreate --remove-orphans`; otherwise a
|
||||
plain `up -d --remove-orphans` (ensures running, no bounce).
|
||||
- Preserved: the restore-mode DB reset stays gated on `sourcesChanged && resetDBOnChange`; when it runs
|
||||
it sets `changed = true` (a `down -v` removed the container, so it must be recreated).
|
||||
- First-ever run (no old files → empty bytes) differs from generated content → `changed = true` → creates it.
|
||||
## Deploy
|
||||
Commit → build+push `felhom-controller:0.83.0` on 192.168.0.180 → guest 9201 (`docker pull` →
|
||||
`/etc/felhom-controller-image` → restart bootstrap svc). On controller startup, `EnsureBaseStack` wrote
|
||||
`dynamic/serverstransports.yml` automatically (logged: `[infra] wrote backend transports → … (insecure-skip-verify)`)
|
||||
— no manual file drop needed. Catalog sync (`POST /api/sync`) pulled the two labels; crafty recreated via
|
||||
`POST /api/stacks/crafty-controller/update`.
|
||||
|
||||
**Files:** `internal/web/handlers.go` (helper + gate; added `bytes` import).
|
||||
## Verification (live, guest 9201)
|
||||
| Check | Result |
|
||||
|---|---|
|
||||
| Dynamic file present + loaded | `/opt/docker/stacks/traefik/dynamic/serverstransports.yml` written, no traefik parse error |
|
||||
| **A — public URL** | `https://minecraft.demo-felhom.eu` → **302** (was 502), via Cloudflare edge + in-guest Traefik |
|
||||
| **A — Traefik backend** | access log: `302 … "crafty-controller@docker" "https://172.18.0.6:8443"` (before: `502 … "http://172.18.0.6:8443"`) |
|
||||
| **B — other apps unaffected** | filebrowser (HTTP backend) still **200** via Traefik — scoped, no global change |
|
||||
| **C — scoping proof** | **no** `insecureSkipVerify` in static `traefik.yml`; present ONLY in `dynamic/serverstransports.yml` |
|
||||
| crafty health | `Up (healthy)`, dashboard state `running` |
|
||||
|
||||
## F1 — drop the unused restic binary from the image
|
||||
## Deployed versions (`docker ps`)
|
||||
```
|
||||
felhom-controller gitea.dooplex.hu/admin/felhom-controller:0.83.0 Up (healthy)
|
||||
crafty-controller registry.gitlab.com/crafty-controller/crafty-4:4.4.8 Up (healthy)
|
||||
```
|
||||
|
||||
`controller/Dockerfile`: removed the `restic \` apt line and its `# - restic: …` comment. Disk-tier
|
||||
restic moved to the host agent; no controller code execs the binary. Left **untouched** (still live in
|
||||
the dashboard/UI): `ResticSchedule` config, `migrateResticToRsync` settings migration, and the
|
||||
`Method`/backup-dir-name string references.
|
||||
## Verification method
|
||||
curl to the Cloudflare public edge + in-guest Traefik probe (`--resolve …:127.0.0.1`) + Traefik access
|
||||
logs. (No browser tool used this run.)
|
||||
|
||||
## Tests
|
||||
|
||||
- Added `TestFbNeedsRecreate` (`internal/web/filebrowser_gate_test.go`): unchanged → **false** (no
|
||||
recreate); config differs → **true**; compose differs → **true**; first run (no old files) → **true**.
|
||||
- **Red-proof:** hard-wiring `fbNeedsRecreate` to always return `true` (the old unconditional behaviour)
|
||||
makes the "unchanged → no recreate" case fail; restoring the byte-equality gate turns it green.
|
||||
- Web package top-level tests: +1 (added `TestFbNeedsRecreate`).
|
||||
- Green gate: `go build ./...` ✓ · `go vet ./...` ✓ · `go test ./...` ✓ (all packages ok).
|
||||
|
||||
## Deploy & verify (guest 9201 / felhom-pve)
|
||||
|
||||
Deployed via the golden bootstrap mechanism: `docker pull …:0.82.0` into the guest, set
|
||||
`/etc/felhom-controller-image` → `0.82.0`, `systemctl restart felhom-controller-bootstrap.service`.
|
||||
|
||||
- `docker ps` → `gitea.dooplex.hu/admin/felhom-controller:0.82.0 Up … (healthy)` ✓
|
||||
- **F1:** `docker exec felhom-controller command -v restic` → `NO-RESTIC` ✓
|
||||
- **F2 (no-op):** deploying 0.82.0 restarted the controller; its startup sync logged
|
||||
`FileBrowser sync — no config/compose change, ensured running without recreate (3 storage path(s))`,
|
||||
and FileBrowser `StartedAt` stayed `2026-06-23T18:15:47` (UNCHANGED — not bounced) ✓
|
||||
- **F2 (change path):** dirtied the on-disk `config.yaml` + restarted the controller → log
|
||||
`FileBrowser mounts synced (recreated) — 3 storage path(s), config updated`, FileBrowser `StartedAt`
|
||||
advanced to `2026-06-24T09:05:53` (recreated on a real change) ✓. The sync regenerated `config.yaml`
|
||||
back to canonical (test line gone), FileBrowser + controller healthy — state restored.
|
||||
|
||||
Method: invoked the exact server-side sync (controller restart → `syncFileBrowserMounts`) on the live
|
||||
guest; no browser tool needed for this check (it's container-lifecycle, observed via `docker inspect`).
|
||||
## Observation (carry, not acted on)
|
||||
Generalize a `backend_scheme`/`backend_tls` hint in `.felhom.yml` so future HTTPS-backend apps get the
|
||||
`scheme=https` + `serverstransport=…@file` labels via the catalog convention rather than hand-added —
|
||||
own task.
|
||||
|
||||
Reference in New Issue
Block a user