From f55c1de20cd674ced7dc9a9cd4c218bc8cedaa64 Mon Sep 17 00:00:00 2001 From: Konstantin Dudkov Date: Thu, 21 Nov 2019 15:48:15 +0300 Subject: [PATCH] add relative key link for ConflictsWith field --- helper/schema/schema.go | 12 +++++- helper/schema/schema_test.go | 77 ++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 2 deletions(-) diff --git a/helper/schema/schema.go b/helper/schema/schema.go index c6061da9ee0..8d39f143fa1 100644 --- a/helper/schema/schema.go +++ b/helper/schema/schema.go @@ -1466,20 +1466,28 @@ func validateConflictingAttributes( } for _, conflictingKey := range schema.ConflictsWith { - if raw, ok := c.Get(conflictingKey); ok { + resolvedKey := resolveKey(k, conflictingKey) + if raw, ok := c.Get(resolvedKey); ok { if raw == hcl2shim.UnknownVariableValue { // An unknown value might become unset (null) once known, so // we must defer validation until it's known. continue } return fmt.Errorf( - "%q: conflicts with %s", k, conflictingKey) + "%q: conflicts with %s", k, resolvedKey) } } return nil } +func resolveKey(rootKey string, key string) string { + if strings.HasPrefix(key, "..") && strings.Contains(rootKey, ".") { + return rootKey[:strings.LastIndex(rootKey, ".")+1] + key[2:] + } + return key +} + func removeDuplicates(elements []string) []string { encountered := make(map[string]struct{}, 0) result := []string{} diff --git a/helper/schema/schema_test.go b/helper/schema/schema_test.go index b14e61d218e..b808c401d14 100644 --- a/helper/schema/schema_test.go +++ b/helper/schema/schema_test.go @@ -4907,6 +4907,83 @@ func TestSchemaMap_Validate(t *testing.T) { }, }, + "Conflicting subelements": { + Schema: map[string]*Schema{ + "items": &Schema{ + Type: TypeList, + Required: true, + Elem: &Resource{ + Schema: map[string]*Schema{ + "blacklist": &Schema{ + Type: TypeString, + Optional: true, + ConflictsWith: []string{"..greenlist"}, + }, + "greenlist": &Schema{ + Type: TypeString, + Optional: true, + ConflictsWith: []string{"..blacklist"}, + }, + }, + }, + }, + }, + + Config: map[string]interface{}{ + "items": []interface{}{ + map[string]interface{}{ + "blacklist": "black-val", + "greenlist": "green-val", + }, + map[string]interface{}{ + "blacklist": "black-val", + }, + }, + }, + + Err: true, + Errors: []error{ + fmt.Errorf("\"items.0.blacklist\": conflicts with items.0.greenlist"), + fmt.Errorf("\"items.0.greenlist\": conflicts with items.0.blacklist"), + }, + }, + + "Non-conflicting subelements": { + Schema: map[string]*Schema{ + "items": &Schema{ + Type: TypeList, + Required: true, + Elem: &Resource{ + Schema: map[string]*Schema{ + "blacklist": &Schema{ + Type: TypeString, + Optional: true, + ConflictsWith: []string{"..greenlist"}, + }, + "greenlist": &Schema{ + Type: TypeString, + Optional: true, + ConflictsWith: []string{"..blacklist"}, + }, + }, + }, + }, + }, + + Config: map[string]interface{}{ + "items": []interface{}{ + map[string]interface{}{ + "greenlist": "green-val", + }, + map[string]interface{}{ + "blacklist": "black-val", + }, + }, + }, + + Err: false, + }, + "Required attribute & undefined conflicting optional are good": { Schema: map[string]*Schema{ "required_att": &Schema{