Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 60 additions & 1 deletion test/extended/networking/kubevirt/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package kubevirt

import (
"bytes"
"html/template"
"text/template"
)

const (
Expand Down Expand Up @@ -196,6 +196,63 @@ spec:
password: fedora
chpasswd: { expire: False }
name: cloudinitdisk
`
FedoraVMWithPreconfiguredPrimaryUDNAttachment = `
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
name: {{ .VMName }}
namespace: {{ .VMNamespace }}
spec:
runStrategy: Always
template:
{{- if .PreconfiguredIP }}
metadata:
annotations:
network.kubevirt.io/addresses: {{ printf "%q" .PreconfiguredIP }}
{{- end }}
spec:
domain:
devices:
disks:
- name: containerdisk
disk:
bus: virtio
- name: cloudinitdisk
disk:
bus: virtio
interfaces:
- name: overlay
binding:
name: {{ .NetBindingName }}
{{- if .PreconfiguredMAC }}
macAddress: "{{ .PreconfiguredMAC }}"
{{- end }}
machine:
type: ""
resources:
requests:
memory: 2048M
networks:
- name: overlay
pod: {}
terminationGracePeriodSeconds: 0
volumes:
- name: containerdisk
containerDisk:
image: {{ .FedoraContainterDiskImage }}
- name: cloudinitdisk
cloudInitNoCloud:
networkData: |
version: 2
ethernets:
eth0:
dhcp4: true
dhcp6: true
userData: |-
#cloud-config
password: fedora
chpasswd: { expire: False }
`
vmimTemplate = `
apiVersion: kubevirt.io/v1
Expand All @@ -214,6 +271,8 @@ type CreationTemplateParams struct {
FedoraContainterDiskImage string
NetBindingName string
NetworkName string
PreconfiguredIP string
PreconfiguredMAC string
}

func renderVMTemplate(vmTemplateString string, params CreationTemplateParams) (string, error) {
Expand Down
121 changes: 119 additions & 2 deletions test/extended/networking/livemigration.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,12 @@ var _ = Describe("[sig-network][OCPFeatureGate:PersistentIPsForVirtualization][F
DescribeTableSubtree("created using",
func(createNetworkFn func(netConfig networkAttachmentConfigParams) networkAttachmentConfig) {

DescribeTable("[Suite:openshift/network/virtualization] should keep ip", func(netConfig networkAttachmentConfigParams, vmResource string, opCmd func(cli *kubevirt.Client, vmNamespace, vmName string)) {
DescribeTable("[Suite:openshift/network/virtualization] should keep ip", func(netConfig networkAttachmentConfigParams, vmResource string, opCmd func(cli *kubevirt.Client, vmNamespace, vmName string), wlConfig ...workloadNetworkConfig) {
var err error
var workloadConfig workloadNetworkConfig
if len(wlConfig) > 0 {
workloadConfig = wlConfig[0]
}
l := map[string]string{
"e2e-framework": f.BaseName,
}
Expand Down Expand Up @@ -128,6 +132,14 @@ var _ = Describe("[sig-network][OCPFeatureGate:PersistentIPsForVirtualization][F
vmCreationParams.NetworkName = nadName
}

if len(workloadConfig.preconfiguredIPs) > 0 {
var err error
vmCreationParams.PreconfiguredIP, err = formatAddressesAnnotation(workloadConfig.preconfiguredIPs)
Expect(err).NotTo(HaveOccurred())
}
if workloadConfig.preconfiguredMAC != "" {
vmCreationParams.PreconfiguredMAC = workloadConfig.preconfiguredMAC
}
Expect(virtClient.CreateVM(vmResource, vmCreationParams)).To(Succeed())
waitForVMReadiness(virtClient, vmCreationParams.VMNamespace, vmCreationParams.VMName)

Expand All @@ -151,6 +163,17 @@ var _ = Describe("[sig-network][OCPFeatureGate:PersistentIPsForVirtualization][F
}
Expect(initialAddresses).To(HaveLen(expectedNumberOfAddresses))

if len(workloadConfig.preconfiguredIPs) > 0 {
By("Verifying VM received the preconfigured IP address(es)")
for _, expectedIP := range workloadConfig.preconfiguredIPs {
expectedIP = strings.TrimSpace(expectedIP)
Expect(initialAddresses).To(ContainElement(expectedIP), fmt.Sprintf("Expected IP %s not found in VM addresses %v", expectedIP, initialAddresses))
}
}
if workloadConfig.preconfiguredMAC != "" {
By("Verifying VM received the preconfigured MAC address")
verifyVMMAC(virtClient, vmName, workloadConfig.preconfiguredMAC)
}
httpServerPodsIPs := httpServerTestPodsMultusNetworkIPs(netConfig, httpServerPods)

By(fmt.Sprintf("Check east/west traffic before test operation using IPs: %v", httpServerPodsIPs))
Expand All @@ -173,6 +196,10 @@ var _ = Describe("[sig-network][OCPFeatureGate:PersistentIPsForVirtualization][F
ShouldNot(BeEmpty())
Expect(obtainedAddresses).To(ConsistOf(initialAddresses))

if workloadConfig.preconfiguredMAC != "" {
By("Verifying VM MAC address persisted after test operation")
verifyVMMAC(virtClient, vmName, workloadConfig.preconfiguredMAC)
}
By("Check east/west after test operation")
checkEastWestTraffic(virtClient, vmName, httpServerPodsIPs)
},
Expand Down Expand Up @@ -241,7 +268,51 @@ var _ = Describe("[sig-network][OCPFeatureGate:PersistentIPsForVirtualization][F
},
kubevirt.FedoraVMWithSecondaryNetworkAttachment,
restartVM,
))
),
Entry(
"[OCPFeatureGate:PreconfiguredUDNAddresses] when the VM with preconfigured IPs attached to a primary UDN is restarted",
networkAttachmentConfigParams{
name: nadName,
topology: "layer2",
role: "primary",
allowPersistentIPs: true,
},
kubevirt.FedoraVMWithPreconfiguredPrimaryUDNAttachment,
restartVM,
workloadNetworkConfig{
preconfiguredIPs: []string{"203.203.0.50", "2014:100:200::50"},
},
),
Entry(
"[OCPFeatureGate:PreconfiguredUDNAddresses] when the VM with preconfigured MAC attached to a primary UDN is restarted",
networkAttachmentConfigParams{
name: nadName,
topology: "layer2",
role: "primary",
allowPersistentIPs: true,
},
kubevirt.FedoraVMWithPreconfiguredPrimaryUDNAttachment,
restartVM,
workloadNetworkConfig{
preconfiguredMAC: "02:0A:0B:0C:0D:50",
},
),
Entry(
"[OCPFeatureGate:PreconfiguredUDNAddresses] when the VM with preconfigured IP and MAC attached to a primary UDN is migrated between nodes",
networkAttachmentConfigParams{
name: nadName,
topology: "layer2",
role: "primary",
allowPersistentIPs: true,
},
kubevirt.FedoraVMWithPreconfiguredPrimaryUDNAttachment,
migrateVM,
workloadNetworkConfig{
preconfiguredIPs: []string{"203.203.0.51", "2014:100:200::51"},
preconfiguredMAC: "02:0A:0B:0C:0D:51",
},
),
)
},
Entry("NetworkAttachmentDefinitions", func(c networkAttachmentConfigParams) networkAttachmentConfig {
netConfig := newNetworkAttachmentConfig(c)
Expand Down Expand Up @@ -428,6 +499,14 @@ func obtainAddresses(virtClient *kubevirt.Client, vmName string) ([]string, erro
return addressFromStatus(virtClient, vmName)
}

func obtainMAC(virtClient *kubevirt.Client, vmName string) (string, error) {
macStr, err := virtClient.GetJSONPath("vmi", vmName, "{@.status.interfaces[0].mac}")
if err != nil {
return "", fmt.Errorf("failed to extract the MAC address from VM %q: %w", vmName, err)
}
return strings.ToUpper(macStr), nil
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do you need to use ToUpper ? It is perfectly able to parse macs with lowercased valid hex characters (a through F).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

at the end we're comparing strings: {@.status.interfaces[0].mac} gives the MAC in lower case, we compare it to the MAC string with upper. I aligned them to work fluently, but we can instead input MACs with lower case..

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see ! OK, we're good.

Maybe it would be preferable to actually compare macs instead, but this solution is OK for me.

}

func restartVM(cli *kubevirt.Client, vmNamespace, vmName string) {
GinkgoHelper()
By(fmt.Sprintf("Restarting vmi %s/%s", vmNamespace, vmName))
Expand All @@ -442,6 +521,22 @@ func migrateVM(cli *kubevirt.Client, vmNamespace, vmName string) {
waitForVMIMSuccess(cli, vmNamespace, vmName)
}

func verifyVMMAC(virtClient *kubevirt.Client, vmName, expectedMAC string) {
GinkgoHelper()
var actualMAC string
Eventually(func(g Gomega) string {
GinkgoHelper()

var err error
actualMAC, err = obtainMAC(virtClient, vmName)
g.Expect(err).NotTo(HaveOccurred(), "Failed to obtain MAC address for VM")
return actualMAC
}).
WithPolling(time.Second).
WithTimeout(5 * time.Minute).
Should(Equal(expectedMAC))
}

func waitForPodsCondition(fr *framework.Framework, pods []*corev1.Pod, conditionFn func(g Gomega, pod *corev1.Pod)) {
for _, pod := range pods {
Eventually(func(g Gomega) {
Expand Down Expand Up @@ -627,3 +722,25 @@ func networkName(netSpecConfig string) string {
Expect(json.Unmarshal([]byte(netSpecConfig), &nc)).To(Succeed())
return nc.Name
}

// formatAddressesAnnotation converts slice of IPs to the required JSON format for kubevirt addresses annotation
func formatAddressesAnnotation(preconfiguredIPs []string) (string, error) {
const primaryUDNNetworkName = "overlay"
if len(preconfiguredIPs) == 0 {
return "", nil
}

ips := make([]string, len(preconfiguredIPs))
for i, ip := range preconfiguredIPs {
ips[i] = strings.TrimSpace(ip)
}

staticIPs, err := json.Marshal(map[string][]string{
primaryUDNNetworkName: ips,
})
if err != nil {
return "", fmt.Errorf("failed to marshal static IPs: %w", err)
}

return string(staticIPs), nil
}
6 changes: 6 additions & 0 deletions test/extended/networking/network_segmentation.go
Original file line number Diff line number Diff line change
Expand Up @@ -1890,6 +1890,12 @@ type networkAttachmentConfigParams struct {
role string
}

// workloadNetworkConfig contains workload-specific network customizations
type workloadNetworkConfig struct {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it makes sense to "prepare" for the future and assume we want to one day have multiple of these. For that, you'd have to add here the workload name. If we ever want to extend this to pods (god forbid) we might actually have to add the resource type as well. Anyway, I'm digressing ...

We can postpone it until it is actually needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes let's postpone until we know more.

preconfiguredIPs []string
preconfiguredMAC string
}

type networkAttachmentConfig struct {
networkAttachmentConfigParams
}
Expand Down
12 changes: 12 additions & 0 deletions test/extended/util/annotate/generated/zz_generated.annotations.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading