mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-05 18:24:07 +00:00
Fix volume modify e2e tests because pv controller set the current vac once the pvc is bound
This commit is contained in:
parent
7f5510921d
commit
aa3e1fbf35
70
test/e2e/framework/pv/wait.go
Normal file
70
test/e2e/framework/pv/wait.go
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
Copyright 2024 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package pv
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
"k8s.io/kubernetes/test/utils/format"
|
||||
"k8s.io/utils/ptr"
|
||||
)
|
||||
|
||||
// WaitForPersistentVolumeClaimModified waits the given timeout duration for the specified claim to become bound with the
|
||||
// desired volume attributes class.
|
||||
// Returns an error if timeout occurs first.
|
||||
func WaitForPersistentVolumeClaimModified(ctx context.Context, c clientset.Interface, claim *v1.PersistentVolumeClaim, timeout time.Duration) error {
|
||||
desiredClass := ptr.Deref(claim.Spec.VolumeAttributesClassName, "")
|
||||
|
||||
var match = func(claim *v1.PersistentVolumeClaim) bool {
|
||||
for _, condition := range claim.Status.Conditions {
|
||||
// conditions that indicate the claim is being modified
|
||||
// or has an error when modifying the volume
|
||||
if condition.Type == v1.PersistentVolumeClaimVolumeModifyVolumeError ||
|
||||
condition.Type == v1.PersistentVolumeClaimVolumeModifyingVolume {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// check if claim is bound with the desired volume attributes class
|
||||
currentClass := ptr.Deref(claim.Status.CurrentVolumeAttributesClassName, "")
|
||||
return claim.Status.Phase == v1.ClaimBound &&
|
||||
desiredClass == currentClass && claim.Status.ModifyVolumeStatus == nil
|
||||
}
|
||||
|
||||
if match(claim) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return framework.Gomega().
|
||||
Eventually(ctx, framework.GetObject(c.CoreV1().PersistentVolumeClaims(claim.Namespace).Get, claim.Name, metav1.GetOptions{})).
|
||||
WithTimeout(timeout).
|
||||
Should(framework.MakeMatcher(func(claim *v1.PersistentVolumeClaim) (func() string, error) {
|
||||
if match(claim) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return func() string {
|
||||
return fmt.Sprintf("expected claim's status to be modified with the given VolumeAttirbutesClass %s, got instead:\n%s", desiredClass, format.Object(claim, 1))
|
||||
}, nil
|
||||
}))
|
||||
}
|
@ -33,6 +33,7 @@ import (
|
||||
e2efeature "k8s.io/kubernetes/test/e2e/feature"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
|
||||
e2epv "k8s.io/kubernetes/test/e2e/framework/pv"
|
||||
e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper"
|
||||
e2evolume "k8s.io/kubernetes/test/e2e/framework/volume"
|
||||
storageframework "k8s.io/kubernetes/test/e2e/storage/framework"
|
||||
@ -164,10 +165,9 @@ func (v *volumeModifyTestSuite) DefineTests(driver storageframework.TestDriver,
|
||||
ginkgo.DeferCleanup(e2epod.DeletePodWithWait, f.ClientSet, pod)
|
||||
framework.ExpectNoError(err, "While creating test pod with VAC")
|
||||
|
||||
createdPVC, err := f.ClientSet.CoreV1().PersistentVolumeClaims(f.Namespace.Name).Get(ctx, l.resource.Pvc.Name, metav1.GetOptions{})
|
||||
framework.ExpectNoError(err, "While getting created PVC")
|
||||
// Check VAC matches on created PVC, but not current VAC in status
|
||||
gomega.Expect(vacMatches(createdPVC, l.vac.Name, false)).To(gomega.BeTrueBecause("Created PVC should match expected VAC"))
|
||||
ginkgo.By("Checking PVC status")
|
||||
err = e2epv.WaitForPersistentVolumeClaimModified(ctx, f.ClientSet, l.resource.Pvc, modifyVolumeWaitPeriod)
|
||||
framework.ExpectNoError(err, "While waiting for PVC to have expected VAC")
|
||||
})
|
||||
|
||||
ginkgo.It("should modify volume with no VAC", func(ctx context.Context) {
|
||||
@ -191,11 +191,9 @@ func (v *volumeModifyTestSuite) DefineTests(driver storageframework.TestDriver,
|
||||
l.resource.Pvc = SetPVCVACName(ctx, l.resource.Pvc, l.vac.Name, f.ClientSet, setVACWaitPeriod)
|
||||
gomega.Expect(l.resource.Pvc).NotTo(gomega.BeNil())
|
||||
|
||||
ginkgo.By("Waiting for modification to finish")
|
||||
l.resource.Pvc = WaitForVolumeModification(ctx, l.resource.Pvc, f.ClientSet, modifyVolumeWaitPeriod)
|
||||
|
||||
pvcConditions := l.resource.Pvc.Status.Conditions
|
||||
gomega.Expect(pvcConditions).To(gomega.BeEmpty(), "PVC should not have conditions")
|
||||
ginkgo.By("Checking PVC status")
|
||||
err = e2epv.WaitForPersistentVolumeClaimModified(ctx, f.ClientSet, l.resource.Pvc, modifyVolumeWaitPeriod)
|
||||
framework.ExpectNoError(err, "While waiting for PVC to have expected VAC")
|
||||
})
|
||||
|
||||
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,
|
||||
l.resource.Pvc = SetPVCVACName(ctx, l.resource.Pvc, newVAC.Name, f.ClientSet, setVACWaitPeriod)
|
||||
gomega.Expect(l.resource.Pvc).NotTo(gomega.BeNil())
|
||||
|
||||
ginkgo.By("Waiting for modification to finish")
|
||||
l.resource.Pvc = WaitForVolumeModification(ctx, l.resource.Pvc, f.ClientSet, modifyVolumeWaitPeriod)
|
||||
|
||||
pvcConditions := l.resource.Pvc.Status.Conditions
|
||||
gomega.Expect(pvcConditions).To(gomega.BeEmpty(), "PVC should not have conditions")
|
||||
ginkgo.By("Checking PVC status")
|
||||
err = e2epv.WaitForPersistentVolumeClaimModified(ctx, f.ClientSet, l.resource.Pvc, modifyVolumeWaitPeriod)
|
||||
framework.ExpectNoError(err, "While waiting for PVC to have expected VAC")
|
||||
})
|
||||
}
|
||||
|
||||
@ -250,45 +246,8 @@ func SetPVCVACName(ctx context.Context, origPVC *v1.PersistentVolumeClaim, name
|
||||
return patchedPVC
|
||||
}
|
||||
|
||||
// WaitForVolumeModification waits for the volume to be modified
|
||||
// The input PVC is assumed to have a VolumeAttributesClassName set
|
||||
func WaitForVolumeModification(ctx context.Context, pvc *v1.PersistentVolumeClaim, c clientset.Interface, timeout time.Duration) *v1.PersistentVolumeClaim {
|
||||
var newPVC *v1.PersistentVolumeClaim
|
||||
pvName := pvc.Spec.VolumeName
|
||||
gomega.Eventually(ctx, func(g gomega.Gomega) {
|
||||
pv, err := c.CoreV1().PersistentVolumes().Get(ctx, pvName, metav1.GetOptions{})
|
||||
framework.ExpectNoError(err, "While getting existing PV")
|
||||
g.Expect(pv.Spec.VolumeAttributesClassName).NotTo(gomega.BeNil())
|
||||
newPVC, err = c.CoreV1().PersistentVolumeClaims(pvc.Namespace).Get(ctx, pvc.Name, metav1.GetOptions{})
|
||||
framework.ExpectNoError(err, "While getting new PVC")
|
||||
g.Expect(vacMatches(newPVC, *pv.Spec.VolumeAttributesClassName, true)).To(gomega.BeTrueBecause("Modified PVC should match expected VAC"))
|
||||
}, timeout, modifyPollInterval).Should(gomega.Succeed())
|
||||
return newPVC
|
||||
}
|
||||
|
||||
func CleanupVAC(ctx context.Context, vac *storagev1beta1.VolumeAttributesClass, c clientset.Interface, timeout time.Duration) {
|
||||
gomega.Eventually(ctx, func() error {
|
||||
return c.StorageV1beta1().VolumeAttributesClasses().Delete(ctx, vac.Name, metav1.DeleteOptions{})
|
||||
}, timeout, modifyPollInterval).Should(gomega.BeNil())
|
||||
}
|
||||
|
||||
func vacMatches(pvc *v1.PersistentVolumeClaim, expectedVac string, checkStatusCurrentVac bool) bool {
|
||||
// Check the following to ensure the VAC matches and that all pending modifications are complete:
|
||||
// 1. VAC Name matches Expected
|
||||
// 2. PVC Modify Volume status is either nil or has an empty status string
|
||||
// 3. PVC Status Current VAC Matches Expected (only if checkStatusCurrentVac is true)
|
||||
// (3) is only expected to be true after a VAC is modified, but not when a VAC is used to create a volume
|
||||
if pvc.Spec.VolumeAttributesClassName == nil || *pvc.Spec.VolumeAttributesClassName != expectedVac {
|
||||
return false
|
||||
}
|
||||
if pvc.Status.ModifyVolumeStatus != nil && (pvc.Status.ModifyVolumeStatus.Status != "" || pvc.Status.ModifyVolumeStatus.TargetVolumeAttributesClassName != expectedVac) {
|
||||
return false
|
||||
}
|
||||
if checkStatusCurrentVac {
|
||||
if pvc.Status.CurrentVolumeAttributesClassName == nil || *pvc.Status.CurrentVolumeAttributesClassName != expectedVac {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user