forked from projectcalico/calico
-
Notifications
You must be signed in to change notification settings - Fork 0
/
errors.go
310 lines (260 loc) · 7.72 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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
// Copyright (c) 2020 Tigera, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package errors
import (
"fmt"
"net/http"
networkingv1 "k8s.io/api/networking/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// Error indicating a problem connecting to the backend.
type ErrorDatastoreError struct {
Err error
Identifier interface{}
}
func (e ErrorDatastoreError) Error() string {
return e.Err.Error()
}
func (e ErrorDatastoreError) Status() metav1.Status {
if i, ok := e.Err.(apierrors.APIStatus); ok {
return i.Status()
}
// Just wrap in a status error.
return metav1.Status{
Status: metav1.StatusFailure,
Code: http.StatusBadRequest,
Reason: metav1.StatusReasonInvalid,
Message: fmt.Sprintf(e.Error()),
Details: &metav1.StatusDetails{
Name: fmt.Sprintf("%v", e.Identifier),
},
}
}
// Error indicating a resource does not exist. Used when attempting to delete or
// update a non-existent resource.
type ErrorResourceDoesNotExist struct {
Err error
Identifier interface{}
}
func (e ErrorResourceDoesNotExist) Error() string {
return fmt.Sprintf("resource does not exist: %v with error: %v", e.Identifier, e.Err)
}
// Error indicating an operation is not supported.
type ErrorOperationNotSupported struct {
Operation string
Identifier interface{}
Reason string
}
func (e ErrorOperationNotSupported) Error() string {
if e.Reason == "" {
return fmt.Sprintf("operation %s is not supported on %v", e.Operation, e.Identifier)
} else {
return fmt.Sprintf("operation %s is not supported on %v: %s", e.Operation, e.Identifier, e.Reason)
}
}
// Error indicating a resource already exists. Used when attempting to create a
// resource that already exists.
type ErrorResourceAlreadyExists struct {
Err error
Identifier interface{}
}
func (e ErrorResourceAlreadyExists) Error() string {
return fmt.Sprintf("resource already exists: %v", e.Identifier)
}
// Error indicating a problem connecting to the backend.
type ErrorConnectionUnauthorized struct {
Err error
}
func (e ErrorConnectionUnauthorized) Error() string {
return fmt.Sprintf("connection is unauthorized: %v", e.Err)
}
// Validation error containing the fields that are failed validation.
type ErrorValidation struct {
ErroredFields []ErroredField
}
type ErroredField struct {
Name string
Value interface{}
Reason string
}
func (e ErroredField) String() string {
var fieldString string
if e.Value == nil {
fieldString = e.Name
} else {
fieldString = fmt.Sprintf("%s = '%v'", e.Name, e.Value)
}
if e.Reason != "" {
fieldString = fmt.Sprintf("%s (%s)", fieldString, e.Reason)
}
return fieldString
}
func (e ErrorValidation) Error() string {
if len(e.ErroredFields) == 0 {
return "unknown validation error"
} else if len(e.ErroredFields) == 1 {
f := e.ErroredFields[0]
return fmt.Sprintf("error with field %s", f)
} else {
s := "error with the following fields:\n"
for _, f := range e.ErroredFields {
s = s + fmt.Sprintf("- %s\n", f)
}
return s
}
}
// Error indicating insufficient identifiers have been supplied on a resource
// management request (create, apply, update, get, delete).
type ErrorInsufficientIdentifiers struct {
Name string
}
func (e ErrorInsufficientIdentifiers) Error() string {
return fmt.Sprintf("insufficient identifiers, missing '%s'", e.Name)
}
// Error indicating an atomic update attempt that failed due to a update conflict.
type ErrorResourceUpdateConflict struct {
Err error
Identifier interface{}
}
func (e ErrorResourceUpdateConflict) Error() string {
return fmt.Sprintf("update conflict: %v", e.Identifier)
}
// Error indicating that the caller has attempted to release an IP address using
// outdated information.
type ErrorBadHandle struct {
Requested string
Expected string
}
func (e ErrorBadHandle) Error() string {
f := "the given handle (%s) does not match (%s) when attempting to release IP"
return fmt.Sprintf(f, e.Requested, e.Expected)
}
// Error indicating that the caller has attempted to release an IP address using
// outdated information.
type ErrorBadSequenceNumber struct {
Requested uint64
Expected uint64
}
func (e ErrorBadSequenceNumber) Error() string {
f := "the given sequence number (%d) does not match (%d) when attempting to release IP"
return fmt.Sprintf(f, e.Requested, e.Expected)
}
// Error indicating that the operation may have partially succeeded, then
// failed, without rolling back. A common example is when a function failed
// in an acceptable way after it successfully wrote some data to the datastore.
type ErrorPartialFailure struct {
Err error
}
func (e ErrorPartialFailure) Error() string {
return fmt.Sprintf("operation partially failed: %v", e.Err)
}
// UpdateErrorIdentifier modifies the supplied error to use the new resource
// identifier.
func UpdateErrorIdentifier(err error, id interface{}) error {
if err == nil {
return nil
}
switch e := err.(type) {
case ErrorDatastoreError:
e.Identifier = id
err = e
case ErrorResourceDoesNotExist:
e.Identifier = id
err = e
case ErrorOperationNotSupported:
e.Identifier = id
err = e
case ErrorResourceAlreadyExists:
e.Identifier = id
err = e
case ErrorResourceUpdateConflict:
e.Identifier = id
err = e
}
return err
}
// Error indicating the datastore has failed to parse an entry.
type ErrorParsingDatastoreEntry struct {
RawKey string
RawValue string
Err error
}
func (e ErrorParsingDatastoreEntry) Error() string {
return fmt.Sprintf("failed to parse datastore entry key=%s; value=%s: %v", e.RawKey, e.RawValue, e.Err)
}
type ErrorPolicyConversionRule struct {
EgressRule *networkingv1.NetworkPolicyEgressRule
IngressRule *networkingv1.NetworkPolicyIngressRule
Reason string
}
func (e ErrorPolicyConversionRule) String() string {
var fieldString string
switch {
case e.EgressRule != nil:
fieldString = fmt.Sprintf("%+v", e.EgressRule)
case e.IngressRule != nil:
fieldString = fmt.Sprintf("%+v", e.IngressRule)
default:
fieldString = "unknown rule"
}
if e.Reason != "" {
fieldString = fmt.Sprintf("%s (%s)", fieldString, e.Reason)
}
return fieldString
}
type ErrorPolicyConversion struct {
PolicyName string
Rules []ErrorPolicyConversionRule
}
func (e *ErrorPolicyConversion) BadEgressRule(rule *networkingv1.NetworkPolicyEgressRule, reason string) {
// Copy rule
badRule := *rule
e.Rules = append(e.Rules, ErrorPolicyConversionRule{
EgressRule: &badRule,
IngressRule: nil,
Reason: reason,
})
}
func (e *ErrorPolicyConversion) BadIngressRule(
rule *networkingv1.NetworkPolicyIngressRule, reason string) {
// Copy rule
badRule := *rule
e.Rules = append(e.Rules, ErrorPolicyConversionRule{
EgressRule: nil,
IngressRule: &badRule,
Reason: reason,
})
}
func (e ErrorPolicyConversion) Error() string {
s := fmt.Sprintf("policy: %s", e.PolicyName)
switch {
case len(e.Rules) == 0:
s += ": unknown policy conversion error"
case len(e.Rules) == 1:
f := e.Rules[0]
s += fmt.Sprintf(": error with rule %s", f)
default:
s += ": error with the following rules:\n"
for _, f := range e.Rules {
s += fmt.Sprintf("- %s\n", f)
}
}
return s
}
func (e ErrorPolicyConversion) GetError() error {
if len(e.Rules) == 0 {
return nil
}
return e
}