diff --git a/test/e2e/clusterctl_upgrade.go b/test/e2e/clusterctl_upgrade.go index 419e90b3676c..038f7085e46f 100644 --- a/test/e2e/clusterctl_upgrade.go +++ b/test/e2e/clusterctl_upgrade.go @@ -87,6 +87,13 @@ type ClusterctlUpgradeSpecInput struct { MgmtFlavor string CNIManifestPath string WorkloadFlavor string + // Custom providers can be specified to upgrade to a pre-release or a custom version instead of upgrading to the latest using contact + CoreProvider string + BootstrapProviders []string + ControlPlaneProviders []string + InfrastructureProviders []string + IPAMProviders []string + RuntimeExtensionProviders []string } // ClusterctlUpgradeSpec implements a test that verifies clusterctl upgrade of a management cluster. @@ -345,15 +352,38 @@ func ClusterctlUpgradeSpec(ctx context.Context, inputGetter func() ClusterctlUpg client.MatchingLabels{clusterv1.ClusterLabelName: workLoadClusterName}, ) Expect(err).NotTo(HaveOccurred()) - - By("Upgrading providers to the latest version available") - clusterctl.UpgradeManagementClusterAndWait(ctx, clusterctl.UpgradeManagementClusterAndWaitInput{ - ClusterctlConfigPath: input.ClusterctlConfigPath, - ClusterctlVariables: input.UpgradeClusterctlVariables, - ClusterProxy: managementClusterProxy, - Contract: clusterv1.GroupVersion.Version, - LogFolder: filepath.Join(input.ArtifactFolder, "clusters", cluster.Name), - }, input.E2EConfig.GetIntervals(specName, "wait-controllers")...) + // Check if the user want a custom upgrade + isCustomUpgrade := input.CoreProvider != "" || + len(input.BootstrapProviders) > 0 || + len(input.ControlPlaneProviders) > 0 || + len(input.InfrastructureProviders) > 0 || + len(input.IPAMProviders) > 0 || + len(input.RuntimeExtensionProviders) > 0 + + if isCustomUpgrade { + By("Upgrading providers to custom versions") + clusterctl.UpgradeManagementClusterAndWait(ctx, clusterctl.UpgradeManagementClusterAndWaitInput{ + ClusterctlConfigPath: input.ClusterctlConfigPath, + ClusterctlVariables: input.UpgradeClusterctlVariables, + ClusterProxy: managementClusterProxy, + CoreProvider: input.CoreProvider, + BootstrapProviders: input.BootstrapProviders, + ControlPlaneProviders: input.ControlPlaneProviders, + InfrastructureProviders: input.InfrastructureProviders, + IPAMProviders: input.IPAMProviders, + RuntimeExtensionProviders: input.RuntimeExtensionProviders, + LogFolder: filepath.Join(input.ArtifactFolder, "clusters", cluster.Name), + }, input.E2EConfig.GetIntervals(specName, "wait-controllers")...) + } else { + By("Upgrading providers to the latest version available") + clusterctl.UpgradeManagementClusterAndWait(ctx, clusterctl.UpgradeManagementClusterAndWaitInput{ + ClusterctlConfigPath: input.ClusterctlConfigPath, + ClusterctlVariables: input.UpgradeClusterctlVariables, + ClusterProxy: managementClusterProxy, + Contract: clusterv1.GroupVersion.Version, + LogFolder: filepath.Join(input.ArtifactFolder, "clusters", cluster.Name), + }, input.E2EConfig.GetIntervals(specName, "wait-controllers")...) + } By("THE MANAGEMENT CLUSTER WAS SUCCESSFULLY UPGRADED!") diff --git a/test/framework/clusterctl/client.go b/test/framework/clusterctl/client.go index c999035cd749..5c0e20b5f964 100644 --- a/test/framework/clusterctl/client.go +++ b/test/framework/clusterctl/client.go @@ -139,12 +139,18 @@ func InitWithBinary(_ context.Context, binary string, input InitInput) { // UpgradeInput is the input for Upgrade. type UpgradeInput struct { - LogFolder string - ClusterctlConfigPath string - ClusterctlVariables map[string]string - ClusterName string - KubeconfigPath string - Contract string + LogFolder string + ClusterctlConfigPath string + ClusterctlVariables map[string]string + ClusterName string + KubeconfigPath string + Contract string + CoreProvider string + BootstrapProviders []string + ControlPlaneProviders []string + InfrastructureProviders []string + IPAMProviders []string + RuntimeExtensionProviders []string } // Upgrade calls clusterctl upgrade apply with the list of providers defined in the local repository. @@ -159,19 +165,49 @@ func Upgrade(ctx context.Context, input UpgradeInput) { input.ClusterctlConfigPath = outputPath } - log.Logf("clusterctl upgrade apply --contract %s --config %s --kubeconfig %s", - input.Contract, - input.ClusterctlConfigPath, - input.KubeconfigPath, - ) + // Check if the user want a custom upgrade + isCustomUpgrade := input.CoreProvider != "" || + len(input.BootstrapProviders) > 0 || + len(input.ControlPlaneProviders) > 0 || + len(input.InfrastructureProviders) > 0 || + len(input.IPAMProviders) > 0 || + len(input.RuntimeExtensionProviders) > 0 + + Expect((input.Contract != "" && !isCustomUpgrade) || (input.Contract == "" && isCustomUpgrade)).To(BeTrue(), `Invalid arguments. Either the input.Contract parameter or at least one of the following providers has to be set: + input.CoreProvider, input.BootstrapProviders, input.ControlPlaneProviders, input.InfrastructureProviders, input.IPAMProviders, input.RuntimeExtensionProviders`) + + if isCustomUpgrade { + log.Logf("clusterctl upgrade apply --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, + ) + } else { + log.Logf("clusterctl upgrade apply --contract %s --config %s --kubeconfig %s", + input.Contract, + input.ClusterctlConfigPath, + input.KubeconfigPath, + ) + } upgradeOpt := clusterctlclient.ApplyUpgradeOptions{ Kubeconfig: clusterctlclient.Kubeconfig{ Path: input.KubeconfigPath, Context: "", }, - Contract: input.Contract, - WaitProviders: true, + Contract: input.Contract, + CoreProvider: input.CoreProvider, + BootstrapProviders: input.BootstrapProviders, + ControlPlaneProviders: input.ControlPlaneProviders, + InfrastructureProviders: input.InfrastructureProviders, + IPAMProviders: input.IPAMProviders, + RuntimeExtensionProviders: input.RuntimeExtensionProviders, + WaitProviders: true, } clusterctlClient, log := getClusterctlClientWithLogger(input.ClusterctlConfigPath, "clusterctl-upgrade.log", input.LogFolder) diff --git a/test/framework/clusterctl/clusterctl_helpers.go b/test/framework/clusterctl/clusterctl_helpers.go index c5efdf883900..25f1425335be 100644 --- a/test/framework/clusterctl/clusterctl_helpers.go +++ b/test/framework/clusterctl/clusterctl_helpers.go @@ -127,11 +127,17 @@ func InitManagementClusterAndWatchControllerLogs(ctx context.Context, input Init // UpgradeManagementClusterAndWaitInput is the input type for UpgradeManagementClusterAndWait. type UpgradeManagementClusterAndWaitInput struct { - ClusterProxy framework.ClusterProxy - ClusterctlConfigPath string - ClusterctlVariables map[string]string - Contract string - LogFolder string + ClusterProxy framework.ClusterProxy + ClusterctlConfigPath string + ClusterctlVariables map[string]string + Contract string + CoreProvider string + BootstrapProviders []string + ControlPlaneProviders []string + InfrastructureProviders []string + IPAMProviders []string + RuntimeExtensionProviders []string + LogFolder string } // UpgradeManagementClusterAndWait upgrades provider a management cluster using clusterctl, and waits for the cluster to be ready. @@ -139,16 +145,32 @@ func UpgradeManagementClusterAndWait(ctx context.Context, input UpgradeManagemen Expect(ctx).NotTo(BeNil(), "ctx is required for UpgradeManagementClusterAndWait") Expect(input.ClusterProxy).ToNot(BeNil(), "Invalid argument. input.ClusterProxy can't be nil when calling UpgradeManagementClusterAndWait") Expect(input.ClusterctlConfigPath).To(BeAnExistingFile(), "Invalid argument. input.ClusterctlConfigPath must be an existing file when calling UpgradeManagementClusterAndWait") - Expect(input.Contract).ToNot(BeEmpty(), "Invalid argument. input.Contract can't be empty when calling UpgradeManagementClusterAndWait") + // Check if the user want a custom upgrade + isCustomUpgrade := input.CoreProvider != "" || + len(input.BootstrapProviders) > 0 || + len(input.ControlPlaneProviders) > 0 || + len(input.InfrastructureProviders) > 0 || + len(input.IPAMProviders) > 0 || + len(input.RuntimeExtensionProviders) > 0 + + Expect((input.Contract != "" && !isCustomUpgrade) || (input.Contract == "" && isCustomUpgrade)).To(BeTrue(), `Invalid argument. Either the input.Contract parameter or at least one of the following providers has to be set: + input.CoreProvider, input.BootstrapProviders, input.ControlPlaneProviders, input.InfrastructureProviders, input.IPAMProviders, input.RuntimeExtensionProviders`) + Expect(os.MkdirAll(input.LogFolder, 0750)).To(Succeed(), "Invalid argument. input.LogFolder can't be created for UpgradeManagementClusterAndWait") Upgrade(ctx, UpgradeInput{ - ClusterctlConfigPath: input.ClusterctlConfigPath, - ClusterctlVariables: input.ClusterctlVariables, - ClusterName: input.ClusterProxy.GetName(), - KubeconfigPath: input.ClusterProxy.GetKubeconfigPath(), - Contract: input.Contract, - LogFolder: input.LogFolder, + ClusterctlConfigPath: input.ClusterctlConfigPath, + ClusterctlVariables: input.ClusterctlVariables, + ClusterName: input.ClusterProxy.GetName(), + KubeconfigPath: input.ClusterProxy.GetKubeconfigPath(), + Contract: input.Contract, + CoreProvider: input.CoreProvider, + BootstrapProviders: input.BootstrapProviders, + ControlPlaneProviders: input.ControlPlaneProviders, + InfrastructureProviders: input.InfrastructureProviders, + IPAMProviders: input.IPAMProviders, + RuntimeExtensionProviders: input.RuntimeExtensionProviders, + LogFolder: input.LogFolder, }) client := input.ClusterProxy.GetClient()