k8s.io/kubernetes@v1.29.3/test/e2e/storage/vsphere/pv_reclaimpolicy.go (about)

     1  /*
     2  Copyright 2017 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 vsphere
    18  
    19  import (
    20  	"context"
    21  	"strconv"
    22  	"time"
    23  
    24  	"github.com/onsi/ginkgo/v2"
    25  	v1 "k8s.io/api/core/v1"
    26  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    27  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    28  	clientset "k8s.io/client-go/kubernetes"
    29  	"k8s.io/kubernetes/test/e2e/feature"
    30  	"k8s.io/kubernetes/test/e2e/framework"
    31  	e2enode "k8s.io/kubernetes/test/e2e/framework/node"
    32  	e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
    33  	e2epv "k8s.io/kubernetes/test/e2e/framework/pv"
    34  	e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper"
    35  	"k8s.io/kubernetes/test/e2e/storage/utils"
    36  	admissionapi "k8s.io/pod-security-admission/api"
    37  )
    38  
    39  var _ = utils.SIGDescribe("PersistentVolumes", feature.Vsphere, feature.ReclaimPolicy, func() {
    40  	f := framework.NewDefaultFramework("persistentvolumereclaim")
    41  	f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged
    42  	var (
    43  		c          clientset.Interface
    44  		ns         string
    45  		volumePath string
    46  		pv         *v1.PersistentVolume
    47  		pvc        *v1.PersistentVolumeClaim
    48  		nodeInfo   *NodeInfo
    49  	)
    50  
    51  	ginkgo.BeforeEach(func(ctx context.Context) {
    52  		c = f.ClientSet
    53  		ns = f.Namespace.Name
    54  		framework.ExpectNoError(e2enode.WaitForAllNodesSchedulable(ctx, c, f.Timeouts.NodeSchedulable))
    55  	})
    56  
    57  	f.Describe("persistentvolumereclaim:vsphere", feature.Vsphere, func() {
    58  		ginkgo.BeforeEach(func(ctx context.Context) {
    59  			e2eskipper.SkipUnlessProviderIs("vsphere")
    60  			ginkgo.DeferCleanup(testCleanupVSpherePersistentVolumeReclaim, c, nodeInfo, ns, volumePath, pv, pvc)
    61  			Bootstrap(f)
    62  			nodeInfo = GetReadySchedulableRandomNodeInfo(ctx, c)
    63  			pv = nil
    64  			pvc = nil
    65  			volumePath = ""
    66  		})
    67  
    68  		/*
    69  			This test verifies persistent volume should be deleted when reclaimPolicy on the PV is set to delete and
    70  			associated claim is deleted
    71  
    72  			Test Steps:
    73  			1. Create vmdk
    74  			2. Create PV Spec with volume path set to VMDK file created in Step-1, and PersistentVolumeReclaimPolicy is set to Delete
    75  			3. Create PVC with the storage request set to PV's storage capacity.
    76  			4. Wait for PV and PVC to bound.
    77  			5. Delete PVC
    78  			6. Verify PV is deleted automatically.
    79  		*/
    80  		ginkgo.It("should delete persistent volume when reclaimPolicy set to delete and associated claim is deleted", func(ctx context.Context) {
    81  			var err error
    82  			volumePath, pv, pvc, err = testSetupVSpherePersistentVolumeReclaim(ctx, c, nodeInfo, ns, v1.PersistentVolumeReclaimDelete)
    83  			framework.ExpectNoError(err)
    84  
    85  			deletePVCAfterBind(ctx, c, ns, pvc, pv, f.Timeouts)
    86  			pvc = nil
    87  
    88  			ginkgo.By("verify pv is deleted")
    89  			err = e2epv.WaitForPersistentVolumeDeleted(ctx, c, pv.Name, 3*time.Second, 300*time.Second)
    90  			framework.ExpectNoError(err)
    91  
    92  			pv = nil
    93  			volumePath = ""
    94  		})
    95  
    96  		/*
    97  			Test Steps:
    98  			1. Create vmdk
    99  			2. Create PV Spec with volume path set to VMDK file created in Step-1, and PersistentVolumeReclaimPolicy is set to Delete
   100  			3. Create PVC with the storage request set to PV's storage capacity.
   101  			4. Wait for PV and PVC to bound.
   102  			5. Delete PVC.
   103  			6. Verify volume is attached to the node and volume is accessible in the pod.
   104  			7. Verify PV status should be failed.
   105  			8. Delete the pod.
   106  			9. Verify PV should be detached from the node and automatically deleted.
   107  		*/
   108  		ginkgo.It("should not detach and unmount PV when associated pvc with delete as reclaimPolicy is deleted when it is in use by the pod", func(ctx context.Context) {
   109  			var err error
   110  
   111  			volumePath, pv, pvc, err = testSetupVSpherePersistentVolumeReclaim(ctx, c, nodeInfo, ns, v1.PersistentVolumeReclaimDelete)
   112  			framework.ExpectNoError(err)
   113  			// Wait for PV and PVC to Bind
   114  			framework.ExpectNoError(e2epv.WaitOnPVandPVC(ctx, c, f.Timeouts, ns, pv, pvc))
   115  
   116  			ginkgo.By("Creating the Pod")
   117  			pod, err := e2epod.CreateClientPod(ctx, c, ns, pvc)
   118  			framework.ExpectNoError(err)
   119  
   120  			ginkgo.By("Deleting the Claim")
   121  			framework.ExpectNoError(e2epv.DeletePersistentVolumeClaim(ctx, c, pvc.Name, ns), "Failed to delete PVC ", pvc.Name)
   122  			pvc = nil
   123  
   124  			// Verify PV is Present, after PVC is deleted and PV status should be Failed.
   125  			pv, err := c.CoreV1().PersistentVolumes().Get(ctx, pv.Name, metav1.GetOptions{})
   126  			framework.ExpectNoError(err)
   127  			err = e2epv.WaitForPersistentVolumePhase(ctx, v1.VolumeFailed, c, pv.Name, 1*time.Second, 60*time.Second)
   128  			framework.ExpectNoError(err)
   129  
   130  			ginkgo.By("Verify the volume is attached to the node")
   131  			isVolumeAttached, verifyDiskAttachedError := diskIsAttached(ctx, pv.Spec.VsphereVolume.VolumePath, pod.Spec.NodeName)
   132  			framework.ExpectNoError(verifyDiskAttachedError)
   133  			if !isVolumeAttached {
   134  				framework.Failf("Disk %s is not attached with the node %s", pv.Spec.VsphereVolume.VolumePath, pod.Spec.NodeName)
   135  			}
   136  
   137  			ginkgo.By("Verify the volume is accessible and available in the pod")
   138  			verifyVSphereVolumesAccessible(ctx, c, pod, []*v1.PersistentVolume{pv})
   139  			framework.Logf("Verified that Volume is accessible in the POD after deleting PV claim")
   140  
   141  			ginkgo.By("Deleting the Pod")
   142  			framework.ExpectNoError(e2epod.DeletePodWithWait(ctx, c, pod), "Failed to delete pod ", pod.Name)
   143  
   144  			ginkgo.By("Verify PV is detached from the node after Pod is deleted")
   145  			err = waitForVSphereDiskToDetach(ctx, pv.Spec.VsphereVolume.VolumePath, pod.Spec.NodeName)
   146  			framework.ExpectNoError(err)
   147  
   148  			ginkgo.By("Verify PV should be deleted automatically")
   149  			framework.ExpectNoError(e2epv.WaitForPersistentVolumeDeleted(ctx, c, pv.Name, 1*time.Second, 30*time.Second))
   150  			pv = nil
   151  			volumePath = ""
   152  		})
   153  
   154  		/*
   155  			This test Verify persistent volume should be retained when reclaimPolicy on the PV is set to retain
   156  			and associated claim is deleted
   157  
   158  			Test Steps:
   159  			1. Create vmdk
   160  			2. Create PV Spec with volume path set to VMDK file created in Step-1, and PersistentVolumeReclaimPolicy is set to Retain
   161  			3. Create PVC with the storage request set to PV's storage capacity.
   162  			4. Wait for PV and PVC to bound.
   163  			5. Write some content in the volume.
   164  			6. Delete PVC
   165  			7. Verify PV is retained.
   166  			8. Delete retained PV.
   167  			9. Create PV Spec with the same volume path used in step 2.
   168  			10. Create PVC with the storage request set to PV's storage capacity.
   169  			11. Created POD using PVC created in Step 10 and verify volume content is matching.
   170  		*/
   171  
   172  		ginkgo.It("should retain persistent volume when reclaimPolicy set to retain when associated claim is deleted", func(ctx context.Context) {
   173  			var err error
   174  			var volumeFileContent = "hello from vsphere cloud provider, Random Content is :" + strconv.FormatInt(time.Now().UnixNano(), 10)
   175  
   176  			volumePath, pv, pvc, err = testSetupVSpherePersistentVolumeReclaim(ctx, c, nodeInfo, ns, v1.PersistentVolumeReclaimRetain)
   177  			framework.ExpectNoError(err)
   178  
   179  			writeContentToVSpherePV(ctx, c, f.Timeouts, pvc, volumeFileContent)
   180  
   181  			ginkgo.By("Delete PVC")
   182  			framework.ExpectNoError(e2epv.DeletePersistentVolumeClaim(ctx, c, pvc.Name, ns), "Failed to delete PVC ", pvc.Name)
   183  			pvc = nil
   184  
   185  			ginkgo.By("Verify PV is retained")
   186  			framework.Logf("Waiting for PV %v to become Released", pv.Name)
   187  			err = e2epv.WaitForPersistentVolumePhase(ctx, v1.VolumeReleased, c, pv.Name, 3*time.Second, 300*time.Second)
   188  			framework.ExpectNoError(err)
   189  			framework.ExpectNoError(e2epv.DeletePersistentVolume(ctx, c, pv.Name), "Failed to delete PV ", pv.Name)
   190  
   191  			ginkgo.By("Creating the PV for same volume path")
   192  			pv = getVSpherePersistentVolumeSpec(volumePath, v1.PersistentVolumeReclaimRetain, nil)
   193  			pv, err = c.CoreV1().PersistentVolumes().Create(ctx, pv, metav1.CreateOptions{})
   194  			framework.ExpectNoError(err)
   195  
   196  			ginkgo.By("creating the pvc")
   197  			pvc = getVSpherePersistentVolumeClaimSpec(ns, nil)
   198  			pvc, err = c.CoreV1().PersistentVolumeClaims(ns).Create(ctx, pvc, metav1.CreateOptions{})
   199  			framework.ExpectNoError(err)
   200  
   201  			ginkgo.By("wait for the pv and pvc to bind")
   202  			framework.ExpectNoError(e2epv.WaitOnPVandPVC(ctx, c, f.Timeouts, ns, pv, pvc))
   203  			verifyContentOfVSpherePV(ctx, c, f.Timeouts, pvc, volumeFileContent)
   204  
   205  		})
   206  	})
   207  })
   208  
   209  // Test Setup for persistentvolumereclaim tests for vSphere Provider
   210  func testSetupVSpherePersistentVolumeReclaim(ctx context.Context, c clientset.Interface, nodeInfo *NodeInfo, ns string, persistentVolumeReclaimPolicy v1.PersistentVolumeReclaimPolicy) (volumePath string, pv *v1.PersistentVolume, pvc *v1.PersistentVolumeClaim, err error) {
   211  	ginkgo.By("running testSetupVSpherePersistentVolumeReclaim")
   212  	ginkgo.By("creating vmdk")
   213  	volumePath, err = nodeInfo.VSphere.CreateVolume(&VolumeOptions{}, nodeInfo.DataCenterRef)
   214  	if err != nil {
   215  		return
   216  	}
   217  	ginkgo.By("creating the pv")
   218  	pv = getVSpherePersistentVolumeSpec(volumePath, persistentVolumeReclaimPolicy, nil)
   219  	pv, err = c.CoreV1().PersistentVolumes().Create(ctx, pv, metav1.CreateOptions{})
   220  	if err != nil {
   221  		return
   222  	}
   223  	ginkgo.By("creating the pvc")
   224  	pvc = getVSpherePersistentVolumeClaimSpec(ns, nil)
   225  	pvc, err = c.CoreV1().PersistentVolumeClaims(ns).Create(ctx, pvc, metav1.CreateOptions{})
   226  	return
   227  }
   228  
   229  // Test Cleanup for persistentvolumereclaim tests for vSphere Provider
   230  func testCleanupVSpherePersistentVolumeReclaim(ctx context.Context, c clientset.Interface, nodeInfo *NodeInfo, ns string, volumePath string, pv *v1.PersistentVolume, pvc *v1.PersistentVolumeClaim) {
   231  	ginkgo.By("running testCleanupVSpherePersistentVolumeReclaim")
   232  	if len(volumePath) > 0 {
   233  		err := nodeInfo.VSphere.DeleteVolume(volumePath, nodeInfo.DataCenterRef)
   234  		framework.ExpectNoError(err)
   235  	}
   236  	if pv != nil {
   237  		framework.ExpectNoError(e2epv.DeletePersistentVolume(ctx, c, pv.Name), "Failed to delete PV ", pv.Name)
   238  	}
   239  	if pvc != nil {
   240  		framework.ExpectNoError(e2epv.DeletePersistentVolumeClaim(ctx, c, pvc.Name, ns), "Failed to delete PVC ", pvc.Name)
   241  	}
   242  }
   243  
   244  // func to wait until PV and PVC bind and once bind completes, delete the PVC
   245  func deletePVCAfterBind(ctx context.Context, c clientset.Interface, ns string, pvc *v1.PersistentVolumeClaim, pv *v1.PersistentVolume, timeouts *framework.TimeoutContext) {
   246  	var err error
   247  
   248  	ginkgo.By("wait for the pv and pvc to bind")
   249  	framework.ExpectNoError(e2epv.WaitOnPVandPVC(ctx, c, timeouts, ns, pv, pvc))
   250  
   251  	ginkgo.By("delete pvc")
   252  	framework.ExpectNoError(e2epv.DeletePersistentVolumeClaim(ctx, c, pvc.Name, ns), "Failed to delete PVC ", pvc.Name)
   253  	_, err = c.CoreV1().PersistentVolumeClaims(ns).Get(ctx, pvc.Name, metav1.GetOptions{})
   254  	if !apierrors.IsNotFound(err) {
   255  		framework.ExpectNoError(err)
   256  	}
   257  }