@@ -17,10 +17,17 @@ limitations under the License.
17
17
package node
18
18
19
19
import (
20
+ "encoding/json"
21
+ "fmt"
22
+ "reflect"
20
23
"sort"
21
24
"testing"
22
25
23
26
"github.com/stretchr/testify/assert"
27
+
28
+ corev1 "k8s.io/api/core/v1"
29
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
30
+ "k8s.io/apimachinery/pkg/types"
24
31
)
25
32
26
33
func TestDeleteEdges_locked (t * testing.T ) {
@@ -176,3 +183,229 @@ func TestDeleteEdges_locked(t *testing.T) {
176
183
})
177
184
}
178
185
}
186
+
187
+ func TestIndex (t * testing.T ) {
188
+ g := NewGraph ()
189
+ g .destinationEdgeThreshold = 3
190
+
191
+ a := NewAuthorizer (g , nil , nil ).(* NodeAuthorizer )
192
+
193
+ addPod := func (podNumber , nodeNumber int ) {
194
+ t .Helper ()
195
+ nodeName := fmt .Sprintf ("node%d" , nodeNumber )
196
+ podName := fmt .Sprintf ("pod%d" , podNumber )
197
+ pod := & corev1.Pod {
198
+ ObjectMeta : metav1.ObjectMeta {Name : podName , Namespace : "ns" , UID : types .UID (fmt .Sprintf ("pod%duid1" , podNumber ))},
199
+ Spec : corev1.PodSpec {
200
+ NodeName : nodeName ,
201
+ ServiceAccountName : "sa1" ,
202
+ DeprecatedServiceAccount : "sa1" ,
203
+ Volumes : []corev1.Volume {
204
+ {Name : "volume1" , VolumeSource : corev1.VolumeSource {ConfigMap : & corev1.ConfigMapVolumeSource {LocalObjectReference : corev1.LocalObjectReference {Name : "cm1" }}}},
205
+ {Name : "volume2" , VolumeSource : corev1.VolumeSource {ConfigMap : & corev1.ConfigMapVolumeSource {LocalObjectReference : corev1.LocalObjectReference {Name : "cm2" }}}},
206
+ {Name : "volume3" , VolumeSource : corev1.VolumeSource {ConfigMap : & corev1.ConfigMapVolumeSource {LocalObjectReference : corev1.LocalObjectReference {Name : "cm3" }}}},
207
+ },
208
+ },
209
+ }
210
+ g .AddPod (pod )
211
+ if ok , err := a .hasPathFrom (nodeName , configMapVertexType , "ns" , "cm1" ); err != nil || ! ok {
212
+ t .Errorf ("expected path from %s to cm1, got %v, %v" , nodeName , ok , err )
213
+ }
214
+ }
215
+
216
+ toString := func (id int ) string {
217
+ for _ , namespaceName := range g .vertices {
218
+ for _ , nameVertex := range namespaceName {
219
+ for _ , vertex := range nameVertex {
220
+ if vertex .id == id {
221
+ return vertex .String ()
222
+ }
223
+ }
224
+ }
225
+ }
226
+ return ""
227
+ }
228
+ expectGraph := func (expect map [string ][]string ) {
229
+ t .Helper ()
230
+ actual := map [string ][]string {}
231
+ for _ , node := range g .graph .Nodes () {
232
+ sortedTo := []string {}
233
+ for _ , to := range g .graph .From (node ) {
234
+ sortedTo = append (sortedTo , toString (to .ID ()))
235
+ }
236
+ sort .Strings (sortedTo )
237
+ actual [toString (node .ID ())] = sortedTo
238
+ }
239
+ if ! reflect .DeepEqual (expect , actual ) {
240
+ e , _ := json .MarshalIndent (expect , "" , " " )
241
+ a , _ := json .MarshalIndent (actual , "" , " " )
242
+ t .Errorf ("expected graph:\n %s\n got:\n %s" , string (e ), string (a ))
243
+ }
244
+ }
245
+ expectIndex := func (expect map [string ][]string ) {
246
+ t .Helper ()
247
+ actual := map [string ][]string {}
248
+ for from , to := range g .destinationEdgeIndex {
249
+ sortedValues := []string {}
250
+ for member := range to .members {
251
+ sortedValues = append (sortedValues , toString (member ))
252
+ }
253
+ sort .Strings (sortedValues )
254
+ actual [toString (from )] = sortedValues
255
+ }
256
+ if ! reflect .DeepEqual (expect , actual ) {
257
+ e , _ := json .MarshalIndent (expect , "" , " " )
258
+ a , _ := json .MarshalIndent (actual , "" , " " )
259
+ t .Errorf ("expected index:\n %s\n got:\n %s" , string (e ), string (a ))
260
+ }
261
+ }
262
+
263
+ for i := 1 ; i <= g .destinationEdgeThreshold ; i ++ {
264
+ addPod (i , i )
265
+ if i < g .destinationEdgeThreshold {
266
+ // if we're under the threshold, no index expected
267
+ expectIndex (map [string ][]string {})
268
+ }
269
+ }
270
+ expectGraph (map [string ][]string {
271
+ "node:node1" : {},
272
+ "node:node2" : {},
273
+ "node:node3" : {},
274
+ "pod:ns/pod1" : {"node:node1" },
275
+ "pod:ns/pod2" : {"node:node2" },
276
+ "pod:ns/pod3" : {"node:node3" },
277
+ "configmap:ns/cm1" : {"pod:ns/pod1" , "pod:ns/pod2" , "pod:ns/pod3" },
278
+ "configmap:ns/cm2" : {"pod:ns/pod1" , "pod:ns/pod2" , "pod:ns/pod3" },
279
+ "configmap:ns/cm3" : {"pod:ns/pod1" , "pod:ns/pod2" , "pod:ns/pod3" },
280
+ "serviceAccount:ns/sa1" : {"pod:ns/pod1" , "pod:ns/pod2" , "pod:ns/pod3" },
281
+ })
282
+ expectIndex (map [string ][]string {
283
+ "configmap:ns/cm1" : {"node:node1" , "node:node2" , "node:node3" },
284
+ "configmap:ns/cm2" : {"node:node1" , "node:node2" , "node:node3" },
285
+ "configmap:ns/cm3" : {"node:node1" , "node:node2" , "node:node3" },
286
+ "serviceAccount:ns/sa1" : {"node:node1" , "node:node2" , "node:node3" },
287
+ })
288
+
289
+ // delete one to drop below the threshold
290
+ g .DeletePod ("pod1" , "ns" )
291
+ expectGraph (map [string ][]string {
292
+ "node:node2" : {},
293
+ "node:node3" : {},
294
+ "pod:ns/pod2" : {"node:node2" },
295
+ "pod:ns/pod3" : {"node:node3" },
296
+ "configmap:ns/cm1" : {"pod:ns/pod2" , "pod:ns/pod3" },
297
+ "configmap:ns/cm2" : {"pod:ns/pod2" , "pod:ns/pod3" },
298
+ "configmap:ns/cm3" : {"pod:ns/pod2" , "pod:ns/pod3" },
299
+ "serviceAccount:ns/sa1" : {"pod:ns/pod2" , "pod:ns/pod3" },
300
+ })
301
+ expectIndex (map [string ][]string {})
302
+
303
+ // add two to get above the threshold
304
+ addPod (1 , 1 )
305
+ addPod (4 , 1 )
306
+ expectGraph (map [string ][]string {
307
+ "node:node1" : {},
308
+ "node:node2" : {},
309
+ "node:node3" : {},
310
+ "pod:ns/pod1" : {"node:node1" },
311
+ "pod:ns/pod2" : {"node:node2" },
312
+ "pod:ns/pod3" : {"node:node3" },
313
+ "pod:ns/pod4" : {"node:node1" },
314
+ "configmap:ns/cm1" : {"pod:ns/pod1" , "pod:ns/pod2" , "pod:ns/pod3" , "pod:ns/pod4" },
315
+ "configmap:ns/cm2" : {"pod:ns/pod1" , "pod:ns/pod2" , "pod:ns/pod3" , "pod:ns/pod4" },
316
+ "configmap:ns/cm3" : {"pod:ns/pod1" , "pod:ns/pod2" , "pod:ns/pod3" , "pod:ns/pod4" },
317
+ "serviceAccount:ns/sa1" : {"pod:ns/pod1" , "pod:ns/pod2" , "pod:ns/pod3" , "pod:ns/pod4" },
318
+ })
319
+ expectIndex (map [string ][]string {
320
+ "configmap:ns/cm1" : {"node:node1" , "node:node2" , "node:node3" },
321
+ "configmap:ns/cm2" : {"node:node1" , "node:node2" , "node:node3" },
322
+ "configmap:ns/cm3" : {"node:node1" , "node:node2" , "node:node3" },
323
+ "serviceAccount:ns/sa1" : {"node:node1" , "node:node2" , "node:node3" },
324
+ })
325
+
326
+ // delete one to remain above the threshold
327
+ g .DeletePod ("pod1" , "ns" )
328
+ expectGraph (map [string ][]string {
329
+ "node:node1" : {},
330
+ "node:node2" : {},
331
+ "node:node3" : {},
332
+ "pod:ns/pod2" : {"node:node2" },
333
+ "pod:ns/pod3" : {"node:node3" },
334
+ "pod:ns/pod4" : {"node:node1" },
335
+ "configmap:ns/cm1" : {"pod:ns/pod2" , "pod:ns/pod3" , "pod:ns/pod4" },
336
+ "configmap:ns/cm2" : {"pod:ns/pod2" , "pod:ns/pod3" , "pod:ns/pod4" },
337
+ "configmap:ns/cm3" : {"pod:ns/pod2" , "pod:ns/pod3" , "pod:ns/pod4" },
338
+ "serviceAccount:ns/sa1" : {"pod:ns/pod2" , "pod:ns/pod3" , "pod:ns/pod4" },
339
+ })
340
+ expectIndex (map [string ][]string {
341
+ "configmap:ns/cm1" : {"node:node1" , "node:node2" , "node:node3" },
342
+ "configmap:ns/cm2" : {"node:node1" , "node:node2" , "node:node3" },
343
+ "configmap:ns/cm3" : {"node:node1" , "node:node2" , "node:node3" },
344
+ "serviceAccount:ns/sa1" : {"node:node1" , "node:node2" , "node:node3" },
345
+ })
346
+
347
+ // Set node->configmap references
348
+ g .SetNodeConfigMap ("node1" , "cm1" , "ns" )
349
+ g .SetNodeConfigMap ("node2" , "cm1" , "ns" )
350
+ g .SetNodeConfigMap ("node3" , "cm1" , "ns" )
351
+ expectGraph (map [string ][]string {
352
+ "node:node1" : {},
353
+ "node:node2" : {},
354
+ "node:node3" : {},
355
+ "pod:ns/pod2" : {"node:node2" },
356
+ "pod:ns/pod3" : {"node:node3" },
357
+ "pod:ns/pod4" : {"node:node1" },
358
+ "configmap:ns/cm1" : {"node:node1" , "node:node2" , "node:node3" , "pod:ns/pod2" , "pod:ns/pod3" , "pod:ns/pod4" },
359
+ "configmap:ns/cm2" : {"pod:ns/pod2" , "pod:ns/pod3" , "pod:ns/pod4" },
360
+ "configmap:ns/cm3" : {"pod:ns/pod2" , "pod:ns/pod3" , "pod:ns/pod4" },
361
+ "serviceAccount:ns/sa1" : {"pod:ns/pod2" , "pod:ns/pod3" , "pod:ns/pod4" },
362
+ })
363
+ expectIndex (map [string ][]string {
364
+ "configmap:ns/cm1" : {"node:node1" , "node:node2" , "node:node3" },
365
+ "configmap:ns/cm2" : {"node:node1" , "node:node2" , "node:node3" },
366
+ "configmap:ns/cm3" : {"node:node1" , "node:node2" , "node:node3" },
367
+ "serviceAccount:ns/sa1" : {"node:node1" , "node:node2" , "node:node3" },
368
+ })
369
+
370
+ // Update node->configmap reference
371
+ g .SetNodeConfigMap ("node1" , "cm2" , "ns" )
372
+ expectGraph (map [string ][]string {
373
+ "node:node1" : {},
374
+ "node:node2" : {},
375
+ "node:node3" : {},
376
+ "pod:ns/pod2" : {"node:node2" },
377
+ "pod:ns/pod3" : {"node:node3" },
378
+ "pod:ns/pod4" : {"node:node1" },
379
+ "configmap:ns/cm1" : {"node:node2" , "node:node3" , "pod:ns/pod2" , "pod:ns/pod3" , "pod:ns/pod4" },
380
+ "configmap:ns/cm2" : {"node:node1" , "pod:ns/pod2" , "pod:ns/pod3" , "pod:ns/pod4" },
381
+ "configmap:ns/cm3" : {"pod:ns/pod2" , "pod:ns/pod3" , "pod:ns/pod4" },
382
+ "serviceAccount:ns/sa1" : {"pod:ns/pod2" , "pod:ns/pod3" , "pod:ns/pod4" },
383
+ })
384
+ expectIndex (map [string ][]string {
385
+ "configmap:ns/cm1" : {"node:node1" , "node:node2" , "node:node3" },
386
+ "configmap:ns/cm2" : {"node:node1" , "node:node2" , "node:node3" },
387
+ "configmap:ns/cm3" : {"node:node1" , "node:node2" , "node:node3" },
388
+ "serviceAccount:ns/sa1" : {"node:node1" , "node:node2" , "node:node3" },
389
+ })
390
+
391
+ // Remove node->configmap reference
392
+ g .SetNodeConfigMap ("node1" , "" , "" )
393
+ expectGraph (map [string ][]string {
394
+ "node:node1" : {},
395
+ "node:node2" : {},
396
+ "node:node3" : {},
397
+ "pod:ns/pod2" : {"node:node2" },
398
+ "pod:ns/pod3" : {"node:node3" },
399
+ "pod:ns/pod4" : {"node:node1" },
400
+ "configmap:ns/cm1" : {"node:node2" , "node:node3" , "pod:ns/pod2" , "pod:ns/pod3" , "pod:ns/pod4" },
401
+ "configmap:ns/cm2" : {"pod:ns/pod2" , "pod:ns/pod3" , "pod:ns/pod4" },
402
+ "configmap:ns/cm3" : {"pod:ns/pod2" , "pod:ns/pod3" , "pod:ns/pod4" },
403
+ "serviceAccount:ns/sa1" : {"pod:ns/pod2" , "pod:ns/pod3" , "pod:ns/pod4" },
404
+ })
405
+ expectIndex (map [string ][]string {
406
+ "configmap:ns/cm1" : {"node:node1" , "node:node2" , "node:node3" },
407
+ "configmap:ns/cm2" : {"node:node1" , "node:node2" , "node:node3" },
408
+ "configmap:ns/cm3" : {"node:node1" , "node:node2" , "node:node3" },
409
+ "serviceAccount:ns/sa1" : {"node:node1" , "node:node2" , "node:node3" },
410
+ })
411
+ }
0 commit comments