@@ -37,39 +37,35 @@ import (
37
37
"sigs.k8s.io/controller-runtime/pkg/client"
38
38
)
39
39
40
- // checkSpecAndStat checks that the spec and status blocks exist. If noStore is set to true, this function
41
- // will not store the result of the test in scTests and will instead just wait until the spec and
42
- // status blocks exist or return an error after the timeout.
43
- func checkSpecAndStat (runtimeClient client.Client , obj * unstructured.Unstructured , noStore bool ) error {
44
- testSpec := scorecardTest {testType : basicOperator , name : "Spec Block Exists" , maximumPoints : 1 }
45
- testStat := scorecardTest {testType : basicOperator , name : "Status Block Exist" , maximumPoints : 1 }
46
- err := wait .Poll (time .Second * 1 , time .Second * time .Duration (SCConf .InitTimeout ), func () (bool , error ) {
47
- err := runtimeClient .Get (context .TODO (), types.NamespacedName {Namespace : obj .GetNamespace (), Name : obj .GetName ()}, obj )
48
- if err != nil {
49
- return false , fmt .Errorf ("error getting custom resource: %v" , err )
50
- }
51
- var specPass , statusPass bool
52
- if obj .Object ["spec" ] != nil {
53
- testSpec .earnedPoints = 1
54
- specPass = true
55
- }
56
-
57
- if obj .Object ["status" ] != nil {
58
- testStat .earnedPoints = 1
59
- statusPass = true
60
- }
61
- return statusPass && specPass , nil
62
- })
63
- if ! noStore {
64
- scTests = append (scTests , testSpec , testStat )
40
+ // checkSpec checks that the spec block exists
41
+ func checkSpec (test * Test , vars ScorecardVars ) error {
42
+ score := Score {maximumPoints : 1 }
43
+ err := runtimeClient .Get (context .TODO (), types.NamespacedName {Namespace : vars .crObj .GetNamespace (), Name : vars .crObj .GetName ()}, vars .crObj )
44
+ if err != nil {
45
+ return fmt .Errorf ("error getting custom resource: %v" , err )
65
46
}
66
- if err != nil && err != wait . ErrWaitTimeout {
67
- return err
47
+ if vars . crObj . Object [ "spec" ] != nil {
48
+ score . earnedPoints = 1
68
49
}
69
- if testSpec .earnedPoints != 1 {
50
+ test .scores = append (test .scores , score )
51
+ if score .earnedPoints != 1 {
70
52
scSuggestions = append (scSuggestions , "Add a 'spec' field to your Custom Resource" )
71
53
}
72
- if testStat .earnedPoints != 1 {
54
+ return nil
55
+ }
56
+
57
+ // checkStat checks that the stat block exists
58
+ func checkStat (test * Test , vars ScorecardVars ) error {
59
+ score := Score {maximumPoints : 1 }
60
+ err := runtimeClient .Get (context .TODO (), types.NamespacedName {Namespace : vars .crObj .GetNamespace (), Name : vars .crObj .GetName ()}, vars .crObj )
61
+ if err != nil {
62
+ return fmt .Errorf ("error getting custom resource: %v" , err )
63
+ }
64
+ if vars .crObj .Object ["status" ] != nil {
65
+ score .earnedPoints = 1
66
+ }
67
+ test .scores = append (test .scores , score )
68
+ if score .earnedPoints != 1 {
73
69
scSuggestions = append (scSuggestions , "Add a 'status' field to your Custom Resource" )
74
70
}
75
71
return nil
@@ -81,30 +77,29 @@ func checkSpecAndStat(runtimeClient client.Client, obj *unstructured.Unstructure
81
77
// see if the status changes as a result. This is a bit prone to breakage as this is a black box test and we don't
82
78
// know much about how the operators we are testing actually work and may pass an invalid value. In the future, we
83
79
// should use user-specified tests
84
- func checkStatusUpdate (runtimeClient client. Client , obj * unstructured. Unstructured ) error {
85
- test := scorecardTest { testType : basicOperator , name : "Operator actions are reflected in status" , maximumPoints : 1 }
86
- err := runtimeClient .Get (context .TODO (), types.NamespacedName {Namespace : obj . GetNamespace (), Name : obj . GetName ()}, obj )
80
+ func checkStatusUpdate (test * Test , vars ScorecardVars ) error {
81
+ score := Score { maximumPoints : 1 }
82
+ err := runtimeClient .Get (context .TODO (), types.NamespacedName {Namespace : vars . crObj . GetNamespace (), Name : vars . crObj . GetName ()}, vars . crObj )
87
83
if err != nil {
88
84
return fmt .Errorf ("error getting custom resource: %v" , err )
89
85
}
90
- if obj .Object ["status" ] == nil || obj .Object ["spec" ] == nil {
91
- scTests = append (scTests , test )
86
+ if vars .crObj .Object ["status" ] == nil || vars .crObj .Object ["spec" ] == nil {
92
87
return nil
93
88
}
94
89
statCopy := make (map [string ]interface {})
95
- for k , v := range obj .Object ["status" ].(map [string ]interface {}) {
90
+ for k , v := range vars . crObj .Object ["status" ].(map [string ]interface {}) {
96
91
statCopy [k ] = v
97
92
}
98
- specMap := obj .Object ["spec" ].(map [string ]interface {})
99
- err = modifySpecAndCheck (specMap , obj )
93
+ specMap := vars . crObj .Object ["spec" ].(map [string ]interface {})
94
+ err = modifySpecAndCheck (specMap , vars . crObj )
100
95
if err != nil {
101
- test .earnedPoints = 0
96
+ score .earnedPoints = 0
97
+ test .scores = append (test .scores , score )
102
98
scSuggestions = append (scSuggestions , "Make sure that the 'status' block is always updated to reflect changes after the 'spec' block is changed" )
103
- scTests = append (scTests , test )
104
99
return nil
105
100
}
106
- test .earnedPoints = 1
107
- scTests = append (scTests , test )
101
+ score .earnedPoints = 1
102
+ test . scores = append (test . scores , score )
108
103
return nil
109
104
}
110
105
@@ -169,28 +164,27 @@ func modifySpecAndCheck(specMap map[string]interface{}, obj *unstructured.Unstru
169
164
170
165
// wiritingIntoCRsHasEffect simply looks at the proxy logs and verifies that the operator is sending PUT
171
166
// and/or POST requests to the API server, which should mean that it is creating or modifying resources.
172
- func writingIntoCRsHasEffect (obj * unstructured.Unstructured ) (string , error ) {
173
- test := scorecardTest {testType : basicOperator , name : "Writing into CRs has an effect" , maximumPoints : 1 }
167
+ func writingIntoCRsHasEffect (test * Test , vars ScorecardVars ) error {
174
168
kubeclient , err := kubernetes .NewForConfig (kubeconfig )
175
169
if err != nil {
176
- return "" , fmt .Errorf ("failed to create kubeclient: %v" , err )
170
+ return fmt .Errorf ("failed to create kubeclient: %v" , err )
177
171
}
178
172
dep := & appsv1.Deployment {}
179
- err = runtimeClient .Get (context .TODO (), types.NamespacedName {Namespace : obj .GetNamespace (), Name : deploymentName }, dep )
173
+ err = runtimeClient .Get (context .TODO (), types.NamespacedName {Namespace : vars . crObj .GetNamespace (), Name : deploymentName }, dep )
180
174
if err != nil {
181
- return "" , fmt .Errorf ("failed to get newly created operator deployment: %v" , err )
175
+ return fmt .Errorf ("failed to get newly created operator deployment: %v" , err )
182
176
}
183
177
set := labels .Set (dep .Spec .Selector .MatchLabels )
184
178
pods := & v1.PodList {}
185
179
err = runtimeClient .List (context .TODO (), & client.ListOptions {LabelSelector : set .AsSelector ()}, pods )
186
180
if err != nil {
187
- return "" , fmt .Errorf ("failed to get list of pods in deployment: %v" , err )
181
+ return fmt .Errorf ("failed to get list of pods in deployment: %v" , err )
188
182
}
189
183
proxyPod = & pods .Items [0 ]
190
- req := kubeclient .CoreV1 ().Pods (obj .GetNamespace ()).GetLogs (proxyPod .GetName (), & v1.PodLogOptions {Container : "scorecard-proxy" })
184
+ req := kubeclient .CoreV1 ().Pods (vars . crObj .GetNamespace ()).GetLogs (proxyPod .GetName (), & v1.PodLogOptions {Container : "scorecard-proxy" })
191
185
readCloser , err := req .Stream ()
192
186
if err != nil {
193
- return "" , fmt .Errorf ("failed to get logs: %v" , err )
187
+ return fmt .Errorf ("failed to get logs: %v" , err )
194
188
}
195
189
defer func () {
196
190
if err := readCloser .Close (); err != nil && ! fileutil .IsClosedError (err ) {
@@ -200,10 +194,11 @@ func writingIntoCRsHasEffect(obj *unstructured.Unstructured) (string, error) {
200
194
buf := new (bytes.Buffer )
201
195
_ , err = buf .ReadFrom (readCloser )
202
196
if err != nil {
203
- return "" , fmt .Errorf ("test failed and failed to read pod logs: %v" , err )
197
+ return fmt .Errorf ("test failed and failed to read pod logs: %v" , err )
204
198
}
205
199
logs := buf .String ()
206
200
msgMap := make (map [string ]interface {})
201
+ score := Score {maximumPoints : 1 }
207
202
for _ , msg := range strings .Split (logs , "\n " ) {
208
203
if err := json .Unmarshal ([]byte (msg ), & msgMap ); err != nil {
209
204
continue
@@ -213,13 +208,13 @@ func writingIntoCRsHasEffect(obj *unstructured.Unstructured) (string, error) {
213
208
continue
214
209
}
215
210
if method == "PUT" || method == "POST" {
216
- test .earnedPoints = 1
211
+ score .earnedPoints = 1
217
212
break
218
213
}
219
214
}
220
- scTests = append (scTests , test )
221
- if test .earnedPoints != 1 {
215
+ test . scores = append (test . scores , score )
216
+ if score .earnedPoints != 1 {
222
217
scSuggestions = append (scSuggestions , "The operator should write into objects to update state. No PUT or POST requests from you operator were recorded by the scorecard." )
223
218
}
224
- return buf . String (), nil
219
+ return nil
225
220
}
0 commit comments