1
16
17 package storage
18
19 import (
20 "context"
21 "time"
22
23 "github.com/onsi/ginkgo/v2"
24 "github.com/onsi/gomega"
25
26 v1 "k8s.io/api/core/v1"
27 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28 "k8s.io/apimachinery/pkg/labels"
29 utilerrors "k8s.io/apimachinery/pkg/util/errors"
30 clientset "k8s.io/client-go/kubernetes"
31 volumeutil "k8s.io/kubernetes/pkg/volume/util"
32 "k8s.io/kubernetes/test/e2e/framework"
33 e2enode "k8s.io/kubernetes/test/e2e/framework/node"
34 e2epv "k8s.io/kubernetes/test/e2e/framework/pv"
35 "k8s.io/kubernetes/test/e2e/storage/utils"
36 admissionapi "k8s.io/pod-security-admission/api"
37 )
38
39 var _ = utils.SIGDescribe("PV Protection", func() {
40 var (
41 client clientset.Interface
42 nameSpace string
43 err error
44 pvc *v1.PersistentVolumeClaim
45 pv *v1.PersistentVolume
46 pvConfig e2epv.PersistentVolumeConfig
47 pvcConfig e2epv.PersistentVolumeClaimConfig
48 volLabel labels.Set
49 selector *metav1.LabelSelector
50 )
51
52 f := framework.NewDefaultFramework("pv-protection")
53 f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged
54 ginkgo.BeforeEach(func(ctx context.Context) {
55 client = f.ClientSet
56 nameSpace = f.Namespace.Name
57 framework.ExpectNoError(e2enode.WaitForAllNodesSchedulable(ctx, client, f.Timeouts.NodeSchedulable))
58
59
60 volLabel = labels.Set{e2epv.VolumeSelectorKey: nameSpace}
61 selector = metav1.SetAsLabelSelector(volLabel)
62
63 pvConfig = e2epv.PersistentVolumeConfig{
64 NamePrefix: "hostpath-",
65 Labels: volLabel,
66 PVSource: v1.PersistentVolumeSource{
67 HostPath: &v1.HostPathVolumeSource{
68 Path: "/tmp/data",
69 },
70 },
71 }
72
73 emptyStorageClass := ""
74 pvcConfig = e2epv.PersistentVolumeClaimConfig{
75 Selector: selector,
76 StorageClassName: &emptyStorageClass,
77 }
78
79 ginkgo.By("Creating a PV")
80
81 pv = e2epv.MakePersistentVolume(pvConfig)
82
83 pv, err = client.CoreV1().PersistentVolumes().Create(ctx, pv, metav1.CreateOptions{})
84 framework.ExpectNoError(err, "Error creating PV")
85
86 ginkgo.By("Waiting for PV to enter phase Available")
87 framework.ExpectNoError(e2epv.WaitForPersistentVolumePhase(ctx, v1.VolumeAvailable, client, pv.Name, 1*time.Second, 30*time.Second))
88
89 ginkgo.By("Checking that PV Protection finalizer is set")
90 pv, err = client.CoreV1().PersistentVolumes().Get(ctx, pv.Name, metav1.GetOptions{})
91 framework.ExpectNoError(err, "While getting PV status")
92 gomega.Expect(pv.ObjectMeta.Finalizers).Should(gomega.ContainElement(volumeutil.PVProtectionFinalizer), "PV Protection finalizer(%v) is not set in %v", volumeutil.PVProtectionFinalizer, pv.ObjectMeta.Finalizers)
93 })
94
95 ginkgo.AfterEach(func(ctx context.Context) {
96 framework.Logf("AfterEach: Cleaning up test resources.")
97 if errs := e2epv.PVPVCCleanup(ctx, client, nameSpace, pv, pvc); len(errs) > 0 {
98 framework.Failf("AfterEach: Failed to delete PVC and/or PV. Errors: %v", utilerrors.NewAggregate(errs))
99 }
100 })
101
102 ginkgo.It("Verify \"immediate\" deletion of a PV that is not bound to a PVC", func(ctx context.Context) {
103 ginkgo.By("Deleting the PV")
104 err = client.CoreV1().PersistentVolumes().Delete(ctx, pv.Name, *metav1.NewDeleteOptions(0))
105 framework.ExpectNoError(err, "Error deleting PV")
106 err = e2epv.WaitForPersistentVolumeDeleted(ctx, client, pv.Name, framework.Poll, f.Timeouts.PVDelete)
107 framework.ExpectNoError(err, "waiting for PV to be deleted")
108 })
109
110 ginkgo.It("Verify that PV bound to a PVC is not removed immediately", func(ctx context.Context) {
111 ginkgo.By("Creating a PVC")
112 pvc = e2epv.MakePersistentVolumeClaim(pvcConfig, nameSpace)
113 pvc, err = client.CoreV1().PersistentVolumeClaims(pvc.Namespace).Create(ctx, pvc, metav1.CreateOptions{})
114 framework.ExpectNoError(err, "Error creating PVC")
115
116 ginkgo.By("Waiting for PVC to become Bound")
117 err = e2epv.WaitForPersistentVolumeClaimPhase(ctx, v1.ClaimBound, client, nameSpace, pvc.Name, framework.Poll, f.Timeouts.ClaimBound)
118 framework.ExpectNoError(err, "Failed waiting for PVC to be bound %v", err)
119
120 ginkgo.By("Deleting the PV, however, the PV must not be removed from the system as it's bound to a PVC")
121 err = client.CoreV1().PersistentVolumes().Delete(ctx, pv.Name, *metav1.NewDeleteOptions(0))
122 framework.ExpectNoError(err, "Error deleting PV")
123
124 ginkgo.By("Checking that the PV status is Terminating")
125 pv, err = client.CoreV1().PersistentVolumes().Get(ctx, pv.Name, metav1.GetOptions{})
126 framework.ExpectNoError(err, "While checking PV status")
127 gomega.Expect(pv.ObjectMeta.DeletionTimestamp).ToNot(gomega.BeNil())
128
129 ginkgo.By("Deleting the PVC that is bound to the PV")
130 err = client.CoreV1().PersistentVolumeClaims(pvc.Namespace).Delete(ctx, pvc.Name, *metav1.NewDeleteOptions(0))
131 framework.ExpectNoError(err, "Error deleting PVC")
132
133 ginkgo.By("Checking that the PV is automatically removed from the system because it's no longer bound to a PVC")
134 err = e2epv.WaitForPersistentVolumeDeleted(ctx, client, pv.Name, framework.Poll, f.Timeouts.PVDelete)
135 framework.ExpectNoError(err, "waiting for PV to be deleted")
136 })
137 })
138
View as plain text