aboutsummaryrefslogtreecommitdiff
path: root/plugin/kubernetes
diff options
context:
space:
mode:
Diffstat (limited to 'plugin/kubernetes')
-rw-r--r--plugin/kubernetes/README.md14
-rw-r--r--plugin/kubernetes/handler_test.go7
-rw-r--r--plugin/kubernetes/metadata.go59
-rw-r--r--plugin/kubernetes/metadata_test.go126
4 files changed, 204 insertions, 2 deletions
diff --git a/plugin/kubernetes/README.md b/plugin/kubernetes/README.md
index 22614db8e..68efdae0c 100644
--- a/plugin/kubernetes/README.md
+++ b/plugin/kubernetes/README.md
@@ -225,3 +225,17 @@ or the word "any"), then that label will match all values. The labels that acce
*.service.default.svc.cluster.local. 5 IN A 192.168.25.15
```
This response can be randomized using the `loadbalance` plugin
+
+## Metadata
+
+The kubernetes plugin will publish the following metadata, if the _metadata_
+plugin is also enabled:
+
+ * kubernetes/endpoint: the endpoint name in the query
+ * kubernetes/kind: the resource kind (pod or svc) in the query
+ * kubernetes/namespace: the namespace in the query
+ * kubernetes/port-name: the port name in an SRV query
+ * kubernetes/protocol: the protocol in an SRV query
+ * kubernetes/service: the service name in the query
+ * kubernetes/client-namespace: the client pod's namespace, if `pods verified` mode is enabled
+ * kubernetes/client-pod-name: the client pod's name, if `pods verified` mode is enabled
diff --git a/plugin/kubernetes/handler_test.go b/plugin/kubernetes/handler_test.go
index e1a8212ca..0efd03c07 100644
--- a/plugin/kubernetes/handler_test.go
+++ b/plugin/kubernetes/handler_test.go
@@ -495,9 +495,12 @@ func (APIConnServeTest) EpIndexReverse(string) []*object.Endpoints { return nil
func (APIConnServeTest) SvcIndexReverse(string) []*object.Service { return nil }
func (APIConnServeTest) Modified() int64 { return time.Now().Unix() }
-func (APIConnServeTest) PodIndex(string) []*object.Pod {
+func (APIConnServeTest) PodIndex(ip string) []*object.Pod {
+ if ip != "10.240.0.1" {
+ return []*object.Pod{}
+ }
a := []*object.Pod{
- {Namespace: "podns", PodIP: "10.240.0.1"}, // Remote IP set in test.ResponseWriter
+ {Namespace: "podns", Name: "foo", PodIP: "10.240.0.1"}, // Remote IP set in test.ResponseWriter
}
return a
}
diff --git a/plugin/kubernetes/metadata.go b/plugin/kubernetes/metadata.go
new file mode 100644
index 000000000..323ae9e11
--- /dev/null
+++ b/plugin/kubernetes/metadata.go
@@ -0,0 +1,59 @@
+package kubernetes
+
+import (
+ "context"
+
+ "github.com/coredns/coredns/plugin/metadata"
+ "github.com/coredns/coredns/request"
+)
+
+// Metadata implements the metadata.Provider interface.
+func (k *Kubernetes) Metadata(ctx context.Context, state request.Request) context.Context {
+ // possible optimization: cache r so it doesn't need to be calculated again in ServeDNS
+ r, err := parseRequest(state)
+ if err != nil {
+ metadata.SetValueFunc(ctx, "kubernetes/parse-error", func() string {
+ return err.Error()
+ })
+ return ctx
+ }
+
+ metadata.SetValueFunc(ctx, "kubernetes/port-name", func() string {
+ return r.port
+ })
+
+ metadata.SetValueFunc(ctx, "kubernetes/protocol", func() string {
+ return r.protocol
+ })
+
+ metadata.SetValueFunc(ctx, "kubernetes/endpoint", func() string {
+ return r.endpoint
+ })
+
+ metadata.SetValueFunc(ctx, "kubernetes/service", func() string {
+ return r.service
+ })
+
+ metadata.SetValueFunc(ctx, "kubernetes/namespace", func() string {
+ return r.namespace
+ })
+
+ metadata.SetValueFunc(ctx, "kubernetes/kind", func() string {
+ return r.podOrSvc
+ })
+
+ pod := k.podWithIP(state.IP())
+ if pod == nil {
+ return ctx
+ }
+
+ metadata.SetValueFunc(ctx, "kubernetes/client-namespace", func() string {
+ return pod.Namespace
+ })
+
+ metadata.SetValueFunc(ctx, "kubernetes/client-pod-name", func() string {
+ return pod.Name
+ })
+
+ return ctx
+}
diff --git a/plugin/kubernetes/metadata_test.go b/plugin/kubernetes/metadata_test.go
new file mode 100644
index 000000000..44f16f13e
--- /dev/null
+++ b/plugin/kubernetes/metadata_test.go
@@ -0,0 +1,126 @@
+package kubernetes
+
+import (
+ "context"
+ "testing"
+
+ "github.com/coredns/coredns/plugin/metadata"
+ "github.com/coredns/coredns/plugin/test"
+ "github.com/coredns/coredns/request"
+
+ "github.com/miekg/dns"
+)
+
+var metadataCases = []struct {
+ Qname string
+ Qtype uint16
+ RemoteIP string
+ Md map[string]string
+}{
+ {
+ Qname: "foo.bar.notapod.cluster.local.", Qtype: dns.TypeA,
+ Md: map[string]string{
+ "kubernetes/parse-error": "invalid query name",
+ },
+ },
+ {
+ Qname: "10-240-0-1.podns.pod.cluster.local.", Qtype: dns.TypeA,
+ Md: map[string]string{
+ "kubernetes/endpoint": "",
+ "kubernetes/kind": "pod",
+ "kubernetes/namespace": "podns",
+ "kubernetes/port-name": "*",
+ "kubernetes/protocol": "*",
+ "kubernetes/service": "10-240-0-1",
+ "kubernetes/client-namespace": "podns",
+ "kubernetes/client-pod-name": "foo",
+ },
+ },
+ {
+ Qname: "s.ns.svc.cluster.local.", Qtype: dns.TypeA,
+ Md: map[string]string{
+ "kubernetes/endpoint": "",
+ "kubernetes/kind": "svc",
+ "kubernetes/namespace": "ns",
+ "kubernetes/port-name": "*",
+ "kubernetes/protocol": "*",
+ "kubernetes/service": "s",
+ "kubernetes/client-namespace": "podns",
+ "kubernetes/client-pod-name": "foo",
+ },
+ },
+ {
+ Qname: "s.ns.svc.cluster.local.", Qtype: dns.TypeA,
+ RemoteIP: "10.10.10.10",
+ Md: map[string]string{
+ "kubernetes/endpoint": "",
+ "kubernetes/kind": "svc",
+ "kubernetes/namespace": "ns",
+ "kubernetes/port-name": "*",
+ "kubernetes/protocol": "*",
+ "kubernetes/service": "s",
+ },
+ },
+ {
+ Qname: "_http._tcp.s.ns.svc.cluster.local.", Qtype: dns.TypeSRV,
+ RemoteIP: "10.10.10.10",
+ Md: map[string]string{
+ "kubernetes/endpoint": "",
+ "kubernetes/kind": "svc",
+ "kubernetes/namespace": "ns",
+ "kubernetes/port-name": "http",
+ "kubernetes/protocol": "tcp",
+ "kubernetes/service": "s",
+ },
+ },
+ {
+ Qname: "ep.s.ns.svc.cluster.local.", Qtype: dns.TypeA,
+ RemoteIP: "10.10.10.10",
+ Md: map[string]string{
+ "kubernetes/endpoint": "ep",
+ "kubernetes/kind": "svc",
+ "kubernetes/namespace": "ns",
+ "kubernetes/port-name": "*",
+ "kubernetes/protocol": "*",
+ "kubernetes/service": "s",
+ },
+ },
+}
+
+func mapsDiffer(a, b map[string]string) bool {
+ if len(a) != len(b) {
+ return true
+ }
+
+ for k, va := range a {
+ vb, ok := b[k]
+ if !ok || va != vb {
+ return true
+ }
+ }
+ return false
+}
+
+func TestMetadata(t *testing.T) {
+ k := New([]string{"cluster.local."})
+ k.APIConn = &APIConnServeTest{}
+
+ for i, tc := range metadataCases {
+ ctx := metadata.ContextWithMetadata(context.Background())
+ state := request.Request{
+ Req: &dns.Msg{Question: []dns.Question{{Name: tc.Qname, Qtype: tc.Qtype}}},
+ Zone: "cluster.local.",
+ W: &test.ResponseWriter{RemoteIP: tc.RemoteIP},
+ }
+
+ k.Metadata(ctx, state)
+
+ md := make(map[string]string)
+ for _, l := range metadata.Labels(ctx) {
+ md[l] = metadata.ValueFunc(ctx, l)()
+ }
+ if mapsDiffer(tc.Md, md) {
+ t.Errorf("case %d expected metadata %v and got %v", i, tc.Md, md)
+ }
+ }
+}