Skip to content

Commit c03efdb

Browse files
committed
fix: use QuotaExceeded reason when FederatedResourceQuota is exceeded
Signed-off-by: kajal-jotwani <[email protected]>
1 parent b175217 commit c03efdb

File tree

2 files changed

+41
-5
lines changed

2 files changed

+41
-5
lines changed

pkg/webhook/resourcebinding/validating.go

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
admissionv1 "k8s.io/api/admission/v1"
2828
corev1 "k8s.io/api/core/v1"
2929
apierrors "k8s.io/apimachinery/pkg/api/errors"
30+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3031
"k8s.io/apimachinery/pkg/util/validation/field"
3132
"k8s.io/client-go/util/retry"
3233
"k8s.io/klog/v2"
@@ -77,7 +78,7 @@ func (v *ValidatingAdmission) Handle(ctx context.Context, req admission.Request)
7778
return admission.Errored(http.StatusInternalServerError, err)
7879
}
7980
klog.Errorf("Admission denied for ResourceBinding %s/%s: %v", rb.Namespace, rb.Name, err)
80-
return admission.Denied(err.Error())
81+
return buildDenyResponse(err.Error())
8182
}
8283

8384
if features.FeatureGate.Enabled(features.MultiplePodTemplatesScheduling) {
@@ -301,6 +302,23 @@ func (v *ValidatingAdmission) decodeRBs(req admission.Request) (
301302
return decodedRB, decodedOldRB, nil
302303
}
303304

305+
func buildDenyResponse(errMsg string) admission.Response {
306+
if strings.Contains(errMsg, "FederatedResourceQuota") && strings.Contains(errMsg, "exceeded") {
307+
resp := admission.Response{
308+
AdmissionResponse: admissionv1.AdmissionResponse{
309+
Allowed: false,
310+
Result: &metav1.Status{
311+
Message: errMsg,
312+
Reason: util.QuotaExceededReason,
313+
Code: int32(http.StatusForbidden),
314+
},
315+
},
316+
}
317+
return resp
318+
}
319+
return admission.Denied(errMsg)
320+
}
321+
304322
func (v *ValidatingAdmission) calculateRBUsages(rb, oldRB *workv1alpha2.ResourceBinding) (corev1.ResourceList, corev1.ResourceList, error) {
305323
newRbTotalUsage := helper.CalculateResourceUsage(rb)
306324
klog.V(4).Infof("Calculated total usage for incoming RB %s/%s: %v", rb.Namespace, rb.Name, newRbTotalUsage)

pkg/webhook/resourcebinding/validating_test.go

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import (
4040
policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1"
4141
workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2"
4242
"github.com/karmada-io/karmada/pkg/features"
43+
"github.com/karmada-io/karmada/pkg/util"
4344
)
4445

4546
// testScheme is the scheme used for fake client in tests.
@@ -186,6 +187,20 @@ func makeTestFRQ(namespace, name string, opts ...FRQOption) *policyv1alpha1.Fede
186187
// boolPtr returns a pointer to a boolean value.
187188
func boolPtr(b bool) *bool { return &b }
188189

190+
// quotaExceededResponse creates an admission response for quota exceeded errors.
191+
func quotaExceededResponse(message string) admission.Response {
192+
return admission.Response{
193+
AdmissionResponse: admissionv1.AdmissionResponse{
194+
Allowed: false,
195+
Result: &metav1.Status{
196+
Message: message,
197+
Reason: util.QuotaExceededReason,
198+
Code: int32(http.StatusForbidden),
199+
},
200+
},
201+
}
202+
}
203+
189204
// --- Admission Request Builder ---
190205
type admissionRequestBuilder struct {
191206
t *testing.T
@@ -527,7 +542,7 @@ func TestValidatingAdmission_Handle(t *testing.T) {
527542
decoder: &fakeDecoder{decodeObj: rbCreateExceeds},
528543
clientObjects: []client.Object{frqForCreateExceeds},
529544
enableFederatedQuotaEnforcementFeatureGate: true,
530-
wantResponse: admission.Denied("FederatedResourceQuota(quota-ns/frq-create-exceeds) exceeded for resource cpu: requested sum 200m, limit 150m."),
545+
wantResponse: quotaExceededResponse("FederatedResourceQuota(quota-ns/frq-create-exceeds) exceeded for resource cpu: requested sum 200m, limit 150m."),
531546
},
532547
{
533548
name: "update passes quota (allowed response, non-dryrun)",
@@ -562,7 +577,7 @@ func TestValidatingAdmission_Handle(t *testing.T) {
562577
decoder: &fakeDecoder{decodeObj: rbUpdateFailNew, rawDecodedObj: rbUpdateFailOld},
563578
clientObjects: []client.Object{frqForUpdateFail},
564579
enableFederatedQuotaEnforcementFeatureGate: true,
565-
wantResponse: admission.Denied("FederatedResourceQuota(quota-ns/frq-update-fail) exceeded for resource cpu: requested sum 110m, limit 100m."),
580+
wantResponse: quotaExceededResponse("FederatedResourceQuota(quota-ns/frq-update-fail) exceeded for resource cpu: requested sum 110m, limit 100m."),
566581
},
567582
{
568583
name: "validateComponents: zero components (should allow)",
@@ -656,7 +671,7 @@ func TestValidatingAdmission_Handle(t *testing.T) {
656671
decoder: &fakeDecoder{decodeObj: rbWithComponents},
657672
clientObjects: []client.Object{frqForComponentsExceeded},
658673
enableFederatedQuotaEnforcementFeatureGate: true,
659-
wantResponse: admission.Denied("FederatedResourceQuota(quota-ns/frq-components-exceeded) exceeded for resource cpu: requested sum 160m, limit 150m."),
674+
wantResponse: quotaExceededResponse("FederatedResourceQuota(quota-ns/frq-components-exceeded) exceeded for resource cpu: requested sum 160m, limit 150m."),
660675
},
661676
{
662677
name: "update components passes quota (allowed response)",
@@ -678,7 +693,7 @@ func TestValidatingAdmission_Handle(t *testing.T) {
678693
decoder: &fakeDecoder{decodeObj: rbComponentsFailNew, rawDecodedObj: rbComponentsFailOld},
679694
clientObjects: []client.Object{frqForComponentsFail},
680695
enableFederatedQuotaEnforcementFeatureGate: true,
681-
wantResponse: admission.Denied("FederatedResourceQuota(quota-ns/frq-components-fail) exceeded for resource cpu: requested sum 110m, limit 100m."),
696+
wantResponse: quotaExceededResponse("FederatedResourceQuota(quota-ns/frq-components-fail) exceeded for resource cpu: requested sum 110m, limit 100m."),
682697
},
683698
}
684699

@@ -722,6 +737,9 @@ func TestValidatingAdmission_Handle(t *testing.T) {
722737
if got.Result.Code != tt.wantResponse.Result.Code {
723738
t.Errorf("Handle() got.Result.Code = %d, want %d", got.Result.Code, tt.wantResponse.Result.Code)
724739
}
740+
if got.Result.Reason != tt.wantResponse.Result.Reason {
741+
t.Errorf("Handle() got.Result.Reason = %q, want %q", got.Result.Reason, tt.wantResponse.Result.Reason)
742+
}
725743
}
726744

727745
if len(got.Patches) != 0 {

0 commit comments

Comments
 (0)