Compare commits

...

4 Commits

Author SHA1 Message Date
Gabriel José Mouallem Rodrigues
f1405e2a74
Merge eefb45ca5a into f38a3e3a08 2026-07-29 08:16:04 +02:00
renovate[bot]
f38a3e3a08
chore(deps): update amazon/aws-cli docker tag to v2.36.9 (#1035)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-28 19:27:14 +02:00
renovate[bot]
5ff12acda0
chore(deps): update mcr.microsoft.com/azure-storage/azurite:3.36.0 docker digest to 76b8127 (#1036)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-28 19:17:29 +02:00
Gabriel Jose Mouallem Rodrigues
eefb45ca5a fix: add retry logic to updateRecoveryWindow for concurrent status updates
When backup completion and retention policy enforcement run concurrently,
both call updateRecoveryWindow to update the ObjectStore status. This can
cause "object has been modified" errors due to Kubernetes optimistic
concurrency control.

This change wraps the status update in retry.RetryOnConflict, matching
the pattern already used in setLastFailedBackupTime in the same file.
The retry logic fetches a fresh copy of the ObjectStore before each
update attempt, ensuring the resourceVersion is current.

Fixes #758

Signed-off-by: Gabriel Mouallem <gabriel@latitude.sh>
2026-02-03 15:01:30 -03:00
3 changed files with 28 additions and 18 deletions

View File

@ -33,7 +33,8 @@ import (
) )
// updateRecoveryWindow updates the recovery window inside the object // updateRecoveryWindow updates the recovery window inside the object
// store status subresource // store status subresource. It uses retry logic to handle concurrent
// updates from backup completion and retention policy enforcement.
func updateRecoveryWindow( func updateRecoveryWindow(
ctx context.Context, ctx context.Context,
c client.Client, c client.Client,
@ -41,24 +42,33 @@ func updateRecoveryWindow(
objectStore *barmancloudv1.ObjectStore, objectStore *barmancloudv1.ObjectStore,
serverName string, serverName string,
) error { ) error {
// Set the recovery window inside the barman object store object objectStoreKey := client.ObjectKeyFromObject(objectStore)
convertTime := func(t *time.Time) *metav1.Time {
if t == nil { return retry.RetryOnConflict(retry.DefaultBackoff, func() error {
return nil var freshObjectStore barmancloudv1.ObjectStore
if err := c.Get(ctx, objectStoreKey, &freshObjectStore); err != nil {
return err
} }
return ptr.To(metav1.NewTime(*t))
}
recoveryWindow := objectStore.Status.ServerRecoveryWindow[serverName] // Set the recovery window inside the barman object store object
recoveryWindow.FirstRecoverabilityPoint = convertTime(backupList.GetFirstRecoverabilityPoint()) convertTime := func(t *time.Time) *metav1.Time {
recoveryWindow.LastSuccessfulBackupTime = convertTime(backupList.GetLastSuccessfulBackupTime()) if t == nil {
return nil
}
return ptr.To(metav1.NewTime(*t))
}
if objectStore.Status.ServerRecoveryWindow == nil { recoveryWindow := freshObjectStore.Status.ServerRecoveryWindow[serverName]
objectStore.Status.ServerRecoveryWindow = make(map[string]barmancloudv1.RecoveryWindow) recoveryWindow.FirstRecoverabilityPoint = convertTime(backupList.GetFirstRecoverabilityPoint())
} recoveryWindow.LastSuccessfulBackupTime = convertTime(backupList.GetLastSuccessfulBackupTime())
objectStore.Status.ServerRecoveryWindow[serverName] = recoveryWindow
return c.Status().Update(ctx, objectStore) if freshObjectStore.Status.ServerRecoveryWindow == nil {
freshObjectStore.Status.ServerRecoveryWindow = make(map[string]barmancloudv1.RecoveryWindow)
}
freshObjectStore.Status.ServerRecoveryWindow[serverName] = recoveryWindow
return c.Status().Update(ctx, &freshObjectStore)
})
} }
// setLastFailedBackupTime sets the last failed backup time in the // setLastFailedBackupTime sets the last failed backup time in the

View File

@ -73,7 +73,7 @@ func newAzuriteDeployment(namespace, name string) *appsv1.Deployment {
Name: name, Name: name,
// renovate: datasource=docker depName=mcr.microsoft.com/azure-storage/azurite versioning=docker // renovate: datasource=docker depName=mcr.microsoft.com/azure-storage/azurite versioning=docker
// Version: 3.36.0 // Version: 3.36.0
Image: "mcr.microsoft.com/azure-storage/azurite@sha256:37493d0f2e764467421ffe16eb3caa39277e5fa7f6adea18eb5bbfb3c5247f98", Image: "mcr.microsoft.com/azure-storage/azurite@sha256:76b8127d608fab8287a14a4bfeb9a5502cdcffb4bf1e86f09f324ebb0e70edba",
Args: []string{ Args: []string{
"azurite-blob", "azurite-blob",
"--blobHost", "--blobHost",

View File

@ -121,8 +121,8 @@ func newS3ClientDeployment(namespace string) *appsv1.Deployment {
{ {
Name: s3ClientName, Name: s3ClientName,
// renovate: datasource=docker depName=amazon/aws-cli versioning=docker // renovate: datasource=docker depName=amazon/aws-cli versioning=docker
// Version: 2.36.8 // Version: 2.36.9
Image: "docker.io/amazon/aws-cli@sha256:7e1b11a3c93bc5af81f496de0662f666b2352a4a6666e8ebae904fe102b131b6", Image: "docker.io/amazon/aws-cli@sha256:00dee8ccaf669721f8163944ea9e6ac13183851b23d5b7a9868a608bc932cfdb",
Command: []string{"sleep", "infinity"}, Command: []string{"sleep", "infinity"},
Env: []corev1.EnvVar{ Env: []corev1.EnvVar{
{ {