From 76e406ea30f03ce6267ff1cfa9bb5eb24c2b1b01 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Thu, 30 Apr 2020 11:15:43 -0400 Subject: [PATCH] helper/schema: InternalValidate fix for configuration block type checking The validation for `AtLeastOneOf`, `ConflictsWith`, `ExactlyOneOf`, and `RequiredWith` should not flag configuration block attributes without `Type: TypeList` and `MaxItems: 1` if they are the last part of the reference. --- helper/schema/schema.go | 5 +- helper/schema/schema_test.go | 312 +++++++++++++++++++++++++++++++++++ 2 files changed, 315 insertions(+), 2 deletions(-) diff --git a/helper/schema/schema.go b/helper/schema/schema.go index 1c82765e2fb..df0172fa108 100644 --- a/helper/schema/schema.go +++ b/helper/schema/schema.go @@ -868,7 +868,7 @@ func checkKeysAgainstSchemaFlags(k string, keys []string, topSchemaMap schemaMap parts := strings.Split(key, ".") sm := topSchemaMap var target *Schema - for _, part := range parts { + for idx, part := range parts { // Skip index fields if 0 partInt, err := strconv.Atoi(part) @@ -891,7 +891,8 @@ func checkKeysAgainstSchemaFlags(k string, keys []string, topSchemaMap schemaMap continue } - if target.Type == TypeSet || target.MaxItems != 1 { + // Skip Type/MaxItems check if not the last element + if (target.Type == TypeSet || target.MaxItems != 1) && idx+1 != len(parts) { return fmt.Errorf("%s configuration block reference (%s) can only be used with TypeList and MaxItems: 1 configuration blocks", k, key) } diff --git a/helper/schema/schema_test.go b/helper/schema/schema_test.go index dc25b1bd8ec..3b5ea8a052e 100644 --- a/helper/schema/schema_test.go +++ b/helper/schema/schema_test.go @@ -3831,6 +3831,45 @@ func TestSchemaMap_InternalValidate(t *testing.T) { true, }, + "AtLeastOneOf string syntax with list attribute": { + map[string]*Schema{ + "list_attr": { + Type: TypeList, + Optional: true, + Elem: &Schema{Type: TypeString}, + }, + "test": { + Type: TypeBool, + Optional: true, + AtLeastOneOf: []string{"list_attr"}, + }, + }, + false, + }, + + "AtLeastOneOf string syntax with list configuration block": { + map[string]*Schema{ + "config_block_attr": { + Type: TypeList, + Optional: true, + Elem: &Resource{ + Schema: map[string]*Schema{ + "nested_attr": { + Type: TypeString, + Optional: true, + }, + }, + }, + }, + "test": { + Type: TypeBool, + Optional: true, + AtLeastOneOf: []string{"config_block_attr"}, + }, + }, + false, + }, + "AtLeastOneOf string syntax with map attribute": { map[string]*Schema{ "map_attr": { @@ -3847,6 +3886,45 @@ func TestSchemaMap_InternalValidate(t *testing.T) { false, }, + "AtLeastOneOf string syntax with set attribute": { + map[string]*Schema{ + "set_attr": { + Type: TypeSet, + Optional: true, + Elem: &Schema{Type: TypeString}, + }, + "test": { + Type: TypeBool, + Optional: true, + AtLeastOneOf: []string{"set_attr"}, + }, + }, + false, + }, + + "AtLeastOneOf string syntax with set configuration block": { + map[string]*Schema{ + "config_block_attr": { + Type: TypeSet, + Optional: true, + Elem: &Resource{ + Schema: map[string]*Schema{ + "nested_attr": { + Type: TypeString, + Optional: true, + }, + }, + }, + }, + "test": { + Type: TypeBool, + Optional: true, + AtLeastOneOf: []string{"config_block_attr"}, + }, + }, + false, + }, + "AtLeastOneOf string syntax with self reference": { map[string]*Schema{ "test": { @@ -4093,6 +4171,45 @@ func TestSchemaMap_InternalValidate(t *testing.T) { true, }, + "ConflictsWith string syntax with list attribute": { + map[string]*Schema{ + "list_attr": { + Type: TypeList, + Optional: true, + Elem: &Schema{Type: TypeString}, + }, + "test": { + Type: TypeBool, + Optional: true, + ConflictsWith: []string{"list_attr"}, + }, + }, + false, + }, + + "ConflictsWith string syntax with list configuration block": { + map[string]*Schema{ + "config_block_attr": { + Type: TypeList, + Optional: true, + Elem: &Resource{ + Schema: map[string]*Schema{ + "nested_attr": { + Type: TypeString, + Optional: true, + }, + }, + }, + }, + "test": { + Type: TypeBool, + Optional: true, + ConflictsWith: []string{"config_block_attr"}, + }, + }, + false, + }, + "ConflictsWith string syntax with map attribute": { map[string]*Schema{ "map_attr": { @@ -4109,6 +4226,45 @@ func TestSchemaMap_InternalValidate(t *testing.T) { false, }, + "ConflictsWith string syntax with set attribute": { + map[string]*Schema{ + "set_attr": { + Type: TypeSet, + Optional: true, + Elem: &Schema{Type: TypeString}, + }, + "test": { + Type: TypeBool, + Optional: true, + ConflictsWith: []string{"set_attr"}, + }, + }, + false, + }, + + "ConflictsWith string syntax with set configuration block": { + map[string]*Schema{ + "config_block_attr": { + Type: TypeSet, + Optional: true, + Elem: &Resource{ + Schema: map[string]*Schema{ + "nested_attr": { + Type: TypeString, + Optional: true, + }, + }, + }, + }, + "test": { + Type: TypeBool, + Optional: true, + ConflictsWith: []string{"config_block_attr"}, + }, + }, + false, + }, + "ConflictsWith string syntax with self reference": { map[string]*Schema{ "test": { @@ -4356,6 +4512,45 @@ func TestSchemaMap_InternalValidate(t *testing.T) { true, }, + "ExactlyOneOf string syntax with list attribute": { + map[string]*Schema{ + "list_attr": { + Type: TypeList, + Optional: true, + Elem: &Schema{Type: TypeString}, + }, + "test": { + Type: TypeBool, + Optional: true, + ExactlyOneOf: []string{"list_attr"}, + }, + }, + false, + }, + + "ExactlyOneOf string syntax with list configuration block": { + map[string]*Schema{ + "config_block_attr": { + Type: TypeList, + Optional: true, + Elem: &Resource{ + Schema: map[string]*Schema{ + "nested_attr": { + Type: TypeString, + Optional: true, + }, + }, + }, + }, + "test": { + Type: TypeBool, + Optional: true, + ExactlyOneOf: []string{"config_block_attr"}, + }, + }, + false, + }, + "ExactlyOneOf string syntax with map attribute": { map[string]*Schema{ "map_attr": { @@ -4372,6 +4567,45 @@ func TestSchemaMap_InternalValidate(t *testing.T) { false, }, + "ExactlyOneOf string syntax with set attribute": { + map[string]*Schema{ + "set_attr": { + Type: TypeSet, + Optional: true, + Elem: &Schema{Type: TypeString}, + }, + "test": { + Type: TypeBool, + Optional: true, + ExactlyOneOf: []string{"set_attr"}, + }, + }, + false, + }, + + "ExactlyOneOf string syntax with set configuration block": { + map[string]*Schema{ + "config_block_attr": { + Type: TypeSet, + Optional: true, + Elem: &Resource{ + Schema: map[string]*Schema{ + "nested_attr": { + Type: TypeString, + Optional: true, + }, + }, + }, + }, + "test": { + Type: TypeBool, + Optional: true, + ExactlyOneOf: []string{"config_block_attr"}, + }, + }, + false, + }, + "ExactlyOneOf string syntax with self reference": { map[string]*Schema{ "test": { @@ -4619,6 +4853,45 @@ func TestSchemaMap_InternalValidate(t *testing.T) { true, }, + "RequiredWith string syntax with list attribute": { + map[string]*Schema{ + "list_attr": { + Type: TypeList, + Optional: true, + Elem: &Schema{Type: TypeString}, + }, + "test": { + Type: TypeBool, + Optional: true, + RequiredWith: []string{"list_attr"}, + }, + }, + false, + }, + + "RequiredWith string syntax with list configuration block": { + map[string]*Schema{ + "config_block_attr": { + Type: TypeList, + Optional: true, + Elem: &Resource{ + Schema: map[string]*Schema{ + "nested_attr": { + Type: TypeString, + Optional: true, + }, + }, + }, + }, + "test": { + Type: TypeBool, + Optional: true, + RequiredWith: []string{"config_block_attr"}, + }, + }, + false, + }, + "RequiredWith string syntax with map attribute": { map[string]*Schema{ "map_attr": { @@ -4635,6 +4908,45 @@ func TestSchemaMap_InternalValidate(t *testing.T) { false, }, + "RequiredWith string syntax with set attribute": { + map[string]*Schema{ + "set_attr": { + Type: TypeSet, + Optional: true, + Elem: &Schema{Type: TypeString}, + }, + "test": { + Type: TypeBool, + Optional: true, + RequiredWith: []string{"set_attr"}, + }, + }, + false, + }, + + "RequiredWith string syntax with set configuration block": { + map[string]*Schema{ + "config_block_attr": { + Type: TypeSet, + Optional: true, + Elem: &Resource{ + Schema: map[string]*Schema{ + "nested_attr": { + Type: TypeString, + Optional: true, + }, + }, + }, + }, + "test": { + Type: TypeBool, + Optional: true, + RequiredWith: []string{"config_block_attr"}, + }, + }, + false, + }, + "RequiredWith string syntax with self reference": { map[string]*Schema{ "test": {