aboutsummaryrefslogtreecommitdiff
path: root/plugin/kubernetes/metrics_test.go
diff options
context:
space:
mode:
authorGravatar Chris O'Haver <cohaver@infoblox.com> 2020-10-30 08:14:30 -0400
committerGravatar GitHub <noreply@github.com> 2020-10-30 08:14:30 -0400
commit272ccb195d31cd1622d48f961f3a189ce3abb937 (patch)
treeb5db771e2371b2e4ede772dff2c2c4217188115c /plugin/kubernetes/metrics_test.go
parentc840caf1ef77d8f86ee7d11f644e0d6ea42c469a (diff)
downloadcoredns-272ccb195d31cd1622d48f961f3a189ce3abb937.tar.gz
coredns-272ccb195d31cd1622d48f961f3a189ce3abb937.tar.zst
coredns-272ccb195d31cd1622d48f961f3a189ce3abb937.zip
plugin/kubernetes: Watch EndpointSlices (#4209)
* initial commit Signed-off-by: Chris O'Haver <cohaver@infoblox.com> * convert endpointslices to object.endpoints Signed-off-by: Chris O'Haver <cohaver@infoblox.com> * add opt hard coded for now Signed-off-by: Chris O'Haver <cohaver@infoblox.com> * check that server supports endpointslice Signed-off-by: Chris O'Haver <cohaver@infoblox.com> * fix import grouping Signed-off-by: Chris O'Haver <cohaver@infoblox.com> * dont use endpoint slice in 1.17 or 1.18 Signed-off-by: Chris O'Haver <cohaver@infoblox.com> * bump kind/k8s in circle ci to latest Signed-off-by: Chris O'Haver <cohaver@infoblox.com> * drop k8s to latest supported by kind Signed-off-by: Chris O'Haver <cohaver@infoblox.com> * use endpointslice name as endoint Name; index by Service name Signed-off-by: Chris O'Haver <cohaver@infoblox.com> * use index key comparison in nsAddrs() Signed-off-by: Chris O'Haver <cohaver@infoblox.com> * add Index to object.Endpoint fixtures; fix direct endpoint name compares Signed-off-by: Chris O'Haver <cohaver@infoblox.com> * add slice dup check and test Signed-off-by: Chris O'Haver <cohaver@infoblox.com> * todo Signed-off-by: Chris O'Haver <cohaver@infoblox.com> * add ep-slice skew dup test for reverse Signed-off-by: Chris O'Haver <cohaver@infoblox.com> * nsaddrs: de-dup ep-slice skew dups; add test Signed-off-by: Chris O'Haver <cohaver@infoblox.com> * remove todo Signed-off-by: Chris O'Haver <cohaver@infoblox.com> * address various feedback Signed-off-by: Chris O'Haver <cohaver@infoblox.com> * consolidate endpoint/slice informer code Signed-off-by: Chris O'Haver <cohaver@infoblox.com> * fix endpoint informer consolidation; use clearer func name Signed-off-by: Chris O'Haver <cohaver@infoblox.com> * log info; use major/minor fields Signed-off-by: Chris O'Haver <cohaver@infoblox.com> * fix nsAddr and unit test Signed-off-by: Chris O'Haver <cohaver@infoblox.com> * add latency tracking for endpointslices Signed-off-by: Chris O'Haver <cohaver@infoblox.com> * endpointslice latency unit test & fix Signed-off-by: Chris O'Haver <cohaver@infoblox.com> * code shuffling Signed-off-by: Chris O'Haver <cohaver@infoblox.com> * rename endpointslices in tests Signed-off-by: Chris O'Haver <cohaver@infoblox.com> * remove de-dup from nsAddrs and test Signed-off-by: Chris O'Haver <cohaver@infoblox.com> * remove de-dup from findServices / test Signed-off-by: Chris O'Haver <cohaver@infoblox.com>
Diffstat (limited to 'plugin/kubernetes/metrics_test.go')
-rw-r--r--plugin/kubernetes/metrics_test.go146
1 files changed, 116 insertions, 30 deletions
diff --git a/plugin/kubernetes/metrics_test.go b/plugin/kubernetes/metrics_test.go
index 0ab6f3c20..43b5ca382 100644
--- a/plugin/kubernetes/metrics_test.go
+++ b/plugin/kubernetes/metrics_test.go
@@ -10,6 +10,7 @@ import (
"github.com/prometheus/client_golang/prometheus/testutil"
api "k8s.io/api/core/v1"
+ discovery "k8s.io/api/discovery/v1beta1"
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/kubernetes"
@@ -20,15 +21,92 @@ const (
namespace = "testns"
)
-func TestDNSProgrammingLatency(t *testing.T) {
+var expected = `
+ # HELP coredns_kubernetes_dns_programming_duration_seconds Histogram of the time (in seconds) it took to program a dns instance.
+ # TYPE coredns_kubernetes_dns_programming_duration_seconds histogram
+ coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="0.001"} 0
+ coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="0.002"} 0
+ coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="0.004"} 0
+ coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="0.008"} 0
+ coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="0.016"} 0
+ coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="0.032"} 0
+ coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="0.064"} 0
+ coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="0.128"} 0
+ coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="0.256"} 0
+ coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="0.512"} 0
+ coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="1.024"} 1
+ coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="2.048"} 2
+ coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="4.096"} 2
+ coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="8.192"} 2
+ coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="16.384"} 2
+ coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="32.768"} 2
+ coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="65.536"} 2
+ coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="131.072"} 2
+ coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="262.144"} 2
+ coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="524.288"} 2
+ coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="+Inf"} 2
+ coredns_kubernetes_dns_programming_duration_seconds_sum{service_kind="headless_with_selector"} 3
+ coredns_kubernetes_dns_programming_duration_seconds_count{service_kind="headless_with_selector"} 2
+ `
+
+func TestDNSProgrammingLatencyEndpointSlices(t *testing.T) {
+ client := fake.NewSimpleClientset()
+ now := time.Now()
+ ctx := context.TODO()
+ controller := newdnsController(ctx, client, dnsControlOpts{
+ initEndpointsCache: true,
+ useEndpointSlices: true,
+ // This is needed as otherwise the fake k8s client doesn't work properly.
+ skipAPIObjectsCleanup: true,
+ })
+
+ durationSinceFunc = func(t time.Time) time.Duration {
+ return now.Sub(t)
+ }
+ DNSProgrammingLatency.Reset()
+ go controller.Run()
+
+ endpoints1 := []discovery.Endpoint{{
+ Addresses: []string{"1.2.3.4"},
+ }}
+
+ endpoints2 := []discovery.Endpoint{{
+ Addresses: []string{"1.2.3.45"},
+ }}
+
+ createService(t, client, controller, "my-service", api.ClusterIPNone)
+ createEndpointSlice(t, client, "my-service", now.Add(-2*time.Second), endpoints1)
+ updateEndpointSlice(t, client, "my-service", now.Add(-1*time.Second), endpoints2)
+
+ createEndpointSlice(t, client, "endpoints-no-service", now.Add(-4*time.Second), nil)
+
+ createService(t, client, controller, "clusterIP-service", "10.40.0.12")
+ createEndpointSlice(t, client, "clusterIP-service", now.Add(-8*time.Second), nil)
+
+ createService(t, client, controller, "headless-no-annotation", api.ClusterIPNone)
+ createEndpointSlice(t, client, "headless-no-annotation", nil, nil)
+
+ createService(t, client, controller, "headless-wrong-annotation", api.ClusterIPNone)
+ createEndpointSlice(t, client, "headless-wrong-annotation", "wrong-value", nil)
+
+ controller.Stop()
+
+ if err := testutil.CollectAndCompare(DNSProgrammingLatency, strings.NewReader(expected)); err != nil {
+ t.Error(err)
+ }
+}
+
+func TestDnsProgrammingLatencyEndpoints(t *testing.T) {
client := fake.NewSimpleClientset()
now := time.Now()
ctx := context.TODO()
controller := newdnsController(ctx, client, dnsControlOpts{
initEndpointsCache: true,
+ useEndpointSlices: false,
// This is needed as otherwise the fake k8s client doesn't work properly.
skipAPIObjectsCleanup: true,
})
+
durationSinceFunc = func(t time.Time) time.Duration {
return now.Sub(t)
}
@@ -59,33 +137,7 @@ func TestDNSProgrammingLatency(t *testing.T) {
createEndpoints(t, client, "headless-wrong-annotation", "wrong-value", nil)
controller.Stop()
- expected := `
- # HELP coredns_kubernetes_dns_programming_duration_seconds Histogram of the time (in seconds) it took to program a dns instance.
- # TYPE coredns_kubernetes_dns_programming_duration_seconds histogram
- coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="0.001"} 0
- coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="0.002"} 0
- coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="0.004"} 0
- coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="0.008"} 0
- coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="0.016"} 0
- coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="0.032"} 0
- coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="0.064"} 0
- coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="0.128"} 0
- coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="0.256"} 0
- coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="0.512"} 0
- coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="1.024"} 1
- coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="2.048"} 2
- coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="4.096"} 2
- coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="8.192"} 2
- coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="16.384"} 2
- coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="32.768"} 2
- coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="65.536"} 2
- coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="131.072"} 2
- coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="262.144"} 2
- coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="524.288"} 2
- coredns_kubernetes_dns_programming_duration_seconds_bucket{service_kind="headless_with_selector",le="+Inf"} 2
- coredns_kubernetes_dns_programming_duration_seconds_sum{service_kind="headless_with_selector"} 3
- coredns_kubernetes_dns_programming_duration_seconds_count{service_kind="headless_with_selector"} 2
- `
+
if err := testutil.CollectAndCompare(DNSProgrammingLatency, strings.NewReader(expected)); err != nil {
t.Error(err)
}
@@ -105,6 +157,24 @@ func buildEndpoints(name string, lastChangeTriggerTime interface{}, subsets []ap
}
}
+func buildEndpointSlice(name string, lastChangeTriggerTime interface{}, endpoints []discovery.Endpoint) *discovery.EndpointSlice {
+ annotations := make(map[string]string)
+ switch v := lastChangeTriggerTime.(type) {
+ case string:
+ annotations[api.EndpointsLastChangeTriggerTime] = v
+ case time.Time:
+ annotations[api.EndpointsLastChangeTriggerTime] = v.Format(time.RFC3339Nano)
+ }
+ return &discovery.EndpointSlice{
+ ObjectMeta: meta.ObjectMeta{
+ Namespace: namespace, Name: name + "-12345",
+ Labels: map[string]string{discovery.LabelServiceName: name},
+ Annotations: annotations,
+ },
+ Endpoints: endpoints,
+ }
+}
+
func createEndpoints(t *testing.T, client kubernetes.Interface, name string, triggerTime interface{}, subsets []api.EndpointSubset) {
ctx := context.TODO()
_, err := client.CoreV1().Endpoints(namespace).Create(ctx, buildEndpoints(name, triggerTime, subsets), meta.CreateOptions{})
@@ -121,11 +191,27 @@ func updateEndpoints(t *testing.T, client kubernetes.Interface, name string, tri
}
}
-func createService(t *testing.T, client kubernetes.Interface, controller dnsController, name string, clusterIP string) {
+func createEndpointSlice(t *testing.T, client kubernetes.Interface, name string, triggerTime interface{}, endpoints []discovery.Endpoint) {
+ ctx := context.TODO()
+ _, err := client.DiscoveryV1beta1().EndpointSlices(namespace).Create(ctx, buildEndpointSlice(name, triggerTime, endpoints), meta.CreateOptions{})
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+func updateEndpointSlice(t *testing.T, client kubernetes.Interface, name string, triggerTime interface{}, endpoints []discovery.Endpoint) {
+ ctx := context.TODO()
+ _, err := client.DiscoveryV1beta1().EndpointSlices(namespace).Update(ctx, buildEndpointSlice(name, triggerTime, endpoints), meta.UpdateOptions{})
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+func createService(t *testing.T, client kubernetes.Interface, controller dnsController, name string, clusterIp string) {
ctx := context.TODO()
if _, err := client.CoreV1().Services(namespace).Create(ctx, &api.Service{
ObjectMeta: meta.ObjectMeta{Namespace: namespace, Name: name},
- Spec: api.ServiceSpec{ClusterIP: clusterIP},
+ Spec: api.ServiceSpec{ClusterIP: clusterIp},
}, meta.CreateOptions{}); err != nil {
t.Fatal(err)
}