Skip to content

Commit aa3e1fb

Browse files
carloryAndrewSirenko
authored andcommitted
Fix volume modify e2e tests because pv controller set the current vac once the pvc is bound
1 parent 7f55109 commit aa3e1fb

File tree

2 files changed

+80
-51
lines changed

2 files changed

+80
-51
lines changed

test/e2e/framework/pv/wait.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
Copyright 2024 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 pv
18+
19+
import (
20+
"context"
21+
"fmt"
22+
"time"
23+
24+
v1 "k8s.io/api/core/v1"
25+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26+
clientset "k8s.io/client-go/kubernetes"
27+
"k8s.io/kubernetes/test/e2e/framework"
28+
"k8s.io/kubernetes/test/utils/format"
29+
"k8s.io/utils/ptr"
30+
)
31+
32+
// WaitForPersistentVolumeClaimModified waits the given timeout duration for the specified claim to become bound with the
33+
// desired volume attributes class.
34+
// Returns an error if timeout occurs first.
35+
func WaitForPersistentVolumeClaimModified(ctx context.Context, c clientset.Interface, claim *v1.PersistentVolumeClaim, timeout time.Duration) error {
36+
desiredClass := ptr.Deref(claim.Spec.VolumeAttributesClassName, "")
37+
38+
var match = func(claim *v1.PersistentVolumeClaim) bool {
39+
for _, condition := range claim.Status.Conditions {
40+
// conditions that indicate the claim is being modified
41+
// or has an error when modifying the volume
42+
if condition.Type == v1.PersistentVolumeClaimVolumeModifyVolumeError ||
43+
condition.Type == v1.PersistentVolumeClaimVolumeModifyingVolume {
44+
return false
45+
}
46+
}
47+
48+
// check if claim is bound with the desired volume attributes class
49+
currentClass := ptr.Deref(claim.Status.CurrentVolumeAttributesClassName, "")
50+
return claim.Status.Phase == v1.ClaimBound &&
51+
desiredClass == currentClass && claim.Status.ModifyVolumeStatus == nil
52+
}
53+
54+
if match(claim) {
55+
return nil
56+
}
57+
58+
return framework.Gomega().
59+
Eventually(ctx, framework.GetObject(c.CoreV1().PersistentVolumeClaims(claim.Namespace).Get, claim.Name, metav1.GetOptions{})).
60+
WithTimeout(timeout).
61+
Should(framework.MakeMatcher(func(claim *v1.PersistentVolumeClaim) (func() string, error) {
62+
if match(claim) {
63+
return nil, nil
64+
}
65+
66+
return func() string {
67+
return fmt.Sprintf("expected claim's status to be modified with the given VolumeAttirbutesClass %s, got instead:\n%s", desiredClass, format.Object(claim, 1))
68+
}, nil
69+
}))
70+
}

test/e2e/storage/testsuites/volume_modify.go

Lines changed: 10 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import (
3333
e2efeature "k8s.io/kubernetes/test/e2e/feature"
3434
"k8s.io/kubernetes/test/e2e/framework"
3535
e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
36+
e2epv "k8s.io/kubernetes/test/e2e/framework/pv"
3637
e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper"
3738
e2evolume "k8s.io/kubernetes/test/e2e/framework/volume"
3839
storageframework "k8s.io/kubernetes/test/e2e/storage/framework"
@@ -164,10 +165,9 @@ func (v *volumeModifyTestSuite) DefineTests(driver storageframework.TestDriver,
164165
ginkgo.DeferCleanup(e2epod.DeletePodWithWait, f.ClientSet, pod)
165166
framework.ExpectNoError(err, "While creating test pod with VAC")
166167

167-
createdPVC, err := f.ClientSet.CoreV1().PersistentVolumeClaims(f.Namespace.Name).Get(ctx, l.resource.Pvc.Name, metav1.GetOptions{})
168-
framework.ExpectNoError(err, "While getting created PVC")
169-
// Check VAC matches on created PVC, but not current VAC in status
170-
gomega.Expect(vacMatches(createdPVC, l.vac.Name, false)).To(gomega.BeTrueBecause("Created PVC should match expected VAC"))
168+
ginkgo.By("Checking PVC status")
169+
err = e2epv.WaitForPersistentVolumeClaimModified(ctx, f.ClientSet, l.resource.Pvc, modifyVolumeWaitPeriod)
170+
framework.ExpectNoError(err, "While waiting for PVC to have expected VAC")
171171
})
172172

173173
ginkgo.It("should modify volume with no VAC", func(ctx context.Context) {
@@ -191,11 +191,9 @@ func (v *volumeModifyTestSuite) DefineTests(driver storageframework.TestDriver,
191191
l.resource.Pvc = SetPVCVACName(ctx, l.resource.Pvc, l.vac.Name, f.ClientSet, setVACWaitPeriod)
192192
gomega.Expect(l.resource.Pvc).NotTo(gomega.BeNil())
193193

194-
ginkgo.By("Waiting for modification to finish")
195-
l.resource.Pvc = WaitForVolumeModification(ctx, l.resource.Pvc, f.ClientSet, modifyVolumeWaitPeriod)
196-
197-
pvcConditions := l.resource.Pvc.Status.Conditions
198-
gomega.Expect(pvcConditions).To(gomega.BeEmpty(), "PVC should not have conditions")
194+
ginkgo.By("Checking PVC status")
195+
err = e2epv.WaitForPersistentVolumeClaimModified(ctx, f.ClientSet, l.resource.Pvc, modifyVolumeWaitPeriod)
196+
framework.ExpectNoError(err, "While waiting for PVC to have expected VAC")
199197
})
200198

201199
ginkgo.It("should modify volume that already has a VAC", func(ctx context.Context) {
@@ -225,11 +223,9 @@ func (v *volumeModifyTestSuite) DefineTests(driver storageframework.TestDriver,
225223
l.resource.Pvc = SetPVCVACName(ctx, l.resource.Pvc, newVAC.Name, f.ClientSet, setVACWaitPeriod)
226224
gomega.Expect(l.resource.Pvc).NotTo(gomega.BeNil())
227225

228-
ginkgo.By("Waiting for modification to finish")
229-
l.resource.Pvc = WaitForVolumeModification(ctx, l.resource.Pvc, f.ClientSet, modifyVolumeWaitPeriod)
230-
231-
pvcConditions := l.resource.Pvc.Status.Conditions
232-
gomega.Expect(pvcConditions).To(gomega.BeEmpty(), "PVC should not have conditions")
226+
ginkgo.By("Checking PVC status")
227+
err = e2epv.WaitForPersistentVolumeClaimModified(ctx, f.ClientSet, l.resource.Pvc, modifyVolumeWaitPeriod)
228+
framework.ExpectNoError(err, "While waiting for PVC to have expected VAC")
233229
})
234230
}
235231

@@ -250,45 +246,8 @@ func SetPVCVACName(ctx context.Context, origPVC *v1.PersistentVolumeClaim, name
250246
return patchedPVC
251247
}
252248

253-
// WaitForVolumeModification waits for the volume to be modified
254-
// The input PVC is assumed to have a VolumeAttributesClassName set
255-
func WaitForVolumeModification(ctx context.Context, pvc *v1.PersistentVolumeClaim, c clientset.Interface, timeout time.Duration) *v1.PersistentVolumeClaim {
256-
var newPVC *v1.PersistentVolumeClaim
257-
pvName := pvc.Spec.VolumeName
258-
gomega.Eventually(ctx, func(g gomega.Gomega) {
259-
pv, err := c.CoreV1().PersistentVolumes().Get(ctx, pvName, metav1.GetOptions{})
260-
framework.ExpectNoError(err, "While getting existing PV")
261-
g.Expect(pv.Spec.VolumeAttributesClassName).NotTo(gomega.BeNil())
262-
newPVC, err = c.CoreV1().PersistentVolumeClaims(pvc.Namespace).Get(ctx, pvc.Name, metav1.GetOptions{})
263-
framework.ExpectNoError(err, "While getting new PVC")
264-
g.Expect(vacMatches(newPVC, *pv.Spec.VolumeAttributesClassName, true)).To(gomega.BeTrueBecause("Modified PVC should match expected VAC"))
265-
}, timeout, modifyPollInterval).Should(gomega.Succeed())
266-
return newPVC
267-
}
268-
269249
func CleanupVAC(ctx context.Context, vac *storagev1beta1.VolumeAttributesClass, c clientset.Interface, timeout time.Duration) {
270250
gomega.Eventually(ctx, func() error {
271251
return c.StorageV1beta1().VolumeAttributesClasses().Delete(ctx, vac.Name, metav1.DeleteOptions{})
272252
}, timeout, modifyPollInterval).Should(gomega.BeNil())
273253
}
274-
275-
func vacMatches(pvc *v1.PersistentVolumeClaim, expectedVac string, checkStatusCurrentVac bool) bool {
276-
// Check the following to ensure the VAC matches and that all pending modifications are complete:
277-
// 1. VAC Name matches Expected
278-
// 2. PVC Modify Volume status is either nil or has an empty status string
279-
// 3. PVC Status Current VAC Matches Expected (only if checkStatusCurrentVac is true)
280-
// (3) is only expected to be true after a VAC is modified, but not when a VAC is used to create a volume
281-
if pvc.Spec.VolumeAttributesClassName == nil || *pvc.Spec.VolumeAttributesClassName != expectedVac {
282-
return false
283-
}
284-
if pvc.Status.ModifyVolumeStatus != nil && (pvc.Status.ModifyVolumeStatus.Status != "" || pvc.Status.ModifyVolumeStatus.TargetVolumeAttributesClassName != expectedVac) {
285-
return false
286-
}
287-
if checkStatusCurrentVac {
288-
if pvc.Status.CurrentVolumeAttributesClassName == nil || *pvc.Status.CurrentVolumeAttributesClassName != expectedVac {
289-
return false
290-
}
291-
}
292-
293-
return true
294-
}

0 commit comments

Comments
 (0)