From 5df21d576c622b2fad8e36519d15d331a1fd72e8 Mon Sep 17 00:00:00 2001 From: Alex Luong Date: Tue, 3 Sep 2024 09:07:14 +0700 Subject: [PATCH 1/6] suppress matching ipv6 dns record --- .../resource_cloudflare_record.go | 20 +++++++++++++++++++ .../sdkv2provider/schema_cloudflare_record.go | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/internal/sdkv2provider/resource_cloudflare_record.go b/internal/sdkv2provider/resource_cloudflare_record.go index d738ef95f7..c8cb876e63 100644 --- a/internal/sdkv2provider/resource_cloudflare_record.go +++ b/internal/sdkv2provider/resource_cloudflare_record.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "net" "strings" "time" @@ -501,3 +502,22 @@ func suppressTrailingDots(k, old, new string, d *schema.ResourceData) bool { return strings.TrimSuffix(old, ".") == newTrimmed } + +func suppressMatchingIpv6(_, old, new string, _ *schema.ResourceData) bool { + oldIpv6 := net.ParseIP(old) + if oldIpv6 == nil || oldIpv6.To16() == nil { + return false + } + newIpv6 := net.ParseIP(new) + if newIpv6 == nil || newIpv6.To16() == nil { + return false + } + return oldIpv6.Equal(newIpv6) +} + +func suppressContent(k, old, new string, d *schema.ResourceData) bool { + if suppressMatchingIpv6(k, old, new, d) { + return true + } + return suppressTrailingDots(k, old, new, d) +} diff --git a/internal/sdkv2provider/schema_cloudflare_record.go b/internal/sdkv2provider/schema_cloudflare_record.go index 40fbc8eb8a..f370829af1 100644 --- a/internal/sdkv2provider/schema_cloudflare_record.go +++ b/internal/sdkv2provider/schema_cloudflare_record.go @@ -58,7 +58,7 @@ func resourceCloudflareRecordSchema() map[string]*schema.Schema { Optional: true, Computed: true, ExactlyOneOf: []string{"data", "content", "value"}, - DiffSuppressFunc: suppressTrailingDots, + DiffSuppressFunc: suppressContent, Description: "The content of the record.", }, From 20b8cf8653a80a390f43b9d69ed47f5d509437b2 Mon Sep 17 00:00:00 2001 From: Alex Luong Date: Tue, 3 Sep 2024 09:14:46 +0700 Subject: [PATCH 2/6] add changelog entry --- .changelog/3888.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/3888.txt diff --git a/.changelog/3888.txt b/.changelog/3888.txt new file mode 100644 index 0000000000..36fc356d8f --- /dev/null +++ b/.changelog/3888.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/cloudflare_record: Suppress matching ipv6 dns record +``` From b6bdeb5382bf04674f3e2bd8a3f960bf3ed7040d Mon Sep 17 00:00:00 2001 From: Alex Luong Date: Tue, 3 Sep 2024 10:26:49 +0700 Subject: [PATCH 3/6] regression test --- .../resource_cloudflare_record_test.go | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/internal/sdkv2provider/resource_cloudflare_record_test.go b/internal/sdkv2provider/resource_cloudflare_record_test.go index 7297150291..4893723dea 100644 --- a/internal/sdkv2provider/resource_cloudflare_record_test.go +++ b/internal/sdkv2provider/resource_cloudflare_record_test.go @@ -13,6 +13,7 @@ import ( "github.com/cloudflare/terraform-provider-cloudflare/internal/consts" "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/plancheck" "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/pkg/errors" "github.com/stretchr/testify/assert" @@ -672,6 +673,35 @@ func TestAccCloudflareRecord_ClearTags(t *testing.T) { }) } +func TestAccCloudflareRecord_CompareIPv6(t *testing.T) { + t.Parallel() + zoneID := os.Getenv("CLOUDFLARE_ZONE_ID") + rnd := generateRandomResourceName() + name := fmt.Sprintf("cloudflare_record.%s", rnd) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: providerFactories, + CheckDestroy: testAccCheckCloudflareRecordDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckCloudflareRecordConfigIPv6(zoneID, rnd, rnd, "2001:4860:4860:0:0:0:0:8888"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(name, "name", rnd), + resource.TestCheckResourceAttr(name, "type", "AAAA"), + resource.TestCheckResourceAttr(name, "content", "2001:4860:4860:0:0:0:0:8888"), + ), + }, + { + Config: testAccCheckCloudflareRecordConfigIPv6(zoneID, rnd, rnd, "2001:4860:4860::8888"), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{plancheck.ExpectEmptyPlan()}, + }, + }, + }, + }) +} + func TestSuppressTrailingDots(t *testing.T) { t.Parallel() @@ -1076,3 +1106,14 @@ func testAccCheckCloudflareRecordDNSKEY(zoneID, name string) string { } `, zoneID, name) } + +func testAccCheckCloudflareRecordConfigIPv6(zoneID, name, rnd, content string) string { + return fmt.Sprintf(` +resource "cloudflare_record" "%[3]s" { + zone_id = "%[1]s" + name = "%[2]s" + content = "%[4]s" + type = "AAAA" + ttl = 3600 +}`, zoneID, name, rnd, content) +} From bda76ab512536e3f3848b10e635d3120de53b3ba Mon Sep 17 00:00:00 2001 From: Alex Luong Date: Tue, 3 Sep 2024 10:27:46 +0700 Subject: [PATCH 4/6] remove unused params --- internal/sdkv2provider/resource_cloudflare_record.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/sdkv2provider/resource_cloudflare_record.go b/internal/sdkv2provider/resource_cloudflare_record.go index c8cb876e63..33beea687e 100644 --- a/internal/sdkv2provider/resource_cloudflare_record.go +++ b/internal/sdkv2provider/resource_cloudflare_record.go @@ -503,7 +503,7 @@ func suppressTrailingDots(k, old, new string, d *schema.ResourceData) bool { return strings.TrimSuffix(old, ".") == newTrimmed } -func suppressMatchingIpv6(_, old, new string, _ *schema.ResourceData) bool { +func suppressMatchingIpv6(old, new string) bool { oldIpv6 := net.ParseIP(old) if oldIpv6 == nil || oldIpv6.To16() == nil { return false @@ -516,7 +516,7 @@ func suppressMatchingIpv6(_, old, new string, _ *schema.ResourceData) bool { } func suppressContent(k, old, new string, d *schema.ResourceData) bool { - if suppressMatchingIpv6(k, old, new, d) { + if suppressMatchingIpv6(old, new) { return true } return suppressTrailingDots(k, old, new, d) From 24be6afacb0c4d6df19399b4ed596fb92c4ffc5f Mon Sep 17 00:00:00 2001 From: Jacob Bednarz Date: Tue, 3 Sep 2024 14:52:09 +1000 Subject: [PATCH 5/6] fix test assertion --- internal/sdkv2provider/resource_cloudflare_record_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/sdkv2provider/resource_cloudflare_record_test.go b/internal/sdkv2provider/resource_cloudflare_record_test.go index 4893723dea..e76fae4f67 100644 --- a/internal/sdkv2provider/resource_cloudflare_record_test.go +++ b/internal/sdkv2provider/resource_cloudflare_record_test.go @@ -689,7 +689,7 @@ func TestAccCloudflareRecord_CompareIPv6(t *testing.T) { Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(name, "name", rnd), resource.TestCheckResourceAttr(name, "type", "AAAA"), - resource.TestCheckResourceAttr(name, "content", "2001:4860:4860:0:0:0:0:8888"), + resource.TestCheckResourceAttr(name, "content", "2001:4860:4860::8888"), ), }, { From d76c534c59ddbfbefa7fb26f07497a66926104d8 Mon Sep 17 00:00:00 2001 From: Jacob Bednarz Date: Tue, 3 Sep 2024 14:52:54 +1000 Subject: [PATCH 6/6] add more esoteric IPv6 shortened versions for unit tests --- .../resource_cloudflare_record_test.go | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/internal/sdkv2provider/resource_cloudflare_record_test.go b/internal/sdkv2provider/resource_cloudflare_record_test.go index e76fae4f67..0456329958 100644 --- a/internal/sdkv2provider/resource_cloudflare_record_test.go +++ b/internal/sdkv2provider/resource_cloudflare_record_test.go @@ -727,6 +727,28 @@ func TestSuppressTrailingDots(t *testing.T) { } } +func TestIPv6Comparison(t *testing.T) { + t.Parallel() + + cases := []struct { + old string + new string + }{ + {"2001:db8:3333:4444:5555:6666:7777:8888", "2001:db8:3333:4444:5555:6666:7777:8888"}, + {"1050:0000:0000:0000:0005:0600:300c:326b", "1050:0:0:0:5:0600:300c:326b"}, + {"ff06:0:0:0:0:0:0:c3", "ff06::c3"}, + {"0:0:0:0:0:0:0:0", "::"}, + {"2001:db8::", "2001:db8:0:0:0:0:0:0"}, + {"::1234:5678", "0:0:0:0:0:0:1234:5678"}, + {"2001:db8:0:0:0:0:1234:5678", "2001:db8::1234:5678"}, + } + + for _, c := range cases { + got := suppressContent("", c.old, c.new, nil) + assert.Equal(t, true, got) + } +} + func testAccCheckCloudflareRecordRecreated(before, after *cloudflare.DNSRecord) resource.TestCheckFunc { return func(s *terraform.State) error { if before.ID == after.ID {