Only retry on resourcequota transient conflict

Signed-off-by: Jakub Jaruszewski <jjaruszewski@man.poznan.pl>
pull/32088/head
Jakub Jaruszewski 4 weeks ago
parent 8a45247161
commit c178b0d9ed
No known key found for this signature in database
GPG Key ID: 43268828175AE8A3

@ -323,8 +323,9 @@ func (c *Client) makeCreateApplyFunc(serverSideApply, forceConflicts, dryRun boo
slog.String("name", target.Name),
slog.String("gvk", target.Mapping.GroupVersionKind.String()))
return retry.RetryOnConflict(
return retry.OnError(
retry.DefaultRetry,
isQuotaConflict,
func() error {
err := patchResourceServerSide(target, dryRun, forceConflicts, fieldValidationDirective)
if err != nil {
@ -954,6 +955,26 @@ func isIncompatibleServerError(err error) bool {
return err.(*apierrors.StatusError).Status().Code == http.StatusUnsupportedMediaType
}
// isQuotaConflict checks if the error is a conflict error specifically caused by
// a ResourceQuota. This is used to determine if a retry should be attempted,
// since quota conflicts are typically transient and can be resolved by retrying.
func isQuotaConflict(err error) bool {
if !apierrors.IsConflict(err) {
return false
}
// Check the error message for the specific ResourceQuota conflict pattern.
// The error message from the ResourceQuota admission controller contains:
// "Operation cannot be fulfilled on resourcequotas" and "the object has been modified"
errMsg := err.Error()
if strings.Contains(errMsg, "Operation cannot be fulfilled on resourcequotas") &&
strings.Contains(errMsg, "the object has been modified") {
return true
}
return false
}
// getManagedFieldsManager returns the manager string. If one was set it will be returned.
// Otherwise, one is calculated based on the name of the binary.
func getManagedFieldsManager() string {

@ -282,6 +282,24 @@ func TestCreate(t *testing.T) {
return actions
}(),
},
"Create fail: managed fields conflict (server-side apply)": {
Pods: newPodList("seal"),
ServerSideApply: true,
Callback: func(t *testing.T, _ testCase, _ []RequestResponseAction, req *http.Request) (*http.Response, error) {
t.Helper()
// Return a generic 409 conflict (not quota-related)
// This simulates a managed fields conflict
return &http.Response{
StatusCode: http.StatusConflict,
Request: req,
}, nil
},
ExpectedErrorContains: "the server reported a conflict",
ExpectedActions: []string{
"/namespaces/default/pods/seal:PATCH",
},
},
}
c := newTestClient(t)

Loading…
Cancel
Save