17
17
package main
18
18
19
19
import (
20
+ "context"
20
21
"errors"
21
22
"fmt"
22
23
"sort"
23
24
"strconv"
24
25
"strings"
26
+ "time"
25
27
26
- "github.com/aws/aws-sdk-go/aws"
27
- "github.com/aws/aws-sdk-go/aws/credentials"
28
- "github.com/aws/aws-sdk-go/aws/session"
29
- "github.com/aws/aws-sdk-go/service/route53"
28
+ "github.com/aws/aws-sdk-go-v2/aws"
29
+ "github.com/aws/aws-sdk-go-v2/config"
30
+ "github.com/aws/aws-sdk-go-v2/credentials"
31
+ "github.com/aws/aws-sdk-go-v2/service/route53"
32
+ "github.com/aws/aws-sdk-go-v2/service/route53/types"
30
33
"github.com/ethereum/go-ethereum/log"
31
34
"github.com/ethereum/go-ethereum/p2p/dnsdisc"
32
35
"gopkg.in/urfave/cli.v1"
@@ -38,6 +41,7 @@ const (
38
41
// https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/DNSLimitations.html#limits-api-requests-changeresourcerecordsets
39
42
route53ChangeSizeLimit = 32000
40
43
route53ChangeCountLimit = 1000
44
+ maxRetryLimit = 60
41
45
)
42
46
43
47
var (
58
62
)
59
63
60
64
type route53Client struct {
61
- api * route53.Route53
65
+ api * route53.Client
62
66
zoneID string
63
67
}
64
68
@@ -74,13 +78,13 @@ func newRoute53Client(ctx *cli.Context) *route53Client {
74
78
if akey == "" || asec == "" {
75
79
exit (fmt .Errorf ("need Route53 Access Key ID and secret proceed" ))
76
80
}
77
- config := & aws.Config { Credentials : credentials .NewStaticCredentials (akey , asec , "" )}
78
- session , err := session . NewSession ( config )
81
+ creds := aws .NewCredentialsCache ( credentials .NewStaticCredentialsProvider (akey , asec , "" ))
82
+ cfg , err := config . LoadDefaultConfig ( context . Background (), config . WithCredentialsProvider ( creds ) )
79
83
if err != nil {
80
- exit (fmt .Errorf ("can't create AWS session : %v" , err ))
84
+ exit (fmt .Errorf ("can't initialize AWS configuration : %v" , err ))
81
85
}
82
86
return & route53Client {
83
- api : route53 .New ( session ),
87
+ api : route53 .NewFromConfig ( cfg ),
84
88
zoneID : ctx .String (route53ZoneIDFlag .Name ),
85
89
}
86
90
}
@@ -105,25 +109,43 @@ func (c *route53Client) deploy(name string, t *dnsdisc.Tree) error {
105
109
return nil
106
110
}
107
111
108
- // Submit change batches.
112
+ // Submit all change batches.
109
113
batches := splitChanges (changes , route53ChangeSizeLimit , route53ChangeCountLimit )
114
+ changesToCheck := make ([]* route53.ChangeResourceRecordSetsOutput , len (batches ))
110
115
for i , changes := range batches {
111
116
log .Info (fmt .Sprintf ("Submitting %d changes to Route53" , len (changes )))
112
- batch := new (route53.ChangeBatch )
113
- batch .SetChanges (changes )
114
- batch .SetComment (fmt .Sprintf ("enrtree update %d/%d of %s at seq %d" , i + 1 , len (batches ), name , t .Seq ()))
117
+ batch := & types.ChangeBatch {
118
+ Changes : changes ,
119
+ Comment : aws .String (fmt .Sprintf ("enrtree update %d/%d of %s at seq %d" , i + 1 , len (batches ), name , t .Seq ())),
120
+ }
115
121
req := & route53.ChangeResourceRecordSetsInput {HostedZoneId : & c .zoneID , ChangeBatch : batch }
116
- resp , err : = c .api .ChangeResourceRecordSets (req )
122
+ changesToCheck [ i ] , err = c .api .ChangeResourceRecordSets (context . TODO (), req )
117
123
if err != nil {
118
124
return err
119
125
}
126
+ }
120
127
121
- log .Info (fmt .Sprintf ("Waiting for change request %s" , * resp .ChangeInfo .Id ))
122
- wreq := & route53.GetChangeInput {Id : resp .ChangeInfo .Id }
123
- if err := c .api .WaitUntilResourceRecordSetsChanged (wreq ); err != nil {
124
- return err
128
+ // wait for all change batches to propagate
129
+ for _ , change := range changesToCheck {
130
+ log .Info (fmt .Sprintf ("Waiting for change request %s" , * change .ChangeInfo .Id ))
131
+ wreq := & route53.GetChangeInput {Id : change .ChangeInfo .Id }
132
+ var count int
133
+ for {
134
+ wresp , err := c .api .GetChange (context .TODO (), wreq )
135
+ if err != nil {
136
+ return err
137
+ }
138
+
139
+ count ++
140
+
141
+ if wresp .ChangeInfo .Status == types .ChangeStatusInsync || count >= maxRetryLimit {
142
+ break
143
+ }
144
+
145
+ time .Sleep (30 * time .Second )
125
146
}
126
147
}
148
+
127
149
return nil
128
150
}
129
151
@@ -140,7 +162,7 @@ func (c *route53Client) findZoneID(name string) (string, error) {
140
162
log .Info (fmt .Sprintf ("Finding Route53 Zone ID for %s" , name ))
141
163
var req route53.ListHostedZonesByNameInput
142
164
for {
143
- resp , err := c .api .ListHostedZonesByName (& req )
165
+ resp , err := c .api .ListHostedZonesByName (context . TODO (), & req )
144
166
if err != nil {
145
167
return "" , err
146
168
}
@@ -149,7 +171,7 @@ func (c *route53Client) findZoneID(name string) (string, error) {
149
171
return * zone .Id , nil
150
172
}
151
173
}
152
- if ! * resp .IsTruncated {
174
+ if ! resp .IsTruncated {
153
175
break
154
176
}
155
177
req .DNSName = resp .NextDNSName
@@ -159,15 +181,15 @@ func (c *route53Client) findZoneID(name string) (string, error) {
159
181
}
160
182
161
183
// computeChanges creates DNS changes for the given record.
162
- func (c * route53Client ) computeChanges (name string , records map [string ]string , existing map [string ]recordSet ) []* route53 .Change {
184
+ func (c * route53Client ) computeChanges (name string , records map [string ]string , existing map [string ]recordSet ) []types .Change {
163
185
// Convert all names to lowercase.
164
186
lrecords := make (map [string ]string , len (records ))
165
187
for name , r := range records {
166
188
lrecords [strings .ToLower (name )] = r
167
189
}
168
190
records = lrecords
169
191
170
- var changes []* route53 .Change
192
+ var changes []types .Change
171
193
for path , val := range records {
172
194
ttl := int64 (rootTTL )
173
195
if path != name {
@@ -204,21 +226,21 @@ func (c *route53Client) computeChanges(name string, records map[string]string, e
204
226
}
205
227
206
228
// sortChanges ensures DNS changes are in leaf-added -> root-changed -> leaf-deleted order.
207
- func sortChanges (changes []* route53 .Change ) {
229
+ func sortChanges (changes []types .Change ) {
208
230
score := map [string ]int {"CREATE" : 1 , "UPSERT" : 2 , "DELETE" : 3 }
209
231
sort .Slice (changes , func (i , j int ) bool {
210
- if * changes [i ].Action == * changes [j ].Action {
232
+ if changes [i ].Action == changes [j ].Action {
211
233
return * changes [i ].ResourceRecordSet .Name < * changes [j ].ResourceRecordSet .Name
212
234
}
213
- return score [* changes [i ].Action ] < score [* changes [j ].Action ]
235
+ return score [string ( changes [i ].Action ) ] < score [string ( changes [j ].Action ) ]
214
236
})
215
237
}
216
238
217
239
// splitChanges splits up DNS changes such that each change batch
218
240
// is smaller than the given RDATA limit.
219
- func splitChanges (changes []* route53 .Change , sizeLimit , countLimit int ) [][]* route53 .Change {
241
+ func splitChanges (changes []types .Change , sizeLimit , countLimit int ) [][]types .Change {
220
242
var (
221
- batches [][]* route53 .Change
243
+ batches [][]types .Change
222
244
batchSize int
223
245
batchCount int
224
246
)
@@ -241,7 +263,7 @@ func splitChanges(changes []*route53.Change, sizeLimit, countLimit int) [][]*rou
241
263
}
242
264
243
265
// changeSize returns the RDATA size of a DNS change.
244
- func changeSize (ch * route53 .Change ) int {
266
+ func changeSize (ch types .Change ) int {
245
267
size := 0
246
268
for _ , rr := range ch .ResourceRecordSet .ResourceRecords {
247
269
if rr .Value != nil {
@@ -251,8 +273,8 @@ func changeSize(ch *route53.Change) int {
251
273
return size
252
274
}
253
275
254
- func changeCount (ch * route53 .Change ) int {
255
- if * ch .Action == "UPSERT" {
276
+ func changeCount (ch types .Change ) int {
277
+ if ch .Action == types . ChangeActionUpsert {
256
278
return 2
257
279
}
258
280
return 1
@@ -262,42 +284,58 @@ func changeCount(ch *route53.Change) int {
262
284
func (c * route53Client ) collectRecords (name string ) (map [string ]recordSet , error ) {
263
285
log .Info (fmt .Sprintf ("Retrieving existing TXT records on %s (%s)" , name , c .zoneID ))
264
286
var req route53.ListResourceRecordSetsInput
265
- req .SetHostedZoneId ( c .zoneID )
287
+ req .HostedZoneId = & c .zoneID
266
288
existing := make (map [string ]recordSet )
267
- err := c .api .ListResourceRecordSetsPages (& req , func (resp * route53.ListResourceRecordSetsOutput , last bool ) bool {
289
+ for {
290
+ resp , err := c .api .ListResourceRecordSets (context .TODO (), & req )
291
+ if err != nil {
292
+ return existing , err
293
+ }
294
+
268
295
for _ , set := range resp .ResourceRecordSets {
269
- if ! isSubdomain (* set .Name , name ) || * set .Type != "TXT" {
296
+ if ! isSubdomain (* set .Name , name ) || set .Type != types . RRTypeTxt {
270
297
continue
271
298
}
299
+
272
300
s := recordSet {ttl : * set .TTL }
273
301
for _ , rec := range set .ResourceRecords {
274
302
s .values = append (s .values , * rec .Value )
275
303
}
276
304
name := strings .TrimSuffix (* set .Name , "." )
277
305
existing [name ] = s
278
306
}
279
- return true
280
- })
281
- return existing , err
307
+
308
+ if ! resp .IsTruncated {
309
+ break
310
+ }
311
+
312
+ // sets the cursor to the next batch
313
+ req .StartRecordIdentifier = resp .NextRecordIdentifier
314
+ }
315
+
316
+ return existing , nil
282
317
}
283
318
284
319
// newTXTChange creates a change to a TXT record.
285
- func newTXTChange (action , name string , ttl int64 , values ... string ) * route53.Change {
286
- var c route53.Change
287
- var r route53.ResourceRecordSet
288
- var rrs []* route53.ResourceRecord
320
+ func newTXTChange (action , name string , ttl int64 , values ... string ) types.Change {
321
+ r := types.ResourceRecordSet {
322
+ Type : types .RRTypeTxt ,
323
+ Name : & name ,
324
+ TTL : & ttl ,
325
+ }
326
+ var rrs []types.ResourceRecord
289
327
for _ , val := range values {
290
- rr := new (route53 .ResourceRecord )
291
- rr .SetValue (val )
328
+ var rr types .ResourceRecord
329
+ rr .Value = aws . String (val )
292
330
rrs = append (rrs , rr )
293
331
}
294
- r . SetType ( "TXT" )
295
- r .SetName ( name )
296
- r . SetTTL ( ttl )
297
- r . SetResourceRecords ( rrs )
298
- c . SetAction (action )
299
- c . SetResourceRecordSet ( & r )
300
- return & c
332
+
333
+ r .ResourceRecords = rrs
334
+
335
+ return types. Change {
336
+ Action : types . ChangeAction (action ),
337
+ ResourceRecordSet : & r ,
338
+ }
301
339
}
302
340
303
341
// isSubdomain returns true if name is a subdomain of domain.
0 commit comments