Skip to content

Commit bd2ea7a

Browse files
committed
Handle unit length valueFrom values
Handle unit length `valueFrom` values and skip strings where we expect them to be type-cast-able to `float64`, instead of erroring, since that is the expected behavior, and what's being done for other types.
1 parent 1cda0bf commit bd2ea7a

File tree

2 files changed

+63
-4
lines changed

2 files changed

+63
-4
lines changed

pkg/customresourcestate/registry_factory.go

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ type compiledMetric interface {
143143
Type() metric.Type
144144
}
145145

146-
// newCompiledMetric returns a compiledMetric depending given the metric type.
146+
// newCompiledMetric returns a compiledMetric depending on given the metric type.
147147
func newCompiledMetric(m Metric) (compiledMetric, error) {
148148
switch m.Type {
149149
case MetricTypeGauge:
@@ -217,7 +217,40 @@ func (c *compiledGauge) Values(v interface{}) (result []eachValue, errs []error)
217217
switch iter := v.(type) {
218218
case map[string]interface{}:
219219
for key, it := range iter {
220-
ev, err := c.value(it)
220+
// Try to deduce `valueFrom`'s value from the current element.
221+
var ev *eachValue
222+
var err error
223+
var didResolveValueFrom bool
224+
// `valueFrom` will ultimately be rendered into a string and sent to the fallback in place, which also expects a string.
225+
// So we'll do the same and operate on the string representation of `valueFrom`'s value.
226+
sValueFrom := c.ValueFrom.String()
227+
// No comma means we're looking at a unit-length path (in an array).
228+
if !strings.Contains(sValueFrom, ",") &&
229+
sValueFrom[0] == '[' &&
230+
// "[...]" and not "[]".
231+
len(sValueFrom) > 2 {
232+
extractedValueFrom := sValueFrom[1 : len(sValueFrom)-1]
233+
if key == extractedValueFrom {
234+
gotFloat, err := toFloat64(it, c.NilIsZero)
235+
if err != nil {
236+
onError(fmt.Errorf("[%s]: %w", key, err))
237+
continue
238+
}
239+
labels := make(map[string]string)
240+
ev = &eachValue{
241+
Labels: labels,
242+
Value: gotFloat,
243+
}
244+
didResolveValueFrom = true
245+
}
246+
}
247+
// Fallback to the regular path resolution, if we didn't manage to resolve `valueFrom`'s value.
248+
if !didResolveValueFrom {
249+
ev, err = c.value(it)
250+
if ev == nil {
251+
continue
252+
}
253+
}
221254
if err != nil {
222255
onError(fmt.Errorf("[%s]: %w", key, err))
223256
continue
@@ -387,7 +420,19 @@ func less(a, b map[string]string) bool {
387420

388421
func (c compiledGauge) value(it interface{}) (*eachValue, error) {
389422
labels := make(map[string]string)
390-
value, err := toFloat64(c.ValueFrom.Get(it), c.NilIsZero)
423+
got := c.ValueFrom.Get(it)
424+
// If `valueFrom` was not resolved, respect `NilIsZero` and return.
425+
if got == nil {
426+
if c.NilIsZero {
427+
return &eachValue{
428+
Labels: labels,
429+
Value: 0,
430+
}, nil
431+
}
432+
// Don't error if there was not a type-casting issue (`toFloat64`), but rather a failed lookup.
433+
return nil, nil
434+
}
435+
value, err := toFloat64(got, c.NilIsZero)
391436
if err != nil {
392437
return nil, fmt.Errorf("%s: %w", c.ValueFrom, err)
393438
}
@@ -554,7 +599,10 @@ func compilePath(path []string) (out valuePath, _ error) {
554599
} else if s, ok := m.([]interface{}); ok {
555600
i, err := strconv.Atoi(part)
556601
if err != nil {
557-
return fmt.Errorf("invalid list index: %s", part)
602+
// This means we are here: [ <string>, <int>, ... ] (eg., [ "foo", "0", ... ], i.e., <path>.foo[0]...
603+
// ^
604+
// Skip over.
605+
return nil
558606
}
559607
if i < 0 {
560608
// negative index

pkg/customresourcestate/registry_factory_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,17 @@ func Test_values(t *testing.T) {
173173
newEachValue(t, 2, "type", "type-a", "active", "1"),
174174
newEachValue(t, 4, "type", "type-b", "active", "3"),
175175
}},
176+
{name: "path-relative valueFrom value", each: &compiledGauge{
177+
compiledCommon: compiledCommon{
178+
path: mustCompilePath(t, "metadata"),
179+
labelFromPath: map[string]valuePath{
180+
"name": mustCompilePath(t, "name"),
181+
},
182+
},
183+
ValueFrom: mustCompilePath(t, "creationTimestamp"),
184+
}, wantResult: []eachValue{
185+
newEachValue(t, 1.6563744e+09),
186+
}},
176187
{name: "array", each: &compiledGauge{
177188
compiledCommon: compiledCommon{
178189
path: mustCompilePath(t, "status", "conditions"),

0 commit comments

Comments
 (0)