Skip to content

Commit

Permalink
[#25] - update api to patch individual record types
Browse files Browse the repository at this point in the history
  • Loading branch information
n3integration committed Feb 9, 2019
1 parent f74916f commit 3f84d52
Show file tree
Hide file tree
Showing 7 changed files with 269 additions and 135 deletions.
15 changes: 12 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<dl>
<dt>Terraform v0.11.x</dt>
<dd>https://github.com/n3integration/terraform-godaddy/releases/tag/v1.6.3</dd>
<dd>https://github.com/n3integration/terraform-godaddy/releases/tag/v1.6.4</dd>
<dt>Terraform v0.10.x</dt>
<dd>https://github.com/n3integration/terraform-godaddy/releases/tag/v1.5.0</dd>
<dt>Terraform v0.9.x</dt>
Expand Down Expand Up @@ -58,8 +58,13 @@ types include:
```terraform
resource "godaddy_domain_record" "gd-fancy-domain" {
domain = "fancy-domain.com"
customer = "1234" // required if provider key does not belong to customer
// required if provider key does not belong to customer
customer = "1234"
// specify zero or more record blocks
// a record block allows you to configure A, or NS records with a custom time-to-live value
// a record block also allow you to configure AAAA, CNAME, TXT, or MX records
record {
name = "www"
type = "CNAME"
Expand All @@ -75,7 +80,11 @@ resource "godaddy_domain_record" "gd-fancy-domain" {
priority = 1
}
// specify any A records associated with the domain
addresses = ["192.168.1.2", "192.168.1.3"]
// specify any custom nameservers for your domain
// note: godaddy now requires that the 'custom' nameservers are first supplied through the ui
nameservers = ["ns7.domains.com", "ns6.domains.com"]
}
```
Expand All @@ -90,7 +99,7 @@ fully automated imports.

## License

Copyright 2017 n3integration@gmail.com
Copyright 2019 n3integration@gmail.com

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
81 changes: 8 additions & 73 deletions api/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"log"
"net"
"net/http"
"net/url"
Expand All @@ -19,8 +21,6 @@ const (
headerContent = "Content-Type"
headerCustomerID = "X-Shopper-Id"
mediaTypeJSON = "application/json"
pathDomainRecords = "%s/v1/domains/%s/records"
pathDomains = "%s/v1/domains/%s"
rateLimit = 1 * time.Second
)

Expand Down Expand Up @@ -83,75 +83,6 @@ func NewClient(baseURL, key, secret string) (*Client, error) {
}, nil
}

// GetDomains fetches the details for the provided domain
func (c *Client) GetDomains(customerID string) ([]Domain, error) {
domainURL := fmt.Sprintf(pathDomains, c.baseURL, "")
req, err := http.NewRequest(http.MethodGet, domainURL, nil)

if err != nil {
return nil, err
}

var d []Domain
if err := c.execute(customerID, req, &d); err != nil {
return nil, err
}

return d, nil
}

// GetDomain fetches the details for the provided domain
func (c *Client) GetDomain(customerID, domain string) (*Domain, error) {
domainURL := fmt.Sprintf(pathDomains, c.baseURL, domain)
req, err := http.NewRequest(http.MethodGet, domainURL, nil)

if err != nil {
return nil, err
}

d := new(Domain)
if err := c.execute(customerID, req, &d); err != nil {
return nil, err
}

return d, nil
}

// GetDomainRecords fetches all of the existing records for the provided domain
func (c *Client) GetDomainRecords(customerID, domain string) ([]*DomainRecord, error) {
domainURL := fmt.Sprintf(pathDomainRecords, c.baseURL, domain)
req, err := http.NewRequest(http.MethodGet, domainURL, nil)

if err != nil {
return nil, err
}

records := make([]*DomainRecord, 0)
if err := c.execute(customerID, req, &records); err != nil {
return nil, err
}

return records, nil
}

// UpdateDomainRecords replaces all of the existing records for the provided domain
func (c *Client) UpdateDomainRecords(customerID, domain string, records []*DomainRecord) error {
msg, err := json.Marshal(records)
if err != nil {
return err
}

domainURL := fmt.Sprintf(pathDomainRecords, c.baseURL, domain)
method := http.MethodPut

req, err := http.NewRequest(method, domainURL, bytes.NewBuffer(msg))
if err != nil {
return err
}

return c.execute(customerID, req, nil)
}

func (c *Client) execute(customerID string, req *http.Request, result interface{}) error {
if len(strings.TrimSpace(customerID)) > 0 {
req.Header.Set(headerCustomerID, customerID)
Expand All @@ -172,7 +103,9 @@ func (c *Client) execute(customerID string, req *http.Request, result interface{
return err
}

body, err := ioutil.ReadAll(resp.Body)
buffer := new(bytes.Buffer)
body, err := ioutil.ReadAll(io.TeeReader(resp.Body, buffer))
log.Printf("%s %s", resp.Status, buffer)
if err != nil {
return err
}
Expand All @@ -191,7 +124,9 @@ func validate(resp *http.Response) error {
return nil
}

body, err := ioutil.ReadAll(resp.Body)
buffer := new(bytes.Buffer)
body, err := ioutil.ReadAll(io.TeeReader(resp.Body, buffer))
log.Println(buffer)
if err != nil {
return err
}
Expand Down
110 changes: 110 additions & 0 deletions api/domains.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package api

import (
"bytes"
"encoding/json"
"fmt"
"log"
"net/http"
"strings"
)

var (
pathDomainRecords = "%s/v1/domains/%s/records"
pathDomainRecordsByType = "%s/v1/domains/%s/records/%s"
pathDomains = "%s/v1/domains/%s"
)

// GetDomains fetches the details for the provided domain
func (c *Client) GetDomains(customerID string) ([]Domain, error) {
domainURL := fmt.Sprintf(pathDomains, c.baseURL, "")
req, err := http.NewRequest(http.MethodGet, domainURL, nil)

if err != nil {
return nil, err
}

var d []Domain
if err := c.execute(customerID, req, &d); err != nil {
return nil, err
}

return d, nil
}

// GetDomain fetches the details for the provided domain
func (c *Client) GetDomain(customerID, domain string) (*Domain, error) {
domainURL := fmt.Sprintf(pathDomains, c.baseURL, domain)
req, err := http.NewRequest(http.MethodGet, domainURL, nil)

if err != nil {
return nil, err
}

d := new(Domain)
if err := c.execute(customerID, req, &d); err != nil {
return nil, err
}

return d, nil
}

// GetDomainRecords fetches all of the existing records for the provided domain
func (c *Client) GetDomainRecords(customerID, domain string) ([]*DomainRecord, error) {
domainURL := fmt.Sprintf(pathDomainRecords, c.baseURL, domain)
req, err := http.NewRequest(http.MethodGet, domainURL, nil)

if err != nil {
return nil, err
}

records := make([]*DomainRecord, 0)
if err := c.execute(customerID, req, &records); err != nil {
return nil, err
}

return records, nil
}

// UpdateDomainRecords replaces all of the existing records for the provided domain
func (c *Client) UpdateDomainRecords(customerID, domain string, records []*DomainRecord) error {
for _, t := range supportedTypes {
typeRecords := c.domainRecordsOfType(t, records)
if IsDisallowed(t, typeRecords) {
continue
}

msg, err := json.Marshal(typeRecords)
if err != nil {
return err
}

buffer := bytes.NewBuffer(msg)
domainURL := fmt.Sprintf(pathDomainRecordsByType, c.baseURL, domain, t)
log.Println(domainURL)
log.Println(buffer)

req, err := http.NewRequest(http.MethodPut, domainURL, buffer)
if err != nil {
return err
}

if err := c.execute(customerID, req, nil); err != nil {
return err
}
}

return nil
}

func (c *Client) domainRecordsOfType(t string, records []*DomainRecord) []*DomainRecord {
typeRecords := make([]*DomainRecord, 0)

for _, record := range records {
if strings.EqualFold(record.Type, t) {
typeRecords = append(typeRecords, record)
}
}

return typeRecords
}
7 changes: 6 additions & 1 deletion api/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ func NewARecord(data string) (*DomainRecord, error) {

// ValidateData performs bounds checking on a data element
func ValidateData(t, data string) error {
switch (t) {
switch t {
case TXTType:
if len(data) < 0 || len(data) > 512 {
return fmt.Errorf("data must be between 0..512 characters in length")
Expand Down Expand Up @@ -170,6 +170,11 @@ func IsDefaultNSRecord(record *DomainRecord) bool {
return record.Name == Ptr && record.Type == NSType && record.TTL == DefaultTTL
}

// IsDisallowed prevents empty NS|SOA record lists from being propagated, which is disallowed
func IsDisallowed(t string, records []*DomainRecord) bool {
return len(records) == 0 && strings.EqualFold(t, NSType) || strings.EqualFold(t, SOAType)
}

func isSupportedType(recType string) bool {
for _, t := range supportedTypes {
if t == recType {
Expand Down
Loading

0 comments on commit 3f84d52

Please sign in to comment.