mirror of
https://github.com/kubernetes-sigs/external-dns.git
synced 2025-08-06 01:26:59 +02:00
Enhance compatibility and process molecule Services (#166)
* feat(service): enhance compatibility, process molecule services * ref(service): simplify label detection for molecule servics
This commit is contained in:
parent
285cb4cb35
commit
096c68be79
@ -40,7 +40,7 @@ type Config struct {
|
||||
Provider string
|
||||
GoogleProject string
|
||||
Policy string
|
||||
Compatibility bool
|
||||
Compatibility string
|
||||
MetricsAddress string
|
||||
Interval time.Duration
|
||||
Once bool
|
||||
@ -71,7 +71,7 @@ func (cfg *Config) ParseFlags(args []string) error {
|
||||
flags.StringVar(&cfg.Provider, "provider", "", "the DNS provider to materialize the records in: <aws|google>")
|
||||
flags.StringVar(&cfg.GoogleProject, "google-project", "", "gcloud project to target")
|
||||
flags.StringVar(&cfg.Policy, "policy", "sync", "the policy to use: <sync|upsert-only>")
|
||||
flags.BoolVar(&cfg.Compatibility, "compatibility", false, "enable to process annotation semantics from legacy implementations")
|
||||
flags.StringVar(&cfg.Compatibility, "compatibility", "", "enable to process annotation semantics from legacy implementations: <mate|molecule>")
|
||||
flags.StringVar(&cfg.MetricsAddress, "metrics-address", defaultMetricsAddress, "address to expose metrics on")
|
||||
flags.StringVar(&cfg.LogFormat, "log-format", defaultLogFormat, "log format output: <text|json>")
|
||||
flags.DurationVar(&cfg.Interval, "interval", time.Minute, "interval between synchronizations")
|
||||
|
@ -42,7 +42,7 @@ func TestParseFlags(t *testing.T) {
|
||||
Provider: "",
|
||||
GoogleProject: "",
|
||||
Policy: "sync",
|
||||
Compatibility: false,
|
||||
Compatibility: "",
|
||||
MetricsAddress: defaultMetricsAddress,
|
||||
Interval: time.Minute,
|
||||
Once: false,
|
||||
@ -69,7 +69,7 @@ func TestParseFlags(t *testing.T) {
|
||||
Provider: "",
|
||||
GoogleProject: "",
|
||||
Policy: "sync",
|
||||
Compatibility: false,
|
||||
Compatibility: "",
|
||||
MetricsAddress: defaultMetricsAddress,
|
||||
Interval: time.Minute,
|
||||
Once: false,
|
||||
@ -96,7 +96,7 @@ func TestParseFlags(t *testing.T) {
|
||||
Provider: "",
|
||||
GoogleProject: "",
|
||||
Policy: "sync",
|
||||
Compatibility: false,
|
||||
Compatibility: "",
|
||||
MetricsAddress: defaultMetricsAddress,
|
||||
Interval: time.Minute,
|
||||
Once: false,
|
||||
@ -128,7 +128,7 @@ func TestParseFlags(t *testing.T) {
|
||||
Provider: "",
|
||||
GoogleProject: "",
|
||||
Policy: "sync",
|
||||
Compatibility: false,
|
||||
Compatibility: "",
|
||||
MetricsAddress: defaultMetricsAddress,
|
||||
Interval: time.Minute,
|
||||
Once: false,
|
||||
@ -154,7 +154,7 @@ func TestParseFlags(t *testing.T) {
|
||||
"--provider", "provider",
|
||||
"--google-project", "project",
|
||||
"--policy", "upsert-only",
|
||||
"--compatibility",
|
||||
"--compatibility=mate",
|
||||
"--metrics-address", "127.0.0.1:9099",
|
||||
"--interval", "10m",
|
||||
"--once",
|
||||
@ -175,7 +175,7 @@ func TestParseFlags(t *testing.T) {
|
||||
Provider: "provider",
|
||||
GoogleProject: "project",
|
||||
Policy: "upsert-only",
|
||||
Compatibility: true,
|
||||
Compatibility: "mate",
|
||||
MetricsAddress: "127.0.0.1:9099",
|
||||
Interval: 10 * time.Minute,
|
||||
Once: true,
|
||||
|
@ -23,13 +23,21 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
mateAnnotationKey = "zalando.org/dnsname"
|
||||
mateAnnotationKey = "zalando.org/dnsname"
|
||||
moleculeAnnotationKey = "domainName"
|
||||
)
|
||||
|
||||
// legacyEndpointsFromService tries to retrieve Endpoints from Services
|
||||
// annotated with legacy annotations.
|
||||
func legacyEndpointsFromService(svc *v1.Service) []*endpoint.Endpoint {
|
||||
return legacyEndpointsFromMateService(svc)
|
||||
func legacyEndpointsFromService(svc *v1.Service, compatibility string) []*endpoint.Endpoint {
|
||||
switch compatibility {
|
||||
case "mate":
|
||||
return legacyEndpointsFromMateService(svc)
|
||||
case "molecule":
|
||||
return legacyEndpointsFromMoleculeService(svc)
|
||||
}
|
||||
|
||||
return []*endpoint.Endpoint{}
|
||||
}
|
||||
|
||||
// legacyEndpointsFromMateService tries to retrieve Endpoints from Services
|
||||
@ -55,3 +63,32 @@ func legacyEndpointsFromMateService(svc *v1.Service) []*endpoint.Endpoint {
|
||||
|
||||
return endpoints
|
||||
}
|
||||
|
||||
// legacyEndpointsFromMoleculeService tries to retrieve Endpoints from Services
|
||||
// annotated with Molecule Software's annotation semantics.
|
||||
func legacyEndpointsFromMoleculeService(svc *v1.Service) []*endpoint.Endpoint {
|
||||
var endpoints []*endpoint.Endpoint
|
||||
|
||||
// Check that the Service opted-in to being processed.
|
||||
if svc.Labels["dns"] != "route53" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get the desired hostname of the service from the annotation.
|
||||
hostname, exists := svc.Annotations[moleculeAnnotationKey]
|
||||
if !exists {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Create a corresponding endpoint for each configured external entrypoint.
|
||||
for _, lb := range svc.Status.LoadBalancer.Ingress {
|
||||
if lb.IP != "" {
|
||||
endpoints = append(endpoints, endpoint.NewEndpoint(hostname, lb.IP, ""))
|
||||
}
|
||||
if lb.Hostname != "" {
|
||||
endpoints = append(endpoints, endpoint.NewEndpoint(hostname, lb.Hostname, ""))
|
||||
}
|
||||
}
|
||||
|
||||
return endpoints
|
||||
}
|
||||
|
@ -36,13 +36,13 @@ import (
|
||||
type serviceSource struct {
|
||||
client kubernetes.Interface
|
||||
namespace string
|
||||
// set to true to process Services with legacy annotations
|
||||
compatibility bool
|
||||
// process Services with legacy annotations
|
||||
compatibility string
|
||||
fqdntemplate *template.Template
|
||||
}
|
||||
|
||||
// NewServiceSource creates a new serviceSource with the given client and namespace scope.
|
||||
func NewServiceSource(client kubernetes.Interface, namespace, fqdntemplate string, compatibility bool) (Source, error) {
|
||||
func NewServiceSource(client kubernetes.Interface, namespace, fqdntemplate string, compatibility string) (Source, error) {
|
||||
var tmpl *template.Template
|
||||
var err error
|
||||
if fqdntemplate != "" {
|
||||
@ -81,8 +81,8 @@ func (sc *serviceSource) Endpoints() ([]*endpoint.Endpoint, error) {
|
||||
svcEndpoints := endpointsFromService(&svc)
|
||||
|
||||
// process legacy annotations if no endpoints were returned and compatibility mode is enabled.
|
||||
if len(svcEndpoints) == 0 && sc.compatibility {
|
||||
svcEndpoints = legacyEndpointsFromService(&svc)
|
||||
if len(svcEndpoints) == 0 && sc.compatibility != "" {
|
||||
svcEndpoints = legacyEndpointsFromService(&svc, sc.compatibility)
|
||||
}
|
||||
|
||||
// apply template if none of the above is found
|
||||
|
@ -55,7 +55,7 @@ func TestNewServiceSource(t *testing.T) {
|
||||
},
|
||||
} {
|
||||
t.Run(ti.title, func(t *testing.T) {
|
||||
_, err := NewServiceSource(fake.NewSimpleClientset(), "", ti.fqdntemplate, false)
|
||||
_, err := NewServiceSource(fake.NewSimpleClientset(), "", ti.fqdntemplate, "")
|
||||
if ti.expectError && err == nil {
|
||||
t.Error("invalid template should return err")
|
||||
}
|
||||
@ -73,8 +73,9 @@ func testServiceEndpoints(t *testing.T) {
|
||||
targetNamespace string
|
||||
svcNamespace string
|
||||
svcName string
|
||||
compatibility bool
|
||||
compatibility string
|
||||
fqdntemplate string
|
||||
labels map[string]string
|
||||
annotations map[string]string
|
||||
lbs []string
|
||||
expected []*endpoint.Endpoint
|
||||
@ -84,8 +85,9 @@ func testServiceEndpoints(t *testing.T) {
|
||||
"",
|
||||
"testing",
|
||||
"foo",
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
map[string]string{},
|
||||
map[string]string{},
|
||||
[]string{"1.2.3.4"},
|
||||
[]*endpoint.Endpoint{},
|
||||
@ -95,8 +97,9 @@ func testServiceEndpoints(t *testing.T) {
|
||||
"",
|
||||
"testing",
|
||||
"foo",
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
map[string]string{},
|
||||
map[string]string{
|
||||
hostnameAnnotationKey: "foo.example.org.",
|
||||
},
|
||||
@ -110,8 +113,9 @@ func testServiceEndpoints(t *testing.T) {
|
||||
"",
|
||||
"testing",
|
||||
"foo",
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
map[string]string{},
|
||||
map[string]string{
|
||||
hostnameAnnotationKey: "foo.example.org.",
|
||||
},
|
||||
@ -125,8 +129,9 @@ func testServiceEndpoints(t *testing.T) {
|
||||
"",
|
||||
"testing",
|
||||
"foo",
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
map[string]string{},
|
||||
map[string]string{
|
||||
hostnameAnnotationKey: "foo.example.org", // Trailing dot is omitted
|
||||
},
|
||||
@ -141,8 +146,9 @@ func testServiceEndpoints(t *testing.T) {
|
||||
"",
|
||||
"testing",
|
||||
"foo",
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
map[string]string{},
|
||||
map[string]string{
|
||||
controllerAnnotationKey: controllerAnnotationValue,
|
||||
hostnameAnnotationKey: "foo.example.org.",
|
||||
@ -157,8 +163,9 @@ func testServiceEndpoints(t *testing.T) {
|
||||
"",
|
||||
"testing",
|
||||
"foo",
|
||||
false,
|
||||
"",
|
||||
"{{.Name}}.ext-dns.test.com",
|
||||
map[string]string{},
|
||||
map[string]string{
|
||||
controllerAnnotationKey: "some-other-tool",
|
||||
hostnameAnnotationKey: "foo.example.org.",
|
||||
@ -171,8 +178,9 @@ func testServiceEndpoints(t *testing.T) {
|
||||
"testing",
|
||||
"testing",
|
||||
"foo",
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
map[string]string{},
|
||||
map[string]string{
|
||||
hostnameAnnotationKey: "foo.example.org.",
|
||||
},
|
||||
@ -186,8 +194,9 @@ func testServiceEndpoints(t *testing.T) {
|
||||
"testing",
|
||||
"other-testing",
|
||||
"foo",
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
map[string]string{},
|
||||
map[string]string{
|
||||
hostnameAnnotationKey: "foo.example.org.",
|
||||
},
|
||||
@ -199,8 +208,9 @@ func testServiceEndpoints(t *testing.T) {
|
||||
"",
|
||||
"other-testing",
|
||||
"foo",
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
map[string]string{},
|
||||
map[string]string{
|
||||
hostnameAnnotationKey: "foo.example.org.",
|
||||
},
|
||||
@ -214,8 +224,9 @@ func testServiceEndpoints(t *testing.T) {
|
||||
"",
|
||||
"testing",
|
||||
"foo",
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
map[string]string{},
|
||||
map[string]string{
|
||||
hostnameAnnotationKey: "foo.example.org.",
|
||||
},
|
||||
@ -227,8 +238,9 @@ func testServiceEndpoints(t *testing.T) {
|
||||
"",
|
||||
"testing",
|
||||
"foo",
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
map[string]string{},
|
||||
map[string]string{
|
||||
hostnameAnnotationKey: "foo.example.org.",
|
||||
},
|
||||
@ -243,8 +255,9 @@ func testServiceEndpoints(t *testing.T) {
|
||||
"",
|
||||
"testing",
|
||||
"foo",
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
map[string]string{},
|
||||
map[string]string{
|
||||
"zalando.org/dnsname": "foo.example.org.",
|
||||
},
|
||||
@ -256,8 +269,9 @@ func testServiceEndpoints(t *testing.T) {
|
||||
"",
|
||||
"testing",
|
||||
"foo",
|
||||
true,
|
||||
"mate",
|
||||
"",
|
||||
map[string]string{},
|
||||
map[string]string{
|
||||
"zalando.org/dnsname": "foo.example.org.",
|
||||
},
|
||||
@ -266,14 +280,33 @@ func testServiceEndpoints(t *testing.T) {
|
||||
{DNSName: "foo.example.org", Target: "1.2.3.4"},
|
||||
},
|
||||
},
|
||||
{
|
||||
"services annotated with legacy molecule annotations return an endpoint in compatibility mode",
|
||||
"",
|
||||
"testing",
|
||||
"foo",
|
||||
"molecule",
|
||||
"",
|
||||
map[string]string{
|
||||
"dns": "route53",
|
||||
},
|
||||
map[string]string{
|
||||
"domainName": "foo.example.org.",
|
||||
},
|
||||
[]string{"1.2.3.4"},
|
||||
[]*endpoint.Endpoint{
|
||||
{DNSName: "foo.example.org", Target: "1.2.3.4"},
|
||||
},
|
||||
},
|
||||
{
|
||||
"not annotated services with set fqdntemplate return an endpoint with target IP",
|
||||
"",
|
||||
"testing",
|
||||
"foo",
|
||||
false,
|
||||
"",
|
||||
"{{.Name}}.bar.example.com",
|
||||
map[string]string{},
|
||||
map[string]string{},
|
||||
[]string{"1.2.3.4", "elb.com"},
|
||||
[]*endpoint.Endpoint{
|
||||
{DNSName: "foo.bar.example.com", Target: "1.2.3.4"},
|
||||
@ -285,9 +318,10 @@ func testServiceEndpoints(t *testing.T) {
|
||||
"",
|
||||
"testing",
|
||||
"foo",
|
||||
false,
|
||||
"",
|
||||
"{{.Calibre}}.bar.example.com",
|
||||
map[string]string{},
|
||||
map[string]string{},
|
||||
[]string{"1.2.3.4"},
|
||||
[]*endpoint.Endpoint{},
|
||||
},
|
||||
@ -296,8 +330,9 @@ func testServiceEndpoints(t *testing.T) {
|
||||
"",
|
||||
"testing",
|
||||
"foo",
|
||||
true,
|
||||
"mate",
|
||||
"{{.Name}}.bar.example.com",
|
||||
map[string]string{},
|
||||
map[string]string{
|
||||
"zalando.org/dnsname": "mate.example.org.",
|
||||
},
|
||||
@ -325,6 +360,7 @@ func testServiceEndpoints(t *testing.T) {
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: tc.svcNamespace,
|
||||
Name: tc.svcName,
|
||||
Labels: tc.labels,
|
||||
Annotations: tc.annotations,
|
||||
},
|
||||
Status: v1.ServiceStatus{
|
||||
@ -379,7 +415,7 @@ func BenchmarkServiceEndpoints(b *testing.B) {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
client, _ := NewServiceSource(kubernetes, v1.NamespaceAll, "", false)
|
||||
client, _ := NewServiceSource(kubernetes, v1.NamespaceAll, "", "")
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := client.Endpoints()
|
||||
|
Loading…
Reference in New Issue
Block a user