Skip to content

Commit 7d16a92

Browse files
RamLavimaiqueb
andcommitted
networking: Add primaryUDN VM Addr collision test w/ preconfigured addr
Validates that KubeVirt VMs with preconfigured MAC and IP addresses maintain those addresses correctly before and after a vmi with duplicate IP/MAC request is made, and that the vmi with the duplicate address get the appropriate address conflict error event. Co-authored-by: Miguel Duarte Barroso <[email protected]> Signed-off-by: Ram Lavi <[email protected]>
1 parent 87d58ca commit 7d16a92

File tree

2 files changed

+108
-0
lines changed

2 files changed

+108
-0
lines changed

test/extended/networking/kubevirt/client.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import (
1616
"strings"
1717
"time"
1818

19+
"sigs.k8s.io/yaml"
20+
1921
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2022
e2ekubectl "k8s.io/kubernetes/test/e2e/framework/kubectl"
2123

@@ -93,6 +95,64 @@ func (c *Client) GetJSONPath(resource, name, jsonPath string) (string, error) {
9395
}
9496
return strings.TrimSuffix(strings.TrimPrefix(output, `"`), `"`), nil
9597
}
98+
99+
func (c *Client) GetPodsByLabel(labelKey, labelValue string) ([]string, error) {
100+
output, err := c.oc.AsAdmin().Run("get").Args("pods", "-n", c.oc.Namespace(), "-l", fmt.Sprintf("%s=%s", labelKey, labelValue), "-o", "name").Output()
101+
if err != nil {
102+
return nil, err
103+
}
104+
if output == "" {
105+
return []string{}, nil
106+
}
107+
108+
lines := strings.Split(strings.TrimSpace(output), "\n")
109+
podNames := make([]string, 0, len(lines))
110+
for _, line := range lines {
111+
if line != "" {
112+
podName := strings.TrimPrefix(line, "pod/")
113+
podNames = append(podNames, podName)
114+
}
115+
}
116+
return podNames, nil
117+
}
118+
119+
func (c *Client) GetEventsForPod(podName string) ([]string, error) {
120+
output, err := c.oc.AsAdmin().Run("get").Args("events", "-n", c.oc.Namespace(), "--field-selector", fmt.Sprintf("involvedObject.name=%s,involvedObject.kind=Pod", podName), "-o", "custom-columns=MESSAGE:.message", "--no-headers").Output()
121+
if err != nil {
122+
return nil, err
123+
}
124+
if output == "" {
125+
return []string{}, nil
126+
}
127+
lines := strings.Split(strings.TrimSpace(output), "\n")
128+
messages := make([]string, 0, len(lines))
129+
for _, line := range lines {
130+
if line != "" {
131+
messages = append(messages, line)
132+
}
133+
}
134+
return messages, nil
135+
}
136+
137+
func (c *Client) CreateVMIFromSpec(vmNamespace, vmName string, vmiSpec map[string]interface{}) error {
138+
newVMI := map[string]interface{}{
139+
"apiVersion": "kubevirt.io/v1",
140+
"kind": "VirtualMachineInstance",
141+
"metadata": map[string]interface{}{
142+
"name": vmName,
143+
"namespace": vmNamespace,
144+
},
145+
"spec": vmiSpec,
146+
}
147+
148+
newVMIYAML, err := yaml.Marshal(newVMI)
149+
if err != nil {
150+
return err
151+
}
152+
153+
return c.Apply(string(newVMIYAML))
154+
}
155+
96156
func ensureVirtctl(oc *exutil.CLI, dir string) (string, error) {
97157
filepath := filepath.Join(dir, "virtctl")
98158
_, err := os.Stat(filepath)

test/extended/networking/livemigration.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,20 @@ var _ = Describe("[sig-network][OCPFeatureGate:PersistentIPsForVirtualization][F
312312
preconfiguredMAC: "02:0A:0B:0C:0D:51",
313313
},
314314
),
315+
Entry(
316+
"[OCPFeatureGate:PreconfiguredUDNAddresses] when the VM with preconfigured IP address is created when the address is already taken",
317+
networkAttachmentConfigParams{
318+
name: nadName,
319+
topology: "layer2",
320+
role: "primary",
321+
allowPersistentIPs: true,
322+
},
323+
kubevirt.FedoraVMWithPreconfiguredPrimaryUDNAttachment,
324+
duplicateVM,
325+
workloadNetworkConfig{
326+
preconfiguredIPs: []string{"203.203.0.100", "2014:100:200::100"},
327+
},
328+
),
315329
)
316330
},
317331
Entry("NetworkAttachmentDefinitions", func(c networkAttachmentConfigParams) networkAttachmentConfig {
@@ -537,6 +551,40 @@ func verifyVMMAC(virtClient *kubevirt.Client, vmName, expectedMAC string) {
537551
Should(Equal(expectedMAC))
538552
}
539553

554+
func duplicateVM(cli *kubevirt.Client, vmNamespace, vmName string) {
555+
GinkgoHelper()
556+
duplicateVMName := vmName + "-duplicate"
557+
By(fmt.Sprintf("Duplicating VM %s/%s to %s/%s", vmNamespace, vmName, vmNamespace, duplicateVMName))
558+
559+
vmiSpecJSON, err := cli.GetJSONPath("vmi", vmName, "{.spec}")
560+
Expect(err).NotTo(HaveOccurred())
561+
var vmiSpec map[string]interface{}
562+
Expect(json.Unmarshal([]byte(vmiSpecJSON), &vmiSpec)).To(Succeed())
563+
564+
Expect(cli.CreateVMIFromSpec(vmNamespace, duplicateVMName, vmiSpec)).To(Succeed())
565+
waitForVMPodEventWithMessage(cli, vmNamespace, duplicateVMName, "IP is already allocated", 2*time.Minute)
566+
}
567+
568+
func waitForVMPodEventWithMessage(vmClient *kubevirt.Client, vmNamespace, vmName, expectedEventMessage string, timeout time.Duration) {
569+
GinkgoHelper()
570+
By(fmt.Sprintf("Waiting for event containing %q on VM %s/%s virt-launcher pod", expectedEventMessage, vmNamespace, vmName))
571+
572+
Eventually(func(g Gomega) []string {
573+
const vmLabelKey = "vm.kubevirt.io/name"
574+
podNames, err := vmClient.GetPodsByLabel(vmLabelKey, vmName)
575+
g.Expect(err).NotTo(HaveOccurred(), "Failed to get pods by label %s=%s", vmLabelKey, vmName)
576+
g.Expect(podNames).To(HaveLen(1), "Expected exactly one virt-launcher pod for VM %s/%s, but found %d pods: %v", vmNamespace, vmName, len(podNames), podNames)
577+
578+
virtLauncherPodName := podNames[0]
579+
eventMessages, err := vmClient.GetEventsForPod(virtLauncherPodName)
580+
g.Expect(err).NotTo(HaveOccurred(), "Failed to get events for pod %s", virtLauncherPodName)
581+
582+
return eventMessages
583+
}).WithPolling(time.Second).WithTimeout(timeout).Should(
584+
ContainElement(ContainSubstring(expectedEventMessage)),
585+
fmt.Sprintf("Expected to find an event containing %q", expectedEventMessage))
586+
}
587+
540588
func waitForPodsCondition(fr *framework.Framework, pods []*corev1.Pod, conditionFn func(g Gomega, pod *corev1.Pod)) {
541589
for _, pod := range pods {
542590
Eventually(func(g Gomega) {

0 commit comments

Comments
 (0)