Commit 90407b39 authored by Michael FIG's avatar Michael FIG
Browse files

Azure: Support multiple A targets.

parent 97014170
master Raffo-patch-1 add-infoblox-maintainers changelog-for-v0.7.3 correctly-update-aws-records-when-type-changes dansimone/support-prefer-ingress-annotations dependabot/go_modules/github.com/Azure/azure-sdk-for-go-61.4.0incompatible dependabot/go_modules/github.com/aliyun/alibaba-cloud-sdk-go-1.61.1473 dependabot/go_modules/github.com/exoscale/egoscale-1.19.0 dependabot/go_modules/github.com/projectcontour/contour-1.20.0 dependabot/go_modules/k8s.io/apimachinery-0.23.3 fix-1820 gh-pages go-1.12.7 incubator-kep infoblox-multiple-A-records-fix labeler linki-patch-3 linki-patch-4 linki-patch-6 njuettner-patch-1 njuettner/go_modules/github.com/akamai/AkamaiOPEN-edgegrid-golang-0.9.11 njuettner/go_modules/github.com/alecthomas/kingpin-2.2.6incompatible njuettner/go_modules/github.com/digitalocean/godo-1.34.0 njuettner/go_modules/github.com/pkg/errors-0.9.1 njuettner/go_modules/github.com/prometheus/client_golang-1.5.1 normalize raffo-fix-2348 raffo/add-dependabot raffo/add-kustomize-base raffo/add-trivy-scanning raffo/arm raffo/arm32v7 raffo/bump-ci-timeout raffo/bump-cloudbuild-timeout raffo/bump-deps-sec raffo/bump-kustomize raffo/bump-kustomize-1 raffo/bump-kustomize-version-0.7.5 raffo/bump-modules raffo/codeQL raffo/drop-the-changelog raffo/e2e-aws raffo/edit-infoblox-maintainers raffo/fix-1820 raffo/fix-1936 raffo/fix-build raffo/fix-dependabot raffo/fix-ns-deletion raffo/fix-scaleway-security raffo/fix-that-typo raffo/fix-trivy raffo/fix-trivy-again raffo/fix-vulnerabilities raffo/goarm raffo/gpr-docker-image raffo/knolog raffo/kustomize-endpoints raffo/multiarch raffo/multiarch-docs raffo/new-ingress-resource raffo/new-maintainers raffo/provider-structure-refactor raffo/release-conventions raffo/release-note-patch raffo/release-script raffo/release-script-update raffo/release-v0.7.2 raffo/remove-azure-test raffo/remove-broken-link raffo/remove-incubator-readme raffo/remove-masters raffo/revert-tzdata raffo/split-sources raffo/update-kustomize-080 raffo/update-v0.10-role raffo/use-actions raffo/v0.7.6 revert-963-ns1-provider-ammended sagor999/infoblox-multiple-A-records test-things travis-test v0.5.15 v0.5.17 validate-txt-prefix v1.0.0-mf v0.10.2 v0.10.1 v0.10.0 v0.9.0 v0.8.0 v0.7.6 v0.7.5 v0.7.4 v0.7.3 v0.7.2 v0.7.1 v0.7.0 v0.6.0 v0.5.18 v0.5.17 v0.5.16 v0.5.15 v0.5.14 v0.5.13 external-dns-helm-chart-1.7.1 external-dns-helm-chart-1.7.0 external-dns-helm-chart-1.6.0 external-dns-helm-chart-1.5.0 external-dns-helm-chart-1.4.1 external-dns-helm-chart-1.4.0 external-dns-helm-chart-1.3.2 external-dns-helm-chart-1.3.1 external-dns-helm-chart-1.3.0 external-dns-helm-chart-1.2.0
No related merge requests found
Showing with 87 additions and 36 deletions
+87 -36
......@@ -25,7 +25,7 @@ RUN make build
FROM registry.opensource.zalan.do/stups/alpine:latest
LABEL maintainer="Team Teapot @ Zalando SE <team-teapot@zalando.de>"
COPY --from=builder /kubernetes-incubator/external-dns/build/external-dns /bin/external-dns
COPY --from=builder /github.com/kubernetes-incubator/external-dns/build/external-dns /bin/external-dns
USER nobody
......
......@@ -179,9 +179,9 @@ func (p *AzureProvider) Records() (endpoints []*endpoint.Endpoint, _ error) {
return true
}
name := formatAzureDNSName(*recordSet.Name, *zone.Name)
target := extractAzureTarget(&recordSet)
if target == "" {
log.Errorf("Failed to extract target for '%s' with type '%s'.", name, recordType)
targets := extractAzureTargets(&recordSet)
if len(targets) == 0 {
log.Errorf("Failed to extract targets for '%s' with type '%s'.", name, recordType)
return true
}
var ttl endpoint.TTL
......@@ -189,7 +189,7 @@ func (p *AzureProvider) Records() (endpoints []*endpoint.Endpoint, _ error) {
ttl = endpoint.TTL(*recordSet.TTL)
}
ep := endpoint.NewEndpointWithTTL(name, recordType, endpoint.TTL(ttl), target)
ep := endpoint.NewEndpointWithTTL(name, recordType, endpoint.TTL(ttl), targets...)
log.Debugf(
"Found %s record for '%s' with target '%s'.",
ep.RecordType,
......@@ -414,14 +414,16 @@ func (p *AzureProvider) newRecordSet(endpoint *endpoint.Endpoint) (dns.RecordSet
}
switch dns.RecordType(endpoint.RecordType) {
case dns.A:
aRecords := make([]dns.ARecord, len(endpoint.Targets))
for i, target := range endpoint.Targets {
aRecords[i] = dns.ARecord{
Ipv4Address: to.StringPtr(target),
}
}
return dns.RecordSet{
RecordSetProperties: &dns.RecordSetProperties{
TTL: to.Int64Ptr(ttl),
ARecords: &[]dns.ARecord{
{
Ipv4Address: to.StringPtr(endpoint.Targets[0]),
},
},
TTL: to.Int64Ptr(ttl),
ARecords: &aRecords,
},
}, nil
case dns.CNAME:
......@@ -459,22 +461,26 @@ func formatAzureDNSName(recordName, zoneName string) string {
}
// Helper function (shared with text code)
func extractAzureTarget(recordSet *dns.RecordSet) string {
func extractAzureTargets(recordSet *dns.RecordSet) []string {
properties := recordSet.RecordSetProperties
if properties == nil {
return ""
return []string{}
}
// Check for A records
aRecords := properties.ARecords
if aRecords != nil && len(*aRecords) > 0 && (*aRecords)[0].Ipv4Address != nil {
return *(*aRecords)[0].Ipv4Address
targets := make([]string, len(*aRecords))
for i, aRecord := range *aRecords {
targets[i] = *aRecord.Ipv4Address
}
return targets
}
// Check for CNAME records
cnameRecord := properties.CnameRecord
if cnameRecord != nil && cnameRecord.Cname != nil {
return *cnameRecord.Cname
return []string{*cnameRecord.Cname}
}
// Check for TXT records
......@@ -482,8 +488,8 @@ func extractAzureTarget(recordSet *dns.RecordSet) string {
if txtRecords != nil && len(*txtRecords) > 0 && (*txtRecords)[0].Value != nil {
values := (*txtRecords)[0].Value
if values != nil && len(*values) > 0 {
return (*values)[0]
return []string{(*values)[0]}
}
}
return ""
return []string{}
}
......@@ -57,47 +57,52 @@ func (client *mockZonesClient) ListByResourceGroupNextResults(lastResults dns.Zo
return dns.ZoneListResult{}, nil
}
func aRecordSetPropertiesGetter(value string, ttl int64) *dns.RecordSetProperties {
func aRecordSetPropertiesGetter(values []string, ttl int64) *dns.RecordSetProperties {
aRecords := make([]dns.ARecord, len(values))
for i, value := range values {
aRecords[i] = dns.ARecord{
Ipv4Address: to.StringPtr(value),
}
}
return &dns.RecordSetProperties{
TTL: to.Int64Ptr(ttl),
ARecords: &[]dns.ARecord{
{
Ipv4Address: to.StringPtr(value),
},
},
TTL: to.Int64Ptr(ttl),
ARecords: &aRecords,
}
}
func cNameRecordSetPropertiesGetter(value string, ttl int64) *dns.RecordSetProperties {
func cNameRecordSetPropertiesGetter(values []string, ttl int64) *dns.RecordSetProperties {
return &dns.RecordSetProperties{
TTL: to.Int64Ptr(ttl),
CnameRecord: &dns.CnameRecord{
Cname: to.StringPtr(value),
Cname: to.StringPtr(values[0]),
},
}
}
func txtRecordSetPropertiesGetter(value string, ttl int64) *dns.RecordSetProperties {
func txtRecordSetPropertiesGetter(values []string, ttl int64) *dns.RecordSetProperties {
return &dns.RecordSetProperties{
TTL: to.Int64Ptr(ttl),
TxtRecords: &[]dns.TxtRecord{
{
Value: &[]string{value},
Value: &[]string{values[0]},
},
},
}
}
func othersRecordSetPropertiesGetter(value string, ttl int64) *dns.RecordSetProperties {
func othersRecordSetPropertiesGetter(values []string, ttl int64) *dns.RecordSetProperties {
return &dns.RecordSetProperties{
TTL: to.Int64Ptr(ttl),
}
}
func createMockRecordSet(name, recordType, value string) dns.RecordSet {
return createMockRecordSetWithTTL(name, recordType, value, 0)
func createMockRecordSet(name, recordType string, values ...string) dns.RecordSet {
return createMockRecordSetMultiWithTTL(name, recordType, 0, values...)
}
func createMockRecordSetWithTTL(name, recordType, value string, ttl int64) dns.RecordSet {
var getterFunc func(value string, ttl int64) *dns.RecordSetProperties
return createMockRecordSetMultiWithTTL(name, recordType, ttl, value)
}
func createMockRecordSetMultiWithTTL(name, recordType string, ttl int64, values ...string) dns.RecordSet {
var getterFunc func(values []string, ttl int64) *dns.RecordSetProperties
switch recordType {
case endpoint.RecordTypeA:
......@@ -112,7 +117,7 @@ func createMockRecordSetWithTTL(name, recordType, value string, ttl int64) dns.R
return dns.RecordSet{
Name: to.StringPtr(name),
Type: to.StringPtr("Microsoft.Network/dnszones/" + recordType),
RecordSetProperties: getterFunc(value, ttl),
RecordSetProperties: getterFunc(values, ttl),
}
}
......@@ -148,7 +153,7 @@ func (client *mockRecordsClient) CreateOrUpdate(resourceGroupName string, zoneNa
formatAzureDNSName(relativeRecordSetName, zoneName),
string(recordType),
ttl,
extractAzureTarget(&parameters),
extractAzureTargets(&parameters)...,
),
)
return parameters, nil
......@@ -209,6 +214,46 @@ func TestAzureRecord(t *testing.T) {
}
func TestAzureMultiRecord(t *testing.T) {
zonesClient := mockZonesClient{
mockZoneListResult: &dns.ZoneListResult{
Value: &[]dns.Zone{
createMockZone("example.com", "/dnszones/example.com"),
},
},
}
recordsClient := mockRecordsClient{
mockRecordSet: &[]dns.RecordSet{
createMockRecordSet("@", "NS", "ns1-03.azure-dns.com."),
createMockRecordSet("@", "SOA", "Email: azuredns-hostmaster.microsoft.com"),
createMockRecordSet("@", endpoint.RecordTypeA, "123.123.123.122", "234.234.234.233"),
createMockRecordSet("@", endpoint.RecordTypeTXT, "heritage=external-dns,external-dns/owner=default"),
createMockRecordSetMultiWithTTL("nginx", endpoint.RecordTypeA, 3600, "123.123.123.123", "234.234.234.234"),
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 {
t.Fatal(err)
}
expected := []*endpoint.Endpoint{
endpoint.NewEndpoint("example.com", endpoint.RecordTypeA, "123.123.123.122", "234.234.234.233"),
endpoint.NewEndpoint("example.com", endpoint.RecordTypeTXT, "heritage=external-dns,external-dns/owner=default"),
endpoint.NewEndpointWithTTL("nginx.example.com", endpoint.RecordTypeA, 3600, "123.123.123.123", "234.234.234.234"),
endpoint.NewEndpointWithTTL("nginx.example.com", endpoint.RecordTypeTXT, recordTTL, "heritage=external-dns,external-dns/owner=default"),
endpoint.NewEndpointWithTTL("hack.example.com", endpoint.RecordTypeCNAME, 10, "hack.azurewebsites.net"),
}
validateAzureEndpoints(t, actual, expected)
}
func TestAzureApplyChanges(t *testing.T) {
recordsClient := mockRecordsClient{}
......@@ -224,7 +269,7 @@ func TestAzureApplyChanges(t *testing.T) {
validateAzureEndpoints(t, recordsClient.updatedEndpoints, []*endpoint.Endpoint{
endpoint.NewEndpointWithTTL("example.com", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.2.3.4"),
endpoint.NewEndpointWithTTL("example.com", endpoint.RecordTypeTXT, endpoint.TTL(recordTTL), "tag"),
endpoint.NewEndpointWithTTL("foo.example.com", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.2.3.4"),
endpoint.NewEndpointWithTTL("foo.example.com", endpoint.RecordTypeA, endpoint.TTL(recordTTL), "1.2.3.4", "1.2.3.5"),
endpoint.NewEndpointWithTTL("foo.example.com", endpoint.RecordTypeTXT, endpoint.TTL(recordTTL), "tag"),
endpoint.NewEndpointWithTTL("bar.example.com", endpoint.RecordTypeCNAME, endpoint.TTL(recordTTL), "other.com"),
endpoint.NewEndpointWithTTL("bar.example.com", endpoint.RecordTypeTXT, endpoint.TTL(recordTTL), "tag"),
......@@ -265,7 +310,7 @@ func testAzureApplyChangesInternal(t *testing.T, dryRun bool, client RecordsClie
createRecords := []*endpoint.Endpoint{
endpoint.NewEndpoint("example.com", endpoint.RecordTypeA, "1.2.3.4"),
endpoint.NewEndpoint("example.com", endpoint.RecordTypeTXT, "tag"),
endpoint.NewEndpoint("foo.example.com", endpoint.RecordTypeA, "1.2.3.4"),
endpoint.NewEndpoint("foo.example.com", endpoint.RecordTypeA, "1.2.3.5", "1.2.3.4"),
endpoint.NewEndpoint("foo.example.com", endpoint.RecordTypeTXT, "tag"),
endpoint.NewEndpoint("bar.example.com", endpoint.RecordTypeCNAME, "other.com"),
endpoint.NewEndpoint("bar.example.com", endpoint.RecordTypeTXT, "tag"),
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment