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