diff --git a/controllers/node_handler.go b/controllers/node_handler.go index 4e73e05..fcb3213 100644 --- a/controllers/node_handler.go +++ b/controllers/node_handler.go @@ -83,7 +83,7 @@ func ApplyProfiles(ctx context.Context, params reconcileParameters, data *state. if err == nil { continue } - if errors.Is(err, retryErr) { + if errors.As(err, &retryErr) { profilesWithRetryError[ps.Profile.Name] = struct{}{} } else { errs = append(errs, err) diff --git a/plugin/impl/eviction.go b/plugin/impl/eviction.go index 0e5e9aa..3e6f9f1 100644 --- a/plugin/impl/eviction.go +++ b/plugin/impl/eviction.go @@ -94,7 +94,8 @@ func (e *Eviction) Trigger(params plugin.Parameters) error { ForceEviction: e.ForceEviction, }) if err != nil { - return err + params.Log.Error(err, "Drain encountered errors; will retry next reconcile", "node", params.Node.Name) + return &plugin.RetryError{Message: err.Error()} } if !drained { params.Log.Info("Drain still in progress; will continue in next reconcile", "node", params.Node.Name) diff --git a/plugin/plugin_test.go b/plugin/plugin_test.go index ff9c94e..5b72de8 100644 --- a/plugin/plugin_test.go +++ b/plugin/plugin_test.go @@ -18,7 +18,7 @@ func TestPlugins(t *testing.T) { RunSpecs(t, "Plugin Suite") } -var _ = Describe("CheckError", func() { +var _ = Describe("ChainError", func() { chainErr := ChainError{ Message: "msg", Err: errors.New("err"), @@ -35,6 +35,25 @@ var _ = Describe("CheckError", func() { }) }) +var _ = Describe("RetryError", func() { + It("is extractable via errors.As through ChainError wrapping", func() { + retryErr := &RetryError{Message: "drain still in progress"} + wrapped := &ChainError{Message: "trigger chain failed", Err: retryErr} + + var extracted *RetryError + Expect(errors.As(wrapped, &extracted)).To(BeTrue()) + Expect(extracted.Message).To(Equal("drain still in progress")) + }) + + It("is not matched by errors.Is with a different instance", func() { + retryErr := &RetryError{Message: "some error"} + wrapped := &ChainError{Message: "trigger chain failed", Err: retryErr} + + // errors.Is uses pointer identity for types without Is() method + Expect(errors.Is(wrapped, &RetryError{})).To(BeFalse()) + }) +}) + var _ = Describe("Registry", func() { var emptyConfig *ucfgwrap.Config diff --git a/state/state.go b/state/state.go index 521926a..1c3be5d 100644 --- a/state/state.go +++ b/state/state.go @@ -192,7 +192,8 @@ func Apply(state NodeState, node *v1.Node, data *Data, params plugin.Parameters) } if stateInfo.Previous != stateInfo.Current { err := state.Enter(params, data) - if errors.Is(err, &plugin.RetryError{}) { + var retryErr *plugin.RetryError + if errors.As(err, &retryErr) { return result, err } if err != nil {