k8s.io/kubernetes@v1.29.3/test/e2e/storage/pv_protection.go (about) 1 /* 2 Copyright 2018 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 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 // Enforce binding only within test space via selector labels 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 // make the pv definitions 81 pv = e2epv.MakePersistentVolume(pvConfig) 82 // create the PV 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 })