k8s.io/kubernetes@v1.29.3/test/e2e/storage/flexvolume_mounted_volume_resize.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 "fmt" 22 "path" 23 "time" 24 25 "github.com/onsi/ginkgo/v2" 26 "github.com/onsi/gomega" 27 v1 "k8s.io/api/core/v1" 28 storagev1 "k8s.io/api/storage/v1" 29 "k8s.io/apimachinery/pkg/api/resource" 30 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 31 utilerrors "k8s.io/apimachinery/pkg/util/errors" 32 clientset "k8s.io/client-go/kubernetes" 33 "k8s.io/kubernetes/test/e2e/feature" 34 "k8s.io/kubernetes/test/e2e/framework" 35 e2edeployment "k8s.io/kubernetes/test/e2e/framework/deployment" 36 e2enode "k8s.io/kubernetes/test/e2e/framework/node" 37 e2epod "k8s.io/kubernetes/test/e2e/framework/pod" 38 e2epv "k8s.io/kubernetes/test/e2e/framework/pv" 39 e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper" 40 "k8s.io/kubernetes/test/e2e/storage/testsuites" 41 "k8s.io/kubernetes/test/e2e/storage/utils" 42 admissionapi "k8s.io/pod-security-admission/api" 43 ) 44 45 const ( 46 // total time to wait for cloudprovider or file system resize to finish 47 totalResizeWaitPeriod = 10 * time.Minute 48 ) 49 50 var _ = utils.SIGDescribe(feature.Flexvolumes, "Mounted flexvolume expand", framework.WithSlow(), func() { 51 var ( 52 c clientset.Interface 53 ns string 54 err error 55 pvc *v1.PersistentVolumeClaim 56 resizableSc *storagev1.StorageClass 57 node *v1.Node 58 nodeName string 59 nodeKeyValueLabel map[string]string 60 nodeLabelValue string 61 nodeKey string 62 ) 63 64 f := framework.NewDefaultFramework("mounted-flexvolume-expand") 65 f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged 66 ginkgo.BeforeEach(func(ctx context.Context) { 67 e2eskipper.SkipUnlessProviderIs("aws", "gce", "local") 68 e2eskipper.SkipUnlessMasterOSDistroIs("debian", "ubuntu", "gci", "custom") 69 e2eskipper.SkipUnlessNodeOSDistroIs("debian", "ubuntu", "gci", "custom") 70 e2eskipper.SkipUnlessSSHKeyPresent() 71 c = f.ClientSet 72 ns = f.Namespace.Name 73 framework.ExpectNoError(e2enode.WaitForAllNodesSchedulable(ctx, c, f.Timeouts.NodeSchedulable)) 74 75 node, err = e2enode.GetRandomReadySchedulableNode(ctx, f.ClientSet) 76 framework.ExpectNoError(err) 77 nodeName = node.Name 78 79 nodeKey = "mounted_flexvolume_expand_" + ns 80 nodeLabelValue = ns 81 nodeKeyValueLabel = map[string]string{nodeKey: nodeLabelValue} 82 e2enode.AddOrUpdateLabelOnNode(c, nodeName, nodeKey, nodeLabelValue) 83 ginkgo.DeferCleanup(e2enode.RemoveLabelOffNode, c, nodeName, nodeKey) 84 85 test := testsuites.StorageClassTest{ 86 Name: "flexvolume-resize", 87 Timeouts: f.Timeouts, 88 ClaimSize: "2Gi", 89 AllowVolumeExpansion: true, 90 Provisioner: "flex-expand", 91 } 92 93 resizableSc, err = c.StorageV1().StorageClasses().Create(ctx, newStorageClass(test, ns, "resizing"), metav1.CreateOptions{}) 94 if err != nil { 95 fmt.Printf("storage class creation error: %v\n", err) 96 } 97 framework.ExpectNoError(err, "Error creating resizable storage class") 98 if !*resizableSc.AllowVolumeExpansion { 99 framework.Failf("Class %s does not allow volume expansion", resizableSc.Name) 100 } 101 102 pvc = e2epv.MakePersistentVolumeClaim(e2epv.PersistentVolumeClaimConfig{ 103 StorageClassName: &(resizableSc.Name), 104 ClaimSize: "2Gi", 105 }, ns) 106 pvc, err = c.CoreV1().PersistentVolumeClaims(pvc.Namespace).Create(ctx, pvc, metav1.CreateOptions{}) 107 framework.ExpectNoError(err, "Error creating pvc") 108 ginkgo.DeferCleanup(func(ctx context.Context) { 109 framework.Logf("AfterEach: Cleaning up resources for mounted volume resize") 110 if errs := e2epv.PVPVCCleanup(ctx, c, ns, nil, pvc); len(errs) > 0 { 111 framework.Failf("AfterEach: Failed to delete PVC and/or PV. Errors: %v", utilerrors.NewAggregate(errs)) 112 } 113 }) 114 }) 115 116 ginkgo.It("Should verify mounted flex volumes can be resized", func(ctx context.Context) { 117 driver := "dummy-attachable" 118 ginkgo.By(fmt.Sprintf("installing flexvolume %s on node %s as %s", path.Join(driverDir, driver), node.Name, driver)) 119 installFlex(ctx, c, node, "k8s", driver, path.Join(driverDir, driver)) 120 ginkgo.By(fmt.Sprintf("installing flexvolume %s on (master) node %s as %s", path.Join(driverDir, driver), node.Name, driver)) 121 installFlex(ctx, c, nil, "k8s", driver, path.Join(driverDir, driver)) 122 123 pv := e2epv.MakePersistentVolume(e2epv.PersistentVolumeConfig{ 124 PVSource: v1.PersistentVolumeSource{ 125 FlexVolume: &v1.FlexPersistentVolumeSource{ 126 Driver: "k8s/" + driver, 127 }}, 128 NamePrefix: "pv-", 129 StorageClassName: resizableSc.Name, 130 VolumeMode: pvc.Spec.VolumeMode, 131 }) 132 133 _, err = e2epv.CreatePV(ctx, c, f.Timeouts, pv) 134 framework.ExpectNoError(err, "Error creating pv %v", err) 135 136 ginkgo.By("Waiting for PVC to be in bound phase") 137 pvcClaims := []*v1.PersistentVolumeClaim{pvc} 138 var pvs []*v1.PersistentVolume 139 140 pvs, err = e2epv.WaitForPVClaimBoundPhase(ctx, c, pvcClaims, framework.ClaimProvisionTimeout) 141 framework.ExpectNoError(err, "Failed waiting for PVC to be bound %v", err) 142 gomega.Expect(pvs).To(gomega.HaveLen(1)) 143 144 ginkgo.By("Creating a deployment with the provisioned volume") 145 deployment, err := e2edeployment.CreateDeployment(ctx, c, int32(1), map[string]string{"test": "app"}, nodeKeyValueLabel, ns, pvcClaims, admissionapi.LevelRestricted, "") 146 framework.ExpectNoError(err, "Failed creating deployment %v", err) 147 ginkgo.DeferCleanup(c.AppsV1().Deployments(ns).Delete, deployment.Name, metav1.DeleteOptions{}) 148 149 ginkgo.By("Expanding current pvc") 150 newSize := resource.MustParse("6Gi") 151 newPVC, err := testsuites.ExpandPVCSize(ctx, pvc, newSize, c) 152 framework.ExpectNoError(err, "While updating pvc for more size") 153 pvc = newPVC 154 gomega.Expect(pvc).NotTo(gomega.BeNil()) 155 156 pvcSize := pvc.Spec.Resources.Requests[v1.ResourceStorage] 157 if pvcSize.Cmp(newSize) != 0 { 158 framework.Failf("error updating pvc size %q", pvc.Name) 159 } 160 161 ginkgo.By("Waiting for cloudprovider resize to finish") 162 err = testsuites.WaitForControllerVolumeResize(ctx, pvc, c, totalResizeWaitPeriod) 163 framework.ExpectNoError(err, "While waiting for pvc resize to finish") 164 165 ginkgo.By("Getting a pod from deployment") 166 podList, err := e2edeployment.GetPodsForDeployment(ctx, c, deployment) 167 framework.ExpectNoError(err, "While getting pods from deployment") 168 gomega.Expect(podList.Items).NotTo(gomega.BeEmpty()) 169 pod := podList.Items[0] 170 171 ginkgo.By("Deleting the pod from deployment") 172 err = e2epod.DeletePodWithWait(ctx, c, &pod) 173 framework.ExpectNoError(err, "while deleting pod for resizing") 174 175 ginkgo.By("Waiting for deployment to create new pod") 176 pod, err = waitForDeploymentToRecreatePod(ctx, c, deployment) 177 framework.ExpectNoError(err, "While waiting for pod to be recreated") 178 179 ginkgo.By("Waiting for file system resize to finish") 180 pvc, err = testsuites.WaitForFSResize(ctx, pvc, c) 181 framework.ExpectNoError(err, "while waiting for fs resize to finish") 182 183 pvcConditions := pvc.Status.Conditions 184 gomega.Expect(pvcConditions).To(gomega.BeEmpty(), "pvc should not have conditions") 185 }) 186 })