diff --git a/pkg/customresourcestate/custom_resource_metrics_test.go b/pkg/customresourcestate/custom_resource_metrics_test.go new file mode 100644 index 0000000000..9f1e1cdcd3 --- /dev/null +++ b/pkg/customresourcestate/custom_resource_metrics_test.go @@ -0,0 +1,60 @@ +package customresourcestate + +import ( + "testing" +) + +func TestNewCustomResourceMetrics(t *testing.T) { + tests := []struct { + r Resource + wantErr bool + name string + }{ + { + // https://github.com/kubernetes/kube-state-metrics/issues/1886 + name: "dynamic metric type (not just hardcoded to gauge)", + r: Resource{ + GroupVersionKind: GroupVersionKind{ + Group: "apps", + Version: "v1", + Kind: "Deployment", + }, + Labels: Labels{ + LabelsFromPath: map[string][]string{ + "name": {"metadata", "name"}, + }, + }, + Metrics: []Generator{ + { + Name: "test_metrics", + Help: "metrics for testing", + Each: Metric{ + Type: MetricTypeInfo, + Info: &MetricInfo{ + MetricMeta: MetricMeta{ + Path: []string{ + "metadata", + "annotations", + }, + }, + LabelFromKey: "test", + }, + }, + }, + }, + }, + wantErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + v, err := NewCustomResourceMetrics(tt.r) + expectedError := v.(*customResourceMetrics).Families[0].Each.Type() != "info" + if (err != nil) != tt.wantErr || expectedError { + t.Errorf("NewCustomResourceMetrics() error = %v, wantErr %v", err, tt.wantErr) + return + } + }) + } +} diff --git a/pkg/customresourcestate/registry_factory.go b/pkg/customresourcestate/registry_factory.go index 2c9ae80297..e027cae8e7 100644 --- a/pkg/customresourcestate/registry_factory.go +++ b/pkg/customresourcestate/registry_factory.go @@ -118,6 +118,7 @@ type compiledEach compiledMetric type compiledCommon struct { labelFromPath map[string]valuePath path valuePath + t metric.Type } func (c compiledCommon) Path() valuePath { @@ -126,6 +127,9 @@ func (c compiledCommon) Path() valuePath { func (c compiledCommon) LabelFromPath() map[string]valuePath { return c.labelFromPath } +func (c compiledCommon) Type() metric.Type { + return c.t +} type eachValue struct { Labels map[string]string @@ -136,6 +140,7 @@ type compiledMetric interface { Values(v interface{}) (result []eachValue, err []error) Path() valuePath LabelFromPath() map[string]valuePath + Type() metric.Type } // newCompiledMetric returns a compiledMetric depending given the metric type. @@ -146,6 +151,7 @@ func newCompiledMetric(m Metric) (compiledMetric, error) { return nil, errors.New("expected each.gauge to not be nil") } cc, err := compileCommon(m.Gauge.MetricMeta) + cc.t = metric.Gauge if err != nil { return nil, fmt.Errorf("each.gauge: %w", err) } @@ -164,6 +170,7 @@ func newCompiledMetric(m Metric) (compiledMetric, error) { return nil, errors.New("expected each.info to not be nil") } cc, err := compileCommon(m.Info.MetricMeta) + cc.t = metric.Info if err != nil { return nil, fmt.Errorf("each.info: %w", err) } @@ -176,6 +183,7 @@ func newCompiledMetric(m Metric) (compiledMetric, error) { return nil, errors.New("expected each.stateSet to not be nil") } cc, err := compileCommon(m.StateSet.MetricMeta) + cc.t = metric.StateSet if err != nil { return nil, fmt.Errorf("each.stateSet: %w", err) } @@ -569,8 +577,7 @@ func famGen(f compiledFamily) generator.FamilyGenerator { errLog := klog.V(f.ErrorLogV) return generator.FamilyGenerator{ Name: f.Name, - // TODO(@rexagod): This should be dynamic. - Type: metric.Gauge, + Type: f.Each.Type(), Help: f.Help, GenerateFunc: func(obj interface{}) *metric.Family { return generate(obj.(*unstructured.Unstructured), f, errLog) diff --git a/pkg/metric/metric.go b/pkg/metric/metric.go index 96bf8c8063..ccfd65c027 100644 --- a/pkg/metric/metric.go +++ b/pkg/metric/metric.go @@ -38,12 +38,19 @@ var ( ) // Type represents the type of a metric e.g. a counter. See -// https://prometheus.io/docs/concepts/metric_types/. +// https://prometheus.io/docs/concepts/metric_types/ and, +// https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md#metric-types. type Type string // Gauge defines a Prometheus gauge. var Gauge Type = "gauge" +// Info defines an OpenMetrics info. +var Info Type = "info" + +// StateSet defines an OpenMetrics stateset. +var StateSet Type = "stateset" + // Counter defines a Prometheus counter. var Counter Type = "counter"