From 3e8034fe13bd61d11f34f3ba62bc7209d96379b1 Mon Sep 17 00:00:00 2001 From: Shelly Kagan Date: Sun, 21 Apr 2024 16:21:25 +0300 Subject: [PATCH 1/6] Update version of instancetype and prefernce yamls to use beta instead of alpha Signed-off-by: Shelly Kagan --- tests/manifests/instancetype.yaml | 2 +- tests/manifests/preference.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/manifests/instancetype.yaml b/tests/manifests/instancetype.yaml index 3ce9b70a..0f3c5dc7 100644 --- a/tests/manifests/instancetype.yaml +++ b/tests/manifests/instancetype.yaml @@ -1,4 +1,4 @@ -apiVersion: instancetype.kubevirt.io/v1alpha2 +apiVersion: instancetype.kubevirt.io/v1beta1 kind: VirtualMachineInstancetype metadata: name: test-vm-instancetype diff --git a/tests/manifests/preference.yaml b/tests/manifests/preference.yaml index 1e5d373f..d39e8b33 100644 --- a/tests/manifests/preference.yaml +++ b/tests/manifests/preference.yaml @@ -1,4 +1,4 @@ -apiVersion: instancetype.kubevirt.io/v1alpha2 +apiVersion: instancetype.kubevirt.io/v1beta1 kind: VirtualMachinePreference metadata: name: test-vm-preference From 682e28302475e4613c3a94f822d9de3e82e4c8e5 Mon Sep 17 00:00:00 2001 From: Shelly Kagan Date: Sun, 21 Apr 2024 16:21:52 +0300 Subject: [PATCH 2/6] Move start of vm to after writer pod succeeded First write to the pvc and only after start the vm, this will prevent the option of pvc already mounted to the virt-launcher and then the writer-pod might fail writing from another pod it will be scheduled on. Also delete redundant stop of vm before deletion. Fixes: https://issues.redhat.com/browse/CNV-39913 Signed-off-by: Shelly Kagan --- tests/resource_filtering_test.go | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/tests/resource_filtering_test.go b/tests/resource_filtering_test.go index 69983294..6ff76223 100644 --- a/tests/resource_filtering_test.go +++ b/tests/resource_filtering_test.go @@ -542,16 +542,16 @@ var _ = Describe("Resource includes", func() { volumeName := vmSpec.Spec.DataVolumeTemplates[0].Name framework.EventuallyDVWith(f.KvClient, f.Namespace.Name, volumeName, 180, HaveSucceeded()) + By("Writing to PVC filesystem") + writerPod := runPodAndWaitSucceeded(f.KvClient, f.Namespace.Name, writerPod(volumeName)) + deletePod(f.KvClient, f.Namespace.Name, writerPod.Name) + By("Starting the virtual machine") err = framework.StartVirtualMachine(f.KvClient, f.Namespace.Name, vmSpec.Name) Expect(err).ToNot(HaveOccurred()) err = framework.WaitForVirtualMachineStatus(f.KvClient, f.Namespace.Name, vmSpec.Name, kvv1.VirtualMachineStatusRunning) Expect(err).ToNot(HaveOccurred()) - By("Writing to PVC filesystem") - writerPod := runPodAndWaitSucceeded(f.KvClient, f.Namespace.Name, writerPod(volumeName)) - deletePod(f.KvClient, f.Namespace.Name, writerPod.Name) - By("Pausing the virtual machine") err = framework.PauseVirtualMachine(f.KvClient, f.Namespace.Name, vmSpec.Name) Expect(err).ToNot(HaveOccurred()) @@ -566,10 +566,6 @@ var _ = Describe("Resource includes", func() { Expect(err).ToNot(HaveOccurred()) By("Deleting VMs") - err = framework.StopVirtualMachine(f.KvClient, f.Namespace.Name, vmSpec.Name) - Expect(err).ToNot(HaveOccurred()) - err = framework.WaitForVirtualMachineStatus(f.KvClient, f.Namespace.Name, vmSpec.Name, kvv1.VirtualMachineStatusStopped) - Expect(err).ToNot(HaveOccurred()) err = framework.DeleteVirtualMachine(f.KvClient, f.Namespace.Name, vmIncluded.Name) Expect(err).ToNot(HaveOccurred()) ok, err := framework.WaitVirtualMachineDeleted(f.KvClient, f.Namespace.Name, vmIncluded.Name) @@ -595,7 +591,7 @@ var _ = Describe("Resource includes", func() { By("Checking DataVolume import succeeds") framework.EventuallyDVWith(f.KvClient, f.Namespace.Name, volumeName, 180, HaveSucceeded()) - By("Verifying DataVolume is re-imported - file should not exists") + By("Verifying DataVolume has re-imported - file should not exists") readerPod := runPodAndWaitSucceeded(f.KvClient, f.Namespace.Name, verifyNoFile(volumeName)) deletePod(f.KvClient, f.Namespace.Name, readerPod.Name) }) From 38feab15ae3e5ca3b66c7de086d28f4b8eb3d1b0 Mon Sep 17 00:00:00 2001 From: Shelly Kagan Date: Sun, 21 Apr 2024 15:05:31 +0300 Subject: [PATCH 3/6] Gather all pod related functions in one place *Remove duplicated function (NewPod) *Fix pod security issues by using function that already handles that *Move pod functions to new file *Create and use wait for pod phase function Signed-off-by: Shelly Kagan --- tests/dv_backup_test.go | 21 +++-- tests/framework/pod.go | 140 +++++++++++++++++++++++++++++++ tests/framework/storage.go | 104 ----------------------- tests/resource_filtering_test.go | 81 ++++-------------- 4 files changed, 166 insertions(+), 180 deletions(-) create mode 100644 tests/framework/pod.go diff --git a/tests/dv_backup_test.go b/tests/dv_backup_test.go index 3f14e10d..b9de283f 100644 --- a/tests/dv_backup_test.go +++ b/tests/dv_backup_test.go @@ -9,7 +9,6 @@ import ( . "github.com/onsi/gomega" velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" cdiv1 "kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1" "kubevirt.io/kubevirt-velero-plugin/tests/framework" . "kubevirt.io/kubevirt-velero-plugin/tests/framework/matcher" @@ -122,14 +121,7 @@ var _ = Describe("DV Backup", func() { framework.EventuallyDVWith(f.KvClient, srcDv.Namespace, srcDv.Name, 180, HaveSucceeded()) By("Creating source pod") - podSpec := framework.NewPod("source-use-pod", sourceVolumeName, "while true; do echo hello; sleep 2; done") - _, err = f.KvClient.CoreV1().Pods(sourceNamespace.Name).Create(context.TODO(), podSpec, metav1.CreateOptions{}) - Expect(err).ToNot(HaveOccurred()) - Eventually(func() v1.PodPhase { - pod, err := f.KvClient.CoreV1().Pods(sourceNamespace.Name).Get(context.TODO(), podSpec.Name, metav1.GetOptions{}) - Expect(err).ToNot(HaveOccurred()) - return pod.Status.Phase - }, 90*time.Second, 2*time.Second).Should(Equal(v1.PodRunning)) + sourcePod := framework.RunPodAndWaitPhase(f.KvClient, sourceNamespace.Name, sourcePod(sourceVolumeName), v1.PodRunning) By("Creating clone DV - object under test") dvSpec := framework.NewCloneDataVolume(dvName, "100Mi", srcDv.Namespace, srcDv.Name, f.StorageClass) @@ -152,8 +144,7 @@ var _ = Describe("DV Backup", func() { Expect(ok).To(BeTrue()) By("Deleting source pod") - err = f.KvClient.CoreV1().Pods(sourceNamespace.Name).Delete(context.TODO(), podSpec.Name, metav1.DeleteOptions{}) - Expect(err).ToNot(HaveOccurred()) + framework.DeletePod(f.KvClient, sourceNamespace.Name, sourcePod.Name) By("Creating restore test-restore") err = framework.CreateRestoreForBackup(timeout, backupName, restoreName, f.BackupNamespace, true) @@ -167,3 +158,11 @@ var _ = Describe("DV Backup", func() { }) }) }) + +func sourcePod(volumeName string) *v1.Pod { + return framework.PodWithPvcSpec( + "source-use-pod", + volumeName, + []string{"sh"}, + []string{"-c", "while true; do echo hello; sleep 2; done"}) +} diff --git a/tests/framework/pod.go b/tests/framework/pod.go new file mode 100644 index 00000000..0ade4edf --- /dev/null +++ b/tests/framework/pod.go @@ -0,0 +1,140 @@ +package framework + +import ( + "context" + "fmt" + "time" + + ginkgo "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + v1 "k8s.io/api/core/v1" + "k8s.io/client-go/kubernetes" + "k8s.io/utils/pointer" + + apierrs "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "kubevirt.io/client-go/kubecli" +) + +const ( + busyboxImage = "quay.io/quay/busybox:latest" +) + +func PodWithPvcSpec(podName, pvcName string, cmd, args []string) *v1.Pod { + volumeName := "pv1" + // uid is used as the qemu group in fsGroup + const uid int64 = 107 + + return &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: podName, + Annotations: map[string]string{ + "cdi.kubevirt.io/testing": podName, + }, + }, + Spec: v1.PodSpec{ + SecurityContext: &v1.PodSecurityContext{ + FSGroup: pointer.Int64(uid), + }, + RestartPolicy: v1.RestartPolicyNever, + Containers: []v1.Container{ + { + Name: podName, + Image: busyboxImage, + Command: cmd, + Args: args, + Resources: v1.ResourceRequirements{ + Limits: map[v1.ResourceName]resource.Quantity{ + v1.ResourceCPU: *resource.NewQuantity(0, resource.DecimalSI), + v1.ResourceMemory: *resource.NewQuantity(0, resource.DecimalSI)}, + Requests: map[v1.ResourceName]resource.Quantity{ + v1.ResourceCPU: *resource.NewQuantity(0, resource.DecimalSI), + v1.ResourceMemory: *resource.NewQuantity(0, resource.DecimalSI)}, + }, + VolumeMounts: []v1.VolumeMount{ + { + Name: volumeName, + MountPath: "/pvc", + }, + }, + SecurityContext: &v1.SecurityContext{ + RunAsNonRoot: pointer.Bool(true), + RunAsUser: pointer.Int64(uid), + RunAsGroup: pointer.Int64(uid), + Capabilities: &v1.Capabilities{ + Drop: []v1.Capability{ + "ALL", + }, + }, + SeccompProfile: &v1.SeccompProfile{ + Type: v1.SeccompProfileTypeRuntimeDefault, + }, + AllowPrivilegeEscalation: pointer.Bool(false), + }, + }, + }, + Volumes: []v1.Volume{ + { + Name: volumeName, + VolumeSource: v1.VolumeSource{ + PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{ + ClaimName: pvcName, + }, + }, + }, + }, + }, + } +} + +func RunPodAndWaitPhase(kvClient kubecli.KubevirtClient, namespace string, podSpec *v1.Pod, expectedPhase v1.PodPhase) *v1.Pod { + ginkgo.By("creating a pod") + pod, err := kvClient.CoreV1().Pods(namespace).Create(context.Background(), podSpec, metav1.CreateOptions{}) + Expect(err).WithOffset(1).ToNot(HaveOccurred()) + + ginkgo.By("Wait for pod to reach a completed phase") + Eventually(func() v1.PodPhase { + updatedPod, err := kvClient.CoreV1().Pods(namespace).Get(context.Background(), pod.Name, metav1.GetOptions{}) + if err != nil { + fmt.Fprintf(ginkgo.GinkgoWriter, "Failed getting pod phase: %s\n", err) + return v1.PodUnknown + } + return updatedPod.Status.Phase + }, 2*time.Minute, 5*time.Second).WithOffset(1).Should(Equal(expectedPhase)) + + return pod +} + +func FindLauncherPod(client *kubernetes.Clientset, namespace string, vmName string) v1.Pod { + var pod v1.Pod + pods, err := client.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{ + LabelSelector: "kubevirt.io=virt-launcher", + }) + Expect(err).WithOffset(1).ToNot(HaveOccurred()) + for _, item := range pods.Items { + if ann, ok := item.GetAnnotations()["kubevirt.io/domain"]; ok && ann == vmName { + pod = item + } + } + Expect(pod).WithOffset(1).ToNot(BeNil()) + return pod +} + +func DeletePod(kvClient kubecli.KubevirtClient, namespace, podName string) { + ginkgo.By("Delete pod") + zero := int64(0) + err := kvClient.CoreV1().Pods(namespace).Delete(context.Background(), podName, + metav1.DeleteOptions{ + GracePeriodSeconds: &zero, + }) + Expect(err).WithOffset(1).ToNot(HaveOccurred()) + + ginkgo.By("verify deleted") + Eventually(func() error { + _, err := kvClient.CoreV1().Pods(namespace).Get(context.Background(), podName, metav1.GetOptions{}) + return err + }, 3*time.Minute, 5*time.Second). + WithOffset(1). + Should(Satisfy(apierrs.IsNotFound), "pod should disappear") +} diff --git a/tests/framework/storage.go b/tests/framework/storage.go index 7428c6aa..17aecbd5 100644 --- a/tests/framework/storage.go +++ b/tests/framework/storage.go @@ -12,7 +12,6 @@ import ( "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/resource" "k8s.io/client-go/kubernetes" - "k8s.io/utils/pointer" apierrs "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -25,7 +24,6 @@ import ( const ( pollInterval = 2 * time.Second waitTime = 180 * time.Second - busyboxImage = "quay.io/quay/busybox:latest" ) func IsDataVolumeGC(kvClient kubecli.KubevirtClient) bool { @@ -270,108 +268,6 @@ func NewPVC(pvcName, size, storageClass string) *v1.PersistentVolumeClaim { return pvcSpec } -func NewPod(podName, pvcName, cmd string) *v1.Pod { - return &v1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: podName, - Annotations: map[string]string{ - "cdi.kubevirt.io/testing": podName, - }, - }, - Spec: v1.PodSpec{ - // this may be causing an issue - TerminationGracePeriodSeconds: &[]int64{10}[0], - RestartPolicy: v1.RestartPolicyNever, - Containers: []v1.Container{ - { - Name: "runner", - Image: busyboxImage, - Command: []string{"/bin/sh", "-c", cmd}, - Resources: v1.ResourceRequirements{ - Limits: map[v1.ResourceName]resource.Quantity{ - v1.ResourceCPU: *resource.NewQuantity(0, resource.DecimalSI), - v1.ResourceMemory: *resource.NewQuantity(0, resource.DecimalSI)}, - Requests: map[v1.ResourceName]resource.Quantity{ - v1.ResourceCPU: *resource.NewQuantity(0, resource.DecimalSI), - v1.ResourceMemory: *resource.NewQuantity(0, resource.DecimalSI)}, - }, - VolumeMounts: []v1.VolumeMount{ - { - Name: "storage", - MountPath: "/mnt", - }, - }, - }, - }, - Volumes: []v1.Volume{ - { - Name: "storage", - VolumeSource: v1.VolumeSource{ - PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{ - ClaimName: pvcName, - }, - }, - }, - }, - }, - } -} - -func PodWithPvcSpec(podName, pvcName string, cmd, args []string) *v1.Pod { - volumeName := "pv1" - const uid int64 = 107 - - return &v1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - GenerateName: podName, - }, - Spec: v1.PodSpec{ - SecurityContext: &v1.PodSecurityContext{ - FSGroup: pointer.Int64(uid), - }, - RestartPolicy: v1.RestartPolicyNever, - Containers: []v1.Container{ - { - Name: podName, - Image: busyboxImage, - Command: cmd, - Args: args, - VolumeMounts: []v1.VolumeMount{ - { - Name: volumeName, - MountPath: "/pvc", - }, - }, - SecurityContext: &v1.SecurityContext{ - RunAsNonRoot: pointer.Bool(true), - RunAsUser: pointer.Int64(uid), - RunAsGroup: pointer.Int64(uid), - Capabilities: &v1.Capabilities{ - Drop: []v1.Capability{ - "ALL", - }, - }, - SeccompProfile: &v1.SeccompProfile{ - Type: v1.SeccompProfileTypeRuntimeDefault, - }, - AllowPrivilegeEscalation: pointer.Bool(false), - }, - }, - }, - Volumes: []v1.Volume{ - { - Name: volumeName, - VolumeSource: v1.VolumeSource{ - PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{ - ClaimName: pvcName, - }, - }, - }, - }, - }, - } -} - func NewCloneDataVolume(name, size, srcNamespace, srcPvcName string, storageClassName string) *cdiv1.DataVolume { dv := &cdiv1.DataVolume{ ObjectMeta: metav1.ObjectMeta{ diff --git a/tests/resource_filtering_test.go b/tests/resource_filtering_test.go index 6ff76223..b874b006 100644 --- a/tests/resource_filtering_test.go +++ b/tests/resource_filtering_test.go @@ -396,7 +396,7 @@ var _ = Describe("Resource includes", func() { By("Writing to PVC filesystem") writerPod := runPodAndWaitSucceeded(f.KvClient, f.Namespace.Name, writerPod(volumeName)) - deletePod(f.KvClient, f.Namespace.Name, writerPod.Name) + framework.DeletePod(f.KvClient, f.Namespace.Name, writerPod.Name) By("Creating backup") resources := "virtualmachines,datavolumes,persistentvolumeclaims,persistentvolumes" @@ -431,7 +431,7 @@ var _ = Describe("Resource includes", func() { By("Verifying DataVolume does not re-import content - file should exists") readerPod := runPodAndWaitSucceeded(f.KvClient, f.Namespace.Name, verifyFileExists(volumeName)) - deletePod(f.KvClient, f.Namespace.Name, readerPod.Name) + framework.DeletePod(f.KvClient, f.Namespace.Name, readerPod.Name) By("Verifying included VM exists") err = framework.WaitForVirtualMachineStatus(f.KvClient, f.Namespace.Name, vmIncluded.Name, kvv1.VirtualMachineStatusStopped) @@ -544,7 +544,7 @@ var _ = Describe("Resource includes", func() { By("Writing to PVC filesystem") writerPod := runPodAndWaitSucceeded(f.KvClient, f.Namespace.Name, writerPod(volumeName)) - deletePod(f.KvClient, f.Namespace.Name, writerPod.Name) + framework.DeletePod(f.KvClient, f.Namespace.Name, writerPod.Name) By("Starting the virtual machine") err = framework.StartVirtualMachine(f.KvClient, f.Namespace.Name, vmSpec.Name) @@ -593,7 +593,7 @@ var _ = Describe("Resource includes", func() { By("Verifying DataVolume has re-imported - file should not exists") readerPod := runPodAndWaitSucceeded(f.KvClient, f.Namespace.Name, verifyNoFile(volumeName)) - deletePod(f.KvClient, f.Namespace.Name, readerPod.Name) + framework.DeletePod(f.KvClient, f.Namespace.Name, readerPod.Name) }) It("[test_id:10192]Selecting VM but not VMI or Pod: Backing up should fail if the VM is running", func() { @@ -774,7 +774,7 @@ var _ = Describe("Resource includes", func() { By("Writing to PVC filesystem") writerPod := runPodAndWaitSucceeded(f.KvClient, f.Namespace.Name, writerPod(volumeName)) - deletePod(f.KvClient, f.Namespace.Name, writerPod.Name) + framework.DeletePod(f.KvClient, f.Namespace.Name, writerPod.Name) By("Creating backup") resources := "virtualmachines,persistentvolumeclaims,persistentvolumes" @@ -802,7 +802,7 @@ var _ = Describe("Resource includes", func() { // DV may not exist, so just check the PVC By("Verifying PVC is NOT re-imported - file exists") readerPod := runPodAndWaitSucceeded(f.KvClient, f.Namespace.Name, verifyFileExists(volumeName)) - deletePod(f.KvClient, f.Namespace.Name, readerPod.Name) + framework.DeletePod(f.KvClient, f.Namespace.Name, readerPod.Name) By("Verifying included VM exists") err = framework.WaitForVirtualMachineStatus(f.KvClient, f.Namespace.Name, vmIncluded.Name, kvv1.VirtualMachineStatusStopped) @@ -819,7 +819,7 @@ var _ = Describe("Resource includes", func() { By("Writing to PVC filesystem") writerPod := runPodAndWaitSucceeded(f.KvClient, f.Namespace.Name, writerPod(volumeName)) - deletePod(f.KvClient, f.Namespace.Name, writerPod.Name) + framework.DeletePod(f.KvClient, f.Namespace.Name, writerPod.Name) By("Creating backup") resources := "virtualmachines" @@ -846,7 +846,7 @@ var _ = Describe("Resource includes", func() { By("Verifying DataVolume is re-imported - file should not exists") readerPod := runPodAndWaitSucceeded(f.KvClient, f.Namespace.Name, verifyNoFile(volumeName)) - deletePod(f.KvClient, f.Namespace.Name, readerPod.Name) + framework.DeletePod(f.KvClient, f.Namespace.Name, readerPod.Name) By("Verifying included VM exists") err = framework.WaitForVirtualMachineStatus(f.KvClient, f.Namespace.Name, vmIncluded.Name, kvv1.VirtualMachineStatusStopped) @@ -2094,7 +2094,7 @@ var _ = Describe("Resource excludes", func() { By("Writing to PVC filesystem") writerPod := runPodAndWaitSucceeded(f.KvClient, f.Namespace.Name, writerPod(volumeName)) - deletePod(f.KvClient, f.Namespace.Name, writerPod.Name) + framework.DeletePod(f.KvClient, f.Namespace.Name, writerPod.Name) By("Creating backup") resources := "datavolume" @@ -2118,7 +2118,7 @@ var _ = Describe("Resource excludes", func() { By("Verifying DataVolume does not re-import content - file should exists") readerPod := runPodAndWaitSucceeded(f.KvClient, f.Namespace.Name, verifyFileExists(volumeName)) - deletePod(f.KvClient, f.Namespace.Name, readerPod.Name) + framework.DeletePod(f.KvClient, f.Namespace.Name, readerPod.Name) By("Verifying included VM exists") err = framework.WaitForVirtualMachineStatus(f.KvClient, f.Namespace.Name, vmIncluded.Name, kvv1.VirtualMachineStatusStopped, kvv1.VirtualMachineStatusRunning) @@ -2584,7 +2584,7 @@ var _ = Describe("Resource excludes", func() { addExcludeLabelToLauncherPodForVM := func(vmName string) { retryOnceOnErr( func() error { - pod := FindLauncherPod(f.K8sClient, f.Namespace.Name, vmName) + pod := framework.FindLauncherPod(f.K8sClient, f.Namespace.Name, vmName) pod.SetLabels(addExcludeLabel(pod.GetLabels())) _, err := f.K8sClient.CoreV1().Pods(f.Namespace.Name).Update(context.TODO(), &pod, metav1.UpdateOptions{}) return err @@ -2852,7 +2852,7 @@ var _ = Describe("Resource excludes", func() { volumeName := vmSpec.Spec.DataVolumeTemplates[0].Name By("Writing to PVC filesystem") writerPod := runPodAndWaitSucceeded(f.KvClient, f.Namespace.Name, writerPod(volumeName)) - deletePod(f.KvClient, f.Namespace.Name, writerPod.Name) + framework.DeletePod(f.KvClient, f.Namespace.Name, writerPod.Name) By("Adding exclude labels") if !framework.IsDataVolumeGC(f.KvClient) { @@ -2884,7 +2884,7 @@ var _ = Describe("Resource excludes", func() { By("Verifying DataVolume has re-imported - file should not exists") readerPod := runPodAndWaitSucceeded(f.KvClient, f.Namespace.Name, verifyNoFile(volumeName)) - deletePod(f.KvClient, f.Namespace.Name, readerPod.Name) + framework.DeletePod(f.KvClient, f.Namespace.Name, readerPod.Name) By("Verifying included VM exists") err = framework.WaitForVirtualMachineStatus(f.KvClient, f.Namespace.Name, vmIncluded.Name, kvv1.VirtualMachineStatusStopped, kvv1.VirtualMachineStatusRunning) @@ -2901,7 +2901,7 @@ var _ = Describe("Resource excludes", func() { By("Writing to PVC filesystem") writerPod := runPodAndWaitSucceeded(f.KvClient, f.Namespace.Name, writerPod(volumeName)) - deletePod(f.KvClient, f.Namespace.Name, writerPod.Name) + framework.DeletePod(f.KvClient, f.Namespace.Name, writerPod.Name) By("Adding exclude label to DV") if !framework.IsDataVolumeGC(f.KvClient) { @@ -2929,7 +2929,7 @@ var _ = Describe("Resource excludes", func() { By("Verifying PVC is not re-imported - file exists") readerPod := runPodAndWaitSucceeded(f.KvClient, f.Namespace.Name, verifyFileExists(volumeName)) - deletePod(f.KvClient, f.Namespace.Name, readerPod.Name) + framework.DeletePod(f.KvClient, f.Namespace.Name, readerPod.Name) By("Verifying included VM exists") err = framework.WaitForVirtualMachineStatus(f.KvClient, f.Namespace.Name, vmIncluded.Name, kvv1.VirtualMachineStatusStopped, kvv1.VirtualMachineStatusRunning) @@ -3376,21 +3376,6 @@ func addExpectedPVs(client *kubernetes.Clientset, namespace string, resources ma resources["PersistentVolume"] = pvs } -func FindLauncherPod(client *kubernetes.Clientset, namespace string, vmName string) v1.Pod { - var pod v1.Pod - pods, err := client.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{ - LabelSelector: "kubevirt.io=virt-launcher", - }) - Expect(err).WithOffset(1).ToNot(HaveOccurred()) - for _, item := range pods.Items { - if ann, ok := item.GetAnnotations()["kubevirt.io/domain"]; ok && ann == vmName { - pod = item - } - } - Expect(pod).WithOffset(1).ToNot(BeNil()) - return pod -} - func updateVm(kvClient kubecli.KubevirtClient, namespace string, name string, update func(*kvv1.VirtualMachine) *kvv1.VirtualMachine) func() error { return func() error { @@ -3456,41 +3441,7 @@ func retryOnceOnErr(f func() error) Assertion { } func runPodAndWaitSucceeded(kvClient kubecli.KubevirtClient, namespace string, podSpec *v1.Pod) *v1.Pod { - By("creating a pod") - pod, err := kvClient.CoreV1().Pods(namespace).Create(context.Background(), podSpec, metav1.CreateOptions{}) - Expect(err).WithOffset(1).ToNot(HaveOccurred()) - - By("Wait for pod to reach a completed phase") - Eventually(func() error { - updatedPod, err := kvClient.CoreV1().Pods(namespace).Get(context.Background(), pod.Name, metav1.GetOptions{}) - if err != nil { - return err - } - if updatedPod.Status.Phase != v1.PodSucceeded { - return fmt.Errorf("Pod in phase %s, expected Succeeded", updatedPod.Status.Phase) - } - return nil - }, 3*time.Minute, 5*time.Second).WithOffset(1).Should(Succeed(), "pod should reach Succeeded state") - - return pod -} - -func deletePod(kvClient kubecli.KubevirtClient, namespace, podName string) { - By("Delete pod") - zero := int64(0) - err := kvClient.CoreV1().Pods(namespace).Delete(context.Background(), podName, - metav1.DeleteOptions{ - GracePeriodSeconds: &zero, - }) - Expect(err).WithOffset(1).ToNot(HaveOccurred()) - - By("verify deleted") - Eventually(func() error { - _, err := kvClient.CoreV1().Pods(namespace).Get(context.Background(), podName, metav1.GetOptions{}) - return err - }, 3*time.Minute, 5*time.Second). - WithOffset(1). - Should(Satisfy(apierrs.IsNotFound), "pod should disappear") + return framework.RunPodAndWaitPhase(kvClient, namespace, podSpec, v1.PodSucceeded) } func verifyFileExists(volumeName string) *v1.Pod { From af30cfb2e932901bfbce495dcb68498674e7a1bd Mon Sep 17 00:00:00 2001 From: Shelly Kagan Date: Sun, 21 Apr 2024 17:08:38 +0300 Subject: [PATCH 4/6] Remove debug code Signed-off-by: Shelly Kagan --- tests/vm_backup_test.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/vm_backup_test.go b/tests/vm_backup_test.go index 09b2c57f..4a408900 100644 --- a/tests/vm_backup_test.go +++ b/tests/vm_backup_test.go @@ -361,10 +361,6 @@ var _ = Describe("[smoke] VM Backup", func() { Expect(err).ToNot(HaveOccurred()) By("Verifying VM") err = framework.WaitForVirtualMachineStatus(f.KvClient, f.Namespace.Name, vm.Name, kvv1.VirtualMachineStatusRunning) - if err != nil { - fmt.Println("SLEEEEEEEEPPP") - time.Sleep(time.Minute * 1000) - } Expect(err).ToNot(HaveOccurred()) }) From e57280fb0b15b7222871af8b673472c52c889461 Mon Sep 17 00:00:00 2001 From: Shelly Kagan Date: Sun, 21 Apr 2024 17:09:13 +0300 Subject: [PATCH 5/6] Change cluster to have default 2 nodes Signed-off-by: Shelly Kagan --- cluster-up/hack/common.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cluster-up/hack/common.sh b/cluster-up/hack/common.sh index 4f40c013..e2577b1e 100644 --- a/cluster-up/hack/common.sh +++ b/cluster-up/hack/common.sh @@ -18,7 +18,7 @@ fi KUBEVIRTCI_CLUSTER_PATH=${KUBEVIRTCI_CLUSTER_PATH:-${KUBEVIRTCI_PATH}/cluster} KUBEVIRT_PROVIDER=${KUBEVIRT_PROVIDER:-k8s-1.27} -KUBEVIRT_NUM_NODES=${KUBEVIRT_NUM_NODES:-1} +KUBEVIRT_NUM_NODES=${KUBEVIRT_NUM_NODES:-2} KUBEVIRT_MEMORY_SIZE=${KUBEVIRT_MEMORY_SIZE:-5120M} KUBEVIRT_NUM_SECONDARY_NICS=${KUBEVIRT_NUM_SECONDARY_NICS:-0} KUBEVIRT_DEPLOY_ISTIO=${KUBEVIRT_DEPLOY_ISTIO:-false} From 26fb1a3ad8a16cc8a516b027ed6a2a83052c50b9 Mon Sep 17 00:00:00 2001 From: Shelly Kagan Date: Tue, 30 Apr 2024 16:31:40 +0300 Subject: [PATCH 6/6] Replace deprecated pointer with ptr package Signed-off-by: Shelly Kagan --- go.mod | 2 +- go.sum | 4 +- tests/framework/pod.go | 12 +- vendor/k8s.io/utils/integer/integer.go | 8 +- vendor/k8s.io/utils/pointer/pointer.go | 283 ++++++------------------- vendor/k8s.io/utils/ptr/OWNERS | 10 + vendor/k8s.io/utils/ptr/README.md | 3 + vendor/k8s.io/utils/ptr/ptr.go | 73 +++++++ vendor/modules.txt | 3 +- 9 files changed, 162 insertions(+), 236 deletions(-) create mode 100644 vendor/k8s.io/utils/ptr/OWNERS create mode 100644 vendor/k8s.io/utils/ptr/README.md create mode 100644 vendor/k8s.io/utils/ptr/ptr.go diff --git a/go.mod b/go.mod index 0f86d4fb..0e1faf9c 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( k8s.io/apimachinery v0.27.1 k8s.io/client-go v12.0.0+incompatible k8s.io/klog/v2 v2.120.1 - k8s.io/utils v0.0.0-20230505201702-9f6742963106 + k8s.io/utils v0.0.0-20240423183400-0849a56e8f22 kubevirt.io/api v1.2.0 kubevirt.io/client-go v1.1.1 kubevirt.io/containerized-data-importer-api v1.58.0 diff --git a/go.sum b/go.sum index bc9ed9de..9c9aef07 100644 --- a/go.sum +++ b/go.sum @@ -1591,8 +1591,8 @@ k8s.io/utils v0.0.0-20200414100711-2df71ebbae66/go.mod h1:jPW/WVKK9YHAvNhRxK0md/ k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20221107191617-1a15be271d1d/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -k8s.io/utils v0.0.0-20230505201702-9f6742963106 h1:EObNQ3TW2D+WptiYXlApGNLVy0zm/JIBVY9i+M4wpAU= -k8s.io/utils v0.0.0-20230505201702-9f6742963106/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/utils v0.0.0-20240423183400-0849a56e8f22 h1:ao5hUqGhsqdm+bYbjH/pRkCs0unBGe9UyDahzs9zQzQ= +k8s.io/utils v0.0.0-20240423183400-0849a56e8f22/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= kubevirt.io/api v1.2.0 h1:1f8XQLPl4BuHPsc6SHTPnYSYeDxucKCQGa8CdrGJSRc= kubevirt.io/api v1.2.0/go.mod h1:SbeR9ma4EwnaOZEUkh/lNz0kzYm5LPpEDE30vKXC5Zg= kubevirt.io/client-go v1.1.1 h1:X/fk9kLW65aHRM3GW71UIzXLZsALPoggt4786yLYz1g= diff --git a/tests/framework/pod.go b/tests/framework/pod.go index 0ade4edf..a4ed65f3 100644 --- a/tests/framework/pod.go +++ b/tests/framework/pod.go @@ -9,7 +9,7 @@ import ( . "github.com/onsi/gomega" v1 "k8s.io/api/core/v1" "k8s.io/client-go/kubernetes" - "k8s.io/utils/pointer" + "k8s.io/utils/ptr" apierrs "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/resource" @@ -35,7 +35,7 @@ func PodWithPvcSpec(podName, pvcName string, cmd, args []string) *v1.Pod { }, Spec: v1.PodSpec{ SecurityContext: &v1.PodSecurityContext{ - FSGroup: pointer.Int64(uid), + FSGroup: ptr.To[int64](uid), }, RestartPolicy: v1.RestartPolicyNever, Containers: []v1.Container{ @@ -59,9 +59,9 @@ func PodWithPvcSpec(podName, pvcName string, cmd, args []string) *v1.Pod { }, }, SecurityContext: &v1.SecurityContext{ - RunAsNonRoot: pointer.Bool(true), - RunAsUser: pointer.Int64(uid), - RunAsGroup: pointer.Int64(uid), + RunAsNonRoot: ptr.To(true), + RunAsUser: ptr.To[int64](uid), + RunAsGroup: ptr.To[int64](uid), Capabilities: &v1.Capabilities{ Drop: []v1.Capability{ "ALL", @@ -70,7 +70,7 @@ func PodWithPvcSpec(podName, pvcName string, cmd, args []string) *v1.Pod { SeccompProfile: &v1.SeccompProfile{ Type: v1.SeccompProfileTypeRuntimeDefault, }, - AllowPrivilegeEscalation: pointer.Bool(false), + AllowPrivilegeEscalation: ptr.To(false), }, }, }, diff --git a/vendor/k8s.io/utils/integer/integer.go b/vendor/k8s.io/utils/integer/integer.go index e4e740ca..e0811e83 100644 --- a/vendor/k8s.io/utils/integer/integer.go +++ b/vendor/k8s.io/utils/integer/integer.go @@ -16,6 +16,8 @@ limitations under the License. package integer +import "math" + // IntMax returns the maximum of the params func IntMax(a, b int) int { if b > a { @@ -65,9 +67,7 @@ func Int64Min(a, b int64) int64 { } // RoundToInt32 rounds floats into integer numbers. +// Deprecated: use math.Round() and a cast directly. func RoundToInt32(a float64) int32 { - if a < 0 { - return int32(a - 0.5) - } - return int32(a + 0.5) + return int32(math.Round(a)) } diff --git a/vendor/k8s.io/utils/pointer/pointer.go b/vendor/k8s.io/utils/pointer/pointer.go index b8103223..b673a642 100644 --- a/vendor/k8s.io/utils/pointer/pointer.go +++ b/vendor/k8s.io/utils/pointer/pointer.go @@ -14,12 +14,15 @@ See the License for the specific language governing permissions and limitations under the License. */ +// Deprecated: Use functions in k8s.io/utils/ptr instead: ptr.To to obtain +// a pointer, ptr.Deref to dereference a pointer, ptr.Equal to compare +// dereferenced pointers. package pointer import ( - "fmt" - "reflect" "time" + + "k8s.io/utils/ptr" ) // AllPtrFieldsNil tests whether all pointer fields in a struct are nil. This is useful when, @@ -28,383 +31,219 @@ import ( // // This function is only valid for structs and pointers to structs. Any other // type will cause a panic. Passing a typed nil pointer will return true. -func AllPtrFieldsNil(obj interface{}) bool { - v := reflect.ValueOf(obj) - if !v.IsValid() { - panic(fmt.Sprintf("reflect.ValueOf() produced a non-valid Value for %#v", obj)) - } - if v.Kind() == reflect.Ptr { - if v.IsNil() { - return true - } - v = v.Elem() - } - for i := 0; i < v.NumField(); i++ { - if v.Field(i).Kind() == reflect.Ptr && !v.Field(i).IsNil() { - return false - } - } - return true -} - -// Int returns a pointer to an int -func Int(i int) *int { - return &i -} +// +// Deprecated: Use ptr.AllPtrFieldsNil instead. +var AllPtrFieldsNil = ptr.AllPtrFieldsNil + +// Int returns a pointer to an int. +var Int = ptr.To[int] // IntPtr is a function variable referring to Int. // -// Deprecated: Use Int instead. +// Deprecated: Use ptr.To instead. var IntPtr = Int // for back-compat // IntDeref dereferences the int ptr and returns it if not nil, or else // returns def. -func IntDeref(ptr *int, def int) int { - if ptr != nil { - return *ptr - } - return def -} +var IntDeref = ptr.Deref[int] // IntPtrDerefOr is a function variable referring to IntDeref. // -// Deprecated: Use IntDeref instead. +// Deprecated: Use ptr.Deref instead. var IntPtrDerefOr = IntDeref // for back-compat // Int32 returns a pointer to an int32. -func Int32(i int32) *int32 { - return &i -} +var Int32 = ptr.To[int32] // Int32Ptr is a function variable referring to Int32. // -// Deprecated: Use Int32 instead. +// Deprecated: Use ptr.To instead. var Int32Ptr = Int32 // for back-compat // Int32Deref dereferences the int32 ptr and returns it if not nil, or else // returns def. -func Int32Deref(ptr *int32, def int32) int32 { - if ptr != nil { - return *ptr - } - return def -} +var Int32Deref = ptr.Deref[int32] // Int32PtrDerefOr is a function variable referring to Int32Deref. // -// Deprecated: Use Int32Deref instead. +// Deprecated: Use ptr.Deref instead. var Int32PtrDerefOr = Int32Deref // for back-compat // Int32Equal returns true if both arguments are nil or both arguments // dereference to the same value. -func Int32Equal(a, b *int32) bool { - if (a == nil) != (b == nil) { - return false - } - if a == nil { - return true - } - return *a == *b -} +var Int32Equal = ptr.Equal[int32] // Uint returns a pointer to an uint -func Uint(i uint) *uint { - return &i -} +var Uint = ptr.To[uint] // UintPtr is a function variable referring to Uint. // -// Deprecated: Use Uint instead. +// Deprecated: Use ptr.To instead. var UintPtr = Uint // for back-compat // UintDeref dereferences the uint ptr and returns it if not nil, or else // returns def. -func UintDeref(ptr *uint, def uint) uint { - if ptr != nil { - return *ptr - } - return def -} +var UintDeref = ptr.Deref[uint] // UintPtrDerefOr is a function variable referring to UintDeref. // -// Deprecated: Use UintDeref instead. +// Deprecated: Use ptr.Deref instead. var UintPtrDerefOr = UintDeref // for back-compat // Uint32 returns a pointer to an uint32. -func Uint32(i uint32) *uint32 { - return &i -} +var Uint32 = ptr.To[uint32] // Uint32Ptr is a function variable referring to Uint32. // -// Deprecated: Use Uint32 instead. +// Deprecated: Use ptr.To instead. var Uint32Ptr = Uint32 // for back-compat // Uint32Deref dereferences the uint32 ptr and returns it if not nil, or else // returns def. -func Uint32Deref(ptr *uint32, def uint32) uint32 { - if ptr != nil { - return *ptr - } - return def -} +var Uint32Deref = ptr.Deref[uint32] // Uint32PtrDerefOr is a function variable referring to Uint32Deref. // -// Deprecated: Use Uint32Deref instead. +// Deprecated: Use ptr.Deref instead. var Uint32PtrDerefOr = Uint32Deref // for back-compat // Uint32Equal returns true if both arguments are nil or both arguments // dereference to the same value. -func Uint32Equal(a, b *uint32) bool { - if (a == nil) != (b == nil) { - return false - } - if a == nil { - return true - } - return *a == *b -} +var Uint32Equal = ptr.Equal[uint32] // Int64 returns a pointer to an int64. -func Int64(i int64) *int64 { - return &i -} +var Int64 = ptr.To[int64] // Int64Ptr is a function variable referring to Int64. // -// Deprecated: Use Int64 instead. +// Deprecated: Use ptr.To instead. var Int64Ptr = Int64 // for back-compat // Int64Deref dereferences the int64 ptr and returns it if not nil, or else // returns def. -func Int64Deref(ptr *int64, def int64) int64 { - if ptr != nil { - return *ptr - } - return def -} +var Int64Deref = ptr.Deref[int64] // Int64PtrDerefOr is a function variable referring to Int64Deref. // -// Deprecated: Use Int64Deref instead. +// Deprecated: Use ptr.Deref instead. var Int64PtrDerefOr = Int64Deref // for back-compat // Int64Equal returns true if both arguments are nil or both arguments // dereference to the same value. -func Int64Equal(a, b *int64) bool { - if (a == nil) != (b == nil) { - return false - } - if a == nil { - return true - } - return *a == *b -} +var Int64Equal = ptr.Equal[int64] // Uint64 returns a pointer to an uint64. -func Uint64(i uint64) *uint64 { - return &i -} +var Uint64 = ptr.To[uint64] // Uint64Ptr is a function variable referring to Uint64. // -// Deprecated: Use Uint64 instead. +// Deprecated: Use ptr.To instead. var Uint64Ptr = Uint64 // for back-compat // Uint64Deref dereferences the uint64 ptr and returns it if not nil, or else // returns def. -func Uint64Deref(ptr *uint64, def uint64) uint64 { - if ptr != nil { - return *ptr - } - return def -} +var Uint64Deref = ptr.Deref[uint64] // Uint64PtrDerefOr is a function variable referring to Uint64Deref. // -// Deprecated: Use Uint64Deref instead. +// Deprecated: Use ptr.Deref instead. var Uint64PtrDerefOr = Uint64Deref // for back-compat // Uint64Equal returns true if both arguments are nil or both arguments // dereference to the same value. -func Uint64Equal(a, b *uint64) bool { - if (a == nil) != (b == nil) { - return false - } - if a == nil { - return true - } - return *a == *b -} +var Uint64Equal = ptr.Equal[uint64] // Bool returns a pointer to a bool. -func Bool(b bool) *bool { - return &b -} +var Bool = ptr.To[bool] // BoolPtr is a function variable referring to Bool. // -// Deprecated: Use Bool instead. +// Deprecated: Use ptr.To instead. var BoolPtr = Bool // for back-compat // BoolDeref dereferences the bool ptr and returns it if not nil, or else // returns def. -func BoolDeref(ptr *bool, def bool) bool { - if ptr != nil { - return *ptr - } - return def -} +var BoolDeref = ptr.Deref[bool] // BoolPtrDerefOr is a function variable referring to BoolDeref. // -// Deprecated: Use BoolDeref instead. +// Deprecated: Use ptr.Deref instead. var BoolPtrDerefOr = BoolDeref // for back-compat // BoolEqual returns true if both arguments are nil or both arguments // dereference to the same value. -func BoolEqual(a, b *bool) bool { - if (a == nil) != (b == nil) { - return false - } - if a == nil { - return true - } - return *a == *b -} +var BoolEqual = ptr.Equal[bool] // String returns a pointer to a string. -func String(s string) *string { - return &s -} +var String = ptr.To[string] // StringPtr is a function variable referring to String. // -// Deprecated: Use String instead. +// Deprecated: Use ptr.To instead. var StringPtr = String // for back-compat // StringDeref dereferences the string ptr and returns it if not nil, or else // returns def. -func StringDeref(ptr *string, def string) string { - if ptr != nil { - return *ptr - } - return def -} +var StringDeref = ptr.Deref[string] // StringPtrDerefOr is a function variable referring to StringDeref. // -// Deprecated: Use StringDeref instead. +// Deprecated: Use ptr.Deref instead. var StringPtrDerefOr = StringDeref // for back-compat // StringEqual returns true if both arguments are nil or both arguments // dereference to the same value. -func StringEqual(a, b *string) bool { - if (a == nil) != (b == nil) { - return false - } - if a == nil { - return true - } - return *a == *b -} +var StringEqual = ptr.Equal[string] // Float32 returns a pointer to a float32. -func Float32(i float32) *float32 { - return &i -} +var Float32 = ptr.To[float32] // Float32Ptr is a function variable referring to Float32. // -// Deprecated: Use Float32 instead. +// Deprecated: Use ptr.To instead. var Float32Ptr = Float32 // Float32Deref dereferences the float32 ptr and returns it if not nil, or else // returns def. -func Float32Deref(ptr *float32, def float32) float32 { - if ptr != nil { - return *ptr - } - return def -} +var Float32Deref = ptr.Deref[float32] // Float32PtrDerefOr is a function variable referring to Float32Deref. // -// Deprecated: Use Float32Deref instead. +// Deprecated: Use ptr.Deref instead. var Float32PtrDerefOr = Float32Deref // for back-compat // Float32Equal returns true if both arguments are nil or both arguments // dereference to the same value. -func Float32Equal(a, b *float32) bool { - if (a == nil) != (b == nil) { - return false - } - if a == nil { - return true - } - return *a == *b -} +var Float32Equal = ptr.Equal[float32] // Float64 returns a pointer to a float64. -func Float64(i float64) *float64 { - return &i -} +var Float64 = ptr.To[float64] // Float64Ptr is a function variable referring to Float64. // -// Deprecated: Use Float64 instead. +// Deprecated: Use ptr.To instead. var Float64Ptr = Float64 // Float64Deref dereferences the float64 ptr and returns it if not nil, or else // returns def. -func Float64Deref(ptr *float64, def float64) float64 { - if ptr != nil { - return *ptr - } - return def -} +var Float64Deref = ptr.Deref[float64] // Float64PtrDerefOr is a function variable referring to Float64Deref. // -// Deprecated: Use Float64Deref instead. +// Deprecated: Use ptr.Deref instead. var Float64PtrDerefOr = Float64Deref // for back-compat // Float64Equal returns true if both arguments are nil or both arguments // dereference to the same value. -func Float64Equal(a, b *float64) bool { - if (a == nil) != (b == nil) { - return false - } - if a == nil { - return true - } - return *a == *b -} +var Float64Equal = ptr.Equal[float64] // Duration returns a pointer to a time.Duration. -func Duration(d time.Duration) *time.Duration { - return &d -} +var Duration = ptr.To[time.Duration] // DurationDeref dereferences the time.Duration ptr and returns it if not nil, or else // returns def. -func DurationDeref(ptr *time.Duration, def time.Duration) time.Duration { - if ptr != nil { - return *ptr - } - return def -} +var DurationDeref = ptr.Deref[time.Duration] // DurationEqual returns true if both arguments are nil or both arguments // dereference to the same value. -func DurationEqual(a, b *time.Duration) bool { - if (a == nil) != (b == nil) { - return false - } - if a == nil { - return true - } - return *a == *b -} +var DurationEqual = ptr.Equal[time.Duration] diff --git a/vendor/k8s.io/utils/ptr/OWNERS b/vendor/k8s.io/utils/ptr/OWNERS new file mode 100644 index 00000000..0d639275 --- /dev/null +++ b/vendor/k8s.io/utils/ptr/OWNERS @@ -0,0 +1,10 @@ +# See the OWNERS docs at https://go.k8s.io/owners + +approvers: +- apelisse +- stewart-yu +- thockin +reviewers: +- apelisse +- stewart-yu +- thockin diff --git a/vendor/k8s.io/utils/ptr/README.md b/vendor/k8s.io/utils/ptr/README.md new file mode 100644 index 00000000..2ca8073d --- /dev/null +++ b/vendor/k8s.io/utils/ptr/README.md @@ -0,0 +1,3 @@ +# Pointer + +This package provides some functions for pointer-based operations. diff --git a/vendor/k8s.io/utils/ptr/ptr.go b/vendor/k8s.io/utils/ptr/ptr.go new file mode 100644 index 00000000..659ed3b9 --- /dev/null +++ b/vendor/k8s.io/utils/ptr/ptr.go @@ -0,0 +1,73 @@ +/* +Copyright 2023 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package ptr + +import ( + "fmt" + "reflect" +) + +// AllPtrFieldsNil tests whether all pointer fields in a struct are nil. This is useful when, +// for example, an API struct is handled by plugins which need to distinguish +// "no plugin accepted this spec" from "this spec is empty". +// +// This function is only valid for structs and pointers to structs. Any other +// type will cause a panic. Passing a typed nil pointer will return true. +func AllPtrFieldsNil(obj interface{}) bool { + v := reflect.ValueOf(obj) + if !v.IsValid() { + panic(fmt.Sprintf("reflect.ValueOf() produced a non-valid Value for %#v", obj)) + } + if v.Kind() == reflect.Ptr { + if v.IsNil() { + return true + } + v = v.Elem() + } + for i := 0; i < v.NumField(); i++ { + if v.Field(i).Kind() == reflect.Ptr && !v.Field(i).IsNil() { + return false + } + } + return true +} + +// To returns a pointer to the given value. +func To[T any](v T) *T { + return &v +} + +// Deref dereferences ptr and returns the value it points to if no nil, or else +// returns def. +func Deref[T any](ptr *T, def T) T { + if ptr != nil { + return *ptr + } + return def +} + +// Equal returns true if both arguments are nil or both arguments +// dereference to the same value. +func Equal[T comparable](a, b *T) bool { + if (a == nil) != (b == nil) { + return false + } + if a == nil { + return true + } + return *a == *b +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 6770540e..febb130a 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -726,7 +726,7 @@ k8s.io/kube-openapi/pkg/schemamutation k8s.io/kube-openapi/pkg/spec3 k8s.io/kube-openapi/pkg/util/proto k8s.io/kube-openapi/pkg/validation/spec -# k8s.io/utils v0.0.0-20230505201702-9f6742963106 +# k8s.io/utils v0.0.0-20240423183400-0849a56e8f22 ## explicit; go 1.18 k8s.io/utils/clock k8s.io/utils/clock/testing @@ -734,6 +734,7 @@ k8s.io/utils/integer k8s.io/utils/internal/third_party/forked/golang/net k8s.io/utils/net k8s.io/utils/pointer +k8s.io/utils/ptr k8s.io/utils/strings/slices # kubevirt.io/api v1.2.0 ## explicit; go 1.17