refactor: extract the empty WAL archive decision into a helper

The WAL archive hook and the restore job hook each derived, inline,
whether to verify the archive destination before proceeding. Pull each
decision into a small function so the operator-decision-versus-fallback
logic can be exercised on its own. Behavior is unchanged: archiving still
fails on a marker-file stat error, and restore still falls back to the
Cluster annotation alone.

Signed-off-by: Armando Ruocco <armando.ruocco@enterprisedb.com>
This commit is contained in:
Armando Ruocco 2026-07-17 16:19:08 +02:00 committed by Leonardo Cecchi
parent 7efb2cdf56
commit 6fddc14398
2 changed files with 46 additions and 25 deletions

View File

@ -157,19 +157,13 @@ func (w WALServiceImplementation) Archive(
}
// Step 2: Check if the archive location is safe to perform archiving.
// The operator owns the marker file's lifecycle, so a non-nil decision
// already accounts for it and is obeyed as-is. A nil value means an
// operator that predates this field; fall back to checking the marker
// file and Cluster annotation directly.
var checkEmptyWalArchive bool
if request.CheckEmptyWalArchive != nil {
checkEmptyWalArchive = *request.CheckEmptyWalArchive
} else {
checkFileExisting, err := fileutils.FileExists(emptyWalArchiveFile)
if err != nil {
return nil, fmt.Errorf("while checking for empty wal archive check file %q: %w", emptyWalArchiveFile, err)
}
checkEmptyWalArchive = utils.IsEmptyWalArchiveCheckEnabled(&configuration.Cluster.ObjectMeta) && checkFileExisting
checkEmptyWalArchive, err := resolveArchiveEmptyWalArchiveCheck(
request.CheckEmptyWalArchive,
configuration.Cluster,
emptyWalArchiveFile,
)
if err != nil {
return nil, err
}
if checkEmptyWalArchive {
@ -234,6 +228,31 @@ func (w WALServiceImplementation) Archive(
return &wal.WALArchiveResult{}, nil
}
// resolveArchiveEmptyWalArchiveCheck reports whether the WAL archive
// destination must be verified before archiving this segment.
//
// The operator owns the marker file's lifecycle, so when it sets the decision
// (non-nil) that value already accounts for the marker and is obeyed as-is. A
// nil value comes from an operator that predates this field, so we fall back to
// the previous logic: the Cluster annotation combined with the on-disk marker
// file.
func resolveArchiveEmptyWalArchiveCheck(
operatorDecision *bool,
cluster *cnpgv1.Cluster,
markerFilePath string,
) (bool, error) {
if operatorDecision != nil {
return *operatorDecision, nil
}
markerFilePresent, err := fileutils.FileExists(markerFilePath)
if err != nil {
return false, fmt.Errorf("while checking for empty wal archive check file %q: %w", markerFilePath, err)
}
return utils.IsEmptyWalArchiveCheckEnabled(&cluster.ObjectMeta) && markerFilePresent, nil
}
// Restore implements the WALService interface
func (w WALServiceImplementation) Restore(
ctx context.Context,

View File

@ -290,24 +290,26 @@ func (impl *JobHookImpl) checkBackupDestination(
}
}
// Check if we're ok to restore from the desired destination. Unlike
// archiving, restore is a one-shot operation that has never been gated
// on the first-archive marker file, so the only fallback needed here
// (for an operator that predates this field) is the Cluster annotation.
var checkEmptyWalArchive bool
if operatorCheckEmptyWalArchive != nil {
checkEmptyWalArchive = *operatorCheckEmptyWalArchive
} else {
checkEmptyWalArchive = utils.IsEmptyWalArchiveCheckEnabled(&cluster.ObjectMeta)
}
if checkEmptyWalArchive {
if resolveRestoreEmptyWalArchiveCheck(operatorCheckEmptyWalArchive, cluster) {
return common.CheckBackupDestination(ctx, barmanConfiguration, walArchiver, serverName)
}
return nil
}
// resolveRestoreEmptyWalArchiveCheck reports whether the destination must be
// verified before restoring. When the operator sets the decision (non-nil) it
// is obeyed as-is; a nil value comes from an operator that predates this field,
// so we fall back to the Cluster annotation. Unlike archiving, restore is a
// one-shot operation that has never been gated on the first-archive marker
// file, so the annotation is the only fallback needed.
func resolveRestoreEmptyWalArchiveCheck(operatorDecision *bool, cluster *cnpgv1.Cluster) bool {
if operatorDecision != nil {
return *operatorDecision
}
return utils.IsEmptyWalArchiveCheckEnabled(&cluster.ObjectMeta)
}
// restoreCustomWalDir moves the current pg_wal data to the specified custom wal dir and applies the symlink
// returns indicating if any changes were made and any error encountered in the process
func (impl JobHookImpl) restoreCustomWalDir(ctx context.Context) (bool, error) {