diff --git a/internal/controller/linodecluster_controller.go b/internal/controller/linodecluster_controller.go index 72baadf1f..3692a3c45 100644 --- a/internal/controller/linodecluster_controller.go +++ b/internal/controller/linodecluster_controller.go @@ -72,17 +72,11 @@ type LinodeClusterReconciler struct { // Reconcile is part of the main kubernetes reconciliation loop which aims to // move the current state of the cluster closer to the desired state. -func (r *LinodeClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { +func (r *LinodeClusterReconciler) Reconcile(ctx context.Context, linodeCluster *infrav1alpha2.LinodeCluster) (ctrl.Result, error) { ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultedLoopTimeout(r.ReconcileTimeout)) defer cancel() - logger := ctrl.LoggerFrom(ctx).WithName("LinodeClusterReconciler").WithValues("name", req.String()) - linodeCluster := &infrav1alpha2.LinodeCluster{} - if err := r.TracedClient().Get(ctx, req.NamespacedName, linodeCluster); err != nil { - logger.Info("Failed to fetch Linode cluster", "error", err.Error()) - - return ctrl.Result{}, client.IgnoreNotFound(err) - } + logger := ctrl.LoggerFrom(ctx).WithName("LinodeClusterReconciler").WithValues("name", linodeCluster.Name, "namespace", linodeCluster.Namespace) cluster, err := kutil.GetOwnerCluster(ctx, r.TracedClient(), linodeCluster.ObjectMeta) if err != nil { @@ -531,7 +525,7 @@ func (r *LinodeClusterReconciler) SetupWithManager(mgr ctrl.Manager, options crc Watches( &infrav1alpha2.LinodeMachine{}, handler.EnqueueRequestsFromMapFunc(linodeMachineToLinodeCluster(r.TracedClient(), mgr.GetLogger())), - ).Complete(wrappedruntimereconciler.NewRuntimeReconcilerWithTracing(r, wrappedruntimereconciler.DefaultDecorator())) + ).Complete(reconciler.AsReconcilerWithTracing(r.TracedClient(), r)) if err != nil { return fmt.Errorf("failed to build controller: %w", err) } diff --git a/internal/controller/linodeobjectstoragebucket_controller.go b/internal/controller/linodeobjectstoragebucket_controller.go index 77acb6352..262fbf686 100644 --- a/internal/controller/linodeobjectstoragebucket_controller.go +++ b/internal/controller/linodeobjectstoragebucket_controller.go @@ -43,7 +43,6 @@ import ( "github.com/linode/cluster-api-provider-linode/cloud/scope" "github.com/linode/cluster-api-provider-linode/cloud/services" wrappedruntimeclient "github.com/linode/cluster-api-provider-linode/observability/wrappers/runtimeclient" - wrappedruntimereconciler "github.com/linode/cluster-api-provider-linode/observability/wrappers/runtimereconciler" "github.com/linode/cluster-api-provider-linode/util" "github.com/linode/cluster-api-provider-linode/util/reconciler" ) @@ -75,20 +74,11 @@ type LinodeObjectStorageBucketReconciler struct { // // For more details, check Reconcile and its Result here: // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.17.0/pkg/reconcile -func (r *LinodeObjectStorageBucketReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { +func (r *LinodeObjectStorageBucketReconciler) Reconcile(ctx context.Context, objectStorageBucket *infrav1alpha2.LinodeObjectStorageBucket) (ctrl.Result, error) { ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultedLoopTimeout(r.ReconcileTimeout)) defer cancel() - logger := r.Logger.WithValues("name", req.String()) - - objectStorageBucket := &infrav1alpha2.LinodeObjectStorageBucket{} - if err := r.TracedClient().Get(ctx, req.NamespacedName, objectStorageBucket); err != nil { - if err = client.IgnoreNotFound(err); err != nil { - logger.Error(err, "Failed to fetch LinodeObjectStorageBucket", "name", req.String()) - } - - return ctrl.Result{}, err - } + logger := r.Logger.WithValues("name", objectStorageBucket.Name, "namespace", objectStorageBucket.Namespace) if _, ok := objectStorageBucket.Labels[clusterv1.ClusterNameLabel]; ok { cluster, err := kutil.GetClusterFromMetadata(ctx, r.TracedClient(), objectStorageBucket.ObjectMeta) @@ -267,7 +257,7 @@ func (r *LinodeObjectStorageBucketReconciler) SetupWithManager(mgr ctrl.Manager, &clusterv1.Cluster{}, handler.EnqueueRequestsFromMapFunc(linodeObjectStorageBucketMapper), builder.WithPredicates(predicates.ClusterPausedTransitionsOrInfrastructureProvisioned(mgr.GetScheme(), mgr.GetLogger())), - ).Complete(wrappedruntimereconciler.NewRuntimeReconcilerWithTracing(r, wrappedruntimereconciler.DefaultDecorator())) + ).Complete(reconciler.AsReconcilerWithTracing(r.TracedClient(), r)) if err != nil { return fmt.Errorf("failed to build controller: %w", err) } diff --git a/internal/controller/linodeobjectstoragekey_controller.go b/internal/controller/linodeobjectstoragekey_controller.go index 30ff68773..c7f956728 100644 --- a/internal/controller/linodeobjectstoragekey_controller.go +++ b/internal/controller/linodeobjectstoragekey_controller.go @@ -44,7 +44,6 @@ import ( "github.com/linode/cluster-api-provider-linode/cloud/scope" "github.com/linode/cluster-api-provider-linode/cloud/services" wrappedruntimeclient "github.com/linode/cluster-api-provider-linode/observability/wrappers/runtimeclient" - wrappedruntimereconciler "github.com/linode/cluster-api-provider-linode/observability/wrappers/runtimereconciler" "github.com/linode/cluster-api-provider-linode/util" "github.com/linode/cluster-api-provider-linode/util/reconciler" ) @@ -75,23 +74,14 @@ type LinodeObjectStorageKeyReconciler struct { // // For more details, check Reconcile and its Result here: // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.18.2/pkg/reconcile -func (r *LinodeObjectStorageKeyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { +func (r *LinodeObjectStorageKeyReconciler) Reconcile(ctx context.Context, objectStorageKey *infrav1alpha2.LinodeObjectStorageKey) (ctrl.Result, error) { ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultedLoopTimeout(r.ReconcileTimeout)) defer cancel() - logger := r.Logger.WithValues("name", req.String()) + logger := r.Logger.WithValues("name", objectStorageKey.Name, "namespace", objectStorageKey.Namespace) tracedClient := r.TracedClient() - objectStorageKey := &infrav1alpha2.LinodeObjectStorageKey{} - if err := tracedClient.Get(ctx, req.NamespacedName, objectStorageKey); err != nil { - if err = client.IgnoreNotFound(err); err != nil { - logger.Error(err, "Failed to fetch LinodeObjectStorageKey", "name", req.String()) - } - - return ctrl.Result{}, err - } - if _, ok := objectStorageKey.Labels[clusterv1.ClusterNameLabel]; ok { cluster, err := kutil.GetClusterFromMetadata(ctx, r.TracedClient(), objectStorageKey.ObjectMeta) if err != nil { @@ -348,7 +338,7 @@ func (r *LinodeObjectStorageKeyReconciler) SetupWithManager(mgr ctrl.Manager, op &clusterv1.Cluster{}, handler.EnqueueRequestsFromMapFunc(linodeObjectStorageKeyMapper), builder.WithPredicates(predicates.ClusterPausedTransitionsOrInfrastructureProvisioned(mgr.GetScheme(), mgr.GetLogger())), - ).Complete(wrappedruntimereconciler.NewRuntimeReconcilerWithTracing(r, wrappedruntimereconciler.DefaultDecorator())) + ).Complete(reconciler.AsReconcilerWithTracing(r.TracedClient(), r)) if err != nil { return fmt.Errorf("failed to build controller: %w", err) } diff --git a/internal/controller/linodeplacementgroup_controller.go b/internal/controller/linodeplacementgroup_controller.go index 6cb023d83..5b1861689 100644 --- a/internal/controller/linodeplacementgroup_controller.go +++ b/internal/controller/linodeplacementgroup_controller.go @@ -44,7 +44,6 @@ import ( infrav1alpha2 "github.com/linode/cluster-api-provider-linode/api/v1alpha2" "github.com/linode/cluster-api-provider-linode/cloud/scope" wrappedruntimeclient "github.com/linode/cluster-api-provider-linode/observability/wrappers/runtimeclient" - wrappedruntimereconciler "github.com/linode/cluster-api-provider-linode/observability/wrappers/runtimereconciler" "github.com/linode/cluster-api-provider-linode/util" "github.com/linode/cluster-api-provider-linode/util/reconciler" ) @@ -68,20 +67,12 @@ type LinodePlacementGroupReconciler struct { // move the current state of the Placement Group closer to the desired state. // -func (r *LinodePlacementGroupReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { +func (r *LinodePlacementGroupReconciler) Reconcile(ctx context.Context, linodeplacementgroup *infrav1alpha2.LinodePlacementGroup) (ctrl.Result, error) { ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultedLoopTimeout(r.ReconcileTimeout)) defer cancel() - log := ctrl.LoggerFrom(ctx).WithName("LinodePlacementGroupReconciler").WithValues("name", req.String()) + log := ctrl.LoggerFrom(ctx).WithName("LinodePlacementGroupReconciler").WithValues("name", linodeplacementgroup.Name, "namespace", linodeplacementgroup.Namespace) - linodeplacementgroup := &infrav1alpha2.LinodePlacementGroup{} - if err := r.TracedClient().Get(ctx, req.NamespacedName, linodeplacementgroup); err != nil { - if err = client.IgnoreNotFound(err); err != nil { - log.Error(err, "Failed to fetch LinodePlacementGroup") - } - - return ctrl.Result{}, err - } var cluster *clusterv1.Cluster var err error if _, ok := linodeplacementgroup.Labels[clusterv1.ClusterNameLabel]; ok { @@ -404,7 +395,7 @@ func (r *LinodePlacementGroupReconciler) SetupWithManager(mgr ctrl.Manager, opti &clusterv1.Cluster{}, handler.EnqueueRequestsFromMapFunc(linodePlacementGroupMapper), builder.WithPredicates(predicates.ClusterPausedTransitionsOrInfrastructureProvisioned(mgr.GetScheme(), mgr.GetLogger())), - ).Complete(wrappedruntimereconciler.NewRuntimeReconcilerWithTracing(r, wrappedruntimereconciler.DefaultDecorator())) + ).Complete(reconciler.AsReconcilerWithTracing(r.TracedClient(), r)) if err != nil { return fmt.Errorf("failed to build controller: %w", err) } diff --git a/internal/controller/linodevpc_controller.go b/internal/controller/linodevpc_controller.go index 28883b276..a9e0c39b3 100644 --- a/internal/controller/linodevpc_controller.go +++ b/internal/controller/linodevpc_controller.go @@ -76,18 +76,11 @@ type LinodeVPCReconciler struct { // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.16.0/pkg/reconcile // -func (r *LinodeVPCReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { +func (r *LinodeVPCReconciler) Reconcile(ctx context.Context, linodeVPC *infrav1alpha2.LinodeVPC) (ctrl.Result, error) { ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultedLoopTimeout(r.ReconcileTimeout)) defer cancel() - log := ctrl.LoggerFrom(ctx).WithName("LinodeVPCReconciler").WithValues("name", req.String()) - linodeVPC := &infrav1alpha2.LinodeVPC{} - if err := r.TracedClient().Get(ctx, req.NamespacedName, linodeVPC); err != nil { - if err = client.IgnoreNotFound(err); err != nil { - log.Error(err, "Failed to fetch LinodeVPC") - } - return ctrl.Result{}, err - } + log := ctrl.LoggerFrom(ctx).WithName("LinodeVPCReconciler").WithValues("name", linodeVPC.Name, "namespace", linodeVPC.Namespace) var cluster *clusterv1.Cluster var err error @@ -519,7 +512,7 @@ func (r *LinodeVPCReconciler) SetupWithManager(mgr ctrl.Manager, options crcontr &clusterv1.Cluster{}, handler.EnqueueRequestsFromMapFunc(linodeVPCMapper), builder.WithPredicates(predicates.ClusterPausedTransitionsOrInfrastructureProvisioned(mgr.GetScheme(), mgr.GetLogger())), - ).Complete(wrappedruntimereconciler.NewRuntimeReconcilerWithTracing(r, wrappedruntimereconciler.DefaultDecorator())) + ).Complete(reconciler.AsReconcilerWithTracing(r.TracedClient(), r)) if err != nil { return fmt.Errorf("failed to build controller: %w", err) } diff --git a/util/reconciler/typedreconciler.go b/util/reconciler/typedreconciler.go new file mode 100644 index 000000000..5c29f9749 --- /dev/null +++ b/util/reconciler/typedreconciler.go @@ -0,0 +1,38 @@ +package reconciler + +import ( + "context" + + o11yreconciler "github.com/linode/cluster-api-provider-linode/observability/wrappers/runtimereconciler" + clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/reconcile" +) + +func AsReconcilerWithTracing[object client.Object](k8sClient client.Client, rec reconcile.ObjectReconciler[object]) reconcile.Reconciler { + capiReconciler := &capiReconcilerAdapter[object]{ + objReconciler: rec, + k8sClient: k8sClient, + } + + return o11yreconciler.NewRuntimeReconcilerWithTracing( + reconcile.AsReconciler( + k8sClient, capiReconciler), + o11yreconciler.DefaultDecorator()) +} + +type capiReconcilerAdapter[object client.Object] struct { + objReconciler reconcile.ObjectReconciler[object] + k8sClient client.Client +} + +func (a *capiReconcilerAdapter[object]) Reconcile(ctx context.Context, o object) (reconcile.Result, error) { + // Skip normal reconciliation when clusterctl marks the object for deletion during a move. + // Reconciling here could recreate or mutate infrastructure while ownership is being handed off. + if annotations := o.GetAnnotations(); annotations != nil { + if _, exists := annotations[clusterctlv1.DeleteForMoveAnnotation]; exists { + return reconcile.Result{}, nil + } + } + return a.objReconciler.Reconcile(ctx, o) +}