client.go raw

   1  package client
   2  
   3  import (
   4  	"encoding/json"
   5  	"errors"
   6  	"fmt"
   7  	"github.com/labbsr0x/bindman-dns-webhook/src/types"
   8  	"github.com/labbsr0x/goh/gohclient"
   9  	"net/http"
  10  	"strings"
  11  )
  12  
  13  const recordsPath = "/records"
  14  
  15  // DNSWebhookClient defines the basic structure of a DNS Listener
  16  type DNSWebhookClient struct {
  17  	ClientAPI gohclient.API
  18  }
  19  
  20  // New builds the client to communicate with the dns manager
  21  func New(managerAddress string, httpClient *http.Client) (*DNSWebhookClient, error) {
  22  	if strings.TrimSpace(managerAddress) == "" {
  23  		return nil, errors.New("managerAddress parameter must be a non-empty string")
  24  	}
  25  	client, err := gohclient.New(httpClient, managerAddress)
  26  	if err != nil {
  27  		return nil, err
  28  	}
  29  	client.Accept = "application/json"
  30  	client.ContentType = "application/json"
  31  	client.UserAgent = "bindman-dns-webhook-client"
  32  
  33  	return &DNSWebhookClient{
  34  		ClientAPI: client,
  35  	}, nil
  36  }
  37  
  38  // GetRecords communicates with the dns manager and gets the DNS Records
  39  func (l *DNSWebhookClient) GetRecords() (result []types.DNSRecord, err error) {
  40  	resp, data, err := l.ClientAPI.Get(recordsPath)
  41  	if err != nil {
  42  		return
  43  	}
  44  	if resp.StatusCode == http.StatusOK {
  45  		err = json.Unmarshal(data, &result)
  46  	} else {
  47  		err = parseResponseBodyToError(data)
  48  	}
  49  	return
  50  }
  51  
  52  // GetRecord communicates with the dns manager and gets a DNS Record
  53  func (l *DNSWebhookClient) GetRecord(name, recordType string) (result types.DNSRecord, err error) {
  54  	resp, data, err := l.ClientAPI.Get(fmt.Sprintf(recordsPath+"/%s/%s", name, recordType))
  55  	if err != nil {
  56  		return
  57  	}
  58  	if resp.StatusCode == http.StatusOK {
  59  		err = json.Unmarshal(data, &result)
  60  	} else {
  61  		err = parseResponseBodyToError(data)
  62  	}
  63  	return
  64  }
  65  
  66  // AddRecord adds a DNS record
  67  func (l *DNSWebhookClient) AddRecord(name string, recordType string, value string) error {
  68  	return l.addOrUpdateRecord(&types.DNSRecord{Value: value, Name: name, Type: recordType}, l.ClientAPI.Post)
  69  }
  70  
  71  // UpdateRecord is a function that calls the defined webhook to update a specific dns record
  72  func (l *DNSWebhookClient) UpdateRecord(record *types.DNSRecord) error {
  73  	return l.addOrUpdateRecord(record, l.ClientAPI.Put)
  74  }
  75  
  76  // addOrUpdateRecord .
  77  func (l *DNSWebhookClient) addOrUpdateRecord(record *types.DNSRecord, action func(url string, body []byte) (*http.Response, []byte, error)) error {
  78  	if errs := record.Check(); errs != nil {
  79  		return fmt.Errorf("invalid DNS Record: %v", strings.Join(errs, ", "))
  80  	}
  81  	mr, err := json.Marshal(record)
  82  	if err != nil {
  83  		return err
  84  	}
  85  	resp, data, err := action(recordsPath, mr)
  86  	if err != nil {
  87  		return err
  88  	}
  89  	if resp.StatusCode != http.StatusNoContent {
  90  		return parseResponseBodyToError(data)
  91  	}
  92  	return nil
  93  }
  94  
  95  // RemoveRecord is a function that calls the defined webhook to remove a specific dns record
  96  func (l *DNSWebhookClient) RemoveRecord(name, recordType string) error {
  97  	resp, data, err := l.ClientAPI.Delete(fmt.Sprintf(recordsPath+"/%s/%s", name, recordType))
  98  	if err != nil {
  99  		return err
 100  	}
 101  	if resp.StatusCode != http.StatusNoContent {
 102  		return parseResponseBodyToError(data)
 103  	}
 104  	return err
 105  }
 106  
 107  func parseResponseBodyToError(data []byte) error {
 108  	var err types.Error
 109  	if errUnmarshal := json.Unmarshal(data, &err); errUnmarshal != nil {
 110  		return errUnmarshal
 111  	}
 112  	return &err
 113  }
 114