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

79 lines
2.6 KiB
Go

package kvm2
import (
"encoding/xml"
"strings"
"time"
"gitea.home.hrajfrisbee.cz/kacerr/egress-proxies-operator/internal/provider"
)
// The GC mark lives in the domain's <metadata> as one element in kvm2's own
// namespace (spec entry 8). The namespace is what selects it in
// DomainGetMetadata; libvirt 11.6 hands the element back without the xmlns
// declaration, so parsing matches on the local name only.
const (
metadataURI = "https://gitea.home.hrajfrisbee.cz/kacerr/egress-proxies-operator/kvm2"
metadataLocalName = "instance"
)
// instanceMetadata is the mark as it is written and read back. The fields
// are the element's text as is; managed and createdAt interpret them.
type instanceMetadata struct {
XMLName xml.Name
Managed string `xml:"managed"`
UID string `xml:"uid"`
CreatedAt string `xml:"createdAt"`
}
func newInstanceMetadata(uid string, createdAt time.Time) instanceMetadata {
return instanceMetadata{
XMLName: xml.Name{Space: metadataURI, Local: metadataLocalName},
Managed: provider.LabelManagedYes,
UID: uid,
CreatedAt: createdAt.UTC().Format(time.RFC3339),
}
}
func (m instanceMetadata) managed() bool {
return m.Managed == provider.LabelManagedYes
}
// createdAt returns the zero time when the element carries no parsable
// timestamp; GC treats that as old, which the spec accepts.
func (m instanceMetadata) createdAt() time.Time {
t, err := time.Parse(time.RFC3339, m.CreatedAt)
if err != nil {
return time.Time{}
}
return t
}
// marshalInstanceMetadata renders the namespaced element that goes under
// the domain's <metadata>.
func marshalInstanceMetadata(m instanceMetadata) (string, error) {
m.XMLName = xml.Name{Space: metadataURI, Local: metadataLocalName}
out, err := xml.Marshal(m)
if err != nil {
return "", permanentf("marshalling instance metadata: %v", err)
}
return string(out), nil
}
// parseInstanceMetadata reads the element back, with or without its xmlns
// declaration. Anything that is not an <instance> element is ErrPermanent:
// the domain's metadata is corrupt and no retry fixes it.
func parseInstanceMetadata(s string) (instanceMetadata, error) {
var m instanceMetadata
if strings.TrimSpace(s) == "" {
return instanceMetadata{}, permanentf("parsing instance metadata: empty document")
}
if err := xml.Unmarshal([]byte(s), &m); err != nil {
return instanceMetadata{}, permanentf("parsing instance metadata: %v", err)
}
if m.XMLName.Local != metadataLocalName {
return instanceMetadata{}, permanentf("parsing instance metadata: root element is <%s>, want <%s>", m.XMLName.Local, metadataLocalName)
}
return m, nil
}