Report comparison cleanup recovery state
This commit is contained in:
@@ -445,22 +445,44 @@ func unrecognizedBundleError(action string, err error) error {
|
||||
return fmt.Errorf("%w: %s: %v", ErrUnrecognizedBundle, action, err)
|
||||
}
|
||||
|
||||
// BackupRecoveryState describes what remains of a prior bundle after cleanup
|
||||
// reports an error.
|
||||
type BackupRecoveryState string
|
||||
|
||||
const (
|
||||
BackupRecoveryComplete BackupRecoveryState = "complete"
|
||||
BackupRecoveryPartial BackupRecoveryState = "partial"
|
||||
BackupRecoveryAbsent BackupRecoveryState = "absent"
|
||||
BackupRecoveryUnknown BackupRecoveryState = "unknown"
|
||||
)
|
||||
|
||||
// PublicationResult describes the durable state of a publication attempt.
|
||||
type PublicationResult struct {
|
||||
Committed bool
|
||||
RetainedBackupPath string
|
||||
Committed bool
|
||||
RecoveryState BackupRecoveryState
|
||||
RecoveryPath string
|
||||
}
|
||||
|
||||
// PublicationCleanupError reports that a committed bundle could not remove its
|
||||
// prior sibling backup. The new bundle remains installed and the backup path
|
||||
// is retained for operator recovery.
|
||||
// PublicationCleanupError reports that a committed bundle could not completely
|
||||
// remove its prior sibling backup. The new bundle remains installed; recovery
|
||||
// fields describe the state observed after cleanup failed.
|
||||
type PublicationCleanupError struct {
|
||||
RetainedBackupPath string
|
||||
Err error
|
||||
RecoveryState BackupRecoveryState
|
||||
RecoveryPath string
|
||||
Err error
|
||||
}
|
||||
|
||||
func (err *PublicationCleanupError) Error() string {
|
||||
return fmt.Sprintf("remove comparison backup %q: %v", err.RetainedBackupPath, err.Err)
|
||||
switch err.RecoveryState {
|
||||
case BackupRecoveryComplete:
|
||||
return fmt.Sprintf("remove comparison backup %q: %v; complete recovery bundle remains", err.RecoveryPath, err.Err)
|
||||
case BackupRecoveryPartial:
|
||||
return fmt.Sprintf("remove comparison backup %q: %v; partial remnants remain", err.RecoveryPath, err.Err)
|
||||
case BackupRecoveryAbsent:
|
||||
return fmt.Sprintf("remove comparison backup: %v; no recovery bundle remains", err.Err)
|
||||
default:
|
||||
return fmt.Sprintf("remove comparison backup: %v; recovery state is unknown", err.Err)
|
||||
}
|
||||
}
|
||||
|
||||
func (err *PublicationCleanupError) Unwrap() error {
|
||||
@@ -558,12 +580,26 @@ func publish(ctx context.Context, plan DestinationPlan, bundle LogicalBundle, op
|
||||
}
|
||||
temporaryDirectory = ""
|
||||
if err := operations.removeAll(backupDirectory); err != nil {
|
||||
cleanupErr := &PublicationCleanupError{RetainedBackupPath: backupDirectory, Err: err}
|
||||
return PublicationResult{Committed: true, RetainedBackupPath: backupDirectory}, cleanupErr
|
||||
recoveryState, recoveryPath := inspectBackupRecovery(backupDirectory)
|
||||
cleanupErr := &PublicationCleanupError{RecoveryState: recoveryState, RecoveryPath: recoveryPath, Err: err}
|
||||
return PublicationResult{Committed: true, RecoveryState: recoveryState, RecoveryPath: recoveryPath}, cleanupErr
|
||||
}
|
||||
return PublicationResult{Committed: true}, nil
|
||||
}
|
||||
|
||||
func inspectBackupRecovery(backupDirectory string) (BackupRecoveryState, string) {
|
||||
if _, err := os.Lstat(backupDirectory); err != nil {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
return BackupRecoveryAbsent, ""
|
||||
}
|
||||
return BackupRecoveryUnknown, ""
|
||||
}
|
||||
if _, err := RecognizeBundle(backupDirectory); err == nil {
|
||||
return BackupRecoveryComplete, backupDirectory
|
||||
}
|
||||
return BackupRecoveryPartial, backupDirectory
|
||||
}
|
||||
|
||||
func authorizeMovedDestination(plan DestinationPlan, backupDirectory string) error {
|
||||
backupPlan, err := PlanDestination(plan.WorkingDirectory, backupDirectory, plan.Replace)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user