mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 03:41:45 +00:00
Merge pull request #92071 from RainbowMango/pr_force_promlint_in_testutils
Enable promlint in metrics tests
This commit is contained in:
commit
49c50720e4
@ -17,7 +17,9 @@ limitations under the License.
|
|||||||
package testutil
|
package testutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/prometheus/testutil/promlint"
|
"github.com/prometheus/client_golang/prometheus/testutil/promlint"
|
||||||
)
|
)
|
||||||
@ -28,14 +30,26 @@ import (
|
|||||||
// We setup this list for allow and not fail on the current violations.
|
// We setup this list for allow and not fail on the current violations.
|
||||||
// Generally speaking, you need to fix the problem for a new metric rather than add it into the list.
|
// Generally speaking, you need to fix the problem for a new metric rather than add it into the list.
|
||||||
var exceptionMetrics = []string{
|
var exceptionMetrics = []string{
|
||||||
|
// k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/server/egressselector
|
||||||
|
"apiserver_egress_dialer_dial_failure_count", // counter metrics should have "_total" suffix
|
||||||
|
|
||||||
|
// k8s.io/apiserver/pkg/util/flowcontrol/fairqueuing/queueset
|
||||||
|
"apiserver_flowcontrol_current_inqueue_requests", // label names should be written in 'snake_case' not 'camelCase',
|
||||||
|
"apiserver_flowcontrol_current_executing_requests", // label names should be written in 'snake_case' not 'camelCase'
|
||||||
|
"apiserver_flowcontrol_rejected_requests_total", // label names should be written in 'snake_case' not 'camelCase'
|
||||||
|
|
||||||
|
// k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/server/healthz
|
||||||
|
"apiserver_request_total", // label names should be written in 'snake_case' not 'camelCase'
|
||||||
|
|
||||||
|
// k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/endpoints/filters
|
||||||
|
"authenticated_user_requests", // counter metrics should have "_total" suffix
|
||||||
|
"authentication_attempts", // counter metrics should have "_total" suffix
|
||||||
|
|
||||||
// kube-apiserver
|
// kube-apiserver
|
||||||
"aggregator_openapi_v2_regeneration_count",
|
"aggregator_openapi_v2_regeneration_count",
|
||||||
"apiserver_admission_step_admission_duration_seconds_summary",
|
"apiserver_admission_step_admission_duration_seconds_summary",
|
||||||
"apiserver_current_inflight_requests",
|
"apiserver_current_inflight_requests",
|
||||||
"apiserver_longrunning_gauge",
|
"apiserver_longrunning_gauge",
|
||||||
"apiserver_request_total",
|
|
||||||
"authenticated_user_requests",
|
|
||||||
"authentication_attempts",
|
|
||||||
"get_token_count",
|
"get_token_count",
|
||||||
"get_token_fail_count",
|
"get_token_fail_count",
|
||||||
"ssh_tunnel_open_count",
|
"ssh_tunnel_open_count",
|
||||||
@ -49,14 +63,22 @@ var exceptionMetrics = []string{
|
|||||||
"get_token_fail_count",
|
"get_token_fail_count",
|
||||||
"node_collector_evictions_number",
|
"node_collector_evictions_number",
|
||||||
|
|
||||||
// kubelet-resource-v1alpha1
|
// k8s.io/kubernetes/pkg/kubelet/server/stats
|
||||||
"container_cpu_usage_seconds_total",
|
"container_cpu_usage_seconds_total", // non-counter metrics should not have "_total" suffix
|
||||||
"node_cpu_usage_seconds_total",
|
"node_cpu_usage_seconds_total", // non-counter metrics should not have "_total" suffix
|
||||||
|
|
||||||
|
// k8s.io/kubernetes/pkg/kubelet/pleg
|
||||||
|
"kubelet_running_container_count", // non-histogram and non-summary metrics should not have "_count" suffix
|
||||||
|
"kubelet_running_pod_count", // non-histogram and non-summary metrics should not have "_count" suffix
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Problem is an issue detected by a Linter.
|
// A Problem is an issue detected by a Linter.
|
||||||
type Problem promlint.Problem
|
type Problem promlint.Problem
|
||||||
|
|
||||||
|
func (p *Problem) String() string {
|
||||||
|
return fmt.Sprintf("%s:%s", p.Metric, p.Text)
|
||||||
|
}
|
||||||
|
|
||||||
// A Linter is a Prometheus metrics linter. It identifies issues with metric
|
// A Linter is a Prometheus metrics linter. It identifies issues with metric
|
||||||
// names, types, and metadata, and reports them to the caller.
|
// names, types, and metadata, and reports them to the caller.
|
||||||
type Linter struct {
|
type Linter struct {
|
||||||
@ -101,3 +123,42 @@ func NewPromLinter(r io.Reader) *Linter {
|
|||||||
promLinter: promlint.New(r),
|
promLinter: promlint.New(r),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mergeProblems(problems []Problem) string {
|
||||||
|
var problemsMsg []string
|
||||||
|
|
||||||
|
for index := range problems {
|
||||||
|
problemsMsg = append(problemsMsg, problems[index].String())
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Join(problemsMsg, ",")
|
||||||
|
}
|
||||||
|
|
||||||
|
// shouldIgnore returns true if metric in the exception list, otherwise returns false.
|
||||||
|
func shouldIgnore(metricName string) bool {
|
||||||
|
for i := range exceptionMetrics {
|
||||||
|
if metricName == exceptionMetrics[i] {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// getLintError will ignore the metrics in exception list and converts lint problem to error.
|
||||||
|
func getLintError(problems []promlint.Problem) error {
|
||||||
|
var filteredProblems []Problem
|
||||||
|
for _, problem := range problems {
|
||||||
|
if shouldIgnore(problem.Metric) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
filteredProblems = append(filteredProblems, Problem(problem))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(filteredProblems) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("lint error: %s", mergeProblems(filteredProblems))
|
||||||
|
}
|
||||||
|
@ -59,3 +59,46 @@ func TestLinter(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMergeProblems(t *testing.T) {
|
||||||
|
problemOne := Problem{
|
||||||
|
Metric: "metric_one",
|
||||||
|
Text: "problem one",
|
||||||
|
}
|
||||||
|
problemTwo := Problem{
|
||||||
|
Metric: "metric_two",
|
||||||
|
Text: "problem two",
|
||||||
|
}
|
||||||
|
|
||||||
|
var tests = []struct {
|
||||||
|
name string
|
||||||
|
problems []Problem
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "no problem",
|
||||||
|
problems: nil,
|
||||||
|
expected: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "one problem",
|
||||||
|
problems: []Problem{problemOne},
|
||||||
|
expected: "metric_one:problem one",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "more than one problem",
|
||||||
|
problems: []Problem{problemOne, problemTwo},
|
||||||
|
expected: "metric_one:problem one,metric_two:problem two",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
tc := test
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
got := mergeProblems(tc.problems)
|
||||||
|
if tc.expected != got {
|
||||||
|
t.Errorf("expected: %s, but got: %s", tc.expected, got)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -30,6 +30,14 @@ import (
|
|||||||
// pedantic Registry. It then does the same as GatherAndCompare, gathering the
|
// pedantic Registry. It then does the same as GatherAndCompare, gathering the
|
||||||
// metrics from the pedantic Registry.
|
// metrics from the pedantic Registry.
|
||||||
func CollectAndCompare(c metrics.Collector, expected io.Reader, metricNames ...string) error {
|
func CollectAndCompare(c metrics.Collector, expected io.Reader, metricNames ...string) error {
|
||||||
|
lintProblems, err := testutil.CollectAndLint(c, metricNames...)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := getLintError(lintProblems); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return testutil.CollectAndCompare(c, expected, metricNames...)
|
return testutil.CollectAndCompare(c, expected, metricNames...)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,6 +46,14 @@ func CollectAndCompare(c metrics.Collector, expected io.Reader, metricNames ...s
|
|||||||
// exposition format. If any metricNames are provided, only metrics with those
|
// exposition format. If any metricNames are provided, only metrics with those
|
||||||
// names are compared.
|
// names are compared.
|
||||||
func GatherAndCompare(g metrics.Gatherer, expected io.Reader, metricNames ...string) error {
|
func GatherAndCompare(g metrics.Gatherer, expected io.Reader, metricNames ...string) error {
|
||||||
|
lintProblems, err := testutil.GatherAndLint(g, metricNames...)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := getLintError(lintProblems); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return testutil.GatherAndCompare(g, expected, metricNames...)
|
return testutil.GatherAndCompare(g, expected, metricNames...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,13 +27,13 @@ func TestNewFakeKubeRegistry(t *testing.T) {
|
|||||||
registryVersion := "1.18.0"
|
registryVersion := "1.18.0"
|
||||||
counter := metrics.NewCounter(
|
counter := metrics.NewCounter(
|
||||||
&metrics.CounterOpts{
|
&metrics.CounterOpts{
|
||||||
Name: "test_counter_name",
|
Name: "test_normal_total",
|
||||||
Help: "counter help",
|
Help: "counter help",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
deprecatedCounter := metrics.NewCounter(
|
deprecatedCounter := metrics.NewCounter(
|
||||||
&metrics.CounterOpts{
|
&metrics.CounterOpts{
|
||||||
Name: "test_deprecated_counter",
|
Name: "test_deprecated_total",
|
||||||
Help: "counter help",
|
Help: "counter help",
|
||||||
DeprecatedVersion: "1.18.0",
|
DeprecatedVersion: "1.18.0",
|
||||||
},
|
},
|
||||||
@ -55,18 +55,18 @@ func TestNewFakeKubeRegistry(t *testing.T) {
|
|||||||
name: "normal",
|
name: "normal",
|
||||||
metric: counter,
|
metric: counter,
|
||||||
expected: `
|
expected: `
|
||||||
# HELP test_counter_name [ALPHA] counter help
|
# HELP test_normal_total [ALPHA] counter help
|
||||||
# TYPE test_counter_name counter
|
# TYPE test_normal_total counter
|
||||||
test_counter_name 0
|
test_normal_total 0
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "deprecated",
|
name: "deprecated",
|
||||||
metric: deprecatedCounter,
|
metric: deprecatedCounter,
|
||||||
expected: `
|
expected: `
|
||||||
# HELP test_deprecated_counter [ALPHA] (Deprecated since 1.18.0) counter help
|
# HELP test_deprecated_total [ALPHA] (Deprecated since 1.18.0) counter help
|
||||||
# TYPE test_deprecated_counter counter
|
# TYPE test_deprecated_total counter
|
||||||
test_deprecated_counter 0
|
test_deprecated_total 0
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user