Skip to content

Commit 02fd1a9

Browse files
committed
Make CRS metrics type dynamic
All CRS metrics are hardcoded to "gauge" type, this patch addresses that.
1 parent f01ce58 commit 02fd1a9

File tree

3 files changed

+94
-5
lines changed

3 files changed

+94
-5
lines changed
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
Copyright 2022 The Kubernetes Authors All rights reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package customresourcestate
18+
19+
import (
20+
"testing"
21+
)
22+
23+
func TestNewCustomResourceMetrics(t *testing.T) {
24+
tests := []struct {
25+
r Resource
26+
wantErr bool
27+
name string
28+
}{
29+
{
30+
// https://github.com/kubernetes/kube-state-metrics/issues/1886
31+
name: "dynamic metric type (not just hardcoded to gauge)",
32+
r: Resource{
33+
GroupVersionKind: GroupVersionKind{
34+
Group: "apps",
35+
Version: "v1",
36+
Kind: "Deployment",
37+
},
38+
Labels: Labels{
39+
LabelsFromPath: map[string][]string{
40+
"name": {"metadata", "name"},
41+
},
42+
},
43+
Metrics: []Generator{
44+
{
45+
Name: "test_metrics",
46+
Help: "metrics for testing",
47+
Each: Metric{
48+
Type: MetricTypeInfo,
49+
Info: &MetricInfo{
50+
MetricMeta: MetricMeta{
51+
Path: []string{
52+
"metadata",
53+
"annotations",
54+
},
55+
},
56+
LabelFromKey: "test",
57+
},
58+
},
59+
},
60+
},
61+
},
62+
wantErr: false,
63+
},
64+
}
65+
66+
for _, tt := range tests {
67+
t.Run(tt.name, func(t *testing.T) {
68+
v, err := NewCustomResourceMetrics(tt.r)
69+
expectedError := v.(*customResourceMetrics).Families[0].Each.Type() != "info"
70+
if (err != nil) != tt.wantErr || expectedError {
71+
t.Errorf("NewCustomResourceMetrics() error = %v, wantErr %v", err, tt.wantErr)
72+
return
73+
}
74+
})
75+
}
76+
}

pkg/customresourcestate/registry_factory.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ type compiledEach compiledMetric
118118
type compiledCommon struct {
119119
labelFromPath map[string]valuePath
120120
path valuePath
121+
t metric.Type
121122
}
122123

123124
func (c compiledCommon) Path() valuePath {
@@ -126,6 +127,9 @@ func (c compiledCommon) Path() valuePath {
126127
func (c compiledCommon) LabelFromPath() map[string]valuePath {
127128
return c.labelFromPath
128129
}
130+
func (c compiledCommon) Type() metric.Type {
131+
return c.t
132+
}
129133

130134
type eachValue struct {
131135
Labels map[string]string
@@ -136,6 +140,7 @@ type compiledMetric interface {
136140
Values(v interface{}) (result []eachValue, err []error)
137141
Path() valuePath
138142
LabelFromPath() map[string]valuePath
143+
Type() metric.Type
139144
}
140145

141146
// newCompiledMetric returns a compiledMetric depending given the metric type.
@@ -146,6 +151,7 @@ func newCompiledMetric(m Metric) (compiledMetric, error) {
146151
return nil, errors.New("expected each.gauge to not be nil")
147152
}
148153
cc, err := compileCommon(m.Gauge.MetricMeta)
154+
cc.t = metric.Gauge
149155
if err != nil {
150156
return nil, fmt.Errorf("each.gauge: %w", err)
151157
}
@@ -164,6 +170,7 @@ func newCompiledMetric(m Metric) (compiledMetric, error) {
164170
return nil, errors.New("expected each.info to not be nil")
165171
}
166172
cc, err := compileCommon(m.Info.MetricMeta)
173+
cc.t = metric.Info
167174
if err != nil {
168175
return nil, fmt.Errorf("each.info: %w", err)
169176
}
@@ -176,6 +183,7 @@ func newCompiledMetric(m Metric) (compiledMetric, error) {
176183
return nil, errors.New("expected each.stateSet to not be nil")
177184
}
178185
cc, err := compileCommon(m.StateSet.MetricMeta)
186+
cc.t = metric.StateSet
179187
if err != nil {
180188
return nil, fmt.Errorf("each.stateSet: %w", err)
181189
}
@@ -569,8 +577,7 @@ func famGen(f compiledFamily) generator.FamilyGenerator {
569577
errLog := klog.V(f.ErrorLogV)
570578
return generator.FamilyGenerator{
571579
Name: f.Name,
572-
// TODO(@rexagod): This should be dynamic.
573-
Type: metric.Gauge,
580+
Type: f.Each.Type(),
574581
Help: f.Help,
575582
GenerateFunc: func(obj interface{}) *metric.Family {
576583
return generate(obj.(*unstructured.Unstructured), f, errLog)

pkg/metric/metric.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,19 @@ var (
3838
)
3939

4040
// Type represents the type of a metric e.g. a counter. See
41-
// https://prometheus.io/docs/concepts/metric_types/.
41+
// https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md#metric-types.
4242
type Type string
4343

44-
// Gauge defines a Prometheus gauge.
44+
// Gauge defines a OpenMetrics gauge.
4545
var Gauge Type = "gauge"
4646

47-
// Counter defines a Prometheus counter.
47+
// Info defines an OpenMetrics info.
48+
var Info Type = "info"
49+
50+
// StateSet defines an OpenMetrics stateset.
51+
var StateSet Type = "stateset"
52+
53+
// Counter defines a OpenMetrics counter.
4854
var Counter Type = "counter"
4955

5056
// Metric represents a single time series.

0 commit comments

Comments
 (0)