Skip to content

Commit 8ac04e4

Browse files
authored
Remove ParseJSONQuery function and replace it with unstructured (#469)
* Remove ParseJSONQuery function and replace it with unstructured functions * Better error formatting * Fix the attributes
1 parent d1a9d73 commit 8ac04e4

File tree

7 files changed

+89
-102
lines changed

7 files changed

+89
-102
lines changed

pkg/gatherers/clusterconfig/install_plans.go

+30-38
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88

99
"k8s.io/apimachinery/pkg/api/errors"
1010
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
11+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
1112
"k8s.io/apimachinery/pkg/runtime/schema"
1213
"k8s.io/apimachinery/pkg/util/json"
1314
"k8s.io/client-go/dynamic"
@@ -21,6 +22,20 @@ import (
2122
// InstallPlansTopX is the Maximal number of Install plans by non-unique instances count
2223
const InstallPlansTopX = 100
2324

25+
type collectedPlan struct {
26+
Namespace string
27+
Name string
28+
CSV string
29+
Count int
30+
}
31+
32+
// InstallPlanAnonymizer implements serialization of top x installplans
33+
type InstallPlanAnonymizer struct {
34+
v map[string]*collectedPlan
35+
total int
36+
limit int
37+
}
38+
2439
// GatherInstallPlans collects Top x InstallPlans from all openshift namespaces.
2540
// Because InstallPlans have unique generated names, it groups them by namespace and the "template"
2641
// for name generation from field generateName.
@@ -78,11 +93,12 @@ func gatherInstallPlans(ctx context.Context,
7893
return nil, []error{err}
7994
}
8095
jsonMap := u.UnstructuredContent()
81-
var items []interface{}
82-
err = failEarly(
83-
func() error { return utils.ParseJSONQuery(jsonMap, "metadata.continue?", &cont) },
84-
func() error { return utils.ParseJSONQuery(jsonMap, "items", &items) },
85-
)
96+
// continue will not be always present - we can ignore the return bool value
97+
cont, _, err = unstructured.NestedString(jsonMap, "metadata", "continue")
98+
if err != nil {
99+
return nil, []error{err}
100+
}
101+
items, err := utils.NestedSliceWrapper(jsonMap, "items")
86102
if err != nil {
87103
return nil, []error{err}
88104
}
@@ -105,21 +121,21 @@ func gatherInstallPlans(ctx context.Context,
105121
func collectInstallPlan(recs map[string]*collectedPlan, item interface{}) []error {
106122
// Get common prefix
107123
csv := "[NONE]"
108-
var clusterServiceVersionNames []interface{}
109-
var ns, genName string
110124
var itemMap map[string]interface{}
111125
var ok bool
112126
if itemMap, ok = item.(map[string]interface{}); !ok {
113127
return []error{fmt.Errorf("cannot cast item to map %v", item)}
114128
}
115129

116-
err := failEarly(
117-
func() error {
118-
return utils.ParseJSONQuery(itemMap, "spec.clusterServiceVersionNames", &clusterServiceVersionNames)
119-
},
120-
func() error { return utils.ParseJSONQuery(itemMap, "metadata.namespace", &ns) },
121-
func() error { return utils.ParseJSONQuery(itemMap, "metadata.generateName", &genName) },
122-
)
130+
clusterServiceVersionNames, err := utils.NestedSliceWrapper(itemMap, "spec", "clusterServiceVersionNames")
131+
if err != nil {
132+
return []error{err}
133+
}
134+
ns, err := utils.NestedStringWrapper(itemMap, "metadata", "namespace")
135+
if err != nil {
136+
return []error{err}
137+
}
138+
genName, err := utils.NestedStringWrapper(itemMap, "metadata", "generateName")
123139
if err != nil {
124140
return []error{err}
125141
}
@@ -138,30 +154,6 @@ func collectInstallPlan(recs map[string]*collectedPlan, item interface{}) []erro
138154
return nil
139155
}
140156

141-
func failEarly(fns ...func() error) error {
142-
for _, f := range fns {
143-
err := f()
144-
if err != nil {
145-
return err
146-
}
147-
}
148-
return nil
149-
}
150-
151-
type collectedPlan struct {
152-
Namespace string
153-
Name string
154-
CSV string
155-
Count int
156-
}
157-
158-
// InstallPlanAnonymizer implements serialization of top x installplans
159-
type InstallPlanAnonymizer struct {
160-
v map[string]*collectedPlan
161-
total int
162-
limit int
163-
}
164-
165157
// Marshal implements serialization of InstallPlan
166158
func (a InstallPlanAnonymizer) Marshal(_ context.Context) ([]byte, error) {
167159
if a.limit == 0 {

pkg/gatherers/clusterconfig/install_plans_test.go

+1-4
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ import (
1515
"k8s.io/apimachinery/pkg/runtime/serializer/yaml"
1616
dynamicfake "k8s.io/client-go/dynamic/fake"
1717
kubefake "k8s.io/client-go/kubernetes/fake"
18-
19-
"github.com/openshift/insights-operator/pkg/utils"
2018
)
2119

2220
//nolint: funlen, lll, gocyclo
@@ -79,8 +77,7 @@ func Test_InstallPlans_Gather(t *testing.T) {
7977
}
8078
gv, _ := schema.ParseGroupVersion(installplan.GetAPIVersion())
8179
gvr := schema.GroupVersionResource{Version: gv.Version, Group: gv.Group, Resource: "installplans"}
82-
var ns string
83-
err = utils.ParseJSONQuery(installplan.Object, "metadata.namespace", &ns)
80+
ns, _, err := unstructured.NestedString(installplan.Object, "metadata", "namespace")
8481
if err != nil {
8582
t.Fatal("unable to read ns ", err)
8683
}

pkg/gatherers/clusterconfig/olm_operators.go

+5-7
Original file line numberDiff line numberDiff line change
@@ -64,17 +64,16 @@ func gatherOLMOperators(ctx context.Context, dynamicClient dynamic.Interface) ([
6464
if err != nil {
6565
return nil, []error{err}
6666
}
67-
var refs []interface{}
6867
olms := []olmOperator{}
6968
errs := []error{}
7069
for _, i := range olmOperators.Items {
7170
newOlm := olmOperator{
7271
Name: i.GetName(),
7372
}
74-
err := utils.ParseJSONQuery(i.Object, "status.components.refs", &refs)
73+
refs, err := utils.NestedSliceWrapper(i.Object, "status", "components", "refs")
7574
if err != nil {
7675
// if no references are found then add an error and OLM operator with only name and continue
77-
errs = append(errs, fmt.Errorf("cannot find \"status.components.refs\" in %s definition: %v", i.GetName(), err))
76+
errs = append(errs, fmt.Errorf("cannot find \"status.components.refs\" in %s definition", i.GetName()))
7877
olms = append(olms, newOlm)
7978
continue
8079
}
@@ -182,14 +181,13 @@ func getCsvFromRef(ctx context.Context, dynamicClient dynamic.Interface, csvRef
182181
// parseCsv tries to parse "status.conditions" and "spec.displayName" from the input map.
183182
// Returns an error if any of the values cannot be parsed.
184183
func parseCsv(csv map[string]interface{}) (name string, conditions []interface{}, err error) {
185-
err = utils.ParseJSONQuery(csv, "status.conditions", &conditions)
184+
conditions, err = utils.NestedSliceWrapper(csv, "status", "conditions")
186185
if err != nil {
187186
return "", nil, err
188187
}
189-
err = utils.ParseJSONQuery(csv, "spec.displayName", &name)
188+
name, err = utils.NestedStringWrapper(csv, "spec", "displayName")
190189
if err != nil {
191190
return "", nil, err
192191
}
193-
194-
return name, conditions, nil
192+
return
195193
}

pkg/gatherers/clusterconfig/olm_operators_test.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func Test_OLMOperators_Gather(t *testing.T) {
5757
"Operator doesn't have CSV reference",
5858
"testdata/olm_operator_2.yaml",
5959
"testdata/csv_1.yaml",
60-
fmt.Errorf("cannot find \"status.components.refs\" in test-olm-operator-with-no-ref definition: key refs wasn't found in map[] "),
60+
fmt.Errorf("cannot find \"status.components.refs\" in test-olm-operator-with-no-ref definition"),
6161
olmOperator{
6262
Name: "test-olm-operator-with-no-ref",
6363
},
@@ -66,7 +66,7 @@ func Test_OLMOperators_Gather(t *testing.T) {
6666
"Operator CSV doesn't have the displayName",
6767
"testdata/olm_operator_1.yaml",
6868
"testdata/csv_2.yaml",
69-
fmt.Errorf("cannot read test-olm-operator.v1.2.3 ClusterServiceVersion attributes: key displayName wasn't found in map[] "),
69+
fmt.Errorf("cannot read test-olm-operator.v1.2.3 ClusterServiceVersion attributes: can't find spec.displayName"),
7070
olmOperator{
7171
Name: "test-olm-operator",
7272
Version: "v1.2.3",
@@ -116,7 +116,7 @@ func Test_OLMOperators_Gather(t *testing.T) {
116116
}
117117
}
118118
if len(records) != 1 {
119-
t.Fatalf("unexpected number or records %d", len(records))
119+
t.Fatalf("unexpected number of records %d", len(records))
120120
}
121121
ooa, ok := records[0].Item.(record.JSONMarshaller).Object.([]olmOperator)
122122
if !ok {

pkg/gatherers/clusterconfig/operators.go

+9-6
Original file line numberDiff line numberDiff line change
@@ -151,12 +151,15 @@ func collectClusterOperatorResources(ctx context.Context,
151151
if clusterResource == nil {
152152
continue
153153
}
154-
var kind, name, apiVersion string
155-
err = failEarly(
156-
func() error { return utils.ParseJSONQuery(clusterResource.Object, "kind", &kind) },
157-
func() error { return utils.ParseJSONQuery(clusterResource.Object, "apiVersion", &apiVersion) },
158-
func() error { return utils.ParseJSONQuery(clusterResource.Object, "metadata.name", &name) },
159-
)
154+
kind, err := utils.NestedStringWrapper(clusterResource.Object, "kind")
155+
if err != nil {
156+
continue
157+
}
158+
apiVersion, err := utils.NestedStringWrapper(clusterResource.Object, "apiVersion")
159+
if err != nil {
160+
continue
161+
}
162+
name, err := utils.NestedStringWrapper(clusterResource.Object, "metadata", "name")
160163
if err != nil {
161164
continue
162165
}

pkg/utils/parse_json_query.go

-44
This file was deleted.

pkg/utils/unstructerd_wrappers.go

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package utils
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
7+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
8+
)
9+
10+
func NestedStringWrapper(obj map[string]interface{}, fields ...string) (string, error) {
11+
s, ok, err := unstructured.NestedString(obj, fields...)
12+
if !ok {
13+
return "", fmt.Errorf("can't find %s", formatSlice(fields...))
14+
}
15+
if err != nil {
16+
return "", err
17+
}
18+
19+
return s, nil
20+
}
21+
22+
func NestedSliceWrapper(obj map[string]interface{}, fields ...string) ([]interface{}, error) {
23+
s, ok, err := unstructured.NestedSlice(obj, fields...)
24+
if !ok {
25+
return nil, fmt.Errorf("can't find %s", formatSlice(fields...))
26+
}
27+
if err != nil {
28+
return nil, err
29+
}
30+
31+
return s, nil
32+
}
33+
34+
func formatSlice(s ...string) string {
35+
var str string
36+
for _, f := range s {
37+
str += fmt.Sprintf("%s.", f)
38+
}
39+
str = strings.TrimRight(str, ".")
40+
return str
41+
}

0 commit comments

Comments
 (0)