Skip to content

Commit

Permalink
Attache machine metadata to DomainXML (#84)
Browse files Browse the repository at this point in the history
  • Loading branch information
so-sahu authored Dec 21, 2023
1 parent f56a3ab commit 1b74c6d
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 212 deletions.
36 changes: 36 additions & 0 deletions pkg/controllers/machine_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ package controllers

import (
"context"
"encoding/json"
"encoding/xml"
"errors"
"fmt"
"os"
Expand All @@ -18,13 +20,15 @@ import (
providerimage "github.com/ironcore-dev/libvirt-provider/pkg/image"
"github.com/ironcore-dev/libvirt-provider/pkg/libvirt/guest"
libvirtutils "github.com/ironcore-dev/libvirt-provider/pkg/libvirt/utils"
providermeta "github.com/ironcore-dev/libvirt-provider/pkg/meta"
"github.com/ironcore-dev/libvirt-provider/pkg/os/osutils"
providernetworkinterface "github.com/ironcore-dev/libvirt-provider/pkg/plugins/networkinterface"
providervolume "github.com/ironcore-dev/libvirt-provider/pkg/plugins/volume"
providerhost "github.com/ironcore-dev/libvirt-provider/pkg/providerhost" // TODO: Change to a better naming for all imports, libvirthost?
"github.com/ironcore-dev/libvirt-provider/pkg/raw"
"github.com/ironcore-dev/libvirt-provider/pkg/store"
"github.com/ironcore-dev/libvirt-provider/pkg/utils"
machinev1alpha1 "github.com/ironcore-dev/libvirt-provider/provider/api/v1alpha1"
"k8s.io/client-go/util/workqueue"
"k8s.io/utils/ptr"
"libvirt.org/go/libvirtxml"
Expand Down Expand Up @@ -512,6 +516,10 @@ func (r *MachineReconciler) domainFor(
},
}

if err := r.setDomainMetadata(log, machine, domainDesc); err != nil {
return nil, nil, nil, err
}

if err := r.setDomainResources(ctx, log, machine, domainDesc); err != nil {
return nil, nil, nil, err
}
Expand Down Expand Up @@ -554,6 +562,34 @@ func (r *MachineReconciler) domainFor(
return domainDesc, volumeStates, nicStates, nil
}

func (r *MachineReconciler) setDomainMetadata(log logr.Logger, machine *api.Machine, domain *libvirtxml.Domain) error {
labels, found := machine.Metadata.Annotations[machinev1alpha1.LabelsAnnotation]
if !found {
log.V(1).Info("IRI machine labels are not annotated in the API machine")
return nil
}
var irimachineLabels map[string]string
err := json.Unmarshal([]byte(labels), &irimachineLabels)
if err != nil {
return fmt.Errorf("error unmarshalling iri machine labels: %w", err)
}

encodedLabels := providermeta.IRIMachineLabelsEncoder(irimachineLabels)

domainMetadata := &providermeta.LibvirtProviderMetadata{
IRIMmachineLabels: encodedLabels,
}

domainMetadataXML, err := xml.Marshal(domainMetadata)
if err != nil {
return err
}
domain.Metadata = &libvirtxml.DomainMetadata{
XML: string(domainMetadataXML),
}
return nil
}

func (r *MachineReconciler) setDomainResources(ctx context.Context, log logr.Logger, machine *api.Machine, domain *libvirtxml.Domain) error {
// TODO: check if there is better or check possible while conversion to uint
domain.Memory = &libvirtxml.DomainMemory{
Expand Down
49 changes: 24 additions & 25 deletions pkg/meta/meta.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@

package meta

import "encoding/xml"
import (
"encoding/xml"
"fmt"
"strings"
)

type LibvirtProviderMetadata struct {
Namespace string `xml:"namespace"`
Name string `xml:"name"`
SGXMemory *int64 `xml:"sgx_memory,omitempty"`
SGXNode *int `xml:"sgx_node,omitempty"`
IRIMmachineLabels string `xml:"irimachinelabels"`
}

// Since go does not support XML namespaces easily (see https://github.com/golang/go/issues/9519),
Expand All @@ -19,11 +20,8 @@ type LibvirtProviderMetadata struct {
func (m *LibvirtProviderMetadata) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
start.Name.Local = "libvirtprovider:metadata"
return e.EncodeElement(&marshalMetadata{
XMLNS: "https://github.com/ironcore-dev/libvirt-provider",
Namespace: m.Namespace,
Name: m.Name,
SGXMemory: m.SGXMemory,
SGXNode: m.SGXNode,
XMLNS: "https://github.com/ironcore-dev/libvirt-provider",
IRIMmachineLabels: m.IRIMmachineLabels,
}, start)
}

Expand All @@ -33,26 +31,27 @@ func (m *LibvirtProviderMetadata) UnmarshalXML(d *xml.Decoder, start xml.StartEl
return err
}

m.Namespace = unmarshal.Namespace
m.Name = unmarshal.Name
m.SGXMemory = unmarshal.SGXMemory
m.SGXNode = unmarshal.SGXNode
m.IRIMmachineLabels = unmarshal.IRIMmachineLabels
return nil
}

type marshalMetadata struct {
XMLName xml.Name `xml:"libvirtprovider:metadata"`
XMLNS string `xml:"xmlns:libvirtprovider,attr"`
Namespace string `xml:"libvirtprovider:namespace"`
Name string `xml:"libvirtprovider:name"`
SGXMemory *int64 `xml:"libvirtprovider:sgx_memory,omitempty"`
SGXNode *int `xml:"libvirtprovider:sgx_node,omitempty"`
XMLName xml.Name `xml:"libvirtprovider:metadata"`
XMLNS string `xml:"xmlns:libvirtprovider,attr"`
IRIMmachineLabels string `xml:"libvirtprovider:irimachinelabels"`
}

type unmarshalMetadata struct {
XMLName xml.Name `xml:"metadata"`
Namespace string `xml:"namespace"`
Name string `xml:"name"`
SGXMemory *int64 `xml:"sgx_memory,omitempty"`
SGXNode *int `xml:"sgx_node,omitempty"`
XMLName xml.Name `xml:"metadata"`
IRIMmachineLabels string `xml:"irimachinelabels"`
}

func IRIMachineLabelsEncoder(data map[string]string) string {
var builder strings.Builder

for key, value := range data {
builder.WriteString(fmt.Sprintf("\n\"%s\": \"%s\"", key, value))
}

return builder.String()
}
100 changes: 53 additions & 47 deletions pkg/meta/meta_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,64 +9,70 @@ import (
. "github.com/ironcore-dev/libvirt-provider/pkg/meta"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"k8s.io/utils/ptr"
)

const expectedXML = `<libvirtprovider:metadata xmlns:libvirtprovider="https://github.com/ironcore-dev/libvirt-provider"><libvirtprovider:namespace>foo</libvirtprovider:namespace><libvirtprovider:name>bar</libvirtprovider:name></libvirtprovider:metadata>`
const sgxExpectedXML = `<libvirtprovider:metadata xmlns:libvirtprovider="https://github.com/ironcore-dev/libvirt-provider"><libvirtprovider:namespace>foo</libvirtprovider:namespace><libvirtprovider:name>bar</libvirtprovider:name><libvirtprovider:sgx_memory>68719476736</libvirtprovider:sgx_memory><libvirtprovider:sgx_node>0</libvirtprovider:sgx_node></libvirtprovider:metadata>`
const libvirtProviderURL = "https://github.com/ironcore-dev/libvirt-provider"

var _ = Describe("Meta", func() {
Context("LibvirtProviderMetadata", func() {
Describe("Marshal", func() {
It("should correctly marshal the metadata", func() {
metadata := &LibvirtProviderMetadata{
Namespace: "foo",
Name: "bar",
}
var _ = Describe("LibvirtProviderMetadata", func() {
Context("Marshalling", func() {
It("marshals LibvirtProviderMetadata correctly when metadata is populated", func() {
metadata := &LibvirtProviderMetadata{
IRIMmachineLabels: "test-labels",
}

data, err := xml.Marshal(metadata)
Expect(err).NotTo(HaveOccurred())
Expect(string(data)).To(Equal(expectedXML))
})
data, err := xml.Marshal(metadata)
Expect(err).NotTo(HaveOccurred())
Expect(string(data)).To(Equal(createExpectedXML("test-labels")))
})

Describe("Unmarshal", func() {
It("should correctly unmarshal the metadata", func() {
metadata := &LibvirtProviderMetadata{}
Expect(xml.Unmarshal([]byte(expectedXML), metadata)).To(Succeed())
Expect(metadata).To(Equal(&LibvirtProviderMetadata{
Namespace: "foo",
Name: "bar",
}))
})
It("marshals LibvirtProviderMetadata correctly when no metadata present", func() {
metadata := &LibvirtProviderMetadata{}

data, err := xml.Marshal(metadata)
Expect(err).NotTo(HaveOccurred())
Expect(string(data)).To(Equal(createExpectedXML("")))
})
})

Describe("SGX Marshal", func() {
It("should correctly marshal the SGX metadata", func() {
metadata := &LibvirtProviderMetadata{
Namespace: "foo",
Name: "bar",
SGXMemory: ptr.To[int64](68719476736),
SGXNode: ptr.To[int](0),
}
Context("Unmarshalling", func() {
It("unmarshals XML to LibvirtProviderMetadata correctly when metadata is populated", func() {
metadata := &LibvirtProviderMetadata{}
Expect(xml.Unmarshal([]byte(createExpectedXML("test-labels")), metadata)).To(Succeed())
Expect(metadata).To(Equal(&LibvirtProviderMetadata{
IRIMmachineLabels: "test-labels",
}))
})

data, err := xml.Marshal(metadata)
Expect(err).NotTo(HaveOccurred())
Expect(string(data)).To(Equal(sgxExpectedXML))
})
It("unmarshals XML to LibvirtProviderMetadata correctly when no metadata present", func() {
metadata := &LibvirtProviderMetadata{}
Expect(xml.Unmarshal([]byte(createExpectedXML("")), metadata)).To(Succeed())
Expect(metadata).To(Equal(&LibvirtProviderMetadata{}))
})
})

Describe("SGX Unmarshal", func() {
It("should correctly unmarshal the SGX metadata", func() {
metadata := &LibvirtProviderMetadata{}
Expect(xml.Unmarshal([]byte(sgxExpectedXML), metadata)).To(Succeed())
Expect(metadata).To(Equal(&LibvirtProviderMetadata{
Namespace: "foo",
Name: "bar",
SGXMemory: ptr.To[int64](68719476736),
SGXNode: ptr.To[int](0),
}))
})
Context("IRIMachineLabelsEncoder", func() {
It("encodes IRIMachineLabels correctly when labels are populated", func() {
labels := map[string]string{
"machinepoollet.ironcore.dev/machine-uid": "test-uid",
"downward-api.machinepoollet.ironcore.dev/root-machine-name": "root-test-name",
"downward-api.machinepoollet.ironcore.dev/root-machine-namespace": "root-test-namespace",
"downward-api.machinepoollet.ironcore.dev/root-machine-uid": "root-test-uid",
"machinepoollet.ironcore.dev/machine-namespace": "test-namespace",
"machinepoollet.ironcore.dev/machine-name": "test-name",
}

data := IRIMachineLabelsEncoder(labels)

Expect(data).To(ContainSubstring(`"machinepoollet.ironcore.dev/machine-uid": "test-uid"`))
Expect(data).To(ContainSubstring(`"downward-api.machinepoollet.ironcore.dev/root-machine-name": "root-test-name"`))
Expect(data).To(ContainSubstring(`"downward-api.machinepoollet.ironcore.dev/root-machine-namespace": "root-test-namespace"`))
Expect(data).To(ContainSubstring(`"downward-api.machinepoollet.ironcore.dev/root-machine-uid": "root-test-uid"`))
Expect(data).To(ContainSubstring(`"machinepoollet.ironcore.dev/machine-namespace": "test-namespace"`))
Expect(data).To(ContainSubstring(`"machinepoollet.ironcore.dev/machine-name": "test-name"`))
})
})
})

func createExpectedXML(labels string) string {
return `<libvirtprovider:metadata xmlns:libvirtprovider="` + libvirtProviderURL + `"><libvirtprovider:irimachinelabels>` + labels + `</libvirtprovider:irimachinelabels></libvirtprovider:metadata>`
}
Loading

0 comments on commit 1b74c6d

Please sign in to comment.