Skip to content

Commit a67cf0b

Browse files
committed
Add volume modificatoin recovery e2e test
1 parent 33c64b3 commit a67cf0b

File tree

2 files changed

+92
-5
lines changed

2 files changed

+92
-5
lines changed

test/e2e/framework/pv/wait.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,42 @@ func WaitForPersistentVolumeClaimModified(ctx context.Context, c clientset.Inter
6868
}, nil
6969
}))
7070
}
71+
72+
// WaitForPersistentVolumeClaimModificationFailure waits the given timeout duration for the specified claim to have
73+
// failed to bind to the invalid volume attributes class.
74+
// Returns an error if timeout occurs first.
75+
func WaitForPersistentVolumeClaimModificationFailure(ctx context.Context, c clientset.Interface, claim *v1.PersistentVolumeClaim, timeout time.Duration) error {
76+
desiredClass := ptr.Deref(claim.Spec.VolumeAttributesClassName, "")
77+
78+
var match = func(claim *v1.PersistentVolumeClaim) bool {
79+
for _, condition := range claim.Status.Conditions {
80+
if condition.Type != v1.PersistentVolumeClaimVolumeModifyVolumeError {
81+
return false
82+
}
83+
}
84+
85+
// check if claim's current volume attributes class is NOT desired one, and has appropriate ModifyVolumeStatus
86+
currentClass := ptr.Deref(claim.Status.CurrentVolumeAttributesClassName, "")
87+
return claim.Status.Phase == v1.ClaimBound &&
88+
desiredClass != currentClass && claim.Status.ModifyVolumeStatus != nil &&
89+
(claim.Status.ModifyVolumeStatus.Status == v1.PersistentVolumeClaimModifyVolumeInProgress ||
90+
claim.Status.ModifyVolumeStatus.Status == v1.PersistentVolumeClaimModifyVolumeInfeasible)
91+
}
92+
93+
if match(claim) {
94+
return nil
95+
}
96+
97+
return framework.Gomega().
98+
Eventually(ctx, framework.GetObject(c.CoreV1().PersistentVolumeClaims(claim.Namespace).Get, claim.Name, metav1.GetOptions{})).
99+
WithTimeout(timeout).
100+
Should(framework.MakeMatcher(func(claim *v1.PersistentVolumeClaim) (func() string, error) {
101+
if match(claim) {
102+
return nil, nil
103+
}
104+
105+
return func() string {
106+
return fmt.Sprintf("expected claim's status to NOT be modified with the given VolumeAttirbutesClass %s, got instead:\n%s", desiredClass, format.Object(claim, 1))
107+
}, nil
108+
}))
109+
}

test/e2e/storage/testsuites/volume_modify.go

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,10 @@ import (
4141
)
4242

4343
const (
44-
modifyPollInterval = 2 * time.Second
45-
setVACWaitPeriod = 30 * time.Second
46-
modifyingConditionSyncWaitPeriod = 2 * time.Minute
47-
modifyVolumeWaitPeriod = 10 * time.Minute
48-
vacCleanupWaitPeriod = 30 * time.Second
44+
modifyPollInterval = 2 * time.Second
45+
setVACWaitPeriod = 30 * time.Second
46+
modifyVolumeWaitPeriod = 10 * time.Minute
47+
vacCleanupWaitPeriod = 30 * time.Second
4948
)
5049

5150
type volumeModifyTestSuite struct {
@@ -227,6 +226,46 @@ func (v *volumeModifyTestSuite) DefineTests(driver storageframework.TestDriver,
227226
err = e2epv.WaitForPersistentVolumeClaimModified(ctx, f.ClientSet, l.resource.Pvc, modifyVolumeWaitPeriod)
228227
framework.ExpectNoError(err, "While waiting for PVC to have expected VAC")
229228
})
229+
230+
ginkgo.It("should recover from invalid target VAC by updating PVC to new valid VAC", func(ctx context.Context) {
231+
init(ctx, false /* volume created without VAC */)
232+
ginkgo.DeferCleanup(cleanup)
233+
234+
// Create VAC with unsupported parameter
235+
invalidVAC := MakeInvalidVAC(l.config)
236+
_, err := f.ClientSet.StorageV1beta1().VolumeAttributesClasses().Create(ctx, invalidVAC, metav1.CreateOptions{})
237+
framework.ExpectNoError(err, "While creating new VolumeAttributesClass")
238+
ginkgo.DeferCleanup(CleanupVAC, invalidVAC, f.ClientSet, vacCleanupWaitPeriod)
239+
240+
ginkgo.By("Creating a pod with dynamically provisioned volume")
241+
podConfig := e2epod.Config{
242+
NS: f.Namespace.Name,
243+
PVCs: []*v1.PersistentVolumeClaim{l.resource.Pvc},
244+
SeLinuxLabel: e2epod.GetLinuxLabel(),
245+
NodeSelection: l.config.ClientNodeSelection,
246+
ImageID: e2epod.GetDefaultTestImageID(),
247+
}
248+
pod, err := e2epod.CreateSecPodWithNodeSelection(ctx, f.ClientSet, &podConfig, f.Timeouts.PodStart)
249+
ginkgo.DeferCleanup(e2epod.DeletePodWithWait, f.ClientSet, pod)
250+
framework.ExpectNoError(err, "While creating pod for modifying")
251+
252+
ginkgo.By("Attempting to modify PVC via VolumeAttributeClass that contains unsupported parameters")
253+
newPVC := SetPVCVACName(ctx, l.resource.Pvc, invalidVAC.Name, f.ClientSet, setVACWaitPeriod)
254+
l.resource.Pvc = newPVC
255+
gomega.Expect(l.resource.Pvc).NotTo(gomega.BeNil())
256+
257+
ginkgo.By("Waiting for modification to fail")
258+
err = e2epv.WaitForPersistentVolumeClaimModificationFailure(ctx, f.ClientSet, l.resource.Pvc, modifyVolumeWaitPeriod)
259+
framework.ExpectNoError(err, "While waiting for PVC to have conditions")
260+
261+
ginkgo.By("Modifying PVC to new valid VAC")
262+
l.resource.Pvc = SetPVCVACName(ctx, l.resource.Pvc, l.vac.Name, f.ClientSet, setVACWaitPeriod)
263+
gomega.Expect(l.resource.Pvc).NotTo(gomega.BeNil())
264+
265+
ginkgo.By("Checking PVC status")
266+
err = e2epv.WaitForPersistentVolumeClaimModified(ctx, f.ClientSet, l.resource.Pvc, modifyVolumeWaitPeriod)
267+
framework.ExpectNoError(err, "While waiting for PVC to have expected VAC")
268+
})
230269
}
231270

232271
// SetPVCVACName sets the VolumeAttributesClassName on a PVC object
@@ -246,6 +285,15 @@ func SetPVCVACName(ctx context.Context, origPVC *v1.PersistentVolumeClaim, name
246285
return patchedPVC
247286
}
248287

288+
func MakeInvalidVAC(config *storageframework.PerTestConfig) *storagev1beta1.VolumeAttributesClass {
289+
return storageframework.CopyVolumeAttributesClass(&storagev1beta1.VolumeAttributesClass{
290+
DriverName: config.GetUniqueDriverName(),
291+
Parameters: map[string]string{
292+
"xxInvalidParameterKey": "xxInvalidParameterValue",
293+
},
294+
}, config.Framework.Namespace.Name, "e2e-vac-invalid")
295+
}
296+
249297
func CleanupVAC(ctx context.Context, vac *storagev1beta1.VolumeAttributesClass, c clientset.Interface, timeout time.Duration) {
250298
gomega.Eventually(ctx, func() error {
251299
return c.StorageV1beta1().VolumeAttributesClasses().Delete(ctx, vac.Name, metav1.DeleteOptions{})

0 commit comments

Comments
 (0)