Skip to content

Commit 49c5072

Browse files
authored
Merge pull request kubernetes#92071 from RainbowMango/pr_force_promlint_in_testutils
Enable promlint in metrics tests
2 parents bfa6eb1 + 0ee146e commit 49c5072

File tree

4 files changed

+134
-14
lines changed

4 files changed

+134
-14
lines changed

staging/src/k8s.io/component-base/metrics/testutil/promlint.go

Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ limitations under the License.
1717
package testutil
1818

1919
import (
20+
"fmt"
2021
"io"
22+
"strings"
2123

2224
"github.com/prometheus/client_golang/prometheus/testutil/promlint"
2325
)
@@ -28,14 +30,26 @@ import (
2830
// We setup this list for allow and not fail on the current violations.
2931
// Generally speaking, you need to fix the problem for a new metric rather than add it into the list.
3032
var exceptionMetrics = []string{
33+
// k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/server/egressselector
34+
"apiserver_egress_dialer_dial_failure_count", // counter metrics should have "_total" suffix
35+
36+
// k8s.io/apiserver/pkg/util/flowcontrol/fairqueuing/queueset
37+
"apiserver_flowcontrol_current_inqueue_requests", // label names should be written in 'snake_case' not 'camelCase',
38+
"apiserver_flowcontrol_current_executing_requests", // label names should be written in 'snake_case' not 'camelCase'
39+
"apiserver_flowcontrol_rejected_requests_total", // label names should be written in 'snake_case' not 'camelCase'
40+
41+
// k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/server/healthz
42+
"apiserver_request_total", // label names should be written in 'snake_case' not 'camelCase'
43+
44+
// k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/endpoints/filters
45+
"authenticated_user_requests", // counter metrics should have "_total" suffix
46+
"authentication_attempts", // counter metrics should have "_total" suffix
47+
3148
// kube-apiserver
3249
"aggregator_openapi_v2_regeneration_count",
3350
"apiserver_admission_step_admission_duration_seconds_summary",
3451
"apiserver_current_inflight_requests",
3552
"apiserver_longrunning_gauge",
36-
"apiserver_request_total",
37-
"authenticated_user_requests",
38-
"authentication_attempts",
3953
"get_token_count",
4054
"get_token_fail_count",
4155
"ssh_tunnel_open_count",
@@ -49,14 +63,22 @@ var exceptionMetrics = []string{
4963
"get_token_fail_count",
5064
"node_collector_evictions_number",
5165

52-
// kubelet-resource-v1alpha1
53-
"container_cpu_usage_seconds_total",
54-
"node_cpu_usage_seconds_total",
66+
// k8s.io/kubernetes/pkg/kubelet/server/stats
67+
"container_cpu_usage_seconds_total", // non-counter metrics should not have "_total" suffix
68+
"node_cpu_usage_seconds_total", // non-counter metrics should not have "_total" suffix
69+
70+
// k8s.io/kubernetes/pkg/kubelet/pleg
71+
"kubelet_running_container_count", // non-histogram and non-summary metrics should not have "_count" suffix
72+
"kubelet_running_pod_count", // non-histogram and non-summary metrics should not have "_count" suffix
5573
}
5674

5775
// A Problem is an issue detected by a Linter.
5876
type Problem promlint.Problem
5977

78+
func (p *Problem) String() string {
79+
return fmt.Sprintf("%s:%s", p.Metric, p.Text)
80+
}
81+
6082
// A Linter is a Prometheus metrics linter. It identifies issues with metric
6183
// names, types, and metadata, and reports them to the caller.
6284
type Linter struct {
@@ -101,3 +123,42 @@ func NewPromLinter(r io.Reader) *Linter {
101123
promLinter: promlint.New(r),
102124
}
103125
}
126+
127+
func mergeProblems(problems []Problem) string {
128+
var problemsMsg []string
129+
130+
for index := range problems {
131+
problemsMsg = append(problemsMsg, problems[index].String())
132+
}
133+
134+
return strings.Join(problemsMsg, ",")
135+
}
136+
137+
// shouldIgnore returns true if metric in the exception list, otherwise returns false.
138+
func shouldIgnore(metricName string) bool {
139+
for i := range exceptionMetrics {
140+
if metricName == exceptionMetrics[i] {
141+
return true
142+
}
143+
}
144+
145+
return false
146+
}
147+
148+
// getLintError will ignore the metrics in exception list and converts lint problem to error.
149+
func getLintError(problems []promlint.Problem) error {
150+
var filteredProblems []Problem
151+
for _, problem := range problems {
152+
if shouldIgnore(problem.Metric) {
153+
continue
154+
}
155+
156+
filteredProblems = append(filteredProblems, Problem(problem))
157+
}
158+
159+
if len(filteredProblems) == 0 {
160+
return nil
161+
}
162+
163+
return fmt.Errorf("lint error: %s", mergeProblems(filteredProblems))
164+
}

staging/src/k8s.io/component-base/metrics/testutil/promlint_test.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,46 @@ func TestLinter(t *testing.T) {
5959
})
6060
}
6161
}
62+
63+
func TestMergeProblems(t *testing.T) {
64+
problemOne := Problem{
65+
Metric: "metric_one",
66+
Text: "problem one",
67+
}
68+
problemTwo := Problem{
69+
Metric: "metric_two",
70+
Text: "problem two",
71+
}
72+
73+
var tests = []struct {
74+
name string
75+
problems []Problem
76+
expected string
77+
}{
78+
{
79+
name: "no problem",
80+
problems: nil,
81+
expected: "",
82+
},
83+
{
84+
name: "one problem",
85+
problems: []Problem{problemOne},
86+
expected: "metric_one:problem one",
87+
},
88+
{
89+
name: "more than one problem",
90+
problems: []Problem{problemOne, problemTwo},
91+
expected: "metric_one:problem one,metric_two:problem two",
92+
},
93+
}
94+
95+
for _, test := range tests {
96+
tc := test
97+
t.Run(tc.name, func(t *testing.T) {
98+
got := mergeProblems(tc.problems)
99+
if tc.expected != got {
100+
t.Errorf("expected: %s, but got: %s", tc.expected, got)
101+
}
102+
})
103+
}
104+
}

staging/src/k8s.io/component-base/metrics/testutil/testutil.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@ import (
3030
// pedantic Registry. It then does the same as GatherAndCompare, gathering the
3131
// metrics from the pedantic Registry.
3232
func CollectAndCompare(c metrics.Collector, expected io.Reader, metricNames ...string) error {
33+
lintProblems, err := testutil.CollectAndLint(c, metricNames...)
34+
if err != nil {
35+
return err
36+
}
37+
if err := getLintError(lintProblems); err != nil {
38+
return err
39+
}
40+
3341
return testutil.CollectAndCompare(c, expected, metricNames...)
3442
}
3543

@@ -38,6 +46,14 @@ func CollectAndCompare(c metrics.Collector, expected io.Reader, metricNames ...s
3846
// exposition format. If any metricNames are provided, only metrics with those
3947
// names are compared.
4048
func GatherAndCompare(g metrics.Gatherer, expected io.Reader, metricNames ...string) error {
49+
lintProblems, err := testutil.GatherAndLint(g, metricNames...)
50+
if err != nil {
51+
return err
52+
}
53+
if err := getLintError(lintProblems); err != nil {
54+
return err
55+
}
56+
4157
return testutil.GatherAndCompare(g, expected, metricNames...)
4258
}
4359

staging/src/k8s.io/component-base/metrics/testutil/testutil_test.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,13 @@ func TestNewFakeKubeRegistry(t *testing.T) {
2727
registryVersion := "1.18.0"
2828
counter := metrics.NewCounter(
2929
&metrics.CounterOpts{
30-
Name: "test_counter_name",
30+
Name: "test_normal_total",
3131
Help: "counter help",
3232
},
3333
)
3434
deprecatedCounter := metrics.NewCounter(
3535
&metrics.CounterOpts{
36-
Name: "test_deprecated_counter",
36+
Name: "test_deprecated_total",
3737
Help: "counter help",
3838
DeprecatedVersion: "1.18.0",
3939
},
@@ -55,18 +55,18 @@ func TestNewFakeKubeRegistry(t *testing.T) {
5555
name: "normal",
5656
metric: counter,
5757
expected: `
58-
# HELP test_counter_name [ALPHA] counter help
59-
# TYPE test_counter_name counter
60-
test_counter_name 0
58+
# HELP test_normal_total [ALPHA] counter help
59+
# TYPE test_normal_total counter
60+
test_normal_total 0
6161
`,
6262
},
6363
{
6464
name: "deprecated",
6565
metric: deprecatedCounter,
6666
expected: `
67-
# HELP test_deprecated_counter [ALPHA] (Deprecated since 1.18.0) counter help
68-
# TYPE test_deprecated_counter counter
69-
test_deprecated_counter 0
67+
# HELP test_deprecated_total [ALPHA] (Deprecated since 1.18.0) counter help
68+
# TYPE test_deprecated_total counter
69+
test_deprecated_total 0
7070
`,
7171
},
7272
{

0 commit comments

Comments
 (0)