v2 given tests compiled against a panic-only skeleton (go vet clean); no reference implementation. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
59 lines
3.0 KiB
Markdown
59 lines
3.0 KiB
Markdown
# v2 task 05: wiring, the smoke run, README
|
|
|
|
**Branch:** `v2` (run `git switch v2`; `git status --short` must be empty, otherwise stop)
|
|
**Commit subject:** `Wire wake and identity into crossbar; v2 smoke and README`
|
|
|
|
## Goal
|
|
|
|
Put the pieces together: the proxy wakes a sleeping host when a route has no healthy host left,
|
|
`main` builds the waker from config and wraps the proxy in the identity middleware when
|
|
`identity` is on, the given fake upstream can be woken, and `tools/smoke.sh` proves the whole of
|
|
v2 over real HTTP.
|
|
|
|
## Files
|
|
|
|
- Copy (**replaces** v1's): `cmd/fakeupstream/main.go`, `tools/smoke.sh`, `example.toml`
|
|
- Modify: `internal/proxy/proxy.go` (or a new file), `cmd/crossbar/main.go`, `README.md`, `docs/implementer-log.md`
|
|
|
|
## Rules
|
|
|
|
1. `proxy.Handler` gains `func (p *Handler) SetWaker(w Waker)` where
|
|
`type Waker interface{ Wake(ctx context.Context, host string) bool }` (defined in `proxy`).
|
|
When `leases.Acquire` returns `ErrNoHost` and a waker is set: for each candidate host of the
|
|
route, in order, that has a wake target (ask `cfg.Hosts[h].Wake != nil`), call
|
|
`Wake(r.Context(), h)`; on `true`, retry `Acquire` once; on `false` for every candidate, 503
|
|
`{"error":"no healthy host","woke":["<hosts tried>"]}`. The context-guard's "no host fits"
|
|
path (task 02) also tries waking a host whose `PerSlotCtx` is unknown or large enough, before
|
|
answering 400.
|
|
2. `cmd/crossbar`: build `wake.New(targets, hosts)` from every host with `Wake != nil`
|
|
(`hosts` is the `proxy.HostView`, which has `Healthy`), call `p.SetWaker(w)`. When
|
|
`cfg.Identity != "off"`: `checker := identity.NewChecker(identity.TailscaleResolver{})` or
|
|
`identity.NewHeaderChecker()`; wrap the proxy handler:
|
|
`mux.Handle("/", identity.Middleware(checker, func(route string) ([]string, bool) { rt, ok := cfg.Routes[route]; return rt.Peers, ok }, p))`.
|
|
Log at start which mode is active; with `"header"` log a warning that it is insecure.
|
|
3. Copy the three given files; `make build`; `make smoke` → `smoke: ok (…)`. The smoke's check 2
|
|
waits up to 40 s for the wake; the fake wakes in ~1 s.
|
|
4. README: sections stay; add under `## Operate` the wake behaviour and the identity modes with
|
|
the `peers` example; under `## Configure` the three new keys; `## What v2 does not do`:
|
|
`/slots`, request coalescing, TLS — `PLAN.md`.
|
|
|
|
## Steps
|
|
|
|
- [ ] **1.** `git switch v2`; copy the three given files.
|
|
- [ ] **2. Write the code** (proxy waker path, `main`). `gofmt -w .`
|
|
- [ ] **3.** `go test -race -count=1 ./...` → all `ok`. **4.** `make smoke` → `smoke: ok`.
|
|
- [ ] **5.** README. **6.** `make gate`. **7.** Row `v2/05-wiring-smoke`; commit.
|
|
|
|
```sh
|
|
git add internal/proxy cmd/crossbar cmd/fakeupstream tools/smoke.sh example.toml README.md docs/implementer-log.md
|
|
git commit
|
|
```
|
|
|
|
## Done when
|
|
|
|
- `make smoke` prints `smoke: ok (…)`; gate ok; the three copied files byte-identical.
|
|
|
|
## Stop and report if
|
|
|
|
- `make smoke` fails twice in the same way; quote the failing check and the crossbar log.
|