From d7961ed16f68f6e585f0c40df17edb5349530a6b Mon Sep 17 00:00:00 2001 From: Glenn Pratt Date: Wed, 15 Apr 2026 22:41:37 -0700 Subject: [PATCH 1/5] prevent deletion of objects moved by clusterctl --- .../controller/linodecluster_controller.go | 12 ++---- .../linodeobjectstoragebucket_controller.go | 16 ++------ .../linodeobjectstoragekey_controller.go | 16 ++------ .../linodeplacementgroup_controller.go | 15 ++------ internal/controller/linodevpc_controller.go | 13 ++----- util/reconciler/typedreconciler.go | 38 +++++++++++++++++++ 6 files changed, 53 insertions(+), 57 deletions(-) create mode 100644 util/reconciler/typedreconciler.go 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) +} From 39704638e62d40633d68c712bbd3a6473a85c0c0 Mon Sep 17 00:00:00 2001 From: Glenn Pratt Date: Fri, 29 May 2026 11:19:43 -0700 Subject: [PATCH 2/5] fixes --- internal/controller/linodecluster_controller_test.go | 5 +---- internal/controller/linodefirewall_controller_helpers.go | 2 +- .../linodeobjectstoragebucket_controller_test.go | 8 ++++---- .../controller/linodeobjectstoragekey_controller_test.go | 8 ++++---- internal/controller/linodevpc_controller.go | 1 - util/reconciler/typedreconciler.go | 9 +++++---- 6 files changed, 15 insertions(+), 18 deletions(-) diff --git a/internal/controller/linodecluster_controller_test.go b/internal/controller/linodecluster_controller_test.go index b5998bb70..4f110b0c6 100644 --- a/internal/controller/linodecluster_controller_test.go +++ b/internal/controller/linodecluster_controller_test.go @@ -29,7 +29,6 @@ import ( clusterv1 "sigs.k8s.io/cluster-api/api/core/v1beta2" "sigs.k8s.io/cluster-api/util/patch" "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/reconcile" infrav1alpha2 "github.com/linode/cluster-api-provider-linode/api/v1alpha2" "github.com/linode/cluster-api-provider-linode/cloud/scope" @@ -291,9 +290,7 @@ var _ = Describe("cluster-lifecycle", Ordered, Label("cluster", "cluster-lifecyc }), Result("no capl cluster error", func(ctx context.Context, mck Mock) { reconciler.Client = k8sClient - _, err := reconciler.Reconcile(ctx, reconcile.Request{ - NamespacedName: client.ObjectKeyFromObject(cScope.LinodeCluster), - }) + _, err := reconciler.Reconcile(ctx, cScope.LinodeCluster) Expect(err).NotTo(HaveOccurred()) Expect(linodeCluster.Status.Ready).To(BeFalseBecause("failed to get Cluster/no-capl-cluster: clusters.cluster.x-k8s.io \"no-capl-cluster\" not found")) }), diff --git a/internal/controller/linodefirewall_controller_helpers.go b/internal/controller/linodefirewall_controller_helpers.go index 1c57bf89f..b232b101b 100644 --- a/internal/controller/linodefirewall_controller_helpers.go +++ b/internal/controller/linodefirewall_controller_helpers.go @@ -57,7 +57,7 @@ func findObjectsForObject(logger logr.Logger, tracedClient client.Client) handle logger.Info("LinodeFirewall(s) not found for %s") return nil - case err != nil: + default: logger.Error(err, "Failed to get LinodeFirewalls") return nil diff --git a/internal/controller/linodeobjectstoragebucket_controller_test.go b/internal/controller/linodeobjectstoragebucket_controller_test.go index 9921b4b6e..30448d169 100644 --- a/internal/controller/linodeobjectstoragebucket_controller_test.go +++ b/internal/controller/linodeobjectstoragebucket_controller_test.go @@ -36,6 +36,7 @@ import ( "github.com/linode/cluster-api-provider-linode/cloud/scope" "github.com/linode/cluster-api-provider-linode/mock" "github.com/linode/cluster-api-provider-linode/util" + utilreconciler "github.com/linode/cluster-api-provider-linode/util/reconciler" . "github.com/linode/cluster-api-provider-linode/mock/mocktest" . "github.com/onsi/ginkgo/v2" @@ -325,7 +326,7 @@ var _ = Describe("errors", Label("bucket", "errors"), func() { }), Result("no error", func(ctx context.Context, mck Mock) { reconciler.Client = mck.K8sClient - _, err := reconciler.Reconcile(ctx, reconcile.Request{ + _, err := utilreconciler.AsReconcilerWithTracing(mck.K8sClient, &reconciler).Reconcile(ctx, reconcile.Request{ NamespacedName: client.ObjectKeyFromObject(bScope.Bucket), }) Expect(err).NotTo(HaveOccurred()) @@ -338,18 +339,17 @@ var _ = Describe("errors", Label("bucket", "errors"), func() { Result("error", func(ctx context.Context, mck Mock) { reconciler.Client = mck.K8sClient reconciler.Logger = bScope.Logger - _, err := reconciler.Reconcile(ctx, reconcile.Request{ + _, err := utilreconciler.AsReconcilerWithTracing(mck.K8sClient, &reconciler).Reconcile(ctx, reconcile.Request{ NamespacedName: client.ObjectKeyFromObject(bScope.Bucket), }) Expect(err.Error()).To(ContainSubstring("non-404 error")) - Expect(mck.Logs()).To(ContainSubstring("Failed to fetch LinodeObjectStorageBucket")) }), ), ), Result("scope params is missing args", func(ctx context.Context, mck Mock) { reconciler.Client = mck.K8sClient reconciler.Logger = bScope.Logger - _, err := reconciler.Reconcile(ctx, reconcile.Request{ + _, err := utilreconciler.AsReconcilerWithTracing(mck.K8sClient, &reconciler).Reconcile(ctx, reconcile.Request{ NamespacedName: client.ObjectKeyFromObject(bScope.Bucket), }) Expect(err.Error()).To(ContainSubstring("failed to create object storage bucket scope")) diff --git a/internal/controller/linodeobjectstoragekey_controller_test.go b/internal/controller/linodeobjectstoragekey_controller_test.go index 75b086048..50ec15648 100644 --- a/internal/controller/linodeobjectstoragekey_controller_test.go +++ b/internal/controller/linodeobjectstoragekey_controller_test.go @@ -38,6 +38,7 @@ import ( infrav1 "github.com/linode/cluster-api-provider-linode/api/v1alpha2" "github.com/linode/cluster-api-provider-linode/cloud/scope" "github.com/linode/cluster-api-provider-linode/mock" + utilreconciler "github.com/linode/cluster-api-provider-linode/util/reconciler" . "github.com/linode/cluster-api-provider-linode/mock/mocktest" . "github.com/onsi/ginkgo/v2" @@ -441,7 +442,7 @@ var _ = Describe("errors", Label("key", "key-errors"), func() { }), Result("no error", func(ctx context.Context, mck Mock) { reconciler.Client = mck.K8sClient - _, err := reconciler.Reconcile(ctx, reconcile.Request{ + _, err := utilreconciler.AsReconcilerWithTracing(mck.K8sClient, &reconciler).Reconcile(ctx, reconcile.Request{ NamespacedName: client.ObjectKeyFromObject(keyScope.Key), }) Expect(err).NotTo(HaveOccurred()) @@ -454,18 +455,17 @@ var _ = Describe("errors", Label("key", "key-errors"), func() { Result("error", func(ctx context.Context, mck Mock) { reconciler.Client = mck.K8sClient reconciler.Logger = keyScope.Logger - _, err := reconciler.Reconcile(ctx, reconcile.Request{ + _, err := utilreconciler.AsReconcilerWithTracing(mck.K8sClient, &reconciler).Reconcile(ctx, reconcile.Request{ NamespacedName: client.ObjectKeyFromObject(keyScope.Key), }) Expect(err.Error()).To(ContainSubstring("non-404 error")) - Expect(mck.Logs()).To(ContainSubstring("Failed to fetch LinodeObjectStorageKey")) }), ), ), Result("scope params is missing args", func(ctx context.Context, mck Mock) { reconciler.Client = mck.K8sClient reconciler.Logger = keyScope.Logger - _, err := reconciler.Reconcile(ctx, reconcile.Request{ + _, err := utilreconciler.AsReconcilerWithTracing(mck.K8sClient, &reconciler).Reconcile(ctx, reconcile.Request{ NamespacedName: client.ObjectKeyFromObject(keyScope.Key), }) Expect(err.Error()).To(ContainSubstring("failed to create object storage key scope")) diff --git a/internal/controller/linodevpc_controller.go b/internal/controller/linodevpc_controller.go index a9e0c39b3..482b16c87 100644 --- a/internal/controller/linodevpc_controller.go +++ b/internal/controller/linodevpc_controller.go @@ -45,7 +45,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" ) diff --git a/util/reconciler/typedreconciler.go b/util/reconciler/typedreconciler.go index 5c29f9749..1d60e3efb 100644 --- a/util/reconciler/typedreconciler.go +++ b/util/reconciler/typedreconciler.go @@ -3,10 +3,11 @@ 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" + + o11yreconciler "github.com/linode/cluster-api-provider-linode/observability/wrappers/runtimereconciler" ) func AsReconcilerWithTracing[object client.Object](k8sClient client.Client, rec reconcile.ObjectReconciler[object]) reconcile.Reconciler { @@ -26,13 +27,13 @@ type capiReconcilerAdapter[object client.Object] struct { k8sClient client.Client } -func (a *capiReconcilerAdapter[object]) Reconcile(ctx context.Context, o object) (reconcile.Result, error) { +func (a *capiReconcilerAdapter[object]) Reconcile(ctx context.Context, obj 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 annotations := obj.GetAnnotations(); annotations != nil { if _, exists := annotations[clusterctlv1.DeleteForMoveAnnotation]; exists { return reconcile.Result{}, nil } } - return a.objReconciler.Reconcile(ctx, o) + return a.objReconciler.Reconcile(ctx, obj) } From 6f729fb5fb8361bc6c42e36c12907df5ecc60f54 Mon Sep 17 00:00:00 2001 From: Glenn Pratt Date: Fri, 29 May 2026 16:42:05 -0400 Subject: [PATCH 3/5] allow cloudfront --- .github/workflows/build-push.yml | 1 + .github/workflows/e2e-test.yaml | 1 + .github/workflows/e2e-upgrade-test.yaml | 1 + .github/workflows/go-analyze.yml | 1 + .github/workflows/pull_request_ci.yaml | 1 + 5 files changed, 5 insertions(+) diff --git a/.github/workflows/build-push.yml b/.github/workflows/build-push.yml index f03e17ab7..8222acc3e 100644 --- a/.github/workflows/build-push.yml +++ b/.github/workflows/build-push.yml @@ -27,6 +27,7 @@ jobs: index.docker.io:443 registry-1.docker.io:443 production.cloudflare.docker.com:443 + production.cloudfront.docker.com:443 gcr.io:443 golang.org:443 go.dev:443 diff --git a/.github/workflows/e2e-test.yaml b/.github/workflows/e2e-test.yaml index 1eacba845..706e8c715 100644 --- a/.github/workflows/e2e-test.yaml +++ b/.github/workflows/e2e-test.yaml @@ -102,6 +102,7 @@ jobs: registry-1.docker.io:443 auth.docker.io:443 production.cloudflare.docker.com:443 + production.cloudfront.docker.com:443 storage.googleapis.com:443 registry.k8s.io:443 *.pkg.dev:443 diff --git a/.github/workflows/e2e-upgrade-test.yaml b/.github/workflows/e2e-upgrade-test.yaml index d5e8c35af..87ed15829 100644 --- a/.github/workflows/e2e-upgrade-test.yaml +++ b/.github/workflows/e2e-upgrade-test.yaml @@ -66,6 +66,7 @@ jobs: registry-1.docker.io:443 auth.docker.io:443 production.cloudflare.docker.com:443 + production.cloudfront.docker.com:443 storage.googleapis.com:443 registry.k8s.io:443 *.pkg.dev:443 diff --git a/.github/workflows/go-analyze.yml b/.github/workflows/go-analyze.yml index e1697a338..2b6db9a3e 100644 --- a/.github/workflows/go-analyze.yml +++ b/.github/workflows/go-analyze.yml @@ -56,6 +56,7 @@ jobs: *.githubusercontent.com:443 auth.docker.io:443 production.cloudflare.docker.com:443 + production.cloudfront.docker.com:443 vuln.go.dev:443 storage.googleapis.com:443 golangci-lint.run:443 diff --git a/.github/workflows/pull_request_ci.yaml b/.github/workflows/pull_request_ci.yaml index a37805b69..30ba69669 100644 --- a/.github/workflows/pull_request_ci.yaml +++ b/.github/workflows/pull_request_ci.yaml @@ -127,6 +127,7 @@ jobs: registry-1.docker.io:443 auth.docker.io:443 production.cloudflare.docker.com:443 + production.cloudfront.docker.com:443 gcr.io:443 storage.googleapis.com:443 From c2e3de9a4df52bf7c13cf6e63323a8f5ac65577c Mon Sep 17 00:00:00 2001 From: Glenn Pratt Date: Fri, 29 May 2026 17:07:36 -0400 Subject: [PATCH 4/5] upgrade golang.org/x/net for vulcheck failure --- go.mod | 12 ++++++------ go.sum | 28 ++++++++++++++-------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/go.mod b/go.mod index 3702deb34..170ef17f2 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( go.uber.org/automaxprocs v1.6.0 go.uber.org/mock v0.6.0 go4.org/netipx v0.0.0-20231129151722-fdeea329fbba - golang.org/x/mod v0.34.0 + golang.org/x/mod v0.35.0 k8s.io/api v0.35.3 k8s.io/apimachinery v0.35.3 k8s.io/client-go v0.35.3 @@ -137,13 +137,13 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/ratelimit v0.3.1 // indirect go.uber.org/zap v1.27.1 // indirect - golang.org/x/net v0.53.0 // indirect + golang.org/x/net v0.55.0 // indirect golang.org/x/oauth2 v0.35.0 // indirect - golang.org/x/sys v0.43.0 // indirect - golang.org/x/term v0.42.0 // indirect - golang.org/x/text v0.36.0 // indirect + golang.org/x/sys v0.45.0 // indirect + golang.org/x/term v0.43.0 // indirect + golang.org/x/text v0.37.0 // indirect golang.org/x/time v0.12.0 // indirect - golang.org/x/tools v0.43.0 // indirect + golang.org/x/tools v0.44.0 // indirect gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20260406210006-6f92a3bedf2d // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260406210006-6f92a3bedf2d // indirect diff --git a/go.sum b/go.sum index bea21a143..932ae8e85 100644 --- a/go.sum +++ b/go.sum @@ -321,28 +321,28 @@ go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= -golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI= -golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q= +golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI= +golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8= golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw= golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM= -golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI= -golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY= -golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA= -golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs= +golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM= +golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU= +golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8= +golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww= golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ= golang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= -golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= -golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/term v0.42.0 h1:UiKe+zDFmJobeJ5ggPwOshJIVt6/Ft0rcfrXZDLWAWY= -golang.org/x/term v0.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY= -golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg= -golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164= +golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= +golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4= +golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk= +golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= +golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= -golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s= -golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0= +golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c= +golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI= gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0= gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= From 96f641b02eba9b7789f76e060a477391fe8b53f5 Mon Sep 17 00:00:00 2001 From: Glenn Pratt Date: Fri, 29 May 2026 17:54:56 -0400 Subject: [PATCH 5/5] coverpkg --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 1dd454714..aa7601c7a 100644 --- a/Makefile +++ b/Makefile @@ -154,7 +154,7 @@ docs: .PHONY: test test: generate fmt vet envtest ## Run tests. - KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use ${ENVTEST_K8S_VERSION#v} --bin-dir $(CACHE_BIN) -p path)" go test -race -timeout 60s `go list ./... | grep -v ./mock$$` -coverprofile cover.out.tmp + KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use ${ENVTEST_K8S_VERSION#v} --bin-dir $(CACHE_BIN) -p path)" go test -timeout 60s `go list ./... | grep -v ./mock$$` -coverpkg=./... -coverprofile cover.out.tmp grep -v "zz_generated.*" cover.out.tmp > cover.out rm cover.out.tmp