support for rdpool resource

This commit is contained in:
ebilhoo 2017-04-13 20:11:43 +00:00
parent 09031a9133
commit 11939b402c
3 changed files with 366 additions and 0 deletions

View File

@ -8,6 +8,29 @@ import (
"github.com/hashicorp/terraform/terraform" "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 { func testAccTcpoolCheckDestroy(s *terraform.State) error {
client := testAccProvider.Meta().(*udnssdk.Client) client := testAccProvider.Meta().(*udnssdk.Client)

View File

@ -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
}

View File

@ -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
}
}
`