Skip to content

Commit 23a801e

Browse files
authored
fix(parameters): re-enqueue Component when matching ParametersDefinition becomes Available (#10219)
1 parent 5ac7dd7 commit 23a801e

2 files changed

Lines changed: 402 additions & 0 deletions

File tree

controllers/parameters/componentdrivenparameter_controller.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
92112
func (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+
98178
func (r *ComponentDrivenParameterReconciler) reconcile(reqCtx intctrlutil.RequestCtx, component *appsv1.Component) (ctrl.Result, error) {
99179
var err error
100180
var existingObject *parametersv1alpha1.ComponentParameter

0 commit comments

Comments
 (0)