Merge pull request #134389 from thockin/takeover-130780

Add resourcequota WarningsOnCreate when request > limits
This commit is contained in:
Kubernetes Prow Robot
2025-10-06 14:52:58 -07:00
committed by GitHub
2 changed files with 112 additions and 1 deletions

View File

@@ -18,6 +18,7 @@ package resourcequota
import (
"context"
"fmt"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/validation/field"
@@ -74,9 +75,36 @@ func (resourcequotaStrategy) Validate(ctx context.Context, obj runtime.Object) f
return validation.ValidateResourceQuota(resourcequota)
}
// all known resource names that we want to check for request <= limit
var knownResourceNames = []api.ResourceName{
api.ResourceCPU,
api.ResourceMemory,
api.ResourceStorage,
api.ResourceEphemeralStorage,
}
// 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)
var allWarnings []string
for _, resourceName := range knownResourceNames {
requestResourceName := api.ResourceName(fmt.Sprintf("requests.%s", resourceName))
request, requestOK := resourcequota.Spec.Hard[requestResourceName]
if !requestOK && (resourceName == api.ResourceCPU || resourceName == api.ResourceMemory) {
// try the bare name for cpu and memory
request, requestOK = resourcequota.Spec.Hard[resourceName]
if requestOK {
requestResourceName = resourceName
}
}
limitResourceName := api.ResourceName(fmt.Sprintf("limits.%s", resourceName))
limit, limitOK := resourcequota.Spec.Hard[limitResourceName]
if requestOK && limitOK && request.Cmp(limit) > 0 {
allWarnings = append(allWarnings, fmt.Sprintf("ResourceQuota %s (%s) should be less than %s (%s)",
requestResourceName, request.String(), limitResourceName, limit.String()))
}
}
return allWarnings
}
// Canonicalize normalizes the object after validation.

View File

@@ -17,6 +17,8 @@ limitations under the License.
package resourcequota
import (
"context"
"reflect"
"testing"
"k8s.io/apimachinery/pkg/api/resource"
@@ -58,3 +60,84 @@ 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"),
api.ResourceName("requests.storage"): resource.MustParse("1Gi"),
api.ResourceName("limits.storage"): resource.MustParse("2Gi"),
api.ResourceName("requests.ephemeral-storage"): resource.MustParse("1Gi"),
api.ResourceName("limits.ephemeral-storage"): 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"),
api.ResourceName("requests.storage"): resource.MustParse("3Gi"),
api.ResourceName("limits.storage"): resource.MustParse("2Gi"),
api.ResourceName("requests.ephemeral-storage"): resource.MustParse("3Gi"),
api.ResourceName("limits.ephemeral-storage"): resource.MustParse("2Gi"),
},
},
},
wantWarnings: []string{
"ResourceQuota requests.cpu (2) should be less than limits.cpu (1)",
"ResourceQuota requests.memory (3Gi) should be less than limits.memory (2Gi)",
"ResourceQuota requests.storage (3Gi) should be less than limits.storage (2Gi)",
"ResourceQuota requests.ephemeral-storage (3Gi) should be less than limits.ephemeral-storage (2Gi)",
},
},
{
name: "Request greater than limit, bare names",
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{
"ResourceQuota cpu (2) should be less than limits.cpu (1)",
"ResourceQuota 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 len(warnings)+len(tt.wantWarnings) > 0 && !reflect.DeepEqual(warnings, tt.wantWarnings) {
t.Errorf("WarningsOnCreate()\n got: %q\n want: %q", warnings, tt.wantWarnings)
}
})
}
}