@@ -207,40 +207,33 @@ func (c *ServicesController) Start(ctx context.Context) error {
207207func (c * ServicesController ) addServiceFunc (obj interface {}) {
208208 svc , ok := obj .(* v1.Service )
209209 if ! ok {
210- // object is not Service
210+ // Object is not a Service.
211211 return
212212 }
213213 if ! hasWholeIPAnnotation (svc ) {
214214 return
215215 }
216216
217- // Retrieve the corresponding endpoint.
217+ // Always add the service to the mapping, even if the endpoint is nil.
218+ se := & ServiceEndpoints {
219+ Service : svc ,
220+ Endpoint : nil ,
221+ }
222+ c .Services .Set (svc .Namespace , svc .Name , se )
223+
224+ // Try to retrieve the corresponding endpoint from the API server.
218225 ep , err := c .Clientset .CoreV1 ().Endpoints (svc .Namespace ).Get (context .TODO (), svc .Name , metav1.GetOptions {})
219226 if err != nil && ! errors .IsNotFound (err ) {
220227 log .Error (err , "failed to get endpoints for service" )
221228 return
222229 }
223- if ep == nil {
224- // Endpoint not found
225- return
226- }
227- if ! hasValidServiceIP (svc ) || ! hasValidEndpointIP (ep ) {
228- return
229- }
230-
231- // Ensure NAT mapping.
232- c .Proxy .EnsureRules (svc .Status .LoadBalancer .Ingress [0 ].IP , ep .Subsets [0 ].Addresses [0 ].IP )
233-
234- // Add the service if not already present.
235- if _ , exists := c .Services .Get (svc .Namespace , svc .Name ); exists {
236- // Service already added
237- return
238- }
239- se := & ServiceEndpoints {
240- Service : svc ,
241- Endpoint : ep ,
230+ // If the endpoint exists and both Service and Endpoint have valid IPs, update the mapping.
231+ if err == nil && ep != nil && hasValidEndpointIP (ep ) && hasValidServiceIP (svc ) {
232+ se .Endpoint = ep
233+ c .Services .Set (svc .Namespace , svc .Name , se )
234+ // Ensure NAT mapping rules are set.
235+ c .Proxy .EnsureRules (svc .Status .LoadBalancer .Ingress [0 ].IP , ep .Subsets [0 ].Addresses [0 ].IP )
242236 }
243- c .Services .Set (svc .Namespace , svc .Name , se )
244237}
245238
246239// deleteServiceFunc handles the deletion of a service.
@@ -266,81 +259,106 @@ func (c *ServicesController) deleteServiceFunc(obj interface{}) {
266259
267260// updateServiceFunc handles service updates.
268261func (c * ServicesController ) updateServiceFunc (oldObj , newObj interface {}) {
262+ // Cast the object to a Service type.
269263 svc , ok := newObj .(* v1.Service )
270264 if ! ok {
271- // object is not Service
265+ // Object is not a Service.
272266 return
273267 }
274268
275- // If the annotation is missing, delete the service.
269+ // If the required annotation is missing, remove the service mapping and delete NAT rules if applicable .
276270 if ! hasWholeIPAnnotation (svc ) {
277271 if se , exists := c .Services .Get (svc .Namespace , svc .Name ); exists {
278272 if hasValidServiceIP (se .Service ) && hasValidEndpointIP (se .Endpoint ) {
279- c .Proxy .DeleteRules (se .Service .Status .LoadBalancer .Ingress [0 ].IP , se .Endpoint .Subsets [0 ].Addresses [0 ].IP )
273+ c .Proxy .DeleteRules (
274+ se .Service .Status .LoadBalancer .Ingress [0 ].IP ,
275+ se .Endpoint .Subsets [0 ].Addresses [0 ].IP ,
276+ )
280277 }
281278 c .Services .Delete (svc .Namespace , svc .Name )
282279 }
283280 return
284281 }
285282
286- se , exists := c .Services .Get (svc .Namespace , svc .Name )
287- // If the service does not have a valid IP, delete it.
283+ // If the service does not have a valid IP, remove the service mapping.
288284 if ! hasValidServiceIP (svc ) {
289- if exists && hasValidServiceIP (se .Service ) && hasValidEndpointIP (se .Endpoint ) {
290- c .Proxy .DeleteRules (se .Service .Status .LoadBalancer .Ingress [0 ].IP , se .Endpoint .Subsets [0 ].Addresses [0 ].IP )
285+ if se , exists := c .Services .Get (svc .Namespace , svc .Name ); exists {
286+ if hasValidServiceIP (se .Service ) && hasValidEndpointIP (se .Endpoint ) {
287+ c .Proxy .DeleteRules (
288+ se .Service .Status .LoadBalancer .Ingress [0 ].IP ,
289+ se .Endpoint .Subsets [0 ].Addresses [0 ].IP ,
290+ )
291+ }
292+ c .Services .Delete (svc .Namespace , svc .Name )
291293 }
292- c .Services .Delete (svc .Namespace , svc .Name )
293294 return
294295 }
295296
296- // Retrieve the corresponding endpoint .
297+ // Attempt to retrieve the corresponding endpoints .
297298 ep , err := c .Clientset .CoreV1 ().Endpoints (svc .Namespace ).Get (context .TODO (), svc .Name , metav1.GetOptions {})
298- if err != nil && ! errors .IsNotFound (err ) {
299- log .Error (err , "failed to get endpoints for service" )
300- return
301- }
302- if ep == nil {
303- // Endpoint not found
304- return
299+ if err != nil {
300+ // If the error is NotFound, treat the endpoint as nil.
301+ if errors .IsNotFound (err ) {
302+ ep = nil
303+ } else {
304+ log .Error (err , "failed to get endpoints for service" )
305+ // Update the mapping with a nil endpoint so it can be updated later.
306+ c .Services .Set (svc .Namespace , svc .Name , & ServiceEndpoints {Service : svc , Endpoint : nil })
307+ return
308+ }
305309 }
306- if ! hasValidEndpointIP (ep ) {
307- if exists && hasValidServiceIP (se .Service ) && hasValidEndpointIP (se .Endpoint ) {
308- c .Proxy .DeleteRules (se .Service .Status .LoadBalancer .Ingress [0 ].IP , se .Endpoint .Subsets [0 ].Addresses [0 ].IP )
310+
311+ // If the endpoint is nil or does not have a valid IP,
312+ // update the mapping with a nil endpoint and remove any existing NAT rules.
313+ if ep == nil || ! hasValidEndpointIP (ep ) {
314+ if se , exists := c .Services .Get (svc .Namespace , svc .Name ); exists &&
315+ hasValidServiceIP (se .Service ) && hasValidEndpointIP (se .Endpoint ) {
316+ c .Proxy .DeleteRules (
317+ se .Service .Status .LoadBalancer .Ingress [0 ].IP ,
318+ se .Endpoint .Subsets [0 ].Addresses [0 ].IP ,
319+ )
309320 }
310- c .Services .Delete (svc .Namespace , svc .Name )
321+ c .Services .Set (svc .Namespace , svc .Name , & ServiceEndpoints { Service : svc , Endpoint : nil } )
311322 return
312323 }
313324
314- // Ensure NAT mapping is up to date .
315- c . Proxy . EnsureRules ( svc . Status . LoadBalancer . Ingress [ 0 ]. IP , ep . Subsets [ 0 ]. Addresses [ 0 ]. IP )
316- if exists {
317- se . Service = svc
318- se . Endpoint = ep
319- c . Services . Set ( svc . Namespace , svc . Name , se )
320- } else {
321- c . Services . Set ( svc . Namespace , svc . Name , & ServiceEndpoints { Service : svc , Endpoint : ep })
322- }
325+ // At this point, both the Service and Endpoint have valid IPs .
326+ // Ensure NAT mapping is up-to-date.
327+ c . Proxy . EnsureRules (
328+ svc . Status . LoadBalancer . Ingress [ 0 ]. IP ,
329+ ep . Subsets [ 0 ]. Addresses [ 0 ]. IP ,
330+ )
331+
332+ // Update or add the service mapping with the new endpoint.
333+ c . Services . Set ( svc . Namespace , svc . Name , & ServiceEndpoints { Service : svc , Endpoint : ep })
323334}
324335
325336// addEndpointFunc handles the addition of endpoints.
326337func (c * ServicesController ) addEndpointFunc (obj interface {}) {
338+ // Cast the object to an Endpoints type.
327339 ep , ok := obj .(* v1.Endpoints )
328340 if ! ok {
329- // object is not Endpoints
341+ // Object is not an Endpoints.
330342 return
331343 }
332344
345+ // Retrieve the ServiceEndpoints mapping for the service.
333346 se , exists := c .Services .Get (ep .Namespace , ep .Name )
334347 if ! exists {
335- // Service is not managed by us
348+ // If the service is not managed by us, do nothing.
336349 return
337350 }
338- // Update the endpoint in the service map.
351+
352+ // Update the endpoint in the mapping.
339353 c .Services .SetEndpoint (ep .Namespace , ep .Name , ep )
340- if ! hasValidServiceIP (se .Service ) || ! hasValidEndpointIP (ep ) {
341- return
354+
355+ // If both the Service and the Endpoint have valid IPs, ensure NAT mapping rules.
356+ if hasValidServiceIP (se .Service ) && hasValidEndpointIP (ep ) {
357+ c .Proxy .EnsureRules (
358+ se .Service .Status .LoadBalancer .Ingress [0 ].IP ,
359+ ep .Subsets [0 ].Addresses [0 ].IP ,
360+ )
342361 }
343- c .Proxy .EnsureRules (se .Service .Status .LoadBalancer .Ingress [0 ].IP , ep .Subsets [0 ].Addresses [0 ].IP )
344362}
345363
346364// deleteEndpointFunc handles endpoint deletions.
@@ -395,15 +413,38 @@ func (c *ServicesController) updateEndpointFunc(oldObj, newObj interface{}) {
395413}
396414
397415// hasValidServiceIP checks whether the service has a valid IP.
416+ // It returns false if the service is nil, if the LoadBalancer Ingress slice is empty,
417+ // or if the first Ingress entry does not have a valid (non-empty) IP.
398418func hasValidServiceIP (svc * v1.Service ) bool {
399- return len (svc .Status .LoadBalancer .Ingress ) > 0 && svc .Status .LoadBalancer .Ingress [0 ].IP != ""
419+ // Return false if svc is nil.
420+ if svc == nil {
421+ return false
422+ }
423+ // Ensure that there is at least one LoadBalancer Ingress.
424+ if len (svc .Status .LoadBalancer .Ingress ) == 0 {
425+ return false
426+ }
427+ // Check if the first Ingress has a non-empty IP.
428+ return svc .Status .LoadBalancer .Ingress [0 ].IP != ""
400429}
401430
402431// hasValidEndpointIP checks whether the endpoints have a valid IP.
432+ // It returns false if the endpoints object is nil or does not contain a valid IP.
403433func hasValidEndpointIP (ep * v1.Endpoints ) bool {
404- return len (ep .Subsets ) > 0 &&
405- len (ep .Subsets [0 ].Addresses ) > 0 &&
406- ep .Subsets [0 ].Addresses [0 ].IP != ""
434+ // Return false if ep is nil.
435+ if ep == nil {
436+ return false
437+ }
438+ // Ensure that there is at least one subset.
439+ if len (ep .Subsets ) == 0 {
440+ return false
441+ }
442+ // Ensure that the first subset contains at least one address.
443+ if len (ep .Subsets [0 ].Addresses ) == 0 {
444+ return false
445+ }
446+ // Check if the first address has a non-empty IP.
447+ return ep .Subsets [0 ].Addresses [0 ].IP != ""
407448}
408449
409450// hasWholeIPAnnotation checks if the service has the wholeIP annotation set to true.
0 commit comments