Skip to content

Commit

Permalink
tests/e2e, persistentip: Introduce primary-UDN helper functions
Browse files Browse the repository at this point in the history
Introducing the functions needed in order to run the current test suite
for primary UDN interfaces:
- defaultNetworkStatusAnnotationIPs - as the getIP function for primary
UDN.
- vmiWithPasst - as the vmi Generating function for primary UDN.
These will be introduced as parameter functions when primary-UDN Entry
is introduced in future commit.

Moreover, since the function getting the IPs for primary-UDN case needs
to return error, this is added to the general function signature.

Signed-off-by: Ram Lavi <[email protected]>
  • Loading branch information
RamLavi committed Oct 8, 2024
1 parent 9505683 commit 8c58962
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 11 deletions.
55 changes: 48 additions & 7 deletions test/e2e/persistentips_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const (

type testParams struct {
role string
ipsFrom func(vmi *kubevirtv1.VirtualMachineInstance) []string
ipsFrom func(vmi *kubevirtv1.VirtualMachineInstance) ([]string, error)
vmi func(namespace string) *kubevirtv1.VirtualMachineInstance
}

Expand Down Expand Up @@ -114,7 +114,8 @@ var _ = DescribeTableSubtree("Persistent IPs", func(params testParams) {

It("should keep ips after live migration", func() {
Expect(testenv.Client.Get(context.Background(), client.ObjectKeyFromObject(vmi), vmi)).To(Succeed())
vmiIPsBeforeMigration := params.ipsFrom(vmi)
vmiIPsBeforeMigration, err := params.ipsFrom(vmi)
Expect(err).NotTo(HaveOccurred())
Expect(vmiIPsBeforeMigration).NotTo(BeEmpty())

testenv.LiveMigrateVirtualMachine(td.Namespace, vm.Name)
Expand Down Expand Up @@ -185,7 +186,8 @@ var _ = DescribeTableSubtree("Persistent IPs", func(params testParams) {

It("should keep ips after restart", func() {
Expect(testenv.Client.Get(context.Background(), client.ObjectKeyFromObject(vmi), vmi)).To(Succeed())
vmiIPsBeforeRestart := params.ipsFrom(vmi)
vmiIPsBeforeRestart, err := params.ipsFrom(vmi)
Expect(err).NotTo(HaveOccurred())
Expect(vmiIPsBeforeRestart).NotTo(BeEmpty())
vmiUUIDBeforeRestart := vmi.UID

Expand Down Expand Up @@ -232,7 +234,8 @@ var _ = DescribeTableSubtree("Persistent IPs", func(params testParams) {
ShouldNot(BeEmpty())

Expect(testenv.Client.Get(context.Background(), client.ObjectKeyFromObject(vmi), vmi)).To(Succeed())
ips := params.ipsFrom(vmi)
ips, err := params.ipsFrom(vmi)
Expect(err).NotTo(HaveOccurred())
Expect(ips).NotTo(BeEmpty())
})

Expand Down Expand Up @@ -279,7 +282,8 @@ var _ = DescribeTableSubtree("Persistent IPs", func(params testParams) {

It("should keep ips after live migration", func() {
Expect(testenv.Client.Get(context.Background(), client.ObjectKeyFromObject(vmi), vmi)).To(Succeed())
vmiIPsBeforeMigration := params.ipsFrom(vmi)
vmiIPsBeforeMigration, err := params.ipsFrom(vmi)
Expect(err).NotTo(HaveOccurred())
Expect(vmiIPsBeforeMigration).NotTo(BeEmpty())

testenv.LiveMigrateVirtualMachine(td.Namespace, vmi.Name)
Expand Down Expand Up @@ -331,8 +335,17 @@ func removeFinalizersPatch() ([]byte, error) {
return json.Marshal(patch)
}

func secondaryNetworkVMIStatusIPs(vmi *kubevirtv1.VirtualMachineInstance) []string {
return testenv.GetIPsFromVMIStatus(vmi, secondaryLogicalNetworkInterfaceName)
func secondaryNetworkVMIStatusIPs(vmi *kubevirtv1.VirtualMachineInstance) ([]string, error) {
return testenv.GetIPsFromVMIStatus(vmi, secondaryLogicalNetworkInterfaceName), nil
}

func defaultNetworkStatusAnnotationIPs(vmi *kubevirtv1.VirtualMachineInstance) ([]string, error) {
defNetworkStatus, err := testenv.DefaultNetworkStatus(vmi)
if err != nil {
return nil, err
}

return defNetworkStatus.IPs, nil
}

func vmiWithMultus(namespace string) *kubevirtv1.VirtualMachineInstance {
Expand All @@ -357,3 +370,31 @@ func vmiWithMultus(namespace string) *kubevirtv1.VirtualMachineInstance {
}),
)
}

func vmiWithPasst(namespace string) *kubevirtv1.VirtualMachineInstance {
const (
interfaceName = "passtnet"
cloudInitNetworkData = `
version: 2
ethernets:
eth0:
dhcp4: true`
)
return testenv.NewVirtualMachineInstance(
namespace,
testenv.WithMemory("2048Mi"),
testenv.WithInterface(kubevirtv1.Interface{
Name: interfaceName,
Binding: &kubevirtv1.PluginBinding{
Name: "passt",
},
}),
testenv.WithNetwork(kubevirtv1.Network{
Name: interfaceName,
NetworkSource: kubevirtv1.NetworkSource{
Pod: &kubevirtv1.PodNetwork{},
},
}),
testenv.WithCloudInitNoCloudVolume(cloudInitNetworkData),
)
}
13 changes: 13 additions & 0 deletions test/env/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,19 @@ func WithNetwork(network kubevirtv1.Network) VMIOption {
}
}

func WithCloudInitNoCloudVolume(cloudInitNetworkData string) VMIOption {
return func(vmi *kubevirtv1.VirtualMachineInstance) {
vmi.Spec.Volumes = append(vmi.Spec.Volumes, kubevirtv1.Volume{
Name: "cloudinitdisk",
VolumeSource: kubevirtv1.VolumeSource{
CloudInitNoCloud: &kubevirtv1.CloudInitNoCloudSource{
NetworkData: cloudInitNetworkData,
},
},
})
}
}

type VMOption func(vm *kubevirtv1.VirtualMachine)

func NewVirtualMachine(vmi *kubevirtv1.VirtualMachineInstance, opts ...VMOption) *kubevirtv1.VirtualMachine {
Expand Down
77 changes: 77 additions & 0 deletions test/env/getter.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@ package env

import (
"context"
"encoding/json"
"fmt"

nadv1 "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/apis/k8s.cni.cncf.io/v1"

corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"sigs.k8s.io/controller-runtime/pkg/client"

Expand Down Expand Up @@ -46,3 +51,75 @@ func GetIPsFromVMIStatus(vmi *kubevirtv1.VirtualMachineInstance, networkInterfac
}
return ifaceStatus.IPs
}

func virtualMachineInstancePod(vmi *kubevirtv1.VirtualMachineInstance) (*corev1.Pod, error) {
pod, err := lookupPodBySelector(vmi.Namespace, vmiLabelSelector(vmi), vmiFieldSelector(vmi))
if err != nil {
return nil, fmt.Errorf("failed to find pod for VMI %s (%s)", vmi.Name, string(vmi.GetUID()))
}
return pod, nil
}

func lookupPodBySelector(namespace string, labelSelector, fieldSelector map[string]string) (*corev1.Pod, error) {
pods := &corev1.PodList{}
err := Client.List(
context.Background(),
pods,
client.InNamespace(namespace),
client.MatchingLabels(labelSelector),
client.MatchingFields(fieldSelector))
if err != nil {
return nil, err
}

if len(pods.Items) == 0 {
return nil, fmt.Errorf("failed to lookup pod with labels %v, fields %v in namespace %s", labelSelector, fieldSelector, namespace)
}

return &pods.Items[0], nil
}

func vmiLabelSelector(vmi *kubevirtv1.VirtualMachineInstance) map[string]string {
return map[string]string{kubevirtv1.CreatedByLabel: string(vmi.GetUID())}
}

func vmiFieldSelector(vmi *kubevirtv1.VirtualMachineInstance) map[string]string {
fieldSelectors := map[string]string{}
if vmi.Status.Phase == kubevirtv1.Running {
const podPhase = "status.phase"
fieldSelectors[podPhase] = string(corev1.PodRunning)
}
return fieldSelectors
}

func parsePodNetworkStatusAnnotation(podNetStatus string) ([]nadv1.NetworkStatus, error) {
if len(podNetStatus) == 0 {
return nil, fmt.Errorf("network status annotation not found")
}

var netStatus []nadv1.NetworkStatus
if err := json.Unmarshal([]byte(podNetStatus), &netStatus); err != nil {
return nil, err
}

return netStatus, nil
}

func DefaultNetworkStatus(vmi *kubevirtv1.VirtualMachineInstance) (*nadv1.NetworkStatus, error) {
virtLauncherPod, err := virtualMachineInstancePod(vmi)
if err != nil {
return nil, err
}

netStatuses, err := parsePodNetworkStatusAnnotation(virtLauncherPod.Annotations[nadv1.NetworkStatusAnnot])
if err != nil {
return nil, err
}

for _, netStatus := range netStatuses {
if netStatus.Default {
return &netStatus, nil
}
}
return nil, fmt.Errorf("primary IPs not found")
}
15 changes: 11 additions & 4 deletions test/env/matcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,18 @@ func vmiStatusConditions(vmi *kubevirtv1.VirtualMachineInstance) []kubevirtv1.Vi
return vmi.Status.Conditions
}

func MatchIPs(getIPsFunc func(vmi *kubevirtv1.VirtualMachineInstance) []string, ipsMatcher gomegatypes.GomegaMatcher) gomegatypes.GomegaMatcher {
return WithTransform(func(vmi *kubevirtv1.VirtualMachineInstance) []string {
return getIPsFunc(vmi)
type IPResult struct {
IPs []string
Err error
}

func MatchIPs(getIPsFunc func(vmi *kubevirtv1.VirtualMachineInstance) ([]string, error), ipsMatcher gomegatypes.GomegaMatcher) gomegatypes.GomegaMatcher {
return WithTransform(func(vmi *kubevirtv1.VirtualMachineInstance) IPResult {
ips, err := getIPsFunc(vmi)
return IPResult{IPs: ips, Err: err}
}, SatisfyAll(
WithTransform(func(ips []string) []string { return ips }, ipsMatcher),
WithTransform(func(result IPResult) error { return result.Err }, Succeed()),
WithTransform(func(result IPResult) []string { return result.IPs }, ipsMatcher),
))
}

Expand Down

0 comments on commit 8c58962

Please sign in to comment.