-
Notifications
You must be signed in to change notification settings - Fork 2
/
provider.go
177 lines (145 loc) · 4.87 KB
/
provider.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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
// Package namecheap implements a DNS record management client compatible
// with the libdns interfaces for namecheap.
package namecheap
import (
"context"
"sync"
"time"
"github.com/libdns/libdns"
"github.com/libdns/namecheap/internal/namecheap"
)
func parseIntoHostRecord(record libdns.Record) namecheap.HostRecord {
return namecheap.HostRecord{
HostID: record.ID,
RecordType: namecheap.RecordType(record.Type),
Name: record.Name,
TTL: uint16(record.TTL.Seconds()),
Address: record.Value,
}
}
func parseFromHostRecord(hostRecord namecheap.HostRecord) libdns.Record {
return libdns.Record{
ID: hostRecord.HostID,
Type: string(hostRecord.RecordType),
Name: hostRecord.Name,
TTL: time.Duration(hostRecord.TTL) * time.Second,
Value: hostRecord.Address,
}
}
// Provider facilitates DNS record manipulation with namecheap.
// The libdns methods that return updated structs do not have
// their ID fields set since this information is not returned
// by the namecheap API.
type Provider struct {
// APIKey is your namecheap API key.
// See: https://www.namecheap.com/support/api/intro/
// for more details.
APIKey string `json:"api_key,omitempty"`
// User is your namecheap API user. This can be the same as your username.
User string `json:"user,omitempty"`
// APIEndpoint to use. If testing, you can use the "sandbox" endpoint
// instead of the production one.
APIEndpoint string `json:"api_endpoint,omitempty"`
// ClientIP is the IP address of the requesting client.
// If this is not set, a discovery service will be
// used to determine the public ip of the machine.
// You must first whitelist your IP in the namecheap console
// before using the API.
ClientIP string `json:"client_ip,omitempty"`
mu sync.Mutex
}
// getClient inititializes a new namecheap client.
func (p *Provider) getClient() (*namecheap.Client, error) {
p.mu.Lock()
defer p.mu.Unlock()
options := []namecheap.ClientOption{}
if p.APIEndpoint != "" {
options = append(options, namecheap.WithEndpoint(p.APIEndpoint))
}
if p.ClientIP == "" {
options = append(options, namecheap.AutoDiscoverPublicIP())
}
client, err := namecheap.NewClient(p.APIKey, p.User, options...)
if err != nil {
return nil, err
}
return client, nil
}
// GetRecords lists all the records in the zone.
// This method does return records with the ID field set.
func (p *Provider) GetRecords(ctx context.Context, zone string) ([]libdns.Record, error) {
client, err := p.getClient()
if err != nil {
return nil, err
}
hostRecords, err := client.GetHosts(ctx, zone)
if err != nil {
return nil, err
}
var records []libdns.Record
for _, hr := range hostRecords {
records = append(records, parseFromHostRecord(hr))
}
return records, nil
}
// AppendRecords adds records to the zone. It returns the records that were added.
// Note that the records returned do NOT have their IDs set as the namecheap
// API does not return this info.
func (p *Provider) AppendRecords(ctx context.Context, zone string, records []libdns.Record) ([]libdns.Record, error) {
var hostRecords []namecheap.HostRecord
for _, r := range records {
hostRecords = append(hostRecords, parseIntoHostRecord(r))
}
client, err := p.getClient()
if err != nil {
return nil, err
}
_, err = client.AddHosts(ctx, zone, hostRecords)
if err != nil {
return nil, err
}
return records, nil
}
// SetRecords sets the records in the zone, either by updating existing records or creating new ones.
// It returns the updated records. Note that this method may alter the IDs of existing records on the
// server but may return records without their IDs set or with their old IDs set.
func (p *Provider) SetRecords(ctx context.Context, zone string, records []libdns.Record) ([]libdns.Record, error) {
var hostRecords []namecheap.HostRecord
for _, r := range records {
hostRecords = append(hostRecords, parseIntoHostRecord(r))
}
client, err := p.getClient()
if err != nil {
return nil, err
}
_, err = client.SetHosts(ctx, zone, hostRecords)
if err != nil {
return nil, err
}
return records, nil
}
// DeleteRecords deletes the records from the zone. It returns the records that were deleted.
// Note that the records returned do NOT have their IDs set as the namecheap
// API does not return this info.
func (p *Provider) DeleteRecords(ctx context.Context, zone string, records []libdns.Record) ([]libdns.Record, error) {
var hostRecords []namecheap.HostRecord
for _, r := range records {
hostRecords = append(hostRecords, parseIntoHostRecord(r))
}
client, err := p.getClient()
if err != nil {
return nil, err
}
_, err = client.DeleteHosts(ctx, zone, hostRecords)
if err != nil {
return nil, err
}
return records, nil
}
// Interface guards
var (
_ libdns.RecordGetter = (*Provider)(nil)
_ libdns.RecordAppender = (*Provider)(nil)
_ libdns.RecordSetter = (*Provider)(nil)
_ libdns.RecordDeleter = (*Provider)(nil)
)