@@ -40,17 +40,22 @@ import (
4040 k8serrors "k8s.io/apimachinery/pkg/api/errors"
4141 "k8s.io/apimachinery/pkg/api/meta"
4242 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
43+ "k8s.io/apimachinery/pkg/types"
4344 "k8s.io/client-go/tools/record"
4445 ctrl "sigs.k8s.io/controller-runtime"
4546 "sigs.k8s.io/controller-runtime/pkg/builder"
4647 "sigs.k8s.io/controller-runtime/pkg/client"
4748 "sigs.k8s.io/controller-runtime/pkg/controller"
4849 "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
4950 "sigs.k8s.io/controller-runtime/pkg/event"
51+ "sigs.k8s.io/controller-runtime/pkg/handler"
5052 "sigs.k8s.io/controller-runtime/pkg/predicate"
53+ "sigs.k8s.io/controller-runtime/pkg/reconcile"
5154)
5255
5356const (
57+ hostImageAuthSecretIndexField = ".spec.image.authSecretName"
58+
5459 hostErrorRetryDelay = time .Second * 10
5560 unmanagedRetryDelay = time .Minute * 10
5661 preprovImageRetryDelay = time .Minute * 5
@@ -2428,14 +2433,37 @@ func (r *BareMetalHostReconciler) updateEventHandler(e event.UpdateEvent) bool {
24282433// SetupWithManager registers the reconciler to be run by the manager.
24292434func (r * BareMetalHostReconciler ) SetupWithManager (mgr ctrl.Manager , preprovImgEnable bool , maxConcurrentReconcile int ) error {
24302435 r .Recorder = mgr .GetEventRecorderFor ("baremetalhost-controller" )
2436+
2437+ // Add index for image auth secret name to enable efficient secret-to-BMH lookups
2438+ if err := mgr .GetFieldIndexer ().IndexField (
2439+ context .Background (),
2440+ & metal3api.BareMetalHost {},
2441+ hostImageAuthSecretIndexField ,
2442+ func (obj client.Object ) []string {
2443+ host := obj .(* metal3api.BareMetalHost )
2444+ if host .Spec .Image != nil && host .Spec .Image .AuthSecretName != nil && * host .Spec .Image .AuthSecretName != "" {
2445+ return []string {* host .Spec .Image .AuthSecretName }
2446+ }
2447+ return nil
2448+ },
2449+ ); err != nil {
2450+ return fmt .Errorf ("failed to create image auth secret index: %w" , err )
2451+ }
2452+
24312453 controller := ctrl .NewControllerManagedBy (mgr ).
24322454 For (& metal3api.BareMetalHost {}).
24332455 WithEventFilter (
24342456 predicate.Funcs {
24352457 UpdateFunc : r .updateEventHandler ,
24362458 }).
24372459 WithOptions (controller.Options {MaxConcurrentReconciles : maxConcurrentReconcile }).
2438- Owns (& corev1.Secret {}, builder .MatchEveryOwner )
2460+ Owns (& corev1.Secret {}, builder .MatchEveryOwner ).
2461+ // Watch Secrets to trigger reconciliation when auth secrets are updated (key rotation)
2462+ Watches (
2463+ & corev1.Secret {},
2464+ handler .EnqueueRequestsFromMapFunc (r .findBMHsForAuthSecret ),
2465+ builder .WithPredicates (predicate.ResourceVersionChangedPredicate {}),
2466+ )
24392467
24402468 if preprovImgEnable {
24412469 // We use SetControllerReference() to set the owner reference, so no
@@ -2446,6 +2474,38 @@ func (r *BareMetalHostReconciler) SetupWithManager(mgr ctrl.Manager, preprovImgE
24462474 return controller .Complete (r )
24472475}
24482476
2477+ // findBMHsForAuthSecret returns a list of reconcile requests for BareMetalHosts
2478+ // that reference the given Secret as their image auth secret.
2479+ // This enables auto-reconciliation when auth secrets are updated (key rotation).
2480+ func (r * BareMetalHostReconciler ) findBMHsForAuthSecret (ctx context.Context , secret client.Object ) []reconcile.Request {
2481+ // Only process secrets in the same namespace as BMHs
2482+ hosts := & metal3api.BareMetalHostList {}
2483+ if err := r .Client .List (
2484+ ctx ,
2485+ hosts ,
2486+ client .InNamespace (secret .GetNamespace ()),
2487+ client.MatchingFields {hostImageAuthSecretIndexField : secret .GetName ()},
2488+ ); err != nil {
2489+ r .Log .Error (err , "failed to list BareMetalHosts for secret" , "secret" , secret .GetName ())
2490+ return nil
2491+ }
2492+
2493+ requests := make ([]reconcile.Request , len (hosts .Items ))
2494+ for i , host := range hosts .Items {
2495+ requests [i ] = reconcile.Request {
2496+ NamespacedName : types.NamespacedName {
2497+ Name : host .Name ,
2498+ Namespace : host .Namespace ,
2499+ },
2500+ }
2501+ r .Log .Info ("queuing BMH reconcile due to auth secret change" ,
2502+ "baremetalhost" , host .Name ,
2503+ "secret" , secret .GetName ())
2504+ }
2505+
2506+ return requests
2507+ }
2508+
24492509func (r * BareMetalHostReconciler ) reconcileHostData (ctx context.Context , host * metal3api.BareMetalHost , request ctrl.Request ) (result ctrl.Result , err error ) {
24502510 reqLogger := r .Log .WithValues ("baremetalhost" , request .NamespacedName )
24512511
0 commit comments