Skip to content

Commit 9e566c0

Browse files
gnufiedbertinatto
authored andcommitted
UPSTREAM: 134071: Wait for quota to report used before creating pvc
This should avoid races between pvc creation and quota creation
1 parent 9bdf101 commit 9e566c0

File tree

1 file changed

+40
-0
lines changed

1 file changed

+40
-0
lines changed

test/e2e/storage/csimock/base.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,13 @@ import (
2828

2929
csipbv1 "github.com/container-storage-interface/spec/lib/go/csi"
3030
"github.com/onsi/ginkgo/v2"
31+
"github.com/onsi/gomega/gcustom"
32+
gomegatypes "github.com/onsi/gomega/types"
3133
"google.golang.org/grpc/codes"
3234
v1 "k8s.io/api/core/v1"
3335
storagev1 "k8s.io/api/storage/v1"
3436
apierrors "k8s.io/apimachinery/pkg/api/errors"
37+
"k8s.io/apimachinery/pkg/api/resource"
3538
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3639
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
3740
"k8s.io/apimachinery/pkg/fields"
@@ -518,9 +521,46 @@ func (m *mockDriverSetup) createResourceQuota(ctx context.Context, quota *v1.Res
518521
quota, err = f.ClientSet.CoreV1().ResourceQuotas(f.Namespace.Name).Create(ctx, quota, metav1.CreateOptions{})
519522
framework.ExpectNoError(err, "Failed to create resourceQuota")
520523
m.quotas = append(m.quotas, quota)
524+
usedResources := v1.ResourceList{}
525+
usedResources[pvcSizeQuotaKey] = resource.MustParse("0")
526+
usedResources[pvcCountQuotaKey] = resource.MustParse("0")
527+
err = m.waitForResourceQuota(ctx, f.Namespace.Name, quota.Name, usedResources)
528+
framework.ExpectNoError(err, "Failed to wait for resourcequota creation")
521529
return quota
522530
}
523531

532+
func (m *mockDriverSetup) waitForResourceQuota(ctx context.Context, ns, quotaName string, used v1.ResourceList) error {
533+
var lastResourceQuota *v1.ResourceQuota
534+
f := m.f
535+
err := framework.Gomega().Eventually(ctx, framework.GetObject(f.ClientSet.CoreV1().ResourceQuotas(ns).Get, quotaName, metav1.GetOptions{})).Should(haveUsedResources(used, &lastResourceQuota))
536+
if lastResourceQuota != nil && err == nil {
537+
framework.Logf("Got expected ResourceQuota:\n%s", format.Object(lastResourceQuota, 1))
538+
}
539+
return err
540+
}
541+
542+
func haveUsedResources(used v1.ResourceList, lastResourceQuota **v1.ResourceQuota) gomegatypes.GomegaMatcher {
543+
// The template emits the actual ResourceQuota object as YAML.
544+
// In particular the ManagedFields are interesting because both
545+
// kube-apiserver and kube-controller-manager set the status.
546+
return gcustom.MakeMatcher(func(resourceQuota *v1.ResourceQuota) (bool, error) {
547+
if lastResourceQuota != nil {
548+
*lastResourceQuota = resourceQuota
549+
}
550+
// used may not yet be calculated
551+
if resourceQuota.Status.Used == nil {
552+
return false, nil
553+
}
554+
// verify that the quota shows the expected used resource values
555+
for k, v := range used {
556+
if actualValue, found := resourceQuota.Status.Used[k]; !found || (actualValue.Cmp(v) != 0) {
557+
return false, nil
558+
}
559+
}
560+
return true, nil
561+
}).WithTemplate("Expected:\n{{.FormattedActual}}\n{{.To}} have the following .status.used entries:\n{{range $key, $value := .Data}} {{$key}}: \"{{$value.ToUnstructured}}\"\n{{end}}").WithTemplateData(used /* Formatting of the map is done inside the template. */)
562+
}
563+
524564
func waitForCSIDriver(cs clientset.Interface, driverName string) error {
525565
timeout := 4 * time.Minute
526566

0 commit comments

Comments
 (0)