Files
egress-proxies-operator/internal/provider/kvm2/volume.go
T
kacerrandClaude Opus 5 54525bf67a kvm2: gofmt volume.go
Making baseVolumeName multi-line in the H4 commit collapsed the
alignment gofmt gives a run of single-line funcs, and the commit went out
with the old spacing. Caught by make test, whose fmt target rewrites the
file and leaves the tree dirty.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 21:07:10 +00:00

103 lines
3.4 KiB
Go

package kvm2
import (
"crypto/sha256"
"encoding/hex"
"encoding/xml"
"gitea.home.hrajfrisbee.cz/kacerr/egress-proxies-operator/internal/provider"
)
// Volume names in the host's pool (spec entries 4 and 10). The per-VM
// volumes derive from the domain name; the base image from its catalogue
// key or, for a URL image, from a hash of the URL.
func overlayVolumeName(name string) string { return name + ".qcow2" }
func seedVolumeName(name string) string { return name + "-seed.iso" }
// baseVolumeName carries the provider entry because the base is shared by
// every Proxy on a host but must not be shared by two entries: the kvm
// provider builds base-<key>.<format> in the same pool from the same
// catalogue shape, and two kvm2 entries pointing one key at different URLs
// would otherwise agree on the name and disagree on the contents.
func baseVolumeName(entry, key, format string) string {
return "base-" + entry + "-" + key + "." + format
}
func markerVolumeName(baseName string) string { return baseName + ".sha256" }
// urlImageKey stands in for the catalogue key of an image given as a URL:
// the first 16 hex characters of sha256(url).
func urlImageKey(url string) string {
sum := sha256.Sum256([]byte(url))
return hex.EncodeToString(sum[:])[:16]
}
// volumeSpec is what StorageVolCreateXML needs. BackingPath and
// BackingFormat are set for an overlay only.
type volumeSpec struct {
Name string
CapacityBytes int64
Format string
BackingPath string
BackingFormat string
}
type volumeXML struct {
XMLName xml.Name `xml:"volume"`
Type string `xml:"type,attr"`
Name string `xml:"name"`
Capacity volumeCapacityXML `xml:"capacity"`
Target volumeTargetXML `xml:"target"`
BackingStore *backingStoreXML `xml:"backingStore"`
}
type volumeCapacityXML struct {
Unit string `xml:"unit,attr"`
Value int64 `xml:",chardata"`
}
type volumeTargetXML struct {
Format volumeFormatXML `xml:"format"`
}
type volumeFormatXML struct {
Type string `xml:"type,attr"`
}
type backingStoreXML struct {
Path string `xml:"path"`
Format volumeFormatXML `xml:"format"`
}
func validVolumeFormat(f string) bool {
return f == provider.KVMFormatQcow2 || f == provider.KVMFormatRaw
}
func buildVolumeXML(v volumeSpec) (string, error) {
if v.Name == "" {
return "", permanentf("volume XML: name is empty")
}
if v.CapacityBytes <= 0 {
return "", permanentf("volume XML for %q: capacity must be positive, got %d", v.Name, v.CapacityBytes)
}
if !validVolumeFormat(v.Format) {
return "", permanentf("volume XML for %q: unknown format %q (want %s or %s)", v.Name, v.Format, provider.KVMFormatQcow2, provider.KVMFormatRaw)
}
x := volumeXML{
Type: "file",
Name: v.Name,
Capacity: volumeCapacityXML{Unit: "bytes", Value: v.CapacityBytes},
Target: volumeTargetXML{Format: volumeFormatXML{Type: v.Format}},
}
if v.BackingPath != "" {
if !validVolumeFormat(v.BackingFormat) {
return "", permanentf("volume XML for %q: unknown backing format %q (want %s or %s)", v.Name, v.BackingFormat, provider.KVMFormatQcow2, provider.KVMFormatRaw)
}
x.BackingStore = &backingStoreXML{Path: v.BackingPath, Format: volumeFormatXML{Type: v.BackingFormat}}
}
out, err := xml.MarshalIndent(x, "", " ")
if err != nil {
return "", permanentf("volume XML for %q: %v", v.Name, err)
}
return string(out), nil
}