Repository: kubernetes-sigs/cluster-api
Pull request #5377 (2021-10-04 14:31:02)

🌱 Allow passing in provider contract and clusterctl binary in the clusterctl upgrade spec
Signed-off-by: Naadir Jeewa <jeewan@vmware.com>

<!-- please add a icon to the title of this PR (see https://sigs.k8s.io/cluster-api/VERSIONING.md), and delete this line and similar ones -->
<!-- the icon will be either ⚠️ (:warning:, major or breaking changes), ✨ (:sparkles:, feature additions), 🐛 (:bug:, patch and bugfixes), 📖 (:book:, documentation or proposals), or 🌱 (:seedling:, minor or other) -->

**What this PR does / why we need it**:
I would like to run both v1alpha4 -> v1beta1 and v1alpha3 -> v1beta1 tests in the same job, so expanding the clusterctl upgrade spec to allow different provider contracts to be tested.

**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 #

/assign @sbueringer 
/area testing

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

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

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

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

- **[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"]} -->

Patch:
diff --git a/bootstrap/kubeadm/controllers/kubeadmconfig_controller.go b/bootstrap/kubeadm/controllers/kubeadmconfig_controller.go
index b80ee52a7..d0829c066 100644
--- a/bootstrap/kubeadm/controllers/kubeadmconfig_controller.go
+++ b/bootstrap/kubeadm/controllers/kubeadmconfig_controller.go
@@ -98,10 +98,11 @@ func (r *KubeadmConfigReconciler) SetupWithManager(ctx context.Context, mgr ctrl
 	b := ctrl.NewControllerManagedBy(mgr).
 		For(&bootstrapv1.KubeadmConfig{}).
 		WithOptions(options).
+		WithEventFilter(predicates.ResourceNotPausedAndHasFilterLabel(ctrl.LoggerFrom(ctx), r.WatchFilterValue)).
 		Watches(
 			&source.Kind{Type: &clusterv1.Machine{}},
 			handler.EnqueueRequestsFromMapFunc(r.MachineToBootstrapMapFunc),
-		).WithEventFilter(predicates.ResourceNotPausedAndHasFilterLabel(ctrl.LoggerFrom(ctx), r.WatchFilterValue))
+		)
 
 	if feature.Gates.Enabled(feature.MachinePool) {
 		b = b.Watches(
diff --git a/cmd/clusterctl/client/repository/components.go b/cmd/clusterctl/client/repository/components.go
index 831cc05ad..0e284256b 100644
--- a/cmd/clusterctl/client/repository/components.go
+++ b/cmd/clusterctl/client/repository/components.go
@@ -42,12 +42,16 @@ const (
 	clusterRoleKind                    = "ClusterRole"
 	clusterRoleBindingKind             = "ClusterRoleBinding"
 	roleBindingKind                    = "RoleBinding"
-	certificateKind                    = "Certificate"
 	mutatingWebhookConfigurationKind   = "MutatingWebhookConfiguration"
 	validatingWebhookConfigurationKind = "ValidatingWebhookConfiguration"
 	customResourceDefinitionKind       = "CustomResourceDefinition"
 )
 
+const (
+	// WebhookNamespaceName is the namespace used to deploy Cluster API webhooks.
+	WebhookNamespaceName = "capi-webhook-system"
+)
+
 // Components wraps a YAML file that defines the provider components
 // to be installed in a management cluster (CRD, Controller, RBAC etc.)
 // It is important to notice that clusterctl applies a set of processing steps to the “raw” component YAML read
@@ -309,8 +313,6 @@ func fixTargetNamespace(objs []unstructured.Unstructured, targetNamespace string
 			o.SetName(targetNamespace)
 		}
 
-		originalNamespace := o.GetNamespace()
-
 		// if the object is namespaced, set the namespace name
 		if util.IsResourceNamespaced(o.GetKind()) {
 			o.SetNamespace(targetNamespace)
@@ -323,14 +325,6 @@ func fixTargetNamespace(objs []unstructured.Unstructured, targetNamespace string
 				return nil, err
 			}
 		}
-
-		if o.GetKind() == certificateKind {
-			var err error
-			o, err = fixCertificate(o, originalNamespace, targetNamespace)
-			if err != nil {
-				return nil, err
-			}
-		}
 		objs[i] = o
 	}
 	return objs, nil
@@ -419,7 +413,6 @@ func fixValidatingWebhookNamespaceReferences(o unstructured.Unstructured, target
 	}
 	return o, errors.Errorf("failed to patch %s ValidatingWebhookConfiguration", version)
 }
-
 func fixCRDWebhookNamespaceReference(o unstructured.Unstructured, targetNamespace string) (unstructured.Unstructured, error) {
 	version := o.GroupVersionKind().Version
 	switch version {
@@ -446,33 +439,6 @@ func fixCRDWebhookNamespaceReference(o unstructured.Unstructured, targetNamespac
 	return o, errors.Errorf("failed to patch %s CustomResourceDefinition", version)
 }
 
-// fixCertificate fixes the dnsNames of cert-manager Certificates. The DNS names contain the dns names of the provider
-// services (including the namespace) and thus have to be modified to use the target namespace instead.
-func fixCertificate(o unstructured.Unstructured, originalNamespace, targetNamespace string) (unstructured.Unstructured, error) {
-	dnsNames, ok, err := unstructured.NestedStringSlice(o.UnstructuredContent(), "spec", "dnsNames")
-	if err != nil {
-		return o, errors.Wrapf(err, "failed to get .spec.dnsNames from Certificate %s/%s", o.GetNamespace(), o.GetName())
-	}
-	// Return if we don't find .spec.dnsNames.
-	if !ok {
-		return o, nil
-	}
-
-	// Iterate through dnsNames and adjust the namespace.
-	// The dnsNames slice usually looks like this:
-	// - $(SERVICE_NAME).$(SERVICE_NAMESPACE).svc
-	// - $(SERVICE_NAME).$(SERVICE_NAMESPACE).svc.cluster.local
-	for i, dnsName := range dnsNames {
-		dnsNames[i] = strings.Replace(dnsName, fmt.Sprintf(".%s.", originalNamespace), fmt.Sprintf(".%s.", targetNamespace), 1)
-	}
-
-	if err := unstructured.SetNestedStringSlice(o.UnstructuredContent(), dnsNames, "spec", "dnsNames"); err != nil {
-		return o, errors.Wrapf(err, "failed to set .spec.dnsNames to Certificate %s/%s", o.GetNamespace(), o.GetName())
-	}
-
-	return o, nil
-}
-
 // fixRBAC ensures all the ClusterRole and ClusterRoleBinding have the name prefixed with the namespace name and that
 // all the clusterRole/clusterRoleBinding namespaced subjects refers to targetNamespace.
 func fixRBAC(objs []unstructured.Unstructured, targetNamespace string) ([]unstructured.Unstructured, error) {
diff --git a/controllers/machine_controller.go b/controllers/machine_controller.go
index 7d8a712e4..fa7535b8f 100644
--- a/controllers/machine_controller.go
+++ b/controllers/machine_controller.go
@@ -103,10 +103,7 @@ func (r *MachineReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manag
 		&source.Kind{Type: &clusterv1.Cluster{}},
 		handler.EnqueueRequestsFromMapFunc(clusterToMachines),
 		// TODO: should this wait for Cluster.Status.InfrastructureReady similar to Infra Machine resources?
-		predicates.All(ctrl.LoggerFrom(ctx),
-			predicates.ClusterUnpaused(ctrl.LoggerFrom(ctx)),
-			predicates.ResourceHasFilterLabel(ctrl.LoggerFrom(ctx), r.WatchFilterValue),
-		),
+		predicates.ClusterUnpaused(ctrl.LoggerFrom(ctx)),
 	)
 	if err != nil {
 		return errors.Wrap(err, "failed to add Watch for Clusters to controller manager")
diff --git a/controllers/machinedeployment_controller.go b/controllers/machinedeployment_controller.go
index ff5d65dab..b6118c0dc 100644
--- a/controllers/machinedeployment_controller.go
+++ b/controllers/machinedeployment_controller.go
@@ -83,10 +83,7 @@ func (r *MachineDeploymentReconciler) SetupWithManager(ctx context.Context, mgr
 		&source.Kind{Type: &clusterv1.Cluster{}},
 		handler.EnqueueRequestsFromMapFunc(clusterToMachineDeployments),
 		// TODO: should this wait for Cluster.Status.InfrastructureReady similar to Infra Machine resources?
-		predicates.All(ctrl.LoggerFrom(ctx),
-			predicates.ClusterUnpaused(ctrl.LoggerFrom(ctx)),
-			predicates.ResourceHasFilterLabel(ctrl.LoggerFrom(ctx), r.WatchFilterValue),
-		),
+		predicates.ClusterUnpaused(ctrl.LoggerFrom(ctx)),
 	)
 	if err != nil {
 		return errors.Wrap(err, "failed to add Watch for Clusters to controller manager")
diff --git a/controllers/machinehealthcheck_controller.go b/controllers/machinehealthcheck_controller.go
index 108d5c23b..0df5e61d4 100644
--- a/controllers/machinehealthcheck_controller.go
+++ b/controllers/machinehealthcheck_controller.go
@@ -97,10 +97,7 @@ func (r *MachineHealthCheckReconciler) SetupWithManager(ctx context.Context, mgr
 		&source.Kind{Type: &clusterv1.Cluster{}},
 		handler.EnqueueRequestsFromMapFunc(r.clusterToMachineHealthCheck),
 		// TODO: should this wait for Cluster.Status.InfrastructureReady similar to Infra Machine resources?
-		predicates.All(ctrl.LoggerFrom(ctx),
-			predicates.ClusterUnpaused(ctrl.LoggerFrom(ctx)),
-			predicates.ResourceHasFilterLabel(ctrl.LoggerFrom(ctx), r.WatchFilterValue),
-		),
+		predicates.ClusterUnpaused(ctrl.LoggerFrom(ctx)),
 	)
 	if err != nil {
 		return errors.Wrap(err, "failed to add Watch for Clusters to controller manager")
diff --git a/controllers/machineset_controller.go b/controllers/machineset_controller.go
index 8920ad123..ed43c386d 100644
--- a/controllers/machineset_controller.go
+++ b/controllers/machineset_controller.go
@@ -98,10 +98,7 @@ func (r *MachineSetReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Ma
 		&source.Kind{Type: &clusterv1.Cluster{}},
 		handler.EnqueueRequestsFromMapFunc(clusterToMachineSets),
 		// TODO: should this wait for Cluster.Status.InfrastructureReady similar to Infra Machine resources?
-		predicates.All(ctrl.LoggerFrom(ctx),
-			predicates.ClusterUnpaused(ctrl.LoggerFrom(ctx)),
-			predicates.ResourceHasFilterLabel(ctrl.LoggerFrom(ctx), r.WatchFilterValue),
-		),
+		predicates.ClusterUnpaused(ctrl.LoggerFrom(ctx)),
 	)
 	if err != nil {
 		return errors.Wrap(err, "failed to add Watch for Clusters to controller manager")
diff --git a/docs/book/src/developer/providers/implementers-guide/overview.md b/docs/book/src/developer/providers/implementers-guide/overview.md
index 7a8c90cef..86b1c279c 100644
--- a/docs/book/src/developer/providers/implementers-guide/overview.md
+++ b/docs/book/src/developer/providers/implementers-guide/overview.md
@@ -33,20 +33,18 @@ brew install kustomize
 
 ```bash
 # Install kubectl
-KUBECTL_VERSION=$(curl -sfL https://dl.k8s.io/release/stable.txt)
+KUBECTL_VERSION=$(curl -sf https://dl.k8s.io/release/stable.txt)
 curl -fLO https://dl.k8s.io/release/${KUBECTL_VERSION}/bin/linux/amd64/kubectl
 
 # Install kustomize
 OS_TYPE=linux
-FILE=kustomize_*_${OS_TYPE}_amd64.tar.gz
 curl -sf https://api.github.com/repos/kubernetes-sigs/kustomize/releases/latest |\
   grep browser_download |\
   grep ${OS_TYPE} |\
   cut -d '"' -f 4 |\
   xargs curl -f -O -L
-tar zxvf $FILE; rm -f $FILE
-sudo mv kustomize /usr/local/bin/kustomize
-sudo chmod u+x /usr/local/bin/kustomize
+mv kustomize_*_${OS_TYPE}_amd64 /usr/local/bin/kustomize
+chmod u+x /usr/local/bin/kustomize
 ```
 
 {{#/tab }}
diff --git a/exp/controllers/machinepool_controller.go b/exp/controllers/machinepool_controller.go
index 5693d2257..d2061cd30 100644
--- a/exp/controllers/machinepool_controller.go
+++ b/exp/controllers/machinepool_controller.go
@@ -83,10 +83,7 @@ func (r *MachinePoolReconciler) SetupWithManager(ctx context.Context, mgr ctrl.M
 		&source.Kind{Type: &clusterv1.Cluster{}},
 		handler.EnqueueRequestsFromMapFunc(clusterToMachinePools),
 		// TODO: should this wait for Cluster.Status.InfrastructureReady similar to Infra Machine resources?
-		predicates.All(ctrl.LoggerFrom(ctx),
-			predicates.ClusterUnpaused(ctrl.LoggerFrom(ctx)),
-			predicates.ResourceHasFilterLabel(ctrl.LoggerFrom(ctx), r.WatchFilterValue),
-		),
+		predicates.ClusterUnpaused(ctrl.LoggerFrom(ctx)),
 	)
 	if err != nil {
 		return errors.Wrap(err, "failed adding Watch for Cluster to controller manager")
diff --git a/go.mod b/go.mod
index 6a83ddf22..63180ed4a 100644
--- a/go.mod
+++ b/go.mod
@@ -38,6 +38,6 @@ require (
 	k8s.io/klog/v2 v2.9.0
 	k8s.io/kubectl v0.21.4
 	k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a
-	sigs.k8s.io/controller-runtime v0.10.2
+	sigs.k8s.io/controller-runtime v0.10.1
 	sigs.k8s.io/yaml v1.2.0
 )
diff --git a/go.sum b/go.sum
index ab7aee5c6..9adc754a6 100644
--- a/go.sum
+++ b/go.sum
@@ -1125,8 +1125,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.22/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
-sigs.k8s.io/controller-runtime v0.10.2 h1:jW8qiY+yMnnPx6O9hu63tgcwaKzd1yLYui+mpvClOOc=
-sigs.k8s.io/controller-runtime v0.10.2/go.mod h1:CQp8eyUQZ/Q7PJvnIrB6/hgfTC1kBkGylwsLgOQi1WY=
+sigs.k8s.io/controller-runtime v0.10.1 h1:+eLHgY/VrJWnfg6iXUqhCUqNXgPH1NZeP9drNAAgWlg=
+sigs.k8s.io/controller-runtime v0.10.1/go.mod h1:CQp8eyUQZ/Q7PJvnIrB6/hgfTC1kBkGylwsLgOQi1WY=
 sigs.k8s.io/kustomize/api v0.8.8/go.mod h1:He1zoK0nk43Pc6NlV085xDXDXTNprtcyKZVm3swsdNY=
 sigs.k8s.io/kustomize/cmd/config v0.9.10/go.mod h1:Mrby0WnRH7hA6OwOYnYpfpiY0WJIMgYrEDfwOeFdMK0=
 sigs.k8s.io/kustomize/kustomize/v4 v4.1.2/go.mod h1:PxBvo4WGYlCLeRPL+ziT64wBXqbgfcalOS/SXa/tcyo=


Test patch:
diff --git a/cmd/clusterctl/client/repository/components_test.go b/cmd/clusterctl/client/repository/components_test.go
index 642a3d177..a051ec2be 100644
--- a/cmd/clusterctl/client/repository/components_test.go
+++ b/cmd/clusterctl/client/repository/components_test.go
@@ -523,58 +523,6 @@ func Test_fixTargetNamespace(t *testing.T) {
 				},
 			},
 		},
-		{
-			name: "fix cert-manager Certificate",
-			objs: []unstructured.Unstructured{
-				{
-					Object: map[string]interface{}{
-						"apiVersion": "cert-manager.io/v1",
-						"kind":       "Certificate",
-						"metadata": map[string]interface{}{
-							"name":      "capi-serving-cert",
-							"namespace": "capi-system",
-						},
-						"spec": map[string]interface{}{
-							"dnsNames": []interface{}{
-								"capi-webhook-service.capi-system.svc",
-								"capi-webhook-service.capi-system.svc.cluster.local",
-								"random-other-dns-name",
-							},
-							"issuerRef": map[string]interface{}{
-								"kind": "Issuer",
-								"name": "capi-selfsigned-issuer",
-							},
-							"secretName": "capi-webhook-service-cert",
-						},
-					},
-				},
-			},
-			targetNamespace: "bar",
-			want: []unstructured.Unstructured{
-				{
-					Object: map[string]interface{}{
-						"apiVersion": "cert-manager.io/v1",
-						"kind":       "Certificate",
-						"metadata": map[string]interface{}{
-							"name":      "capi-serving-cert",
-							"namespace": "bar",
-						},
-						"spec": map[string]interface{}{
-							"dnsNames": []interface{}{
-								"capi-webhook-service.bar.svc",
-								"capi-webhook-service.bar.svc.cluster.local",
-								"random-other-dns-name",
-							},
-							"issuerRef": map[string]interface{}{
-								"kind": "Issuer",
-								"name": "capi-selfsigned-issuer",
-							},
-							"secretName": "capi-webhook-service-cert",
-						},
-					},
-				},
-			},
-		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
diff --git a/test/e2e/clusterctl_upgrade.go b/test/e2e/clusterctl_upgrade.go
index ed822a25f..3d86580a8 100644
--- a/test/e2e/clusterctl_upgrade.go
+++ b/test/e2e/clusterctl_upgrade.go
@@ -53,20 +53,22 @@ const (
 
 // ClusterctlUpgradeSpecInput is the input for ClusterctlUpgradeSpec.
 type ClusterctlUpgradeSpecInput struct {
-	E2EConfig             *clusterctl.E2EConfig
-	ClusterctlConfigPath  string
-	BootstrapClusterProxy framework.ClusterProxy
-	ArtifactFolder        string
-	SkipCleanup           bool
-	PreUpgrade            func(managementClusterProxy framework.ClusterProxy)
-	PostUpgrade           func(managementClusterProxy framework.ClusterProxy)
-	MgmtFlavor            string
-	WorkloadFlavor        string
+	E2EConfig                 *clusterctl.E2EConfig
+	ClusterctlConfigPath      string
+	BootstrapClusterProxy     framework.ClusterProxy
+	ArtifactFolder            string
+	InitWithBinary            string
+	InitWithProvidersContract string
+	SkipCleanup               bool
+	PreUpgrade                func(managementClusterProxy framework.ClusterProxy)
+	PostUpgrade               func(managementClusterProxy framework.ClusterProxy)
+	MgmtFlavor                string
+	WorkloadFlavor            string
 }
 
 // ClusterctlUpgradeSpec implements a test that verifies clusterctl upgrade of a management cluster.
 //
-// NOTE: this test is designed to test v1alpha3 --> v1alpha4 upgrades.
+// NOTE: this test is designed to test older versions of Cluster API --> v1beta1 upgrades.
 func ClusterctlUpgradeSpec(ctx context.Context, inputGetter func() ClusterctlUpgradeSpecInput) {
 	var (
 		specName = "clusterctl-upgrade"
@@ -76,6 +78,7 @@ func ClusterctlUpgradeSpec(ctx context.Context, inputGetter func() ClusterctlUpg
 		testCancelWatches context.CancelFunc
 
 		managementClusterName          string
+		clusterctlBinaryURL            string
 		managementClusterNamespace     *corev1.Namespace
 		managementClusterCancelWatches context.CancelFunc
 		managementClusterResources     *clusterctl.ApplyClusterTemplateAndWaitResult
@@ -90,8 +93,16 @@ func ClusterctlUpgradeSpec(ctx context.Context, inputGetter func() ClusterctlUpg
 		Expect(input.E2EConfig).ToNot(BeNil(), "Invalid argument. input.E2EConfig can't be nil when calling %s spec", specName)
 		Expect(input.ClusterctlConfigPath).To(BeAnExistingFile(), "Invalid argument. input.ClusterctlConfigPath must be an existing file when calling %s spec", specName)
 		Expect(input.BootstrapClusterProxy).ToNot(BeNil(), "Invalid argument. input.BootstrapClusterProxy can't be nil when calling %s spec", specName)
-		Expect(input.E2EConfig.Variables).To(HaveKey(initWithBinaryVariableName), "Invalid argument. %s variable must be defined when calling %s spec", initWithBinaryVariableName, specName)
-		Expect(input.E2EConfig.Variables[initWithBinaryVariableName]).ToNot(BeEmpty(), "Invalid argument. %s variable can't be empty when calling %s spec", initWithBinaryVariableName, specName)
+		var clusterctlBinaryURLTemplate string
+		if input.InitWithBinary == "" {
+			Expect(input.E2EConfig.Variables).To(HaveKey(initWithBinaryVariableName), "Invalid argument. %s variable must be defined when calling %s spec", initWithBinaryVariableName, specName)
+			Expect(input.E2EConfig.Variables[initWithBinaryVariableName]).ToNot(BeEmpty(), "Invalid argument. %s variable can't be empty when calling %s spec", initWithBinaryVariableName, specName)
+			clusterctlBinaryURLTemplate = input.E2EConfig.GetVariable(initWithBinaryVariableName)
+		} else {
+			clusterctlBinaryURLTemplate = input.InitWithBinary
+		}
+		clusterctlBinaryURLReplacer := strings.NewReplacer("{OS}", runtime.GOOS, "{ARCH}", runtime.GOARCH)
+		clusterctlBinaryURL = clusterctlBinaryURLReplacer.Replace(clusterctlBinaryURLTemplate)
 		Expect(input.E2EConfig.Variables).To(HaveKey(initWithKubernetesVersion))
 		Expect(input.E2EConfig.Variables).To(HaveKey(KubernetesVersion))
 		Expect(os.MkdirAll(input.ArtifactFolder, 0750)).To(Succeed(), "Invalid argument. input.ArtifactFolder can't be created for %s spec", specName)
@@ -143,10 +154,7 @@ func ClusterctlUpgradeSpec(ctx context.Context, inputGetter func() ClusterctlUpg
 		// Get a ClusterProxy so we can interact with the workload cluster
 		managementClusterProxy = input.BootstrapClusterProxy.GetWorkloadCluster(ctx, cluster.Namespace, cluster.Name)
 
-		// Download the v1alpha3 clusterctl version to be used for setting up the management cluster to be upgraded
-		clusterctlBinaryURL := input.E2EConfig.GetVariable(initWithBinaryVariableName)
-		clusterctlBinaryURL = strings.ReplaceAll(clusterctlBinaryURL, "{OS}", runtime.GOOS)
-		clusterctlBinaryURL = strings.ReplaceAll(clusterctlBinaryURL, "{ARCH}", runtime.GOARCH)
+		// Download the older clusterctl version to be used for setting up the management cluster to be upgraded
 
 		log.Logf("Downloading clusterctl binary from %s", clusterctlBinaryURL)
 		clusterctlBinaryPath := downloadToTmpFile(clusterctlBinaryURL)
@@ -164,6 +172,9 @@ func ClusterctlUpgradeSpec(ctx context.Context, inputGetter func() ClusterctlUpg
 		if input.E2EConfig.HasVariable(initWithProvidersContract) {
 			contract = input.E2EConfig.GetVariable(initWithProvidersContract)
 		}
+		if input.InitWithProvidersContract != "" {
+			contract = input.InitWithProvidersContract
+		}
 
 		clusterctl.InitManagementClusterAndWatchControllerLogs(ctx, clusterctl.InitManagementClusterAndWatchControllerLogsInput{
 			ClusterctlBinaryPath:    clusterctlBinaryPath, // use older version of clusterctl to init the management cluster
diff --git a/test/go.mod b/test/go.mod
index f35f7421c..7fb7aa21c 100644
--- a/test/go.mod
+++ b/test/go.mod
@@ -24,7 +24,7 @@ require (
 	k8s.io/klog/v2 v2.9.0
 	k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a
 	sigs.k8s.io/cluster-api v0.0.0-00010101000000-000000000000
-	sigs.k8s.io/controller-runtime v0.10.2
+	sigs.k8s.io/controller-runtime v0.10.1
 	sigs.k8s.io/kind v0.11.1
 	sigs.k8s.io/yaml v1.2.0
 )
diff --git a/test/go.sum b/test/go.sum
index 41da39b4f..2f3fc3da4 100644
--- a/test/go.sum
+++ b/test/go.sum
@@ -1469,8 +1469,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.22/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
-sigs.k8s.io/controller-runtime v0.10.2 h1:jW8qiY+yMnnPx6O9hu63tgcwaKzd1yLYui+mpvClOOc=
-sigs.k8s.io/controller-runtime v0.10.2/go.mod h1:CQp8eyUQZ/Q7PJvnIrB6/hgfTC1kBkGylwsLgOQi1WY=
+sigs.k8s.io/controller-runtime v0.10.1 h1:+eLHgY/VrJWnfg6iXUqhCUqNXgPH1NZeP9drNAAgWlg=
+sigs.k8s.io/controller-runtime v0.10.1/go.mod h1:CQp8eyUQZ/Q7PJvnIrB6/hgfTC1kBkGylwsLgOQi1WY=
 sigs.k8s.io/kind v0.11.1 h1:pVzOkhUwMBrCB0Q/WllQDO3v14Y+o2V0tFgjTqIUjwA=
 sigs.k8s.io/kind v0.11.1/go.mod h1:fRpgVhtqAWrtLB9ED7zQahUimpUXuG/iHT88xYqEGIA=
 sigs.k8s.io/kustomize/api v0.8.8/go.mod h1:He1zoK0nk43Pc6NlV085xDXDXTNprtcyKZVm3swsdNY=