2017-02-10 23:11:55 +01:00
|
|
|
package consul
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"regexp"
|
2017-02-13 21:09:29 +01:00
|
|
|
"strconv"
|
2017-02-10 23:11:55 +01:00
|
|
|
"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
|
|
|
|
|
2017-02-13 21:09:29 +01:00
|
|
|
// validateIntMax is the maximum integer value to accept as input
|
|
|
|
type validateIntMax int
|
|
|
|
|
2017-02-10 23:11:55 +01:00
|
|
|
// 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)))
|
2017-02-13 21:09:29 +01:00
|
|
|
case validateIntMax:
|
|
|
|
fns = append(fns, validateIntMaxFactory(name, int(u)))
|
2017-02-10 23:11:55 +01:00
|
|
|
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 {
|
2017-02-16 23:08:15 +01:00
|
|
|
errors = append(errors, errwrap.Wrapf(fmt.Sprintf("Invalid %s specified (%q): {{err}}", name, v.(string)), err))
|
2017-02-10 23:11:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-13 21:09:29 +01:00
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-10 23:11:55 +01:00
|
|
|
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) {
|
2017-02-13 21:09:29 +01:00
|
|
|
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))
|
2017-02-10 23:11:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|