Skip to content

Commit dc7c272

Browse files
committed
Fix order for adding Services to map
1 parent f14d233 commit dc7c272

1 file changed

Lines changed: 102 additions & 61 deletions

File tree

pkg/controllers/services_controller.go

Lines changed: 102 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -207,40 +207,33 @@ func (c *ServicesController) Start(ctx context.Context) error {
207207
func (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.
268261
func (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.
326337
func (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.
398418
func 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.
403433
func 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

Comments
 (0)