helper/schema: fix panic when validating composite type

Don't check if the root key is being computed for composite types.
Instead, continue recursing the composite type in order to check if
the sub-key, key.N, for each individual element is being computed.

Fixes a panic which occurs when validating a composite type where
the value is an unknown kind for the schema.
This commit is contained in:
Emil Hessman 2015-01-12 13:57:47 +01:00
parent 9c02a6e4f7
commit 2bc612e6f8
2 changed files with 60 additions and 11 deletions

View File

@ -142,7 +142,7 @@ type Schema struct {
// element type is a complex structure, potentially with its own lifecycle.
Elem interface{}
// The follow fields are only valid for a TypeSet type.
// The following fields are only valid for a TypeSet type.
//
// Set defines a function to determine the unique ID of an item so that
// a proper set can be built.
@ -902,7 +902,7 @@ func (m schemaMap) validate(
"%s: this field cannot be set", k)}
}
return m.validatePrimitive(k, raw, schema, c)
return m.validateType(k, raw, schema, c)
}
func (m schemaMap) validateList(
@ -915,7 +915,7 @@ func (m schemaMap) validateList(
rawV := reflect.ValueOf(raw)
if rawV.Kind() != reflect.Slice {
return nil, []error{fmt.Errorf(
"%s: should be a list", k)}
"%s: should be an array", k)}
}
// Now build the []interface{}
@ -936,8 +936,7 @@ func (m schemaMap) validateList(
// This is a sub-resource
ws2, es2 = m.validateObject(key, t.Schema, c)
case *Schema:
// This is some sort of primitive
ws2, es2 = m.validatePrimitive(key, raw, t, c)
ws2, es2 = m.validateType(key, raw, t, c)
}
if len(ws2) > 0 {
@ -1041,12 +1040,6 @@ func (m schemaMap) validatePrimitive(
}
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
@ -1071,3 +1064,20 @@ func (m schemaMap) validatePrimitive(
return nil, nil
}
func (m schemaMap) validateType(
k string,
raw interface{},
schema *Schema,
c *terraform.ResourceConfig) ([]string, []error) {
switch schema.Type {
case TypeSet:
fallthrough
case TypeList:
return m.validateList(k, raw, schema, c)
case TypeMap:
return m.validateMap(k, raw, schema, c)
default:
return m.validatePrimitive(k, raw, schema, c)
}
}

View File

@ -2503,6 +2503,45 @@ func TestSchemaMap_Validate(t *testing.T) {
Err: true,
},
{
Schema: map[string]*Schema{
"security_groups": &Schema{
Type: TypeSet,
Optional: true,
Computed: true,
ForceNew: true,
Elem: &Schema{Type: TypeString},
Set: func(v interface{}) int {
return len(v.(string))
},
},
},
Config: map[string]interface{}{
"security_groups": []interface{}{"${var.foo}"},
},
Err: false,
},
{
Schema: map[string]*Schema{
"security_groups": &Schema{
Type: TypeSet,
Optional: true,
Computed: true,
ForceNew: true,
Elem: &Schema{Type: TypeString},
},
},
Config: map[string]interface{}{
"security_groups": "${var.foo}",
},
Err: true,
},
}
for i, tc := range cases {