Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

resource/cloudflare_record: handle import for data #1942

Merged
merged 1 commit into from
Sep 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/1942.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:bug
resource/cloudflare_record: update Read method to pull from remote API instead of local configuration which is empty during `Import`
```
31 changes: 27 additions & 4 deletions internal/provider/import_resource_cloudflare_record_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,43 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

func TestAccCloudflareRecord_Import(t *testing.T) {
func TestAccCloudflareRecord_ImportBasic(t *testing.T) {
zoneID := os.Getenv("CLOUDFLARE_ZONE_ID")
rnd := generateRandomResourceName()
name := fmt.Sprintf("cloudflare_record.%s", rnd)
resourceName := fmt.Sprintf("cloudflare_record.%s", rnd)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: testAccCheckCloudflareRecordConfigBasic(zoneID, rnd, rnd),
},
{
ResourceName: resourceName,
ImportStateIdPrefix: fmt.Sprintf("%s/", zoneID),
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"allow_overwrite"},
},
},
})
}

func TestAccCloudflareRecord_ImportSRV(t *testing.T) {
zoneID := os.Getenv("CLOUDFLARE_ZONE_ID")
rnd := generateRandomResourceName()
resourceName := fmt.Sprintf("cloudflare_record.%s", rnd)
domain := os.Getenv("CLOUDFLARE_DOMAIN")

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: testAccCheckCloudflareRecordConfigBasic(zoneID, name, rnd),
Config: testAccCheckCloudflareRecordConfigSRV(zoneID, rnd, domain),
},
{
ResourceName: name,
ResourceName: resourceName,
ImportStateIdPrefix: fmt.Sprintf("%s/", zoneID),
ImportState: true,
ImportStateVerify: true,
Expand Down
19 changes: 13 additions & 6 deletions internal/provider/resource_cloudflare_record.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,15 +198,14 @@ func resourceCloudflareRecordRead(ctx context.Context, d *schema.ResourceData, m
return diag.FromErr(err)
}

data, dataOk := d.GetOk("data")
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the crux of the bug; it would look in d.Get for the value which on Import would never exist. this should have always pulled from the API anyway to ensure the remote was the source of truth, not the local files.

tflog.Debug(ctx, fmt.Sprintf("Data found in config: %#v", data))
tflog.Debug(ctx, fmt.Sprintf("Data found in config: %#v", record.Data))

readDataMap := make(map[string]interface{})

if dataOk {
dataMap := data.([]interface{})[0]
if record.Data != nil {
dataMap := record.Data.(map[string]interface{})
if dataMap != nil {
for id, value := range dataMap.(map[string]interface{}) {
for id, value := range dataMap {
newData, err := transformToCloudflareDNSData(record.Type, id, value)
if err != nil {
return diag.FromErr(err)
Expand Down Expand Up @@ -409,11 +408,19 @@ func transformToCloudflareDNSData(recordType string, id string, value interface{
case id == "flags":
switch {
case strings.ToUpper(recordType) == "SRV",
strings.ToUpper(recordType) == "CAA",
strings.ToUpper(recordType) == "DNSKEY":
newValue, err = value.(string), nil
case strings.ToUpper(recordType) == "NAPTR":
newValue, err = value.(string), nil
case strings.ToUpper(recordType) == "CAA":
// this is required because "flags" is shared however, it comes from
// the API as a float64 but the Terraform internal type is string 😢.
switch value.(type) {
case float64:
newValue, err = fmt.Sprintf("%.0f", value.(float64)), nil
case string:
newValue, err = value.(string), nil
}
}
case contains(dnsTypeIntFields, id):
newValue, err = value, nil
Expand Down
21 changes: 11 additions & 10 deletions internal/provider/resource_cloudflare_record_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,10 +199,11 @@ func TestAccCloudflareRecord_SRV(t *testing.T) {
CheckDestroy: testAccCheckCloudflareRecordDestroy,
Steps: []resource.TestStep{
{
Config: testAccCheckCloudflareRecordConfigSRV(zoneID, "tf-acctest-srv", rnd),
Config: testAccCheckCloudflareRecordConfigSRV(zoneID, rnd, domain),
Check: resource.ComposeTestCheckFunc(
testAccCheckCloudflareRecordExists(resourceName, &record),
resource.TestCheckResourceAttr(resourceName, "hostname", fmt.Sprintf("_xmpp-client._tcp.tf-acctest-srv.%s", domain)),
resource.TestCheckResourceAttr(resourceName, "name", fmt.Sprintf("_xmpp-client._tcp.%s", rnd)),
resource.TestCheckResourceAttr(resourceName, "hostname", fmt.Sprintf("_xmpp-client._tcp.%s.%s", rnd, domain)),
resource.TestCheckResourceAttr(resourceName, "value", "0 5222 talk.l.google.com"),
resource.TestCheckResourceAttr(resourceName, "proxiable", "false"),
resource.TestCheckResourceAttr(resourceName, "data.0.priority", "5"),
Expand All @@ -211,7 +212,7 @@ func TestAccCloudflareRecord_SRV(t *testing.T) {
resource.TestCheckResourceAttr(resourceName, "data.0.target", "talk.l.google.com"),
resource.TestCheckResourceAttr(resourceName, "data.0.service", "_xmpp-client"),
resource.TestCheckResourceAttr(resourceName, "data.0.proto", "_tcp"),
resource.TestCheckResourceAttr(resourceName, "data.0.name", "tf-acctest-srv"),
resource.TestCheckResourceAttr(resourceName, "data.0.name", rnd+"."+domain),
),
},
},
Expand Down Expand Up @@ -526,7 +527,7 @@ func TestAccCloudflareRecord_HTTPS(t *testing.T) {
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(name, "data.0.priority", "1"),
resource.TestCheckResourceAttr(name, "data.0.target", "."),
resource.TestCheckResourceAttr(name, "data.0.value", "alpn=h2"),
resource.TestCheckResourceAttr(name, "data.0.value", `alpn="h2"`),
),
},
},
Expand Down Expand Up @@ -688,23 +689,23 @@ resource "cloudflare_record" "%[3]s" {
}`, zoneID, name, rnd)
}

func testAccCheckCloudflareRecordConfigSRV(zoneID, name, rnd string) string {
func testAccCheckCloudflareRecordConfigSRV(zoneID, rnd, domain string) string {
return fmt.Sprintf(`
resource "cloudflare_record" "%[3]s" {
resource "cloudflare_record" "%[2]s" {
zone_id = "%[1]s"
name = "%[2]s"
name = "_xmpp-client._tcp.%[2]s"
data {
priority = 5
weight = 0
port = 5222
target = "talk.l.google.com"
service = "_xmpp-client"
proto = "_tcp"
name = "%[2]s"
name = "%[2]s.%[3]s"
}
type = "SRV"
ttl = 3600
}`, zoneID, name, rnd)
}`, zoneID, rnd, domain)
}

func testAccCheckCloudflareRecordConfigCAA(resourceName, zoneID, name string, ttl int) string {
Expand Down Expand Up @@ -812,7 +813,7 @@ resource "cloudflare_record" "%[2]s" {
data {
priority = "1"
target = "."
value = "alpn=h2"
value = "alpn=\"h2\""
}
ttl = 300
}`, zoneID, rnd)
Expand Down