forked from openshift/compliance-operator
/
errors.go
125 lines (107 loc) · 3.43 KB
/
errors.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package common
import (
"fmt"
"github.com/go-logr/logr"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
)
// ErrorHandler defines a function that handles errors
// It can be used in a non retriable or a retriable error.
type ErrorHandler func() (reconcile.Result, error)
// NonRetriableCtrlError wraps errors with the addition of having
// the information for the error being non-retriable
type NonRetriableCtrlError struct {
err error
canRetry bool
customHandler ErrorHandler
}
// Timeout Error
type TimeoutError struct {
err error
}
func (t TimeoutError) Error() string {
return t.err.Error()
}
func (cerr NonRetriableCtrlError) Error() string {
return cerr.err.Error()
}
// blank assignment to verify that RetriableCtrlError implements error
var _ error = &NonRetriableCtrlError{}
// IsRetriable exposes if the error is retriable or not
func (cerr NonRetriableCtrlError) IsRetriable() bool {
return cerr.canRetry
}
// HasCustomHandler checks whether an error has a custom handler
func (cerr NonRetriableCtrlError) HasCustomHandler() bool {
return cerr.customHandler != nil
}
// WrapNonRetriableCtrlError wraps an error with the RetriableCtrlError interface
func WrapNonRetriableCtrlError(err error) *NonRetriableCtrlError {
return &NonRetriableCtrlError{
canRetry: false,
err: err,
}
}
// NewNonRetriableCtrlError creates an error with the RetriableCtrlError interface
func NewNonRetriableCtrlError(errorFmt string, args ...interface{}) *NonRetriableCtrlError {
return &NonRetriableCtrlError{
canRetry: false,
err: fmt.Errorf(errorFmt, args...),
}
}
// NewTimeoutError creates an error with the RetriableCtrlError interface
func NewTimeoutError(errorFmt string, args ...interface{}) *TimeoutError {
return &TimeoutError{
err: fmt.Errorf(errorFmt, args...),
}
}
// NewRetriableCtrlErrorWithCustomHandler creates an error with the RetriableCtrlError interface
// This error is retriable has a custom handler
func NewRetriableCtrlErrorWithCustomHandler(customHandler ErrorHandler, errorFmt string, args ...interface{}) *NonRetriableCtrlError {
return &NonRetriableCtrlError{
canRetry: true,
customHandler: customHandler,
err: fmt.Errorf(errorFmt, args...),
}
}
// IsRetriable returns whether the error is retriable or not using the
// NonRetriableCtrlError interface
func IsRetriable(err error) bool {
ccErr, ok := err.(*NonRetriableCtrlError)
if ok {
return ccErr.IsRetriable()
}
return true
}
// HasCustomHandler returns whether the error has a custom handler
// or not
func HasCustomHandler(err error) bool {
ccErr, ok := err.(*NonRetriableCtrlError)
if ok {
return ccErr.HasCustomHandler()
}
return false
}
// CallCustomHandler calls the custom handler for an error if it has one
func CallCustomHandler(err error) (reconcile.Result, error) {
ccErr, ok := err.(*NonRetriableCtrlError)
if ok {
return ccErr.customHandler()
}
return reconcile.Result{}, nil
}
// ReturnWithRetriableError will check if the error is retriable we return it.
// If it's not retriable, we return nil so the reconciler doesn't keep looping.
func ReturnWithRetriableError(log logr.Logger, err error) (reconcile.Result, error) {
if IsRetriable(err) {
if HasCustomHandler(err) {
return CallCustomHandler(err)
}
log.Error(err, "Retriable error")
return reconcile.Result{}, err
}
if HasCustomHandler(err) {
return CallCustomHandler(err)
}
log.Error(err, "Non-retriable error")
return reconcile.Result{}, nil
}