Add KVM provider image cache: fetch base images into host pools on first use

resolveImage maps placement.image to a configured key or URL; imageCache
streams the download through StorageVolUpload with a sha256 tee, writes
a marker volume when the upload is verified, and re-fetches when the
marker is missing or the configured checksum changed. Errors carry
taxonomy sentinels that classify now honours. Adds the in-memory fake
libvirt API used from here on.

Step 3b of docs/plans/2026-09-04-1404-kvm-provider.md.

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 6322184d50
commit 6dba33adf2
6 changed files with 1087 additions and 8 deletions
+14 -7
View File
@@ -9,14 +9,21 @@ import (
"gitea.home.hrajfrisbee.cz/kacerr/egress-proxies-operator/internal/provider"
)
// classify maps a libvirt error onto the provider taxonomy. Missing domain
// or volume → NotFound; anything the host will keep rejecting (bad XML,
// unsupported config, denied access, missing pool) → Permanent; every other
// libvirt code, plus SSH/transport failures and cancellation, → Transient,
// because retrying is safer than latching Failed on an error nobody taught
// this function to recognise. libvirt exposes no quota signal, so nothing
// maps to QuotaExceeded.
// classify maps an error onto the provider taxonomy. Errors the package
// already tagged with a sentinel (image download failures, placement
// errors) keep their class. For libvirt errors: missing domain or volume →
// NotFound; anything the host will keep rejecting (bad XML, unsupported
// config, denied access, missing pool) → Permanent; every other libvirt
// code, plus SSH/transport failures and cancellation, → Transient, because
// retrying is safer than latching Failed on an error nobody taught this
// function to recognise. libvirt exposes no quota signal, so nothing maps
// to QuotaExceeded.
func classify(err error) error {
for _, class := range []error{provider.ErrNotFound, provider.ErrQuotaExceeded, provider.ErrPermanent, provider.ErrTransient} {
if errors.Is(err, class) {
return class
}
}
var lerr libvirt.Error
if !errors.As(err, &lerr) {
return provider.ErrTransient