Skip to content

Commit

Permalink
CA: wrap the provided errors in ToAutoscalerError() and AddPrefix(), …
Browse files Browse the repository at this point in the history
…implement Unwrap()

This allows using errors.Is() to check if an AutoscalerError wraps
a sentinel error (e.g. cloudprovider.ErrNotImplemented) when a prefix is
added to it.
  • Loading branch information
towca committed Nov 27, 2024
1 parent 30e57c9 commit bc16a6f
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1835,11 +1835,8 @@ func TestAuthErrorHandling(t *testing.T) {
Options: &defaultOptions,
}
results := runSimpleScaleUpTest(t, config)
expected := errors.NewAutoscalerError(
errors.AutoscalerErrorType("authError"),
"failed to increase node group size: auth error",
)
assert.Equal(t, expected, results.ScaleUpError)
assert.Equal(t, errors.AutoscalerErrorType("authError"), results.ScaleUpError.Type())
assert.Equal(t, "failed to increase node group size: auth error", results.ScaleUpError.Error())
assertLegacyRegistryEntry(t, "cluster_autoscaler_failed_scale_ups_total{reason=\"authError\"} 1")
}

Expand Down
34 changes: 24 additions & 10 deletions cluster-autoscaler/utils/errors/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,9 @@ type AutoscalerError interface {
}

type autoscalerErrorImpl struct {
errorType AutoscalerErrorType
msg string
errorType AutoscalerErrorType
wrappedErr error
msg string
}

const (
Expand Down Expand Up @@ -75,37 +76,50 @@ func NewAutoscalerError(errorType AutoscalerErrorType, msg string, args ...inter
}
}

// ToAutoscalerError converts an error to AutoscalerError with given type,
// ToAutoscalerError wraps an error to AutoscalerError with given type,
// unless it already is an AutoscalerError (in which case it's not modified).
// errors.Is() works correctly on the wrapped error.
func ToAutoscalerError(defaultType AutoscalerErrorType, err error) AutoscalerError {
if e, ok := err.(AutoscalerError); ok {
return e
}
if err == nil {
return nil
}
return NewAutoscalerError(defaultType, "%v", err)
return autoscalerErrorImpl{
errorType: defaultType,
wrappedErr: err,
}
}

// Error implements golang error interface
func (e autoscalerErrorImpl) Error() string {
return e.msg
msg := e.msg
if e.wrappedErr != nil {
msg = msg + e.wrappedErr.Error()
}
return msg
}

// Unwrap returns the error wrapped via ToAutoscalerError or AddPrefix, so that errors.Is() works
// correctly.
func (e autoscalerErrorImpl) Unwrap() error {
return e.wrappedErr
}

// Type returns the type of AutoscalerError
func (e autoscalerErrorImpl) Type() AutoscalerErrorType {
return e.errorType
}

// AddPrefix adds a prefix to error message.
// Returns the error it's called for convenient inline use.
// Example:
// AddPrefix returns an error wrapping this one, with the added prefix. errors.Is() works
// correctly on the wrapped error.
// Example usage:
// if err := DoSomething(myObject); err != nil {
//
// return err.AddPrefix("can't do something with %v: ", myObject)
//
// }
func (e autoscalerErrorImpl) AddPrefix(msg string, args ...interface{}) AutoscalerError {
e.msg = fmt.Sprintf(msg, args...) + e.msg
return e
return autoscalerErrorImpl{errorType: e.errorType, wrappedErr: e, msg: fmt.Sprintf(msg, args...)}
}

0 comments on commit bc16a6f

Please sign in to comment.