Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix bug in the civo provider to avoid infinite record creation #3687

Merged
merged 5 commits into from
Jun 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions docs/tutorials/civo.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

This tutorial describes how to setup ExternalDNS for usage within a Kubernetes cluster using Civo DNS Manager.

Make sure to use **>0.12.2** version of ExternalDNS for this tutorial.
Make sure to use **>0.13.5** version of ExternalDNS for this tutorial.

## Managing DNS with Civo

Expand All @@ -12,8 +12,7 @@ If you want to learn about how to use Civo DNS Manager read the following tutori

## Get Civo Token

Copy the token in the settings fo your account

Copy the token in the settings for your account
The environment variable `CIVO_TOKEN` will be needed to run ExternalDNS with Civo.

## Deploy ExternalDNS
Expand Down
10 changes: 10 additions & 0 deletions provider/civo/civo.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ type CivoChanges struct {
Updates []*CivoChangeUpdate
}

// Empty returns true if there are no changes
func (c *CivoChanges) Empty() bool {
return len(c.Creates) == 0 && len(c.Updates) == 0 && len(c.Deletes) == 0
}

// CivoChangeCreate Civo Domain Record Creates
type CivoChangeCreate struct {
Domain civogo.DNSDomain
Expand Down Expand Up @@ -169,6 +174,11 @@ func (p *CivoProvider) fetchZones(ctx context.Context) ([]civogo.DNSDomain, erro

// submitChanges takes a zone and a collection of Changes and sends them as a single transaction.
func (p *CivoProvider) submitChanges(ctx context.Context, changes CivoChanges) error {
if changes.Empty() {
log.Info("All records are already up to date")
return nil
}

for _, change := range changes.Creates {
logFields := log.Fields{
"Type": change.Options.Type,
Expand Down
148 changes: 148 additions & 0 deletions provider/civo/civo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -809,6 +809,154 @@ func TestCivo_submitChangesDelete(t *testing.T) {
assert.NoError(t, err)
}

func TestCivoChangesEmpty(t *testing.T) {
// Test empty CivoChanges
c := &CivoChanges{}
assert.True(t, c.Empty())

// Test CivoChanges with Creates
c = &CivoChanges{
Creates: []*CivoChangeCreate{
{
Domain: civogo.DNSDomain{
ID: "12345",
AccountID: "1",
Name: "example.com",
},
Options: &civogo.DNSRecordConfig{
Type: civogo.DNSRecordTypeA,
Name: "www",
Value: "192.1.1.1",
Priority: 0,
TTL: 600,
},
},
},
}
assert.False(t, c.Empty())

// Test CivoChanges with Updates
c = &CivoChanges{
Updates: []*CivoChangeUpdate{
{
Domain: civogo.DNSDomain{
ID: "12345",
AccountID: "1",
Name: "example.com",
},
DomainRecord: civogo.DNSRecord{
ID: "76cc107f-fbef-4e2b-b97f-f5d34f4075d3",
AccountID: "1",
DNSDomainID: "12345",
Name: "mail",
Value: "192.168.1.2",
Type: "MX",
Priority: 10,
TTL: 600,
},
Options: civogo.DNSRecordConfig{
Type: "MX",
Name: "mail",
Value: "192.168.1.3",
Priority: 10,
TTL: 600,
},
},
},
}
assert.False(t, c.Empty())

// Test CivoChanges with Deletes
c = &CivoChanges{
Deletes: []*CivoChangeDelete{
{
Domain: civogo.DNSDomain{
ID: "12345",
AccountID: "1",
Name: "example.com",
},
DomainRecord: civogo.DNSRecord{
ID: "76cc107f-fbef-4e2b-b97f-f5d34f4075d3",
AccountID: "1",
DNSDomainID: "12345",
Name: "mail",
Value: "192.168.1.3",
Type: "MX",
Priority: 10,
TTL: 600,
},
},
},
}
assert.False(t, c.Empty())

// Test CivoChanges with Creates, Updates, and Deletes
c = &CivoChanges{
Creates: []*CivoChangeCreate{
{
Domain: civogo.DNSDomain{
ID: "12345",
AccountID: "1",
Name: "example.com",
},
Options: &civogo.DNSRecordConfig{
Type: civogo.DNSRecordTypeA,
Name: "www",
Value: "192.1.1.1",
Priority: 0,
TTL: 600,
},
},
},
Updates: []*CivoChangeUpdate{
{
Domain: civogo.DNSDomain{
ID: "12345",
AccountID: "1",
Name: "example.com",
},
DomainRecord: civogo.DNSRecord{
ID: "76cc107f-fbef-4e2b-b97f-f5d34f4075d3",
AccountID: "1",
DNSDomainID: "12345",
Name: "mail",
Value: "192.168.1.2",
Type: "MX",
Priority: 10,
TTL: 600,
},
Options: civogo.DNSRecordConfig{
Type: "MX",
Name: "mail",
Value: "192.168.1.3",
Priority: 10,
TTL: 600,
},
},
},
Deletes: []*CivoChangeDelete{
{
Domain: civogo.DNSDomain{
ID: "12345",
AccountID: "1",
Name: "example.com",
},
DomainRecord: civogo.DNSRecord{
ID: "76cc107f-fbef-4e2b-b97f-f5d34f4075d3",
AccountID: "1",
DNSDomainID: "12345",
Name: "mail",
Value: "192.168.1.3",
Type: "MX",
Priority: 10,
TTL: 600,
},
},
},
}
assert.False(t, c.Empty())
}

// This function is an adapted copy of the testify package's ElementsMatch function with the
// call to ObjectsAreEqual replaced with cmp.Equal which better handles struct's with pointers to
// other structs. It also ignores ordering when comparing unlike cmp.Equal.
Expand Down
Loading