UltraDNS Provider

This commit is contained in:
Josh Masseo 2015-07-04 03:26:13 -05:00 committed by Paul Hinze
parent 85b4b5813f
commit 1b4991163f
23 changed files with 2606 additions and 0 deletions

4
Godeps/Godeps.json generated
View File

@ -154,6 +154,10 @@
"ImportPath": "github.com/DreamItGetIT/statuscake",
"Rev": "8cbe86575f00210a6df2c19cb2f59b00cd181de3"
},
{
"ImportPath": "github.com/Ensighten/udnssdk",
"Rev": "0290933f5e8afd933f2823fce32bf2847e6ea603"
},
{
"ImportPath": "github.com/apparentlymart/go-cidr/cidr",
"Rev": "a3ebdb999b831ecb6ab8a226e31b07b2b9061c47"

View File

@ -0,0 +1,12 @@
package main
import (
"github.com/hashicorp/terraform/builtin/providers/ultradns"
"github.com/hashicorp/terraform/plugin"
)
func main() {
plugin.Serve(&plugin.ServeOpts{
ProviderFunc: ultradns.Provider,
})
}

View File

@ -0,0 +1,28 @@
package ultradns
import (
"fmt"
"log"
"github.com/Ensighten/udnssdk"
)
// Config collects the connection service-endpoint and credentials
type Config struct {
Username string
Password string
BaseURL string
}
// Client returns a new client for accessing UltraDNS.
func (c *Config) Client() (*udnssdk.Client, error) {
client, err := udnssdk.NewClient(c.Username, c.Password, c.BaseURL)
if err != nil {
return nil, fmt.Errorf("Error setting up client: %s", err)
}
log.Printf("[INFO] UltraDNS Client configured for user: %s", client.Username)
return client, nil
}

View File

@ -0,0 +1,49 @@
package ultradns
import (
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/terraform"
)
// Provider returns a terraform.ResourceProvider.
func Provider() terraform.ResourceProvider {
return &schema.Provider{
Schema: map[string]*schema.Schema{
"username": &schema.Schema{
Type: schema.TypeString,
Required: true,
DefaultFunc: schema.EnvDefaultFunc("ULTRADNS_USERNAME", nil),
Description: "UltraDNS Username.",
},
"password": &schema.Schema{
Type: schema.TypeString,
Required: true,
DefaultFunc: schema.EnvDefaultFunc("ULTRADNS_PASSWORD", nil),
Description: "UltraDNS User Password",
},
"baseurl": &schema.Schema{
Type: schema.TypeString,
Required: true,
DefaultFunc: schema.EnvDefaultFunc("ULTRADNS_BASEURL", nil),
Description: "UltraDNS Base Url(defaults to testing)",
},
},
ResourcesMap: map[string]*schema.Resource{
"ultradns_record": resourceUltraDNSRecord(),
},
ConfigureFunc: providerConfigure,
}
}
func providerConfigure(d *schema.ResourceData) (interface{}, error) {
config := Config{
Username: d.Get("username").(string),
Password: d.Get("password").(string),
BaseURL: d.Get("baseurl").(string),
}
return config.Client()
}

View File

@ -0,0 +1,43 @@
package ultradns
import (
"os"
"testing"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/terraform"
)
var testAccProviders map[string]terraform.ResourceProvider
var testAccProvider *schema.Provider
func init() {
testAccProvider = Provider().(*schema.Provider)
testAccProviders = map[string]terraform.ResourceProvider{
"ultradns": testAccProvider,
}
}
func TestProvider(t *testing.T) {
if err := Provider().(*schema.Provider).InternalValidate(); err != nil {
t.Fatalf("err: %s", err)
}
}
func TestProvider_impl(t *testing.T) {
var _ terraform.ResourceProvider = Provider()
}
func testAccPreCheck(t *testing.T) {
if v := os.Getenv("ULTRADNS_USERNAME"); v == "" {
t.Fatal("ULTRADNS_USERNAME must be set for acceptance tests")
}
if v := os.Getenv("ULTRADNS_PASSWORD"); v == "" {
t.Fatal("ULTRADNS_PASSWORD must be set for acceptance tests")
}
if v := os.Getenv("ULTRADNS_DOMAIN"); v == "" {
t.Fatal("ULTRADNS_DOMAIN must be set for acceptance tests. The domain is used to create and destroy record against.")
}
}

View File

@ -0,0 +1,218 @@
package ultradns
import (
"fmt"
"log"
"strconv"
"strings"
"github.com/Ensighten/udnssdk"
"github.com/hashicorp/terraform/helper/schema"
)
type rRSetResource struct {
OwnerName string
RRType string
RData []string
TTL int
Profile *udnssdk.StringProfile
Zone string
}
func newRRSetResource(d *schema.ResourceData) (rRSetResource, error) {
r := rRSetResource{}
if attr, ok := d.GetOk("name"); ok {
r.OwnerName = attr.(string)
}
if attr, ok := d.GetOk("type"); ok {
r.RRType = attr.(string)
}
if attr, ok := d.GetOk("zone"); ok {
r.Zone = attr.(string)
}
if attr, ok := d.GetOk("rdata"); ok {
rdata := attr.([]interface{})
r.RData = make([]string, len(rdata))
for i, j := range rdata {
r.RData[i] = j.(string)
}
}
if attr, ok := d.GetOk("ttl"); ok {
r.TTL, _ = strconv.Atoi(attr.(string))
}
return r, nil
}
func (r rRSetResource) RRSetKey() udnssdk.RRSetKey {
return udnssdk.RRSetKey{
Zone: r.Zone,
Type: r.RRType,
Name: r.OwnerName,
}
}
func (r rRSetResource) RRSet() udnssdk.RRSet {
return udnssdk.RRSet{
OwnerName: r.OwnerName,
RRType: r.RRType,
RData: r.RData,
TTL: r.TTL,
}
}
func (r rRSetResource) ID() string {
return fmt.Sprintf("%s.%s", r.OwnerName, r.Zone)
}
func populateResourceDataFromRRSet(r udnssdk.RRSet, d *schema.ResourceData) error {
zone := d.Get("zone")
// ttl
d.Set("ttl", r.TTL)
// rdata
err := d.Set("rdata", r.RData)
if err != nil {
return fmt.Errorf("ultradns_record.rdata set failed: %#v", err)
}
// 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))
}
}
return nil
}
func resourceUltraDNSRecord() *schema.Resource {
return &schema.Resource{
Create: resourceUltraDNSRecordCreate,
Read: resourceUltraDNSRecordRead,
Update: resourceUltraDNSRecordUpdate,
Delete: resourceUltraDNSRecordDelete,
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,
},
"type": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"rdata": &schema.Schema{
Type: schema.TypeList,
Required: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
// Optional
"ttl": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Default: "3600",
},
// Computed
"hostname": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
},
}
}
func resourceUltraDNSRecordCreate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*udnssdk.Client)
r, err := newRRSetResource(d)
if err != nil {
return err
}
log.Printf("[INFO] ultradns_record create: %#v", r.RRSet())
_, err = client.RRSets.Create(r.RRSetKey(), r.RRSet())
if err != nil {
return fmt.Errorf("Failed to create UltraDNS RRSet: %s", err)
}
d.SetId(r.ID())
log.Printf("[INFO] ultradns_record.id: %s", d.Id())
return resourceUltraDNSRecordRead(d, meta)
}
func resourceUltraDNSRecordRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*udnssdk.Client)
r, err := newRRSetResource(d)
if err != nil {
return err
}
rrsets, err := client.RRSets.Select(r.RRSetKey())
if err != nil {
uderr, ok := err.(*udnssdk.ErrorResponseList)
if ok {
for _, r := range uderr.Responses {
// 70002 means Records Not Found
if r.ErrorCode == 70002 {
d.SetId("")
return nil
}
return fmt.Errorf("ultradns_record not found: %s", err)
}
}
return fmt.Errorf("ultradns_record not found: %s", err)
}
rec := rrsets[0]
return populateResourceDataFromRRSet(rec, d)
}
func resourceUltraDNSRecordUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*udnssdk.Client)
r, err := newRRSetResource(d)
if err != nil {
return err
}
log.Printf("[INFO] ultradns_record update: %#v", r.RRSet())
_, err = client.RRSets.Update(r.RRSetKey(), r.RRSet())
if err != nil {
return fmt.Errorf("ultradns_record update failed: %s", err)
}
return resourceUltraDNSRecordRead(d, meta)
}
func resourceUltraDNSRecordDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*udnssdk.Client)
r, err := newRRSetResource(d)
if err != nil {
return err
}
log.Printf("[INFO] ultradns_record delete: %#v", r.RRSet())
_, err = client.RRSets.Delete(r.RRSetKey())
if err != nil {
return fmt.Errorf("ultradns_record delete failed: %s", err)
}
return nil
}

View File

@ -0,0 +1,177 @@
package ultradns
import (
"fmt"
"os"
"testing"
"github.com/Ensighten/udnssdk"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)
func TestAccUltraDNSRecord_Basic(t *testing.T) {
var record udnssdk.RRSet
domain := os.Getenv("ULTRADNS_DOMAIN")
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckUltraDNSRecordDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: fmt.Sprintf(testAccCheckUltraDNSRecordConfigBasic, domain),
Check: resource.ComposeTestCheckFunc(
testAccCheckUltraDNSRecordExists("ultradns_record.foobar", &record),
testAccCheckUltraDNSRecordAttributes(&record),
resource.TestCheckResourceAttr(
"ultradns_record.foobar", "name", "terraform"),
resource.TestCheckResourceAttr(
"ultradns_record.foobar", "zone", domain),
resource.TestCheckResourceAttr(
"ultradns_record.foobar", "rdata.0", "192.168.0.10"),
),
},
},
})
}
func TestAccUltraDNSRecord_Updated(t *testing.T) {
var record udnssdk.RRSet
domain := os.Getenv("ULTRADNS_DOMAIN")
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckUltraDNSRecordDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: fmt.Sprintf(testAccCheckUltraDNSRecordConfigBasic, domain),
Check: resource.ComposeTestCheckFunc(
testAccCheckUltraDNSRecordExists("ultradns_record.foobar", &record),
testAccCheckUltraDNSRecordAttributes(&record),
resource.TestCheckResourceAttr(
"ultradns_record.foobar", "name", "terraform"),
resource.TestCheckResourceAttr(
"ultradns_record.foobar", "zone", domain),
resource.TestCheckResourceAttr(
"ultradns_record.foobar", "rdata.0", "192.168.0.10"),
),
},
resource.TestStep{
Config: fmt.Sprintf(testAccCheckUltraDNSRecordConfigNewValue, domain),
Check: resource.ComposeTestCheckFunc(
testAccCheckUltraDNSRecordExists("ultradns_record.foobar", &record),
testAccCheckUltraDNSRecordAttributesUpdated(&record),
resource.TestCheckResourceAttr(
"ultradns_record.foobar", "name", "terraform"),
resource.TestCheckResourceAttr(
"ultradns_record.foobar", "zone", domain),
resource.TestCheckResourceAttr(
"ultradns_record.foobar", "rdata.0", "192.168.0.11"),
),
},
},
})
}
func testAccCheckUltraDNSRecordDestroy(s *terraform.State) error {
client := testAccProvider.Meta().(*udnssdk.Client)
for _, rs := range s.RootModule().Resources {
if rs.Type != "ultradns_record" {
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 testAccCheckUltraDNSRecordAttributes(record *udnssdk.RRSet) resource.TestCheckFunc {
return func(s *terraform.State) error {
if record.RData[0] != "192.168.0.10" {
return fmt.Errorf("Bad content: %v", record.RData)
}
return nil
}
}
func testAccCheckUltraDNSRecordAttributesUpdated(record *udnssdk.RRSet) resource.TestCheckFunc {
return func(s *terraform.State) error {
if record.RData[0] != "192.168.0.11" {
return fmt.Errorf("Bad content: %v", record.RData)
}
return nil
}
}
func testAccCheckUltraDNSRecordExists(n string, record *udnssdk.RRSet) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s", n)
}
if rs.Primary.ID == "" {
return fmt.Errorf("No Record ID is set")
}
client := testAccProvider.Meta().(*udnssdk.Client)
k := udnssdk.RRSetKey{
Zone: rs.Primary.Attributes["zone"],
Name: rs.Primary.Attributes["name"],
Type: rs.Primary.Attributes["type"],
}
foundRecord, err := client.RRSets.Select(k)
if err != nil {
return err
}
if foundRecord[0].OwnerName != rs.Primary.Attributes["hostname"] {
return fmt.Errorf("Record not found: %+v,\n %+v\n", foundRecord, rs.Primary.Attributes)
}
*record = foundRecord[0]
return nil
}
}
const testAccCheckUltraDNSRecordConfigBasic = `
resource "ultradns_record" "foobar" {
zone = "%s"
name = "terraform"
rdata = [ "192.168.0.10" ]
type = "A"
ttl = 3600
}`
const testAccCheckUltraDNSRecordConfigNewValue = `
resource "ultradns_record" "foobar" {
zone = "%s"
name = "terraform"
rdata = [ "192.168.0.11" ]
type = "A"
ttl = 3600
}`

67
vendor/github.com/Ensighten/udnssdk/account.go generated vendored Normal file
View File

@ -0,0 +1,67 @@
package udnssdk
import (
"fmt"
)
// AccountsService provides access to account resources
type AccountsService struct {
client *Client
}
// Account represents responses from the service
type Account struct {
AccountName string `json:"accountName"`
AccountHolderUserName string `json:"accountHolderUserName"`
OwnerUserName string `json:"ownerUserName"`
NumberOfUsers int `json:"numberOfUsers"`
NumberOfGroups int `json:"numberOfGroups"`
AccountType string `json:"accountType"`
}
// AccountListDTO represents a account index response
type AccountListDTO struct {
Accounts []Account `json:"accounts"`
Resultinfo ResultInfo `json:"resultInfo"`
}
// AccountKey represents the string identifier of an Account
type AccountKey string
// URI generates the URI for an Account
func (k AccountKey) URI() string {
uri := "accounts"
if k != "" {
uri = fmt.Sprintf("accounts/%s", k)
}
return uri
}
// AccountsURI generates the URI for Accounts collection
func AccountsURI() string {
return "accounts"
}
// Select requests all Accounts of user
func (s *AccountsService) Select() ([]Account, *Response, error) {
var ald AccountListDTO
res, err := s.client.get(AccountsURI(), &ald)
accts := []Account{}
for _, t := range ald.Accounts {
accts = append(accts, t)
}
return accts, res, err
}
// Find requests an Account by AccountKey
func (s *AccountsService) Find(k AccountKey) (Account, *Response, error) {
var t Account
res, err := s.client.get(k.URI(), &t)
return t, res, err
}
// Delete requests deletion of an Account by AccountKey
func (s *AccountsService) Delete(k AccountKey) (*Response, error) {
return s.client.delete(k.URI(), nil)
}

79
vendor/github.com/Ensighten/udnssdk/alert.go generated vendored Normal file
View File

@ -0,0 +1,79 @@
package udnssdk
import (
"log"
"time"
)
// AlertsService manages Alerts
type AlertsService struct {
client *Client
}
// ProbeAlertDataDTO wraps a probe alert response
type ProbeAlertDataDTO struct {
PoolRecord string `json:"poolRecord"`
ProbeType string `json:"probeType"`
ProbeStatus string `json:"probeStatus"`
AlertDate time.Time `json:"alertDate"`
FailoverOccured bool `json:"failoverOccured"`
OwnerName string `json:"ownerName"`
Status string `json:"status"`
}
// ProbeAlertDataListDTO wraps the response for an index of probe alerts
type ProbeAlertDataListDTO struct {
Alerts []ProbeAlertDataDTO `json:"alerts"`
Queryinfo QueryInfo `json:"queryInfo"`
Resultinfo ResultInfo `json:"resultInfo"`
}
// Select returns all probe alerts with a RRSetKey
func (s *AlertsService) Select(k RRSetKey) ([]ProbeAlertDataDTO, error) {
// TODO: Sane Configuration for timeouts / retries
maxerrs := 5
waittime := 5 * time.Second
// init accumulators
as := []ProbeAlertDataDTO{}
offset := 0
errcnt := 0
for {
reqAlerts, ri, res, err := s.SelectWithOffset(k, offset)
if err != nil {
if res.StatusCode >= 500 {
errcnt = errcnt + 1
if errcnt < maxerrs {
time.Sleep(waittime)
continue
}
}
return as, err
}
log.Printf("ResultInfo: %+v\n", ri)
for _, a := range reqAlerts {
as = append(as, a)
}
if ri.ReturnedCount+ri.Offset >= ri.TotalCount {
return as, nil
}
offset = ri.ReturnedCount + ri.Offset
continue
}
}
// SelectWithOffset returns the probe alerts with a RRSetKey, accepting an offset
func (s *AlertsService) SelectWithOffset(k RRSetKey, offset int) ([]ProbeAlertDataDTO, ResultInfo, *Response, error) {
var ald ProbeAlertDataListDTO
uri := k.AlertsQueryURI(offset)
res, err := s.client.get(uri, &ald)
as := []ProbeAlertDataDTO{}
for _, a := range ald.Alerts {
as = append(as, a)
}
return as, ald.Resultinfo, res, err
}

15
vendor/github.com/Ensighten/udnssdk/common.go generated vendored Normal file
View File

@ -0,0 +1,15 @@
package udnssdk
// GetResultByURI just requests a URI
func (c *Client) GetResultByURI(uri string) (*Response, error) {
req, err := c.NewRequest("GET", uri, nil)
if err != nil {
return nil, err
}
res, err := c.HTTPClient.Do(req)
if err != nil {
return &Response{Response: res}, err
}
return &Response{Response: res}, err
}

306
vendor/github.com/Ensighten/udnssdk/directional_pool.go generated vendored Normal file
View File

@ -0,0 +1,306 @@
package udnssdk
import (
"fmt"
"log"
"time"
)
// DirectionalPoolsService manages 'account level' 'geo' and 'ip' groups for directional-pools
type DirectionalPoolsService struct {
client *Client
}
// DirectionalPool wraps an account-level directional-groups response from a index request
type DirectionalPool struct {
DirectionalPoolID string `json:"taskId"`
DirectionalPoolStatusCode string `json:"taskStatusCode"`
Message string `json:"message"`
ResultURI string `json:"resultUri"`
}
// AccountLevelGeoDirectionalGroupDTO wraps an account-level, geo directonal-group response
type AccountLevelGeoDirectionalGroupDTO struct {
Name string `json:"name"`
Description string `json:"description"`
Codes []string `json:"codes"`
}
// IPAddrDTO wraps an IP address range or CIDR block
type IPAddrDTO struct {
Start string `json:"start,omitempty"`
End string `json:"end,omitempty"`
CIDR string `json:"cidr,omitempty"`
Address string `json:"address,omitempty"`
}
// AccountLevelIPDirectionalGroupDTO wraps an account-level, IP directional-group response
type AccountLevelIPDirectionalGroupDTO struct {
Name string `json:"name"`
Description string `json:"description"`
IPs []IPAddrDTO `json:"ips"`
}
// DirectionalPoolListDTO wraps a list of account-level directional-groups response from a index request
type DirectionalPoolListDTO struct {
DirectionalPools []DirectionalPool `json:"tasks"`
Queryinfo QueryInfo `json:"queryInfo"`
Resultinfo ResultInfo `json:"resultInfo"`
}
// AccountLevelGeoDirectionalGroupListDTO wraps a list of account-level, geo directional-groups response from a index request
type AccountLevelGeoDirectionalGroupListDTO struct {
AccountName string `json:"zoneName"`
GeoGroups []AccountLevelGeoDirectionalGroupDTO `json:"geoGroups"`
Queryinfo QueryInfo `json:"queryInfo"`
Resultinfo ResultInfo `json:"resultInfo"`
}
// AccountLevelIPDirectionalGroupListDTO wraps an account-level, IP directional-group response
type AccountLevelIPDirectionalGroupListDTO struct {
AccountName string `json:"zoneName"`
IPGroups []AccountLevelIPDirectionalGroupDTO `json:"ipGroups"`
Queryinfo QueryInfo `json:"queryInfo"`
Resultinfo ResultInfo `json:"resultInfo"`
}
// Geos allows access to the Geo DirectionalPools API
func (s *DirectionalPoolsService) Geos() *GeoDirectionalPoolsService {
return &GeoDirectionalPoolsService{client: s.client}
}
// IPs allows access to the IP DirectionalPools API
func (s *DirectionalPoolsService) IPs() *IPDirectionalPoolsService {
return &IPDirectionalPoolsService{client: s.client}
}
// DirectionalPoolKey collects the identifiers of a DirectionalPool
type DirectionalPoolKey struct {
Account AccountKey
Type string
Name string
}
// URI generates the URI for directional pools by account, type & slug ID
func (k DirectionalPoolKey) URI() string {
if k.Name == "" {
return fmt.Sprintf("%s/dirgroups/%s", k.Account.URI(), k.Type)
}
return fmt.Sprintf("%s/dirgroups/%s/%s", k.Account.URI(), k.Type, k.Name)
}
// QueryURI generates the URI for directional pools by account, type, query & offset
func (k DirectionalPoolKey) QueryURI(query string, offset int) string {
uri := k.URI()
if query != "" {
uri = fmt.Sprintf("%s?sort=NAME&query=%s&offset=%d", uri, query, offset)
} else {
uri = fmt.Sprintf("%s?offset=%d", uri, offset)
}
return uri
}
// GeoDirectionalPoolKey collects the identifiers of an DirectionalPool with type Geo
type GeoDirectionalPoolKey struct {
Account AccountKey
Name string
}
// DirectionalPoolKey generates the DirectionalPoolKey for the GeoDirectionalPoolKey
func (k GeoDirectionalPoolKey) DirectionalPoolKey() DirectionalPoolKey {
return DirectionalPoolKey{
Account: k.Account,
Type: "geo",
Name: k.Name,
}
}
// URI generates the URI for a GeoDirectionalPool
func (k GeoDirectionalPoolKey) URI() string {
return k.DirectionalPoolKey().URI()
}
// QueryURI generates the GeoDirectionalPool URI with query
func (k GeoDirectionalPoolKey) QueryURI(query string, offset int) string {
return k.DirectionalPoolKey().QueryURI(query, offset)
}
// GeoDirectionalPoolsService manages 'geo' groups for directional-pools
type GeoDirectionalPoolsService struct {
client *Client
}
// Select requests all geo directional-pools, by query and account, providing pagination and error handling
func (s *GeoDirectionalPoolsService) Select(k GeoDirectionalPoolKey, query string) ([]AccountLevelGeoDirectionalGroupDTO, error) {
// TODO: Sane Configuration for timeouts / retries
maxerrs := 5
waittime := 5 * time.Second
// init accumulators
dtos := []AccountLevelGeoDirectionalGroupDTO{}
errcnt := 0
offset := 0
for {
reqDtos, ri, res, err := s.SelectWithOffset(k, query, offset)
if err != nil {
if res.StatusCode >= 500 {
errcnt = errcnt + 1
if errcnt < maxerrs {
time.Sleep(waittime)
continue
}
}
return dtos, err
}
log.Printf("[DEBUG] ResultInfo: %+v\n", ri)
for _, d := range reqDtos {
dtos = append(dtos, d)
}
if ri.ReturnedCount+ri.Offset >= ri.TotalCount {
return dtos, nil
}
offset = ri.ReturnedCount + ri.Offset
continue
}
}
// SelectWithOffset requests list of geo directional-pools, by query & account, and an offset, returning the directional-group, the list-metadata, the actual response, or an error
func (s *GeoDirectionalPoolsService) SelectWithOffset(k GeoDirectionalPoolKey, query string, offset int) ([]AccountLevelGeoDirectionalGroupDTO, ResultInfo, *Response, error) {
var tld AccountLevelGeoDirectionalGroupListDTO
res, err := s.client.get(k.QueryURI(query, offset), &tld)
pis := []AccountLevelGeoDirectionalGroupDTO{}
for _, pi := range tld.GeoGroups {
pis = append(pis, pi)
}
return pis, tld.Resultinfo, res, err
}
// Find requests a geo directional-pool by name & account
func (s *GeoDirectionalPoolsService) Find(k GeoDirectionalPoolKey) (AccountLevelGeoDirectionalGroupDTO, *Response, error) {
var t AccountLevelGeoDirectionalGroupDTO
res, err := s.client.get(k.URI(), &t)
return t, res, err
}
// Create requests creation of a DirectionalPool by DirectionalPoolKey given a directional-pool
func (s *GeoDirectionalPoolsService) Create(k GeoDirectionalPoolKey, val interface{}) (*Response, error) {
return s.client.post(k.URI(), val, nil)
}
// Update requests update of a DirectionalPool by DirectionalPoolKey given a directional-pool
func (s *GeoDirectionalPoolsService) Update(k GeoDirectionalPoolKey, val interface{}) (*Response, error) {
return s.client.put(k.URI(), val, nil)
}
// Delete requests deletion of a DirectionalPool
func (s *GeoDirectionalPoolsService) Delete(k GeoDirectionalPoolKey) (*Response, error) {
return s.client.delete(k.URI(), nil)
}
// IPDirectionalPoolKey collects the identifiers of an DirectionalPool with type IP
type IPDirectionalPoolKey struct {
Account AccountKey
Name string
}
// DirectionalPoolKey generates the DirectionalPoolKey for the IPDirectionalPoolKey
func (k IPDirectionalPoolKey) DirectionalPoolKey() DirectionalPoolKey {
return DirectionalPoolKey{
Account: k.Account,
Type: "ip",
Name: k.Name,
}
}
// URI generates the IPDirectionalPool query URI
func (k IPDirectionalPoolKey) URI() string {
return k.DirectionalPoolKey().URI()
}
// QueryURI generates the IPDirectionalPool URI with query
func (k IPDirectionalPoolKey) QueryURI(query string, offset int) string {
return k.DirectionalPoolKey().QueryURI(query, offset)
}
// IPDirectionalPoolsService manages 'geo' groups for directional-pools
type IPDirectionalPoolsService struct {
client *Client
}
// Select requests all IP directional-pools, using pagination and error handling
func (s *IPDirectionalPoolsService) Select(k IPDirectionalPoolKey, query string) ([]AccountLevelIPDirectionalGroupDTO, error) {
// TODO: Sane Configuration for timeouts / retries
maxerrs := 5
waittime := 5 * time.Second
// init accumulators
gs := []AccountLevelIPDirectionalGroupDTO{}
errcnt := 0
offset := 0
for {
reqIPGroups, ri, res, err := s.SelectWithOffset(k, query, offset)
if err != nil {
if res.StatusCode >= 500 {
errcnt = errcnt + 1
if errcnt < maxerrs {
time.Sleep(waittime)
continue
}
}
return gs, err
}
log.Printf("ResultInfo: %+v\n", ri)
for _, g := range reqIPGroups {
gs = append(gs, g)
}
if ri.ReturnedCount+ri.Offset >= ri.TotalCount {
return gs, nil
}
offset = ri.ReturnedCount + ri.Offset
continue
}
}
// SelectWithOffset requests all IP directional-pools, by query & account, and an offset, returning the list of IP groups, list metadata & the actual response, or an error
func (s *IPDirectionalPoolsService) SelectWithOffset(k IPDirectionalPoolKey, query string, offset int) ([]AccountLevelIPDirectionalGroupDTO, ResultInfo, *Response, error) {
var tld AccountLevelIPDirectionalGroupListDTO
res, err := s.client.get(k.QueryURI(query, offset), &tld)
pis := []AccountLevelIPDirectionalGroupDTO{}
for _, pi := range tld.IPGroups {
pis = append(pis, pi)
}
return pis, tld.Resultinfo, res, err
}
// Find requests a directional-pool by name & account
func (s *IPDirectionalPoolsService) Find(k IPDirectionalPoolKey) (AccountLevelIPDirectionalGroupDTO, *Response, error) {
var t AccountLevelIPDirectionalGroupDTO
res, err := s.client.get(k.URI(), &t)
return t, res, err
}
// Create requests creation of a DirectionalPool by DirectionalPoolKey given a directional-pool
func (s *IPDirectionalPoolsService) Create(k IPDirectionalPoolKey, val interface{}) (*Response, error) {
return s.client.post(k.URI(), val, nil)
}
// Update requests update of a DirectionalPool by DirectionalPoolKey given a directional-pool
func (s *IPDirectionalPoolsService) Update(k IPDirectionalPoolKey, val interface{}) (*Response, error) {
return s.client.put(k.URI(), val, nil)
}
// Delete deletes an directional-pool
func (s *IPDirectionalPoolsService) Delete(k IPDirectionalPoolKey) (*Response, error) {
return s.client.delete(k.URI(), nil)
}

124
vendor/github.com/Ensighten/udnssdk/event.go generated vendored Normal file
View File

@ -0,0 +1,124 @@
package udnssdk
import (
"fmt"
"log"
"time"
)
// EventsService manages Events
type EventsService struct {
client *Client
}
// EventInfoDTO wraps an event's info response
type EventInfoDTO struct {
ID string `json:"id"`
PoolRecord string `json:"poolRecord"`
EventType string `json:"type"`
Start time.Time `json:"start"`
Repeat string `json:"repeat"`
End time.Time `json:"end"`
Notify string `json:"notify"`
}
// EventInfoListDTO wraps a list of event info and list metadata, from an index request
type EventInfoListDTO struct {
Events []EventInfoDTO `json:"events"`
Queryinfo QueryInfo `json:"queryInfo"`
Resultinfo ResultInfo `json:"resultInfo"`
}
// EventKey collects the identifiers of an Event
type EventKey struct {
Zone string
Type string
Name string
GUID string
}
// RRSetKey generates the RRSetKey for the EventKey
func (p EventKey) RRSetKey() RRSetKey {
return RRSetKey{
Zone: p.Zone,
Type: p.Type,
Name: p.Name,
}
}
// URI generates the URI for a probe
func (p EventKey) URI() string {
return fmt.Sprintf("%s/%s", p.RRSetKey().EventsURI(), p.GUID)
}
// Select requests all events, using pagination and error handling
func (s *EventsService) Select(r RRSetKey, query string) ([]EventInfoDTO, error) {
// TODO: Sane Configuration for timeouts / retries
maxerrs := 5
waittime := 5 * time.Second
// init accumulators
pis := []EventInfoDTO{}
offset := 0
errcnt := 0
for {
reqEvents, ri, res, err := s.SelectWithOffset(r, query, offset)
if err != nil {
if res.StatusCode >= 500 {
errcnt = errcnt + 1
if errcnt < maxerrs {
time.Sleep(waittime)
continue
}
}
return pis, err
}
log.Printf("ResultInfo: %+v\n", ri)
for _, pi := range reqEvents {
pis = append(pis, pi)
}
if ri.ReturnedCount+ri.Offset >= ri.TotalCount {
return pis, nil
}
offset = ri.ReturnedCount + ri.Offset
continue
}
}
// SelectWithOffset requests list of events by RRSetKey, query and offset, also returning list metadata, the actual response, or an error
func (s *EventsService) SelectWithOffset(r RRSetKey, query string, offset int) ([]EventInfoDTO, ResultInfo, *Response, error) {
var tld EventInfoListDTO
uri := r.EventsQueryURI(query, offset)
res, err := s.client.get(uri, &tld)
pis := []EventInfoDTO{}
for _, pi := range tld.Events {
pis = append(pis, pi)
}
return pis, tld.Resultinfo, res, err
}
// Find requests an event by name, type, zone & guid, also returning the actual response, or an error
func (s *EventsService) Find(e EventKey) (EventInfoDTO, *Response, error) {
var t EventInfoDTO
res, err := s.client.get(e.URI(), &t)
return t, res, err
}
// Create requests creation of an event by RRSetKey, with provided event-info, returning actual response or an error
func (s *EventsService) Create(r RRSetKey, ev EventInfoDTO) (*Response, error) {
return s.client.post(r.EventsURI(), ev, nil)
}
// Update requests update of an event by EventKey, withprovided event-info, returning the actual response or an error
func (s *EventsService) Update(e EventKey, ev EventInfoDTO) (*Response, error) {
return s.client.put(e.URI(), ev, nil)
}
// Delete requests deletion of an event by EventKey, returning the actual response or an error
func (s *EventsService) Delete(e EventKey) (*Response, error) {
return s.client.delete(e.URI(), nil)
}

133
vendor/github.com/Ensighten/udnssdk/notification.go generated vendored Normal file
View File

@ -0,0 +1,133 @@
package udnssdk
import (
"fmt"
"log"
"time"
)
// NotificationsService manages Probes
type NotificationsService struct {
client *Client
}
// NotificationDTO manages notifications
type NotificationDTO struct {
Email string `json:"email"`
PoolRecords []NotificationPoolRecord `json:"poolRecords"`
}
// NotificationPoolRecord does things unknown
type NotificationPoolRecord struct {
PoolRecord string `json:"poolRecord"`
Notification NotificationInfoDTO `json:"notification"`
}
// NotificationInfoDTO does things unknown
type NotificationInfoDTO struct {
Probe bool `json:"probe"`
Record bool `json:"record"`
Scheduled bool `json:"scheduled"`
}
// NotificationListDTO does things unknown
type NotificationListDTO struct {
Notifications []NotificationDTO `json:"notifications"`
Queryinfo QueryInfo `json:"queryInfo"`
Resultinfo ResultInfo `json:"resultInfo"`
}
// NotificationKey collects the identifiers of an Notification
type NotificationKey struct {
Zone string
Type string
Name string
Email string
}
// RRSetKey generates the RRSetKey for the NotificationKey
func (k NotificationKey) RRSetKey() RRSetKey {
return RRSetKey{
Zone: k.Zone,
Type: k.Type,
Name: k.Name,
}
}
// URI generates the URI for a probe
func (k NotificationKey) URI() string {
return fmt.Sprintf("%s/%s", k.RRSetKey().NotificationsURI(), k.Email)
}
// Select requests all notifications by RRSetKey and optional query, using pagination and error handling
func (s *NotificationsService) Select(k RRSetKey, query string) ([]NotificationDTO, *Response, error) {
// TODO: Sane Configuration for timeouts / retries
maxerrs := 5
waittime := 5 * time.Second
// init accumulators
pis := []NotificationDTO{}
errcnt := 0
offset := 0
for {
reqNotifications, ri, res, err := s.SelectWithOffset(k, query, offset)
if err != nil {
if res.StatusCode >= 500 {
errcnt = errcnt + 1
if errcnt < maxerrs {
time.Sleep(waittime)
continue
}
}
return pis, res, err
}
log.Printf("[DEBUG] ResultInfo: %+v\n", ri)
for _, pi := range reqNotifications {
pis = append(pis, pi)
}
if ri.ReturnedCount+ri.Offset >= ri.TotalCount {
return pis, res, nil
}
offset = ri.ReturnedCount + ri.Offset
continue
}
}
// SelectWithOffset requests list of notifications by RRSetKey, query and offset, also returning list metadata, the actual response, or an error
func (s *NotificationsService) SelectWithOffset(k RRSetKey, query string, offset int) ([]NotificationDTO, ResultInfo, *Response, error) {
var tld NotificationListDTO
uri := k.NotificationsQueryURI(query, offset)
res, err := s.client.get(uri, &tld)
log.Printf("DEBUG - ResultInfo: %+v\n", tld.Resultinfo)
pis := []NotificationDTO{}
for _, pi := range tld.Notifications {
pis = append(pis, pi)
}
return pis, tld.Resultinfo, res, err
}
// Find requests a notification by NotificationKey,returning the actual response, or an error
func (s *NotificationsService) Find(k NotificationKey) (NotificationDTO, *Response, error) {
var t NotificationDTO
res, err := s.client.get(k.URI(), &t)
return t, res, err
}
// Create requests creation of an event by RRSetKey, with provided NotificationInfoDTO, returning actual response or an error
func (s *NotificationsService) Create(k NotificationKey, n NotificationDTO) (*Response, error) {
return s.client.post(k.URI(), n, nil)
}
// Update requests update of an event by NotificationKey, with provided NotificationInfoDTO, returning the actual response or an error
func (s *NotificationsService) Update(k NotificationKey, n NotificationDTO) (*Response, error) {
return s.client.put(k.URI(), n, nil)
}
// Delete requests deletion of an event by NotificationKey, returning the actual response or an error
func (s *NotificationsService) Delete(k NotificationKey) (*Response, error) {
return s.client.delete(k.URI(), nil)
}

252
vendor/github.com/Ensighten/udnssdk/probe.go generated vendored Normal file
View File

@ -0,0 +1,252 @@
package udnssdk
import (
"encoding/json"
"fmt"
"strings"
)
// ProbeInfoDTO wraps a probe response
type ProbeInfoDTO struct {
ID string `json:"id"`
PoolRecord string `json:"poolRecord"`
ProbeType string `json:"type"`
Interval string `json:"interval"`
Agents []string `json:"agents"`
Threshold int `json:"threshold"`
Details *ProbeDetailsDTO `json:"details"`
}
// ProbeDetailsLimitDTO wraps a probe
type ProbeDetailsLimitDTO struct {
Warning int `json:"warning"`
Critical int `json:"critical"`
Fail int `json:"fail"`
}
// ProbeDetailsDTO wraps the details of a probe
type ProbeDetailsDTO struct {
data []byte
Detail interface{} `json:"detail,omitempty"`
typ string
}
// GetData returns the data because I'm working around something.
func (s *ProbeDetailsDTO) GetData() []byte {
return s.data
}
// Populate does magical things with json unmarshalling to unroll the Probe into
// an appropriate datatype. These are helper structures and functions for testing
// and direct API use. In the Terraform implementation, we will use Terraforms own
// warped schema structure to handle the marshalling and unmarshalling.
func (s *ProbeDetailsDTO) Populate(typ string) (err error) {
// TODO: actually document
switch strings.ToUpper(typ) {
case "HTTP":
var pp HTTPProbeDetailsDTO
err = json.Unmarshal(s.data, &pp)
s.typ = typ
s.Detail = pp
return err
case "PING":
var pp PingProbeDetailsDTO
err = json.Unmarshal(s.data, &pp)
s.typ = typ
s.Detail = pp
return err
case "FTP":
var pp FTPProbeDetailsDTO
err = json.Unmarshal(s.data, &pp)
s.typ = typ
s.Detail = pp
return err
case "TCP":
var pp TCPProbeDetailsDTO
err = json.Unmarshal(s.data, &pp)
s.typ = typ
s.Detail = pp
return err
case "SMTP":
var pp SMTPProbeDetailsDTO
err = json.Unmarshal(s.data, &pp)
s.typ = typ
s.Detail = pp
return err
case "SMTP_SEND":
var pp SMTPSENDProbeDetailsDTO
err = json.Unmarshal(s.data, &pp)
s.typ = typ
s.Detail = pp
return err
case "DNS":
var pp DNSProbeDetailsDTO
err = json.Unmarshal(s.data, &pp)
s.typ = typ
s.Detail = pp
return err
default:
return fmt.Errorf("ERROR - ProbeDetailsDTO.Populate(\"%s\") - Fall through!\n", typ)
}
}
// UnmarshalJSON does what it says on the tin
func (s *ProbeDetailsDTO) UnmarshalJSON(b []byte) (err error) {
s.data = b
return nil
}
// MarshalJSON does what it says on the tin
func (s *ProbeDetailsDTO) MarshalJSON() ([]byte, error) {
var err error
if s.Detail != nil {
return json.Marshal(s.Detail)
}
if len(s.data) != 0 {
return s.data, err
}
return json.Marshal(nil)
}
// GoString returns a string representation of the ProbeDetailsDTO internal data
func (s *ProbeDetailsDTO) GoString() string {
return string(s.data)
}
func (s *ProbeDetailsDTO) String() string {
return string(s.data)
}
// Transaction wraps a transaction response
type Transaction struct {
Method string `json:"method"`
URL string `json:"url"`
TransmittedData string `json:"transmittedData,omitempty"`
FollowRedirects bool `json:"followRedirects,omitempty"`
Limits map[string]ProbeDetailsLimitDTO `json:"limits"`
}
// HTTPProbeDetailsDTO wraps HTTP probe details
type HTTPProbeDetailsDTO struct {
Transactions []Transaction `json:"transactions"`
TotalLimits *ProbeDetailsLimitDTO `json:"totalLimits,omitempty"`
}
// PingProbeDetailsDTO wraps Ping probe details
type PingProbeDetailsDTO struct {
Packets int `json:"packets,omitempty"`
PacketSize int `json:"packetSize,omitempty"`
Limits map[string]ProbeDetailsLimitDTO `json:"limits"`
}
// FTPProbeDetailsDTO wraps FTP probe details
type FTPProbeDetailsDTO struct {
Port int `json:"port,omitempty"`
PassiveMode bool `json:"passiveMode,omitempty"`
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
Path string `json:"path"`
Limits map[string]ProbeDetailsLimitDTO `json:"limits"`
}
// TCPProbeDetailsDTO wraps TCP probe details
type TCPProbeDetailsDTO struct {
Port int `json:"port,omitempty"`
ControlIP string `json:"controlIP,omitempty"`
Limits map[string]ProbeDetailsLimitDTO `json:"limits"`
}
// SMTPProbeDetailsDTO wraps SMTP probe details
type SMTPProbeDetailsDTO struct {
Port int `json:"port,omitempty"`
Limits map[string]ProbeDetailsLimitDTO `json:"limits"`
}
// SMTPSENDProbeDetailsDTO wraps SMTP SEND probe details
type SMTPSENDProbeDetailsDTO struct {
Port int `json:"port,omitempty"`
From string `json:"from"`
To string `json:"to"`
Message string `json:"message,omitempty"`
Limits map[string]ProbeDetailsLimitDTO `json:"limits"`
}
// DNSProbeDetailsDTO wraps DNS probe details
type DNSProbeDetailsDTO struct {
Port int `json:"port,omitempty"`
TCPOnly bool `json:"tcpOnly,omitempty"`
RecordType string `json:"type,omitempty"`
OwnerName string `json:"ownerName,omitempty"`
Limits map[string]ProbeDetailsLimitDTO `json:"limits"`
}
// ProbeListDTO wraps a list of probes
type ProbeListDTO struct {
Probes []ProbeInfoDTO `json:"probes"`
Queryinfo QueryInfo `json:"queryInfo"`
Resultinfo ResultInfo `json:"resultInfo"`
}
// ProbesService manages Probes
type ProbesService struct {
client *Client
}
// ProbeKey collects the identifiers of a Probe
type ProbeKey struct {
Zone string
Name string
ID string
}
// RRSetKey generates the RRSetKey for the ProbeKey
func (k ProbeKey) RRSetKey() RRSetKey {
return RRSetKey{
Zone: k.Zone,
Type: "A", // Only A records have probes
Name: k.Name,
}
}
// URI generates the URI for a probe
func (k ProbeKey) URI() string {
return fmt.Sprintf("%s/%s", k.RRSetKey().ProbesURI(), k.ID)
}
// Select returns all probes by a RRSetKey, with an optional query
func (s *ProbesService) Select(k RRSetKey, query string) ([]ProbeInfoDTO, *Response, error) {
var pld ProbeListDTO
// This API does not support pagination.
uri := k.ProbesQueryURI(query)
res, err := s.client.get(uri, &pld)
ps := []ProbeInfoDTO{}
if err == nil {
for _, t := range pld.Probes {
ps = append(ps, t)
}
}
return ps, res, err
}
// Find returns a probe from a ProbeKey
func (s *ProbesService) Find(k ProbeKey) (ProbeInfoDTO, *Response, error) {
var t ProbeInfoDTO
res, err := s.client.get(k.URI(), &t)
return t, res, err
}
// Create creates a probe with a RRSetKey using the ProbeInfoDTO dp
func (s *ProbesService) Create(k RRSetKey, dp ProbeInfoDTO) (*Response, error) {
return s.client.post(k.ProbesURI(), dp, nil)
}
// Update updates a probe given a ProbeKey with the ProbeInfoDTO dp
func (s *ProbesService) Update(k ProbeKey, dp ProbeInfoDTO) (*Response, error) {
return s.client.put(k.URI(), dp, nil)
}
// Delete deletes a probe by its ProbeKey
func (s *ProbesService) Delete(k ProbeKey) (*Response, error) {
return s.client.delete(k.URI(), nil)
}

103
vendor/github.com/Ensighten/udnssdk/readme.md generated vendored Normal file
View File

@ -0,0 +1,103 @@
# udnssdk - A ultradns SDK for GoLang
## about
This is a golang 'SDK' for UltraDNS that I copapasta'd from weppos/dnsimple.
It seemed like an ideal donor since the use case is terraform.
## How It works:
client := udnssdk.NewClient("username","password",udnssdk.DefaultTestBaseURL)
There is DefaultTestBaseURL and DefaultLiveBaseURL.
When you call NewClient, it performs the 'oauth2' authorization step.
The refresh token is saved, but not implemented. It should ideally be an error
condition triggering a reauth and retry. But since Terraform is the use case, this won't be an issue.
### RRSet Declaration
type RRSet struct {
OwnerName string `json:"ownerName"`
RRType string `json:"rrtype"`
TTL int `json:"ttl"`
RData []string `json:"rdata"`
}
###GetRRSets(DomainName, RecordName(leave blank for all), RecordType[A|CNAME|ANY])
rrsets, resp, err := client.Zones.GetRRSets("domain.com","","ANY")
rrsets, resp, err := client.Zones.GetRRSets("domain.com","www","ANY")
rrsets, resp, err := client.Zones.GetRRSets("domain.com","","MX")
rrsets, resp, err := client.Zones.GetRRSets("domain.com","www","SRV")
###CreateRRSet(DomainName, RRSet)
rr1 := &udnssdk.RRSet{OwnerName: "test", RRType: "A", TTL: 300, RData: []string{"127.0.0.1"}}
resp2,err2 := client.Zones.CreateRRSet("ensighten.com",*rr1)
###UpdateRRSet(DomainName, RRSet)
UpdateRRSet requires you to specify the complete RRSet for the update. This implementation does not support PATCHing.
rr1 := &udnssdk.RRSet{OwnerName: "test", RRType: "A", TTL: 300, RData: []string{"192.168.1.1"}}
resp2,err2 := client.Zones.CreateRRSet("domain.com",*rr1)
###DeleteRRSet(DomainName, RRSet)
Delete RRSet only uses the ownerName and RRType values from the RRSet object.
rr3 := &udnssdk.RRSet{OwnerName: "test", RRType: "A"} // This is permissible.
resp3,err3 := client.RRSets.DeleteRRSet("domain.com",*rr3)
## Example Program
package main
// udnssdk - a golang sdk for the ultradns REST service.
// based on weppos/dnsimple
import (
"fmt"
"udnssdk"
)
func main() {
client := udnssdk.NewClient("username","password",udnssdk.DefaultTestBaseURL)
if client == nil {
fmt.Printf("Fail")
} else {
fmt.Printf("Win\n")
rrsets, resp, err := client.RRSets.GetRRSets("domain.com","test","ANY")
fmt.Printf("%+v\n",rrsets)
fmt.Printf("%+v\n",resp)
fmt.Printf("%+v\n",err)
fmt.Printf("------------------------\n")
fmt.Printf("---- Create RRSet\n")
rr1 := &udnssdk.RRSet{OwnerName: "test", RRType: "A", TTL: 300, RData: []string{"127.0.0.1}}
resp2,err2 := client.RRSets.CreateRRSet("domain.com",*rr1)
fmt.Printf("Resp2: %+v\n", resp2)
fmt.Printf("Err2: %+v\n", err2)
fmt.Printf("------------------------\n")
fmt.Printf("------------------------\n")
fmt.Printf("---- Update RRSet\n")
fmt.Printf("------------------------\n")
rr2 := &udnssdk.RRSet{OwnerName: "test", RRType: "A", TTL: 300, RData: []string{"127.0.0.2"}}
resp3, err3 := client.RRSets.UpdateRRSet("domain.com",*rr2)
fmt.Printf("Resp3: %+v\n", resp3)
fmt.Printf("Err3: %+v\n", err3)
fmt.Printf("------------------------\n")
fmt.Printf("------------------------\n")
fmt.Printf("---- Delete RRSet\n")
fmt.Printf("------------------------\n")
resp4,err4 := client.RRSets.DeleteRRSet("domain.com",*rr2)
fmt.Printf("Resp4: %+v\n", resp4)
fmt.Printf("Err4: %+v\n", err4)
fmt.Printf("------------------------\n")
}
}
#thanks
* [weppo's dnsimple go sdk @ github](https://github.com/weppos/go-dnsimple)
* [pearkes dnsimple sdk (this one is used by terraform) @ github](https://github.com/pearkes/dnsimple)
* [terraform](http://terraform.io)
* [UltraDNS's various SDK's](https://github.com/ultradns)

377
vendor/github.com/Ensighten/udnssdk/rrset.go generated vendored Normal file
View File

@ -0,0 +1,377 @@
package udnssdk
import (
"encoding/json"
"fmt"
"log"
"time"
)
// RRSetsService provides access to RRSet resources
type RRSetsService struct {
client *Client
}
// Here is the big 'Profile' mess that should get refactored to a more managable place
// StringProfile wraps a Profile string
type StringProfile struct {
Profile string `json:"profile,omitempty"`
}
// Metaprofile is a helper struct for extracting a Context from a StringProfile
type Metaprofile struct {
Context ProfileSchema `json:"@context"`
}
// ProfileSchema are the schema URIs for RRSet Profiles
type ProfileSchema string
const (
// DirPoolSchema is the schema URI for a Directional pool profile
DirPoolSchema ProfileSchema = "http://schemas.ultradns.com/DirPool.jsonschema"
// RDPoolSchema is the schema URI for a Resource Distribution pool profile
RDPoolSchema = "http://schemas.ultradns.com/RDPool.jsonschema"
// SBPoolSchema is the schema URI for a SiteBacker pool profile
SBPoolSchema = "http://schemas.ultradns.com/SBPool.jsonschema"
// TCPoolSchema is the schema URI for a Traffic Controller pool profile
TCPoolSchema = "http://schemas.ultradns.com/TCPool.jsonschema"
)
// DirPoolProfile wraps a Profile for a Directional Pool
type DirPoolProfile struct {
Context ProfileSchema `json:"@context"`
Description string `json:"description"`
ConflictResolve string `json:"conflictResolve,omitempty"`
RDataInfo []DPRDataInfo `json:"rdataInfo"`
NoResponse DPRDataInfo `json:"noResponse"`
}
// DPRDataInfo wraps the rdataInfo object of a DirPoolProfile response
type DPRDataInfo struct {
AllNonConfigured bool `json:"allNonConfigured,omitempty"`
IPInfo IPInfo `json:"ipInfo,omitempty"`
GeoInfo GeoInfo `json:"geoInfo,omitempty"`
}
// IPInfo wraps the ipInfo object of a DPRDataInfo
type IPInfo struct {
Name string `json:"name"`
IsAccountLevel bool `json:"isAccountLevel,omitempty"`
Ips []IPAddrDTO `json:"ips"`
}
// GeoInfo wraps the geoInfo object of a DPRDataInfo
type GeoInfo struct {
Name string `json:"name"`
IsAccountLevel bool `json:"isAccountLevel,omitempty"`
Codes []string `json:"codes"`
}
// RDPoolProfile wraps a Profile for a Resource Distribution pool
type RDPoolProfile struct {
Context ProfileSchema `json:"@context"`
Order string `json:"order"`
Description string `json:"description"`
}
// SBPoolProfile wraps a Profile for a SiteBacker pool
type SBPoolProfile struct {
Context ProfileSchema `json:"@context"`
Description string `json:"description"`
RunProbes bool `json:"runProbes,omitempty"`
ActOnProbes bool `json:"actOnProbes,omitempty"`
Order string `json:"order,omitempty"`
MaxActive int `json:"maxActive,omitempty"`
MaxServed int `json:"maxServed,omitempty"`
RDataInfo []SBRDataInfo `json:"rdataInfo"`
BackupRecords []BackupRecord `json:"backupRecords"`
}
// SBRDataInfo wraps the rdataInfo object of a SBPoolProfile
type SBRDataInfo struct {
State string `json:"state"`
RunProbes bool `json:"runProbes,omitempty"`
Priority int `json:"priority"`
FailoverDelay int `json:"failoverDelay,omitempty"`
Threshold int `json:"threshold"`
Weight int `json:"weight"`
}
// BackupRecord wraps the backupRecord objects of an SBPoolProfile response
type BackupRecord struct {
RData string `json:"rdata"`
FailoverDelay int `json:"failoverDelay,omitempty"`
}
// TCPoolProfile wraps a Profile for a Traffic Controller pool
type TCPoolProfile struct {
Context ProfileSchema `json:"@context"`
Description string `json:"description"`
RunProbes bool `json:"runProbes,omitempty"`
ActOnProbes bool `json:"actOnProbes,omitempty"`
MaxToLB int `json:"maxToLB,omitempty"`
RDataInfo []SBRDataInfo `json:"rdataInfo"`
BackupRecord BackupRecord `json:"backupRecord"`
}
// UnmarshalJSON does what it says on the tin
func (sp *StringProfile) UnmarshalJSON(b []byte) (err error) {
sp.Profile = string(b)
return nil
}
// MarshalJSON does what it says on the tin
func (sp *StringProfile) MarshalJSON() ([]byte, error) {
if sp.Profile != "" {
return []byte(sp.Profile), nil
}
return json.Marshal(nil)
}
// Metaprofile converts a StringProfile to a Metaprofile to extract the context
func (sp *StringProfile) Metaprofile() (Metaprofile, error) {
var mp Metaprofile
if sp.Profile == "" {
return mp, fmt.Errorf("Empty Profile cannot be converted to a Metaprofile")
}
err := json.Unmarshal([]byte(sp.Profile), &mp)
if err != nil {
return mp, fmt.Errorf("Error getting profile type: %+v\n", err)
}
return mp, nil
}
// Context extracts the schema context from a StringProfile
func (sp *StringProfile) Context() ProfileSchema {
mp, err := sp.Metaprofile()
if err != nil {
log.Printf("[ERROR] %+s\n", err)
return ""
}
return mp.Context
}
// GoString returns the StringProfile's Profile.
func (sp *StringProfile) GoString() string {
return sp.Profile
}
// String returns the StringProfile's Profile.
func (sp *StringProfile) String() string {
return sp.Profile
}
// GetProfileObject extracts the full Profile by its schema type
func (sp *StringProfile) GetProfileObject() interface{} {
c := sp.Context()
switch c {
case DirPoolSchema:
var dpp DirPoolProfile
err := json.Unmarshal([]byte(sp.Profile), &dpp)
if err != nil {
log.Printf("Could not Unmarshal the DirPoolProfile.\n")
return nil
}
return dpp
case RDPoolSchema:
var rdp RDPoolProfile
err := json.Unmarshal([]byte(sp.Profile), &rdp)
if err != nil {
log.Printf("Could not Unmarshal the RDPoolProfile.\n")
return nil
}
return rdp
case SBPoolSchema:
var sbp SBPoolProfile
err := json.Unmarshal([]byte(sp.Profile), &sbp)
if err != nil {
log.Printf("Could not Unmarshal the SBPoolProfile.\n")
return nil
}
return sbp
case TCPoolSchema:
var tcp TCPoolProfile
err := json.Unmarshal([]byte(sp.Profile), &tcp)
if err != nil {
log.Printf("Could not Unmarshal the TCPoolProfile.\n")
return nil
}
return tcp
default:
log.Printf("ERROR - Fall through on GetProfileObject - %s.\n", c)
return fmt.Errorf("Fallthrough on GetProfileObject type %s\n", c)
}
}
// RRSet wraps an RRSet resource
type RRSet struct {
OwnerName string `json:"ownerName"`
RRType string `json:"rrtype"`
TTL int `json:"ttl"`
RData []string `json:"rdata"`
Profile *StringProfile `json:"profile,omitempty"`
}
// RRSetListDTO wraps a list of RRSet resources
type RRSetListDTO struct {
ZoneName string `json:"zoneName"`
Rrsets []RRSet `json:"rrsets"`
Queryinfo QueryInfo `json:"queryInfo"`
Resultinfo ResultInfo `json:"resultInfo"`
}
// RRSetKey collects the identifiers of a Zone
type RRSetKey struct {
Zone string
Type string
Name string
}
// URI generates the URI for an RRSet
func (k RRSetKey) URI() string {
uri := fmt.Sprintf("zones/%s/rrsets", k.Zone)
if k.Type != "" {
uri += fmt.Sprintf("/%v", k.Type)
if k.Name != "" {
uri += fmt.Sprintf("/%v", k.Name)
}
}
return uri
}
// QueryURI generates the query URI for an RRSet and offset
func (k RRSetKey) QueryURI(offset int) string {
// TODO: find a more appropriate place to set "" to "ANY"
if k.Type == "" {
k.Type = "ANY"
}
return fmt.Sprintf("%s?offset=%d", k.URI(), offset)
}
// AlertsURI generates the URI for an RRSet
func (k RRSetKey) AlertsURI() string {
return fmt.Sprintf("%s/alerts", k.URI())
}
// AlertsQueryURI generates the alerts query URI for an RRSet with query
func (k RRSetKey) AlertsQueryURI(offset int) string {
uri := k.AlertsURI()
if offset != 0 {
uri = fmt.Sprintf("%s?offset=%d", uri, offset)
}
return uri
}
// EventsURI generates the URI for an RRSet
func (k RRSetKey) EventsURI() string {
return fmt.Sprintf("%s/events", k.URI())
}
// EventsQueryURI generates the events query URI for an RRSet with query
func (k RRSetKey) EventsQueryURI(query string, offset int) string {
uri := k.EventsURI()
if query != "" {
return fmt.Sprintf("%s?sort=NAME&query=%s&offset=%d", uri, query, offset)
}
if offset != 0 {
return fmt.Sprintf("%s?offset=%d", uri, offset)
}
return uri
}
// NotificationsURI generates the notifications URI for an RRSet
func (k RRSetKey) NotificationsURI() string {
return fmt.Sprintf("%s/notifications", k.URI())
}
// NotificationsQueryURI generates the notifications query URI for an RRSet with query
func (k RRSetKey) NotificationsQueryURI(query string, offset int) string {
uri := k.NotificationsURI()
if query != "" {
uri = fmt.Sprintf("%s?sort=NAME&query=%s&offset=%d", uri, query, offset)
} else {
uri = fmt.Sprintf("%s?offset=%d", uri, offset)
}
return uri
}
// ProbesURI generates the probes URI for an RRSet
func (k RRSetKey) ProbesURI() string {
return fmt.Sprintf("%s/probes", k.URI())
}
// ProbesQueryURI generates the probes query URI for an RRSet with query
func (k RRSetKey) ProbesQueryURI(query string) string {
uri := k.ProbesURI()
if query != "" {
uri = fmt.Sprintf("%s?sort=NAME&query=%s", uri, query)
}
return uri
}
// Select will list the zone rrsets, paginating through all available results
func (s *RRSetsService) Select(k RRSetKey) ([]RRSet, error) {
// TODO: Sane Configuration for timeouts / retries
maxerrs := 5
waittime := 5 * time.Second
rrsets := []RRSet{}
errcnt := 0
offset := 0
for {
reqRrsets, ri, res, err := s.SelectWithOffset(k, offset)
if err != nil {
if res.StatusCode >= 500 {
errcnt = errcnt + 1
if errcnt < maxerrs {
time.Sleep(waittime)
continue
}
}
return rrsets, err
}
log.Printf("ResultInfo: %+v\n", ri)
for _, rrset := range reqRrsets {
rrsets = append(rrsets, rrset)
}
if ri.ReturnedCount+ri.Offset >= ri.TotalCount {
return rrsets, nil
}
offset = ri.ReturnedCount + ri.Offset
continue
}
}
// SelectWithOffset requests zone rrsets by RRSetKey & optional offset
func (s *RRSetsService) SelectWithOffset(k RRSetKey, offset int) ([]RRSet, ResultInfo, *Response, error) {
var rrsld RRSetListDTO
uri := k.QueryURI(offset)
res, err := s.client.get(uri, &rrsld)
rrsets := []RRSet{}
for _, rrset := range rrsld.Rrsets {
rrsets = append(rrsets, rrset)
}
return rrsets, rrsld.Resultinfo, res, err
}
// Create creates an rrset with val
func (s *RRSetsService) Create(k RRSetKey, rrset RRSet) (*Response, error) {
var ignored interface{}
return s.client.post(k.URI(), rrset, &ignored)
}
// Update updates a RRSet with the provided val
func (s *RRSetsService) Update(k RRSetKey, val RRSet) (*Response, error) {
var ignored interface{}
return s.client.put(k.URI(), val, &ignored)
}
// Delete deletes an RRSet
func (s *RRSetsService) Delete(k RRSetKey) (*Response, error) {
return s.client.delete(k.URI(), nil)
}

124
vendor/github.com/Ensighten/udnssdk/task.go generated vendored Normal file
View File

@ -0,0 +1,124 @@
package udnssdk
import (
"fmt"
"log"
"time"
)
// TasksService provides access to the tasks resources
type TasksService struct {
client *Client
}
// Task wraps a task response
type Task struct {
TaskID string `json:"taskId"`
TaskStatusCode string `json:"taskStatusCode"`
Message string `json:"message"`
ResultURI string `json:"resultUri"`
}
// TaskListDTO wraps a list of Task resources, from an HTTP response
type TaskListDTO struct {
Tasks []Task `json:"tasks"`
Queryinfo QueryInfo `json:"queryInfo"`
Resultinfo ResultInfo `json:"resultInfo"`
}
type taskWrapper struct {
Task Task `json:"task"`
}
// TaskID represents the string identifier of a task
type TaskID string
// ResultURI generates URI for the task result
func (t TaskID) ResultURI() string {
return fmt.Sprintf("%s/result", t.URI())
}
// URI generates the URI for a task
func (t TaskID) URI() string {
return fmt.Sprintf("tasks/%s", t)
}
// TasksQueryURI generates the query URI for the tasks collection given a query and offset
func TasksQueryURI(query string, offset int) string {
if query != "" {
return fmt.Sprintf("tasks?sort=NAME&query=%s&offset=%d", query, offset)
}
return fmt.Sprintf("tasks?offset=%d", offset)
}
// Select requests all tasks, with pagination
func (s *TasksService) Select(query string) ([]Task, error) {
// TODO: Sane Configuration for timeouts / retries
maxerrs := 5
waittime := 5 * time.Second
// init accumulators
dtos := []Task{}
offset := 0
errcnt := 0
for {
reqDtos, ri, res, err := s.SelectWithOffset(query, offset)
if err != nil {
if res.StatusCode >= 500 {
errcnt = errcnt + 1
if errcnt < maxerrs {
time.Sleep(waittime)
continue
}
}
return dtos, err
}
log.Printf("[DEBUG] ResultInfo: %+v\n", ri)
for _, d := range reqDtos {
dtos = append(dtos, d)
}
if ri.ReturnedCount+ri.Offset >= ri.TotalCount {
return dtos, nil
}
offset = ri.ReturnedCount + ri.Offset
continue
}
}
// SelectWithOffset request tasks by query & offset, list them also returning list metadata, the actual response, or an error
func (s *TasksService) SelectWithOffset(query string, offset int) ([]Task, ResultInfo, *Response, error) {
var tld TaskListDTO
uri := TasksQueryURI(query, offset)
res, err := s.client.get(uri, &tld)
ts := []Task{}
for _, t := range tld.Tasks {
ts = append(ts, t)
}
return ts, tld.Resultinfo, res, err
}
// Find Get the status of a task.
func (s *TasksService) Find(t TaskID) (Task, *Response, error) {
var tv Task
res, err := s.client.get(t.URI(), &tv)
return tv, res, err
}
// FindResult requests
func (s *TasksService) FindResult(t TaskID) (*Response, error) {
return s.client.GetResultByURI(t.ResultURI())
}
// FindResultByTask requests a task by the provided task's result uri
func (s *TasksService) FindResultByTask(t Task) (*Response, error) {
return s.client.GetResultByURI(t.ResultURI)
}
// Delete requests deletions
func (s *TasksService) Delete(t TaskID) (*Response, error) {
return s.client.delete(t.URI(), nil)
}

377
vendor/github.com/Ensighten/udnssdk/udnssdk.go generated vendored Normal file
View File

@ -0,0 +1,377 @@
package udnssdk
// udnssdk - a golang sdk for the ultradns REST service.
// 2015-07-03 - jmasseo@gmail.com
import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"net/url"
"time"
)
const (
libraryVersion = "0.1"
// DefaultTestBaseURL returns the URL for UltraDNS's test restapi endpoint
DefaultTestBaseURL = "https://test-restapi.ultradns.com/"
// DefaultLiveBaseURL returns the URL for UltraDNS's production restapi endpoint
DefaultLiveBaseURL = "https://restapi.ultradns.com/"
userAgent = "udnssdk-go/" + libraryVersion
apiVersion = "v1"
)
// QueryInfo wraps a query request
type QueryInfo struct {
Q string `json:"q"`
Sort string `json:"sort"`
Reverse bool `json:"reverse"`
Limit int `json:"limit"`
}
// ResultInfo wraps the list metadata for an index response
type ResultInfo struct {
TotalCount int `json:"totalCount"`
Offset int `json:"offset"`
ReturnedCount int `json:"returnedCount"`
}
// Client wraps our general-purpose Service Client
type Client struct {
// This is our client structure.
HTTPClient *http.Client
// UltraDNS makes a call to an authorization API using your username and
// password, returning an 'Access Token' and a 'Refresh Token'.
// Our use case does not require the refresh token, but we should implement
// for completeness.
AccessToken string
RefreshToken string
Username string
Password string
BaseURL string
UserAgent string
// Accounts API
Accounts *AccountsService
// Probe Alerts API
Alerts *AlertsService
// Directional Pools API
DirectionalPools *DirectionalPoolsService
// Events API
Events *EventsService
// Notifications API
Notifications *NotificationsService
// Probes API
Probes *ProbesService
// Resource Record Sets API
RRSets *RRSetsService
// Tasks API
Tasks *TasksService
}
// NewClient returns a new ultradns API client.
func NewClient(username, password, BaseURL string) (*Client, error) {
accesstoken, refreshtoken, err := GetAuthTokens(username, password, BaseURL)
if err != nil {
return nil, err
}
c := &Client{
AccessToken: accesstoken,
RefreshToken: refreshtoken,
Username: username,
Password: password,
HTTPClient: &http.Client{},
BaseURL: BaseURL,
UserAgent: userAgent,
}
c.Accounts = &AccountsService{client: c}
c.Alerts = &AlertsService{client: c}
c.DirectionalPools = &DirectionalPoolsService{client: c}
c.Events = &EventsService{client: c}
c.Notifications = &NotificationsService{client: c}
c.Probes = &ProbesService{client: c}
c.RRSets = &RRSetsService{client: c}
c.Tasks = &TasksService{client: c}
return c, nil
}
// newStubClient returns a new ultradns API client.
func newStubClient(username, password, BaseURL, accesstoken, refreshtoken string) (*Client, error) {
c := &Client{
AccessToken: accesstoken,
RefreshToken: refreshtoken,
Username: username,
Password: password,
HTTPClient: &http.Client{},
BaseURL: BaseURL,
UserAgent: userAgent,
}
c.Accounts = &AccountsService{client: c}
c.Alerts = &AlertsService{client: c}
c.DirectionalPools = &DirectionalPoolsService{client: c}
c.Events = &EventsService{client: c}
c.Notifications = &NotificationsService{client: c}
c.Probes = &ProbesService{client: c}
c.RRSets = &RRSetsService{client: c}
c.Tasks = &TasksService{client: c}
return c, nil
}
// NewAuthRequest creates an Authorization request to get an access and refresh token.
//
// {
// "tokenType":"Bearer",
// "refreshToken":"48472efcdce044c8850ee6a395c74a7872932c7112",
// "accessToken":"b91d037c75934fc89a9f43fe4a",
// "expiresIn":"3600",
// "expires_in":"3600"
// }
// AuthResponse wraps the response to an auth request
type AuthResponse struct {
TokenType string `json:"tokenType"`
AccessToken string `json:"accessToken"`
RefreshToken string `json:"refreshToken"`
ExpiresIn string `json:"expiresIn"`
}
// GetAuthTokens requests by username, password & base URL, returns the access-token & refresh-token, or a possible error
func GetAuthTokens(username, password, BaseURL string) (string, string, error) {
res, err := http.PostForm(fmt.Sprintf("%s/%s/authorization/token", BaseURL, apiVersion), url.Values{"grant_type": {"password"}, "username": {username}, "password": {password}})
if err != nil {
return "", "", err
}
//response := &Response{Response: res}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return "", "", err
}
err = CheckAuthResponse(res, body)
if err != nil {
return "", "", err
}
var authr AuthResponse
err = json.Unmarshal(body, &authr)
if err != nil {
return string(body), "JSON Decode Error", err
}
return authr.AccessToken, authr.RefreshToken, err
}
// NewRequest creates an API request.
// The path is expected to be a relative path and will be resolved
// according to the BaseURL of the Client. Paths should always be specified without a preceding slash.
func (c *Client) NewRequest(method, path string, payload interface{}) (*http.Request, error) {
url := c.BaseURL + fmt.Sprintf("%s/%s", apiVersion, path)
body := new(bytes.Buffer)
if payload != nil {
err := json.NewEncoder(body).Encode(payload)
if err != nil {
return nil, err
}
}
req, err := http.NewRequest(method, url, body)
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
req.Header.Add("Accept", "application/json")
req.Header.Add("User-Agent", c.UserAgent)
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", c.AccessToken))
req.Header.Add("Token", fmt.Sprintf("Bearer %s", c.AccessToken))
return req, nil
}
func (c *Client) get(path string, v interface{}) (*Response, error) {
return c.Do("GET", path, nil, v)
}
func (c *Client) post(path string, payload, v interface{}) (*Response, error) {
return c.Do("POST", path, payload, v)
}
func (c *Client) put(path string, payload, v interface{}) (*Response, error) {
return c.Do("PUT", path, payload, v)
}
func (c *Client) delete(path string, payload interface{}) (*Response, error) {
return c.Do("DELETE", path, payload, nil)
}
// Do sends an API request and returns the API response.
// The API response is JSON decoded and stored in the value pointed by v,
// or returned as an error if an API error has occurred.
// If v implements the io.Writer interface, the raw response body will be written to v,
// without attempting to decode it.
func (c *Client) Do(method, path string, payload, v interface{}) (*Response, error) {
req, err := c.NewRequest(method, path, payload)
if err != nil {
return nil, err
}
log.Printf("[DEBUG] HTTP Request: %+v\n", req)
res, err := c.HTTPClient.Do(req)
log.Printf("[DEBUG] HTTP Response: %+v\n", res)
if err != nil {
return nil, err
}
defer res.Body.Close()
origresponse := &Response{Response: res}
var nres *http.Response
nres = res
if res.StatusCode == 202 {
// This is a deferred task.
tid := TaskID(res.Header.Get("X-Task-Id"))
log.Printf("[DEBUG] Received Async Task %+v.. will retry...\n", tid)
// TODO: Sane Configuration for timeouts / retries
timeout := 5
waittime := 5 * time.Second
i := 0
breakmeout := false
for i < timeout || breakmeout {
myt, statusres, err := c.Tasks.Find(tid)
if err != nil {
return origresponse, err
}
log.Printf("[DEBUG] Task ID: %+v Retry: %d Status Code: %s\n", tid, i, myt.TaskStatusCode)
switch myt.TaskStatusCode {
case "COMPLETE":
// Yay
tres, err := c.Tasks.FindResultByTask(myt)
if err != nil {
return origresponse, err
}
nres = tres.Response
breakmeout = true
case "PENDING", "IN_PROCESS":
i = i + 1
time.Sleep(waittime)
continue
case "ERROR":
return statusres, err
}
}
}
response := &Response{Response: nres}
err = CheckResponse(nres)
if err != nil {
return response, err
}
if v != nil {
if w, ok := v.(io.Writer); ok {
io.Copy(w, res.Body)
} else {
err = json.NewDecoder(res.Body).Decode(v)
}
}
return response, err
}
// A Response represents an API response.
type Response struct {
*http.Response
}
// ErrorResponse represents an error caused by an API request.
// Example:
// {"errorCode":60001,"errorMessage":"invalid_grant:Invalid username & password combination.","error":"invalid_grant","error_description":"60001: invalid_grant:Invalid username & password combination."}
type ErrorResponse struct {
Response *http.Response // HTTP response that caused this error
ErrorCode int `json:"errorCode"` // error code
ErrorMessage string `json:"errorMessage"` // human-readable message
ErrorStr string `json:"error"`
ErrorDescription string `json:"error_description"`
}
// ErrorResponseList wraps an HTTP response that has a list of errors
type ErrorResponseList struct {
Response *http.Response // HTTP response that caused this error
Responses []ErrorResponse
}
// Error implements the error interface.
func (r ErrorResponse) Error() string {
return fmt.Sprintf("%v %v: %d %d %v",
r.Response.Request.Method, r.Response.Request.URL,
r.Response.StatusCode, r.ErrorCode, r.ErrorMessage)
}
func (r ErrorResponseList) Error() string {
return fmt.Sprintf("%v %v: %d %d %v",
r.Response.Request.Method, r.Response.Request.URL,
r.Response.StatusCode, r.Responses[0].ErrorCode, r.Responses[0].ErrorMessage)
}
// CheckAuthResponse checks the API response for errors, and returns them if so
func CheckAuthResponse(r *http.Response, body []byte) error {
if code := r.StatusCode; 200 <= code && code <= 299 {
return nil
}
// Attempt marshaling to ErrorResponse
var er ErrorResponse
err := json.Unmarshal(body, &er)
if err == nil {
er.Response = r
return er
}
// Attempt marshaling to ErrorResponseList
var ers []ErrorResponse
err = json.Unmarshal(body, &ers)
if err == nil {
return &ErrorResponseList{Response: r, Responses: ers}
}
return fmt.Errorf("Response had non-successful status: %d, but could not extract error from body: %+v", r.StatusCode, body)
}
// CheckResponse checks the API response for errors, and returns them if present.
// A response is considered an error if the status code is different than 2xx. Specific requests
// may have additional requirements, but this is sufficient in most of the cases.
func CheckResponse(r *http.Response) error {
if code := r.StatusCode; 200 <= code && code <= 299 {
return nil
}
body, err := ioutil.ReadAll(r.Body)
if err != nil {
return err
}
// Attempt marshaling to ErrorResponse
var er ErrorResponse
err = json.Unmarshal(body, &er)
if err == nil {
er.Response = r
return er
}
// Attempt marshaling to ErrorResponseList
var ers []ErrorResponse
err = json.Unmarshal(body, &ers)
if err == nil {
return &ErrorResponseList{Response: r, Responses: ers}
}
return fmt.Errorf("Response had non-successful status: %d, but could not extract error from body: %+v", r.StatusCode, body)
}

View File

@ -33,6 +33,7 @@ body.layout-rundeck,
body.layout-statuscake,
body.layout-template,
body.layout-tls,
body.layout-ultradns,
body.layout-vcd,
body.layout-vsphere,
body.layout-docs,

View File

@ -0,0 +1,39 @@
---
layout: "ultradns"
page_title: "Provider: UltraDNS"
sidebar_current: "docs-ultradns-index"
description: |-
The UltraDNS provider is used to interact with the resources supported by UltraDNS. The provider needs to be configured with the proper credentials before it can be used.
---
# UltraDNS Provider
The UltraDNS provider is used to interact with the
resources supported by UltraDNS. The provider needs to be configured
with the proper credentials before it can be used.
Use the navigation to the left to read about the available resources.
## Example Usage
```
# Configure the UltraDNS provider
provider "ultradns" {
username = "${var.ultradns_username}"
password = "${var.ultradns_password}"
baseurl = "https://test-restapi.ultradns.com/"
}
# Create a record
resource "ultradns_record" "www" {
...
}
```
## Argument Reference
The following arguments are supported:
* `username` - (Required) The UltraDNS username. It must be provided, but it can also be sourced from the `ULTRADNS_USERNAME` environment variable.
* `password` - (Required) The password associated with the username. It must be provided, but it can also be sourced from the `ULTRADNS_PASSWORD` environment variable.
* `baseurl` - (Required) The base url for the UltraDNS REST API, but it can also be sourced from the `ULTRADNS_BASEURL` environment variable.

View File

@ -0,0 +1,48 @@
---
layout: "ultradns"
page_title: "UltraDNS: ultradns_record"
sidebar_current: "docs-ultradns-resource-record"
description: |-
Provides a UltraDNS record resource.
---
# ultradns\_record
Provides a UltraDNS record resource.
## Example Usage
```
# Add a record to the domain
resource "ultradns_record" "foobar" {
zone = "${var.ultradns_domain}"
name = "terraform"
rdata = [ "192.168.0.11" ]
type = "A"
ttl = 3600
}
```
## Argument Reference
See [related part of UltraDNS Docs](https://restapi.ultradns.com/v1/docs#post-rrset) for details about valid values.
The following arguments are supported:
* `zone` - (Required) The domain to add the record to
* `name` - (Required) The name of the record
* `rdata` - (Required) An array containing the values of the record
* `type` - (Required) The type of the record
* `ttl` - (Optional) The TTL of the record
## Attributes Reference
The following attributes are exported:
* `id` - The record ID
* `name` - The name of the record
* `rdata` - An array containing the values of the record
* `type` - The type of the record
* `ttl` - The TTL of the record
* `zone` - The domain of the record
* `hostname` - The FQDN of the record

View File

@ -241,6 +241,10 @@
<a href="/docs/providers/tls/index.html">TLS</a>
</li>
<li<%= sidebar_current("docs-providers-ultradns") %>>
<a href="/docs/providers/ultradns/index.html">UltraDNS</a>
</li>
<li<%= sidebar_current("docs-providers-vcd") %>>
<a href="/docs/providers/vcd/index.html">VMware vCloud Director</a>
</li>

View File

@ -0,0 +1,26 @@
<% wrap_layout :inner do %>
<% content_for :sidebar do %>
<div class="docs-sidebar hidden-print affix-top" role="complementary">
<ul class="nav docs-sidenav">
<li<%= sidebar_current("docs-home") %>>
<a href="/docs/providers/index.html">&laquo; Documentation Home</a>
</li>
<li<%= sidebar_current("docs-ultradns-index") %>>
<a href="/docs/providers/ultradns/index.html">UltraDNS Provider</a>
</li>
<li<%= sidebar_current(/^docs-ultradns-resource/) %>>
<a href="#">Resources</a>
<ul class="nav nav-visible">
<li<%= sidebar_current("docs-ultradns-resource-record") %>>
<a href="/docs/providers/ultradns/r/record.html">ultradns_record</a>
</li>
</ul>
</li>
</ul>
</div>
<% end %>
<%= yield %>
<% end %>