From 2bc612e6f81a19b4986dacf72b156baf52decb02 Mon Sep 17 00:00:00 2001 From: Emil Hessman Date: Mon, 12 Jan 2015 13:57:47 +0100 Subject: [PATCH] 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. --- helper/schema/schema.go | 32 +++++++++++++++++++---------- helper/schema/schema_test.go | 39 ++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 11 deletions(-) diff --git a/helper/schema/schema.go b/helper/schema/schema.go index 383f8704c..f334dc2a4 100644 --- a/helper/schema/schema.go +++ b/helper/schema/schema.go @@ -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) + } +} diff --git a/helper/schema/schema_test.go b/helper/schema/schema_test.go index 9f56d386f..8c682dac2 100644 --- a/helper/schema/schema_test.go +++ b/helper/schema/schema_test.go @@ -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 {