Skip to content

Commit

Permalink
Support A record for multile IPs for a headless services.
Browse files Browse the repository at this point in the history
Non statefulset pods associating to a headless service have different
IPs, but have a same hostname. In this case, external-dns registered
only one A record due to attempting to register multiple A records for
a same hostname for each IP.
This patch now registers one A record having multiple IPs.
  • Loading branch information
toshipp committed Jul 27, 2018
1 parent aa8d04f commit 44f319e
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 30 deletions.
27 changes: 17 additions & 10 deletions source/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ func (sc *serviceSource) extractHeadlessEndpoints(svc *v1.Service, hostname stri
return endpoints
}

targetsByHeadlessDomain := make(map[string][]string)
for _, v := range pods.Items {
headlessDomain := hostname
if v.Spec.Hostname != "" {
Expand All @@ -166,30 +167,36 @@ func (sc *serviceSource) extractHeadlessEndpoints(svc *v1.Service, hostname stri
log.Debugf("Generating matching endpoint %s with HostIP %s", headlessDomain, v.Status.HostIP)
// To reduce traffice on the DNS API only add record for running Pods. Good Idea?
if v.Status.Phase == v1.PodRunning {
if ttl.IsConfigured() {
endpoints = append(endpoints, endpoint.NewEndpointWithTTL(headlessDomain, endpoint.RecordTypeA, ttl, v.Status.HostIP))
} else {
endpoints = append(endpoints, endpoint.NewEndpoint(headlessDomain, endpoint.RecordTypeA, v.Status.HostIP))
}
targetsByHeadlessDomain[headlessDomain] = append(targetsByHeadlessDomain[headlessDomain], v.Status.HostIP)
} else {
log.Debugf("Pod %s is not in running phase", v.Spec.Hostname)
}
} else {
log.Debugf("Generating matching endpoint %s with PodIP %s", headlessDomain, v.Status.PodIP)
// To reduce traffice on the DNS API only add record for running Pods. Good Idea?
if v.Status.Phase == v1.PodRunning {
if ttl.IsConfigured() {
endpoints = append(endpoints, endpoint.NewEndpointWithTTL(headlessDomain, endpoint.RecordTypeA, ttl, v.Status.PodIP))
} else {
endpoints = append(endpoints, endpoint.NewEndpoint(headlessDomain, endpoint.RecordTypeA, v.Status.PodIP))
}
targetsByHeadlessDomain[headlessDomain] = append(targetsByHeadlessDomain[headlessDomain], v.Status.PodIP)
} else {
log.Debugf("Pod %s is not in running phase", v.Spec.Hostname)
}
}

}

headlessDomains := []string{}
for headlessDomain := range targetsByHeadlessDomain {
headlessDomains = append(headlessDomains, headlessDomain)
}
sort.Strings(headlessDomains)
for _, headlessDomain := range headlessDomains {
targets := targetsByHeadlessDomain[headlessDomain]
if ttl.IsConfigured() {
endpoints = append(endpoints, endpoint.NewEndpointWithTTL(headlessDomain, endpoint.RecordTypeA, ttl, targets...))
} else {
endpoints = append(endpoints, endpoint.NewEndpoint(headlessDomain, endpoint.RecordTypeA, targets...))
}
}

return endpoints
}

Expand Down
38 changes: 18 additions & 20 deletions source/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1235,7 +1235,7 @@ func TestHeadlessServices(t *testing.T) {
labels map[string]string
annotations map[string]string
clusterIP string
podIP string
podIPs []string
selector map[string]string
lbs []string
podnames []string
Expand All @@ -1257,7 +1257,7 @@ func TestHeadlessServices(t *testing.T) {
hostnameAnnotationKey: "service.example.org",
},
v1.ClusterIPNone,
"1.1.1.1",
[]string{"1.1.1.1", "1.1.1.2"},
map[string]string{
"component": "foo",
},
Expand All @@ -1267,7 +1267,7 @@ func TestHeadlessServices(t *testing.T) {
[]v1.PodPhase{v1.PodRunning, v1.PodRunning},
[]*endpoint.Endpoint{
{DNSName: "foo-0.service.example.org", Targets: endpoint.Targets{"1.1.1.1"}},
{DNSName: "foo-1.service.example.org", Targets: endpoint.Targets{"1.1.1.1"}},
{DNSName: "foo-1.service.example.org", Targets: endpoint.Targets{"1.1.1.2"}},
},
false,
},
Expand All @@ -1285,7 +1285,7 @@ func TestHeadlessServices(t *testing.T) {
ttlAnnotationKey: "1",
},
v1.ClusterIPNone,
"1.1.1.1",
[]string{"1.1.1.1", "1.1.1.2"},
map[string]string{
"component": "foo",
},
Expand All @@ -1295,7 +1295,7 @@ func TestHeadlessServices(t *testing.T) {
[]v1.PodPhase{v1.PodRunning, v1.PodRunning},
[]*endpoint.Endpoint{
{DNSName: "foo-0.service.example.org", Targets: endpoint.Targets{"1.1.1.1"}, RecordTTL: endpoint.TTL(1)},
{DNSName: "foo-1.service.example.org", Targets: endpoint.Targets{"1.1.1.1"}, RecordTTL: endpoint.TTL(1)},
{DNSName: "foo-1.service.example.org", Targets: endpoint.Targets{"1.1.1.2"}, RecordTTL: endpoint.TTL(1)},
},
false,
},
Expand All @@ -1312,7 +1312,7 @@ func TestHeadlessServices(t *testing.T) {
hostnameAnnotationKey: "service.example.org",
},
v1.ClusterIPNone,
"1.1.1.1",
[]string{"1.1.1.1", "1.1.1.2"},
map[string]string{
"component": "foo",
},
Expand All @@ -1338,7 +1338,7 @@ func TestHeadlessServices(t *testing.T) {
hostnameAnnotationKey: "service.example.org",
},
v1.ClusterIPNone,
"1.1.1.1",
[]string{"1.1.1.1", "1.1.1.2"},
map[string]string{
"component": "foo",
},
Expand All @@ -1347,8 +1347,7 @@ func TestHeadlessServices(t *testing.T) {
[]string{"", ""},
[]v1.PodPhase{v1.PodRunning, v1.PodRunning},
[]*endpoint.Endpoint{
{DNSName: "service.example.org", Targets: endpoint.Targets{"1.1.1.1"}},
{DNSName: "service.example.org", Targets: endpoint.Targets{"1.1.1.1"}},
{DNSName: "service.example.org", Targets: endpoint.Targets{"1.1.1.1", "1.1.1.2"}},
},
false,
},
Expand Down Expand Up @@ -1387,7 +1386,7 @@ func TestHeadlessServices(t *testing.T) {
Annotations: tc.annotations,
},
Status: v1.PodStatus{
PodIP: tc.podIP,
PodIP: tc.podIPs[i],
Phase: tc.phases[i],
},
}
Expand Down Expand Up @@ -1435,7 +1434,7 @@ func TestHeadlessServicesHostIP(t *testing.T) {
labels map[string]string
annotations map[string]string
clusterIP string
hostIP string
hostIPs []string
selector map[string]string
lbs []string
podnames []string
Expand All @@ -1457,7 +1456,7 @@ func TestHeadlessServicesHostIP(t *testing.T) {
hostnameAnnotationKey: "service.example.org",
},
v1.ClusterIPNone,
"1.1.1.1",
[]string{"1.1.1.1", "1.1.1.2"},
map[string]string{
"component": "foo",
},
Expand All @@ -1467,7 +1466,7 @@ func TestHeadlessServicesHostIP(t *testing.T) {
[]v1.PodPhase{v1.PodRunning, v1.PodRunning},
[]*endpoint.Endpoint{
{DNSName: "foo-0.service.example.org", Targets: endpoint.Targets{"1.1.1.1"}},
{DNSName: "foo-1.service.example.org", Targets: endpoint.Targets{"1.1.1.1"}},
{DNSName: "foo-1.service.example.org", Targets: endpoint.Targets{"1.1.1.2"}},
},
false,
},
Expand All @@ -1485,7 +1484,7 @@ func TestHeadlessServicesHostIP(t *testing.T) {
ttlAnnotationKey: "1",
},
v1.ClusterIPNone,
"1.1.1.1",
[]string{"1.1.1.1", "1.1.1.2"},
map[string]string{
"component": "foo",
},
Expand All @@ -1495,7 +1494,7 @@ func TestHeadlessServicesHostIP(t *testing.T) {
[]v1.PodPhase{v1.PodRunning, v1.PodRunning},
[]*endpoint.Endpoint{
{DNSName: "foo-0.service.example.org", Targets: endpoint.Targets{"1.1.1.1"}, RecordTTL: endpoint.TTL(1)},
{DNSName: "foo-1.service.example.org", Targets: endpoint.Targets{"1.1.1.1"}, RecordTTL: endpoint.TTL(1)},
{DNSName: "foo-1.service.example.org", Targets: endpoint.Targets{"1.1.1.2"}, RecordTTL: endpoint.TTL(1)},
},
false,
},
Expand All @@ -1512,7 +1511,7 @@ func TestHeadlessServicesHostIP(t *testing.T) {
hostnameAnnotationKey: "service.example.org",
},
v1.ClusterIPNone,
"1.1.1.1",
[]string{"1.1.1.1", "1.1.1.2"},
map[string]string{
"component": "foo",
},
Expand All @@ -1538,7 +1537,7 @@ func TestHeadlessServicesHostIP(t *testing.T) {
hostnameAnnotationKey: "service.example.org",
},
v1.ClusterIPNone,
"1.1.1.1",
[]string{"1.1.1.1", "1.1.1.2"},
map[string]string{
"component": "foo",
},
Expand All @@ -1547,8 +1546,7 @@ func TestHeadlessServicesHostIP(t *testing.T) {
[]string{"", ""},
[]v1.PodPhase{v1.PodRunning, v1.PodRunning},
[]*endpoint.Endpoint{
{DNSName: "service.example.org", Targets: endpoint.Targets{"1.1.1.1"}},
{DNSName: "service.example.org", Targets: endpoint.Targets{"1.1.1.1"}},
{DNSName: "service.example.org", Targets: endpoint.Targets{"1.1.1.1", "1.1.1.2"}},
},
false,
},
Expand Down Expand Up @@ -1587,7 +1585,7 @@ func TestHeadlessServicesHostIP(t *testing.T) {
Annotations: tc.annotations,
},
Status: v1.PodStatus{
HostIP: tc.hostIP,
HostIP: tc.hostIPs[i],
Phase: tc.phases[i],
},
}
Expand Down

0 comments on commit 44f319e

Please sign in to comment.