diff --git a/.changelog/1740.txt b/.changelog/1740.txt new file mode 100644 index 0000000000..b8e8327b51 --- /dev/null +++ b/.changelog/1740.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/cloudflare_record: Validate that DNS record names are non-empty +``` diff --git a/internal/provider/resource_cloudflare_record.go b/internal/provider/resource_cloudflare_record.go index 12b9f984b1..2fc7e6af77 100644 --- a/internal/provider/resource_cloudflare_record.go +++ b/internal/provider/resource_cloudflare_record.go @@ -98,9 +98,13 @@ func resourceCloudflareRecordCreate(ctx context.Context, d *schema.ResourceData, newRecord.TTL = ttl.(int) } + if newRecord.Name == "" { + return diag.FromErr(fmt.Errorf("record on zone %s must not have an empty name (use @ for the zone apex)", newRecord.ZoneID)) + } + // Validate value based on type - if err := validateRecordName(newRecord.Type, newRecord.Content); err != nil { - return diag.FromErr(fmt.Errorf("error validating record name %q: %w", newRecord.Name, err)) + if err := validateRecordContent(newRecord.Type, newRecord.Content); err != nil { + return diag.FromErr(fmt.Errorf("error validating record content of %q: %w", newRecord.Name, err)) } var proxiedVal *bool @@ -185,8 +189,8 @@ func resourceCloudflareRecordRead(ctx context.Context, d *schema.ResourceData, m record, err := client.DNSRecord(ctx, zoneID, d.Id()) if err != nil { - if strings.Contains(err.Error(), "Invalid dns record identifier") || - strings.Contains(err.Error(), "HTTP status 404") { + var notFoundError *cloudflare.NotFoundError + if errors.As(err, ¬FoundError) { tflog.Warn(ctx, fmt.Sprintf("Removing record from state because it's not found in API")) d.SetId("") return nil diff --git a/internal/provider/resource_cloudflare_record_test.go b/internal/provider/resource_cloudflare_record_test.go index 2cd4b5306f..17eb2fc99e 100644 --- a/internal/provider/resource_cloudflare_record_test.go +++ b/internal/provider/resource_cloudflare_record_test.go @@ -476,7 +476,7 @@ func TestAccCloudflareRecord_MXWithPriorityZero(t *testing.T) { Config: testAccCheckCloudflareRecordConfigMXWithPriorityZero(zoneID, rnd, zoneName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "priority", "0"), - resource.TestCheckResourceAttr(resourceName, "value", "."), + resource.TestCheckResourceAttr(resourceName, "value", "mail.terraform.cfapi.net"), ), }, }, @@ -772,7 +772,7 @@ func testAccCheckCloudflareRecordConfigMXWithPriorityZero(zoneID, name, zoneName resource "cloudflare_record" "%[2]s" { zone_id = "%[1]s" name = "%[2]s" - value = "." + value = "mail.terraform.cfapi.net" type = "MX" priority = 0 proxied = false diff --git a/internal/provider/validators.go b/internal/provider/validators.go index 73ca3e956e..3a651e8f9c 100644 --- a/internal/provider/validators.go +++ b/internal/provider/validators.go @@ -27,9 +27,9 @@ func validateRecordType(t string, proxied bool) error { return fmt.Errorf("type %q cannot be proxied", t) } -// validateRecordName ensures that based on supplied record type, the name content matches -// Currently only validates A and AAAA types. -func validateRecordName(t string, value string) error { +// validateRecordContent ensures that the record's content is valid for the +// supplied record type. Currently only validates A and AAAA types. +func validateRecordContent(t string, value string) error { switch t { case "A": // Must be ipv4 addr diff --git a/internal/provider/validators_test.go b/internal/provider/validators_test.go index 6012957e5b..7b8175907c 100644 --- a/internal/provider/validators_test.go +++ b/internal/provider/validators_test.go @@ -51,8 +51,8 @@ func TestValidateRecordName(t *testing.T) { } for k, v := range validNames { - if err := validateRecordName(k, v); err != nil { - t.Fatalf("%q should be a valid name for type %q: %v", v, k, err) + if err := validateRecordContent(k, v); err != nil { + t.Fatalf("%q should be valid content for type %q: %v", v, k, err) } } @@ -62,8 +62,8 @@ func TestValidateRecordName(t *testing.T) { "TXT": "\n", } for k, v := range invalidNames { - if err := validateRecordName(k, v); err == nil { - t.Fatalf("%q should be an invalid name for type %q", v, k) + if err := validateRecordContent(k, v); err == nil { + t.Fatalf("%q should be invalid content for type %q", v, k) } } }