Skip to content

Commit

Permalink
Add retry logic to better handle concurrent API requests.
Browse files Browse the repository at this point in the history
  • Loading branch information
Johan Bloemberg committed Apr 18, 2019
1 parent cd13a67 commit 6154303
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 37 deletions.
3 changes: 3 additions & 0 deletions .envrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export TRANSIP_ACCOUNT_NAME=aequitas
export TRANSIP_TEST_DOMAIN=locohost.nl
export TRANSIP_PRIVATE_KEY=$(keyring get transip $TRANSIP_ACCOUNT_NAME)
10 changes: 8 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version = $(shell git describe --tags)
version = $(shell git describe --tags --abbrev=0)

releases = \
terraform-provider-transip_${version}_darwin_amd64.tgz \
Expand All @@ -16,7 +16,13 @@ deps: ${GOPATH}/src/github.com/transip/gotransip ${GOPATH}/src/github.com/hashic
${GOPATH}/src/github.com/transip/gotransip ${GOPATH}/src/github.com/hashicorp/terraform:
go get -d

test_integration: test
test_integration: TF_ACC=1

test: | deps
TF_ACC=${TF_ACC} go test -v

clean:
rm -rf terraform-provider-transip*.tgz build/
rm -rf terraform-provider-transip* build/

.PHONY: release
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,15 @@ data "transip_domain" "example_com" {
# Simple CNAME record
resource "transip_dns_record" "www" {
domain = "${transip_domain.example_com.id}"
domain = "${data.transip_domain.example_com.id}"
name = "www"
type = "CNAME"
content = ["@"]
}
# A record with multiple entries, eg: for round robin DNS
resource "transip_dns_record" "test" {
domain = "${transip_domain.example_com.id}"
domain = "${data.transip_domain.example_com.id}"
name = "test"
type = "A"
Expand All @@ -66,8 +66,8 @@ resource "transip_dns_record" "test" {
}
# IPv6 record
resource "transip_dns_record" "test" {
domain = "${transip_domain.example_com.id}"
resource "transip_dns_record" "testv6" {
domain = "${data.transip_domain.example_com.id}"
name = "test"
expire = 300
type = "AAAA"
Expand All @@ -84,14 +84,14 @@ data "transip_vps" "test" {
# Set hostname for VPS using data source
resource "transip_dns_record" "vps" {
domain = "${transip_domain.example_com.id}"
domain = "${data.transip_domain.example_com.id}"
name = "vps"
type = "A"
content = ["${data.transip_vps.test.ipv4_address}"]
}
resource "transip_dns_record" "vps" {
domain = "${transip_domain.example_com.id}"
domain = "${data.transip_domain.example_com.id}"
name = "vps"
type = "AAAA"
Expand Down
8 changes: 2 additions & 6 deletions data_source_transip_domain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
)

func TestAccTransipDataSourceDomain(t *testing.T) {
var testConfig = `data "transip_domain" "test" {name = "%s"}`

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Expand All @@ -24,9 +26,3 @@ func TestAccTransipDataSourceDomain(t *testing.T) {
},
})
}

var testConfig = `
data "transip_domain" "test" {
name = "%s"
}
`
65 changes: 42 additions & 23 deletions resource_transip_dns_record.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"strings"

"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/helper/validation"
"github.com/transip/gotransip"
Expand Down Expand Up @@ -138,34 +139,52 @@ func resourceDNSRecordUpdate(d *schema.ResourceData, m interface{}) error {
entryType := domain.DNSEntryType(d.Get("type").(string))
content := d.Get("content").([]interface{})

dom, err := domain.GetInfo(client, domainName)
if err != nil {
return fmt.Errorf("failed to get domain %s for writing DNS record entries: %s", domainName, err)
}
return resource.Retry(d.Timeout(schema.TimeoutCreate), func() *resource.RetryError {
dom, err := domain.GetInfo(client, domainName)
if err != nil {
return resource.NonRetryableError(
fmt.Errorf("failed to get domain %s for writing DNS record entries: %s", domainName, err))
}

var newEntries []domain.DNSEntry
for _, e := range dom.DNSEntries {
if e.Name == entryName && e.Type == entryType {
continue
var newEntries []domain.DNSEntry
for _, e := range dom.DNSEntries {
if e.Name == entryName && e.Type == entryType {
continue
}
newEntries = append(newEntries, e)
}
newEntries = append(newEntries, e)
}

for _, c := range content {
newEntries = append(newEntries, domain.DNSEntry{
Name: entryName,
TTL: expire,
Type: entryType,
Content: c.(string),
})
}
for _, c := range content {
newEntries = append(newEntries, domain.DNSEntry{
Name: entryName,
TTL: expire,
Type: entryType,
Content: c.(string),
})
}

err = domain.SetDNSEntries(client, domainName, newEntries)
if err != nil {
return fmt.Errorf("failed to update DNS entries for domain %s: %s", domainName, err)
}
err = domain.SetDNSEntries(client, domainName, newEntries)

// this happens on concurrent requests where another API request is accessing the same object
if err != nil && strings.Contains(err.Error(), "OBJECT_IS_LOCKED") {
return resource.RetryableError(fmt.Errorf("Domain is locked: %s", err))
}

// This happens on concurrent requests where another API request is accessing the same object or
// a race condition where the previously read object was modified and saved.
// SOAP Fault 100: Je probeert een oude versie van dit object op te slaan. Er is al een nieuwere versie beschikbaar.
// SOAP Fault 100: Er is een interne fout opgetreden, neem a.u.b. contact op met support. (OBJECT_IS_LOCKED)
if err != nil && strings.Contains(err.Error(), "SOAP Fault 100") {
return resource.RetryableError(fmt.Errorf("Domain object is locked or changed during API call: %s", err))
}

if err != nil {
return resource.NonRetryableError(
fmt.Errorf("failed to update DNS entries for domain %s: %s", domainName, err))
}

return resourceDNSRecordRead(d, m)
return resource.NonRetryableError(resourceDNSRecordRead(d, m))
})
}

func resourceDNSRecordDelete(d *schema.ResourceData, m interface{}) error {
Expand Down
75 changes: 75 additions & 0 deletions resource_transip_dns_record_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package main

import (
"fmt"
"os"
"testing"
"time"

"github.com/hashicorp/terraform/helper/resource"
)

func TestAccTransipResourceDomain(t *testing.T) {
timestamp := time.Now().Unix()
testConfig := fmt.Sprintf(`
data "transip_domain" "test" {
name = "%s"
}
resource "transip_dns_record" "test1" {
domain = "${data.transip_domain.test.id}"
name = "_terraform_provider_transip1_%d"
type = "CNAME"
content = ["@"]
}
`, os.Getenv("TRANSIP_TEST_DOMAIN"), timestamp)

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testConfig,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet("transip_dns_record.test1", "name"),
),
},
},
})
}

func TestAccTransipResourceDomainConcurrent(t *testing.T) {
timestamp := time.Now().Unix()
testConfig := fmt.Sprintf(`
data "transip_domain" "test" {
name = "%s"
}
resource "transip_dns_record" "test1" {
domain = "${data.transip_domain.test.id}"
name = "_terraform_provider_transip1_%d"
type = "CNAME"
content = ["@"]
}
resource "transip_dns_record" "test2" {
domain = "${data.transip_domain.test.id}"
name = "_terraform_provider_transip2_%d"
type = "CNAME"
content = ["@"]
}
`, os.Getenv("TRANSIP_TEST_DOMAIN"), timestamp, timestamp)

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testConfig,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet("transip_dns_record.test1", "name"),
),
},
},
})
}

0 comments on commit 6154303

Please sign in to comment.