/
validators.go
146 lines (123 loc) · 4.73 KB
/
validators.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
package consul
import (
"fmt"
"regexp"
"strconv"
"time"
"github.com/hashicorp/errwrap"
)
// An array of inputs used as typed arguments and converted from their type into
// function objects that are dynamically constructed and executed.
type validatorInputs []interface{}
// validateDurationMin is the minimum duration to accept as input
type validateDurationMin string
// validateIntMax is the maximum integer value to accept as input
type validateIntMax int
// validateIntMin is the minimum integer value to accept as input
type validateIntMin int
// validateRegexp is a regexp pattern to use to validate schema input.
type validateRegexp string
// makeValidateionFunc takes the name of the attribute and a list of typed
// validator inputs in order to create a validation closure that calls each
// validator in serial until either a warning or error is returned from the
// first validation function.
func makeValidationFunc(name string, validators []interface{}) func(v interface{}, key string) (warnings []string, errors []error) {
if len(validators) == 0 {
return nil
}
fns := make([]func(v interface{}, key string) (warnings []string, errors []error), 0, len(validators))
for _, v := range validators {
switch u := v.(type) {
case validateDurationMin:
fns = append(fns, validateDurationMinFactory(name, string(u)))
case validateIntMax:
fns = append(fns, validateIntMaxFactory(name, int(u)))
case validateIntMin:
fns = append(fns, validateIntMinFactory(name, int(u)))
case validateRegexp:
fns = append(fns, validateRegexpFactory(name, string(u)))
}
}
return func(v interface{}, key string) (warnings []string, errors []error) {
for _, fn := range fns {
warnings, errors = fn(v, key)
if len(warnings) > 0 || len(errors) > 0 {
break
}
}
return warnings, errors
}
}
func validateDurationMinFactory(name, minDuration string) func(v interface{}, key string) (warnings []string, errors []error) {
dMin, err := time.ParseDuration(minDuration)
if err != nil {
return func(interface{}, string) (warnings []string, errors []error) {
return nil, []error{
errwrap.Wrapf(fmt.Sprintf("PROVIDER BUG: duration %q not valid: {{err}}", minDuration), err),
}
}
}
return func(v interface{}, key string) (warnings []string, errors []error) {
d, err := time.ParseDuration(v.(string))
if err != nil {
errors = append(errors, errwrap.Wrapf(fmt.Sprintf("Invalid %s specified (%q): {{err}}", name, v.(string)), err))
}
if d < dMin {
errors = append(errors, fmt.Errorf("Invalid %s specified: duration %q less than the required minimum %s", name, v.(string), dMin))
}
return warnings, errors
}
}
func validateIntMaxFactory(name string, max int) func(v interface{}, key string) (warnings []string, errors []error) {
return func(v interface{}, key string) (warnings []string, errors []error) {
switch u := v.(type) {
case string:
i, err := strconv.ParseInt(u, 10, 64)
if err != nil {
errors = append(errors, errwrap.Wrapf(fmt.Sprintf("unable to convert %q to an integer: {{err}}", u), err))
break
}
if i > int64(max) {
errors = append(errors, fmt.Errorf("Invalid %s specified: %d more than the required maximum %d", name, v.(int), max))
}
case int:
if u > max {
errors = append(errors, fmt.Errorf("Invalid %s specified: %d more than the required maximum %d", name, v.(int), max))
}
default:
errors = append(errors, fmt.Errorf("Unsupported type in int max validation: %T", v))
}
return warnings, errors
}
}
func validateIntMinFactory(name string, min int) func(v interface{}, key string) (warnings []string, errors []error) {
return func(v interface{}, key string) (warnings []string, errors []error) {
switch u := v.(type) {
case string:
i, err := strconv.ParseInt(u, 10, 64)
if err != nil {
errors = append(errors, errwrap.Wrapf(fmt.Sprintf("unable to convert %q to an integer: {{err}}", u), err))
break
}
if i < int64(min) {
errors = append(errors, fmt.Errorf("Invalid %s specified: %d less than the required minimum %d", name, v.(int), min))
}
case int:
if u < min {
errors = append(errors, fmt.Errorf("Invalid %s specified: %d less than the required minimum %d", name, v.(int), min))
}
default:
errors = append(errors, fmt.Errorf("Unsupported type in int min validation: %T", v))
}
return warnings, errors
}
}
func validateRegexpFactory(name string, reString string) func(v interface{}, key string) (warnings []string, errors []error) {
re := regexp.MustCompile(reString)
return func(v interface{}, key string) (warnings []string, errors []error) {
if !re.MatchString(v.(string)) {
errors = append(errors, fmt.Errorf("Invalid %s specified (%q): regexp failed to match string", name, v.(string)))
}
return warnings, errors
}
}