Repository: traefik/traefik
File: pkg/provider/kubernetes/gateway/client.go (Go)

Code before:
// The events are only used for signaling anyway so dropping a few is ok.
func eventHandlerFunc(events chan<- interface{}, obj interface{}) {
	select {
	case events <- obj:
	default:
	}
}

// translateNotFoundError will translate a "not found" error to a boolean return
// value which indicates if the resource exists and a nil error.
func translateNotFoundError(err error) (bool, error) {
	if kerror.IsNotFound(err) {
		return false, nil
	}
	return err == nil, err
}

func gatewayStatusEquals(statusA, statusB gatev1.GatewayStatus) bool {
	if len(statusA.Listeners) != len(statusB.Listeners) {
		return false
	}

	if !conditionsEquals(statusA.Conditions, statusB.Conditions) {
		return false
	}

	listenerMatches := 0
	for _, newListener := range statusB.Listeners {
		for _, oldListener := range statusA.Listeners {
			if newListener.Name == oldListener.Name {
				if !conditionsEquals(newListener.Conditions, oldListener.Conditions) {
					return false
				}

				if newListener.AttachedRoutes != oldListener.AttachedRoutes {
					return false
				}

				listenerMatches++
			}
		}
	}

	return listenerMatches == len(statusA.Listeners)
}

func conditionsEquals(conditionsA, conditionsB []metav1.Condition) bool {
	if len(conditionsA) != len(conditionsB) {
		return false
	}


Review comment (bug):
@kevinpollet shouldn't this also check for addresses? I debugged the problem I was talking to you about [yesterday](https://github.com/traefik/traefik/pull/10667) down to this function. I debugged cloning the repo, building my image, and running Traefik with additional logs.

I ended up always having the gateway.statusAddress to null because this function avoids the update but the two gateway objects are not equal, one has the address set from the service/ip/hostname and the other does not. This function seems not to take into account that so it never updates the gateway with an address, breaking external-dns.

Can you please have a look?

Code after:
		return true
	}

	return slices.Contains(c.watchedNamespaces, namespace)
}

// eventHandlerFunc will pass the obj on to the events channel or drop it.
// This is so passing the events along won't block in the case of high volume.
// The events are only used for signaling anyway so dropping a few is ok.
func eventHandlerFunc(events chan<- interface{}, obj interface{}) {
	select {
	case events <- obj:
	default:
	}
}

// translateNotFoundError will translate a "not found" error to a boolean return
// value which indicates if the resource exists and a nil error.
func translateNotFoundError(err error) (bool, error) {
	if kerror.IsNotFound(err) {
		return false, nil
	}
	return err == nil, err
}

func gatewayStatusEqual(statusA, statusB gatev1.GatewayStatus) bool {
	if len(statusA.Listeners) != len(statusB.Listeners) {
		return false
	}

	if !conditionsEqual(statusA.Conditions, statusB.Conditions) {
		return false
	}

	listenerMatches := 0
	for _, newListener := range statusB.Listeners {
		for _, oldListener := range statusA.Listeners {
			if newListener.Name == oldListener.Name {
				if !conditionsEqual(newListener.Conditions, oldListener.Conditions) {
					return false
				}

				if newListener.AttachedRoutes != oldListener.AttachedRoutes {
					return false
				}

				listenerMatches++
			}
		}
	}