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 })