mirror of
https://github.com/kubernetes-sigs/external-dns.git
synced 2025-08-06 17:46:57 +02:00
feat: add regex domain filters
Signed-off-by: Enrique Gonzalez <goga.enrique@gmail.com>
This commit is contained in:
parent
d0c776b0e7
commit
c5e0227180
@ -17,7 +17,10 @@ limitations under the License.
|
||||
package endpoint
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// DomainFilter holds a lists of valid domain names
|
||||
@ -26,6 +29,10 @@ type DomainFilter struct {
|
||||
Filters []string
|
||||
// exclude define what domains not to match
|
||||
exclude []string
|
||||
// regex defines a regular expression to match the domains
|
||||
regex string
|
||||
// regexExclusion defines a regular expression to exclude the domains matched
|
||||
regexExclusion string
|
||||
}
|
||||
|
||||
// prepareFilters provides consistent trimming for filters/exclude params
|
||||
@ -39,16 +46,26 @@ func prepareFilters(filters []string) []string {
|
||||
|
||||
// NewDomainFilterWithExclusions returns a new DomainFilter, given a list of matches and exclusions
|
||||
func NewDomainFilterWithExclusions(domainFilters []string, excludeDomains []string) DomainFilter {
|
||||
return DomainFilter{prepareFilters(domainFilters), prepareFilters(excludeDomains)}
|
||||
return DomainFilter{prepareFilters(domainFilters), prepareFilters(excludeDomains), "", ""}
|
||||
}
|
||||
|
||||
// NewDomainFilter returns a new DomainFilter given a comma separated list of domains
|
||||
func NewDomainFilter(domainFilters []string) DomainFilter {
|
||||
return DomainFilter{prepareFilters(domainFilters), []string{}}
|
||||
return DomainFilter{prepareFilters(domainFilters), []string{}, "", ""}
|
||||
}
|
||||
|
||||
// NewRegexDomainFilter returns a new DomainFilter given a regular expression
|
||||
func NewRegexDomainFilter(regexDomainFilter string, regexDomainExclusion string) DomainFilter {
|
||||
return DomainFilter{[]string{}, []string{}, regexDomainFilter, regexDomainExclusion}
|
||||
}
|
||||
|
||||
// Match checks whether a domain can be found in the DomainFilter.
|
||||
// RegexFilter takes precedence over Filters
|
||||
func (df DomainFilter) Match(domain string) bool {
|
||||
if df.regex != "" {
|
||||
return matchRegex(df.regex, df.regexExclusion, domain)
|
||||
}
|
||||
|
||||
return matchFilter(df.Filters, domain, true) && !matchFilter(df.exclude, domain, false)
|
||||
}
|
||||
|
||||
@ -78,9 +95,34 @@ func matchFilter(filters []string, domain string, emptyval bool) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// matchRegex determines if a domain matches the configured regular expressions in the DomainFilter.
|
||||
// The negativeRegex, if set, takes precedence over regex. Therefore,
|
||||
// matchRegex returns true when only regex regular expression matches the domain.
|
||||
// Otherwise, if either negativeRegex matches or regex does not match the domain, it will return false.
|
||||
func matchRegex(regex string, negativeRegex string, domain string) bool {
|
||||
strippedDomain := strings.ToLower(strings.TrimSuffix(domain, "."))
|
||||
|
||||
if negativeRegex != "" {
|
||||
match, err := regexp.MatchString(negativeRegex, strippedDomain)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to filter domain %s with the regex-exclusion filter: %v", domain, err)
|
||||
}
|
||||
if match {
|
||||
return false
|
||||
}
|
||||
}
|
||||
match, err := regexp.MatchString(regex, strippedDomain)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to filter domain %s with the regex filter: %v", domain, err)
|
||||
}
|
||||
return match
|
||||
}
|
||||
|
||||
// IsConfigured returns true if DomainFilter is configured, false otherwise
|
||||
func (df DomainFilter) IsConfigured() bool {
|
||||
if len(df.Filters) == 1 {
|
||||
if df.regex != "" {
|
||||
return true
|
||||
} else if len(df.Filters) == 1 {
|
||||
return df.Filters[0] != ""
|
||||
}
|
||||
return len(df.Filters) > 0
|
||||
|
8
main.go
8
main.go
@ -115,7 +115,13 @@ func main() {
|
||||
// Combine multiple sources into a single, deduplicated source.
|
||||
endpointsSource := source.NewDedupSource(source.NewMultiSource(sources))
|
||||
|
||||
domainFilter := endpoint.NewDomainFilterWithExclusions(cfg.DomainFilter, cfg.ExcludeDomains)
|
||||
// RegexDomainFilter overrides DomainFilter
|
||||
var domainFilter endpoint.DomainFilter
|
||||
if cfg.RegexDomainFilter != "" {
|
||||
domainFilter = endpoint.NewRegexDomainFilter(cfg.RegexDomainFilter, cfg.RegexDomainExclusion)
|
||||
} else {
|
||||
domainFilter = endpoint.NewDomainFilterWithExclusions(cfg.DomainFilter, cfg.ExcludeDomains)
|
||||
}
|
||||
zoneIDFilter := provider.NewZoneIDFilter(cfg.ZoneIDFilter)
|
||||
zoneTypeFilter := provider.NewZoneTypeFilter(cfg.AWSZoneType)
|
||||
zoneTagFilter := provider.NewZoneTagFilter(cfg.AWSZoneTagFilter)
|
||||
|
@ -61,6 +61,8 @@ type Config struct {
|
||||
GoogleBatchChangeInterval time.Duration
|
||||
DomainFilter []string
|
||||
ExcludeDomains []string
|
||||
RegexDomainFilter string
|
||||
RegexDomainExclusion string
|
||||
ZoneIDFilter []string
|
||||
AlibabaCloudConfigFile string
|
||||
AlibabaCloudZoneType string
|
||||
@ -164,6 +166,8 @@ var defaultConfig = &Config{
|
||||
GoogleBatchChangeInterval: time.Second,
|
||||
DomainFilter: []string{},
|
||||
ExcludeDomains: []string{},
|
||||
RegexDomainFilter: "",
|
||||
RegexDomainExclusion: "",
|
||||
AlibabaCloudConfigFile: "/etc/kubernetes/alibaba-cloud.json",
|
||||
AWSZoneType: "",
|
||||
AWSZoneTagFilter: []string{},
|
||||
@ -315,6 +319,8 @@ func (cfg *Config) ParseFlags(args []string) error {
|
||||
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("exclude-domains", "Exclude subdomains (optional)").Default("").StringsVar(&cfg.ExcludeDomains)
|
||||
app.Flag("regex-domain-filter", "Limit possible domains and target zones by a Regex filter; Overrides domain-filter (optional)").Default("").StringVar(&cfg.RegexDomainFilter)
|
||||
app.Flag("regex-domain-exclusion", "Regex filter that excludes domains and target zones matched by regex-domain-filter (optional)").Default("").StringVar(&cfg.RegexDomainExclusion)
|
||||
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("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)
|
||||
|
@ -44,6 +44,8 @@ var (
|
||||
GoogleBatchChangeInterval: time.Second,
|
||||
DomainFilter: []string{""},
|
||||
ExcludeDomains: []string{""},
|
||||
RegexDomainFilter: "",
|
||||
RegexDomainExclusion: "",
|
||||
ZoneIDFilter: []string{""},
|
||||
AlibabaCloudConfigFile: "/etc/kubernetes/alibaba-cloud.json",
|
||||
AWSZoneType: "",
|
||||
@ -117,6 +119,8 @@ var (
|
||||
GoogleBatchChangeInterval: time.Second * 2,
|
||||
DomainFilter: []string{"example.org", "company.com"},
|
||||
ExcludeDomains: []string{"xapi.example.org", "xapi.company.com"},
|
||||
RegexDomainFilter: "(example\\.org|company\\.com)$",
|
||||
RegexDomainExclusion: "xapi\\.(example\\.org|company\\.com)$",
|
||||
ZoneIDFilter: []string{"/hostedzone/ZTST1", "/hostedzone/ZTST2"},
|
||||
AlibabaCloudConfigFile: "/etc/kubernetes/alibaba-cloud.json",
|
||||
AWSZoneType: "private",
|
||||
@ -247,6 +251,8 @@ func TestParseFlags(t *testing.T) {
|
||||
"--domain-filter=company.com",
|
||||
"--exclude-domains=xapi.example.org",
|
||||
"--exclude-domains=xapi.company.com",
|
||||
"--regex-domain-filter=(example\\.org|company\\.com)$",
|
||||
"--regex-domain-exclusion=xapi\\.(example\\.org|company\\.com)$",
|
||||
"--zone-id-filter=/hostedzone/ZTST1",
|
||||
"--zone-id-filter=/hostedzone/ZTST2",
|
||||
"--aws-zone-type=private",
|
||||
@ -325,6 +331,8 @@ func TestParseFlags(t *testing.T) {
|
||||
"EXTERNAL_DNS_OVH_ENDPOINT": "ovh-ca",
|
||||
"EXTERNAL_DNS_DOMAIN_FILTER": "example.org\ncompany.com",
|
||||
"EXTERNAL_DNS_EXCLUDE_DOMAINS": "xapi.example.org\nxapi.company.com",
|
||||
"EXTERNAL_DNS_REGEX_DOMAIN_FILTER": "(example\\.org|company\\.com)$",
|
||||
"EXTERNAL_DNS_REGEX_DOMAIN_EXCLUSION": "xapi\\.(example\\.org|company\\.com)$",
|
||||
"EXTERNAL_DNS_PDNS_SERVER": "http://ns.example.com:8081",
|
||||
"EXTERNAL_DNS_PDNS_API_KEY": "some-secret-key",
|
||||
"EXTERNAL_DNS_PDNS_TLS_ENABLED": "1",
|
||||
|
Loading…
Reference in New Issue
Block a user