/
client.go
143 lines (124 loc) · 4.48 KB
/
client.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package hostingde
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"
)
const defaultBaseURL = "https://secure.hosting.de/api/dns/v1/json"
// RecordsAddRequest represents a DNS record to add
type RecordsAddRequest struct {
Name string `json:"name"`
Type string `json:"type"`
Content string `json:"content"`
TTL int `json:"ttl"`
}
// RecordsDeleteRequest represents a DNS record to remove
type RecordsDeleteRequest struct {
Name string `json:"name"`
Type string `json:"type"`
Content string `json:"content"`
ID string `json:"id"`
}
// ZoneConfigObject represents the ZoneConfig-section of a hosting.de API response.
type ZoneConfigObject struct {
AccountID string `json:"accountId"`
EmailAddress string `json:"emailAddress"`
ID string `json:"id"`
LastChangeDate string `json:"lastChangeDate"`
MasterIP string `json:"masterIp"`
Name string `json:"name"`
NameUnicode string `json:"nameUnicode"`
SOAValues struct {
Expire int `json:"expire"`
NegativeTTL int `json:"negativeTtl"`
Refresh int `json:"refresh"`
Retry int `json:"retry"`
Serial string `json:"serial"`
TTL int `json:"ttl"`
} `json:"soaValues"`
Status string `json:"status"`
TemplateValues string `json:"templateValues"`
Type string `json:"type"`
ZoneTransferWhitelist []string `json:"zoneTransferWhitelist"`
}
// ZoneUpdateError represents an error in a ZoneUpdateResponse
type ZoneUpdateError struct {
Code int `json:"code"`
ContextObject string `json:"contextObject"`
ContextPath string `json:"contextPath"`
Details []string `json:"details"`
Text string `json:"text"`
Value string `json:"value"`
}
// ZoneUpdateMetadata represents the metadata in a ZoneUpdateResponse
type ZoneUpdateMetadata struct {
ClientTransactionID string `json:"clientTransactionId"`
ServerTransactionID string `json:"serverTransactionId"`
}
// ZoneUpdateResponse represents a response from hosting.de API
type ZoneUpdateResponse struct {
Errors []ZoneUpdateError `json:"errors"`
Metadata ZoneUpdateMetadata `json:"metadata"`
Warnings []string `json:"warnings"`
Status string `json:"status"`
Response struct {
Records []struct {
Content string `json:"content"`
Type string `json:"type"`
ID string `json:"id"`
Name string `json:"name"`
LastChangeDate string `json:"lastChangeDate"`
Priority int `json:"priority"`
RecordTemplateID string `json:"recordTemplateId"`
ZoneConfigID string `json:"zoneConfigId"`
TTL int `json:"ttl"`
} `json:"records"`
ZoneConfig ZoneConfigObject `json:"zoneConfig"`
} `json:"response"`
}
// ZoneConfigSelector represents a "minimal" ZoneConfig object used in hosting.de API requests
type ZoneConfigSelector struct {
Name string `json:"name"`
}
// ZoneUpdateRequest represents a hosting.de API ZoneUpdate request
type ZoneUpdateRequest struct {
AuthToken string `json:"authToken"`
ZoneConfigSelector `json:"zoneConfig"`
RecordsToAdd []RecordsAddRequest `json:"recordsToAdd"`
RecordsToDelete []RecordsDeleteRequest `json:"recordsToDelete"`
}
func (d *DNSProvider) updateZone(updateRequest ZoneUpdateRequest) (*ZoneUpdateResponse, error) {
body, err := json.Marshal(updateRequest)
if err != nil {
return nil, err
}
req, err := http.NewRequest(http.MethodPost, defaultBaseURL+"/zoneUpdate", bytes.NewReader(body))
if err != nil {
return nil, err
}
resp, err := d.config.HTTPClient.Do(req)
if err != nil {
return nil, fmt.Errorf("error querying API: %v", err)
}
defer resp.Body.Close()
content, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, errors.New(toUnreadableBodyMessage(req, content))
}
// Everything looks good; but we'll need the ID later to delete the record
updateResponse := &ZoneUpdateResponse{}
err = json.Unmarshal(content, updateResponse)
if err != nil {
return nil, fmt.Errorf("%v: %s", err, toUnreadableBodyMessage(req, content))
}
if updateResponse.Status != "success" && updateResponse.Status != "pending" {
return updateResponse, errors.New(toUnreadableBodyMessage(req, content))
}
return updateResponse, nil
}
func toUnreadableBodyMessage(req *http.Request, rawBody []byte) string {
return fmt.Sprintf("the request %s sent a response with a body which is an invalid format: %q", req.URL, string(rawBody))
}