Skip to content

Commit

Permalink
Delete aws route53 record sets that contain filter in zones that do not.
Browse files Browse the repository at this point in the history
WRT #80
  • Loading branch information
genevieve committed Jan 6, 2020
1 parent 34f9249 commit 319f0a6
Show file tree
Hide file tree
Showing 7 changed files with 210 additions and 39 deletions.
49 changes: 38 additions & 11 deletions aws/route53/fakes/record_sets.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
)

type RecordSets struct {
DeleteCall struct {
DeleteAllCall struct {
sync.Mutex
CallCount int
Receives struct {
Expand All @@ -20,6 +20,20 @@ type RecordSets struct {
}
Stub func(*string, string, []*awsroute53.ResourceRecordSet) error
}
DeleteWithFilterCall struct {
sync.Mutex
CallCount int
Receives struct {
HostedZoneId *string
HostedZoneName string
RecordSets []*awsroute53.ResourceRecordSet
Filter string
}
Returns struct {
Error error
}
Stub func(*string, string, []*awsroute53.ResourceRecordSet, string) error
}
GetCall struct {
sync.Mutex
CallCount int
Expand All @@ -34,17 +48,30 @@ type RecordSets struct {
}
}

func (f *RecordSets) Delete(param1 *string, param2 string, param3 []*awsroute53.ResourceRecordSet) error {
f.DeleteCall.Lock()
defer f.DeleteCall.Unlock()
f.DeleteCall.CallCount++
f.DeleteCall.Receives.HostedZoneId = param1
f.DeleteCall.Receives.HostedZoneName = param2
f.DeleteCall.Receives.RecordSets = param3
if f.DeleteCall.Stub != nil {
return f.DeleteCall.Stub(param1, param2, param3)
func (f *RecordSets) DeleteAll(param1 *string, param2 string, param3 []*awsroute53.ResourceRecordSet) error {
f.DeleteAllCall.Lock()
defer f.DeleteAllCall.Unlock()
f.DeleteAllCall.CallCount++
f.DeleteAllCall.Receives.HostedZoneId = param1
f.DeleteAllCall.Receives.HostedZoneName = param2
f.DeleteAllCall.Receives.RecordSets = param3
if f.DeleteAllCall.Stub != nil {
return f.DeleteAllCall.Stub(param1, param2, param3)
}
return f.DeleteAllCall.Returns.Error
}
func (f *RecordSets) DeleteWithFilter(param1 *string, param2 string, param3 []*awsroute53.ResourceRecordSet, param4 string) error {
f.DeleteWithFilterCall.Lock()
defer f.DeleteWithFilterCall.Unlock()
f.DeleteWithFilterCall.CallCount++
f.DeleteWithFilterCall.Receives.HostedZoneId = param1
f.DeleteWithFilterCall.Receives.HostedZoneName = param2
f.DeleteWithFilterCall.Receives.RecordSets = param3
f.DeleteWithFilterCall.Receives.Filter = param4
if f.DeleteWithFilterCall.Stub != nil {
return f.DeleteWithFilterCall.Stub(param1, param2, param3, param4)
}
return f.DeleteCall.Returns.Error
return f.DeleteWithFilterCall.Returns.Error
}
func (f *RecordSets) Get(param1 *string) ([]*awsroute53.ResourceRecordSet, error) {
f.GetCall.Lock()
Expand Down
28 changes: 19 additions & 9 deletions aws/route53/hosted_zone.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package route53

import (
"fmt"
"strings"

awsroute53 "github.com/aws/aws-sdk-go/service/route53"
)
Expand All @@ -11,14 +12,16 @@ type HostedZone struct {
id *string
identifier string
recordSets recordSets
filter string
}

func NewHostedZone(client hostedZonesClient, id, name *string, recordSets recordSets) HostedZone {
func NewHostedZone(client hostedZonesClient, id, name *string, recordSets recordSets, filter string) HostedZone {
return HostedZone{
client: client,
id: id,
identifier: *name,
recordSets: recordSets,
filter: filter,
}
}

Expand All @@ -28,14 +31,21 @@ func (h HostedZone) Delete() error {
return fmt.Errorf("Get Record Sets: %s", err)
}

err = h.recordSets.Delete(h.id, h.identifier, r)
if err != nil {
return fmt.Errorf("Delete Record Sets: %s", err)
}

_, err = h.client.DeleteHostedZone(&awsroute53.DeleteHostedZoneInput{Id: h.id})
if err != nil {
return fmt.Errorf("Delete: %s", err)
if strings.Contains(h.Name(), h.filter) {
err = h.recordSets.DeleteAll(h.id, h.identifier, r)
if err != nil {
return fmt.Errorf("Delete All Record Sets: %s", err)
}

_, err = h.client.DeleteHostedZone(&awsroute53.DeleteHostedZoneInput{Id: h.id})
if err != nil {
return fmt.Errorf("Delete: %s", err)
}
} else {
err = h.recordSets.DeleteWithFilter(h.id, h.identifier, r, h.filter)
if err != nil {
return fmt.Errorf("Delete Record Sets With Filter: %s", err)
}
}

return nil
Expand Down
62 changes: 51 additions & 11 deletions aws/route53/hosted_zone_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ var _ = Describe("HostedZone", func() {
recordSets *fakes.RecordSets
id *string
name *string
filter string

hostedZone route53.HostedZone
)
Expand All @@ -26,55 +27,94 @@ var _ = Describe("HostedZone", func() {
recordSets = &fakes.RecordSets{}
id = aws.String("the-zone-id")
name = aws.String("the-zone-name")
filter = "zone"

hostedZone = route53.NewHostedZone(client, id, name, recordSets)
hostedZone = route53.NewHostedZone(client, id, name, recordSets, filter)
})

Describe("Delete", func() {
It("deletes the record sets and deletes the hosted zone", func() {
It("deletes all record sets and deletes the hosted zone", func() {
err := hostedZone.Delete()
Expect(err).NotTo(HaveOccurred())

Expect(recordSets.GetCall.CallCount).To(Equal(1))
Expect(recordSets.GetCall.Receives.HostedZoneId).To(Equal(id))

Expect(recordSets.DeleteCall.CallCount).To(Equal(1))
Expect(recordSets.DeleteCall.Receives.HostedZoneId).To(Equal(id))
Expect(recordSets.DeleteAllCall.CallCount).To(Equal(1))
Expect(recordSets.DeleteAllCall.Receives.HostedZoneId).To(Equal(id))

Expect(recordSets.DeleteWithFilterCall.CallCount).To(Equal(0))

Expect(client.DeleteHostedZoneCall.CallCount).To(Equal(1))
Expect(client.DeleteHostedZoneCall.Receives.DeleteHostedZoneInput.Id).To(Equal(id))
})

Context("when the zone does not contain the filter", func() {
BeforeEach(func() {
filter = "banana"
hostedZone = route53.NewHostedZone(client, id, name, recordSets, filter)
})

It("deletes only record sets in the zone that contain the filter", func() {
err := hostedZone.Delete()
Expect(err).NotTo(HaveOccurred())

Expect(recordSets.GetCall.CallCount).To(Equal(1))
Expect(recordSets.GetCall.Receives.HostedZoneId).To(Equal(id))

Expect(recordSets.DeleteAllCall.CallCount).To(Equal(0))

Expect(recordSets.DeleteWithFilterCall.CallCount).To(Equal(1))
Expect(recordSets.DeleteWithFilterCall.Receives.HostedZoneId).To(Equal(id))
Expect(recordSets.DeleteWithFilterCall.Receives.Filter).To(Equal("banana"))

Expect(client.DeleteHostedZoneCall.CallCount).To(Equal(0))
})
})

Context("when record sets fails to get", func() {
BeforeEach(func() {
recordSets.GetCall.Returns.Error = errors.New("banana")
recordSets.GetCall.Returns.Error = errors.New("ruhroh")
})

It("returns the error", func() {
err := hostedZone.Delete()
Expect(err).To(MatchError("Get Record Sets: ruhroh"))
})
})

Context("when deleting all record sets fails", func() {
BeforeEach(func() {
recordSets.DeleteAllCall.Returns.Error = errors.New("ruhroh")
})

It("returns the error", func() {
err := hostedZone.Delete()
Expect(err).To(MatchError("Get Record Sets: banana"))
Expect(err).To(MatchError("Delete All Record Sets: ruhroh"))
})
})

Context("when record sets fails to delete", func() {
Context("when deleting record sets with filter fails", func() {
BeforeEach(func() {
recordSets.DeleteCall.Returns.Error = errors.New("banana")
filter = "banana"
hostedZone = route53.NewHostedZone(client, id, name, recordSets, filter)
recordSets.DeleteWithFilterCall.Returns.Error = errors.New("ruhroh")
})

It("returns the error", func() {
err := hostedZone.Delete()
Expect(err).To(MatchError("Delete Record Sets: banana"))
Expect(err).To(MatchError("Delete Record Sets With Filter: ruhroh"))
})
})

Context("when the client fails to delete the zone", func() {
BeforeEach(func() {
client.DeleteHostedZoneCall.Returns.Error = errors.New("banana")
client.DeleteHostedZoneCall.Returns.Error = errors.New("ruhroh")
})

It("returns the error", func() {
err := hostedZone.Delete()
Expect(err).To(MatchError("Delete: banana"))
Expect(err).To(MatchError("Delete: ruhroh"))
})
})
})
Expand Down
23 changes: 20 additions & 3 deletions aws/route53/hosted_zones.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ type HostedZones struct {
//go:generate faux --interface recordSets --output fakes/record_sets.go
type recordSets interface {
Get(hostedZoneId *string) ([]*awsroute53.ResourceRecordSet, error)
Delete(hostedZoneId *string, hostedZoneName string, recordSets []*awsroute53.ResourceRecordSet) error
DeleteAll(hostedZoneId *string, hostedZoneName string, recordSets []*awsroute53.ResourceRecordSet) error
DeleteWithFilter(hostedZoneId *string, hostedZoneName string, recordSets []*awsroute53.ResourceRecordSet, filter string) error
}

func NewHostedZones(client hostedZonesClient, logger logger, recordSets recordSets) HostedZones {
Expand All @@ -42,9 +43,9 @@ func (z HostedZones) List(filter string) ([]common.Deletable, error) {

var resources []common.Deletable
for _, zone := range zones.HostedZones {
r := NewHostedZone(z.client, zone.Id, zone.Name, z.recordSets)
r := NewHostedZone(z.client, zone.Id, zone.Name, z.recordSets, filter)

if !strings.Contains(r.Name(), filter) {
if !strings.Contains(r.Name(), filter) && !z.recordSetsContainFilter(zone.Id, filter) {
continue
}

Expand All @@ -62,3 +63,19 @@ func (z HostedZones) List(filter string) ([]common.Deletable, error) {
func (z HostedZones) Type() string {
return "route53-hosted-zone"
}

// Check if any record sets in the hosted zone reference the filter.
func (z HostedZones) recordSetsContainFilter(hostedZoneId *string, filter string) bool {
records, err := z.recordSets.Get(hostedZoneId)
if err != nil {
return false
}

for _, record := range records {
if strings.Contains(*record.Name, filter) {
return true
}
}

return false
}
16 changes: 16 additions & 0 deletions aws/route53/hosted_zones_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ var _ = Describe("HostedZones", func() {
BeforeEach(func() {
client = &fakes.HostedZonesClient{}
logger = &fakes.Logger{}
recordSets = &fakes.RecordSets{}

hostedZones = route53.NewHostedZones(client, logger, recordSets)
})
Expand Down Expand Up @@ -75,6 +76,21 @@ var _ = Describe("HostedZones", func() {
})
})

Context("when the record sets contain the filter", func() {
BeforeEach(func() {
recordSets.GetCall.Returns.ResourceRecordSetSlice = []*awsroute53.ResourceRecordSet{{
Name: aws.String("kiwi"),
}}
})
It("does not return it in the list", func() {
items, err := hostedZones.List("kiwi")
Expect(err).NotTo(HaveOccurred())

Expect(logger.PromptWithDetailsCall.CallCount).To(Equal(1))
Expect(items).To(HaveLen(1))
})
})

Context("when the user responds no to the prompt", func() {
BeforeEach(func() {
logger.PromptWithDetailsCall.Returns.Proceed = false
Expand Down
26 changes: 25 additions & 1 deletion aws/route53/record_sets.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func (r RecordSets) Get(hostedZoneId *string) ([]*awsroute53.ResourceRecordSet,
return records, nil
}

func (r RecordSets) Delete(hostedZoneId *string, hostedZoneName string, records []*awsroute53.ResourceRecordSet) error {
func (r RecordSets) DeleteAll(hostedZoneId *string, hostedZoneName string, records []*awsroute53.ResourceRecordSet) error {
var changes []*awsroute53.Change
for _, record := range records {
if strings.TrimSuffix(*record.Name, ".") == strings.TrimSuffix(hostedZoneName, ".") && (*record.Type == "NS" || *record.Type == "SOA") {
Expand All @@ -72,3 +72,27 @@ func (r RecordSets) Delete(hostedZoneId *string, hostedZoneName string, records

return nil
}

func (r RecordSets) DeleteWithFilter(hostedZoneId *string, hostedZoneName string, records []*awsroute53.ResourceRecordSet, filter string) error {
var changes []*awsroute53.Change
for _, record := range records {
if strings.Contains(*record.Name, filter) && *record.Type == "A" {
changes = append(changes, &awsroute53.Change{
Action: aws.String("DELETE"),
ResourceRecordSet: record,
})
}
}

if len(changes) > 0 {
_, err := r.client.ChangeResourceRecordSets(&awsroute53.ChangeResourceRecordSetsInput{
HostedZoneId: hostedZoneId,
ChangeBatch: &awsroute53.ChangeBatch{Changes: changes},
})
if err != nil {
return fmt.Errorf("Delete Resource Record Sets in Hosted Zone %s: %s", hostedZoneName, err)
}
}

return nil
}

0 comments on commit 319f0a6

Please sign in to comment.