func (m schemaMap) validate( k string, schema *Schema, c *terraform.ResourceConfig) ([]string, []error) { raw, ok := c.Get(k) if !ok && schema.DefaultFunc != nil { // We have a dynamic default. Check if we have a value. var err error raw, err = schema.DefaultFunc() if err != nil { return nil, []error{fmt.Errorf( "%q, error loading default: %s", k, err)} } // We're okay as long as we had a value set ok = raw != nil } if !ok { if schema.Required { return nil, []error{fmt.Errorf( "%q: required field is not set", k)} } return nil, nil } if !schema.Required && !schema.Optional { // This is a computed-only field return nil, []error{fmt.Errorf( "%q: this field cannot be set", k)} } return m.validateType(k, raw, schema, c) }
func (m schemaMap) validateObject( k string, schema map[string]*Schema, c *terraform.ResourceConfig) ([]string, []error) { var ws []string var es []error for subK, s := range schema { key := subK if k != "" { key = fmt.Sprintf("%s.%s", k, subK) } ws2, es2 := m.validate(key, s, c) if len(ws2) > 0 { ws = append(ws, ws2...) } if len(es2) > 0 { es = append(es, es2...) } } // Detect any extra/unknown keys and report those as errors. raw, _ := c.Get(k) if m, ok := raw.(map[string]interface{}); ok { for subk, _ := range m { if _, ok := schema[subk]; !ok { es = append(es, fmt.Errorf( "%s: invalid or unknown key: %s", k, subk)) } } } return ws, es }
func (m schemaMap) validateMap( k string, raw interface{}, schema *Schema, c *terraform.ResourceConfig) ([]string, []error) { // We use reflection to verify the slice because you can't // case to []interface{} unless the slice is exactly that type. rawV := reflect.ValueOf(raw) switch rawV.Kind() { case reflect.String: // If raw and reified are equal, this is a string and should // be rejected. reified, reifiedOk := c.Get(k) log.Printf("[jen20] reified: %s", spew.Sdump(reified)) log.Printf("[jen20] raw: %s", spew.Sdump(raw)) if reifiedOk && raw == reified && !c.IsComputed(k) { return nil, []error{fmt.Errorf("%s: should be a map", k)} } // Otherwise it's likely raw is an interpolation. return nil, nil case reflect.Map: case reflect.Slice: default: return nil, []error{fmt.Errorf("%s: should be a map", k)} } // If it is not a slice, it is valid if rawV.Kind() != reflect.Slice { return nil, nil } // It is a slice, verify that all the elements are maps raws := make([]interface{}, rawV.Len()) for i, _ := range raws { raws[i] = rawV.Index(i).Interface() } for _, raw := range raws { v := reflect.ValueOf(raw) if v.Kind() != reflect.Map { return nil, []error{fmt.Errorf( "%s: should be a map", k)} } } if schema.ValidateFunc != nil { validatableMap := make(map[string]interface{}) for _, raw := range raws { for k, v := range raw.(map[string]interface{}) { validatableMap[k] = v } } return schema.ValidateFunc(validatableMap, k) } return nil, nil }
func (m schemaMap) validatePrimitive( k string, raw interface{}, schema *Schema, c *terraform.ResourceConfig) ([]string, []error) { if c.IsComputed(k) { // If the key is being computed, then it is not an error return nil, nil } var decoded interface{} switch schema.Type { case TypeBool: // Verify that we can parse this as the correct type var n bool if err := mapstructure.WeakDecode(raw, &n); err != nil { return nil, []error{err} } decoded = n case TypeInt: // Verify that we can parse this as an int var n int if err := mapstructure.WeakDecode(raw, &n); err != nil { return nil, []error{err} } decoded = n case TypeFloat: // Verify that we can parse this as an int var n float64 if err := mapstructure.WeakDecode(raw, &n); err != nil { return nil, []error{err} } decoded = n case TypeString: // Verify that we can parse this as a string var n string if err := mapstructure.WeakDecode(raw, &n); err != nil { return nil, []error{err} } decoded = n default: panic(fmt.Sprintf("Unknown validation type: %#v", schema.Type)) } if schema.ValidateFunc != nil { return schema.ValidateFunc(decoded, k) } return nil, nil }
func (m schemaMap) validateConflictingAttributes( k string, schema *Schema, c *terraform.ResourceConfig) error { if len(schema.ConflictsWith) == 0 { return nil } for _, conflicting_key := range schema.ConflictsWith { if value, ok := c.Get(conflicting_key); ok { return fmt.Errorf( "%q: conflicts with %s (%#v)", k, conflicting_key, value) } } return nil }
func (m schemaMap) validatePrimitive( k string, raw interface{}, schema *Schema, c *terraform.ResourceConfig) ([]string, []error) { if c.IsComputed(k) { // If the key is being computed, then it is not an error return nil, nil } switch schema.Type { case TypeSet: fallthrough case TypeList: return m.validateList(k, raw, schema, c) case TypeMap: return m.validateMap(k, raw, schema, c) case TypeBool: // Verify that we can parse this as the correct type var n bool if err := mapstructure.WeakDecode(raw, &n); err != nil { return nil, []error{err} } case TypeInt: // Verify that we can parse this as an int var n int if err := mapstructure.WeakDecode(raw, &n); err != nil { return nil, []error{err} } case TypeString: // Verify that we can parse this as a string var n string if err := mapstructure.WeakDecode(raw, &n); err != nil { return nil, []error{err} } default: panic(fmt.Sprintf("Unknown validation type: %#v", schema.Type)) } return nil, nil }
func (m schemaMap) validate( k string, schema *Schema, c *terraform.ResourceConfig) ([]string, []error) { raw, ok := c.Get(k) if !ok { if schema.Required { return nil, []error{fmt.Errorf( "%s: required field is not set", k)} } return nil, nil } if !schema.Required && !schema.Optional { // This is a computed-only field return nil, []error{fmt.Errorf( "%s: this field cannot be set", k)} } return m.validatePrimitive(k, raw, schema, c) }
func (m schemaMap) validatePrimitive( k string, raw interface{}, schema *Schema, c *terraform.ResourceConfig) ([]string, []error) { // Catch if the user gave a complex type where a primitive was // expected, so we can return a friendly error message that // doesn't contain Go type system terminology. switch reflect.ValueOf(raw).Type().Kind() { case reflect.Slice: return nil, []error{ fmt.Errorf("%s must be a single value, not a list", k), } case reflect.Map: return nil, []error{ fmt.Errorf("%s must be a single value, not a map", k), } default: // ok } if c.IsComputed(k) { // If the key is being computed, then it is not an error as // long as it's not a slice or map. return nil, nil } var decoded interface{} switch schema.Type { case TypeBool: // Verify that we can parse this as the correct type var n bool if err := mapstructure.WeakDecode(raw, &n); err != nil { return nil, []error{err} } decoded = n case TypeInt: // Verify that we can parse this as an int var n int if err := mapstructure.WeakDecode(raw, &n); err != nil { return nil, []error{err} } decoded = n case TypeFloat: // Verify that we can parse this as an int var n float64 if err := mapstructure.WeakDecode(raw, &n); err != nil { return nil, []error{err} } decoded = n case TypeString: // Verify that we can parse this as a string var n string if err := mapstructure.WeakDecode(raw, &n); err != nil { return nil, []error{err} } decoded = n default: panic(fmt.Sprintf("Unknown validation type: %#v", schema.Type)) } if schema.ValidateFunc != nil { return schema.ValidateFunc(decoded, k) } return nil, nil }