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