From cb1d3e88c85e5f79ed6d72b2057f1a41f114c1e3 Mon Sep 17 00:00:00 2001 From: Camil Blanaru Date: Tue, 24 Jun 2025 18:01:35 +0200 Subject: [PATCH] Track WAL submission times in ObjectStore status --- api/v1/objectstore_types.go | 6 ++++ api/v1/zz_generated.deepcopy.go | 8 +++++ .../barmancloud.cnpg.io_objectstores.yaml | 10 ++++++ internal/cnpgi/common/wal.go | 34 +++++++++++++++++++ internal/cnpgi/instance/retention.go | 17 +++++++--- manifest.yaml | 10 ++++++ 6 files changed, 80 insertions(+), 5 deletions(-) diff --git a/api/v1/objectstore_types.go b/api/v1/objectstore_types.go index 80c4742..c33f085 100644 --- a/api/v1/objectstore_types.go +++ b/api/v1/objectstore_types.go @@ -75,6 +75,12 @@ type RecoveryWindow struct { // The last successful backup time LastSuccessfulBackupTime *metav1.Time `json:"lastSuccussfulBackupTime,omitempty"` + + // The timestamp of the first WAL file successfully submitted to the object store + FirstWALSubmissionTime *metav1.Time `json:"firstWALSubmissionTime,omitempty"` + + // The timestamp of the last WAL file successfully submitted to the object store + LastWALSubmissionTime *metav1.Time `json:"lastWALSubmissionTime,omitempty"` } // +kubebuilder:object:root=true diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index 11fb2ae..f7b60c4 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -157,6 +157,14 @@ func (in *RecoveryWindow) DeepCopyInto(out *RecoveryWindow) { in, out := &in.LastSuccessfulBackupTime, &out.LastSuccessfulBackupTime *out = (*in).DeepCopy() } + if in.FirstWALSubmissionTime != nil { + in, out := &in.FirstWALSubmissionTime, &out.FirstWALSubmissionTime + *out = (*in).DeepCopy() + } + if in.LastWALSubmissionTime != nil { + in, out := &in.LastWALSubmissionTime, &out.LastWALSubmissionTime + *out = (*in).DeepCopy() + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RecoveryWindow. diff --git a/config/crd/bases/barmancloud.cnpg.io_objectstores.yaml b/config/crd/bases/barmancloud.cnpg.io_objectstores.yaml index 6fb87b5..7dfcddd 100644 --- a/config/crd/bases/barmancloud.cnpg.io_objectstores.yaml +++ b/config/crd/bases/barmancloud.cnpg.io_objectstores.yaml @@ -609,10 +609,20 @@ spec: restored. format: date-time type: string + firstWALSubmissionTime: + description: The timestamp of the first WAL file successfully + submitted to the object store + format: date-time + type: string lastSuccussfulBackupTime: description: The last successful backup time format: date-time type: string + lastWALSubmissionTime: + description: The timestamp of the last WAL file successfully + submitted to the object store + format: date-time + type: string type: object description: ServerRecoveryWindow maps each server to its recovery window diff --git a/internal/cnpgi/common/wal.go b/internal/cnpgi/common/wal.go index 0da8a39..ef8dfbc 100644 --- a/internal/cnpgi/common/wal.go +++ b/internal/cnpgi/common/wal.go @@ -17,6 +17,7 @@ import ( walUtils "github.com/cloudnative-pg/machinery/pkg/fileutils/wals" "github.com/cloudnative-pg/machinery/pkg/log" apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" @@ -184,6 +185,12 @@ func (w WALServiceImplementation) Archive( } } + // Update WAL submission timing in ObjectStore status after successful archiving + if err := w.updateWALSubmissionTime(ctx, &objectStore, configuration.ServerName); err != nil { + contextLogger.Error(err, "failed to update WAL submission time in ObjectStore status") + // Don't fail the archiving operation for status update errors + } + return &wal.WALArchiveResult{}, nil } @@ -469,3 +476,30 @@ func isEndOfWALStream(results []barmanRestorer.Result) bool { return false } + +// updateWALSubmissionTime updates the WAL submission timing in the ObjectStore status +func (w WALServiceImplementation) updateWALSubmissionTime( + ctx context.Context, + objectStore *barmancloudv1.ObjectStore, + serverName string, +) error { + now := metav1.NewTime(time.Now()) + + if objectStore.Status.ServerRecoveryWindow == nil { + objectStore.Status.ServerRecoveryWindow = make(map[string]barmancloudv1.RecoveryWindow) + } + + recoveryWindow := objectStore.Status.ServerRecoveryWindow[serverName] + + // Set first WAL submission time if not already set + if recoveryWindow.FirstWALSubmissionTime == nil { + recoveryWindow.FirstWALSubmissionTime = &now + } + + // Always update last WAL submission time + recoveryWindow.LastWALSubmissionTime = &now + + objectStore.Status.ServerRecoveryWindow[serverName] = recoveryWindow + + return w.Client.Status().Update(ctx, objectStore) +} diff --git a/internal/cnpgi/instance/retention.go b/internal/cnpgi/instance/retention.go index 6b68dfb..37f475e 100644 --- a/internal/cnpgi/instance/retention.go +++ b/internal/cnpgi/instance/retention.go @@ -176,14 +176,21 @@ func (c *CatalogMaintenanceRunnable) updateRecoveryWindow( return ptr.To(metav1.NewTime(*t)) } - recoveryWindow := barmancloudv1.RecoveryWindow{ - FirstRecoverabilityPoint: convertTime(backupList.GetFirstRecoverabilityPoint()), - LastSuccessfulBackupTime: convertTime(backupList.GetLastSuccessfulBackupTime()), - } - if objectStore.Status.ServerRecoveryWindow == nil { objectStore.Status.ServerRecoveryWindow = make(map[string]barmancloudv1.RecoveryWindow) } + + // get existing recovery window to preserve WAL submission timing + existingWindow := objectStore.Status.ServerRecoveryWindow[serverName] + + recoveryWindow := barmancloudv1.RecoveryWindow{ + FirstRecoverabilityPoint: convertTime(backupList.GetFirstRecoverabilityPoint()), + LastSuccessfulBackupTime: convertTime(backupList.GetLastSuccessfulBackupTime()), + // preserve existing WAL submission timing + FirstWALSubmissionTime: existingWindow.FirstWALSubmissionTime, + LastWALSubmissionTime: existingWindow.LastWALSubmissionTime, + } + objectStore.Status.ServerRecoveryWindow[serverName] = recoveryWindow return c.Client.Status().Update(ctx, objectStore) diff --git a/manifest.yaml b/manifest.yaml index c43ef4b..7dc9f0b 100644 --- a/manifest.yaml +++ b/manifest.yaml @@ -608,10 +608,20 @@ spec: restored. format: date-time type: string + firstWALSubmissionTime: + description: The timestamp of the first WAL file successfully + submitted to the object store + format: date-time + type: string lastSuccussfulBackupTime: description: The last successful backup time format: date-time type: string + lastWALSubmissionTime: + description: The timestamp of the last WAL file successfully + submitted to the object store + format: date-time + type: string type: object description: ServerRecoveryWindow maps each server to its recovery window