Skip to content

Commit

Permalink
e2e: Add e2e tests for deletion flows
Browse files Browse the repository at this point in the history
Signed-off-by: Or Shoval <[email protected]>
  • Loading branch information
oshoval committed Aug 1, 2024
1 parent 20abe0e commit 9742198
Show file tree
Hide file tree
Showing 2 changed files with 142 additions and 3 deletions.
129 changes: 126 additions & 3 deletions test/e2e/persistentips_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,17 @@ package e2e

import (
"context"
"encoding/json"
"fmt"
"os/exec"
"time"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"

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

kubevirtv1 "kubevirt.io/api/core/v1"
Expand Down Expand Up @@ -61,7 +65,7 @@ var _ = Describe("Persistent IPs", func() {
})
Context("and a virtual machine using it is also created", func() {
BeforeEach(func() {
By("Creating VM using the nad")
By("Creating VM with secondary attachments")
Expect(testenv.Client.Create(context.Background(), vm)).To(Succeed())

By(fmt.Sprintf("Waiting for readiness at virtual machine %s", vm.Name))
Expand Down Expand Up @@ -98,14 +102,60 @@ var _ = Describe("Persistent IPs", func() {

})

It("should garbage collect IPAMClaims after virtual machine deletion", func() {
It("should garbage collect IPAMClaims after VM deletion", func() {
Expect(testenv.Client.Delete(context.Background(), vm)).To(Succeed())
Eventually(testenv.IPAMClaimsFromNamespace(vm.Namespace)).
WithTimeout(time.Minute).
WithPolling(time.Second).
Should(BeEmpty())
})

It("should garbage collect IPAMClaims after VM foreground deletion", func() {
Expect(testenv.Client.Delete(context.Background(), vm, foregroundDeleteOptions())).To(Succeed())
Eventually(testenv.IPAMClaimsFromNamespace(vm.Namespace)).
WithTimeout(time.Minute).
WithPolling(time.Second).
Should(BeEmpty())
})

When("the VM is stopped", func() {
BeforeEach(func() {
By("Invoking virtctl stop")
output, err := exec.Command("virtctl", "stop", "-n", td.Namespace, vmi.Name).CombinedOutput()
Expect(err).NotTo(HaveOccurred(), output)

By("Ensuring VM is not running")
Eventually(testenv.ThisVMI(vmi), 360*time.Second, 1*time.Second).Should(
SatisfyAll(
Not(testenv.BeCreated()),
Not(testenv.BeReady()),
))

Consistently(testenv.IPAMClaimsFromNamespace(vm.Namespace)).
WithTimeout(time.Minute).
WithPolling(time.Second).
ShouldNot(BeEmpty())
})

It("should garbage collect IPAMClaims after VM is deleted", func() {
By("Delete VM and check ipam claims are gone")
Expect(testenv.Client.Delete(context.Background(), vm)).To(Succeed())
Eventually(testenv.IPAMClaimsFromNamespace(vm.Namespace)).
WithTimeout(time.Minute).
WithPolling(time.Second).
Should(BeEmpty())
})

It("should garbage collect IPAMClaims after VM is foreground deleted", func() {
By("Foreground delete VM and check ipam claims are gone")
Expect(testenv.Client.Delete(context.Background(), vm, foregroundDeleteOptions())).To(Succeed())
Eventually(testenv.IPAMClaimsFromNamespace(vm.Namespace)).
WithTimeout(time.Minute).
WithPolling(time.Second).
Should(BeEmpty())
})
})

It("should keep ips after restart", func() {
vmiIPsBeforeRestart := vmi.Status.Interfaces[0].IPs
vmiUUIDBeforeRestart := vmi.UID
Expand All @@ -130,6 +180,55 @@ var _ = Describe("Persistent IPs", func() {
})
})

When("requested for a VM whose VMI has extra finalizers", func() {
const testFinalizer = "testFinalizer"

BeforeEach(func() {
By("Adding VMI custom finalizer to control VMI deletion")
vm.Spec.Template.ObjectMeta.Finalizers = []string{testFinalizer}

By("Creating VM with secondary attachments")
Expect(testenv.Client.Create(context.Background(), vm)).To(Succeed())

By(fmt.Sprintf("Waiting for readiness at virtual machine %s", vm.Name))
Eventually(testenv.ThisVMReadiness(vm)).
WithPolling(time.Second).
WithTimeout(5 * time.Minute).
Should(BeTrue())

By("Wait for IPAMClaim to get created")
Eventually(testenv.IPAMClaimsFromNamespace(vm.Namespace)).
WithTimeout(time.Minute).
WithPolling(time.Second).
ShouldNot(BeEmpty())

Expect(testenv.Client.Get(context.Background(), client.ObjectKeyFromObject(vmi), vmi)).To(Succeed())

Expect(vmi.Status.Interfaces).NotTo(BeEmpty())
Expect(vmi.Status.Interfaces[0].IPs).NotTo(BeEmpty())
})

It("should garbage collect IPAMClaims after VM foreground deletion, only after VMI is gone", func() {
By("Foreground delete the VM, and validate the IPAMClaim isnt deleted since VMI exists")
Expect(testenv.Client.Delete(context.Background(), vm, foregroundDeleteOptions())).To(Succeed())
Consistently(testenv.IPAMClaimsFromNamespace(vm.Namespace)).
WithTimeout(time.Minute).
WithPolling(time.Second).
ShouldNot(BeEmpty())

By("Remove the finalizer (all the other are already deleted in this stage)")
patchData, err := removeFinalizersPatch()
Expect(err).NotTo(HaveOccurred())
Expect(testenv.Client.Patch(context.TODO(), vmi, client.RawPatch(types.MergePatchType, patchData))).To(Succeed())

By("Check IPAMClaims are now deleted")
Eventually(testenv.IPAMClaimsFromNamespace(vm.Namespace)).
WithTimeout(time.Minute).
WithPolling(time.Second).
Should(BeEmpty())
})
})

Context("and a virtual machine instance using it is also created", func() {
BeforeEach(func() {
By("Creating VMI using the nad")
Expand Down Expand Up @@ -163,14 +262,38 @@ var _ = Describe("Persistent IPs", func() {

})

It("should garbage collect IPAMClaims after virtual machine deletion", func() {
It("should garbage collect IPAMClaims after VMI deletion", func() {
Expect(testenv.Client.Delete(context.Background(), vmi)).To(Succeed())
Eventually(testenv.IPAMClaimsFromNamespace(vmi.Namespace)).
WithTimeout(time.Minute).
WithPolling(time.Second).
Should(BeEmpty())
})

It("should garbage collect IPAMClaims after VMI foreground deletion", func() {
Expect(testenv.Client.Delete(context.Background(), vmi, foregroundDeleteOptions())).To(Succeed())
Eventually(testenv.IPAMClaimsFromNamespace(vmi.Namespace)).
WithTimeout(time.Minute).
WithPolling(time.Second).
Should(BeEmpty())
})
})

})
})

func foregroundDeleteOptions() *client.DeleteOptions {
foreground := metav1.DeletePropagationForeground
return &client.DeleteOptions{
PropagationPolicy: &foreground,
}
}

func removeFinalizersPatch() ([]byte, error) {
patch := map[string]interface{}{
"metadata": map[string]interface{}{
"finalizers": []string{},
},
}
return json.Marshal(patch)
}
16 changes: 16 additions & 0 deletions test/env/matcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,22 @@ func BeRestarted(oldUID types.UID) gomegatypes.GomegaMatcher {
}))
}

func BeCreated() gomegatypes.GomegaMatcher {
return gstruct.PointTo(gstruct.MatchFields(gstruct.IgnoreExtras, gstruct.Fields{
"Status": gstruct.MatchFields(gstruct.IgnoreExtras, gstruct.Fields{
"Created": BeTrue(),
}),
}))
}

func BeReady() gomegatypes.GomegaMatcher {
return gstruct.PointTo(gstruct.MatchFields(gstruct.IgnoreExtras, gstruct.Fields{
"Status": gstruct.MatchFields(gstruct.IgnoreExtras, gstruct.Fields{
"Ready": BeTrue(),
}),
}))
}

func ContainConditionVMIReady() gomegatypes.GomegaMatcher {
return WithTransform(vmiStatusConditions,
ContainElement(SatisfyAll(
Expand Down

0 comments on commit 9742198

Please sign in to comment.