From 357dd424dabd23cbbc3c8a7a2bed4924c9f7ed31 Mon Sep 17 00:00:00 2001 From: Myasnikov Daniil Date: Wed, 29 Apr 2026 10:50:16 +0500 Subject: [PATCH] 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 --- .../images/objectstorage/Dockerfile | 5 ++- .../91-bucketaccess-conflict-retry.diff | 39 +++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 packages/system/objectstorage-controller/images/objectstorage/patches/91-bucketaccess-conflict-retry.diff diff --git a/packages/system/objectstorage-controller/images/objectstorage/Dockerfile b/packages/system/objectstorage-controller/images/objectstorage/Dockerfile index 260446c3..d71e5566 100644 --- a/packages/system/objectstorage-controller/images/objectstorage/Dockerfile +++ b/packages/system/objectstorage-controller/images/objectstorage/Dockerfile @@ -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 diff --git a/packages/system/objectstorage-controller/images/objectstorage/patches/91-bucketaccess-conflict-retry.diff b/packages/system/objectstorage-controller/images/objectstorage/patches/91-bucketaccess-conflict-retry.diff new file mode 100644 index 00000000..e4b06c42 --- /dev/null +++ b/packages/system/objectstorage-controller/images/objectstorage/patches/91-bucketaccess-conflict-retry.diff @@ -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) {