Skip to content

Commit e3a3f7c

Browse files
authored
cmd/devp2p: use AWS-SDK v2 (#22360)
This updates the DNS deployer to use AWS SDK v2. Migration is relatively seamless, although there were two locations that required a slightly different approach to achieve the same results. In particular, waiting for DNS change propagation is very different with SDK v2. This change also optimizes DNS updates by publishing all changes before waiting for propagation.
1 parent d50e9d2 commit e3a3f7c

File tree

4 files changed

+153
-87
lines changed

4 files changed

+153
-87
lines changed

cmd/devp2p/dns_route53.go

Lines changed: 87 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,19 @@
1717
package main
1818

1919
import (
20+
"context"
2021
"errors"
2122
"fmt"
2223
"sort"
2324
"strconv"
2425
"strings"
26+
"time"
2527

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"
3033
"github.com/ethereum/go-ethereum/log"
3134
"github.com/ethereum/go-ethereum/p2p/dnsdisc"
3235
"gopkg.in/urfave/cli.v1"
@@ -38,6 +41,7 @@ const (
3841
// https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/DNSLimitations.html#limits-api-requests-changeresourcerecordsets
3942
route53ChangeSizeLimit = 32000
4043
route53ChangeCountLimit = 1000
44+
maxRetryLimit = 60
4145
)
4246

4347
var (
@@ -58,7 +62,7 @@ var (
5862
)
5963

6064
type route53Client struct {
61-
api *route53.Route53
65+
api *route53.Client
6266
zoneID string
6367
}
6468

@@ -74,13 +78,13 @@ func newRoute53Client(ctx *cli.Context) *route53Client {
7478
if akey == "" || asec == "" {
7579
exit(fmt.Errorf("need Route53 Access Key ID and secret proceed"))
7680
}
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))
7983
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))
8185
}
8286
return &route53Client{
83-
api: route53.New(session),
87+
api: route53.NewFromConfig(cfg),
8488
zoneID: ctx.String(route53ZoneIDFlag.Name),
8589
}
8690
}
@@ -105,25 +109,43 @@ func (c *route53Client) deploy(name string, t *dnsdisc.Tree) error {
105109
return nil
106110
}
107111

108-
// Submit change batches.
112+
// Submit all change batches.
109113
batches := splitChanges(changes, route53ChangeSizeLimit, route53ChangeCountLimit)
114+
changesToCheck := make([]*route53.ChangeResourceRecordSetsOutput, len(batches))
110115
for i, changes := range batches {
111116
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+
}
115121
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)
117123
if err != nil {
118124
return err
119125
}
126+
}
120127

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)
125146
}
126147
}
148+
127149
return nil
128150
}
129151

@@ -140,7 +162,7 @@ func (c *route53Client) findZoneID(name string) (string, error) {
140162
log.Info(fmt.Sprintf("Finding Route53 Zone ID for %s", name))
141163
var req route53.ListHostedZonesByNameInput
142164
for {
143-
resp, err := c.api.ListHostedZonesByName(&req)
165+
resp, err := c.api.ListHostedZonesByName(context.TODO(), &req)
144166
if err != nil {
145167
return "", err
146168
}
@@ -149,7 +171,7 @@ func (c *route53Client) findZoneID(name string) (string, error) {
149171
return *zone.Id, nil
150172
}
151173
}
152-
if !*resp.IsTruncated {
174+
if !resp.IsTruncated {
153175
break
154176
}
155177
req.DNSName = resp.NextDNSName
@@ -159,15 +181,15 @@ func (c *route53Client) findZoneID(name string) (string, error) {
159181
}
160182

161183
// 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 {
163185
// Convert all names to lowercase.
164186
lrecords := make(map[string]string, len(records))
165187
for name, r := range records {
166188
lrecords[strings.ToLower(name)] = r
167189
}
168190
records = lrecords
169191

170-
var changes []*route53.Change
192+
var changes []types.Change
171193
for path, val := range records {
172194
ttl := int64(rootTTL)
173195
if path != name {
@@ -204,21 +226,21 @@ func (c *route53Client) computeChanges(name string, records map[string]string, e
204226
}
205227

206228
// 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) {
208230
score := map[string]int{"CREATE": 1, "UPSERT": 2, "DELETE": 3}
209231
sort.Slice(changes, func(i, j int) bool {
210-
if *changes[i].Action == *changes[j].Action {
232+
if changes[i].Action == changes[j].Action {
211233
return *changes[i].ResourceRecordSet.Name < *changes[j].ResourceRecordSet.Name
212234
}
213-
return score[*changes[i].Action] < score[*changes[j].Action]
235+
return score[string(changes[i].Action)] < score[string(changes[j].Action)]
214236
})
215237
}
216238

217239
// splitChanges splits up DNS changes such that each change batch
218240
// 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 {
220242
var (
221-
batches [][]*route53.Change
243+
batches [][]types.Change
222244
batchSize int
223245
batchCount int
224246
)
@@ -241,7 +263,7 @@ func splitChanges(changes []*route53.Change, sizeLimit, countLimit int) [][]*rou
241263
}
242264

243265
// changeSize returns the RDATA size of a DNS change.
244-
func changeSize(ch *route53.Change) int {
266+
func changeSize(ch types.Change) int {
245267
size := 0
246268
for _, rr := range ch.ResourceRecordSet.ResourceRecords {
247269
if rr.Value != nil {
@@ -251,8 +273,8 @@ func changeSize(ch *route53.Change) int {
251273
return size
252274
}
253275

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 {
256278
return 2
257279
}
258280
return 1
@@ -262,42 +284,58 @@ func changeCount(ch *route53.Change) int {
262284
func (c *route53Client) collectRecords(name string) (map[string]recordSet, error) {
263285
log.Info(fmt.Sprintf("Retrieving existing TXT records on %s (%s)", name, c.zoneID))
264286
var req route53.ListResourceRecordSetsInput
265-
req.SetHostedZoneId(c.zoneID)
287+
req.HostedZoneId = &c.zoneID
266288
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+
268295
for _, set := range resp.ResourceRecordSets {
269-
if !isSubdomain(*set.Name, name) || *set.Type != "TXT" {
296+
if !isSubdomain(*set.Name, name) || set.Type != types.RRTypeTxt {
270297
continue
271298
}
299+
272300
s := recordSet{ttl: *set.TTL}
273301
for _, rec := range set.ResourceRecords {
274302
s.values = append(s.values, *rec.Value)
275303
}
276304
name := strings.TrimSuffix(*set.Name, ".")
277305
existing[name] = s
278306
}
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
282317
}
283318

284319
// 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
289327
for _, val := range values {
290-
rr := new(route53.ResourceRecord)
291-
rr.SetValue(val)
328+
var rr types.ResourceRecord
329+
rr.Value = aws.String(val)
292330
rrs = append(rrs, rr)
293331
}
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+
}
301339
}
302340

303341
// isSubdomain returns true if name is a subdomain of domain.

0 commit comments

Comments
 (0)