Skip to content

Commit

Permalink
Merge pull request #745 from anandkumarpatel/feature/ignore-annotations
Browse files Browse the repository at this point in the history
allow hostname annotations to be ignored
  • Loading branch information
k8s-ci-robot authored Feb 18, 2019
2 parents e1da3a6 + ed71ab6 commit d0dc99f
Show file tree
Hide file tree
Showing 12 changed files with 557 additions and 183 deletions.
1 change: 1 addition & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ func main() {
AnnotationFilter: cfg.AnnotationFilter,
FQDNTemplate: cfg.FQDNTemplate,
CombineFQDNAndAnnotation: cfg.CombineFQDNAndAnnotation,
IgnoreHostnameAnnotation: cfg.IgnoreHostnameAnnotation,
Compatibility: cfg.Compatibility,
PublishInternal: cfg.PublishInternal,
PublishHostIP: cfg.PublishHostIP,
Expand Down
3 changes: 3 additions & 0 deletions pkg/apis/externaldns/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ type Config struct {
AnnotationFilter string
FQDNTemplate string
CombineFQDNAndAnnotation bool
IgnoreHostnameAnnotation bool
Compatibility string
PublishInternal bool
PublishHostIP bool
Expand Down Expand Up @@ -121,6 +122,7 @@ var defaultConfig = &Config{
AnnotationFilter: "",
FQDNTemplate: "",
CombineFQDNAndAnnotation: false,
IgnoreHostnameAnnotation: false,
Compatibility: "",
PublishInternal: false,
PublishHostIP: false,
Expand Down Expand Up @@ -231,6 +233,7 @@ func (cfg *Config) ParseFlags(args []string) error {
app.Flag("annotation-filter", "Filter sources managed by external-dns via annotation using label selector semantics (default: all sources)").Default(defaultConfig.AnnotationFilter).StringVar(&cfg.AnnotationFilter)
app.Flag("fqdn-template", "A templated string that's used to generate DNS names from sources that don't define a hostname themselves, or to add a hostname suffix when paired with the fake source (optional). Accepts comma separated list for multiple global FQDN.").Default(defaultConfig.FQDNTemplate).StringVar(&cfg.FQDNTemplate)
app.Flag("combine-fqdn-annotation", "Combine FQDN template and Annotations instead of overwriting").BoolVar(&cfg.CombineFQDNAndAnnotation)
app.Flag("ignore-hostname-annotation", "Ignore hostname annotation when generating DNS names, valid only when using fqdn-template is set (optional, default: false)").BoolVar(&cfg.IgnoreHostnameAnnotation)
app.Flag("compatibility", "Process annotation semantics from legacy implementations (optional, options: mate, molecule)").Default(defaultConfig.Compatibility).EnumVar(&cfg.Compatibility, "", "mate", "molecule")
app.Flag("publish-internal-services", "Allow external-dns to publish DNS records for ClusterIP services (optional)").BoolVar(&cfg.PublishInternal)
app.Flag("publish-host-ip", "Allow external-dns to publish host-ip for headless services (optional)").BoolVar(&cfg.PublishHostIP)
Expand Down
113 changes: 58 additions & 55 deletions pkg/apis/externaldns/types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,61 +83,62 @@ var (
}

overriddenConfig = &Config{
Master: "http://127.0.0.1:8080",
KubeConfig: "/some/path",
RequestTimeout: time.Second * 77,
IstioIngressGateway: "istio-other/istio-otheringressgateway",
Sources: []string{"service", "ingress", "connector"},
Namespace: "namespace",
FQDNTemplate: "{{.Name}}.service.example.com",
Compatibility: "mate",
Provider: "google",
GoogleProject: "project",
DomainFilter: []string{"example.org", "company.com"},
ZoneIDFilter: []string{"/hostedzone/ZTST1", "/hostedzone/ZTST2"},
AlibabaCloudConfigFile: "/etc/kubernetes/alibaba-cloud.json",
AWSZoneType: "private",
AWSZoneTagFilter: []string{"tag=foo"},
AWSAssumeRole: "some-other-role",
AWSBatchChangeSize: 100,
AWSBatchChangeInterval: time.Second * 2,
AWSEvaluateTargetHealth: false,
AWSAPIRetries: 13,
AzureConfigFile: "azure.json",
AzureResourceGroup: "arg",
CloudflareProxied: true,
CloudflareZonesPerPage: 20,
InfobloxGridHost: "127.0.0.1",
InfobloxWapiPort: 8443,
InfobloxWapiUsername: "infoblox",
InfobloxWapiPassword: "infoblox",
InfobloxWapiVersion: "2.6.1",
InfobloxSSLVerify: false,
OCIConfigFile: "oci.yaml",
InMemoryZones: []string{"example.org", "company.com"},
PDNSServer: "http://ns.example.com:8081",
PDNSAPIKey: "some-secret-key",
PDNSTLSEnabled: true,
TLSCA: "/path/to/ca.crt",
TLSClientCert: "/path/to/cert.pem",
TLSClientCertKey: "/path/to/key.pem",
Policy: "upsert-only",
Registry: "noop",
TXTOwnerID: "owner-1",
TXTPrefix: "associated-txt-record",
TXTCacheInterval: 12 * time.Hour,
Interval: 10 * time.Minute,
Once: true,
DryRun: true,
LogFormat: "json",
MetricsAddress: "127.0.0.1:9099",
LogLevel: logrus.DebugLevel.String(),
ConnectorSourceServer: "localhost:8081",
ExoscaleEndpoint: "https://api.foo.ch/dns",
ExoscaleAPIKey: "1",
ExoscaleAPISecret: "2",
CRDSourceAPIVersion: "test.k8s.io/v1alpha1",
CRDSourceKind: "Endpoint",
Master: "http://127.0.0.1:8080",
KubeConfig: "/some/path",
RequestTimeout: time.Second * 77,
IstioIngressGateway: "istio-other/istio-otheringressgateway",
Sources: []string{"service", "ingress", "connector"},
Namespace: "namespace",
IgnoreHostnameAnnotation: true,
FQDNTemplate: "{{.Name}}.service.example.com",
Compatibility: "mate",
Provider: "google",
GoogleProject: "project",
DomainFilter: []string{"example.org", "company.com"},
ZoneIDFilter: []string{"/hostedzone/ZTST1", "/hostedzone/ZTST2"},
AlibabaCloudConfigFile: "/etc/kubernetes/alibaba-cloud.json",
AWSZoneType: "private",
AWSZoneTagFilter: []string{"tag=foo"},
AWSAssumeRole: "some-other-role",
AWSBatchChangeSize: 100,
AWSBatchChangeInterval: time.Second * 2,
AWSEvaluateTargetHealth: false,
AWSAPIRetries: 13,
AzureConfigFile: "azure.json",
AzureResourceGroup: "arg",
CloudflareProxied: true,
CloudflareZonesPerPage: 20,
InfobloxGridHost: "127.0.0.1",
InfobloxWapiPort: 8443,
InfobloxWapiUsername: "infoblox",
InfobloxWapiPassword: "infoblox",
InfobloxWapiVersion: "2.6.1",
InfobloxSSLVerify: false,
OCIConfigFile: "oci.yaml",
InMemoryZones: []string{"example.org", "company.com"},
PDNSServer: "http://ns.example.com:8081",
PDNSAPIKey: "some-secret-key",
PDNSTLSEnabled: true,
TLSCA: "/path/to/ca.crt",
TLSClientCert: "/path/to/cert.pem",
TLSClientCertKey: "/path/to/key.pem",
Policy: "upsert-only",
Registry: "noop",
TXTOwnerID: "owner-1",
TXTPrefix: "associated-txt-record",
TXTCacheInterval: 12 * time.Hour,
Interval: 10 * time.Minute,
Once: true,
DryRun: true,
LogFormat: "json",
MetricsAddress: "127.0.0.1:9099",
LogLevel: logrus.DebugLevel.String(),
ConnectorSourceServer: "localhost:8081",
ExoscaleEndpoint: "https://api.foo.ch/dns",
ExoscaleAPIKey: "1",
ExoscaleAPISecret: "2",
CRDSourceAPIVersion: "test.k8s.io/v1alpha1",
CRDSourceKind: "Endpoint",
}
)

Expand Down Expand Up @@ -169,6 +170,7 @@ func TestParseFlags(t *testing.T) {
"--source=connector",
"--namespace=namespace",
"--fqdn-template={{.Name}}.service.example.com",
"--ignore-hostname-annotation",
"--compatibility=mate",
"--provider=google",
"--google-project=project",
Expand Down Expand Up @@ -234,6 +236,7 @@ func TestParseFlags(t *testing.T) {
"EXTERNAL_DNS_SOURCE": "service\ningress\nconnector",
"EXTERNAL_DNS_NAMESPACE": "namespace",
"EXTERNAL_DNS_FQDN_TEMPLATE": "{{.Name}}.service.example.com",
"EXTERNAL_DNS_IGNORE_HOSTNAME_ANNOTATION": "1",
"EXTERNAL_DNS_COMPATIBILITY": "mate",
"EXTERNAL_DNS_PROVIDER": "google",
"EXTERNAL_DNS_GOOGLE_PROJECT": "project",
Expand Down
4 changes: 4 additions & 0 deletions pkg/apis/externaldns/validation/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,9 @@ func ValidateConfig(cfg *externaldns.Config) error {
return errors.New("TTL specified for Dyn is negative")
}
}

if cfg.IgnoreHostnameAnnotation && cfg.FQDNTemplate == "" {
return errors.New("FQDN Template must be set if ignoring annotations")
}
return nil
}
8 changes: 8 additions & 0 deletions pkg/apis/externaldns/validation/validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,11 @@ func TestValidateGoodDynConfig(t *testing.T) {
assert.Nil(t, err, "Configuration should be valid, got this error instead", err)
}
}

func TestValidateBadIgnoreHostnameAnnotationsConfig(t *testing.T) {
cfg := externaldns.NewConfig()
cfg.IgnoreHostnameAnnotation = true
cfg.FQDNTemplate = ""

assert.Error(t, ValidateConfig(cfg))
}
44 changes: 25 additions & 19 deletions source/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,15 @@ import (
// The gateway implementation uses the spec.servers.hosts values for the hostnames.
// Use targetAnnotationKey to explicitly set Endpoint.
type gatewaySource struct {
kubeClient kubernetes.Interface
istioClient istiomodel.ConfigStore
istioNamespace string
istioIngressGatewayName string
namespace string
annotationFilter string
fqdnTemplate *template.Template
combineFQDNAnnotation bool
kubeClient kubernetes.Interface
istioClient istiomodel.ConfigStore
istioNamespace string
istioIngressGatewayName string
namespace string
annotationFilter string
fqdnTemplate *template.Template
combineFQDNAnnotation bool
ignoreHostnameAnnotation bool
}

// NewIstioGatewaySource creates a new gatewaySource with the given config.
Expand All @@ -57,6 +58,7 @@ func NewIstioGatewaySource(
annotationFilter string,
fqdnTemplate string,
combineFqdnAnnotation bool,
ignoreHostnameAnnotation bool,
) (Source, error) {
var (
tmpl *template.Template
Expand All @@ -77,14 +79,15 @@ func NewIstioGatewaySource(
}

return &gatewaySource{
kubeClient: kubeClient,
istioClient: istioClient,
istioNamespace: istioNamespace,
istioIngressGatewayName: istioIngressGatewayName,
namespace: namespace,
annotationFilter: annotationFilter,
fqdnTemplate: tmpl,
combineFQDNAnnotation: combineFqdnAnnotation,
kubeClient: kubeClient,
istioClient: istioClient,
istioNamespace: istioNamespace,
istioIngressGatewayName: istioIngressGatewayName,
namespace: namespace,
annotationFilter: annotationFilter,
fqdnTemplate: tmpl,
combineFQDNAnnotation: combineFqdnAnnotation,
ignoreHostnameAnnotation: ignoreHostnameAnnotation,
}, nil
}

Expand Down Expand Up @@ -269,9 +272,12 @@ func (sc *gatewaySource) endpointsFromGatewayConfig(config istiomodel.Config) ([
}
}

hostnameList := getHostnamesFromAnnotations(config.Annotations)
for _, hostname := range hostnameList {
endpoints = append(endpoints, endpointsForHostname(hostname, targets, ttl, providerSpecific)...)
// Skip endpoints if we do not want entries from annotations
if !sc.ignoreHostnameAnnotation {
hostnameList := getHostnamesFromAnnotations(config.Annotations)
for _, hostname := range hostnameList {
endpoints = append(endpoints, endpointsForHostname(hostname, targets, ttl, providerSpecific)...)
}
}

return endpoints, nil
Expand Down
50 changes: 50 additions & 0 deletions source/gateway_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ func (suite *GatewaySuite) SetupTest() {
"",
"{{.Name}}",
false,
false,
)
suite.NoError(err, "should initialize gateway source")

Expand Down Expand Up @@ -141,6 +142,7 @@ func TestNewIstioGatewaySource(t *testing.T) {
ti.annotationFilter,
ti.fqdnTemplate,
ti.combineFQDNAndAnnotation,
false,
)
if ti.expectError {
assert.Error(t, err)
Expand Down Expand Up @@ -273,6 +275,7 @@ func testGatewayEndpoints(t *testing.T) {
expectError bool
fqdnTemplate string
combineFQDNAndAnnotation bool
ignoreHostnameAnnotation bool
}{
{
title: "no gateway",
Expand Down Expand Up @@ -913,6 +916,51 @@ func testGatewayEndpoints(t *testing.T) {
expected: []*endpoint.Endpoint{},
fqdnTemplate: "{{.Name}}.ext-dns.test.com",
},
{
title: "ignore hostname annotations",
ignoreHostnameAnnotation: true,
targetNamespace: "",
ingressGateway: fakeIngressGateway{
ips: []string{"8.8.8.8"},
hostnames: []string{"lb.com"},
},
configItems: []fakeGatewayConfig{
{
name: "fake1",
namespace: namespace,
annotations: map[string]string{
hostnameAnnotationKey: "ignore.me",
},
dnsnames: [][]string{{"example.org"}},
},
{
name: "fake2",
namespace: namespace,
annotations: map[string]string{
hostnameAnnotationKey: "ignore.me.too",
},
dnsnames: [][]string{{"new.org"}},
},
},
expected: []*endpoint.Endpoint{
{
DNSName: "example.org",
Targets: endpoint.Targets{"8.8.8.8"},
},
{
DNSName: "example.org",
Targets: endpoint.Targets{"lb.com"},
},
{
DNSName: "new.org",
Targets: endpoint.Targets{"8.8.8.8"},
},
{
DNSName: "new.org",
Targets: endpoint.Targets{"lb.com"},
},
},
},
} {
t.Run(ti.title, func(t *testing.T) {
configs := make([]istiomodel.Config, 0)
Expand All @@ -939,6 +987,7 @@ func testGatewayEndpoints(t *testing.T) {
ti.annotationFilter,
ti.fqdnTemplate,
ti.combineFQDNAndAnnotation,
ti.ignoreHostnameAnnotation,
)
require.NoError(t, err)

Expand Down Expand Up @@ -972,6 +1021,7 @@ func newTestGatewaySource(ingress *v1.Service) (*gatewaySource, error) {
"",
"{{.Name}}",
false,
false,
)
if err != nil {
return nil, err
Expand Down
Loading

0 comments on commit d0dc99f

Please sign in to comment.