From 3c40f03593a57e9d35080d88825a9cebc723d309 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20R=C3=BCger?= Date: Mon, 27 Feb 2023 12:17:29 +0100 Subject: [PATCH] feat(customresourcestate): Support percentages --- docs/customresourcestate-metrics.md | 1 + pkg/customresourcestate/registry_factory.go | 7 +++++++ pkg/customresourcestate/registry_factory_test.go | 9 +++++++++ 3 files changed, 17 insertions(+) diff --git a/docs/customresourcestate-metrics.md b/docs/customresourcestate-metrics.md index 613c3f0276..565ab5019e 100644 --- a/docs/customresourcestate-metrics.md +++ b/docs/customresourcestate-metrics.md @@ -255,6 +255,7 @@ Supported types are: * `"true"` and `"yes"` are mapped to `1.0` and `"false"` and `"no"` are mapped to `0.0` (all case insensitive) * RFC3339 times are parsed to float timestamp * Quantities like "250m" or "512Gi" are parsed to float using https://github.com/kubernetes/apimachinery/blob/master/pkg/api/resource/quantity.go + * Percentages ending with a "%" are parsed to float * finally the string is parsed to float using https://pkg.go.dev/strconv#ParseFloat which should support all common number formats. If that fails an error is yielded ##### Example for status conditions on Kubernetes Controllers diff --git a/pkg/customresourcestate/registry_factory.go b/pkg/customresourcestate/registry_factory.go index ff250bda4a..d48d3a0e6c 100644 --- a/pkg/customresourcestate/registry_factory.go +++ b/pkg/customresourcestate/registry_factory.go @@ -27,6 +27,7 @@ import ( "k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/util/validation" "k8s.io/klog/v2" "k8s.io/kube-state-metrics/v2/pkg/metric" @@ -701,6 +702,12 @@ func toFloat64(value interface{}, nilIsZero bool) (float64, error) { if t, e := resource.ParseQuantity(value.(string)); e == nil { return t.AsApproximateFloat64(), nil } + // The string contains a percentage with a suffix "%" + if e := validation.IsValidPercent(value.(string)); len(e) == 0 { + t, e := strconv.ParseFloat(strings.TrimRight(value.(string), "%"), 64) + return t / 100, e + } + return strconv.ParseFloat(value.(string), 64) case byte: v = float64(vv) diff --git a/pkg/customresourcestate/registry_factory_test.go b/pkg/customresourcestate/registry_factory_test.go index 30576b6006..70f6db2a10 100644 --- a/pkg/customresourcestate/registry_factory_test.go +++ b/pkg/customresourcestate/registry_factory_test.go @@ -66,6 +66,7 @@ func init() { "uptime": 43.21, "quantity_milli": "250m", "quantity_binarySI": "5Gi", + "percentage": "28%", "condition_values": Array{ Obj{ "name": "a", @@ -229,6 +230,14 @@ func Test_values(t *testing.T) { }, wantResult: []eachValue{ newEachValue(t, 5.36870912e+09), }}, + {name: "percentage", each: &compiledGauge{ + compiledCommon: compiledCommon{ + path: mustCompilePath(t, "status", "percentage"), + }, + }, wantResult: []eachValue{ + newEachValue(t, 0.28), + }}, + {name: "boolean_string", each: &compiledGauge{ compiledCommon: compiledCommon{ path: mustCompilePath(t, "spec", "paused"),