@@ -33,7 +33,9 @@ import (
3333 "k8s.io/client-go/tools/record"
3434 ctrl "sigs.k8s.io/controller-runtime"
3535 "sigs.k8s.io/controller-runtime/pkg/client"
36+ "sigs.k8s.io/controller-runtime/pkg/handler"
3637 "sigs.k8s.io/controller-runtime/pkg/log"
38+ "sigs.k8s.io/controller-runtime/pkg/reconcile"
3739
3840 appsv1 "github.com/apecloud/kubeblocks/apis/apps/v1"
3941 parametersv1alpha1 "github.com/apecloud/kubeblocks/apis/parameters/v1alpha1"
@@ -89,12 +91,90 @@ func (r *ComponentDrivenParameterReconciler) Reconcile(ctx context.Context, req
8991}
9092
9193// SetupWithManager sets up the controller with the Manager.
94+ //
95+ // In addition to the primary `For(Component)` watch, we also watch
96+ // `ParametersDefinition` so that a Component which was reconciled into the
97+ // silent "no valid parameter template" branch (because its dependent PD was
98+ // not yet Available) gets re-enqueued once the matching PD becomes Available.
99+ // The watch layer stays intentionally notification-only:
100+ //
101+ // - Availability, ServiceVersion, create/update/delete/no-op, and stale
102+ // cleanup semantics remain centralized in the reconcile path through
103+ // `ResolveCmpdParametersDefs` and `buildComponentParameter`.
104+ // - The map function `componentsAffectedByParametersDefinition` only lists
105+ // Components from the controller-runtime cache and filters them by the
106+ // PD's `Spec.ComponentDef` pattern using the same matcher as
107+ // `ResolveCmpdParametersDefs`. Only Components whose `Spec.CompDef` would
108+ // have plausibly matched this PD are enqueued.
109+ // - controller-runtime runs EnqueueRequestsFromMapFunc on both old and new
110+ // objects for Update events, so a PD pattern change enqueues Components
111+ // matching either side of the change.
92112func (r * ComponentDrivenParameterReconciler ) SetupWithManager (mgr ctrl.Manager ) error {
93113 return ctrl .NewControllerManagedBy (mgr ).
94114 For (& appsv1.Component {}).
115+ Watches (
116+ & parametersv1alpha1.ParametersDefinition {},
117+ handler .EnqueueRequestsFromMapFunc (r .componentsAffectedByParametersDefinition ),
118+ ).
95119 Complete (r )
96120}
97121
122+ // componentsAffectedByParametersDefinition resolves the set of Components
123+ // that may be affected by a change to the given ParametersDefinition.
124+ //
125+ // It applies the same `ComponentDef` pattern matching that
126+ // `ResolveCmpdParametersDefs` uses, so the enqueue set is the dependency
127+ // inverse of the resolution graph: if the reconcile would have considered
128+ // this PD as a candidate descriptor, the Component is enqueued.
129+ //
130+ // We deliberately do NOT enforce the ServiceVersion narrowing here. The
131+ // reconcile is idempotent and the existing silent-nil branch covers
132+ // mismatched SVs, so any over-enqueue collapses cheaply rather than risking
133+ // a missed re-enqueue.
134+ //
135+ // For Update events, controller-runtime calls this map function for both the
136+ // old and new ParametersDefinition objects. That means ComponentDef pattern
137+ // changes enqueue Components matching either side of the update; reconcile
138+ // then creates, updates, deletes, or no-ops from the current dependency state.
139+ func (r * ComponentDrivenParameterReconciler ) componentsAffectedByParametersDefinition (ctx context.Context , obj client.Object ) []reconcile.Request {
140+ paramsDef , ok := obj .(* parametersv1alpha1.ParametersDefinition )
141+ if ! ok {
142+ return nil
143+ }
144+ pattern := paramsDef .Spec .ComponentDef
145+ if pattern == "" {
146+ return nil
147+ }
148+ logger := log .FromContext (ctx ).
149+ WithName ("ComponentDrivenParameterReconciler" ).
150+ WithValues ("ParametersDefinition" , paramsDef .Name )
151+
152+ compList := & appsv1.ComponentList {}
153+ if err := r .Client .List (ctx , compList ); err != nil {
154+ logger .V (1 ).Info ("componentsAffectedByParametersDefinition: list Components failed" , "error" , err )
155+ return nil
156+ }
157+ requests := make ([]reconcile.Request , 0 , len (compList .Items ))
158+ for i := range compList .Items {
159+ comp := & compList .Items [i ]
160+ if comp .Spec .CompDef == "" {
161+ continue
162+ }
163+ if ! component .PrefixOrRegexMatched (comp .Spec .CompDef , pattern ) {
164+ continue
165+ }
166+ requests = append (requests , reconcile.Request {
167+ NamespacedName : types.NamespacedName {
168+ Namespace : comp .Namespace ,
169+ Name : comp .Name ,
170+ },
171+ })
172+ }
173+ logger .V (1 ).Info ("componentsAffectedByParametersDefinition: enqueued" ,
174+ "pattern" , pattern , "matched" , len (requests ), "scanned" , len (compList .Items ))
175+ return requests
176+ }
177+
98178func (r * ComponentDrivenParameterReconciler ) reconcile (reqCtx intctrlutil.RequestCtx , component * appsv1.Component ) (ctrl.Result , error ) {
99179 var err error
100180 var existingObject * parametersv1alpha1.ComponentParameter
0 commit comments