From 79678dd39359b9bd617fe283d05fad2ca1c37094 Mon Sep 17 00:00:00 2001 From: "rongfu.leng" Date: Thu, 13 Mar 2025 21:06:59 +0800 Subject: [PATCH] feat: add resourcequota WarningsOnCreate request less than limits Signed-off-by: rongfu.leng --- pkg/registry/core/resourcequota/strategy.go | 22 +++++- .../core/resourcequota/strategy_test.go | 73 +++++++++++++++++++ 2 files changed, 94 insertions(+), 1 deletion(-) diff --git a/pkg/registry/core/resourcequota/strategy.go b/pkg/registry/core/resourcequota/strategy.go index a57416d3fd0..5bb563190f1 100644 --- a/pkg/registry/core/resourcequota/strategy.go +++ b/pkg/registry/core/resourcequota/strategy.go @@ -18,6 +18,7 @@ package resourcequota import ( "context" + "fmt" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" @@ -76,7 +77,26 @@ func (resourcequotaStrategy) Validate(ctx context.Context, obj runtime.Object) f // WarningsOnCreate returns warnings for the creation of the given object. func (resourcequotaStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { - return nil + resourcequota := obj.(*api.ResourceQuota) + allWarnings := make([]string, 0) + coreReosurces := []api.ResourceName{ + api.ResourceCPU, api.ResourceMemory, + api.ResourceStorage, api.ResourceEphemeralStorage, + } + for _, resourceName := range coreReosurces { + requestResourceName := fmt.Sprintf("requests.%s", resourceName) + requestResource, requestOK := resourcequota.Spec.Hard[api.ResourceName(requestResourceName)] + if (resourceName == api.ResourceCPU || resourceName == api.ResourceMemory) && !requestOK { + requestResourceName = string(resourceName) + requestResource, requestOK = resourcequota.Spec.Hard[api.ResourceName(requestResourceName)] + } + limitResourceName := fmt.Sprintf("limits.%s", resourceName) + limitResource, limitOK := resourcequota.Spec.Hard[api.ResourceName(limitResourceName)] + if requestOK && limitOK && requestResource.Cmp(limitResource) == 1 { + allWarnings = append(allWarnings, fmt.Sprintf("Create ResourceQuota requests.%s: %s should be less than limits.%s: %s", resourceName, requestResource.String(), resourceName, limitResource.String())) + } + } + return allWarnings } // Canonicalize normalizes the object after validation. diff --git a/pkg/registry/core/resourcequota/strategy_test.go b/pkg/registry/core/resourcequota/strategy_test.go index c571c2a336d..12ce262dc31 100644 --- a/pkg/registry/core/resourcequota/strategy_test.go +++ b/pkg/registry/core/resourcequota/strategy_test.go @@ -17,6 +17,8 @@ limitations under the License. package resourcequota import ( + "context" + "reflect" "testing" "k8s.io/apimachinery/pkg/api/resource" @@ -58,3 +60,74 @@ func TestResourceQuotaStrategy(t *testing.T) { t.Errorf("ResourceQuota does not allow setting status on create") } } + +func Test_WarningsOnCreate(t *testing.T) { + tests := []struct { + name string + args *api.ResourceQuota + wantWarnings []string + }{ + { + name: "Empty Hard Spec", + args: &api.ResourceQuota{}, + wantWarnings: []string{}, + }, + { + name: "Request less than limit", + args: &api.ResourceQuota{ + Spec: api.ResourceQuotaSpec{ + Hard: api.ResourceList{ + api.ResourceName("requests.cpu"): resource.MustParse("500m"), + api.ResourceName("limits.cpu"): resource.MustParse("1"), + api.ResourceName("requests.memory"): resource.MustParse("1Gi"), + api.ResourceName("limits.memory"): resource.MustParse("2Gi"), + }, + }, + }, + wantWarnings: []string{}, + }, + { + name: "Request greater than limit", + args: &api.ResourceQuota{ + Spec: api.ResourceQuotaSpec{ + Hard: api.ResourceList{ + api.ResourceName("requests.cpu"): resource.MustParse("2"), + api.ResourceName("limits.cpu"): resource.MustParse("1"), + api.ResourceName("requests.memory"): resource.MustParse("3Gi"), + api.ResourceName("limits.memory"): resource.MustParse("2Gi"), + }, + }, + }, + wantWarnings: []string{ + "Create ResourceQuota requests.cpu: 2 should be less than limits.cpu: 1", + "Create ResourceQuota requests.memory: 3Gi should be less than limits.memory: 2Gi", + }, + }, + { + name: "Request greater than limit, and not requests", + args: &api.ResourceQuota{ + Spec: api.ResourceQuotaSpec{ + Hard: api.ResourceList{ + api.ResourceName("cpu"): resource.MustParse("2"), + api.ResourceName("limits.cpu"): resource.MustParse("1"), + api.ResourceName("memory"): resource.MustParse("3Gi"), + api.ResourceName("limits.memory"): resource.MustParse("2Gi"), + }, + }, + }, + wantWarnings: []string{ + "Create ResourceQuota requests.cpu: 2 should be less than limits.cpu: 1", + "Create ResourceQuota requests.memory: 3Gi should be less than limits.memory: 2Gi", + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + warnings := Strategy.WarningsOnCreate(context.Background(), tt.args) + if !reflect.DeepEqual(warnings, tt.wantWarnings) { + t.Errorf("WarningsOnCreate() warnings = %v, wantWarnings %v", warnings, tt.wantWarnings) + } + }) + } +}