From 11939b402caa267fc31c4e63d7aaf15a77b5d06c Mon Sep 17 00:00:00 2001 From: ebilhoo Date: Thu, 13 Apr 2017 20:11:43 +0000 Subject: [PATCH] support for rdpool resource --- builtin/providers/ultradns/common_test.go | 23 ++ .../ultradns/resource_ultradns_rdpool.go | 243 ++++++++++++++++++ .../ultradns/resource_ultradns_rdpool_test.go | 100 +++++++ 3 files changed, 366 insertions(+) create mode 100644 builtin/providers/ultradns/resource_ultradns_rdpool.go create mode 100644 builtin/providers/ultradns/resource_ultradns_rdpool_test.go diff --git a/builtin/providers/ultradns/common_test.go b/builtin/providers/ultradns/common_test.go index 24470e0d3..05823fdcd 100644 --- a/builtin/providers/ultradns/common_test.go +++ b/builtin/providers/ultradns/common_test.go @@ -8,6 +8,29 @@ import ( "github.com/hashicorp/terraform/terraform" ) +func testAccRdpoolCheckDestroy(s *terraform.State) error { + client := testAccProvider.Meta().(*udnssdk.Client) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "ultradns_rdpool" { + continue + } + + k := udnssdk.RRSetKey{ + Zone: rs.Primary.Attributes["zone"], + Name: rs.Primary.Attributes["name"], + Type: rs.Primary.Attributes["type"], + } + + _, err := client.RRSets.Select(k) + if err == nil { + return fmt.Errorf("Record still exists") + } + } + + return nil +} + func testAccTcpoolCheckDestroy(s *terraform.State) error { client := testAccProvider.Meta().(*udnssdk.Client) diff --git a/builtin/providers/ultradns/resource_ultradns_rdpool.go b/builtin/providers/ultradns/resource_ultradns_rdpool.go new file mode 100644 index 000000000..e67b57219 --- /dev/null +++ b/builtin/providers/ultradns/resource_ultradns_rdpool.go @@ -0,0 +1,243 @@ +package ultradns + +import ( + "fmt" + "log" + "strings" + + "github.com/Ensighten/udnssdk" + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceUltradnsRdpool() *schema.Resource { + return &schema.Resource{ + Create: resourceUltradnsRdpoolCreate, + Read: resourceUltradnsRdpoolRead, + Update: resourceUltradnsRdpoolUpdate, + Delete: resourceUltradnsRdpoolDelete, + + Schema: map[string]*schema.Schema{ + // Required + "zone": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "order": &schema.Schema{ + Type: schema.TypeString, + Required: true, + // 0-255 char + // FIXED | RANDOM | ROUND_ROBIN + }, + "rdata": &schema.Schema{ + Type: schema.TypeSet, + Set: schema.HashString, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + // Optional + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + // 0-255 char + }, + "ttl": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Default: 3600, + }, + // Computed + "hostname": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +// CRUD Operations + +func resourceUltradnsRdpoolCreate(d *schema.ResourceData, meta interface{}) error { + log.Printf("[INFO] ultradns_rdpool create") + client := meta.(*udnssdk.Client) + + r, err := newRRSetResourceFromRdpool(d) + if err != nil { + return err + } + + log.Printf("[INFO] ultradns_rdpool create: %#v", r) + _, err = client.RRSets.Create(r.RRSetKey(), r.RRSet()) + if err != nil { + return fmt.Errorf("create failed: %#v -> %v", r, err) + } + + d.SetId(r.ID()) + log.Printf("[INFO] ultradns_rdpool.id: %v", d.Id()) + + return resourceUltradnsRdpoolRead(d, meta) +} + +func resourceUltradnsRdpoolRead(d *schema.ResourceData, meta interface{}) error { + log.Printf("[INFO] ultradns_rdpool read") + client := meta.(*udnssdk.Client) + + rr, err := newRRSetResourceFromRdpool(d) + if err != nil { + return err + } + + rrsets, err := client.RRSets.Select(rr.RRSetKey()) + if err != nil { + uderr, ok := err.(*udnssdk.ErrorResponseList) + if ok { + for _, resps := range uderr.Responses { + // 70002 means Records Not Found + if resps.ErrorCode == 70002 { + d.SetId("") + return nil + } + return fmt.Errorf("resource not found: %v", err) + } + } + return fmt.Errorf("resource not found: %v", err) + } + + r := rrsets[0] + + zone := d.Get("zone") + // ttl + d.Set("ttl", r.TTL) + // hostname + if r.OwnerName == "" { + d.Set("hostname", zone) + } else { + if strings.HasSuffix(r.OwnerName, ".") { + d.Set("hostname", r.OwnerName) + } else { + d.Set("hostname", fmt.Sprintf("%s.%s", r.OwnerName, zone)) + } + } + + // And now... the Profile! + if r.Profile == nil { + return fmt.Errorf("RRSet.profile missing: invalid RDPool schema in: %#v", r) + } + p, err := r.Profile.RDPoolProfile() + if err != nil { + return fmt.Errorf("RRSet.profile could not be unmarshalled: %v\n", err) + } + + // Set simple values + d.Set("description", p.Description) + d.Set("order", p.Order) + + // TODO: rigorously test this to see if we can remove the error handling + + //TODO + + //err = d.Set("rdata", makeSetFromStrings(r.RData)) + //err = d.Set("rdata", makeSetFromRdataAlone(r.RData)) + if err != nil { + return fmt.Errorf("rdata set failed: %#v", err) + } + return nil +} + +func resourceUltradnsRdpoolUpdate(d *schema.ResourceData, meta interface{}) error { + log.Printf("[INFO] ultradns_rdpool update") + client := meta.(*udnssdk.Client) + + r, err := newRRSetResourceFromRdpool(d) + if err != nil { + return err + } + + log.Printf("[INFO] ultradns_rdpool update: %+v", r) + _, err = client.RRSets.Update(r.RRSetKey(), r.RRSet()) + if err != nil { + return fmt.Errorf("resource update failed: %v", err) + } + + return resourceUltradnsRdpoolRead(d, meta) +} + +func resourceUltradnsRdpoolDelete(d *schema.ResourceData, meta interface{}) error { + log.Printf("[INFO] ultradns_rdpool delete") + client := meta.(*udnssdk.Client) + + r, err := newRRSetResourceFromRdpool(d) + if err != nil { + return err + } + + log.Printf("[INFO] ultradns_rdpool delete: %+v", r) + _, err = client.RRSets.Delete(r.RRSetKey()) + if err != nil { + return fmt.Errorf("resource delete failed: %v", err) + } + + return nil +} + +// Resource Helpers + +func newRRSetResourceFromRdpool(d *schema.ResourceData) (rRSetResource, error) { + //rDataRaw := d.Get("rdata").(*schema.Set).List() + r := rRSetResource{ + // "The only valid rrtype value for SiteBacker or Traffic Controller pools is A" + // per https://portal.ultradns.com/static/docs/REST-API_User_Guide.pdf + RRType: "A", + Zone: d.Get("zone").(string), + OwnerName: d.Get("name").(string), + TTL: d.Get("ttl").(int), + //RData: unzipRdataHosts(rDataRaw), + } + if attr, ok := d.GetOk("rdata"); ok { + rdata := attr.(*schema.Set).List() + r.RData = make([]string, len(rdata)) + for i, j := range rdata { + r.RData[i] = j.(string) + } + } + + profile := udnssdk.RDPoolProfile{ + Context: udnssdk.RDPoolSchema, + Order: d.Get("order").(string), + Description: d.Get("description").(string), + } + + rp := profile.RawProfile() + r.Profile = rp + + return r, nil +} + +// zip RData into []map[string]interface{} +func zipRDataAlone(rds []string) []map[string]interface{} { + result := make([]map[string]interface{}, 0, len(rds)) + for _, rd := range rds { + r := map[string]interface{}{ + // "host": rds[i], + "host": rd, + } + result = append(result, r) + } + return result +} + +// makeSetFromRdatas encodes an array of Rdata into a +// *schema.Set in the appropriate structure for the schema +func makeSetFromRdataAlone(rds []string) *schema.Set { + s := &schema.Set{F: hashRdatas} + rs := zipRDataAlone(rds) + for _, r := range rs { + s.Add(r) + } + return s +} diff --git a/builtin/providers/ultradns/resource_ultradns_rdpool_test.go b/builtin/providers/ultradns/resource_ultradns_rdpool_test.go new file mode 100644 index 000000000..1ddd9c025 --- /dev/null +++ b/builtin/providers/ultradns/resource_ultradns_rdpool_test.go @@ -0,0 +1,100 @@ +package ultradns + +import ( + "fmt" + "testing" + + "github.com/Ensighten/udnssdk" + "github.com/hashicorp/terraform/helper/resource" +) + +func TestAccUltradnsRdpool(t *testing.T) { + var record udnssdk.RRSet + domain := "ultradns.phinze.com" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccRdpoolCheckDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: fmt.Sprintf(testCfgRdpoolMinimal, domain), + Check: resource.ComposeTestCheckFunc( + testAccCheckUltradnsRecordExists("ultradns_rdpool.it", &record), + // Specified + resource.TestCheckResourceAttr("ultradns_rdpool.it", "zone", domain), + resource.TestCheckResourceAttr("ultradns_rdpool.it", "name", "test-rdpool-minimal"), + resource.TestCheckResourceAttr("ultradns_rdpool.it", "ttl", "300"), + + // hashRdatas(): 10.6.0.1 -> 2847814707 + resource.TestCheckResourceAttr("ultradns_rdpool.it", "rdata.2847814707.host", "10.6.0.1"), + // Defaults + resource.TestCheckResourceAttr("ultradns_rdpool.it", "description", "Minimal RD Pool"), + resource.TestCheckResourceAttr("ultradns_rdpool.it", "rdata.2847814707.priority", "1"), + // Generated + resource.TestCheckResourceAttr("ultradns_rdpool.it", "id", "test-rdpool-minimal.ultradns.phinze.com"), + resource.TestCheckResourceAttr("ultradns_rdpool.it", "hostname", "test-rdpool-minimal.ultradns.phinze.com."), + ), + }, + resource.TestStep{ + Config: fmt.Sprintf(testCfgRdpoolMaximal, domain), + Check: resource.ComposeTestCheckFunc( + testAccCheckUltradnsRecordExists("ultradns_rdpool.it", &record), + // Specified + resource.TestCheckResourceAttr("ultradns_rdpool.it", "zone", domain), + resource.TestCheckResourceAttr("ultradns_rdpool.it", "name", "test-rdpool-maximal"), + resource.TestCheckResourceAttr("ultradns_rdpool.it", "ttl", "300"), + resource.TestCheckResourceAttr("ultradns_rdpool.it", "description", "traffic controller pool with all settings tuned"), + + resource.TestCheckResourceAttr("ultradns_rdpool.it", "act_on_probes", "false"), + resource.TestCheckResourceAttr("ultradns_rdpool.it", "max_to_lb", "2"), + resource.TestCheckResourceAttr("ultradns_rdpool.it", "run_probes", "false"), + + // hashRdatas(): 10.6.1.1 -> 2826722820 + resource.TestCheckResourceAttr("ultradns_rdpool.it", "rdata.2826722820.host", "10.6.1.1"), + resource.TestCheckResourceAttr("ultradns_rdpool.it", "rdata.2826722820.priority", "1"), + + // hashRdatas(): 10.6.1.2 -> 829755326 + resource.TestCheckResourceAttr("ultradns_rdpool.it", "rdata.829755326.host", "10.6.1.2"), + resource.TestCheckResourceAttr("ultradns_rdpool.it", "rdata.829755326.priority", "2"), + + // Generated + resource.TestCheckResourceAttr("ultradns_rdpool.it", "id", "test-rdpool-maximal.ultradns.phinze.com"), + resource.TestCheckResourceAttr("ultradns_rdpool.it", "hostname", "test-rdpool-maximal.ultradns.phinze.com."), + ), + }, + }, + }) +} + +const testCfgRdpoolMinimal = ` +resource "ultradns_rdpool" "it" { + zone = "%s" + name = "test-rdpool-minimal" + ttl = 300 + description = "Minimal RD Pool" + + rdata { + host = "10.6.0.1" + } +} +` + +const testCfgRdpoolMaximal = ` +resource "ultradns_rdpool" "it" { + zone = "%s" + name = "test-rdpool-maximal" + order = "ROUND_ROBIN" + ttl = 300 + description = "traffic controller pool with all settings tuned" + rdata { + host = "10.6.1.1" + priority = 1 + } + + rdata { + host = "10.6.1.2" + priority = 2 + } +} +`