diff --git a/pkg/migrator/core.go b/pkg/migrator/core.go index efdaf847a..bf959ba9d 100644 --- a/pkg/migrator/core.go +++ b/pkg/migrator/core.go @@ -209,19 +209,11 @@ func (m *migrator) migrateOneItem(ctx context.Context, item *unstructured.Unstru return nil } if canRetry(err) { - seconds, delay := errors.SuggestsClientDelay(err) - switch { - case delay && len(namespace) > 0: - klog.Warningf("migration of %s, in the %s namespace, will be retried after a %ds delay: %v", name, namespace, seconds, err) - time.Sleep(time.Duration(seconds) * time.Second) - case delay: - klog.Warningf("migration of %s will be retried after a %ds delay: %v", name, seconds, err) - time.Sleep(time.Duration(seconds) * time.Second) - case !delay && len(namespace) > 0: - klog.Warningf("migration of %s, in the %s namespace, will be retried: %v", name, namespace, err) - default: - klog.Warningf("migration of %s will be retried: %v", name, err) - } + delaySeconds, _ := errors.SuggestsClientDelay(err) + delay := time.Duration(delaySeconds) * time.Second + klog.V(logLevelForTryError(err)).InfoS("Retrying migration", + "object", klog.KRef(namespace, name), "delay", delay, "err", err) + time.Sleep(delay) continue } // error is not retriable @@ -244,7 +236,7 @@ func (m *migrator) try(ctx context.Context, namespace, name string, item *unstru if err == nil { return false, nil } - return errors.IsConflict(err), err + return isConflictError(err), err // TODO: The oc admin uses a defer function to do bandwidth limiting // after doing all operations. The rate limiter is marked as an alpha diff --git a/pkg/migrator/errors.go b/pkg/migrator/errors.go index da1cdba6f..726e48849 100644 --- a/pkg/migrator/errors.go +++ b/pkg/migrator/errors.go @@ -21,6 +21,7 @@ import ( "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/util/net" + "k8s.io/klog/v2" ) // ErrRetriable is a wrapper for an error that a migrator may use to indicate the @@ -52,6 +53,18 @@ func isConnectionRefusedError(err error) bool { return strings.Contains(err.Error(), "connection refused") } +// isUIDPreconditionError checks whether the error contains "Precondition failed: UID in precondition". +// This error message is typically present when the resource is deleted before it can be written back. +func isUIDPreconditionError(err error) bool { + return strings.Contains(err.Error(), "Precondition failed: UID in precondition") +} + +// isConflictError checks whether the given error is a conflict error. +// This is true when errors.IsConflict or isUIDPreconditionError returns true. +func isConflictError(err error) bool { + return errors.IsConflict(err) || isUIDPreconditionError(err) +} + // interpret adds retry information to the provided error. And it might change // the error to nil. func interpret(err error) error { @@ -63,7 +76,7 @@ func interpret(err error) error { return nil case errors.IsMethodNotSupported(err): return ErrNotRetriable{err} - case errors.IsConflict(err): + case isConflictError(err): return ErrRetriable{err} case errors.IsServerTimeout(err): return ErrRetriable{err} @@ -91,3 +104,12 @@ func canRetry(err error) bool { } return true } + +func logLevelForTryError(err error) klog.Level { + switch { + case errors.IsNotFound(err), isConflictError(err): + return 2 + default: + return 0 + } +}