Skip to content

Commit

Permalink
Add upsert mode that can be used with import to only add/replace addi…
Browse files Browse the repository at this point in the history
…tional records found in the file
  • Loading branch information
nneul authored and barnybug committed Jan 17, 2021
1 parent faaedb8 commit ce3fc7b
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 11 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ Also you can 'dry-run' import, to check what will happen:

$ cli53 import --file zonefile.txt --replace --wait --dry-run example.com

Upsert with an imported zone (replace existing and add new records, without deleting):

$ cli53 import --file zonefile.txt --upsert example.com

Create an A record pointed to 192.168.0.1 with TTL of 60 seconds:

$ cli53 rrcreate example.com 'www 60 A 192.168.0.1'
Expand Down
33 changes: 22 additions & 11 deletions commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ type importArgs struct {
wait bool
editauth bool
replace bool
upsert bool
dryrun bool
}

Expand Down Expand Up @@ -279,7 +280,7 @@ func importBind(args importArgs) {

grouped := groupRecords(records)
existing := map[string]*route53.ResourceRecordSet{}
if args.replace {
if args.replace || args.upsert {
rrsets, err := ListAllRecordSets(r53, *zone.Id)
fatalIfErr(err)
for _, rrset := range rrsets {
Expand All @@ -299,24 +300,34 @@ func importBind(args importArgs) {
// no difference - leave it untouched
delete(existing, key)
} else {
// new record, add
change := route53.Change{
Action: aws.String("CREATE"),
ResourceRecordSet: rrset,
// new record, add or upsert
if args.upsert {
change := route53.Change{
Action: aws.String("UPSERT"),
ResourceRecordSet: rrset,
}
additions = append(additions, &change)
} else {
change := route53.Change{
Action: aws.String("CREATE"),
ResourceRecordSet: rrset,
}
additions = append(additions, &change)
}
additions = append(additions, &change)
}
}
}

// remaining records in existing should be deleted
deletions := []*route53.Change{}
for _, rrset := range existing {
change := route53.Change{
Action: aws.String("DELETE"),
ResourceRecordSet: rrset,
if !args.upsert {
for _, rrset := range existing {
change := route53.Change{
Action: aws.String("DELETE"),
ResourceRecordSet: rrset,
}
deletions = append(deletions, &change)
}
deletions = append(deletions, &change)
}

if args.dryrun {
Expand Down
6 changes: 6 additions & 0 deletions internal/features/import.feature
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ Feature: import
And I run "cli53 import --replace --file tests/replace2.txt $domain"
Then the domain "$domain" export matches file "tests/replace2.txt"

Scenario: I can import (upsert) a zone
Given I have a domain "$domain"
When I run "cli53 import --file tests/upsert1.txt $domain"
And I run "cli53 import --upsert --file tests/upsert2.txt $domain"
Then the domain "$domain" export matches file "tests/upsert3.txt"

Scenario: I can import dry-run (with changes)
Given I have a domain "$domain"
When I run "cli53 import --file tests/replace1.txt $domain"
Expand Down
5 changes: 5 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,10 @@ func Main(args []string) int {
Name: "replace",
Usage: "replace all existing records",
},
&cli.BoolFlag{
Name: "upsert",
Usage: "update or replace records, do not delete existing",
},
&cli.BoolFlag{
Name: "dry-run",
Aliases: []string{"n"},
Expand All @@ -174,6 +178,7 @@ func Main(args []string) int {
wait: c.Bool("wait"),
editauth: c.Bool("editauth"),
replace: c.Bool("replace"),
upsert: c.Bool("upsert"),
dryrun: c.Bool("dry-run"),
}
importBind(args)
Expand Down
14 changes: 14 additions & 0 deletions tests/upsert1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
@ 86400 IN A 10.0.0.1
@ 86400 IN MX 10 mail.example.com.
@ 86400 IN MX 20 mail2.example.com.
@ 900 IN SOA ns1.somenameserver.com. blah.example.com. 1 7200 900 1209600 86400
@ 172800 IN NS ns1.somenameserver.com.
@ 172800 IN NS ns2.somenameserver.com.
@ 86400 IN TXT "v=spf1 a mx a:cli53.example.com mx:mail.example.com ip4:10.0.0.0/24 ~all"
mail 86400 IN A 10.0.0.2
mail2 86400 IN A 10.0.0.3
test 86400 IN TXT "multivalued" " txt \"quoted\" record"
www 86400 IN A 10.0.0.1
www2 86400 IN A 10.0.0.1
unchanged 86400 IN A 10.1.0.1
alias 86400 AWS ALIAS A www $self false
5 changes: 5 additions & 0 deletions tests/upsert2.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
test 86400 IN TXT "multivalued" " txt \"quoted\" record"
www2 86400 IN A 10.0.0.5
www3 86400 IN A 10.0.0.5
unchanged 86400 IN A 10.1.0.1
alias 86400 AWS ALIAS A www $self false
15 changes: 15 additions & 0 deletions tests/upsert3.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
@ 86400 IN A 10.0.0.1
@ 86400 IN MX 10 mail.example.com.
@ 86400 IN MX 20 mail2.example.com.
@ 900 IN SOA ns1.somenameserver.com. blah.example.com. 1 7200 900 1209600 86400
@ 172800 IN NS ns1.somenameserver.com.
@ 172800 IN NS ns2.somenameserver.com.
@ 86400 IN TXT "v=spf1 a mx a:cli53.example.com mx:mail.example.com ip4:10.0.0.0/24 ~all"
mail 86400 IN A 10.0.0.2
mail2 86400 IN A 10.0.0.3
test 86400 IN TXT "multivalued" " txt \"quoted\" record"
www 86400 IN A 10.0.0.1
www2 86400 IN A 10.0.0.5
www3 86400 IN A 10.0.0.5
unchanged 86400 IN A 10.1.0.1
alias 86400 AWS ALIAS A www $self false

0 comments on commit ce3fc7b

Please sign in to comment.