Files
egress-proxies-operator/internal/provider/kvm2/volume.go
T

96 lines
3.0 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" }
func baseVolumeName(key, format string) string { return "base-" + 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
}