@@ -2,12 +2,11 @@ package clusterconfig
2
2
3
3
import (
4
4
"context"
5
- "encoding/json "
5
+ "fmt "
6
6
"strings"
7
7
8
8
"k8s.io/apimachinery/pkg/api/errors"
9
9
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10
- "k8s.io/klog/v2"
11
10
12
11
"k8s.io/apimachinery/pkg/runtime/schema"
13
12
"k8s.io/client-go/dynamic"
@@ -17,13 +16,17 @@ import (
17
16
18
17
var (
19
18
operatorGVR = schema.GroupVersionResource {Group : "operators.coreos.com" , Version : "v1" , Resource : "operators" }
20
- clusterServiceVersionGVR = schema.GroupVersionResource {Group : "operators.coreos.com" , Version : "v1alpha1" , Resource : "clusterserviceversions" }
19
+ clusterServiceVersionGVR = schema.GroupVersionResource {
20
+ Group : "operators.coreos.com" ,
21
+ Version : "v1alpha1" ,
22
+ Resource : "clusterserviceversions" }
21
23
)
22
24
23
25
type olmOperator struct {
24
- Name string `json:"name"`
25
- Version string `json:"version"`
26
- Conditions []interface {} `json:"csv_conditions"`
26
+ Name string `json:"name"`
27
+ DisplayName string `json:"displayName"`
28
+ Version string `json:"version"`
29
+ Conditions []interface {} `json:"csv_conditions"`
27
30
}
28
31
29
32
// ClusterServiceVersion helper struct
@@ -63,39 +66,56 @@ func gatherOLMOperators(ctx context.Context, dynamicClient dynamic.Interface) ([
63
66
}
64
67
var refs []interface {}
65
68
olms := []olmOperator {}
69
+ errs := []error {}
66
70
for _ , i := range olmOperators .Items {
71
+ newOlm := olmOperator {
72
+ Name : i .GetName (),
73
+ }
67
74
err := parseJSONQuery (i .Object , "status.components.refs" , & refs )
68
75
if err != nil {
69
- klog .Errorf ("Cannot find \" status.components.refs\" in %s definition: %v" , i .GetName (), err )
76
+ // 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 ))
78
+ olms = append (olms , newOlm )
70
79
continue
71
80
}
72
81
for _ , r := range refs {
73
- csvRef := getCSVRefFromRefs (r )
82
+ csvRef , err := findCSVRefInRefs (r )
83
+ if err != nil {
84
+ errs = append (errs , err )
85
+ olms = append (olms , newOlm )
86
+ continue
87
+ }
88
+ // CSV reference can still be nil
74
89
if csvRef == nil {
75
90
continue
76
91
}
77
- conditions , err := getCSVConditions (ctx , dynamicClient , csvRef )
92
+ newOlm .Version = csvRef .Version
93
+
94
+ name , conditions , err := getCSVAndParse (ctx , dynamicClient , csvRef )
78
95
if err != nil {
79
- klog .Errorf ("failed to get %s conditions: %v" , csvRef .Name , err )
96
+ // append the error and the OLM data we already have and continue
97
+ errs = append (errs , err )
98
+ olms = append (olms , newOlm )
80
99
continue
81
100
}
82
- olmO := olmOperator {
83
- Name : i .GetName (),
84
- Version : csvRef .Version ,
85
- Conditions : conditions ,
86
- }
87
- if isInArray (olmO , olms ) {
101
+ newOlm .DisplayName = name
102
+ newOlm .Conditions = conditions
103
+
104
+ if isInArray (newOlm , olms ) {
88
105
continue
89
106
}
90
- olms = append (olms , olmO )
107
+ olms = append (olms , newOlm )
91
108
}
92
109
}
93
110
if len (olms ) == 0 {
94
111
return nil , nil
95
112
}
96
113
r := record.Record {
97
114
Name : "config/olm_operators" ,
98
- Item : OlmOperatorAnonymizer {operators : olms },
115
+ Item : record.JSONMarshaller {Object : olms },
116
+ }
117
+ if len (errs ) != 0 {
118
+ return []record.Record {r }, errs
99
119
}
100
120
return []record.Record {r }, nil
101
121
}
@@ -109,48 +129,67 @@ func isInArray(o olmOperator, a []olmOperator) bool {
109
129
return false
110
130
}
111
131
112
- func getCSVRefFromRefs (r interface {}) * csvRef {
132
+ //getCSVAndParse gets full CSV definition from csvRef and tries to parse the definition
133
+ func getCSVAndParse (ctx context.Context , dynamicClient dynamic.Interface , csvRef * csvRef ) (name string , conditions []interface {}, err error ) {
134
+ csv , err := getCsvFromRef (ctx , dynamicClient , csvRef )
135
+ if err != nil {
136
+ return "" , nil , fmt .Errorf ("failed to get %s ClusterServiceVersion: %v" , csvRef .Name , err )
137
+ }
138
+ name , conditions , err = parseCsv (csv )
139
+
140
+ if err != nil {
141
+ return "" , nil , fmt .Errorf ("cannot read %s ClusterServiceVersion attributes: %v" , csvRef .Name , err )
142
+ }
143
+
144
+ return name , conditions , nil
145
+ }
146
+
147
+ //findCSVRefInRefs tries to find ClusterServiceVersion reference in the references
148
+ //and parse the ClusterServiceVersion if successful.
149
+ //It can return nil with no error if the CSV was not found
150
+ func findCSVRefInRefs (r interface {}) (* csvRef , error ) {
113
151
refMap , ok := r .(map [string ]interface {})
114
152
if ! ok {
115
- klog .Errorf ("Cannot convert %s to map[string]interface{}" , r )
116
- return nil
153
+ return nil , fmt .Errorf ("cannot convert %s to map[string]interface{}" , r )
117
154
}
118
155
// version is part of the name of ClusterServiceVersion
119
156
if refMap ["kind" ] == "ClusterServiceVersion" {
120
157
name := refMap ["name" ].(string )
158
+ if ! strings .Contains (name , "." ) {
159
+ return nil , fmt .Errorf ("clusterserviceversion \" %s\" probably doesn't include version" , name )
160
+ }
121
161
nameVer := strings .SplitN (name , "." , 2 )
122
162
csvRef := & csvRef {
123
163
Name : name ,
124
164
Namespace : refMap ["namespace" ].(string ),
125
165
Version : nameVer [1 ],
126
166
}
127
- return csvRef
167
+ return csvRef , nil
128
168
}
129
- return nil
169
+ return nil , nil
130
170
}
131
171
132
- func getCSVConditions (ctx context.Context , dynamicClient dynamic.Interface , csvRef * csvRef ) ([ ]interface {}, error ) {
172
+ func getCsvFromRef (ctx context.Context , dynamicClient dynamic.Interface , csvRef * csvRef ) (map [ string ]interface {}, error ) {
133
173
csv , err := dynamicClient .Resource (clusterServiceVersionGVR ).Namespace (csvRef .Namespace ).Get (ctx , csvRef .Name , metav1.GetOptions {})
134
174
if err != nil {
135
175
return nil , err
136
176
}
177
+ return csv .Object , nil
178
+ }
179
+
180
+ //parseCsv tries to parse "status.conditions" and "spec.displayName" from the input map.
181
+ // Returns an error if any of the values cannot be parsed.
182
+ func parseCsv (csv map [string ]interface {}) (string , []interface {}, error ) {
137
183
var conditions []interface {}
138
- err = parseJSONQuery (csv .Object , "status.conditions" , & conditions )
184
+ var name string
185
+ err := parseJSONQuery (csv , "status.conditions" , & conditions )
139
186
if err != nil {
140
- return nil , err
187
+ return "" , nil , err
188
+ }
189
+ err = parseJSONQuery (csv , "spec.displayName" , & name )
190
+ if err != nil {
191
+ return "" , nil , err
141
192
}
142
- return conditions , nil
143
- }
144
-
145
- // OlmOperatorAnonymizer implements HostSubnet serialization
146
- type OlmOperatorAnonymizer struct { operators []olmOperator }
147
-
148
- // Marshal implements OlmOperator serialization
149
- func (a OlmOperatorAnonymizer ) Marshal (_ context.Context ) ([]byte , error ) {
150
- return json .Marshal (a .operators )
151
- }
152
193
153
- // GetExtension returns extension for OlmOperator object
154
- func (a OlmOperatorAnonymizer ) GetExtension () string {
155
- return "json"
194
+ return name , conditions , nil
156
195
}
0 commit comments