k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/test/e2e/storage/csimock/csi_honor_pv_reclaim_policy.go (about)

     1  /*
     2  Copyright 2024 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 csimock
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"time"
    23  
    24  	"github.com/onsi/ginkgo/v2"
    25  	"github.com/onsi/gomega"
    26  	v1 "k8s.io/api/core/v1"
    27  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    28  	storagehelpers "k8s.io/component-helpers/storage/volume"
    29  	"k8s.io/kubernetes/pkg/features"
    30  	"k8s.io/kubernetes/test/e2e/feature"
    31  	"k8s.io/kubernetes/test/e2e/framework"
    32  	e2epv "k8s.io/kubernetes/test/e2e/framework/pv"
    33  	"k8s.io/kubernetes/test/e2e/storage/utils"
    34  	admissionapi "k8s.io/pod-security-admission/api"
    35  	"k8s.io/utils/ptr"
    36  )
    37  
    38  var _ = utils.SIGDescribe("CSI Mock honor pv reclaim policy", feature.HonorPVReclaimPolicy, framework.WithFeatureGate(features.HonorPVReclaimPolicy), func() {
    39  	f := framework.NewDefaultFramework("csi-mock-honor-pv-reclaim-policy")
    40  	f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged
    41  	m := newMockDriverSetup(f)
    42  
    43  	ginkgo.Context("CSI honor pv reclaim policy using mock driver", func() {
    44  		ginkgo.It("Dynamic provisioning should honor pv delete reclaim policy", func(ctx context.Context) {
    45  			m.init(ctx, testParameters{
    46  				registerDriver:             true,
    47  				enableHonorPVReclaimPolicy: true,
    48  				reclaimPolicy:              ptr.To(v1.PersistentVolumeReclaimDelete),
    49  			})
    50  			ginkgo.DeferCleanup(m.cleanup)
    51  
    52  			_, pvc := m.createPVC(ctx)
    53  
    54  			ginkgo.By(fmt.Sprintf("Waiting for PVC %s to be bound", pvc.Name))
    55  			pvs, err := e2epv.WaitForPVClaimBoundPhase(ctx, f.ClientSet, []*v1.PersistentVolumeClaim{pvc}, framework.ClaimProvisionTimeout)
    56  			framework.ExpectNoError(err, "failed to wait for PVC to be bound")
    57  			gomega.Expect(pvs).To(gomega.HaveLen(1), "expected 1 PV to be bound to PVC, got %d", len(pvs))
    58  
    59  			pv := pvs[0]
    60  			ginkgo.By(fmt.Sprintf("PVC %s is bound to PV %s", pvc.Name, pv.Name))
    61  			gomega.Expect(pv.Spec.PersistentVolumeReclaimPolicy).To(gomega.Equal(v1.PersistentVolumeReclaimDelete),
    62  				"expected PV %s to have reclaim policy %s, got %s", pv.Name, v1.PersistentVolumeReclaimDelete, pv.Spec.PersistentVolumeReclaimPolicy)
    63  			// For dynamic provisioning, the PV should be created with the deletion protection finalizer.
    64  			gomega.Expect(pv.Finalizers).To(gomega.ContainElement(storagehelpers.PVDeletionProtectionFinalizer),
    65  				"expected PV %s to have finalizer %s", pv.Name, storagehelpers.PVDeletionProtectionFinalizer)
    66  
    67  			ginkgo.By(fmt.Sprintf("Deleting PV %s", pv.Name))
    68  			err = f.ClientSet.CoreV1().PersistentVolumes().Delete(ctx, pv.Name, metav1.DeleteOptions{})
    69  			framework.ExpectNoError(err, "failed to delete PV %s", pv.Name)
    70  
    71  			ginkgo.By(fmt.Sprintf("Deleting PVC %s", pvc.Name))
    72  			err = f.ClientSet.CoreV1().PersistentVolumeClaims(pvc.Namespace).Delete(ctx, pvc.Name, metav1.DeleteOptions{})
    73  			framework.ExpectNoError(err, "failed to delete PVC %s", pvc.Name)
    74  
    75  			ginkgo.By(fmt.Sprintf("Waiting for PV %s to be deleted", pv.Name))
    76  			err = e2epv.WaitForPersistentVolumeDeleted(ctx, f.ClientSet, pv.Name, framework.Poll, 2*time.Minute)
    77  			framework.ExpectNoError(err, "failed to wait for PV to be deleted")
    78  
    79  			ginkgo.By(fmt.Sprintf("Verifying that the driver received DeleteVolume call for PV %s", pv.Name))
    80  			gomega.Expect(m.driver.GetCalls(ctx)).To(gomega.ContainElement(gomega.HaveField("Method", gomega.Equal("DeleteVolume"))))
    81  		})
    82  
    83  		ginkgo.It("Dynamic provisioning should honor pv retain reclaim policy", func(ctx context.Context) {
    84  			m.init(ctx, testParameters{
    85  				registerDriver:             true,
    86  				enableHonorPVReclaimPolicy: true,
    87  				reclaimPolicy:              ptr.To(v1.PersistentVolumeReclaimRetain),
    88  			})
    89  			ginkgo.DeferCleanup(m.cleanup)
    90  
    91  			_, pvc := m.createPVC(ctx)
    92  
    93  			ginkgo.By(fmt.Sprintf("Waiting for PVC %s to be bound", pvc.Name))
    94  			pvs, err := e2epv.WaitForPVClaimBoundPhase(ctx, f.ClientSet, []*v1.PersistentVolumeClaim{pvc}, framework.ClaimProvisionTimeout)
    95  			framework.ExpectNoError(err, "failed to wait for PVC to be bound")
    96  			gomega.Expect(pvs).To(gomega.HaveLen(1), "expected 1 PV to be bound to PVC, got %d", len(pvs))
    97  
    98  			pv := pvs[0]
    99  			ginkgo.By(fmt.Sprintf("PVC %s is bound to PV %s", pvc.Name, pv.Name))
   100  			gomega.Expect(pv.Spec.PersistentVolumeReclaimPolicy).To(gomega.Equal(v1.PersistentVolumeReclaimRetain),
   101  				"expected PV %s to have reclaim policy %s, got %s", pv.Name, v1.PersistentVolumeReclaimRetain, pv.Spec.PersistentVolumeReclaimPolicy)
   102  
   103  			ginkgo.By(fmt.Sprintf("Verifying that the PV %s does not have finalizer %s after creation", pv.Name, storagehelpers.PVDeletionProtectionFinalizer))
   104  			gomega.Consistently(ctx, framework.GetObject(f.ClientSet.CoreV1().PersistentVolumes().Get, pv.Name, metav1.GetOptions{})).
   105  				WithPolling(framework.Poll).WithTimeout(framework.ClaimProvisionTimeout).ShouldNot(gomega.HaveField("Finalizers",
   106  				gomega.ContainElement(storagehelpers.PVDeletionProtectionFinalizer)), "pv unexpectedly has the finalizer %s", storagehelpers.PVDeletionProtectionFinalizer)
   107  
   108  			ginkgo.By(fmt.Sprintf("Deleting PV %s", pv.Name))
   109  			err = f.ClientSet.CoreV1().PersistentVolumes().Delete(ctx, pv.Name, metav1.DeleteOptions{})
   110  			framework.ExpectNoError(err, "failed to delete PV %s", pv.Name)
   111  
   112  			ginkgo.By(fmt.Sprintf("Deleting PVC %s", pvc.Name))
   113  			err = f.ClientSet.CoreV1().PersistentVolumeClaims(pvc.Namespace).Delete(ctx, pvc.Name, metav1.DeleteOptions{})
   114  			framework.ExpectNoError(err, "failed to delete PVC %s", pvc.Name)
   115  
   116  			ginkgo.By(fmt.Sprintf("Waiting for PV %s to be deleted", pv.Name))
   117  			err = e2epv.WaitForPersistentVolumeDeleted(ctx, f.ClientSet, pv.Name, framework.Poll, 2*time.Minute)
   118  			framework.ExpectNoError(err, "failed to wait for PV to be deleted")
   119  
   120  			ginkgo.By(fmt.Sprintf("Verifying that the driver did not receive DeleteVolume call for PV %s", pv.Name))
   121  			gomega.Expect(m.driver.GetCalls(ctx)).NotTo(gomega.ContainElement(gomega.HaveField("Method", gomega.Equal("DeleteVolume"))))
   122  		})
   123  
   124  		ginkgo.It("Static provisioning should honor pv delete reclaim policy", func(ctx context.Context) {
   125  			m.init(ctx, testParameters{
   126  				registerDriver:             true,
   127  				enableHonorPVReclaimPolicy: true,
   128  				reclaimPolicy:              ptr.To(v1.PersistentVolumeReclaimDelete),
   129  			})
   130  			ginkgo.DeferCleanup(m.cleanup)
   131  
   132  			sc, pv, pvc := m.createPVPVC(ctx)
   133  			gomega.Expect(pv.Spec.PersistentVolumeReclaimPolicy).To(gomega.Equal(v1.PersistentVolumeReclaimDelete),
   134  				"expected PV %s to have reclaim policy %s, got %s", pv.Name, v1.PersistentVolumeReclaimDelete, pv.Spec.PersistentVolumeReclaimPolicy)
   135  			gomega.Expect(pv.Annotations).NotTo(gomega.HaveKeyWithValue(storagehelpers.AnnDynamicallyProvisioned, sc.Provisioner), "expected PV %s to not have annotation %s", pv.Name, storagehelpers.AnnDynamicallyProvisioned)
   136  
   137  			ginkgo.By(fmt.Sprintf("Verifying that the PV %s has finalizer %s after creation", pv.Name, storagehelpers.PVDeletionProtectionFinalizer))
   138  			gomega.Eventually(ctx, framework.GetObject(f.ClientSet.CoreV1().PersistentVolumes().Get, pv.Name, metav1.GetOptions{})).
   139  				WithPolling(framework.Poll).WithTimeout(framework.ClaimProvisionTimeout).Should(gomega.HaveField("Finalizers",
   140  				gomega.ContainElement(storagehelpers.PVDeletionProtectionFinalizer)), "failed to wait for PV to have finalizer %s", storagehelpers.PVDeletionProtectionFinalizer)
   141  
   142  			ginkgo.By(fmt.Sprintf("Deleting PV %s", pv.Name))
   143  			err := f.ClientSet.CoreV1().PersistentVolumes().Delete(ctx, pv.Name, metav1.DeleteOptions{})
   144  			framework.ExpectNoError(err, "failed to delete PV %s", pv.Name)
   145  
   146  			ginkgo.By(fmt.Sprintf("Deleting PVC %s", pvc.Name))
   147  			err = f.ClientSet.CoreV1().PersistentVolumeClaims(pvc.Namespace).Delete(ctx, pvc.Name, metav1.DeleteOptions{})
   148  			framework.ExpectNoError(err, "failed to delete PVC %s", pvc.Name)
   149  
   150  			ginkgo.By(fmt.Sprintf("Waiting for PV %s to be deleted", pv.Name))
   151  			err = e2epv.WaitForPersistentVolumeDeleted(ctx, f.ClientSet, pv.Name, framework.Poll, 2*time.Minute)
   152  			framework.ExpectNoError(err, "failed to wait for PV to be deleted")
   153  
   154  			ginkgo.By(fmt.Sprintf("Verifying that the driver received DeleteVolume call for PV %s", pv.Name))
   155  			gomega.Expect(m.driver.GetCalls(ctx)).To(gomega.ContainElement(gomega.HaveField("Method", gomega.Equal("DeleteVolume"))))
   156  		})
   157  
   158  		ginkgo.It("Static provisioning should honor pv retain reclaim policy", func(ctx context.Context) {
   159  			m.init(ctx, testParameters{
   160  				registerDriver:             true,
   161  				enableHonorPVReclaimPolicy: true,
   162  				reclaimPolicy:              ptr.To(v1.PersistentVolumeReclaimRetain),
   163  			})
   164  			ginkgo.DeferCleanup(m.cleanup)
   165  
   166  			sc, pv, pvc := m.createPVPVC(ctx)
   167  			gomega.Expect(pv.Spec.PersistentVolumeReclaimPolicy).To(gomega.Equal(v1.PersistentVolumeReclaimRetain),
   168  				"expected PV %s to have reclaim policy %s, got %s", pv.Name, v1.PersistentVolumeReclaimRetain, pv.Spec.PersistentVolumeReclaimPolicy)
   169  			gomega.Expect(pv.Annotations).NotTo(gomega.HaveKeyWithValue(storagehelpers.AnnDynamicallyProvisioned, sc.Provisioner), "expected PV %s to not have annotation %s", pv.Name, storagehelpers.AnnDynamicallyProvisioned)
   170  
   171  			ginkgo.By(fmt.Sprintf("Verifying that the PV %s does not have finalizer %s after creation", pv.Name, storagehelpers.PVDeletionProtectionFinalizer))
   172  			gomega.Consistently(ctx, framework.GetObject(f.ClientSet.CoreV1().PersistentVolumes().Get, pv.Name, metav1.GetOptions{})).
   173  				WithPolling(framework.Poll).WithTimeout(framework.ClaimProvisionTimeout).ShouldNot(gomega.HaveField("Finalizers",
   174  				gomega.ContainElement(storagehelpers.PVDeletionProtectionFinalizer)), "pv unexpectedly has the finalizer %s", storagehelpers.PVDeletionProtectionFinalizer)
   175  
   176  			ginkgo.By(fmt.Sprintf("Deleting PV %s", pv.Name))
   177  			err := f.ClientSet.CoreV1().PersistentVolumes().Delete(ctx, pv.Name, metav1.DeleteOptions{})
   178  			framework.ExpectNoError(err, "failed to delete PV %s", pv.Name)
   179  
   180  			ginkgo.By(fmt.Sprintf("Deleting PVC %s", pvc.Name))
   181  			err = f.ClientSet.CoreV1().PersistentVolumeClaims(pvc.Namespace).Delete(ctx, pvc.Name, metav1.DeleteOptions{})
   182  			framework.ExpectNoError(err, "failed to delete PVC %s", pvc.Name)
   183  
   184  			ginkgo.By(fmt.Sprintf("Waiting for PV %s to be deleted", pv.Name))
   185  			err = e2epv.WaitForPersistentVolumeDeleted(ctx, f.ClientSet, pv.Name, framework.Poll, 2*time.Minute)
   186  			framework.ExpectNoError(err, "failed to wait for PV to be deleted")
   187  
   188  			ginkgo.By(fmt.Sprintf("Verifying that the driver did not receive DeleteVolume call for PV %s", pv.Name))
   189  			gomega.Expect(m.driver.GetCalls(ctx)).NotTo(gomega.ContainElement(gomega.HaveField("Method", gomega.Equal("DeleteVolume"))))
   190  		})
   191  	})
   192  })