k8s.io/kubernetes@v1.29.3/test/e2e/storage/vsphere/persistent_volumes-vsphere.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  	"time"
    22  
    23  	"github.com/onsi/ginkgo/v2"
    24  	v1 "k8s.io/api/core/v1"
    25  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  	"k8s.io/apimachinery/pkg/labels"
    27  	clientset "k8s.io/client-go/kubernetes"
    28  	"k8s.io/kubernetes/test/e2e/feature"
    29  	"k8s.io/kubernetes/test/e2e/framework"
    30  	e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
    31  	e2epv "k8s.io/kubernetes/test/e2e/framework/pv"
    32  	e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper"
    33  	"k8s.io/kubernetes/test/e2e/storage/utils"
    34  	admissionapi "k8s.io/pod-security-admission/api"
    35  )
    36  
    37  // Testing configurations of single a PV/PVC pair attached to a vSphere Disk
    38  var _ = utils.SIGDescribe("PersistentVolumes:vsphere", feature.Vsphere, func() {
    39  	var (
    40  		c          clientset.Interface
    41  		ns         string
    42  		volumePath string
    43  		pv         *v1.PersistentVolume
    44  		pvc        *v1.PersistentVolumeClaim
    45  		clientPod  *v1.Pod
    46  		pvConfig   e2epv.PersistentVolumeConfig
    47  		pvcConfig  e2epv.PersistentVolumeClaimConfig
    48  		err        error
    49  		node       string
    50  		volLabel   labels.Set
    51  		selector   *metav1.LabelSelector
    52  		nodeInfo   *NodeInfo
    53  	)
    54  
    55  	f := framework.NewDefaultFramework("pv")
    56  	f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged
    57  	/*
    58  		Test Setup
    59  
    60  		1. Create volume (vmdk)
    61  		2. Create PV with volume path for the vmdk.
    62  		3. Create PVC to bind with PV.
    63  		4. Create a POD using the PVC.
    64  		5. Verify Disk and Attached to the node.
    65  	*/
    66  	ginkgo.BeforeEach(func(ctx context.Context) {
    67  		e2eskipper.SkipUnlessProviderIs("vsphere")
    68  		Bootstrap(f)
    69  		c = f.ClientSet
    70  		ns = f.Namespace.Name
    71  		clientPod = nil
    72  		pvc = nil
    73  		pv = nil
    74  		nodeInfo = GetReadySchedulableRandomNodeInfo(ctx, c)
    75  
    76  		volLabel = labels.Set{e2epv.VolumeSelectorKey: ns}
    77  		selector = metav1.SetAsLabelSelector(volLabel)
    78  
    79  		volumePath, err = nodeInfo.VSphere.CreateVolume(&VolumeOptions{}, nodeInfo.DataCenterRef)
    80  		framework.ExpectNoError(err)
    81  		ginkgo.DeferCleanup(func() {
    82  			nodeInfo.VSphere.DeleteVolume(volumePath, nodeInfo.DataCenterRef)
    83  		})
    84  		pvConfig = e2epv.PersistentVolumeConfig{
    85  			NamePrefix: "vspherepv-",
    86  			Labels:     volLabel,
    87  			PVSource: v1.PersistentVolumeSource{
    88  				VsphereVolume: &v1.VsphereVirtualDiskVolumeSource{
    89  					VolumePath: volumePath,
    90  					FSType:     "ext4",
    91  				},
    92  			},
    93  			Prebind: nil,
    94  		}
    95  		emptyStorageClass := ""
    96  		pvcConfig = e2epv.PersistentVolumeClaimConfig{
    97  			Selector:         selector,
    98  			StorageClassName: &emptyStorageClass,
    99  		}
   100  		ginkgo.By("Creating the PV and PVC")
   101  		pv, pvc, err = e2epv.CreatePVPVC(ctx, c, f.Timeouts, pvConfig, pvcConfig, ns, false)
   102  		framework.ExpectNoError(err)
   103  		ginkgo.DeferCleanup(func() {
   104  			framework.ExpectNoError(e2epv.DeletePersistentVolume(ctx, c, pv.Name), "AfterEach: failed to delete PV ", pv.Name)
   105  		})
   106  		ginkgo.DeferCleanup(func() {
   107  			framework.ExpectNoError(e2epv.DeletePersistentVolumeClaim(ctx, c, pvc.Name, ns), "AfterEach: failed to delete PVC ", pvc.Name)
   108  		})
   109  		framework.ExpectNoError(e2epv.WaitOnPVandPVC(ctx, c, f.Timeouts, ns, pv, pvc))
   110  
   111  		ginkgo.By("Creating the Client Pod")
   112  		clientPod, err = e2epod.CreateClientPod(ctx, c, ns, pvc)
   113  		framework.ExpectNoError(err)
   114  		node = clientPod.Spec.NodeName
   115  		ginkgo.DeferCleanup(func() {
   116  			framework.ExpectNoError(e2epod.DeletePodWithWait(ctx, c, clientPod), "AfterEach: failed to delete pod ", clientPod.Name)
   117  		})
   118  		ginkgo.DeferCleanup(func() {
   119  			framework.ExpectNoError(waitForVSphereDiskToDetach(ctx, volumePath, node), "wait for vsphere disk to detach")
   120  		})
   121  
   122  		ginkgo.By("Verify disk should be attached to the node")
   123  		isAttached, err := diskIsAttached(ctx, volumePath, node)
   124  		framework.ExpectNoError(err)
   125  		if !isAttached {
   126  			framework.Failf("Disk %s is not attached with the node", volumePath)
   127  		}
   128  	})
   129  
   130  	ginkgo.It("should test that deleting a PVC before the pod does not cause pod deletion to fail on vsphere volume detach", func(ctx context.Context) {
   131  		ginkgo.By("Deleting the Claim")
   132  		framework.ExpectNoError(e2epv.DeletePersistentVolumeClaim(ctx, c, pvc.Name, ns), "Failed to delete PVC ", pvc.Name)
   133  		pvc = nil
   134  
   135  		ginkgo.By("Deleting the Pod")
   136  		framework.ExpectNoError(e2epod.DeletePodWithWait(ctx, c, clientPod), "Failed to delete pod ", clientPod.Name)
   137  	})
   138  
   139  	/*
   140  		Delete the PV and then the pod.  Expect the pod to succeed in unmounting and detaching PD on delete.
   141  
   142  		Test Steps:
   143  		1. Delete PV.
   144  		2. Delete POD, POD deletion should succeed.
   145  	*/
   146  	ginkgo.It("should test that deleting the PV before the pod does not cause pod deletion to fail on vsphere volume detach", func(ctx context.Context) {
   147  		ginkgo.By("Deleting the Persistent Volume")
   148  		framework.ExpectNoError(e2epv.DeletePersistentVolume(ctx, c, pv.Name), "Failed to delete PV ", pv.Name)
   149  		pv = nil
   150  
   151  		ginkgo.By("Deleting the pod")
   152  		framework.ExpectNoError(e2epod.DeletePodWithWait(ctx, c, clientPod), "Failed to delete pod ", clientPod.Name)
   153  	})
   154  	/*
   155  		This test verifies that a volume mounted to a pod remains mounted after a kubelet restarts.
   156  		Steps:
   157  		1. Write to the volume
   158  		2. Restart kubelet
   159  		3. Verify that written file is accessible after kubelet restart
   160  	*/
   161  	f.It("should test that a file written to the vsphere volume mount before kubelet restart can be read after restart", f.WithDisruptive(), func(ctx context.Context) {
   162  		e2eskipper.SkipUnlessSSHKeyPresent()
   163  		utils.TestKubeletRestartsAndRestoresMount(ctx, c, f, clientPod, e2epod.VolumeMountPath1)
   164  	})
   165  
   166  	/*
   167  		This test verifies that a volume mounted to a pod that is deleted while the kubelet is down
   168  		unmounts volume when the kubelet returns.
   169  
   170  		Steps:
   171  		1. Verify volume is mounted on the node.
   172  		2. Stop kubelet.
   173  		3. Delete pod.
   174  		4. Start kubelet.
   175  		5. Verify that volume mount not to be found.
   176  	*/
   177  	f.It("should test that a vsphere volume mounted to a pod that is deleted while the kubelet is down unmounts when the kubelet returns", f.WithDisruptive(), func(ctx context.Context) {
   178  		e2eskipper.SkipUnlessSSHKeyPresent()
   179  		utils.TestVolumeUnmountsFromDeletedPod(ctx, c, f, clientPod, e2epod.VolumeMountPath1)
   180  	})
   181  
   182  	/*
   183  		This test verifies that deleting the Namespace of a PVC and Pod causes the successful detach of Persistent Disk
   184  
   185  		Steps:
   186  		1. Delete Namespace.
   187  		2. Wait for namespace to get deleted. (Namespace deletion should trigger deletion of belonging pods)
   188  		3. Verify volume should be detached from the node.
   189  	*/
   190  	ginkgo.It("should test that deleting the Namespace of a PVC and Pod causes the successful detach of vsphere volume", func(ctx context.Context) {
   191  		ginkgo.By("Deleting the Namespace")
   192  		err := c.CoreV1().Namespaces().Delete(ctx, ns, metav1.DeleteOptions{})
   193  		framework.ExpectNoError(err)
   194  
   195  		err = framework.WaitForNamespacesDeleted(ctx, c, []string{ns}, 3*time.Minute)
   196  		framework.ExpectNoError(err)
   197  
   198  		ginkgo.By("Verifying Persistent Disk detaches")
   199  		err = waitForVSphereDiskToDetach(ctx, volumePath, node)
   200  		framework.ExpectNoError(err)
   201  	})
   202  })