@@ -24,10 +24,13 @@ import (
24
24
)
25
25
26
26
const (
27
- informerResyncPeriod = 1 * time .Minute
28
- defaultMetadataTTL = 300 * time .Second
27
+ informerResyncPeriod = 1 * time .Minute
28
+ defaultMetadataTTL = 300 * time .Second
29
+ defaultK8sNodeCacheTTL = 300 * time .Second
29
30
)
30
31
32
+ var registeredK8sNodeCache * k8sNodeCache = newK8sNodeCache ()
33
+
31
34
type nodeRequest struct {
32
35
node * v1.Node
33
36
timestamp time.Time
@@ -48,6 +51,104 @@ type nodeController struct {
48
51
nodeLastAdded map [string ]time.Time
49
52
}
50
53
54
+ // k8sNodeCache stores node related info as registered in k8s
55
+ type k8sNodeCache struct {
56
+ sync.RWMutex
57
+ nodes map [string ]* v1.Node
58
+ providerIDs map [string ]string
59
+ lastUpdate time.Time
60
+ ttl time.Duration
61
+ }
62
+
63
+ // updateCache updates the k8s node cache with the latest nodes from the k8s API server.
64
+ func (c * k8sNodeCache ) updateCache (kubeclient kubernetes.Interface ) {
65
+ c .Lock ()
66
+ defer c .Unlock ()
67
+ if time .Since (c .lastUpdate ) < c .ttl {
68
+ return
69
+ }
70
+
71
+ nodeList , err := kubeclient .CoreV1 ().Nodes ().List (context .TODO (), metav1.ListOptions {})
72
+ if err != nil {
73
+ klog .Errorf ("failed to list nodes, cannot create/update k8s node cache: %s" , err )
74
+ return
75
+ }
76
+
77
+ nodes := make (map [string ]* v1.Node , len (nodeList .Items ))
78
+ providerIDs := make (map [string ]string , len (nodeList .Items ))
79
+ for _ , node := range nodeList .Items {
80
+ if node .Spec .ProviderID == "" {
81
+ klog .Errorf ("Empty providerID [%s] for node %s, skipping it" , node .Spec .ProviderID , node .Name )
82
+ continue
83
+ }
84
+ nodes [node .Name ] = & node
85
+ providerIDs [node .Spec .ProviderID ] = node .Name
86
+ }
87
+
88
+ c .nodes = nodes
89
+ c .providerIDs = providerIDs
90
+ c .lastUpdate = time .Now ()
91
+ }
92
+
93
+ // addNodeToCache stores the specified node in k8s node cache
94
+ func (c * k8sNodeCache ) addNodeToCache (node * v1.Node ) {
95
+ c .Lock ()
96
+ defer c .Unlock ()
97
+ if node .Spec .ProviderID == "" {
98
+ klog .Errorf ("Empty providerID [%s] for node %s, skipping it" , node .Spec .ProviderID , node .Name )
99
+ return
100
+ }
101
+ c .nodes [node .Name ] = node
102
+ c .providerIDs [node .Spec .ProviderID ] = node .Name
103
+ }
104
+
105
+ // getNodeLabel returns the k8s node label for the given provider ID or instance label.
106
+ // If the provider ID or label is not found in the cache, it returns an empty string and false.
107
+ func (c * k8sNodeCache ) getNodeLabel (providerID string , instanceLabel string ) (string , bool ) {
108
+ c .RLock ()
109
+ defer c .RUnlock ()
110
+
111
+ // check if instance label matches with the registered k8s node
112
+ if _ , exists := c .nodes [instanceLabel ]; exists {
113
+ return instanceLabel , true
114
+ }
115
+
116
+ // check if provider id matches with the registered k8s node
117
+ if label , exists := c .providerIDs [providerID ]; exists {
118
+ return label , true
119
+ }
120
+
121
+ return "" , false
122
+ }
123
+
124
+ // getProviderID returns linode specific providerID for given k8s node name
125
+ func (c * k8sNodeCache ) getProviderID (nodeName string ) (string , bool ) {
126
+ c .RLock ()
127
+ defer c .RUnlock ()
128
+
129
+ if node , exists := c .nodes [nodeName ]; exists {
130
+ return node .Spec .ProviderID , true
131
+ }
132
+
133
+ return "" , false
134
+ }
135
+
136
+ // newK8sNodeCache returns new k8s node cache instance
137
+ func newK8sNodeCache () * k8sNodeCache {
138
+ timeout := defaultK8sNodeCacheTTL
139
+ if raw , ok := os .LookupEnv ("K8S_NODECACHE_TTL" ); ok {
140
+ if t , err := strconv .Atoi (raw ); t > 0 && err == nil {
141
+ timeout = time .Duration (t ) * time .Second
142
+ }
143
+ }
144
+
145
+ return & k8sNodeCache {
146
+ nodes : make (map [string ]* v1.Node , 0 ),
147
+ providerIDs : make (map [string ]string , 0 ),
148
+ ttl : timeout ,
149
+ }
150
+ }
151
+
51
152
func newNodeController (kubeclient kubernetes.Interface , client client.Client , informer v1informers.NodeInformer , instanceCache * instances ) * nodeController {
52
153
timeout := defaultMetadataTTL
53
154
if raw , ok := os .LookupEnv ("LINODE_METADATA_TTL" ); ok {
@@ -145,6 +246,7 @@ func (s *nodeController) processNext() bool {
145
246
klog .Errorf ("failed to add metadata for node (%s); will not retry: %s" , request .node .Name , err )
146
247
}
147
248
249
+ registeredK8sNodeCache .updateCache (s .kubeclient )
148
250
return true
149
251
}
150
252
@@ -187,9 +289,7 @@ func (s *nodeController) handleNode(ctx context.Context, node *v1.Node) error {
187
289
188
290
expectedPrivateIP := ""
189
291
// linode API response for linode will contain only one private ip
190
- // if any private ip is configured. If it changes in future or linode
191
- // supports other subnets with nodebalancer, this logic needs to be updated.
192
- // https://www.linode.com/docs/api/linode-instances/#linode-view
292
+ // if any private ip is configured.
193
293
for _ , addr := range linode .IPv4 {
194
294
if isPrivate (addr ) {
195
295
expectedPrivateIP = addr .String ()
@@ -202,6 +302,7 @@ func (s *nodeController) handleNode(ctx context.Context, node *v1.Node) error {
202
302
return nil
203
303
}
204
304
305
+ var updatedNode * v1.Node
205
306
if err := retry .RetryOnConflict (retry .DefaultRetry , func () error {
206
307
// Get a fresh copy of the node so the resource version is up-to-date
207
308
nodeResult , err := s .kubeclient .CoreV1 ().Nodes ().Get (ctx , node .Name , metav1.GetOptions {})
@@ -223,13 +324,16 @@ func (s *nodeController) handleNode(ctx context.Context, node *v1.Node) error {
223
324
if nodeResult .Annotations [annotations .AnnLinodeNodePrivateIP ] != expectedPrivateIP && expectedPrivateIP != "" {
224
325
nodeResult .Annotations [annotations .AnnLinodeNodePrivateIP ] = expectedPrivateIP
225
326
}
226
- _ , err = s .kubeclient .CoreV1 ().Nodes ().Update (ctx , nodeResult , metav1.UpdateOptions {})
327
+ updatedNode , err = s .kubeclient .CoreV1 ().Nodes ().Update (ctx , nodeResult , metav1.UpdateOptions {})
227
328
return err
228
329
}); err != nil {
229
330
klog .V (1 ).ErrorS (err , "Node update error" )
230
331
return err
231
332
}
232
333
334
+ if updatedNode != nil {
335
+ registeredK8sNodeCache .addNodeToCache (updatedNode )
336
+ }
233
337
s .SetLastMetadataUpdate (node .Name )
234
338
235
339
return nil
0 commit comments