5.8 KiB
5.8 KiB
Plan: Discovery API documentation (docs/api.md)
Created: 2026-08-11 21:52
Context
The operator serves an HTTP discovery/lease API on :8090 (internal/discovery/) that crawler clients use to list proxies, acquire TTL leases, release them, and report rate-limiting. There is no dedicated API reference today: README has four quickstart curls (no auth header, no schemas), and docs/architecture.md §7 has an ASCII route map. The user wants full documentation with curl examples for every feature.
Decisions made with user: doc lives in a new docs/api.md; commit straight to main (no MR).
Deliverable
1. New file docs/api.md — full API reference
Content (all facts verified against code during planning):
- Overview & base URL — what the API is; in-cluster FQDN
http://egress-proxies-operator-controller-manager-discovery-service.egress-proxies-operator-system.svc.cluster.local:8090(Service:config/default/discovery_service.yaml); local access viakubectl port-forward svc/egress-proxies-operator-controller-manager-discovery-service 8090:8090. - Authentication — static bearer token from
DISCOVERY_TOKENenv var (populated from the optionaldiscovery-tokenSecret, keytoken;config/manager/manager.yaml). Empty token ⇒ auth disabled with startup warning. Curl:-H "Authorization: Bearer $TOKEN"on every example./healthzalways exempt. - Conventions — JSON everywhere; error envelope
{"error":"<code>","message":"<text>"}; request bodies capped at 64 KiB; proxies with a deletion timestamp are excluded from all responses. - Configuration table —
--discovery-addr(default:8090),--max-lease-ttl(default 1h),--lease-cooldown(default 15m),DISCOVERY_TOKEN. Note the shipped Deployment passes none of these flags, so defaults apply. - Endpoints, each with request/response schema, status codes, and a copy-pasteable curl example:
GET /healthz— liveness, unauthenticated.GET /v1/proxies— filtershealthy=true|false(else 400invalid_query) and repeatableattr.<key>=<value>(verbatim equality onspec.attributes, all pairs must match). Response{"proxies":[proxyView...],"count":N}sorted by id. FullproxyViewfield table:id(ns/name),ip,port,attributes,phase(Pending/Provisioning/Ready/Unhealthy/Deleting/Failed),healthy(conditionHealthy== True),latencyMillis,activeLeases,maxLeases(default 5; explicit 0 = unleasable).POST /v1/leases— body{selector, ttlSeconds, target}all optional; TTL defaults 5m, capped at max-lease-ttl (else 400invalid_ttl). 201{leaseID, proxy, expiresAt, ttlSeconds}; 409no_matchwithconsidered/atCapacity/inCooldown/unhealthycounts (documented meanings).DELETE /v1/leases/{id}— early release; always 204, idempotent.POST /v1/leases/{id}/report— body{result: ok|rate_limited|banned, target}; 204, 404unknown_lease, 400invalid_result.okis a pure ack;rate_limitedandbannedbehave identically today (both start one cooldown window).
- Selection & cooldown semantics (short section — this is the non-obvious part clients need):
- Selection order: fewest active leases → lowest latency → lexicographic id; deterministic; only healthy, non-deleting proxies with free capacity are candidates.
- Cooldown: 15m default (
--lease-cooldown), keyed{proxy, target}. Report with a target blocks only leases requesting that target; report without a target (and lease without one) creates a global cooldown blocking all acquisitions of that proxy — call this footgun out explicitly. - Expired leases stay reportable for one cooldown window past TTL.
- End-to-end workflow example — numbered curl walkthrough: acquire → use
proxy.ip:portas HTTP proxy (curl -x) → reportrate_limitedon 429 → release. Using ajq-extractedleaseID. - Caveats — lease/cooldown state is in-memory and per-process: single replica only, operator restart drops all leases and cooldowns.
2. Pointers to the new doc (small edits)
README.md: one-line link near the quickstart curl section ("full reference: docs/api.md").docs/architecture.md§7: one-line link todocs/api.mdas the detailed reference.
3. Housekeeping per CLAUDE.md
- First action post-approval: copy this plan to
docs/plans/<timestamp>-discovery-api-docs.md(timestamp fromdate "+%Y-%m-%d-%H%M"), commit it alone. - Then write the docs, commit to
mainwithCo-Authored-By: Claude <noreply@anthropic.com>trailer, push. - Append execution summary + status checklist to
docs/plans-executions/<same-timestamp>-discovery-api-docs.mdin the docs commit. - Add
CHANGELOG.mdentry (timestamp viadate "+%Y-%m-%d %H:%M %Z") once the user confirms.
Key source files (facts source of truth)
- internal/discovery/handlers.go, internal/discovery/server.go — routes, schemas, status codes, auth, limits.
- internal/lease/store.go — selection order, cooldown/retention, stats.
- api/v1alpha1/proxy_types.go, api/v1alpha1/helpers.go — defaults (port 3128, maxLeases 5), phases, conditions.
- cmd/main.go — flags/env defaults.
- config/default/discovery_service.yaml, config/manager/manager.yaml — service DNS, token secret.
Verification
- Cross-check every documented status code / field name against
internal/discovery/server_test.goexpectations. - Sanity-run
go build ./... && go test -short ./internal/discovery/ ./internal/lease/(no code changes expected — confirms docs match current behavior, not a stale tree). - Optionally lint the curl JSON bodies by piping each through
jq .locally.