Skip to content
Open
Show file tree
Hide file tree
Changes from 8 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
87 changes: 66 additions & 21 deletions pkg/customresourcestate/registry_factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,16 +279,34 @@ func (c *compiledGauge) Values(v interface{}) (result []eachValue, errs []error)
}
case []interface{}:
for i, it := range iter {
value, err := c.value(it)
if err != nil {
onError(fmt.Errorf("[%d]: %w", i, err))
continue
}
if value == nil {
continue
// 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)
}
} else {
value, err := c.value(it)
if err != nil {
onError(fmt.Errorf("[%d]: %w", i, err))
continue
}
if value == nil {
continue
}
addPathLabels(it, c.LabelFromPath(), value.Labels)
result = append(result, *value)
}
addPathLabels(it, c.LabelFromPath(), value.Labels)
result = append(result, *value)
}
default:
value, err := c.value(v)
Expand Down Expand Up @@ -582,7 +600,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 +676,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