Add the discovery HTTP API: list, lease, release, report over the manager cache

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-08-09 15:26:11 +02:00
parent f6d50e4744
commit 4aa3d47e3c
6 changed files with 950 additions and 8 deletions

View File

@@ -11,7 +11,7 @@ Pairs with [docs/plans/2026-08-07-1747-proxy-operator.md](../plans/2026-08-07-17
- [x] Step 4 — Reconciler (`internal/controller/`)
- [x] Step 5 — Health engine (`internal/health/`)
- [x] Step 6 — Lease store (`internal/lease/`)
- [ ] Step 7 — Discovery API (`internal/discovery/`)
- [x] Step 7 — Discovery API (`internal/discovery/`)
- [ ] Step 8 — GCP provider (`internal/provider/gcp/`)
- [ ] Step 9 — Orphan GC + metrics
- [ ] Step 10 — Wiring, config, docs
@@ -758,3 +758,56 @@ Worth noting: `docs/architecture.md` was not extended this step — the
lease store is HTTP-driven, not cluster-event-driven, so its diagram
belongs with the discovery API and lands in Step 7 (banner updated to say
so).
## Step 7 — Discovery API (`internal/discovery/`)
Implemented `server.go` (Runnable + middleware chain) and `handlers.go`
(the four endpoints + `proxyView` wire shape) per the plan: stdlib
`http.ServeMux` method+wildcard routing (no third-party router — see the
plan clarification commit: this is a stdlib feature since Go 1.22, the
project stays on the pinned Go 1.26), middleware outermost-first recover →
request-log → `MaxBytesReader(64KiB)` → constant-time bearer auth with
`/healthz` exempt, empty `DISCOVERY_TOKEN` serving unauthenticated with a
loud startup warning, `NeedLeaderElection() = false` with the plan's
runnable-ordering rationale in the doc comment, and graceful `Shutdown`
with a 10 s grace on ctx cancel.
The `LeaseStore` interface landed consumer-side in this package (spec §8
wants handlers swappable to a CRD/Redis store); `internal/lease.*Store`
satisfies it without modification.
Judgment calls the plan/spec left open:
- **409 arithmetic:** the store only ever sees healthy candidates, so its
`Considered` excludes unhealthy matches. The handler counts unhealthy
selector-matches itself and reports `considered = healthy + unhealthy`,
keeping the plan's example arithmetic (7 = 2+2+3) consistent.
- **TTL handling:** omitted/zero `ttlSeconds` → 300 s default; negative or
above `MaxLeaseTTL` (default 1h, flag in Step 10) → 400 `invalid_ttl`
rather than silent clamping — a client asking for a week-long lease
should find out, not get an hour quietly.
- **Grant response includes the fresh `activeLeases`** (the just-granted
lease counted), read back via `Store.Counts()` after the acquire.
- Proxies with a deletionTimestamp are filtered out of both list and
candidate selection — a proxy mid-teardown shouldn't be advertised.
Tests (87.3% coverage, `-race -count=2` clean, green on first run):
httptest over the real handler chain with a fake cache reader and a real
`lease.Store` — auth on/off/wrong-token/healthz-exempt, list filtering
(attributes, healthy, combined, empty-is-200), grant shape (201, default
TTL, lowest-latency pick, RFC3339 expiresAt, activeLeases=1), the full
409 body arithmetic, invalid TTL/body/result, idempotent 204 release,
report→cooldown→409 round-trip, 404 on unknown lease, and a real
`Start` on `127.0.0.1:0` (via the new `BoundAddr()` accessor) serving
healthz then shutting down cleanly on cancel.
```bash
go test -race -count=2 ./internal/discovery/
make test # whole repo green
```
Worth noting: `go mod tidy` promoted `github.com/go-logr/logr` from
indirect to direct (the server holds a `logr.Logger` field). The
`--discovery-addr`, `--max-lease-ttl` flags and the `DISCOVERY_TOKEN`
Secret mount arrive with `cmd/main.go` in Step 10. `docs/architecture.md`
gained §7 covering the whole HTTP path and the store's sweep Runnable.