Repository: kubernetes-sigs/cluster-api
Pull request #6122 (2022-02-14 12:12:00)

📖 Improve version support documentation
**What this PR does / why we need it**:
Improving version support matrix to better surface the practices we are following.
TL;DR; we try to go over and behind Kubernetes support matrix to meet the users where they are, but at the same time there should be boundaries to what we can reasonably support/validate with our CI signal. 

**Which issue(s) this PR fixes**:
Fixes https://github.com/kubernetes-sigs/cluster-api/issues/4444

/cc @CecileRobertMichon @vincepri @enxebre @sbueringer 

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

This pull-request has been approved by:
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please ask for approval from **fabriziopandini** after the PR has been reviewed.

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":["fabriziopandini"]} -->
k8s-ci-robot: New changes are detected. LGTM label has been removed.

Patch:
diff --git a/Makefile b/Makefile
index b9d26ad85..9088ae632 100644
--- a/Makefile
+++ b/Makefile
@@ -143,7 +143,7 @@ ALL_GENERATE_MODULES = core kubeadm-bootstrap kubeadm-control-plane
 
 .PHONY: generate
 generate: ## Run all generate-manifests-*, generate-go-deepcopy-* and generate-go-conversions-* targets
-	$(MAKE) generate-modules generate-manifests generate-go-deepcopy generate-go-conversions
+	$(MAKE) generate-manifests generate-go-deepcopy generate-go-conversions
 	$(MAKE) -C $(CAPD_DIR) generate
 
 .PHONY: generate-manifests
@@ -280,14 +280,8 @@ generate-go-conversions-kubeadm-control-plane: $(CONVERSION_GEN) ## Generate con
 		--output-file-base=zz_generated.conversion $(CONVERSION_GEN_OUTPUT_BASE) \
 		--go-header-file=./hack/boilerplate/boilerplate.generatego.txt
 
-.PHONY: generate-modules
-generate-modules: ## Run go mod tidy to ensure modules are up to date
-	go mod tidy
-	cd $(TOOLS_DIR); go mod tidy
-	cd $(TEST_DIR); go mod tidy
-
-.PHONY: generate-diagrams
-generate-diagrams: ## Generate diagrams for *.plantuml files
+.PHONY: diagrams
+diagrams: ## Generate diagrams for *.plantuml files
 	$(MAKE) -C docs diagrams
 
 ## --------------------------------------
@@ -296,6 +290,12 @@ generate-diagrams: ## Generate diagrams for *.plantuml files
 
 ##@ lint and verify:
 
+.PHONY: modules
+modules: ## Run go mod tidy to ensure modules are up to date
+	go mod tidy
+	cd $(TOOLS_DIR); go mod tidy
+	cd $(TEST_DIR); go mod tidy
+
 .PHONY: lint
 lint: $(GOLANGCI_LINT) ## Lint the codebase
 	$(GOLANGCI_LINT) run -v $(GOLANGCI_LINT_EXTRA_ARGS)
@@ -306,21 +306,21 @@ lint: $(GOLANGCI_LINT) ## Lint the codebase
 lint-fix: $(GOLANGCI_LINT) ## Lint the codebase and run auto-fixers if supported by the linter
 	GOLANGCI_LINT_EXTRA_ARGS=--fix $(MAKE) lint
 
-.PHONY: tiltfile-fix
-tiltfile-fix: ## Format the Tiltfile
-	./hack/verify-starlark.sh fix
-
 .PHONY: apidiff
 apidiff: $(GO_APIDIFF) ## Check for API differences
 	$(GO_APIDIFF) $(shell git rev-parse origin/main) --print-compatible
 
+.PHONY: format-tiltfile
+format-tiltfile: ## Format the Tiltfile
+	./hack/verify-starlark.sh fix
+
 ALL_VERIFY_CHECKS = doctoc boilerplate shellcheck tiltfile modules gen conversions docker-provider book-links
 
 .PHONY: verify
 verify: $(addprefix verify-,$(ALL_VERIFY_CHECKS)) ## Run all verify-* targets
 
 .PHONY: verify-modules
-verify-modules: generate-modules  ## Verify go modules are up to date
+verify-modules: modules  ## Verify go modules are up to date
 	@if !(git diff --quiet HEAD -- go.sum go.mod $(TOOLS_DIR)/go.mod $(TOOLS_DIR)/go.sum $(TEST_DIR)/go.mod $(TEST_DIR)/go.sum); then \
 		git diff; \
 		echo "go module files are out of date"; exit 1; \
@@ -399,16 +399,10 @@ docker-pull-prerequisites:
 	docker pull $(GO_CONTAINER_IMAGE)
 	docker pull gcr.io/distroless/static:latest
 
-.PHONY: docker-build-all
-docker-build-all: $(addprefix docker-build-,$(ALL_ARCH)) ## Build docker images for all architectures
-
-docker-build-%:
-	$(MAKE) ARCH=$* docker-build
-
 ALL_DOCKER_BUILD = core kubeadm-bootstrap kubeadm-control-plane
 
 .PHONY: docker-build
-docker-build: docker-pull-prerequisites ## Run docker-build-* targets for all providers
+docker-build: docker-pull-prerequisites ## Run all docker-build-* targets
 	$(MAKE) ARCH=$(ARCH) $(addprefix docker-build-,$(ALL_DOCKER_BUILD)) 
 
 .PHONY: docker-build-core
@@ -433,10 +427,6 @@ docker-build-kubeadm-control-plane: ## Build the docker image for kubeadm contro
 e2e-framework: ## Builds the CAPI e2e framework
 	cd $(E2E_FRAMEWORK_DIR); go build ./...
 
-.PHONY: serve-book
-serve-book: ## Build and serve the book (with live-reload)
-	$(MAKE) -C docs/book serve
-
 ## --------------------------------------
 ## Testing
 ## --------------------------------------
@@ -451,28 +441,32 @@ KUBEBUILDER_ASSETS ?= $(shell $(SETUP_ENVTEST) use --use-env -p path $(KUBEBUILD
 test: $(SETUP_ENVTEST) ## Run unit and integration tests
 	KUBEBUILDER_ASSETS="$(KUBEBUILDER_ASSETS)" go test ./... $(TEST_ARGS)
 
-.PHONY: test-verbose
-test-verbose: ## Run unit and integration tests with verbose flag
-	$(MAKE) test TEST_ARGS="$(TEST_ARGS) -v"
+.PHONY: test-e2e
+test-e2e: ## Run the e2e tests
+	$(MAKE) -C $(TEST_DIR)/e2e run
 
 .PHONY: test-junit
-test-junit: $(SETUP_ENVTEST) $(GOTESTSUM) ## Run unit and integration tests and generate a junit report
+test-junit: $(SETUP_ENVTEST) $(GOTESTSUM) ## Run tests with verbose setting and generate a junit report
 	set +o errexit; (KUBEBUILDER_ASSETS="$(KUBEBUILDER_ASSETS)" go test -json ./... $(TEST_ARGS); echo $$? > $(ARTIFACTS)/junit.exitcode) | tee $(ARTIFACTS)/junit.stdout
 	$(GOTESTSUM) --junitfile $(ARTIFACTS)/junit.xml --raw-command cat $(ARTIFACTS)/junit.stdout
 	exit $$(cat $(ARTIFACTS)/junit.exitcode)
 
 .PHONY: test-cover
-test-cover: ## Run unit and integration tests and generate a coverage report
+test-cover: ## Run tests with code coverage and code generate reports
 	$(MAKE) test TEST_ARGS="$(TEST_ARGS) -coverprofile=out/coverage.out"
 	go tool cover -func=out/coverage.out -o out/coverage.txt
 	go tool cover -html=out/coverage.out -o out/coverage.html
 
-.PHONY: test-e2e
-test-e2e: ## Run e2e tests
-	$(MAKE) -C $(TEST_DIR)/e2e run
+.PHONY: test-verbose
+test-verbose: ## Run tests with verbose settings
+	$(MAKE) test TEST_ARGS="$(TEST_ARGS) -v"
+
+.PHONY: serve-book
+serve-book: ## Build and serve the book with live-reloading enabled
+	$(MAKE) -C docs/book serve
 
 .PHONY: kind-cluster
-kind-cluster: ## Create a new kind cluster designed for development with Tilt
+kind-cluster: ## Create a new kind cluster designed for testing with Tilt
 	hack/kind-install-for-capd.sh
 
 .PHONY: docker-build-e2e
@@ -610,6 +604,12 @@ release-notes: $(RELEASE_NOTES_DIR) $(RELEASE_NOTES)
 	go run ./hack/tools/release/notes.go --from=$(PREVIOUS_TAG) > $(RELEASE_NOTES_DIR)/$(RELEASE_TAG).md; \
 	fi
 
+.PHONY: docker-build-all
+docker-build-all: $(addprefix docker-build-,$(ALL_ARCH)) ## Build all the architecture docker images
+
+docker-build-%:
+	$(MAKE) ARCH=$* docker-build
+
 .PHONY: promote-images
 promote-images: $(KPROMO)
 	$(KPROMO) pr --project cluster-api --tag $(RELEASE_TAG) --reviewers "$(IMAGE_REVIEWERS)" --fork $(USER_FORK)
diff --git a/Tiltfile b/Tiltfile
index 1a9ded7fe..e81e9ce19 100644
--- a/Tiltfile
+++ b/Tiltfile
@@ -93,11 +93,11 @@ providers = {
             "internal",
             "third_party",
         ],
-        "additional_docker_helper_commands": "RUN curl -LO https://dl.k8s.io/release/v1.23.3/bin/linux/{ARCH}/kubectl && chmod +x ./kubectl && mv ./kubectl /usr/bin/kubectl".format(
-            ARCH = os_arch,
+        "additional_docker_helper_commands": "RUN wget -qO- https://dl.k8s.io/v1.21.2/kubernetes-client-linux-{arch}.tar.gz | tar xvz".format(
+            arch = os_arch,
         ),
         "additional_docker_build_commands": """
-COPY --from=tilt-helper /usr/bin/kubectl /usr/bin/kubectl
+COPY --from=tilt-helper /go/kubernetes/client/bin/kubectl /usr/bin/kubectl
 """,
         "label": "CAPD",
     },
@@ -322,17 +322,11 @@ def deploy_provider_crds():
     )
 
 def deploy_observability():
-    if "promtail" in settings.get("deploy_observability", []):
-        k8s_yaml(read_file("./.tiltbuild/yaml/promtail.observability.yaml"), allow_duplicates = True)
-        k8s_resource(workload = "promtail", extra_pod_selectors = [{"app": "promtail"}], labels = ["observability"], resource_deps = ["loki"])
+    k8s_yaml(read_file("./.tiltbuild/yaml/observability.tools.yaml"))
 
-    if "loki" in settings.get("deploy_observability", []):
-        k8s_yaml(read_file("./.tiltbuild/yaml/loki.observability.yaml"), allow_duplicates = True)
-        k8s_resource(workload = "loki", extra_pod_selectors = [{"app": "loki"}], labels = ["observability"])
-
-    if "grafana" in settings.get("deploy_observability", []):
-        k8s_yaml(read_file("./.tiltbuild/yaml/grafana.observability.yaml"), allow_duplicates = True)
-        k8s_resource(workload = "grafana", port_forwards = "3001:3000", extra_pod_selectors = [{"app": "grafana"}], labels = ["observability"])
+    k8s_resource(workload = "promtail", extra_pod_selectors = [{"app": "promtail"}], labels = ["observability"])
+    k8s_resource(workload = "loki", extra_pod_selectors = [{"app": "loki"}], labels = ["observability"])
+    k8s_resource(workload = "grafana", port_forwards = "3000", extra_pod_selectors = [{"app": "grafana"}], labels = ["observability"])
 
 def prepare_all():
     allow_k8s_arg = ""
@@ -351,8 +345,8 @@ def prepare_all():
     # Note: we are creating clusterctl CRDs using kustomize (vs using clusterctl) because we want to create
     # a dependency between these resources and provider resources.
     kustomize_build_arg = "--kustomize-builds clusterctl.crd:./cmd/clusterctl/config/crd/ "
-    for tool in settings.get("deploy_observability", []):
-        kustomize_build_arg = kustomize_build_arg + "--kustomize-builds {tool}.observability:./hack/observability/{tool}/ ".format(tool = tool)
+    if settings.get("deploy_observability"):
+        kustomize_build_arg = kustomize_build_arg + "--kustomize-builds observability.tools:./hack/observability/ "
     providers_arg = ""
     for name in get_providers():
         p = providers.get(name)
@@ -388,6 +382,7 @@ prepare_all()
 
 deploy_provider_crds()
 
-deploy_observability()
+if settings.get("deploy_observability"):
+    deploy_observability()
 
 enable_providers()
diff --git a/api/v1alpha4/conversion.go b/api/v1alpha4/conversion.go
index 70dbd8725..3bfb31ba0 100644
--- a/api/v1alpha4/conversion.go
+++ b/api/v1alpha4/conversion.go
@@ -38,14 +38,8 @@ func (src *Cluster) ConvertTo(dstRaw conversion.Hub) error {
 	}
 
 	if restored.Spec.Topology != nil {
-		if dst.Spec.Topology == nil {
-			dst.Spec.Topology = &clusterv1.Topology{}
-		}
 		dst.Spec.Topology.Variables = restored.Spec.Topology.Variables
 		if restored.Spec.Topology.Workers != nil {
-			if dst.Spec.Topology.Workers == nil {
-				dst.Spec.Topology.Workers = &clusterv1.WorkersTopology{}
-			}
 			for i := range restored.Spec.Topology.Workers.MachineDeployments {
 				dst.Spec.Topology.Workers.MachineDeployments[i].FailureDomain = restored.Spec.Topology.Workers.MachineDeployments[i].FailureDomain
 				dst.Spec.Topology.Workers.MachineDeployments[i].Variables = restored.Spec.Topology.Workers.MachineDeployments[i].Variables
diff --git a/bootstrap/kubeadm/api/v1alpha3/conversion.go b/bootstrap/kubeadm/api/v1alpha3/conversion.go
index df89a27b9..42bbb1cb4 100644
--- a/bootstrap/kubeadm/api/v1alpha3/conversion.go
+++ b/bootstrap/kubeadm/api/v1alpha3/conversion.go
@@ -54,15 +54,9 @@ func (src *KubeadmConfig) ConvertTo(dstRaw conversion.Hub) error {
 
 	dst.Spec.Ignition = restored.Spec.Ignition
 	if restored.Spec.InitConfiguration != nil {
-		if dst.Spec.InitConfiguration == nil {
-			dst.Spec.InitConfiguration = &bootstrapv1.InitConfiguration{}
-		}
 		dst.Spec.InitConfiguration.Patches = restored.Spec.InitConfiguration.Patches
 	}
 	if restored.Spec.JoinConfiguration != nil {
-		if dst.Spec.JoinConfiguration == nil {
-			dst.Spec.JoinConfiguration = &bootstrapv1.JoinConfiguration{}
-		}
 		dst.Spec.JoinConfiguration.Patches = restored.Spec.JoinConfiguration.Patches
 	}
 
@@ -125,15 +119,9 @@ func (src *KubeadmConfigTemplate) ConvertTo(dstRaw conversion.Hub) error {
 
 	dst.Spec.Template.Spec.Ignition = restored.Spec.Template.Spec.Ignition
 	if restored.Spec.Template.Spec.InitConfiguration != nil {
-		if dst.Spec.Template.Spec.InitConfiguration == nil {
-			dst.Spec.Template.Spec.InitConfiguration = &bootstrapv1.InitConfiguration{}
-		}
 		dst.Spec.Template.Spec.InitConfiguration.Patches = restored.Spec.Template.Spec.InitConfiguration.Patches
 	}
 	if restored.Spec.Template.Spec.JoinConfiguration != nil {
-		if dst.Spec.Template.Spec.JoinConfiguration == nil {
-			dst.Spec.Template.Spec.JoinConfiguration = &bootstrapv1.JoinConfiguration{}
-		}
 		dst.Spec.Template.Spec.JoinConfiguration.Patches = restored.Spec.Template.Spec.JoinConfiguration.Patches
 	}
 
diff --git a/bootstrap/kubeadm/api/v1alpha4/conversion.go b/bootstrap/kubeadm/api/v1alpha4/conversion.go
index 75ee00286..89c444aee 100644
--- a/bootstrap/kubeadm/api/v1alpha4/conversion.go
+++ b/bootstrap/kubeadm/api/v1alpha4/conversion.go
@@ -39,15 +39,9 @@ func (src *KubeadmConfig) ConvertTo(dstRaw conversion.Hub) error {
 
 	dst.Spec.Ignition = restored.Spec.Ignition
 	if restored.Spec.InitConfiguration != nil {
-		if dst.Spec.InitConfiguration == nil {
-			dst.Spec.InitConfiguration = &bootstrapv1.InitConfiguration{}
-		}
 		dst.Spec.InitConfiguration.Patches = restored.Spec.InitConfiguration.Patches
 	}
 	if restored.Spec.JoinConfiguration != nil {
-		if dst.Spec.JoinConfiguration == nil {
-			dst.Spec.JoinConfiguration = &bootstrapv1.JoinConfiguration{}
-		}
 		dst.Spec.JoinConfiguration.Patches = restored.Spec.JoinConfiguration.Patches
 	}
 
@@ -91,15 +85,9 @@ func (src *KubeadmConfigTemplate) ConvertTo(dstRaw conversion.Hub) error {
 
 	dst.Spec.Template.Spec.Ignition = restored.Spec.Template.Spec.Ignition
 	if restored.Spec.Template.Spec.InitConfiguration != nil {
-		if dst.Spec.Template.Spec.InitConfiguration == nil {
-			dst.Spec.Template.Spec.InitConfiguration = &bootstrapv1.InitConfiguration{}
-		}
 		dst.Spec.Template.Spec.InitConfiguration.Patches = restored.Spec.Template.Spec.InitConfiguration.Patches
 	}
 	if restored.Spec.Template.Spec.JoinConfiguration != nil {
-		if dst.Spec.Template.Spec.JoinConfiguration == nil {
-			dst.Spec.Template.Spec.JoinConfiguration = &bootstrapv1.JoinConfiguration{}
-		}
 		dst.Spec.Template.Spec.JoinConfiguration.Patches = restored.Spec.Template.Spec.JoinConfiguration.Patches
 	}
 
diff --git a/bootstrap/kubeadm/internal/controllers/kubeadmconfig_controller.go b/bootstrap/kubeadm/internal/controllers/kubeadmconfig_controller.go
index 7bb951f6f..a7be733a6 100644
--- a/bootstrap/kubeadm/internal/controllers/kubeadmconfig_controller.go
+++ b/bootstrap/kubeadm/internal/controllers/kubeadmconfig_controller.go
@@ -713,7 +713,7 @@ func (r *KubeadmConfigReconciler) resolveSecretFileContent(ctx context.Context,
 	return data, nil
 }
 
-// ClusterToKubeadmConfigs is a handler.ToRequestsFunc to be used to enqueue
+// ClusterToKubeadmConfigs is a handler.ToRequestsFunc to be used to enqeue
 // requests for reconciliation of KubeadmConfigs.
 func (r *KubeadmConfigReconciler) ClusterToKubeadmConfigs(o client.Object) []ctrl.Request {
 	result := []ctrl.Request{}
@@ -761,7 +761,7 @@ func (r *KubeadmConfigReconciler) ClusterToKubeadmConfigs(o client.Object) []ctr
 	return result
 }
 
-// MachineToBootstrapMapFunc is a handler.ToRequestsFunc to be used to enqueue
+// MachineToBootstrapMapFunc is a handler.ToRequestsFunc to be used to enqeue
 // request for reconciliation of KubeadmConfig.
 func (r *KubeadmConfigReconciler) MachineToBootstrapMapFunc(o client.Object) []ctrl.Request {
 	m, ok := o.(*clusterv1.Machine)
diff --git a/cmd/clusterctl/client/config/cert_manager.go b/cmd/clusterctl/client/config/cert_manager.go
index 2104c8c1e..a8ce09c82 100644
--- a/cmd/clusterctl/client/config/cert_manager.go
+++ b/cmd/clusterctl/client/config/cert_manager.go
@@ -19,7 +19,7 @@ package config
 // CertManager defines cert-manager configuration.
 type CertManager interface {
 	// URL returns the name of the cert-manager repository.
-	// If empty, "https://github.com/cert-manager/cert-manager/releases/latest/cert-manager.yaml" will be used.
+	// If empty, "https://github.com/jetstack/cert-manager/releases/latest/cert-manager.yaml" will be used.
 	URL() string
 
 	// Version returns the cert-manager version to install.
diff --git a/controlplane/kubeadm/api/v1alpha3/conversion.go b/controlplane/kubeadm/api/v1alpha3/conversion.go
index b27bc73de..cd7c1913a 100644
--- a/controlplane/kubeadm/api/v1alpha3/conversion.go
+++ b/controlplane/kubeadm/api/v1alpha3/conversion.go
@@ -57,15 +57,9 @@ func (src *KubeadmControlPlane) ConvertTo(dstRaw conversion.Hub) error {
 
 	dst.Spec.KubeadmConfigSpec.Ignition = restored.Spec.KubeadmConfigSpec.Ignition
 	if restored.Spec.KubeadmConfigSpec.InitConfiguration != nil {
-		if dst.Spec.KubeadmConfigSpec.InitConfiguration == nil {
-			dst.Spec.KubeadmConfigSpec.InitConfiguration = &bootstrapv1.InitConfiguration{}
-		}
 		dst.Spec.KubeadmConfigSpec.InitConfiguration.Patches = restored.Spec.KubeadmConfigSpec.InitConfiguration.Patches
 	}
 	if restored.Spec.KubeadmConfigSpec.JoinConfiguration != nil {
-		if dst.Spec.KubeadmConfigSpec.JoinConfiguration == nil {
-			dst.Spec.KubeadmConfigSpec.JoinConfiguration = &bootstrapv1.JoinConfiguration{}
-		}
 		dst.Spec.KubeadmConfigSpec.JoinConfiguration.Patches = restored.Spec.KubeadmConfigSpec.JoinConfiguration.Patches
 	}
 
diff --git a/controlplane/kubeadm/api/v1alpha4/conversion.go b/controlplane/kubeadm/api/v1alpha4/conversion.go
index af8843f32..7147736f2 100644
--- a/controlplane/kubeadm/api/v1alpha4/conversion.go
+++ b/controlplane/kubeadm/api/v1alpha4/conversion.go
@@ -21,7 +21,6 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/conversion"
 
 	bootstrapv1alpha4 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1alpha4"
-	bootstrapv1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1beta1"
 	controlplanev1 "sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1beta1"
 	utilconversion "sigs.k8s.io/cluster-api/util/conversion"
 )
@@ -41,15 +40,9 @@ func (src *KubeadmControlPlane) ConvertTo(dstRaw conversion.Hub) error {
 
 	dst.Spec.KubeadmConfigSpec.Ignition = restored.Spec.KubeadmConfigSpec.Ignition
 	if restored.Spec.KubeadmConfigSpec.InitConfiguration != nil {
-		if dst.Spec.KubeadmConfigSpec.InitConfiguration == nil {
-			dst.Spec.KubeadmConfigSpec.InitConfiguration = &bootstrapv1.InitConfiguration{}
-		}
 		dst.Spec.KubeadmConfigSpec.InitConfiguration.Patches = restored.Spec.KubeadmConfigSpec.InitConfiguration.Patches
 	}
 	if restored.Spec.KubeadmConfigSpec.JoinConfiguration != nil {
-		if dst.Spec.KubeadmConfigSpec.JoinConfiguration == nil {
-			dst.Spec.KubeadmConfigSpec.JoinConfiguration = &bootstrapv1.JoinConfiguration{}
-		}
 		dst.Spec.KubeadmConfigSpec.JoinConfiguration.Patches = restored.Spec.KubeadmConfigSpec.JoinConfiguration.Patches
 	}
 
@@ -95,15 +88,9 @@ func (src *KubeadmControlPlaneTemplate) ConvertTo(dstRaw conversion.Hub) error {
 	dst.Spec.Template.Spec.KubeadmConfigSpec.Ignition = restored.Spec.Template.Spec.KubeadmConfigSpec.Ignition
 	dst.Spec.Template.Spec.MachineTemplate = restored.Spec.Template.Spec.MachineTemplate
 	if restored.Spec.Template.Spec.KubeadmConfigSpec.InitConfiguration != nil {
-		if dst.Spec.Template.Spec.KubeadmConfigSpec.InitConfiguration == nil {
-			dst.Spec.Template.Spec.KubeadmConfigSpec.InitConfiguration = &bootstrapv1.InitConfiguration{}
-		}
 		dst.Spec.Template.Spec.KubeadmConfigSpec.InitConfiguration.Patches = restored.Spec.Template.Spec.KubeadmConfigSpec.InitConfiguration.Patches
 	}
 	if restored.Spec.Template.Spec.KubeadmConfigSpec.JoinConfiguration != nil {
-		if dst.Spec.Template.Spec.KubeadmConfigSpec.JoinConfiguration == nil {
-			dst.Spec.Template.Spec.KubeadmConfigSpec.JoinConfiguration = &bootstrapv1.JoinConfiguration{}
-		}
 		dst.Spec.Template.Spec.KubeadmConfigSpec.JoinConfiguration.Patches = restored.Spec.Template.Spec.KubeadmConfigSpec.JoinConfiguration.Patches
 	}
 
diff --git a/docs/book/src/clusterctl/commands/init.md b/docs/book/src/clusterctl/commands/init.md
index 500af289b..202a1eb05 100644
--- a/docs/book/src/clusterctl/commands/init.md
+++ b/docs/book/src/clusterctl/commands/init.md
@@ -62,10 +62,6 @@ for each selected provider.
 
 You can specify the provider version by appending a version tag to the provider name, e.g. `aws:v0.4.1`.
 
-Pinning the version provides better control over what clusterctl chooses to install
-(usually required in an enterprise environment). Version pinning should always be used when using [image overrides](../configuration.md#image-overrides), or when relying on internal repositories with a separated
-software supply chain, or a custom versioning schema.
-
 </aside>
 
 <aside class="note">
diff --git a/docs/book/src/clusterctl/configuration.md b/docs/book/src/clusterctl/configuration.md
index 820f3a78e..6588536d8 100644
--- a/docs/book/src/clusterctl/configuration.md
+++ b/docs/book/src/clusterctl/configuration.md
@@ -57,7 +57,7 @@ the environment variable takes precedence.
 While doing init, clusterctl checks if there is a version of cert-manager already installed. If not, clusterctl will
 install a default version.
 
-By default, cert-manager will be fetched from `https://github.com/cert-manager/cert-manager/releases`; however, if the user
+By default, cert-manager will be fetched from `https://github.com/jetstack/cert-manager/releases`; however, if the user
 wants to use a different repository, it is possible to use the following configuration:
 
 ```yaml
@@ -170,9 +170,6 @@ overridesFolder: /Users/foobar/workspace/dev-releases
 Image override is an advanced feature and wrong configuration can easily lead to non-functional clusters.
 It's strongly recommended to test configurations on dev/test environments before using this functionality in production.
 
-This feature must always be used in conjunction with 
-[version tag](commands/init.md#provider-version) when executing clusterctl commands.
-
 </aside>
 
 When working in air-gapped environments, it's necessary to alter the manifests to be installed in order to pull
diff --git a/docs/book/src/developer/guide.md b/docs/book/src/developer/guide.md
index 4a90f65c2..db0e1d35e 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.5.3/cert-manager.yaml
+kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.5.3/cert-manager.yaml
 ```
 
 Ensure the cert-manager webhook service is ready before creating the Cluster API components.
@@ -92,7 +92,7 @@ This can be done by running:
 kubectl wait --for=condition=Available --timeout=300s apiservice v1beta1.webhook.cert-manager.io
 ```
 
-[cert-manager]: https://github.com/cert-manager/cert-manager
+[cert-manager]: https://github.com/jetstack/cert-manager
 
 ## Development
 
diff --git a/docs/book/src/developer/tilt.md b/docs/book/src/developer/tilt.md
index f0d29fc62..1c0b2eef5 100644
--- a/docs/book/src/developer/tilt.md
+++ b/docs/book/src/developer/tilt.md
@@ -66,8 +66,8 @@ for more details.
 **kustomize_substitutions** (Map{String: String}, default={}): An optional map of substitutions for `${}`-style placeholders in the
 provider's yaml.
 
-**deploy_observability** ([string], default=[]): If set, installs on the dev cluster one of more observability
-tools. Supported values are `grafana`, `loki` and/or `promtail` (Note: the UI for `grafana` will be accessible via a link in the tilt console).
+**deploy_observability** (Bool, default=false): If set to true, it will instrall grafana, loki and promtail in the dev
+cluster. Grafana UI will be accessible via a link in the tilt console.
 Important! This feature requires the `helm` command to be available in the user's path.
 
 **debug** (Map{string: Map} default{}): A map of named configurations for the provider. The key is the name of the provider.
diff --git a/docs/book/src/reference/versions.md b/docs/book/src/reference/versions.md
index bb35d26bf..ce2e2adf3 100644
--- a/docs/book/src/reference/versions.md
+++ b/docs/book/src/reference/versions.md
@@ -15,7 +15,27 @@ 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 current release (N), N-1, and N-2. To find out the exact range of Kubernetes versions supported by each component, please see the [tables](#release-components) below.
+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 
+  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! 
+  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.
+
+Whenever a new Cluster API release is cut, we will document the Kubernetes version compatibility matrix the release
+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. 
+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.
 
 See the [following section](#kubernetes-version-support-as-a-function-of-cluster-topology) to understand how cluster topology affects version support.
 
diff --git a/docs/book/src/user/quick-start.md b/docs/book/src/user/quick-start.md
index 98a931a46..b63ad4462 100644
--- a/docs/book/src/user/quick-start.md
+++ b/docs/book/src/user/quick-start.md
@@ -101,7 +101,7 @@ The clusterctl CLI tool handles the lifecycle of a Cluster API management cluste
 #### Install clusterctl binary with curl on linux
 Download the latest release; on linux, type:
 ```
-curl -L {{#releaselink gomodule:"sigs.k8s.io/cluster-api" asset:"clusterctl-linux-amd64" version:"1.1.x"}} -o clusterctl
+curl -L {{#releaselink gomodule:"sigs.k8s.io/cluster-api" asset:"clusterctl-linux-amd64" version:"1.0.x"}} -o clusterctl
 ```
 Make the clusterctl binary executable.
 ```
@@ -122,12 +122,12 @@ clusterctl version
 #### Install clusterctl binary with curl on macOS
 Download the latest release; on macOS, type:
 ```
-curl -L {{#releaselink gomodule:"sigs.k8s.io/cluster-api" asset:"clusterctl-darwin-amd64" version:"1.1.x"}} -o clusterctl
+curl -L {{#releaselink gomodule:"sigs.k8s.io/cluster-api" asset:"clusterctl-darwin-amd64" version:"1.0.x"}} -o clusterctl
 ```
 
 Or if your Mac has an M1 CPU ("Apple Silicon"):
 ```
-curl -L {{#releaselink gomodule:"sigs.k8s.io/cluster-api" asset:"clusterctl-darwin-arm64" version:"1.1.x"}} -o clusterctl
+curl -L {{#releaselink gomodule:"sigs.k8s.io/cluster-api" asset:"clusterctl-darwin-arm64" version:"1.0.x"}} -o clusterctl
 ```
 
 Make the clusterctl binary executable.
@@ -515,9 +515,7 @@ export WORKER_NODE_TYPE="t1.small"
 export GCP_REGION="<GCP_REGION>"
 export GCP_PROJECT="<GCP_PROJECT>"
 # Make sure to use same kubernetes version here as building the GCE image
-export KUBERNETES_VERSION=1.23.3
-# This is the image you built. See https://github.com/kubernetes-sigs/image-builder
-export IMAGE_ID=projects/$GCP_PROJECT/global/images/<built image>
+export KUBERNETES_VERSION=1.20.9
 export GCP_CONTROL_PLANE_MACHINE_TYPE=n1-standard-2
 export GCP_NODE_MACHINE_TYPE=n1-standard-2
 export GCP_NETWORK_NAME=<GCP_NETWORK_NAME or default>
diff --git a/docs/book/src/user/troubleshooting.md b/docs/book/src/user/troubleshooting.md
index 1473ab7d8..274945c42 100644
--- a/docs/book/src/user/troubleshooting.md
+++ b/docs/book/src/user/troubleshooting.md
@@ -104,26 +104,3 @@ Alternatively a Cert Manager yaml file can be placed in the [clusterctl override
 
 More information on the clusterctl config file can be found at [its page in the book](../clusterctl/configuration.md#clusterctl-configuration-file)
 
-## Clusterctl failing to start providers due to outdated image overrides
-
-clusterctl allows users to configure [image overrides](../clusterctl/configuration.md#image-overrides) via the clusterctl config file.
-However, when the image override is pinning a provider image to a specific version, it could happen that this
-conflicts with clusterctl behavior of picking the latest version of a provider.
-
-E.g., if you are pinning KCP images to version v1.0.2 but then clusterctl init fetches yamls for version v1.1.0 or greater KCP will 
-fail to start with the following error: 
-
-```
-invalid argument "ClusterTopology=false,KubeadmBootstrapFormatIgnition=false" for "--feature-gates" flag: unrecognized feature gate: KubeadmBootstrapFormatIgnition
-```
-
-In order to solve this problem you should specify the version of the provider you are installing by appending a
-version tag to the provider name:
-
-```shell
-clusterctl init -b kubeadm:v1.0.2 -c kubeadm:v1.0.2 --core cluster-api:v1.0.2 -i docker:v1.0.2
-```
-
-Even if slightly verbose, pinning the version provides a better control over what is installed, as usually
-required in an enterprise environment, especially if you rely on an internal repository with a separated
-software supply chain or a custom versioning schema.
\ No newline at end of file
diff --git a/go.mod b/go.mod
index cd863d0aa..430614590 100644
--- a/go.mod
+++ b/go.mod
@@ -41,7 +41,7 @@ require (
 	k8s.io/klog/v2 v2.30.0
 	k8s.io/kubectl v0.23.0
 	k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b
-	sigs.k8s.io/controller-runtime v0.11.1
+	sigs.k8s.io/controller-runtime v0.11.0
 	sigs.k8s.io/yaml v1.3.0
 )
 
diff --git a/go.sum b/go.sum
index a9ec7b532..4be9b57c9 100644
--- a/go.sum
+++ b/go.sum
@@ -1207,8 +1207,8 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8
 rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
 rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
 sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.25/go.mod h1:Mlj9PNLmG9bZ6BHFwFKDo5afkpWyUISkb9Me0GnK66I=
-sigs.k8s.io/controller-runtime v0.11.1 h1:7YIHT2QnHJArj/dk9aUkYhfqfK5cIxPOX5gPECfdZLU=
-sigs.k8s.io/controller-runtime v0.11.1/go.mod h1:KKwLiTooNGu+JmLZGn9Sl3Gjmfj66eMbCQznLP5zcqA=
+sigs.k8s.io/controller-runtime v0.11.0 h1:DqO+c8mywcZLFJWILq4iktoECTyn30Bkj0CwgqMpZWQ=
+sigs.k8s.io/controller-runtime v0.11.0/go.mod h1:KKwLiTooNGu+JmLZGn9Sl3Gjmfj66eMbCQznLP5zcqA=
 sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 h1:fD1pz4yfdADVNfFmcP2aBEtudwUQ1AlLnRBALr33v3s=
 sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs=
 sigs.k8s.io/kustomize/api v0.10.1 h1:KgU7hfYoscuqag84kxtzKdEC3mKMb99DPI3a0eaV1d0=
diff --git a/hack/observability/grafana/kustomization.yaml b/hack/observability/grafana/kustomization.yaml
deleted file mode 100644
index efee13fe2..000000000
--- a/hack/observability/grafana/kustomization.yaml
+++ /dev/null
@@ -1,9 +0,0 @@
-resources:
-  - ../namespace.yaml
-
-helmCharts:
-  - name: grafana
-    repo: https://grafana.github.io/helm-charts
-    releaseName: grafana
-    namespace: observability
-    valuesFile: values.yaml
diff --git a/hack/observability/kustomization.yaml b/hack/observability/kustomization.yaml
new file mode 100644
index 000000000..7d238084e
--- /dev/null
+++ b/hack/observability/kustomization.yaml
@@ -0,0 +1,19 @@
+resources:
+  - namespace.yaml
+
+helmCharts:
+  - name: promtail
+    repo: https://grafana.github.io/helm-charts
+    releaseName: promtail
+    namespace: observability
+    valuesFile: ./promtail/values.yaml
+  - name: loki
+    repo: https://grafana.github.io/helm-charts
+    releaseName: loki
+    namespace: observability
+    valuesFile: ./loki/values.yaml
+  - name: grafana
+    repo: https://grafana.github.io/helm-charts
+    releaseName: grafana
+    namespace: observability
+    valuesFile: ./grafana/values.yaml
diff --git a/hack/observability/loki/kustomization.yaml b/hack/observability/loki/kustomization.yaml
deleted file mode 100644
index 1462fa75b..000000000
--- a/hack/observability/loki/kustomization.yaml
+++ /dev/null
@@ -1,9 +0,0 @@
-resources:
-  - ../namespace.yaml
-
-helmCharts:
-  - name: loki
-    repo: https://grafana.github.io/helm-charts
-    releaseName: loki
-    namespace: observability
-    valuesFile: values.yaml
diff --git a/hack/observability/promtail/kustomization.yaml b/hack/observability/promtail/kustomization.yaml
deleted file mode 100644
index 7233ed2e4..000000000
--- a/hack/observability/promtail/kustomization.yaml
+++ /dev/null
@@ -1,9 +0,0 @@
-resources:
-  - ../namespace.yaml
-
-helmCharts:
-  - name: promtail
-    repo: https://grafana.github.io/helm-charts
-    releaseName: promtail
-    namespace: observability
-    valuesFile: values.yaml
diff --git a/hack/tools/go.mod b/hack/tools/go.mod
index 6dfc91c41..b2d543682 100644
--- a/hack/tools/go.mod
+++ b/hack/tools/go.mod
@@ -24,7 +24,7 @@ require (
 	k8s.io/klog/v2 v2.30.0
 	sigs.k8s.io/cluster-api v0.0.0-00010101000000-000000000000
 	sigs.k8s.io/cluster-api/test v0.0.0-00010101000000-000000000000
-	sigs.k8s.io/controller-runtime v0.11.1
+	sigs.k8s.io/controller-runtime v0.11.0
 	sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20211110210527-619e6b92dab9
 	sigs.k8s.io/controller-tools v0.8.0
 	sigs.k8s.io/kubebuilder/docs/book/utils v0.0.0-20211028165026-57688c578b5d
diff --git a/hack/tools/go.sum b/hack/tools/go.sum
index 49b2843e6..c606381de 100644
--- a/hack/tools/go.sum
+++ b/hack/tools/go.sum
@@ -1925,8 +1925,8 @@ rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
 sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
 sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
 sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.25/go.mod h1:Mlj9PNLmG9bZ6BHFwFKDo5afkpWyUISkb9Me0GnK66I=
-sigs.k8s.io/controller-runtime v0.11.1 h1:7YIHT2QnHJArj/dk9aUkYhfqfK5cIxPOX5gPECfdZLU=
-sigs.k8s.io/controller-runtime v0.11.1/go.mod h1:KKwLiTooNGu+JmLZGn9Sl3Gjmfj66eMbCQznLP5zcqA=
+sigs.k8s.io/controller-runtime v0.11.0 h1:DqO+c8mywcZLFJWILq4iktoECTyn30Bkj0CwgqMpZWQ=
+sigs.k8s.io/controller-runtime v0.11.0/go.mod h1:KKwLiTooNGu+JmLZGn9Sl3Gjmfj66eMbCQznLP5zcqA=
 sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20211110210527-619e6b92dab9 h1:ylYUI5uaq/guUFerFRVG81FHSA5/3+fERCE1RQbQUZ4=
 sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20211110210527-619e6b92dab9/go.mod h1:+sJcI1F0QI0Cv+8fp5rH5B2fK1LxzrAQqYnaPx9nY8I=
 sigs.k8s.io/controller-tools v0.8.0 h1:uUkfTGEwrguqYYfcI2RRGUnC8mYdCFDqfwPKUcNJh1o=
diff --git a/hack/tools/tilt-prepare/main.go b/hack/tools/tilt-prepare/main.go
index bcffe4573..1dfee9eba 100644
--- a/hack/tools/tilt-prepare/main.go
+++ b/hack/tools/tilt-prepare/main.go
@@ -355,8 +355,6 @@ func kustomizeTask(path, out string) taskFunction {
 			path,
 			// enable helm to enable helmChartInflationGenerator.
 			"--enable-helm",
-			// to allow picking up resource files from a different folder.
-			"--load-restrictor=LoadRestrictionsNone",
 		)
 
 		var stdout, stderr bytes.Buffer
diff --git a/hack/verify-starlark.sh b/hack/verify-starlark.sh
index c2ba3e8ff..fce7421c7 100755
--- a/hack/verify-starlark.sh
+++ b/hack/verify-starlark.sh
@@ -45,7 +45,7 @@ cleanup() {
     echo "Found errors:"
     cat "${OUT}"
     echo ""
-    echo "run make tiltfile-fix to fix the errors"
+    echo "run make format-tiltfile to fix the errors"
     ret=1
   fi
   echo "Cleaning up..."
diff --git a/internal/controllers/machineset/machineset_controller.go b/internal/controllers/machineset/machineset_controller.go
index 5d85a596c..9716cb3d4 100644
--- a/internal/controllers/machineset/machineset_controller.go
+++ b/internal/controllers/machineset/machineset_controller.go
@@ -561,7 +561,7 @@ func (r *Reconciler) waitForMachineDeletion(ctx context.Context, machineList []*
 	return nil
 }
 
-// MachineToMachineSets is a handler.ToRequestsFunc to be used to enqueue requests for reconciliation
+// MachineToMachineSets is a handler.ToRequestsFunc to be used to enqeue requests for reconciliation
 // for MachineSets that might adopt an orphaned Machine.
 func (r *Reconciler) MachineToMachineSets(o client.Object) []ctrl.Request {
 	ctx := context.Background()


Test patch:
diff --git a/docs/book/src/developer/providers/implementers-guide/building_running_and_testing.md b/docs/book/src/developer/providers/implementers-guide/building_running_and_testing.md
index ab1297501..8fb05fb72 100644
--- a/docs/book/src/developer/providers/implementers-guide/building_running_and_testing.md
+++ b/docs/book/src/developer/providers/implementers-guide/building_running_and_testing.md
@@ -19,11 +19,11 @@ The approach most Cluster API projects is using [a `Makefile` that uses `sed` to
 Cluster API uses [cert-manager] to manage the certificates it needs for its webhooks.
 Before you apply Cluster API's yaml, you should [install `cert-manager`][cm-install]
 
-[cert-manager]: https://github.com/cert-manager/cert-manager
+[cert-manager]: https://github.com/jetstack/cert-manager
 [cm-install]: https://cert-manager.io/docs/installation/
 
 ```
-kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/<version>/cert-manager.yaml
+kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/<version>/cert-manager.yaml
 ```
 
 ### Cluster API
diff --git a/docs/book/src/developer/testing.md b/docs/book/src/developer/testing.md
index 52ae14ab4..df547ad6b 100644
--- a/docs/book/src/developer/testing.md
+++ b/docs/book/src/developer/testing.md
@@ -11,69 +11,29 @@ Unit tests focus on individual pieces of logic - a single func - and don't requi
 be fast and great for getting the first signal on the current implementation, but unit tests have the risk of
 allowing integration bugs to slip through.
 
-In Cluster API most of the unit tests are developed using [go test], [gomega] and the [fakeclient]; however using
-[fakeclient] is not suitable for all the use cases due to some limitations in how it is implemented. In some cases
-contributors will be required to use [envtest]. See the [quick reference](#quick-reference) below for more details.
+Historically, in Cluster API unit tests were developed using [go test], [gomega] and the [fakeclient]; see the quick reference below.
 
-### Mocking external APIs
-In some cases when writing tests it is required to mock external API, e.g. etcd client API or the AWS SDK API.
-
-This problem is usually well scoped in core Cluster API, and in most cases it is already solved by using fake
-implementations of the target API to be injected during tests.
-
-Instead, mocking is much more relevant for infrastructure providers; in order to address the issue
-some providers can use simulators reproducing the behaviour of a real infrastructure providers (e.g CAPV);
-if this is not possible, a viable solution is to use mocks (e.g CAPA).
-
-### Generic providers
-When writing tests core Cluster API contributors should ensure that the code works with any providers, and thus it is required
-to not use any specific provider implementation. Instead, the so-called generic providers e.g. "GenericInfrastructureCluster" 
-should be used because they implement the plain Cluster API contract. This prevents tests from relying on assumptions that 
-may not hold true in all cases.
-
-Please note that in the long term we would like to improve the implementation of generic providers, centralizing
-the existing set of utilities scattered across the codebase, but while details of this work will be defined do not
-hesitate to reach out to reviewers and maintainers for guidance.
+However, considering some changes introduced in the v0.3.x releases (e.g. ObservedGeneration, Conditions), there is a common
+agreement among Cluster API maintainers that using [fakeclient] should be progressively deprecated in favor of using
+[envtest]. See the quick reference below.
 
 ## Integration tests
 
 Integration tests are focused on testing the behavior of an entire controller or the interactions between two or
 more Cluster API controllers.
 
-In Cluster API, integration tests are based on [envtest] and one or more controllers configured to run against
+In older versions of Cluster API, integration tests were based on a real cluster and meant to be run in CI only; however,
+now we are considering a different approach based on [envtest] and with one or more controllers configured to run against
 the test cluster.
 
-With this approach it is possible to interact with Cluster API almost like in a real environment, by creating/updating
-Kubernetes objects and waiting for the controllers to take action. See the [quick reference](#quick-reference) below for more details.
-
-Also in case of integration tests, considerations about [mocking external APIs](#mocking-external-apis) and usage of [generic providers](#generic-providers) apply. 
-
-## Test maintainability
-
-Tests are an integral part of the project codebase.
-
-Cluster API maintainers and all the contributors should be committed to help in ensuring that tests are easily maintainable,
-easily readable, well documented and consistent across the code base.
-
-In light of continuing improving our practice around this ambitious goal, we are starting to introduce a shared set of:
+With this approach it is possible to interact with Cluster API like in a real environment, by creating/updating
+Kubernetes objects and waiting for the controllers to take action.
 
-- Builders (`sigs.k8s.io/cluster-api/internal/test/builder`), allowing to create test objects in a simple and consistent way.
-- Matchers (`sigs.k8s.io/cluster-api/internal/test/matchers`), improving how we write test assertions.
+Please note that while using this mode, as of today, when testing the interactions with an infrastructure provider
+some infrastructure components will be generated, and this could have relevant impacts on test durations (and requirements).
 
-Each contribution in growing this set of utilities or their adoption across the codebase is more than welcome!
-
-Another consideration that can help in improving test maintainability is the idea of testing "by layers"; this idea could 
-apply whenever we are testing "higher-level" functions that internally uses one or more "lower-level" functions;
-in order to avoid writing/maintaining redundant tests, whenever possible contributors should take care of testing
-_only_ the logic that is implemented in the "higher-level" function, delegating the test function called internally
-to a "lower-level" set of unit tests.
-
-A similar concern could be raised also in the case whenever there is overlap between unit tests and integration tests,
-but in this case the distinctive value of the two layers of testing is determined by how test are designed:
-
-- unit test are focused on code structure: func(input) = output, including edge case values, asserting error conditions etc.
-- integration test are user story driven: as a user, I want express some desired state using API objects, wait for the
-  reconcilers to take action, check the new system state.
+While, as of today this is a strong limitation, in the future we might consider to have a "dry-run" option in CAPD or
+a fake infrastructure provider to allow test coverage for testing the interactions with an infrastructure provider as well.
 
 ## Running unit and integration tests
 
@@ -280,10 +240,21 @@ var (
 )
 
 func TestMain(m *testing.M) {
-	// Setup envtest
-	...
+	setupIndexes := func(ctx context.Context, mgr ctrl.Manager) {
+		if err := index.AddDefaultIndexes(ctx, mgr); err != nil {
+			panic(fmt.Sprintf("unable to setup index: %v", err))
+		}
+	}
+
+	setupReconcilers := func(ctx context.Context, mgr ctrl.Manager) {
+		if err := (&MyReconciler{
+			Client:  mgr.GetClient(),
+			Log:     log.NullLogger{},
+		}).SetupWithManager(mgr, controller.Options{MaxConcurrentReconciles: 1}); err != nil {
+			panic(fmt.Sprintf("Failed to start the MyReconciler: %v", err))
+		}
+	}
 
-	// Run tests
 	os.Exit(envtest.Run(ctx, envtest.RunInput{
 		M:        m,
 		SetupEnv: func(e *envtest.Environment) { env = e },
@@ -294,11 +265,14 @@ func TestMain(m *testing.M) {
 ```
 
 Most notably, [envtest] provides not only a real API server to use during testing, but it offers the opportunity
-to configure one or more controllers to run against the test cluster, as well as creating informers index. 
+to configure one or more controllers to run against the test cluster. By using this feature it is possible to use
+[envtest] for developing Cluster API integration tests.
 
 ```golang
 func TestMain(m *testing.M) {
-	// Setup envtest
+	// Bootstrapping test environment
+	...
+
 	setupReconcilers := func(ctx context.Context, mgr ctrl.Manager) {
 		if err := (&MyReconciler{
 			Client:  mgr.GetClient(),
@@ -308,32 +282,17 @@ func TestMain(m *testing.M) {
 		}
 	}
 
-	setupIndexes := func(ctx context.Context, mgr ctrl.Manager) {
-		if err := index.AddDefaultIndexes(ctx, mgr); err != nil {
-		panic(fmt.Sprintf("unable to setup index: %v", err))
-	}
-    
-    // Run tests
+	// Run tests
 	...
 }
 ```
 
-By combining pre-configured validation and mutating webhooks and reconcilers/indexes it is possible
-to use [envtest] for developing Cluster API integration tests that can mimic how the system
-behaves in real Cluster.
-
-Please note that, because [envtest] uses a real kube-apiserver that is shared across many test cases, the developer
+Please note that, because [envtest] uses a real kube-apiserver that is shared across many tests, the developer
 should take care in ensuring each test runs in isolation from the others, by:
 
 - Creating objects in separated namespaces.
 - Avoiding object name conflict.
 
-Developers should also be aware of the fact that the informers cache used to access the [envtest]
-depends on actual etcd watches/API calls for updates, and thus it could happen that after creating 
-or deleting objects the cache takes a few milliseconds to get updated. This can lead to test flakes, 
-and thus it always recommended to use patterns like create and wait or delete and wait; Cluster API env
-test provides a set of utils for this scope.
-
 However, developers should be aware that in some ways, the test control plane will behave differently from “real”
 clusters, and that might have an impact on how you write tests.
 
@@ -415,15 +374,13 @@ comes with a set of limitations that could hamper the validity of a test, most n
 
 - it does not properly handle a set of fields which are common in the Kubernetes API objects (and Cluster API objects as well)
   like e.g. `creationTimestamp`, `resourceVersion`, `generation`, `uid`
-- [fakeclient] operations do not trigger defaulting or validation webhooks, so there are no enforced guarantees about the semantic accuracy
+- API calls doe not execute defaulting or validation webhooks, so there are no enforced guarantees about the semantic accuracy
   of the test objects.
-- the [fakeclient] does not use a cache based on informers/API calls/etcd watches, so the test written in this way
-  can't help in surfacing race conditions related to how those components behave in real cluster.
-- there is no support for cache index/operations using cache indexes. 
 
-Accordingly, using [fakeclient] is not suitable for all the use cases, so in some cases contributors will be required
-to use [envtest] instead. In case of doubts about which one to use when writing tests, don't hesitate to ask for
-guidance from project maintainers.
+Historically, [fakeclient] is widely used in Cluster API, however, given the growing relevance of the above limitations
+with regard to some changes introduced in the v0.3.x releases (e.g. ObservedGeneration, Conditions), there is a common
+agreement among Cluster API maintainers that using [fakeclient] should be progressively deprecated in favor of use
+of [envtest].
 
 ### `ginkgo`
 [Ginkgo] is a Go testing framework built to help you efficiently write expressive and comprehensive tests using Behavior-Driven Development (“BDD”) style.
diff --git a/test/go.mod b/test/go.mod
index 4abd6db3d..b1aa98e89 100644
--- a/test/go.mod
+++ b/test/go.mod
@@ -23,7 +23,7 @@ require (
 	k8s.io/klog/v2 v2.30.0
 	k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b
 	sigs.k8s.io/cluster-api v0.0.0-00010101000000-000000000000
-	sigs.k8s.io/controller-runtime v0.11.1
+	sigs.k8s.io/controller-runtime v0.11.0
 	sigs.k8s.io/kind v0.11.1
 	sigs.k8s.io/yaml v1.3.0
 )
diff --git a/test/go.sum b/test/go.sum
index 006d63eac..e02635a6e 100644
--- a/test/go.sum
+++ b/test/go.sum
@@ -1562,8 +1562,8 @@ rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
 sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
 sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
 sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.25/go.mod h1:Mlj9PNLmG9bZ6BHFwFKDo5afkpWyUISkb9Me0GnK66I=
-sigs.k8s.io/controller-runtime v0.11.1 h1:7YIHT2QnHJArj/dk9aUkYhfqfK5cIxPOX5gPECfdZLU=
-sigs.k8s.io/controller-runtime v0.11.1/go.mod h1:KKwLiTooNGu+JmLZGn9Sl3Gjmfj66eMbCQznLP5zcqA=
+sigs.k8s.io/controller-runtime v0.11.0 h1:DqO+c8mywcZLFJWILq4iktoECTyn30Bkj0CwgqMpZWQ=
+sigs.k8s.io/controller-runtime v0.11.0/go.mod h1:KKwLiTooNGu+JmLZGn9Sl3Gjmfj66eMbCQznLP5zcqA=
 sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 h1:fD1pz4yfdADVNfFmcP2aBEtudwUQ1AlLnRBALr33v3s=
 sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs=
 sigs.k8s.io/kind v0.11.1 h1:pVzOkhUwMBrCB0Q/WllQDO3v14Y+o2V0tFgjTqIUjwA=
diff --git a/test/infrastructure/docker/examples/machine-pool.yaml b/test/infrastructure/docker/examples/machine-pool.yaml
index 7bd71803b..756608237 100644
--- a/test/infrastructure/docker/examples/machine-pool.yaml
+++ b/test/infrastructure/docker/examples/machine-pool.yaml
@@ -48,13 +48,6 @@ spec:
           # kind will implement systemd support in: https://github.com/kubernetes-sigs/kind/issues/1726
           cgroup-driver: cgroupfs
           eviction-hard: nodefs.available<0%,nodefs.inodesFree<0%,imagefs.available<0%
-    joinConfiguration:
-      nodeRegistration:
-        kubeletExtraArgs:
-          # We have to pin the cgroupDriver to cgroupfs as kubeadm >=1.21 defaults to systemd
-          # kind will implement systemd support in: https://github.com/kubernetes-sigs/kind/issues/1726
-          cgroup-driver: cgroupfs
-          eviction-hard: nodefs.available<0%,nodefs.inodesFree<0%,imagefs.available<0%
 ---
 apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
 kind: DockerCluster
diff --git a/test/infrastructure/docker/examples/simple-cluster-ipv6.yaml b/test/infrastructure/docker/examples/simple-cluster-ipv6.yaml
index 74159a94a..7c426f404 100644
--- a/test/infrastructure/docker/examples/simple-cluster-ipv6.yaml
+++ b/test/infrastructure/docker/examples/simple-cluster-ipv6.yaml
@@ -77,10 +77,6 @@ spec:
     joinConfiguration:
       nodeRegistration:
         kubeletExtraArgs:
-          # We have to pin the cgroupDriver to cgroupfs as kubeadm >=1.21 defaults to systemd
-          # kind will implement systemd support in: https://github.com/kubernetes-sigs/kind/issues/1726
-          cgroup-driver: cgroupfs
-          eviction-hard: nodefs.available<0%,nodefs.inodesFree<0%,imagefs.available<0%
           node-ip: "::"
 ---
 apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
diff --git a/test/infrastructure/docker/examples/simple-cluster.yaml b/test/infrastructure/docker/examples/simple-cluster.yaml
index 59ab573c3..7ab36e43b 100644
--- a/test/infrastructure/docker/examples/simple-cluster.yaml
+++ b/test/infrastructure/docker/examples/simple-cluster.yaml
@@ -68,13 +68,6 @@ spec:
           # kind will implement systemd support in: https://github.com/kubernetes-sigs/kind/issues/1726
           cgroup-driver: cgroupfs
           eviction-hard: nodefs.available<0%,nodefs.inodesFree<0%,imagefs.available<0%
-    joinConfiguration:
-      nodeRegistration:
-        kubeletExtraArgs:
-          # We have to pin the cgroupDriver to cgroupfs as kubeadm >=1.21 defaults to systemd
-          # kind will implement systemd support in: https://github.com/kubernetes-sigs/kind/issues/1726
-          cgroup-driver: cgroupfs
-          eviction-hard: nodefs.available<0%,nodefs.inodesFree<0%,imagefs.available<0%
 ---
 apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
 kind: DockerMachineTemplate
diff --git a/test/infrastructure/docker/internal/controllers/dockermachine_controller.go b/test/infrastructure/docker/internal/controllers/dockermachine_controller.go
index 24e365414..c09b38cce 100644
--- a/test/infrastructure/docker/internal/controllers/dockermachine_controller.go
+++ b/test/infrastructure/docker/internal/controllers/dockermachine_controller.go
@@ -385,7 +385,7 @@ func (r *DockerMachineReconciler) SetupWithManager(ctx context.Context, mgr ctrl
 	)
 }
 
-// DockerClusterToDockerMachines is a handler.ToRequestsFunc to be used to enqueue
+// DockerClusterToDockerMachines is a handler.ToRequestsFunc to be used to enqeue
 // requests for reconciliation of DockerMachines.
 func (r *DockerMachineReconciler) DockerClusterToDockerMachines(o client.Object) []ctrl.Request {
 	result := []ctrl.Request{}