@@ -17,6 +17,7 @@ limitations under the License.
17
17
package node
18
18
19
19
import (
20
+ "fmt"
20
21
"sync"
21
22
"time"
22
23
@@ -79,7 +80,8 @@ func (e *destinationEdge) DestinationID() int { return e.Destination.ID() }
79
80
// pvc <- pv
80
81
// pv <- secret
81
82
type Graph struct {
82
- lock sync.RWMutex
83
+ lock sync.RWMutex
84
+ // Calling graph.SetEdge is restricted to the addEdgeLocked method of Graph.
83
85
graph * simple.DirectedAcyclicGraph
84
86
// vertices is a map of type -> namespace -> name -> vertex
85
87
vertices map [vertexType ]namespaceVertexMapping
@@ -138,6 +140,20 @@ var vertexTypes = map[vertexType]string{
138
140
serviceAccountVertexType : "serviceAccount" ,
139
141
}
140
142
143
+ // vertexTypeWithAuthoritativeIndex indicates which types of vertices can hold
144
+ // a destination edge index that is authoritative i.e. if the index exists,
145
+ // then it always stores all of the Nodes that are reachable from that vertex
146
+ // in the graph.
147
+ var vertexTypeWithAuthoritativeIndex = map [vertexType ]bool {
148
+ configMapVertexType : true ,
149
+ sliceVertexType : true ,
150
+ podVertexType : true ,
151
+ pvcVertexType : true ,
152
+ resourceClaimVertexType : true ,
153
+ vaVertexType : true ,
154
+ serviceAccountVertexType : true ,
155
+ }
156
+
141
157
// must be called under a write lock
142
158
func (g * Graph ) getOrCreateVertexLocked (vertexType vertexType , namespace , name string ) * namedVertex {
143
159
if vertex , exists := g .getVertexRLocked (vertexType , namespace , name ); exists {
@@ -348,7 +364,8 @@ func (g *Graph) AddPod(pod *corev1.Pod) {
348
364
g .deleteVertexLocked (podVertexType , pod .Namespace , pod .Name )
349
365
podVertex := g .getOrCreateVertexLocked (podVertexType , pod .Namespace , pod .Name )
350
366
nodeVertex := g .getOrCreateVertexLocked (nodeVertexType , "" , pod .Spec .NodeName )
351
- g .graph .SetEdge (newDestinationEdge (podVertex , nodeVertex , nodeVertex ))
367
+ // Edge adds must be handled by addEdgeLocked instead of direct g.graph.SetEdge calls.
368
+ g .addEdgeLocked (podVertex , nodeVertex , nodeVertex )
352
369
353
370
// Short-circuit adding edges to other resources for mirror pods.
354
371
// A node must never be able to create a pod that grants them permissions on other API objects.
@@ -363,24 +380,21 @@ func (g *Graph) AddPod(pod *corev1.Pod) {
363
380
// ref https://github.com/kubernetes/kubernetes/issues/58790
364
381
if len (pod .Spec .ServiceAccountName ) > 0 {
365
382
serviceAccountVertex := g .getOrCreateVertexLocked (serviceAccountVertexType , pod .Namespace , pod .Spec .ServiceAccountName )
366
- e := newDestinationEdge (serviceAccountVertex , podVertex , nodeVertex )
367
- g .graph .SetEdge (e )
368
- g .addEdgeToDestinationIndexLocked (e )
383
+ // Edge adds must be handled by addEdgeLocked instead of direct g.graph.SetEdge calls.
384
+ g .addEdgeLocked (serviceAccountVertex , podVertex , nodeVertex )
369
385
}
370
386
371
387
podutil .VisitPodSecretNames (pod , func (secret string ) bool {
372
388
secretVertex := g .getOrCreateVertexLocked (secretVertexType , pod .Namespace , secret )
373
- e := newDestinationEdge (secretVertex , podVertex , nodeVertex )
374
- g .graph .SetEdge (e )
375
- g .addEdgeToDestinationIndexLocked (e )
389
+ // Edge adds must be handled by addEdgeLocked instead of direct g.graph.SetEdge calls.
390
+ g .addEdgeLocked (secretVertex , podVertex , nodeVertex )
376
391
return true
377
392
})
378
393
379
394
podutil .VisitPodConfigmapNames (pod , func (configmap string ) bool {
380
395
configmapVertex := g .getOrCreateVertexLocked (configMapVertexType , pod .Namespace , configmap )
381
- e := newDestinationEdge (configmapVertex , podVertex , nodeVertex )
382
- g .graph .SetEdge (e )
383
- g .addEdgeToDestinationIndexLocked (e )
396
+ // Edge adds must be handled by addEdgeLocked instead of direct g.graph.SetEdge calls.
397
+ g .addEdgeLocked (configmapVertex , podVertex , nodeVertex )
384
398
return true
385
399
})
386
400
@@ -393,9 +407,8 @@ func (g *Graph) AddPod(pod *corev1.Pod) {
393
407
}
394
408
if claimName != "" {
395
409
pvcVertex := g .getOrCreateVertexLocked (pvcVertexType , pod .Namespace , claimName )
396
- e := newDestinationEdge (pvcVertex , podVertex , nodeVertex )
397
- g .graph .SetEdge (e )
398
- g .addEdgeToDestinationIndexLocked (e )
410
+ // Edge adds must be handled by addEdgeLocked instead of direct g.graph.SetEdge calls.
411
+ g .addEdgeLocked (pvcVertex , podVertex , nodeVertex )
399
412
}
400
413
}
401
414
@@ -407,12 +420,34 @@ func (g *Graph) AddPod(pod *corev1.Pod) {
407
420
// was created and never will be because it isn't needed.
408
421
if err == nil && claimName != nil {
409
422
claimVertex := g .getOrCreateVertexLocked (resourceClaimVertexType , pod .Namespace , * claimName )
410
- e := newDestinationEdge (claimVertex , podVertex , nodeVertex )
411
- g .graph .SetEdge (e )
412
- g .addEdgeToDestinationIndexLocked (e )
423
+ // Edge adds must be handled by addEdgeLocked instead of direct g.graph.SetEdge calls.
424
+ g .addEdgeLocked (claimVertex , podVertex , nodeVertex )
413
425
}
414
426
}
415
427
}
428
+
429
+ // Must be called under a write lock.
430
+ // All edge adds must be handled by that method rather than by calling
431
+ // g.graph.SetEdge directly.
432
+ // Note: if "from" belongs to vertexTypeWithAuthoritativeIndex, then
433
+ // "destination" must be non-nil.
434
+ func (g * Graph ) addEdgeLocked (from , to , destination * namedVertex ) {
435
+ if destination != nil {
436
+ e := newDestinationEdge (from , to , destination )
437
+ g .graph .SetEdge (e )
438
+ g .addEdgeToDestinationIndexLocked (e )
439
+ return
440
+ }
441
+
442
+ // We must not create edges without a Node label from a vertex that is
443
+ // supposed to hold authoritative destination edge index only.
444
+ // Entering this branch would mean there's a bug in the Node authorizer.
445
+ if vertexTypeWithAuthoritativeIndex [from .vertexType ] {
446
+ panic (fmt .Sprintf ("vertex of type %q must have destination edges only" , vertexTypes [from .vertexType ]))
447
+ }
448
+ g .graph .SetEdge (simple.Edge {F : from , T : to })
449
+ }
450
+
416
451
func (g * Graph ) DeletePod (name , namespace string ) {
417
452
start := time .Now ()
418
453
defer func () {
@@ -444,11 +479,13 @@ func (g *Graph) AddPV(pv *corev1.PersistentVolume) {
444
479
pvVertex := g .getOrCreateVertexLocked (pvVertexType , "" , pv .Name )
445
480
446
481
// since we don't know the other end of the pvc -> pod -> node chain (or it may not even exist yet), we can't decorate these edges with kubernetes node info
447
- g .graph .SetEdge (simple.Edge {F : pvVertex , T : g .getOrCreateVertexLocked (pvcVertexType , pv .Spec .ClaimRef .Namespace , pv .Spec .ClaimRef .Name )})
482
+ // Edge adds must be handled by addEdgeLocked instead of direct g.graph.SetEdge calls.
483
+ g .addEdgeLocked (pvVertex , g .getOrCreateVertexLocked (pvcVertexType , pv .Spec .ClaimRef .Namespace , pv .Spec .ClaimRef .Name ), nil )
448
484
pvutil .VisitPVSecretNames (pv , func (namespace , secret string , kubeletVisible bool ) bool {
449
485
// This grants access to the named secret in the same namespace as the bound PVC
450
486
if kubeletVisible {
451
- g .graph .SetEdge (simple.Edge {F : g .getOrCreateVertexLocked (secretVertexType , namespace , secret ), T : pvVertex })
487
+ // Edge adds must be handled by addEdgeLocked instead of direct g.graph.SetEdge calls.
488
+ g .addEdgeLocked (g .getOrCreateVertexLocked (secretVertexType , namespace , secret ), pvVertex , nil )
452
489
}
453
490
return true
454
491
})
@@ -482,7 +519,8 @@ func (g *Graph) AddVolumeAttachment(attachmentName, nodeName string) {
482
519
if len (nodeName ) > 0 {
483
520
vaVertex := g .getOrCreateVertexLocked (vaVertexType , "" , attachmentName )
484
521
nodeVertex := g .getOrCreateVertexLocked (nodeVertexType , "" , nodeName )
485
- g .graph .SetEdge (newDestinationEdge (vaVertex , nodeVertex , nodeVertex ))
522
+ // Edge adds must be handled by addEdgeLocked instead of direct g.graph.SetEdge calls.
523
+ g .addEdgeLocked (vaVertex , nodeVertex , nodeVertex )
486
524
}
487
525
}
488
526
func (g * Graph ) DeleteVolumeAttachment (name string ) {
@@ -513,7 +551,8 @@ func (g *Graph) AddResourceSlice(sliceName, nodeName string) {
513
551
if len (nodeName ) > 0 {
514
552
sliceVertex := g .getOrCreateVertexLocked (sliceVertexType , "" , sliceName )
515
553
nodeVertex := g .getOrCreateVertexLocked (nodeVertexType , "" , nodeName )
516
- g .graph .SetEdge (newDestinationEdge (sliceVertex , nodeVertex , nodeVertex ))
554
+ // Edge adds must be handled by addEdgeLocked instead of direct g.graph.SetEdge calls.
555
+ g .addEdgeLocked (sliceVertex , nodeVertex , nodeVertex )
517
556
}
518
557
}
519
558
func (g * Graph ) DeleteResourceSlice (sliceName string ) {
0 commit comments