Skip to content

Commit

Permalink
operands/kubevirt: Set Kubevirt CR new primary UDN Binding plugin
Browse files Browse the repository at this point in the history
The ability to register network bindings to Kubevirt VMs was proposed
[0] in order to allow Kubevirt VMs to connect to network bindings and
gain advanced user defined network capabilities.
The configuration is added to the kubevirt CR (kubevirt feature gate* +
configuring the binding parameters).

This commit deploys and registers a primary user-defined-network (UDN)
binding to the kubevirt CR, so it could be used by kubevirt users.

* enabling the `NetworkBindingPlugins` kubevirt
feature-gate on kubevirt CR is not needed as it is already set by
default by HCO [1].

[0] kubevirt/community#280
[1]
kubevirt#2603

Signed-off-by: Ram Lavi <[email protected]>
  • Loading branch information
RamLavi committed Aug 4, 2024
1 parent 45510fa commit 0edec0a
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 3 deletions.
53 changes: 50 additions & 3 deletions controllers/operands/kubevirt.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"fmt"
"maps"
"os"
"path"
"reflect"
"strconv"
"strings"
Expand Down Expand Up @@ -45,6 +46,12 @@ const (
DefaultARM64EmulatedMachines = "virt*"
)

const (
// Needs to align with the NAD that will be deployed by CNAO
primaryUDNNetworkBindingName = "primary-user-defined-network"
primaryUDNNetworkBindingNamespace = "default"
)

var (
useKVMEmulation = false
)
Expand Down Expand Up @@ -421,11 +428,16 @@ func getKVConfig(hc *hcov1beta1.HyperConverged) (*kubevirtcorev1.KubeVirtConfigu

seccompConfig := getKVSeccompConfig()

networkBindings, err := getNetworkBindings(hc.Spec.NetworkBinding, hc.Spec.FeatureGates)
if err != nil {
return nil, err
}

config := &kubevirtcorev1.KubeVirtConfiguration{
DeveloperConfiguration: devConfig,
NetworkConfiguration: &kubevirtcorev1.NetworkConfiguration{
NetworkInterface: string(kubevirtcorev1.MasqueradeInterface),
Binding: hc.Spec.NetworkBinding,
Binding: networkBindings,
},
MigrationConfiguration: kvLiveMigration,
PermittedHostDevices: toKvPermittedHostDevices(hc.Spec.PermittedHostDevices),
Expand Down Expand Up @@ -509,10 +521,30 @@ func getKVConfig(hc *hcov1beta1.HyperConverged) (*kubevirtcorev1.KubeVirtConfigu
if hc.Spec.ResourceRequirements != nil {
config.AutoCPULimitNamespaceLabelSelector = hc.Spec.ResourceRequirements.AutoCPULimitNamespaceLabelSelector.DeepCopy()
}

return config, nil
}

func getNetworkBindings(
hcoNetworkBindings map[string]kubevirtcorev1.InterfaceBindingPlugin,
hcoFeatureGates hcov1beta1.HyperConvergedFeatureGates) (map[string]kubevirtcorev1.InterfaceBindingPlugin, error) {
networkBindings := maps.Clone(hcoNetworkBindings)

if hcoFeatureGates.PrimaryUserDefinedNetworkBinding != nil && *hcoFeatureGates.PrimaryUserDefinedNetworkBinding {
if networkBindings == nil {
networkBindings = make(map[string]kubevirtcorev1.InterfaceBindingPlugin)
}

var sidecarImage string
var ok bool
if sidecarImage, ok = os.LookupEnv(hcoutil.PrimaryUDNImageEnvV); !ok {
return nil, errors.New("failed to get primary UDN image env Var")
}
networkBindings[primaryUDNNetworkBindingName] = primaryUserDefinedNetworkBinding(sidecarImage)
}
return networkBindings, nil

}

func getObsoleteCPUConfig(hcObsoleteCPUConf *hcov1beta1.HyperConvergedObsoleteCPUs) (map[string]bool, string) {
obsoleteCPUModels := make(map[string]bool)
for _, cpu := range hardcodedObsoleteCPUModels {
Expand Down Expand Up @@ -736,6 +768,22 @@ func getKVDevConfig(hc *hcov1beta1.HyperConverged) *kubevirtcorev1.DeveloperConf
return devConf
}

func primaryUserDefinedNetworkBinding(sidecarImage string) kubevirtcorev1.InterfaceBindingPlugin {
const bindingComputeMemoryOverhead = "500Mi"
return kubevirtcorev1.InterfaceBindingPlugin{
NetworkAttachmentDefinition: path.Join(primaryUDNNetworkBindingNamespace, primaryUDNNetworkBindingName),
SidecarImage: sidecarImage,
Migration: &kubevirtcorev1.InterfaceBindingMigration{
Method: kubevirtcorev1.LinkRefresh,
},
ComputeResourceOverhead: &corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceMemory: resource.MustParse(bindingComputeMemoryOverhead),
},
},
}
}

// Static for now, could be configured in the HCO CR in the future
func getKVSeccompConfig() *kubevirtcorev1.SeccompConfiguration {
return &kubevirtcorev1.SeccompConfiguration{
Expand Down Expand Up @@ -811,7 +859,6 @@ func getFeatureGateChecks(featureGates *hcov1beta1.HyperConvergedFeatureGates) [
if featureGates.AutoResourceLimits != nil && *featureGates.AutoResourceLimits {
fgs = append(fgs, kvAutoResourceLimits)
}

if featureGates.AlignCPUs != nil && *featureGates.AlignCPUs {
fgs = append(fgs, kvAlignCPUs)
}
Expand Down
61 changes: 61 additions & 0 deletions controllers/operands/kubevirt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1815,6 +1815,7 @@ Version: 1.2.3`)
Context("Feature Gates", func() {

getClusterInfo := hcoutil.GetClusterInfo
const expectedPrimaryUDNImage = "quay.io/some-org/some-repo@some-sha"

BeforeEach(func() {
hcoutil.GetClusterInfo = func() hcoutil.ClusterInfo {
Expand All @@ -1826,6 +1827,14 @@ Version: 1.2.3`)
hcoutil.GetClusterInfo = getClusterInfo
})

BeforeEach(func() {
Expect(os.Setenv(hcoutil.PrimaryUDNImageEnvV, expectedPrimaryUDNImage)).To(Succeed())
})

AfterEach(func() {
Expect(os.Unsetenv(hcoutil.PrimaryUDNImageEnvV)).To(Succeed())
})

Context("test feature gates in NewKubeVirt", func() {
It("should add the WithHostPassthroughCPU feature gate if it's set in HyperConverged CR", func() {
// one enabled, one disabled and one missing
Expand Down Expand Up @@ -2056,6 +2065,58 @@ Version: 1.2.3`)
Expect(existingResource.Annotations).ToNot(HaveKey(kubevirtcorev1.EmulatorThreadCompleteToEvenParity))
})

It("should add the Primary User Defined Network Binding to Kubevirt CR if PrimaryUserDefinedNetworkBinding is true in HyperConverged CR", func() {
hco.Spec.FeatureGates = hcov1beta1.HyperConvergedFeatureGates{
PrimaryUserDefinedNetworkBinding: ptr.To(true),
}
hco.Spec.NetworkBinding = nil

existingResource, err := NewKubeVirt(hco)
Expect(err).ToNot(HaveOccurred())

Expect(existingResource.Spec.Configuration.NetworkConfiguration).NotTo(BeNil())
Expect(existingResource.Spec.Configuration.NetworkConfiguration.Binding).NotTo(BeNil())
expectedInterfaceBindingPlugin := kubevirtcorev1.InterfaceBindingPlugin{
NetworkAttachmentDefinition: primaryUDNNetworkBindingNamespace + "/" + primaryUDNNetworkBindingName,
SidecarImage: expectedPrimaryUDNImage,
Migration: &kubevirtcorev1.InterfaceBindingMigration{
Method: kubevirtcorev1.LinkRefresh,
},
ComputeResourceOverhead: &corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceMemory: resource.MustParse("500Mi"),
},
},
}
Expect(existingResource.Spec.Configuration.NetworkConfiguration.Binding[primaryUDNNetworkBindingName]).To(Equal(expectedInterfaceBindingPlugin))
})

It("should not add the Primary User Defined Network Binding to Kubevirt CR if PrimaryUserDefinedNetworkBinding is false in HyperConverged CR", func() {
hco.Spec.FeatureGates = hcov1beta1.HyperConvergedFeatureGates{
PrimaryUserDefinedNetworkBinding: ptr.To(false),
}
hco.Spec.NetworkBinding = nil

existingResource, err := NewKubeVirt(hco)
Expect(err).ToNot(HaveOccurred())

Expect(existingResource.Spec.Configuration.NetworkConfiguration).NotTo(BeNil())
Expect(existingResource.Spec.Configuration.NetworkConfiguration.Binding).To(BeNil())
})

It("should not add the Primary User Defined Network Binding to Kubevirt CR if PrimaryUserDefinedNetworkBinding is not set in HyperConverged CR", func() {
hco.Spec.FeatureGates = hcov1beta1.HyperConvergedFeatureGates{
PrimaryUserDefinedNetworkBinding: nil,
}
hco.Spec.NetworkBinding = nil

existingResource, err := NewKubeVirt(hco)
Expect(err).ToNot(HaveOccurred())

Expect(existingResource.Spec.Configuration.NetworkConfiguration).NotTo(BeNil())
Expect(existingResource.Spec.Configuration.NetworkConfiguration.Binding).To(BeNil())
})

It("should not add the feature gates if FeatureGates field is empty", func() {
mandatoryKvFeatureGates = getMandatoryKvFeatureGates(false)
hco.Spec.FeatureGates = hcov1beta1.HyperConvergedFeatureGates{}
Expand Down

0 comments on commit 0edec0a

Please sign in to comment.