podman
611 строк · 16.1 Кб
1// Copyright 2015 go-swagger maintainers
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package errors
16
17import (
18"encoding/json"
19"fmt"
20"strings"
21)
22
23const (
24invalidType = "%s is an invalid type name"
25typeFail = "%s in %s must be of type %s"
26typeFailWithData = "%s in %s must be of type %s: %q"
27typeFailWithError = "%s in %s must be of type %s, because: %s"
28requiredFail = "%s in %s is required"
29readOnlyFail = "%s in %s is readOnly"
30tooLongMessage = "%s in %s should be at most %d chars long"
31tooShortMessage = "%s in %s should be at least %d chars long"
32patternFail = "%s in %s should match '%s'"
33enumFail = "%s in %s should be one of %v"
34multipleOfFail = "%s in %s should be a multiple of %v"
35maxIncFail = "%s in %s should be less than or equal to %v"
36maxExcFail = "%s in %s should be less than %v"
37minIncFail = "%s in %s should be greater than or equal to %v"
38minExcFail = "%s in %s should be greater than %v"
39uniqueFail = "%s in %s shouldn't contain duplicates"
40maxItemsFail = "%s in %s should have at most %d items"
41minItemsFail = "%s in %s should have at least %d items"
42typeFailNoIn = "%s must be of type %s"
43typeFailWithDataNoIn = "%s must be of type %s: %q"
44typeFailWithErrorNoIn = "%s must be of type %s, because: %s"
45requiredFailNoIn = "%s is required"
46readOnlyFailNoIn = "%s is readOnly"
47tooLongMessageNoIn = "%s should be at most %d chars long"
48tooShortMessageNoIn = "%s should be at least %d chars long"
49patternFailNoIn = "%s should match '%s'"
50enumFailNoIn = "%s should be one of %v"
51multipleOfFailNoIn = "%s should be a multiple of %v"
52maxIncFailNoIn = "%s should be less than or equal to %v"
53maxExcFailNoIn = "%s should be less than %v"
54minIncFailNoIn = "%s should be greater than or equal to %v"
55minExcFailNoIn = "%s should be greater than %v"
56uniqueFailNoIn = "%s shouldn't contain duplicates"
57maxItemsFailNoIn = "%s should have at most %d items"
58minItemsFailNoIn = "%s should have at least %d items"
59noAdditionalItems = "%s in %s can't have additional items"
60noAdditionalItemsNoIn = "%s can't have additional items"
61tooFewProperties = "%s in %s should have at least %d properties"
62tooFewPropertiesNoIn = "%s should have at least %d properties"
63tooManyProperties = "%s in %s should have at most %d properties"
64tooManyPropertiesNoIn = "%s should have at most %d properties"
65unallowedProperty = "%s.%s in %s is a forbidden property"
66unallowedPropertyNoIn = "%s.%s is a forbidden property"
67failedAllPatternProps = "%s.%s in %s failed all pattern properties"
68failedAllPatternPropsNoIn = "%s.%s failed all pattern properties"
69multipleOfMustBePositive = "factor MultipleOf declared for %s must be positive: %v"
70)
71
72// All code responses can be used to differentiate errors for different handling
73// by the consuming program
74const (
75// CompositeErrorCode remains 422 for backwards-compatibility
76// and to separate it from validation errors with cause
77CompositeErrorCode = 422
78// InvalidTypeCode is used for any subclass of invalid types
79InvalidTypeCode = 600 + iota
80RequiredFailCode
81TooLongFailCode
82TooShortFailCode
83PatternFailCode
84EnumFailCode
85MultipleOfFailCode
86MaxFailCode
87MinFailCode
88UniqueFailCode
89MaxItemsFailCode
90MinItemsFailCode
91NoAdditionalItemsCode
92TooFewPropertiesCode
93TooManyPropertiesCode
94UnallowedPropertyCode
95FailedAllPatternPropsCode
96MultipleOfMustBePositiveCode
97ReadOnlyFailCode
98)
99
100// CompositeError is an error that groups several errors together
101type CompositeError struct {
102Errors []error
103code int32
104message string
105}
106
107// Code for this error
108func (c *CompositeError) Code() int32 {
109return c.code
110}
111
112func (c *CompositeError) Error() string {
113if len(c.Errors) > 0 {
114msgs := []string{c.message + ":"}
115for _, e := range c.Errors {
116msgs = append(msgs, e.Error())
117}
118return strings.Join(msgs, "\n")
119}
120return c.message
121}
122
123// MarshalJSON implements the JSON encoding interface
124func (c CompositeError) MarshalJSON() ([]byte, error) {
125return json.Marshal(map[string]interface{}{
126"code": c.code,
127"message": c.message,
128"errors": c.Errors,
129})
130}
131
132// CompositeValidationError an error to wrap a bunch of other errors
133func CompositeValidationError(errors ...error) *CompositeError {
134return &CompositeError{
135code: CompositeErrorCode,
136Errors: append([]error{}, errors...),
137message: "validation failure list",
138}
139}
140
141// ValidateName recursively sets the name for all validations or updates them for nested properties
142func (c *CompositeError) ValidateName(name string) *CompositeError {
143for i, e := range c.Errors {
144if ve, ok := e.(*Validation); ok {
145c.Errors[i] = ve.ValidateName(name)
146} else if ce, ok := e.(*CompositeError); ok {
147c.Errors[i] = ce.ValidateName(name)
148}
149}
150
151return c
152}
153
154// FailedAllPatternProperties an error for when the property doesn't match a pattern
155func FailedAllPatternProperties(name, in, key string) *Validation {
156msg := fmt.Sprintf(failedAllPatternProps, name, key, in)
157if in == "" {
158msg = fmt.Sprintf(failedAllPatternPropsNoIn, name, key)
159}
160return &Validation{
161code: FailedAllPatternPropsCode,
162Name: name,
163In: in,
164Value: key,
165message: msg,
166}
167}
168
169// PropertyNotAllowed an error for when the property doesn't match a pattern
170func PropertyNotAllowed(name, in, key string) *Validation {
171msg := fmt.Sprintf(unallowedProperty, name, key, in)
172if in == "" {
173msg = fmt.Sprintf(unallowedPropertyNoIn, name, key)
174}
175return &Validation{
176code: UnallowedPropertyCode,
177Name: name,
178In: in,
179Value: key,
180message: msg,
181}
182}
183
184// TooFewProperties an error for an object with too few properties
185func TooFewProperties(name, in string, n int64) *Validation {
186msg := fmt.Sprintf(tooFewProperties, name, in, n)
187if in == "" {
188msg = fmt.Sprintf(tooFewPropertiesNoIn, name, n)
189}
190return &Validation{
191code: TooFewPropertiesCode,
192Name: name,
193In: in,
194Value: n,
195message: msg,
196}
197}
198
199// TooManyProperties an error for an object with too many properties
200func TooManyProperties(name, in string, n int64) *Validation {
201msg := fmt.Sprintf(tooManyProperties, name, in, n)
202if in == "" {
203msg = fmt.Sprintf(tooManyPropertiesNoIn, name, n)
204}
205return &Validation{
206code: TooManyPropertiesCode,
207Name: name,
208In: in,
209Value: n,
210message: msg,
211}
212}
213
214// AdditionalItemsNotAllowed an error for invalid additional items
215func AdditionalItemsNotAllowed(name, in string) *Validation {
216msg := fmt.Sprintf(noAdditionalItems, name, in)
217if in == "" {
218msg = fmt.Sprintf(noAdditionalItemsNoIn, name)
219}
220return &Validation{
221code: NoAdditionalItemsCode,
222Name: name,
223In: in,
224message: msg,
225}
226}
227
228// InvalidCollectionFormat another flavor of invalid type error
229func InvalidCollectionFormat(name, in, format string) *Validation {
230return &Validation{
231code: InvalidTypeCode,
232Name: name,
233In: in,
234Value: format,
235message: fmt.Sprintf("the collection format %q is not supported for the %s param %q", format, in, name),
236}
237}
238
239// InvalidTypeName an error for when the type is invalid
240func InvalidTypeName(typeName string) *Validation {
241return &Validation{
242code: InvalidTypeCode,
243Value: typeName,
244message: fmt.Sprintf(invalidType, typeName),
245}
246}
247
248// InvalidType creates an error for when the type is invalid
249func InvalidType(name, in, typeName string, value interface{}) *Validation {
250var message string
251
252if in != "" {
253switch value.(type) {
254case string:
255message = fmt.Sprintf(typeFailWithData, name, in, typeName, value)
256case error:
257message = fmt.Sprintf(typeFailWithError, name, in, typeName, value)
258default:
259message = fmt.Sprintf(typeFail, name, in, typeName)
260}
261} else {
262switch value.(type) {
263case string:
264message = fmt.Sprintf(typeFailWithDataNoIn, name, typeName, value)
265case error:
266message = fmt.Sprintf(typeFailWithErrorNoIn, name, typeName, value)
267default:
268message = fmt.Sprintf(typeFailNoIn, name, typeName)
269}
270}
271
272return &Validation{
273code: InvalidTypeCode,
274Name: name,
275In: in,
276Value: value,
277message: message,
278}
279
280}
281
282// DuplicateItems error for when an array contains duplicates
283func DuplicateItems(name, in string) *Validation {
284msg := fmt.Sprintf(uniqueFail, name, in)
285if in == "" {
286msg = fmt.Sprintf(uniqueFailNoIn, name)
287}
288return &Validation{
289code: UniqueFailCode,
290Name: name,
291In: in,
292message: msg,
293}
294}
295
296// TooManyItems error for when an array contains too many items
297func TooManyItems(name, in string, max int64, value interface{}) *Validation {
298msg := fmt.Sprintf(maxItemsFail, name, in, max)
299if in == "" {
300msg = fmt.Sprintf(maxItemsFailNoIn, name, max)
301}
302
303return &Validation{
304code: MaxItemsFailCode,
305Name: name,
306In: in,
307Value: value,
308message: msg,
309}
310}
311
312// TooFewItems error for when an array contains too few items
313func TooFewItems(name, in string, min int64, value interface{}) *Validation {
314msg := fmt.Sprintf(minItemsFail, name, in, min)
315if in == "" {
316msg = fmt.Sprintf(minItemsFailNoIn, name, min)
317}
318return &Validation{
319code: MinItemsFailCode,
320Name: name,
321In: in,
322Value: value,
323message: msg,
324}
325}
326
327// ExceedsMaximumInt error for when maximum validation fails
328func ExceedsMaximumInt(name, in string, max int64, exclusive bool, value interface{}) *Validation {
329var message string
330if in == "" {
331m := maxIncFailNoIn
332if exclusive {
333m = maxExcFailNoIn
334}
335message = fmt.Sprintf(m, name, max)
336} else {
337m := maxIncFail
338if exclusive {
339m = maxExcFail
340}
341message = fmt.Sprintf(m, name, in, max)
342}
343return &Validation{
344code: MaxFailCode,
345Name: name,
346In: in,
347Value: value,
348message: message,
349}
350}
351
352// ExceedsMaximumUint error for when maximum validation fails
353func ExceedsMaximumUint(name, in string, max uint64, exclusive bool, value interface{}) *Validation {
354var message string
355if in == "" {
356m := maxIncFailNoIn
357if exclusive {
358m = maxExcFailNoIn
359}
360message = fmt.Sprintf(m, name, max)
361} else {
362m := maxIncFail
363if exclusive {
364m = maxExcFail
365}
366message = fmt.Sprintf(m, name, in, max)
367}
368return &Validation{
369code: MaxFailCode,
370Name: name,
371In: in,
372Value: value,
373message: message,
374}
375}
376
377// ExceedsMaximum error for when maximum validation fails
378func ExceedsMaximum(name, in string, max float64, exclusive bool, value interface{}) *Validation {
379var message string
380if in == "" {
381m := maxIncFailNoIn
382if exclusive {
383m = maxExcFailNoIn
384}
385message = fmt.Sprintf(m, name, max)
386} else {
387m := maxIncFail
388if exclusive {
389m = maxExcFail
390}
391message = fmt.Sprintf(m, name, in, max)
392}
393return &Validation{
394code: MaxFailCode,
395Name: name,
396In: in,
397Value: value,
398message: message,
399}
400}
401
402// ExceedsMinimumInt error for when minimum validation fails
403func ExceedsMinimumInt(name, in string, min int64, exclusive bool, value interface{}) *Validation {
404var message string
405if in == "" {
406m := minIncFailNoIn
407if exclusive {
408m = minExcFailNoIn
409}
410message = fmt.Sprintf(m, name, min)
411} else {
412m := minIncFail
413if exclusive {
414m = minExcFail
415}
416message = fmt.Sprintf(m, name, in, min)
417}
418return &Validation{
419code: MinFailCode,
420Name: name,
421In: in,
422Value: value,
423message: message,
424}
425}
426
427// ExceedsMinimumUint error for when minimum validation fails
428func ExceedsMinimumUint(name, in string, min uint64, exclusive bool, value interface{}) *Validation {
429var message string
430if in == "" {
431m := minIncFailNoIn
432if exclusive {
433m = minExcFailNoIn
434}
435message = fmt.Sprintf(m, name, min)
436} else {
437m := minIncFail
438if exclusive {
439m = minExcFail
440}
441message = fmt.Sprintf(m, name, in, min)
442}
443return &Validation{
444code: MinFailCode,
445Name: name,
446In: in,
447Value: value,
448message: message,
449}
450}
451
452// ExceedsMinimum error for when minimum validation fails
453func ExceedsMinimum(name, in string, min float64, exclusive bool, value interface{}) *Validation {
454var message string
455if in == "" {
456m := minIncFailNoIn
457if exclusive {
458m = minExcFailNoIn
459}
460message = fmt.Sprintf(m, name, min)
461} else {
462m := minIncFail
463if exclusive {
464m = minExcFail
465}
466message = fmt.Sprintf(m, name, in, min)
467}
468return &Validation{
469code: MinFailCode,
470Name: name,
471In: in,
472Value: value,
473message: message,
474}
475}
476
477// NotMultipleOf error for when multiple of validation fails
478func NotMultipleOf(name, in string, multiple, value interface{}) *Validation {
479var msg string
480if in == "" {
481msg = fmt.Sprintf(multipleOfFailNoIn, name, multiple)
482} else {
483msg = fmt.Sprintf(multipleOfFail, name, in, multiple)
484}
485return &Validation{
486code: MultipleOfFailCode,
487Name: name,
488In: in,
489Value: value,
490message: msg,
491}
492}
493
494// EnumFail error for when an enum validation fails
495func EnumFail(name, in string, value interface{}, values []interface{}) *Validation {
496var msg string
497if in == "" {
498msg = fmt.Sprintf(enumFailNoIn, name, values)
499} else {
500msg = fmt.Sprintf(enumFail, name, in, values)
501}
502
503return &Validation{
504code: EnumFailCode,
505Name: name,
506In: in,
507Value: value,
508Values: values,
509message: msg,
510}
511}
512
513// Required error for when a value is missing
514func Required(name, in string, value interface{}) *Validation {
515var msg string
516if in == "" {
517msg = fmt.Sprintf(requiredFailNoIn, name)
518} else {
519msg = fmt.Sprintf(requiredFail, name, in)
520}
521return &Validation{
522code: RequiredFailCode,
523Name: name,
524In: in,
525Value: value,
526message: msg,
527}
528}
529
530// ReadOnly error for when a value is present in request
531func ReadOnly(name, in string, value interface{}) *Validation {
532var msg string
533if in == "" {
534msg = fmt.Sprintf(readOnlyFailNoIn, name)
535} else {
536msg = fmt.Sprintf(readOnlyFail, name, in)
537}
538return &Validation{
539code: ReadOnlyFailCode,
540Name: name,
541In: in,
542Value: value,
543message: msg,
544}
545}
546
547// TooLong error for when a string is too long
548func TooLong(name, in string, max int64, value interface{}) *Validation {
549var msg string
550if in == "" {
551msg = fmt.Sprintf(tooLongMessageNoIn, name, max)
552} else {
553msg = fmt.Sprintf(tooLongMessage, name, in, max)
554}
555return &Validation{
556code: TooLongFailCode,
557Name: name,
558In: in,
559Value: value,
560message: msg,
561}
562}
563
564// TooShort error for when a string is too short
565func TooShort(name, in string, min int64, value interface{}) *Validation {
566var msg string
567if in == "" {
568msg = fmt.Sprintf(tooShortMessageNoIn, name, min)
569} else {
570msg = fmt.Sprintf(tooShortMessage, name, in, min)
571}
572
573return &Validation{
574code: TooShortFailCode,
575Name: name,
576In: in,
577Value: value,
578message: msg,
579}
580}
581
582// FailedPattern error for when a string fails a regex pattern match
583// the pattern that is returned is the ECMA syntax version of the pattern not the golang version.
584func FailedPattern(name, in, pattern string, value interface{}) *Validation {
585var msg string
586if in == "" {
587msg = fmt.Sprintf(patternFailNoIn, name, pattern)
588} else {
589msg = fmt.Sprintf(patternFail, name, in, pattern)
590}
591
592return &Validation{
593code: PatternFailCode,
594Name: name,
595In: in,
596Value: value,
597message: msg,
598}
599}
600
601// MultipleOfMustBePositive error for when a
602// multipleOf factor is negative
603func MultipleOfMustBePositive(name, in string, factor interface{}) *Validation {
604return &Validation{
605code: MultipleOfMustBePositiveCode,
606Name: name,
607In: in,
608Value: factor,
609message: fmt.Sprintf(multipleOfMustBePositive, name, factor),
610}
611}
612