1
16
17 package storage
18
19 import (
20 "context"
21 "github.com/onsi/ginkgo/v2"
22 "github.com/onsi/gomega"
23 v1 "k8s.io/api/core/v1"
24 storagev1 "k8s.io/api/storage/v1"
25 "k8s.io/apimachinery/pkg/api/resource"
26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27 admissionapi "k8s.io/pod-security-admission/api"
28
29 utilerrors "k8s.io/apimachinery/pkg/util/errors"
30 clientset "k8s.io/client-go/kubernetes"
31 "k8s.io/kubernetes/test/e2e/feature"
32 "k8s.io/kubernetes/test/e2e/framework"
33 e2edeployment "k8s.io/kubernetes/test/e2e/framework/deployment"
34 e2enode "k8s.io/kubernetes/test/e2e/framework/node"
35 e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
36 e2epv "k8s.io/kubernetes/test/e2e/framework/pv"
37 e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper"
38 "k8s.io/kubernetes/test/e2e/storage/testsuites"
39 "k8s.io/kubernetes/test/e2e/storage/utils"
40 )
41
42 var _ = utils.SIGDescribe("Mounted volume expand", feature.StorageProvider, func() {
43 var (
44 c clientset.Interface
45 ns string
46 pvc *v1.PersistentVolumeClaim
47 sc *storagev1.StorageClass
48 nodeName string
49 nodeKeyValueLabel map[string]string
50 nodeLabelValue string
51 nodeKey string
52 )
53
54 f := framework.NewDefaultFramework("mounted-volume-expand")
55 f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged
56 ginkgo.BeforeEach(func(ctx context.Context) {
57 e2eskipper.SkipUnlessProviderIs("aws", "gce")
58 c = f.ClientSet
59 ns = f.Namespace.Name
60 framework.ExpectNoError(e2enode.WaitForAllNodesSchedulable(ctx, c, f.Timeouts.NodeSchedulable))
61
62 node, err := e2enode.GetRandomReadySchedulableNode(ctx, f.ClientSet)
63 framework.ExpectNoError(err)
64 nodeName = node.Name
65
66 nodeKey = "mounted_volume_expand_" + ns
67 nodeLabelValue = ns
68 nodeKeyValueLabel = map[string]string{nodeKey: nodeLabelValue}
69 e2enode.AddOrUpdateLabelOnNode(c, nodeName, nodeKey, nodeLabelValue)
70 ginkgo.DeferCleanup(e2enode.RemoveLabelOffNode, c, nodeName, nodeKey)
71
72 test := testsuites.StorageClassTest{
73 Name: "default",
74 Timeouts: f.Timeouts,
75 ClaimSize: "2Gi",
76 AllowVolumeExpansion: true,
77 DelayBinding: true,
78 Parameters: make(map[string]string),
79 }
80
81 sc = testsuites.SetupStorageClass(ctx, c, newStorageClass(test, ns, "resizing"))
82 if !*sc.AllowVolumeExpansion {
83 framework.Failf("Class %s does not allow volume expansion", sc.Name)
84 }
85
86 pvc = e2epv.MakePersistentVolumeClaim(e2epv.PersistentVolumeClaimConfig{
87 ClaimSize: test.ClaimSize,
88 StorageClassName: &(sc.Name),
89 VolumeMode: &test.VolumeMode,
90 }, ns)
91 pvc, err = c.CoreV1().PersistentVolumeClaims(pvc.Namespace).Create(ctx, pvc, metav1.CreateOptions{})
92 framework.ExpectNoError(err, "Error creating pvc")
93 ginkgo.DeferCleanup(func(ctx context.Context) {
94 framework.Logf("AfterEach: Cleaning up resources for mounted volume resize")
95
96 if errs := e2epv.PVPVCCleanup(ctx, c, ns, nil, pvc); len(errs) > 0 {
97 framework.Failf("AfterEach: Failed to delete PVC and/or PV. Errors: %v", utilerrors.NewAggregate(errs))
98 }
99 })
100 })
101
102 ginkgo.It("Should verify mounted devices can be resized", func(ctx context.Context) {
103 pvcClaims := []*v1.PersistentVolumeClaim{pvc}
104
105
106
107
108 ginkgo.By("Creating a deployment with selected PVC")
109 deployment, err := e2edeployment.CreateDeployment(ctx, c, int32(1), map[string]string{"test": "app"}, nodeKeyValueLabel, ns, pvcClaims, admissionapi.LevelRestricted, "")
110 framework.ExpectNoError(err, "Failed creating deployment %v", err)
111 ginkgo.DeferCleanup(c.AppsV1().Deployments(ns).Delete, deployment.Name, metav1.DeleteOptions{})
112
113
114 ginkgo.By("Checking for bound PVC")
115 pvs, err := e2epv.WaitForPVClaimBoundPhase(ctx, c, pvcClaims, framework.ClaimProvisionTimeout)
116 framework.ExpectNoError(err, "Failed waiting for PVC to be bound %v", err)
117 gomega.Expect(pvs).To(gomega.HaveLen(1))
118
119 ginkgo.By("Wait for a pod from deployment to be running")
120 podList, err := e2edeployment.GetPodsForDeployment(ctx, c, deployment)
121 framework.ExpectNoError(err, "While getting pods from deployment")
122 gomega.Expect(podList.Items).NotTo(gomega.BeEmpty())
123 pod := podList.Items[0]
124 err = e2epod.WaitTimeoutForPodRunningInNamespace(ctx, c, pod.Name, pod.Namespace, f.Timeouts.PodStart)
125 framework.ExpectNoError(err, "While waiting for pods to be ready")
126
127 ginkgo.By("Expanding current pvc")
128 newSize := resource.MustParse("6Gi")
129 newPVC, err := testsuites.ExpandPVCSize(ctx, pvc, newSize, c)
130 framework.ExpectNoError(err, "While updating pvc for more size")
131 pvc = newPVC
132 gomega.Expect(pvc).NotTo(gomega.BeNil())
133
134 pvcSize := pvc.Spec.Resources.Requests[v1.ResourceStorage]
135 if pvcSize.Cmp(newSize) != 0 {
136 framework.Failf("error updating pvc size %q", pvc.Name)
137 }
138
139 ginkgo.By("Waiting for cloudprovider resize to finish")
140 err = testsuites.WaitForControllerVolumeResize(ctx, pvc, c, totalResizeWaitPeriod)
141 framework.ExpectNoError(err, "While waiting for pvc resize to finish")
142
143 ginkgo.By("Getting a pod from deployment")
144 podList, err = e2edeployment.GetPodsForDeployment(ctx, c, deployment)
145 framework.ExpectNoError(err, "While getting pods from deployment")
146 gomega.Expect(podList.Items).NotTo(gomega.BeEmpty())
147 pod = podList.Items[0]
148
149 ginkgo.By("Deleting the pod from deployment")
150 err = e2epod.DeletePodWithWait(ctx, c, &pod)
151 framework.ExpectNoError(err, "while deleting pod for resizing")
152
153 ginkgo.By("Waiting for deployment to create new pod")
154 pod, err = waitForDeploymentToRecreatePod(ctx, c, deployment)
155 framework.ExpectNoError(err, "While waiting for pod to be recreated")
156
157 ginkgo.By("Waiting for file system resize to finish")
158 pvc, err = testsuites.WaitForFSResize(ctx, pvc, c)
159 framework.ExpectNoError(err, "while waiting for fs resize to finish")
160
161 pvcConditions := pvc.Status.Conditions
162 gomega.Expect(pvcConditions).To(gomega.BeEmpty(), "pvc should not have conditions")
163 })
164 })
165
View as plain text