Wire the KVM provider: main.go, kvm-ssh Secret mount, samples, docs, CHANGELOG

Registers "kvm" in the provider builtins, mounts an optional kvm-ssh
Secret at /etc/proxy-operator/kvm, adds a kvm-home providers-config
sample and a proxy_kvm.yaml Proxy sample, documents the provider in
docs/kvm-provider.md (prerequisites, config reference, image cache and
its do-not-replace-in-use rule, known gaps), and updates the README
and architecture provider sections and decision log.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-09-10 19:13:51 +00:00
co-authored by Claude Fable 5.1
parent b3984ca69d
commit 791988b5a0
11 changed files with 448 additions and 6 deletions
@@ -8,7 +8,7 @@ Plan: [2026-09-04-1404-kvm-provider.md](../plans/2026-09-04-1404-kvm-provider.md
- [x] Step 3 — Transport + errors (`conn.go`, `errors.go`)
- [x] Step 3b — Image cache (`image.go`)
- [x] Step 4 — Provider methods (`kvm.go`) over a fake API
- [ ] Step 5 — Wiring, manifests, samples, docs, CHANGELOG
- [x] Step 5 — Wiring, manifests, samples, docs, CHANGELOG
- [x] Step 6 — Integration test against a real hypervisor (written and compiled; first real run is part of Step 7)
- [ ] Step 7 — Manual validation + MR
@@ -338,3 +338,54 @@ Step 3b "confirm on a real host" notes get answered. The test's config
is built directly rather than through the provider package's validation
(unexported), so a typo in an env var surfaces from `New` or from
libvirt, not from a validation message.
## Step 5 — Wiring, manifests, samples, docs, CHANGELOG
Done after Step 6 (see that entry for why the order flipped). Everything
the plan listed, plus a few things it did not:
- `cmd/main.go`: `"kvm": kvm.New` in the builtins map. No RBAC change —
the provider talks to hypervisors, not the API server.
- `config/manager/manager.yaml`: `kvm-ssh` Secret mounted read-only at
`/etc/proxy-operator/kvm` with `optional: true`, so deployments without
a kvm provider are unaffected. It nests under the providers-config
mount at `/etc/proxy-operator`; kustomize renders it (`kubectl
kustomize config/default` checked). The container runs as uid 65532
and Secret files default to 0644, so the key is readable without an
`fsGroup`; the `kubectl create secret` recipe is in a comment next to
the mount, in `docs/kvm-provider.md` and in the README.
- `config/samples/providers-config.yaml`: `kvm-home` block with Debian 13
and Ubuntu 24.04 official image URLs, two machine types, one host, and
every optional field shown commented out. Parsed through
`provider.LoadConfigFile` in a throwaway test to make sure the sample
validates. `config/samples/proxy_kvm.yaml` uses the GCP sample's squid
cloud-init and shows `ssh_authorized_keys` commented out rather than
set — a sample with a placeholder key would either fail cloud-init or
invite pasting a real key into a committed file. Added to the samples
kustomization; `config/manager/providers_config.yaml`'s comment now
mentions kvm.
- `docs/kvm-provider.md`: prerequisites with a three-line preflight
(`virsh list`, `pool-info`, `ip link` over ssh), cluster setup, the full
config reference table, placement table, a table of what lands on the
host and its lifetime, how the image cache works and how to evict, the
**warning not to change or evict an image while Proxies use it** (the
reviewer's finding from Step 4, carried as a documented rule since the
content-addressed-naming alternative was not chosen), how to log in,
and the known gaps.
- README: providers bullet and a "KVM setup" section mirroring the GCP
one. `docs/architecture.md`: components row, a §5 block for the kvm
call flow in the same style as the other two, and five decision-log
entries (SSH transport, operator-fetched images, seed always rebuilt,
`nostate` → Provisioning, skip-vs-fail in the GC sweep).
- `CHANGELOG.md` entry at the top, stating explicitly that the provider
is not yet validated on a real host.
Verification: `go build ./...`, `go vet ./...`, `go test -short` on
`cmd` and `internal/provider/...`, and both kustomizations rendered.
`hack/providers-dev.yaml` untouched, as planned.
Worth noting: the CRD has no rule requiring all three placement fields
(that is GCP's own check), so the single-host "zone may be omitted"
behaviour works without an API change. And with this step the branch is
feature-complete but **unproven**: Step 7 runs the integration test and
the end-to-end checklist against a real hypervisor before the MR.