Files
egress-proxies-operator/internal/provider/kvm/seed.go
T
kacerrandClaude Fable 5.1 162607dfe2 Add KVM provider pure builders: domain XML, volumes, seed ISO, metadata
Introduces internal/provider/kvm with the side-effect-free pieces of the
provider: providerID format/parse, the namespaced <metadata> element that
carries the GC contract, q35 domain XML over pool volumes, volume XML for
overlays and raw seeds, the NoCloud seed ISO built with kdomanski/iso9660,
and config defaults. All unit-tested.

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

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-10 19:13:51 +00:00

53 lines
1.7 KiB
Go

package kvm
import (
"bytes"
"fmt"
"strings"
"github.com/kdomanski/iso9660"
)
// seedLabel is the volume label cloud-init's NoCloud datasource looks for.
const seedLabel = "cidata"
// defaultVendorData is the cloud-init vendor-data shipped on every seed
// unless the config overrides it. cloud-init merges it under the Proxy's own
// user-data, so stock images grow a guest agent (which lets the provider
// read the VM's IP before ARP sees traffic) without the user's cloud-init
// having to know about it.
const defaultVendorData = `#cloud-config
packages:
- qemu-guest-agent
runcmd:
- [systemctl, enable, --now, qemu-guest-agent]
`
// buildSeedISO renders a NoCloud seed: user-data verbatim, vendor-data as
// given, and a meta-data whose instance-id is the deterministic VM name, so a
// re-created seed for the same name is byte-identical and cloud-init never
// mistakes a reboot for a new instance.
func buildSeedISO(name, userData, vendorData string) ([]byte, error) {
w, err := iso9660.NewWriter()
if err != nil {
return nil, fmt.Errorf("creating iso writer: %w", err)
}
defer w.Cleanup() //nolint:errcheck // temp-dir cleanup; nothing to do on failure
files := []struct{ name, body string }{
{"user-data", userData},
{"meta-data", fmt.Sprintf("instance-id: %s\nlocal-hostname: %s\n", name, name)},
{"vendor-data", vendorData},
}
for _, f := range files {
if err := w.AddFile(strings.NewReader(f.body), f.name); err != nil {
return nil, fmt.Errorf("adding %s to seed iso: %w", f.name, err)
}
}
var buf bytes.Buffer
if err := w.WriteTo(&buf, seedLabel); err != nil {
return nil, fmt.Errorf("writing seed iso: %w", err)
}
return buf.Bytes(), nil
}