Commit 5c10eba3 authored by Chris O'Haver's avatar Chris O'Haver Committed by John Belamaric

handle clusterIP endpoint queries (#730)

parent 930c54ef
...@@ -366,6 +366,7 @@ func (k *Kubernetes) Records(r recordRequest) ([]msg.Service, error) { ...@@ -366,6 +366,7 @@ func (k *Kubernetes) Records(r recordRequest) ([]msg.Service, error) {
} }
records := k.getRecordsForK8sItems(services, pods, r) records := k.getRecordsForK8sItems(services, pods, r)
return records, nil return records, nil
} }
...@@ -386,8 +387,8 @@ func (k *Kubernetes) getRecordsForK8sItems(services []service, pods []pod, r rec ...@@ -386,8 +387,8 @@ func (k *Kubernetes) getRecordsForK8sItems(services []service, pods []pod, r rec
zonePath := msg.Path(r.zone, "coredns") zonePath := msg.Path(r.zone, "coredns")
for _, svc := range services { for _, svc := range services {
if svc.addr == api.ClusterIPNone { if svc.addr == api.ClusterIPNone || len(svc.endpoints) > 0 {
// This is a headless service, create records for each endpoint // This is a headless service or endpoints are present, create records for each endpoint
for _, ep := range svc.endpoints { for _, ep := range svc.endpoints {
s := msg.Service{ s := msg.Service{
Host: ep.addr.IP, Host: ep.addr.IP,
...@@ -522,47 +523,52 @@ func (k *Kubernetes) findServices(r recordRequest) ([]service, error) { ...@@ -522,47 +523,52 @@ func (k *Kubernetes) findServices(r recordRequest) ([]service, error) {
continue continue
} }
s := service{name: svc.Name, namespace: svc.Namespace} s := service{name: svc.Name, namespace: svc.Namespace}
// External Service
if svc.Spec.ExternalName != "" { // Endpoint query or headless service
s.addr = svc.Spec.ExternalName if svc.Spec.ClusterIP == api.ClusterIPNone || r.endpoint != "" {
resultItems = append(resultItems, s)
continue
}
// ClusterIP service
if svc.Spec.ClusterIP != api.ClusterIPNone {
s.addr = svc.Spec.ClusterIP s.addr = svc.Spec.ClusterIP
for _, p := range svc.Spec.Ports { endpointsList := k.APIConn.EndpointsList()
if !(symbolMatches(r.port, strings.ToLower(p.Name), portWildcard) && symbolMatches(r.protocol, strings.ToLower(string(p.Protocol)), protocolWildcard)) { for _, ep := range endpointsList.Items {
if ep.ObjectMeta.Name != svc.Name || ep.ObjectMeta.Namespace != svc.Namespace {
continue continue
} }
s.ports = append(s.ports, p) for _, eps := range ep.Subsets {
for _, addr := range eps.Addresses {
for _, p := range eps.Ports {
ephostname := endpointHostname(addr)
if r.endpoint != "" && r.endpoint != ephostname {
continue
}
if !(symbolMatches(r.port, strings.ToLower(p.Name), portWildcard) && symbolMatches(r.protocol, strings.ToLower(string(p.Protocol)), protocolWildcard)) {
continue
}
s.endpoints = append(s.endpoints, endpoint{addr: addr, port: p})
}
}
}
}
if len(s.endpoints) > 0 {
resultItems = append(resultItems, s)
} }
continue
}
// External service
if svc.Spec.ExternalName != "" {
s.addr = svc.Spec.ExternalName
resultItems = append(resultItems, s) resultItems = append(resultItems, s)
continue continue
} }
// Headless service
s.addr = svc.Spec.ClusterIP
endpointsList := k.APIConn.EndpointsList()
for _, ep := range endpointsList.Items { // ClusterIP service
if ep.ObjectMeta.Name != svc.Name || ep.ObjectMeta.Namespace != svc.Namespace { s.addr = svc.Spec.ClusterIP
for _, p := range svc.Spec.Ports {
if !(symbolMatches(r.port, strings.ToLower(p.Name), portWildcard) && symbolMatches(r.protocol, strings.ToLower(string(p.Protocol)), protocolWildcard)) {
continue continue
} }
for _, eps := range ep.Subsets { s.ports = append(s.ports, p)
for _, addr := range eps.Addresses {
for _, p := range eps.Ports {
ephostname := endpointHostname(addr)
if r.endpoint != "" && r.endpoint != ephostname {
continue
}
if !(symbolMatches(r.port, strings.ToLower(p.Name), portWildcard) && symbolMatches(r.protocol, strings.ToLower(string(p.Protocol)), protocolWildcard)) {
continue
}
s.endpoints = append(s.endpoints, endpoint{addr: addr, port: p})
}
}
}
} }
resultItems = append(resultItems, s) resultItems = append(resultItems, s)
} }
return resultItems, nil return resultItems, nil
......
...@@ -348,7 +348,8 @@ func (APIConnServiceTest) EndpointsList() api.EndpointsList { ...@@ -348,7 +348,8 @@ func (APIConnServiceTest) EndpointsList() api.EndpointsList {
{ {
Addresses: []api.EndpointAddress{ Addresses: []api.EndpointAddress{
{ {
IP: "172.0.0.1", IP: "172.0.0.1",
Hostname: "ep1a",
}, },
}, },
Ports: []api.EndpointPort{ Ports: []api.EndpointPort{
...@@ -455,6 +456,7 @@ func TestServices(t *testing.T) { ...@@ -455,6 +456,7 @@ func TestServices(t *testing.T) {
// Cluster IP Services // Cluster IP Services
{qname: "svc1.testns.svc.interwebs.test.", qtype: dns.TypeA, answer: svcAns{host: "10.0.0.1", key: "/coredns/test/interwebs/svc/testns/svc1"}}, {qname: "svc1.testns.svc.interwebs.test.", qtype: dns.TypeA, answer: svcAns{host: "10.0.0.1", key: "/coredns/test/interwebs/svc/testns/svc1"}},
{qname: "_http._tcp.svc1.testns.svc.interwebs.test.", qtype: dns.TypeSRV, answer: svcAns{host: "10.0.0.1", key: "/coredns/test/interwebs/svc/testns/svc1"}}, {qname: "_http._tcp.svc1.testns.svc.interwebs.test.", qtype: dns.TypeSRV, answer: svcAns{host: "10.0.0.1", key: "/coredns/test/interwebs/svc/testns/svc1"}},
{qname: "ep1a.svc1.testns.svc.interwebs.test.", qtype: dns.TypeA, answer: svcAns{host: "172.0.0.1", key: "/coredns/test/interwebs/svc/testns/svc1/ep1a"}},
// External Services // External Services
{qname: "external.testns.svc.interwebs.test.", qtype: dns.TypeCNAME, answer: svcAns{host: "coredns.io", key: "/coredns/test/interwebs/svc/testns/external"}}, {qname: "external.testns.svc.interwebs.test.", qtype: dns.TypeCNAME, answer: svcAns{host: "coredns.io", key: "/coredns/test/interwebs/svc/testns/external"}},
......
...@@ -29,6 +29,16 @@ var dnsTestCases = []test.Case{ ...@@ -29,6 +29,16 @@ var dnsTestCases = []test.Case{
Rcode: dns.RcodeNameError, Rcode: dns.RcodeNameError,
Answer: []dns.RR{}, Answer: []dns.RR{},
}, },
{
Qname: "bogusendpoint.svc-1-a.test-1.svc.cluster.local.", Qtype: dns.TypeA,
Rcode: dns.RcodeNameError,
Answer: []dns.RR{},
},
{
Qname: "bogusendpoint.headless-svc.test-1.svc.cluster.local.", Qtype: dns.TypeA,
Rcode: dns.RcodeNameError,
Answer: []dns.RR{},
},
{ {
Qname: "svc-1-a.*.svc.cluster.local.", Qtype: dns.TypeA, Qname: "svc-1-a.*.svc.cluster.local.", Qtype: dns.TypeA,
Rcode: dns.RcodeSuccess, Rcode: dns.RcodeSuccess,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment