fix(objectstorage-controller): retry on Bucket update conflict during BucketAccess reconcile

Upstream COSI v0.2.2's BucketAccess reconciler does a Get->mutate->Update
on the parent Bucket and surfaces "Operation cannot be fulfilled ... the
object has been modified" as a FailedGrantAccess event when it races
against the Bucket reconciler in the same controller process. Wrap the
mutation in retry.RetryOnConflict so the reconcile loop refreshes and
retries instead of leaking the conflict to users.

Carried as 91-bucketaccess-conflict-retry.diff until upstreamed
(cf. 89-reconciliation.diff and 90-bucket-name.diff, both dropped
in c29d501b once merged upstream).

Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
This commit is contained in:
Myasnikov Daniil 2026-04-29 10:50:16 +05:00
parent 358ac66a2a
commit 357dd424da
No known key found for this signature in database
GPG key ID: FA953A439C637F04
2 changed files with 43 additions and 1 deletions

View file

@ -2,12 +2,15 @@
FROM alpine AS source
ARG COMMIT_REF=v0.2.2
RUN apk add --no-cache curl tar
RUN apk add --no-cache curl tar git
WORKDIR /src
RUN curl -sSL https://github.com/kubernetes-sigs/container-object-storage-interface/archive/${COMMIT_REF}.tar.gz \
| tar -xz --strip-components=1
COPY patches /patches
RUN git apply /patches/*.diff
FROM --platform=$BUILDPLATFORM docker.io/golang:1.24 AS builder
ARG TARGETOS
ARG TARGETARCH

View file

@ -0,0 +1,39 @@
diff --git a/sidecar/pkg/bucketaccess/bucketaccess_controller.go b/sidecar/pkg/bucketaccess/bucketaccess_controller.go
index a4db5c4..b351f9e 100644
--- a/sidecar/pkg/bucketaccess/bucketaccess_controller.go
+++ b/sidecar/pkg/bucketaccess/bucketaccess_controller.go
@@ -31,6 +31,7 @@ import (
kube "k8s.io/client-go/kubernetes"
kubecorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/client-go/tools/record"
+ "k8s.io/client-go/util/retry"
"k8s.io/klog/v2"
cosiapi "sigs.k8s.io/container-object-storage-interface/client/apis"
"sigs.k8s.io/container-object-storage-interface/client/apis/objectstorage/consts"
@@ -273,11 +274,22 @@ func (bal *BucketAccessListener) Add(ctx context.Context, inputBucketAccess *v1a
}
}
- if controllerutil.AddFinalizer(bucket, consts.BABucketFinalizer) {
- _, err = bal.buckets().Update(ctx, bucket, metav1.UpdateOptions{})
- if err != nil {
- return bal.recordError(inputBucketAccess, v1.EventTypeWarning, v1alpha1.FailedGrantAccess, err)
+ // Re-fetch and update inside RetryOnConflict to handle the case where the Bucket
+ // reconciler in the same controller process mutates the Bucket between our Get
+ // and Update, which surfaces as "the object has been modified" on the parent
+ // Bucket and emits FailedGrantAccess on the BucketAccess.
+ if err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
+ latest, getErr := bal.buckets().Get(ctx, bucketClaim.Status.BucketName, metav1.GetOptions{})
+ if getErr != nil {
+ return getErr
+ }
+ if !controllerutil.AddFinalizer(latest, consts.BABucketFinalizer) {
+ return nil
}
+ _, updateErr := bal.buckets().Update(ctx, latest, metav1.UpdateOptions{})
+ return updateErr
+ }); err != nil {
+ return bal.recordError(inputBucketAccess, v1.EventTypeWarning, v1alpha1.FailedGrantAccess, err)
}
if controllerutil.AddFinalizer(bucketAccess, consts.BAFinalizer) {