From b95c281945938e4b108425ce8b3958c33e581d3f Mon Sep 17 00:00:00 2001 From: Matthew Arnold Date: Tue, 13 Feb 2024 16:28:53 -0500 Subject: [PATCH 1/6] Remove unused timeouts. Signed-off-by: Matthew Arnold --- tests/e2e/lib/virt_helpers.go | 4 ++-- tests/e2e/virt_backup_restore_suite_test.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/e2e/lib/virt_helpers.go b/tests/e2e/lib/virt_helpers.go index c53a0928f7..6617714e98 100644 --- a/tests/e2e/lib/virt_helpers.go +++ b/tests/e2e/lib/virt_helpers.go @@ -525,7 +525,7 @@ func (v *VirtOperator) IsVirtInstalled() bool { // EnsureVirtInstallation makes sure the OpenShift Virtualization operator is // installed. This will install the operator if it is not already present. -func (v *VirtOperator) EnsureVirtInstallation(timeout time.Duration) error { +func (v *VirtOperator) EnsureVirtInstallation() error { if v.IsVirtInstalled() { log.Printf("Virtualization operator already installed, no action needed") return nil @@ -565,7 +565,7 @@ func (v *VirtOperator) EnsureVirtInstallation(timeout time.Duration) error { } // EnsureVirtRemoval makes sure the virtualization operator is removed. -func (v *VirtOperator) EnsureVirtRemoval(timeout time.Duration) error { +func (v *VirtOperator) EnsureVirtRemoval() error { log.Printf("Removing hyperconverged operator") if err := v.ensureHcoRemoved(3 * time.Minute); err != nil { return err diff --git a/tests/e2e/virt_backup_restore_suite_test.go b/tests/e2e/virt_backup_restore_suite_test.go index c492f399c9..720b5343e3 100644 --- a/tests/e2e/virt_backup_restore_suite_test.go +++ b/tests/e2e/virt_backup_restore_suite_test.go @@ -22,7 +22,7 @@ var _ = Describe("VM backup and restore tests", Ordered, func() { Expect(v).ToNot(BeNil()) if !v.IsVirtInstalled() { - err = v.EnsureVirtInstallation(5 * time.Minute) + err = v.EnsureVirtInstallation() Expect(err).To(BeNil()) wasInstalledFromTest = true } @@ -30,7 +30,7 @@ var _ = Describe("VM backup and restore tests", Ordered, func() { var _ = AfterAll(func() { if v != nil && wasInstalledFromTest { - v.EnsureVirtRemoval(6 * time.Minute) + v.EnsureVirtRemoval() } }) From 8298dedbf68b9b1e82b92e9a52ef47d5f95acdec Mon Sep 17 00:00:00 2001 From: Matthew Arnold Date: Tue, 13 Feb 2024 16:36:05 -0500 Subject: [PATCH 2/6] Add ability to enable KVM emulation. This is needed on cloud clusters that don't use host virtualization or nested virtualization. Assume it is needed in CI. Signed-off-by: Matthew Arnold --- tests/e2e/lib/virt_helpers.go | 86 +++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/tests/e2e/lib/virt_helpers.go b/tests/e2e/lib/virt_helpers.go index 6617714e98..53b9b37827 100644 --- a/tests/e2e/lib/virt_helpers.go +++ b/tests/e2e/lib/virt_helpers.go @@ -23,6 +23,11 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" ) +const ( + emulationAnnotation = "kubevirt.kubevirt.io/jsonpatch" + useEmulation = `[{"op": "add", "path": "/spec/configuration/developerConfiguration", "value": {"useEmulation": true}}]` +) + var packageManifestsGvr = schema.GroupVersionResource{ Group: "packages.operators.coreos.com", Resource: "packagemanifests", @@ -35,6 +40,12 @@ var hyperConvergedGvr = schema.GroupVersionResource{ Version: "v1beta1", } +var virtualMachineGvr = schema.GroupVersionResource{ + Group: "kubevirt.io", + Resource: "virtualmachines", + Version: "v1", +} + var csvGvr = schema.GroupVersionResource{ Group: "operators.coreos.com", Resource: "clusterserviceversion", @@ -210,6 +221,32 @@ func (v *VirtOperator) checkHco() bool { return health == "healthy" } +// Check if KVM emulation is enabled. +func (v *VirtOperator) checkEmulation() bool { + hco, err := v.Dynamic.Resource(hyperConvergedGvr).Namespace("openshift-cnv").Get(context.Background(), "kubevirt-hyperconverged", v1.GetOptions{}) + if err != nil { + return false + } + if hco == nil { + return false + } + + // Look for JSON patcher annotation that enables emulation. + patcher, ok, err := unstructured.NestedString(hco.UnstructuredContent(), "metadata", "annotations", emulationAnnotation) + if err != nil { + log.Printf("Failed to get KVM emulation annotation from HCO: %v", err) + return false + } + if !ok { + log.Printf("No KVM emulation annotation (%s) listed on HCO!", emulationAnnotation) + } + if strings.Compare(patcher, useEmulation) == 0 { + return true + } + + return false +} + // Creates the target virtualization namespace, likely openshift-cnv or kubevirt-hyperconverged func (v *VirtOperator) installNamespace() error { err := v.Client.Create(context.Background(), &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: v.Namespace}}) @@ -281,6 +318,36 @@ func (v *VirtOperator) installHco() error { return nil } +func (v *VirtOperator) configureEmulation() error { + hco, err := v.Dynamic.Resource(hyperConvergedGvr).Namespace("openshift-cnv").Get(context.Background(), "kubevirt-hyperconverged", v1.GetOptions{}) + if err != nil { + return err + } + if hco == nil { + return fmt.Errorf("could not find hyperconverged operator to set emulation annotation") + } + + annotations, ok, err := unstructured.NestedMap(hco.UnstructuredContent(), "metadata", "annotations") + if err != nil { + return err + } + if !ok { + annotations = make(map[string]interface{}) + } + annotations[emulationAnnotation] = useEmulation + + if err := unstructured.SetNestedMap(hco.UnstructuredContent(), annotations, "metadata", "annotations"); err != nil { + return err + } + + _, err = v.Dynamic.Resource(hyperConvergedGvr).Namespace("openshift-cnv").Update(context.Background(), hco, v1.UpdateOptions{}) + if err != nil { + return err + } + + return nil +} + // Creates target namespace if needed, and waits for it to exist func (v *VirtOperator) ensureNamespace(timeout time.Duration) error { if !v.checkNamespace() { @@ -513,6 +580,25 @@ func (v *VirtOperator) ensureHcoRemoved(timeout time.Duration) error { return err } +// Enable KVM emulation for use on cloud clusters that do not have direct +// access to the host server's virtualization capabilities. +func (v *VirtOperator) ensureEmulation(timeout time.Duration) error { + if v.checkEmulation() { + log.Printf("KVM emulation already enabled, no work needed to turn it on.") + return nil + } + + if err := v.configureEmulation(); err != nil { + return err + } + + err := wait.PollImmediate(5*time.Second, timeout, func() (bool, error) { + return v.checkEmulation(), nil + }) + + return err +} + // IsVirtInstalled returns whether or not the OpenShift Virtualization operator // is installed and ready, by checking for a HyperConverged operator resource. func (v *VirtOperator) IsVirtInstalled() bool { From 0b30eea4cca9a3fdaa109358c966ca468951b8d6 Mon Sep 17 00:00:00 2001 From: Matthew Arnold Date: Tue, 13 Feb 2024 16:47:49 -0500 Subject: [PATCH 3/6] Clone base data volume before creating a VM. Also minor factoring of data volume creation, and add a place for the VM creation test. Signed-off-by: Matthew Arnold --- tests/e2e/lib/virt_helpers.go | 14 ++++ tests/e2e/lib/virt_storage_helpers.go | 79 ++++++++++++++++++--- tests/e2e/virt_backup_restore_suite_test.go | 9 ++- 3 files changed, 91 insertions(+), 11 deletions(-) diff --git a/tests/e2e/lib/virt_helpers.go b/tests/e2e/lib/virt_helpers.go index 53b9b37827..aa61c0efe5 100644 --- a/tests/e2e/lib/virt_helpers.go +++ b/tests/e2e/lib/virt_helpers.go @@ -684,3 +684,17 @@ func (v *VirtOperator) EnsureVirtRemoval() error { return nil } + +// Create a Virtual Machine from an existing PVC. +func (v *VirtOperator) CreateVM(namespace, name, source string) error { + log.Printf("Enabling KVM emulation...") + if err := v.ensureEmulation(10 * time.Second); err != nil { + return fmt.Errorf("failed to enable KVM emulation: %w", err) + } + + if err := v.CloneDisk(namespace, source, name, 5*time.Minute); err != nil { + return err + } + + return nil +} diff --git a/tests/e2e/lib/virt_storage_helpers.go b/tests/e2e/lib/virt_storage_helpers.go index dc04a05d9d..88117b8f14 100644 --- a/tests/e2e/lib/virt_storage_helpers.go +++ b/tests/e2e/lib/virt_storage_helpers.go @@ -59,10 +59,30 @@ func (v *VirtOperator) checkDataVolumeReady(namespace, name string) bool { return phase == "Succeeded" } -// Create a DataVolume and ask it to fill itself with the contents of the given -// URL. Also add annotations to immediately create and bind to a PersistentVolume, +func (v *VirtOperator) getDataVolumeSize(namespace, name string) (string, error) { + unstructuredDataVolume, err := v.getDataVolume(namespace, name) + if err != nil { + log.Printf("Error getting DataVolume %s/%s: %v", namespace, name, err) + return "", err + } + if unstructuredDataVolume == nil { + return "", err + } + size, ok, err := unstructured.NestedString(unstructuredDataVolume.UnstructuredContent(), "spec", "pvc", "resources", "requests", "storage") + if err != nil { + log.Printf("Error getting size from DataVolume: %v", err) + return "", err + } + if !ok { + return "", err + } + return size, nil +} + +// Create a DataVolume, accepting an unstructured source specification. +// Also add annotations to immediately create and bind to a PersistentVolume, // and to avoid deleting the DataVolume after the PVC is all ready. -func (v *VirtOperator) createDataVolumeFromUrl(namespace, name, url, size string) error { +func (v *VirtOperator) createDataVolumeFromSource(namespace, name, size string, source map[string]interface{}) error { unstructuredDataVolume := unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "cdi.kubevirt.io/v1beta1", @@ -76,11 +96,7 @@ func (v *VirtOperator) createDataVolumeFromUrl(namespace, name, url, size string }, }, "spec": map[string]interface{}{ - "source": map[string]interface{}{ - "http": map[string]interface{}{ - "url": url, - }, - }, + "source": source, "pvc": map[string]interface{}{ "accessModes": []string{ "ReadWriteOnce", @@ -110,6 +126,27 @@ func (v *VirtOperator) createDataVolumeFromUrl(namespace, name, url, size string return nil } +// Create a DataVolume and ask it to fill itself with the contents of the given URL. +func (v *VirtOperator) createDataVolumeFromUrl(namespace, name, url, size string) error { + urlSource := map[string]interface{}{ + "http": map[string]interface{}{ + "url": url, + }, + } + return v.createDataVolumeFromSource(namespace, name, size, urlSource) +} + +// Create a DataVolume as a clone of an existing PVC. +func (v *VirtOperator) createDataVolumeFromPvc(namespace, sourceName, cloneName, size string) error { + pvcSource := map[string]interface{}{ + "pvc": map[string]interface{}{ + "name": sourceName, + "namespace": namespace, + }, + } + return v.createDataVolumeFromSource(namespace, cloneName, size, pvcSource) +} + // Create a DataVolume and wait for it to be ready. func (v *VirtOperator) EnsureDataVolume(namespace, name, url, size string, timeout time.Duration) error { if !v.checkDataVolumeExists(namespace, name) { @@ -155,3 +192,29 @@ func (v *VirtOperator) EnsureDataVolumeRemoval(namespace, name string, timeout t return nil } + +// Clone a DataVolume and wait for the copy to be ready. +func (v *VirtOperator) CloneDisk(namespace, sourceName, cloneName string, timeout time.Duration) error { + log.Printf("Cloning %s/%s to %s/%s...", namespace, sourceName, namespace, cloneName) + if !v.checkDataVolumeExists(namespace, sourceName) { + return fmt.Errorf("source disk does not exist") + } + + size, err := v.getDataVolumeSize(namespace, sourceName) + if err != nil { + return fmt.Errorf("failed to get disk size for clone: %w", err) + } + + if err := v.createDataVolumeFromPvc(namespace, sourceName, cloneName, size); err != nil { + return fmt.Errorf("failed to clone disk: %w", err) + } + + err = wait.PollImmediate(5*time.Second, timeout, func() (bool, error) { + return v.checkDataVolumeReady(namespace, cloneName), nil + }) + if err != nil { + return fmt.Errorf("timed out waiting to clone DataVolume %s/%s to %s/%s: %w", namespace, sourceName, namespace, cloneName, err) + } + + return nil +} diff --git a/tests/e2e/virt_backup_restore_suite_test.go b/tests/e2e/virt_backup_restore_suite_test.go index 720b5343e3..2e7afc0381 100644 --- a/tests/e2e/virt_backup_restore_suite_test.go +++ b/tests/e2e/virt_backup_restore_suite_test.go @@ -26,11 +26,15 @@ var _ = Describe("VM backup and restore tests", Ordered, func() { Expect(err).To(BeNil()) wasInstalledFromTest = true } + + err = v.EnsureDataVolume("openshift-cnv", "cirros-dv", "https://download.cirros-cloud.net/0.6.2/cirros-0.6.2-x86_64-disk.img", "128Mi", 5*time.Minute) + Expect(err).To(BeNil()) }) var _ = AfterAll(func() { if v != nil && wasInstalledFromTest { v.EnsureVirtRemoval() + v.EnsureDataVolumeRemoval("openshift-cnv", "cirros-dv", 2*time.Minute) } }) @@ -39,9 +43,8 @@ var _ = Describe("VM backup and restore tests", Ordered, func() { Expect(installed).To(BeTrue()) }) - It("should upload a data volume successfully", Label("virt"), func() { - err := v.EnsureDataVolume("openshift-cnv", "cirros", "https://download.cirros-cloud.net/0.6.2/cirros-0.6.2-x86_64-disk.img", "128Mi", 5*time.Minute) + It("should create and boot a virtual machine", Label("virt"), func() { + err := v.CreateVM("openshift-cnv", "cirros-vm", "cirros-dv") Expect(err).To(BeNil()) - v.EnsureDataVolumeRemoval("openshift-cnv", "cirros", 2*time.Minute) }) }) From 6e66cd85fefc300b2e9802a1bf3ba94c50cf0f1c Mon Sep 17 00:00:00 2001 From: Matthew Arnold Date: Tue, 13 Feb 2024 21:35:56 -0500 Subject: [PATCH 4/6] Add a test to start a virtual machine. This clones the CirrOS data volume and attaches it to a new VM, then cleans everything up once it goes running. Signed-off-by: Matthew Arnold --- tests/e2e/lib/virt_helpers.go | 153 ++++++++++++++++++-- tests/e2e/lib/virt_storage_helpers.go | 2 +- tests/e2e/virt_backup_restore_suite_test.go | 16 +- 3 files changed, 156 insertions(+), 15 deletions(-) diff --git a/tests/e2e/lib/virt_helpers.go b/tests/e2e/lib/virt_helpers.go index aa61c0efe5..1f77a20a9f 100644 --- a/tests/e2e/lib/virt_helpers.go +++ b/tests/e2e/lib/virt_helpers.go @@ -12,6 +12,7 @@ import ( operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -580,12 +581,142 @@ func (v *VirtOperator) ensureHcoRemoved(timeout time.Duration) error { return err } +func (v *VirtOperator) getVmStatus(namespace, name string) (string, error) { + vm, err := v.Dynamic.Resource(virtualMachineGvr).Namespace(namespace).Get(context.Background(), name, v1.GetOptions{}) + if err != nil { + return "", err + } + + status, ok, err := unstructured.NestedString(vm.UnstructuredContent(), "status", "printableStatus") + if err != nil { + return "", err + } + if !ok { + return "", fmt.Errorf("status field not populated yet on VM %s/%s", namespace, name) + } + log.Printf("VM %s/%s status is: %s", namespace, name, status) + + return status, nil +} + +func (v *VirtOperator) checkVmExists(namespace, name string) bool { + _, err := v.getVmStatus(namespace, name) + if err == nil { + return true + } + return false +} + +func (v *VirtOperator) checkVmStatus(namespace, name, expectedStatus string) bool { + status, _ := v.getVmStatus(namespace, name) + return status == expectedStatus +} + +func (v *VirtOperator) createVm(namespace, name, source string) error { + unstructuredVm := unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "kubevirt.io/v1", + "kind": "VirtualMachine", + "metadata": map[string]interface{}{ + "name": name, + "namespace": namespace, + }, + "spec": map[string]interface{}{ + "running": true, + "template": map[string]interface{}{ + "spec": map[string]interface{}{ + "domain": map[string]interface{}{ + "devices": map[string]interface{}{ + "disks": []map[string]interface{}{ + { + "disk": map[string]interface{}{ + "bus": "virtio", + }, + "name": "rootdisk", + }, + }, + }, + "resources": map[string]interface{}{ + "requests": map[string]interface{}{ + "cpu": "1", + "memory": "256Mi", + }, + }, + }, + "volumes": []map[string]interface{}{ + { + "dataVolume": map[string]interface{}{ + "name": name, + }, + "name": "rootdisk", + }, + }, + }, + }, + }, + }, + } + + if _, err := v.Dynamic.Resource(virtualMachineGvr).Namespace(namespace).Create(context.TODO(), &unstructuredVm, v1.CreateOptions{}); err != nil { + return fmt.Errorf("error creating VM %s/%s: %w", namespace, name, err) + } + + return nil +} + +func (v *VirtOperator) removeVm(namespace, name string) error { + if err := v.Dynamic.Resource(virtualMachineGvr).Namespace(namespace).Delete(context.TODO(), name, v1.DeleteOptions{}); err != nil { + if !apierrors.IsNotFound(err) { + return fmt.Errorf("error deleting VM %s/%s: %w", namespace, name, err) + } + log.Printf("VM %s/%s not found, delete not necessary.", namespace, name) + } + + return nil +} + +func (v *VirtOperator) ensureVm(namespace, name, source string, timeout time.Duration) error { + if v.checkVmExists(namespace, name) { + log.Printf("VM %s/%s already exists.", namespace, name) + return nil + } + + if err := v.createVm(namespace, name, source); err != nil { + return fmt.Errorf("failed to create VM %s/%s: %w", namespace, name, err) + } + + err := wait.PollImmediate(5*time.Second, timeout, func() (bool, error) { + return v.checkVmStatus(namespace, name, "Running"), nil + }) + + return err +} + +func (v *VirtOperator) ensureVmRemoval(namespace, name string, timeout time.Duration) error { + if !v.checkVmExists(namespace, name) { + log.Printf("VM %s/%s already removed, no action required", namespace, name) + return nil + } + + if err := v.removeVm(namespace, name); err != nil { + return err + } + + err := wait.PollImmediate(5*time.Second, timeout, func() (bool, error) { + return !v.checkVmExists(namespace, name), nil + }) + + return err +} + // Enable KVM emulation for use on cloud clusters that do not have direct // access to the host server's virtualization capabilities. -func (v *VirtOperator) ensureEmulation(timeout time.Duration) error { +func (v *VirtOperator) EnsureEmulation(timeout time.Duration) error { if v.checkEmulation() { log.Printf("KVM emulation already enabled, no work needed to turn it on.") return nil + } else { + log.Printf("Enabling KVM emulation...") } if err := v.configureEmulation(); err != nil { @@ -685,16 +816,14 @@ func (v *VirtOperator) EnsureVirtRemoval() error { return nil } -// Create a Virtual Machine from an existing PVC. -func (v *VirtOperator) CreateVM(namespace, name, source string) error { - log.Printf("Enabling KVM emulation...") - if err := v.ensureEmulation(10 * time.Second); err != nil { - return fmt.Errorf("failed to enable KVM emulation: %w", err) - } - - if err := v.CloneDisk(namespace, source, name, 5*time.Minute); err != nil { - return err - } +// Create a virtual machine from an existing PVC. +func (v *VirtOperator) CreateVm(namespace, name, source string, timeout time.Duration) error { + log.Printf("Creating virtual machine %s/%s", namespace, name) + return v.ensureVm(namespace, name, source, timeout) +} - return nil +// Remove a virtual machine, but leave its data volume. +func (v *VirtOperator) RemoveVm(namespace, name string, timeout time.Duration) error { + log.Printf("Removing virtual machine %s/%s", namespace, name) + return v.ensureVmRemoval(namespace, name, timeout) } diff --git a/tests/e2e/lib/virt_storage_helpers.go b/tests/e2e/lib/virt_storage_helpers.go index 88117b8f14..4f7f28212f 100644 --- a/tests/e2e/lib/virt_storage_helpers.go +++ b/tests/e2e/lib/virt_storage_helpers.go @@ -171,7 +171,7 @@ func (v *VirtOperator) EnsureDataVolume(namespace, name, url, size string, timeo } // Delete a DataVolume and wait for it to go away. -func (v *VirtOperator) EnsureDataVolumeRemoval(namespace, name string, timeout time.Duration) error { +func (v *VirtOperator) RemoveDataVolume(namespace, name string, timeout time.Duration) error { err := v.deleteDataVolume(namespace, name) if err != nil { if apierrors.IsNotFound(err) { diff --git a/tests/e2e/virt_backup_restore_suite_test.go b/tests/e2e/virt_backup_restore_suite_test.go index 2e7afc0381..523fb12ff0 100644 --- a/tests/e2e/virt_backup_restore_suite_test.go +++ b/tests/e2e/virt_backup_restore_suite_test.go @@ -27,6 +27,9 @@ var _ = Describe("VM backup and restore tests", Ordered, func() { wasInstalledFromTest = true } + err = v.EnsureEmulation(10 * time.Second) + Expect(err).To(BeNil()) + err = v.EnsureDataVolume("openshift-cnv", "cirros-dv", "https://download.cirros-cloud.net/0.6.2/cirros-0.6.2-x86_64-disk.img", "128Mi", 5*time.Minute) Expect(err).To(BeNil()) }) @@ -34,7 +37,6 @@ var _ = Describe("VM backup and restore tests", Ordered, func() { var _ = AfterAll(func() { if v != nil && wasInstalledFromTest { v.EnsureVirtRemoval() - v.EnsureDataVolumeRemoval("openshift-cnv", "cirros-dv", 2*time.Minute) } }) @@ -44,7 +46,17 @@ var _ = Describe("VM backup and restore tests", Ordered, func() { }) It("should create and boot a virtual machine", Label("virt"), func() { - err := v.CreateVM("openshift-cnv", "cirros-vm", "cirros-dv") + namespace := "openshift-cnv" + source := "cirros-dv" + name := "cirros-vm" + + err := v.CloneDisk(namespace, source, name, 5*time.Minute) Expect(err).To(BeNil()) + + err = v.CreateVm(namespace, name, source, 5*time.Minute) + Expect(err).To(BeNil()) + + v.RemoveVm(namespace, name, 2*time.Minute) + v.RemoveDataVolume(namespace, name, 2*time.Minute) }) }) From d67a4a5c452fd13d9776c2c75aeb95f5eeb1359f Mon Sep 17 00:00:00 2001 From: Matthew Arnold Date: Wed, 14 Feb 2024 10:03:24 -0500 Subject: [PATCH 5/6] Clean up base CirrOS disk before removing HCO. I took this out by mistake in a previous commit. Signed-off-by: Matthew Arnold --- tests/e2e/virt_backup_restore_suite_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/e2e/virt_backup_restore_suite_test.go b/tests/e2e/virt_backup_restore_suite_test.go index 523fb12ff0..b65aeff11f 100644 --- a/tests/e2e/virt_backup_restore_suite_test.go +++ b/tests/e2e/virt_backup_restore_suite_test.go @@ -36,6 +36,7 @@ var _ = Describe("VM backup and restore tests", Ordered, func() { var _ = AfterAll(func() { if v != nil && wasInstalledFromTest { + v.RemoveDataVolume("openshift-cnv", "cirros-dv", 2*time.Minute) v.EnsureVirtRemoval() } }) From 708e39a165e6d41a788e8f7cd56987377f4025ca Mon Sep 17 00:00:00 2001 From: Matthew Arnold Date: Wed, 14 Feb 2024 13:57:04 -0500 Subject: [PATCH 6/6] Address some review comments. Signed-off-by: Matthew Arnold --- tests/e2e/lib/virt_helpers.go | 9 ++---- tests/e2e/lib/virt_storage_helpers.go | 4 +-- tests/e2e/virt_backup_restore_suite_test.go | 32 +++++++++++++++++++-- 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/tests/e2e/lib/virt_helpers.go b/tests/e2e/lib/virt_helpers.go index 1f77a20a9f..6c138bf48a 100644 --- a/tests/e2e/lib/virt_helpers.go +++ b/tests/e2e/lib/virt_helpers.go @@ -676,11 +676,6 @@ func (v *VirtOperator) removeVm(namespace, name string) error { } func (v *VirtOperator) ensureVm(namespace, name, source string, timeout time.Duration) error { - if v.checkVmExists(namespace, name) { - log.Printf("VM %s/%s already exists.", namespace, name) - return nil - } - if err := v.createVm(namespace, name, source); err != nil { return fmt.Errorf("failed to create VM %s/%s: %w", namespace, name, err) } @@ -715,10 +710,10 @@ func (v *VirtOperator) EnsureEmulation(timeout time.Duration) error { if v.checkEmulation() { log.Printf("KVM emulation already enabled, no work needed to turn it on.") return nil - } else { - log.Printf("Enabling KVM emulation...") } + log.Printf("Enabling KVM emulation...") + if err := v.configureEmulation(); err != nil { return err } diff --git a/tests/e2e/lib/virt_storage_helpers.go b/tests/e2e/lib/virt_storage_helpers.go index 4f7f28212f..c4303957e5 100644 --- a/tests/e2e/lib/virt_storage_helpers.go +++ b/tests/e2e/lib/virt_storage_helpers.go @@ -148,12 +148,12 @@ func (v *VirtOperator) createDataVolumeFromPvc(namespace, sourceName, cloneName, } // Create a DataVolume and wait for it to be ready. -func (v *VirtOperator) EnsureDataVolume(namespace, name, url, size string, timeout time.Duration) error { +func (v *VirtOperator) EnsureDataVolumeFromUrl(namespace, name, url, size string, timeout time.Duration) error { if !v.checkDataVolumeExists(namespace, name) { if err := v.createDataVolumeFromUrl(namespace, name, url, size); err != nil { return err } - log.Printf("Created DataVolume %s/%s", namespace, name) + log.Printf("Created DataVolume %s/%s from %s", namespace, name, url) } else { log.Printf("DataVolume %s/%s already created, checking for readiness", namespace, name) } diff --git a/tests/e2e/virt_backup_restore_suite_test.go b/tests/e2e/virt_backup_restore_suite_test.go index b65aeff11f..0cd843b94d 100644 --- a/tests/e2e/virt_backup_restore_suite_test.go +++ b/tests/e2e/virt_backup_restore_suite_test.go @@ -1,6 +1,10 @@ package e2e_test import ( + "fmt" + "io" + "net/http" + "strings" "time" . "github.com/onsi/ginkgo/v2" @@ -8,6 +12,27 @@ import ( . "github.com/openshift/oadp-operator/tests/e2e/lib" ) +func getLatestCirrosImageURL() (string, error) { + cirrosVersionURL := "https://download.cirros-cloud.net/version/released" + + resp, err := http.Get(cirrosVersionURL) + if err != nil { + return "", err + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return "", err + } + + latestCirrosVersion := strings.TrimSpace(string(body)) + + imageURL := fmt.Sprintf("https://download.cirros-cloud.net/%s/cirros-%s-x86_64-disk.img", latestCirrosVersion, latestCirrosVersion) + + return imageURL, nil +} + var _ = Describe("VM backup and restore tests", Ordered, func() { var v *VirtOperator var err error @@ -30,13 +55,16 @@ var _ = Describe("VM backup and restore tests", Ordered, func() { err = v.EnsureEmulation(10 * time.Second) Expect(err).To(BeNil()) - err = v.EnsureDataVolume("openshift-cnv", "cirros-dv", "https://download.cirros-cloud.net/0.6.2/cirros-0.6.2-x86_64-disk.img", "128Mi", 5*time.Minute) + url, err := getLatestCirrosImageURL() + Expect(err).To(BeNil()) + err = v.EnsureDataVolumeFromUrl("openshift-cnv", "cirros-dv", url, "128Mi", 5*time.Minute) Expect(err).To(BeNil()) }) var _ = AfterAll(func() { + v.RemoveDataVolume("openshift-cnv", "cirros-dv", 2*time.Minute) + if v != nil && wasInstalledFromTest { - v.RemoveDataVolume("openshift-cnv", "cirros-dv", 2*time.Minute) v.EnsureVirtRemoval() } })