Repository: kubernetes-sigs/cluster-api
Pull request #5600 (2021-11-05 18:46:52)

🌱 e2e: self-hosted (clusterctl move) with clusterclass
<!-- please add a icon to the title of this PR (see https://sigs.k8s.io/cluster-api/VERSIONING.md), and delete this line and similar ones -->
<!-- the icon will be either ⚠️ (:warning:, major or breaking changes), ✨ (:sparkles:, feature additions), 🐛 (:bug:, patch and bugfixes), 📖 (:book:, documentation or proposals), or 🌱 (:seedling:, minor or other) -->

**What this PR does / why we need it**:

This PR add another self-hosted E2E test (tests `clusterctl move`) to also work with ClusterClass based clusters.

**Which issue(s) this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close the issue(s) when PR gets merged)*:
Fixes #


k8s-ci-robot: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by:
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please assign **sbueringer** after the PR has been reviewed.
You can assign the PR to them by writing `/assign @sbueringer` in a comment when ready.

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubernetes-sigs%2Fcluster-api).

<details open>
Needs approval from an approver in each of these files:

- **[test/OWNERS](https://github.com/kubernetes-sigs/cluster-api/blob/main/test/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["sbueringer"]} -->
ykakarap: /test pull-cluster-api-e2e-full-main
ykakarap: /test pull-cluster-api-e2e-full-main

once more to check for flakes (if any) :) 
ykakarap: /assign @fabriziopandini 
randomvariable: Mostly what Fabrizio said.

Patch:
diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml
index f8adf7629..c1487ae7c 100644
--- a/.github/workflows/golangci-lint.yml
+++ b/.github/workflows/golangci-lint.yml
@@ -13,11 +13,10 @@ jobs:
         working-directory:
           - ""
           - test
-          - hack/tools
     steps:
       - uses: actions/checkout@v2
       - name: golangci-lint
         uses: golangci/golangci-lint-action@v2
         with:
-          version: v1.43.0
+          version: v1.42.1
           working-directory: ${{matrix.working-directory}}
diff --git a/.golangci.yml b/.golangci.yml
index 0eed8ddd4..37b86add7 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -8,7 +8,6 @@ linters:
   - dogsled
   - errcheck
   - exportloopref
-  - gci
   - goconst
   - gocritic
   - gocyclo
@@ -43,8 +42,6 @@ linters-settings:
   ifshort:
     # Maximum length of variable declaration measured in number of characters, after which linter won't suggest using short syntax.
     max-decl-chars: 50
-  gci:
-    local-prefixes: "false"
   importas:
     no-unaliased: true
     alias:
@@ -152,17 +149,9 @@ issues:
     - stylecheck
     text: "ST1016: methods on the same type should have the same receiver name"
     path: .*(api|types)\/.*\/conversion.*\.go$
-  # hack/tools
-  - linters:
-    - typecheck
-    text: import (".+") is a program, not an importable package
-    path: ^tools\.go$
 
 run:
   timeout: 10m
-  build-tags:
-  - tools
-  - e2e
   skip-files:
   - "zz_generated.*\\.go$"
   skip-dirs:
diff --git a/Makefile b/Makefile
index fc0fd57c6..a85ed128e 100644
--- a/Makefile
+++ b/Makefile
@@ -251,7 +251,6 @@ e2e-framework: ## Builds the CAPI e2e framework
 lint: $(GOLANGCI_LINT) ## Lint codebase
 	$(GOLANGCI_LINT) run -v $(GOLANGCI_LINT_EXTRA_ARGS)
 	cd $(TEST_DIR); $(GOLANGCI_LINT) run -v $(GOLANGCI_LINT_EXTRA_ARGS)
-	cd $(TOOLS_DIR); $(GOLANGCI_LINT) run -v $(GOLANGCI_LINT_EXTRA_ARGS)
 
 .PHONY: lint-fix
 lint-fix: $(GOLANGCI_LINT) ## Lint the codebase and run auto-fixers if supported by the linter.
diff --git a/OWNERS_ALIASES b/OWNERS_ALIASES
index 4cca9bce6..2e2af9b75 100644
--- a/OWNERS_ALIASES
+++ b/OWNERS_ALIASES
@@ -51,7 +51,6 @@ aliases:
   # -----------------------------------------------------------
 
   cluster-api-controlplane-provider-kubeadm-maintainers:
-  - randomvariable
   cluster-api-controlplane-provider-kubeadm-reviewers:
 
   # -----------------------------------------------------------
@@ -66,9 +65,7 @@ aliases:
   # -----------------------------------------------------------
 
   cluster-api-test-reviewers:
-  - randomvariable
   cluster-api-test-maintainers:
-  - sbueringer
 
   # -----------------------------------------------------------
   # OWNER_ALIASES for test/framework
diff --git a/Tiltfile b/Tiltfile
index 98f3b89ca..944ff607d 100644
--- a/Tiltfile
+++ b/Tiltfile
@@ -4,6 +4,12 @@ load("ext://local_output", "local_output")
 
 version_settings(True, ">=0.22.2")
 
+envsubst_cmd = "./hack/tools/bin/envsubst"
+kustomize_cmd = "./hack/tools/bin/kustomize"
+yq_cmd = "./hack/tools/bin/yq"
+os_name = local_output("go env GOOS")
+os_arch = local_output("go env GOARCH")
+
 settings = {
     "deploy_cert_manager": True,
     "preload_images_for_kind": True,
@@ -18,17 +24,11 @@ settings.update(read_json(
     default = {},
 ))
 
-allow_k8s_contexts(settings.get("allowed_contexts"))
-
-envsubst_cmd = "./hack/tools/bin/envsubst"
-kustomize_cmd = "./hack/tools/bin/kustomize"
-yq_cmd = "./hack/tools/bin/yq"
-os_name = local_output("go env GOOS")
-os_arch = local_output("go env GOARCH")
-
 if settings.get("trigger_mode") == "manual":
     trigger_mode(TRIGGER_MODE_MANUAL)
 
+allow_k8s_contexts(settings.get("allowed_contexts"))
+
 default_registry(settings.get("default_registry"))
 
 always_enable_providers = ["core"]
diff --git a/api/v1alpha3/cluster_types.go b/api/v1alpha3/cluster_types.go
index af53ea0c0..ae74d7b07 100644
--- a/api/v1alpha3/cluster_types.go
+++ b/api/v1alpha3/cluster_types.go
@@ -24,6 +24,7 @@ import (
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/utils/pointer"
+
 	capierrors "sigs.k8s.io/cluster-api/errors"
 )
 
diff --git a/api/v1alpha4/cluster_types.go b/api/v1alpha4/cluster_types.go
index dbc70ac6f..794363ab6 100644
--- a/api/v1alpha4/cluster_types.go
+++ b/api/v1alpha4/cluster_types.go
@@ -25,6 +25,7 @@ import (
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/utils/pointer"
+
 	capierrors "sigs.k8s.io/cluster-api/errors"
 )
 
diff --git a/api/v1beta1/cluster_types.go b/api/v1beta1/cluster_types.go
index b71033fbf..b4c3273d1 100644
--- a/api/v1beta1/cluster_types.go
+++ b/api/v1beta1/cluster_types.go
@@ -26,6 +26,7 @@ import (
 	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/utils/pointer"
+
 	capierrors "sigs.k8s.io/cluster-api/errors"
 )
 
diff --git a/api/v1beta1/cluster_webhook.go b/api/v1beta1/cluster_webhook.go
index 2d182291a..e122dc2c6 100644
--- a/api/v1beta1/cluster_webhook.go
+++ b/api/v1beta1/cluster_webhook.go
@@ -31,9 +31,6 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/webhook"
 )
 
-// Deprecated: This file, including all public and private methods, will be removed in a future release.
-// The Cluster webhook validation implementation and API can now be found in the webhooks package.
-
 // SetupWebhookWithManager sets up Cluster webhooks.
 // Deprecated: This method is going to be removed in a next release.
 // Note: We're not using this method anymore and are using webhooks.Cluster.SetupWebhookWithManager instead.
@@ -50,7 +47,6 @@ var _ webhook.Validator = &Cluster{}
 
 // Default satisfies the defaulting webhook interface.
 // Deprecated: This method is going to be removed in a next release.
-// Note: We're not using this method anymore and are using webhooks.Cluster.Default instead.
 func (c *Cluster) Default() {
 	if c.Spec.InfrastructureRef != nil && len(c.Spec.InfrastructureRef.Namespace) == 0 {
 		c.Spec.InfrastructureRef.Namespace = c.Namespace
@@ -71,14 +67,12 @@ func (c *Cluster) Default() {
 
 // ValidateCreate implements webhook.Validator so a webhook will be registered for the type.
 // Deprecated: This method is going to be removed in a next release.
-// Note: We're not using this method anymore and are using webhooks.Cluster.ValidateCreate instead.
 func (c *Cluster) ValidateCreate() error {
 	return c.validate(nil)
 }
 
 // ValidateUpdate implements webhook.Validator so a webhook will be registered for the type.
 // Deprecated: This method is going to be removed in a next release.
-// Note: We're not using this method anymore and are using webhooks.Cluster.ValidateUpdate instead.
 func (c *Cluster) ValidateUpdate(old runtime.Object) error {
 	oldCluster, ok := old.(*Cluster)
 	if !ok {
@@ -89,7 +83,6 @@ func (c *Cluster) ValidateUpdate(old runtime.Object) error {
 
 // ValidateDelete implements webhook.Validator so a webhook will be registered for the type.
 // Deprecated: This method is going to be removed in a next release.
-// Note: We're not using this method anymore and are using webhooks.Cluster.ValidateDelete instead.
 func (c *Cluster) ValidateDelete() error {
 	return nil
 }
diff --git a/api/v1beta1/clusterclass_webhook.go b/api/v1beta1/clusterclass_webhook.go
index b8e6455cb..0079cfe19 100644
--- a/api/v1beta1/clusterclass_webhook.go
+++ b/api/v1beta1/clusterclass_webhook.go
@@ -31,9 +31,6 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/webhook"
 )
 
-// Deprecated: This file, including all public and private methods, will be removed in a future release.
-// The ClusterClass webhook validation implementation and API can now be found in the webhooks package.
-
 // SetupWebhookWithManager sets up ClusterClass webhooks.
 // Deprecated: This method is going to be removed in a next release.
 // Note: We're not using this method anymore and are using webhooks.ClusterClass.SetupWebhookWithManager instead.
@@ -50,7 +47,6 @@ var _ webhook.Defaulter = &ClusterClass{}
 
 // Default satisfies the defaulting webhook interface.
 // Deprecated: This method is going to be removed in a next release.
-// Note: We're not using this method anymore and are using webhooks.ClusterClass.Default instead.
 func (in *ClusterClass) Default() {
 	// Default all namespaces in the references to the object namespace.
 	defaultNamespace(in.Spec.Infrastructure.Ref, in.Namespace)
@@ -74,14 +70,12 @@ func defaultNamespace(ref *corev1.ObjectReference, namespace string) {
 
 // ValidateCreate implements webhook.Validator so a webhook will be registered for the type.
 // Deprecated: This method is going to be removed in a next release.
-// Note: We're not using this method anymore and are using webhooks.ClusterClass.ValidateCreate instead.
 func (in *ClusterClass) ValidateCreate() error {
 	return in.validate(nil)
 }
 
 // ValidateUpdate implements webhook.Validator so a webhook will be registered for the type.
 // Deprecated: This method is going to be removed in a next release.
-// Note: We're not using this method anymore and are using webhooks.ClusterClass.ValidateUpdate instead.
 func (in *ClusterClass) ValidateUpdate(old runtime.Object) error {
 	oldClusterClass, ok := old.(*ClusterClass)
 	if !ok {
@@ -92,7 +86,6 @@ func (in *ClusterClass) ValidateUpdate(old runtime.Object) error {
 
 // ValidateDelete implements webhook.Validator so a webhook will be registered for the type.
 // Deprecated: This method is going to be removed in a next release.
-// Note: We're not using this method anymore and are using webhooks.ClusterClass.ValidateDelete instead.
 func (in *ClusterClass) ValidateDelete() error {
 	return nil
 }
diff --git a/api/v1beta1/machine_webhook.go b/api/v1beta1/machine_webhook.go
index 00f02b6b5..cce7981ea 100644
--- a/api/v1beta1/machine_webhook.go
+++ b/api/v1beta1/machine_webhook.go
@@ -20,10 +20,11 @@ import (
 	"fmt"
 	"strings"
 
+	"sigs.k8s.io/cluster-api/util/version"
+
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/util/validation/field"
-	"sigs.k8s.io/cluster-api/util/version"
 	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/webhook"
 )
diff --git a/bootstrap/kubeadm/main.go b/bootstrap/kubeadm/main.go
index fb7a7d6bf..563cfac1a 100644
--- a/bootstrap/kubeadm/main.go
+++ b/bootstrap/kubeadm/main.go
@@ -26,7 +26,6 @@ import (
 	"os"
 	"time"
 
-	// +kubebuilder:scaffold:imports
 	"github.com/spf13/pflag"
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/runtime"
@@ -47,6 +46,7 @@ import (
 	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 	"sigs.k8s.io/controller-runtime/pkg/controller"
+	// +kubebuilder:scaffold:imports
 )
 
 var (
diff --git a/bootstrap/kubeadm/types/upstreamv1beta1/bootstraptokenstring.go b/bootstrap/kubeadm/types/upstreamv1beta1/bootstraptokenstring.go
index f8da6e099..70b083117 100644
--- a/bootstrap/kubeadm/types/upstreamv1beta1/bootstraptokenstring.go
+++ b/bootstrap/kubeadm/types/upstreamv1beta1/bootstraptokenstring.go
@@ -21,6 +21,7 @@ import (
 	"strings"
 
 	"github.com/pkg/errors"
+
 	bootstrapapi "k8s.io/cluster-bootstrap/token/api"
 	bootstraputil "k8s.io/cluster-bootstrap/token/util"
 )
diff --git a/bootstrap/kubeadm/types/upstreamv1beta2/bootstraptokenstring.go b/bootstrap/kubeadm/types/upstreamv1beta2/bootstraptokenstring.go
index ef263945c..83ff743a0 100644
--- a/bootstrap/kubeadm/types/upstreamv1beta2/bootstraptokenstring.go
+++ b/bootstrap/kubeadm/types/upstreamv1beta2/bootstraptokenstring.go
@@ -21,6 +21,7 @@ import (
 	"strings"
 
 	"github.com/pkg/errors"
+
 	bootstrapapi "k8s.io/cluster-bootstrap/token/api"
 	bootstraputil "k8s.io/cluster-bootstrap/token/util"
 )
diff --git a/bootstrap/kubeadm/types/upstreamv1beta3/bootstraptokenstring.go b/bootstrap/kubeadm/types/upstreamv1beta3/bootstraptokenstring.go
index b846a5d4f..d59295bab 100644
--- a/bootstrap/kubeadm/types/upstreamv1beta3/bootstraptokenstring.go
+++ b/bootstrap/kubeadm/types/upstreamv1beta3/bootstraptokenstring.go
@@ -21,6 +21,7 @@ import (
 	"strings"
 
 	"github.com/pkg/errors"
+
 	bootstrapapi "k8s.io/cluster-bootstrap/token/api"
 	bootstraputil "k8s.io/cluster-bootstrap/token/util"
 )
diff --git a/cmd/clusterctl/client/cluster/cert_manager.go b/cmd/clusterctl/client/cluster/cert_manager.go
index a0137bea9..9eb0d5516 100644
--- a/cmd/clusterctl/client/cluster/cert_manager.go
+++ b/cmd/clusterctl/client/cluster/cert_manager.go
@@ -26,14 +26,15 @@ import (
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
 	"k8s.io/apimachinery/pkg/util/version"
+	"sigs.k8s.io/cluster-api/cmd/clusterctl/client/repository"
+	"sigs.k8s.io/controller-runtime/pkg/client"
+
 	clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
 	"sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
-	"sigs.k8s.io/cluster-api/cmd/clusterctl/client/repository"
 	"sigs.k8s.io/cluster-api/cmd/clusterctl/internal/util"
 	logf "sigs.k8s.io/cluster-api/cmd/clusterctl/log"
 	utilresource "sigs.k8s.io/cluster-api/util/resource"
 	utilyaml "sigs.k8s.io/cluster-api/util/yaml"
-	"sigs.k8s.io/controller-runtime/pkg/client"
 )
 
 const (
diff --git a/cmd/clusterctl/client/cluster/mover.go b/cmd/clusterctl/client/cluster/mover.go
index 4966c120e..6352788e2 100644
--- a/cmd/clusterctl/client/cluster/mover.go
+++ b/cmd/clusterctl/client/cluster/mover.go
@@ -128,9 +128,6 @@ func (o *objectMover) Restore(toCluster Client, directory string) error {
 	// by a naming convention (without any explicit OwnerReference).
 	objectGraph.setSoftOwnership()
 
-	// Completes the graph by setting for each node the list of tenants the node belongs to.
-	objectGraph.setTenants()
-
 	// Check whether nodes are not included in GVK considered for restore.
 	objectGraph.checkVirtualNode()
 
diff --git a/cmd/clusterctl/client/config.go b/cmd/clusterctl/client/config.go
index 49d5d7d04..3c79fe7bf 100644
--- a/cmd/clusterctl/client/config.go
+++ b/cmd/clusterctl/client/config.go
@@ -23,6 +23,7 @@ import (
 	"github.com/pkg/errors"
 	"k8s.io/apimachinery/pkg/util/version"
 	"k8s.io/utils/pointer"
+
 	clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
 	"sigs.k8s.io/cluster-api/cmd/clusterctl/client/cluster"
 	"sigs.k8s.io/cluster-api/cmd/clusterctl/client/repository"
diff --git a/cmd/clusterctl/client/config/providers_client.go b/cmd/clusterctl/client/config/providers_client.go
index b2ab25413..35f241548 100644
--- a/cmd/clusterctl/client/config/providers_client.go
+++ b/cmd/clusterctl/client/config/providers_client.go
@@ -35,7 +35,6 @@ const (
 const (
 	AWSProviderName       = "aws"
 	AzureProviderName     = "azure"
-	BYOHProviderName      = "byoh"
 	DockerProviderName    = "docker"
 	DOProviderName        = "digitalocean"
 	GCPProviderName       = "gcp"
@@ -170,11 +169,6 @@ func (p *providersClient) defaults() []Provider {
 			url:          "https://github.com/spectrocloud/cluster-api-provider-maas/releases/latest/infrastructure-components.yaml",
 			providerType: clusterctlv1.InfrastructureProviderType,
 		},
-		&provider{
-			name:         BYOHProviderName,
-			url:          "https://github.com/vmware-tanzu/cluster-api-provider-bringyourownhost/releases/latest/infrastructure-components.yaml",
-			providerType: clusterctlv1.InfrastructureProviderType,
-		},
 
 		// Bootstrap providers
 		&provider{
diff --git a/cmd/clusterctl/client/config/reader_viper.go b/cmd/clusterctl/client/config/reader_viper.go
index 52f7fa288..b65f234e2 100644
--- a/cmd/clusterctl/client/config/reader_viper.go
+++ b/cmd/clusterctl/client/config/reader_viper.go
@@ -89,7 +89,7 @@ func (v *viperReader) Init(path string) error {
 		case url.Scheme == "https" || url.Scheme == "http":
 			configPath := filepath.Join(homedir.HomeDir(), ConfigFolder)
 			if len(v.configPaths) > 0 {
-				configPath = v.configPaths[0]
+				configPath = filepath.Join(v.configPaths[0])
 			}
 			if err := os.MkdirAll(configPath, os.ModePerm); err != nil {
 				return err
diff --git a/cmd/clusterctl/client/repository/overrides.go b/cmd/clusterctl/client/repository/overrides.go
index 0882794dd..913376719 100644
--- a/cmd/clusterctl/client/repository/overrides.go
+++ b/cmd/clusterctl/client/repository/overrides.go
@@ -85,7 +85,7 @@ func getLocalOverride(info *newOverrideInput) ([]byte, error) {
 	// it the local override exists, use it
 	_, err := os.Stat(overridePath)
 	if err == nil {
-		content, err := os.ReadFile(overridePath) //nolint:gosec
+		content, err := os.ReadFile(overridePath)
 		if err != nil {
 			return nil, errors.Wrapf(err, "failed to read local override for %s", overridePath)
 		}
diff --git a/cmd/clusterctl/client/repository/repository_github.go b/cmd/clusterctl/client/repository/repository_github.go
index 4b439aece..8a97b1fcf 100644
--- a/cmd/clusterctl/client/repository/repository_github.go
+++ b/cmd/clusterctl/client/repository/repository_github.go
@@ -25,11 +25,12 @@ import (
 	"path/filepath"
 	"strings"
 
+	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
+
 	"github.com/google/go-github/v33/github"
 	"github.com/pkg/errors"
 	"golang.org/x/oauth2"
 	"k8s.io/apimachinery/pkg/util/version"
-	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
 	"sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
 )
 
diff --git a/cmd/clusterctl/client/repository/repository_local.go b/cmd/clusterctl/client/repository/repository_local.go
index a7a51fa0c..4dee68aed 100644
--- a/cmd/clusterctl/client/repository/repository_local.go
+++ b/cmd/clusterctl/client/repository/repository_local.go
@@ -23,9 +23,10 @@ import (
 	"runtime"
 	"strings"
 
+	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
+
 	"github.com/pkg/errors"
 	"k8s.io/apimachinery/pkg/util/version"
-	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
 	"sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
 )
 
@@ -102,7 +103,7 @@ func (r *localRepository) GetFile(version, fileName string) ([]byte, error) {
 	if f.IsDir() {
 		return nil, errors.Errorf("invalid path: file %q is actually a directory %q", fileName, absolutePath)
 	}
-	content, err := os.ReadFile(absolutePath) //nolint:gosec
+	content, err := os.ReadFile(absolutePath)
 	if err != nil {
 		return nil, errors.Wrapf(err, "failed to read file %q from local release %s", absolutePath, version)
 	}
diff --git a/cmd/clusterctl/client/repository/template.go b/cmd/clusterctl/client/repository/template.go
index 26bd9e673..ebb04591b 100644
--- a/cmd/clusterctl/client/repository/template.go
+++ b/cmd/clusterctl/client/repository/template.go
@@ -22,6 +22,7 @@ import (
 	"github.com/pkg/errors"
 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
 	"k8s.io/apimachinery/pkg/util/sets"
+
 	"sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
 	yaml "sigs.k8s.io/cluster-api/cmd/clusterctl/client/yamlprocessor"
 	utilyaml "sigs.k8s.io/cluster-api/util/yaml"
diff --git a/cmd/clusterctl/cmd/generate_provider.go b/cmd/clusterctl/cmd/generate_provider.go
index 84b40278e..0816cdda8 100644
--- a/cmd/clusterctl/cmd/generate_provider.go
+++ b/cmd/clusterctl/cmd/generate_provider.go
@@ -19,6 +19,7 @@ package cmd
 import (
 	"github.com/pkg/errors"
 	"github.com/spf13/cobra"
+
 	clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
 	"sigs.k8s.io/cluster-api/cmd/clusterctl/client"
 )
diff --git a/cmd/clusterctl/cmd/upgrade_apply.go b/cmd/clusterctl/cmd/upgrade_apply.go
index 3c681b16d..6dbc7be04 100644
--- a/cmd/clusterctl/cmd/upgrade_apply.go
+++ b/cmd/clusterctl/cmd/upgrade_apply.go
@@ -18,6 +18,7 @@ package cmd
 
 import (
 	"github.com/pkg/errors"
+
 	"github.com/spf13/cobra"
 	"sigs.k8s.io/cluster-api/cmd/clusterctl/client"
 )
diff --git a/cmd/clusterctl/cmd/version_checker.go b/cmd/clusterctl/cmd/version_checker.go
index 8218b7b92..802a2ca75 100644
--- a/cmd/clusterctl/cmd/version_checker.go
+++ b/cmd/clusterctl/cmd/version_checker.go
@@ -176,7 +176,7 @@ func writeStateFile(path string, vs *VersionState) error {
 }
 
 func readStateFile(filepath string) (*VersionState, error) {
-	b, err := os.ReadFile(filepath) //nolint:gosec
+	b, err := os.ReadFile(filepath)
 	if err != nil {
 		if os.IsNotExist(err) {
 			// if the file doesn't exist yet, don't error
diff --git a/controllers/cluster_controller.go b/controllers/cluster_controller.go
index c0df04621..f9de356e4 100644
--- a/controllers/cluster_controller.go
+++ b/controllers/cluster_controller.go
@@ -23,6 +23,8 @@ import (
 	"strings"
 	"time"
 
+	"sigs.k8s.io/cluster-api/util/collections"
+
 	"github.com/pkg/errors"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	"k8s.io/apimachinery/pkg/api/meta"
@@ -35,7 +37,6 @@ import (
 	"sigs.k8s.io/cluster-api/feature"
 	"sigs.k8s.io/cluster-api/util"
 	"sigs.k8s.io/cluster-api/util/annotations"
-	"sigs.k8s.io/cluster-api/util/collections"
 	"sigs.k8s.io/cluster-api/util/conditions"
 	"sigs.k8s.io/cluster-api/util/patch"
 	"sigs.k8s.io/cluster-api/util/predicates"
diff --git a/controllers/machinehealthcheck_controller.go b/controllers/machinehealthcheck_controller.go
index 4ca1810e2..f7495e0f6 100644
--- a/controllers/machinehealthcheck_controller.go
+++ b/controllers/machinehealthcheck_controller.go
@@ -24,12 +24,13 @@ import (
 	"strings"
 	"time"
 
+	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+
 	"github.com/go-logr/logr"
 	"github.com/pkg/errors"
 	corev1 "k8s.io/api/core/v1"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
 	"k8s.io/apimachinery/pkg/types"
 	kerrors "k8s.io/apimachinery/pkg/util/errors"
 	"k8s.io/apimachinery/pkg/util/intstr"
@@ -219,7 +220,7 @@ func (r *MachineHealthCheckReconciler) reconcile(ctx context.Context, logger log
 	// do sort to avoid keep changing m.Status as the returned machines are not in order
 	sort.Strings(m.Status.Targets)
 
-	nodeStartupTimeout := m.Spec.NodeStartupTimeout
+	nodeStartupTimeout := m.Spec.NodeStartupTimeout // nolint:ifshort
 	if nodeStartupTimeout == nil {
 		nodeStartupTimeout = &clusterv1.DefaultNodeStartupTimeout
 	}
diff --git a/controllers/topology/internal/mergepatch/mergepatch.go b/controllers/topology/internal/mergepatch/mergepatch.go
index 75fe758d1..2f1723813 100644
--- a/controllers/topology/internal/mergepatch/mergepatch.go
+++ b/controllers/topology/internal/mergepatch/mergepatch.go
@@ -21,7 +21,7 @@ import (
 	"context"
 	"encoding/json"
 
-	jsonpatch "github.com/evanphx/json-patch/v5"
+	jsonpatch "github.com/evanphx/json-patch"
 	"github.com/pkg/errors"
 	"k8s.io/apimachinery/pkg/types"
 	"sigs.k8s.io/cluster-api/controllers/topology/internal/contract"
diff --git a/controlplane/kubeadm/api/v1alpha3/kubeadm_control_plane_types.go b/controlplane/kubeadm/api/v1alpha3/kubeadm_control_plane_types.go
index ed230205e..5f20da423 100644
--- a/controlplane/kubeadm/api/v1alpha3/kubeadm_control_plane_types.go
+++ b/controlplane/kubeadm/api/v1alpha3/kubeadm_control_plane_types.go
@@ -21,6 +21,7 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/util/intstr"
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha3"
+
 	cabpkv1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1alpha3"
 	"sigs.k8s.io/cluster-api/errors"
 )
diff --git a/controlplane/kubeadm/api/v1beta1/kubeadm_control_plane_webhook.go b/controlplane/kubeadm/api/v1beta1/kubeadm_control_plane_webhook.go
index 0791f0070..63338bd41 100644
--- a/controlplane/kubeadm/api/v1beta1/kubeadm_control_plane_webhook.go
+++ b/controlplane/kubeadm/api/v1beta1/kubeadm_control_plane_webhook.go
@@ -23,7 +23,7 @@ import (
 
 	"github.com/blang/semver"
 	"github.com/coredns/corefile-migration/migration"
-	jsonpatch "github.com/evanphx/json-patch/v5"
+	jsonpatch "github.com/evanphx/json-patch"
 	"github.com/pkg/errors"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	"k8s.io/apimachinery/pkg/runtime"
diff --git a/controlplane/kubeadm/controllers/scale.go b/controlplane/kubeadm/controllers/scale.go
index e153b4e17..950bf6bc1 100644
--- a/controlplane/kubeadm/controllers/scale.go
+++ b/controlplane/kubeadm/controllers/scale.go
@@ -21,6 +21,8 @@ import (
 	"strings"
 
 	"github.com/blang/semver"
+	"sigs.k8s.io/cluster-api/util/collections"
+
 	"github.com/pkg/errors"
 	corev1 "k8s.io/api/core/v1"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -29,7 +31,6 @@ import (
 	controlplanev1 "sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1beta1"
 	"sigs.k8s.io/cluster-api/controlplane/kubeadm/internal"
 	"sigs.k8s.io/cluster-api/util"
-	"sigs.k8s.io/cluster-api/util/collections"
 	"sigs.k8s.io/cluster-api/util/conditions"
 	ctrl "sigs.k8s.io/controller-runtime"
 )
diff --git a/controlplane/kubeadm/controllers/status.go b/controlplane/kubeadm/controllers/status.go
index c79c62ba2..e4605bef9 100644
--- a/controlplane/kubeadm/controllers/status.go
+++ b/controlplane/kubeadm/controllers/status.go
@@ -19,12 +19,13 @@ package controllers
 import (
 	"context"
 
+	"sigs.k8s.io/cluster-api/util/collections"
+
 	"github.com/pkg/errors"
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
 	controlplanev1 "sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1beta1"
 	"sigs.k8s.io/cluster-api/controlplane/kubeadm/internal"
 	"sigs.k8s.io/cluster-api/util"
-	"sigs.k8s.io/cluster-api/util/collections"
 	"sigs.k8s.io/cluster-api/util/conditions"
 	ctrl "sigs.k8s.io/controller-runtime"
 )
diff --git a/controlplane/kubeadm/main.go b/controlplane/kubeadm/main.go
index b309a25a5..a68f830b0 100644
--- a/controlplane/kubeadm/main.go
+++ b/controlplane/kubeadm/main.go
@@ -26,7 +26,6 @@ import (
 	"os"
 	"time"
 
-	// +kubebuilder:scaffold:imports
 	"github.com/spf13/pflag"
 	appsv1 "k8s.io/api/apps/v1"
 	corev1 "k8s.io/api/core/v1"
@@ -49,6 +48,7 @@ import (
 	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 	"sigs.k8s.io/controller-runtime/pkg/controller"
+	// +kubebuilder:scaffold:imports
 )
 
 var (
diff --git a/docs/book/src/clusterctl/provider-contract.md b/docs/book/src/clusterctl/provider-contract.md
index ba006dbe0..a74b82847 100644
--- a/docs/book/src/clusterctl/provider-contract.md
+++ b/docs/book/src/clusterctl/provider-contract.md
@@ -185,7 +185,6 @@ providers.
 |CACPK         | cluster.x-k8s.io/provider=control-plane-kubeadm        |
 |CACPN         | cluster.x-k8s.io/provider=control-plane-nested        |
 |CAPA          | cluster.x-k8s.io/provider=infrastructure-aws           |
-|CAPB          | cluster.x-k8s.io/provider=infrastructure-byoh          |
 |CAPV          | cluster.x-k8s.io/provider=infrastructure-vsphere       |
 |CAPD          | cluster.x-k8s.io/provider=infrastructure-docker        |
 |CAPM3         | cluster.x-k8s.io/provider=infrastructure-metal3        |
diff --git a/docs/book/src/reference/providers.md b/docs/book/src/reference/providers.md
index 364df7db0..06866f015 100644
--- a/docs/book/src/reference/providers.md
+++ b/docs/book/src/reference/providers.md
@@ -16,7 +16,6 @@ updated info about which API version they are supporting.
 - [Azure](https://github.com/kubernetes-sigs/cluster-api-provider-azure)
 - [Azure Stack HCI](https://github.com/microsoft/cluster-api-provider-azurestackhci)
 - [Baidu Cloud](https://github.com/baidu/cluster-api-provider-baiducloud)
-- [BYOH](https://github.com/vmware-tanzu/cluster-api-provider-bringyourownhost)
 - [Metal3](https://github.com/metal3-io/cluster-api-provider-metal3)
 - [DigitalOcean](https://github.com/kubernetes-sigs/cluster-api-provider-digitalocean)
 - [Exoscale](https://github.com/exoscale/cluster-api-provider-exoscale)
diff --git a/exp/api/v1beta1/machinepool_webhook.go b/exp/api/v1beta1/machinepool_webhook.go
index a388dfbbc..f2fc4041b 100644
--- a/exp/api/v1beta1/machinepool_webhook.go
+++ b/exp/api/v1beta1/machinepool_webhook.go
@@ -19,10 +19,11 @@ package v1beta1
 import (
 	"fmt"
 
+	"k8s.io/utils/pointer"
+
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	runtime "k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/util/validation/field"
-	"k8s.io/utils/pointer"
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
 	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/webhook"
diff --git a/exp/controllers/machinepool_controller_phases.go b/exp/controllers/machinepool_controller_phases.go
index f9cb766c2..960516911 100644
--- a/exp/controllers/machinepool_controller_phases.go
+++ b/exp/controllers/machinepool_controller_phases.go
@@ -22,6 +22,9 @@ import (
 	"reflect"
 	"time"
 
+	"sigs.k8s.io/cluster-api/util"
+	ctrl "sigs.k8s.io/controller-runtime"
+
 	"github.com/pkg/errors"
 	corev1 "k8s.io/api/core/v1"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -31,11 +34,9 @@ import (
 	"sigs.k8s.io/cluster-api/controllers/external"
 	capierrors "sigs.k8s.io/cluster-api/errors"
 	expv1 "sigs.k8s.io/cluster-api/exp/api/v1beta1"
-	"sigs.k8s.io/cluster-api/util"
 	"sigs.k8s.io/cluster-api/util/annotations"
 	"sigs.k8s.io/cluster-api/util/conditions"
 	"sigs.k8s.io/cluster-api/util/patch"
-	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
 	"sigs.k8s.io/controller-runtime/pkg/handler"
 	"sigs.k8s.io/controller-runtime/pkg/source"
diff --git a/exp/util/util.go b/exp/util/util.go
index 6abf7d5c4..9e70b033d 100644
--- a/exp/util/util.go
+++ b/exp/util/util.go
@@ -22,6 +22,7 @@ import (
 
 	"github.com/go-logr/logr"
 	"github.com/pkg/errors"
+
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime/schema"
 	clusterv1exp "sigs.k8s.io/cluster-api/exp/api/v1beta1"
diff --git a/go.mod b/go.mod
index 0ff9fee9b..8709e0227 100644
--- a/go.mod
+++ b/go.mod
@@ -9,7 +9,7 @@ require (
 	github.com/davecgh/go-spew v1.1.1
 	github.com/docker/distribution v2.7.1+incompatible
 	github.com/drone/envsubst/v2 v2.0.0-20210615175204-7bf45dbf5372
-	github.com/evanphx/json-patch/v5 v5.6.0
+	github.com/evanphx/json-patch v4.11.0+incompatible
 	github.com/fatih/color v1.13.0
 	github.com/go-logr/logr v0.4.0
 	github.com/gobuffalo/flect v0.2.3
diff --git a/go.sum b/go.sum
index dd0cc2a92..f795c572b 100644
--- a/go.sum
+++ b/go.sum
@@ -163,8 +163,6 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
 github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ=
 github.com/evanphx/json-patch v4.11.0+incompatible h1:glyUF9yIYtMHzn8xaKw5rMhdWcwsYV8dZHIq5567/xs=
 github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
-github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww=
-github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4=
 github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM=
 github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4=
 github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc=
diff --git a/hack/boilerplate/README.md b/hack/boilerplate/README.md
deleted file mode 100644
index 83d221a5b..000000000
--- a/hack/boilerplate/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# Boilerplate utilities
-
-The boilerplate validation utilities have been copied and adapted from upstream Kubernetes, see https://github.com/kubernetes/kubernetes/blob/4dfd73940396730caf331e35cbb28235d233f2a0/hack/boilerplate.
diff --git a/hack/boilerplate/boilerplate.Dockerfile.txt b/hack/boilerplate/boilerplate.Dockerfile.txt
index bf65541d8..f6a6f6896 100644
--- a/hack/boilerplate/boilerplate.Dockerfile.txt
+++ b/hack/boilerplate/boilerplate.Dockerfile.txt
@@ -13,3 +13,4 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
+
diff --git a/hack/boilerplate/boilerplate.bzl.txt b/hack/boilerplate/boilerplate.bzl.txt
index 34cb349c4..384f325ab 100644
--- a/hack/boilerplate/boilerplate.bzl.txt
+++ b/hack/boilerplate/boilerplate.bzl.txt
@@ -11,3 +11,4 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
+
diff --git a/hack/boilerplate/boilerplate.generatego.txt b/hack/boilerplate/boilerplate.generatego.txt
index 0926592d3..b7c650da4 100644
--- a/hack/boilerplate/boilerplate.generatego.txt
+++ b/hack/boilerplate/boilerplate.generatego.txt
@@ -13,3 +13,4 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */
+
diff --git a/hack/boilerplate/boilerplate.py b/hack/boilerplate/boilerplate.py
index 1af9d03ca..9ab4b4497 100755
--- a/hack/boilerplate/boilerplate.py
+++ b/hack/boilerplate/boilerplate.py
@@ -62,6 +62,10 @@ def get_refs():
     return refs
 
 def is_generated_file(filename, data, regexs):
+    for d in generated_files:
+            if d in filename:
+                return True
+
     for d in skipped_ungenerated_files:
         if d in filename:
             return False
@@ -99,7 +103,7 @@ def file_passes(filename, refs, regexs):
     if extension == "go" or extension == "generatego":
         p = regexs["go_build_constraints"]
         (data, found) = p.subn("", data, 1)
-    elif extension in ["sh", "py"]:
+    elif extension == "sh":
         p = regexs["shebang"]
         (data, found) = p.subn("", data, 1)
 
@@ -119,11 +123,9 @@ def file_passes(filename, refs, regexs):
     for d in data:
         if p.search(d):
             if generated:
-                print('File %s has the YEAR field, but it should not be in generated file' %
-                      filename, file=verbose_out)
+                print('File %s has the YEAR field, but it should not be in generated file' % filename, file=verbose_out)
             else:
-                print('File %s has the YEAR field, but missing the year of date' %
-                      filename, file=verbose_out)
+                print('File %s has the YEAR field, but missing the year of date' % filename, file=verbose_out)
             return False
 
     if not generated:
@@ -136,8 +138,7 @@ def file_passes(filename, refs, regexs):
 
     # if we don't match the reference at this point, fail
     if ref != data:
-        print("Header in %s does not match reference, diff:" %
-              filename, file=verbose_out)
+        print("Header in %s does not match reference, diff:" % filename, file=verbose_out)
         if args.verbose:
             print(file=verbose_out)
             for line in difflib.unified_diff(ref, data, 'reference', filename, lineterm=''):
@@ -150,13 +151,14 @@ def file_passes(filename, refs, regexs):
 def file_extension(filename):
     return os.path.splitext(filename)[1].split(".")[-1].lower()
 
-skipped_dirs = ['third_party', 'tilt_modules', '_gopath', '_output', '.git', 'cluster/env.sh',
-                "vendor", "test/e2e/generated/bindata.go", "hack/boilerplate/test",
-                "staging/src/k8s.io/kubectl/pkg/generated/bindata.go"]
+skipped_dirs = ['Godeps', 'third_party', '_gopath', '_output', '.git', 'cluster/env.sh',
+                "vendor", "hack/boilerplate/test", "tilt_modules"]
 
 # list all the files contain 'DO NOT EDIT', but are not generated
-skipped_ungenerated_files = [
-    'hack/lib/swagger.sh', 'hack/boilerplate/boilerplate.py']
+skipped_ungenerated_files = ['hack/lib/swagger.sh', 'hack/boilerplate/boilerplate.py']
+
+# list all the files that does not contain 'DO NOT EDIT', but are generated
+generated_files = []
 
 def normalize_files(files):
     newfiles = []
@@ -203,19 +205,16 @@ def get_dates():
 def get_regexs():
     regexs = {}
     # Search for "YEAR" which exists in the boilerplate, but shouldn't in the real thing
-    regexs["year"] = re.compile('YEAR')
+    regexs["year"] = re.compile( 'YEAR' )
     # get_dates return 2014, 2015, 2016, 2017, or 2018 until the current year as a regex like: "(2014|2015|2016|2017|2018)";
     # company holder names can be anything
     regexs["date"] = re.compile(get_dates())
-    # strip the following build constraints/tags:
-    # //go:build
-    # // +build \n\n
-    regexs["go_build_constraints"] = re.compile(
-        r"^(//(go:build| \+build).*\n)+\n", re.MULTILINE)
-    # strip #!.* from scripts
+    # strip // +build \n\n build constraints
+    regexs["go_build_constraints"] = re.compile(r"^(// \+build.*\n)+\n", re.MULTILINE)
+    # strip #!.* from shell scripts
     regexs["shebang"] = re.compile(r"^(#!.*\n)\n*", re.MULTILINE)
     # Search for generated files
-    regexs["generated"] = re.compile('DO NOT EDIT')
+    regexs["generated"] = re.compile( 'DO NOT EDIT' )
     return regexs
 
 def main():
@@ -230,4 +229,4 @@ def main():
     return 0
 
 if __name__ == "__main__":
-    sys.exit(main())
+  sys.exit(main())
diff --git a/hack/boilerplate/boilerplate.py.txt b/hack/boilerplate/boilerplate.py.txt
index 34cb349c4..a2e72e598 100644
--- a/hack/boilerplate/boilerplate.py.txt
+++ b/hack/boilerplate/boilerplate.py.txt
@@ -1,3 +1,5 @@
+#!/usr/bin/env python
+
 # Copyright YEAR The Kubernetes Authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -11,3 +13,4 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
+
diff --git a/hack/boilerplate/boilerplate.sh.txt b/hack/boilerplate/boilerplate.sh.txt
index 34cb349c4..384f325ab 100644
--- a/hack/boilerplate/boilerplate.sh.txt
+++ b/hack/boilerplate/boilerplate.sh.txt
@@ -11,3 +11,4 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
+
diff --git a/hack/tools/go.mod b/hack/tools/go.mod
index d214b09e2..dd95d7650 100644
--- a/hack/tools/go.mod
+++ b/hack/tools/go.mod
@@ -4,19 +4,19 @@ go 1.16
 
 require (
 	github.com/blang/semver v3.5.1+incompatible
-	github.com/drone/envsubst/v2 v2.0.0-20210730161058-179042472c46
-	github.com/hashicorp/go-multierror v1.1.1
+	github.com/drone/envsubst/v2 v2.0.0-20210615175204-7bf45dbf5372
+	github.com/hashicorp/go-multierror v1.0.0
 	github.com/joelanford/go-apidiff v0.1.0
 	github.com/mikefarah/yq/v4 v4.13.5
-	github.com/onsi/ginkgo v1.16.5
+	github.com/onsi/ginkgo v1.16.4
 	github.com/pkg/errors v0.9.1
 	github.com/sergi/go-diff v1.2.0 // indirect
-	golang.org/x/exp v0.0.0-20211029160041-3396431c207b // indirect
-	golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023
+	golang.org/x/exp v0.0.0-20210625193404-fa9d1d177d71 // indirect
+	golang.org/x/tools v0.1.5
 	gotest.tools/gotestsum v1.6.4
 	k8s.io/code-generator v0.22.2
 	k8s.io/klog/v2 v2.9.0
-	sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20211025141024-c73b143dc503
+	sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20210827150604-1730628f118b
 	sigs.k8s.io/controller-tools v0.7.0
-	sigs.k8s.io/kubebuilder/docs/book/utils v0.0.0-20211028165026-57688c578b5d
+	sigs.k8s.io/kubebuilder/docs/book/utils v0.0.0-20210702145813-742983631190
 )
diff --git a/hack/tools/go.sum b/hack/tools/go.sum
index 25e917543..527e0fa59 100644
--- a/hack/tools/go.sum
+++ b/hack/tools/go.sum
@@ -139,8 +139,8 @@ github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8
 github.com/dnephin/pflag v1.0.7 h1:oxONGlWxhmUct0YzKTgrpQv9AUA1wtPBn7zuSjJqptk=
 github.com/dnephin/pflag v1.0.7/go.mod h1:uxE91IoWURlOiTUIA8Mq5ZZkAv3dPUfZNaT80Zm7OQE=
 github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
-github.com/drone/envsubst/v2 v2.0.0-20210730161058-179042472c46 h1:7QPwrLT79GlD5sizHf27aoY2RTvw62mO6x7mxkScNk0=
-github.com/drone/envsubst/v2 v2.0.0-20210730161058-179042472c46/go.mod h1:esf2rsHFNlZlxsqsZDojNBcnNs5REqIvRrWRHqX0vEU=
+github.com/drone/envsubst/v2 v2.0.0-20210615175204-7bf45dbf5372 h1:lMxlL2YBq247PkbbAhbcpEzDhqRp9IX6LSVy5WUz97s=
+github.com/drone/envsubst/v2 v2.0.0-20210615175204-7bf45dbf5372/go.mod h1:esf2rsHFNlZlxsqsZDojNBcnNs5REqIvRrWRHqX0vEU=
 github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
 github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
 github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
@@ -322,9 +322,8 @@ github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brv
 github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
 github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
 github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
+github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
 github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
-github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
-github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
 github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
 github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
 github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
@@ -456,9 +455,8 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
 github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
 github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
+github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
 github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
-github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
-github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
 github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
 github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
 github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
@@ -606,7 +604,6 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
 github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
-github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
 go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
 go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
 go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
@@ -672,9 +669,8 @@ golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8U
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g=
 golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
-golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
-golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -687,8 +683,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
 golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
-golang.org/x/exp v0.0.0-20211029160041-3396431c207b h1:58UzImHd/vC6WxTQm75bwlBAOU/jDjzIMHUGO8O65UM=
-golang.org/x/exp v0.0.0-20211029160041-3396431c207b/go.mod h1:OyI624f2tQ/aU3IMa7GB16Hk54CHURAfHfj6tMqtyhA=
+golang.org/x/exp v0.0.0-20210625193404-fa9d1d177d71 h1:j9CMOaHQ8BVtX7w3W1PpDn2ENQmYFgwyaewLqatSovY=
+golang.org/x/exp v0.0.0-20210625193404-fa9d1d177d71/go.mod h1:DVyR6MI7P4kEQgvZJSj1fQGrWIi2RzIrfYWycwheUAc=
 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -716,10 +712,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
 golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
-golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57 h1:LQmS1nU0twXLA96Kt7U9qtHJEbBk3z6Q0V4UXjZkpr4=
-golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -767,9 +761,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
 golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
 golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
 golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
+golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 h1:ADo5wSpq2gqaCGQWzk7S5vd//0iyyLeAratkEoG5dLE=
 golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY=
-golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -860,11 +853,9 @@ golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA=
 golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0=
-golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE=
@@ -876,9 +867,8 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
 golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
-golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
 golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -950,9 +940,8 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f
 golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
 golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
 golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA=
 golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
-golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023 h1:0c3L82FDQ5rt1bjTBlchS8t6RQ6299/+5bWMnRLh+uI=
-golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -1154,12 +1143,12 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8
 rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
 rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
 sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.22/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
-sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20211025141024-c73b143dc503 h1:t2jqjbep3XTlPSJfsjCkeSPJMs+QuL/VTyzAIN99zOw=
-sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20211025141024-c73b143dc503/go.mod h1:Fxb8+lsIhcPWKq89RReMSzjcv3COhP0D37vJplt4ABg=
+sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20210827150604-1730628f118b h1:DzEpvyjrou46yDaQ5/gACrHUMwT8howR0Pn/pFuVD3w=
+sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20210827150604-1730628f118b/go.mod h1:Fxb8+lsIhcPWKq89RReMSzjcv3COhP0D37vJplt4ABg=
 sigs.k8s.io/controller-tools v0.7.0 h1:iZIz1vEcavyEfxjcTLs1WH/MPf4vhPCtTKhoHqV8/G0=
 sigs.k8s.io/controller-tools v0.7.0/go.mod h1:bpBAo0VcSDDLuWt47evLhMLPxRPxMDInTEH/YbdeMK0=
-sigs.k8s.io/kubebuilder/docs/book/utils v0.0.0-20211028165026-57688c578b5d h1:KLiQzLW3RZJR19+j4pw2h5iioyAyqCkDBEAFdnGa3N8=
-sigs.k8s.io/kubebuilder/docs/book/utils v0.0.0-20211028165026-57688c578b5d/go.mod h1:NRdZafr4zSCseLQggdvIMXa7umxf+Q+PJzrj3wFwiGE=
+sigs.k8s.io/kubebuilder/docs/book/utils v0.0.0-20210702145813-742983631190 h1:y13LG4qWQA8VxwrrLWp458Gw8i9nfy1qImu8kW1jOkg=
+sigs.k8s.io/kubebuilder/docs/book/utils v0.0.0-20210702145813-742983631190/go.mod h1:NRdZafr4zSCseLQggdvIMXa7umxf+Q+PJzrj3wFwiGE=
 sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
 sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno=
 sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
diff --git a/hack/tools/mdbook/embed/embed.go b/hack/tools/mdbook/embed/embed.go
index 3d2cb89dd..f12203e22 100644
--- a/hack/tools/mdbook/embed/embed.go
+++ b/hack/tools/mdbook/embed/embed.go
@@ -1,4 +1,3 @@
-//go:build tools
 // +build tools
 
 /*
@@ -32,13 +31,10 @@ import (
 	"sigs.k8s.io/kubebuilder/docs/book/utils/plugin"
 )
 
-// Embed adds support to embed github release artifact links.
+// Embed.
 type Embed struct{}
 
-// SupportsOutput checks if the given plugin supports the given output format.
-func (Embed) SupportsOutput(_ string) bool { return true }
-
-// Process modifies the book in the input, which gets returned as the result of the plugin.
+func (_ Embed) SupportsOutput(_ string) bool { return true }
 func (l Embed) Process(input *plugin.Input) error {
 	return plugin.EachCommand(&input.Book, "embed-github", func(chapter *plugin.BookChapter, args string) (string, error) {
 		tags := reflect.StructTag(strings.TrimSpace(args))
diff --git a/hack/tools/mdbook/releaselink/releaselink.go b/hack/tools/mdbook/releaselink/releaselink.go
index 7310755a0..44da84349 100644
--- a/hack/tools/mdbook/releaselink/releaselink.go
+++ b/hack/tools/mdbook/releaselink/releaselink.go
@@ -1,4 +1,3 @@
-//go:build tools
 // +build tools
 
 /*
@@ -44,10 +43,7 @@ import (
 // By default pre-releases won't be included unless a `prereleases` parameter is set to `true`.
 type ReleaseLink struct{}
 
-// SupportsOutput checks if the given plugin supports the given output format.
-func (ReleaseLink) SupportsOutput(_ string) bool { return true }
-
-// Process modifies the book in the input, which gets returned as the result of the plugin.
+func (_ ReleaseLink) SupportsOutput(_ string) bool { return true }
 func (l ReleaseLink) Process(input *plugin.Input) error {
 	return plugin.EachCommand(&input.Book, "releaselink", func(chapter *plugin.BookChapter, args string) (string, error) {
 		tags := reflect.StructTag(strings.TrimSpace(args))
diff --git a/hack/tools/mdbook/tabulate/tabulate.go b/hack/tools/mdbook/tabulate/tabulate.go
index dece4ef2a..2ac838aaf 100644
--- a/hack/tools/mdbook/tabulate/tabulate.go
+++ b/hack/tools/mdbook/tabulate/tabulate.go
@@ -1,4 +1,3 @@
-//go:build tools
 // +build tools
 
 /*
@@ -29,13 +28,10 @@ import (
 	"sigs.k8s.io/kubebuilder/docs/book/utils/plugin"
 )
 
-// Tabulate adds support for switchable tabs in mdbook.
+// Tabulate.
 type Tabulate struct{}
 
-// SupportsOutput checks if the given plugin supports the given output format.
-func (Tabulate) SupportsOutput(_ string) bool { return true }
-
-// Process modifies the book in the input, which gets returned as the result of the plugin.
+func (_ Tabulate) SupportsOutput(_ string) bool { return true }
 func (l Tabulate) Process(input *plugin.Input) error {
 	if err := plugin.EachCommand(&input.Book, "tabs", func(chapter *plugin.BookChapter, args string) (string, error) {
 		var bld strings.Builder
@@ -46,14 +42,14 @@ func (l Tabulate) Process(input *plugin.Input) error {
 		bld.WriteString(groupName)
 		bld.WriteString(`" class="tabset">`)
 		for i, tabName := range strings.Split(tags.Get("tabs"), ",") {
-			groupTabID := fmt.Sprintf("%s-%s", groupName, tabName)
+			groupTabId := fmt.Sprintf("%s-%s", groupName, tabName)
 			checked := ""
 			if i == 0 {
 				checked = "checked"
 			}
 
-			bld.WriteString(fmt.Sprintf(`<input type="radio" name="%s" id="%s" aria-controls="%s" %s>`, groupName, groupTabID, groupTabID, checked))
-			bld.WriteString(fmt.Sprintf(`<label for="%s">%s</label>`, groupTabID, tabName))
+			bld.WriteString(fmt.Sprintf(`<input type="radio" name="%s" id="%s" aria-controls="%s" %s>`, groupName, groupTabId, groupTabId, checked))
+			bld.WriteString(fmt.Sprintf(`<label for="%s">%s</label>`, groupTabId, tabName))
 		}
 		bld.WriteString(`<div class="tab-panels">`)
 
diff --git a/hack/tools/release/notes.go b/hack/tools/release/notes.go
index f7b44e70a..940011117 100644
--- a/hack/tools/release/notes.go
+++ b/hack/tools/release/notes.go
@@ -1,4 +1,3 @@
-//go:build tools
 // +build tools
 
 /*
@@ -87,7 +86,7 @@ func firstCommit() string {
 
 func run() int {
 	lastTag := lastTag()
-	cmd := exec.Command("git", "rev-list", lastTag+"..HEAD", "--merges", "--pretty=format:%B") //nolint:gosec
+	cmd := exec.Command("git", "rev-list", lastTag+"..HEAD", "--merges", "--pretty=format:%B")
 
 	merges := map[string][]string{
 		features:      {},
@@ -157,7 +156,7 @@ func run() int {
 			continue
 		}
 		body = fmt.Sprintf("- %s", body)
-		_, _ = fmt.Sscanf(c.merge, "Merge pull request %s from %s", &prNumber, &fork)
+		fmt.Sscanf(c.merge, "Merge pull request %s from %s", &prNumber, &fork)
 		if key == documentation {
 			merges[key] = append(merges[key], prNumber)
 			continue
@@ -188,6 +187,7 @@ func run() int {
 			}
 			fmt.Println()
 		}
+
 	}
 
 	fmt.Println("")
diff --git a/hack/tools/tools.go b/hack/tools/tools.go
index 554a910ef..248cc707c 100644
--- a/hack/tools/tools.go
+++ b/hack/tools/tools.go
@@ -1,4 +1,3 @@
-//go:build tools
 // +build tools
 
 /*
diff --git a/internal/matchers/matchers.go b/internal/matchers/matchers.go
index 6d17630c1..9f0580c0a 100644
--- a/internal/matchers/matchers.go
+++ b/internal/matchers/matchers.go
@@ -22,7 +22,7 @@ import (
 	"fmt"
 	"reflect"
 
-	jsonpatch "github.com/evanphx/json-patch/v5"
+	jsonpatch "github.com/evanphx/json-patch"
 	"github.com/onsi/gomega/format"
 	"github.com/pkg/errors"
 	"k8s.io/apimachinery/pkg/runtime"
diff --git a/main.go b/main.go
index 80b6bf2b4..02545705f 100644
--- a/main.go
+++ b/main.go
@@ -25,7 +25,6 @@ import (
 	"os"
 	"time"
 
-	// +kubebuilder:scaffold:imports
 	"github.com/spf13/pflag"
 	corev1 "k8s.io/api/core/v1"
 	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
@@ -56,6 +55,7 @@ import (
 	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 	"sigs.k8s.io/controller-runtime/pkg/controller"
+	// +kubebuilder:scaffold:imports
 )
 
 var (
diff --git a/util/conditions/matchers.go b/util/conditions/matchers.go
index 0bfaadcaa..a2fd65174 100644
--- a/util/conditions/matchers.go
+++ b/util/conditions/matchers.go
@@ -21,6 +21,7 @@ import (
 
 	"github.com/onsi/gomega/format"
 	"github.com/onsi/gomega/types"
+
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
 )
 
diff --git a/util/container/image.go b/util/container/image.go
index fa1166759..91b32ce6c 100644
--- a/util/container/image.go
+++ b/util/container/image.go
@@ -18,15 +18,14 @@ limitations under the License.
 package container
 
 import (
+	"fmt"
+	"path"
+	"regexp"
 
 	//  Import the crypto sha256 algorithm for the docker image parser to work
 	_ "crypto/sha256"
-
 	//  Import the crypto/sha512 algorithm for the docker image parser to work with 384 and 512 sha hashes
 	_ "crypto/sha512"
-	"fmt"
-	"path"
-	"regexp"
 
 	"github.com/docker/distribution/reference"
 	"github.com/pkg/errors"
diff --git a/util/failuredomains/failure_domains.go b/util/failuredomains/failure_domains.go
index 7755c823b..005d2f36a 100644
--- a/util/failuredomains/failure_domains.go
+++ b/util/failuredomains/failure_domains.go
@@ -22,6 +22,7 @@ import (
 
 	"k8s.io/klog/v2/klogr"
 	"k8s.io/utils/pointer"
+
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
 	"sigs.k8s.io/cluster-api/util/collections"
 )
diff --git a/util/predicates/generic_predicates.go b/util/predicates/generic_predicates.go
index 0840e2be3..47e33b0ca 100644
--- a/util/predicates/generic_predicates.go
+++ b/util/predicates/generic_predicates.go
@@ -22,6 +22,7 @@ import (
 	"github.com/go-logr/logr"
 	"sigs.k8s.io/cluster-api/util/annotations"
 	"sigs.k8s.io/cluster-api/util/labels"
+
 	"sigs.k8s.io/controller-runtime/pkg/client"
 	"sigs.k8s.io/controller-runtime/pkg/event"
 	"sigs.k8s.io/controller-runtime/pkg/predicate"
diff --git a/webhooks/cluster.go b/webhooks/cluster.go
index 673b97f03..fdfa64a05 100644
--- a/webhooks/cluster.go
+++ b/webhooks/cluster.go
@@ -19,26 +19,20 @@ package webhooks
 import (
 	"context"
 	"fmt"
-	"strings"
 
-	"github.com/blang/semver"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	"k8s.io/apimachinery/pkg/runtime"
-	"k8s.io/apimachinery/pkg/util/sets"
-	"k8s.io/apimachinery/pkg/util/validation/field"
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
-	"sigs.k8s.io/cluster-api/feature"
-	"sigs.k8s.io/cluster-api/util/version"
 	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/webhook"
 )
 
 // SetupWebhookWithManager sets up Cluster webhooks.
-func (webhook *Cluster) SetupWebhookWithManager(mgr ctrl.Manager) error {
+func (c *Cluster) SetupWebhookWithManager(mgr ctrl.Manager) error {
 	return ctrl.NewWebhookManagedBy(mgr).
 		For(&clusterv1.Cluster{}).
-		WithDefaulter(webhook).
-		WithValidator(webhook).
+		WithDefaulter(c).
+		WithValidator(c).
 		Complete()
 }
 
@@ -52,42 +46,39 @@ var _ webhook.CustomDefaulter = &Cluster{}
 var _ webhook.CustomValidator = &Cluster{}
 
 // Default satisfies the defaulting webhook interface.
-func (webhook *Cluster) Default(_ context.Context, obj runtime.Object) error {
+func (c *Cluster) Default(_ context.Context, obj runtime.Object) error {
 	cluster, ok := obj.(*clusterv1.Cluster)
 	if !ok {
 		return apierrors.NewBadRequest(fmt.Sprintf("expected a Cluster but got a %T", obj))
 	}
 
-	if cluster.Spec.InfrastructureRef != nil && len(cluster.Spec.InfrastructureRef.Namespace) == 0 {
-		cluster.Spec.InfrastructureRef.Namespace = cluster.Namespace
-	}
-
-	if cluster.Spec.ControlPlaneRef != nil && len(cluster.Spec.ControlPlaneRef.Namespace) == 0 {
-		cluster.Spec.ControlPlaneRef.Namespace = cluster.Namespace
-	}
+	// Note: The code in Default is intentionally not duplicated to avoid that we accidentally
+	// implement new checks in the API package and forget to duplicate them to the webhook package.
+	// The idea is to add new defaulting which requires a reader in the webhook package.
+	// When we drop the method in the API package we must inline it here.
+	cluster.Default()
 
-	// If the Cluster uses a managed topology
-	if cluster.Spec.Topology != nil {
-		// tolerate version strings without a "v" prefix: prepend it if it's not there
-		if !strings.HasPrefix(cluster.Spec.Topology.Version, "v") {
-			cluster.Spec.Topology.Version = "v" + cluster.Spec.Topology.Version
-		}
-	}
 	return nil
 }
 
-// ValidateCreate implements webhook.CustomValidator so a webhook will be registered for the type.
-func (webhook *Cluster) ValidateCreate(_ context.Context, obj runtime.Object) error {
+// ValidateCreate implements webhook.Validator so a webhook will be registered for the type.
+func (c *Cluster) ValidateCreate(_ context.Context, obj runtime.Object) error {
 	cluster, ok := obj.(*clusterv1.Cluster)
 	if !ok {
 		return apierrors.NewBadRequest(fmt.Sprintf("expected a Cluster but got a %T", obj))
 	}
-	return webhook.validate(nil, cluster)
+
+	// Note: The code in ValidateCreate is intentionally not duplicated to avoid that we accidentally
+	// implement new checks in the API package and forget to duplicate them to the webhook package.
+	// The idea is to add new validation which requires a reader and Cluster variable/patch validation
+	// in the webhook package.
+	// When we drop the method in the API package we must inline it here.
+	return cluster.ValidateCreate()
 }
 
-// ValidateUpdate implements webhook.CustomValidator so a webhook will be registered for the type.
-func (webhook *Cluster) ValidateUpdate(_ context.Context, oldObj, newObj runtime.Object) error {
-	newCluster, ok := newObj.(*clusterv1.Cluster)
+// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type.
+func (c *Cluster) ValidateUpdate(_ context.Context, oldObj, newObj runtime.Object) error {
+	cluster, ok := newObj.(*clusterv1.Cluster)
 	if !ok {
 		return apierrors.NewBadRequest(fmt.Sprintf("expected a Cluster but got a %T", newObj))
 	}
@@ -95,154 +86,20 @@ func (webhook *Cluster) ValidateUpdate(_ context.Context, oldObj, newObj runtime
 	if !ok {
 		return apierrors.NewBadRequest(fmt.Sprintf("expected a Cluster but got a %T", oldObj))
 	}
-	return webhook.validate(oldCluster, newCluster)
-}
-
-// ValidateDelete implements webhook.CustomValidator so a webhook will be registered for the type.
-func (webhook *Cluster) ValidateDelete(_ context.Context, obj runtime.Object) error {
-	return nil
-}
-
-func (webhook *Cluster) validate(old, new *clusterv1.Cluster) error {
-	var allErrs field.ErrorList
-	if new.Spec.InfrastructureRef != nil && new.Spec.InfrastructureRef.Namespace != new.Namespace {
-		allErrs = append(
-			allErrs,
-			field.Invalid(
-				field.NewPath("spec", "infrastructureRef", "namespace"),
-				new.Spec.InfrastructureRef.Namespace,
-				"must match metadata.namespace",
-			),
-		)
-	}
-
-	if new.Spec.ControlPlaneRef != nil && new.Spec.ControlPlaneRef.Namespace != new.Namespace {
-		allErrs = append(
-			allErrs,
-			field.Invalid(
-				field.NewPath("spec", "controlPlaneRef", "namespace"),
-				new.Spec.ControlPlaneRef.Namespace,
-				"must match metadata.namespace",
-			),
-		)
-	}
-
-	// Validate the managed topology, if defined.
-	if new.Spec.Topology != nil {
-		if topologyErrs := webhook.validateTopology(old, new); len(topologyErrs) > 0 {
-			allErrs = append(allErrs, topologyErrs...)
-		}
-	}
 
-	if len(allErrs) == 0 {
-		return nil
-	}
-	return apierrors.NewInvalid(clusterv1.GroupVersion.WithKind("Cluster").GroupKind(), new.Name, allErrs)
+	// Note: The code in ValidateUpdate is intentionally not duplicated to avoid that we accidentally
+	// implement new checks in the API package and forget to duplicate them to the webhook package.
+	// The idea is to add new validation which requires a reader and Cluster variable/patch validation
+	// in the webhook package.
+	// When we drop the method in the API package we must inline it here.
+	return cluster.ValidateUpdate(oldCluster)
 }
 
-func (webhook *Cluster) validateTopology(old, new *clusterv1.Cluster) field.ErrorList {
-	// NOTE: ClusterClass and managed topologies are behind ClusterTopology feature gate flag; the web hook
-	// must prevent the usage of Cluster.Topology in case the feature flag is disabled.
-	if !feature.Gates.Enabled(feature.ClusterTopology) {
-		return field.ErrorList{
-			field.Forbidden(
-				field.NewPath("spec", "topology"),
-				"can be set only if the ClusterTopology feature flag is enabled",
-			),
-		}
-	}
-
-	var allErrs field.ErrorList
-
-	// class should be defined.
-	if len(new.Spec.Topology.Class) == 0 {
-		allErrs = append(
-			allErrs,
-			field.Invalid(
-				field.NewPath("spec", "topology", "class"),
-				new.Spec.Topology.Class,
-				"cannot be empty",
-			),
-		)
-	}
-
-	// version should be valid.
-	if !version.KubeSemver.MatchString(new.Spec.Topology.Version) {
-		allErrs = append(
-			allErrs,
-			field.Invalid(
-				field.NewPath("spec", "topology", "version"),
-				new.Spec.Topology.Version,
-				"must be a valid semantic version",
-			),
-		)
-	}
-
-	// MachineDeployment names must be unique.
-	if new.Spec.Topology.Workers != nil {
-		names := sets.String{}
-		for _, md := range new.Spec.Topology.Workers.MachineDeployments {
-			if names.Has(md.Name) {
-				allErrs = append(allErrs,
-					field.Invalid(
-						field.NewPath("spec", "topology", "workers", "machineDeployments"),
-						md,
-						fmt.Sprintf("MachineDeployment names should be unique. MachineDeployment with name %q is defined more than once.", md.Name),
-					),
-				)
-			}
-			names.Insert(md.Name)
-		}
-	}
-
-	if old != nil { // On update
-		// Class could not be mutated.
-		if new.Spec.Topology.Class != old.Spec.Topology.Class {
-			allErrs = append(
-				allErrs,
-				field.Invalid(
-					field.NewPath("spec", "topology", "class"),
-					new.Spec.Topology.Class,
-					"class cannot be changed",
-				),
-			)
-		}
-
-		// Version could only be increased.
-		inVersion, err := semver.ParseTolerant(new.Spec.Topology.Version)
-		if err != nil {
-			allErrs = append(
-				allErrs,
-				field.Invalid(
-					field.NewPath("spec", "topology", "version"),
-					new.Spec.Topology.Version,
-					"is not a valid version",
-				),
-			)
-		}
-		oldVersion, err := semver.ParseTolerant(old.Spec.Topology.Version)
-		if err != nil {
-			// NOTE: this should never happen. Nevertheless, handling this for extra caution.
-			allErrs = append(
-				allErrs,
-				field.Invalid(
-					field.NewPath("spec", "topology", "version"),
-					new.Spec.Topology.Class,
-					"cannot be compared with the old version",
-				),
-			)
-		}
-		if inVersion.NE(semver.Version{}) && oldVersion.NE(semver.Version{}) && version.Compare(inVersion, oldVersion, version.WithBuildTags()) == -1 {
-			allErrs = append(
-				allErrs,
-				field.Invalid(
-					field.NewPath("spec", "topology", "version"),
-					new.Spec.Topology.Version,
-					"cannot be decreased",
-				),
-			)
-		}
+// ValidateDelete implements webhook.Validator so a webhook will be registered for the type.
+func (c *Cluster) ValidateDelete(ctx context.Context, obj runtime.Object) error {
+	cluster, ok := obj.(*clusterv1.Cluster)
+	if !ok {
+		return apierrors.NewBadRequest(fmt.Sprintf("expected a Cluster but got a %T", obj))
 	}
-
-	return allErrs
+	return cluster.ValidateDelete()
 }
diff --git a/webhooks/clusterclass.go b/webhooks/clusterclass.go
index 046663b9c..f10dd5508 100644
--- a/webhooks/clusterclass.go
+++ b/webhooks/clusterclass.go
@@ -19,25 +19,19 @@ package webhooks
 import (
 	"context"
 	"fmt"
-	"strings"
 
-	corev1 "k8s.io/api/core/v1"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	"k8s.io/apimachinery/pkg/runtime"
-	"k8s.io/apimachinery/pkg/runtime/schema"
-	"k8s.io/apimachinery/pkg/util/sets"
-	"k8s.io/apimachinery/pkg/util/validation/field"
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
-	"sigs.k8s.io/cluster-api/feature"
 	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/webhook"
 )
 
-func (webhook *ClusterClass) SetupWebhookWithManager(mgr ctrl.Manager) error {
+func (c *ClusterClass) SetupWebhookWithManager(mgr ctrl.Manager) error {
 	return ctrl.NewWebhookManagedBy(mgr).
 		For(&clusterv1.ClusterClass{}).
-		WithDefaulter(webhook).
-		WithValidator(webhook).
+		WithDefaulter(c).
+		WithValidator(c).
 		Complete()
 }
 
@@ -51,44 +45,39 @@ var _ webhook.CustomDefaulter = &ClusterClass{}
 var _ webhook.CustomValidator = &ClusterClass{}
 
 // Default implements defaulting for ClusterClass create and update.
-func (webhook *ClusterClass) Default(_ context.Context, obj runtime.Object) error {
-	in, ok := obj.(*clusterv1.ClusterClass)
+func (c *ClusterClass) Default(_ context.Context, obj runtime.Object) error {
+	clusterClass, ok := obj.(*clusterv1.ClusterClass)
 	if !ok {
 		return apierrors.NewBadRequest(fmt.Sprintf("expected a ClusterClass but got a %T", obj))
 	}
-	// Default all namespaces in the references to the object namespace.
-	defaultNamespace(in.Spec.Infrastructure.Ref, in.Namespace)
-	defaultNamespace(in.Spec.ControlPlane.Ref, in.Namespace)
 
-	if in.Spec.ControlPlane.MachineInfrastructure != nil {
-		defaultNamespace(in.Spec.ControlPlane.MachineInfrastructure.Ref, in.Namespace)
-	}
+	// Note: The code in Default is intentionally not duplicated to avoid that we accidentally
+	// implement new checks in the API package and forget to duplicate them to the webhook package.
+	// The idea is to add new defaulting which requires a reader in the webhook package.
+	// When we drop the method in the API package we must inline it here.
+	clusterClass.Default()
 
-	for i := range in.Spec.Workers.MachineDeployments {
-		defaultNamespace(in.Spec.Workers.MachineDeployments[i].Template.Bootstrap.Ref, in.Namespace)
-		defaultNamespace(in.Spec.Workers.MachineDeployments[i].Template.Infrastructure.Ref, in.Namespace)
-	}
 	return nil
 }
 
-func defaultNamespace(ref *corev1.ObjectReference, namespace string) {
-	if ref != nil && len(ref.Namespace) == 0 {
-		ref.Namespace = namespace
-	}
-}
-
 // ValidateCreate implements validation for ClusterClass create.
-func (webhook *ClusterClass) ValidateCreate(_ context.Context, obj runtime.Object) error {
-	in, ok := obj.(*clusterv1.ClusterClass)
+func (c *ClusterClass) ValidateCreate(_ context.Context, obj runtime.Object) error {
+	clusterClass, ok := obj.(*clusterv1.ClusterClass)
 	if !ok {
 		return apierrors.NewBadRequest(fmt.Sprintf("expected a ClusterClass but got a %T", obj))
 	}
-	return webhook.validate(nil, in)
+
+	// Note: The code in ValidateCreate is intentionally not duplicated to avoid that we accidentally
+	// implement new checks in the API package and forget to duplicate them to the webhook package.
+	// The idea is to add new validation which requires a reader and ClusterClass variable/patch validation
+	// in the webhook package.
+	// When we drop the method in the API package we must inline it here.
+	return clusterClass.ValidateCreate()
 }
 
 // ValidateUpdate implements validation for ClusterClass update.
-func (webhook *ClusterClass) ValidateUpdate(_ context.Context, oldObj, newObj runtime.Object) error {
-	newClusterClass, ok := newObj.(*clusterv1.ClusterClass)
+func (c *ClusterClass) ValidateUpdate(_ context.Context, oldObj, newObj runtime.Object) error {
+	clusterClass, ok := newObj.(*clusterv1.ClusterClass)
 	if !ok {
 		return apierrors.NewBadRequest(fmt.Sprintf("expected a ClusterClass but got a %T", newObj))
 	}
@@ -96,286 +85,21 @@ func (webhook *ClusterClass) ValidateUpdate(_ context.Context, oldObj, newObj ru
 	if !ok {
 		return apierrors.NewBadRequest(fmt.Sprintf("expected a ClusterClass but got a %T", oldObj))
 	}
-	return webhook.validate(oldClusterClass, newClusterClass)
-}
-
-// ValidateDelete implements validation for ClusterClass delete.
-func (webhook *ClusterClass) ValidateDelete(ctx context.Context, obj runtime.Object) error {
-	return nil
-}
-
-func (webhook *ClusterClass) validate(old, in *clusterv1.ClusterClass) error {
-	// NOTE: ClusterClass and managed topologies are behind ClusterTopology feature gate flag; the web hook
-	// must prevent creating in objects in case the feature flag is disabled.
-	if !feature.Gates.Enabled(feature.ClusterTopology) {
-		return field.Forbidden(
-			field.NewPath("spec"),
-			"can be set only if the ClusterTopology feature flag is enabled",
-		)
-	}
-
-	var allErrs field.ErrorList
-
-	// Ensure all references are valid.
-	allErrs = append(allErrs, webhook.validateAllRefs(in)...)
-
-	// Ensure all MachineDeployment classes are unique.
-	allErrs = append(allErrs, webhook.validateUniqueClasses(in.Spec.Workers, field.NewPath("spec", "workers"))...)
-
-	// Ensure spec changes are compatible.
-	allErrs = append(allErrs, webhook.validateCompatibleSpecChanges(old, in)...)
-
-	if len(allErrs) > 0 {
-		return apierrors.NewInvalid(clusterv1.GroupVersion.WithKind("ClusterClass").GroupKind(), in.Name, allErrs)
-	}
-	return nil
-}
-
-func (webhook *ClusterClass) validateAllRefs(in *clusterv1.ClusterClass) field.ErrorList {
-	var allErrs field.ErrorList
-
-	allErrs = append(allErrs, webhook.validateTemplate(&in.Spec.Infrastructure, in.Namespace, field.NewPath("spec", "infrastructure"))...)
-	allErrs = append(allErrs, webhook.validateTemplate(&in.Spec.ControlPlane.LocalObjectTemplate, in.Namespace, field.NewPath("spec", "controlPlane"))...)
-	if in.Spec.ControlPlane.MachineInfrastructure != nil {
-		allErrs = append(allErrs, webhook.validateTemplate(in.Spec.ControlPlane.MachineInfrastructure, in.Namespace, field.NewPath("spec", "controlPlane", "machineInfrastructure"))...)
-	}
-
-	for i, class := range in.Spec.Workers.MachineDeployments {
-		allErrs = append(allErrs, webhook.validateTemplate(&class.Template.Bootstrap, in.Namespace, field.NewPath("spec", "workers", "machineDeployments").Index(i).Child("template", "bootstrap"))...)
-		allErrs = append(allErrs, webhook.validateTemplate(&class.Template.Infrastructure, in.Namespace, field.NewPath("spec", "workers", "machineDeployments").Index(i).Child("template", "infrastructure"))...)
-	}
-
-	return allErrs
-}
-
-func (webhook *ClusterClass) validateCompatibleSpecChanges(old, in *clusterv1.ClusterClass) field.ErrorList {
-	var allErrs field.ErrorList
-
-	// in case of create, no changes to verify
-	// return early.
-	if old == nil {
-		return nil
-	}
-
-	// Validate changes to MachineDeployments.
-	allErrs = append(allErrs, webhook.validateMachineDeploymentsCompatibleChanges(old, in)...)
-
-	// Validate InfrastructureClusterTemplate changes in a compatible way.
-	allErrs = append(allErrs, webhook.validateTemplatesAreCompatible(in.Spec.Infrastructure,
-		old.Spec.Infrastructure,
-		field.NewPath("spec", "infrastructure"),
-	)...)
-
-	// Validate control plane changes in a compatible way.
-	allErrs = append(allErrs, webhook.validateTemplatesAreCompatible(in.Spec.ControlPlane.LocalObjectTemplate,
-		old.Spec.ControlPlane.LocalObjectTemplate,
-		field.NewPath("spec", "controlPlane"),
-	)...)
-
-	if in.Spec.ControlPlane.MachineInfrastructure != nil && old.Spec.ControlPlane.MachineInfrastructure != nil {
-		allErrs = append(allErrs, webhook.validateTemplatesAreCompatible(
-			*old.Spec.ControlPlane.MachineInfrastructure,
-			*in.Spec.ControlPlane.MachineInfrastructure,
-			field.NewPath("spec", "controlPlane", "machineInfrastructure"),
-		)...)
-	}
 
-	return allErrs
+	// Note: The code in ValidateUpdate is intentionally not duplicated to avoid that we accidentally
+	// implement new checks in the API package and forget to duplicate them to the webhook package.
+	// The idea is to add new validation which requires a reader and ClusterClass variable/patch validation
+	// in the webhook package.
+	// When we drop the method in the API package we must inline it here.
+	return clusterClass.ValidateUpdate(oldClusterClass)
 }
 
-func (webhook *ClusterClass) validateMachineDeploymentsCompatibleChanges(old, in *clusterv1.ClusterClass) field.ErrorList {
-	var allErrs field.ErrorList
-
-	// Ensure no MachineDeployment class was removed.
-	classes := webhook.classNamesFromWorkerClass(in.Spec.Workers)
-	for _, oldClass := range old.Spec.Workers.MachineDeployments {
-		if !classes.Has(oldClass.Class) {
-			allErrs = append(allErrs,
-				field.Invalid(
-					field.NewPath("spec", "workers", "machineDeployments"),
-					in.Spec.Workers.MachineDeployments,
-					fmt.Sprintf("The %q MachineDeployment class can't be removed.", oldClass.Class),
-				),
-			)
-		}
-	}
-
-	// Ensure previous MachineDeployment class was modified in a compatible way.
-	for i, class := range in.Spec.Workers.MachineDeployments {
-		for _, oldClass := range old.Spec.Workers.MachineDeployments {
-			if class.Class == oldClass.Class {
-				// NOTE: class.Template.Metadata and class.Template.Bootstrap are allowed to change;
-				// class.Template.Bootstrap are ensured syntactically correct by validateAllRefs.
-
-				// Validates class.Template.Infrastructure template changes in a compatible way
-				allErrs = append(allErrs, webhook.validateTemplatesAreCompatible(
-					class.Template.Infrastructure,
-					oldClass.Template.Infrastructure,
-					field.NewPath("spec", "workers", "machineDeployments").Index(i).Child("template", "infrastructure"),
-				)...)
-			}
-		}
-	}
-
-	return allErrs
-}
-
-func (webhook *ClusterClass) validateTemplate(in *clusterv1.LocalObjectTemplate, namespace string, pathPrefix *field.Path) field.ErrorList {
-	var allErrs field.ErrorList
-
-	// check if ref is not nil.
-	if in.Ref == nil {
-		return field.ErrorList{field.Invalid(
-			pathPrefix.Child("ref"),
-			in.Ref.Name,
-			"cannot be nil",
-		)}
-	}
-
-	// check if a name is provided
-	if in.Ref.Name == "" {
-		allErrs = append(allErrs,
-			field.Invalid(
-				pathPrefix.Child("ref", "name"),
-				in.Ref.Name,
-				"cannot be empty",
-			),
-		)
-	}
-
-	// validate if namespace matches the provided namespace
-	if namespace != "" && in.Ref.Namespace != namespace {
-		allErrs = append(
-			allErrs,
-			field.Invalid(
-				pathPrefix.Child("ref", "namespace"),
-				in.Ref.Namespace,
-				fmt.Sprintf("must be '%s'", namespace),
-			),
-		)
-	}
-
-	// check if kind is a template
-	if len(in.Ref.Kind) <= len(clusterv1.TemplateSuffix) || !strings.HasSuffix(in.Ref.Kind, clusterv1.TemplateSuffix) {
-		allErrs = append(allErrs,
-			field.Invalid(
-				pathPrefix.Child("ref", "kind"),
-				in.Ref.Kind,
-				fmt.Sprintf("kind must be of form '<name>%s'", clusterv1.TemplateSuffix),
-			),
-		)
-	}
-
-	// check if apiVersion is valid
-	gv, err := schema.ParseGroupVersion(in.Ref.APIVersion)
-	if err != nil {
-		allErrs = append(allErrs,
-			field.Invalid(
-				pathPrefix.Child("ref", "apiVersion"),
-				in.Ref.APIVersion,
-				fmt.Sprintf("must be a valid apiVersion: %v", err),
-			),
-		)
-	}
-	if err == nil && gv.Empty() {
-		allErrs = append(allErrs,
-			field.Invalid(
-				pathPrefix.Child("ref", "apiVersion"),
-				in.Ref.APIVersion,
-				"value cannot be empty",
-			),
-		)
-	}
-
-	return allErrs
-}
-
-// validateTemplatesAreCompatible checks if a reference is compatible with the old one.
-// NOTE: this func assumes that validateTemplate() is called before, thus both ref are defined and syntactically valid;
-// also namespace are enforced to be the same of the ClusterClass.
-func (webhook *ClusterClass) validateTemplatesAreCompatible(old, in clusterv1.LocalObjectTemplate, pathPrefix *field.Path) field.ErrorList {
-	var allErrs field.ErrorList
-
-	// Check for nil Ref here to avoid panic.
-	if in.Ref == nil || old.Ref == nil {
-		return allErrs
-	}
-
-	// Ensure that the API Group and Kind does not change, while instead we allow version to change.
-	// TODO: In the future we might want to relax this requirement with some sort of opt-in behavior (e.g. annotation).
-
-	gv, err := schema.ParseGroupVersion(in.Ref.APIVersion)
-	if err != nil {
-		// NOTE this should never happen.
-		allErrs = append(allErrs,
-			field.Invalid(
-				pathPrefix.Child("ref", "apiVersion"),
-				in.Ref.APIVersion,
-				fmt.Sprintf("must be a valid apiVersion: %v", err),
-			),
-		)
-	}
-
-	oldGV, err := schema.ParseGroupVersion(old.Ref.APIVersion)
-	if err != nil {
-		// NOTE this should never happen.
-		allErrs = append(allErrs,
-			field.Invalid(
-				pathPrefix.Child("ref", "apiVersion"),
-				old.Ref.APIVersion,
-				fmt.Sprintf("must be a valid apiVersion: %v", err),
-			),
-		)
-	}
-
-	if gv.Group != oldGV.Group {
-		allErrs = append(allErrs,
-			field.Invalid(
-				pathPrefix.Child("ref", "apiVersion"),
-				in.Ref.APIVersion,
-				"apiGroup cannot be changed",
-			),
-		)
-	}
-
-	if in.Ref.Kind != old.Ref.Kind {
-		allErrs = append(allErrs,
-			field.Invalid(
-				pathPrefix.Child("ref", "kind"),
-				in.Ref.Kind,
-				"value cannot be changed",
-			),
-		)
-	}
-
-	return allErrs
-}
-
-// classNames returns the set of MachineDeployment class names.
-func (webhook *ClusterClass) classNamesFromWorkerClass(w clusterv1.WorkersClass) sets.String {
-	classes := sets.NewString()
-	for _, class := range w.MachineDeployments {
-		classes.Insert(class.Class)
-	}
-	return classes
-}
-
-func (webhook *ClusterClass) validateUniqueClasses(w clusterv1.WorkersClass, pathPrefix *field.Path) field.ErrorList {
-	var allErrs field.ErrorList
-
-	classes := sets.NewString()
-	for i, class := range w.MachineDeployments {
-		if classes.Has(class.Class) {
-			allErrs = append(allErrs,
-				field.Invalid(
-					pathPrefix.Child("machineDeployments").Index(i).Child("class"),
-					class.Class,
-					fmt.Sprintf("MachineDeployment class should be unique. MachineDeployment with class %q is defined more than once.", class.Class),
-				),
-			)
-		}
-		classes.Insert(class.Class)
+// ValidateDelete implements validation for ClusterClass delete.
+func (c *ClusterClass) ValidateDelete(ctx context.Context, obj runtime.Object) error {
+	clusterClass, ok := obj.(*clusterv1.ClusterClass)
+	if !ok {
+		return apierrors.NewBadRequest(fmt.Sprintf("expected a ClusterClass but got a %T", obj))
 	}
 
-	return allErrs
+	return clusterClass.ValidateDelete()
 }


Test patch:
diff --git a/api/v1alpha3/suite_test.go b/api/v1alpha3/suite_test.go
index d951964c2..56e6a5f10 100644
--- a/api/v1alpha3/suite_test.go
+++ b/api/v1alpha3/suite_test.go
@@ -20,11 +20,11 @@ import (
 	"os"
 	"testing"
 
-	// +kubebuilder:scaffold:imports
 	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 	"k8s.io/client-go/kubernetes/scheme"
 	"sigs.k8s.io/cluster-api/internal/envtest"
 	ctrl "sigs.k8s.io/controller-runtime"
+	// +kubebuilder:scaffold:imports
 )
 
 var (
diff --git a/api/v1alpha3/webhook_test.go b/api/v1alpha3/webhook_test.go
index 0cdc63a2a..66c2e3463 100644
--- a/api/v1alpha3/webhook_test.go
+++ b/api/v1alpha3/webhook_test.go
@@ -21,11 +21,13 @@ import (
 	"testing"
 
 	. "github.com/onsi/gomega"
+
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/utils/pointer"
-	"sigs.k8s.io/cluster-api/util"
 	"sigs.k8s.io/controller-runtime/pkg/client"
+
+	"sigs.k8s.io/cluster-api/util"
 )
 
 func TestClusterConversion(t *testing.T) {
diff --git a/api/v1beta1/clusterclass_webhook_test.go b/api/v1beta1/clusterclass_webhook_test.go
index 9eae8ac13..1cef05d83 100644
--- a/api/v1beta1/clusterclass_webhook_test.go
+++ b/api/v1beta1/clusterclass_webhook_test.go
@@ -24,6 +24,7 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	utilfeature "k8s.io/component-base/featuregate/testing"
 	"sigs.k8s.io/cluster-api/feature"
+
 	utildefaulting "sigs.k8s.io/cluster-api/util/defaulting"
 )
 
diff --git a/api/v1beta1/machine_webhook_test.go b/api/v1beta1/machine_webhook_test.go
index 5902d9d37..fd18f564e 100644
--- a/api/v1beta1/machine_webhook_test.go
+++ b/api/v1beta1/machine_webhook_test.go
@@ -20,10 +20,11 @@ import (
 	"testing"
 
 	. "github.com/onsi/gomega"
+	utildefaulting "sigs.k8s.io/cluster-api/util/defaulting"
+
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/utils/pointer"
-	utildefaulting "sigs.k8s.io/cluster-api/util/defaulting"
 )
 
 func TestMachineDefault(t *testing.T) {
diff --git a/api/v1beta1/machinedeployment_webhook_test.go b/api/v1beta1/machinedeployment_webhook_test.go
index 117089c67..f99773525 100644
--- a/api/v1beta1/machinedeployment_webhook_test.go
+++ b/api/v1beta1/machinedeployment_webhook_test.go
@@ -20,6 +20,7 @@ import (
 	"testing"
 
 	. "github.com/onsi/gomega"
+
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/util/intstr"
 	"k8s.io/utils/pointer"
diff --git a/api/v1beta1/machinehealthcheck_webhook_test.go b/api/v1beta1/machinehealthcheck_webhook_test.go
index bccaf306e..08e779cdd 100644
--- a/api/v1beta1/machinehealthcheck_webhook_test.go
+++ b/api/v1beta1/machinehealthcheck_webhook_test.go
@@ -21,6 +21,7 @@ import (
 	"time"
 
 	. "github.com/onsi/gomega"
+
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/util/intstr"
diff --git a/bootstrap/kubeadm/api/v1alpha3/suite_test.go b/bootstrap/kubeadm/api/v1alpha3/suite_test.go
index d951964c2..56e6a5f10 100644
--- a/bootstrap/kubeadm/api/v1alpha3/suite_test.go
+++ b/bootstrap/kubeadm/api/v1alpha3/suite_test.go
@@ -20,11 +20,11 @@ import (
 	"os"
 	"testing"
 
-	// +kubebuilder:scaffold:imports
 	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 	"k8s.io/client-go/kubernetes/scheme"
 	"sigs.k8s.io/cluster-api/internal/envtest"
 	ctrl "sigs.k8s.io/controller-runtime"
+	// +kubebuilder:scaffold:imports
 )
 
 var (
diff --git a/bootstrap/kubeadm/api/v1alpha3/webhook_test.go b/bootstrap/kubeadm/api/v1alpha3/webhook_test.go
index 4926497ec..47eb155a6 100644
--- a/bootstrap/kubeadm/api/v1alpha3/webhook_test.go
+++ b/bootstrap/kubeadm/api/v1alpha3/webhook_test.go
@@ -21,6 +21,7 @@ import (
 	"testing"
 
 	. "github.com/onsi/gomega"
+
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/utils/pointer"
 	"sigs.k8s.io/cluster-api/bootstrap/kubeadm/types/upstreamv1beta1"
diff --git a/bootstrap/kubeadm/api/v1alpha4/kubeadm_types_test.go b/bootstrap/kubeadm/api/v1alpha4/kubeadm_types_test.go
index b0c9a858e..012a26e2f 100644
--- a/bootstrap/kubeadm/api/v1alpha4/kubeadm_types_test.go
+++ b/bootstrap/kubeadm/api/v1alpha4/kubeadm_types_test.go
@@ -22,6 +22,7 @@ import (
 	"testing"
 
 	. "github.com/onsi/gomega"
+
 	"github.com/pkg/errors"
 )
 
diff --git a/bootstrap/kubeadm/api/v1beta1/kubeadm_types_test.go b/bootstrap/kubeadm/api/v1beta1/kubeadm_types_test.go
index 732215d1e..50cb79095 100644
--- a/bootstrap/kubeadm/api/v1beta1/kubeadm_types_test.go
+++ b/bootstrap/kubeadm/api/v1beta1/kubeadm_types_test.go
@@ -22,6 +22,7 @@ import (
 	"testing"
 
 	. "github.com/onsi/gomega"
+
 	"github.com/pkg/errors"
 )
 
diff --git a/bootstrap/kubeadm/api/v1beta1/kubeadmconfig_types_test.go b/bootstrap/kubeadm/api/v1beta1/kubeadmconfig_types_test.go
index 1df1908fe..038ae2f9d 100644
--- a/bootstrap/kubeadm/api/v1beta1/kubeadmconfig_types_test.go
+++ b/bootstrap/kubeadm/api/v1beta1/kubeadmconfig_types_test.go
@@ -20,6 +20,7 @@ import (
 	"testing"
 
 	. "github.com/onsi/gomega"
+
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
diff --git a/bootstrap/kubeadm/internal/cloudinit/cloudinit_test.go b/bootstrap/kubeadm/internal/cloudinit/cloudinit_test.go
index 96c5814ad..43717c307 100644
--- a/bootstrap/kubeadm/internal/cloudinit/cloudinit_test.go
+++ b/bootstrap/kubeadm/internal/cloudinit/cloudinit_test.go
@@ -20,6 +20,7 @@ import (
 	"testing"
 
 	. "github.com/onsi/gomega"
+
 	"k8s.io/utils/pointer"
 	bootstrapv1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1beta1"
 	"sigs.k8s.io/cluster-api/util/certs"
diff --git a/bootstrap/kubeadm/internal/controllers/kubeadmconfig_controller_test.go b/bootstrap/kubeadm/internal/controllers/kubeadmconfig_controller_test.go
index 88c9a92f7..2f4f82f6e 100644
--- a/bootstrap/kubeadm/internal/controllers/kubeadmconfig_controller_test.go
+++ b/bootstrap/kubeadm/internal/controllers/kubeadmconfig_controller_test.go
@@ -30,6 +30,11 @@ import (
 	"k8s.io/apimachinery/pkg/types"
 	bootstrapapi "k8s.io/cluster-bootstrap/token/api"
 	"k8s.io/utils/pointer"
+	ctrl "sigs.k8s.io/controller-runtime"
+	"sigs.k8s.io/controller-runtime/pkg/client"
+	"sigs.k8s.io/controller-runtime/pkg/client/fake"
+	"sigs.k8s.io/controller-runtime/pkg/reconcile"
+
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
 	bootstrapv1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1beta1"
 	fakeremote "sigs.k8s.io/cluster-api/controllers/remote/fake"
@@ -39,10 +44,6 @@ import (
 	"sigs.k8s.io/cluster-api/util/conditions"
 	"sigs.k8s.io/cluster-api/util/patch"
 	"sigs.k8s.io/cluster-api/util/secret"
-	ctrl "sigs.k8s.io/controller-runtime"
-	"sigs.k8s.io/controller-runtime/pkg/client"
-	"sigs.k8s.io/controller-runtime/pkg/client/fake"
-	"sigs.k8s.io/controller-runtime/pkg/reconcile"
 )
 
 // MachineToBootstrapMapFunc return kubeadm bootstrap configref name when configref exists.
diff --git a/bootstrap/kubeadm/internal/controllers/suite_test.go b/bootstrap/kubeadm/internal/controllers/suite_test.go
index 552b23c38..ce9081315 100644
--- a/bootstrap/kubeadm/internal/controllers/suite_test.go
+++ b/bootstrap/kubeadm/internal/controllers/suite_test.go
@@ -20,9 +20,9 @@ import (
 	"os"
 	"testing"
 
-	// +kubebuilder:scaffold:imports
 	"sigs.k8s.io/cluster-api/internal/envtest"
 	ctrl "sigs.k8s.io/controller-runtime"
+	// +kubebuilder:scaffold:imports
 )
 
 var (
diff --git a/bootstrap/kubeadm/internal/locking/control_plane_init_mutex_test.go b/bootstrap/kubeadm/internal/locking/control_plane_init_mutex_test.go
index e61352a94..53a30c04a 100644
--- a/bootstrap/kubeadm/internal/locking/control_plane_init_mutex_test.go
+++ b/bootstrap/kubeadm/internal/locking/control_plane_init_mutex_test.go
@@ -23,8 +23,9 @@ import (
 	"fmt"
 	"testing"
 
-	"github.com/go-logr/logr"
 	. "github.com/onsi/gomega"
+
+	"github.com/go-logr/logr"
 	corev1 "k8s.io/api/core/v1"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
diff --git a/bootstrap/kubeadm/types/upstreamv1beta1/bootstraptokenstring_test.go b/bootstrap/kubeadm/types/upstreamv1beta1/bootstraptokenstring_test.go
index 3a723e74f..1beb31526 100644
--- a/bootstrap/kubeadm/types/upstreamv1beta1/bootstraptokenstring_test.go
+++ b/bootstrap/kubeadm/types/upstreamv1beta1/bootstraptokenstring_test.go
@@ -22,6 +22,7 @@ import (
 	"testing"
 
 	. "github.com/onsi/gomega"
+
 	"github.com/pkg/errors"
 )
 
diff --git a/bootstrap/kubeadm/types/upstreamv1beta2/bootstraptokenstring_test.go b/bootstrap/kubeadm/types/upstreamv1beta2/bootstraptokenstring_test.go
index 56f1e1d38..45de0b2bc 100644
--- a/bootstrap/kubeadm/types/upstreamv1beta2/bootstraptokenstring_test.go
+++ b/bootstrap/kubeadm/types/upstreamv1beta2/bootstraptokenstring_test.go
@@ -22,6 +22,7 @@ import (
 	"testing"
 
 	. "github.com/onsi/gomega"
+
 	"github.com/pkg/errors"
 )
 
diff --git a/bootstrap/kubeadm/types/upstreamv1beta3/conversion_test.go b/bootstrap/kubeadm/types/upstreamv1beta3/conversion_test.go
index 93bb3735f..10ae782ac 100644
--- a/bootstrap/kubeadm/types/upstreamv1beta3/conversion_test.go
+++ b/bootstrap/kubeadm/types/upstreamv1beta3/conversion_test.go
@@ -22,8 +22,9 @@ import (
 	fuzz "github.com/google/gofuzz"
 	. "github.com/onsi/gomega"
 	"k8s.io/apimachinery/pkg/api/apitesting/fuzzer"
-	"k8s.io/apimachinery/pkg/runtime"
 	runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
+
+	"k8s.io/apimachinery/pkg/runtime"
 	"sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1beta1"
 	utilconversion "sigs.k8s.io/cluster-api/util/conversion"
 )
diff --git a/bootstrap/util/configowner_test.go b/bootstrap/util/configowner_test.go
index d3768b6d8..44e49c44e 100644
--- a/bootstrap/util/configowner_test.go
+++ b/bootstrap/util/configowner_test.go
@@ -20,6 +20,7 @@ import (
 	"testing"
 
 	. "github.com/onsi/gomega"
+
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/utils/pointer"
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
diff --git a/bootstrap/util/suite_test.go b/bootstrap/util/suite_test.go
index b3401b32b..1b611e6b4 100644
--- a/bootstrap/util/suite_test.go
+++ b/bootstrap/util/suite_test.go
@@ -20,9 +20,9 @@ import (
 	"os"
 	"testing"
 
-	// +kubebuilder:scaffold:imports
 	"sigs.k8s.io/cluster-api/internal/envtest"
 	ctrl "sigs.k8s.io/controller-runtime"
+	// +kubebuilder:scaffold:imports
 )
 
 var (
diff --git a/cmd/clusterctl/client/client_test.go b/cmd/clusterctl/client/client_test.go
index 7f59273f6..bfdbfc465 100644
--- a/cmd/clusterctl/client/client_test.go
+++ b/cmd/clusterctl/client/client_test.go
@@ -25,6 +25,7 @@ import (
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/runtime/serializer"
 	"k8s.io/apimachinery/pkg/util/wait"
+
 	clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
 	"sigs.k8s.io/cluster-api/cmd/clusterctl/client/cluster"
 	"sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
diff --git a/cmd/clusterctl/client/cluster/components_test.go b/cmd/clusterctl/client/cluster/components_test.go
index 3e27c054b..7b7bd5056 100644
--- a/cmd/clusterctl/client/cluster/components_test.go
+++ b/cmd/clusterctl/client/cluster/components_test.go
@@ -21,7 +21,10 @@ import (
 	"testing"
 
 	"github.com/google/go-cmp/cmp"
+	"sigs.k8s.io/cluster-api/cmd/clusterctl/internal/scheme"
+
 	. "github.com/onsi/gomega"
+
 	corev1 "k8s.io/api/core/v1"
 	rbacv1 "k8s.io/api/rbac/v1"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -29,7 +32,6 @@ import (
 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
 	clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
-	"sigs.k8s.io/cluster-api/cmd/clusterctl/internal/scheme"
 	"sigs.k8s.io/cluster-api/cmd/clusterctl/internal/test"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 )
diff --git a/cmd/clusterctl/client/cluster/installer_test.go b/cmd/clusterctl/client/cluster/installer_test.go
index 86889adda..a4e43c2a4 100644
--- a/cmd/clusterctl/client/cluster/installer_test.go
+++ b/cmd/clusterctl/client/cluster/installer_test.go
@@ -20,6 +20,7 @@ import (
 	"testing"
 
 	. "github.com/onsi/gomega"
+
 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
 	clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
 	"sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
diff --git a/cmd/clusterctl/client/cluster/mover_test.go b/cmd/clusterctl/client/cluster/mover_test.go
index 7c7f74959..88ce00bcf 100644
--- a/cmd/clusterctl/client/cluster/mover_test.go
+++ b/cmd/clusterctl/client/cluster/mover_test.go
@@ -571,7 +571,7 @@ func Test_objectMover_backupTargetObject(t *testing.T) {
 				}
 
 				path := filepath.Join(dir, expectedFilename)
-				fileContents, err := os.ReadFile(path) //nolint:gosec
+				fileContents, err := os.ReadFile(path)
 				if err != nil {
 					g.Expect(err).NotTo(HaveOccurred())
 					return
@@ -901,12 +901,8 @@ func Test_objectMover_restore(t *testing.T) {
 				g.Expect(graph.addRestoredObj(&objs[i])).NotTo(HaveOccurred())
 			}
 
-			// restore works on the target cluster which does not yet have objs to discover
-			// instead set the owners and tenants correctly on object graph like how ObjectMover.Restore does
-			// https://github.com/kubernetes-sigs/cluster-api/blob/main/cmd/clusterctl/client/cluster/mover.go#L129-L132
-			graph.setSoftOwnership()
-			graph.setTenants()
-			graph.checkVirtualNode()
+			// trigger discovery the content of the source cluster
+			g.Expect(graph.Discovery("")).To(Succeed())
 
 			err = mover.restore(graph, toProxy)
 			if tt.wantErr {
diff --git a/cmd/clusterctl/client/cluster/template_test.go b/cmd/clusterctl/client/cluster/template_test.go
index 9daefd056..79e3ea88d 100644
--- a/cmd/clusterctl/client/cluster/template_test.go
+++ b/cmd/clusterctl/client/cluster/template_test.go
@@ -25,8 +25,9 @@ import (
 	"path/filepath"
 	"testing"
 
-	"github.com/google/go-github/v33/github"
 	. "github.com/onsi/gomega"
+
+	"github.com/google/go-github/v33/github"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
diff --git a/cmd/clusterctl/client/cluster/upgrader_test.go b/cmd/clusterctl/client/cluster/upgrader_test.go
index 16d51963b..f8c357489 100644
--- a/cmd/clusterctl/client/cluster/upgrader_test.go
+++ b/cmd/clusterctl/client/cluster/upgrader_test.go
@@ -21,6 +21,7 @@ import (
 
 	"github.com/google/go-cmp/cmp"
 	. "github.com/onsi/gomega"
+
 	clusterv1v1alpha3 "sigs.k8s.io/cluster-api/api/v1alpha3"
 	clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
 	"sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
diff --git a/cmd/clusterctl/client/clusterclass_test.go b/cmd/clusterctl/client/clusterclass_test.go
index 3be255b6a..172655bfc 100644
--- a/cmd/clusterctl/client/clusterclass_test.go
+++ b/cmd/clusterctl/client/clusterclass_test.go
@@ -22,6 +22,7 @@ import (
 
 	. "github.com/onsi/gomega"
 	"github.com/onsi/gomega/types"
+
 	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
diff --git a/cmd/clusterctl/client/config/cert_manager_client_test.go b/cmd/clusterctl/client/config/cert_manager_client_test.go
index 11f7404b5..0f0d5e8f1 100644
--- a/cmd/clusterctl/client/config/cert_manager_client_test.go
+++ b/cmd/clusterctl/client/config/cert_manager_client_test.go
@@ -20,6 +20,7 @@ import (
 	"testing"
 
 	. "github.com/onsi/gomega"
+
 	"sigs.k8s.io/cluster-api/cmd/clusterctl/internal/test"
 )
 
diff --git a/cmd/clusterctl/client/config/imagemeta_client_test.go b/cmd/clusterctl/client/config/imagemeta_client_test.go
index c18ee93f5..be5c7bbf7 100644
--- a/cmd/clusterctl/client/config/imagemeta_client_test.go
+++ b/cmd/clusterctl/client/config/imagemeta_client_test.go
@@ -21,6 +21,7 @@ import (
 	"testing"
 
 	. "github.com/onsi/gomega"
+
 	"sigs.k8s.io/cluster-api/cmd/clusterctl/internal/test"
 )
 
diff --git a/cmd/clusterctl/client/config/providers_client_test.go b/cmd/clusterctl/client/config/providers_client_test.go
index 6f4777337..1b5d0f3e3 100644
--- a/cmd/clusterctl/client/config/providers_client_test.go
+++ b/cmd/clusterctl/client/config/providers_client_test.go
@@ -22,6 +22,7 @@ import (
 	"testing"
 
 	. "github.com/onsi/gomega"
+
 	clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
 	"sigs.k8s.io/cluster-api/cmd/clusterctl/internal/test"
 )
diff --git a/cmd/clusterctl/client/config/reader_memory_test.go b/cmd/clusterctl/client/config/reader_memory_test.go
index f62ba83e1..0ea0232a5 100644
--- a/cmd/clusterctl/client/config/reader_memory_test.go
+++ b/cmd/clusterctl/client/config/reader_memory_test.go
@@ -20,6 +20,7 @@ import (
 	"testing"
 
 	. "github.com/onsi/gomega"
+
 	"sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
 )
 
diff --git a/cmd/clusterctl/client/config/variables_client_test.go b/cmd/clusterctl/client/config/variables_client_test.go
index e2c5d2ed3..e7fe36efb 100644
--- a/cmd/clusterctl/client/config/variables_client_test.go
+++ b/cmd/clusterctl/client/config/variables_client_test.go
@@ -20,6 +20,7 @@ import (
 	"testing"
 
 	. "github.com/onsi/gomega"
+
 	"sigs.k8s.io/cluster-api/cmd/clusterctl/internal/test"
 )
 
diff --git a/cmd/clusterctl/client/config_test.go b/cmd/clusterctl/client/config_test.go
index dc2312724..bb836d58d 100644
--- a/cmd/clusterctl/client/config_test.go
+++ b/cmd/clusterctl/client/config_test.go
@@ -28,6 +28,7 @@ import (
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/utils/pointer"
+
 	clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
 	"sigs.k8s.io/cluster-api/cmd/clusterctl/client/cluster"
 	"sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
@@ -64,7 +65,6 @@ func Test_clusterctlClient_GetProvidersConfig(t *testing.T) {
 				config.TalosControlPlaneProviderName,
 				config.AWSProviderName,
 				config.AzureProviderName,
-				config.BYOHProviderName,
 				config.DOProviderName,
 				config.DockerProviderName,
 				config.GCPProviderName,
@@ -96,7 +96,6 @@ func Test_clusterctlClient_GetProvidersConfig(t *testing.T) {
 				config.TalosControlPlaneProviderName,
 				config.AWSProviderName,
 				config.AzureProviderName,
-				config.BYOHProviderName,
 				config.DOProviderName,
 				config.DockerProviderName,
 				config.GCPProviderName,
diff --git a/cmd/clusterctl/client/init_test.go b/cmd/clusterctl/client/init_test.go
index 49e193668..9ce56187e 100644
--- a/cmd/clusterctl/client/init_test.go
+++ b/cmd/clusterctl/client/init_test.go
@@ -22,6 +22,7 @@ import (
 
 	. "github.com/onsi/gomega"
 	"github.com/pkg/errors"
+
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
 	clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
 	"sigs.k8s.io/cluster-api/cmd/clusterctl/client/cluster"
diff --git a/cmd/clusterctl/client/repository/client_test.go b/cmd/clusterctl/client/repository/client_test.go
index 84842c9ed..97316a154 100644
--- a/cmd/clusterctl/client/repository/client_test.go
+++ b/cmd/clusterctl/client/repository/client_test.go
@@ -21,6 +21,7 @@ import (
 	"testing"
 
 	. "github.com/onsi/gomega"
+
 	clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
 	"sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
 	yaml "sigs.k8s.io/cluster-api/cmd/clusterctl/client/yamlprocessor"
diff --git a/cmd/clusterctl/client/repository/clusterclass_client_test.go b/cmd/clusterctl/client/repository/clusterclass_client_test.go
index 717d572e1..096721d04 100644
--- a/cmd/clusterctl/client/repository/clusterclass_client_test.go
+++ b/cmd/clusterctl/client/repository/clusterclass_client_test.go
@@ -22,6 +22,7 @@ import (
 
 	. "github.com/onsi/gomega"
 	"github.com/pkg/errors"
+
 	clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
 	"sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
 	yaml "sigs.k8s.io/cluster-api/cmd/clusterctl/client/yamlprocessor"
diff --git a/cmd/clusterctl/client/repository/components_client_test.go b/cmd/clusterctl/client/repository/components_client_test.go
index 96b265dfc..4ac5ab34b 100644
--- a/cmd/clusterctl/client/repository/components_client_test.go
+++ b/cmd/clusterctl/client/repository/components_client_test.go
@@ -22,6 +22,7 @@ import (
 
 	. "github.com/onsi/gomega"
 	"github.com/pkg/errors"
+
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
 	clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
 	"sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
diff --git a/cmd/clusterctl/client/repository/components_test.go b/cmd/clusterctl/client/repository/components_test.go
index 96ce1eab2..8fb9fee2d 100644
--- a/cmd/clusterctl/client/repository/components_test.go
+++ b/cmd/clusterctl/client/repository/components_test.go
@@ -20,6 +20,7 @@ import (
 	"testing"
 
 	. "github.com/onsi/gomega"
+
 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
 	clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
diff --git a/cmd/clusterctl/client/repository/metadata_client_test.go b/cmd/clusterctl/client/repository/metadata_client_test.go
index a67172dec..0f8635d88 100644
--- a/cmd/clusterctl/client/repository/metadata_client_test.go
+++ b/cmd/clusterctl/client/repository/metadata_client_test.go
@@ -20,6 +20,7 @@ import (
 	"testing"
 
 	. "github.com/onsi/gomega"
+
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
 	"sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
diff --git a/cmd/clusterctl/client/repository/repository_github_test.go b/cmd/clusterctl/client/repository/repository_github_test.go
index 160bc12af..4570875a0 100644
--- a/cmd/clusterctl/client/repository/repository_github_test.go
+++ b/cmd/clusterctl/client/repository/repository_github_test.go
@@ -21,8 +21,9 @@ import (
 	"net/http"
 	"testing"
 
-	"github.com/google/go-github/v33/github"
 	. "github.com/onsi/gomega"
+
+	"github.com/google/go-github/v33/github"
 	"k8s.io/utils/pointer"
 	clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
 	"sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
diff --git a/cmd/clusterctl/client/repository/repository_local_test.go b/cmd/clusterctl/client/repository/repository_local_test.go
index 3c268b000..18f41b6ca 100644
--- a/cmd/clusterctl/client/repository/repository_local_test.go
+++ b/cmd/clusterctl/client/repository/repository_local_test.go
@@ -22,6 +22,7 @@ import (
 	"testing"
 
 	. "github.com/onsi/gomega"
+
 	clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
 	"sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
 	"sigs.k8s.io/cluster-api/cmd/clusterctl/internal/test"
diff --git a/cmd/clusterctl/client/repository/template_client_test.go b/cmd/clusterctl/client/repository/template_client_test.go
index c1f9286f7..30a54b673 100644
--- a/cmd/clusterctl/client/repository/template_client_test.go
+++ b/cmd/clusterctl/client/repository/template_client_test.go
@@ -22,6 +22,7 @@ import (
 
 	. "github.com/onsi/gomega"
 	"github.com/pkg/errors"
+
 	clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
 	"sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
 	yaml "sigs.k8s.io/cluster-api/cmd/clusterctl/client/yamlprocessor"
diff --git a/cmd/clusterctl/client/repository/template_test.go b/cmd/clusterctl/client/repository/template_test.go
index 0735c29f1..46685a658 100644
--- a/cmd/clusterctl/client/repository/template_test.go
+++ b/cmd/clusterctl/client/repository/template_test.go
@@ -21,6 +21,7 @@ import (
 	"testing"
 
 	. "github.com/onsi/gomega"
+
 	"sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
 	yaml "sigs.k8s.io/cluster-api/cmd/clusterctl/client/yamlprocessor"
 	"sigs.k8s.io/cluster-api/cmd/clusterctl/internal/test"
diff --git a/cmd/clusterctl/client/upgrade_test.go b/cmd/clusterctl/client/upgrade_test.go
index 1afc31bb7..34f18b123 100644
--- a/cmd/clusterctl/client/upgrade_test.go
+++ b/cmd/clusterctl/client/upgrade_test.go
@@ -22,6 +22,7 @@ import (
 
 	"github.com/google/go-cmp/cmp"
 	. "github.com/onsi/gomega"
+
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
 	clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
diff --git a/cmd/clusterctl/cmd/config_repositories_test.go b/cmd/clusterctl/cmd/config_repositories_test.go
index 669300f58..ff980c5e8 100644
--- a/cmd/clusterctl/cmd/config_repositories_test.go
+++ b/cmd/clusterctl/cmd/config_repositories_test.go
@@ -111,7 +111,6 @@ nested              ControlPlaneProvider     https://github.com/kubernetes-sigs/
 talos               ControlPlaneProvider     https://github.com/talos-systems/cluster-api-control-plane-provider-talos/releases/latest/   control-plane-components.yaml
 aws                 InfrastructureProvider                                                                                                my-aws-infrastructure-components.yaml
 azure               InfrastructureProvider   https://github.com/kubernetes-sigs/cluster-api-provider-azure/releases/latest/               infrastructure-components.yaml
-byoh                InfrastructureProvider   https://github.com/vmware-tanzu/cluster-api-provider-bringyourownhost/releases/latest/       infrastructure-components.yaml
 digitalocean        InfrastructureProvider   https://github.com/kubernetes-sigs/cluster-api-provider-digitalocean/releases/latest/        infrastructure-components.yaml
 docker              InfrastructureProvider   https://github.com/kubernetes-sigs/cluster-api/releases/latest/                              infrastructure-components-development.yaml
 gcp                 InfrastructureProvider   https://github.com/kubernetes-sigs/cluster-api-provider-gcp/releases/latest/                 infrastructure-components.yaml
@@ -169,10 +168,6 @@ var expectedOutputYaml = `- File: core_components.yaml
   Name: azure
   ProviderType: InfrastructureProvider
   URL: https://github.com/kubernetes-sigs/cluster-api-provider-azure/releases/latest/
-- File: infrastructure-components.yaml
-  Name: byoh
-  ProviderType: InfrastructureProvider
-  URL: https://github.com/vmware-tanzu/cluster-api-provider-bringyourownhost/releases/latest/
 - File: infrastructure-components.yaml
   Name: digitalocean
   ProviderType: InfrastructureProvider
diff --git a/cmd/clusterctl/cmd/describe_cluster_test.go b/cmd/clusterctl/cmd/describe_cluster_test.go
index 311a21ea1..0932c3c14 100644
--- a/cmd/clusterctl/cmd/describe_cluster_test.go
+++ b/cmd/clusterctl/cmd/describe_cluster_test.go
@@ -21,14 +21,15 @@ import (
 	"strings"
 	"testing"
 
-	"github.com/fatih/color"
 	"github.com/gosuri/uitable"
 	. "github.com/onsi/gomega"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/types"
+	"sigs.k8s.io/cluster-api/util/conditions"
+
+	"github.com/fatih/color"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
 	"sigs.k8s.io/cluster-api/cmd/clusterctl/client/tree"
-	"sigs.k8s.io/cluster-api/util/conditions"
 	ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
 )
 
diff --git a/cmd/clusterctl/cmd/version_checker_test.go b/cmd/clusterctl/cmd/version_checker_test.go
index 48dd1e2da..b97da8732 100644
--- a/cmd/clusterctl/cmd/version_checker_test.go
+++ b/cmd/clusterctl/cmd/version_checker_test.go
@@ -280,7 +280,7 @@ func TestVersionChecker_WriteStateFile(t *testing.T) {
 	g.Expect(err).ToNot(HaveOccurred())
 	// ensure that the state file has been created
 	g.Expect(tmpVersionFile).Should(BeARegularFile())
-	fb, err := os.ReadFile(tmpVersionFile) //nolint:gosec
+	fb, err := os.ReadFile(tmpVersionFile)
 	g.Expect(err).ToNot(HaveOccurred())
 	var actualVersionState VersionState
 	g.Expect(yaml.Unmarshal(fb, &actualVersionState)).To(Succeed())
diff --git a/cmd/clusterctl/internal/util/objs_test.go b/cmd/clusterctl/internal/util/objs_test.go
index 783133bdd..f2f6ba3d1 100644
--- a/cmd/clusterctl/internal/util/objs_test.go
+++ b/cmd/clusterctl/internal/util/objs_test.go
@@ -21,6 +21,7 @@ import (
 	"testing"
 
 	. "github.com/onsi/gomega"
+
 	appsv1 "k8s.io/api/apps/v1"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
diff --git a/cmd/clusterctl/log/logger_test.go b/cmd/clusterctl/log/logger_test.go
index 4cfee268c..cfe578c08 100644
--- a/cmd/clusterctl/log/logger_test.go
+++ b/cmd/clusterctl/log/logger_test.go
@@ -20,6 +20,7 @@ import (
 	"testing"
 
 	. "github.com/onsi/gomega"
+
 	"github.com/pkg/errors"
 )
 
diff --git a/controllers/cluster_controller_test.go b/controllers/cluster_controller_test.go
index 6f5e8d710..2dd3199a3 100644
--- a/controllers/cluster_controller_test.go
+++ b/controllers/cluster_controller_test.go
@@ -23,15 +23,16 @@ import (
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/utils/pointer"
+	ctrl "sigs.k8s.io/controller-runtime"
+	"sigs.k8s.io/controller-runtime/pkg/client"
+	"sigs.k8s.io/controller-runtime/pkg/client/fake"
+
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
 	expv1 "sigs.k8s.io/cluster-api/exp/api/v1beta1"
 	"sigs.k8s.io/cluster-api/feature"
 	"sigs.k8s.io/cluster-api/util"
 	"sigs.k8s.io/cluster-api/util/conditions"
 	"sigs.k8s.io/cluster-api/util/patch"
-	ctrl "sigs.k8s.io/controller-runtime"
-	"sigs.k8s.io/controller-runtime/pkg/client"
-	"sigs.k8s.io/controller-runtime/pkg/client/fake"
 )
 
 const (
diff --git a/controllers/external/util_test.go b/controllers/external/util_test.go
index f5dddf338..8a61a3d24 100644
--- a/controllers/external/util_test.go
+++ b/controllers/external/util_test.go
@@ -20,6 +20,7 @@ import (
 	"testing"
 
 	. "github.com/onsi/gomega"
+
 	"github.com/pkg/errors"
 	corev1 "k8s.io/api/core/v1"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
diff --git a/controllers/machine_controller_test.go b/controllers/machine_controller_test.go
index f30f0e469..645be1fcb 100644
--- a/controllers/machine_controller_test.go
+++ b/controllers/machine_controller_test.go
@@ -27,17 +27,18 @@ import (
 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
 	"k8s.io/client-go/kubernetes/scheme"
 	"k8s.io/utils/pointer"
+	ctrl "sigs.k8s.io/controller-runtime"
+	"sigs.k8s.io/controller-runtime/pkg/client"
+	"sigs.k8s.io/controller-runtime/pkg/client/fake"
+	"sigs.k8s.io/controller-runtime/pkg/log"
+	"sigs.k8s.io/controller-runtime/pkg/reconcile"
+
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
 	"sigs.k8s.io/cluster-api/controllers/remote"
 	"sigs.k8s.io/cluster-api/internal/builder"
 	"sigs.k8s.io/cluster-api/util"
 	"sigs.k8s.io/cluster-api/util/conditions"
 	"sigs.k8s.io/cluster-api/util/patch"
-	ctrl "sigs.k8s.io/controller-runtime"
-	"sigs.k8s.io/controller-runtime/pkg/client"
-	"sigs.k8s.io/controller-runtime/pkg/client/fake"
-	"sigs.k8s.io/controller-runtime/pkg/log"
-	"sigs.k8s.io/controller-runtime/pkg/reconcile"
 )
 
 func TestWatches(t *testing.T) {
diff --git a/controllers/noderefutil/util_test.go b/controllers/noderefutil/util_test.go
index a071e27ef..5e4efba7e 100644
--- a/controllers/noderefutil/util_test.go
+++ b/controllers/noderefutil/util_test.go
@@ -21,6 +21,7 @@ import (
 	"time"
 
 	. "github.com/onsi/gomega"
+
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
diff --git a/controllers/remote/cluster_test.go b/controllers/remote/cluster_test.go
index eb51cc01c..7e57878cf 100644
--- a/controllers/remote/cluster_test.go
+++ b/controllers/remote/cluster_test.go
@@ -21,12 +21,14 @@ import (
 	"time"
 
 	. "github.com/onsi/gomega"
+
 	corev1 "k8s.io/api/core/v1"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"sigs.k8s.io/cluster-api/util/secret"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 	"sigs.k8s.io/controller-runtime/pkg/client/fake"
+
+	"sigs.k8s.io/cluster-api/util/secret"
 )
 
 var (
diff --git a/controllers/remote/suite_test.go b/controllers/remote/suite_test.go
index 792af78fa..8aaa94f71 100644
--- a/controllers/remote/suite_test.go
+++ b/controllers/remote/suite_test.go
@@ -21,9 +21,9 @@ import (
 	"testing"
 	"time"
 
-	// +kubebuilder:scaffold:imports
 	"sigs.k8s.io/cluster-api/internal/envtest"
 	ctrl "sigs.k8s.io/controller-runtime"
+	// +kubebuilder:scaffold:imports
 )
 
 const (
diff --git a/controllers/suite_test.go b/controllers/suite_test.go
index 22471f8bc..a501eec06 100644
--- a/controllers/suite_test.go
+++ b/controllers/suite_test.go
@@ -23,7 +23,6 @@ import (
 	"testing"
 	"time"
 
-	// +kubebuilder:scaffold:imports
 	. "github.com/onsi/gomega"
 	"github.com/onsi/gomega/types"
 	"github.com/pkg/errors"
@@ -38,6 +37,7 @@ import (
 	"sigs.k8s.io/cluster-api/internal/envtest"
 	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/controller"
+	// +kubebuilder:scaffold:imports
 )
 
 const (
diff --git a/controlplane/kubeadm/api/v1alpha3/conversion_test.go b/controlplane/kubeadm/api/v1alpha3/conversion_test.go
index 8c8e8756f..4136db0f8 100644
--- a/controlplane/kubeadm/api/v1alpha3/conversion_test.go
+++ b/controlplane/kubeadm/api/v1alpha3/conversion_test.go
@@ -21,6 +21,7 @@ import (
 
 	fuzz "github.com/google/gofuzz"
 	"k8s.io/apimachinery/pkg/api/apitesting/fuzzer"
+
 	runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
 	cabpkv1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1beta1"
 	"sigs.k8s.io/cluster-api/bootstrap/kubeadm/types/upstreamv1beta1"
diff --git a/controlplane/kubeadm/api/v1alpha3/suite_test.go b/controlplane/kubeadm/api/v1alpha3/suite_test.go
index d951964c2..56e6a5f10 100644
--- a/controlplane/kubeadm/api/v1alpha3/suite_test.go
+++ b/controlplane/kubeadm/api/v1alpha3/suite_test.go
@@ -20,11 +20,11 @@ import (
 	"os"
 	"testing"
 
-	// +kubebuilder:scaffold:imports
 	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 	"k8s.io/client-go/kubernetes/scheme"
 	"sigs.k8s.io/cluster-api/internal/envtest"
 	ctrl "sigs.k8s.io/controller-runtime"
+	// +kubebuilder:scaffold:imports
 )
 
 var (
diff --git a/controlplane/kubeadm/api/v1alpha3/webhook_test.go b/controlplane/kubeadm/api/v1alpha3/webhook_test.go
index deb6f5faf..97b714e20 100644
--- a/controlplane/kubeadm/api/v1alpha3/webhook_test.go
+++ b/controlplane/kubeadm/api/v1alpha3/webhook_test.go
@@ -21,13 +21,15 @@ import (
 	"testing"
 
 	. "github.com/onsi/gomega"
+
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/utils/pointer"
+	"sigs.k8s.io/controller-runtime/pkg/client"
+
 	cabpkv1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1alpha3"
 	"sigs.k8s.io/cluster-api/bootstrap/kubeadm/types/upstreamv1beta1"
 	"sigs.k8s.io/cluster-api/util"
-	"sigs.k8s.io/controller-runtime/pkg/client"
 )
 
 func TestKubeadmControlPlaneConversion(t *testing.T) {
diff --git a/controlplane/kubeadm/api/v1alpha4/conversion_test.go b/controlplane/kubeadm/api/v1alpha4/conversion_test.go
index c37ccf78f..c72668fcd 100644
--- a/controlplane/kubeadm/api/v1alpha4/conversion_test.go
+++ b/controlplane/kubeadm/api/v1alpha4/conversion_test.go
@@ -21,6 +21,7 @@ import (
 
 	fuzz "github.com/google/gofuzz"
 	"k8s.io/apimachinery/pkg/api/apitesting/fuzzer"
+
 	runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
 	cabpkv1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1beta1"
 	"sigs.k8s.io/cluster-api/bootstrap/kubeadm/types/upstreamv1beta1"
diff --git a/controlplane/kubeadm/controllers/scale_test.go b/controlplane/kubeadm/controllers/scale_test.go
index d5f55a3d7..722aedc17 100644
--- a/controlplane/kubeadm/controllers/scale_test.go
+++ b/controlplane/kubeadm/controllers/scale_test.go
@@ -22,15 +22,17 @@ import (
 	"testing"
 	"time"
 
+	"sigs.k8s.io/cluster-api/util/collections"
+
 	. "github.com/onsi/gomega"
+	"sigs.k8s.io/cluster-api/util/conditions"
+
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/client-go/tools/record"
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
 	bootstrapv1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1beta1"
 	controlplanev1 "sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1beta1"
 	"sigs.k8s.io/cluster-api/controlplane/kubeadm/internal"
-	"sigs.k8s.io/cluster-api/util/collections"
-	"sigs.k8s.io/cluster-api/util/conditions"
 	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 )
diff --git a/controlplane/kubeadm/controllers/status_test.go b/controlplane/kubeadm/controllers/status_test.go
index 357660f4f..ad10771af 100644
--- a/controlplane/kubeadm/controllers/status_test.go
+++ b/controlplane/kubeadm/controllers/status_test.go
@@ -21,6 +21,7 @@ import (
 	"testing"
 
 	. "github.com/onsi/gomega"
+
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/client-go/tools/record"
diff --git a/controlplane/kubeadm/controllers/suite_test.go b/controlplane/kubeadm/controllers/suite_test.go
index 60ad47aea..b9200178b 100644
--- a/controlplane/kubeadm/controllers/suite_test.go
+++ b/controlplane/kubeadm/controllers/suite_test.go
@@ -20,11 +20,11 @@ import (
 	"os"
 	"testing"
 
-	// +kubebuilder:scaffold:imports
 	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"sigs.k8s.io/cluster-api/internal/envtest"
 	ctrl "sigs.k8s.io/controller-runtime"
+	// +kubebuilder:scaffold:imports
 )
 
 var (
diff --git a/controlplane/kubeadm/controllers/upgrade_test.go b/controlplane/kubeadm/controllers/upgrade_test.go
index 20ac721bd..8d08e7782 100644
--- a/controlplane/kubeadm/controllers/upgrade_test.go
+++ b/controlplane/kubeadm/controllers/upgrade_test.go
@@ -21,7 +21,10 @@ import (
 	"fmt"
 	"testing"
 
+	"sigs.k8s.io/cluster-api/util/collections"
+
 	. "github.com/onsi/gomega"
+
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/client-go/tools/record"
@@ -29,7 +32,6 @@ import (
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
 	bootstrapv1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1beta1"
 	"sigs.k8s.io/cluster-api/controlplane/kubeadm/internal"
-	"sigs.k8s.io/cluster-api/util/collections"
 	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 )
diff --git a/controlplane/kubeadm/internal/control_plane_test.go b/controlplane/kubeadm/internal/control_plane_test.go
index 8fa9eb997..5dd3069fb 100644
--- a/controlplane/kubeadm/internal/control_plane_test.go
+++ b/controlplane/kubeadm/internal/control_plane_test.go
@@ -19,7 +19,10 @@ package internal
 import (
 	"testing"
 
+	"sigs.k8s.io/cluster-api/util/collections"
+
 	. "github.com/onsi/gomega"
+
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/types"
@@ -27,7 +30,6 @@ import (
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
 	bootstrapv1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1beta1"
 	controlplanev1 "sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1beta1"
-	"sigs.k8s.io/cluster-api/util/collections"
 	"sigs.k8s.io/cluster-api/util/conditions"
 )
 
diff --git a/controlplane/kubeadm/internal/etcd/etcd_test.go b/controlplane/kubeadm/internal/etcd/etcd_test.go
index f9ac6e846..1d0a62078 100644
--- a/controlplane/kubeadm/internal/etcd/etcd_test.go
+++ b/controlplane/kubeadm/internal/etcd/etcd_test.go
@@ -20,6 +20,7 @@ import (
 	"testing"
 
 	. "github.com/onsi/gomega"
+
 	"github.com/pkg/errors"
 	"go.etcd.io/etcd/api/v3/etcdserverpb"
 	clientv3 "go.etcd.io/etcd/client/v3"
diff --git a/controlplane/kubeadm/internal/etcd_client_generator_test.go b/controlplane/kubeadm/internal/etcd_client_generator_test.go
index 290634b35..7931d0187 100644
--- a/controlplane/kubeadm/internal/etcd_client_generator_test.go
+++ b/controlplane/kubeadm/internal/etcd_client_generator_test.go
@@ -24,9 +24,12 @@ import (
 	"testing"
 
 	. "github.com/onsi/gomega"
+
 	"go.etcd.io/etcd/api/v3/etcdserverpb"
 	clientv3 "go.etcd.io/etcd/client/v3"
+
 	"k8s.io/client-go/rest"
+
 	"sigs.k8s.io/cluster-api/controlplane/kubeadm/internal/etcd"
 	etcdfake "sigs.k8s.io/cluster-api/controlplane/kubeadm/internal/etcd/fake"
 )
diff --git a/controlplane/kubeadm/internal/workload_cluster_conditions_test.go b/controlplane/kubeadm/internal/workload_cluster_conditions_test.go
index 7be1050a9..3e3fb7f3b 100644
--- a/controlplane/kubeadm/internal/workload_cluster_conditions_test.go
+++ b/controlplane/kubeadm/internal/workload_cluster_conditions_test.go
@@ -21,6 +21,7 @@ import (
 
 	. "github.com/onsi/gomega"
 	"github.com/pkg/errors"
+
 	pb "go.etcd.io/etcd/api/v3/etcdserverpb"
 	clientv3 "go.etcd.io/etcd/client/v3"
 	corev1 "k8s.io/api/core/v1"
diff --git a/controlplane/kubeadm/internal/workload_cluster_rbac_test.go b/controlplane/kubeadm/internal/workload_cluster_rbac_test.go
index 9154384ff..855a345f2 100644
--- a/controlplane/kubeadm/internal/workload_cluster_rbac_test.go
+++ b/controlplane/kubeadm/internal/workload_cluster_rbac_test.go
@@ -20,8 +20,9 @@ import (
 	"errors"
 	"testing"
 
-	"github.com/blang/semver"
 	. "github.com/onsi/gomega"
+
+	"github.com/blang/semver"
 	rbacv1 "k8s.io/api/rbac/v1"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	"k8s.io/apimachinery/pkg/runtime/schema"
diff --git a/exp/addons/api/v1alpha3/clusterresourcesetbinding_types_test.go b/exp/addons/api/v1alpha3/clusterresourcesetbinding_types_test.go
index 64f2afa96..1391548f5 100644
--- a/exp/addons/api/v1alpha3/clusterresourcesetbinding_types_test.go
+++ b/exp/addons/api/v1alpha3/clusterresourcesetbinding_types_test.go
@@ -22,6 +22,7 @@ import (
 	"time"
 
 	. "github.com/onsi/gomega"
+
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
diff --git a/exp/addons/api/v1alpha3/suite_test.go b/exp/addons/api/v1alpha3/suite_test.go
index d951964c2..56e6a5f10 100644
--- a/exp/addons/api/v1alpha3/suite_test.go
+++ b/exp/addons/api/v1alpha3/suite_test.go
@@ -20,11 +20,11 @@ import (
 	"os"
 	"testing"
 
-	// +kubebuilder:scaffold:imports
 	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 	"k8s.io/client-go/kubernetes/scheme"
 	"sigs.k8s.io/cluster-api/internal/envtest"
 	ctrl "sigs.k8s.io/controller-runtime"
+	// +kubebuilder:scaffold:imports
 )
 
 var (
diff --git a/exp/addons/api/v1alpha3/webhook_test.go b/exp/addons/api/v1alpha3/webhook_test.go
index 537b5204c..72c344124 100644
--- a/exp/addons/api/v1alpha3/webhook_test.go
+++ b/exp/addons/api/v1alpha3/webhook_test.go
@@ -23,6 +23,7 @@ import (
 
 	. "github.com/onsi/gomega"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
 	"sigs.k8s.io/cluster-api/util"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 )
diff --git a/exp/addons/api/v1alpha4/clusterresourcesetbinding_types_test.go b/exp/addons/api/v1alpha4/clusterresourcesetbinding_types_test.go
index 24ce2bd3a..ceefafaf6 100644
--- a/exp/addons/api/v1alpha4/clusterresourcesetbinding_types_test.go
+++ b/exp/addons/api/v1alpha4/clusterresourcesetbinding_types_test.go
@@ -22,6 +22,7 @@ import (
 	"time"
 
 	. "github.com/onsi/gomega"
+
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
diff --git a/exp/addons/api/v1beta1/clusterresourceset_webhook_test.go b/exp/addons/api/v1beta1/clusterresourceset_webhook_test.go
index eeba6b8e3..cfb168844 100644
--- a/exp/addons/api/v1beta1/clusterresourceset_webhook_test.go
+++ b/exp/addons/api/v1beta1/clusterresourceset_webhook_test.go
@@ -20,6 +20,7 @@ import (
 	"testing"
 
 	. "github.com/onsi/gomega"
+
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	utildefaulting "sigs.k8s.io/cluster-api/util/defaulting"
 )
diff --git a/exp/addons/api/v1beta1/clusterresourcesetbinding_types_test.go b/exp/addons/api/v1beta1/clusterresourcesetbinding_types_test.go
index 5c59e40f5..51be63303 100644
--- a/exp/addons/api/v1beta1/clusterresourcesetbinding_types_test.go
+++ b/exp/addons/api/v1beta1/clusterresourcesetbinding_types_test.go
@@ -22,6 +22,7 @@ import (
 	"time"
 
 	. "github.com/onsi/gomega"
+
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
diff --git a/exp/addons/controllers/clusterresourceset_controller_test.go b/exp/addons/controllers/clusterresourceset_controller_test.go
index 655f83c5d..3d77b4c66 100644
--- a/exp/addons/controllers/clusterresourceset_controller_test.go
+++ b/exp/addons/controllers/clusterresourceset_controller_test.go
@@ -23,6 +23,7 @@ import (
 
 	. "github.com/onsi/gomega"
 	"github.com/pkg/errors"
+
 	corev1 "k8s.io/api/core/v1"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
diff --git a/exp/addons/controllers/clusterresourceset_helpers_test.go b/exp/addons/controllers/clusterresourceset_helpers_test.go
index b9c756ceb..8e78b5f9a 100644
--- a/exp/addons/controllers/clusterresourceset_helpers_test.go
+++ b/exp/addons/controllers/clusterresourceset_helpers_test.go
@@ -22,6 +22,7 @@ import (
 	"time"
 
 	. "github.com/onsi/gomega"
+
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
diff --git a/exp/addons/controllers/suite_test.go b/exp/addons/controllers/suite_test.go
index c2696d06e..e37190d19 100644
--- a/exp/addons/controllers/suite_test.go
+++ b/exp/addons/controllers/suite_test.go
@@ -22,7 +22,6 @@ import (
 	"os"
 	"testing"
 
-	// +kubebuilder:scaffold:imports
 	corev1 "k8s.io/api/core/v1"
 	"sigs.k8s.io/cluster-api/api/v1beta1/index"
 	"sigs.k8s.io/cluster-api/controllers/remote"
@@ -31,6 +30,7 @@ import (
 	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 	"sigs.k8s.io/controller-runtime/pkg/controller"
+	// +kubebuilder:scaffold:imports
 )
 
 var (
diff --git a/exp/api/v1alpha3/suite_test.go b/exp/api/v1alpha3/suite_test.go
index d951964c2..56e6a5f10 100644
--- a/exp/api/v1alpha3/suite_test.go
+++ b/exp/api/v1alpha3/suite_test.go
@@ -20,11 +20,11 @@ import (
 	"os"
 	"testing"
 
-	// +kubebuilder:scaffold:imports
 	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 	"k8s.io/client-go/kubernetes/scheme"
 	"sigs.k8s.io/cluster-api/internal/envtest"
 	ctrl "sigs.k8s.io/controller-runtime"
+	// +kubebuilder:scaffold:imports
 )
 
 var (
diff --git a/exp/api/v1alpha3/webhook_test.go b/exp/api/v1alpha3/webhook_test.go
index afc793cb3..02a2b1e18 100644
--- a/exp/api/v1alpha3/webhook_test.go
+++ b/exp/api/v1alpha3/webhook_test.go
@@ -24,6 +24,7 @@ import (
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/utils/pointer"
+
 	clusterv1alpha3 "sigs.k8s.io/cluster-api/api/v1alpha3"
 	"sigs.k8s.io/cluster-api/util"
 	"sigs.k8s.io/controller-runtime/pkg/client"
diff --git a/exp/api/v1beta1/machinepool_webhook_test.go b/exp/api/v1beta1/machinepool_webhook_test.go
index b751b6438..103767829 100644
--- a/exp/api/v1beta1/machinepool_webhook_test.go
+++ b/exp/api/v1beta1/machinepool_webhook_test.go
@@ -20,6 +20,7 @@ import (
 	"testing"
 
 	. "github.com/onsi/gomega"
+
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/utils/pointer"
diff --git a/exp/controllers/machinepool_controller_noderef_test.go b/exp/controllers/machinepool_controller_noderef_test.go
index 0bfcb75fc..22a3d1187 100644
--- a/exp/controllers/machinepool_controller_noderef_test.go
+++ b/exp/controllers/machinepool_controller_noderef_test.go
@@ -20,6 +20,7 @@ import (
 	"testing"
 
 	. "github.com/onsi/gomega"
+
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/client-go/tools/record"
diff --git a/exp/controllers/machinepool_controller_phases_test.go b/exp/controllers/machinepool_controller_phases_test.go
index a1ec4eb55..cc05c2b1e 100644
--- a/exp/controllers/machinepool_controller_phases_test.go
+++ b/exp/controllers/machinepool_controller_phases_test.go
@@ -21,6 +21,7 @@ import (
 	"time"
 
 	. "github.com/onsi/gomega"
+
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
diff --git a/exp/controllers/machinepool_controller_test.go b/exp/controllers/machinepool_controller_test.go
index 6f3ef53aa..39ab6e6b0 100644
--- a/exp/controllers/machinepool_controller_test.go
+++ b/exp/controllers/machinepool_controller_test.go
@@ -20,6 +20,7 @@ import (
 	"testing"
 
 	. "github.com/onsi/gomega"
+
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
diff --git a/exp/controllers/suite_test.go b/exp/controllers/suite_test.go
index d9c19c681..a70f23142 100644
--- a/exp/controllers/suite_test.go
+++ b/exp/controllers/suite_test.go
@@ -22,11 +22,11 @@ import (
 	"os"
 	"testing"
 
-	// +kubebuilder:scaffold:imports
 	"sigs.k8s.io/cluster-api/api/v1beta1/index"
 	"sigs.k8s.io/cluster-api/internal/envtest"
 	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/controller"
+	// +kubebuilder:scaffold:imports
 )
 
 var (
diff --git a/internal/envtest/webhooks.go b/internal/envtest/webhooks.go
index 785e03932..c7ab03c61 100644
--- a/internal/envtest/webhooks.go
+++ b/internal/envtest/webhooks.go
@@ -45,7 +45,7 @@ func initWebhookInstallOptions() envtest.WebhookInstallOptions {
 	// Get the root of the current file to use in CRD paths.
 	_, filename, _, _ := goruntime.Caller(0) //nolint
 	root := path.Join(path.Dir(filename), "..", "..")
-	configyamlFile, err := os.ReadFile(filepath.Join(root, "config", "webhook", "manifests.yaml")) //nolint:gosec
+	configyamlFile, err := os.ReadFile(filepath.Join(root, "config", "webhook", "manifests.yaml"))
 	if err != nil {
 		klog.Fatalf("Failed to read core webhook configuration file: %v ", err)
 	}
@@ -58,7 +58,7 @@ func initWebhookInstallOptions() envtest.WebhookInstallOptions {
 		klog.Fatalf("Failed to append core controller webhook config: %v", err)
 	}
 
-	bootstrapyamlFile, err := os.ReadFile(filepath.Join(root, "bootstrap", "kubeadm", "config", "webhook", "manifests.yaml")) //nolint:gosec
+	bootstrapyamlFile, err := os.ReadFile(filepath.Join(root, "bootstrap", "kubeadm", "config", "webhook", "manifests.yaml"))
 	if err != nil {
 		klog.Fatalf("Failed to get bootstrap yaml file: %v", err)
 	}
@@ -67,7 +67,7 @@ func initWebhookInstallOptions() envtest.WebhookInstallOptions {
 	if err != nil {
 		klog.Fatalf("Failed to append bootstrap controller webhook config: %v", err)
 	}
-	controlplaneyamlFile, err := os.ReadFile(filepath.Join(root, "controlplane", "kubeadm", "config", "webhook", "manifests.yaml")) //nolint:Gosec
+	controlplaneyamlFile, err := os.ReadFile(filepath.Join(root, "controlplane", "kubeadm", "config", "webhook", "manifests.yaml"))
 	if err != nil {
 		klog.Fatalf(" Failed to get controlplane yaml file err: %v", err)
 	}
diff --git a/test/e2e/cluster_upgrade.go b/test/e2e/cluster_upgrade.go
index fbc4f99b5..d8a8aacfc 100644
--- a/test/e2e/cluster_upgrade.go
+++ b/test/e2e/cluster_upgrade.go
@@ -24,6 +24,7 @@ import (
 
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/gomega"
+
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/utils/pointer"
 	"sigs.k8s.io/cluster-api/test/framework"
diff --git a/test/e2e/cluster_upgrade_test.go b/test/e2e/cluster_upgrade_test.go
index 62615280a..ae53fed76 100644
--- a/test/e2e/cluster_upgrade_test.go
+++ b/test/e2e/cluster_upgrade_test.go
@@ -1,4 +1,3 @@
-//go:build e2e
 // +build e2e
 
 /*
diff --git a/test/e2e/clusterctl_upgrade_test.go b/test/e2e/clusterctl_upgrade_test.go
index 78bfa6d88..d4ba26d68 100644
--- a/test/e2e/clusterctl_upgrade_test.go
+++ b/test/e2e/clusterctl_upgrade_test.go
@@ -1,4 +1,3 @@
-//go:build e2e
 // +build e2e
 
 /*
diff --git a/test/e2e/common.go b/test/e2e/common.go
index 2568e58d5..ca37c6d8a 100644
--- a/test/e2e/common.go
+++ b/test/e2e/common.go
@@ -25,6 +25,7 @@ import (
 	. "github.com/onsi/ginkgo"
 	"github.com/onsi/gomega/types"
 	corev1 "k8s.io/api/core/v1"
+
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
 	"sigs.k8s.io/cluster-api/test/framework"
 	"sigs.k8s.io/cluster-api/util"
diff --git a/test/e2e/data/infrastructure-docker/v1beta1/clusterclass-quick-start.yaml b/test/e2e/data/infrastructure-docker/v1beta1/clusterclass-quick-start.yaml
index 72a65fe7c..ac86a8d11 100644
--- a/test/e2e/data/infrastructure-docker/v1beta1/clusterclass-quick-start.yaml
+++ b/test/e2e/data/infrastructure-docker/v1beta1/clusterclass-quick-start.yaml
@@ -103,7 +103,10 @@ metadata:
   name: quick-start-docker-worker-machinetemplate
 spec:
   template:
-    spec: {}
+    spec:
+      extraMounts:
+      - containerPath: "/var/run/docker.sock"
+        hostPath: "/var/run/docker.sock"
 ---
 apiVersion: bootstrap.cluster.x-k8s.io/v1beta1
 kind: KubeadmConfigTemplate
@@ -114,6 +117,7 @@ spec:
     spec:
       joinConfiguration:
         nodeRegistration:
+          criSocket: /var/run/containerd/containerd.sock
           kubeletExtraArgs:
             # We have to pin the cgroupDriver to cgroupfs as kubeadm >=1.21 defaults to systemd
             # kind will implement systemd support in: https://github.com/kubernetes-sigs/kind/issues/1726
diff --git a/test/e2e/e2e_suite_test.go b/test/e2e/e2e_suite_test.go
index 38521f424..f7e25e990 100644
--- a/test/e2e/e2e_suite_test.go
+++ b/test/e2e/e2e_suite_test.go
@@ -1,4 +1,3 @@
-//go:build e2e
 // +build e2e
 
 /*
@@ -29,6 +28,8 @@ import (
 
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/gomega"
+	ctrl "sigs.k8s.io/controller-runtime"
+
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
@@ -36,10 +37,9 @@ import (
 	"sigs.k8s.io/cluster-api/test/framework/bootstrap"
 	"sigs.k8s.io/cluster-api/test/framework/clusterctl"
 	"sigs.k8s.io/cluster-api/test/framework/ginkgoextensions"
-	ctrl "sigs.k8s.io/controller-runtime"
 )
 
-// Test suite flags.
+// Test suite flags
 var (
 	// configPath is the path to the e2e config file.
 	configPath string
@@ -58,7 +58,7 @@ var (
 	skipCleanup bool
 )
 
-// Test suite global vars.
+// Test suite global vars
 var (
 	ctx = ctrl.SetupSignalHandler()
 
@@ -109,7 +109,7 @@ var _ = SynchronizedBeforeSuite(func() []byte {
 	// Before all ParallelNodes.
 
 	Expect(configPath).To(BeAnExistingFile(), "Invalid test suite argument. e2e.config should be an existing file.")
-	Expect(os.MkdirAll(artifactFolder, 0755)).To(Succeed(), "Invalid test suite argument. Can't create e2e.artifacts-folder %q", artifactFolder) //nolint:gosec
+	Expect(os.MkdirAll(artifactFolder, 0755)).To(Succeed(), "Invalid test suite argument. Can't create e2e.artifacts-folder %q", artifactFolder)
 
 	By("Initializing a runtime.Scheme with all the GVK relevant for this test")
 	scheme := initScheme()
diff --git a/test/e2e/k8s_conformance.go b/test/e2e/k8s_conformance.go
index add1bef15..ce085f981 100644
--- a/test/e2e/k8s_conformance.go
+++ b/test/e2e/k8s_conformance.go
@@ -24,8 +24,10 @@ import (
 
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/gomega"
+
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/utils/pointer"
+
 	"sigs.k8s.io/cluster-api/test/framework"
 	"sigs.k8s.io/cluster-api/test/framework/clusterctl"
 	"sigs.k8s.io/cluster-api/test/framework/kubetest"
diff --git a/test/e2e/k8s_conformance_test.go b/test/e2e/k8s_conformance_test.go
index ba7e8caa5..1697f2489 100644
--- a/test/e2e/k8s_conformance_test.go
+++ b/test/e2e/k8s_conformance_test.go
@@ -1,4 +1,3 @@
-//go:build e2e
 // +build e2e
 
 /*
diff --git a/test/e2e/kcp_adoption_test.go b/test/e2e/kcp_adoption_test.go
index 8c3e44bf0..b96327dba 100644
--- a/test/e2e/kcp_adoption_test.go
+++ b/test/e2e/kcp_adoption_test.go
@@ -1,4 +1,3 @@
-//go:build e2e
 // +build e2e
 
 /*
@@ -21,6 +20,8 @@ package e2e
 
 import (
 	. "github.com/onsi/ginkgo"
+
+	"sigs.k8s.io/cluster-api/test/framework"
 )
 
 var _ = Describe("When testing KCP adoption", func() {
@@ -29,7 +30,7 @@ var _ = Describe("When testing KCP adoption", func() {
 		return KCPAdoptionSpecInput{
 			E2EConfig:             e2eConfig,
 			ClusterctlConfigPath:  clusterctlConfigPath,
-			BootstrapClusterProxy: bootstrapClusterProxy,
+			BootstrapClusterProxy: bootstrapClusterProxy.(framework.ClusterProxy),
 			ArtifactFolder:        artifactFolder,
 			SkipCleanup:           skipCleanup,
 		}
diff --git a/test/e2e/kcp_upgrade.go b/test/e2e/kcp_upgrade.go
index c4b621823..138ad76c3 100644
--- a/test/e2e/kcp_upgrade.go
+++ b/test/e2e/kcp_upgrade.go
@@ -24,8 +24,10 @@ import (
 
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/gomega"
+
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/utils/pointer"
+
 	"sigs.k8s.io/cluster-api/test/framework"
 	"sigs.k8s.io/cluster-api/test/framework/clusterctl"
 	"sigs.k8s.io/cluster-api/util"
diff --git a/test/e2e/kcp_upgrade_test.go b/test/e2e/kcp_upgrade_test.go
index dd455e993..ec1378b37 100644
--- a/test/e2e/kcp_upgrade_test.go
+++ b/test/e2e/kcp_upgrade_test.go
@@ -1,4 +1,3 @@
-//go:build e2e
 // +build e2e
 
 /*
@@ -21,6 +20,7 @@ package e2e
 
 import (
 	. "github.com/onsi/ginkgo"
+
 	"sigs.k8s.io/cluster-api/test/framework/clusterctl"
 )
 
diff --git a/test/e2e/machine_pool.go b/test/e2e/machine_pool.go
index dd5c7a942..e865307b2 100644
--- a/test/e2e/machine_pool.go
+++ b/test/e2e/machine_pool.go
@@ -1,4 +1,3 @@
-//go:build e2e
 // +build e2e
 
 /*
@@ -27,14 +26,16 @@ import (
 
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/gomega"
+
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/utils/pointer"
+
 	"sigs.k8s.io/cluster-api/test/framework"
 	"sigs.k8s.io/cluster-api/test/framework/clusterctl"
 	"sigs.k8s.io/cluster-api/util"
 )
 
-// MachinePoolInput is the input for MachinePoolSpec.
+// MachinePoolInput is the input for MachinePoolSpec
 type MachinePoolInput struct {
 	E2EConfig             *clusterctl.E2EConfig
 	ClusterctlConfigPath  string
@@ -63,7 +64,7 @@ func MachinePoolSpec(ctx context.Context, inputGetter func() MachinePoolInput) {
 		Expect(input.E2EConfig).ToNot(BeNil(), "Invalid argument. input.E2EConfig can't be nil when calling %s spec", specName)
 		Expect(input.ClusterctlConfigPath).To(BeAnExistingFile(), "Invalid argument. input.ClusterctlConfigPath must be an existing file when calling %s spec", specName)
 		Expect(input.BootstrapClusterProxy).ToNot(BeNil(), "Invalid argument. input.BootstrapClusterProxy can't be nil when calling %s spec", specName)
-		Expect(os.MkdirAll(input.ArtifactFolder, 0755)).To(Succeed(), "Invalid argument. input.ArtifactFolder can't be created for %s spec", specName) //nolint:gosec
+		Expect(os.MkdirAll(input.ArtifactFolder, 0755)).To(Succeed(), "Invalid argument. input.ArtifactFolder can't be created for %s spec", specName)
 		Expect(input.E2EConfig.Variables).To(HaveKey(KubernetesVersion))
 		Expect(input.E2EConfig.Variables).To(HaveValidVersion(input.E2EConfig.GetVariable(KubernetesVersion)))
 
diff --git a/test/e2e/machine_pool_test.go b/test/e2e/machine_pool_test.go
index 71cf604a6..8765d8680 100644
--- a/test/e2e/machine_pool_test.go
+++ b/test/e2e/machine_pool_test.go
@@ -1,4 +1,3 @@
-//go:build e2e
 // +build e2e
 
 /*
diff --git a/test/e2e/md_rollout.go b/test/e2e/md_rollout.go
index cb1651dd3..4500807f5 100644
--- a/test/e2e/md_rollout.go
+++ b/test/e2e/md_rollout.go
@@ -24,8 +24,10 @@ import (
 
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/gomega"
+
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/utils/pointer"
+
 	"sigs.k8s.io/cluster-api/test/framework"
 	"sigs.k8s.io/cluster-api/test/framework/clusterctl"
 	"sigs.k8s.io/cluster-api/util"
diff --git a/test/e2e/md_rollout_test.go b/test/e2e/md_rollout_test.go
index ffd813acb..6fd6cff01 100644
--- a/test/e2e/md_rollout_test.go
+++ b/test/e2e/md_rollout_test.go
@@ -1,4 +1,3 @@
-//go:build e2e
 // +build e2e
 
 /*
diff --git a/test/e2e/md_scale.go b/test/e2e/md_scale.go
index fcfea638a..97c02264b 100644
--- a/test/e2e/md_scale.go
+++ b/test/e2e/md_scale.go
@@ -24,6 +24,7 @@ import (
 
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/gomega"
+
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/utils/pointer"
 	"sigs.k8s.io/cluster-api/test/framework"
diff --git a/test/e2e/md_scale_test.go b/test/e2e/md_scale_test.go
index 01f10a0aa..8f094ed49 100644
--- a/test/e2e/md_scale_test.go
+++ b/test/e2e/md_scale_test.go
@@ -1,4 +1,3 @@
-//go:build e2e
 // +build e2e
 
 /*
diff --git a/test/e2e/mhc_remediations.go b/test/e2e/mhc_remediations.go
index 0d8275f0d..0f56136fe 100644
--- a/test/e2e/mhc_remediations.go
+++ b/test/e2e/mhc_remediations.go
@@ -24,8 +24,10 @@ import (
 
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/gomega"
+
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/utils/pointer"
+
 	"sigs.k8s.io/cluster-api/test/framework"
 	"sigs.k8s.io/cluster-api/test/framework/clusterctl"
 	"sigs.k8s.io/cluster-api/util"
diff --git a/test/e2e/mhc_remediations_test.go b/test/e2e/mhc_remediations_test.go
index d7e2d559d..2c4a440c2 100644
--- a/test/e2e/mhc_remediations_test.go
+++ b/test/e2e/mhc_remediations_test.go
@@ -1,4 +1,3 @@
-//go:build e2e
 // +build e2e
 
 /*
diff --git a/test/e2e/node_drain_timeout.go b/test/e2e/node_drain_timeout.go
index 9ba6d9d16..4ff0a35e9 100644
--- a/test/e2e/node_drain_timeout.go
+++ b/test/e2e/node_drain_timeout.go
@@ -25,6 +25,7 @@ import (
 
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/gomega"
+
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/utils/pointer"
diff --git a/test/e2e/node_drain_timeout_test.go b/test/e2e/node_drain_timeout_test.go
index 988f5f133..ae24b9459 100644
--- a/test/e2e/node_drain_timeout_test.go
+++ b/test/e2e/node_drain_timeout_test.go
@@ -1,4 +1,3 @@
-//go:build e2e
 // +build e2e
 
 /*
diff --git a/test/e2e/quick_start.go b/test/e2e/quick_start.go
index 65541fb07..9b0ce1b1c 100644
--- a/test/e2e/quick_start.go
+++ b/test/e2e/quick_start.go
@@ -24,8 +24,10 @@ import (
 
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/gomega"
+
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/utils/pointer"
+
 	"sigs.k8s.io/cluster-api/test/framework"
 	"sigs.k8s.io/cluster-api/test/framework/clusterctl"
 	"sigs.k8s.io/cluster-api/util"
diff --git a/test/e2e/quick_start_test.go b/test/e2e/quick_start_test.go
index f8b9c0370..27ac25952 100644
--- a/test/e2e/quick_start_test.go
+++ b/test/e2e/quick_start_test.go
@@ -1,4 +1,3 @@
-//go:build e2e
 // +build e2e
 
 /*
diff --git a/test/e2e/self_hosted.go b/test/e2e/self_hosted.go
index a30379a31..92bfa39db 100644
--- a/test/e2e/self_hosted.go
+++ b/test/e2e/self_hosted.go
@@ -18,12 +18,15 @@ package e2e
 
 import (
 	"context"
+	"errors"
 	"fmt"
 	"os"
 	"path/filepath"
 
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/gomega"
+	"sigs.k8s.io/controller-runtime/pkg/client"
+
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/utils/pointer"
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
@@ -32,7 +35,6 @@ import (
 	"sigs.k8s.io/cluster-api/test/framework/bootstrap"
 	"sigs.k8s.io/cluster-api/test/framework/clusterctl"
 	"sigs.k8s.io/cluster-api/util"
-	"sigs.k8s.io/controller-runtime/pkg/client"
 )
 
 // SelfHostedSpecInput is the input for SelfHostedSpec.
@@ -98,11 +100,28 @@ func SelfHostedSpec(ctx context.Context, inputGetter func() SelfHostedSpecInput)
 
 		By("Turning the workload cluster into a management cluster")
 
-		// In case of the cluster id a DockerCluster, we should load controller images into the nodes.
+		// In case the cluster is a DockerCluster, we should load controller images into the nodes.
 		// Nb. this can be achieved also by changing the DockerMachine spec, but for the time being we are using
 		// this approach because this allows to have a single source of truth for images, the e2e config
+		// Nb. If the cluster is a managed topology cluster.Spec.InfrastructureRef will be nil till
+		// the cluster object is reconciled. Therefore, we always try to fetch the reconciled cluster object from
+		// the server to check if it is a DockerCluster.
 		cluster := clusterResources.Cluster
-		if cluster.Spec.InfrastructureRef.Kind == "DockerCluster" {
+		isDockerCluster := false
+		Eventually(func() error {
+			c := input.BootstrapClusterProxy.GetClient()
+			tmpCluster := &clusterv1.Cluster{}
+			if err := c.Get(ctx, client.ObjectKey{Name: cluster.Name, Namespace: cluster.Namespace}, tmpCluster); err != nil {
+				return err
+			}
+			if tmpCluster.Spec.InfrastructureRef != nil {
+				isDockerCluster = tmpCluster.Spec.InfrastructureRef.Kind == "DockerCluster"
+				return nil
+			}
+			return errors.New("cluster object not yet reconciled")
+		}, "1m", "5s").Should(Succeed())
+
+		if isDockerCluster {
 			Expect(bootstrap.LoadImagesToKindCluster(ctx, bootstrap.LoadImagesToKindClusterInput{
 				Name:   cluster.Name,
 				Images: input.E2EConfig.Images,
diff --git a/test/e2e/self_hosted_test.go b/test/e2e/self_hosted_test.go
index 9ad83c84c..aa6957e71 100644
--- a/test/e2e/self_hosted_test.go
+++ b/test/e2e/self_hosted_test.go
@@ -36,3 +36,18 @@ var _ = Describe("When testing Cluster API working on self-hosted clusters", fun
 	})
 
 })
+
+var _ = Describe("When testing Cluster API working on self-hosted clusters using ClusterClass", func() {
+
+	SelfHostedSpec(ctx, func() SelfHostedSpecInput {
+		return SelfHostedSpecInput{
+			E2EConfig:             e2eConfig,
+			ClusterctlConfigPath:  clusterctlConfigPath,
+			BootstrapClusterProxy: bootstrapClusterProxy,
+			ArtifactFolder:        artifactFolder,
+			SkipCleanup:           skipCleanup,
+			Flavor:                "topology",
+		}
+	})
+
+})
diff --git a/test/framework/alltypes_helpers.go b/test/framework/alltypes_helpers.go
index 2e23d05ef..4f38d18f6 100644
--- a/test/framework/alltypes_helpers.go
+++ b/test/framework/alltypes_helpers.go
@@ -26,6 +26,7 @@ import (
 
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/gomega"
+
 	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	apimeta "k8s.io/apimachinery/pkg/api/meta"
diff --git a/test/framework/bootstrap/kind_provider.go b/test/framework/bootstrap/kind_provider.go
index 5406b688b..ea096b160 100644
--- a/test/framework/bootstrap/kind_provider.go
+++ b/test/framework/bootstrap/kind_provider.go
@@ -22,6 +22,7 @@ import (
 	"os"
 
 	. "github.com/onsi/gomega"
+
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
 	"sigs.k8s.io/cluster-api/test/framework/internal/log"
 	kindv1 "sigs.k8s.io/kind/pkg/apis/config/v1alpha4"
diff --git a/test/framework/bootstrap/kind_util.go b/test/framework/bootstrap/kind_util.go
index 219582f39..45e284a9e 100644
--- a/test/framework/bootstrap/kind_util.go
+++ b/test/framework/bootstrap/kind_util.go
@@ -24,6 +24,7 @@ import (
 
 	. "github.com/onsi/gomega"
 	"github.com/pkg/errors"
+
 	"sigs.k8s.io/cluster-api/test/framework/clusterctl"
 	"sigs.k8s.io/cluster-api/test/framework/internal/log"
 	"sigs.k8s.io/cluster-api/test/infrastructure/container"
diff --git a/test/framework/cluster_helpers.go b/test/framework/cluster_helpers.go
index 847dcd979..c3b8204fd 100644
--- a/test/framework/cluster_helpers.go
+++ b/test/framework/cluster_helpers.go
@@ -22,6 +22,7 @@ import (
 
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/gomega"
+
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
 	"sigs.k8s.io/cluster-api/test/framework/internal/log"
diff --git a/test/framework/clusterctl/client.go b/test/framework/clusterctl/client.go
index 55eca28a8..8b904ccc0 100644
--- a/test/framework/clusterctl/client.go
+++ b/test/framework/clusterctl/client.go
@@ -26,6 +26,7 @@ import (
 
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/gomega"
+
 	clusterctlclient "sigs.k8s.io/cluster-api/cmd/clusterctl/client"
 	clusterctllog "sigs.k8s.io/cluster-api/cmd/clusterctl/log"
 	"sigs.k8s.io/cluster-api/test/framework/clusterctl/logger"
diff --git a/test/framework/clusterctl/clusterctl_config.go b/test/framework/clusterctl/clusterctl_config.go
index b4b058533..f75c4ab71 100644
--- a/test/framework/clusterctl/clusterctl_config.go
+++ b/test/framework/clusterctl/clusterctl_config.go
@@ -20,6 +20,7 @@ import (
 	"os"
 
 	. "github.com/onsi/gomega"
+
 	"sigs.k8s.io/yaml"
 )
 
diff --git a/test/framework/clusterctl/clusterctl_helpers.go b/test/framework/clusterctl/clusterctl_helpers.go
index 729889c89..f016172ec 100644
--- a/test/framework/clusterctl/clusterctl_helpers.go
+++ b/test/framework/clusterctl/clusterctl_helpers.go
@@ -22,6 +22,7 @@ import (
 	"path/filepath"
 
 	. "github.com/onsi/gomega"
+
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
 	"sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
 	controlplanev1 "sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1beta1"
diff --git a/test/framework/clusterctl/e2e_config.go b/test/framework/clusterctl/e2e_config.go
index 9448a581b..b87395b85 100644
--- a/test/framework/clusterctl/e2e_config.go
+++ b/test/framework/clusterctl/e2e_config.go
@@ -30,6 +30,7 @@ import (
 	"time"
 
 	. "github.com/onsi/gomega"
+
 	"github.com/pkg/errors"
 	"k8s.io/apimachinery/pkg/util/version"
 	"k8s.io/utils/pointer"
diff --git a/test/framework/clusterctl/logger/log_file.go b/test/framework/clusterctl/logger/log_file.go
index 867bf2b6b..94d205066 100644
--- a/test/framework/clusterctl/logger/log_file.go
+++ b/test/framework/clusterctl/logger/log_file.go
@@ -21,8 +21,9 @@ import (
 	"os"
 	"path/filepath"
 
-	"github.com/go-logr/logr"
 	. "github.com/onsi/gomega"
+
+	"github.com/go-logr/logr"
 )
 
 // Provides a log_file that can be used to store the logs generated by clusterctl actions.
diff --git a/test/framework/clusterctl/repository.go b/test/framework/clusterctl/repository.go
index 4f37d0c2e..8cd4a3d40 100644
--- a/test/framework/clusterctl/repository.go
+++ b/test/framework/clusterctl/repository.go
@@ -31,8 +31,9 @@ import (
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/gomega"
 	"github.com/pkg/errors"
-	clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
 	"sigs.k8s.io/cluster-api/test/framework/exec"
+
+	clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
 )
 
 const (
@@ -58,7 +59,7 @@ type CreateRepositoryInput struct {
 // NOTE: this transformation is specifically designed for replacing "data: ${envSubstVar}".
 func (i *CreateRepositoryInput) RegisterClusterResourceSetConfigMapTransformation(manifestPath, envSubstVar string) {
 	By(fmt.Sprintf("Reading the ClusterResourceSet manifest %s", manifestPath))
-	manifestData, err := os.ReadFile(manifestPath) //nolint:gosec
+	manifestData, err := os.ReadFile(manifestPath)
 	Expect(err).ToNot(HaveOccurred(), "Failed to read the ClusterResourceSet manifest file")
 	Expect(manifestData).ToNot(BeEmpty(), "ClusterResourceSet manifest file should not be empty")
 
diff --git a/test/framework/clusterresourceset_helpers.go b/test/framework/clusterresourceset_helpers.go
index 7abb11ce1..510aebe60 100644
--- a/test/framework/clusterresourceset_helpers.go
+++ b/test/framework/clusterresourceset_helpers.go
@@ -22,6 +22,7 @@ import (
 
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/gomega"
+
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/types"
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
diff --git a/test/framework/control_plane.go b/test/framework/control_plane.go
index 057d4ab5f..9386935d0 100644
--- a/test/framework/control_plane.go
+++ b/test/framework/control_plane.go
@@ -21,6 +21,7 @@ import (
 
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/gomega"
+
 	controlplanev1 "sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1beta1"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 )
diff --git a/test/framework/controller_helpers.go b/test/framework/controller_helpers.go
index 7c11238c0..2ab726eae 100644
--- a/test/framework/controller_helpers.go
+++ b/test/framework/controller_helpers.go
@@ -20,6 +20,7 @@ import (
 	"context"
 
 	. "github.com/onsi/gomega"
+
 	appsv1 "k8s.io/api/apps/v1"
 )
 
diff --git a/test/framework/convenience_test.go b/test/framework/convenience_test.go
index 9c6788f85..64a08dc36 100644
--- a/test/framework/convenience_test.go
+++ b/test/framework/convenience_test.go
@@ -22,6 +22,7 @@ import (
 	. "github.com/onsi/gomega"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/runtime/schema"
+
 	"sigs.k8s.io/cluster-api/test/framework"
 )
 
diff --git a/test/framework/daemonset_helpers.go b/test/framework/daemonset_helpers.go
index 9afcacbfc..dcc1b1918 100644
--- a/test/framework/daemonset_helpers.go
+++ b/test/framework/daemonset_helpers.go
@@ -21,9 +21,10 @@ import (
 
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/gomega"
+	containerutil "sigs.k8s.io/cluster-api/util/container"
+
 	appsv1 "k8s.io/api/apps/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	containerutil "sigs.k8s.io/cluster-api/util/container"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 )
 
diff --git a/test/framework/deployment_helpers.go b/test/framework/deployment_helpers.go
index dcd2fcbb6..2652e56d1 100644
--- a/test/framework/deployment_helpers.go
+++ b/test/framework/deployment_helpers.go
@@ -29,12 +29,14 @@ import (
 
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/gomega"
+
 	appsv1 "k8s.io/api/apps/v1"
 	corev1 "k8s.io/api/core/v1"
-	"k8s.io/api/policy/v1beta1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/util/intstr"
 	"k8s.io/client-go/kubernetes"
+
+	"k8s.io/api/policy/v1beta1"
 	"k8s.io/utils/pointer"
 	controlplanev1 "sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1beta1"
 	"sigs.k8s.io/cluster-api/test/framework/internal/log"
diff --git a/test/framework/kubetest/run.go b/test/framework/kubetest/run.go
index e60626bca..e218974ec 100644
--- a/test/framework/kubetest/run.go
+++ b/test/framework/kubetest/run.go
@@ -201,7 +201,7 @@ func (c kubetestConfig) toFlags() []string {
 
 func parseKubetestConfig(kubetestConfigFile string) (kubetestConfig, error) {
 	conf := make(kubetestConfig)
-	data, err := os.ReadFile(kubetestConfigFile) //nolint:gosec
+	data, err := os.ReadFile(kubetestConfigFile)
 	if err != nil {
 		return nil, fmt.Errorf("unable to read kubetest config file %s: %w", kubetestConfigFile, err)
 	}
diff --git a/test/framework/machine_helpers.go b/test/framework/machine_helpers.go
index efc999856..871094334 100644
--- a/test/framework/machine_helpers.go
+++ b/test/framework/machine_helpers.go
@@ -22,6 +22,7 @@ import (
 
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/gomega"
+
 	"github.com/pkg/errors"
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/types"
diff --git a/test/framework/machinedeployment_helpers.go b/test/framework/machinedeployment_helpers.go
index e34f98867..78dbe0472 100644
--- a/test/framework/machinedeployment_helpers.go
+++ b/test/framework/machinedeployment_helpers.go
@@ -22,6 +22,7 @@ import (
 
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/gomega"
+
 	"github.com/pkg/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
diff --git a/test/framework/machinehealthcheck_helpers.go b/test/framework/machinehealthcheck_helpers.go
index a49226092..7403924f2 100644
--- a/test/framework/machinehealthcheck_helpers.go
+++ b/test/framework/machinehealthcheck_helpers.go
@@ -23,6 +23,7 @@ import (
 
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/gomega"
+
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/types"
diff --git a/test/framework/machinepool_helpers.go b/test/framework/machinepool_helpers.go
index be17e234e..1697244f1 100644
--- a/test/framework/machinepool_helpers.go
+++ b/test/framework/machinepool_helpers.go
@@ -19,14 +19,16 @@ package framework
 import (
 	"context"
 
-	. "github.com/onsi/ginkgo"
-	. "github.com/onsi/gomega"
 	"github.com/pkg/errors"
 	corev1 "k8s.io/api/core/v1"
-	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
-	clusterv1exp "sigs.k8s.io/cluster-api/exp/api/v1beta1"
 	"sigs.k8s.io/cluster-api/test/framework/internal/log"
 	"sigs.k8s.io/cluster-api/util/patch"
+
+	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/gomega"
+
+	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
+	clusterv1exp "sigs.k8s.io/cluster-api/exp/api/v1beta1"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 )
 
diff --git a/test/framework/namespace_helpers.go b/test/framework/namespace_helpers.go
index 3ec8a6a87..43018ee5d 100644
--- a/test/framework/namespace_helpers.go
+++ b/test/framework/namespace_helpers.go
@@ -26,6 +26,7 @@ import (
 
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/gomega"
+
 	corev1 "k8s.io/api/core/v1"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
diff --git a/test/framework/node_helpers.go b/test/framework/node_helpers.go
index 2b0f1da21..aabda58f9 100644
--- a/test/framework/node_helpers.go
+++ b/test/framework/node_helpers.go
@@ -20,6 +20,7 @@ import (
 	"context"
 
 	. "github.com/onsi/gomega"
+
 	corev1 "k8s.io/api/core/v1"
 	"sigs.k8s.io/cluster-api/controllers/noderefutil"
 )
diff --git a/test/framework/pod_helpers.go b/test/framework/pod_helpers.go
index 88f4fc0dc..1c9f4382a 100644
--- a/test/framework/pod_helpers.go
+++ b/test/framework/pod_helpers.go
@@ -21,6 +21,7 @@ import (
 	"strings"
 
 	. "github.com/onsi/gomega"
+
 	"github.com/pkg/errors"
 	corev1 "k8s.io/api/core/v1"
 	"sigs.k8s.io/controller-runtime/pkg/client"
diff --git a/test/go.sum b/test/go.sum
index f0301276a..67f7a7222 100644
--- a/test/go.sum
+++ b/test/go.sum
@@ -312,9 +312,8 @@ github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMi
 github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
 github.com/evanphx/json-patch v4.11.0+incompatible h1:glyUF9yIYtMHzn8xaKw5rMhdWcwsYV8dZHIq5567/xs=
 github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
+github.com/evanphx/json-patch/v5 v5.2.0 h1:8ozOH5xxoMYDt5/u+yMTsVXydVCbTORFnOOoq2lumco=
 github.com/evanphx/json-patch/v5 v5.2.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4=
-github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww=
-github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4=
 github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4=
 github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc=
 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
diff --git a/test/infrastructure/docker/controllers/dockercluster_controller.go b/test/infrastructure/docker/controllers/dockercluster_controller.go
index d205e0d7d..03e7bdfdd 100644
--- a/test/infrastructure/docker/controllers/dockercluster_controller.go
+++ b/test/infrastructure/docker/controllers/dockercluster_controller.go
@@ -20,6 +20,8 @@ package controllers
 import (
 	"context"
 
+	"sigs.k8s.io/controller-runtime/pkg/controller"
+
 	"github.com/go-logr/logr"
 	"github.com/pkg/errors"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -32,7 +34,6 @@ import (
 	"sigs.k8s.io/cluster-api/util/predicates"
 	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/client"
-	"sigs.k8s.io/controller-runtime/pkg/controller"
 	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
 	"sigs.k8s.io/controller-runtime/pkg/handler"
 	"sigs.k8s.io/controller-runtime/pkg/source"
diff --git a/test/infrastructure/docker/controllers/dockermachine_controller_test.go b/test/infrastructure/docker/controllers/dockermachine_controller_test.go
index e546d2d29..572dc00ec 100644
--- a/test/infrastructure/docker/controllers/dockermachine_controller_test.go
+++ b/test/infrastructure/docker/controllers/dockermachine_controller_test.go
@@ -20,6 +20,7 @@ import (
 	"testing"
 
 	. "github.com/onsi/gomega"
+
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
diff --git a/test/infrastructure/docker/docker/kind_manager.go b/test/infrastructure/docker/docker/kind_manager.go
index 9d8beb023..409d0b1c0 100644
--- a/test/infrastructure/docker/docker/kind_manager.go
+++ b/test/infrastructure/docker/docker/kind_manager.go
@@ -22,6 +22,7 @@ import (
 	"net"
 
 	"github.com/pkg/errors"
+
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
 	"sigs.k8s.io/cluster-api/test/infrastructure/container"
 	"sigs.k8s.io/cluster-api/test/infrastructure/docker/docker/types"
diff --git a/test/infrastructure/docker/docker/machine.go b/test/infrastructure/docker/docker/machine.go
index 952e13272..9189fc1ce 100644
--- a/test/infrastructure/docker/docker/machine.go
+++ b/test/infrastructure/docker/docker/machine.go
@@ -29,15 +29,16 @@ import (
 	"github.com/go-logr/logr"
 	"github.com/pkg/errors"
 	"k8s.io/apimachinery/pkg/util/wait"
+	ctrl "sigs.k8s.io/controller-runtime"
+	"sigs.k8s.io/kind/pkg/apis/config/v1alpha4"
+	"sigs.k8s.io/kind/pkg/cluster/constants"
+
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
 	"sigs.k8s.io/cluster-api/test/infrastructure/container"
 	infrav1 "sigs.k8s.io/cluster-api/test/infrastructure/docker/api/v1beta1"
 	"sigs.k8s.io/cluster-api/test/infrastructure/docker/cloudinit"
 	"sigs.k8s.io/cluster-api/test/infrastructure/docker/docker/types"
 	clusterapicontainer "sigs.k8s.io/cluster-api/util/container"
-	ctrl "sigs.k8s.io/controller-runtime"
-	"sigs.k8s.io/kind/pkg/apis/config/v1alpha4"
-	"sigs.k8s.io/kind/pkg/cluster/constants"
 )
 
 const (
diff --git a/test/infrastructure/docker/exp/api/v1alpha3/dockermachinepool_types.go b/test/infrastructure/docker/exp/api/v1alpha3/dockermachinepool_types.go
index b259c8752..37a3b4679 100644
--- a/test/infrastructure/docker/exp/api/v1alpha3/dockermachinepool_types.go
+++ b/test/infrastructure/docker/exp/api/v1alpha3/dockermachinepool_types.go
@@ -18,6 +18,7 @@ package v1alpha3
 
 import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha3"
 	infrav1 "sigs.k8s.io/cluster-api/test/infrastructure/docker/api/v1alpha3"
 )
diff --git a/test/infrastructure/docker/exp/api/v1beta1/dockermachinepool_types.go b/test/infrastructure/docker/exp/api/v1beta1/dockermachinepool_types.go
index 1f8093d20..fb462be2c 100644
--- a/test/infrastructure/docker/exp/api/v1beta1/dockermachinepool_types.go
+++ b/test/infrastructure/docker/exp/api/v1beta1/dockermachinepool_types.go
@@ -18,6 +18,7 @@ package v1beta1
 
 import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
 	infrav1 "sigs.k8s.io/cluster-api/test/infrastructure/docker/api/v1beta1"
 )
diff --git a/test/infrastructure/docker/main.go b/test/infrastructure/docker/main.go
index 9de2b253e..c0de2661f 100644
--- a/test/infrastructure/docker/main.go
+++ b/test/infrastructure/docker/main.go
@@ -23,7 +23,6 @@ import (
 	"os"
 	"time"
 
-	// +kubebuilder:scaffold:imports
 	"github.com/spf13/pflag"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/client-go/kubernetes/scheme"
@@ -46,6 +45,7 @@ import (
 	expcontrollers "sigs.k8s.io/cluster-api/test/infrastructure/docker/exp/controllers"
 	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/controller"
+	// +kubebuilder:scaffold:imports
 )
 
 var (
diff --git a/util/collections/machine_filters_test.go b/util/collections/machine_filters_test.go
index 94bf34d7d..c0893c8a1 100644
--- a/util/collections/machine_filters_test.go
+++ b/util/collections/machine_filters_test.go
@@ -20,14 +20,16 @@ import (
 	"testing"
 	"time"
 
+	"sigs.k8s.io/cluster-api/util/collections"
+	"sigs.k8s.io/controller-runtime/pkg/client/fake"
+
 	. "github.com/onsi/gomega"
+	"sigs.k8s.io/cluster-api/util/conditions"
+
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/utils/pointer"
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
 	controlplanev1 "sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1beta1"
-	"sigs.k8s.io/cluster-api/util/collections"
-	"sigs.k8s.io/cluster-api/util/conditions"
-	"sigs.k8s.io/controller-runtime/pkg/client/fake"
 )
 
 func falseFilter(_ *clusterv1.Machine) bool {
diff --git a/util/conversion/conversion_test.go b/util/conversion/conversion_test.go
index 704f2c677..bfdf1e116 100644
--- a/util/conversion/conversion_test.go
+++ b/util/conversion/conversion_test.go
@@ -20,6 +20,7 @@ import (
 	"testing"
 
 	. "github.com/onsi/gomega"
+
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
 	"k8s.io/apimachinery/pkg/runtime/schema"
diff --git a/util/failuredomains/failure_domains_test.go b/util/failuredomains/failure_domains_test.go
index fcbabe0f1..40eb40151 100644
--- a/util/failuredomains/failure_domains_test.go
+++ b/util/failuredomains/failure_domains_test.go
@@ -19,10 +19,13 @@ package failuredomains
 import (
 	"testing"
 
+	"sigs.k8s.io/cluster-api/util/collections"
+
 	. "github.com/onsi/gomega"
+
 	"k8s.io/utils/pointer"
+
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
-	"sigs.k8s.io/cluster-api/util/collections"
 )
 
 func TestNewFailureDomainPicker(t *testing.T) {
diff --git a/util/kubeconfig/kubeconfig_test.go b/util/kubeconfig/kubeconfig_test.go
index 1134c005b..980eb2641 100644
--- a/util/kubeconfig/kubeconfig_test.go
+++ b/util/kubeconfig/kubeconfig_test.go
@@ -26,6 +26,7 @@ import (
 	"time"
 
 	. "github.com/onsi/gomega"
+
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/client-go/tools/clientcmd"
diff --git a/util/patch/patch_test.go b/util/patch/patch_test.go
index 44c95d61e..8d70cab5b 100644
--- a/util/patch/patch_test.go
+++ b/util/patch/patch_test.go
@@ -22,6 +22,7 @@ import (
 
 	"github.com/google/go-cmp/cmp"
 	. "github.com/onsi/gomega"
+
 	appsv1 "k8s.io/api/apps/v1"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
diff --git a/util/patch/suite_test.go b/util/patch/suite_test.go
index 6cb0c066b..b3f6265df 100644
--- a/util/patch/suite_test.go
+++ b/util/patch/suite_test.go
@@ -21,9 +21,9 @@ import (
 	"testing"
 	"time"
 
-	// +kubebuilder:scaffold:imports
 	"sigs.k8s.io/cluster-api/internal/envtest"
 	ctrl "sigs.k8s.io/controller-runtime"
+	// +kubebuilder:scaffold:imports
 )
 
 const (
diff --git a/util/resource/resource_test.go b/util/resource/resource_test.go
index 5afb3b6ec..50d853f1e 100644
--- a/util/resource/resource_test.go
+++ b/util/resource/resource_test.go
@@ -20,6 +20,7 @@ import (
 	"testing"
 
 	. "github.com/onsi/gomega"
+
 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
 )
 
diff --git a/util/secret/certificates_test.go b/util/secret/certificates_test.go
index 16e778b12..e6c48c252 100644
--- a/util/secret/certificates_test.go
+++ b/util/secret/certificates_test.go
@@ -20,6 +20,7 @@ import (
 	"testing"
 
 	. "github.com/onsi/gomega"
+
 	bootstrapv1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1beta1"
 	"sigs.k8s.io/cluster-api/util/secret"
 )
diff --git a/webhooks/cluster_test.go b/webhooks/cluster_test.go
index 187ba0ae0..3fe238784 100644
--- a/webhooks/cluster_test.go
+++ b/webhooks/cluster_test.go
@@ -20,6 +20,7 @@ import (
 	"testing"
 
 	. "github.com/onsi/gomega"
+
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	utilfeature "k8s.io/component-base/featuregate/testing"
@@ -30,7 +31,7 @@ import (
 func TestClusterDefaultNamespaces(t *testing.T) {
 	g := NewWithT(t)
 
-	c := &clusterv1.Cluster{
+	in := &clusterv1.Cluster{
 		ObjectMeta: metav1.ObjectMeta{
 			Namespace: "fooboo",
 		},
@@ -39,12 +40,14 @@ func TestClusterDefaultNamespaces(t *testing.T) {
 			ControlPlaneRef:   &corev1.ObjectReference{},
 		},
 	}
+
 	webhook := &Cluster{}
-	t.Run("for Cluster", customDefaultValidateTest(ctx, c, webhook))
-	g.Expect(webhook.Default(ctx, c)).To(Succeed())
+	t.Run("for Cluster", customDefaultValidateTest(ctx, in, webhook))
 
-	g.Expect(c.Spec.InfrastructureRef.Namespace).To(Equal(c.Namespace))
-	g.Expect(c.Spec.ControlPlaneRef.Namespace).To(Equal(c.Namespace))
+	g.Expect(webhook.Default(ctx, in)).To(Succeed())
+
+	g.Expect(in.Spec.InfrastructureRef.Namespace).To(Equal(in.Namespace))
+	g.Expect(in.Spec.ControlPlaneRef.Namespace).To(Equal(in.Namespace))
 }
 
 func TestClusterDefaultTopologyVersion(t *testing.T) {
@@ -54,7 +57,7 @@ func TestClusterDefaultTopologyVersion(t *testing.T) {
 
 	g := NewWithT(t)
 
-	c := &clusterv1.Cluster{
+	in := &clusterv1.Cluster{
 		ObjectMeta: metav1.ObjectMeta{
 			Namespace: "fooboo",
 		},
@@ -66,380 +69,8 @@ func TestClusterDefaultTopologyVersion(t *testing.T) {
 		},
 	}
 	webhook := &Cluster{}
-	t.Run("for Cluster", customDefaultValidateTest(ctx, c, webhook))
-	g.Expect(webhook.Default(ctx, c)).To(Succeed())
-
-	g.Expect(c.Spec.Topology.Version).To(HavePrefix("v"))
-}
-
-func TestClusterValidation(t *testing.T) {
-	// NOTE: ClusterTopology feature flag is disabled by default, thus preventing to set Cluster.Topologies.
-
-	tests := []struct {
-		name      string
-		in        *clusterv1.Cluster
-		old       *clusterv1.Cluster
-		expectErr bool
-	}{
-		{
-			name:      "should return error when cluster namespace and infrastructure ref namespace mismatch",
-			expectErr: true,
-			in: &clusterv1.Cluster{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "foo",
-				},
-				Spec: clusterv1.ClusterSpec{
-					InfrastructureRef: &corev1.ObjectReference{
-						Namespace: "bar",
-					},
-					ControlPlaneRef: &corev1.ObjectReference{
-						Namespace: "foo",
-					},
-				},
-			},
-		},
-		{
-			name:      "should return error when cluster namespace and controlplane ref namespace mismatch",
-			expectErr: true,
-			in: &clusterv1.Cluster{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "foo",
-				},
-				Spec: clusterv1.ClusterSpec{
-					InfrastructureRef: &corev1.ObjectReference{
-						Namespace: "foo",
-					},
-					ControlPlaneRef: &corev1.ObjectReference{
-						Namespace: "bar",
-					},
-				},
-			},
-		},
-		{
-			name:      "should succeed when namespaces match",
-			expectErr: false,
-			in: &clusterv1.Cluster{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "foo",
-				},
-				Spec: clusterv1.ClusterSpec{
-					ControlPlaneRef: &corev1.ObjectReference{
-						Namespace: "foo",
-					},
-					InfrastructureRef: &corev1.ObjectReference{
-						Namespace: "foo",
-					},
-				},
-			},
-		},
-		{
-			name:      "fails if topology is set but feature flag is disabled",
-			expectErr: true,
-			in: &clusterv1.Cluster{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "foo",
-				},
-				Spec: clusterv1.ClusterSpec{
-					ControlPlaneRef: &corev1.ObjectReference{
-						Namespace: "foo",
-					},
-					InfrastructureRef: &corev1.ObjectReference{
-						Namespace: "foo",
-					},
-					Topology: &clusterv1.Topology{},
-				},
-			},
-		},
-	}
-
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			g := NewWithT(t)
-			webhook := Cluster{}
-			err := webhook.validate(tt.old, tt.in)
-			if tt.expectErr {
-				g.Expect(err).To(HaveOccurred())
-			} else {
-				g.Expect(err).ToNot(HaveOccurred())
-			}
-		})
-	}
-}
+	t.Run("for Cluster", customDefaultValidateTest(ctx, in, webhook))
+	g.Expect(webhook.Default(ctx, in)).To(Succeed())
 
-func TestClusterTopologyValidation(t *testing.T) {
-	// NOTE: ClusterTopology feature flag is disabled by default, thus preventing to set Cluster.Topologies.
-	// Enabling the feature flag temporarily for this test.
-	defer utilfeature.SetFeatureGateDuringTest(t, feature.Gates, feature.ClusterTopology, true)()
-
-	tests := []struct {
-		name      string
-		in        *clusterv1.Cluster
-		old       *clusterv1.Cluster
-		expectErr bool
-	}{
-		{
-			name:      "should return error when topology does not have class",
-			expectErr: true,
-			in: &clusterv1.Cluster{
-				Spec: clusterv1.ClusterSpec{
-					Topology: &clusterv1.Topology{},
-				},
-			},
-		},
-		{
-			name:      "should return error when topology does not have valid version",
-			expectErr: true,
-			in: &clusterv1.Cluster{
-				Spec: clusterv1.ClusterSpec{
-					Topology: &clusterv1.Topology{
-						Class:   "foo",
-						Version: "invalid",
-					},
-				},
-			},
-		},
-		{
-			name:      "should return error when downgrading topology version - major",
-			expectErr: true,
-			old: &clusterv1.Cluster{
-				Spec: clusterv1.ClusterSpec{
-					Topology: &clusterv1.Topology{
-						Class:   "foo",
-						Version: "v2.2.3",
-					},
-				},
-			},
-			in: &clusterv1.Cluster{
-				Spec: clusterv1.ClusterSpec{
-					Topology: &clusterv1.Topology{
-						Class:   "foo",
-						Version: "v1.2.3",
-					},
-				},
-			},
-		},
-		{
-			name:      "should return error when downgrading topology version - minor",
-			expectErr: true,
-			old: &clusterv1.Cluster{
-				Spec: clusterv1.ClusterSpec{
-					Topology: &clusterv1.Topology{
-						Class:   "foo",
-						Version: "v1.2.3",
-					},
-				},
-			},
-			in: &clusterv1.Cluster{
-				Spec: clusterv1.ClusterSpec{
-					Topology: &clusterv1.Topology{
-						Class:   "foo",
-						Version: "v1.1.3",
-					},
-				},
-			},
-		},
-		{
-			name:      "should return error when downgrading topology version - patch",
-			expectErr: true,
-			old: &clusterv1.Cluster{
-				Spec: clusterv1.ClusterSpec{
-					Topology: &clusterv1.Topology{
-						Class:   "foo",
-						Version: "v1.2.3",
-					},
-				},
-			},
-			in: &clusterv1.Cluster{
-				Spec: clusterv1.ClusterSpec{
-					Topology: &clusterv1.Topology{
-						Class:   "foo",
-						Version: "v1.2.2",
-					},
-				},
-			},
-		},
-		{
-			name:      "should return error when downgrading topology version - pre-release",
-			expectErr: true,
-			old: &clusterv1.Cluster{
-				Spec: clusterv1.ClusterSpec{
-					Topology: &clusterv1.Topology{
-						Class:   "foo",
-						Version: "v1.2.3-xyz.2",
-					},
-				},
-			},
-			in: &clusterv1.Cluster{
-				Spec: clusterv1.ClusterSpec{
-					Topology: &clusterv1.Topology{
-						Class:   "foo",
-						Version: "v1.2.3-xyz.1",
-					},
-				},
-			},
-		},
-		{
-			name:      "should return error when downgrading topology version - build tag",
-			expectErr: true,
-			old: &clusterv1.Cluster{
-				Spec: clusterv1.ClusterSpec{
-					Topology: &clusterv1.Topology{
-						Class:   "foo",
-						Version: "v1.2.3+xyz.2",
-					},
-				},
-			},
-			in: &clusterv1.Cluster{
-				Spec: clusterv1.ClusterSpec{
-					Topology: &clusterv1.Topology{
-						Class:   "foo",
-						Version: "v1.2.3+xyz.1",
-					},
-				},
-			},
-		},
-		{
-			name:      "should return error when duplicated MachineDeployments names exists in a Topology",
-			expectErr: true,
-			in: &clusterv1.Cluster{
-				Spec: clusterv1.ClusterSpec{
-					Topology: &clusterv1.Topology{
-						Class:   "foo",
-						Version: "v1.19.1",
-						Workers: &clusterv1.WorkersTopology{
-							MachineDeployments: []clusterv1.MachineDeploymentTopology{
-								{
-									Name: "aa",
-								},
-								{
-									Name: "aa",
-								},
-							},
-						},
-					},
-				},
-			},
-		},
-		{
-			name:      "should pass when MachineDeployments names in a Topology are unique",
-			expectErr: false,
-			in: &clusterv1.Cluster{
-				Spec: clusterv1.ClusterSpec{
-					Topology: &clusterv1.Topology{
-						Class:   "foo",
-						Version: "v1.19.1",
-						Workers: &clusterv1.WorkersTopology{
-							MachineDeployments: []clusterv1.MachineDeploymentTopology{
-								{
-									Name: "aa",
-								},
-								{
-									Name: "bb",
-								},
-							},
-						},
-					},
-				},
-			},
-		},
-		{
-			name:      "should return error on update when Topology class is changed",
-			expectErr: true,
-			old: &clusterv1.Cluster{
-				Spec: clusterv1.ClusterSpec{
-					InfrastructureRef: &corev1.ObjectReference{},
-					Topology: &clusterv1.Topology{
-						Class:   "foo",
-						Version: "v1.19.1",
-					},
-				},
-			},
-			in: &clusterv1.Cluster{
-				Spec: clusterv1.ClusterSpec{
-					InfrastructureRef: &corev1.ObjectReference{},
-					Topology: &clusterv1.Topology{
-						Class:   "bar",
-						Version: "v1.19.1",
-					},
-				},
-			},
-		},
-		{
-			name:      "should return error on update when Topology version is downgraded",
-			expectErr: true,
-			old: &clusterv1.Cluster{
-				Spec: clusterv1.ClusterSpec{
-					InfrastructureRef: &corev1.ObjectReference{},
-					Topology: &clusterv1.Topology{
-						Class:   "foo",
-						Version: "v1.19.1",
-					},
-				},
-			},
-			in: &clusterv1.Cluster{
-				Spec: clusterv1.ClusterSpec{
-					InfrastructureRef: &corev1.ObjectReference{},
-					Topology: &clusterv1.Topology{
-						Class:   "foo",
-						Version: "v1.19.0",
-					},
-				},
-			},
-		},
-		{
-			name:      "should update",
-			expectErr: false,
-			old: &clusterv1.Cluster{
-				Spec: clusterv1.ClusterSpec{
-					InfrastructureRef: &corev1.ObjectReference{},
-					Topology: &clusterv1.Topology{
-						Class:   "foo",
-						Version: "v1.19.1",
-						Workers: &clusterv1.WorkersTopology{
-							MachineDeployments: []clusterv1.MachineDeploymentTopology{
-								{
-									Name: "aa",
-								},
-								{
-									Name: "bb",
-								},
-							},
-						},
-					},
-				},
-			},
-			in: &clusterv1.Cluster{
-				Spec: clusterv1.ClusterSpec{
-					InfrastructureRef: &corev1.ObjectReference{},
-					Topology: &clusterv1.Topology{
-						Class:   "foo",
-						Version: "v1.19.2",
-						Workers: &clusterv1.WorkersTopology{
-							MachineDeployments: []clusterv1.MachineDeploymentTopology{
-								{
-									Name: "aa",
-								},
-								{
-									Name: "bb",
-								},
-							},
-						},
-					},
-				},
-			},
-		},
-	}
-
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			g := NewWithT(t)
-			webhook := Cluster{}
-			err := webhook.validate(tt.old, tt.in)
-			if tt.expectErr {
-				g.Expect(err).To(HaveOccurred())
-			} else {
-				g.Expect(err).ToNot(HaveOccurred())
-			}
-		})
-	}
+	g.Expect(in.Spec.Topology.Version).To(HavePrefix("v"))
 }
diff --git a/webhooks/clusterclass_test.go b/webhooks/clusterclass_test.go
index 772026cca..eceb1ca86 100644
--- a/webhooks/clusterclass_test.go
+++ b/webhooks/clusterclass_test.go
@@ -74,6 +74,7 @@ func TestClusterClassDefaultNamespaces(t *testing.T) {
 	}
 
 	webhook := &ClusterClass{}
+
 	t.Run("for ClusterClass", customDefaultValidateTest(ctx, in, webhook))
 
 	g := NewWithT(t)
@@ -88,1371 +89,3 @@ func TestClusterClassDefaultNamespaces(t *testing.T) {
 		g.Expect(in.Spec.Workers.MachineDeployments[i].Template.Infrastructure.Ref.Namespace).To(Equal(namespace))
 	}
 }
-
-func TestClusterClassValidationFeatureGated(t *testing.T) {
-	// NOTE: ClusterTopology feature flag is disabled by default, thus preventing to create or update ClusterClasses.
-
-	ref := &corev1.ObjectReference{
-		APIVersion: "foo",
-		Kind:       "barTemplate",
-		Name:       "baz",
-		Namespace:  "default",
-	}
-	tests := []struct {
-		name      string
-		in        *clusterv1.ClusterClass
-		old       *clusterv1.ClusterClass
-		expectErr bool
-	}{
-		{
-			name: "creation should fail if feature flag is disabled, no matter the ClusterClass is valid(or not)",
-			in: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate: clusterv1.LocalObjectTemplate{Ref: ref},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-						},
-					},
-				},
-			},
-			expectErr: true,
-		},
-		{
-			name: "update should fail if feature flag is disabled, no matter the ClusterClass is valid(or not)",
-			old: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate: clusterv1.LocalObjectTemplate{Ref: ref},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-						},
-					},
-				},
-			},
-			in: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate: clusterv1.LocalObjectTemplate{Ref: ref},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Metadata:       clusterv1.ObjectMeta{},
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-						},
-					},
-				},
-			},
-			expectErr: true,
-		},
-	}
-
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			g := NewWithT(t)
-			webhook := &ClusterClass{}
-			if tt.expectErr {
-				g.Expect(webhook.validate(tt.old, tt.in)).NotTo(Succeed())
-			} else {
-				g.Expect(webhook.validate(tt.old, tt.in)).To(Succeed())
-			}
-		})
-	}
-}
-
-func TestClusterClassValidation(t *testing.T) {
-	// NOTE: ClusterTopology feature flag is disabled by default, thus preventing to create or update ClusterClasses.
-	// Enabling the feature flag temporarily for this test.
-	defer utilfeature.SetFeatureGateDuringTest(t, feature.Gates, feature.ClusterTopology, true)()
-
-	ref := &corev1.ObjectReference{
-		APIVersion: "group.test.io/foo",
-		Kind:       "barTemplate",
-		Name:       "baz",
-		Namespace:  "default",
-	}
-	refInAnotherNamespace := &corev1.ObjectReference{
-		APIVersion: "group.test.io/foo",
-		Kind:       "barTemplate",
-		Name:       "baz",
-		Namespace:  "another-namespace",
-	}
-	refBadTemplate := &corev1.ObjectReference{
-		APIVersion: "group.test.io/foo",
-		Kind:       "bar",
-		Name:       "baz",
-		Namespace:  "default",
-	}
-	refBadAPIVersion := &corev1.ObjectReference{
-		APIVersion: "group/test.io/v1/foo",
-		Kind:       "barTemplate",
-		Name:       "baz",
-		Namespace:  "default",
-	}
-	refEmptyName := &corev1.ObjectReference{
-		APIVersion: "group.test.io/foo",
-		Namespace:  "default",
-		Kind:       "barTemplate",
-	}
-	incompatibleRef := &corev1.ObjectReference{
-		APIVersion: "group.test.io/foo",
-		Kind:       "another-barTemplate",
-		Name:       "baz",
-		Namespace:  "default",
-	}
-	compatibleRef := &corev1.ObjectReference{
-		APIVersion: "group.test.io/another-foo",
-		Kind:       "barTemplate",
-		Name:       "another-baz",
-		Namespace:  "default",
-	}
-
-	tests := []struct {
-		name      string
-		in        *clusterv1.ClusterClass
-		old       *clusterv1.ClusterClass
-		expectErr bool
-	}{
-
-		/*
-			CREATE Tests
-		*/
-
-		{
-			name: "create pass",
-			in: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate: clusterv1.LocalObjectTemplate{Ref: ref},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-							{
-								Class: "bb",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-						},
-					},
-				},
-			},
-			expectErr: false,
-		},
-
-		// empty name in ref tests
-		{
-			name: "create fail infrastructure has empty name",
-			in: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: refEmptyName},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate: clusterv1.LocalObjectTemplate{Ref: ref},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-						},
-					},
-				},
-			},
-			expectErr: true,
-		},
-		{
-			name: "create fail control plane class has empty name",
-			in: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate: clusterv1.LocalObjectTemplate{Ref: refEmptyName},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-						},
-					},
-				},
-			},
-			expectErr: true,
-		},
-		{
-			name: "create fail control plane class machineinfrastructure has empty name",
-			in: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate:   clusterv1.LocalObjectTemplate{Ref: ref},
-						MachineInfrastructure: &clusterv1.LocalObjectTemplate{Ref: refEmptyName},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-						},
-					},
-				},
-			},
-			expectErr: true,
-		},
-		{
-			name: "create fail machine deployment bootstrap has empty name",
-			in: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate: clusterv1.LocalObjectTemplate{Ref: ref},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: refEmptyName},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-						},
-					},
-				},
-			},
-			expectErr: true,
-		},
-		{
-			name: "create fail machine deployment infrastructure has empty name",
-			in: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate: clusterv1.LocalObjectTemplate{Ref: ref},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: refEmptyName},
-								},
-							},
-						},
-					},
-				},
-			},
-			expectErr: true,
-		},
-
-		// inconsistent namespace in ref tests
-		{
-			name: "create fail if infrastructure has inconsistent namespace",
-			in: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: refInAnotherNamespace},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate: clusterv1.LocalObjectTemplate{Ref: ref},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-						},
-					},
-				},
-			},
-			expectErr: true,
-		},
-		{
-			name: "create fail if control plane has inconsistent namespace",
-			in: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate: clusterv1.LocalObjectTemplate{Ref: refInAnotherNamespace},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-						},
-					},
-				},
-			},
-			expectErr: true,
-		},
-		{
-			name: "create fail if control plane class machineinfrastructure has inconsistent namespace",
-			in: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate:   clusterv1.LocalObjectTemplate{Ref: ref},
-						MachineInfrastructure: &clusterv1.LocalObjectTemplate{Ref: refInAnotherNamespace},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-						},
-					},
-				},
-			},
-			expectErr: true,
-		},
-		{
-			name: "create fail if machine deployment / bootstrap has inconsistent namespace",
-			in: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate: clusterv1.LocalObjectTemplate{Ref: ref},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: refInAnotherNamespace},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-						},
-					},
-				},
-			},
-			expectErr: true,
-		},
-		{
-			name: "create fail if machine deployment / infrastructure has inconsistent namespace",
-			in: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate: clusterv1.LocalObjectTemplate{Ref: ref},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: refInAnotherNamespace},
-								},
-							},
-						},
-					},
-				},
-			},
-			expectErr: true,
-		},
-
-		// bad template in ref tests
-		{
-			name: "create fail if bad template in control plane",
-			in: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: refBadTemplate},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate: clusterv1.LocalObjectTemplate{Ref: ref},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-						},
-					},
-				},
-			},
-			old:       nil,
-			expectErr: true,
-		},
-		{
-			name: "create fail if bad template in control plane class machineinfrastructure",
-			in: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate:   clusterv1.LocalObjectTemplate{Ref: ref},
-						MachineInfrastructure: &clusterv1.LocalObjectTemplate{Ref: refBadTemplate},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-						},
-					},
-				},
-			},
-			old:       nil,
-			expectErr: true,
-		},
-		{
-			name: "create fail if bad template in infrastructure",
-			in: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate: clusterv1.LocalObjectTemplate{Ref: refBadTemplate},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-						},
-					},
-				},
-			},
-			old:       nil,
-			expectErr: true,
-		},
-		{
-			name: "create fail if bad template in machine deployment bootstrap",
-			in: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate: clusterv1.LocalObjectTemplate{Ref: ref},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: refBadTemplate},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-						},
-					},
-				},
-			},
-			old:       nil,
-			expectErr: true,
-		},
-		{
-			name: "create fail if bad template in machine deployment infrastructure",
-			in: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate: clusterv1.LocalObjectTemplate{Ref: ref},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: refBadTemplate},
-								},
-							},
-						},
-					},
-				},
-			},
-			old:       nil,
-			expectErr: true,
-		},
-
-		// bad apiVersion in ref tests
-		{
-			name: "create fail if bad apiVersion in control plane",
-			in: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate: clusterv1.LocalObjectTemplate{Ref: refBadAPIVersion},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-						},
-					},
-				},
-			},
-			old:       nil,
-			expectErr: true,
-		},
-		{
-			name: "create fail if bad apiVersion in control plane class machineinfrastructure",
-			in: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate:   clusterv1.LocalObjectTemplate{Ref: ref},
-						MachineInfrastructure: &clusterv1.LocalObjectTemplate{Ref: refBadAPIVersion},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-						},
-					},
-				},
-			},
-			old:       nil,
-			expectErr: true,
-		},
-		{
-			name: "create fail if bad apiVersion in infrastructure",
-			in: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: refBadAPIVersion},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate: clusterv1.LocalObjectTemplate{Ref: ref},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-						},
-					},
-				},
-			},
-			old:       nil,
-			expectErr: true,
-		},
-		{
-			name: "create fail if bad apiVersion in machine deployment bootstrap",
-			in: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate: clusterv1.LocalObjectTemplate{Ref: ref},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: refBadAPIVersion},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-						},
-					},
-				},
-			},
-			old:       nil,
-			expectErr: true,
-		},
-		{
-			name: "create fail if bad apiVersion in machine deployment infrastructure",
-			in: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate: clusterv1.LocalObjectTemplate{Ref: ref},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: refBadAPIVersion},
-								},
-							},
-						},
-					},
-				},
-			},
-			old:       nil,
-			expectErr: true,
-		},
-
-		// create test
-		{
-			name: "create fail if duplicated DeploymentClasses",
-			in: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate: clusterv1.LocalObjectTemplate{Ref: ref},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-						},
-					},
-				},
-			},
-			expectErr: true,
-		},
-
-		/*
-			UPDATE Tests
-		*/
-
-		{
-			name: "update pass in case of no changes",
-			old: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate: clusterv1.LocalObjectTemplate{Ref: ref},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-						},
-					},
-				},
-			},
-			in: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate: clusterv1.LocalObjectTemplate{Ref: ref},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Metadata:       clusterv1.ObjectMeta{},
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-						},
-					},
-				},
-			},
-			expectErr: false,
-		},
-		{
-			name: "update pass if infrastructure changes in a compatible way",
-			old: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate: clusterv1.LocalObjectTemplate{Ref: ref},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Metadata:       clusterv1.ObjectMeta{},
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-						},
-					},
-				},
-			},
-			in: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: compatibleRef},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate: clusterv1.LocalObjectTemplate{Ref: ref},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Metadata:       clusterv1.ObjectMeta{},
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-						},
-					},
-				},
-			},
-			expectErr: false,
-		},
-		{
-			name: "update fails if infrastructure changes in an incompatible way",
-			old: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate: clusterv1.LocalObjectTemplate{Ref: ref},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Metadata:       clusterv1.ObjectMeta{},
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-						},
-					},
-				},
-			},
-			in: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: incompatibleRef},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate: clusterv1.LocalObjectTemplate{Ref: ref},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Metadata:       clusterv1.ObjectMeta{},
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-						},
-					},
-				},
-			},
-			expectErr: true,
-		},
-		{
-			name: "update pass if controlPlane changes in a compatible way",
-			old: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate:   clusterv1.LocalObjectTemplate{Ref: ref},
-						MachineInfrastructure: &clusterv1.LocalObjectTemplate{Ref: ref},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Metadata:       clusterv1.ObjectMeta{},
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-						},
-					},
-				},
-			},
-			in: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						Metadata: clusterv1.ObjectMeta{
-							Labels:      map[string]string{"foo": "bar"},
-							Annotations: map[string]string{"foo": "bar"},
-						},
-						LocalObjectTemplate:   clusterv1.LocalObjectTemplate{Ref: compatibleRef},
-						MachineInfrastructure: &clusterv1.LocalObjectTemplate{Ref: compatibleRef},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Metadata:       clusterv1.ObjectMeta{},
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-						},
-					},
-				},
-			},
-			expectErr: false,
-		},
-		{
-			name: "update fails if controlPlane changes in an incompatible way (control plane template)",
-			old: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate: clusterv1.LocalObjectTemplate{Ref: ref},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Metadata:       clusterv1.ObjectMeta{},
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-						},
-					},
-				},
-			},
-			in: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate: clusterv1.LocalObjectTemplate{Ref: incompatibleRef},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Metadata:       clusterv1.ObjectMeta{},
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-						},
-					},
-				},
-			},
-			expectErr: true,
-		},
-		{
-			name: "update fails if controlPlane changes in an incompatible way (control plane infrastructure machine template)",
-			old: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate:   clusterv1.LocalObjectTemplate{Ref: ref},
-						MachineInfrastructure: &clusterv1.LocalObjectTemplate{Ref: ref},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Metadata:       clusterv1.ObjectMeta{},
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-						},
-					},
-				},
-			},
-			in: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate:   clusterv1.LocalObjectTemplate{Ref: ref},
-						MachineInfrastructure: &clusterv1.LocalObjectTemplate{Ref: incompatibleRef},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Metadata:       clusterv1.ObjectMeta{},
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-						},
-					},
-				},
-			},
-			expectErr: true,
-		},
-		{
-			name: "update pass if a machine deployment changes in a compatible way",
-			old: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate: clusterv1.LocalObjectTemplate{Ref: ref},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Metadata:       clusterv1.ObjectMeta{},
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-						},
-					},
-				},
-			},
-			in: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate: clusterv1.LocalObjectTemplate{Ref: ref},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Metadata: clusterv1.ObjectMeta{
-										Labels:      map[string]string{"foo": "bar"},
-										Annotations: map[string]string{"foo": "bar"},
-									},
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: incompatibleRef}, // NOTE: this should be tolerated
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: compatibleRef},
-								},
-							},
-						},
-					},
-				},
-			},
-			expectErr: false,
-		},
-		{
-			name: "update fails a machine deployment changes in an incompatible way",
-			old: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate: clusterv1.LocalObjectTemplate{Ref: ref},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Metadata:       clusterv1.ObjectMeta{},
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-						},
-					},
-				},
-			},
-			in: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate: clusterv1.LocalObjectTemplate{Ref: ref},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Metadata:       clusterv1.ObjectMeta{},
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: incompatibleRef},
-								},
-							},
-						},
-					},
-				},
-			},
-			expectErr: true,
-		},
-		{
-			name: "update pass if a machine deployment class gets added",
-			old: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate: clusterv1.LocalObjectTemplate{Ref: ref},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-						},
-					},
-				},
-			},
-			in: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate: clusterv1.LocalObjectTemplate{Ref: ref},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-							{
-								Class: "bb",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-						},
-					},
-				},
-			},
-			expectErr: false,
-		},
-		{
-			name: "update fails if a duplicated deployment class gets added",
-			old: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate: clusterv1.LocalObjectTemplate{Ref: ref},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-						},
-					},
-				},
-			},
-			in: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate: clusterv1.LocalObjectTemplate{Ref: ref},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-						},
-					},
-				},
-			},
-			expectErr: true,
-		},
-		{
-			name: "update fails if a machine deployment class gets removed",
-			old: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate: clusterv1.LocalObjectTemplate{Ref: ref},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-							{
-								Class: "bb",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-						},
-					},
-				},
-			},
-			in: &clusterv1.ClusterClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: "default",
-				},
-				Spec: clusterv1.ClusterClassSpec{
-					Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-					ControlPlane: clusterv1.ControlPlaneClass{
-						LocalObjectTemplate: clusterv1.LocalObjectTemplate{Ref: ref},
-					},
-					Workers: clusterv1.WorkersClass{
-						MachineDeployments: []clusterv1.MachineDeploymentClass{
-							{
-								Class: "aa",
-								Template: clusterv1.MachineDeploymentClassTemplate{
-									Bootstrap:      clusterv1.LocalObjectTemplate{Ref: ref},
-									Infrastructure: clusterv1.LocalObjectTemplate{Ref: ref},
-								},
-							},
-						},
-					},
-				},
-			},
-			expectErr: true,
-		},
-	}
-
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			g := NewWithT(t)
-			webhook := &ClusterClass{}
-			if tt.expectErr {
-				g.Expect(webhook.validate(tt.old, tt.in)).NotTo(Succeed())
-			} else {
-				g.Expect(webhook.validate(tt.old, tt.in)).To(Succeed())
-			}
-		})
-	}
-}