github.com/hooklift/terraform@v0.11.0-beta1.0.20171117000744-6786c1361ffe/helper/validation/validation.go (about) 1 package validation 2 3 import ( 4 "fmt" 5 "net" 6 "reflect" 7 "regexp" 8 "strings" 9 10 "github.com/hashicorp/terraform/helper/schema" 11 "github.com/hashicorp/terraform/helper/structure" 12 ) 13 14 // IntBetween returns a SchemaValidateFunc which tests if the provided value 15 // is of type int and is between min and max (inclusive) 16 func IntBetween(min, max int) schema.SchemaValidateFunc { 17 return func(i interface{}, k string) (s []string, es []error) { 18 v, ok := i.(int) 19 if !ok { 20 es = append(es, fmt.Errorf("expected type of %s to be int", k)) 21 return 22 } 23 24 if v < min || v > max { 25 es = append(es, fmt.Errorf("expected %s to be in the range (%d - %d), got %d", k, min, max, v)) 26 return 27 } 28 29 return 30 } 31 } 32 33 // IntAtLeast returns a SchemaValidateFunc which tests if the provided value 34 // is of type int and is at least min (inclusive) 35 func IntAtLeast(min int) schema.SchemaValidateFunc { 36 return func(i interface{}, k string) (s []string, es []error) { 37 v, ok := i.(int) 38 if !ok { 39 es = append(es, fmt.Errorf("expected type of %s to be int", k)) 40 return 41 } 42 43 if v < min { 44 es = append(es, fmt.Errorf("expected %s to be at least (%d), got %d", k, min, v)) 45 return 46 } 47 48 return 49 } 50 } 51 52 // IntAtMost returns a SchemaValidateFunc which tests if the provided value 53 // is of type int and is at most max (inclusive) 54 func IntAtMost(max int) schema.SchemaValidateFunc { 55 return func(i interface{}, k string) (s []string, es []error) { 56 v, ok := i.(int) 57 if !ok { 58 es = append(es, fmt.Errorf("expected type of %s to be int", k)) 59 return 60 } 61 62 if v > max { 63 es = append(es, fmt.Errorf("expected %s to be at most (%d), got %d", k, max, v)) 64 return 65 } 66 67 return 68 } 69 } 70 71 // StringInSlice returns a SchemaValidateFunc which tests if the provided value 72 // is of type string and matches the value of an element in the valid slice 73 // will test with in lower case if ignoreCase is true 74 func StringInSlice(valid []string, ignoreCase bool) schema.SchemaValidateFunc { 75 return func(i interface{}, k string) (s []string, es []error) { 76 v, ok := i.(string) 77 if !ok { 78 es = append(es, fmt.Errorf("expected type of %s to be string", k)) 79 return 80 } 81 82 for _, str := range valid { 83 if v == str || (ignoreCase && strings.ToLower(v) == strings.ToLower(str)) { 84 return 85 } 86 } 87 88 es = append(es, fmt.Errorf("expected %s to be one of %v, got %s", k, valid, v)) 89 return 90 } 91 } 92 93 // StringLenBetween returns a SchemaValidateFunc which tests if the provided value 94 // is of type string and has length between min and max (inclusive) 95 func StringLenBetween(min, max int) schema.SchemaValidateFunc { 96 return func(i interface{}, k string) (s []string, es []error) { 97 v, ok := i.(string) 98 if !ok { 99 es = append(es, fmt.Errorf("expected type of %s to be string", k)) 100 return 101 } 102 if len(v) < min || len(v) > max { 103 es = append(es, fmt.Errorf("expected length of %s to be in the range (%d - %d), got %s", k, min, max, v)) 104 } 105 return 106 } 107 } 108 109 // NoZeroValues is a SchemaValidateFunc which tests if the provided value is 110 // not a zero value. It's useful in situations where you want to catch 111 // explicit zero values on things like required fields during validation. 112 func NoZeroValues(i interface{}, k string) (s []string, es []error) { 113 if reflect.ValueOf(i).Interface() == reflect.Zero(reflect.TypeOf(i)).Interface() { 114 switch reflect.TypeOf(i).Kind() { 115 case reflect.String: 116 es = append(es, fmt.Errorf("%s must not be empty", k)) 117 case reflect.Int, reflect.Float64: 118 es = append(es, fmt.Errorf("%s must not be zero", k)) 119 default: 120 // this validator should only ever be applied to TypeString, TypeInt and TypeFloat 121 panic(fmt.Errorf("can't use NoZeroValues with %T attribute %s", i, k)) 122 } 123 } 124 return 125 } 126 127 // CIDRNetwork returns a SchemaValidateFunc which tests if the provided value 128 // is of type string, is in valid CIDR network notation, and has significant bits between min and max (inclusive) 129 func CIDRNetwork(min, max int) schema.SchemaValidateFunc { 130 return func(i interface{}, k string) (s []string, es []error) { 131 v, ok := i.(string) 132 if !ok { 133 es = append(es, fmt.Errorf("expected type of %s to be string", k)) 134 return 135 } 136 137 _, ipnet, err := net.ParseCIDR(v) 138 if err != nil { 139 es = append(es, fmt.Errorf( 140 "expected %s to contain a valid CIDR, got: %s with err: %s", k, v, err)) 141 return 142 } 143 144 if ipnet == nil || v != ipnet.String() { 145 es = append(es, fmt.Errorf( 146 "expected %s to contain a valid network CIDR, expected %s, got %s", 147 k, ipnet, v)) 148 } 149 150 sigbits, _ := ipnet.Mask.Size() 151 if sigbits < min || sigbits > max { 152 es = append(es, fmt.Errorf( 153 "expected %q to contain a network CIDR with between %d and %d significant bits, got: %d", 154 k, min, max, sigbits)) 155 } 156 157 return 158 } 159 } 160 161 // ValidateJsonString is a SchemaValidateFunc which tests to make sure the 162 // supplied string is valid JSON. 163 func ValidateJsonString(v interface{}, k string) (ws []string, errors []error) { 164 if _, err := structure.NormalizeJsonString(v); err != nil { 165 errors = append(errors, fmt.Errorf("%q contains an invalid JSON: %s", k, err)) 166 } 167 return 168 } 169 170 // ValidateListUniqueStrings is a ValidateFunc that ensures a list has no 171 // duplicate items in it. It's useful for when a list is needed over a set 172 // because order matters, yet the items still need to be unique. 173 func ValidateListUniqueStrings(v interface{}, k string) (ws []string, errors []error) { 174 for n1, v1 := range v.([]interface{}) { 175 for n2, v2 := range v.([]interface{}) { 176 if v1.(string) == v2.(string) && n1 != n2 { 177 errors = append(errors, fmt.Errorf("%q: duplicate entry - %s", k, v1.(string))) 178 } 179 } 180 } 181 return 182 } 183 184 // ValidateRegexp returns a SchemaValidateFunc which tests to make sure the 185 // supplied string is a valid regular expression. 186 func ValidateRegexp(v interface{}, k string) (ws []string, errors []error) { 187 if _, err := regexp.Compile(v.(string)); err != nil { 188 errors = append(errors, fmt.Errorf("%q: %s", k, err)) 189 } 190 return 191 }