From 782c16c5138fb0f83ea80ed1793e3be93791d280 Mon Sep 17 00:00:00 2001 From: David Bond Date: Mon, 15 Sep 2025 12:37:28 +0100 Subject: [PATCH] k8s-operator: reset service status before append (#17120) This commit fixes an issue within the service reconciler where we end up in a constant reconciliation loop. When reconciling, the loadbalancer status is appended to but not reset between each reconciliation, leading to an ever growing slice of duplicate statuses. Fixes https://github.com/tailscale/tailscale/issues/17105 Fixes https://github.com/tailscale/tailscale/issues/17107 Signed-off-by: David Bond --- cmd/k8s-operator/operator_test.go | 4 ++++ cmd/k8s-operator/svc.go | 10 ++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/cmd/k8s-operator/operator_test.go b/cmd/k8s-operator/operator_test.go index 50f8738ce..5af237342 100644 --- a/cmd/k8s-operator/operator_test.go +++ b/cmd/k8s-operator/operator_test.go @@ -173,6 +173,10 @@ func TestLoadBalancerClass(t *testing.T) { }, }, } + + // Perform an additional reconciliation loop here to ensure resources don't change through side effects. Mainly + // to prevent infinite reconciliation + expectReconciled(t, sr, "default", "test") expectEqual(t, fc, want) // Turn the service back into a ClusterIP service, which should make the diff --git a/cmd/k8s-operator/svc.go b/cmd/k8s-operator/svc.go index 51ad1aea3..eec1924e7 100644 --- a/cmd/k8s-operator/svc.go +++ b/cmd/k8s-operator/svc.go @@ -348,9 +348,10 @@ func (a *ServiceReconciler) maybeProvision(ctx context.Context, logger *zap.Suga dev := devices[0] logger.Debugf("setting Service LoadBalancer status to %q, %s", dev.hostname, strings.Join(dev.ips, ", ")) - svc.Status.LoadBalancer.Ingress = append(svc.Status.LoadBalancer.Ingress, corev1.LoadBalancerIngress{ - Hostname: dev.hostname, - }) + + ingress := []corev1.LoadBalancerIngress{ + {Hostname: dev.hostname}, + } clusterIPAddr, err := netip.ParseAddr(svc.Spec.ClusterIP) if err != nil { @@ -365,10 +366,11 @@ func (a *ServiceReconciler) maybeProvision(ctx context.Context, logger *zap.Suga continue } if addr.Is4() == clusterIPAddr.Is4() { // only add addresses of the same family - svc.Status.LoadBalancer.Ingress = append(svc.Status.LoadBalancer.Ingress, corev1.LoadBalancerIngress{IP: ip}) + ingress = append(ingress, corev1.LoadBalancerIngress{IP: ip}) } } + svc.Status.LoadBalancer.Ingress = ingress tsoperator.SetServiceCondition(svc, tsapi.ProxyReady, metav1.ConditionTrue, reasonProxyCreated, reasonProxyCreated, a.clock, logger) return nil }