diff --git a/provider/azure.go b/provider/azure.go index 67917dae4..8815e7bd8 100644 --- a/provider/azure.go +++ b/provider/azure.go @@ -153,7 +153,12 @@ func (p *AzureProvider) Records() (endpoints []*endpoint.Endpoint, _ error) { log.Errorf("Failed to extract target for '%s' with type '%s'.", name, recordType) return true } - ep := endpoint.NewEndpoint(name, target, recordType) + var ttl endpoint.TTL + if recordSet.TTL != nil { + ttl = endpoint.TTL(*recordSet.TTL) + } + + ep := endpoint.NewEndpointWithTTL(name, target, recordType, endpoint.TTL(ttl)) log.Debugf( "Found %s record for '%s' with target '%s'.", ep.RecordType, @@ -372,11 +377,15 @@ func (p *AzureProvider) recordSetNameForZone(zone string, endpoint *endpoint.End } func (p *AzureProvider) newRecordSet(endpoint *endpoint.Endpoint) (dns.RecordSet, error) { + var ttl int64 = azureRecordTTL + if endpoint.RecordTTL.IsConfigured() { + ttl = int64(endpoint.RecordTTL) + } switch dns.RecordType(endpoint.RecordType) { case dns.A: return dns.RecordSet{ RecordSetProperties: &dns.RecordSetProperties{ - TTL: to.Int64Ptr(azureRecordTTL), + TTL: to.Int64Ptr(ttl), ARecords: &[]dns.ARecord{ { Ipv4Address: to.StringPtr(endpoint.Target), @@ -387,7 +396,7 @@ func (p *AzureProvider) newRecordSet(endpoint *endpoint.Endpoint) (dns.RecordSet case dns.CNAME: return dns.RecordSet{ RecordSetProperties: &dns.RecordSetProperties{ - TTL: to.Int64Ptr(azureRecordTTL), + TTL: to.Int64Ptr(ttl), CnameRecord: &dns.CnameRecord{ Cname: to.StringPtr(endpoint.Target), }, @@ -396,7 +405,7 @@ func (p *AzureProvider) newRecordSet(endpoint *endpoint.Endpoint) (dns.RecordSet case dns.TXT: return dns.RecordSet{ RecordSetProperties: &dns.RecordSetProperties{ - TTL: to.Int64Ptr(azureRecordTTL), + TTL: to.Int64Ptr(ttl), TxtRecords: &[]dns.TxtRecord{ { Value: &[]string{ diff --git a/provider/azure_test.go b/provider/azure_test.go index 507dd4dd1..2bed99636 100644 --- a/provider/azure_test.go +++ b/provider/azure_test.go @@ -24,7 +24,9 @@ import ( "github.com/Azure/go-autorest/autorest/to" "github.com/kubernetes-incubator/external-dns/endpoint" + "github.com/kubernetes-incubator/external-dns/internal/testutils" "github.com/kubernetes-incubator/external-dns/plan" + "github.com/stretchr/testify/assert" ) type mockZonesClient struct { @@ -54,8 +56,9 @@ func (client *mockZonesClient) ListByResourceGroupNextResults(lastResults dns.Zo return dns.ZoneListResult{}, nil } -func aRecordSetPropertiesGetter(value string) *dns.RecordSetProperties { +func aRecordSetPropertiesGetter(value string, ttl int64) *dns.RecordSetProperties { return &dns.RecordSetProperties{ + TTL: to.Int64Ptr(ttl), ARecords: &[]dns.ARecord{ { Ipv4Address: to.StringPtr(value), @@ -64,16 +67,18 @@ func aRecordSetPropertiesGetter(value string) *dns.RecordSetProperties { } } -func cNameRecordSetPropertiesGetter(value string) *dns.RecordSetProperties { +func cNameRecordSetPropertiesGetter(value string, ttl int64) *dns.RecordSetProperties { return &dns.RecordSetProperties{ + TTL: to.Int64Ptr(ttl), CnameRecord: &dns.CnameRecord{ Cname: to.StringPtr(value), }, } } -func txtRecordSetPropertiesGetter(value string) *dns.RecordSetProperties { +func txtRecordSetPropertiesGetter(value string, ttl int64) *dns.RecordSetProperties { return &dns.RecordSetProperties{ + TTL: to.Int64Ptr(ttl), TxtRecords: &[]dns.TxtRecord{ { Value: &[]string{value}, @@ -82,12 +87,16 @@ func txtRecordSetPropertiesGetter(value string) *dns.RecordSetProperties { } } -func othersRecordSetPropertiesGetter(value string) *dns.RecordSetProperties { - return &dns.RecordSetProperties{} +func othersRecordSetPropertiesGetter(value string, ttl int64) *dns.RecordSetProperties { + return &dns.RecordSetProperties{ + TTL: to.Int64Ptr(ttl), + } } - func createMockRecordSet(name, recordType, value string) dns.RecordSet { - var getterFunc func(value string) *dns.RecordSetProperties + return createMockRecordSetWithTTL(name, recordType, value, 0) +} +func createMockRecordSetWithTTL(name, recordType, value string, ttl int64) dns.RecordSet { + var getterFunc func(value string, ttl int64) *dns.RecordSetProperties switch recordType { case endpoint.RecordTypeA: @@ -102,7 +111,7 @@ func createMockRecordSet(name, recordType, value string) dns.RecordSet { return dns.RecordSet{ Name: to.StringPtr(name), Type: to.StringPtr("Microsoft.Network/dnszones/" + recordType), - RecordSetProperties: getterFunc(value), + RecordSetProperties: getterFunc(value, ttl), } } @@ -128,12 +137,17 @@ func (client *mockRecordsClient) Delete(resourceGroupName string, zoneName strin } func (client *mockRecordsClient) CreateOrUpdate(resourceGroupName string, zoneName string, relativeRecordSetName string, recordType dns.RecordType, parameters dns.RecordSet, ifMatch string, ifNoneMatch string) (dns.RecordSet, error) { + var ttl endpoint.TTL + if parameters.TTL != nil { + ttl = endpoint.TTL(*parameters.TTL) + } client.updatedEndpoints = append( client.updatedEndpoints, - endpoint.NewEndpoint( + endpoint.NewEndpointWithTTL( formatAzureDNSName(relativeRecordSetName, zoneName), extractAzureTarget(¶meters), string(recordType), + ttl, ), ) return parameters, nil @@ -150,6 +164,10 @@ func newAzureProvider(domainFilter DomainFilter, zoneIDFilter ZoneIDFilter, dryR } } +func validateAzureEndpoints(t *testing.T, endpoints []*endpoint.Endpoint, expected []*endpoint.Endpoint) { + assert.True(t, testutils.SameEndpoints(endpoints, expected), "expected and actual endpoints don't match. %s:%s", endpoints, expected) +} + func TestAzureRecord(t *testing.T) { zonesClient := mockZonesClient{ mockZoneListResult: &dns.ZoneListResult{ @@ -165,13 +183,14 @@ func TestAzureRecord(t *testing.T) { createMockRecordSet("@", "SOA", "Email: azuredns-hostmaster.microsoft.com"), createMockRecordSet("@", endpoint.RecordTypeA, "123.123.123.122"), createMockRecordSet("@", endpoint.RecordTypeTXT, "heritage=external-dns,external-dns/owner=default"), - createMockRecordSet("nginx", endpoint.RecordTypeA, "123.123.123.123"), - createMockRecordSet("nginx", endpoint.RecordTypeTXT, "heritage=external-dns,external-dns/owner=default"), - createMockRecordSet("hack", endpoint.RecordTypeCNAME, "hack.azurewebsites.net"), + createMockRecordSetWithTTL("nginx", endpoint.RecordTypeA, "123.123.123.123", 3600), + createMockRecordSetWithTTL("nginx", endpoint.RecordTypeTXT, "heritage=external-dns,external-dns/owner=default", recordTTL), + createMockRecordSetWithTTL("hack", endpoint.RecordTypeCNAME, "hack.azurewebsites.net", 10), }, } provider := newAzureProvider(NewDomainFilter([]string{"example.com"}), NewZoneIDFilter([]string{""}), true, "k8s", &zonesClient, &recordsClient) + actual, err := provider.Records() if err != nil { @@ -180,12 +199,13 @@ func TestAzureRecord(t *testing.T) { expected := []*endpoint.Endpoint{ endpoint.NewEndpoint("example.com", "123.123.123.122", endpoint.RecordTypeA), endpoint.NewEndpoint("example.com", "heritage=external-dns,external-dns/owner=default", endpoint.RecordTypeTXT), - endpoint.NewEndpoint("nginx.example.com", "123.123.123.123", endpoint.RecordTypeA), - endpoint.NewEndpoint("nginx.example.com", "heritage=external-dns,external-dns/owner=default", endpoint.RecordTypeTXT), - endpoint.NewEndpoint("hack.example.com", "hack.azurewebsites.net", endpoint.RecordTypeCNAME), + endpoint.NewEndpointWithTTL("nginx.example.com", "123.123.123.123", endpoint.RecordTypeA, 3600), + endpoint.NewEndpointWithTTL("nginx.example.com", "heritage=external-dns,external-dns/owner=default", endpoint.RecordTypeTXT, recordTTL), + endpoint.NewEndpointWithTTL("hack.example.com", "hack.azurewebsites.net", endpoint.RecordTypeCNAME, 10), } - validateEndpoints(t, actual, expected) + validateAzureEndpoints(t, actual, expected) + } func TestAzureApplyChanges(t *testing.T) { @@ -193,24 +213,24 @@ func TestAzureApplyChanges(t *testing.T) { testAzureApplyChangesInternal(t, false, &recordsClient) - validateEndpoints(t, recordsClient.deletedEndpoints, []*endpoint.Endpoint{ + validateAzureEndpoints(t, recordsClient.deletedEndpoints, []*endpoint.Endpoint{ endpoint.NewEndpoint("old.example.com", "", endpoint.RecordTypeA), endpoint.NewEndpoint("oldcname.example.com", "", endpoint.RecordTypeCNAME), endpoint.NewEndpoint("deleted.example.com", "", endpoint.RecordTypeA), endpoint.NewEndpoint("deletedcname.example.com", "", endpoint.RecordTypeCNAME), }) - validateEndpoints(t, recordsClient.updatedEndpoints, []*endpoint.Endpoint{ - endpoint.NewEndpoint("example.com", "1.2.3.4", endpoint.RecordTypeA), - endpoint.NewEndpoint("example.com", "tag", endpoint.RecordTypeTXT), - endpoint.NewEndpoint("foo.example.com", "1.2.3.4", endpoint.RecordTypeA), - endpoint.NewEndpoint("foo.example.com", "tag", endpoint.RecordTypeTXT), - endpoint.NewEndpoint("bar.example.com", "other.com", endpoint.RecordTypeCNAME), - endpoint.NewEndpoint("bar.example.com", "tag", endpoint.RecordTypeTXT), - endpoint.NewEndpoint("other.com", "5.6.7.8", endpoint.RecordTypeA), - endpoint.NewEndpoint("other.com", "tag", endpoint.RecordTypeTXT), - endpoint.NewEndpoint("new.example.com", "111.222.111.222", endpoint.RecordTypeA), - endpoint.NewEndpoint("newcname.example.com", "other.com", endpoint.RecordTypeCNAME), + validateAzureEndpoints(t, recordsClient.updatedEndpoints, []*endpoint.Endpoint{ + endpoint.NewEndpointWithTTL("example.com", "1.2.3.4", endpoint.RecordTypeA, endpoint.TTL(recordTTL)), + endpoint.NewEndpointWithTTL("example.com", "tag", endpoint.RecordTypeTXT, endpoint.TTL(recordTTL)), + endpoint.NewEndpointWithTTL("foo.example.com", "1.2.3.4", endpoint.RecordTypeA, endpoint.TTL(recordTTL)), + endpoint.NewEndpointWithTTL("foo.example.com", "tag", endpoint.RecordTypeTXT, endpoint.TTL(recordTTL)), + endpoint.NewEndpointWithTTL("bar.example.com", "other.com", endpoint.RecordTypeCNAME, endpoint.TTL(recordTTL)), + endpoint.NewEndpointWithTTL("bar.example.com", "tag", endpoint.RecordTypeTXT, endpoint.TTL(recordTTL)), + endpoint.NewEndpointWithTTL("other.com", "5.6.7.8", endpoint.RecordTypeA, endpoint.TTL(recordTTL)), + endpoint.NewEndpointWithTTL("other.com", "tag", endpoint.RecordTypeTXT, endpoint.TTL(recordTTL)), + endpoint.NewEndpointWithTTL("new.example.com", "111.222.111.222", endpoint.RecordTypeA, 3600), + endpoint.NewEndpointWithTTL("newcname.example.com", "other.com", endpoint.RecordTypeCNAME, 10), }) } @@ -219,9 +239,9 @@ func TestAzureApplyChangesDryRun(t *testing.T) { testAzureApplyChangesInternal(t, true, &recordsClient) - validateEndpoints(t, recordsClient.deletedEndpoints, []*endpoint.Endpoint{}) + validateAzureEndpoints(t, recordsClient.deletedEndpoints, []*endpoint.Endpoint{}) - validateEndpoints(t, recordsClient.updatedEndpoints, []*endpoint.Endpoint{}) + validateAzureEndpoints(t, recordsClient.updatedEndpoints, []*endpoint.Endpoint{}) } func testAzureApplyChangesInternal(t *testing.T, dryRun bool, client RecordsClient) { @@ -260,8 +280,8 @@ func testAzureApplyChangesInternal(t *testing.T, dryRun bool, client RecordsClie endpoint.NewEndpoint("old.nope.com", "121.212.121.212", endpoint.RecordTypeA), } updatedRecords := []*endpoint.Endpoint{ - endpoint.NewEndpoint("new.example.com", "111.222.111.222", endpoint.RecordTypeA), - endpoint.NewEndpoint("newcname.example.com", "other.com", endpoint.RecordTypeCNAME), + endpoint.NewEndpointWithTTL("new.example.com", "111.222.111.222", endpoint.RecordTypeA, 3600), + endpoint.NewEndpointWithTTL("newcname.example.com", "other.com", endpoint.RecordTypeCNAME, 10), endpoint.NewEndpoint("new.nope.com", "222.111.222.111", endpoint.RecordTypeA), }