From c9cb148a3f323be9b8128b2f4bc7a493f61a0fdb Mon Sep 17 00:00:00 2001 From: Chris Burns <29541485+ChrisJBurns@users.noreply.github.com> Date: Thu, 2 Apr 2026 19:06:47 +0100 Subject: [PATCH] Handle stale ReferencingWorkloads in telemetry watch The MCPTelemetryConfig watch handler only enqueued the currently-referenced config when an MCPServer changed. If a server removed its telemetryConfigRef, the previously-referenced config was never reconciled to clean up its stale ReferencingWorkloads entry. Update the watch handler to also enqueue any MCPTelemetryConfig that still lists the changed server in ReferencingWorkloads, matching the pattern already used by MCPOIDCConfig. Closes #4491 Co-Authored-By: Claude Opus 4.6 (1M context) --- .../mcptelemetryconfig_controller.go | 52 ++++++++++++++----- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/cmd/thv-operator/controllers/mcptelemetryconfig_controller.go b/cmd/thv-operator/controllers/mcptelemetryconfig_controller.go index 27ca5da918..876d0490e2 100644 --- a/cmd/thv-operator/controllers/mcptelemetryconfig_controller.go +++ b/cmd/thv-operator/controllers/mcptelemetryconfig_controller.go @@ -140,26 +140,54 @@ func (r *MCPTelemetryConfigReconciler) Reconcile(ctx context.Context, req ctrl.R } // SetupWithManager sets up the controller with the Manager. +// Watches MCPServer changes to maintain accurate ReferencingWorkloads status. func (r *MCPTelemetryConfigReconciler) SetupWithManager(mgr ctrl.Manager) error { - // Watch MCPServer changes to update ReferencingWorkloads status + // Watch MCPServer changes to update ReferencingWorkloads on referenced MCPTelemetryConfigs. + // This handler enqueues both the currently-referenced MCPTelemetryConfig AND any + // MCPTelemetryConfig that still lists this server in ReferencingWorkloads (covers the + // case where a server removes its telemetryConfigRef — the previously-referenced + // config needs to reconcile and clean up the stale entry). mcpServerHandler := handler.EnqueueRequestsFromMapFunc( - func(_ context.Context, obj client.Object) []reconcile.Request { - mcpServer, ok := obj.(*mcpv1alpha1.MCPServer) + func(ctx context.Context, obj client.Object) []reconcile.Request { + server, ok := obj.(*mcpv1alpha1.MCPServer) if !ok { return nil } - // If this MCPServer references a MCPTelemetryConfig, enqueue it for reconciliation - if mcpServer.Spec.TelemetryConfigRef == nil { - return nil + seen := make(map[types.NamespacedName]struct{}) + var requests []reconcile.Request + + // Enqueue the currently-referenced MCPTelemetryConfig (if any) + if server.Spec.TelemetryConfigRef != nil { + nn := types.NamespacedName{ + Name: server.Spec.TelemetryConfigRef.Name, + Namespace: server.Namespace, + } + seen[nn] = struct{}{} + requests = append(requests, reconcile.Request{NamespacedName: nn}) + } + + // Also enqueue any MCPTelemetryConfig that still lists this server in + // ReferencingWorkloads — handles ref-removal and server-deletion cases. + telemetryConfigList := &mcpv1alpha1.MCPTelemetryConfigList{} + if err := r.List(ctx, telemetryConfigList, client.InNamespace(server.Namespace)); err != nil { + log.FromContext(ctx).Error(err, "Failed to list MCPTelemetryConfigs for MCPServer watch") + return requests + } + for _, cfg := range telemetryConfigList.Items { + nn := types.NamespacedName{Name: cfg.Name, Namespace: cfg.Namespace} + if _, already := seen[nn]; already { + continue + } + for _, ref := range cfg.Status.ReferencingWorkloads { + if ref.Kind == "MCPServer" && ref.Name == server.Name { + requests = append(requests, reconcile.Request{NamespacedName: nn}) + break + } + } } - return []reconcile.Request{{ - NamespacedName: types.NamespacedName{ - Name: mcpServer.Spec.TelemetryConfigRef.Name, - Namespace: mcpServer.Namespace, - }, - }} + return requests }, )