mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-22 03:11:40 +00:00
Fix metrics reporting in kube-apiserver
This commit is contained in:
parent
b2de4a6159
commit
3d2a80643a
@ -436,6 +436,7 @@ package_group(
|
|||||||
"//staging/src/k8s.io/component-base/metrics/...",
|
"//staging/src/k8s.io/component-base/metrics/...",
|
||||||
"//test/e2e_node",
|
"//test/e2e_node",
|
||||||
"//test/integration/apiserver/flowcontrol",
|
"//test/integration/apiserver/flowcontrol",
|
||||||
|
"//test/integration/metrics",
|
||||||
"//vendor/...",
|
"//vendor/...",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -594,6 +594,9 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||||||
requestScope = "resource"
|
requestScope = "resource"
|
||||||
operationSuffix = operationSuffix + "WithPath"
|
operationSuffix = operationSuffix + "WithPath"
|
||||||
}
|
}
|
||||||
|
if strings.Index(action.Path, "/{name}") != -1 || action.Verb == "POST" {
|
||||||
|
requestScope = "resource"
|
||||||
|
}
|
||||||
if action.AllNamespaces {
|
if action.AllNamespaces {
|
||||||
requestScope = "cluster"
|
requestScope = "cluster"
|
||||||
operationSuffix = operationSuffix + "ForAllNamespaces"
|
operationSuffix = operationSuffix + "ForAllNamespaces"
|
||||||
|
@ -35,11 +35,13 @@ go_test(
|
|||||||
embed = [":go_default_library"],
|
embed = [":go_default_library"],
|
||||||
tags = ["integration"],
|
tags = ["integration"],
|
||||||
deps = [
|
deps = [
|
||||||
|
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||||
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
|
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
|
||||||
"//staging/src/k8s.io/client-go/rest:go_default_library",
|
"//staging/src/k8s.io/client-go/rest:go_default_library",
|
||||||
"//staging/src/k8s.io/component-base/metrics/testutil:go_default_library",
|
"//staging/src/k8s.io/component-base/metrics/testutil:go_default_library",
|
||||||
"//test/integration/framework:go_default_library",
|
"//test/integration/framework:go_default_library",
|
||||||
|
"//vendor/github.com/prometheus/common/model:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -25,6 +25,9 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/prometheus/common/model"
|
||||||
|
|
||||||
|
v1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
clientset "k8s.io/client-go/kubernetes"
|
clientset "k8s.io/client-go/kubernetes"
|
||||||
@ -111,3 +114,130 @@ func TestApiserverMetrics(t *testing.T) {
|
|||||||
"etcd_request_duration_seconds_sum",
|
"etcd_request_duration_seconds_sum",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestApiserverMetricsLabels(t *testing.T) {
|
||||||
|
_, s, closeFn := framework.RunAMaster(nil)
|
||||||
|
defer closeFn()
|
||||||
|
|
||||||
|
client, err := clientset.NewForConfig(&restclient.Config{Host: s.URL, QPS: -1})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error in create clientset: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedMetrics := []model.Metric{}
|
||||||
|
|
||||||
|
metricLabels := func(group, version, resource, subresource, scope, verb string) model.Metric {
|
||||||
|
return map[model.LabelName]model.LabelValue{
|
||||||
|
model.LabelName("group"): model.LabelValue(group),
|
||||||
|
model.LabelName("version"): model.LabelValue(version),
|
||||||
|
model.LabelName("resource"): model.LabelValue(resource),
|
||||||
|
model.LabelName("subresource"): model.LabelValue(subresource),
|
||||||
|
model.LabelName("scope"): model.LabelValue(scope),
|
||||||
|
model.LabelName("verb"): model.LabelValue(verb),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
callOrDie := func(_ interface{}, err error) {
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
appendExpectedMetric := func(metric model.Metric) {
|
||||||
|
expectedMetrics = append(expectedMetrics, metric)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call appropriate endpoints to ensure particular metrics will be exposed
|
||||||
|
|
||||||
|
// Namespace-scoped resource
|
||||||
|
c := client.CoreV1().Pods(metav1.NamespaceDefault)
|
||||||
|
makePod := func(labelValue string) *v1.Pod {
|
||||||
|
return &v1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "foo",
|
||||||
|
Labels: map[string]string{"foo": labelValue},
|
||||||
|
},
|
||||||
|
Spec: v1.PodSpec{
|
||||||
|
Containers: []v1.Container{
|
||||||
|
{
|
||||||
|
Name: "container",
|
||||||
|
Image: "image",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
callOrDie(c.Create(context.TODO(), makePod("foo"), metav1.CreateOptions{}))
|
||||||
|
appendExpectedMetric(metricLabels("", "v1", "pods", "", "resource", "POST"))
|
||||||
|
callOrDie(c.Update(context.TODO(), makePod("bar"), metav1.UpdateOptions{}))
|
||||||
|
appendExpectedMetric(metricLabels("", "v1", "pods", "", "resource", "PUT"))
|
||||||
|
callOrDie(c.UpdateStatus(context.TODO(), makePod("bar"), metav1.UpdateOptions{}))
|
||||||
|
appendExpectedMetric(metricLabels("", "v1", "pods", "status", "resource", "PUT"))
|
||||||
|
callOrDie(c.Get(context.TODO(), "foo", metav1.GetOptions{}))
|
||||||
|
appendExpectedMetric(metricLabels("", "v1", "pods", "", "resource", "GET"))
|
||||||
|
callOrDie(c.List(context.TODO(), metav1.ListOptions{}))
|
||||||
|
appendExpectedMetric(metricLabels("", "v1", "pods", "", "namespace", "LIST"))
|
||||||
|
callOrDie(nil, c.Delete(context.TODO(), "foo", metav1.DeleteOptions{}))
|
||||||
|
appendExpectedMetric(metricLabels("", "v1", "pods", "", "resource", "DELETE"))
|
||||||
|
// cluster-scoped LIST of namespace-scoped resources
|
||||||
|
callOrDie(client.CoreV1().Pods(metav1.NamespaceAll).List(context.TODO(), metav1.ListOptions{}))
|
||||||
|
appendExpectedMetric(metricLabels("", "v1", "pods", "", "cluster", "LIST"))
|
||||||
|
|
||||||
|
// Cluster-scoped resource
|
||||||
|
cn := client.CoreV1().Namespaces()
|
||||||
|
makeNamespace := func(labelValue string) *v1.Namespace {
|
||||||
|
return &v1.Namespace{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "foo",
|
||||||
|
Labels: map[string]string{"foo": labelValue},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
callOrDie(cn.Create(context.TODO(), makeNamespace("foo"), metav1.CreateOptions{}))
|
||||||
|
appendExpectedMetric(metricLabels("", "v1", "namespaces", "", "resource", "POST"))
|
||||||
|
callOrDie(cn.Update(context.TODO(), makeNamespace("bar"), metav1.UpdateOptions{}))
|
||||||
|
appendExpectedMetric(metricLabels("", "v1", "namespaces", "", "resource", "PUT"))
|
||||||
|
callOrDie(cn.UpdateStatus(context.TODO(), makeNamespace("bar"), metav1.UpdateOptions{}))
|
||||||
|
appendExpectedMetric(metricLabels("", "v1", "namespaces", "status", "resource", "PUT"))
|
||||||
|
callOrDie(cn.Get(context.TODO(), "foo", metav1.GetOptions{}))
|
||||||
|
appendExpectedMetric(metricLabels("", "v1", "namespaces", "", "resource", "GET"))
|
||||||
|
callOrDie(cn.List(context.TODO(), metav1.ListOptions{}))
|
||||||
|
appendExpectedMetric(metricLabels("", "v1", "namespaces", "", "cluster", "LIST"))
|
||||||
|
callOrDie(nil, cn.Delete(context.TODO(), "foo", metav1.DeleteOptions{}))
|
||||||
|
appendExpectedMetric(metricLabels("", "v1", "namespaces", "", "resource", "DELETE"))
|
||||||
|
|
||||||
|
// Verify if all metrics were properly exported.
|
||||||
|
metrics, err := scrapeMetrics(s)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
samples, ok := metrics["apiserver_request_total"]
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("apiserver_request_total metric not exposed")
|
||||||
|
}
|
||||||
|
|
||||||
|
hasLabels := func(current, expected model.Metric) bool {
|
||||||
|
for key, value := range expected {
|
||||||
|
if current[key] != value {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, expectedMetric := range expectedMetrics {
|
||||||
|
found := false
|
||||||
|
for _, sample := range samples {
|
||||||
|
if hasLabels(sample.Metric, expectedMetric) {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
t.Errorf("No sample found for %#v", expectedMetric)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user