mirror of
https://github.com/kubernetes-sigs/external-dns.git
synced 2025-08-06 09:36:58 +02:00
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:
parent
1592ef0afa
commit
73d397961e
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
14
main.go
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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{
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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{
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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
56
provider/domainfilter.go
Normal 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
|
||||
}
|
122
provider/domainfilter_test.go
Normal file
122
provider/domainfilter_test.go
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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(),
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user