Repository: kubernetes-sigs/cluster-api
Pull request #7893 (2023-01-10 18:49:18)

🌱 drop the draft release notes step from github workflow
<!-- please add an icon to the title of this PR (see https://sigs.k8s.io/cluster-api/CONTRIBUTING.md#contributing-a-patch), 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**:

Since the release team is taking care of generating the release notes as needed, dropping the step from the github workflow.

**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:
**Once this PR has been reviewed and has the lgtm label**, please assign cecilerobertmichon for approval by writing `/assign @cecilerobertmichon` in a comment. For more information see [the Kubernetes Code Review Process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process).

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:

- **[OWNERS](https://github.com/kubernetes-sigs/cluster-api/blob/main/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":["cecilerobertmichon"]} -->
ykakarap: cc @kubernetes-sigs/cluster-api-release-team 
k8s-ci-robot: LGTM label has been added.  <details>Git tree hash: d91553855915d234f301b1c47a972015c9b22e79</details>
joekr: /lgtm
hackeramitkumar: +1
/lgtm
nawazkh: /lgtm+

Patch:
diff --git a/.github/workflows/dependabot.yml b/.github/workflows/dependabot.yml
index 9df43336c..3f123df94 100644
--- a/.github/workflows/dependabot.yml
+++ b/.github/workflows/dependabot.yml
@@ -23,8 +23,8 @@ jobs:
         go-version: '1.19'
       id: go
     - name: Check out code into the Go module directory
-      uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3.3.0
-    - uses: actions/cache@58c146cc91c5b9e778e71775dfe9bf1442ad9a12 # tag=v3.2.3
+      uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # tag=v3.2.0
+    - uses: actions/cache@4723a57e26efda3a62cbde1812113b730952852d # tag=v3.2.2
       name: Restore go cache
       with:
         path: |
diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml
index 8de946dfe..a6206ee6e 100644
--- a/.github/workflows/golangci-lint.yml
+++ b/.github/workflows/golangci-lint.yml
@@ -18,7 +18,7 @@ jobs:
           - test
           - hack/tools
     steps:
-      - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3.3.0
+      - uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # tag=v3.2.0
       - uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # tag=v3.5.0
         with:
           go-version: 1.19
diff --git a/.github/workflows/lint-docs-pr.yaml b/.github/workflows/lint-docs-pr.yaml
index c6038fd72..bb540ce75 100644
--- a/.github/workflows/lint-docs-pr.yaml
+++ b/.github/workflows/lint-docs-pr.yaml
@@ -14,7 +14,7 @@ jobs:
     name: Broken Links
     runs-on: ubuntu-latest
     steps:
-    - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3.3.0
+    - uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # tag=v3.2.0
     - uses: gaurav-nelson/github-action-markdown-link-check@5c5dfc0ac2e225883c0e5f03a85311ec2830d368 # tag=v1
       with:
         use-quiet-mode: 'yes'
diff --git a/.github/workflows/lint-docs-weekly.yml b/.github/workflows/lint-docs-weekly.yml
index 1a375ddb9..3b35199b9 100644
--- a/.github/workflows/lint-docs-weekly.yml
+++ b/.github/workflows/lint-docs-weekly.yml
@@ -12,7 +12,7 @@ jobs:
     name: Broken Links
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3.3.0
+      - uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # tag=v3.2.0
       - uses: gaurav-nelson/github-action-markdown-link-check@5c5dfc0ac2e225883c0e5f03a85311ec2830d368 # tag=v1
         with:
           use-quiet-mode: 'yes'
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 817309621..fe3b49af7 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -17,7 +17,7 @@ jobs:
       - name: Set env
         run:  echo "RELEASE_TAG=${GITHUB_REF:10}" >> $GITHUB_ENV
       - name: checkout code
-        uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3.3.0
+        uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # tag=v3.2.0
         with:
           fetch-depth: 0
       - name: Install go
@@ -27,12 +27,9 @@ jobs:
       - name: generate release artifacts
         run: |
           make release
-      - name: generate release notes
-        run: |
-          make release-notes
       - name: Release
         uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # tag=v1
         with:
           draft: true
           files: out/*
-          body_path: _releasenotes/${{ env.RELEASE_TAG }}.md
+          body: "TODO: Copy release notes shared by the comms team"
diff --git a/.github/workflows/scan.yml b/.github/workflows/scan.yml
index abc86e2d2..648f337b1 100644
--- a/.github/workflows/scan.yml
+++ b/.github/workflows/scan.yml
@@ -9,19 +9,14 @@ permissions: {}
 
 jobs:
   scan:
-    strategy:
-      matrix:
-        branch: [ main, release-1.3, release-1.2 ]
     name: Trivy
     runs-on: ubuntu-latest
     steps:
     - name: Check out code
-      uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # tag=v3.3.0
-      with:
-        ref: ${{ matrix.branch }}
+      uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3.1.0
     - name: Setup go
       uses: actions/setup-go@d0a58c1c4d2b25278816e339b944508c875f3613 # tag=v3.4.0
       with:
         go-version: 1.19
     - name: Run verify container script
-      run: make verify-container-images
\ No newline at end of file
+      run: make verify-container-images
diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml
index 4f84c354c..0d0e27023 100644
--- a/.github/workflows/verify.yml
+++ b/.github/workflows/verify.yml
@@ -14,6 +14,9 @@ jobs:
     steps:
     - name: Verifier action
       id: verifier
-      uses: kubernetes-sigs/kubebuilder-release-tools@e90dee822876042e99b7584f99a9cc9f9d74ed17 # tag=v0.3.0
+      uses: kubernetes-sigs/kubebuilder-release-tools@v0.2.0
+      # Don't run this step on PRs created by the cherry-pick bot,
+      # as the PR description is too short, but otherwise the PRs are fine.
+      if: ${{ github.event.pull_request.head.repo.owner.login != 'k8s-infra-cherrypick-robot' }}
       with:
         github_token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.gitignore b/.gitignore
index f39502bcb..04c05814a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,11 +11,11 @@ hack/tools/bin
 *.test
 
 # E2E test templates
-test/e2e/data/infrastructure-docker/main/cluster-template*.yaml
-test/e2e/data/infrastructure-docker/v0.3/cluster-template*.yaml
-test/e2e/data/infrastructure-docker/v0.4/cluster-template*.yaml
-test/e2e/data/infrastructure-docker/v1.2/cluster-template*.yaml
-test/e2e/data/infrastructure-docker/v1.3/cluster-template*.yaml
+test/e2e/data/infrastructure-docker/v1alpha3/cluster-template*.yaml
+test/e2e/data/infrastructure-docker/v1alpha4/cluster-template*.yaml
+test/e2e/data/infrastructure-docker/v1beta1/v1.2/cluster-template*.yaml
+test/e2e/data/infrastructure-docker/v1beta1/v1.3/cluster-template*.yaml
+test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template*.yaml
 
 # E2e test extension deployment
 test/e2e/data/test-extension/deployment.yaml
diff --git a/Makefile b/Makefile
index 0926e89de..3eadbeb66 100644
--- a/Makefile
+++ b/Makefile
@@ -82,8 +82,8 @@ GINKGO_FOCUS ?=
 GINKGO_SKIP ?=
 GINKGO_NODES ?= 1
 GINKGO_TIMEOUT ?= 2h
-GINKGO_POLL_PROGRESS_AFTER ?= 60m
-GINKGO_POLL_PROGRESS_INTERVAL ?= 5m
+GINKGO_POLL_PROGRESS_AFTER ?= 10m
+GINKGO_POLL_PROGRESS_INTERVAL ?= 1m
 E2E_CONF_FILE ?= $(ROOT_DIR)/$(TEST_DIR)/e2e/config/docker.yaml
 SKIP_RESOURCE_CLEANUP ?= false
 USE_EXISTING_CLUSTER ?= false
@@ -111,7 +111,7 @@ SETUP_ENVTEST_BIN := setup-envtest
 SETUP_ENVTEST := $(abspath $(TOOLS_BIN_DIR)/$(SETUP_ENVTEST_BIN)-$(SETUP_ENVTEST_VER))
 SETUP_ENVTEST_PKG := sigs.k8s.io/controller-runtime/tools/setup-envtest
 
-CONTROLLER_GEN_VER := v0.11.1
+CONTROLLER_GEN_VER := v0.10.0
 CONTROLLER_GEN_BIN := controller-gen
 CONTROLLER_GEN := $(abspath $(TOOLS_BIN_DIR)/$(CONTROLLER_GEN_BIN)-$(CONTROLLER_GEN_VER))
 CONTROLLER_GEN_PKG := sigs.k8s.io/controller-tools/cmd/controller-gen
@@ -472,46 +472,56 @@ generate-modules: ## Run go mod tidy to ensure modules are up to date
 	cd $(TEST_DIR); go mod tidy
 
 .PHONY: generate-e2e-templates
-generate-e2e-templates: $(KUSTOMIZE) $(addprefix generate-e2e-templates-, v0.3 v0.4 v1.2 v1.3 main) ## Generate cluster templates for all versions
+generate-e2e-templates: $(KUSTOMIZE) $(addprefix generate-e2e-templates-, v1alpha3 v1alpha4 v1.2 v1.3 v1beta1) ## Generate cluster templates for all versions
 
 DOCKER_TEMPLATES := test/e2e/data/infrastructure-docker
 
-.PHONY: generate-e2e-templates-v0.3
-generate-e2e-templates-v0.3: $(KUSTOMIZE)
-	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/v0.3/cluster-template --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/v0.3/cluster-template.yaml
-
-.PHONY: generate-e2e-templates-v0.4
-generate-e2e-templates-v0.4: $(KUSTOMIZE)
-	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/v0.4/cluster-template --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/v0.4/cluster-template.yaml
+.PHONY: generate-e2e-templates-v1alpha3
+generate-e2e-templates-v1alpha3: $(KUSTOMIZE)
+	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/v1alpha3/cluster-template --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/v1alpha3/cluster-template.yaml
+
+.PHONY: generate-e2e-templates-v1alpha4
+generate-e2e-templates-v1alpha4: $(KUSTOMIZE)
+	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/v1alpha4/cluster-template --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/v1alpha4/cluster-template.yaml
+	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/v1alpha4/cluster-template-md-remediation --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/v1alpha4/cluster-template-md-remediation.yaml
+	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/v1alpha4/cluster-template-kcp-remediation --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/v1alpha4/cluster-template-kcp-remediation.yaml
+	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/v1alpha4/cluster-template-kcp-adoption/step1 --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/v1alpha4/cluster-template-kcp-adoption.yaml
+	echo "---" >> $(DOCKER_TEMPLATES)/v1alpha4/cluster-template-kcp-adoption.yaml
+	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/v1alpha4/cluster-template-kcp-adoption/step2 --load-restrictor LoadRestrictionsNone >> $(DOCKER_TEMPLATES)/v1alpha4/cluster-template-kcp-adoption.yaml
+	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/v1alpha4/cluster-template-machine-pool --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/v1alpha4/cluster-template-machine-pool.yaml
+	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/v1alpha4/cluster-template-node-drain --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/v1alpha4/cluster-template-node-drain.yaml
+	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/v1alpha4/cluster-template-upgrades --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/v1alpha4/cluster-template-upgrades.yaml
+	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/v1alpha4/cluster-template-kcp-scale-in --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/v1alpha4/cluster-template-kcp-scale-in.yaml
+	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/v1alpha4/cluster-template-ipv6 --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/v1alpha4/cluster-template-ipv6.yaml
 
 .PHONY: generate-e2e-templates-v1.2
 generate-e2e-templates-v1.2: $(KUSTOMIZE)
-	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/v1.2/cluster-template --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/v1.2/cluster-template.yaml
-	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/v1.2/cluster-template-topology --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/v1.2/cluster-template-topology.yaml
+	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/v1beta1/v1.2/cluster-template --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/v1beta1/v1.2/cluster-template.yaml
+	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/v1beta1/v1.2/cluster-template-topology --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/v1beta1/v1.2/cluster-template-topology.yaml
 
 .PHONY: generate-e2e-templates-v1.3
 generate-e2e-templates-v1.3: $(KUSTOMIZE)
-	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/v1.3/cluster-template --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/v1.3/cluster-template.yaml
-	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/v1.3/cluster-template-topology --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/v1.3/cluster-template-topology.yaml
-
-.PHONY: generate-e2e-templates-main
-generate-e2e-templates-main: $(KUSTOMIZE)
-	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/main/cluster-template --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/main/cluster-template.yaml
-	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/main/cluster-template-md-remediation --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/main/cluster-template-md-remediation.yaml
-	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/main/cluster-template-kcp-remediation --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/main/cluster-template-kcp-remediation.yaml
-	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/main/cluster-template-kcp-adoption/step1 --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/main/cluster-template-kcp-adoption.yaml
-	echo "---" >> $(DOCKER_TEMPLATES)/main/cluster-template-kcp-adoption.yaml
-	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/main/cluster-template-kcp-adoption/step2 --load-restrictor LoadRestrictionsNone >> $(DOCKER_TEMPLATES)/main/cluster-template-kcp-adoption.yaml
-	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/main/cluster-template-machine-pool --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/main/cluster-template-machine-pool.yaml
-	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/main/cluster-template-node-drain --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/main/cluster-template-node-drain.yaml
-	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/main/cluster-template-upgrades --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/main/cluster-template-upgrades.yaml
-	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/main/cluster-template-upgrades-cgroupfs --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/main/cluster-template-upgrades-cgroupfs.yaml
-	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/main/cluster-template-upgrades-runtimesdk --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/main/cluster-template-upgrades-runtimesdk.yaml
-	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/main/cluster-template-kcp-scale-in --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/main/cluster-template-kcp-scale-in.yaml
-	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/main/cluster-template-ipv6 --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/main/cluster-template-ipv6.yaml
-	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/main/cluster-template-topology-single-node-cluster --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/main/cluster-template-topology-single-node-cluster.yaml
-	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/main/cluster-template-topology --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/main/cluster-template-topology.yaml
-	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/main/cluster-template-ignition --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/main/cluster-template-ignition.yaml
+	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/v1beta1/v1.3/cluster-template --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/v1beta1/v1.3/cluster-template.yaml
+	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/v1beta1/v1.3/cluster-template-topology --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/v1beta1/v1.3/cluster-template-topology.yaml
+
+.PHONY: generate-e2e-templates-v1beta1
+generate-e2e-templates-v1beta1: $(KUSTOMIZE)
+	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/v1beta1/main/cluster-template --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/v1beta1/main/cluster-template.yaml
+	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/v1beta1/main/cluster-template-md-remediation --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/v1beta1/main/cluster-template-md-remediation.yaml
+	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/v1beta1/main/cluster-template-kcp-remediation --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/v1beta1/main/cluster-template-kcp-remediation.yaml
+	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/v1beta1/main/cluster-template-kcp-adoption/step1 --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/v1beta1/main/cluster-template-kcp-adoption.yaml
+	echo "---" >> $(DOCKER_TEMPLATES)/v1beta1/main/cluster-template-kcp-adoption.yaml
+	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/v1beta1/main/cluster-template-kcp-adoption/step2 --load-restrictor LoadRestrictionsNone >> $(DOCKER_TEMPLATES)/v1beta1/main/cluster-template-kcp-adoption.yaml
+	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/v1beta1/main/cluster-template-machine-pool --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/v1beta1/main/cluster-template-machine-pool.yaml
+	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/v1beta1/main/cluster-template-node-drain --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/v1beta1/main/cluster-template-node-drain.yaml
+	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/v1beta1/main/cluster-template-upgrades --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/v1beta1/main/cluster-template-upgrades.yaml
+	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/v1beta1/main/cluster-template-upgrades-cgroupfs --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/v1beta1/main/cluster-template-upgrades-cgroupfs.yaml
+	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/v1beta1/main/cluster-template-upgrades-runtimesdk --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/v1beta1/main/cluster-template-upgrades-runtimesdk.yaml
+	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/v1beta1/main/cluster-template-kcp-scale-in --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/v1beta1/main/cluster-template-kcp-scale-in.yaml
+	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/v1beta1/main/cluster-template-ipv6 --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/v1beta1/main/cluster-template-ipv6.yaml
+	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/v1beta1/main/cluster-template-topology-single-node-cluster --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/v1beta1/main/cluster-template-topology-single-node-cluster.yaml
+	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/v1beta1/main/cluster-template-topology --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/v1beta1/main/cluster-template-topology.yaml
+	$(KUSTOMIZE) build $(DOCKER_TEMPLATES)/v1beta1/main/cluster-template-ignition --load-restrictor LoadRestrictionsNone > $(DOCKER_TEMPLATES)/v1beta1/main/cluster-template-ignition.yaml
 
 .PHONY: generate-test-extension-deployment
 generate-test-extension-deployment: $(KUSTOMIZE)
@@ -524,7 +534,7 @@ generate-metrics-config: $(ENVSUBST_BIN) ## Generate ./hack/observability/kube-s
 	METRICS_DIR="${OBSERVABILITY_DIR}/kube-state-metrics/metrics"; \
 	echo "# This file was auto-generated via: make generate-metrics-config" > "$${OUTPUT_FILE}"; \
 	cat "$${METRICS_DIR}/header.yaml" >> "$${OUTPUT_FILE}"; \
-	for resource in cluster kubeadmcontrolplane machine machinedeployment machinehealthcheck machineset machinepool; do \
+	for resource in cluster kubeadmcontrolplane machine machinedeployment machinehealthcheck machineset; do \
 		cat "$${METRICS_DIR}/$${resource}.yaml"; \
 		RESOURCE="$${resource}" ${ENVSUBST_BIN} < "$${METRICS_DIR}/common_metrics.yaml"; \
 		if [[ "$${resource}" != "cluster" ]]; then \
diff --git a/api/v1beta1/common_types.go b/api/v1beta1/common_types.go
index d505d1420..c355d9d3b 100644
--- a/api/v1beta1/common_types.go
+++ b/api/v1beta1/common_types.go
@@ -146,7 +146,7 @@ const (
 
 // MachineAddress contains information for the node's address.
 type MachineAddress struct {
-	// Machine address type, one of Hostname, ExternalIP, InternalIP, ExternalDNS or InternalDNS.
+	// Machine address type, one of Hostname, ExternalIP or InternalIP.
 	Type MachineAddressType `json:"type"`
 
 	// The machine address.
diff --git a/api/v1beta1/zz_generated.openapi.go b/api/v1beta1/zz_generated.openapi.go
index 44f04c111..cda6c248b 100644
--- a/api/v1beta1/zz_generated.openapi.go
+++ b/api/v1beta1/zz_generated.openapi.go
@@ -1329,7 +1329,7 @@ func schema_sigsk8sio_cluster_api_api_v1beta1_MachineAddress(ref common.Referenc
 				Properties: map[string]spec.Schema{
 					"type": {
 						SchemaProps: spec.SchemaProps{
-							Description: "Machine address type, one of Hostname, ExternalIP, InternalIP, ExternalDNS or InternalDNS.",
+							Description: "Machine address type, one of Hostname, ExternalIP or InternalIP.",
 							Default:     "",
 							Type:        []string{"string"},
 							Format:      "",
diff --git a/bootstrap/kubeadm/config/crd/bases/bootstrap.cluster.x-k8s.io_kubeadmconfigs.yaml b/bootstrap/kubeadm/config/crd/bases/bootstrap.cluster.x-k8s.io_kubeadmconfigs.yaml
index 6075efcf9..1ae748175 100644
--- a/bootstrap/kubeadm/config/crd/bases/bootstrap.cluster.x-k8s.io_kubeadmconfigs.yaml
+++ b/bootstrap/kubeadm/config/crd/bases/bootstrap.cluster.x-k8s.io_kubeadmconfigs.yaml
@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   annotations:
-    controller-gen.kubebuilder.io/version: v0.11.1
+    controller-gen.kubebuilder.io/version: v0.10.0
   creationTimestamp: null
   name: kubeadmconfigs.bootstrap.cluster.x-k8s.io
 spec:
diff --git a/bootstrap/kubeadm/config/crd/bases/bootstrap.cluster.x-k8s.io_kubeadmconfigtemplates.yaml b/bootstrap/kubeadm/config/crd/bases/bootstrap.cluster.x-k8s.io_kubeadmconfigtemplates.yaml
index b2737f59b..b9b33cb1f 100644
--- a/bootstrap/kubeadm/config/crd/bases/bootstrap.cluster.x-k8s.io_kubeadmconfigtemplates.yaml
+++ b/bootstrap/kubeadm/config/crd/bases/bootstrap.cluster.x-k8s.io_kubeadmconfigtemplates.yaml
@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   annotations:
-    controller-gen.kubebuilder.io/version: v0.11.1
+    controller-gen.kubebuilder.io/version: v0.10.0
   creationTimestamp: null
   name: kubeadmconfigtemplates.bootstrap.cluster.x-k8s.io
 spec:
diff --git a/bootstrap/kubeadm/config/manager/manager.yaml b/bootstrap/kubeadm/config/manager/manager.yaml
index d54386179..19b342985 100644
--- a/bootstrap/kubeadm/config/manager/manager.yaml
+++ b/bootstrap/kubeadm/config/manager/manager.yaml
@@ -16,35 +16,27 @@ spec:
         control-plane: controller-manager
     spec:
       containers:
-        - command:
-            - /manager
-          args:
-            - "--leader-elect"
-            - "--metrics-bind-addr=localhost:8080"
-            - "--feature-gates=MachinePool=${EXP_MACHINE_POOL:=false},KubeadmBootstrapFormatIgnition=${EXP_KUBEADM_BOOTSTRAP_FORMAT_IGNITION:=false}"
-            - "--bootstrap-token-ttl=${KUBEADM_BOOTSTRAP_TOKEN_TTL:=15m}"
-          image: controller:latest
-          name: manager
-          ports:
-            - containerPort: 9440
-              name: healthz
-              protocol: TCP
-          readinessProbe:
-            httpGet:
-              path: /readyz
-              port: healthz
-          livenessProbe:
-            httpGet:
-              path: /healthz
-              port: healthz
-          securityContext:
-            allowPrivilegeEscalation: false
-            capabilities:
-              drop:
-                - ALL
-            privileged: false
-            runAsUser: 65532
-            runAsGroup: 65532
+      - command:
+        - /manager
+        args:
+        - "--leader-elect"
+        - "--metrics-bind-addr=localhost:8080"
+        - "--feature-gates=MachinePool=${EXP_MACHINE_POOL:=false},KubeadmBootstrapFormatIgnition=${EXP_KUBEADM_BOOTSTRAP_FORMAT_IGNITION:=false}"
+        - "--bootstrap-token-ttl=${KUBEADM_BOOTSTRAP_TOKEN_TTL:=15m}"
+        image: controller:latest
+        name: manager
+        ports:
+        - containerPort: 9440
+          name: healthz
+          protocol: TCP
+        readinessProbe:
+          httpGet:
+            path: /readyz
+            port: healthz
+        livenessProbe:
+          httpGet:
+            path: /healthz
+            port: healthz
       terminationGracePeriodSeconds: 10
       serviceAccountName: manager
       tolerations:
@@ -52,7 +44,3 @@ spec:
           key: node-role.kubernetes.io/master
         - effect: NoSchedule
           key: node-role.kubernetes.io/control-plane
-      securityContext:
-        runAsNonRoot: true
-        seccompProfile:
-          type: RuntimeDefault
diff --git a/cmd/clusterctl/client/config/cert_manager_client.go b/cmd/clusterctl/client/config/cert_manager_client.go
index 990b93824..179bb31bc 100644
--- a/cmd/clusterctl/client/config/cert_manager_client.go
+++ b/cmd/clusterctl/client/config/cert_manager_client.go
@@ -29,7 +29,7 @@ const (
 	CertManagerConfigKey = "cert-manager"
 
 	// CertManagerDefaultVersion defines the default cert-manager version to be used by clusterctl.
-	CertManagerDefaultVersion = "v1.11.0"
+	CertManagerDefaultVersion = "v1.10.1"
 
 	// CertManagerDefaultURL defines the default cert-manager repository url to be used by clusterctl.
 	// NOTE: At runtime CertManagerDefaultVersion may be replaced with the
diff --git a/cmd/clusterctl/cmd/generate_cluster.go b/cmd/clusterctl/cmd/generate_cluster.go
index 066a24a7e..bf125c9a3 100644
--- a/cmd/clusterctl/cmd/generate_cluster.go
+++ b/cmd/clusterctl/cmd/generate_cluster.go
@@ -42,8 +42,6 @@ type generateClusterOptions struct {
 	configMapDataKey   string
 
 	listVariables bool
-
-	output string
 }
 
 var gc = &generateClusterOptions{}
@@ -139,7 +137,6 @@ func init() {
 	// other flags
 	generateClusterClusterCmd.Flags().BoolVar(&gc.listVariables, "list-variables", false,
 		"Returns the list of variables expected by the template instead of the template yaml")
-	generateClusterClusterCmd.Flags().StringVar(&gc.output, "write-to", "", "Specify the output file to write the template to, defaults to STDOUT if the flag is not set")
 
 	generateCmd.AddCommand(generateClusterClusterCmd)
 }
@@ -195,5 +192,5 @@ func runGenerateClusterTemplate(cmd *cobra.Command, name string) error {
 		return printVariablesOutput(template, templateOptions)
 	}
 
-	return printYamlOutput(template, gc.output)
+	return printYamlOutput(template)
 }
diff --git a/cmd/clusterctl/cmd/generate_provider.go b/cmd/clusterctl/cmd/generate_provider.go
index c9a335f01..eb9bb3d90 100644
--- a/cmd/clusterctl/cmd/generate_provider.go
+++ b/cmd/clusterctl/cmd/generate_provider.go
@@ -34,7 +34,6 @@ type generateProvidersOptions struct {
 	targetNamespace          string
 	textOutput               bool
 	raw                      bool
-	outputFile               string
 }
 
 var gpo = &generateProvidersOptions{}
@@ -96,8 +95,6 @@ func init() {
 	generateProviderCmd.Flags().BoolVar(&gpo.raw, "raw", false,
 		"Generate configuration without variable substitution in a yaml format.")
 
-	generateProviderCmd.Flags().StringVar(&gpo.outputFile, "write-to", "", "Specify the output file to write the template to, defaults to STDOUT if the flag is not set")
-
 	generateCmd.AddCommand(generateProviderCmd)
 }
 
@@ -125,7 +122,7 @@ func runGenerateProviderComponents() error {
 		return printComponentsAsText(components)
 	}
 
-	return printYamlOutput(components, gpo.outputFile)
+	return printYamlOutput(components)
 }
 
 // parseProvider parses command line flags and returns the provider name and type.
diff --git a/cmd/clusterctl/cmd/util.go b/cmd/clusterctl/cmd/util.go
index 59440a132..3653b5c4e 100644
--- a/cmd/clusterctl/cmd/util.go
+++ b/cmd/clusterctl/cmd/util.go
@@ -32,23 +32,16 @@ import (
 	"sigs.k8s.io/cluster-api/cmd/clusterctl/client"
 )
 
-// printYamlOutput prints the yaml content of a generated template to stdout or to a local file if specified.
-func printYamlOutput(printer client.YamlPrinter, outputFile string) error {
+// printYamlOutput prints the yaml content of a generated template to stdout.
+func printYamlOutput(printer client.YamlPrinter) error {
 	yaml, err := printer.Yaml()
 	if err != nil {
 		return err
 	}
-	outputFile = filepath.Clean(strings.TrimSpace(outputFile))
 	yaml = append(yaml, '\n')
-	if outputFile == "" || outputFile == "-" {
-		if _, err := os.Stdout.Write(yaml); err != nil {
-			return errors.Wrap(err, "failed to write yaml to Stdout")
-		}
-		return nil
-	}
 
-	if err := os.WriteFile(outputFile, yaml, 0600); err != nil {
-		return errors.Wrap(err, "failed to write to destination file")
+	if _, err := os.Stdout.Write(yaml); err != nil {
+		return errors.Wrap(err, "failed to write yaml to Stdout")
 	}
 	return nil
 }
diff --git a/cmd/clusterctl/config/crd/bases/clusterctl.cluster.x-k8s.io_metadata.yaml b/cmd/clusterctl/config/crd/bases/clusterctl.cluster.x-k8s.io_metadata.yaml
index a7bc6faae..85a646a87 100644
--- a/cmd/clusterctl/config/crd/bases/clusterctl.cluster.x-k8s.io_metadata.yaml
+++ b/cmd/clusterctl/config/crd/bases/clusterctl.cluster.x-k8s.io_metadata.yaml
@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   annotations:
-    controller-gen.kubebuilder.io/version: v0.11.1
+    controller-gen.kubebuilder.io/version: v0.10.0
   creationTimestamp: null
   name: metadata.clusterctl.cluster.x-k8s.io
 spec:
diff --git a/cmd/clusterctl/config/crd/bases/clusterctl.cluster.x-k8s.io_providers.yaml b/cmd/clusterctl/config/crd/bases/clusterctl.cluster.x-k8s.io_providers.yaml
index ed30f3434..6ca01a62d 100644
--- a/cmd/clusterctl/config/crd/bases/clusterctl.cluster.x-k8s.io_providers.yaml
+++ b/cmd/clusterctl/config/crd/bases/clusterctl.cluster.x-k8s.io_providers.yaml
@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   annotations:
-    controller-gen.kubebuilder.io/version: v0.11.1
+    controller-gen.kubebuilder.io/version: v0.10.0
   creationTimestamp: null
   name: providers.clusterctl.cluster.x-k8s.io
 spec:
diff --git a/cmd/clusterctl/config/manifest/clusterctl-api.yaml b/cmd/clusterctl/config/manifest/clusterctl-api.yaml
index 8625909e2..7a2f4afcd 100644
--- a/cmd/clusterctl/config/manifest/clusterctl-api.yaml
+++ b/cmd/clusterctl/config/manifest/clusterctl-api.yaml
@@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   annotations:
-    controller-gen.kubebuilder.io/version: v0.11.1
+    controller-gen.kubebuilder.io/version: v0.10.0
   creationTimestamp: null
   name: providers.clusterctl.cluster.x-k8s.io
 spec:
diff --git a/config/crd/bases/addons.cluster.x-k8s.io_clusterresourcesetbindings.yaml b/config/crd/bases/addons.cluster.x-k8s.io_clusterresourcesetbindings.yaml
index d8f1629a0..d84f599e4 100644
--- a/config/crd/bases/addons.cluster.x-k8s.io_clusterresourcesetbindings.yaml
+++ b/config/crd/bases/addons.cluster.x-k8s.io_clusterresourcesetbindings.yaml
@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   annotations:
-    controller-gen.kubebuilder.io/version: v0.11.1
+    controller-gen.kubebuilder.io/version: v0.10.0
   creationTimestamp: null
   name: clusterresourcesetbindings.addons.cluster.x-k8s.io
 spec:
diff --git a/config/crd/bases/addons.cluster.x-k8s.io_clusterresourcesets.yaml b/config/crd/bases/addons.cluster.x-k8s.io_clusterresourcesets.yaml
index bfb0ec207..d495f3aa2 100644
--- a/config/crd/bases/addons.cluster.x-k8s.io_clusterresourcesets.yaml
+++ b/config/crd/bases/addons.cluster.x-k8s.io_clusterresourcesets.yaml
@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   annotations:
-    controller-gen.kubebuilder.io/version: v0.11.1
+    controller-gen.kubebuilder.io/version: v0.10.0
   creationTimestamp: null
   name: clusterresourcesets.addons.cluster.x-k8s.io
 spec:
diff --git a/config/crd/bases/cluster.x-k8s.io_clusterclasses.yaml b/config/crd/bases/cluster.x-k8s.io_clusterclasses.yaml
index 3dd293e2d..be491b3e6 100644
--- a/config/crd/bases/cluster.x-k8s.io_clusterclasses.yaml
+++ b/config/crd/bases/cluster.x-k8s.io_clusterclasses.yaml
@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   annotations:
-    controller-gen.kubebuilder.io/version: v0.11.1
+    controller-gen.kubebuilder.io/version: v0.10.0
   creationTimestamp: null
   name: clusterclasses.cluster.x-k8s.io
 spec:
diff --git a/config/crd/bases/cluster.x-k8s.io_clusters.yaml b/config/crd/bases/cluster.x-k8s.io_clusters.yaml
index d08afa6cc..688dd7ed4 100644
--- a/config/crd/bases/cluster.x-k8s.io_clusters.yaml
+++ b/config/crd/bases/cluster.x-k8s.io_clusters.yaml
@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   annotations:
-    controller-gen.kubebuilder.io/version: v0.11.1
+    controller-gen.kubebuilder.io/version: v0.10.0
   creationTimestamp: null
   name: clusters.cluster.x-k8s.io
 spec:
diff --git a/config/crd/bases/cluster.x-k8s.io_machinedeployments.yaml b/config/crd/bases/cluster.x-k8s.io_machinedeployments.yaml
index 0db04ab50..901d811fc 100644
--- a/config/crd/bases/cluster.x-k8s.io_machinedeployments.yaml
+++ b/config/crd/bases/cluster.x-k8s.io_machinedeployments.yaml
@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   annotations:
-    controller-gen.kubebuilder.io/version: v0.11.1
+    controller-gen.kubebuilder.io/version: v0.10.0
   creationTimestamp: null
   name: machinedeployments.cluster.x-k8s.io
 spec:
diff --git a/config/crd/bases/cluster.x-k8s.io_machinehealthchecks.yaml b/config/crd/bases/cluster.x-k8s.io_machinehealthchecks.yaml
index 99b6fdf54..eae496c8b 100644
--- a/config/crd/bases/cluster.x-k8s.io_machinehealthchecks.yaml
+++ b/config/crd/bases/cluster.x-k8s.io_machinehealthchecks.yaml
@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   annotations:
-    controller-gen.kubebuilder.io/version: v0.11.1
+    controller-gen.kubebuilder.io/version: v0.10.0
   creationTimestamp: null
   name: machinehealthchecks.cluster.x-k8s.io
 spec:
diff --git a/config/crd/bases/cluster.x-k8s.io_machinepools.yaml b/config/crd/bases/cluster.x-k8s.io_machinepools.yaml
index 68e2d0d3a..e13b44064 100644
--- a/config/crd/bases/cluster.x-k8s.io_machinepools.yaml
+++ b/config/crd/bases/cluster.x-k8s.io_machinepools.yaml
@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   annotations:
-    controller-gen.kubebuilder.io/version: v0.11.1
+    controller-gen.kubebuilder.io/version: v0.10.0
   creationTimestamp: null
   name: machinepools.cluster.x-k8s.io
 spec:
diff --git a/config/crd/bases/cluster.x-k8s.io_machines.yaml b/config/crd/bases/cluster.x-k8s.io_machines.yaml
index 4fdd74ec3..09c6282f0 100644
--- a/config/crd/bases/cluster.x-k8s.io_machines.yaml
+++ b/config/crd/bases/cluster.x-k8s.io_machines.yaml
@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   annotations:
-    controller-gen.kubebuilder.io/version: v0.11.1
+    controller-gen.kubebuilder.io/version: v0.10.0
   creationTimestamp: null
   name: machines.cluster.x-k8s.io
 spec:
@@ -951,8 +951,8 @@ spec:
                       description: The machine address.
                       type: string
                     type:
-                      description: Machine address type, one of Hostname, ExternalIP,
-                        InternalIP, ExternalDNS or InternalDNS.
+                      description: Machine address type, one of Hostname, ExternalIP
+                        or InternalIP.
                       type: string
                   required:
                   - address
diff --git a/config/crd/bases/cluster.x-k8s.io_machinesets.yaml b/config/crd/bases/cluster.x-k8s.io_machinesets.yaml
index bc02a0794..56ec3259a 100644
--- a/config/crd/bases/cluster.x-k8s.io_machinesets.yaml
+++ b/config/crd/bases/cluster.x-k8s.io_machinesets.yaml
@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   annotations:
-    controller-gen.kubebuilder.io/version: v0.11.1
+    controller-gen.kubebuilder.io/version: v0.10.0
   creationTimestamp: null
   name: machinesets.cluster.x-k8s.io
 spec:
diff --git a/config/crd/bases/ipam.cluster.x-k8s.io_ipaddressclaims.yaml b/config/crd/bases/ipam.cluster.x-k8s.io_ipaddressclaims.yaml
index 539dcfae4..f6e600c72 100644
--- a/config/crd/bases/ipam.cluster.x-k8s.io_ipaddressclaims.yaml
+++ b/config/crd/bases/ipam.cluster.x-k8s.io_ipaddressclaims.yaml
@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   annotations:
-    controller-gen.kubebuilder.io/version: v0.11.1
+    controller-gen.kubebuilder.io/version: v0.10.0
   creationTimestamp: null
   name: ipaddressclaims.ipam.cluster.x-k8s.io
 spec:
diff --git a/config/crd/bases/ipam.cluster.x-k8s.io_ipaddresses.yaml b/config/crd/bases/ipam.cluster.x-k8s.io_ipaddresses.yaml
index 4587244d5..d90142bbe 100644
--- a/config/crd/bases/ipam.cluster.x-k8s.io_ipaddresses.yaml
+++ b/config/crd/bases/ipam.cluster.x-k8s.io_ipaddresses.yaml
@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   annotations:
-    controller-gen.kubebuilder.io/version: v0.11.1
+    controller-gen.kubebuilder.io/version: v0.10.0
   creationTimestamp: null
   name: ipaddresses.ipam.cluster.x-k8s.io
 spec:
diff --git a/config/crd/bases/runtime.cluster.x-k8s.io_extensionconfigs.yaml b/config/crd/bases/runtime.cluster.x-k8s.io_extensionconfigs.yaml
index 3b8de2eff..8c2b8f79b 100644
--- a/config/crd/bases/runtime.cluster.x-k8s.io_extensionconfigs.yaml
+++ b/config/crd/bases/runtime.cluster.x-k8s.io_extensionconfigs.yaml
@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   annotations:
-    controller-gen.kubebuilder.io/version: v0.11.1
+    controller-gen.kubebuilder.io/version: v0.10.0
   creationTimestamp: null
   name: extensionconfigs.runtime.cluster.x-k8s.io
 spec:
diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml
index 5ac9b3967..9fd19a385 100644
--- a/config/manager/manager.yaml
+++ b/config/manager/manager.yaml
@@ -17,47 +17,39 @@ spec:
         control-plane: controller-manager
     spec:
       containers:
-        - command:
-            - /manager
-          args:
-            - "--leader-elect"
-            - "--metrics-bind-addr=localhost:8080"
-            - "--feature-gates=MachinePool=${EXP_MACHINE_POOL:=false},ClusterResourceSet=${EXP_CLUSTER_RESOURCE_SET:=false},ClusterTopology=${CLUSTER_TOPOLOGY:=false},RuntimeSDK=${EXP_RUNTIME_SDK:=false}"
-          image: controller:latest
-          name: manager
-          env:
-            - name: POD_NAMESPACE
-              valueFrom:
-                fieldRef:
-                  fieldPath: metadata.namespace
-            - name: POD_NAME
-              valueFrom:
-                fieldRef:
-                  fieldPath: metadata.name
-            - name: POD_UID
-              valueFrom:
-                fieldRef:
-                  fieldPath: metadata.uid
-          ports:
-            - containerPort: 9440
-              name: healthz
-              protocol: TCP
-          readinessProbe:
-            httpGet:
-              path: /readyz
-              port: healthz
-          livenessProbe:
-            httpGet:
-              path: /healthz
-              port: healthz
-          securityContext:
-            allowPrivilegeEscalation: false
-            capabilities:
-              drop:
-                - ALL
-            privileged: false
-            runAsUser: 65532
-            runAsGroup: 65532
+      - command:
+        - /manager
+        args:
+        - "--leader-elect"
+        - "--metrics-bind-addr=localhost:8080"
+        - "--feature-gates=MachinePool=${EXP_MACHINE_POOL:=false},ClusterResourceSet=${EXP_CLUSTER_RESOURCE_SET:=false},ClusterTopology=${CLUSTER_TOPOLOGY:=false},RuntimeSDK=${EXP_RUNTIME_SDK:=false}"
+        image: controller:latest
+        name: manager
+        env:
+        - name: POD_NAMESPACE
+          valueFrom:
+            fieldRef:
+              fieldPath: metadata.namespace
+        - name: POD_NAME
+          valueFrom:
+            fieldRef:
+              fieldPath: metadata.name
+        - name: POD_UID
+          valueFrom:
+            fieldRef:
+              fieldPath: metadata.uid
+        ports:
+        - containerPort: 9440
+          name: healthz
+          protocol: TCP
+        readinessProbe:
+          httpGet:
+            path: /readyz
+            port: healthz
+        livenessProbe:
+          httpGet:
+            path: /healthz
+            port: healthz
       terminationGracePeriodSeconds: 10
       serviceAccountName: manager
       tolerations:
@@ -65,7 +57,3 @@ spec:
           key: node-role.kubernetes.io/master
         - effect: NoSchedule
           key: node-role.kubernetes.io/control-plane
-      securityContext:
-        runAsNonRoot: true
-        seccompProfile:
-          type: RuntimeDefault
diff --git a/controlplane/kubeadm/config/crd/bases/controlplane.cluster.x-k8s.io_kubeadmcontrolplanes.yaml b/controlplane/kubeadm/config/crd/bases/controlplane.cluster.x-k8s.io_kubeadmcontrolplanes.yaml
index ed855c19a..cdb28bee5 100644
--- a/controlplane/kubeadm/config/crd/bases/controlplane.cluster.x-k8s.io_kubeadmcontrolplanes.yaml
+++ b/controlplane/kubeadm/config/crd/bases/controlplane.cluster.x-k8s.io_kubeadmcontrolplanes.yaml
@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   annotations:
-    controller-gen.kubebuilder.io/version: v0.11.1
+    controller-gen.kubebuilder.io/version: v0.10.0
   creationTimestamp: null
   name: kubeadmcontrolplanes.controlplane.cluster.x-k8s.io
 spec:
diff --git a/controlplane/kubeadm/config/crd/bases/controlplane.cluster.x-k8s.io_kubeadmcontrolplanetemplates.yaml b/controlplane/kubeadm/config/crd/bases/controlplane.cluster.x-k8s.io_kubeadmcontrolplanetemplates.yaml
index 668c5f5be..ef9869f54 100644
--- a/controlplane/kubeadm/config/crd/bases/controlplane.cluster.x-k8s.io_kubeadmcontrolplanetemplates.yaml
+++ b/controlplane/kubeadm/config/crd/bases/controlplane.cluster.x-k8s.io_kubeadmcontrolplanetemplates.yaml
@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   annotations:
-    controller-gen.kubebuilder.io/version: v0.11.1
+    controller-gen.kubebuilder.io/version: v0.10.0
   creationTimestamp: null
   name: kubeadmcontrolplanetemplates.controlplane.cluster.x-k8s.io
 spec:
diff --git a/controlplane/kubeadm/config/manager/manager.yaml b/controlplane/kubeadm/config/manager/manager.yaml
index 34e85f86e..1566e010a 100644
--- a/controlplane/kubeadm/config/manager/manager.yaml
+++ b/controlplane/kubeadm/config/manager/manager.yaml
@@ -16,47 +16,39 @@ spec:
         control-plane: controller-manager
     spec:
       containers:
-        - command:
-            - /manager
-          args:
-            - "--leader-elect"
-            - "--metrics-bind-addr=localhost:8080"
-            - "--feature-gates=ClusterTopology=${CLUSTER_TOPOLOGY:=false},KubeadmBootstrapFormatIgnition=${EXP_KUBEADM_BOOTSTRAP_FORMAT_IGNITION:=false}"
-          image: controller:latest
-          name: manager
-          env:
-            - name: POD_NAMESPACE
-              valueFrom:
-                fieldRef:
-                  fieldPath: metadata.namespace
-            - name: POD_NAME
-              valueFrom:
-                fieldRef:
-                  fieldPath: metadata.name
-            - name: POD_UID
-              valueFrom:
-                fieldRef:
-                  fieldPath: metadata.uid
-          ports:
-            - containerPort: 9440
-              name: healthz
-              protocol: TCP
-          readinessProbe:
-            httpGet:
-              path: /readyz
-              port: healthz
-          livenessProbe:
-            httpGet:
-              path: /healthz
-              port: healthz
-          securityContext:
-            allowPrivilegeEscalation: false
-            capabilities:
-              drop:
-                - ALL
-            privileged: false
-            runAsUser: 65532
-            runAsGroup: 65532
+      - command:
+        - /manager
+        args:
+        - "--leader-elect"
+        - "--metrics-bind-addr=localhost:8080"
+        - "--feature-gates=ClusterTopology=${CLUSTER_TOPOLOGY:=false},KubeadmBootstrapFormatIgnition=${EXP_KUBEADM_BOOTSTRAP_FORMAT_IGNITION:=false}"
+        image: controller:latest
+        name: manager
+        env:
+        - name: POD_NAMESPACE
+          valueFrom:
+            fieldRef:
+              fieldPath: metadata.namespace
+        - name: POD_NAME
+          valueFrom:
+            fieldRef:
+              fieldPath: metadata.name
+        - name: POD_UID
+          valueFrom:
+            fieldRef:
+              fieldPath: metadata.uid
+        ports:
+        - containerPort: 9440
+          name: healthz
+          protocol: TCP
+        readinessProbe:
+          httpGet:
+            path: /readyz
+            port: healthz
+        livenessProbe:
+          httpGet:
+            path: /healthz
+            port: healthz
       terminationGracePeriodSeconds: 10
       serviceAccountName: manager
       tolerations:
@@ -64,7 +56,3 @@ spec:
           key: node-role.kubernetes.io/master
         - effect: NoSchedule
           key: node-role.kubernetes.io/control-plane
-      securityContext:
-        runAsNonRoot: true
-        seccompProfile:
-          type: RuntimeDefault
diff --git a/docs/book/src/clusterctl/commands/init.md b/docs/book/src/clusterctl/commands/init.md
index 9acf8c0a5..ee4b9501f 100644
--- a/docs/book/src/clusterctl/commands/init.md
+++ b/docs/book/src/clusterctl/commands/init.md
@@ -190,7 +190,7 @@ If this happens, there are no guarantees about the proper functioning of `cluste
 Cluster API providers require a cert-manager version supporting the `cert-manager.io/v1` API to be installed in the cluster.
 
 While doing init, clusterctl checks if there is a version of cert-manager already installed. If not, clusterctl will
-install a default version (currently cert-manager v1.11.0). See [clusterctl configuration](../configuration.md) for
+install a default version (currently cert-manager v1.10.1). See [clusterctl configuration](../configuration.md) for
 available options to customize this operation.
 
 <aside class="note warning">
diff --git a/docs/book/src/developer/guide.md b/docs/book/src/developer/guide.md
index f5b1de61b..fbb6e275a 100644
--- a/docs/book/src/developer/guide.md
+++ b/docs/book/src/developer/guide.md
@@ -81,7 +81,7 @@ The generated binary can be found at ./hack/tools/bin/envsubst
 You'll need to deploy [cert-manager] components on your [management cluster][mcluster], using `kubectl`
 
 ```bash
-kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.11.0/cert-manager.yaml
+kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.10.1/cert-manager.yaml
 ```
 
 Ensure the cert-manager webhook service is ready before creating the Cluster API components.
diff --git a/docs/book/src/developer/providers/v1.3-to-v1.4.md b/docs/book/src/developer/providers/v1.3-to-v1.4.md
index 1f783808e..fd19f69e2 100644
--- a/docs/book/src/developer/providers/v1.3-to-v1.4.md
+++ b/docs/book/src/developer/providers/v1.3-to-v1.4.md
@@ -5,13 +5,12 @@ maintainers of providers and consumers of our Go API.
 
 ## Minimum Go version
 
-- The Go version used by Cluster API is still Go 1.19.x
+* The Go version used by Cluster API is still Go 1.19.x
 
 ## Dependencies
 
 **Note**: Only the most relevant dependencies are listed, `k8s.io/` and `ginkgo`/`gomega` dependencies in Cluster API are kept in sync with the versions used by `sigs.k8s.io/controller-runtime`.
 
-- sigs.k8s.io/controller-tools: v0.10.x => v0.11.x
 
 ## Changes by Kind
 
@@ -36,9 +35,5 @@ maintainers of providers and consumers of our Go API.
 ### Other
 
 - `clusterctl upgrade apply` no longer requires a namespace when updating providers. It is now optional and in a future release it will be deprecated. The new syntax is `[namespace/]provider:version`.
-- `WatchDeploymentLogs` is changed to `WatchDeploymentLogsByName`, it works same as before. Another function `WatchDeploymentLogsByLabelSelector` is added to stream logs of deployment by label selector.
-- Cluster API controllers are now using an explicit security context by default.
 
 ### Suggested changes for providers
-
-- Providers should add an explicit security context to their controllers deployment, see [#7831](https://github.com/kubernetes-sigs/cluster-api/pull/7831) for reference.
diff --git a/docs/book/src/developer/tilt.md b/docs/book/src/developer/tilt.md
index 987f7561c..e5474228c 100644
--- a/docs/book/src/developer/tilt.md
+++ b/docs/book/src/developer/tilt.md
@@ -36,17 +36,7 @@ kubectl cluster-info --context kind-capi-test
 
 ### Create a tilt-settings file
 
-Next, create a `tilt-settings.yaml` file and place it in your local copy of `cluster-api`. Here is an example that uses the components from the CAPI repo:
-
-```yaml
-default_registry: gcr.io/your-project-name-here
-enable_providers:
-- docker
-- kubeadm-bootstrap
-- kubeadm-control-plane
-```
-
-To use tilt to launch a provider with its own repo, using Cluster API Provider AWS here, `tilt-settings.yaml` should look like: 
+Next, create a `tilt-settings.yaml` file and place it in your local copy of `cluster-api`. Here is an example:
 
 ```yaml
 default_registry: gcr.io/your-project-name-here
@@ -54,6 +44,7 @@ provider_repos:
 - ../cluster-api-provider-aws
 enable_providers:
 - aws
+- docker
 - kubeadm-bootstrap
 - kubeadm-control-plane
 ```
@@ -374,7 +365,7 @@ A provider must supply a `tilt-provider.yaml` file describing how to build it. H
 ```yaml
 name: aws
 config:
-  image: "gcr.io/k8s-staging-cluster-api-aws/cluster-api-aws-controller"
+  image: "gcr.io/k8s-staging-cluster-api-aws/cluster-api-aws-controller",
   live_reload_deps: ["main.go", "go.mod", "go.sum", "api", "cmd", "controllers", "pkg"]
   label: CAPA
 ```
diff --git a/docs/book/src/reference/jobs.md b/docs/book/src/reference/jobs.md
index e2dc03516..f318b78f9 100644
--- a/docs/book/src/reference/jobs.md
+++ b/docs/book/src/reference/jobs.md
@@ -27,7 +27,7 @@ Prow Presubmits:
   * GINKGO_FOCUS: `[IPv6] [PR-Informing]`, IP_FAMILY: `IPv6`
 * ✳️️ ✴️ [pull-cluster-api-e2e-full-main] `./scripts/ci-e2e.sh`
   * GINKGO_SKIP: `[PR-Blocking] [Conformance] [K8s-Upgrade] [IPv6]` (i.e. "no tags")
-* ✳️️ ✴️ [pull-cluster-api-e2e-workload-upgrade-1-26-latest-main] `./scripts/ci-e2e.sh` FROM: `stable-1.26` TO: `ci/latest-1.27`
+* ✳️️ ✴️ [pull-cluster-api-e2e-workload-upgrade-1-25-latest-main] `./scripts/ci-e2e.sh` FROM: `stable-1.25` TO: `ci/latest-1.26`
   * GINKGO_FOCUS: `[K8s-Upgrade]`
 
 GitHub Presubmit Workflows:
@@ -37,7 +37,7 @@ GitHub Presubmit Workflows:
   * Verifies the PR titles have a valid format, i.e. contains one of the valid icons.
   * Verifies the PR description is valid, i.e. is long enough.
 * Check PR Markdown links (run when markdown files changed)
-  * Checks markdown for broken links.
+  * Checks markdown for broken links. 
 * dependabot (run on dependabot PRs)
   * Regenerates Go modules and code.
 * release (run on tags)
@@ -60,7 +60,7 @@ Prow Postsubmits:
 Prow Periodics:
 * [periodic-cluster-api-test-main] `./scripts/ci-test.sh`
 * [periodic-cluster-api-test-mink8s-main] `./scripts/ci-test.sh`
-  * KUBEBUILDER_ENVTEST_KUBERNETES_VERSION: `1.20.2`
+  * KUBEBUILDER_ENVTEST_KUBERNETES_VERSION: `1.20.2` 
 * [periodic-cluster-api-e2e-main] `./scripts/ci-e2e.sh`
   * GINKGO_SKIP: `[Conformance] [K8s-Upgrade]|[IPv6]`
 * [periodic-cluster-api-e2e-mink8s-main] `./scripts/ci-e2e.sh`
@@ -80,20 +80,18 @@ Prow Periodics:
   * GINKGO_FOCUS: `[K8s-Upgrade]`
 * [periodic-cluster-api-e2e-workload-upgrade-1-24-1-25-main] `./scripts/ci-e2e.sh` FROM: `stable-1.24` TO: `stable-1.25`
   * GINKGO_FOCUS: `[K8s-Upgrade]`
-* [periodic-cluster-api-e2e-workload-upgrade-1-25-1-26-main] `./scripts/ci-e2e.sh` FROM: `stable-1.25` TO: `stable-1.26`
-  * GINKGO_FOCUS: `[K8s-Upgrade]`
-* [periodic-cluster-api-e2e-workload-upgrade-1-26-latest-main] `./scripts/ci-e2e.sh` FROM: `stable-1.26` TO: `ci/latest-1.27`
+* [periodic-cluster-api-e2e-workload-upgrade-1-25-latest-main] `./scripts/ci-e2e.sh` FROM: `stable-1.25` TO: `ci/latest-1.26`
   * GINKGO_FOCUS: `[K8s-Upgrade]`
 * [cluster-api-push-images-nightly] Google Cloud Build: `make release-staging-nightly`
 
 ## Test-infra configuration
 
 * config/jobs/image-pushing/k8s-staging-cluster-api.yaml
-  * Configures nightly and postsubmit jobs to push images and manifests.
+  * Configures nightly and postsubmit jobs to push images and manifests. 
 * config/jobs/kubernetes-sigs/cluster-api/
   * Configures Cluster API  presubmit and periodic jobs.
 * config/testgrids/kubernetes/sig-cluster-lifecycle/config.yaml
-  * Configures Cluster API testgrid dashboards.
+  * Configures Cluster API testgrid dashboards.  
 * config/prow/config.yaml
   * `branch-protection` and `tide` are configured to make the golangci-lint GitHub action mandatory for merge
 * config/prow/plugins.yaml
@@ -105,7 +103,7 @@ Prow Periodics:
   * `plugins`: enables `milestone`, `override` and `require-matching-label` plugins
   * `external_plugins`: enables `cherrypicker`
 * label_sync/labels.yaml
-  * Configures labels for the `cluster-api` repository.
+  * Configures labels for the `cluster-api` repository. 
 
 
 <!-- links -->
@@ -118,7 +116,7 @@ Prow Periodics:
 [pull-cluster-api-e2e-informing-main]: https://testgrid.k8s.io/sig-cluster-lifecycle-cluster-api#capi-pr-e2e-informing-main
 [pull-cluster-api-e2e-informing-ipv6-main]: https://testgrid.k8s.io/sig-cluster-lifecycle-cluster-api#capi-pr-e2e-informing-ipv6-main
 [pull-cluster-api-e2e-full-main]: https://testgrid.k8s.io/sig-cluster-lifecycle-cluster-api#capi-pr-e2e-full-main
-[pull-cluster-api-e2e-workload-upgrade-1-26-latest-main]: https://testgrid.k8s.io/sig-cluster-lifecycle-cluster-api#capi-pr-e2e-main-1-26-latest
+[pull-cluster-api-e2e-workload-upgrade-1-25-latest-main]: https://testgrid.k8s.io/sig-cluster-lifecycle-cluster-api#capi-pr-e2e-main-1-25-latest
 [periodic-cluster-api-test-main]: https://testgrid.k8s.io/sig-cluster-lifecycle-cluster-api#capi-test-main
 [periodic-cluster-api-test-mink8s-main]: https://testgrid.k8s.io/sig-cluster-lifecycle-cluster-api#capi-test-mink8s-main
 [periodic-cluster-api-e2e-main]: https://testgrid.k8s.io/sig-cluster-lifecycle-cluster-api#capi-e2e-main
@@ -132,7 +130,6 @@ Prow Periodics:
 [periodic-cluster-api-e2e-workload-upgrade-1-22-1-23-main]: https://testgrid.k8s.io/sig-cluster-lifecycle-cluster-api#capi-e2e-main-1-22-1-23
 [periodic-cluster-api-e2e-workload-upgrade-1-23-1-24-main]: https://testgrid.k8s.io/sig-cluster-lifecycle-cluster-api#capi-e2e-main-1-23-1-24
 [periodic-cluster-api-e2e-workload-upgrade-1-24-1-25-main]: https://testgrid.k8s.io/sig-cluster-lifecycle-cluster-api#capi-e2e-main-1-24-1-25
-[periodic-cluster-api-e2e-workload-upgrade-1-25-1-26-main]: https://testgrid.k8s.io/sig-cluster-lifecycle-cluster-api#capi-e2e-main-1-25-1-26
-[periodic-cluster-api-e2e-workload-upgrade-1-26-latest-main]: https://testgrid.k8s.io/sig-cluster-lifecycle-cluster-api#capi-e2e-main-1-26-latest
+[periodic-cluster-api-e2e-workload-upgrade-1-25-latest-main]: https://testgrid.k8s.io/sig-cluster-lifecycle-cluster-api#capi-e2e-main-1-25-latest
 [cluster-api-push-images-nightly]: https://testgrid.k8s.io/sig-cluster-lifecycle-image-pushes#cluster-api-push-images-nightly
 [post-cluster-api-push-images]: https://testgrid.k8s.io/sig-cluster-lifecycle-image-pushes#post-cluster-api-push-images
diff --git a/docs/book/src/reference/versions.md b/docs/book/src/reference/versions.md
index 5e3b8ca65..4c53ff08e 100644
--- a/docs/book/src/reference/versions.md
+++ b/docs/book/src/reference/versions.md
@@ -15,17 +15,17 @@ All Infrastructure Providers are maintained by independent teams. Other Bootstra
 
 ## Supported Kubernetes Versions
 
-The project aims to keep the current minor release compatible with the actively supported Kubernetes minor releases, i.e.,
+The project aims to keep the current minor release compatible with the actively supported Kubernetes minor releases, i.e., 
 the current release (N), N-1, and N-2. Where possible we will go above and beyond this trying to help our users support
 both newer and older versions of Kubernetes:
 
-- For a given Cluster API minor release, we give best-effort support for future Kubernetes versions that are released
+- For a given Cluster API minor release, we give best-effort support for future Kubernetes versions that are released 
 	during the release's active support period. Depending on the changes made in Kubernetes, users may be required to
 	update to the next patch release of Cluster API to maintain compatibility.
 - In some cases where support for future Kubernetes versions can't be added, or is considered not practical or too risky
 	adding it, the Kubernetes version support matrix for an existing Cluster API minor release will stop at the last supported version.
 - Cluster API offers best-effort support for older Kubernetes versions where possible.
-	Important! this is not a replacement/alternative for upstream Kubernetes support policies!
+	Important! this is not a replacement/alternative for upstream Kubernetes support policies! 
 	Support for older version of Kubernetes is limited to "Cluster API can start a Cluster with this Kubernetes version"
 	and "Cluster API  can upgrade to the next Kubernetes version"; it does not include any extended support to Kubernetes itself.
 
@@ -33,7 +33,7 @@ Whenever a new Cluster API release is cut, we will document the Kubernetes versi
 has been tested with. Summaries of Kubernetes versions supported by each component are additionally maintained in
 the [tables](#release-components) below.
 
-On a final comment, let's praise all the contributors keeping care of such a wide support matrix.
+On a final comment, let's praise all the contributors keeping care of such a wide support matrix. 
 If someone is looking for opportunities to help with the project, this is definitely an area where additional hands
 and eyes will be more than welcome and greatly beneficial to the entire community.
 
@@ -75,7 +75,7 @@ These diagrams show the relationships between components in a Cluster API releas
 | Kubernetes v1.23* |                      | ✓                 | ✓                 | ✓                 | ✓                 | ✓                 | ✓                 |
 | Kubernetes v1.24  |                      |                   |                   | ✓                 | ✓                 | ✓                 | ✓                 |
 | Kubernetes v1.25  |                      |                   |                   |                   | ✓                 | ✓                 | ✓                 |
-| Kubernetes v1.26  |                      |                   |                   |                   | ✓                 | ✓                 | ✓                 |
+| Kubernetes v1.26  |                      |                   |                   |                   |                   |                   |                   |
 
 
 \* There is an issue with CRDs in Kubernetes v1.23.{0-2}. ClusterClass with patches is affected by that (for more details please see [this issue](https://github.com/kubernetes-sigs/cluster-api/issues/5990)). Therefore we recommend to use Kubernetes v1.23.3+ with ClusterClass.
@@ -99,7 +99,7 @@ The Core Provider also talks to API server of every Workload Cluster. Therefore,
 | Kubernetes v1.23 + kubeadm/v1beta3                                 |                      | ✓                    | ✓                   | ✓                 | ✓                 | ✓                 | ✓                 |
 | Kubernetes v1.24 + kubeadm/v1beta3                                 |                      |                      |                     | ✓                 | ✓                 | ✓                 | ✓                 |
 | Kubernetes v1.25 + kubeadm/v1beta3                                 |                      |                      |                     |                   | ✓                 | ✓                 | ✓                 |
-| Kubernetes v1.26 + kubeadm/v1beta3                                 |                      |                      |                     |                   | ✓                 | ✓                 | ✓                 |
+| Kubernetes v1.26 + kubeadm/v1beta3                                 |                      |                      |                     |                   |                   |                   |                   |
 
 The Kubeadm Bootstrap Provider generates kubeadm configuration using the API version recommended for the target Kubernetes version.
 
@@ -117,7 +117,7 @@ The Kubeadm Bootstrap Provider generates kubeadm configuration using the API ver
 | Kubernetes v1.23 + etcd/v3 |                      | ✓*                   | ✓*                  | ✓                 | ✓                 | ✓                 | ✓                 |
 | Kubernetes v1.24 + etcd/v3 |                      |                      |                     | ✓                 | ✓                 | ✓                 | ✓                 |
 | Kubernetes v1.25 + etcd/v3 |                      |                      |                     |                   | ✓                 | ✓                 | ✓                 |
-| Kubernetes v1.26 + etcd/v3 |                      |                      |                     |                   | ✓                 | ✓                 | ✓                 |
+| Kubernetes v1.26 + etcd/v3 |                      |                      |                     |                   |                   |                   |                   |
 
 The Kubeadm Control Plane Provider talks to the API server and etcd members of every Workload Cluster whose control plane it owns. It uses the etcd v3 API.
 
diff --git a/docs/book/src/tasks/experimental-features/runtime-sdk/implement-extensions.md b/docs/book/src/tasks/experimental-features/runtime-sdk/implement-extensions.md
index ed4873865..ae8a9a3bd 100644
--- a/docs/book/src/tasks/experimental-features/runtime-sdk/implement-extensions.md
+++ b/docs/book/src/tasks/experimental-features/runtime-sdk/implement-extensions.md
@@ -46,8 +46,8 @@ import (
 	"github.com/spf13/pflag"
 	cliflag "k8s.io/component-base/cli/flag"
 	"k8s.io/component-base/logs"
-	logsv1 "k8s.io/component-base/logs/api/v1"
 	"k8s.io/klog/v2"
+	"k8s.io/utils/pointer"
 	ctrl "sigs.k8s.io/controller-runtime"
 
 	runtimecatalog "sigs.k8s.io/cluster-api/exp/runtime/catalog"
@@ -75,7 +75,7 @@ func init() {
 func InitFlags(fs *pflag.FlagSet) {
 	// Initialize logs flags using Kubernetes component-base machinery.
 	logs.AddFlags(fs, logs.SkipLoggingConfigurationFlags())
-	logsv1.AddFlags(logOptions, fs)
+	logOptions.AddFlags(fs)
 
 	// Add test-extension specific flags
 	fs.StringVar(&profilerAddress, "profiler-address", "",
@@ -99,7 +99,7 @@ func main() {
 	pflag.Parse()
 
 	// Validates logs flags using Kubernetes component-base machinery and applies them
-	if err := logsv1.ValidateAndApply(logOptions, nil); err != nil {
+	if err := logOptions.ValidateAndApply(nil); err != nil {
 		setupLog.Error(err, "unable to start extension")
 		os.Exit(1)
 	}
@@ -128,17 +128,17 @@ func main() {
 
 	// Register extension handlers.
 	if err := webhookServer.AddExtensionHandler(server.ExtensionHandler{
-		Hook:        runtimehooksv1.BeforeClusterCreate,
-		Name:        "before-cluster-create",
-		HandlerFunc: DoBeforeClusterCreate,
+		Hook:           runtimehooksv1.BeforeClusterCreate,
+		Name:           "before-cluster-create",
+		HandlerFunc:    DoBeforeClusterCreate,
 	}); err != nil {
 		setupLog.Error(err, "error adding handler")
 		os.Exit(1)
 	}
 	if err := webhookServer.AddExtensionHandler(server.ExtensionHandler{
-		Hook:        runtimehooksv1.BeforeClusterUpgrade,
-		Name:        "before-cluster-upgrade",
-		HandlerFunc: DoBeforeClusterUpgrade,
+		Hook:           runtimehooksv1.BeforeClusterUpgrade,
+		Name:           "before-cluster-upgrade",
+		HandlerFunc:    DoBeforeClusterUpgrade,
 	}); err != nil {
 		setupLog.Error(err, "error adding handler")
 		os.Exit(1)
@@ -292,16 +292,6 @@ controllers processing those resource that might impact system stability.
 
 </aside>
 
-### Settings
-
-Settings can be added to the ExtensionConfig object in the form of a map with string keys and values. These settings are
-sent with each request to hooks registered by that ExtensionConfig. Extension developers can implement behavior in their
-extensions to alter behavior based on these settings. Settings should be well documented by extension developers so that 
-ClusterClass authors can understand usage and expected behaviour.
-
-Settings can be provided for individual external patches by providing them in the ClusterClass `.spec.patches[*].external.settings`.
-This can be used to overwrite settings at the ExtensionConfig level for that patch.
-
 ### Error management
 
 In case a Runtime Extension returns an error, the error will be handled according to the corresponding failure policy
diff --git a/docs/book/src/tasks/experimental-features/runtime-sdk/implement-lifecycle-hooks.md b/docs/book/src/tasks/experimental-features/runtime-sdk/implement-lifecycle-hooks.md
index 5c8220797..21c11ec27 100644
--- a/docs/book/src/tasks/experimental-features/runtime-sdk/implement-lifecycle-hooks.md
+++ b/docs/book/src/tasks/experimental-features/runtime-sdk/implement-lifecycle-hooks.md
@@ -46,7 +46,6 @@ determine/prepare add-ons for the Cluster and block the creation of those object
 ```yaml
 apiVersion: hooks.runtime.cluster.x-k8s.io/v1alpha1
 kind: BeforeClusterCreateRequest
-settings: <Runtime Extension settings>
 cluster:
   apiVersion: cluster.x-k8s.io/v1beta1
   kind: Cluster
@@ -85,7 +84,6 @@ possible once the Control Plane is available. This hook does not block any furth
 ```yaml
 apiVersion: hooks.runtime.cluster.x-k8s.io/v1alpha1
 kind: AfterControlPlaneInitializedRequest
-settings: <Runtime Extension settings>
 cluster:
   apiVersion: cluster.x-k8s.io/v1beta1
   kind: Cluster
@@ -120,7 +118,6 @@ can use this hook to execute pre-upgrade add-on tasks and block upgrades of the
 ```yaml
 apiVersion: hooks.runtime.cluster.x-k8s.io/v1alpha1
 kind: BeforeClusterUpgradeRequest
-settings: <Runtime Extension settings>
 cluster:
   apiVersion: cluster.x-k8s.io/v1beta1
   kind: Cluster
@@ -163,7 +160,6 @@ until everything is ready.
 ```yaml
 apiVersion: hooks.runtime.cluster.x-k8s.io/v1alpha1
 kind: AfterControlPlaneUpgradeRequest
-settings: <Runtime Extension settings>
 cluster:
   apiVersion: cluster.x-k8s.io/v1beta1
   kind: Cluster
@@ -200,7 +196,6 @@ This hook does not block any further changes or upgrades to the Cluster.
 ```yaml
 apiVersion: hooks.runtime.cluster.x-k8s.io/v1alpha1
 kind: AfterClusterUpgradeRequest
-settings: <Runtime Extension settings>
 cluster:
   apiVersion: cluster.x-k8s.io/v1beta1
   kind: Cluster
@@ -236,7 +231,6 @@ cleanup tasks for the add-ons and block deletion of the Cluster and descendant o
 ```yaml
 apiVersion: hooks.runtime.cluster.x-k8s.io/v1alpha1
 kind: BeforeClusterDeleteRequest
-settings: <Runtime Extension settings>
 cluster:
   apiVersion: cluster.x-k8s.io/v1beta1
   kind: Cluster
diff --git a/docs/book/src/tasks/experimental-features/runtime-sdk/implement-topology-mutation-hook.md b/docs/book/src/tasks/experimental-features/runtime-sdk/implement-topology-mutation-hook.md
index 0fcf4834e..e9857b581 100644
--- a/docs/book/src/tasks/experimental-features/runtime-sdk/implement-topology-mutation-hook.md
+++ b/docs/book/src/tasks/experimental-features/runtime-sdk/implement-topology-mutation-hook.md
@@ -88,7 +88,6 @@ templates, the global variables and the template-specific variables. The respons
 ```yaml
 apiVersion: hooks.runtime.cluster.x-k8s.io/v1alpha1
 kind: GeneratePatchesRequest
-settings: <Runtime Extension settings>
 variables:
 - name: <variable-name>
   value: <variable-value>
@@ -152,7 +151,6 @@ contains the result of the validation.
 ```yaml
 apiVersion: hooks.runtime.cluster.x-k8s.io/v1alpha1
 kind: ValidateTopologyRequest
-settings: <Runtime Extension settings>
 variables:
 - name: <variable-name>
   value: <variable-value>
diff --git a/docs/book/src/user/quick-start.md b/docs/book/src/user/quick-start.md
index 598fe5fa5..2d571d0cb 100644
--- a/docs/book/src/user/quick-start.md
+++ b/docs/book/src/user/quick-start.md
@@ -734,7 +734,7 @@ The output of `clusterctl init` is similar to this:
 
 ```bash
 Fetching providers
-Installing cert-manager Version="v1.11.0"
+Installing cert-manager Version="v1.10.1"
 Waiting for cert-manager to be available...
 Installing Provider="cluster-api" Version="v1.0.0" TargetNamespace="capi-system"
 Installing Provider="bootstrap-kubeadm" Version="v1.0.0" TargetNamespace="capi-kubeadm-bootstrap-system"
diff --git a/docs/book/src/user/troubleshooting.md b/docs/book/src/user/troubleshooting.md
index 599336ff4..f57b8a4af 100644
--- a/docs/book/src/user/troubleshooting.md
+++ b/docs/book/src/user/troubleshooting.md
@@ -161,7 +161,7 @@ clusterctl init --infrastructure docker
 ```
 ```bash
 Fetching providers
-Installing cert-manager Version="v1.11.0"
+Installing cert-manager Version="v1.10.1"
 Error: action failed after 10 attempts: failed to get cert-manager object /, Kind=, /: Object 'Kind' is missing in 'unstructured object has no kind'
 ```
 
@@ -173,7 +173,7 @@ cert-manager:
   url: "https://github.com/cert-manager/cert-manager/releases/latest/cert-manager.yaml"
 ```
 
-Alternatively a Cert Manager yaml file can be placed in the [clusterctl overrides layer](../clusterctl/configuration.md#overrides-layer) which is by default in `$HOME/.cluster-api/overrides`. A Cert Manager yaml file can be placed at `$(HOME)/.cluster-api/overrides/cert-manager/v1.11.0/cert-manager.yaml`
+Alternatively a Cert Manager yaml file can be placed in the [clusterctl overrides layer](../clusterctl/configuration.md#overrides-layer) which is by default in `$HOME/.cluster-api/overrides`. A Cert Manager yaml file can be placed at `$(HOME)/.cluster-api/overrides/cert-manager/v1.10.1/cert-manager.yaml`
 
 More information on the clusterctl config file can be found at [its page in the book](../clusterctl/configuration.md#clusterctl-configuration-file)
 
diff --git a/docs/proposals/20220221-runtime-SDK.md b/docs/proposals/20220221-runtime-SDK.md
index 508ed2bed..b2887bd4a 100644
--- a/docs/proposals/20220221-runtime-SDK.md
+++ b/docs/proposals/20220221-runtime-SDK.md
@@ -310,9 +310,6 @@ spec:
   # NamespaceSelector decides whether to run the webhook on a Cluster based on whether the namespace for that Cluster matches the selector.
   # If not specified, the WebHook runs for all the namespaces.
   namespaceSelector: {}
-  # settings is a map[string]string which is sent with each request to a Runtime Extension. These settings can be used by
-  # to modify the behaviour of a Runtime Extension.
-  settings: {}
 ```
 
 Once the extension is registered the [discovery hook](#discovery-hook) is called and the above CR is updated with the list
diff --git a/docs/proposals/20220330-topology-mutation-hook.md b/docs/proposals/20220330-topology-mutation-hook.md
index a16fff967..5abb5cc97 100644
--- a/docs/proposals/20220330-topology-mutation-hook.md
+++ b/docs/proposals/20220330-topology-mutation-hook.md
@@ -140,9 +140,7 @@ Once the extension is registered the discovery hook is called and the Extension
 
 A ClusterClass author can use an External Patch Extension by referencing it in a ClusterClass and adding the corresponding variable definitions.
 
-A ClusterClass can have external patches, inline patches or both. The patches will then be applied in the order in which 
-they are defined. The extension fields of the external patch must match the unique name of RuntimeExtensions assigned during discovery.
-External patches can provide settings in map with key and string values. Settings and their usage are defined by GeneratePatch hook authors.
+A ClusterClass can have external patches, inline patches or both. The patches will then be applied in the order in which they are defined. The extension fields of the external patch must match the unique name of RuntimeExtensions assigned during discovery.
 
 ```yaml
 apiVersion: cluster.x-k8s.io/v1beta1
@@ -156,10 +154,7 @@ spec:
     external:
       generateExtension: "http-proxy.my-awesome-patch"
       validateExtension: "http-proxy-validate.my-awesome-patch"
-      settings:
-        firstSetting: "red"
-        secondSettings: "blue"
-    # inline patch
+  # inline patch
   - name: region
     definitions:
     ...
diff --git a/docs/release/release-tasks.md b/docs/release/release-tasks.md
index c5fbc7e9e..7db7d86dc 100644
--- a/docs/release/release-tasks.md
+++ b/docs/release/release-tasks.md
@@ -90,29 +90,13 @@ The goal of this issue is to bump the versions on the main branch so that the up
 is used for e.g. local development and e2e tests. We also modify tests so that they are testing the previous release.
 
 This comes down to changing occurrences of the old version to the new version, e.g. `v1.3` to `v1.4`:
-1. Setup E2E tests for the new release:
-   1. Goal is that we have clusterctl upgrade tests for the latest stable versions of each contract / for each supported branch. For `v1.4` this means:
-      * v1alpha3: `v0.3`
-      * v1alpha4: `v0.4`
-      * v1beta1: `v1.2`, `v1.3` (will change with each new release)
-   2. Update providers in `docker.yaml`:
-       1. Add a new `v1.3.0` entry.
-       2. Remove providers that are not used anymore (for `v1.4` we don't have to remove any).
-       3. Change `v1.3.99` to `v1.4.99`.
-   3. Adjust `metadata.yaml`'s:
-      1. Create a new `v1.3` `metadata.yaml` (`test/e2e/data/shared/v1.3/metadata.yaml`) by copying
-   `test/e2e/data/shared/main/metadata.yaml`
-      2. Add the new release to the main `metadata.yaml` (`test/e2e/data/shared/main/metadata.yaml`).
-      3. Remove old `metadata.yaml`'s that are not used anymore (for `v1.4` we don't have to remove any).
-   4. Adjust cluster templates in `test/e2e/data/infrastructure-docker`:
-      1. Create a new `v1.3` folder. It should be created based on the `main` folder and only contain the templates
-         we use in the clusterctl upgrade tests (as of today `cluster-template` and `cluster-template-topology`).
-      2. Remove old folders that are not used anymore (for `v1.4` we don't have to remove any).
-   5. Modify the test specs in `test/e2e/clusterctl_upgrade_test.go` (according to the versions we want to test described above).
-      Please note that `InitWithKubernetesVersion` should be the highest mgmt cluster version supported by the respective Cluster API version. 
-2. Update `create-local-repository.py` and `tools/tilt-prepare/main.go`: `v1.3.99` => `v1.4.99`.
-3. Update `.github/workflows/scan.yml` to setup Trivy scanning for the currently supported branches.
-4. Make sure all tests are green (also run `pull-cluster-api-e2e-full-main` and `pull-cluster-api-e2e-workload-upgrade-1-23-latest-main`).
+1. Add new release to top-level `metadata.yaml` and `test/e2e/data/shared/v1beta1/metadata.yaml`.
+2. Update providers in docker.yaml. Roughly:
+   1. Create a new entry for each provider for `v1.3.0`.
+   2. Rename `v1.3.99` to `v1.4.99`.
+3. Modify the test specs in `test/e2e/clusterctl_upgrade_test.go`.
+4. Update `create-local-repository.py` and `tools/tilt-prepare/main.go`: `v1.3.99` => `v1.4.99`.
+5. Make sure all tests are green (also run `pull-cluster-api-e2e-full-main` and `pull-cluster-api-e2e-workload-upgrade-1-23-latest-main`).
 
 Prior art: https://github.com/kubernetes-sigs/cluster-api/pull/6834/files
 
@@ -214,10 +198,9 @@ This can be done by:
 5. Publish `clusterctl` to Homebrew by bumping the version in [clusterctl.rb](https://github.com/Homebrew/homebrew-core/blob/master/Formula/clusterctl.rb).
    <br>**Notes**:
     * This is only done for new latest stable releases, not for beta / RC releases and not for previous release branches.
-    * Check if homebrew already has a PR to update the version (homebrew introduced automation that picks it up). Open one if no PR exists. 
-      * For an example please see: [PR: clusterctl 1.1.5](https://github.com/Homebrew/homebrew-core/pull/105075/files).
-      * Homebrew has [conventions for commit messages](https://docs.brew.sh/Formula-Cookbook#commit) usually
-        the commit message for us should look like: `clusterctl 1.1.5`.
+    * For an example please see: [PR: clusterctl 1.1.5](https://github.com/Homebrew/homebrew-core/pull/105075/files).
+    * Homebrew has [conventions for commit messages](https://docs.brew.sh/Formula-Cookbook#commit) usually
+      the commit message for us should look like: `clusterctl 1.1.5`.
 6. Set EOL date for previous release (prior art: https://github.com/kubernetes-sigs/cluster-api/issues/7146).
 
 Additional information:
diff --git a/go.mod b/go.mod
index 2f28bb38a..9b2abcd33 100644
--- a/go.mod
+++ b/go.mod
@@ -15,12 +15,12 @@ require (
 	github.com/flatcar/container-linux-config-transpiler v0.9.4
 	github.com/flatcar/ignition v0.36.2
 	github.com/go-logr/logr v1.2.3
-	github.com/gobuffalo/flect v1.0.0
+	github.com/gobuffalo/flect v0.3.0
 	github.com/google/go-cmp v0.5.9
 	github.com/google/go-github/v48 v48.2.0
 	github.com/google/gofuzz v1.2.0
 	github.com/mattn/go-runewidth v0.0.14 // indirect
-	github.com/onsi/ginkgo/v2 v2.7.0
+	github.com/onsi/ginkgo/v2 v2.6.1
 	github.com/onsi/gomega v1.24.2
 	github.com/pkg/errors v0.9.1
 	github.com/spf13/cobra v1.6.1
@@ -132,7 +132,7 @@ require (
 	golang.org/x/crypto v0.3.0 // indirect
 	golang.org/x/sys v0.3.0 // indirect
 	golang.org/x/term v0.3.0 // indirect
-	golang.org/x/text v0.6.0
+	golang.org/x/text v0.5.0
 	golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 // indirect
 	gomodules.xyz/jsonpatch/v2 v2.2.0
 	google.golang.org/appengine v1.6.7 // indirect
diff --git a/go.sum b/go.sum
index 8ad889e70..8480bfa1b 100644
--- a/go.sum
+++ b/go.sum
@@ -213,8 +213,8 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh
 github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
 github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
-github.com/gobuffalo/flect v1.0.0 h1:eBFmskjXZgAOagiTXJH25Nt5sdFwNRcb8DKZsIsAUQI=
-github.com/gobuffalo/flect v1.0.0/go.mod h1:l9V6xSb4BlXwsxEMj3FVEub2nkdQjWhPvD8XTTlHPQc=
+github.com/gobuffalo/flect v0.3.0 h1:erfPWM+K1rFNIQeRPdeEXxo8yFr/PO17lhRnS8FUrtk=
+github.com/gobuffalo/flect v0.3.0/go.mod h1:5pf3aGnsvqvCj50AVni7mJJF8ICxGZ8HomberC3pXLE=
 github.com/godbus/dbus v0.0.0-20181025153459-66d97aec3384/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
 github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
 github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
@@ -439,8 +439,8 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn
 github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
 github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
 github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
-github.com/onsi/ginkgo/v2 v2.7.0 h1:/XxtEV3I3Eif/HobnVx9YmJgk8ENdRsuUmM+fLCFNow=
-github.com/onsi/ginkgo/v2 v2.7.0/go.mod h1:yjiuMwPokqY1XauOgju45q3sJt6VzQ/Fict1LFVcsAo=
+github.com/onsi/ginkgo/v2 v2.6.1 h1:1xQPCjcqYw/J5LchOcp4/2q/jzJFjiAOc25chhnDw+Q=
+github.com/onsi/ginkgo/v2 v2.6.1/go.mod h1:yjiuMwPokqY1XauOgju45q3sJt6VzQ/Fict1LFVcsAo=
 github.com/onsi/gomega v1.24.2 h1:J/tulyYK6JwBldPViHJReihxxZ+22FHs0piGjQAvoUE=
 github.com/onsi/gomega v1.24.2/go.mod h1:gs3J10IS7Z7r7eXRoNJIrNqU4ToQukCJhFtKrWgHWnk=
 github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
@@ -549,9 +549,8 @@ github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ai
 github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4=
 github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
-github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
-github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@@ -560,7 +559,6 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
 github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
-github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
 github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
 github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs=
 github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
@@ -816,8 +814,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
 golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
-golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k=
-golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
+golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 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=
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
diff --git a/hack/observability/kube-state-metrics/crd-config.yaml b/hack/observability/kube-state-metrics/crd-config.yaml
index 230fba619..dc5aa9cf2 100644
--- a/hack/observability/kube-state-metrics/crd-config.yaml
+++ b/hack/observability/kube-state-metrics/crd-config.yaml
@@ -39,22 +39,6 @@ spec:
             - spec
             - controlPlaneEndpoint
             - port
-            control_plane_reference_kind:
-            - spec
-            - controlPlaneRef
-            - kind
-            control_plane_reference_name:
-            - spec
-            - controlPlaneRef
-            - name
-            infrastructure_reference_kind:
-            - spec
-            - infrastructureRef
-            - kind
-            infrastructure_reference_name:
-            - spec
-            - infrastructureRef
-            - name
         type: Info
     - name: spec_paused
       help: Whether the cluster is paused and any of its resources will not be processed by the controllers.
@@ -280,48 +264,24 @@ spec:
       each:
         info:
           labelsFromPath:
-            container_runtime_version:
-            - status
-            - nodeInfo
-            - containerRuntimeVersion
             failure_domain:
             - spec
             - failureDomain
-            kernel_version:
+            internal_ip:
             - status
-            - nodeInfo
-            - kernelVersion
-            kubelet_version:
-            - status
-            - nodeInfo
-            - kubeletVersion
-            kube_proxy_version:
-            - status
-            - nodeInfo
-            - kubeProxyVersion
-            os_image:
-            - status
-            - nodeInfo
-            - osImage
+            - addresses
+            - "[type=InternalIP]"
+            - address
             provider_id:
             - spec
             - providerID
             version:
             - spec
             - version
-        type: Info
-    - name: addresses
-      help: Address information about a machine.
-      each:
-        info:
-          path:
-          - status
-          - addresses
-          labelsFromPath:
-            type:
-            - type
-            address:
-            - address
+            containerRuntimeVersion:
+            - status
+            - nodeInfo
+            - containerRuntimeVersion
         type: Info
     - name: status_noderef
       help: Information about the node reference of a machine.
@@ -793,176 +753,3 @@ spec:
           - metadata
           - ownerReferences
         type: Info
-  - groupVersionKind:
-      group: cluster.x-k8s.io
-      kind: MachinePool
-      version: v1beta1
-    labelsFromPath:
-      cluster_name:
-      - spec
-      - clusterName
-      name:
-      - metadata
-      - name
-      namespace:
-      - metadata
-      - namespace
-      uid:
-      - metadata
-      - uid
-    metricNamePrefix: capi_machinepool
-    metrics:
-    - name: spec_replicas
-      help: The number of desired machines for a machinepool.
-      each:
-        gauge:
-          path:
-          - spec
-          - replicas
-        type: Gauge
-    - name: status_replicas
-      help: The number of replicas per machinepool.
-      each:
-        gauge:
-          path:
-          - status
-          - replicas
-          nilIsZero: true
-        type: Gauge
-    - name: status_replicas_ready
-      help: The number of ready replicas per machinepool.
-      each:
-        gauge:
-          path:
-          - status
-          - readyReplicas
-          nilIsZero: true
-        type: Gauge
-    - name: status_replicas_available
-      help: The number of available replicas per machinepool.
-      each:
-        gauge:
-          path:
-          - status
-          - availableReplicas
-          nilIsZero: true
-        type: Gauge
-    - name: status_replicas_unavailable
-      help: The number of unavailable replicas per machinepool.
-      each:
-        gauge:
-          path:
-          - status
-          - unavailableReplicas
-          nilIsZero: true
-        type: Gauge
-    - name: info
-      each:
-        type: Info
-        info:
-          labelsFromPath:
-            infrastructure_reference_name:
-            - spec
-            - template
-            - spec
-            - infrastructureRef
-            - name
-            infrastructure_reference_kind:
-            - spec
-            - template
-            - spec
-            - infrastructureRef
-            - kind
-            bootstrap_configuration_reference_name:
-            - spec
-            - template
-            - spec
-            - bootstrap
-            - configRef
-            - name
-            bootstrap_configuration_reference_kind:
-            - spec
-            - template
-            - spec
-            - bootstrap
-            - configRef
-            - kind
-            failure_domain:
-            - spec
-            - template
-            - spec
-            - failureDomain
-            version:
-            - spec
-            - template
-            - spec
-            - version
-    - name: status_phase
-      help: The machinepools current phase.
-      each:
-        stateSet:
-          labelName: phase
-          list:
-          - ScalingUp
-          - ScalingDown
-          - Running
-          - Failed
-          - Unknown
-          path:
-          - status
-          - phase
-        type: StateSet
-    - name: created
-      help: Unix creation timestamp.
-      each:
-        gauge:
-          path:
-          - metadata
-          - creationTimestamp
-        type: Gauge
-    - name: annotation_paused
-      help: Whether the machinepool is paused and any of its resources will not be processed by the controllers.
-      each:
-        info:
-          path:
-          - metadata
-          - annotations
-          - cluster.x-k8s.io/paused
-          labelsFromPath:
-            paused_value: []
-        type: Info
-    - name: status_condition
-      help: The condition of a machinepool.
-      each:
-        stateSet:
-          labelName: status
-          labelsFromPath:
-            type:
-            - type
-          list:
-          - 'True'
-          - 'False'
-          - Unknown
-          path:
-          - status
-          - conditions
-          valueFrom:
-          - status
-        type: StateSet
-    - name: owner
-      help: Owner references.
-      each:
-        info:
-          labelsFromPath:
-            owner_is_controller:
-            - controller
-            owner_kind:
-            - kind
-            owner_name:
-            - name
-            owner_uid:
-            - uid
-          path:
-          - metadata
-          - ownerReferences
-        type: Info
diff --git a/hack/observability/kube-state-metrics/metrics/cluster.yaml b/hack/observability/kube-state-metrics/metrics/cluster.yaml
index f1e91daa6..f1c1cf120 100644
--- a/hack/observability/kube-state-metrics/metrics/cluster.yaml
+++ b/hack/observability/kube-state-metrics/metrics/cluster.yaml
@@ -35,22 +35,6 @@
             - spec
             - controlPlaneEndpoint
             - port
-            control_plane_reference_kind:
-            - spec
-            - controlPlaneRef
-            - kind
-            control_plane_reference_name:
-            - spec
-            - controlPlaneRef
-            - name
-            infrastructure_reference_kind:
-            - spec
-            - infrastructureRef
-            - kind
-            infrastructure_reference_name:
-            - spec
-            - infrastructureRef
-            - name
         type: Info
     - name: spec_paused
       help: Whether the cluster is paused and any of its resources will not be processed by the controllers.
diff --git a/hack/observability/kube-state-metrics/metrics/machine.yaml b/hack/observability/kube-state-metrics/metrics/machine.yaml
index addf4595c..cf3307fd9 100644
--- a/hack/observability/kube-state-metrics/metrics/machine.yaml
+++ b/hack/observability/kube-state-metrics/metrics/machine.yaml
@@ -22,48 +22,24 @@
       each:
         info:
           labelsFromPath:
-            container_runtime_version:
-            - status
-            - nodeInfo
-            - containerRuntimeVersion
             failure_domain:
             - spec
             - failureDomain
-            kernel_version:
+            internal_ip:
             - status
-            - nodeInfo
-            - kernelVersion
-            kubelet_version:
-            - status
-            - nodeInfo
-            - kubeletVersion
-            kube_proxy_version:
-            - status
-            - nodeInfo
-            - kubeProxyVersion
-            os_image:
-            - status
-            - nodeInfo
-            - osImage
+            - addresses
+            - "[type=InternalIP]"
+            - address
             provider_id:
             - spec
             - providerID
             version:
             - spec
             - version
-        type: Info
-    - name: addresses
-      help: Address information about a machine.
-      each:
-        info:
-          path:
-          - status
-          - addresses
-          labelsFromPath:
-            type:
-            - type
-            address:
-            - address
+            containerRuntimeVersion:
+            - status
+            - nodeInfo
+            - containerRuntimeVersion
         type: Info
     - name: status_noderef
       help: Information about the node reference of a machine.
diff --git a/hack/observability/kube-state-metrics/metrics/machinepool.yaml b/hack/observability/kube-state-metrics/metrics/machinepool.yaml
deleted file mode 100644
index a4dbb4aa7..000000000
--- a/hack/observability/kube-state-metrics/metrics/machinepool.yaml
+++ /dev/null
@@ -1,119 +0,0 @@
-  - groupVersionKind:
-      group: cluster.x-k8s.io
-      kind: MachinePool
-      version: v1beta1
-    labelsFromPath:
-      cluster_name:
-      - spec
-      - clusterName
-      name:
-      - metadata
-      - name
-      namespace:
-      - metadata
-      - namespace
-      uid:
-      - metadata
-      - uid
-    metricNamePrefix: capi_machinepool
-    metrics:
-    - name: spec_replicas
-      help: The number of desired machines for a machinepool.
-      each:
-        gauge:
-          path:
-          - spec
-          - replicas
-        type: Gauge
-    - name: status_replicas
-      help: The number of replicas per machinepool.
-      each:
-        gauge:
-          path:
-          - status
-          - replicas
-          nilIsZero: true
-        type: Gauge
-    - name: status_replicas_ready
-      help: The number of ready replicas per machinepool.
-      each:
-        gauge:
-          path:
-          - status
-          - readyReplicas
-          nilIsZero: true
-        type: Gauge
-    - name: status_replicas_available
-      help: The number of available replicas per machinepool.
-      each:
-        gauge:
-          path:
-          - status
-          - availableReplicas
-          nilIsZero: true
-        type: Gauge
-    - name: status_replicas_unavailable
-      help: The number of unavailable replicas per machinepool.
-      each:
-        gauge:
-          path:
-          - status
-          - unavailableReplicas
-          nilIsZero: true
-        type: Gauge
-    - name: info
-      each:
-        type: Info
-        info:
-          labelsFromPath:
-            infrastructure_reference_name:
-            - spec
-            - template
-            - spec
-            - infrastructureRef
-            - name
-            infrastructure_reference_kind:
-            - spec
-            - template
-            - spec
-            - infrastructureRef
-            - kind
-            bootstrap_configuration_reference_name:
-            - spec
-            - template
-            - spec
-            - bootstrap
-            - configRef
-            - name
-            bootstrap_configuration_reference_kind:
-            - spec
-            - template
-            - spec
-            - bootstrap
-            - configRef
-            - kind
-            failure_domain:
-            - spec
-            - template
-            - spec
-            - failureDomain
-            version:
-            - spec
-            - template
-            - spec
-            - version
-    - name: status_phase
-      help: The machinepools current phase.
-      each:
-        stateSet:
-          labelName: phase
-          list:
-          - ScalingUp
-          - ScalingDown
-          - Running
-          - Failed
-          - Unknown
-          path:
-          - status
-          - phase
-        type: StateSet
diff --git a/hack/observability/visualizer/kustomization.yaml b/hack/observability/visualizer/kustomization.yaml
index 642d73796..f8bbe5295 100644
--- a/hack/observability/visualizer/kustomization.yaml
+++ b/hack/observability/visualizer/kustomization.yaml
@@ -7,4 +7,4 @@ helmCharts:
     releaseName: visualizer
     namespace: observability
     valuesFile: values.yaml
-    version: 1.1.0
+    version: 1.0.0
diff --git a/hack/tools/go.mod b/hack/tools/go.mod
index 27731f29f..e25d68865 100644
--- a/hack/tools/go.mod
+++ b/hack/tools/go.mod
@@ -67,7 +67,7 @@ require (
 	github.com/go-openapi/jsonpointer v0.19.5 // indirect
 	github.com/go-openapi/jsonreference v0.20.0 // indirect
 	github.com/go-openapi/swag v0.22.3 // indirect
-	github.com/gobuffalo/flect v1.0.0 // indirect
+	github.com/gobuffalo/flect v0.3.0 // indirect
 	github.com/gogo/protobuf v1.3.2 // indirect
 	github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
 	github.com/golang/protobuf v1.5.2 // indirect
@@ -136,7 +136,7 @@ require (
 	golang.org/x/sync v0.1.0 // indirect
 	golang.org/x/sys v0.3.0 // indirect
 	golang.org/x/term v0.3.0 // indirect
-	golang.org/x/text v0.6.0 // indirect
+	golang.org/x/text v0.5.0 // indirect
 	golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 // indirect
 	golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
 	gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
diff --git a/hack/tools/go.sum b/hack/tools/go.sum
index 95cbe26e0..1a64ef98a 100644
--- a/hack/tools/go.sum
+++ b/hack/tools/go.sum
@@ -207,8 +207,8 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh
 github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
 github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
-github.com/gobuffalo/flect v1.0.0 h1:eBFmskjXZgAOagiTXJH25Nt5sdFwNRcb8DKZsIsAUQI=
-github.com/gobuffalo/flect v1.0.0/go.mod h1:l9V6xSb4BlXwsxEMj3FVEub2nkdQjWhPvD8XTTlHPQc=
+github.com/gobuffalo/flect v0.3.0 h1:erfPWM+K1rFNIQeRPdeEXxo8yFr/PO17lhRnS8FUrtk=
+github.com/gobuffalo/flect v0.3.0/go.mod h1:5pf3aGnsvqvCj50AVni7mJJF8ICxGZ8HomberC3pXLE=
 github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
 github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
 github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
@@ -415,7 +415,7 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW
 github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
 github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
-github.com/onsi/ginkgo/v2 v2.7.0 h1:/XxtEV3I3Eif/HobnVx9YmJgk8ENdRsuUmM+fLCFNow=
+github.com/onsi/ginkgo/v2 v2.6.1 h1:1xQPCjcqYw/J5LchOcp4/2q/jzJFjiAOc25chhnDw+Q=
 github.com/onsi/gomega v1.24.2 h1:J/tulyYK6JwBldPViHJReihxxZ+22FHs0piGjQAvoUE=
 github.com/onsi/gomega v1.24.2/go.mod h1:gs3J10IS7Z7r7eXRoNJIrNqU4ToQukCJhFtKrWgHWnk=
 github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
@@ -499,9 +499,8 @@ github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ai
 github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4=
 github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
-github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
-github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@@ -511,7 +510,6 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
 github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
-github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
 github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs=
 github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
 github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ=
@@ -774,8 +772,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
 golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
-golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k=
-golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
+golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 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=
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
diff --git a/internal/contract/controlplane.go b/internal/contract/controlplane.go
index 3148477af..788e0e476 100644
--- a/internal/contract/controlplane.go
+++ b/internal/contract/controlplane.go
@@ -22,7 +22,6 @@ import (
 	"github.com/blang/semver"
 	"github.com/pkg/errors"
 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
-	"k8s.io/utils/pointer"
 
 	"sigs.k8s.io/cluster-api/util/version"
 )
@@ -207,7 +206,6 @@ func (c *ControlPlaneContract) IsUpgrading(obj *unstructured.Unstructured) (bool
 // - spec.replicas != status.replicas.
 // - spec.replicas != status.updatedReplicas.
 // - spec.replicas != status.readyReplicas.
-// - status.unavailableReplicas > 0.
 func (c *ControlPlaneContract) IsScaling(obj *unstructured.Unstructured) (bool, error) {
 	desiredReplicas, err := c.Replicas().Get(obj)
 	if err != nil {
@@ -247,29 +245,9 @@ func (c *ControlPlaneContract) IsScaling(obj *unstructured.Unstructured) (bool,
 		return false, errors.Wrap(err, "failed to get control plane status readyReplicas")
 	}
 
-	unavailableReplicas, err := c.UnavailableReplicas().Get(obj)
-	if err != nil {
-		if !errors.Is(err, errNotFound) {
-			return false, errors.Wrap(err, "failed to get control plane status unavailableReplicas")
-		}
-		// If unavailableReplicas is not set on the control plane we assume it is 0.
-		// We have to do this as the following happens after clusterctl move with KCP:
-		// * clusterctl move creates the KCP object without status
-		// * the KCP controller won't patch the field to 0 if it doesn't exist
-		//   * This is because the patchHelper marshals before/after object to JSON to calculate a diff
-		//     and as the unavailableReplicas field is not a pointer, not set and 0 are both rendered as 0.
-		//     If before/after of the field is the same (i.e. 0), there is no diff and thus also no patch to set it to 0.
-		unavailableReplicas = pointer.Int64(0)
-	}
-
-	// Control plane is still scaling if:
-	// * .spec.replicas, .status.replicas, .status.updatedReplicas,
-	//   .status.readyReplicas are not equal and
-	// * unavailableReplicas > 0
 	if *statusReplicas != *desiredReplicas ||
 		*updatedReplicas != *desiredReplicas ||
-		*readyReplicas != *desiredReplicas ||
-		*unavailableReplicas > 0 {
+		*readyReplicas != *desiredReplicas {
 		return true, nil
 	}
 	return false, nil
diff --git a/internal/controllers/topology/cluster/patches/inline/json_patch_generator.go b/internal/controllers/topology/cluster/patches/inline/json_patch_generator.go
index c47bcd33a..6dfcf2c44 100644
--- a/internal/controllers/topology/cluster/patches/inline/json_patch_generator.go
+++ b/internal/controllers/topology/cluster/patches/inline/json_patch_generator.go
@@ -25,7 +25,7 @@ import (
 	"strings"
 	"text/template"
 
-	"github.com/Masterminds/sprig/v3"
+	sprig "github.com/Masterminds/sprig/v3"
 	"github.com/pkg/errors"
 	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 	kerrors "k8s.io/apimachinery/pkg/util/errors"
@@ -170,14 +170,7 @@ func matchesSelector(req *runtimehooksv1.GeneratePatchesRequestItem, templateVar
 				// If templateMDClass matches one of the configured MachineDeploymentClasses.
 				for _, mdClass := range selector.MatchResources.MachineDeploymentClass.Names {
 					// We have to quote mdClass as templateMDClassJSON is a JSON string (e.g. "default-worker").
-					if mdClass == "*" || string(templateMDClassJSON.Raw) == strconv.Quote(mdClass) {
-						return true
-					}
-					unquoted, _ := strconv.Unquote(string(templateMDClassJSON.Raw))
-					if strings.HasPrefix(mdClass, "*") && strings.HasSuffix(unquoted, strings.TrimPrefix(mdClass, "*")) {
-						return true
-					}
-					if strings.HasSuffix(mdClass, "*") && strings.HasPrefix(unquoted, strings.TrimSuffix(mdClass, "*")) {
+					if string(templateMDClassJSON.Raw) == strconv.Quote(mdClass) {
 						return true
 					}
 				}
diff --git a/internal/webhooks/patch_validation.go b/internal/webhooks/patch_validation.go
index c9c61562c..ac0dbd640 100644
--- a/internal/webhooks/patch_validation.go
+++ b/internal/webhooks/patch_validation.go
@@ -23,11 +23,10 @@ import (
 	"strings"
 	"text/template"
 
-	"github.com/Masterminds/sprig/v3"
+	sprig "github.com/Masterminds/sprig/v3"
 	"github.com/pkg/errors"
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/util/sets"
-	"k8s.io/apimachinery/pkg/util/validation"
 	"k8s.io/apimachinery/pkg/util/validation/field"
 
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
@@ -199,45 +198,8 @@ func validateSelectors(selector clusterv1.PatchSelector, class *clusterv1.Cluste
 	if selector.MatchResources.MachineDeploymentClass != nil && len(selector.MatchResources.MachineDeploymentClass.Names) > 0 {
 		for i, name := range selector.MatchResources.MachineDeploymentClass.Names {
 			match := false
-			if strings.Contains(name, "*") {
-				// selector can at most have a single * rune
-				if strings.Count(name, "*") > 1 {
-					allErrs = append(allErrs, field.Invalid(
-						path.Child("matchResources", "machineDeploymentClass", "names").Index(i),
-						name,
-						"selector can at most contain a single \"*\" rune"))
-					break
-				}
-
-				// the * rune can appear only at the beginning, or ending of the selector.
-				if strings.Contains(name, "*") && !(strings.HasPrefix(name, "*") || strings.HasSuffix(name, "*")) {
-					// templateMDClass can only have "*" rune at the start or end of the string
-					allErrs = append(allErrs, field.Invalid(
-						path.Child("matchResources", "machineDeploymentClass", "names").Index(i),
-						name,
-						"\"*\" rune can only appear at the beginning, or ending of the selector"))
-					break
-				}
-				// a valid selector without "*" should comply with Kubernetes naming standards.
-				if validation.IsQualifiedName(strings.ReplaceAll(name, "*", "a")) != nil {
-					allErrs = append(allErrs, field.Invalid(
-						path.Child("matchResources", "machineDeploymentClass", "names").Index(i),
-						name,
-						"selector does not comply with the Kubernetes naming standards"))
-					break
-				}
-			}
 			for _, md := range class.Spec.Workers.MachineDeployments {
-				var matches bool
-				if md.Class == name || name == "*" {
-					matches = true
-				} else if strings.HasPrefix(name, "*") && strings.HasSuffix(md.Class, strings.TrimPrefix(name, "*")) {
-					matches = true
-				} else if strings.HasSuffix(name, "*") && strings.HasPrefix(md.Class, strings.TrimSuffix(name, "*")) {
-					matches = true
-				}
-
-				if matches {
+				if md.Class == name {
 					if selectorMatchTemplate(selector, md.Template.Infrastructure.Ref) ||
 						selectorMatchTemplate(selector, md.Template.Bootstrap.Ref) {
 						match = true


Test patch:
diff --git a/internal/contract/controlplane_test.go b/internal/contract/controlplane_test.go
index 98863ca31..4080cb837 100644
--- a/internal/contract/controlplane_test.go
+++ b/internal/contract/controlplane_test.go
@@ -353,10 +353,9 @@ func TestControlPlaneIsScaling(t *testing.T) {
 					"replicas": int64(2),
 				},
 				"status": map[string]interface{}{
-					"replicas":            int64(2),
-					"updatedReplicas":     int64(2),
-					"readyReplicas":       int64(2),
-					"unavailableReplicas": int64(0),
+					"replicas":        int64(2),
+					"updatedReplicas": int64(2),
+					"readyReplicas":   int64(2),
 				},
 			}},
 			wantScaling: false,
@@ -371,94 +370,45 @@ func TestControlPlaneIsScaling(t *testing.T) {
 			wantScaling: true,
 		},
 		{
-			name: "should return true if status replicas is not set on control plane",
-			obj: &unstructured.Unstructured{Object: map[string]interface{}{
-				"spec": map[string]interface{}{
-					"replicas": int64(2),
-				},
-				"status": map[string]interface{}{
-					"updatedReplicas":     int64(2),
-					"readyReplicas":       int64(2),
-					"unavailableReplicas": int64(0),
-				},
-			}},
-			wantScaling: true,
-		},
-		{
-			name: "should return true if spec replicas and status replicas do not match",
-			obj: &unstructured.Unstructured{Object: map[string]interface{}{
-				"spec": map[string]interface{}{
-					"replicas": int64(2),
-				},
-				"status": map[string]interface{}{
-					"replicas":            int64(1),
-					"updatedReplicas":     int64(2),
-					"readyReplicas":       int64(2),
-					"unavailableReplicas": int64(0),
-				},
-			}},
-			wantScaling: true,
-		},
-		{
-			name: "should return true if status updatedReplicas is not set on control plane",
+			name: "should return true if status.replicas is not set on control plane",
 			obj: &unstructured.Unstructured{Object: map[string]interface{}{
 				"spec": map[string]interface{}{
 					"replicas": int64(2),
 				},
-				"status": map[string]interface{}{
-					"replicas":            int64(2),
-					"readyReplicas":       int64(2),
-					"unavailableReplicas": int64(0),
-				},
-			}},
-			wantScaling: true,
-		},
-		{
-			name: "should return true if spec replicas and status updatedReplicas do not match",
-			obj: &unstructured.Unstructured{Object: map[string]interface{}{
-				"spec": map[string]interface{}{
-					"replicas": int64(2),
-				},
-				"status": map[string]interface{}{
-					"replicas":            int64(2),
-					"updatedReplicas":     int64(1),
-					"readyReplicas":       int64(2),
-					"unavailableReplicas": int64(0),
-				},
+				"status": map[string]interface{}{},
 			}},
 			wantScaling: true,
 		},
 		{
-			name: "should return true if status readyReplicas is not set on control plane",
+			name: "should return true if spec and status replicas do not match",
 			obj: &unstructured.Unstructured{Object: map[string]interface{}{
 				"spec": map[string]interface{}{
 					"replicas": int64(2),
 				},
 				"status": map[string]interface{}{
-					"replicas":            int64(2),
-					"updatedReplicas":     int64(2),
-					"unavailableReplicas": int64(0),
+					"replicas":        int64(1),
+					"updatedReplicas": int64(2),
+					"readyReplicas":   int64(2),
 				},
 			}},
 			wantScaling: true,
 		},
 		{
-			name: "should return true if spec replicas and status readyReplicas do not match",
+			name: "should return true if spec and status updatedReplicas do not match",
 			obj: &unstructured.Unstructured{Object: map[string]interface{}{
 				"spec": map[string]interface{}{
 					"replicas": int64(2),
 				},
 				"status": map[string]interface{}{
-					"replicas":            int64(2),
-					"updatedReplicas":     int64(2),
-					"readyReplicas":       int64(1),
-					"unavailableReplicas": int64(0),
+					"replicas":        int64(2),
+					"updatedReplicas": int64(1),
+					"readyReplicas":   int64(2),
 				},
 			}},
 			wantScaling: true,
 		},
 		{
-			name: "should return false if status unavailableReplicas is not set on control plane",
+			name: "should return true if spec and status readyReplicas do not match",
 			obj: &unstructured.Unstructured{Object: map[string]interface{}{
 				"spec": map[string]interface{}{
 					"replicas": int64(2),
@@ -466,22 +416,7 @@ func TestControlPlaneIsScaling(t *testing.T) {
 				"status": map[string]interface{}{
 					"replicas":        int64(2),
 					"updatedReplicas": int64(2),
-					"readyReplicas":   int64(2),
-				},
-			}},
-			wantScaling: false,
-		},
-		{
-			name: "should return true if status unavailableReplicas is > 0",
-			obj: &unstructured.Unstructured{Object: map[string]interface{}{
-				"spec": map[string]interface{}{
-					"replicas": int64(2),
-				},
-				"status": map[string]interface{}{
-					"replicas":            int64(2),
-					"updatedReplicas":     int64(2),
-					"readyReplicas":       int64(2),
-					"unavailableReplicas": int64(1),
+					"readyReplicas":   int64(1),
 				},
 			}},
 			wantScaling: true,
diff --git a/internal/controllers/topology/cluster/desired_state_test.go b/internal/controllers/topology/cluster/desired_state_test.go
index bee52479d..8e66bd85c 100644
--- a/internal/controllers/topology/cluster/desired_state_test.go
+++ b/internal/controllers/topology/cluster/desired_state_test.go
@@ -611,7 +611,7 @@ func TestComputeControlPlaneVersion(t *testing.T) {
 		defer utilfeature.SetFeatureGateDuringTest(t, feature.Gates, feature.RuntimeSDK, true)()
 
 		// Note: the version used by the machine deployments does
-		// not affect how we're determining the control plane version.
+		// not affect how we determining the control plane version.
 		// We only want to know if the machine deployments are stable.
 		//
 		// A machine deployment is considered stable if all the following are true:
@@ -706,11 +706,10 @@ func TestComputeControlPlaneVersion(t *testing.T) {
 						"spec.replicas": int64(2),
 					}).
 					WithStatusFields(map[string]interface{}{
-						"status.version":             "v1.2.2",
-						"status.replicas":            int64(2),
-						"status.updatedReplicas":     int64(2),
-						"status.readyReplicas":       int64(2),
-						"status.unavailableReplicas": int64(0),
+						"status.version":         "v1.2.2",
+						"status.replicas":        int64(2),
+						"status.updatedReplicas": int64(2),
+						"status.readyReplicas":   int64(2),
 					}).
 					Build(),
 				expectedVersion: "v1.2.3",
@@ -740,11 +739,10 @@ func TestComputeControlPlaneVersion(t *testing.T) {
 						"spec.replicas": int64(2),
 					}).
 					WithStatusFields(map[string]interface{}{
-						"status.version":             "v1.2.2",
-						"status.replicas":            int64(1),
-						"status.updatedReplicas":     int64(1),
-						"status.readyReplicas":       int64(1),
-						"status.unavailableReplicas": int64(0),
+						"status.version":         "v1.2.2",
+						"status.replicas":        int64(1),
+						"status.updatedReplicas": int64(1),
+						"status.readyReplicas":   int64(1),
 					}).
 					Build(),
 				expectedVersion: "v1.2.2",
@@ -758,11 +756,10 @@ func TestComputeControlPlaneVersion(t *testing.T) {
 						"spec.replicas": int64(2),
 					}).
 					WithStatusFields(map[string]interface{}{
-						"status.version":             "v1.2.2",
-						"status.replicas":            int64(2),
-						"status.updatedReplicas":     int64(2),
-						"status.readyReplicas":       int64(2),
-						"status.unavailableReplicas": int64(0),
+						"status.version":         "v1.2.2",
+						"status.replicas":        int64(2),
+						"status.updatedReplicas": int64(2),
+						"status.readyReplicas":   int64(2),
 					}).
 					Build(),
 				machineDeploymentsState: scope.MachineDeploymentsStateMap{
@@ -781,11 +778,10 @@ func TestComputeControlPlaneVersion(t *testing.T) {
 						"spec.replicas": int64(2),
 					}).
 					WithStatusFields(map[string]interface{}{
-						"status.version":             "v1.2.2",
-						"status.replicas":            int64(2),
-						"status.updatedReplicas":     int64(2),
-						"status.readyReplicas":       int64(2),
-						"status.unavailableReplicas": int64(0),
+						"status.version":         "v1.2.2",
+						"status.replicas":        int64(2),
+						"status.updatedReplicas": int64(2),
+						"status.readyReplicas":   int64(2),
 					}).
 					Build(),
 				machineDeploymentsState: scope.MachineDeploymentsStateMap{
@@ -804,11 +800,10 @@ func TestComputeControlPlaneVersion(t *testing.T) {
 						"spec.replicas": int64(2),
 					}).
 					WithStatusFields(map[string]interface{}{
-						"status.version":             "v1.2.2",
-						"status.replicas":            int64(2),
-						"status.updatedReplicas":     int64(2),
-						"status.readyReplicas":       int64(2),
-						"status.unavailableReplicas": int64(0),
+						"status.version":         "v1.2.2",
+						"status.replicas":        int64(2),
+						"status.updatedReplicas": int64(2),
+						"status.readyReplicas":   int64(2),
 					}).
 					Build(),
 				machineDeploymentsState: scope.MachineDeploymentsStateMap{
@@ -827,11 +822,10 @@ func TestComputeControlPlaneVersion(t *testing.T) {
 						"spec.replicas": int64(2),
 					}).
 					WithStatusFields(map[string]interface{}{
-						"status.version":             "v1.2.2",
-						"status.replicas":            int64(2),
-						"status.updatedReplicas":     int64(2),
-						"status.readyReplicas":       int64(2),
-						"status.unavailableReplicas": int64(0),
+						"status.version":         "v1.2.2",
+						"status.replicas":        int64(2),
+						"status.updatedReplicas": int64(2),
+						"status.readyReplicas":   int64(2),
 					}).
 					Build(),
 				machineDeploymentsState: scope.MachineDeploymentsStateMap{
@@ -1217,11 +1211,10 @@ func TestComputeControlPlaneVersion(t *testing.T) {
 				"spec.replicas": int64(2),
 			}).
 			WithStatusFields(map[string]interface{}{
-				"status.version":             "v1.2.2",
-				"status.replicas":            int64(2),
-				"status.updatedReplicas":     int64(2),
-				"status.readyReplicas":       int64(2),
-				"status.unavailableReplicas": int64(0),
+				"status.version":         "v1.2.2",
+				"status.replicas":        int64(2),
+				"status.updatedReplicas": int64(2),
+				"status.readyReplicas":   int64(2),
 			}).
 			Build()
 
@@ -1704,11 +1697,10 @@ func TestComputeMachineDeploymentVersion(t *testing.T) {
 			"spec.replicas": int64(2),
 		}).
 		WithStatusFields(map[string]interface{}{
-			"status.version":             "v1.2.2",
-			"status.replicas":            int64(2),
-			"status.updatedReplicas":     int64(2),
-			"status.readyReplicas":       int64(2),
-			"status.unavailableReplicas": int64(0),
+			"status.version":         "v1.2.2",
+			"status.replicas":        int64(2),
+			"status.updatedReplicas": int64(2),
+			"status.readyReplicas":   int64(2),
 		}).
 		Build()
 	controlPlaneStable123 := builder.ControlPlane("test1", "cp1").
@@ -1717,11 +1709,10 @@ func TestComputeMachineDeploymentVersion(t *testing.T) {
 			"spec.replicas": int64(2),
 		}).
 		WithStatusFields(map[string]interface{}{
-			"status.version":             "v1.2.3",
-			"status.replicas":            int64(2),
-			"status.updatedReplicas":     int64(2),
-			"status.readyReplicas":       int64(2),
-			"status.unavailableReplicas": int64(0),
+			"status.version":         "v1.2.3",
+			"status.replicas":        int64(2),
+			"status.updatedReplicas": int64(2),
+			"status.readyReplicas":   int64(2),
 		}).
 		Build()
 	controlPlaneUpgrading := builder.ControlPlane("test1", "cp1").
@@ -1738,11 +1729,10 @@ func TestComputeMachineDeploymentVersion(t *testing.T) {
 			"spec.replicas": int64(2),
 		}).
 		WithStatusFields(map[string]interface{}{
-			"status.version":             "v1.2.3",
-			"status.replicas":            int64(1),
-			"status.updatedReplicas":     int64(1),
-			"status.readyReplicas":       int64(1),
-			"status.unavailableReplicas": int64(0),
+			"status.version":         "v1.2.3",
+			"status.replicas":        int64(1),
+			"status.updatedReplicas": int64(1),
+			"status.readyReplicas":   int64(1),
 		}).
 		Build()
 	controlPlaneDesired := builder.ControlPlane("test1", "cp1").
diff --git a/internal/controllers/topology/cluster/patches/inline/json_patch_generator_test.go b/internal/controllers/topology/cluster/patches/inline/json_patch_generator_test.go
index 072cd1593..9aa7f2f04 100644
--- a/internal/controllers/topology/cluster/patches/inline/json_patch_generator_test.go
+++ b/internal/controllers/topology/cluster/patches/inline/json_patch_generator_test.go
@@ -617,170 +617,6 @@ func TestMatchesSelector(t *testing.T) {
 			},
 			match: true,
 		},
-		{
-			name: "Match all MD BootstrapTemplate",
-			req: &runtimehooksv1.GeneratePatchesRequestItem{
-				Object: runtime.RawExtension{
-					Object: &unstructured.Unstructured{
-						Object: map[string]interface{}{
-							"apiVersion": "bootstrap.cluster.x-k8s.io/v1beta1",
-							"kind":       "BootstrapTemplate",
-						},
-					},
-				},
-				HolderReference: runtimehooksv1.HolderReference{
-					APIVersion: clusterv1.GroupVersion.String(),
-					Kind:       "MachineDeployment",
-					Name:       "my-md-0",
-					Namespace:  "default",
-					FieldPath:  "spec.template.spec.bootstrap.configRef",
-				},
-			},
-			templateVariables: map[string]apiextensionsv1.JSON{
-				"builtin": {Raw: []byte(`{"machineDeployment":{"class":"classA"}}`)},
-			},
-			selector: clusterv1.PatchSelector{
-				APIVersion: "bootstrap.cluster.x-k8s.io/v1beta1",
-				Kind:       "BootstrapTemplate",
-				MatchResources: clusterv1.PatchSelectorMatch{
-					MachineDeploymentClass: &clusterv1.PatchSelectorMatchMachineDeploymentClass{
-						Names: []string{"*"},
-					},
-				},
-			},
-			match: true,
-		},
-		{
-			name: "Glob match MD BootstrapTemplate with <string>-*",
-			req: &runtimehooksv1.GeneratePatchesRequestItem{
-				Object: runtime.RawExtension{
-					Object: &unstructured.Unstructured{
-						Object: map[string]interface{}{
-							"apiVersion": "bootstrap.cluster.x-k8s.io/v1beta1",
-							"kind":       "BootstrapTemplate",
-						},
-					},
-				},
-				HolderReference: runtimehooksv1.HolderReference{
-					APIVersion: clusterv1.GroupVersion.String(),
-					Kind:       "MachineDeployment",
-					Name:       "my-md-0",
-					Namespace:  "default",
-					FieldPath:  "spec.template.spec.bootstrap.configRef",
-				},
-			},
-			templateVariables: map[string]apiextensionsv1.JSON{
-				"builtin": {Raw: []byte(`{"machineDeployment":{"class":"class-A"}}`)},
-			},
-			selector: clusterv1.PatchSelector{
-				APIVersion: "bootstrap.cluster.x-k8s.io/v1beta1",
-				Kind:       "BootstrapTemplate",
-				MatchResources: clusterv1.PatchSelectorMatch{
-					MachineDeploymentClass: &clusterv1.PatchSelectorMatchMachineDeploymentClass{
-						Names: []string{"class-*"},
-					},
-				},
-			},
-			match: true,
-		},
-		{
-			name: "Glob match MD BootstrapTemplate with *-<string>",
-			req: &runtimehooksv1.GeneratePatchesRequestItem{
-				Object: runtime.RawExtension{
-					Object: &unstructured.Unstructured{
-						Object: map[string]interface{}{
-							"apiVersion": "bootstrap.cluster.x-k8s.io/v1beta1",
-							"kind":       "BootstrapTemplate",
-						},
-					},
-				},
-				HolderReference: runtimehooksv1.HolderReference{
-					APIVersion: clusterv1.GroupVersion.String(),
-					Kind:       "MachineDeployment",
-					Name:       "my-md-0",
-					Namespace:  "default",
-					FieldPath:  "spec.template.spec.bootstrap.configRef",
-				},
-			},
-			templateVariables: map[string]apiextensionsv1.JSON{
-				"builtin": {Raw: []byte(`{"machineDeployment":{"class":"class-A"}}`)},
-			},
-			selector: clusterv1.PatchSelector{
-				APIVersion: "bootstrap.cluster.x-k8s.io/v1beta1",
-				Kind:       "BootstrapTemplate",
-				MatchResources: clusterv1.PatchSelectorMatch{
-					MachineDeploymentClass: &clusterv1.PatchSelectorMatchMachineDeploymentClass{
-						Names: []string{"*-A"},
-					},
-				},
-			},
-			match: true,
-		},
-
-		{
-			name: "Don't match BootstrapTemplate, .matchResources.machineDeploymentClass.names is empty",
-			req: &runtimehooksv1.GeneratePatchesRequestItem{
-				Object: runtime.RawExtension{
-					Object: &unstructured.Unstructured{
-						Object: map[string]interface{}{
-							"apiVersion": "bootstrap.cluster.x-k8s.io/v1beta1",
-							"kind":       "BootstrapTemplate",
-						},
-					},
-				},
-				HolderReference: runtimehooksv1.HolderReference{
-					APIVersion: clusterv1.GroupVersion.String(),
-					Kind:       "MachineDeployment",
-					Name:       "my-md-0",
-					Namespace:  "default",
-					FieldPath:  "spec.template.spec.bootstrap.configRef",
-				},
-			},
-			templateVariables: map[string]apiextensionsv1.JSON{
-				"builtin": {Raw: []byte(`{"machineDeployment":{"class":"classA"}}`)},
-			},
-			selector: clusterv1.PatchSelector{
-				APIVersion: "bootstrap.cluster.x-k8s.io/v1beta1",
-				Kind:       "BootstrapTemplate",
-				MatchResources: clusterv1.PatchSelectorMatch{
-					MachineDeploymentClass: &clusterv1.PatchSelectorMatchMachineDeploymentClass{
-						Names: []string{},
-					},
-				},
-			},
-			match: false,
-		},
-		{
-			name: "Do not match BootstrapTemplate, .matchResources.machineDeploymentClass is set to nil",
-			req: &runtimehooksv1.GeneratePatchesRequestItem{
-				Object: runtime.RawExtension{
-					Object: &unstructured.Unstructured{
-						Object: map[string]interface{}{
-							"apiVersion": "bootstrap.cluster.x-k8s.io/v1beta1",
-							"kind":       "BootstrapTemplate",
-						},
-					},
-				},
-				HolderReference: runtimehooksv1.HolderReference{
-					APIVersion: clusterv1.GroupVersion.String(),
-					Kind:       "MachineDeployment",
-					Name:       "my-md-0",
-					Namespace:  "default",
-					FieldPath:  "spec.template.spec.bootstrap.configRef",
-				},
-			},
-			templateVariables: map[string]apiextensionsv1.JSON{
-				"builtin": {Raw: []byte(`{"machineDeployment":{"class":"classA"}}`)},
-			},
-			selector: clusterv1.PatchSelector{
-				APIVersion: "bootstrap.cluster.x-k8s.io/v1beta1",
-				Kind:       "BootstrapTemplate",
-				MatchResources: clusterv1.PatchSelectorMatch{
-					MachineDeploymentClass: nil,
-				},
-			},
-			match: false,
-		},
 		{
 			name: "Don't match BootstrapTemplate, .matchResources.machineDeploymentClass not set",
 			req: &runtimehooksv1.GeneratePatchesRequestItem{
diff --git a/internal/controllers/topology/cluster/reconcile_state_test.go b/internal/controllers/topology/cluster/reconcile_state_test.go
index 8036e46ab..33d6ff499 100644
--- a/internal/controllers/topology/cluster/reconcile_state_test.go
+++ b/internal/controllers/topology/cluster/reconcile_state_test.go
@@ -498,11 +498,10 @@ func TestReconcile_callAfterClusterUpgrade(t *testing.T) {
 			"spec.replicas": int64(2),
 		}).
 		WithStatusFields(map[string]interface{}{
-			"status.version":             topologyVersion,
-			"status.replicas":            int64(2),
-			"status.updatedReplicas":     int64(2),
-			"status.readyReplicas":       int64(2),
-			"status.unavailableReplicas": int64(0),
+			"status.version":         topologyVersion,
+			"status.replicas":        int64(2),
+			"status.updatedReplicas": int64(2),
+			"status.readyReplicas":   int64(2),
 		}).
 		Build()
 	controlPlaneStableAtLowerVersion := builder.ControlPlane("test1", "cp1").
@@ -511,11 +510,10 @@ func TestReconcile_callAfterClusterUpgrade(t *testing.T) {
 			"spec.replicas": int64(2),
 		}).
 		WithStatusFields(map[string]interface{}{
-			"status.version":             lowerVersion,
-			"status.replicas":            int64(2),
-			"status.updatedReplicas":     int64(2),
-			"status.readyReplicas":       int64(2),
-			"status.unavailableReplicas": int64(0),
+			"status.version":         lowerVersion,
+			"status.replicas":        int64(2),
+			"status.updatedReplicas": int64(2),
+			"status.readyReplicas":   int64(2),
 		}).
 		Build()
 	controlPlaneUpgrading := builder.ControlPlane("test1", "cp1").
@@ -524,11 +522,10 @@ func TestReconcile_callAfterClusterUpgrade(t *testing.T) {
 			"spec.replicas": int64(2),
 		}).
 		WithStatusFields(map[string]interface{}{
-			"status.version":             lowerVersion,
-			"status.replicas":            int64(2),
-			"status.updatedReplicas":     int64(2),
-			"status.readyReplicas":       int64(2),
-			"status.unavailableReplicas": int64(0),
+			"status.version":         lowerVersion,
+			"status.replicas":        int64(2),
+			"status.updatedReplicas": int64(2),
+			"status.readyReplicas":   int64(2),
 		}).
 		Build()
 	controlPlaneScaling := builder.ControlPlane("test1", "cp1").
@@ -537,11 +534,10 @@ func TestReconcile_callAfterClusterUpgrade(t *testing.T) {
 			"spec.replicas": int64(2),
 		}).
 		WithStatusFields(map[string]interface{}{
-			"status.version":             topologyVersion,
-			"status.replicas":            int64(1),
-			"status.updatedReplicas":     int64(1),
-			"status.readyReplicas":       int64(1),
-			"status.unavailableReplicas": int64(0),
+			"status.version":         topologyVersion,
+			"status.replicas":        int64(1),
+			"status.updatedReplicas": int64(1),
+			"status.readyReplicas":   int64(1),
 		}).
 		Build()
 
diff --git a/internal/webhooks/patch_validation_test.go b/internal/webhooks/patch_validation_test.go
index a26946edf..291f124bb 100644
--- a/internal/webhooks/patch_validation_test.go
+++ b/internal/webhooks/patch_validation_test.go
@@ -1810,156 +1810,6 @@ func Test_validateSelectors(t *testing.T) {
 				Build(),
 			wantErr: true,
 		},
-		{
-			name: "error if selector targets an empty MachineDeploymentClass InfrastructureTemplate",
-			selector: clusterv1.PatchSelector{
-				APIVersion:     "infrastructure.cluster.x-k8s.io/v1beta1",
-				Kind:           "InfrastructureMachineTemplate",
-				MatchResources: clusterv1.PatchSelectorMatch{},
-			},
-			clusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1").
-				WithWorkerMachineDeploymentClasses(
-					*builder.MachineDeploymentClass("aa").
-						WithInfrastructureTemplate(
-							refToUnstructured(&corev1.ObjectReference{
-								APIVersion: "infrastructure.cluster.x-k8s.io/v1beta1",
-								Kind:       "InfrastructureMachineTemplate",
-							})).
-						WithBootstrapTemplate(
-							refToUnstructured(&corev1.ObjectReference{
-								APIVersion: "bootstrap.cluster.x-k8s.io/v1beta1",
-								Kind:       "BootstrapTemplate",
-							})).
-						Build(),
-					*builder.MachineDeploymentClass("bb").
-						WithInfrastructureTemplate(
-							refToUnstructured(&corev1.ObjectReference{
-								APIVersion: "infrastructure.cluster.x-k8s.io/v1beta1",
-								Kind:       "NonMatchingInfrastructureMachineTemplate",
-							})).
-						WithBootstrapTemplate(
-							refToUnstructured(&corev1.ObjectReference{
-								APIVersion: "bootstrap.cluster.x-k8s.io/v1beta1",
-								Kind:       "BootstrapTemplate",
-							})).
-						Build(),
-				).
-				Build(),
-			wantErr: true,
-		},
-		{
-			name: "error if selector targets a bad pattern for matching MachineDeploymentClass InfrastructureTemplate",
-			selector: clusterv1.PatchSelector{
-				APIVersion: "infrastructure.cluster.x-k8s.io/v1beta1",
-				Kind:       "InfrastructureMachineTemplate",
-				MatchResources: clusterv1.PatchSelectorMatch{
-					MachineDeploymentClass: &clusterv1.PatchSelectorMatchMachineDeploymentClass{
-						Names: []string{"a*a"},
-					},
-				},
-			},
-			clusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1").
-				WithWorkerMachineDeploymentClasses(
-					*builder.MachineDeploymentClass("a-something-a").
-						WithInfrastructureTemplate(
-							refToUnstructured(&corev1.ObjectReference{
-								APIVersion: "infrastructure.cluster.x-k8s.io/v1beta1",
-								Kind:       "InfrastructureMachineTemplate",
-							})).
-						WithBootstrapTemplate(
-							refToUnstructured(&corev1.ObjectReference{
-								APIVersion: "bootstrap.cluster.x-k8s.io/v1beta1",
-								Kind:       "BootstrapTemplate",
-							})).
-						Build(),
-				).
-				Build(),
-			wantErr: true,
-		},
-		{
-			name: "pass if selector targets an existing MachineDeploymentClass InfrastructureTemplate with prefix *",
-			selector: clusterv1.PatchSelector{
-				APIVersion: "infrastructure.cluster.x-k8s.io/v1beta1",
-				Kind:       "InfrastructureMachineTemplate",
-				MatchResources: clusterv1.PatchSelectorMatch{
-					MachineDeploymentClass: &clusterv1.PatchSelectorMatchMachineDeploymentClass{
-						Names: []string{"a-*"},
-					},
-				},
-			},
-			clusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1").
-				WithWorkerMachineDeploymentClasses(
-					*builder.MachineDeploymentClass("a-something-a").
-						WithInfrastructureTemplate(
-							refToUnstructured(&corev1.ObjectReference{
-								APIVersion: "infrastructure.cluster.x-k8s.io/v1beta1",
-								Kind:       "InfrastructureMachineTemplate",
-							})).
-						WithBootstrapTemplate(
-							refToUnstructured(&corev1.ObjectReference{
-								APIVersion: "bootstrap.cluster.x-k8s.io/v1beta1",
-								Kind:       "BootstrapTemplate",
-							})).
-						Build(),
-				).
-				Build(),
-		},
-		{
-			name: "pass if selector targets an existing MachineDeploymentClass InfrastructureTemplate with suffix *",
-			selector: clusterv1.PatchSelector{
-				APIVersion: "infrastructure.cluster.x-k8s.io/v1beta1",
-				Kind:       "InfrastructureMachineTemplate",
-				MatchResources: clusterv1.PatchSelectorMatch{
-					MachineDeploymentClass: &clusterv1.PatchSelectorMatchMachineDeploymentClass{
-						Names: []string{"*-a"},
-					},
-				},
-			},
-			clusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1").
-				WithWorkerMachineDeploymentClasses(
-					*builder.MachineDeploymentClass("a-something-a").
-						WithInfrastructureTemplate(
-							refToUnstructured(&corev1.ObjectReference{
-								APIVersion: "infrastructure.cluster.x-k8s.io/v1beta1",
-								Kind:       "InfrastructureMachineTemplate",
-							})).
-						WithBootstrapTemplate(
-							refToUnstructured(&corev1.ObjectReference{
-								APIVersion: "bootstrap.cluster.x-k8s.io/v1beta1",
-								Kind:       "BootstrapTemplate",
-							})).
-						Build(),
-				).
-				Build(),
-		},
-		{
-			name: "pass if selector targets all existing MachineDeploymentClass InfrastructureTemplate with *",
-			selector: clusterv1.PatchSelector{
-				APIVersion: "infrastructure.cluster.x-k8s.io/v1beta1",
-				Kind:       "InfrastructureMachineTemplate",
-				MatchResources: clusterv1.PatchSelectorMatch{
-					MachineDeploymentClass: &clusterv1.PatchSelectorMatchMachineDeploymentClass{
-						Names: []string{"*"},
-					},
-				},
-			},
-			clusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1").
-				WithWorkerMachineDeploymentClasses(
-					*builder.MachineDeploymentClass("a-something-a").
-						WithInfrastructureTemplate(
-							refToUnstructured(&corev1.ObjectReference{
-								APIVersion: "infrastructure.cluster.x-k8s.io/v1beta1",
-								Kind:       "InfrastructureMachineTemplate",
-							})).
-						WithBootstrapTemplate(
-							refToUnstructured(&corev1.ObjectReference{
-								APIVersion: "bootstrap.cluster.x-k8s.io/v1beta1",
-								Kind:       "BootstrapTemplate",
-							})).
-						Build(),
-				).
-				Build(),
-		},
 		// The following tests have selectors which match multiple resources at the same time.
 		{
 			name: "fail if selector targets a matching infrastructureCluster reference and a not matching control plane",
diff --git a/scripts/ci-e2e-lib.sh b/scripts/ci-e2e-lib.sh
index aad29cdfa..ee6db3203 100644
--- a/scripts/ci-e2e-lib.sh
+++ b/scripts/ci-e2e-lib.sh
@@ -201,9 +201,9 @@ EOL
 # the actual test run less sensible to the network speed.
 kind:prepullAdditionalImages () {
   # Pulling cert manager images so we can pre-load in kind nodes
-  kind::prepullImage "quay.io/jetstack/cert-manager-cainjector:v1.11.0"
-  kind::prepullImage "quay.io/jetstack/cert-manager-webhook:v1.11.0"
-  kind::prepullImage "quay.io/jetstack/cert-manager-controller:v1.11.0"
+  kind::prepullImage "quay.io/jetstack/cert-manager-cainjector:v1.10.1"
+  kind::prepullImage "quay.io/jetstack/cert-manager-webhook:v1.10.1"
+  kind::prepullImage "quay.io/jetstack/cert-manager-controller:v1.10.1"
 }
 
 # kind:prepullImage pre-pull a docker image if no already present locally.
diff --git a/scripts/ci-e2e.sh b/scripts/ci-e2e.sh
index aaa49c14e..2cf5db91c 100755
--- a/scripts/ci-e2e.sh
+++ b/scripts/ci-e2e.sh
@@ -86,16 +86,6 @@ cleanup() {
   ctr -n moby containers list > "${ARTIFACTS_LOCAL}/containerd-containers.txt" || true
   ctr -n moby images list > "${ARTIFACTS_LOCAL}/containerd-images.txt" || true
   ctr -n moby version > "${ARTIFACTS_LOCAL}/containerd-version.txt" || true
-
-  # Verify that no containers are running at this time
-  # Note: This verifies that all our tests clean up clusters correctly.
-  if [[ ! "$(docker ps -q | wc -l)" -eq "0" ]]
-  then
-     echo "ERROR: Found unexpected running containers:"
-     echo ""
-     docker ps
-     exit 1
-  fi
 }
 trap "cleanup" EXIT SIGINT
 
diff --git a/test/e2e/clusterctl_upgrade.go b/test/e2e/clusterctl_upgrade.go
index 981e29446..a7a2c9363 100644
--- a/test/e2e/clusterctl_upgrade.go
+++ b/test/e2e/clusterctl_upgrade.go
@@ -293,9 +293,9 @@ func ClusterctlUpgradeSpec(ctx context.Context, inputGetter func() ClusterctlUpg
 			input.E2EConfig.GetProviderLatestVersionsByContract(initContract, config.KubeadmControlPlaneProviderName))
 		infrastructureProviders = getValueOrFallback(input.InitWithInfrastructureProviders,
 			input.E2EConfig.GetProviderLatestVersionsByContract(initContract, input.E2EConfig.InfrastructureProviders()...))
-		ipamProviders = getValueOrFallback(input.InitWithIPAMProviders,
+		ipamProviders = getValueOrFallback(input.IPAMProviders,
 			input.E2EConfig.GetProviderLatestVersionsByContract(initContract, input.E2EConfig.IPAMProviders()...))
-		runtimeExtensionProviders = getValueOrFallback(input.InitWithRuntimeExtensionProviders,
+		runtimeExtensionProviders = getValueOrFallback(input.RuntimeExtensionProviders,
 			input.E2EConfig.GetProviderLatestVersionsByContract(initContract, input.E2EConfig.RuntimeExtensionProviders()...))
 
 		clusterctl.InitManagementClusterAndWatchControllerLogs(ctx, clusterctl.InitManagementClusterAndWatchControllerLogsInput{
@@ -436,7 +436,6 @@ func ClusterctlUpgradeSpec(ctx context.Context, inputGetter func() ClusterctlUpg
 		}
 
 		// After the upgrade check that there were no unexpected rollouts.
-		log.Logf("Verify there are no unexpected rollouts")
 		Consistently(func() bool {
 			postUpgradeMachineList := &unstructured.UnstructuredList{}
 			postUpgradeMachineList.SetGroupVersionKind(clusterv1.GroupVersion.WithKind("MachineList"))
@@ -736,7 +735,7 @@ func matchUnstructuredLists(l1 *unstructured.UnstructuredList, l2 *unstructured.
 
 // getValueOrFallback returns the input value unless it is empty, then it returns the fallback input.
 func getValueOrFallback(value []string, fallback []string) []string {
-	if value != nil {
+	if len(value) > 0 {
 		return value
 	}
 	return fallback
diff --git a/test/e2e/clusterctl_upgrade_test.go b/test/e2e/clusterctl_upgrade_test.go
index 805b8f5a1..193d7f155 100644
--- a/test/e2e/clusterctl_upgrade_test.go
+++ b/test/e2e/clusterctl_upgrade_test.go
@@ -53,7 +53,7 @@ var _ = Describe("When testing clusterctl upgrades (v0.4=>current)", func() {
 			SkipCleanup:               skipCleanup,
 			InitWithBinary:            "https://github.com/kubernetes-sigs/cluster-api/releases/download/v0.4.8/clusterctl-{OS}-{ARCH}",
 			InitWithProvidersContract: "v1alpha4",
-			InitWithKubernetesVersion: "v1.23.13",
+			InitWithKubernetesVersion: "v1.25.3",
 		}
 	})
 })
@@ -61,53 +61,34 @@ var _ = Describe("When testing clusterctl upgrades (v0.4=>current)", func() {
 var _ = Describe("When testing clusterctl upgrades (v1.2=>current)", func() {
 	ClusterctlUpgradeSpec(ctx, func() ClusterctlUpgradeSpecInput {
 		return ClusterctlUpgradeSpecInput{
-			E2EConfig:             e2eConfig,
-			ClusterctlConfigPath:  clusterctlConfigPath,
-			BootstrapClusterProxy: bootstrapClusterProxy,
-			ArtifactFolder:        artifactFolder,
-			SkipCleanup:           skipCleanup,
-			InitWithBinary:        "https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.2.7/clusterctl-{OS}-{ARCH}",
-			// We have to pin the providers because with `InitWithProvidersContract` the test would
-			// use the latest version for the contract (which is v1.3.0 for v1beta1).
-			InitWithCoreProvider:            "cluster-api:v1.2.8",
-			InitWithBootstrapProviders:      []string{"kubeadm:v1.2.8"},
-			InitWithControlPlaneProviders:   []string{"kubeadm:v1.2.8"},
-			InitWithInfrastructureProviders: []string{"docker:v1.2.8"},
-			// We have to set this to an empty array as clusterctl v1.2 doesn't support
-			// runtime extension providers. If we don't do this the test will automatically
-			// try to deploy the latest version of our test-extension from docker.yaml.
-			InitWithRuntimeExtensionProviders: []string{},
-			InitWithKubernetesVersion:         "v1.26.0",
+			E2EConfig:                 e2eConfig,
+			ClusterctlConfigPath:      clusterctlConfigPath,
+			BootstrapClusterProxy:     bootstrapClusterProxy,
+			ArtifactFolder:            artifactFolder,
+			SkipCleanup:               skipCleanup,
+			InitWithBinary:            "https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.2.7/clusterctl-{OS}-{ARCH}",
+			InitWithProvidersContract: "v1beta1",
+			InitWithKubernetesVersion: "v1.26.0",
 		}
 	})
 })
 
-var _ = Describe("When testing clusterctl upgrades using ClusterClass (v1.2=>current) [ClusterClass]", func() {
+var _ = Describe("When testing clusterctl upgrades (v1.3=>current)", func() {
 	ClusterctlUpgradeSpec(ctx, func() ClusterctlUpgradeSpecInput {
 		return ClusterctlUpgradeSpecInput{
-			E2EConfig:             e2eConfig,
-			ClusterctlConfigPath:  clusterctlConfigPath,
-			BootstrapClusterProxy: bootstrapClusterProxy,
-			ArtifactFolder:        artifactFolder,
-			SkipCleanup:           skipCleanup,
-			InitWithBinary:        "https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.2.7/clusterctl-{OS}-{ARCH}",
-			// We have to pin the providers because with `InitWithProvidersContract` the test would
-			// use the latest version for the contract (which is v1.3.0 for v1beta1).
-			InitWithCoreProvider:            "cluster-api:v1.2.8",
-			InitWithBootstrapProviders:      []string{"kubeadm:v1.2.8"},
-			InitWithControlPlaneProviders:   []string{"kubeadm:v1.2.8"},
-			InitWithInfrastructureProviders: []string{"docker:v1.2.8"},
-			// We have to set this to an empty array as clusterctl v1.2 doesn't support
-			// runtime extension providers. If we don't do this the test will automatically
-			// try to deploy the latest version of our test-extension from docker.yaml.
-			InitWithRuntimeExtensionProviders: []string{},
-			InitWithKubernetesVersion:         "v1.26.0",
-			WorkloadFlavor:                    "topology",
+			E2EConfig:                 e2eConfig,
+			ClusterctlConfigPath:      clusterctlConfigPath,
+			BootstrapClusterProxy:     bootstrapClusterProxy,
+			ArtifactFolder:            artifactFolder,
+			SkipCleanup:               skipCleanup,
+			InitWithBinary:            "https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.3.0/clusterctl-{OS}-{ARCH}",
+			InitWithProvidersContract: "v1beta1",
+			InitWithKubernetesVersion: "v1.26.0",
 		}
 	})
 })
 
-var _ = Describe("When testing clusterctl upgrades (v1.3=>current)", func() {
+var _ = Describe("When testing clusterctl upgrades using ClusterClass (v1.2=>current) [ClusterClass]", func() {
 	ClusterctlUpgradeSpec(ctx, func() ClusterctlUpgradeSpecInput {
 		return ClusterctlUpgradeSpecInput{
 			E2EConfig:                 e2eConfig,
@@ -115,9 +96,10 @@ var _ = Describe("When testing clusterctl upgrades (v1.3=>current)", func() {
 			BootstrapClusterProxy:     bootstrapClusterProxy,
 			ArtifactFolder:            artifactFolder,
 			SkipCleanup:               skipCleanup,
-			InitWithBinary:            "https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.3.0/clusterctl-{OS}-{ARCH}",
+			InitWithBinary:            "https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.2.7/clusterctl-{OS}-{ARCH}",
 			InitWithProvidersContract: "v1beta1",
 			InitWithKubernetesVersion: "v1.26.0",
+			WorkloadFlavor:            "topology",
 		}
 	})
 })
diff --git a/test/e2e/config/docker.yaml b/test/e2e/config/docker.yaml
index 708ecef3b..44ba0e2ab 100644
--- a/test/e2e/config/docker.yaml
+++ b/test/e2e/config/docker.yaml
@@ -19,11 +19,11 @@ images:
   loadBehavior: tryLoad
 - name: gcr.io/k8s-staging-cluster-api/test-extension-{ARCH}:dev
   loadBehavior: tryLoad
-- name: quay.io/jetstack/cert-manager-cainjector:v1.11.0
+- name: quay.io/jetstack/cert-manager-cainjector:v1.10.1
   loadBehavior: tryLoad
-- name: quay.io/jetstack/cert-manager-webhook:v1.11.0
+- name: quay.io/jetstack/cert-manager-webhook:v1.10.1
   loadBehavior: tryLoad
-- name: quay.io/jetstack/cert-manager-controller:v1.11.0
+- name: quay.io/jetstack/cert-manager-controller:v1.10.1
   loadBehavior: tryLoad
 
 providers:
@@ -39,7 +39,7 @@ providers:
     - old: --metrics-addr=127.0.0.1:8080
       new: --metrics-addr=:8080
     files:
-    - sourcePath: "../data/shared/v0.3/metadata.yaml"
+    - sourcePath: "../data/shared/v1alpha3/metadata.yaml"
   - name: v0.4.8 # latest published release in the v1alpha4 series; this is used for v1alpha4 --> v1beta1 clusterctl upgrades test only.
     value: "https://github.com/kubernetes-sigs/cluster-api/releases/download/v0.4.8/core-components.yaml"
     type: "url"
@@ -48,16 +48,16 @@ providers:
     - old: --metrics-addr=127.0.0.1:8080
       new: --metrics-addr=:8080
     files:
-    - sourcePath: "../data/shared/v0.4/metadata.yaml"
-  - name: v1.2.8 # supported release in the v1beta1 series; this is used for v1beta1 --> main clusterctl upgrades test only.
-    value: "https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.2.8/core-components.yaml"
+    - sourcePath: "../data/shared/v1alpha4/metadata.yaml"
+  - name: v1.2.7 # supported release in the v1beta1 series; this is used for v1beta1 --> main clusterctl upgrades test only.
+    value: "https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.2.7/core-components.yaml"
     type: "url"
     contract: v1beta1
     replacements:
     - old: --metrics-addr=127.0.0.1:8080
       new: --metrics-addr=:8080
     files:
-    - sourcePath: "../data/shared/v1.2/metadata.yaml"
+    - sourcePath: "../data/shared/v1beta1/v1.2/metadata.yaml"
   - name: v1.3.0 # latest published release in the v1beta1 series; this is used for v1beta1 --> main clusterctl upgrades test only.
     value: "https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.3.0/core-components.yaml"
     type: "url"
@@ -66,14 +66,14 @@ providers:
       - old: --metrics-addr=127.0.0.1:8080
         new: --metrics-addr=:8080
     files:
-      - sourcePath: "../data/shared/v1.3/metadata.yaml"
+      - sourcePath: "../data/shared/v1beta1/v1.3/metadata.yaml"
   - name: v1.4.99 # next; use manifest from source files
     value: ../../../config/default
     replacements:
     - old: --metrics-bind-addr=localhost:8080
       new: "--metrics-bind-addr=:8080\n        - --logging-format=json"
     files:
-    - sourcePath: "../data/shared/main/metadata.yaml"
+    - sourcePath: "../data/shared/v1beta1/main/metadata.yaml"
 
 - name: kubeadm
   type: BootstrapProvider
@@ -86,7 +86,7 @@ providers:
     - old: --metrics-addr=127.0.0.1:8080
       new: --metrics-addr=:8080
     files:
-    - sourcePath: "../data/shared/v0.3/metadata.yaml"
+    - sourcePath: "../data/shared/v1alpha3/metadata.yaml"
   - name: v0.4.8 # latest published release in the v1alpha4 series; this is used for v1alpha4 --> v1beta1 clusterctl upgrades test only.
     value: "https://github.com/kubernetes-sigs/cluster-api/releases/download/v0.4.8/bootstrap-components.yaml"
     type: "url"
@@ -95,16 +95,16 @@ providers:
     - old: --metrics-addr=127.0.0.1:8080
       new: --metrics-addr=:8080
     files:
-    - sourcePath: "../data/shared/v0.4/metadata.yaml"
-  - name: v1.2.8 # supported release in the v1beta1 series; this is used for v1beta1 --> main clusterctl upgrades test only.
-    value: "https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.2.8/bootstrap-components.yaml"
+    - sourcePath: "../data/shared/v1alpha4/metadata.yaml"
+  - name: v1.2.7 # supported release in the v1beta1 series; this is used for v1beta1 --> main clusterctl upgrades test only.
+    value: "https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.2.7/bootstrap-components.yaml"
     type: "url"
     contract: v1beta1
     replacements:
     - old: --metrics-addr=127.0.0.1:8080
       new: --metrics-addr=:8080
     files:
-    - sourcePath: "../data/shared/v1.2/metadata.yaml"
+    - sourcePath: "../data/shared/v1beta1/v1.2/metadata.yaml"
   - name: v1.3.0 # latest published release in the v1beta1 series; this is used for v1beta1 --> main clusterctl upgrades test only.
     value: "https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.3.0/bootstrap-components.yaml"
     type: "url"
@@ -113,14 +113,14 @@ providers:
     - old: --metrics-addr=127.0.0.1:8080
       new: --metrics-addr=:8080
     files:
-    - sourcePath: "../data/shared/v1.3/metadata.yaml"
+    - sourcePath: "../data/shared/v1beta1/v1.3/metadata.yaml"
   - name: v1.4.99 # next; use manifest from source files
     value: ../../../bootstrap/kubeadm/config/default
     replacements:
     - old: --metrics-bind-addr=localhost:8080
       new: "--metrics-bind-addr=:8080\n        - --logging-format=json"
     files:
-    - sourcePath: "../data/shared/main/metadata.yaml"
+    - sourcePath: "../data/shared/v1beta1/main/metadata.yaml"
 
 - name: kubeadm
   type: ControlPlaneProvider
@@ -133,7 +133,7 @@ providers:
     - old: --metrics-addr=127.0.0.1:8080
       new: --metrics-addr=:8080
     files:
-    - sourcePath: "../data/shared/v0.3/metadata.yaml"
+    - sourcePath: "../data/shared/v1alpha3/metadata.yaml"
   - name: v0.4.8 # latest published release in the v1alpha4 series; this is used for v1alpha4 --> v1beta1 clusterctl upgrades test only.
     value: "https://github.com/kubernetes-sigs/cluster-api/releases/download/v0.4.8/control-plane-components.yaml"
     type: "url"
@@ -142,16 +142,16 @@ providers:
     - old: --metrics-addr=127.0.0.1:8080
       new: --metrics-addr=:8080
     files:
-    - sourcePath: "../data/shared/v0.4/metadata.yaml"
-  - name: v1.2.8 # supported release in the v1beta1 series; this is used for v1beta1 --> main clusterctl upgrades test only.
-    value: "https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.2.8/control-plane-components.yaml"
+    - sourcePath: "../data/shared/v1alpha4/metadata.yaml"
+  - name: v1.2.7 # supported release in the v1beta1 series; this is used for v1beta1 --> main clusterctl upgrades test only.
+    value: "https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.2.7/control-plane-components.yaml"
     type: "url"
     contract: v1beta1
     replacements:
     - old: --metrics-addr=127.0.0.1:8080
       new: --metrics-addr=:8080
     files:
-    - sourcePath: "../data/shared/v1.2/metadata.yaml"
+    - sourcePath: "../data/shared/v1beta1/v1.2/metadata.yaml"
   - name: v1.3.0 # latest published release in the v1beta1 series; this is used for v1beta1 --> main clusterctl upgrades test only.
     value: "https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.3.0/control-plane-components.yaml"
     type: "url"
@@ -160,14 +160,14 @@ providers:
     - old: --metrics-addr=127.0.0.1:8080
       new: --metrics-addr=:8080
     files:
-    - sourcePath: "../data/shared/v1.3/metadata.yaml"
+    - sourcePath: "../data/shared/v1beta1/v1.3/metadata.yaml"
   - name: v1.4.99 # next; use manifest from source files
     value: ../../../controlplane/kubeadm/config/default
     replacements:
     - old: --metrics-bind-addr=localhost:8080
       new: "--metrics-bind-addr=:8080\n        - --logging-format=json"
     files:
-    - sourcePath: "../data/shared/main/metadata.yaml"
+    - sourcePath: "../data/shared/v1beta1/main/metadata.yaml"
 
 - name: docker
   type: InfrastructureProvider
@@ -180,8 +180,8 @@ providers:
     - old: --metrics-addr=127.0.0.1:8080
       new: --metrics-addr=:8080
     files:
-    - sourcePath: "../data/shared/v0.3/metadata.yaml"
-    - sourcePath: "../data/infrastructure-docker/v0.3/cluster-template.yaml"
+    - sourcePath: "../data/shared/v1alpha3/metadata.yaml"
+    - sourcePath: "../data/infrastructure-docker/v1alpha3/cluster-template.yaml"
   - name: v0.4.8 # latest published release in the v1alpha4 series; this is used for v1alpha4 --> v1beta1 clusterctl upgrades test only.
     value: "https://github.com/kubernetes-sigs/cluster-api/releases/download/v0.4.8/infrastructure-components-development.yaml"
     type: "url"
@@ -190,20 +190,20 @@ providers:
     - old: --metrics-addr=127.0.0.1:8080
       new: --metrics-addr=:8080
     files:
-    - sourcePath: "../data/shared/v0.4/metadata.yaml"
-    - sourcePath: "../data/infrastructure-docker/v0.4/cluster-template.yaml"
-  - name: v1.2.8 # supported release in the v1beta1 series; this is used for v1beta1 --> main clusterctl upgrades test only.
-    value: "https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.2.8/infrastructure-components-development.yaml"
+    - sourcePath: "../data/shared/v1alpha4/metadata.yaml"
+    - sourcePath: "../data/infrastructure-docker/v1alpha4/cluster-template.yaml"
+  - name: v1.2.7 # supported release in the v1beta1 series; this is used for v1beta1 --> main clusterctl upgrades test only.
+    value: "https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.2.7/infrastructure-components-development.yaml"
     type: "url"
     contract: v1beta1
     replacements:
     - old: --metrics-addr=127.0.0.1:8080
       new: --metrics-addr=:8080
     files:
-    - sourcePath: "../data/shared/v1.2/metadata.yaml"
-    - sourcePath: "../data/infrastructure-docker/v1.2/cluster-template.yaml"
-    - sourcePath: "../data/infrastructure-docker/v1.2/cluster-template-topology.yaml"
-    - sourcePath: "../data/infrastructure-docker/v1.2/clusterclass-quick-start.yaml"
+    - sourcePath: "../data/shared/v1beta1/v1.2/metadata.yaml"
+    - sourcePath: "../data/infrastructure-docker/v1beta1/v1.2/cluster-template.yaml"
+    - sourcePath: "../data/infrastructure-docker/v1beta1/v1.2/cluster-template-topology.yaml"
+    - sourcePath: "../data/infrastructure-docker/v1beta1/v1.2/clusterclass-quick-start.yaml"
   - name: v1.3.0 # latest published release in the v1beta1 series; this is used for v1beta1 --> main clusterctl upgrades test only.
     value: "https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.3.0/infrastructure-components-development.yaml"
     type: "url"
@@ -212,10 +212,10 @@ providers:
     - old: --metrics-addr=127.0.0.1:8080
       new: --metrics-addr=:8080
     files:
-    - sourcePath: "../data/shared/v1.3/metadata.yaml"
-    - sourcePath: "../data/infrastructure-docker/v1.3/cluster-template.yaml"
-    - sourcePath: "../data/infrastructure-docker/v1.3/cluster-template-topology.yaml"
-    - sourcePath: "../data/infrastructure-docker/v1.3/clusterclass-quick-start.yaml"
+    - sourcePath: "../data/shared/v1beta1/v1.3/metadata.yaml"
+    - sourcePath: "../data/infrastructure-docker/v1beta1/v1.3/cluster-template.yaml"
+    - sourcePath: "../data/infrastructure-docker/v1beta1/v1.3/cluster-template-topology.yaml"
+    - sourcePath: "../data/infrastructure-docker/v1beta1/v1.3/clusterclass-quick-start.yaml"
   - name: v1.4.99 # next; use manifest from source files
     value: ../../../test/infrastructure/docker/config/default
     replacements:
@@ -223,23 +223,23 @@ providers:
       new: "--metrics-bind-addr=:8080\n        - --logging-format=json"
     files:
     # Add cluster templates
-    - sourcePath: "../data/infrastructure-docker/main/cluster-template.yaml"
-    - sourcePath: "../data/infrastructure-docker/main/cluster-template-md-remediation.yaml"
-    - sourcePath: "../data/infrastructure-docker/main/cluster-template-kcp-remediation.yaml"
-    - sourcePath: "../data/infrastructure-docker/main/cluster-template-kcp-adoption.yaml"
-    - sourcePath: "../data/infrastructure-docker/main/cluster-template-machine-pool.yaml"
-    - sourcePath: "../data/infrastructure-docker/main/cluster-template-node-drain.yaml"
-    - sourcePath: "../data/infrastructure-docker/main/cluster-template-upgrades.yaml"
-    - sourcePath: "../data/infrastructure-docker/main/cluster-template-upgrades-cgroupfs.yaml"
-    - sourcePath: "../data/infrastructure-docker/main/cluster-template-upgrades-runtimesdk.yaml"
-    - sourcePath: "../data/infrastructure-docker/main/cluster-template-kcp-scale-in.yaml"
-    - sourcePath: "../data/infrastructure-docker/main/cluster-template-ipv6.yaml"
-    - sourcePath: "../data/infrastructure-docker/main/cluster-template-topology-single-node-cluster.yaml"
-    - sourcePath: "../data/infrastructure-docker/main/cluster-template-topology.yaml"
-    - sourcePath: "../data/infrastructure-docker/main/cluster-template-ignition.yaml"
-    - sourcePath: "../data/infrastructure-docker/main/clusterclass-quick-start.yaml"
-    - sourcePath: "../data/infrastructure-docker/main/clusterclass-quick-start-runtimesdk.yaml"
-    - sourcePath: "../data/shared/main/metadata.yaml"
+    - sourcePath: "../data/infrastructure-docker/v1beta1/main/cluster-template.yaml"
+    - sourcePath: "../data/infrastructure-docker/v1beta1/main/cluster-template-md-remediation.yaml"
+    - sourcePath: "../data/infrastructure-docker/v1beta1/main/cluster-template-kcp-remediation.yaml"
+    - sourcePath: "../data/infrastructure-docker/v1beta1/main/cluster-template-kcp-adoption.yaml"
+    - sourcePath: "../data/infrastructure-docker/v1beta1/main/cluster-template-machine-pool.yaml"
+    - sourcePath: "../data/infrastructure-docker/v1beta1/main/cluster-template-node-drain.yaml"
+    - sourcePath: "../data/infrastructure-docker/v1beta1/main/cluster-template-upgrades.yaml"
+    - sourcePath: "../data/infrastructure-docker/v1beta1/main/cluster-template-upgrades-cgroupfs.yaml"
+    - sourcePath: "../data/infrastructure-docker/v1beta1/main/cluster-template-upgrades-runtimesdk.yaml"
+    - sourcePath: "../data/infrastructure-docker/v1beta1/main/cluster-template-kcp-scale-in.yaml"
+    - sourcePath: "../data/infrastructure-docker/v1beta1/main/cluster-template-ipv6.yaml"
+    - sourcePath: "../data/infrastructure-docker/v1beta1/main/cluster-template-topology-single-node-cluster.yaml"
+    - sourcePath: "../data/infrastructure-docker/v1beta1/main/cluster-template-topology.yaml"
+    - sourcePath: "../data/infrastructure-docker/v1beta1/main/cluster-template-ignition.yaml"
+    - sourcePath: "../data/infrastructure-docker/v1beta1/main/clusterclass-quick-start.yaml"
+    - sourcePath: "../data/infrastructure-docker/v1beta1/main/clusterclass-quick-start-runtimesdk.yaml"
+    - sourcePath: "../data/shared/v1beta1/main/metadata.yaml"
 
 - name: test-extension
   type: RuntimeExtensionProvider
@@ -247,7 +247,7 @@ providers:
     - name: v1.4.99 # next; use manifest from source files
       value: ../../../test/extension/config/default
       files:
-      - sourcePath: "../data/shared/main/metadata.yaml"
+      - sourcePath: "../data/shared/v1beta1/main/metadata.yaml"
 
 variables:
   # Default variables for the e2e test; those values could be overridden via env variables, thus
diff --git a/test/e2e/data/infrastructure-docker/README.md b/test/e2e/data/infrastructure-docker/README.md
index 1c14e0a27..da1c0a604 100644
--- a/test/e2e/data/infrastructure-docker/README.md
+++ b/test/e2e/data/infrastructure-docker/README.md
@@ -1,17 +1,12 @@
 # CAPD cluster templates
 
 This folder contains cluster templates used in e2e tests. Each sub-folder contains cluster templates
-for the corresponding Cluster API version.
+complying to the corresponding contract.
 
-Sub-folders for the old versions of Cluster API should contain only templates used for the clusterctl upgrade tests.
-In those tests we first deploy an old version of Cluster API, create a workload cluster and then upgrade Cluster API
-to the version from the current branch (and check that the workload cluster still works).
+The templates in [v1alpha3](./v1alpha3), [v1alpha4](./v1alpha4) and [v1.2](./v1beta1/v1.2) are used for 
+clusterctl upgrade tests. In those tests we first deploy an old version of Cluster API and then upgrade 
+to the version from the current branch. We can't use the same templates for `v1.2` and `main` as not all 
+fields we use in `main` already existed in `v1.2`.
 
-As of today we have clusterctl upgrade tests for the latest stable versions of each contract / for each supported branch, i.e.:
-* v1alpha3: v0.3
-* v1alpha4: v0.4
-* v1beta1: v1.2, v1.3 (will change with each new release)
-
-We cannot use the same cluster templates for all Cluster API versions as not each Cluster API version supports
-the same API fields. For example `KubeadmControlPlane.spec.rolloutBefore.certificatesExpiryDays` was introduced 
-with v1.3 so we couldn't have used it in v1.2 cluster templates.
+Note: The `v1.2` folder can be deleted once we start developing on v1.4.x. Depending on if we introduce and 
+use new fields in v1.4.x we might have to introduce a `v1.3` folder then.
diff --git a/test/e2e/data/infrastructure-docker/v1.3/bases/mp.yaml b/test/e2e/data/infrastructure-docker/v1.3/bases/mp.yaml
deleted file mode 100644
index 6dc8170ed..000000000
--- a/test/e2e/data/infrastructure-docker/v1.3/bases/mp.yaml
+++ /dev/null
@@ -1,49 +0,0 @@
----
-# MachinePool which references the DockerMachinePool and KubeadmConfigTemplate below
-apiVersion: cluster.x-k8s.io/v1beta1
-kind: MachinePool
-metadata:
-  name: "${CLUSTER_NAME}-mp-0"
-spec:
-  clusterName: '${CLUSTER_NAME}'
-  replicas: ${WORKER_MACHINE_COUNT}
-  template:
-    spec:
-      bootstrap:
-        configRef:
-          apiVersion: bootstrap.cluster.x-k8s.io/v1beta1
-          kind: KubeadmConfig
-          name: "${CLUSTER_NAME}-mp-0-config"
-      clusterName: '${CLUSTER_NAME}'
-      infrastructureRef:
-        apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
-        kind: DockerMachinePool
-        name: "${CLUSTER_NAME}-dmp-0"
-      version: "${KUBERNETES_VERSION}"
-  failureDomains:
-    - fd4
-    - fd5
-    - fd6
-    - fd7
-    - fd8
----
-# DockerMachinePool using default values referenced by the MachinePool
-apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
-kind: DockerMachinePool
-metadata:
-  name: "${CLUSTER_NAME}-dmp-0"
-spec:
-  template:
-      # The DOCKER_PRELOAD_IMAGES variable gets set in self-hosted E2E tests to the list of images of the E2E configuration.
-      preLoadImages: ${DOCKER_PRELOAD_IMAGES:-[]}
----
-# KubeadmConfigTemplate referenced by the MachinePool
-apiVersion: bootstrap.cluster.x-k8s.io/v1beta1
-kind: KubeadmConfig
-metadata:
-  name: "${CLUSTER_NAME}-mp-0-config"
-spec:
-  joinConfiguration:
-    nodeRegistration:
-      kubeletExtraArgs:
-        eviction-hard: nodefs.available<0%,nodefs.inodesFree<0%,imagefs.available<0%
diff --git a/test/e2e/data/infrastructure-docker/v0.3/bases/cluster-with-kcp.yaml b/test/e2e/data/infrastructure-docker/v1alpha3/bases/cluster-with-kcp.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/v0.3/bases/cluster-with-kcp.yaml
rename to test/e2e/data/infrastructure-docker/v1alpha3/bases/cluster-with-kcp.yaml
diff --git a/test/e2e/data/infrastructure-docker/v0.3/bases/crs.yaml b/test/e2e/data/infrastructure-docker/v1alpha3/bases/crs.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/v0.3/bases/crs.yaml
rename to test/e2e/data/infrastructure-docker/v1alpha3/bases/crs.yaml
diff --git a/test/e2e/data/infrastructure-docker/v0.3/bases/md.yaml b/test/e2e/data/infrastructure-docker/v1alpha3/bases/md.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/v0.3/bases/md.yaml
rename to test/e2e/data/infrastructure-docker/v1alpha3/bases/md.yaml
diff --git a/test/e2e/data/infrastructure-docker/main/cluster-template/kustomization.yaml b/test/e2e/data/infrastructure-docker/v1alpha3/cluster-template/kustomization.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/main/cluster-template/kustomization.yaml
rename to test/e2e/data/infrastructure-docker/v1alpha3/cluster-template/kustomization.yaml
diff --git a/test/e2e/data/infrastructure-docker/v0.4/bases/cluster-with-kcp.yaml b/test/e2e/data/infrastructure-docker/v1alpha4/bases/cluster-with-kcp.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/v0.4/bases/cluster-with-kcp.yaml
rename to test/e2e/data/infrastructure-docker/v1alpha4/bases/cluster-with-kcp.yaml
diff --git a/test/e2e/data/infrastructure-docker/v0.4/bases/crs.yaml b/test/e2e/data/infrastructure-docker/v1alpha4/bases/crs.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/v0.4/bases/crs.yaml
rename to test/e2e/data/infrastructure-docker/v1alpha4/bases/crs.yaml
diff --git a/test/e2e/data/infrastructure-docker/v0.4/bases/md.yaml b/test/e2e/data/infrastructure-docker/v1alpha4/bases/md.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/v0.4/bases/md.yaml
rename to test/e2e/data/infrastructure-docker/v1alpha4/bases/md.yaml
diff --git a/test/e2e/data/infrastructure-docker/v0.4/bases/mp.yaml b/test/e2e/data/infrastructure-docker/v1alpha4/bases/mp.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/v0.4/bases/mp.yaml
rename to test/e2e/data/infrastructure-docker/v1alpha4/bases/mp.yaml
diff --git a/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-ipv6/kcp-ipv6.yaml b/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-ipv6/kcp-ipv6.yaml
new file mode 100644
index 000000000..62f0a89c3
--- /dev/null
+++ b/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-ipv6/kcp-ipv6.yaml
@@ -0,0 +1,22 @@
+---
+kind: KubeadmControlPlane
+apiVersion: controlplane.cluster.x-k8s.io/v1alpha4
+metadata:
+  name: "${CLUSTER_NAME}-control-plane"
+spec:
+  kubeadmConfigSpec:
+    clusterConfiguration:
+      apiServer:
+        # host.docker.internal is required by kubetest when running on MacOS because of the way ports are proxied.
+        certSANs: [localhost, "::", "::1", host.docker.internal]
+    initConfiguration:
+      localAPIEndpoint:
+        advertiseAddress: '::'
+        bindPort: 6443
+      nodeRegistration:
+        kubeletExtraArgs:
+          node-ip: "::"
+    joinConfiguration:
+      nodeRegistration:
+        kubeletExtraArgs:
+          node-ip: "::"
diff --git a/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-ipv6/kustomization.yaml b/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-ipv6/kustomization.yaml
new file mode 100644
index 000000000..1a233e731
--- /dev/null
+++ b/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-ipv6/kustomization.yaml
@@ -0,0 +1,8 @@
+bases:
+  - ../bases/cluster-with-kcp.yaml
+  - ../bases/md.yaml
+  - ../bases/crs.yaml
+
+patchesStrategicMerge:
+  - ./md-ipv6.yaml
+  - ./kcp-ipv6.yaml
diff --git a/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-ipv6/md-ipv6.yaml b/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-ipv6/md-ipv6.yaml
new file mode 100644
index 000000000..106f4968b
--- /dev/null
+++ b/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-ipv6/md-ipv6.yaml
@@ -0,0 +1,16 @@
+---
+apiVersion: bootstrap.cluster.x-k8s.io/v1alpha4
+kind: KubeadmConfigTemplate
+metadata:
+  name: "${CLUSTER_NAME}-md-0"
+spec:
+  template:
+    spec:
+      initConfiguration:
+        nodeRegistration:
+          kubeletExtraArgs:
+            node-ip: "::"
+      joinConfiguration:
+        nodeRegistration:
+          kubeletExtraArgs:
+            node-ip: "::"
diff --git a/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-kcp-adoption/step1/cluster-with-cp0.yaml b/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-kcp-adoption/step1/cluster-with-cp0.yaml
new file mode 100644
index 000000000..aa272922b
--- /dev/null
+++ b/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-kcp-adoption/step1/cluster-with-cp0.yaml
@@ -0,0 +1,76 @@
+---
+# DockerCluster object referenced by the Cluster object
+apiVersion: infrastructure.cluster.x-k8s.io/v1alpha4
+kind: DockerCluster
+metadata:
+  name: '${CLUSTER_NAME}'
+---
+# Cluster object with
+# - No reference to the KubeadmControlPlane object
+# - the label cni=${CLUSTER_NAME}-crs-0, so the cluster can be selected by the ClusterResourceSet.
+apiVersion: cluster.x-k8s.io/v1alpha4
+kind: Cluster
+metadata:
+  name: '${CLUSTER_NAME}'
+  labels:
+    cni: "${CLUSTER_NAME}-crs-0"
+spec:
+  clusterNetwork:
+    services:
+      cidrBlocks: ['${DOCKER_SERVICE_CIDRS}']
+    pods:
+      cidrBlocks: ['${DOCKER_POD_CIDRS}']
+    serviceDomain: '${DOCKER_SERVICE_DOMAIN}'
+  infrastructureRef:
+    apiVersion: infrastructure.cluster.x-k8s.io/v1alpha4
+    kind: DockerCluster
+    name: '${CLUSTER_NAME}'
+---
+# DockerMachine referenced by the Machine cp0
+apiVersion: infrastructure.cluster.x-k8s.io/v1alpha4
+kind: DockerMachine
+metadata:
+  name: "${CLUSTER_NAME}-control-plane-0"
+spec: {}
+---
+# KubeadmConfig referenced by the Machine cp0
+apiVersion: bootstrap.cluster.x-k8s.io/v1alpha4
+kind: KubeadmConfig
+metadata:
+  name: "${CLUSTER_NAME}-control-plane-0"
+spec:
+  clusterConfiguration:
+    controllerManager:
+      extraArgs: {enable-hostpath-provisioner: 'true'}
+    apiServer:
+      certSANs: [localhost, 127.0.0.1]
+  initConfiguration:
+    nodeRegistration:
+      criSocket: unix:///var/run/containerd/containerd.sock
+      kubeletExtraArgs:
+        eviction-hard: 'nodefs.available<0%,nodefs.inodesFree<0%,imagefs.available<0%'
+  joinConfiguration:
+    nodeRegistration:
+      criSocket: unix:///var/run/containerd/containerd.sock
+      kubeletExtraArgs:
+        eviction-hard: 'nodefs.available<0%,nodefs.inodesFree<0%,imagefs.available<0%'
+---
+# cp0 Machine
+apiVersion: cluster.x-k8s.io/v1alpha4
+kind: Machine
+metadata:
+  name: "${CLUSTER_NAME}-control-plane-0"
+  labels:
+    cluster.x-k8s.io/control-plane: ''
+spec:
+  clusterName: "${ CLUSTER_NAME }"
+  version: "${ KUBERNETES_VERSION }"
+  bootstrap:
+    configRef:
+      name: "${ CLUSTER_NAME }-control-plane-0"
+      apiVersion: bootstrap.cluster.x-k8s.io/v1alpha4
+      kind: KubeadmConfig
+  infrastructureRef:
+    name: "${ CLUSTER_NAME }-control-plane-0"
+    apiVersion: infrastructure.cluster.x-k8s.io/v1alpha4
+    kind: DockerMachine
diff --git a/test/e2e/data/infrastructure-docker/main/cluster-template-kcp-adoption/step1/kustomization.yaml b/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-kcp-adoption/step1/kustomization.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/main/cluster-template-kcp-adoption/step1/kustomization.yaml
rename to test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-kcp-adoption/step1/kustomization.yaml
diff --git a/test/e2e/data/infrastructure-docker/main/cluster-template-kcp-adoption/step2/kustomization.yaml b/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-kcp-adoption/step2/kustomization.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/main/cluster-template-kcp-adoption/step2/kustomization.yaml
rename to test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-kcp-adoption/step2/kustomization.yaml
diff --git a/test/e2e/data/infrastructure-docker/main/cluster-template-kcp-remediation/kustomization.yaml b/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-kcp-remediation/kustomization.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/main/cluster-template-kcp-remediation/kustomization.yaml
rename to test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-kcp-remediation/kustomization.yaml
diff --git a/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-kcp-remediation/mhc.yaml b/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-kcp-remediation/mhc.yaml
new file mode 100644
index 000000000..1de43a1ef
--- /dev/null
+++ b/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-kcp-remediation/mhc.yaml
@@ -0,0 +1,18 @@
+---
+# MachineHealthCheck object with
+# - a selector that targets all the machines with label cluster.x-k8s.io/control-plane=""
+# - unhealthyConditions triggering remediation after 10s the condition is set
+apiVersion: cluster.x-k8s.io/v1alpha4
+kind: MachineHealthCheck
+metadata:
+  name: "${CLUSTER_NAME}-mhc-0"
+spec:
+  clusterName: "${CLUSTER_NAME}"
+  maxUnhealthy: 100%
+  selector:
+    matchLabels:
+      cluster.x-k8s.io/control-plane: ""
+  unhealthyConditions:
+    - type: e2e.remediation.condition
+      status: "False"
+      timeout: 10s
diff --git a/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-kcp-scale-in/cluster-with-kcp.yaml b/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-kcp-scale-in/cluster-with-kcp.yaml
new file mode 100644
index 000000000..81426d787
--- /dev/null
+++ b/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-kcp-scale-in/cluster-with-kcp.yaml
@@ -0,0 +1,9 @@
+# KubeadmControlPlane referenced by the Cluster object with
+kind: KubeadmControlPlane
+apiVersion: controlplane.cluster.x-k8s.io/v1alpha4
+metadata:
+  name: "${CLUSTER_NAME}-control-plane"
+spec:
+  rolloutStrategy:
+    rollingUpdate:
+      maxSurge: 0
diff --git a/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-kcp-scale-in/kustomization.yaml b/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-kcp-scale-in/kustomization.yaml
new file mode 100644
index 000000000..50546094a
--- /dev/null
+++ b/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-kcp-scale-in/kustomization.yaml
@@ -0,0 +1,7 @@
+bases:
+- ../bases/crs.yaml
+- ../bases/md.yaml
+- ../bases/cluster-with-kcp.yaml
+
+patchesStrategicMerge:
+- ./cluster-with-kcp.yaml
\ No newline at end of file
diff --git a/test/e2e/data/infrastructure-docker/main/cluster-template-machine-pool/kustomization.yaml b/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-machine-pool/kustomization.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/main/cluster-template-machine-pool/kustomization.yaml
rename to test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-machine-pool/kustomization.yaml
diff --git a/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-md-remediation/kustomization.yaml b/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-md-remediation/kustomization.yaml
new file mode 100644
index 000000000..82c8029e8
--- /dev/null
+++ b/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-md-remediation/kustomization.yaml
@@ -0,0 +1,8 @@
+bases:
+  - ../bases/cluster-with-kcp.yaml
+  - ../bases/md.yaml
+  - ../bases/crs.yaml
+  - mhc.yaml
+
+patchesStrategicMerge:
+- ./md.yaml
diff --git a/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-md-remediation/md.yaml b/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-md-remediation/md.yaml
new file mode 100644
index 000000000..9b93a2288
--- /dev/null
+++ b/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-md-remediation/md.yaml
@@ -0,0 +1,9 @@
+apiVersion: cluster.x-k8s.io/v1alpha4
+kind: MachineDeployment
+metadata:
+  name: "${CLUSTER_NAME}-md-0"
+spec:
+  template:
+    metadata:
+      labels:
+        "e2e.remediation.label": ""
diff --git a/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-md-remediation/mhc.yaml b/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-md-remediation/mhc.yaml
new file mode 100644
index 000000000..236c3632d
--- /dev/null
+++ b/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-md-remediation/mhc.yaml
@@ -0,0 +1,18 @@
+---
+# MachineHealthCheck object with
+# - a selector that targets all the machines with label e2e.remediation.label=""
+# - unhealthyConditions triggering remediation after 10s the condition is set
+apiVersion: cluster.x-k8s.io/v1alpha4
+kind: MachineHealthCheck
+metadata:
+  name: "${CLUSTER_NAME}-mhc-0"
+spec:
+  clusterName: "${CLUSTER_NAME}"
+  maxUnhealthy: 100%
+  selector:
+    matchLabels:
+      e2e.remediation.label: ""
+  unhealthyConditions:
+    - type: e2e.remediation.condition
+      status: "False"
+      timeout: 10s
diff --git a/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-node-drain/cluster-with-kcp.yaml b/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-node-drain/cluster-with-kcp.yaml
new file mode 100644
index 000000000..16cffd0eb
--- /dev/null
+++ b/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-node-drain/cluster-with-kcp.yaml
@@ -0,0 +1,9 @@
+# KubeadmControlPlane referenced by the Cluster object with
+# - the label kcp-adoption.step2, because it should be created in the second step of the kcp-adoption test.
+kind: KubeadmControlPlane
+apiVersion: controlplane.cluster.x-k8s.io/v1alpha4
+metadata:
+  name: "${CLUSTER_NAME}-control-plane"
+spec:
+  machineTemplate:
+    nodeDrainTimeout: ${NODE_DRAIN_TIMEOUT}
diff --git a/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-node-drain/kustomization.yaml b/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-node-drain/kustomization.yaml
new file mode 100644
index 000000000..dde0c51f0
--- /dev/null
+++ b/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-node-drain/kustomization.yaml
@@ -0,0 +1,8 @@
+bases:
+- ../bases/crs.yaml
+- ../bases/md.yaml
+- ../bases/cluster-with-kcp.yaml
+
+patchesStrategicMerge:
+- ./md.yaml
+- ./cluster-with-kcp.yaml
diff --git a/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-node-drain/md.yaml b/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-node-drain/md.yaml
new file mode 100644
index 000000000..4f4ca9c2f
--- /dev/null
+++ b/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-node-drain/md.yaml
@@ -0,0 +1,8 @@
+apiVersion: cluster.x-k8s.io/v1alpha4
+kind: MachineDeployment
+metadata:
+  name: "${CLUSTER_NAME}-md-0"
+spec:
+  template:
+    spec:
+      nodeDrainTimeout: "${NODE_DRAIN_TIMEOUT}"
diff --git a/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-upgrades/kustomization.yaml b/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-upgrades/kustomization.yaml
new file mode 100644
index 000000000..08c1848d7
--- /dev/null
+++ b/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template-upgrades/kustomization.yaml
@@ -0,0 +1,5 @@
+resources:
+  - ../bases/cluster-with-kcp.yaml
+  - ../bases/crs.yaml
+  - ../bases/md.yaml
+  - ../bases/mp.yaml
diff --git a/test/e2e/data/infrastructure-docker/v0.3/cluster-template/kustomization.yaml b/test/e2e/data/infrastructure-docker/v1alpha4/cluster-template/kustomization.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/v0.3/cluster-template/kustomization.yaml
rename to test/e2e/data/infrastructure-docker/v1alpha4/cluster-template/kustomization.yaml
diff --git a/test/e2e/data/infrastructure-docker/main/bases/cluster-with-kcp.yaml b/test/e2e/data/infrastructure-docker/v1beta1/main/bases/cluster-with-kcp.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/main/bases/cluster-with-kcp.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/main/bases/cluster-with-kcp.yaml
diff --git a/test/e2e/data/infrastructure-docker/main/bases/cluster-with-topology.yaml b/test/e2e/data/infrastructure-docker/v1beta1/main/bases/cluster-with-topology.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/main/bases/cluster-with-topology.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/main/bases/cluster-with-topology.yaml
diff --git a/test/e2e/data/infrastructure-docker/main/bases/crs.yaml b/test/e2e/data/infrastructure-docker/v1beta1/main/bases/crs.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/main/bases/crs.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/main/bases/crs.yaml
diff --git a/test/e2e/data/infrastructure-docker/main/bases/md.yaml b/test/e2e/data/infrastructure-docker/v1beta1/main/bases/md.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/main/bases/md.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/main/bases/md.yaml
diff --git a/test/e2e/data/infrastructure-docker/main/bases/mp.yaml b/test/e2e/data/infrastructure-docker/v1beta1/main/bases/mp.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/main/bases/mp.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/main/bases/mp.yaml
diff --git a/test/e2e/data/infrastructure-docker/main/cluster-template-ignition/ignition.yaml b/test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-ignition/ignition.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/main/cluster-template-ignition/ignition.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-ignition/ignition.yaml
diff --git a/test/e2e/data/infrastructure-docker/main/cluster-template-ignition/kustomization.yaml b/test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-ignition/kustomization.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/main/cluster-template-ignition/kustomization.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-ignition/kustomization.yaml
diff --git a/test/e2e/data/infrastructure-docker/main/cluster-template-ipv6/cluster-ipv6.yaml b/test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-ipv6/cluster-ipv6.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/main/cluster-template-ipv6/cluster-ipv6.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-ipv6/cluster-ipv6.yaml
diff --git a/test/e2e/data/infrastructure-docker/main/cluster-template-ipv6/kcp-ipv6.yaml b/test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-ipv6/kcp-ipv6.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/main/cluster-template-ipv6/kcp-ipv6.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-ipv6/kcp-ipv6.yaml
diff --git a/test/e2e/data/infrastructure-docker/main/cluster-template-ipv6/kustomization.yaml b/test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-ipv6/kustomization.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/main/cluster-template-ipv6/kustomization.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-ipv6/kustomization.yaml
diff --git a/test/e2e/data/infrastructure-docker/main/cluster-template-ipv6/md-ipv6.yaml b/test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-ipv6/md-ipv6.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/main/cluster-template-ipv6/md-ipv6.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-ipv6/md-ipv6.yaml
diff --git a/test/e2e/data/infrastructure-docker/main/cluster-template-kcp-adoption/step1/cluster-with-cp0.yaml b/test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-kcp-adoption/step1/cluster-with-cp0.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/main/cluster-template-kcp-adoption/step1/cluster-with-cp0.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-kcp-adoption/step1/cluster-with-cp0.yaml
diff --git a/test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-kcp-adoption/step1/kustomization.yaml b/test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-kcp-adoption/step1/kustomization.yaml
new file mode 100644
index 000000000..fa5f1edcc
--- /dev/null
+++ b/test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-kcp-adoption/step1/kustomization.yaml
@@ -0,0 +1,8 @@
+commonLabels:
+  kcp-adoption.step1: ""
+
+bases:
+  - cluster-with-cp0.yaml
+  - ../../bases/crs.yaml
+
+
diff --git a/test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-kcp-adoption/step2/kustomization.yaml b/test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-kcp-adoption/step2/kustomization.yaml
new file mode 100644
index 000000000..f7b1382cf
--- /dev/null
+++ b/test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-kcp-adoption/step2/kustomization.yaml
@@ -0,0 +1,6 @@
+commonLabels:
+  kcp-adoption.step2: ""
+
+bases:
+  - ../../bases/cluster-with-kcp.yaml
+
diff --git a/test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-kcp-remediation/kustomization.yaml b/test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-kcp-remediation/kustomization.yaml
new file mode 100644
index 000000000..e234e37be
--- /dev/null
+++ b/test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-kcp-remediation/kustomization.yaml
@@ -0,0 +1,5 @@
+bases:
+  - ../bases/cluster-with-kcp.yaml
+  - ../bases/md.yaml
+  - ../bases/crs.yaml
+  - mhc.yaml
diff --git a/test/e2e/data/infrastructure-docker/main/cluster-template-kcp-remediation/mhc.yaml b/test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-kcp-remediation/mhc.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/main/cluster-template-kcp-remediation/mhc.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-kcp-remediation/mhc.yaml
diff --git a/test/e2e/data/infrastructure-docker/main/cluster-template-kcp-scale-in/kcp-scale-in-variable.yaml b/test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-kcp-scale-in/kcp-scale-in-variable.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/main/cluster-template-kcp-scale-in/kcp-scale-in-variable.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-kcp-scale-in/kcp-scale-in-variable.yaml
diff --git a/test/e2e/data/infrastructure-docker/main/cluster-template-kcp-scale-in/kustomization.yaml b/test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-kcp-scale-in/kustomization.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/main/cluster-template-kcp-scale-in/kustomization.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-kcp-scale-in/kustomization.yaml
diff --git a/test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-machine-pool/kustomization.yaml b/test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-machine-pool/kustomization.yaml
new file mode 100644
index 000000000..2323bae83
--- /dev/null
+++ b/test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-machine-pool/kustomization.yaml
@@ -0,0 +1,4 @@
+resources:
+  - ../bases/cluster-with-kcp.yaml
+  - ../bases/mp.yaml
+  - ../bases/crs.yaml
diff --git a/test/e2e/data/infrastructure-docker/main/cluster-template-md-remediation/kustomization.yaml b/test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-md-remediation/kustomization.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/main/cluster-template-md-remediation/kustomization.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-md-remediation/kustomization.yaml
diff --git a/test/e2e/data/infrastructure-docker/main/cluster-template-md-remediation/md.yaml b/test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-md-remediation/md.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/main/cluster-template-md-remediation/md.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-md-remediation/md.yaml
diff --git a/test/e2e/data/infrastructure-docker/main/cluster-template-md-remediation/mhc.yaml b/test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-md-remediation/mhc.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/main/cluster-template-md-remediation/mhc.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-md-remediation/mhc.yaml
diff --git a/test/e2e/data/infrastructure-docker/main/cluster-template-node-drain/cluster-with-kcp.yaml b/test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-node-drain/cluster-with-kcp.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/main/cluster-template-node-drain/cluster-with-kcp.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-node-drain/cluster-with-kcp.yaml
diff --git a/test/e2e/data/infrastructure-docker/main/cluster-template-node-drain/kustomization.yaml b/test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-node-drain/kustomization.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/main/cluster-template-node-drain/kustomization.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-node-drain/kustomization.yaml
diff --git a/test/e2e/data/infrastructure-docker/main/cluster-template-node-drain/md.yaml b/test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-node-drain/md.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/main/cluster-template-node-drain/md.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-node-drain/md.yaml
diff --git a/test/e2e/data/infrastructure-docker/main/cluster-template-topology-single-node-cluster/disable-control-plane-taint-variable.yaml b/test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-topology-single-node-cluster/disable-control-plane-taint-variable.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/main/cluster-template-topology-single-node-cluster/disable-control-plane-taint-variable.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-topology-single-node-cluster/disable-control-plane-taint-variable.yaml
diff --git a/test/e2e/data/infrastructure-docker/main/cluster-template-topology-single-node-cluster/kustomization.yaml b/test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-topology-single-node-cluster/kustomization.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/main/cluster-template-topology-single-node-cluster/kustomization.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-topology-single-node-cluster/kustomization.yaml
diff --git a/test/e2e/data/infrastructure-docker/main/cluster-template-topology/kustomization.yaml b/test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-topology/kustomization.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/main/cluster-template-topology/kustomization.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-topology/kustomization.yaml
diff --git a/test/e2e/data/infrastructure-docker/main/cluster-template-upgrades-cgroupfs/kustomization.yaml b/test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-upgrades-cgroupfs/kustomization.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/main/cluster-template-upgrades-cgroupfs/kustomization.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-upgrades-cgroupfs/kustomization.yaml
diff --git a/test/e2e/data/infrastructure-docker/main/cluster-template-upgrades-cgroupfs/mp-cgroupfs.yaml b/test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-upgrades-cgroupfs/mp-cgroupfs.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/main/cluster-template-upgrades-cgroupfs/mp-cgroupfs.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-upgrades-cgroupfs/mp-cgroupfs.yaml
diff --git a/test/e2e/data/infrastructure-docker/main/cluster-template-upgrades-cgroupfs/mp-default-cgroupfs.yaml b/test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-upgrades-cgroupfs/mp-default-cgroupfs.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/main/cluster-template-upgrades-cgroupfs/mp-default-cgroupfs.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-upgrades-cgroupfs/mp-default-cgroupfs.yaml
diff --git a/test/e2e/data/infrastructure-docker/main/cluster-template-upgrades-runtimesdk/cluster-runtimesdk.yaml b/test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-upgrades-runtimesdk/cluster-runtimesdk.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/main/cluster-template-upgrades-runtimesdk/cluster-runtimesdk.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-upgrades-runtimesdk/cluster-runtimesdk.yaml
diff --git a/test/e2e/data/infrastructure-docker/main/cluster-template-upgrades-runtimesdk/kustomization.yaml b/test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-upgrades-runtimesdk/kustomization.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/main/cluster-template-upgrades-runtimesdk/kustomization.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-upgrades-runtimesdk/kustomization.yaml
diff --git a/test/e2e/data/infrastructure-docker/main/cluster-template-upgrades/kustomization.yaml b/test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-upgrades/kustomization.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/main/cluster-template-upgrades/kustomization.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template-upgrades/kustomization.yaml
diff --git a/test/e2e/data/infrastructure-docker/v0.4/cluster-template/kustomization.yaml b/test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template/kustomization.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/v0.4/cluster-template/kustomization.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/main/cluster-template/kustomization.yaml
diff --git a/test/e2e/data/infrastructure-docker/main/clusterclass-quick-start-runtimesdk.yaml b/test/e2e/data/infrastructure-docker/v1beta1/main/clusterclass-quick-start-runtimesdk.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/main/clusterclass-quick-start-runtimesdk.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/main/clusterclass-quick-start-runtimesdk.yaml
diff --git a/test/e2e/data/infrastructure-docker/v1.3/clusterclass-quick-start.yaml b/test/e2e/data/infrastructure-docker/v1beta1/main/clusterclass-quick-start.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/v1.3/clusterclass-quick-start.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/main/clusterclass-quick-start.yaml
diff --git a/test/e2e/data/infrastructure-docker/v1.2/bases/cluster-with-kcp.yaml b/test/e2e/data/infrastructure-docker/v1beta1/v1.2/bases/cluster-with-kcp.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/v1.2/bases/cluster-with-kcp.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/v1.2/bases/cluster-with-kcp.yaml
diff --git a/test/e2e/data/infrastructure-docker/v1.2/bases/cluster-with-topology.yaml b/test/e2e/data/infrastructure-docker/v1beta1/v1.2/bases/cluster-with-topology.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/v1.2/bases/cluster-with-topology.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/v1.2/bases/cluster-with-topology.yaml
diff --git a/test/e2e/data/infrastructure-docker/v1.2/bases/crs.yaml b/test/e2e/data/infrastructure-docker/v1beta1/v1.2/bases/crs.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/v1.2/bases/crs.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/v1.2/bases/crs.yaml
diff --git a/test/e2e/data/infrastructure-docker/v1.2/bases/md.yaml b/test/e2e/data/infrastructure-docker/v1beta1/v1.2/bases/md.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/v1.2/bases/md.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/v1.2/bases/md.yaml
diff --git a/test/e2e/data/infrastructure-docker/v1.2/cluster-template-topology/kustomization.yaml b/test/e2e/data/infrastructure-docker/v1beta1/v1.2/cluster-template-topology/kustomization.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/v1.2/cluster-template-topology/kustomization.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/v1.2/cluster-template-topology/kustomization.yaml
diff --git a/test/e2e/data/infrastructure-docker/v1.3/cluster-template/kustomization.yaml b/test/e2e/data/infrastructure-docker/v1beta1/v1.2/cluster-template/kustomization.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/v1.3/cluster-template/kustomization.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/v1.2/cluster-template/kustomization.yaml
diff --git a/test/e2e/data/infrastructure-docker/v1.2/clusterclass-quick-start.yaml b/test/e2e/data/infrastructure-docker/v1beta1/v1.2/clusterclass-quick-start.yaml
similarity index 99%
rename from test/e2e/data/infrastructure-docker/v1.2/clusterclass-quick-start.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/v1.2/clusterclass-quick-start.yaml
index ed0d800b7..bdc001d85 100644
--- a/test/e2e/data/infrastructure-docker/v1.2/clusterclass-quick-start.yaml
+++ b/test/e2e/data/infrastructure-docker/v1beta1/v1.2/clusterclass-quick-start.yaml
@@ -290,3 +290,4 @@ spec:
           criSocket: unix:///var/run/containerd/containerd.sock
           kubeletExtraArgs:
             eviction-hard: 'nodefs.available<0%,nodefs.inodesFree<0%,imagefs.available<0%'
+
diff --git a/test/e2e/data/infrastructure-docker/v1.3/bases/cluster-with-kcp.yaml b/test/e2e/data/infrastructure-docker/v1beta1/v1.3/bases/cluster-with-kcp.yaml
similarity index 94%
rename from test/e2e/data/infrastructure-docker/v1.3/bases/cluster-with-kcp.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/v1.3/bases/cluster-with-kcp.yaml
index b266cddcd..fa8720f98 100644
--- a/test/e2e/data/infrastructure-docker/v1.3/bases/cluster-with-kcp.yaml
+++ b/test/e2e/data/infrastructure-docker/v1beta1/v1.3/bases/cluster-with-kcp.yaml
@@ -59,8 +59,6 @@ spec:
       extraMounts:
         - containerPath: "/var/run/docker.sock"
           hostPath: "/var/run/docker.sock"
-      # The DOCKER_PRELOAD_IMAGES variable gets set in self-hosted E2E tests to the list of images of the E2E configuration.
-      preLoadImages: ${DOCKER_PRELOAD_IMAGES:-[]}
 ---
 # KubeadmControlPlane referenced by the Cluster object with
 # - the label kcp-adoption.step2, because it should be created in the second step of the kcp-adoption test.
diff --git a/test/e2e/data/infrastructure-docker/v1.3/bases/cluster-with-topology.yaml b/test/e2e/data/infrastructure-docker/v1beta1/v1.3/bases/cluster-with-topology.yaml
similarity index 71%
rename from test/e2e/data/infrastructure-docker/v1.3/bases/cluster-with-topology.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/v1.3/bases/cluster-with-topology.yaml
index 96574eab7..804d3c7c8 100644
--- a/test/e2e/data/infrastructure-docker/v1.3/bases/cluster-with-topology.yaml
+++ b/test/e2e/data/infrastructure-docker/v1beta1/v1.3/bases/cluster-with-topology.yaml
@@ -18,21 +18,14 @@ spec:
     controlPlane:
       metadata: {}
       nodeDeletionTimeout: "30s"
-      nodeVolumeDetachTimeout: "5m"
       replicas: ${CONTROL_PLANE_MACHINE_COUNT}
     workers:
       machineDeployments:
       - class: "default-worker"
         name: "md-0"
         nodeDeletionTimeout: "30s"
-        nodeVolumeDetachTimeout: "5m"
-        minReadySeconds: 5
         replicas: ${WORKER_MACHINE_COUNT}
         failureDomain: fd4
-        strategy:
-          rollingUpdate:
-            maxSurge: "20%"
-            maxUnavailable: 0
     variables:
       # We set an empty value to use the default tag kubeadm init is using.
     - name: etcdImageTag
@@ -40,6 +33,3 @@ spec:
       # We set an empty value to use the default tag kubeadm init is using.
     - name: coreDNSImageTag
       value: ""
-    - name: preLoadImages
-      # The DOCKER_PRELOAD_IMAGES variable gets set in self-hosted E2E tests to the list of images of the E2E configuration.
-      value: ${DOCKER_PRELOAD_IMAGES:-[]}
diff --git a/test/e2e/data/infrastructure-docker/v1.3/bases/crs.yaml b/test/e2e/data/infrastructure-docker/v1beta1/v1.3/bases/crs.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/v1.3/bases/crs.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/v1.3/bases/crs.yaml
diff --git a/test/e2e/data/infrastructure-docker/v1.3/bases/md.yaml b/test/e2e/data/infrastructure-docker/v1beta1/v1.3/bases/md.yaml
similarity index 89%
rename from test/e2e/data/infrastructure-docker/v1.3/bases/md.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/v1.3/bases/md.yaml
index eacb23f08..11abbc292 100644
--- a/test/e2e/data/infrastructure-docker/v1.3/bases/md.yaml
+++ b/test/e2e/data/infrastructure-docker/v1beta1/v1.3/bases/md.yaml
@@ -11,8 +11,6 @@ spec:
       extraMounts:
         - containerPath: "/var/run/docker.sock"
           hostPath: "/var/run/docker.sock"
-      # The DOCKER_PRELOAD_IMAGES variable gets set in self-hosted E2E tests to the list of images of the E2E configuration.
-      preLoadImages: ${DOCKER_PRELOAD_IMAGES:-[]}
 ---
 # KubeadmConfigTemplate referenced by the MachineDeployment
 apiVersion: bootstrap.cluster.x-k8s.io/v1beta1
diff --git a/test/e2e/data/infrastructure-docker/v1.3/cluster-template-topology/kustomization.yaml b/test/e2e/data/infrastructure-docker/v1beta1/v1.3/cluster-template-topology/kustomization.yaml
similarity index 100%
rename from test/e2e/data/infrastructure-docker/v1.3/cluster-template-topology/kustomization.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/v1.3/cluster-template-topology/kustomization.yaml
diff --git a/test/e2e/data/infrastructure-docker/v1.2/cluster-template/kustomization.yaml b/test/e2e/data/infrastructure-docker/v1beta1/v1.3/cluster-template/kustomization.yaml
similarity index 98%
rename from test/e2e/data/infrastructure-docker/v1.2/cluster-template/kustomization.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/v1.3/cluster-template/kustomization.yaml
index 3c0dd51f9..adb5919ce 100644
--- a/test/e2e/data/infrastructure-docker/v1.2/cluster-template/kustomization.yaml
+++ b/test/e2e/data/infrastructure-docker/v1beta1/v1.3/cluster-template/kustomization.yaml
@@ -2,3 +2,4 @@ bases:
 - ../bases/cluster-with-kcp.yaml
 - ../bases/md.yaml
 - ../bases/crs.yaml
+
diff --git a/test/e2e/data/infrastructure-docker/main/clusterclass-quick-start.yaml b/test/e2e/data/infrastructure-docker/v1beta1/v1.3/clusterclass-quick-start.yaml
similarity index 73%
rename from test/e2e/data/infrastructure-docker/main/clusterclass-quick-start.yaml
rename to test/e2e/data/infrastructure-docker/v1beta1/v1.3/clusterclass-quick-start.yaml
index c847da962..6a8a505a7 100644
--- a/test/e2e/data/infrastructure-docker/main/clusterclass-quick-start.yaml
+++ b/test/e2e/data/infrastructure-docker/v1beta1/v1.3/clusterclass-quick-start.yaml
@@ -75,21 +75,6 @@ spec:
         default: ""
         example: "0"
         description: "kubeadmControlPlaneMaxSurge is the maximum number of control planes that can be scheduled above or under the desired number of control plane machines."
-  - name: preLoadImages
-    required: false
-    schema:
-      openAPIV3Schema:
-        default: []
-        type: array
-        items:
-          type: string
-        description: "preLoadImages sets the images for the docker machines to preload."
-  - name: controlPlaneTaint
-    required: false
-    schema:
-      openAPIV3Schema:
-        type: boolean
-        default: true
   patches:
   - name: lbImageRepository
     definitions:
@@ -137,7 +122,7 @@ spec:
         matchResources:
           machineDeploymentClass:
             names:
-            - '*-worker'
+            - default-worker
       jsonPatches:
       - op: add
         path: "/spec/template/spec/joinConfiguration/nodeRegistration/kubeletExtraArgs/cgroup-driver"
@@ -198,25 +183,6 @@ spec:
         valueFrom:
           template: |
             kindest/node:{{ .builtin.controlPlane.version | replace "+" "_" }}
-  - name: preloadImages
-    description: |
-      Sets the container images to preload to the node that is used for running dockerMachines.
-      This is especially required for self-hosted e2e tests to ensure the required controller images to be available
-      and reduce load to public registries.
-    definitions:
-    - selector:
-        apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
-        kind: DockerMachineTemplate
-        matchResources:
-          controlPlane: true
-          machineDeploymentClass:
-            names:
-            - default-worker
-      jsonPatches:
-      - op: add
-        path: "/spec/template/spec/preLoadImages"
-        valueFrom:
-          variable: preLoadImages
   - name: kubeadmControlPlaneMaxSurge
     description: "Sets the maxSurge value used for rolloutStrategy in the KubeadmControlPlane."
     enabledIf: '{{ ne .kubeadmControlPlaneMaxSurge "" }}'
@@ -231,67 +197,6 @@ spec:
         path: /spec/template/spec/rolloutStrategy/rollingUpdate/maxSurge
         valueFrom:
           template: "{{ .kubeadmControlPlaneMaxSurge }}"
-  - name: controlPlaneTaint
-    enabledIf: "{{ not .controlPlaneTaint }}"
-    definitions:
-    - selector:
-        apiVersion: controlplane.cluster.x-k8s.io/v1beta1
-        kind: KubeadmControlPlaneTemplate
-        matchResources:
-          controlPlane: true
-      jsonPatches:
-      - op: add
-        path: "/spec/template/spec/kubeadmConfigSpec/initConfiguration/nodeRegistration/taints"
-        value: []
-      - op: add
-        path: "/spec/template/spec/kubeadmConfigSpec/joinConfiguration/nodeRegistration/taints"
-        value: []
-  - name: podSecurityStandard
-    description: "Adds an admission configuration for PodSecurity to the kube-apiserver."
-    definitions:
-    - selector:
-        apiVersion: controlplane.cluster.x-k8s.io/v1beta1
-        kind: KubeadmControlPlaneTemplate
-        matchResources:
-          controlPlane: true
-      jsonPatches:
-      - op: add
-        path: "/spec/template/spec/kubeadmConfigSpec/clusterConfiguration/apiServer/extraArgs"
-        value:
-          admission-control-config-file: "/etc/kubernetes/kube-apiserver-admission-pss.yaml"
-      - op: add
-        path: "/spec/template/spec/kubeadmConfigSpec/clusterConfiguration/apiServer/extraVolumes"
-        value:
-        - name: admission-pss
-          hostPath: /etc/kubernetes/kube-apiserver-admission-pss.yaml
-          mountPath: /etc/kubernetes/kube-apiserver-admission-pss.yaml
-          readOnly: true
-          pathType: "File"
-      - op: add
-        path: "/spec/template/spec/kubeadmConfigSpec/files"
-        valueFrom:
-          template: |
-            - content: |
-                apiVersion: apiserver.config.k8s.io/v1
-                kind: AdmissionConfiguration
-                plugins:
-                - name: PodSecurity
-                  configuration:
-                    apiVersion: pod-security.admission.config.k8s.io/v1{{ if semverCompare "< v1.25" .builtin.controlPlane.version }}beta1{{ end }}
-                    kind: PodSecurityConfiguration
-                    defaults:
-                      enforce: "baseline"
-                      enforce-version: "latest"
-                      audit: "baseline"
-                      audit-version: "latest"
-                      warn: "baseline"
-                      warn-version: "latest"
-                    exemptions:
-                      usernames: []
-                      runtimeClasses: []
-                      namespaces: [kube-system]
-              path: /etc/kubernetes/kube-apiserver-admission-pss.yaml
-    enabledIf: '{{ semverCompare ">= v1.24" .builtin.controlPlane.version }}'
 ---
 apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
 kind: DockerClusterTemplate
diff --git a/test/e2e/data/shared/v1.2/metadata.yaml b/test/e2e/data/shared/v1.2/metadata.yaml
deleted file mode 100644
index c45f8cf0c..000000000
--- a/test/e2e/data/shared/v1.2/metadata.yaml
+++ /dev/null
@@ -1,21 +0,0 @@
-apiVersion: clusterctl.cluster.x-k8s.io/v1alpha3
-kind: Metadata
-releaseSeries:
-- major: 1
-  minor: 2
-  contract: v1beta1
-- major: 1
-  minor: 1
-  contract: v1beta1
-- major: 1
-  minor: 0
-  contract: v1beta1
-- major: 0
-  minor: 4
-  contract: v1alpha4
-- major: 0
-  minor: 3
-  contract: v1alpha3
-- major: 0
-  minor: 2
-  contract: v1alpha2
diff --git a/test/e2e/data/shared/v0.3/metadata.yaml b/test/e2e/data/shared/v1alpha3/metadata.yaml
similarity index 100%
rename from test/e2e/data/shared/v0.3/metadata.yaml
rename to test/e2e/data/shared/v1alpha3/metadata.yaml
diff --git a/test/e2e/data/shared/v0.4/metadata.yaml b/test/e2e/data/shared/v1alpha4/metadata.yaml
similarity index 100%
rename from test/e2e/data/shared/v0.4/metadata.yaml
rename to test/e2e/data/shared/v1alpha4/metadata.yaml
diff --git a/test/e2e/data/shared/main/metadata.yaml b/test/e2e/data/shared/v1beta1/main/metadata.yaml
similarity index 100%
rename from test/e2e/data/shared/main/metadata.yaml
rename to test/e2e/data/shared/v1beta1/main/metadata.yaml
diff --git a/test/e2e/data/shared/v1beta1/v1.2/metadata.yaml b/test/e2e/data/shared/v1beta1/v1.2/metadata.yaml
new file mode 100644
index 000000000..10afb3250
--- /dev/null
+++ b/test/e2e/data/shared/v1beta1/v1.2/metadata.yaml
@@ -0,0 +1,21 @@
+apiVersion: clusterctl.cluster.x-k8s.io/v1alpha3
+kind: Metadata
+releaseSeries:
+  - major: 1
+    minor: 2
+    contract: v1beta1
+  - major: 1
+    minor: 1
+    contract: v1beta1
+  - major: 1
+    minor: 0
+    contract: v1beta1
+  - major: 0
+    minor: 4
+    contract: v1alpha4
+  - major: 0
+    minor: 3
+    contract: v1alpha3
+  - major: 0
+    minor: 2
+    contract: v1alpha2
diff --git a/test/e2e/data/shared/v1.3/metadata.yaml b/test/e2e/data/shared/v1beta1/v1.3/metadata.yaml
similarity index 100%
rename from test/e2e/data/shared/v1.3/metadata.yaml
rename to test/e2e/data/shared/v1beta1/v1.3/metadata.yaml
diff --git a/test/e2e/self_hosted.go b/test/e2e/self_hosted.go
index db0c71ec2..beec7415a 100644
--- a/test/e2e/self_hosted.go
+++ b/test/e2e/self_hosted.go
@@ -232,7 +232,7 @@ func SelfHostedSpec(ctx context.Context, inputGetter func() SelfHostedSpecInput)
 		// object. The Cluster object has special processing for the paused field during the move to
 		// avoid having clusterctl as the manager of the field.
 		log.Logf("Ensure clusterctl does not take ownership on any fields on the self-hosted cluster")
-		selfHostedCluster = framework.GetClusterByName(ctx, framework.GetClusterByNameInput{
+		selfHostedCluster := framework.GetClusterByName(ctx, framework.GetClusterByNameInput{
 			Getter:    selfHostedClusterProxy.GetClient(),
 			Name:      cluster.Name,
 			Namespace: selfHostedNamespace.Name,
@@ -261,7 +261,6 @@ func SelfHostedSpec(ctx context.Context, inputGetter func() SelfHostedSpecInput)
 		Expect(controlPlane).ToNot(BeNil())
 
 		// After the move check that there were no unexpected rollouts.
-		log.Logf("Verify there are no unexpected rollouts")
 		Consistently(func() bool {
 			postMoveMachineList := &unstructured.UnstructuredList{}
 			postMoveMachineList.SetGroupVersionKind(clusterv1.GroupVersion.WithKind("MachineList"))
@@ -280,14 +279,8 @@ func SelfHostedSpec(ctx context.Context, inputGetter func() SelfHostedSpecInput)
 			return
 		}
 
-		log.Logf("Waiting for control plane to be ready")
-		framework.WaitForControlPlaneAndMachinesReady(ctx, framework.WaitForControlPlaneAndMachinesReadyInput{
-			GetLister:    selfHostedClusterProxy.GetClient(),
-			Cluster:      clusterResources.Cluster,
-			ControlPlane: clusterResources.ControlPlane,
-		}, input.E2EConfig.GetIntervals(specName, "wait-control-plane")...)
-
 		By("Upgrading the self-hosted Cluster")
+
 		if clusterResources.Cluster.Spec.Topology != nil {
 			// Cluster is using ClusterClass, upgrade via topology.
 			By("Upgrading the Cluster topology")
diff --git a/test/extension/config/default/manager.yaml b/test/extension/config/default/manager.yaml
index 7d7afd36e..26acbe94e 100644
--- a/test/extension/config/default/manager.yaml
+++ b/test/extension/config/default/manager.yaml
@@ -14,18 +14,10 @@ spec:
         app: test-extension-manager
     spec:
       containers:
-        - command:
-            - /manager
-          image: controller:latest
-          name: manager
-          securityContext:
-            allowPrivilegeEscalation: false
-            capabilities:
-              drop:
-                - ALL
-            privileged: false
-            runAsUser: 65532
-            runAsGroup: 65532
+      - command:
+        - /manager
+        image: controller:latest
+        name: manager
       terminationGracePeriodSeconds: 10
       serviceAccountName: manager
       tolerations:
@@ -33,7 +25,3 @@ spec:
           key: node-role.kubernetes.io/master
         - effect: NoSchedule
           key: node-role.kubernetes.io/control-plane
-      securityContext:
-        runAsNonRoot: true
-        seccompProfile:
-          type: RuntimeDefault
diff --git a/test/framework/clusterctl/client.go b/test/framework/clusterctl/client.go
index 1fc7c3128..5c0e20b5f 100644
--- a/test/framework/clusterctl/client.go
+++ b/test/framework/clusterctl/client.go
@@ -61,8 +61,16 @@ type InitInput struct {
 
 // Init calls clusterctl init with the list of providers defined in the local repository.
 func Init(_ context.Context, input InitInput) {
-	args := calculateClusterCtlInitArgs(input)
-	log.Logf("clusterctl %s", strings.Join(args, " "))
+	log.Logf("clusterctl init --core %s --bootstrap %s --control-plane %s --infrastructure %s --ipam %s --runtime-extension %s --config %s --kubeconfig %s",
+		input.CoreProvider,
+		strings.Join(input.BootstrapProviders, ","),
+		strings.Join(input.ControlPlaneProviders, ","),
+		strings.Join(input.InfrastructureProviders, ","),
+		strings.Join(input.IPAMProviders, ","),
+		strings.Join(input.RuntimeExtensionProviders, ","),
+		input.ClusterctlConfigPath,
+		input.KubeconfigPath,
+	)
 
 	initOpt := clusterctlclient.InitOptions{
 		Kubeconfig: clusterctlclient.Kubeconfig{
@@ -88,23 +96,17 @@ func Init(_ context.Context, input InitInput) {
 
 // InitWithBinary uses clusterctl binary to run init with the list of providers defined in the local repository.
 func InitWithBinary(_ context.Context, binary string, input InitInput) {
-	args := calculateClusterCtlInitArgs(input)
-	log.Logf("clusterctl %s", strings.Join(args, " "))
-
-	cmd := exec.Command(binary, args...) //nolint:gosec // We don't care about command injection here.
-
-	out, err := cmd.CombinedOutput()
-	_ = os.WriteFile(filepath.Join(input.LogFolder, "clusterctl-init.log"), out, 0644) //nolint:gosec // this is a log file to be shared via prow artifacts
-	var stdErr string
-	if err != nil {
-		if exitErr, ok := err.(*exec.ExitError); ok {
-			stdErr = string(exitErr.Stderr)
-		}
-	}
-	Expect(err).ToNot(HaveOccurred(), "failed to run clusterctl init:\nstdout:\n%s\nstderr:\n%s", string(out), stdErr)
-}
+	log.Logf("clusterctl init --core %s --bootstrap %s --control-plane %s --infrastructure %s --ipam %s --runtime-extension %s --config %s --kubeconfig %s",
+		input.CoreProvider,
+		strings.Join(input.BootstrapProviders, ","),
+		strings.Join(input.ControlPlaneProviders, ","),
+		strings.Join(input.InfrastructureProviders, ","),
+		strings.Join(input.IPAMProviders, ","),
+		strings.Join(input.RuntimeExtensionProviders, ","),
+		input.ClusterctlConfigPath,
+		input.KubeconfigPath,
+	)
 
-func calculateClusterCtlInitArgs(input InitInput) []string {
 	args := []string{"init", "--config", input.ClusterctlConfigPath, "--kubeconfig", input.KubeconfigPath}
 	if input.CoreProvider != "" {
 		args = append(args, "--core", input.CoreProvider)
@@ -112,9 +114,6 @@ func calculateClusterCtlInitArgs(input InitInput) []string {
 	if len(input.BootstrapProviders) > 0 {
 		args = append(args, "--bootstrap", strings.Join(input.BootstrapProviders, ","))
 	}
-	if len(input.ControlPlaneProviders) > 0 {
-		args = append(args, "--control-plane", strings.Join(input.ControlPlaneProviders, ","))
-	}
 	if len(input.InfrastructureProviders) > 0 {
 		args = append(args, "--infrastructure", strings.Join(input.InfrastructureProviders, ","))
 	}
@@ -124,7 +123,18 @@ func calculateClusterCtlInitArgs(input InitInput) []string {
 	if len(input.RuntimeExtensionProviders) > 0 {
 		args = append(args, "--runtime-extension", strings.Join(input.RuntimeExtensionProviders, ","))
 	}
-	return args
+
+	cmd := exec.Command(binary, args...) //nolint:gosec // We don't care about command injection here.
+
+	out, err := cmd.CombinedOutput()
+	_ = os.WriteFile(filepath.Join(input.LogFolder, "clusterctl-init.log"), out, 0644) //nolint:gosec // this is a log file to be shared via prow artifacts
+	var stdErr string
+	if err != nil {
+		if exitErr, ok := err.(*exec.ExitError); ok {
+			stdErr = string(exitErr.Stderr)
+		}
+	}
+	Expect(err).ToNot(HaveOccurred(), "failed to run clusterctl init:\nstdout:\n%s\nstderr:\n%s", string(out), stdErr)
 }
 
 // UpgradeInput is the input for Upgrade.
diff --git a/test/framework/clusterctl/clusterctl_helpers.go b/test/framework/clusterctl/clusterctl_helpers.go
index a5c25b377..25f142533 100644
--- a/test/framework/clusterctl/clusterctl_helpers.go
+++ b/test/framework/clusterctl/clusterctl_helpers.go
@@ -107,7 +107,7 @@ func InitManagementClusterAndWatchControllerLogs(ctx context.Context, input Init
 		}, intervals...)
 
 		// Start streaming logs from all controller providers
-		framework.WatchDeploymentLogsByName(ctx, framework.WatchDeploymentLogsByNameInput{
+		framework.WatchDeploymentLogs(ctx, framework.WatchDeploymentLogsInput{
 			GetLister:  client,
 			ClientSet:  input.ClusterProxy.GetClientSet(),
 			Deployment: deployment,
@@ -188,7 +188,7 @@ func UpgradeManagementClusterAndWait(ctx context.Context, input UpgradeManagemen
 		}, intervals...)
 
 		// Start streaming logs from all controller providers
-		framework.WatchDeploymentLogsByName(ctx, framework.WatchDeploymentLogsByNameInput{
+		framework.WatchDeploymentLogs(ctx, framework.WatchDeploymentLogsInput{
 			GetLister:  client,
 			ClientSet:  input.ClusterProxy.GetClientSet(),
 			Deployment: deployment,
diff --git a/test/framework/controlplane_helpers.go b/test/framework/controlplane_helpers.go
index 4f5e37cc9..d5545c6c9 100644
--- a/test/framework/controlplane_helpers.go
+++ b/test/framework/controlplane_helpers.go
@@ -22,6 +22,7 @@ import (
 
 	. "github.com/onsi/ginkgo/v2"
 	. "github.com/onsi/gomega"
+	. "github.com/onsi/gomega/gstruct"
 	"github.com/pkg/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/labels"
@@ -163,34 +164,20 @@ type WaitForControlPlaneToBeReadyInput struct {
 func WaitForControlPlaneToBeReady(ctx context.Context, input WaitForControlPlaneToBeReadyInput, intervals ...interface{}) {
 	By("Waiting for the control plane to be ready")
 	controlplane := &controlplanev1.KubeadmControlPlane{}
-	Eventually(func() (bool, error) {
+	Eventually(func() (controlplanev1.KubeadmControlPlane, error) {
 		key := client.ObjectKey{
 			Namespace: input.ControlPlane.GetNamespace(),
 			Name:      input.ControlPlane.GetName(),
 		}
 		if err := input.Getter.Get(ctx, key, controlplane); err != nil {
-			return false, errors.Wrapf(err, "failed to get KCP")
-		}
-
-		desiredReplicas := controlplane.Spec.Replicas
-		statusReplicas := controlplane.Status.Replicas
-		updatedReplicas := controlplane.Status.UpdatedReplicas
-		readyReplicas := controlplane.Status.ReadyReplicas
-		unavailableReplicas := controlplane.Status.UnavailableReplicas
-
-		// Control plane is still rolling out (and thus not ready) if:
-		// * .spec.replicas, .status.replicas, .status.updatedReplicas,
-		//   .status.readyReplicas are not equal and
-		// * unavailableReplicas > 0
-		if statusReplicas != *desiredReplicas ||
-			updatedReplicas != *desiredReplicas ||
-			readyReplicas != *desiredReplicas ||
-			unavailableReplicas > 0 {
-			return false, nil
+			return *controlplane, errors.Wrapf(err, "failed to get KCP")
 		}
-
-		return true, nil
-	}, intervals...).Should(BeTrue(), PrettyPrint(controlplane)+"\n")
+		return *controlplane, nil
+	}, intervals...).Should(MatchFields(IgnoreExtras, Fields{
+		"Status": MatchFields(IgnoreExtras, Fields{
+			"Ready": BeTrue(),
+		}),
+	}), PrettyPrint(controlplane)+"\n")
 }
 
 // AssertControlPlaneFailureDomainsInput is the input for AssertControlPlaneFailureDomains.
diff --git a/test/framework/deployment_helpers.go b/test/framework/deployment_helpers.go
index eeb14dc27..0b5d89f6f 100644
--- a/test/framework/deployment_helpers.go
+++ b/test/framework/deployment_helpers.go
@@ -95,56 +95,34 @@ func DescribeFailedDeployment(input WaitForDeploymentsAvailableInput, deployment
 	return b.String()
 }
 
-// WatchDeploymentLogsByLabelSelectorInput is the input for WatchDeploymentLogsByLabelSelector.
-type WatchDeploymentLogsByLabelSelectorInput struct {
-	GetLister GetLister
-	ClientSet *kubernetes.Clientset
-	Labels    map[string]string
-	LogPath   string
-}
-
-// WatchDeploymentLogsByLabelSelector streams logs for all containers for all pods belonging to a deployment on the basis of label. Each container's logs are streamed
-// in a separate goroutine so they can all be streamed concurrently. This only causes a test failure if there are errors
-// retrieving the deployment, its pods, or setting up a log file. If there is an error with the log streaming itself,
-// that does not cause the test to fail.
-func WatchDeploymentLogsByLabelSelector(ctx context.Context, input WatchDeploymentLogsByLabelSelectorInput) {
-	Expect(ctx).NotTo(BeNil(), "ctx is required for WatchDeploymentLogsByLabelSelector")
-	Expect(input.ClientSet).NotTo(BeNil(), "input.ClientSet is required for WatchDeploymentLogsByLabelSelector")
-	Expect(input.Labels).NotTo(BeNil(), "input.Selector is required for WatchDeploymentLogsByLabelSelector")
-
-	deploymentList := &appsv1.DeploymentList{}
-	Eventually(func() error {
-		return input.GetLister.List(ctx, deploymentList, client.MatchingLabels(input.Labels))
-	}, retryableOperationTimeout, retryableOperationInterval).Should(Succeed(), "Failed to get deployment for labels")
-
-	for _, deployment := range deploymentList.Items {
-		watchPodLogs(ctx, watchPodLogsInput{
-			GetLister:      input.GetLister,
-			ClientSet:      input.ClientSet,
-			Namespace:      deployment.Namespace,
-			DeploymentName: deployment.Name,
-			Labels:         deployment.Spec.Selector.MatchLabels,
-			LogPath:        input.LogPath,
-		})
-	}
-}
-
-// WatchDeploymentLogsByNameInput is the input for WatchDeploymentLogsByName.
-type WatchDeploymentLogsByNameInput struct {
+// WatchDeploymentLogsInput is the input for WatchDeploymentLogs.
+type WatchDeploymentLogsInput struct {
 	GetLister  GetLister
 	ClientSet  *kubernetes.Clientset
 	Deployment *appsv1.Deployment
 	LogPath    string
 }
 
-// WatchDeploymentLogsByName streams logs for all containers for all pods belonging to a deployment. Each container's logs are streamed
+// logMetadata contains metadata about the logs.
+// The format is very similar to the one used by promtail.
+type logMetadata struct {
+	Job       string `json:"job"`
+	Namespace string `json:"namespace"`
+	App       string `json:"app"`
+	Pod       string `json:"pod"`
+	Container string `json:"container"`
+	NodeName  string `json:"node_name"`
+	Stream    string `json:"stream"`
+}
+
+// WatchDeploymentLogs streams logs for all containers for all pods belonging to a deployment. Each container's logs are streamed
 // in a separate goroutine so they can all be streamed concurrently. This only causes a test failure if there are errors
 // retrieving the deployment, its pods, or setting up a log file. If there is an error with the log streaming itself,
 // that does not cause the test to fail.
-func WatchDeploymentLogsByName(ctx context.Context, input WatchDeploymentLogsByNameInput) {
-	Expect(ctx).NotTo(BeNil(), "ctx is required for WatchDeploymentLogsByName")
-	Expect(input.ClientSet).NotTo(BeNil(), "input.ClientSet is required for WatchDeploymentLogsByName")
-	Expect(input.Deployment).NotTo(BeNil(), "input.Deployment is required for WatchDeploymentLogsByName")
+func WatchDeploymentLogs(ctx context.Context, input WatchDeploymentLogsInput) {
+	Expect(ctx).NotTo(BeNil(), "ctx is required for WatchControllerLogs")
+	Expect(input.ClientSet).NotTo(BeNil(), "input.ClientSet is required for WatchControllerLogs")
+	Expect(input.Deployment).NotTo(BeNil(), "input.Deployment is required for WatchControllerLogs")
 
 	deployment := &appsv1.Deployment{}
 	key := client.ObjectKeyFromObject(input.Deployment)
@@ -153,47 +131,23 @@ func WatchDeploymentLogsByName(ctx context.Context, input WatchDeploymentLogsByN
 	}, retryableOperationTimeout, retryableOperationInterval).Should(Succeed(), "Failed to get deployment %s", klog.KObj(input.Deployment))
 
 	selector, err := metav1.LabelSelectorAsMap(deployment.Spec.Selector)
-	Expect(err).NotTo(HaveOccurred(), "Failed to create Pods selector for deployment %s", klog.KObj(input.Deployment))
-	watchPodLogs(ctx, watchPodLogsInput{
-		GetLister:      input.GetLister,
-		ClientSet:      input.ClientSet,
-		Namespace:      deployment.Namespace,
-		DeploymentName: deployment.Name,
-		Labels:         selector,
-		LogPath:        input.LogPath,
-	})
-}
+	Expect(err).NotTo(HaveOccurred(), "Failed to Pods selector for deployment %s", klog.KObj(input.Deployment))
 
-// watchPodLogsInput is the input for watchPodLogs.
-type watchPodLogsInput struct {
-	GetLister      GetLister
-	ClientSet      *kubernetes.Clientset
-	Namespace      string
-	DeploymentName string
-	Labels         map[string]string
-	LogPath        string
-}
-
-// watchPodLogs streams logs for all containers for all pods belonging to a deployment with the given label. Each container's logs are streamed
-// in a separate goroutine so they can all be streamed concurrently. This only causes a test failure if there are errors
-// retrieving the deployment, its pods, or setting up a log file. If there is an error with the log streaming itself,
-// that does not cause the test to fail.
-func watchPodLogs(ctx context.Context, input watchPodLogsInput) {
 	pods := &corev1.PodList{}
-	Expect(input.GetLister.List(ctx, pods, client.InNamespace(input.Namespace), client.MatchingLabels(input.Labels))).To(Succeed(), "Failed to list Pods for deployment %s", klog.KRef(input.Namespace, input.DeploymentName))
+	Expect(input.GetLister.List(ctx, pods, client.InNamespace(input.Deployment.Namespace), client.MatchingLabels(selector))).To(Succeed(), "Failed to list Pods for deployment %s", klog.KObj(input.Deployment))
 
 	for _, pod := range pods.Items {
-		for _, container := range pod.Spec.Containers {
-			log.Logf("Creating log watcher for controller %s, pod %s, container %s", klog.KRef(input.Namespace, input.DeploymentName), pod.Name, container.Name)
+		for _, container := range deployment.Spec.Template.Spec.Containers {
+			log.Logf("Creating log watcher for controller %s, pod %s, container %s", klog.KObj(input.Deployment), pod.Name, container.Name)
 
 			// Create log metadata file.
-			logMetadataFile := filepath.Clean(path.Join(input.LogPath, input.DeploymentName, pod.Name, container.Name+"-log-metadata.json"))
+			logMetadataFile := filepath.Clean(path.Join(input.LogPath, input.Deployment.Name, pod.Name, container.Name+"-log-metadata.json"))
 			Expect(os.MkdirAll(filepath.Dir(logMetadataFile), 0750)).To(Succeed())
 
 			metadata := logMetadata{
-				Job:       input.Namespace + "/" + input.DeploymentName,
-				Namespace: input.Namespace,
-				App:       input.DeploymentName,
+				Job:       input.Deployment.Namespace + "/" + input.Deployment.Name,
+				Namespace: input.Deployment.Namespace,
+				App:       input.Deployment.Name,
 				Pod:       pod.Name,
 				Container: container.Name,
 				NodeName:  pod.Spec.NodeName,
@@ -207,7 +161,7 @@ func watchPodLogs(ctx context.Context, input watchPodLogsInput) {
 			go func(pod corev1.Pod, container corev1.Container) {
 				defer GinkgoRecover()
 
-				logFile := filepath.Clean(path.Join(input.LogPath, input.DeploymentName, pod.Name, container.Name+".log"))
+				logFile := filepath.Clean(path.Join(input.LogPath, input.Deployment.Name, pod.Name, container.Name+".log"))
 				Expect(os.MkdirAll(filepath.Dir(logFile), 0750)).To(Succeed())
 
 				f, err := os.OpenFile(logFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
@@ -219,7 +173,7 @@ func watchPodLogs(ctx context.Context, input watchPodLogsInput) {
 					Follow:    true,
 				}
 
-				podLogs, err := input.ClientSet.CoreV1().Pods(input.Namespace).GetLogs(pod.Name, opts).Stream(ctx)
+				podLogs, err := input.ClientSet.CoreV1().Pods(input.Deployment.Namespace).GetLogs(pod.Name, opts).Stream(ctx)
 				if err != nil {
 					// Failing to stream logs should not cause the test to fail
 					log.Logf("Error starting logs stream for pod %s, container %s: %v", klog.KRef(pod.Namespace, pod.Name), container.Name, err)
@@ -239,19 +193,6 @@ func watchPodLogs(ctx context.Context, input watchPodLogsInput) {
 	}
 }
 
-// logMetadata contains metadata about the logs.
-// The format is very similar to the one used by promtail.
-type logMetadata struct {
-	Job       string            `json:"job"`
-	Namespace string            `json:"namespace"`
-	App       string            `json:"app"`
-	Pod       string            `json:"pod"`
-	Container string            `json:"container"`
-	NodeName  string            `json:"node_name"`
-	Stream    string            `json:"stream"`
-	Labels    map[string]string `json:"labels,omitempty"`
-}
-
 type WatchPodMetricsInput struct {
 	GetLister   GetLister
 	ClientSet   *kubernetes.Clientset
@@ -274,7 +215,7 @@ func WatchPodMetrics(ctx context.Context, input WatchPodMetricsInput) {
 	}, retryableOperationTimeout, retryableOperationInterval).Should(Succeed(), "Failed to get deployment %s", klog.KObj(input.Deployment))
 
 	selector, err := metav1.LabelSelectorAsMap(deployment.Spec.Selector)
-	Expect(err).NotTo(HaveOccurred(), "Failed to create Pods selector for deployment %s", klog.KObj(input.Deployment))
+	Expect(err).NotTo(HaveOccurred(), "Failed to Pods selector for deployment %s", klog.KObj(input.Deployment))
 
 	pods := &corev1.PodList{}
 	Eventually(func() error {
diff --git a/test/go.mod b/test/go.mod
index 6c4c8833a..23d00964a 100644
--- a/test/go.mod
+++ b/test/go.mod
@@ -10,7 +10,7 @@ require (
 	github.com/docker/go-connections v0.4.0
 	github.com/flatcar/ignition v0.36.2
 	github.com/go-logr/logr v1.2.3
-	github.com/onsi/ginkgo/v2 v2.7.0
+	github.com/onsi/ginkgo/v2 v2.6.1
 	github.com/onsi/gomega v1.24.2
 	github.com/pkg/errors v0.9.1
 	github.com/spf13/pflag v1.0.5
@@ -59,7 +59,7 @@ require (
 	github.com/go-openapi/jsonpointer v0.19.5 // indirect
 	github.com/go-openapi/jsonreference v0.20.0 // indirect
 	github.com/go-openapi/swag v0.22.3 // indirect
-	github.com/gobuffalo/flect v1.0.0 // indirect
+	github.com/gobuffalo/flect v0.3.0 // indirect
 	github.com/gogo/protobuf v1.3.2 // indirect
 	github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
 	github.com/golang/protobuf v1.5.2 // indirect
@@ -114,7 +114,7 @@ require (
 	golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 // indirect
 	golang.org/x/sys v0.3.0 // indirect
 	golang.org/x/term v0.3.0 // indirect
-	golang.org/x/text v0.6.0 // indirect
+	golang.org/x/text v0.5.0 // indirect
 	golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 // indirect
 	gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
 	google.golang.org/appengine v1.6.7 // indirect
diff --git a/test/go.sum b/test/go.sum
index 4a84d8fdf..42542f7a3 100644
--- a/test/go.sum
+++ b/test/go.sum
@@ -185,8 +185,8 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh
 github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
 github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
-github.com/gobuffalo/flect v1.0.0 h1:eBFmskjXZgAOagiTXJH25Nt5sdFwNRcb8DKZsIsAUQI=
-github.com/gobuffalo/flect v1.0.0/go.mod h1:l9V6xSb4BlXwsxEMj3FVEub2nkdQjWhPvD8XTTlHPQc=
+github.com/gobuffalo/flect v0.3.0 h1:erfPWM+K1rFNIQeRPdeEXxo8yFr/PO17lhRnS8FUrtk=
+github.com/gobuffalo/flect v0.3.0/go.mod h1:5pf3aGnsvqvCj50AVni7mJJF8ICxGZ8HomberC3pXLE=
 github.com/godbus/dbus v0.0.0-20181025153459-66d97aec3384/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
 github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
 github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
@@ -388,8 +388,8 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLA
 github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
 github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
 github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
-github.com/onsi/ginkgo/v2 v2.7.0 h1:/XxtEV3I3Eif/HobnVx9YmJgk8ENdRsuUmM+fLCFNow=
-github.com/onsi/ginkgo/v2 v2.7.0/go.mod h1:yjiuMwPokqY1XauOgju45q3sJt6VzQ/Fict1LFVcsAo=
+github.com/onsi/ginkgo/v2 v2.6.1 h1:1xQPCjcqYw/J5LchOcp4/2q/jzJFjiAOc25chhnDw+Q=
+github.com/onsi/ginkgo/v2 v2.6.1/go.mod h1:yjiuMwPokqY1XauOgju45q3sJt6VzQ/Fict1LFVcsAo=
 github.com/onsi/gomega v1.24.2 h1:J/tulyYK6JwBldPViHJReihxxZ+22FHs0piGjQAvoUE=
 github.com/onsi/gomega v1.24.2/go.mod h1:gs3J10IS7Z7r7eXRoNJIrNqU4ToQukCJhFtKrWgHWnk=
 github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
@@ -496,7 +496,6 @@ github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
-github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@@ -505,7 +504,6 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
 github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
-github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
 github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
 github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs=
 github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
@@ -742,8 +740,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
 golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
-golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k=
-golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
+golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 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=
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
diff --git a/test/infrastructure/docker/config/crd/bases/infrastructure.cluster.x-k8s.io_dockerclusters.yaml b/test/infrastructure/docker/config/crd/bases/infrastructure.cluster.x-k8s.io_dockerclusters.yaml
index a2ed0cb08..668271447 100644
--- a/test/infrastructure/docker/config/crd/bases/infrastructure.cluster.x-k8s.io_dockerclusters.yaml
+++ b/test/infrastructure/docker/config/crd/bases/infrastructure.cluster.x-k8s.io_dockerclusters.yaml
@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   annotations:
-    controller-gen.kubebuilder.io/version: v0.11.1
+    controller-gen.kubebuilder.io/version: v0.10.0
   creationTimestamp: null
   name: dockerclusters.infrastructure.cluster.x-k8s.io
 spec:
diff --git a/test/infrastructure/docker/config/crd/bases/infrastructure.cluster.x-k8s.io_dockerclustertemplates.yaml b/test/infrastructure/docker/config/crd/bases/infrastructure.cluster.x-k8s.io_dockerclustertemplates.yaml
index 496b50da6..d1356009f 100644
--- a/test/infrastructure/docker/config/crd/bases/infrastructure.cluster.x-k8s.io_dockerclustertemplates.yaml
+++ b/test/infrastructure/docker/config/crd/bases/infrastructure.cluster.x-k8s.io_dockerclustertemplates.yaml
@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   annotations:
-    controller-gen.kubebuilder.io/version: v0.11.1
+    controller-gen.kubebuilder.io/version: v0.10.0
   creationTimestamp: null
   name: dockerclustertemplates.infrastructure.cluster.x-k8s.io
 spec:
diff --git a/test/infrastructure/docker/config/crd/bases/infrastructure.cluster.x-k8s.io_dockermachinepools.yaml b/test/infrastructure/docker/config/crd/bases/infrastructure.cluster.x-k8s.io_dockermachinepools.yaml
index 1752fc535..bcc150805 100644
--- a/test/infrastructure/docker/config/crd/bases/infrastructure.cluster.x-k8s.io_dockermachinepools.yaml
+++ b/test/infrastructure/docker/config/crd/bases/infrastructure.cluster.x-k8s.io_dockermachinepools.yaml
@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   annotations:
-    controller-gen.kubebuilder.io/version: v0.11.1
+    controller-gen.kubebuilder.io/version: v0.10.0
   creationTimestamp: null
   name: dockermachinepools.infrastructure.cluster.x-k8s.io
 spec:
@@ -518,8 +518,8 @@ spec:
                             description: The machine address.
                             type: string
                           type:
-                            description: Machine address type, one of Hostname, ExternalIP,
-                              InternalIP, ExternalDNS or InternalDNS.
+                            description: Machine address type, one of Hostname, ExternalIP
+                              or InternalIP.
                             type: string
                         required:
                         - address
diff --git a/test/infrastructure/docker/config/crd/bases/infrastructure.cluster.x-k8s.io_dockermachines.yaml b/test/infrastructure/docker/config/crd/bases/infrastructure.cluster.x-k8s.io_dockermachines.yaml
index 1c2b99831..80700534d 100644
--- a/test/infrastructure/docker/config/crd/bases/infrastructure.cluster.x-k8s.io_dockermachines.yaml
+++ b/test/infrastructure/docker/config/crd/bases/infrastructure.cluster.x-k8s.io_dockermachines.yaml
@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   annotations:
-    controller-gen.kubebuilder.io/version: v0.11.1
+    controller-gen.kubebuilder.io/version: v0.10.0
   creationTimestamp: null
   name: dockermachines.infrastructure.cluster.x-k8s.io
 spec:
@@ -402,8 +402,8 @@ spec:
                       description: The machine address.
                       type: string
                     type:
-                      description: Machine address type, one of Hostname, ExternalIP,
-                        InternalIP, ExternalDNS or InternalDNS.
+                      description: Machine address type, one of Hostname, ExternalIP
+                        or InternalIP.
                       type: string
                   required:
                   - address
diff --git a/test/infrastructure/docker/config/crd/bases/infrastructure.cluster.x-k8s.io_dockermachinetemplates.yaml b/test/infrastructure/docker/config/crd/bases/infrastructure.cluster.x-k8s.io_dockermachinetemplates.yaml
index 80ec348e6..b8ad20785 100644
--- a/test/infrastructure/docker/config/crd/bases/infrastructure.cluster.x-k8s.io_dockermachinetemplates.yaml
+++ b/test/infrastructure/docker/config/crd/bases/infrastructure.cluster.x-k8s.io_dockermachinetemplates.yaml
@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   annotations:
-    controller-gen.kubebuilder.io/version: v0.11.1
+    controller-gen.kubebuilder.io/version: v0.10.0
   creationTimestamp: null
   name: dockermachinetemplates.infrastructure.cluster.x-k8s.io
 spec: