Remove BPA from Makefile
[icn.git] / cmd / bpa-operator / vendor / k8s.io / apimachinery / pkg / util / validation / field / errors.go
1 /*
2 Copyright 2014 The Kubernetes Authors.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8     http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17 package field
18
19 import (
20         "fmt"
21         "reflect"
22         "strconv"
23         "strings"
24
25         utilerrors "k8s.io/apimachinery/pkg/util/errors"
26         "k8s.io/apimachinery/pkg/util/sets"
27 )
28
29 // Error is an implementation of the 'error' interface, which represents a
30 // field-level validation error.
31 type Error struct {
32         Type     ErrorType
33         Field    string
34         BadValue interface{}
35         Detail   string
36 }
37
38 var _ error = &Error{}
39
40 // Error implements the error interface.
41 func (v *Error) Error() string {
42         return fmt.Sprintf("%s: %s", v.Field, v.ErrorBody())
43 }
44
45 // ErrorBody returns the error message without the field name.  This is useful
46 // for building nice-looking higher-level error reporting.
47 func (v *Error) ErrorBody() string {
48         var s string
49         switch v.Type {
50         case ErrorTypeRequired, ErrorTypeForbidden, ErrorTypeTooLong, ErrorTypeInternal:
51                 s = v.Type.String()
52         default:
53                 value := v.BadValue
54                 valueType := reflect.TypeOf(value)
55                 if value == nil || valueType == nil {
56                         value = "null"
57                 } else if valueType.Kind() == reflect.Ptr {
58                         if reflectValue := reflect.ValueOf(value); reflectValue.IsNil() {
59                                 value = "null"
60                         } else {
61                                 value = reflectValue.Elem().Interface()
62                         }
63                 }
64                 switch t := value.(type) {
65                 case int64, int32, float64, float32, bool:
66                         // use simple printer for simple types
67                         s = fmt.Sprintf("%s: %v", v.Type, value)
68                 case string:
69                         s = fmt.Sprintf("%s: %q", v.Type, t)
70                 case fmt.Stringer:
71                         // anything that defines String() is better than raw struct
72                         s = fmt.Sprintf("%s: %s", v.Type, t.String())
73                 default:
74                         // fallback to raw struct
75                         // TODO: internal types have panic guards against json.Marshalling to prevent
76                         // accidental use of internal types in external serialized form.  For now, use
77                         // %#v, although it would be better to show a more expressive output in the future
78                         s = fmt.Sprintf("%s: %#v", v.Type, value)
79                 }
80         }
81         if len(v.Detail) != 0 {
82                 s += fmt.Sprintf(": %s", v.Detail)
83         }
84         return s
85 }
86
87 // ErrorType is a machine readable value providing more detail about why
88 // a field is invalid.  These values are expected to match 1-1 with
89 // CauseType in api/types.go.
90 type ErrorType string
91
92 // TODO: These values are duplicated in api/types.go, but there's a circular dep.  Fix it.
93 const (
94         // ErrorTypeNotFound is used to report failure to find a requested value
95         // (e.g. looking up an ID).  See NotFound().
96         ErrorTypeNotFound ErrorType = "FieldValueNotFound"
97         // ErrorTypeRequired is used to report required values that are not
98         // provided (e.g. empty strings, null values, or empty arrays).  See
99         // Required().
100         ErrorTypeRequired ErrorType = "FieldValueRequired"
101         // ErrorTypeDuplicate is used to report collisions of values that must be
102         // unique (e.g. unique IDs).  See Duplicate().
103         ErrorTypeDuplicate ErrorType = "FieldValueDuplicate"
104         // ErrorTypeInvalid is used to report malformed values (e.g. failed regex
105         // match, too long, out of bounds).  See Invalid().
106         ErrorTypeInvalid ErrorType = "FieldValueInvalid"
107         // ErrorTypeNotSupported is used to report unknown values for enumerated
108         // fields (e.g. a list of valid values).  See NotSupported().
109         ErrorTypeNotSupported ErrorType = "FieldValueNotSupported"
110         // ErrorTypeForbidden is used to report valid (as per formatting rules)
111         // values which would be accepted under some conditions, but which are not
112         // permitted by the current conditions (such as security policy).  See
113         // Forbidden().
114         ErrorTypeForbidden ErrorType = "FieldValueForbidden"
115         // ErrorTypeTooLong is used to report that the given value is too long.
116         // This is similar to ErrorTypeInvalid, but the error will not include the
117         // too-long value.  See TooLong().
118         ErrorTypeTooLong ErrorType = "FieldValueTooLong"
119         // ErrorTypeInternal is used to report other errors that are not related
120         // to user input.  See InternalError().
121         ErrorTypeInternal ErrorType = "InternalError"
122 )
123
124 // String converts a ErrorType into its corresponding canonical error message.
125 func (t ErrorType) String() string {
126         switch t {
127         case ErrorTypeNotFound:
128                 return "Not found"
129         case ErrorTypeRequired:
130                 return "Required value"
131         case ErrorTypeDuplicate:
132                 return "Duplicate value"
133         case ErrorTypeInvalid:
134                 return "Invalid value"
135         case ErrorTypeNotSupported:
136                 return "Unsupported value"
137         case ErrorTypeForbidden:
138                 return "Forbidden"
139         case ErrorTypeTooLong:
140                 return "Too long"
141         case ErrorTypeInternal:
142                 return "Internal error"
143         default:
144                 panic(fmt.Sprintf("unrecognized validation error: %q", string(t)))
145         }
146 }
147
148 // NotFound returns a *Error indicating "value not found".  This is
149 // used to report failure to find a requested value (e.g. looking up an ID).
150 func NotFound(field *Path, value interface{}) *Error {
151         return &Error{ErrorTypeNotFound, field.String(), value, ""}
152 }
153
154 // Required returns a *Error indicating "value required".  This is used
155 // to report required values that are not provided (e.g. empty strings, null
156 // values, or empty arrays).
157 func Required(field *Path, detail string) *Error {
158         return &Error{ErrorTypeRequired, field.String(), "", detail}
159 }
160
161 // Duplicate returns a *Error indicating "duplicate value".  This is
162 // used to report collisions of values that must be unique (e.g. names or IDs).
163 func Duplicate(field *Path, value interface{}) *Error {
164         return &Error{ErrorTypeDuplicate, field.String(), value, ""}
165 }
166
167 // Invalid returns a *Error indicating "invalid value".  This is used
168 // to report malformed values (e.g. failed regex match, too long, out of bounds).
169 func Invalid(field *Path, value interface{}, detail string) *Error {
170         return &Error{ErrorTypeInvalid, field.String(), value, detail}
171 }
172
173 // NotSupported returns a *Error indicating "unsupported value".
174 // This is used to report unknown values for enumerated fields (e.g. a list of
175 // valid values).
176 func NotSupported(field *Path, value interface{}, validValues []string) *Error {
177         detail := ""
178         if validValues != nil && len(validValues) > 0 {
179                 quotedValues := make([]string, len(validValues))
180                 for i, v := range validValues {
181                         quotedValues[i] = strconv.Quote(v)
182                 }
183                 detail = "supported values: " + strings.Join(quotedValues, ", ")
184         }
185         return &Error{ErrorTypeNotSupported, field.String(), value, detail}
186 }
187
188 // Forbidden returns a *Error indicating "forbidden".  This is used to
189 // report valid (as per formatting rules) values which would be accepted under
190 // some conditions, but which are not permitted by current conditions (e.g.
191 // security policy).
192 func Forbidden(field *Path, detail string) *Error {
193         return &Error{ErrorTypeForbidden, field.String(), "", detail}
194 }
195
196 // TooLong returns a *Error indicating "too long".  This is used to
197 // report that the given value is too long.  This is similar to
198 // Invalid, but the returned error will not include the too-long
199 // value.
200 func TooLong(field *Path, value interface{}, maxLength int) *Error {
201         return &Error{ErrorTypeTooLong, field.String(), value, fmt.Sprintf("must have at most %d characters", maxLength)}
202 }
203
204 // InternalError returns a *Error indicating "internal error".  This is used
205 // to signal that an error was found that was not directly related to user
206 // input.  The err argument must be non-nil.
207 func InternalError(field *Path, err error) *Error {
208         return &Error{ErrorTypeInternal, field.String(), nil, err.Error()}
209 }
210
211 // ErrorList holds a set of Errors.  It is plausible that we might one day have
212 // non-field errors in this same umbrella package, but for now we don't, so
213 // we can keep it simple and leave ErrorList here.
214 type ErrorList []*Error
215
216 // NewErrorTypeMatcher returns an errors.Matcher that returns true
217 // if the provided error is a Error and has the provided ErrorType.
218 func NewErrorTypeMatcher(t ErrorType) utilerrors.Matcher {
219         return func(err error) bool {
220                 if e, ok := err.(*Error); ok {
221                         return e.Type == t
222                 }
223                 return false
224         }
225 }
226
227 // ToAggregate converts the ErrorList into an errors.Aggregate.
228 func (list ErrorList) ToAggregate() utilerrors.Aggregate {
229         errs := make([]error, 0, len(list))
230         errorMsgs := sets.NewString()
231         for _, err := range list {
232                 msg := fmt.Sprintf("%v", err)
233                 if errorMsgs.Has(msg) {
234                         continue
235                 }
236                 errorMsgs.Insert(msg)
237                 errs = append(errs, err)
238         }
239         return utilerrors.NewAggregate(errs)
240 }
241
242 func fromAggregate(agg utilerrors.Aggregate) ErrorList {
243         errs := agg.Errors()
244         list := make(ErrorList, len(errs))
245         for i := range errs {
246                 list[i] = errs[i].(*Error)
247         }
248         return list
249 }
250
251 // Filter removes items from the ErrorList that match the provided fns.
252 func (list ErrorList) Filter(fns ...utilerrors.Matcher) ErrorList {
253         err := utilerrors.FilterOut(list.ToAggregate(), fns...)
254         if err == nil {
255                 return nil
256         }
257         // FilterOut takes an Aggregate and returns an Aggregate
258         return fromAggregate(err.(utilerrors.Aggregate))
259 }