2017-05-30 15:15:38 -04:00
/ *
Copyright 2017 The Kubernetes Authors .
Licensed under the Apache License , Version 2.0 ( the "License" ) ;
you may not use this file except in compliance with the License .
You may obtain a copy of the License at
http : //www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing , software
distributed under the License is distributed on an "AS IS" BASIS ,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
See the License for the specific language governing permissions and
limitations under the License .
* /
package node
import (
2024-08-30 19:08:51 -04:00
"fmt"
2017-05-30 15:15:38 -04:00
"sync"
2020-06-17 11:48:42 -04:00
"time"
2017-05-30 15:15:38 -04:00
2025-09-16 16:24:07 -04:00
certsv1beta1 "k8s.io/api/certificates/v1beta1"
2018-08-08 08:41:00 -04:00
corev1 "k8s.io/api/core/v1"
2021-08-31 02:39:55 -04:00
"k8s.io/component-helpers/storage/ephemeral"
2023-03-03 07:33:20 -05:00
"k8s.io/dynamic-resource-allocation/resourceclaim"
2018-08-09 09:27:23 -04:00
pvutil "k8s.io/kubernetes/pkg/api/v1/persistentvolume"
2018-08-08 08:41:00 -04:00
podutil "k8s.io/kubernetes/pkg/api/v1/pod"
2017-05-30 15:15:38 -04:00
"k8s.io/kubernetes/third_party/forked/gonum/graph"
"k8s.io/kubernetes/third_party/forked/gonum/graph/simple"
)
// namedVertex implements graph.Node and remembers the type, namespace, and name of its related API object
type namedVertex struct {
name string
namespace string
id int
vertexType vertexType
}
func newNamedVertex ( vertexType vertexType , namespace , name string , id int ) * namedVertex {
return & namedVertex {
vertexType : vertexType ,
name : name ,
namespace : namespace ,
id : id ,
}
}
func ( n * namedVertex ) ID ( ) int {
return n . id
}
func ( n * namedVertex ) String ( ) string {
if len ( n . namespace ) == 0 {
return vertexTypes [ n . vertexType ] + ":" + n . name
}
return vertexTypes [ n . vertexType ] + ":" + n . namespace + "/" + n . name
}
// destinationEdge is a graph edge that includes a denormalized reference to the final destination vertex.
// This should only be used when there is a single leaf vertex reachable from T.
type destinationEdge struct {
F graph . Node
T graph . Node
Destination graph . Node
}
func newDestinationEdge ( from , to , destination graph . Node ) graph . Edge {
return & destinationEdge { F : from , T : to , Destination : destination }
}
func ( e * destinationEdge ) From ( ) graph . Node { return e . F }
func ( e * destinationEdge ) To ( ) graph . Node { return e . T }
func ( e * destinationEdge ) Weight ( ) float64 { return 0 }
func ( e * destinationEdge ) DestinationID ( ) int { return e . Destination . ID ( ) }
// Graph holds graph vertices and a way to look up a vertex for a particular API type/namespace/name.
// All edges point toward the vertices representing Kubernetes nodes:
//
// node <- pod
// pod <- secret,configmap,pvc
// pvc <- pv
// pv <- secret
type Graph struct {
2024-08-30 19:08:51 -04:00
lock sync . RWMutex
// Calling graph.SetEdge is restricted to the addEdgeLocked method of Graph.
2017-05-30 15:15:38 -04:00
graph * simple . DirectedAcyclicGraph
// vertices is a map of type -> namespace -> name -> vertex
vertices map [ vertexType ] namespaceVertexMapping
2018-04-19 22:22:25 -04:00
// destinationEdgeIndex is a map of vertex -> set of destination IDs
destinationEdgeIndex map [ int ] * intSet
// destinationEdgeThreshold is the minimum number of distinct destination IDs at which to maintain an index
destinationEdgeThreshold int
2017-05-30 15:15:38 -04:00
}
// namespaceVertexMapping is a map of namespace -> name -> vertex
type namespaceVertexMapping map [ string ] nameVertexMapping
// nameVertexMapping is a map of name -> vertex
type nameVertexMapping map [ string ] * namedVertex
func NewGraph ( ) * Graph {
return & Graph {
vertices : map [ vertexType ] namespaceVertexMapping { } ,
graph : simple . NewDirectedAcyclicGraph ( 0 , 0 ) ,
2018-04-19 22:22:25 -04:00
destinationEdgeIndex : map [ int ] * intSet { } ,
// experimentally determined to be the point at which iteration adds an order of magnitude to the authz check.
// since maintaining indexes costs time/memory while processing graph changes, we don't want to make this too low.
destinationEdgeThreshold : 200 ,
2017-05-30 15:15:38 -04:00
}
}
// vertexType indicates the type of the API object the vertex represents.
// represented as a byte to minimize space used in the vertices.
type vertexType byte
const (
configMapVertexType vertexType = iota
2024-01-24 11:51:40 -05:00
sliceVertexType
2017-05-30 15:15:38 -04:00
nodeVertexType
podVertexType
pvcVertexType
pvVertexType
2023-03-03 07:33:20 -05:00
resourceClaimVertexType
2017-05-30 15:15:38 -04:00
secretVertexType
2018-01-16 23:39:11 -05:00
vaVertexType
2017-11-02 13:26:04 -04:00
serviceAccountVertexType
2024-08-30 03:47:15 -04:00
pcrVertexType
2017-05-30 15:15:38 -04:00
)
var vertexTypes = map [ vertexType ] string {
2017-11-02 13:26:04 -04:00
configMapVertexType : "configmap" ,
2024-03-07 04:14:11 -05:00
sliceVertexType : "resourceslice" ,
2017-11-02 13:26:04 -04:00
nodeVertexType : "node" ,
podVertexType : "pod" ,
pvcVertexType : "pvc" ,
pvVertexType : "pv" ,
2023-03-03 07:33:20 -05:00
resourceClaimVertexType : "resourceclaim" ,
2017-11-02 13:26:04 -04:00
secretVertexType : "secret" ,
vaVertexType : "volumeattachment" ,
serviceAccountVertexType : "serviceAccount" ,
2024-08-30 03:47:15 -04:00
pcrVertexType : "podcertificaterequest" ,
2017-05-30 15:15:38 -04:00
}
2024-08-30 19:08:51 -04:00
// vertexTypeWithAuthoritativeIndex indicates which types of vertices can hold
// a destination edge index that is authoritative i.e. if the index exists,
// then it always stores all of the Nodes that are reachable from that vertex
// in the graph.
var vertexTypeWithAuthoritativeIndex = map [ vertexType ] bool {
configMapVertexType : true ,
sliceVertexType : true ,
podVertexType : true ,
pvcVertexType : true ,
resourceClaimVertexType : true ,
vaVertexType : true ,
serviceAccountVertexType : true ,
2024-08-30 03:47:15 -04:00
pcrVertexType : true ,
2024-08-30 19:08:51 -04:00
}
2017-05-30 15:15:38 -04:00
// must be called under a write lock
2024-09-03 15:27:24 -04:00
func ( g * Graph ) getOrCreateVertexLocked ( vertexType vertexType , namespace , name string ) * namedVertex {
if vertex , exists := g . getVertexRLocked ( vertexType , namespace , name ) ; exists {
2017-05-30 15:15:38 -04:00
return vertex
}
2024-09-03 15:27:24 -04:00
return g . createVertexLocked ( vertexType , namespace , name )
2017-05-30 15:15:38 -04:00
}
// must be called under a read lock
2024-09-03 15:27:24 -04:00
func ( g * Graph ) getVertexRLocked ( vertexType vertexType , namespace , name string ) ( * namedVertex , bool ) {
2017-05-30 15:15:38 -04:00
vertex , exists := g . vertices [ vertexType ] [ namespace ] [ name ]
return vertex , exists
}
// must be called under a write lock
2024-09-03 15:27:24 -04:00
func ( g * Graph ) createVertexLocked ( vertexType vertexType , namespace , name string ) * namedVertex {
2017-05-30 15:15:38 -04:00
typedVertices , exists := g . vertices [ vertexType ]
if ! exists {
typedVertices = namespaceVertexMapping { }
g . vertices [ vertexType ] = typedVertices
}
namespacedVertices , exists := typedVertices [ namespace ]
if ! exists {
namespacedVertices = map [ string ] * namedVertex { }
typedVertices [ namespace ] = namespacedVertices
}
vertex := newNamedVertex ( vertexType , namespace , name , g . graph . NewNodeID ( ) )
namespacedVertices [ name ] = vertex
g . graph . AddNode ( vertex )
return vertex
}
// must be called under write lock
2024-09-03 15:27:24 -04:00
func ( g * Graph ) deleteVertexLocked ( vertexType vertexType , namespace , name string ) {
vertex , exists := g . getVertexRLocked ( vertexType , namespace , name )
2017-05-30 15:15:38 -04:00
if ! exists {
return
}
// find existing neighbors with a single edge (meaning we are their only neighbor)
neighborsToRemove := [ ] graph . Node { }
2020-02-10 13:24:27 -05:00
edgesToRemoveFromIndexes := [ ] graph . Edge { }
2017-05-30 15:15:38 -04:00
g . graph . VisitFrom ( vertex , func ( neighbor graph . Node ) bool {
// this downstream neighbor has only one edge (which must be from us), so remove them as well
if g . graph . Degree ( neighbor ) == 1 {
neighborsToRemove = append ( neighborsToRemove , neighbor )
}
return true
} )
g . graph . VisitTo ( vertex , func ( neighbor graph . Node ) bool {
if g . graph . Degree ( neighbor ) == 1 {
2018-04-19 16:59:09 -04:00
// this upstream neighbor has only one edge (which must be to us), so remove them as well
2017-05-30 15:15:38 -04:00
neighborsToRemove = append ( neighborsToRemove , neighbor )
2018-04-19 22:22:25 -04:00
} else {
2020-02-10 13:24:27 -05:00
// decrement the destination edge index on this neighbor if the edge between us was a destination edge
edgesToRemoveFromIndexes = append ( edgesToRemoveFromIndexes , g . graph . EdgeBetween ( vertex , neighbor ) )
2017-05-30 15:15:38 -04:00
}
return true
} )
// remove the vertex
2024-09-03 15:27:24 -04:00
g . removeVertexLocked ( vertex )
2017-05-30 15:15:38 -04:00
// remove neighbors that are now edgeless
for _ , neighbor := range neighborsToRemove {
2024-09-03 15:27:24 -04:00
g . removeVertexLocked ( neighbor . ( * namedVertex ) )
2017-05-30 15:15:38 -04:00
}
2018-04-19 22:22:25 -04:00
2020-02-10 13:24:27 -05:00
// remove edges from destination indexes for neighbors that dropped outbound edges
for _ , edge := range edgesToRemoveFromIndexes {
2024-09-03 15:27:24 -04:00
g . removeEdgeFromDestinationIndexLocked ( edge )
2018-04-19 22:22:25 -04:00
}
2017-05-30 15:15:38 -04:00
}
2018-02-20 14:28:28 -05:00
// must be called under write lock
// deletes edges from a given vertex type to a specific vertex
// will delete each orphaned "from" vertex, but will never delete the "to" vertex
2024-09-03 15:27:24 -04:00
func ( g * Graph ) deleteEdgesLocked ( fromType , toType vertexType , toNamespace , toName string ) {
2018-02-20 14:28:28 -05:00
// get the "to" side
2024-09-03 15:27:24 -04:00
toVert , exists := g . getVertexRLocked ( toType , toNamespace , toName )
2018-02-20 14:28:28 -05:00
if ! exists {
return
}
// delete all edges between vertices of fromType and toVert
2018-04-19 16:59:09 -04:00
neighborsToRemove := [ ] * namedVertex { }
2020-02-10 13:24:27 -05:00
edgesToRemove := [ ] graph . Edge { }
2018-04-19 16:59:09 -04:00
g . graph . VisitTo ( toVert , func ( from graph . Node ) bool {
fromVert := from . ( * namedVertex )
if fromVert . vertexType != fromType {
return true
2018-02-20 14:28:28 -05:00
}
2020-02-10 13:24:27 -05:00
// this neighbor has only one edge (which must be to us), so remove them as well
if g . graph . Degree ( fromVert ) == 1 {
2018-04-19 16:59:09 -04:00
neighborsToRemove = append ( neighborsToRemove , fromVert )
2018-04-19 22:22:25 -04:00
} else {
2020-02-10 13:24:27 -05:00
edgesToRemove = append ( edgesToRemove , g . graph . EdgeBetween ( from , toVert ) )
2018-04-19 16:59:09 -04:00
}
return true
} )
2018-02-20 14:28:28 -05:00
// clean up orphaned verts
2018-04-19 16:59:09 -04:00
for _ , v := range neighborsToRemove {
2024-09-03 15:27:24 -04:00
g . removeVertexLocked ( v )
2018-04-19 16:59:09 -04:00
}
2018-04-19 22:22:25 -04:00
2020-02-10 13:24:27 -05:00
// remove edges and decrement destination indexes for neighbors that dropped outbound edges
for _ , edge := range edgesToRemove {
g . graph . RemoveEdge ( edge )
2024-09-03 15:27:24 -04:00
g . removeEdgeFromDestinationIndexLocked ( edge )
2020-02-10 13:24:27 -05:00
}
}
2024-09-03 15:27:24 -04:00
// A fastpath for recomputeDestinationIndexLocked for "removing edge" case.
func ( g * Graph ) removeEdgeFromDestinationIndexLocked ( e graph . Edge ) {
2020-02-10 13:24:27 -05:00
n := e . From ( )
// don't maintain indices for nodes with few edges
edgeCount := g . graph . Degree ( n )
if edgeCount < g . destinationEdgeThreshold {
delete ( g . destinationEdgeIndex , n . ID ( ) )
return
}
// decrement the nodeID->destinationID refcount in the index, if the index exists
index := g . destinationEdgeIndex [ n . ID ( ) ]
if index == nil {
return
}
if destinationEdge , ok := e . ( * destinationEdge ) ; ok {
index . decrement ( destinationEdge . DestinationID ( ) )
2018-04-19 22:22:25 -04:00
}
2018-04-19 16:59:09 -04:00
}
2024-09-03 15:27:24 -04:00
// A fastpath for recomputeDestinationIndexLocked for "adding edge case".
func ( g * Graph ) addEdgeToDestinationIndexLocked ( e graph . Edge ) {
2020-01-30 08:23:25 -05:00
n := e . From ( )
index := g . destinationEdgeIndex [ n . ID ( ) ]
if index == nil {
// There is no index, use the full index computation method
2024-09-03 15:27:24 -04:00
g . recomputeDestinationIndexLocked ( n )
2020-01-30 08:23:25 -05:00
return
}
// fast-add the new edge to an existing index
if destinationEdge , ok := e . ( * destinationEdge ) ; ok {
2020-02-10 13:24:13 -05:00
index . increment ( destinationEdge . DestinationID ( ) )
2020-01-30 08:23:25 -05:00
}
}
2018-04-19 16:59:09 -04:00
// must be called under write lock
2024-09-03 15:27:24 -04:00
// removeVertexLocked removes the specified vertex from the graph and from the maintained indices.
2018-04-19 16:59:09 -04:00
// It does nothing to indexes of neighbor vertices.
2024-09-03 15:27:24 -04:00
func ( g * Graph ) removeVertexLocked ( v * namedVertex ) {
2018-04-19 16:59:09 -04:00
g . graph . RemoveNode ( v )
2018-04-19 22:22:25 -04:00
delete ( g . destinationEdgeIndex , v . ID ( ) )
2018-04-19 16:59:09 -04:00
delete ( g . vertices [ v . vertexType ] [ v . namespace ] , v . name )
if len ( g . vertices [ v . vertexType ] [ v . namespace ] ) == 0 {
delete ( g . vertices [ v . vertexType ] , v . namespace )
2018-02-20 14:28:28 -05:00
}
}
2018-04-19 22:22:25 -04:00
// must be called under write lock
2024-09-03 15:27:24 -04:00
// recomputeDestinationIndexLocked recomputes the index of destination ids for the specified vertex
func ( g * Graph ) recomputeDestinationIndexLocked ( n graph . Node ) {
2018-04-19 22:22:25 -04:00
// don't maintain indices for nodes with few edges
edgeCount := g . graph . Degree ( n )
if edgeCount < g . destinationEdgeThreshold {
delete ( g . destinationEdgeIndex , n . ID ( ) )
return
}
// get or create the index
index := g . destinationEdgeIndex [ n . ID ( ) ]
if index == nil {
index = newIntSet ( )
} else {
2020-02-10 13:24:13 -05:00
index . reset ( )
2018-04-19 22:22:25 -04:00
}
// populate the index
g . graph . VisitFrom ( n , func ( dest graph . Node ) bool {
if destinationEdge , ok := g . graph . EdgeBetween ( n , dest ) . ( * destinationEdge ) ; ok {
2020-02-10 13:24:13 -05:00
index . increment ( destinationEdge . DestinationID ( ) )
2018-04-19 22:22:25 -04:00
}
return true
} )
2020-02-10 13:24:27 -05:00
g . destinationEdgeIndex [ n . ID ( ) ] = index
2018-04-19 22:22:25 -04:00
}
2017-05-30 15:15:38 -04:00
// AddPod should only be called once spec.NodeName is populated.
// It sets up edges for the following relationships (which are immutable for a pod once bound to a node):
//
2022-12-17 17:31:05 -05:00
// pod -> node
2022-07-19 20:54:13 -04:00
// secret -> pod
// configmap -> pod
// pvc -> pod
// svcacct -> pod
2018-08-08 08:41:00 -04:00
func ( g * Graph ) AddPod ( pod * corev1 . Pod ) {
2020-06-17 11:48:42 -04:00
start := time . Now ( )
defer func ( ) {
graphActionsDuration . WithLabelValues ( "AddPod" ) . Observe ( time . Since ( start ) . Seconds ( ) )
} ( )
2017-05-30 15:15:38 -04:00
g . lock . Lock ( )
defer g . lock . Unlock ( )
2024-09-03 15:27:24 -04:00
g . deleteVertexLocked ( podVertexType , pod . Namespace , pod . Name )
podVertex := g . getOrCreateVertexLocked ( podVertexType , pod . Namespace , pod . Name )
nodeVertex := g . getOrCreateVertexLocked ( nodeVertexType , "" , pod . Spec . NodeName )
2024-08-30 19:08:51 -04:00
// Edge adds must be handled by addEdgeLocked instead of direct g.graph.SetEdge calls.
g . addEdgeLocked ( podVertex , nodeVertex , nodeVertex )
2017-05-30 15:15:38 -04:00
2018-06-06 11:34:14 -04:00
// Short-circuit adding edges to other resources for mirror pods.
// A node must never be able to create a pod that grants them permissions on other API objects.
// The NodeRestriction admission plugin prevents creation of such pods, but short-circuiting here gives us defense in depth.
2018-08-16 06:02:17 -04:00
if _ , isMirrorPod := pod . Annotations [ corev1 . MirrorPodAnnotationKey ] ; isMirrorPod {
2018-06-06 11:34:14 -04:00
return
}
2024-08-30 03:47:15 -04:00
// The pod unconditionally gets access to the pod's service account. In the
// future, this access could be restricted based on whether or not the pod
// actually mounts a service account token, or has a podcertificate volume.
2017-11-02 13:26:04 -04:00
if len ( pod . Spec . ServiceAccountName ) > 0 {
2024-09-03 15:27:24 -04:00
serviceAccountVertex := g . getOrCreateVertexLocked ( serviceAccountVertexType , pod . Namespace , pod . Spec . ServiceAccountName )
2024-08-30 19:08:51 -04:00
// Edge adds must be handled by addEdgeLocked instead of direct g.graph.SetEdge calls.
g . addEdgeLocked ( serviceAccountVertex , podVertex , nodeVertex )
2017-11-02 13:26:04 -04:00
}
2017-05-30 15:15:38 -04:00
podutil . VisitPodSecretNames ( pod , func ( secret string ) bool {
2024-09-03 15:27:24 -04:00
secretVertex := g . getOrCreateVertexLocked ( secretVertexType , pod . Namespace , secret )
2024-08-30 19:08:51 -04:00
// Edge adds must be handled by addEdgeLocked instead of direct g.graph.SetEdge calls.
g . addEdgeLocked ( secretVertex , podVertex , nodeVertex )
2017-05-30 15:15:38 -04:00
return true
} )
podutil . VisitPodConfigmapNames ( pod , func ( configmap string ) bool {
2024-09-03 15:27:24 -04:00
configmapVertex := g . getOrCreateVertexLocked ( configMapVertexType , pod . Namespace , configmap )
2024-08-30 19:08:51 -04:00
// Edge adds must be handled by addEdgeLocked instead of direct g.graph.SetEdge calls.
g . addEdgeLocked ( configmapVertex , podVertex , nodeVertex )
2017-05-30 15:15:38 -04:00
return true
} )
for _ , v := range pod . Spec . Volumes {
2020-06-08 04:31:38 -04:00
claimName := ""
2017-05-30 15:15:38 -04:00
if v . PersistentVolumeClaim != nil {
2020-06-08 04:31:38 -04:00
claimName = v . PersistentVolumeClaim . ClaimName
2021-10-11 09:57:25 -04:00
} else if v . Ephemeral != nil {
2021-08-31 02:39:55 -04:00
claimName = ephemeral . VolumeClaimName ( pod , & v )
2020-06-08 04:31:38 -04:00
}
if claimName != "" {
2024-09-03 15:27:24 -04:00
pvcVertex := g . getOrCreateVertexLocked ( pvcVertexType , pod . Namespace , claimName )
2024-08-30 19:08:51 -04:00
// Edge adds must be handled by addEdgeLocked instead of direct g.graph.SetEdge calls.
g . addEdgeLocked ( pvcVertex , podVertex , nodeVertex )
2017-05-30 15:15:38 -04:00
}
}
2023-03-03 07:33:20 -05:00
for _ , podResourceClaim := range pod . Spec . ResourceClaims {
claimName , _ , err := resourceclaim . Name ( pod , & podResourceClaim )
// Do we have a valid claim name? If yes, add an edge that grants
// kubelet access to that claim. An error indicates that a claim
// still needs to be created, nil that intentionally no claim
// was created and never will be because it isn't needed.
if err == nil && claimName != nil {
2024-09-03 15:27:24 -04:00
claimVertex := g . getOrCreateVertexLocked ( resourceClaimVertexType , pod . Namespace , * claimName )
2024-08-30 19:08:51 -04:00
// Edge adds must be handled by addEdgeLocked instead of direct g.graph.SetEdge calls.
g . addEdgeLocked ( claimVertex , podVertex , nodeVertex )
2023-03-03 07:33:20 -05:00
}
}
2025-07-17 12:47:35 -04:00
if pod . Status . ExtendedResourceClaimStatus != nil && len ( pod . Status . ExtendedResourceClaimStatus . ResourceClaimName ) > 0 {
claimVertex := g . getOrCreateVertexLocked ( resourceClaimVertexType , pod . Namespace , pod . Status . ExtendedResourceClaimStatus . ResourceClaimName )
// Edge adds must be handled by addEdgeLocked instead of direct g.graph.SetEdge calls.
g . addEdgeLocked ( claimVertex , podVertex , nodeVertex )
}
2017-05-30 15:15:38 -04:00
}
2024-08-30 19:08:51 -04:00
// Must be called under a write lock.
// All edge adds must be handled by that method rather than by calling
// g.graph.SetEdge directly.
// Note: if "from" belongs to vertexTypeWithAuthoritativeIndex, then
// "destination" must be non-nil.
func ( g * Graph ) addEdgeLocked ( from , to , destination * namedVertex ) {
if destination != nil {
e := newDestinationEdge ( from , to , destination )
g . graph . SetEdge ( e )
g . addEdgeToDestinationIndexLocked ( e )
return
}
// We must not create edges without a Node label from a vertex that is
// supposed to hold authoritative destination edge index only.
// Entering this branch would mean there's a bug in the Node authorizer.
if vertexTypeWithAuthoritativeIndex [ from . vertexType ] {
panic ( fmt . Sprintf ( "vertex of type %q must have destination edges only" , vertexTypes [ from . vertexType ] ) )
}
g . graph . SetEdge ( simple . Edge { F : from , T : to } )
}
2017-05-30 15:15:38 -04:00
func ( g * Graph ) DeletePod ( name , namespace string ) {
2020-06-17 11:48:42 -04:00
start := time . Now ( )
defer func ( ) {
graphActionsDuration . WithLabelValues ( "DeletePod" ) . Observe ( time . Since ( start ) . Seconds ( ) )
} ( )
2017-05-30 15:15:38 -04:00
g . lock . Lock ( )
defer g . lock . Unlock ( )
2024-09-03 15:27:24 -04:00
g . deleteVertexLocked ( podVertexType , namespace , name )
2017-05-30 15:15:38 -04:00
}
2024-08-30 03:47:15 -04:00
// AddPodCertificateRequest adds a PodCertificateRequest to the graph.
//
// PCRs technically have two valid edges:
//
// * PCR -> Pod (-> Node)
//
// * PCR -> Node
//
// We only add the direct PCR -> Node edge, since that is enough to perform the
// authorization, and it's a shorter graph traversal. The noderestriction
// admission plugin ensures that all PCRs created have a valid node,
// serviceaccount, and pod combination that actually exists in the cluster.
2025-09-16 16:24:07 -04:00
func ( g * Graph ) AddPodCertificateRequest ( pcr * certsv1beta1 . PodCertificateRequest ) {
2024-08-30 03:47:15 -04:00
start := time . Now ( )
defer func ( ) {
graphActionsDuration . WithLabelValues ( "AddPodCertificateRequest" ) . Observe ( time . Since ( start ) . Seconds ( ) )
} ( )
g . lock . Lock ( )
defer g . lock . Unlock ( )
g . deleteVertexLocked ( pcrVertexType , pcr . ObjectMeta . Namespace , pcr . ObjectMeta . Name )
pcrVertex := g . getOrCreateVertexLocked ( pcrVertexType , pcr . ObjectMeta . Namespace , pcr . ObjectMeta . Name )
nodeVertex := g . getOrCreateVertexLocked ( nodeVertexType , "" , string ( pcr . Spec . NodeName ) )
g . addEdgeLocked ( pcrVertex , nodeVertex , nodeVertex )
}
// DeletePodCertificateRequest removes it from the graph.
2025-09-16 16:24:07 -04:00
func ( g * Graph ) DeletePodCertificateRequest ( pcr * certsv1beta1 . PodCertificateRequest ) {
2024-08-30 03:47:15 -04:00
start := time . Now ( )
defer func ( ) {
graphActionsDuration . WithLabelValues ( "DeletePodCertificateRequest" ) . Observe ( time . Since ( start ) . Seconds ( ) )
} ( )
g . lock . Lock ( )
defer g . lock . Unlock ( )
g . deleteVertexLocked ( pcrVertexType , pcr . ObjectMeta . Namespace , pcr . ObjectMeta . Name )
}
2017-05-30 15:15:38 -04:00
// AddPV sets up edges for the following relationships:
//
2022-07-19 20:54:13 -04:00
// secret -> pv
2017-05-30 15:15:38 -04:00
//
2022-07-19 20:54:13 -04:00
// pv -> pvc
2018-08-09 09:27:23 -04:00
func ( g * Graph ) AddPV ( pv * corev1 . PersistentVolume ) {
2020-06-17 11:48:42 -04:00
start := time . Now ( )
defer func ( ) {
graphActionsDuration . WithLabelValues ( "AddPV" ) . Observe ( time . Since ( start ) . Seconds ( ) )
} ( )
2017-05-30 15:15:38 -04:00
g . lock . Lock ( )
defer g . lock . Unlock ( )
// clear existing edges
2024-09-03 15:27:24 -04:00
g . deleteVertexLocked ( pvVertexType , "" , pv . Name )
2017-05-30 15:15:38 -04:00
// if we have a pvc, establish new edges
if pv . Spec . ClaimRef != nil {
2024-09-03 15:27:24 -04:00
pvVertex := g . getOrCreateVertexLocked ( pvVertexType , "" , pv . Name )
2017-05-30 15:15:38 -04:00
// 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
2024-08-30 19:08:51 -04:00
// Edge adds must be handled by addEdgeLocked instead of direct g.graph.SetEdge calls.
g . addEdgeLocked ( pvVertex , g . getOrCreateVertexLocked ( pvcVertexType , pv . Spec . ClaimRef . Namespace , pv . Spec . ClaimRef . Name ) , nil )
2018-02-23 16:50:43 -05:00
pvutil . VisitPVSecretNames ( pv , func ( namespace , secret string , kubeletVisible bool ) bool {
2017-05-30 15:15:38 -04:00
// This grants access to the named secret in the same namespace as the bound PVC
2018-02-23 16:50:43 -05:00
if kubeletVisible {
2024-08-30 19:08:51 -04:00
// Edge adds must be handled by addEdgeLocked instead of direct g.graph.SetEdge calls.
g . addEdgeLocked ( g . getOrCreateVertexLocked ( secretVertexType , namespace , secret ) , pvVertex , nil )
2018-02-23 16:50:43 -05:00
}
2017-05-30 15:15:38 -04:00
return true
} )
}
}
func ( g * Graph ) DeletePV ( name string ) {
2020-06-17 11:48:42 -04:00
start := time . Now ( )
defer func ( ) {
graphActionsDuration . WithLabelValues ( "DeletePV" ) . Observe ( time . Since ( start ) . Seconds ( ) )
} ( )
2017-05-30 15:15:38 -04:00
g . lock . Lock ( )
defer g . lock . Unlock ( )
2024-09-03 15:27:24 -04:00
g . deleteVertexLocked ( pvVertexType , "" , name )
2017-05-30 15:15:38 -04:00
}
2018-01-16 23:39:11 -05:00
// AddVolumeAttachment sets up edges for the following relationships:
//
2022-07-19 20:54:13 -04:00
// volume attachment -> node
2018-01-16 23:39:11 -05:00
func ( g * Graph ) AddVolumeAttachment ( attachmentName , nodeName string ) {
2020-06-17 11:48:42 -04:00
start := time . Now ( )
defer func ( ) {
graphActionsDuration . WithLabelValues ( "AddVolumeAttachment" ) . Observe ( time . Since ( start ) . Seconds ( ) )
} ( )
2018-01-16 23:39:11 -05:00
g . lock . Lock ( )
defer g . lock . Unlock ( )
// clear existing edges
2024-09-03 15:27:24 -04:00
g . deleteVertexLocked ( vaVertexType , "" , attachmentName )
2018-01-16 23:39:11 -05:00
// if we have a node, establish new edges
if len ( nodeName ) > 0 {
2024-09-03 15:27:24 -04:00
vaVertex := g . getOrCreateVertexLocked ( vaVertexType , "" , attachmentName )
nodeVertex := g . getOrCreateVertexLocked ( nodeVertexType , "" , nodeName )
2024-08-30 19:08:51 -04:00
// Edge adds must be handled by addEdgeLocked instead of direct g.graph.SetEdge calls.
g . addEdgeLocked ( vaVertex , nodeVertex , nodeVertex )
2018-01-16 23:39:11 -05:00
}
}
func ( g * Graph ) DeleteVolumeAttachment ( name string ) {
2020-06-17 11:48:42 -04:00
start := time . Now ( )
defer func ( ) {
graphActionsDuration . WithLabelValues ( "DeleteVolumeAttachment" ) . Observe ( time . Since ( start ) . Seconds ( ) )
} ( )
2018-01-16 23:39:11 -05:00
g . lock . Lock ( )
defer g . lock . Unlock ( )
2024-09-03 15:27:24 -04:00
g . deleteVertexLocked ( vaVertexType , "" , name )
2018-01-16 23:39:11 -05:00
}
2024-01-24 11:51:40 -05:00
2024-03-07 04:14:11 -05:00
// AddResourceSlice sets up edges for the following relationships:
2024-01-24 11:51:40 -05:00
//
// node resource slice -> node
2024-03-07 04:14:11 -05:00
func ( g * Graph ) AddResourceSlice ( sliceName , nodeName string ) {
2024-01-24 11:51:40 -05:00
start := time . Now ( )
defer func ( ) {
2024-03-07 04:14:11 -05:00
graphActionsDuration . WithLabelValues ( "AddResourceSlice" ) . Observe ( time . Since ( start ) . Seconds ( ) )
2024-01-24 11:51:40 -05:00
} ( )
g . lock . Lock ( )
defer g . lock . Unlock ( )
// clear existing edges
2024-09-03 15:27:24 -04:00
g . deleteVertexLocked ( sliceVertexType , "" , sliceName )
2024-01-24 11:51:40 -05:00
// if we have a node, establish new edges
if len ( nodeName ) > 0 {
2024-09-03 15:27:24 -04:00
sliceVertex := g . getOrCreateVertexLocked ( sliceVertexType , "" , sliceName )
nodeVertex := g . getOrCreateVertexLocked ( nodeVertexType , "" , nodeName )
2024-08-30 19:08:51 -04:00
// Edge adds must be handled by addEdgeLocked instead of direct g.graph.SetEdge calls.
g . addEdgeLocked ( sliceVertex , nodeVertex , nodeVertex )
2024-01-24 11:51:40 -05:00
}
}
2024-03-07 04:14:11 -05:00
func ( g * Graph ) DeleteResourceSlice ( sliceName string ) {
2024-01-24 11:51:40 -05:00
start := time . Now ( )
defer func ( ) {
2024-03-07 04:14:11 -05:00
graphActionsDuration . WithLabelValues ( "DeleteResourceSlice" ) . Observe ( time . Since ( start ) . Seconds ( ) )
2024-01-24 11:51:40 -05:00
} ( )
g . lock . Lock ( )
defer g . lock . Unlock ( )
2024-09-03 15:27:24 -04:00
g . deleteVertexLocked ( sliceVertexType , "" , sliceName )
2024-01-24 11:51:40 -05:00
}