From 90109b21af7d61b69fee6eb7b26698740ef96fd4 Mon Sep 17 00:00:00 2001 From: Richa Banker Date: Wed, 6 Aug 2025 20:32:57 -0700 Subject: [PATCH] Wrapper for DeleteLabelValues --- .../k8s.io/component-base/metrics/gauge.go | 19 + .../component-base/metrics/gauge_test.go | 375 ++++++++++++++++++ 2 files changed, 394 insertions(+) diff --git a/staging/src/k8s.io/component-base/metrics/gauge.go b/staging/src/k8s.io/component-base/metrics/gauge.go index 0d6c8b7fbfd..20982f67df4 100644 --- a/staging/src/k8s.io/component-base/metrics/gauge.go +++ b/staging/src/k8s.io/component-base/metrics/gauge.go @@ -161,6 +161,17 @@ func (v *GaugeVec) WithLabelValuesChecked(lvs ...string) (GaugeMetric, error) { return v.GetMetricWithLabelValues(lvs...) } +func (v *GaugeVec) DeleteLabelValuesChecked(lvs ...string) (bool, error) { + if !v.IsCreated() { + if v.IsHidden() { + return false, nil + } + return false, errNotRegistered + } + + return v.GaugeVec.DeleteLabelValues(lvs...), nil +} + // Default Prometheus Vec behavior is that member extraction results in creation of a new element // if one with the unique label values is not found in the underlying stored metricMap. // This means that if this function is called but the underlying metric is not registered @@ -184,6 +195,14 @@ func (v *GaugeVec) WithLabelValues(lvs ...string) GaugeMetric { panic(err) } +func (v *GaugeVec) DeleteLabelValues(lvs ...string) bool { + ans, err := v.DeleteLabelValuesChecked(lvs...) + if err == nil || ErrIsNotRegistered(err) { + return ans + } + panic(err) +} + func (v *GaugeVec) WithChecked(labels map[string]string) (GaugeMetric, error) { if !v.IsCreated() { if v.IsHidden() { diff --git a/staging/src/k8s.io/component-base/metrics/gauge_test.go b/staging/src/k8s.io/component-base/metrics/gauge_test.go index 82c60cf7d91..f20be35244f 100644 --- a/staging/src/k8s.io/component-base/metrics/gauge_test.go +++ b/staging/src/k8s.io/component-base/metrics/gauge_test.go @@ -593,3 +593,378 @@ func TestGaugeWithLabelValueAllowList(t *testing.T) { }) } } + +func TestGaugeVecDeleteLabelValues(t *testing.T) { + version := apimachineryversion.Info{ + Major: "1", + Minor: "15", + GitVersion: "v1.15.0-alpha-1.12345", + } + var tests = []struct { + desc string + opts *GaugeOpts + labels []string + expectMetricExists bool + expectDelete bool + }{ + // Non-deprecated metrics + { + desc: "ALPHA metric non deprecated", + opts: &GaugeOpts{ + Namespace: "namespace", + Name: "metric_delete_table", + Subsystem: "subsystem", + Help: "gauge help", + StabilityLevel: ALPHA, + }, + labels: []string{"label_a", "label_b"}, + expectMetricExists: true, + expectDelete: true, + }, + { + desc: "BETA metric non deprecated", + opts: &GaugeOpts{ + Namespace: "namespace", + Name: "metric_delete_table", + Subsystem: "subsystem", + Help: "gauge help", + StabilityLevel: BETA, + }, + labels: []string{"label_a", "label_b"}, + expectMetricExists: true, + expectDelete: true, + }, + { + desc: "STABLE metric non deprecated", + opts: &GaugeOpts{ + Namespace: "namespace", + Name: "metric_delete_table", + Subsystem: "subsystem", + Help: "gauge help", + StabilityLevel: STABLE, + }, + labels: []string{"label_a", "label_b"}, + expectMetricExists: true, + expectDelete: true, + }, + // Deprecated metrics + { + desc: "ALPHA metric deprecated", + opts: &GaugeOpts{ + Namespace: "namespace", + Name: "metric_delete_table", + Subsystem: "subsystem", + Help: "gauge help", + StabilityLevel: ALPHA, + DeprecatedVersion: "1.15.0", + }, + labels: []string{"label_a", "label_b"}, + expectMetricExists: false, + expectDelete: false, + }, + { + desc: "BETA metric deprecated", + opts: &GaugeOpts{ + Namespace: "namespace", + Name: "metric_delete_table", + Subsystem: "subsystem", + Help: "gauge help", + StabilityLevel: BETA, + DeprecatedVersion: "1.15.0", + }, + labels: []string{"label_a", "label_b"}, + expectMetricExists: true, + expectDelete: true, + }, + { + desc: "STABLE metric deprecated", + opts: &GaugeOpts{ + Namespace: "namespace", + Name: "metric_delete_table", + Subsystem: "subsystem", + Help: "gauge help", + StabilityLevel: STABLE, + DeprecatedVersion: "1.15.0", + }, + labels: []string{"label_a", "label_b"}, + expectMetricExists: true, + expectDelete: true, + }, + // Hidden metrics + { + desc: "ALPHA metric hidden", + opts: &GaugeOpts{ + Namespace: "namespace", + Name: "metric_delete_table", + Subsystem: "subsystem", + Help: "gauge help", + StabilityLevel: ALPHA, + DeprecatedVersion: "1.14.0", + }, + labels: []string{"label_a", "label_b"}, + expectMetricExists: false, + expectDelete: false, + }, + { + desc: "BETA metric hidden", + opts: &GaugeOpts{ + Namespace: "namespace", + Name: "metric_delete_table", + Subsystem: "subsystem", + Help: "gauge help", + StabilityLevel: BETA, + DeprecatedVersion: "1.14.0", + }, + labels: []string{"label_a", "label_b"}, + expectMetricExists: false, + expectDelete: false, + }, + { + desc: "STABLE metric hidden", + opts: &GaugeOpts{ + Namespace: "namespace", + Name: "metric_delete_table", + Subsystem: "subsystem", + Help: "gauge help", + StabilityLevel: STABLE, + DeprecatedVersion: "1.12.0", + }, + labels: []string{"label_a", "label_b"}, + expectMetricExists: false, + expectDelete: false, + }, + } + + for _, test := range tests { + t.Run(test.desc, func(t *testing.T) { + registry := newKubeRegistry(version) + gv := NewGaugeVec(test.opts, test.labels) + registry.MustRegister(gv) + gv.WithLabelValues("foo", "bar").Set(42) + + ms, err := registry.Gather() + require.NoError(t, err) + found := false + for _, mf := range ms { + if *mf.Name == BuildFQName(test.opts.Namespace, test.opts.Subsystem, test.opts.Name) { + for _, m := range mf.GetMetric() { + for _, l := range m.Label { + if *l.Name == "label_a" && *l.Value == "foo" { + found = true + } + } + } + } + } + assert.Equal(t, test.expectMetricExists, found, "Metric existence mismatch before deletion") + + deleted := gv.DeleteLabelValues("foo", "bar") + assert.Equal(t, test.expectDelete, deleted, "DeleteLabelValues return mismatch") + + // Confirm it no longer exists + ms, err = registry.Gather() + require.NoError(t, err) + found = false + for _, mf := range ms { + if *mf.Name == BuildFQName(test.opts.Namespace, test.opts.Subsystem, test.opts.Name) { + for _, m := range mf.GetMetric() { + for _, l := range m.Label { + if *l.Name == "label_a" && *l.Value == "foo" { + found = true + } + } + } + } + } + assert.False(t, found, "Metric with label values should not exist after deletion") + }) + } +} + +func TestGaugeVecDeleteLabelValuesChecked(t *testing.T) { + version := apimachineryversion.Info{ + Major: "1", + Minor: "15", + GitVersion: "v1.15.0-alpha-1.12345", + } + var tests = []struct { + desc string + opts *GaugeOpts + labels []string + expectMetricExists bool + expectDelete bool + }{ + // Non-deprecated metrics + { + desc: "ALPHA metric non deprecated", + opts: &GaugeOpts{ + Namespace: "namespace", + Name: "metric_delete_checked_table", + Subsystem: "subsystem", + Help: "gauge help", + StabilityLevel: ALPHA, + }, + labels: []string{"label_a", "label_b"}, + expectMetricExists: true, + expectDelete: true, + }, + { + desc: "BETA metric non deprecated", + opts: &GaugeOpts{ + Namespace: "namespace", + Name: "metric_delete_checked_table", + Subsystem: "subsystem", + Help: "gauge help", + StabilityLevel: BETA, + }, + labels: []string{"label_a", "label_b"}, + expectMetricExists: true, + expectDelete: true, + }, + { + desc: "STABLE metric non deprecated", + opts: &GaugeOpts{ + Namespace: "namespace", + Name: "metric_delete_checked_table", + Subsystem: "subsystem", + Help: "gauge help", + StabilityLevel: STABLE, + }, + labels: []string{"label_a", "label_b"}, + expectMetricExists: true, + expectDelete: true, + }, + // Deprecated metrics + { + desc: "ALPHA metric deprecated", + opts: &GaugeOpts{ + Namespace: "namespace", + Name: "metric_delete_checked_table", + Subsystem: "subsystem", + Help: "gauge help", + StabilityLevel: ALPHA, + DeprecatedVersion: "1.15.0", + }, + labels: []string{"label_a", "label_b"}, + expectMetricExists: false, + expectDelete: false, + }, + { + desc: "BETA metric deprecated", + opts: &GaugeOpts{ + Namespace: "namespace", + Name: "metric_delete_checked_table", + Subsystem: "subsystem", + Help: "gauge help", + StabilityLevel: BETA, + DeprecatedVersion: "1.15.0", + }, + labels: []string{"label_a", "label_b"}, + expectMetricExists: true, + expectDelete: true, + }, + { + desc: "STABLE metric deprecated", + opts: &GaugeOpts{ + Namespace: "namespace", + Name: "metric_delete_checked_table", + Subsystem: "subsystem", + Help: "gauge help", + StabilityLevel: STABLE, + DeprecatedVersion: "1.15.0", + }, + labels: []string{"label_a", "label_b"}, + expectMetricExists: true, + expectDelete: true, + }, + // Hidden metrics + { + desc: "ALPHA metric hidden", + opts: &GaugeOpts{ + Namespace: "namespace", + Name: "metric_delete_checked_table", + Subsystem: "subsystem", + Help: "gauge help", + StabilityLevel: ALPHA, + DeprecatedVersion: "1.14.0", + }, + labels: []string{"label_a", "label_b"}, + expectMetricExists: false, + expectDelete: false, + }, + { + desc: "BETA metric hidden", + opts: &GaugeOpts{ + Namespace: "namespace", + Name: "metric_delete_checked_table", + Subsystem: "subsystem", + Help: "gauge help", + StabilityLevel: BETA, + DeprecatedVersion: "1.14.0", + }, + labels: []string{"label_a", "label_b"}, + expectMetricExists: false, + expectDelete: false, + }, + { + desc: "STABLE metric hidden", + opts: &GaugeOpts{ + Namespace: "namespace", + Name: "metric_delete_checked_table", + Subsystem: "subsystem", + Help: "gauge help", + StabilityLevel: STABLE, + DeprecatedVersion: "1.12.0", + }, + labels: []string{"label_a", "label_b"}, + expectMetricExists: false, + expectDelete: false, + }, + } + + for _, test := range tests { + t.Run(test.desc, func(t *testing.T) { + registry := newKubeRegistry(version) + gv := NewGaugeVec(test.opts, test.labels) + registry.MustRegister(gv) + gv.WithLabelValues("foo", "bar").Set(42) + + ms, err := registry.Gather() + require.NoError(t, err) + found := false + for _, mf := range ms { + if *mf.Name == BuildFQName(test.opts.Namespace, test.opts.Subsystem, test.opts.Name) { + for _, m := range mf.GetMetric() { + for _, l := range m.Label { + if *l.Name == "label_a" && *l.Value == "foo" { + found = true + } + } + } + } + } + assert.Equal(t, test.expectMetricExists, found, "Metric existence mismatch before deletion") + + deleted, err := gv.DeleteLabelValuesChecked("foo", "bar") + assert.Equal(t, test.expectDelete, deleted, "DeleteLabelValuesChecked return mismatch") + require.NoError(t, err, "DeleteLabelValuesChecked should not return error") + + // Confirm it no longer exists + ms, err = registry.Gather() + require.NoError(t, err) + found = false + for _, mf := range ms { + if *mf.Name == BuildFQName(test.opts.Namespace, test.opts.Subsystem, test.opts.Name) { + for _, m := range mf.GetMetric() { + for _, l := range m.Label { + if *l.Name == "label_a" && *l.Value == "foo" { + found = true + } + } + } + } + } + assert.False(t, found, "Metric with label values should not exist after deletion") + }) + } +}