Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions pkg/customresourcestate/example_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ spec:
path: [status, other]
errorLogV: 5

- name: "other_count_array_deep"
each:
type: Gauge
gauge:
path: [ status, other, '[*]', detail ]
errorLogV: 5

- name: "info"
each:
type: Info
Expand Down
70 changes: 58 additions & 12 deletions pkg/customresourcestate/registry_factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,25 @@ func (c *compiledGauge) Values(v interface{}) (result []eachValue, errs []error)
}
case []interface{}:
for i, it := range iter {
// Check if it is a [][]interface{} if yes loop over it
// Else process normally
if nestedIter, ok := it.([]interface{}); ok {
for j, nestedIt := range nestedIter {
value, err := c.value(nestedIt)

if err != nil {
onError(fmt.Errorf("[%d]: %w", j, err))
continue
}
if value == nil {
continue
}
addPathLabels(nestedIt, c.LabelFromPath(), value.Labels)
result = append(result, *value)
}
continue
}

value, err := c.value(it)
if err != nil {
onError(fmt.Errorf("[%d]: %w", i, err))
Expand Down Expand Up @@ -582,7 +601,24 @@ func (p valuePath) String() string {
func compilePath(path []string) (out valuePath, _ error) {
for i := range path {
part := path[i]

if strings.HasPrefix(part, "[") && strings.HasSuffix(part, "]") {

// Wildcard with filter: [*]
if part == "[*]" {
// function to return all elements in a list
out = append(out, pathOp{
part: part,
op: func(m interface{}) interface{} {
if s, ok := m.([]interface{}); ok {
return s
}
return nil
},
})
continue
}

// list lookup: [key=value]
eq := strings.SplitN(part[1:len(part)-1], "=", 2)
if len(eq) != 2 {
Expand Down Expand Up @@ -641,21 +677,31 @@ func compilePath(path []string) (out valuePath, _ error) {
}
return mp[part]
} else if s, ok := m.([]interface{}); ok {
// case part is an integer index
i, err := strconv.Atoi(part)
if err != nil {
// This means we are here: [ <string>, <int>, ... ] (eg., [ "foo", "0", ... ], i.e., <path>.foo[0]...
// ^
// Skip over.
return nil
}
if i < 0 {
// negative index
i += len(s)
if err == nil {
if i < 0 {
// negative index
i += len(s)
}
if i < 0 || i >= len(s) {
return fmt.Errorf("list index out of range: %s", part)
}
return s[i]
}
if i < 0 || i >= len(s) {
return fmt.Errorf("list index out of range: %s", part)

// case we have a list and the part is an index
var result []interface{}
for _, el := range s {
if m, ok := el.(map[string]interface{}); ok {
if v, ok := m[part]; ok {
result = append(result, v)
}
} else {
continue
}
}
return s[i]
return result
}
return nil
},
Expand Down
71 changes: 71 additions & 0 deletions pkg/customresourcestate/registry_factory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,64 @@ func init() {
"status": "False",
},
},
"parents": Array{
Obj{
"conditions": Array{
Obj{
"type": "Ready",
"status": "True",
"message": "All good",
"reason": "AsExpected",
"lastTransitionTime": "2022-06-28T00:00:00Z",
"observedGeneration": 42,
},
Obj{
"type": "Synced",
"status": "False",
"message": "Not synced",
"reason": "SyncError",
"lastTransitionTime": "2022-06-28T00:00:00Z",
"observedGeneration": 43,
},
},
"controllerName": "foo.bar/baz",
"parentRef": Obj{
"group": "foo.bar",
"kind": "Baz",
"name": "baz-1",
"namespace": "default",
},
},
Obj{
"conditions": Array{
Obj{
"type": "Ready",
"status": "False",
"message": "Not ready",
"reason": "NotReady",
"lastTransitionTime": "2022-06-28T00:00:00Z",
"observedGeneration": 44,
},
},
"controllerName": "qux.corge/grault",
"parentRef": Obj{
"group": "qux.corge",
"kind": "Grault",
"name": "grault-1",
"namespace": "default",
},
},
Obj{
"conditions": Array{},
"controllerName": "garply.waldo/fred",
"parentRef": Obj{
"group": "garply.waldo",
"kind": "Fred",
"name": "fred-1",
"namespace": "default",
},
},
},
},
"metadata": Obj{
"name": "foo",
Expand Down Expand Up @@ -352,6 +410,19 @@ func Test_values(t *testing.T) {
newEachValue(t, 0, "type", "Provisioned"),
newEachValue(t, 1, "type", "Ready"),
}},
{name: "status_parents_conditions", each: &compiledGauge{
compiledCommon: compiledCommon{
path: mustCompilePath(t, "status", "parents", "[*]", "conditions"),
labelFromPath: map[string]valuePath{
"reason": mustCompilePath(t, "reason"),
},
},
ValueFrom: mustCompilePath(t, "status"),
}, wantResult: []eachValue{
newEachValue(t, 1, "reason", "AsExpected"),
newEachValue(t, 0, "reason", "NotReady"),
newEachValue(t, 0, "reason", "SyncError"),
}},
{name: "= expression matching", each: &compiledInfo{
compiledCommon: compiledCommon{
labelFromPath: map[string]valuePath{
Expand Down