From ccc350197ff8f70e3d38b3adfdacfd2a28ca9311 Mon Sep 17 00:00:00 2001 From: bill fumerola Date: Sun, 7 Aug 2016 17:36:27 -0700 Subject: [PATCH] provider/google: atomic Cloud DNS record changes (#6575) Closes #6129 --- dns_change.go | 9 ++- resource_dns_record_set.go | 105 +++++++++++++++++++++++--------- resource_dns_record_set_test.go | 95 +++++++++++++++++++++++++---- 3 files changed, 168 insertions(+), 41 deletions(-) diff --git a/dns_change.go b/dns_change.go index 38a34135..f2f827a3 100644 --- a/dns_change.go +++ b/dns_change.go @@ -1,6 +1,8 @@ package google import ( + "time" + "google.golang.org/api/dns/v1" "github.com/hashicorp/terraform/helper/resource" @@ -30,9 +32,14 @@ func (w *DnsChangeWaiter) RefreshFunc() resource.StateRefreshFunc { } func (w *DnsChangeWaiter) Conf() *resource.StateChangeConf { - return &resource.StateChangeConf{ + state := &resource.StateChangeConf{ Pending: []string{"pending"}, Target: []string{"done"}, Refresh: w.RefreshFunc(), } + state.Delay = 10 * time.Second + state.Timeout = 10 * time.Minute + state.MinTimeout = 2 * time.Second + return state + } diff --git a/resource_dns_record_set.go b/resource_dns_record_set.go index 22f9c60c..49a56d9b 100644 --- a/resource_dns_record_set.go +++ b/resource_dns_record_set.go @@ -3,7 +3,6 @@ package google import ( "fmt" "log" - "time" "github.com/hashicorp/terraform/helper/schema" "google.golang.org/api/dns/v1" @@ -15,6 +14,7 @@ func resourceDnsRecordSet() *schema.Resource { Create: resourceDnsRecordSetCreate, Read: resourceDnsRecordSetRead, Delete: resourceDnsRecordSetDelete, + Update: resourceDnsRecordSetUpdate, Schema: map[string]*schema.Schema{ "managed_zone": &schema.Schema{ @@ -32,7 +32,6 @@ func resourceDnsRecordSet() *schema.Resource { "rrdatas": &schema.Schema{ Type: schema.TypeList, Required: true, - ForceNew: true, Elem: &schema.Schema{ Type: schema.TypeString, }, @@ -41,13 +40,11 @@ func resourceDnsRecordSet() *schema.Resource { "ttl": &schema.Schema{ Type: schema.TypeInt, Required: true, - ForceNew: true, }, "type": &schema.Schema{ Type: schema.TypeString, Required: true, - ForceNew: true, }, "project": &schema.Schema{ @@ -69,8 +66,6 @@ func resourceDnsRecordSetCreate(d *schema.ResourceData, meta interface{}) error zone := d.Get("managed_zone").(string) - rrdatasCount := d.Get("rrdatas.#").(int) - // Build the change chg := &dns.Change{ Additions: []*dns.ResourceRecordSet{ @@ -78,16 +73,11 @@ func resourceDnsRecordSetCreate(d *schema.ResourceData, meta interface{}) error Name: d.Get("name").(string), Type: d.Get("type").(string), Ttl: int64(d.Get("ttl").(int)), - Rrdatas: make([]string, rrdatasCount), + Rrdatas: rrdata(d), }, }, } - for i := 0; i < rrdatasCount; i++ { - rrdata := fmt.Sprintf("rrdatas.%d", i) - chg.Additions[0].Rrdatas[i] = d.Get(rrdata).(string) - } - log.Printf("[DEBUG] DNS Record create request: %#v", chg) chg, err = config.clientDns.Changes.Create(project, zone, chg).Do() if err != nil { @@ -102,11 +92,7 @@ func resourceDnsRecordSetCreate(d *schema.ResourceData, meta interface{}) error Project: project, ManagedZone: zone, } - state := w.Conf() - state.Delay = 10 * time.Second - state.Timeout = 10 * time.Minute - state.MinTimeout = 2 * time.Second - _, err = state.WaitForState() + _, err = w.Conf().WaitForState() if err != nil { return fmt.Errorf("Error waiting for Google DNS change: %s", err) } @@ -167,8 +153,6 @@ func resourceDnsRecordSetDelete(d *schema.ResourceData, meta interface{}) error zone := d.Get("managed_zone").(string) - rrdatasCount := d.Get("rrdatas.#").(int) - // Build the change chg := &dns.Change{ Deletions: []*dns.ResourceRecordSet{ @@ -176,15 +160,11 @@ func resourceDnsRecordSetDelete(d *schema.ResourceData, meta interface{}) error Name: d.Get("name").(string), Type: d.Get("type").(string), Ttl: int64(d.Get("ttl").(int)), - Rrdatas: make([]string, rrdatasCount), + Rrdatas: rrdata(d), }, }, } - for i := 0; i < rrdatasCount; i++ { - rrdata := fmt.Sprintf("rrdatas.%d", i) - chg.Deletions[0].Rrdatas[i] = d.Get(rrdata).(string) - } log.Printf("[DEBUG] DNS Record delete request: %#v", chg) chg, err = config.clientDns.Changes.Create(project, zone, chg).Do() if err != nil { @@ -197,11 +177,7 @@ func resourceDnsRecordSetDelete(d *schema.ResourceData, meta interface{}) error Project: project, ManagedZone: zone, } - state := w.Conf() - state.Delay = 10 * time.Second - state.Timeout = 10 * time.Minute - state.MinTimeout = 2 * time.Second - _, err = state.WaitForState() + _, err = w.Conf().WaitForState() if err != nil { return fmt.Errorf("Error waiting for Google DNS change: %s", err) } @@ -209,3 +185,74 @@ func resourceDnsRecordSetDelete(d *schema.ResourceData, meta interface{}) error d.SetId("") return nil } + +func resourceDnsRecordSetUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + project, err := getProject(d, config) + if err != nil { + return err + } + + zone := d.Get("managed_zone").(string) + recordName := d.Get("name").(string) + + oldTtl, newTtl := d.GetChange("ttl") + oldType, newType := d.GetChange("type") + + oldCountRaw, _ := d.GetChange("rrdatas.#") + oldCount := oldCountRaw.(int) + + chg := &dns.Change{ + Deletions: []*dns.ResourceRecordSet{ + &dns.ResourceRecordSet{ + Name: recordName, + Type: oldType.(string), + Ttl: int64(oldTtl.(int)), + Rrdatas: make([]string, oldCount), + }, + }, + Additions: []*dns.ResourceRecordSet{ + &dns.ResourceRecordSet{ + Name: recordName, + Type: newType.(string), + Ttl: int64(newTtl.(int)), + Rrdatas: rrdata(d), + }, + }, + } + + for i := 0; i < oldCount; i++ { + rrKey := fmt.Sprintf("rrdatas.%d", i) + oldRR, _ := d.GetChange(rrKey) + chg.Deletions[0].Rrdatas[i] = oldRR.(string) + } + log.Printf("[DEBUG] DNS Record change request: %#v old: %#v new: %#v", chg, chg.Deletions[0], chg.Additions[0]) + chg, err = config.clientDns.Changes.Create(project, zone, chg).Do() + if err != nil { + return fmt.Errorf("Error changing DNS RecordSet: %s", err) + } + + w := &DnsChangeWaiter{ + Service: config.clientDns, + Change: chg, + Project: project, + ManagedZone: zone, + } + if _, err = w.Conf().WaitForState(); err != nil { + return fmt.Errorf("Error waiting for Google DNS change: %s", err) + } + + return resourceDnsRecordSetRead(d, meta) +} + +func rrdata( + d *schema.ResourceData, +) []string { + rrdatasCount := d.Get("rrdatas.#").(int) + data := make([]string, rrdatasCount) + for i := 0; i < rrdatasCount; i++ { + data[i] = d.Get(fmt.Sprintf("rrdatas.%d", i)).(string) + } + return data +} diff --git a/resource_dns_record_set_test.go b/resource_dns_record_set_test.go index 94c7fce1..1a128b7d 100644 --- a/resource_dns_record_set_test.go +++ b/resource_dns_record_set_test.go @@ -17,7 +17,64 @@ func TestAccDnsRecordSet_basic(t *testing.T) { CheckDestroy: testAccCheckDnsRecordSetDestroy, Steps: []resource.TestStep{ resource.TestStep{ - Config: testAccDnsRecordSet_basic(zoneName), + Config: testAccDnsRecordSet_basic(zoneName, "127.0.0.10", 300), + Check: resource.ComposeTestCheckFunc( + testAccCheckDnsRecordSetExists( + "google_dns_record_set.foobar", zoneName), + ), + }, + }, + }) +} + +func TestAccDnsRecordSet_modify(t *testing.T) { + zoneName := fmt.Sprintf("dnszone-test-%s", acctest.RandString(10)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckDnsRecordSetDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccDnsRecordSet_basic(zoneName, "127.0.0.10", 300), + Check: resource.ComposeTestCheckFunc( + testAccCheckDnsRecordSetExists( + "google_dns_record_set.foobar", zoneName), + ), + }, + resource.TestStep{ + Config: testAccDnsRecordSet_basic(zoneName, "127.0.0.11", 300), + Check: resource.ComposeTestCheckFunc( + testAccCheckDnsRecordSetExists( + "google_dns_record_set.foobar", zoneName), + ), + }, + resource.TestStep{ + Config: testAccDnsRecordSet_basic(zoneName, "127.0.0.11", 600), + Check: resource.ComposeTestCheckFunc( + testAccCheckDnsRecordSetExists( + "google_dns_record_set.foobar", zoneName), + ), + }, + }, + }) +} + +func TestAccDnsRecordSet_changeType(t *testing.T) { + zoneName := fmt.Sprintf("dnszone-test-%s", acctest.RandString(10)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckDnsRecordSetDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccDnsRecordSet_basic(zoneName, "127.0.0.10", 300), + Check: resource.ComposeTestCheckFunc( + testAccCheckDnsRecordSetExists( + "google_dns_record_set.foobar", zoneName), + ), + }, + resource.TestStep{ + Config: testAccDnsRecordSet_bigChange(zoneName, 600), Check: resource.ComposeTestCheckFunc( testAccCheckDnsRecordSetExists( "google_dns_record_set.foobar", zoneName), @@ -65,20 +122,19 @@ func testAccCheckDnsRecordSetExists(resourceType, resourceName string) resource. if err != nil { return fmt.Errorf("Error confirming DNS RecordSet existence: %#v", err) } - if len(resp.Rrsets) == 0 { + switch len(resp.Rrsets) { + case 0: // The resource doesn't exist anymore return fmt.Errorf("DNS RecordSet not found") - } - - if len(resp.Rrsets) > 1 { + case 1: + return nil + default: return fmt.Errorf("Only expected 1 record set, got %d", len(resp.Rrsets)) } - - return nil } } -func testAccDnsRecordSet_basic(zoneName string) string { +func testAccDnsRecordSet_basic(zoneName string, addr2 string, ttl int) string { return fmt.Sprintf(` resource "google_dns_managed_zone" "parent-zone" { name = "%s" @@ -89,8 +145,25 @@ func testAccDnsRecordSet_basic(zoneName string) string { managed_zone = "${google_dns_managed_zone.parent-zone.name}" name = "test-record.terraform.test." type = "A" - rrdatas = ["127.0.0.1", "127.0.0.10"] - ttl = 600 + rrdatas = ["127.0.0.1", "%s"] + ttl = %d } - `, zoneName) + `, zoneName, addr2, ttl) +} + +func testAccDnsRecordSet_bigChange(zoneName string, ttl int) string { + return fmt.Sprintf(` + resource "google_dns_managed_zone" "parent-zone" { + name = "%s" + dns_name = "terraform.test." + description = "Test Description" + } + resource "google_dns_record_set" "foobar" { + managed_zone = "${google_dns_managed_zone.parent-zone.name}" + name = "test-record.terraform.test." + type = "CNAME" + rrdatas = ["www.terraform.io."] + ttl = %d + } + `, zoneName, ttl) }