Skip to content

Commit

Permalink
Merge ca44b6e into b325616
Browse files Browse the repository at this point in the history
  • Loading branch information
offzale committed Apr 9, 2020
2 parents b325616 + ca44b6e commit 3b32f14
Show file tree
Hide file tree
Showing 7 changed files with 220 additions and 11 deletions.
2 changes: 2 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ func main() {

domainFilter := endpoint.NewDomainFilterWithExclusions(cfg.DomainFilter, cfg.ExcludeDomains)
zoneIDFilter := provider.NewZoneIDFilter(cfg.ZoneIDFilter)
zoneNameFilter := provider.NewZoneNameFilter(cfg.ZoneNameFilter)
zoneTypeFilter := provider.NewZoneTypeFilter(cfg.AWSZoneType)
zoneTagFilter := provider.NewZoneTagFilter(cfg.AWSZoneTagFilter)

Expand All @@ -141,6 +142,7 @@ func main() {
provider.AWSConfig{
DomainFilter: domainFilter,
ZoneIDFilter: zoneIDFilter,
ZoneNameFilter: zoneNameFilter,
ZoneTypeFilter: zoneTypeFilter,
ZoneTagFilter: zoneTagFilter,
BatchChangeSize: cfg.AWSBatchChangeSize,
Expand Down
4 changes: 3 additions & 1 deletion pkg/apis/externaldns/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ type Config struct {
DomainFilter []string
ExcludeDomains []string
ZoneIDFilter []string
ZoneNameFilter []string
AlibabaCloudConfigFile string
AlibabaCloudZoneType string
AWSZoneType string
Expand Down Expand Up @@ -313,9 +314,10 @@ func (cfg *Config) ParseFlags(args []string) error {

// Flags related to providers
app.Flag("provider", "The DNS provider where the DNS records will be created (required, options: aws, aws-sd, google, azure, azure-dns, azure-private-dns, cloudflare, rcodezero, digitalocean, dnsimple, akamai, infoblox, dyn, designate, coredns, skydns, inmemory, ovh, pdns, oci, exoscale, linode, rfc2136, ns1, transip, vinyldns, rdns)").Required().PlaceHolder("provider").EnumVar(&cfg.Provider, "aws", "aws-sd", "google", "azure", "azure-dns", "azure-private-dns", "alibabacloud", "cloudflare", "rcodezero", "digitalocean", "dnsimple", "akamai", "infoblox", "dyn", "designate", "coredns", "skydns", "inmemory", "ovh", "pdns", "oci", "exoscale", "linode", "rfc2136", "ns1", "transip", "vinyldns", "rdns")
app.Flag("domain-filter", "Limit possible target zones by a domain suffix; specify multiple times for multiple domains (optional)").Default("").StringsVar(&cfg.DomainFilter)
app.Flag("domain-filter", "Limit possible domains and target zones by a domain suffix; specify multiple times for multiple domains (optional)").Default("").StringsVar(&cfg.DomainFilter)
app.Flag("exclude-domains", "Exclude subdomains (optional)").Default("").StringsVar(&cfg.ExcludeDomains)
app.Flag("zone-id-filter", "Filter target zones by hosted zone id; specify multiple times for multiple zones (optional)").Default("").StringsVar(&cfg.ZoneIDFilter)
app.Flag("zone-name-filter", "Filter target zones by name; specify multiple times for multiple zones; Overrides domain-filter for target zones (optional)").Default("").StringsVar(&cfg.ZoneNameFilter)
app.Flag("google-project", "When using the Google provider, current project is auto-detected, when running on GCP. Specify other project with this. Must be specified when running outside GCP.").Default(defaultConfig.GoogleProject).StringVar(&cfg.GoogleProject)
app.Flag("google-batch-change-size", "When using the Google provider, set the maximum number of changes that will be applied in each batch.").Default(strconv.Itoa(defaultConfig.GoogleBatchChangeSize)).IntVar(&cfg.GoogleBatchChangeSize)
app.Flag("google-batch-change-interval", "When using the Google provider, set the interval between batch changes.").Default(defaultConfig.GoogleBatchChangeInterval.String()).DurationVar(&cfg.GoogleBatchChangeInterval)
Expand Down
5 changes: 5 additions & 0 deletions pkg/apis/externaldns/types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ var (
DomainFilter: []string{""},
ExcludeDomains: []string{""},
ZoneIDFilter: []string{""},
ZoneNameFilter: []string{""},
AlibabaCloudConfigFile: "/etc/kubernetes/alibaba-cloud.json",
AWSZoneType: "",
AWSZoneTagFilter: []string{""},
Expand Down Expand Up @@ -118,6 +119,7 @@ var (
DomainFilter: []string{"example.org", "company.com"},
ExcludeDomains: []string{"xapi.example.org", "xapi.company.com"},
ZoneIDFilter: []string{"/hostedzone/ZTST1", "/hostedzone/ZTST2"},
ZoneNameFilter: []string{"example.org", "company.com"},
AlibabaCloudConfigFile: "/etc/kubernetes/alibaba-cloud.json",
AWSZoneType: "private",
AWSZoneTagFilter: []string{"tag=foo"},
Expand Down Expand Up @@ -249,6 +251,8 @@ func TestParseFlags(t *testing.T) {
"--exclude-domains=xapi.company.com",
"--zone-id-filter=/hostedzone/ZTST1",
"--zone-id-filter=/hostedzone/ZTST2",
"--zone-name-filter=example.org",
"--zone-name-filter=company.com",
"--aws-zone-type=private",
"--aws-zone-tags=tag=foo",
"--aws-assume-role=some-other-role",
Expand Down Expand Up @@ -333,6 +337,7 @@ func TestParseFlags(t *testing.T) {
"EXTERNAL_DNS_TLS_CLIENT_CERT": "/path/to/cert.pem",
"EXTERNAL_DNS_TLS_CLIENT_CERT_KEY": "/path/to/key.pem",
"EXTERNAL_DNS_ZONE_ID_FILTER": "/hostedzone/ZTST1\n/hostedzone/ZTST2",
"EXTERNAL_DNS_ZONE_NAME_FILTER": "example.org\ncompany.com",
"EXTERNAL_DNS_AWS_ZONE_TYPE": "private",
"EXTERNAL_DNS_AWS_ZONE_TAGS": "tag=foo",
"EXTERNAL_DNS_AWS_ASSUME_ROLE": "some-other-role",
Expand Down
11 changes: 10 additions & 1 deletion provider/aws.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ type AWSProvider struct {
domainFilter endpoint.DomainFilter
// filter hosted zones by id
zoneIDFilter ZoneIDFilter
// filter hosted zones by name
zoneNameFilter ZoneNameFilter
// filter hosted zones by type (e.g. private or public)
zoneTypeFilter ZoneTypeFilter
// filter hosted zones by tags
Expand All @@ -133,6 +135,7 @@ type AWSProvider struct {
type AWSConfig struct {
DomainFilter endpoint.DomainFilter
ZoneIDFilter ZoneIDFilter
ZoneNameFilter ZoneNameFilter
ZoneTypeFilter ZoneTypeFilter
ZoneTagFilter ZoneTagFilter
BatchChangeSize int
Expand Down Expand Up @@ -174,6 +177,7 @@ func NewAWSProvider(awsConfig AWSConfig) (*AWSProvider, error) {
client: route53.New(session),
domainFilter: awsConfig.DomainFilter,
zoneIDFilter: awsConfig.ZoneIDFilter,
zoneNameFilter: awsConfig.ZoneNameFilter,
zoneTypeFilter: awsConfig.ZoneTypeFilter,
zoneTagFilter: awsConfig.ZoneTagFilter,
batchChangeSize: awsConfig.BatchChangeSize,
Expand Down Expand Up @@ -201,7 +205,12 @@ func (p *AWSProvider) Zones(ctx context.Context) (map[string]*route53.HostedZone
continue
}

if !p.domainFilter.Match(aws.StringValue(zone.Name)) {
// zoneNameFilter overrides domainFilter
if p.zoneNameFilter.IsConfigured() {
if !p.zoneNameFilter.Match(aws.StringValue(zone.Name)) {
continue
}
} else if !p.domainFilter.Match(aws.StringValue(zone.Name)) {
continue
}

Expand Down
21 changes: 12 additions & 9 deletions provider/aws_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -288,18 +288,20 @@ func TestAWSZones(t *testing.T) {
for _, ti := range []struct {
msg string
zoneIDFilter ZoneIDFilter
zoneNameFilter ZoneNameFilter
zoneTypeFilter ZoneTypeFilter
zoneTagFilter ZoneTagFilter
expectedZones map[string]*route53.HostedZone
}{
{"no filter", NewZoneIDFilter([]string{}), NewZoneTypeFilter(""), NewZoneTagFilter([]string{}), allZones},
{"public filter", NewZoneIDFilter([]string{}), NewZoneTypeFilter("public"), NewZoneTagFilter([]string{}), publicZones},
{"private filter", NewZoneIDFilter([]string{}), NewZoneTypeFilter("private"), NewZoneTagFilter([]string{}), privateZones},
{"unknown filter", NewZoneIDFilter([]string{}), NewZoneTypeFilter("unknown"), NewZoneTagFilter([]string{}), noZones},
{"zone id filter", NewZoneIDFilter([]string{"/hostedzone/zone-3.ext-dns-test-2.teapot.zalan.do."}), NewZoneTypeFilter(""), NewZoneTagFilter([]string{}), privateZones},
{"tag filter", NewZoneIDFilter([]string{}), NewZoneTypeFilter(""), NewZoneTagFilter([]string{"zone=3"}), privateZones},
{"no filter", NewZoneIDFilter([]string{}), NewZoneNameFilter([]string{}), NewZoneTypeFilter(""), NewZoneTagFilter([]string{}), allZones},
{"public filter", NewZoneIDFilter([]string{}), NewZoneNameFilter([]string{}), NewZoneTypeFilter("public"), NewZoneTagFilter([]string{}), publicZones},
{"private filter", NewZoneIDFilter([]string{}), NewZoneNameFilter([]string{}), NewZoneTypeFilter("private"), NewZoneTagFilter([]string{}), privateZones},
{"unknown filter", NewZoneIDFilter([]string{}), NewZoneNameFilter([]string{}), NewZoneTypeFilter("unknown"), NewZoneTagFilter([]string{}), noZones},
{"zone id filter", NewZoneIDFilter([]string{"/hostedzone/zone-3.ext-dns-test-2.teapot.zalan.do."}), NewZoneNameFilter([]string{}), NewZoneTypeFilter(""), NewZoneTagFilter([]string{}), privateZones},
{"zone name filter", NewZoneIDFilter([]string{}), NewZoneNameFilter([]string{"zone-3.ext-dns-test-2.teapot.zalan.do."}), NewZoneTypeFilter(""), NewZoneTagFilter([]string{}), privateZones},
{"tag filter", NewZoneIDFilter([]string{}), NewZoneNameFilter([]string{}), NewZoneTypeFilter(""), NewZoneTagFilter([]string{"zone=3"}), privateZones},
} {
provider, _ := newAWSProviderWithTagFilter(t, endpoint.NewDomainFilter([]string{"ext-dns-test-2.teapot.zalan.do."}), ti.zoneIDFilter, ti.zoneTypeFilter, ti.zoneTagFilter, defaultEvaluateTargetHealth, false, []*endpoint.Endpoint{})
provider, _ := newAWSProviderWithTagFilter(t, endpoint.NewDomainFilter([]string{"ext-dns-test-2.teapot.zalan.do."}), ti.zoneIDFilter, ti.zoneNameFilter, ti.zoneTypeFilter, ti.zoneTagFilter, defaultEvaluateTargetHealth, false, []*endpoint.Endpoint{})

zones, err := provider.Zones(context.Background())
require.NoError(t, err)
Expand Down Expand Up @@ -1183,10 +1185,10 @@ func escapeAWSRecords(t *testing.T, provider *AWSProvider, zone string) {
}
}
func newAWSProvider(t *testing.T, domainFilter endpoint.DomainFilter, zoneIDFilter ZoneIDFilter, zoneTypeFilter ZoneTypeFilter, evaluateTargetHealth, dryRun bool, records []*endpoint.Endpoint) (*AWSProvider, *Route53APIStub) {
return newAWSProviderWithTagFilter(t, domainFilter, zoneIDFilter, zoneTypeFilter, NewZoneTagFilter([]string{}), evaluateTargetHealth, dryRun, records)
return newAWSProviderWithTagFilter(t, domainFilter, zoneIDFilter, NewZoneNameFilter([]string{}), zoneTypeFilter, NewZoneTagFilter([]string{}), evaluateTargetHealth, dryRun, records)
}

func newAWSProviderWithTagFilter(t *testing.T, domainFilter endpoint.DomainFilter, zoneIDFilter ZoneIDFilter, zoneTypeFilter ZoneTypeFilter, zoneTagFilter ZoneTagFilter, evaluateTargetHealth, dryRun bool, records []*endpoint.Endpoint) (*AWSProvider, *Route53APIStub) {
func newAWSProviderWithTagFilter(t *testing.T, domainFilter endpoint.DomainFilter, zoneIDFilter ZoneIDFilter, zoneNameFilter ZoneNameFilter, zoneTypeFilter ZoneTypeFilter, zoneTagFilter ZoneTagFilter, evaluateTargetHealth, dryRun bool, records []*endpoint.Endpoint) (*AWSProvider, *Route53APIStub) {
client := NewRoute53APIStub()

provider := &AWSProvider{
Expand All @@ -1196,6 +1198,7 @@ func newAWSProviderWithTagFilter(t *testing.T, domainFilter endpoint.DomainFilte
evaluateTargetHealth: evaluateTargetHealth,
domainFilter: domainFilter,
zoneIDFilter: zoneIDFilter,
zoneNameFilter: zoneNameFilter,
zoneTypeFilter: zoneTypeFilter,
zoneTagFilter: zoneTagFilter,
dryRun: false,
Expand Down
58 changes: 58 additions & 0 deletions provider/zone_name_filter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package provider

import "strings"

// ZoneNameFilter holds a list of zone names to filter by
type ZoneNameFilter struct {
zoneNames []string
}

// NewZoneNameFilter returns a new ZoneNameFilter given a list of zone names
func NewZoneNameFilter(zoneNames []string) ZoneNameFilter {
zs := make([]string, len(zoneNames))
for i, zone := range zoneNames {
zs[i] = strings.TrimSuffix(strings.TrimSpace(zone), ".")
}

return ZoneNameFilter{zs}
}

// Match checks whether a zone matches one of the provided zone names
func (f ZoneNameFilter) Match(zoneName string) bool {
// An empty filter includes all names.
if len(f.zoneNames) == 0 {
return true
}

for _, name := range f.zoneNames {
if strings.EqualFold(strings.TrimSuffix(strings.TrimSpace(zoneName), "."), name) {
return true
}
}

return false
}

// IsConfigured returns true if ZoneNameFilter is configured, false otherwise
func (f ZoneNameFilter) IsConfigured() bool {
if len(f.zoneNames) == 1 {
return f.zoneNames[0] != ""
}
return len(f.zoneNames) > 0
}
130 changes: 130 additions & 0 deletions provider/zone_name_filter_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package provider

import (
"testing"

"github.com/stretchr/testify/assert"
)

type zoneNameFilterTest struct {
zoneNameFilter []string
zone string
expected bool
}

func TestZoneNameFilterMatch(t *testing.T) {
zone := "example.org."

for _, tt := range []zoneNameFilterTest{
{
[]string{},
zone,
true,
},
{
[]string{"example.org"},
zone,
true,
},
{
[]string{"example.org."},
zone,
true,
},
{
[]string{" example.org. "},
zone,
true,
},
{
[]string{"example"},
zone,
false,
},
{
[]string{"org."},
zone,
false,
},
{
[]string{"example.org", "company.com"},
zone,
true,
},
{
[]string{"company.com", "example.org"},
zone,
true,
},
{
[]string{"company.com", " example.org. "},
zone,
true,
},
{
[]string{"company.org", "example.com"},
zone,
false,
},
} {
zoneNameFilter := NewZoneNameFilter(tt.zoneNameFilter)
assert.Equal(t, tt.expected, zoneNameFilter.Match(tt.zone))
}
}

func TestZoneNameFilterIsConfigured(t *testing.T) {
for _, tt := range []struct {
zoneNameFilter []string
expected bool
}{
{
[]string{},
false,
},
{
[]string{""},
false,
},
{
[]string{" "},
false,
},
{
[]string{" . "},
false,
},
{
[]string{"", ""},
true,
},
{
[]string{"example.org"},
true,
},
{
[]string{"example.org", "company.com"},
true,
},
} {
t.Run("test IsConfigured", func(t *testing.T) {
f := NewZoneNameFilter(tt.zoneNameFilter)
assert.Equal(t, tt.expected, f.IsConfigured())
})
}
}

0 comments on commit 3b32f14

Please sign in to comment.