@@ -13,6 +13,7 @@ import (
1313 "context"
1414 "reflect"
1515 "strconv"
16+ "time"
1617
1718 "go.opentelemetry.io/otel/attribute"
1819 appsv1 "k8s.io/api/apps/v1"
@@ -22,15 +23,18 @@ import (
2223 ctrl "sigs.k8s.io/controller-runtime"
2324 "sigs.k8s.io/controller-runtime/pkg/client"
2425 "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
25- "sigs.k8s.io/controller-runtime/pkg/handler"
2626 "sigs.k8s.io/controller-runtime/pkg/reconcile"
27+ mcbuilder "sigs.k8s.io/multicluster-runtime/pkg/builder"
28+ mchandler "sigs.k8s.io/multicluster-runtime/pkg/handler"
29+ mcreconcile "sigs.k8s.io/multicluster-runtime/pkg/reconcile"
2730
2831 "github.com/redpanda-data/redpanda-operator/charts/redpanda/v25"
2932 redpandav1alpha2 "github.com/redpanda-data/redpanda-operator/operator/api/redpanda/v1alpha2"
3033 "github.com/redpanda-data/redpanda-operator/operator/internal/controller"
3134 "github.com/redpanda-data/redpanda-operator/operator/internal/lifecycle"
3235 "github.com/redpanda-data/redpanda-operator/operator/internal/statuses"
3336 "github.com/redpanda-data/redpanda-operator/operator/pkg/feature"
37+ "github.com/redpanda-data/redpanda-operator/pkg/multicluster"
3438 "github.com/redpanda-data/redpanda-operator/pkg/otelutil/log"
3539 "github.com/redpanda-data/redpanda-operator/pkg/otelutil/otelkube"
3640 "github.com/redpanda-data/redpanda-operator/pkg/otelutil/trace"
@@ -45,20 +49,14 @@ import (
4549// NodePoolReconciler reconciles a NodePool object. This reconciler in particular should only update status
4650// fields and finalizers on the NodePool objects, rendering of NodePools takes place within the RedpandaReconciler.
4751type NodePoolReconciler struct {
48- Client client. Client
52+ Manager multicluster. Manager
4953}
5054
5155// SetupWithManager sets up the controller with the Manager.
52- func (r * NodePoolReconciler ) SetupWithManager (ctx context.Context , mgr ctrl.Manager ) error {
53- enqueueNodePoolFromCluster , err := controller .RegisterClusterSourceIndex (ctx , mgr , "pool" , & redpandav1alpha2.NodePool {}, & redpandav1alpha2.NodePoolList {})
54- if err != nil {
55- return err
56- }
57-
58- return ctrl .NewControllerManagedBy (mgr ).
59- For (& redpandav1alpha2.NodePool {}).
60- Watches (& redpandav1alpha2.Redpanda {}, enqueueNodePoolFromCluster ).
61- Watches (& appsv1.StatefulSet {}, handler .EnqueueRequestsFromMapFunc (func (ctx context.Context , o client.Object ) []reconcile.Request {
56+ func (r * NodePoolReconciler ) SetupWithManager (ctx context.Context , mgr multicluster.Manager ) error {
57+ builder := mcbuilder .ControllerManagedBy (mgr ).
58+ For (& redpandav1alpha2.NodePool {}, mcbuilder .WithEngageWithLocalCluster (true ), mcbuilder .WithEngageWithProviderClusters (true )).
59+ Watches (& appsv1.StatefulSet {}, mchandler .EnqueueRequestsFromMapFunc (func (ctx context.Context , o client.Object ) []reconcile.Request {
6260 labels := o .GetLabels ()
6361 if labels == nil {
6462 return nil
@@ -77,14 +75,40 @@ func (r *NodePoolReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Mana
7775 Name : name ,
7876 },
7977 }}
80- })).
81- Complete (r )
78+ }))
79+
80+ for _ , clusterName := range mgr .GetClusterNames () {
81+ enqueueNodePoolFromCluster , err := controller .RegisterClusterSourceIndex (ctx , mgr , "pool" , clusterName , & redpandav1alpha2.NodePool {}, & redpandav1alpha2.NodePoolList {})
82+ if err != nil {
83+ return err
84+ }
85+
86+ builder .Watches (& redpandav1alpha2.Redpanda {}, enqueueNodePoolFromCluster , controller .WatchOptions (clusterName )... )
87+ }
88+
89+ return builder .Complete (r )
8290}
8391
8492// Reconcile reconciles NodePool objects
85- func (r * NodePoolReconciler ) Reconcile (ctx context.Context , req ctrl.Request ) (result ctrl.Result , err error ) {
93+ func (r * NodePoolReconciler ) Reconcile (ctx context.Context , req mcreconcile.Request ) (result ctrl.Result , err error ) {
94+ l := log .FromContext (ctx ).WithName ("NodePoolReconciler.Reconcile" )
95+ l .V (1 ).Info ("Starting reconcile loop" )
96+ start := time .Now ()
97+ defer func () {
98+ l .V (1 ).Info ("Finished reconciling" , "elapsed" , time .Since (start ))
99+ }()
100+
101+ k8sCluster , err := r .Manager .GetCluster (ctx , req .ClusterName )
102+ if err != nil {
103+ l .Error (err , "unable to fetch cluster, skipping reconciliation" )
104+ return ctrl.Result {}, nil
105+ }
106+
107+ k8sClient := k8sCluster .GetClient ()
108+
86109 pool := & redpandav1alpha2.NodePool {}
87- if err := r .Client .Get (ctx , req .NamespacedName , pool ); err != nil {
110+
111+ if err := k8sClient .Get (ctx , req .NamespacedName , pool ); err != nil {
88112 return ctrl.Result {}, client .IgnoreNotFound (err )
89113 }
90114
@@ -98,7 +122,7 @@ func (r *NodePoolReconciler) Reconcile(ctx context.Context, req ctrl.Request) (r
98122
99123 if ! feature .V2Managed .Get (ctx , pool ) {
100124 if controllerutil .RemoveFinalizer (pool , FinalizerKey ) {
101- if err := r . Client .Update (ctx , pool ); err != nil {
125+ if err := k8sClient .Update (ctx , pool ); err != nil {
102126 logger .Error (err , "updating cluster finalizer" )
103127 // no need to update the status at this point since the
104128 // previous update failed
@@ -111,7 +135,7 @@ func (r *NodePoolReconciler) Reconcile(ctx context.Context, req ctrl.Request) (r
111135 // Examine if the object is under deletion
112136 if ! pool .ObjectMeta .DeletionTimestamp .IsZero () {
113137 if controllerutil .RemoveFinalizer (pool , FinalizerKey ) {
114- if err := r . Client .Update (ctx , pool ); err != nil {
138+ if err := k8sClient .Update (ctx , pool ); err != nil {
115139 logger .Error (err , "updating cluster finalizer" )
116140 // no need to update the status at this point since the
117141 // previous update failed
@@ -125,7 +149,7 @@ func (r *NodePoolReconciler) Reconcile(ctx context.Context, req ctrl.Request) (r
125149 // If any changes are made, persist the changes and immediately requeue to
126150 // prevent any cache / resource version synchronization issues.
127151 if controllerutil .AddFinalizer (pool , FinalizerKey ) || feature .SetDefaults (ctx , feature .V2Flags , pool ) {
128- if err := r . Client .Update (ctx , pool ); err != nil {
152+ if err := k8sClient .Update (ctx , pool ); err != nil {
129153 logger .Error (err , "updating cluster finalizer or Annotation" )
130154 return ignoreConflict (err )
131155 }
@@ -134,7 +158,7 @@ func (r *NodePoolReconciler) Reconcile(ctx context.Context, req ctrl.Request) (r
134158
135159 var status statuses.NodePoolStatus
136160 var statefulSets appsv1.StatefulSetList
137- if err := r . Client .List (ctx , & statefulSets , client.MatchingLabels {
161+ if err := k8sClient .List (ctx , & statefulSets , client.MatchingLabels {
138162 lifecycle .DefaultNamespaceLabel : pool .Namespace ,
139163 redpanda .NodePoolLabelName : pool .Name ,
140164 }); err != nil {
@@ -191,7 +215,7 @@ func (r *NodePoolReconciler) Reconcile(ctx context.Context, req ctrl.Request) (r
191215 }
192216
193217 cluster := & redpandav1alpha2.Redpanda {}
194- if err := r . Client .Get (ctx , types.NamespacedName {Name : pool .Spec .ClusterRef .Name , Namespace : req .Namespace }, cluster ); err != nil {
218+ if err := k8sClient .Get (ctx , types.NamespacedName {Name : pool .Spec .ClusterRef .Name , Namespace : req .Namespace }, cluster ); err != nil {
195219 if apierrors .IsNotFound (err ) {
196220 status .SetBound (statuses .NodePoolBoundReasonNotBound )
197221 } else {
@@ -204,7 +228,7 @@ func (r *NodePoolReconciler) Reconcile(ctx context.Context, req ctrl.Request) (r
204228 if status .UpdateConditions (pool ) ||
205229 ! reflect .DeepEqual (originalPoolStatus , pool .Status .EmbeddedNodePoolStatus ) ||
206230 (pool .Status .DeployedGeneration != originalPoolGeneration ) {
207- return ignoreConflict (r . Client .Status ().Update (ctx , pool ))
231+ return ignoreConflict (k8sClient .Status ().Update (ctx , pool ))
208232 }
209233
210234 return ctrl.Result {}, nil
0 commit comments