From 4407d765a40f76cdbbc3552192d98ebcbcb1a71a Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Thu, 20 Apr 2023 18:14:48 -0500 Subject: [PATCH] allow duplicate tags --- internal/service/ec2/vpc_test.go | 9 +++++++-- internal/tags/key_value_tags.go | 28 +++++++++++++++++++++++++--- internal/verify/diff.go | 4 ---- 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/internal/service/ec2/vpc_test.go b/internal/service/ec2/vpc_test.go index 2a47f5f1d5bc..3e30f5199609 100644 --- a/internal/service/ec2/vpc_test.go +++ b/internal/service/ec2/vpc_test.go @@ -403,6 +403,8 @@ func TestAccVPC_DefaultTagsProviderAndResource_overlappingTag(t *testing.T) { func TestAccVPC_DefaultTagsProviderAndResource_duplicateTag(t *testing.T) { ctx := acctest.Context(t) + var vpc ec2.Vpc + resourceName := "aws_vpc.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -415,8 +417,11 @@ func TestAccVPC_DefaultTagsProviderAndResource_duplicateTag(t *testing.T) { acctest.ConfigDefaultTags_Tags1("overlapkey", "overlapvalue"), testAccVPCConfig_tags1("overlapkey", "overlapvalue"), ), - PlanOnly: true, - ExpectError: regexp.MustCompile(`"tags" are identical to those in the "default_tags" configuration block`), + Check: resource.ComposeTestCheckFunc( + acctest.CheckVPCExists(ctx, resourceName, &vpc), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags_all.%", "1"), + ), }, }, }) diff --git a/internal/tags/key_value_tags.go b/internal/tags/key_value_tags.go index b39538763163..11a82a0ec881 100644 --- a/internal/tags/key_value_tags.go +++ b/internal/tags/key_value_tags.go @@ -754,15 +754,28 @@ func (tags KeyValueTags) RemoveDuplicates(ctx context.Context, defaultConfig *De configTags := make(map[string]string) if config := d.GetRawPlan(); !config.IsNull() && config.IsKnown() { c := config.GetAttr("tags") - if !c.IsNull() { + if !c.IsNull() && c.IsKnown() { for k, v := range c.AsValueMap() { configTags[k] = v.AsString() } } } + var configIsNull bool if config := d.GetRawConfig(); !config.IsNull() && config.IsKnown() { c := config.GetAttr("tags") + configIsNull = c.IsNull() + if !c.IsNull() && c.IsKnown() { + for k, v := range c.AsValueMap() { + if _, ok := configTags[k]; !ok { + configTags[k] = v.AsString() + } + } + } + } + + if state := d.GetRawState(); !state.IsNull() && state.IsKnown() { + c := state.GetAttr("tags") if !c.IsNull() { for k, v := range c.AsValueMap() { if _, ok := configTags[k]; !ok { @@ -774,11 +787,20 @@ func (tags KeyValueTags) RemoveDuplicates(ctx context.Context, defaultConfig *De for k, v := range configTags { if _, ok := result[k]; !ok { - result[k] = v + if defaultConfig != nil { + if val, ok := defaultConfig.Tags[k]; ok && val.ValueString() == v { + result[k] = v + } + } } } - return New(ctx, result) + out := tags + if !configIsNull { + out = New(ctx, result) + } + + return out } // ToSnakeCase converts a string to snake case. diff --git a/internal/verify/diff.go b/internal/verify/diff.go index 7ea2d7a5f2dd..64f5c80d6fbb 100644 --- a/internal/verify/diff.go +++ b/internal/verify/diff.go @@ -26,10 +26,6 @@ func SetTagsDiff(ctx context.Context, diff *schema.ResourceDiff, meta interface{ resourceTags := tftags.New(ctx, diff.Get("tags").(map[string]interface{})) - //if defaultTagsConfig.TagsEqual(resourceTags) { - // return fmt.Errorf(`"tags" are identical to those in the "default_tags" configuration block of the provider: please de-duplicate and try again`) - //} - allTags := defaultTagsConfig.MergeTags(resourceTags).IgnoreConfig(ignoreTagsConfig) // To ensure "tags_all" is correctly computed, we explicitly set the attribute diff // when the merger of resource-level tags onto provider-level tags results in n > 0 tags,