handle clusterIP endpoint queries (#730)

This commit is contained in:
Chris O'Haver 2017-06-14 10:29:41 -04:00 committed by John Belamaric
parent 930c54ef62
commit 5c10eba31c
3 changed files with 53 additions and 35 deletions

View file

@ -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
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) {
continue continue
} }
s := service{name: svc.Name, namespace: svc.Namespace} s := service{name: svc.Name, namespace: svc.Namespace}
// External Service
// Endpoint query or headless service
if svc.Spec.ClusterIP == api.ClusterIPNone || r.endpoint != "" {
s.addr = svc.Spec.ClusterIP
endpointsList := k.APIConn.EndpointsList()
for _, ep := range endpointsList.Items {
if ep.ObjectMeta.Name != svc.Name || ep.ObjectMeta.Namespace != svc.Namespace {
continue
}
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 != "" { if svc.Spec.ExternalName != "" {
s.addr = svc.Spec.ExternalName s.addr = svc.Spec.ExternalName
resultItems = append(resultItems, s) resultItems = append(resultItems, s)
continue continue
} }
// ClusterIP service
if svc.Spec.ClusterIP != api.ClusterIPNone {
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
}
s.ports = append(s.ports, p)
}
resultItems = append(resultItems, s)
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

View file

@ -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) {
// 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"}},

View file

@ -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,