github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/builtin/providers/consul/validators.go (about)

     1  package consul
     2  
     3  import (
     4  	"fmt"
     5  	"regexp"
     6  	"strconv"
     7  	"time"
     8  
     9  	"github.com/hashicorp/errwrap"
    10  )
    11  
    12  // An array of inputs used as typed arguments and converted from their type into
    13  // function objects that are dynamically constructed and executed.
    14  type validatorInputs []interface{}
    15  
    16  // validateDurationMin is the minimum duration to accept as input
    17  type validateDurationMin string
    18  
    19  // validateIntMax is the maximum integer value to accept as input
    20  type validateIntMax int
    21  
    22  // validateIntMin is the minimum integer value to accept as input
    23  type validateIntMin int
    24  
    25  // validateRegexp is a regexp pattern to use to validate schema input.
    26  type validateRegexp string
    27  
    28  // makeValidateionFunc takes the name of the attribute and a list of typed
    29  // validator inputs in order to create a validation closure that calls each
    30  // validator in serial until either a warning or error is returned from the
    31  // first validation function.
    32  func makeValidationFunc(name string, validators []interface{}) func(v interface{}, key string) (warnings []string, errors []error) {
    33  	if len(validators) == 0 {
    34  		return nil
    35  	}
    36  
    37  	fns := make([]func(v interface{}, key string) (warnings []string, errors []error), 0, len(validators))
    38  	for _, v := range validators {
    39  		switch u := v.(type) {
    40  		case validateDurationMin:
    41  			fns = append(fns, validateDurationMinFactory(name, string(u)))
    42  		case validateIntMax:
    43  			fns = append(fns, validateIntMaxFactory(name, int(u)))
    44  		case validateIntMin:
    45  			fns = append(fns, validateIntMinFactory(name, int(u)))
    46  		case validateRegexp:
    47  			fns = append(fns, validateRegexpFactory(name, string(u)))
    48  		}
    49  	}
    50  
    51  	return func(v interface{}, key string) (warnings []string, errors []error) {
    52  		for _, fn := range fns {
    53  			warnings, errors = fn(v, key)
    54  			if len(warnings) > 0 || len(errors) > 0 {
    55  				break
    56  			}
    57  		}
    58  		return warnings, errors
    59  	}
    60  }
    61  
    62  func validateDurationMinFactory(name, minDuration string) func(v interface{}, key string) (warnings []string, errors []error) {
    63  	dMin, err := time.ParseDuration(minDuration)
    64  	if err != nil {
    65  		return func(interface{}, string) (warnings []string, errors []error) {
    66  			return nil, []error{
    67  				errwrap.Wrapf(fmt.Sprintf("PROVIDER BUG: duration %q not valid: {{err}}", minDuration), err),
    68  			}
    69  		}
    70  	}
    71  
    72  	return func(v interface{}, key string) (warnings []string, errors []error) {
    73  		d, err := time.ParseDuration(v.(string))
    74  		if err != nil {
    75  			errors = append(errors, errwrap.Wrapf(fmt.Sprintf("Invalid %s specified (%q): {{err}}", name, v.(string)), err))
    76  		}
    77  
    78  		if d < dMin {
    79  			errors = append(errors, fmt.Errorf("Invalid %s specified: duration %q less than the required minimum %s", name, v.(string), dMin))
    80  		}
    81  
    82  		return warnings, errors
    83  	}
    84  }
    85  
    86  func validateIntMaxFactory(name string, max int) func(v interface{}, key string) (warnings []string, errors []error) {
    87  	return func(v interface{}, key string) (warnings []string, errors []error) {
    88  		switch u := v.(type) {
    89  		case string:
    90  			i, err := strconv.ParseInt(u, 10, 64)
    91  			if err != nil {
    92  				errors = append(errors, errwrap.Wrapf(fmt.Sprintf("unable to convert %q to an integer: {{err}}", u), err))
    93  				break
    94  			}
    95  
    96  			if i > int64(max) {
    97  				errors = append(errors, fmt.Errorf("Invalid %s specified: %d more than the required maximum %d", name, v.(int), max))
    98  			}
    99  		case int:
   100  			if u > max {
   101  				errors = append(errors, fmt.Errorf("Invalid %s specified: %d more than the required maximum %d", name, v.(int), max))
   102  			}
   103  		default:
   104  			errors = append(errors, fmt.Errorf("Unsupported type in int max validation: %T", v))
   105  		}
   106  
   107  		return warnings, errors
   108  	}
   109  }
   110  
   111  func validateIntMinFactory(name string, min int) func(v interface{}, key string) (warnings []string, errors []error) {
   112  	return func(v interface{}, key string) (warnings []string, errors []error) {
   113  		switch u := v.(type) {
   114  		case string:
   115  			i, err := strconv.ParseInt(u, 10, 64)
   116  			if err != nil {
   117  				errors = append(errors, errwrap.Wrapf(fmt.Sprintf("unable to convert %q to an integer: {{err}}", u), err))
   118  				break
   119  			}
   120  
   121  			if i < int64(min) {
   122  				errors = append(errors, fmt.Errorf("Invalid %s specified: %d less than the required minimum %d", name, v.(int), min))
   123  			}
   124  		case int:
   125  			if u < min {
   126  				errors = append(errors, fmt.Errorf("Invalid %s specified: %d less than the required minimum %d", name, v.(int), min))
   127  			}
   128  		default:
   129  			errors = append(errors, fmt.Errorf("Unsupported type in int min validation: %T", v))
   130  		}
   131  
   132  		return warnings, errors
   133  	}
   134  }
   135  
   136  func validateRegexpFactory(name string, reString string) func(v interface{}, key string) (warnings []string, errors []error) {
   137  	re := regexp.MustCompile(reString)
   138  
   139  	return func(v interface{}, key string) (warnings []string, errors []error) {
   140  		if !re.MatchString(v.(string)) {
   141  			errors = append(errors, fmt.Errorf("Invalid %s specified (%q): regexp failed to match string", name, v.(string)))
   142  		}
   143  
   144  		return warnings, errors
   145  	}
   146  }