github.com/cilium/cilium@v1.16.2/operator/watchers/node.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package watchers 5 6 import ( 7 "fmt" 8 "sync" 9 10 k8sErrors "k8s.io/apimachinery/pkg/api/errors" 11 "k8s.io/apimachinery/pkg/runtime/schema" 12 "k8s.io/client-go/tools/cache" 13 "k8s.io/client-go/util/workqueue" 14 15 "github.com/cilium/cilium/pkg/k8s/informer" 16 slim_corev1 "github.com/cilium/cilium/pkg/k8s/slim/k8s/api/core/v1" 17 slim_metav1 "github.com/cilium/cilium/pkg/k8s/slim/k8s/apis/meta/v1" 18 slimclientset "github.com/cilium/cilium/pkg/k8s/slim/k8s/client/clientset/versioned" 19 "github.com/cilium/cilium/pkg/k8s/utils" 20 ) 21 22 var ( 23 // nodeSyncOnce is used to make sure nodesInit is only setup once. 24 nodeSyncOnce sync.Once 25 26 // slimNodeStore contains all cluster nodes store as slim_core.Node 27 slimNodeStore cache.Store 28 29 // slimNodeStoreSynced is closed once the slimNodeStore is synced 30 // with k8s. 31 slimNodeStoreSynced = make(chan struct{}) 32 33 nodeController cache.Controller 34 35 nodeQueue = workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "node-queue") 36 ) 37 38 // NodeQueueShutDown is a wrapper to expose ShutDown for the global nodeQueue. 39 // It is meant to be used in unit test like the identity-gc one in operator/identity/ 40 // in order to avoid goleak complaining about leaked goroutines. 41 func NodeQueueShutDown() { 42 nodeQueue.ShutDown() 43 } 44 45 type slimNodeGetter interface { 46 GetK8sSlimNode(nodeName string) (*slim_corev1.Node, error) 47 ListK8sSlimNode() []*slim_corev1.Node 48 } 49 50 type nodeGetter struct{} 51 52 // GetK8sSlimNode returns a slim_corev1.Node from the local store. 53 // The return structure should only be used for read purposes and should never 54 // be written into it. 55 func (nodeGetter) GetK8sSlimNode(nodeName string) (*slim_corev1.Node, error) { 56 nodeInterface, exists, err := slimNodeStore.GetByKey(nodeName) 57 if err != nil { 58 return nil, err 59 } 60 if !exists { 61 return nil, k8sErrors.NewNotFound(schema.GroupResource{ 62 Group: "core", 63 Resource: "Node", 64 }, nodeName) 65 } 66 return nodeInterface.(*slim_corev1.Node), nil 67 } 68 69 func (nodeGetter) ListK8sSlimNode() []*slim_corev1.Node { 70 nodesInt := slimNodeStore.List() 71 out := make([]*slim_corev1.Node, 0, len(nodesInt)) 72 for i := range nodesInt { 73 out = append(out, nodesInt[i].(*slim_corev1.Node)) 74 } 75 return out 76 } 77 78 // nodesInit starts up a node watcher to handle node events. 79 func nodesInit(wg *sync.WaitGroup, slimClient slimclientset.Interface, stopCh <-chan struct{}) { 80 nodeSyncOnce.Do(func() { 81 slimNodeStore, nodeController = informer.NewInformer( 82 utils.ListerWatcherFromTyped[*slim_corev1.NodeList](slimClient.CoreV1().Nodes()), 83 &slim_corev1.Node{}, 84 0, 85 cache.ResourceEventHandlerFuncs{ 86 AddFunc: func(obj interface{}) { 87 key, _ := queueKeyFunc(obj) 88 nodeQueue.Add(key) 89 }, 90 UpdateFunc: func(_, newObj interface{}) { 91 key, _ := queueKeyFunc(newObj) 92 nodeQueue.Add(key) 93 }, 94 }, 95 transformToNode, 96 ) 97 wg.Add(1) 98 go func() { 99 defer wg.Done() 100 defer nodeQueue.ShutDown() 101 nodeController.Run(stopCh) 102 }() 103 104 cache.WaitForCacheSync(stopCh, nodeController.HasSynced) 105 close(slimNodeStoreSynced) 106 }) 107 } 108 109 func transformToNode(obj interface{}) (interface{}, error) { 110 switch concreteObj := obj.(type) { 111 case *slim_corev1.Node: 112 n := &slim_corev1.Node{ 113 TypeMeta: concreteObj.TypeMeta, 114 ObjectMeta: slim_metav1.ObjectMeta{ 115 Name: concreteObj.Name, 116 ResourceVersion: concreteObj.ResourceVersion, 117 }, 118 Spec: slim_corev1.NodeSpec{ 119 Taints: concreteObj.Spec.Taints, 120 }, 121 Status: slim_corev1.NodeStatus{ 122 Conditions: concreteObj.Status.Conditions, 123 }, 124 } 125 *concreteObj = slim_corev1.Node{} 126 return n, nil 127 case cache.DeletedFinalStateUnknown: 128 node, ok := concreteObj.Obj.(*slim_corev1.Node) 129 if !ok { 130 return nil, fmt.Errorf("unknown object type %T", concreteObj.Obj) 131 } 132 dfsu := cache.DeletedFinalStateUnknown{ 133 Key: concreteObj.Key, 134 Obj: &slim_corev1.Node{ 135 TypeMeta: node.TypeMeta, 136 ObjectMeta: slim_metav1.ObjectMeta{ 137 Name: node.Name, 138 ResourceVersion: node.ResourceVersion, 139 }, 140 Spec: slim_corev1.NodeSpec{ 141 Taints: node.Spec.Taints, 142 }, 143 Status: slim_corev1.NodeStatus{ 144 Conditions: node.Status.Conditions, 145 }, 146 }, 147 } 148 // Small GC optimization 149 *node = slim_corev1.Node{} 150 return dfsu, nil 151 default: 152 return nil, fmt.Errorf("unknown object type %T", concreteObj) 153 } 154 }