From bef56292913d30dd8ba8cfa1677ad2c36722f7e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A3o=20Sim=C3=B5es?= Date: Wed, 30 Oct 2024 12:25:23 +0000 Subject: [PATCH] Fix ZT lists update When updating the `cloudflare_zero_trust_list` only changes to the `items` field was being considered to determine the list elements to store. However, customers can also use the `items_with_description` field to declare list elements with a description, so it also needs to be considered. This commit fixes the issue, adding an acceptance test to prove its effectiveness. --- .changelog/4477.txt | 3 + .../resource_cloudflare_teams_list.go | 63 +++++++++++++++---- .../resource_cloudflare_teams_list_test.go | 29 ++++++++- 3 files changed, 83 insertions(+), 12 deletions(-) create mode 100644 .changelog/4477.txt diff --git a/.changelog/4477.txt b/.changelog/4477.txt new file mode 100644 index 0000000000..d9a3dd89b2 --- /dev/null +++ b/.changelog/4477.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/cloudflare_zero_trust_list: Consider `items_with_description` when updating a ZT list +``` diff --git a/internal/sdkv2provider/resource_cloudflare_teams_list.go b/internal/sdkv2provider/resource_cloudflare_teams_list.go index 195d33c7c3..0d9f96548d 100644 --- a/internal/sdkv2provider/resource_cloudflare_teams_list.go +++ b/internal/sdkv2provider/resource_cloudflare_teams_list.go @@ -150,12 +150,52 @@ func resourceCloudflareTeamsListUpdate(ctx context.Context, d *schema.ResourceDa return diag.FromErr(fmt.Errorf("failed to find Teams List ID in update response; resource was empty")) } - if d.HasChange("items") { + if d.HasChange("items") || d.HasChange("items_with_description") { oldItemsIface, newItemsIface := d.GetChange("items") + oldItemsWithDescriptionIface, newItemsWithDescriptionIface := d.GetChange("items_with_description") + oldItems := oldItemsIface.(*schema.Set).List() newItems := newItemsIface.(*schema.Set).List() + oldItemsWithDescription := oldItemsWithDescriptionIface.(*schema.Set).List() + newItemsWithDescription := newItemsWithDescriptionIface.(*schema.Set).List() + + convertedOldItems := []cloudflare.TeamsListItem{} + convertedNewItems := []cloudflare.TeamsListItem{} + + for _, v := range oldItems { + item, err := convertItemCFTeamsListItems(v) + if err != nil { + return diag.FromErr(fmt.Errorf("error creating Teams List for account %q: %w", accountID, err)) + } + convertedOldItems = append(convertedOldItems, *item) + } + + for _, v := range oldItemsWithDescription { + item, err := convertItemCFTeamsListItems(v) + if err != nil { + return diag.FromErr(fmt.Errorf("error creating Teams List for account %q: %w", accountID, err)) + } + convertedOldItems = append(convertedOldItems, *item) + } + + for _, v := range newItems { + item, err := convertItemCFTeamsListItems(v) + if err != nil { + return diag.FromErr(fmt.Errorf("error creating Teams List for account %q: %w", accountID, err)) + } + convertedNewItems = append(convertedNewItems, *item) + } + + for _, v := range newItemsWithDescription { + item, err := convertItemCFTeamsListItems(v) + if err != nil { + return diag.FromErr(fmt.Errorf("error creating Teams List for account %q: %w", accountID, err)) + } + convertedNewItems = append(convertedNewItems, *item) + } + patchTeamsList := cloudflare.PatchTeamsListParams{ID: d.Id()} - setListItemDiff(&patchTeamsList, oldItems, newItems) + setListItemDiff(&patchTeamsList, convertedOldItems, convertedNewItems) l, err := client.PatchTeamsList(ctx, identifier, patchTeamsList) @@ -206,21 +246,22 @@ func resourceCloudflareTeamsListImport(ctx context.Context, d *schema.ResourceDa return []*schema.ResourceData{d}, nil } -func setListItemDiff(patchList *cloudflare.PatchTeamsListParams, oldItems, newItems []interface{}) { - counts := make(map[string]int) - for _, val := range newItems { - counts[val.(string)] += 1 +func setListItemDiff(patchList *cloudflare.PatchTeamsListParams, oldItems, newItems []cloudflare.TeamsListItem) { + counts := make(map[cloudflare.TeamsListItem]int) + + for _, item := range newItems { + counts[item] += 1 } - for _, val := range oldItems { - counts[val.(string)] -= 1 + for _, item := range oldItems { + counts[item] -= 1 } - for key, val := range counts { + for item, val := range counts { if val > 0 { - patchList.Append = append(patchList.Append, cloudflare.TeamsListItem{Value: key}) + patchList.Append = append(patchList.Append, item) } if val < 0 { - patchList.Remove = append(patchList.Remove, key) + patchList.Remove = append(patchList.Remove, item.Value) } } } diff --git a/internal/sdkv2provider/resource_cloudflare_teams_list_test.go b/internal/sdkv2provider/resource_cloudflare_teams_list_test.go index 769738c4e4..0088418a76 100644 --- a/internal/sdkv2provider/resource_cloudflare_teams_list_test.go +++ b/internal/sdkv2provider/resource_cloudflare_teams_list_test.go @@ -81,6 +81,20 @@ func TestAccCloudflareTeamsList_BasicWithDescription(t *testing.T) { resource.TestCheckResourceAttr(name, "items_with_description.1.description", "test-2"), ), }, + { + Config: testAccCloudflareTeamsListUpdatedConfigBasicWithDescription(rnd, accountID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(name, consts.AccountIDSchemaKey, accountID), + resource.TestCheckResourceAttr(name, "name", rnd), + resource.TestCheckResourceAttr(name, "type", "DOMAIN"), + resource.TestCheckResourceAttr(name, "description", "My description"), + resource.TestCheckResourceAttr(name, "items.#", "1"), + resource.TestCheckResourceAttr(name, "items_with_description.#", "1"), + resource.TestCheckResourceAttr(name, "items.0", "fedcba.com"), + resource.TestCheckResourceAttr(name, "items_with_description.0.value", "abcd.com"), + resource.TestCheckResourceAttr(name, "items_with_description.0.description", "updated test"), + ), + }, }, }) } @@ -162,12 +176,25 @@ resource "cloudflare_zero_trust_list" "%[1]s" { name = "%[1]s" description = "My description" type = "DOMAIN" - items = [ "abcdef.com"] + items = ["abcdef.com"] items_with_description = [{"value" : "abcd.com", "description": "test"}, {"value" : "abcdefghijk.com", "description": "test-2"}] } `, rnd, accountID) } +func testAccCloudflareTeamsListUpdatedConfigBasicWithDescription(rnd, accountID string) string { + return fmt.Sprintf(` +resource "cloudflare_zero_trust_list" "%[1]s" { + account_id = "%[2]s" + name = "%[1]s" + description = "My description" + type = "DOMAIN" + items = ["fedcba.com"] + items_with_description = [{"value" : "abcd.com", "description": "updated test"}] +} +`, rnd, accountID) +} + func testAccCloudflareTeamsListConfigBigItemCount(rnd, accountID string) string { items := []string{} for i := 0; i < 1000; i++ {