diff --git a/internal/provider/kubernetes/gateway.go b/internal/provider/kubernetes/gateway.go index c6e3a01b9d..7a2a984260 100644 --- a/internal/provider/kubernetes/gateway.go +++ b/internal/provider/kubernetes/gateway.go @@ -201,11 +201,32 @@ func (r *gatewayReconciler) Reconcile(ctx context.Context, request reconcile.Req status.UpdateGatewayStatusScheduledCondition(&gw, true) // update address field and ready condition status.UpdateGatewayStatusReadyCondition(&gw, svc, deployment) - // publish status - key := utils.NamespacedName(&gw) - r.resources.GatewayStatuses.Store(key, &gw) - r.resources.Gateways.Store(key, &gw) + key := utils.NamespacedName(&gw) + // publish status + // do it inline since this code flow updates the + // Status.Addresses field whereas the message bus / subscriber + // does not. + r.statusUpdater.Send(status.Update{ + NamespacedName: key, + Resource: new(gwapiv1b1.Gateway), + Mutator: status.MutatorFunc(func(obj client.Object) client.Object { + g, ok := obj.(*gwapiv1b1.Gateway) + if !ok { + panic(fmt.Sprintf("unsupported object type %T", obj)) + } + gCopy := g.DeepCopy() + gCopy.Status.Conditions = status.MergeConditions(gCopy.Status.Conditions, gw.Status.Conditions...) + gCopy.Status.Addresses = gw.Status.Addresses + return gCopy + + }), + }) + + // only store the resource if it does not exist or it has a newer spec. + if v, ok := r.resources.Gateways.Load(key); !ok || (gw.Generation > v.Generation) { + r.resources.Gateways.Store(key, &gw) + } if key == request.NamespacedName { found = true } @@ -343,8 +364,6 @@ func (r *gatewayReconciler) subscribeAndUpdateStatus(ctx context.Context) { panic(fmt.Sprintf("unsupported object type %T", obj)) } gCopy := g.DeepCopy() - gCopy.Status.Conditions = status.MergeConditions(gCopy.Status.Conditions, val.Status.Conditions...) - gCopy.Status.Addresses = val.Status.Addresses gCopy.Status.Listeners = val.Status.Listeners return gCopy }), diff --git a/internal/provider/kubernetes/httproute.go b/internal/provider/kubernetes/httproute.go index 88eb98a591..6bae34c938 100644 --- a/internal/provider/kubernetes/httproute.go +++ b/internal/provider/kubernetes/httproute.go @@ -212,10 +212,11 @@ func (r *httpRouteReconciler) Reconcile(ctx context.Context, request reconcile.R return reconcile.Result{}, nil } - // Store the httproute in the resource map. - r.resources.HTTPRoutes.Store(routeKey, &route) - log.Info("added httproute to resource map") - + // only store the resource if it does not exist or it has a newer spec. + if v, ok := r.resources.HTTPRoutes.Load(routeKey); !ok || (route.Generation > v.Generation) { + r.resources.HTTPRoutes.Store(routeKey, &route) + log.Info("added httproute to resource map") + } // Get the route's namespace from the cache. nsKey := types.NamespacedName{Name: route.Namespace} ns := new(corev1.Namespace) diff --git a/internal/provider/kubernetes/kubernetes_test.go b/internal/provider/kubernetes/kubernetes_test.go index fec19e3d45..409f7fa183 100644 --- a/internal/provider/kubernetes/kubernetes_test.go +++ b/internal/provider/kubernetes/kubernetes_test.go @@ -235,7 +235,12 @@ func testGatewayScheduledStatus(ctx context.Context, t *testing.T, provider *Pro return cli.Get(ctx, key, gw) == nil }, defaultWait, defaultTick) gws, _ := resources.Gateways.Load(key) - assert.Equal(t, gw, gws) + // Only check if the spec is equal + // The watchable map will not store a resource + // with an updated status if the spec has not changed + // to eliminate this endless loop: + // reconcile->store->translate->update-status->reconcile + assert.Equal(t, gw.Spec, gws.Spec) } func testHTTPRoute(ctx context.Context, t *testing.T, provider *Provider, resources *message.ProviderResources) {