Support for multiple domains within --domain-filter (#252)

* Support for multiple domains within --domain-filter

The parameter accepts a comma separated list of domains with or without trailing dot. Example: --domain-filter="example.org, company.test.,staging.com". Closes #247 and #229

* Add boilerplate header

* Add documentation for methods and structs

* use StringsVar for the domain-filter flag

* go fmt

* Remove camel case from tests

* Revert changes in README.md

* Move DomainFilter to provider package

* Make a new slice and copy elements to it

* Update CHANGELOG.md

* docs: change minor spelling mistake
This commit is contained in:
Nils Juenemann 2017-06-29 18:59:05 +02:00 committed by Yerken
parent 1592ef0afa
commit 73d397961e
20 changed files with 247 additions and 64 deletions

View File

@ -1,3 +1,6 @@
- The flag `--domain-filter` can be repeated multiple times like `--domain-filter=example.com --domain-filter=company.org.`.
- A trailing period is not required anymore for `--domain-filter` when AWS (or any other) provider is used.
## v0.3.0 - 2017-05-08
Features:

View File

@ -84,7 +84,7 @@ spec:
args:
- --source=service
- --source=ingress
- --domain-filter=external-dns-test.my-org.com. # will make ExternalDNS see only the hosted zones matching provided domain, omit to process all available hosted zones
- --domain-filter=external-dns-test.my-org.com # will make ExternalDNS see only the hosted zones matching provided domain, omit to process all available hosted zones
- --provider=aws
- --policy=upsert-only # would prevent ExternalDNS from deleting any records, omit to enable full synchronization
- --registry=txt

View File

@ -81,7 +81,7 @@ spec:
args:
- --source=service
- --source=ingress
- --domain-filter=external-dns-test.gcp.zalan.do. #will make ExternalDNS see only the hosted zones matching provided domain, omit to process all available hosted zones
- --domain-filter=external-dns-test.gcp.zalan.do # will make ExternalDNS see only the hosted zones matching provided domain, omit to process all available hosted zones
- --provider=google
- --google-project=zalando-external-dns-test
- --policy=upsert-only # would prevent ExternalDNS from deleting any records, omit to enable full synchronization

View File

@ -220,7 +220,7 @@ spec:
image: registry.opensource.zalan.do/teapot/external-dns:v0.3.0
args:
- --source=ingress
- --domain-filter=external-dns-test.gcp.zalan.do.
- --domain-filter=external-dns-test.gcp.zalan.do
- --provider=google
- --google-project=zalando-external-dns-test
- --registry=txt

14
main.go
View File

@ -108,20 +108,22 @@ func main() {
endpointsSource := source.NewDedupSource(source.NewMultiSource(sources))
domainFilter := provider.NewDomainFilter(cfg.DomainFilter)
var p provider.Provider
switch cfg.Provider {
case "aws":
p, err = provider.NewAWSProvider(cfg.DomainFilter, cfg.DryRun)
p, err = provider.NewAWSProvider(domainFilter, cfg.DryRun)
case "azure":
p, err = provider.NewAzureProvider(cfg.AzureConfigFile, cfg.DomainFilter, cfg.AzureResourceGroup, cfg.DryRun)
p, err = provider.NewAzureProvider(cfg.AzureConfigFile, domainFilter, cfg.AzureResourceGroup, cfg.DryRun)
case "cloudflare":
p, err = provider.NewCloudFlareProvider(cfg.DomainFilter, cfg.DryRun)
p, err = provider.NewCloudFlareProvider(domainFilter, cfg.DryRun)
case "google":
p, err = provider.NewGoogleProvider(cfg.GoogleProject, cfg.DomainFilter, cfg.DryRun)
p, err = provider.NewGoogleProvider(cfg.GoogleProject, domainFilter, cfg.DryRun)
case "digitalocean":
p, err = provider.NewDigitalOceanProvider(cfg.DomainFilter, cfg.DryRun)
p, err = provider.NewDigitalOceanProvider(domainFilter, cfg.DryRun)
case "inmemory":
p, err = provider.NewInMemoryProvider(provider.InMemoryWithDomain(cfg.DomainFilter), provider.InMemoryWithLogging()), nil
p, err = provider.NewInMemoryProvider(provider.InMemoryWithDomain(domainFilter), provider.InMemoryWithLogging()), nil
default:
log.Fatalf("unknown dns provider: %s", cfg.Provider)
}

View File

@ -36,7 +36,7 @@ type Config struct {
Compatibility string
Provider string
GoogleProject string
DomainFilter string
DomainFilter []string
AzureConfigFile string
AzureResourceGroup string
Policy string
@ -60,7 +60,7 @@ var defaultConfig = &Config{
Compatibility: "",
Provider: "",
GoogleProject: "",
DomainFilter: "",
DomainFilter: []string{},
AzureConfigFile: "/etc/kubernetes/azure.json",
AzureResourceGroup: "",
Policy: "sync",
@ -99,7 +99,7 @@ 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, google, azure, cloudflare, digitalocean, inmemory)").Required().PlaceHolder("provider").EnumVar(&cfg.Provider, "aws", "google", "azure", "cloudflare", "digitalocean", "inmemory")
app.Flag("google-project", "When using the Google provider, specify the Google project (required when --provider=google)").Default(defaultConfig.GoogleProject).StringVar(&cfg.GoogleProject)
app.Flag("domain-filter", "Limit possible target zones by a domain suffix (optional)").Default(defaultConfig.DomainFilter).StringVar(&cfg.DomainFilter)
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("azure-config-file", "When using the Azure provider, specify the Azure configuration file (required when --provider=azure").Default(defaultConfig.AzureConfigFile).StringVar(&cfg.AzureConfigFile)
app.Flag("azure-resource-group", "When using the Azure provider, override the Azure resource group to use (optional)").Default(defaultConfig.AzureResourceGroup).StringVar(&cfg.AzureResourceGroup)

View File

@ -35,7 +35,7 @@ var (
Compatibility: "",
Provider: "google",
GoogleProject: "",
DomainFilter: "",
DomainFilter: []string{""},
AzureConfigFile: "/etc/kubernetes/azure.json",
AzureResourceGroup: "",
Policy: "sync",
@ -59,7 +59,7 @@ var (
Compatibility: "mate",
Provider: "google",
GoogleProject: "project",
DomainFilter: "example.org.",
DomainFilter: []string{"example.org", "company.com"},
AzureConfigFile: "azure.json",
AzureResourceGroup: "arg",
Policy: "upsert-only",
@ -105,7 +105,8 @@ func TestParseFlags(t *testing.T) {
"--google-project=project",
"--azure-config-file=azure.json",
"--azure-resource-group=arg",
"--domain-filter=example.org.",
"--domain-filter=example.org",
"--domain-filter=company.com",
"--policy=upsert-only",
"--registry=noop",
"--txt-owner-id=owner-1",
@ -134,7 +135,7 @@ func TestParseFlags(t *testing.T) {
"EXTERNAL_DNS_GOOGLE_PROJECT": "project",
"EXTERNAL_DNS_AZURE_CONFIG_FILE": "azure.json",
"EXTERNAL_DNS_AZURE_RESOURCE_GROUP": "arg",
"EXTERNAL_DNS_DOMAIN_FILTER": "example.org.",
"EXTERNAL_DNS_DOMAIN_FILTER": "example.org\ncompany.com",
"EXTERNAL_DNS_POLICY": "upsert-only",
"EXTERNAL_DNS_REGISTRY": "noop",
"EXTERNAL_DNS_TXT_OWNER_ID": "owner-1",

View File

@ -70,11 +70,11 @@ type AWSProvider struct {
client Route53API
dryRun bool
// only consider hosted zones managing domains ending in this suffix
domainFilter string
domainFilter DomainFilter
}
// NewAWSProvider initializes a new AWS Route53 based Provider.
func NewAWSProvider(domainFilter string, dryRun bool) (*AWSProvider, error) {
func NewAWSProvider(domainFilter DomainFilter, dryRun bool) (*AWSProvider, error) {
config := aws.NewConfig()
config = config.WithHTTPClient(
@ -109,7 +109,7 @@ func (p *AWSProvider) Zones() (map[string]*route53.HostedZone, error) {
f := func(resp *route53.ListHostedZonesOutput, lastPage bool) (shouldContinue bool) {
for _, zone := range resp.HostedZones {
if strings.HasSuffix(aws.StringValue(zone.Name), p.domainFilter) {
if p.domainFilter.Match(aws.StringValue(zone.Name)) {
zones[aws.StringValue(zone.Id)] = zone
}
}

View File

@ -23,7 +23,6 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/route53"
"github.com/kubernetes-incubator/external-dns/endpoint"
"github.com/kubernetes-incubator/external-dns/internal/testutils"
"github.com/kubernetes-incubator/external-dns/plan"
@ -145,7 +144,7 @@ func (r *Route53APIStub) CreateHostedZone(input *route53.CreateHostedZoneInput)
}
func TestAWSZones(t *testing.T) {
provider := newAWSProvider(t, "ext-dns-test-2.teapot.zalan.do.", false, []*endpoint.Endpoint{})
provider := newAWSProvider(t, NewDomainFilter([]string{"ext-dns-test-2.teapot.zalan.do."}), false, []*endpoint.Endpoint{})
zones, err := provider.Zones()
require.NoError(t, err)
@ -167,7 +166,7 @@ func TestAWSZones(t *testing.T) {
}
func TestAWSRecords(t *testing.T) {
provider := newAWSProvider(t, "ext-dns-test-2.teapot.zalan.do.", false, []*endpoint.Endpoint{
provider := newAWSProvider(t, NewDomainFilter([]string{"ext-dns-test-2.teapot.zalan.do."}), false, []*endpoint.Endpoint{
endpoint.NewEndpoint("list-test.zone-1.ext-dns-test-2.teapot.zalan.do", "1.2.3.4", "A"),
endpoint.NewEndpoint("list-test.zone-2.ext-dns-test-2.teapot.zalan.do", "8.8.8.8", "A"),
endpoint.NewEndpoint("list-test-alias.zone-1.ext-dns-test-2.teapot.zalan.do", "foo.eu-central-1.elb.amazonaws.com", "ALIAS"),
@ -184,7 +183,7 @@ func TestAWSRecords(t *testing.T) {
}
func TestAWSCreateRecords(t *testing.T) {
provider := newAWSProvider(t, "ext-dns-test-2.teapot.zalan.do.", false, []*endpoint.Endpoint{})
provider := newAWSProvider(t, NewDomainFilter([]string{"ext-dns-test-2.teapot.zalan.do."}), false, []*endpoint.Endpoint{})
records := []*endpoint.Endpoint{
endpoint.NewEndpoint("create-test.zone-1.ext-dns-test-2.teapot.zalan.do", "1.2.3.4", ""),
@ -205,7 +204,7 @@ func TestAWSCreateRecords(t *testing.T) {
}
func TestAWSUpdateRecords(t *testing.T) {
provider := newAWSProvider(t, "ext-dns-test-2.teapot.zalan.do.", false, []*endpoint.Endpoint{
provider := newAWSProvider(t, NewDomainFilter([]string{"ext-dns-test-2.teapot.zalan.do."}), false, []*endpoint.Endpoint{
endpoint.NewEndpoint("update-test.zone-1.ext-dns-test-2.teapot.zalan.do", "8.8.8.8", "A"),
endpoint.NewEndpoint("update-test.zone-2.ext-dns-test-2.teapot.zalan.do", "8.8.4.4", "A"),
endpoint.NewEndpoint("update-test-cname.zone-1.ext-dns-test-2.teapot.zalan.do", "foo.elb.amazonaws.com", "CNAME"),
@ -243,7 +242,7 @@ func TestAWSDeleteRecords(t *testing.T) {
endpoint.NewEndpoint("delete-test-cname-alias.zone-1.ext-dns-test-2.teapot.zalan.do", "foo.eu-central-1.elb.amazonaws.com", "CNAME"),
}
provider := newAWSProvider(t, "ext-dns-test-2.teapot.zalan.do.", false, originalEndpoints)
provider := newAWSProvider(t, NewDomainFilter([]string{"ext-dns-test-2.teapot.zalan.do."}), false, originalEndpoints)
require.NoError(t, provider.DeleteRecords(originalEndpoints))
@ -254,7 +253,7 @@ func TestAWSDeleteRecords(t *testing.T) {
}
func TestAWSApplyChanges(t *testing.T) {
provider := newAWSProvider(t, "ext-dns-test-2.teapot.zalan.do.", false, []*endpoint.Endpoint{
provider := newAWSProvider(t, NewDomainFilter([]string{"ext-dns-test-2.teapot.zalan.do."}), false, []*endpoint.Endpoint{
endpoint.NewEndpoint("update-test.zone-1.ext-dns-test-2.teapot.zalan.do", "8.8.8.8", "A"),
endpoint.NewEndpoint("delete-test.zone-1.ext-dns-test-2.teapot.zalan.do", "8.8.8.8", "A"),
endpoint.NewEndpoint("update-test.zone-2.ext-dns-test-2.teapot.zalan.do", "8.8.4.4", "A"),
@ -328,7 +327,7 @@ func TestAWSApplyChangesDryRun(t *testing.T) {
endpoint.NewEndpoint("delete-test-cname-alias.zone-1.ext-dns-test-2.teapot.zalan.do", "qux.elb.amazonaws.com", "ALIAS"),
}
provider := newAWSProvider(t, "ext-dns-test-2.teapot.zalan.do.", true, originalEndpoints)
provider := newAWSProvider(t, NewDomainFilter([]string{"ext-dns-test-2.teapot.zalan.do."}), true, originalEndpoints)
createRecords := []*endpoint.Endpoint{
endpoint.NewEndpoint("create-test.zone-1.ext-dns-test-2.teapot.zalan.do", "8.8.8.8", ""),
@ -480,7 +479,7 @@ func validateAWSChangeRecord(t *testing.T, record *route53.Change, expected *rou
}
func TestAWSCreateRecordsWithCNAME(t *testing.T) {
provider := newAWSProvider(t, "ext-dns-test-2.teapot.zalan.do.", false, []*endpoint.Endpoint{})
provider := newAWSProvider(t, NewDomainFilter([]string{"ext-dns-test-2.teapot.zalan.do."}), false, []*endpoint.Endpoint{})
records := []*endpoint.Endpoint{
{DNSName: "create-test.zone-1.ext-dns-test-2.teapot.zalan.do", Target: "foo.example.org"},
@ -505,7 +504,7 @@ func TestAWSCreateRecordsWithCNAME(t *testing.T) {
}
func TestAWSCreateRecordsWithALIAS(t *testing.T) {
provider := newAWSProvider(t, "ext-dns-test-2.teapot.zalan.do.", false, []*endpoint.Endpoint{})
provider := newAWSProvider(t, NewDomainFilter([]string{"ext-dns-test-2.teapot.zalan.do."}), false, []*endpoint.Endpoint{})
records := []*endpoint.Endpoint{
{DNSName: "create-test.zone-1.ext-dns-test-2.teapot.zalan.do", Target: "foo.eu-central-1.elb.amazonaws.com"},
@ -662,7 +661,7 @@ func clearAWSRecords(t *testing.T, provider *AWSProvider, zone string) {
}
}
func newAWSProvider(t *testing.T, domainFilter string, dryRun bool, records []*endpoint.Endpoint) *AWSProvider {
func newAWSProvider(t *testing.T, domainFilter DomainFilter, dryRun bool, records []*endpoint.Endpoint) *AWSProvider {
client := NewRoute53APIStub()
provider := &AWSProvider{

View File

@ -65,7 +65,7 @@ type RecordsClient interface {
// AzureProvider implements the DNS provider for Microsoft's Azure cloud platform.
type AzureProvider struct {
domainFilter string
domainFilter DomainFilter
dryRun bool
resourceGroup string
zonesClient ZonesClient
@ -75,7 +75,7 @@ type AzureProvider struct {
// NewAzureProvider creates a new Azure provider.
//
// Returns the provider or an error if a provider could not be created.
func NewAzureProvider(configFile string, domainFilter string, resourceGroup string, dryRun bool) (*AzureProvider, error) {
func NewAzureProvider(configFile string, domainFilter DomainFilter, resourceGroup string, dryRun bool) (*AzureProvider, error) {
contents, err := ioutil.ReadFile(configFile)
if err != nil {
return nil, fmt.Errorf("failed to read Azure config file '%s': %v", configFile, err)
@ -195,7 +195,7 @@ func (p *AzureProvider) zones() ([]dns.Zone, error) {
for list.Value != nil && len(*list.Value) > 0 {
for _, zone := range *list.Value {
if zone.Name != nil && strings.HasSuffix(*zone.Name, p.domainFilter) {
if zone.Name != nil && p.domainFilter.Match(*zone.Name) {
zones = append(zones, zone)
}
}

View File

@ -138,7 +138,7 @@ func (client *mockRecordsClient) CreateOrUpdate(resourceGroupName string, zoneNa
return parameters, nil
}
func newAzureProvider(domainFilter string, dryRun bool, resourceGroup string, zonesClient ZonesClient, recordsClient RecordsClient) *AzureProvider {
func newAzureProvider(domainFilter DomainFilter, dryRun bool, resourceGroup string, zonesClient ZonesClient, recordsClient RecordsClient) *AzureProvider {
return &AzureProvider{
domainFilter: domainFilter,
dryRun: dryRun,
@ -169,7 +169,7 @@ func TestAzureRecord(t *testing.T) {
},
}
provider := newAzureProvider("example.com", true, "k8s", &zonesClient, &recordsClient)
provider := newAzureProvider(NewDomainFilter([]string{"example.com"}), true, "k8s", &zonesClient, &recordsClient)
actual, err := provider.Records()
if err != nil {
@ -224,7 +224,7 @@ func TestAzureApplyChangesDryRun(t *testing.T) {
func testAzureApplyChangesInternal(t *testing.T, dryRun bool, client RecordsClient) {
provider := newAzureProvider(
"",
NewDomainFilter([]string{""}),
dryRun,
"group",
&mockZonesClient{

View File

@ -83,7 +83,7 @@ func (z zoneService) DeleteDNSRecord(zoneID, recordID string) error {
type CloudFlareProvider struct {
Client cloudFlareDNS
// only consider hosted zones managing domains ending in this suffix
domainFilter string
domainFilter DomainFilter
DryRun bool
}
@ -94,7 +94,7 @@ type cloudFlareChange struct {
}
// NewCloudFlareProvider initializes a new CloudFlare DNS based Provider.
func NewCloudFlareProvider(domainFilter string, dryRun bool) (*CloudFlareProvider, error) {
func NewCloudFlareProvider(domainFilter DomainFilter, dryRun bool) (*CloudFlareProvider, error) {
// initialize via API email and API key and returns new API object
config, err := cloudflare.New(os.Getenv("CF_API_KEY"), os.Getenv("CF_API_EMAIL"))
if err != nil {
@ -119,7 +119,7 @@ func (p *CloudFlareProvider) Zones() ([]cloudflare.Zone, error) {
}
for _, zone := range zones {
if strings.HasSuffix(zone.Name, p.domainFilter) {
if p.domainFilter.Match(zone.Name) {
result = append(result, zone)
}
}

View File

@ -344,7 +344,7 @@ func TestNewCloudFlareChanges(t *testing.T) {
func TestCloudFlareZones(t *testing.T) {
provider := &CloudFlareProvider{
Client: &mockCloudFlareClient{},
domainFilter: "zalando.to.",
domainFilter: NewDomainFilter([]string{"zalando.to."}),
}
zones, err := provider.Zones()
@ -382,13 +382,13 @@ func TestRecords(t *testing.T) {
func TestNewCloudFlareProvider(t *testing.T) {
_ = os.Setenv("CF_API_KEY", "xxxxxxxxxxxxxxxxx")
_ = os.Setenv("CF_API_EMAIL", "test@test.com")
_, err := NewCloudFlareProvider("ext-dns-test.zalando.to.", true)
_, err := NewCloudFlareProvider(NewDomainFilter([]string{"ext-dns-test.zalando.to."}), true)
if err != nil {
t.Errorf("should not fail, %s", err)
}
_ = os.Unsetenv("CF_API_KEY")
_ = os.Unsetenv("CF_API_EMAIL")
_, err = NewCloudFlareProvider("ext-dns-test.zalando.to.", true)
_, err = NewCloudFlareProvider(NewDomainFilter([]string{"ext-dns-test.zalando.to."}), true)
if err == nil {
t.Errorf("expected to fail")
}

View File

@ -44,7 +44,7 @@ const (
type DigitalOceanProvider struct {
Client godo.DomainsService
// only consider hosted zones managing domains ending in this suffix
domainFilter string
domainFilter DomainFilter
DryRun bool
}
@ -55,7 +55,7 @@ type DigitalOceanChange struct {
}
// NewDigitalOceanProvider initializes a new DigitalOcean DNS based Provider.
func NewDigitalOceanProvider(domainFilter string, dryRun bool) (*DigitalOceanProvider, error) {
func NewDigitalOceanProvider(domainFilter DomainFilter, dryRun bool) (*DigitalOceanProvider, error) {
token, ok := os.LookupEnv("DO_TOKEN")
if !ok {
return nil, fmt.Errorf("No token found")
@ -83,7 +83,7 @@ func (p *DigitalOceanProvider) Zones() ([]godo.Domain, error) {
}
for _, zone := range zones {
if strings.HasSuffix(zone.Name, p.domainFilter) {
if p.domainFilter.Match(zone.Name) {
result = append(result, zone)
}
}

View File

@ -393,7 +393,7 @@ func TestNewDigitalOceanChanges(t *testing.T) {
func TestDigitalOceanZones(t *testing.T) {
provider := &DigitalOceanProvider{
Client: &mockDigitalOceanClient{},
domainFilter: "com",
domainFilter: NewDomainFilter([]string{"com"}),
}
zones, err := provider.Zones()
@ -442,12 +442,12 @@ func TestDigitalOceanApplyChanges(t *testing.T) {
func TestNewDigitalOceanProvider(t *testing.T) {
_ = os.Setenv("DO_TOKEN", "xxxxxxxxxxxxxxxxx")
_, err := NewDigitalOceanProvider("ext-dns-test.zalando.to.", true)
_, err := NewDigitalOceanProvider(NewDomainFilter([]string{"ext-dns-test.zalando.to."}), true)
if err != nil {
t.Errorf("should not fail, %s", err)
}
_ = os.Unsetenv("DO_TOKEN")
_, err = NewDigitalOceanProvider("ext-dns-test.zalando.to.", true)
_, err = NewDigitalOceanProvider(NewDomainFilter([]string{"ext-dns-test.zalando.to."}), true)
if err == nil {
t.Errorf("expected to fail")
}

56
provider/domainfilter.go Normal file
View File

@ -0,0 +1,56 @@
/*
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"
)
// DomainFilter holds a lists of valid domain names
type DomainFilter struct {
filters []string
}
// NewDomainFilter returns a new DomainFilter given a comma separated list of domains
func NewDomainFilter(domainFilters []string) DomainFilter {
filters := make([]string, len(domainFilters))
// user can define filter domains either with trailing dot or without, we remove all trailing periods from
// the internal representation
for i, domain := range domainFilters {
filters[i] = strings.TrimSuffix(strings.TrimSpace(domain), ".")
}
return DomainFilter{filters}
}
// Match checks whether a domain can be found in the DomainFilter.
func (df DomainFilter) Match(domain string) bool {
// return always true, if not filter is specified
if len(df.filters) == 0 {
return true
}
for _, filter := range df.filters {
if strings.HasSuffix(strings.TrimSuffix(domain, "."), filter) {
return true
}
}
return false
}

View File

@ -0,0 +1,122 @@
/*
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 domainFilterTest struct {
domainFilter []string
domains []string
expected bool
}
var domainFilterTests = []domainFilterTest{
{
[]string{"google.com.", "exaring.de", "inovex.de"},
[]string{"google.com", "exaring.de", "inovex.de"},
true,
},
{
[]string{"google.com.", "exaring.de", "inovex.de"},
[]string{"google.com", "exaring.de", "inovex.de"},
true,
},
{
[]string{"google.com.", "exaring.de.", "inovex.de"},
[]string{"google.com", "exaring.de", "inovex.de"},
true,
},
{
[]string{"foo.org. "},
[]string{"foo.org"},
true,
},
{
[]string{" foo.org"},
[]string{"foo.org"},
true,
},
{
[]string{"foo.org."},
[]string{"foo.org"},
true,
},
{
[]string{"foo.org."},
[]string{"baz.org"},
false,
},
{
[]string{"baz.foo.org."},
[]string{"foo.org"},
false,
},
{
[]string{"", "foo.org."},
[]string{"foo.org"},
true,
},
{
[]string{"", "foo.org."},
[]string{},
true,
},
{
[]string{""},
[]string{"foo.org"},
true,
},
{
[]string{""},
[]string{},
true,
},
{
[]string{" "},
[]string{},
true,
},
{
[]string{"bar.sub.example.org"},
[]string{"foo.bar.sub.example.org"},
true,
},
}
func TestDomainFilterMatch(t *testing.T) {
for i, tt := range domainFilterTests {
domainFilter := NewDomainFilter(tt.domainFilter)
for _, domain := range tt.domains {
assert.Equal(t, tt.expected, domainFilter.Match(domain), "should not fail: %v in test-case #%v", domain, i)
assert.Equal(t, tt.expected, domainFilter.Match(domain+"."), "should not fail: %v in test-case #%v", domain+".", i)
}
}
}
func TestDomainFilterMatchWithEmptyFilter(t *testing.T) {
for _, tt := range domainFilterTests {
domainFilter := DomainFilter{}
for i, domain := range tt.domains {
assert.True(t, domainFilter.Match(domain), "should not fail: %v in test-case #%v", domain, i)
assert.True(t, domainFilter.Match(domain+"."), "should not fail: %v in test-case #%v", domain+".", i)
}
}
}

View File

@ -96,7 +96,7 @@ type GoogleProvider struct {
// Enabled dry-run will print any modifying actions rather than execute them.
dryRun bool
// only consider hosted zones managing domains ending in this suffix
domainFilter string
domainFilter DomainFilter
// A client for managing resource record sets
resourceRecordSetsClient resourceRecordSetsClientInterface
// A client for managing hosted zones
@ -106,7 +106,7 @@ type GoogleProvider struct {
}
// NewGoogleProvider initializes a new Google CloudDNS based Provider.
func NewGoogleProvider(project string, domainFilter string, dryRun bool) (*GoogleProvider, error) {
func NewGoogleProvider(project string, domainFilter DomainFilter, dryRun bool) (*GoogleProvider, error) {
gcloud, err := google.DefaultClient(context.TODO(), dns.NdevClouddnsReadwriteScope)
if err != nil {
return nil, err
@ -142,7 +142,7 @@ func (p *GoogleProvider) Zones() (map[string]*dns.ManagedZone, error) {
f := func(resp *dns.ManagedZonesListResponse) error {
for _, zone := range resp.ManagedZones {
if strings.HasSuffix(zone.DnsName, p.domainFilter) {
if p.domainFilter.Match(zone.DnsName) {
zones[zone.Name] = zone
}
}

View File

@ -192,7 +192,7 @@ func hasTrailingDot(target string) bool {
}
func TestGoogleZones(t *testing.T) {
provider := newGoogleProvider(t, "ext-dns-test-2.gcp.zalan.do.", false, []*endpoint.Endpoint{})
provider := newGoogleProvider(t, NewDomainFilter([]string{"ext-dns-test-2.gcp.zalan.do."}), false, []*endpoint.Endpoint{})
zones, err := provider.Zones()
require.NoError(t, err)
@ -211,7 +211,7 @@ func TestGoogleRecords(t *testing.T) {
endpoint.NewEndpoint("list-test-alias.zone-1.ext-dns-test-2.gcp.zalan.do", "foo.elb.amazonaws.com", "CNAME"),
}
provider := newGoogleProvider(t, "ext-dns-test-2.gcp.zalan.do.", false, originalEndpoints)
provider := newGoogleProvider(t, NewDomainFilter([]string{"ext-dns-test-2.gcp.zalan.do."}), false, originalEndpoints)
records, err := provider.Records()
require.NoError(t, err)
@ -220,7 +220,7 @@ func TestGoogleRecords(t *testing.T) {
}
func TestGoogleCreateRecords(t *testing.T) {
provider := newGoogleProvider(t, "ext-dns-test-2.gcp.zalan.do.", false, []*endpoint.Endpoint{})
provider := newGoogleProvider(t, NewDomainFilter([]string{"ext-dns-test-2.gcp.zalan.do."}), false, []*endpoint.Endpoint{})
records := []*endpoint.Endpoint{
endpoint.NewEndpoint("create-test.zone-1.ext-dns-test-2.gcp.zalan.do", "1.2.3.4", ""),
@ -241,7 +241,7 @@ func TestGoogleCreateRecords(t *testing.T) {
}
func TestGoogleUpdateRecords(t *testing.T) {
provider := newGoogleProvider(t, "ext-dns-test-2.gcp.zalan.do.", false, []*endpoint.Endpoint{
provider := newGoogleProvider(t, NewDomainFilter([]string{"ext-dns-test-2.gcp.zalan.do."}), false, []*endpoint.Endpoint{
endpoint.NewEndpoint("update-test.zone-1.ext-dns-test-2.gcp.zalan.do", "8.8.8.8", "A"),
endpoint.NewEndpoint("update-test.zone-2.ext-dns-test-2.gcp.zalan.do", "8.8.4.4", "A"),
endpoint.NewEndpoint("update-test-cname.zone-1.ext-dns-test-2.gcp.zalan.do", "foo.elb.amazonaws.com", "CNAME"),
@ -277,7 +277,7 @@ func TestGoogleDeleteRecords(t *testing.T) {
endpoint.NewEndpoint("delete-test-cname.zone-1.ext-dns-test-2.gcp.zalan.do", "baz.elb.amazonaws.com", "CNAME"),
}
provider := newGoogleProvider(t, "ext-dns-test-2.gcp.zalan.do.", false, originalEndpoints)
provider := newGoogleProvider(t, NewDomainFilter([]string{"ext-dns-test-2.gcp.zalan.do."}), false, originalEndpoints)
require.NoError(t, provider.DeleteRecords(originalEndpoints))
@ -288,7 +288,7 @@ func TestGoogleDeleteRecords(t *testing.T) {
}
func TestGoogleApplyChanges(t *testing.T) {
provider := newGoogleProvider(t, "ext-dns-test-2.gcp.zalan.do.", false, []*endpoint.Endpoint{
provider := newGoogleProvider(t, NewDomainFilter([]string{"ext-dns-test-2.gcp.zalan.do."}), false, []*endpoint.Endpoint{
endpoint.NewEndpoint("update-test.zone-1.ext-dns-test-2.gcp.zalan.do", "8.8.8.8", "A"),
endpoint.NewEndpoint("delete-test.zone-1.ext-dns-test-2.gcp.zalan.do", "8.8.8.8", "A"),
endpoint.NewEndpoint("update-test.zone-2.ext-dns-test-2.gcp.zalan.do", "8.8.4.4", "A"),
@ -352,7 +352,7 @@ func TestGoogleApplyChangesDryRun(t *testing.T) {
endpoint.NewEndpoint("delete-test-cname.zone-1.ext-dns-test-2.gcp.zalan.do", "qux.elb.amazonaws.com", "CNAME"),
}
provider := newGoogleProvider(t, "ext-dns-test-2.gcp.zalan.do.", true, originalEndpoints)
provider := newGoogleProvider(t, NewDomainFilter([]string{"ext-dns-test-2.gcp.zalan.do."}), true, originalEndpoints)
createRecords := []*endpoint.Endpoint{
endpoint.NewEndpoint("create-test.zone-1.ext-dns-test-2.gcp.zalan.do", "8.8.8.8", "A"),
@ -393,7 +393,7 @@ func TestGoogleApplyChangesDryRun(t *testing.T) {
}
func TestGoogleApplyChangesEmpty(t *testing.T) {
provider := newGoogleProvider(t, "ext-dns-test-2.gcp.zalan.do.", false, []*endpoint.Endpoint{})
provider := newGoogleProvider(t, NewDomainFilter([]string{"ext-dns-test-2.gcp.zalan.do."}), false, []*endpoint.Endpoint{})
assert.NoError(t, provider.ApplyChanges(&plan.Changes{}))
}
@ -496,7 +496,7 @@ func validateChangeRecord(t *testing.T, record *dns.ResourceRecordSet, expected
assert.Equal(t, expected.Ttl, record.Ttl)
}
func newGoogleProvider(t *testing.T, domainFilter string, dryRun bool, records []*endpoint.Endpoint) *GoogleProvider {
func newGoogleProvider(t *testing.T, domainFilter DomainFilter, dryRun bool, records []*endpoint.Endpoint) *GoogleProvider {
provider := &GoogleProvider{
project: "zalando-external-dns-test",
domainFilter: domainFilter,

View File

@ -42,7 +42,7 @@ var (
// InMemoryProvider - dns provider only used for testing purposes
// initialized as dns provider with no records
type InMemoryProvider struct {
domain string
domain DomainFilter
client *inMemoryClient
filter *filter
OnApplyChanges func(changes *plan.Changes)
@ -73,9 +73,9 @@ func InMemoryWithLogging() InMemoryOption {
}
// InMemoryWithDomain modifies the domain on which dns zones are filtered
func InMemoryWithDomain(domain string) InMemoryOption {
func InMemoryWithDomain(domainFilter DomainFilter) InMemoryOption {
return func(p *InMemoryProvider) {
p.domain = domain
p.domain = domainFilter
}
}
@ -85,7 +85,7 @@ func NewInMemoryProvider(opts ...InMemoryOption) *InMemoryProvider {
filter: &filter{},
OnApplyChanges: func(changes *plan.Changes) {},
OnRecords: func() {},
domain: "",
domain: NewDomainFilter([]string{""}),
client: newInMemoryClient(),
}