diff --git a/test/e2e/cluster_upgrade_runtimesdk_test.go b/test/e2e/cluster_upgrade_runtimesdk_test.go index e87247dac609..f5d3a18f6c75 100644 --- a/test/e2e/cluster_upgrade_runtimesdk_test.go +++ b/test/e2e/cluster_upgrade_runtimesdk_test.go @@ -82,7 +82,7 @@ var _ = Describe("When upgrading a workload cluster using ClusterClass in a diff framework.ValidateResourceVersionStable(ctx, proxy, namespace, clusterctlcluster.FilterClusterObjectsWithNameFilter(clusterName)) }, // "upgrades" is the same as the "topology" flavor but with an additional MachinePool. - Flavor: ptr.To("cross-ns-upgrades-runtimesdk"), + Flavor: ptr.To("upgrades-runtimesdk"), ClassNamespace: true, // The runtime extension gets deployed to the test-extension-system namespace and is exposed // by the test-extension-webhook-service. diff --git a/test/e2e/cross-ns-quick-start.go b/test/e2e/cross-ns-quick-start.go deleted file mode 100644 index ccd450aada24..000000000000 --- a/test/e2e/cross-ns-quick-start.go +++ /dev/null @@ -1,138 +0,0 @@ -/* -Copyright 2020 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package e2e - -import ( - "context" - "fmt" - "os" - "path/filepath" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - corev1 "k8s.io/api/core/v1" - "k8s.io/utils/ptr" - - "sigs.k8s.io/cluster-api/test/framework" - "sigs.k8s.io/cluster-api/test/framework/clusterctl" - "sigs.k8s.io/cluster-api/util" -) - -// CrossNsSpecInput is the input for QuickStartSpec in separate namespaces. -type CrossNsSpecInput struct { - QuickStartSpecInput -} - -// CrossNsSpecQuickstart implements a spec that mimics the operation described in the Cluster API quick start, that is -// creating a workload cluster, but uses a cross-namespaced cluster class reference. -// This test is meant to provide a first, fast signal to detect regression; it is recommended to use it as a PR blocker test. -// NOTE: This test works with Clusters with and without ClusterClass. -func CrossNsSpecQuickstart(ctx context.Context, inputGetter func() CrossNsSpecInput) { - var ( - specName = "quick-start" - input CrossNsSpecInput - namespace *corev1.Namespace - clusterNamespace *corev1.Namespace - cancelWatches context.CancelFunc - cancelWatchesCluster context.CancelFunc - clusterResources *clusterctl.ApplyClusterTemplateAndWaitResult - ) - - BeforeEach(func() { - Expect(ctx).NotTo(BeNil(), "ctx is required for %s spec", specName) - input = inputGetter() - Expect(input.E2EConfig).ToNot(BeNil(), "Invalid argument. input.E2EConfig can't be nil when calling %s spec", specName) - Expect(input.ClusterctlConfigPath).To(BeAnExistingFile(), "Invalid argument. input.ClusterctlConfigPath must be an existing file when calling %s spec", specName) - Expect(input.BootstrapClusterProxy).ToNot(BeNil(), "Invalid argument. input.BootstrapClusterProxy can't be nil when calling %s spec", specName) - Expect(os.MkdirAll(input.ArtifactFolder, 0750)).To(Succeed(), "Invalid argument. input.ArtifactFolder can't be created for %s spec", specName) - - Expect(input.E2EConfig.Variables).To(HaveKey(KubernetesVersion)) - - // Setup a Namespace where to host objects for this spec and create a watcher for the namespace events. - namespace, cancelWatches = framework.SetupSpecNamespace(ctx, specName, input.BootstrapClusterProxy, input.ArtifactFolder, input.PostNamespaceCreated) - clusterNamespace, cancelWatchesCluster = framework.SetupSpecNamespace(ctx, specName, input.BootstrapClusterProxy, input.ArtifactFolder, input.PostNamespaceCreated) - clusterResources = new(clusterctl.ApplyClusterTemplateAndWaitResult) - }) - - It("Should create a workload cluster in a separate namespace", func() { - infrastructureProvider := clusterctl.DefaultInfrastructureProvider - if input.InfrastructureProvider != nil { - infrastructureProvider = *input.InfrastructureProvider - } - - flavor := clusterctl.DefaultFlavor - if input.Flavor != nil { - flavor = *input.Flavor - } - - controlPlaneMachineCount := ptr.To[int64](1) - if input.ControlPlaneMachineCount != nil { - controlPlaneMachineCount = input.ControlPlaneMachineCount - } - - workerMachineCount := ptr.To[int64](1) - if input.WorkerMachineCount != nil { - workerMachineCount = input.WorkerMachineCount - } - - clusterName := fmt.Sprintf("%s-%s", specName, util.RandomString(6)) - if input.ClusterName != nil { - clusterName = *input.ClusterName - } - - By("Creating a cluster referencing a clusterClass from another namespace") - clusterctl.ApplyClusterTemplateAndWait(ctx, clusterctl.ApplyClusterTemplateAndWaitInput{ - ClusterProxy: input.BootstrapClusterProxy, - ConfigCluster: clusterctl.ConfigClusterInput{ - LogFolder: filepath.Join(input.ArtifactFolder, "clusters", input.BootstrapClusterProxy.GetName()), - ClusterctlConfigPath: input.ClusterctlConfigPath, - ClusterctlVariables: map[string]string{ - "CLUSTER_CLASS_NAMESPACE": namespace.Name, - }, - KubeconfigPath: input.BootstrapClusterProxy.GetKubeconfigPath(), - InfrastructureProvider: infrastructureProvider, - Flavor: flavor, - Namespace: clusterNamespace.Name, - ClusterName: clusterName, - KubernetesVersion: input.E2EConfig.GetVariable(KubernetesVersion), - ControlPlaneMachineCount: controlPlaneMachineCount, - WorkerMachineCount: workerMachineCount, - }, - ControlPlaneWaiters: input.ControlPlaneWaiters, - WaitForClusterIntervals: input.E2EConfig.GetIntervals(specName, "wait-cluster"), - WaitForControlPlaneIntervals: input.E2EConfig.GetIntervals(specName, "wait-control-plane"), - WaitForMachineDeployments: input.E2EConfig.GetIntervals(specName, "wait-worker-nodes"), - PostMachinesProvisioned: func() { - if input.PostMachinesProvisioned != nil { - input.PostMachinesProvisioned(input.BootstrapClusterProxy, clusterNamespace.Name, clusterName) - } - }, - }, clusterResources) - - By("PASSED!") - }) - - AfterEach(func() { - // Dumps all the resources in the spec namespace, then cleanups the cluster object and the spec namespace itself. - framework.DumpSpecResourcesAndCleanup(ctx, specName, input.BootstrapClusterProxy, input.ArtifactFolder, clusterNamespace, cancelWatchesCluster, clusterResources.Cluster, input.E2EConfig.GetIntervals, input.SkipCleanup) - framework.DeleteNamespace(ctx, framework.DeleteNamespaceInput{ - Deleter: input.BootstrapClusterProxy.GetClient(), - Name: namespace.Name, - }) - cancelWatches() - }) -} diff --git a/test/e2e/data/infrastructure-docker/main/bases/cluster-with-topology.yaml b/test/e2e/data/infrastructure-docker/main/bases/cluster-with-topology.yaml index 1fa907f3aab9..7fad4285fec6 100644 --- a/test/e2e/data/infrastructure-docker/main/bases/cluster-with-topology.yaml +++ b/test/e2e/data/infrastructure-docker/main/bases/cluster-with-topology.yaml @@ -14,6 +14,7 @@ spec: serviceDomain: '${DOCKER_SERVICE_DOMAIN}' topology: class: "quick-start" + classNamespace: '${CLUSTER_CLASS_NAMESPACE}' version: "${KUBERNETES_VERSION}" controlPlane: metadata: diff --git a/test/e2e/data/infrastructure-docker/main/cluster-template-upgrades-runtimesdk/cluster-runtimesdk.yaml b/test/e2e/data/infrastructure-docker/main/cluster-template-upgrades-runtimesdk/cluster-runtimesdk.yaml index 004350219aa6..dfe56eadd4d0 100644 --- a/test/e2e/data/infrastructure-docker/main/cluster-template-upgrades-runtimesdk/cluster-runtimesdk.yaml +++ b/test/e2e/data/infrastructure-docker/main/cluster-template-upgrades-runtimesdk/cluster-runtimesdk.yaml @@ -14,6 +14,7 @@ spec: serviceDomain: '${DOCKER_SERVICE_DOMAIN}' topology: class: "quick-start-runtimesdk" + classNamespace: '${CLUSTER_CLASS_NAMESPACE}' version: "${KUBERNETES_VERSION}" controlPlane: metadata: {} diff --git a/test/e2e/quick_start.go b/test/e2e/quick_start.go index 14d17c5d80ce..4998060608e1 100644 --- a/test/e2e/quick_start.go +++ b/test/e2e/quick_start.go @@ -44,6 +44,9 @@ type QuickStartSpecInput struct { // If not set, a random one will be generated. ClusterName *string + // ClassNamespace is an optional class namespace reference, configuring cross-namespace cluster class reference + ClassNamespace *string + // InfrastructureProvider allows to specify the infrastructure provider to be used when looking for // cluster templates. // If not set, clusterctl will look at the infrastructure provider installed in the management cluster; @@ -81,11 +84,12 @@ type QuickStartSpecInput struct { // NOTE: This test works with Clusters with and without ClusterClass. func QuickStartSpec(ctx context.Context, inputGetter func() QuickStartSpecInput) { var ( - specName = "quick-start" - input QuickStartSpecInput - namespace *corev1.Namespace - cancelWatches context.CancelFunc - clusterResources *clusterctl.ApplyClusterTemplateAndWaitResult + specName = "quick-start" + input QuickStartSpecInput + namespace *corev1.Namespace + clusterClassNamespace *corev1.Namespace + cancelWatches context.CancelFunc + clusterResources *clusterctl.ApplyClusterTemplateAndWaitResult ) BeforeEach(func() { @@ -100,6 +104,12 @@ func QuickStartSpec(ctx context.Context, inputGetter func() QuickStartSpecInput) // Setup a Namespace where to host objects for this spec and create a watcher for the namespace events. namespace, cancelWatches = framework.SetupSpecNamespace(ctx, specName, input.BootstrapClusterProxy, input.ArtifactFolder, input.PostNamespaceCreated) + + if input.ClassNamespace != nil { + clusterClassNamespace = framework.CreateNamespace(ctx, framework.CreateNamespaceInput{Creator: input.BootstrapClusterProxy.GetClient(), Name: *input.ClassNamespace}, "40s", "10s") + Expect(clusterClassNamespace).ToNot(BeNil(), "Failed to create namespace %q", *input.ClassNamespace) + } + clusterResources = new(clusterctl.ApplyClusterTemplateAndWaitResult) }) @@ -130,11 +140,19 @@ func QuickStartSpec(ctx context.Context, inputGetter func() QuickStartSpecInput) if input.ClusterName != nil { clusterName = *input.ClusterName } + + variables := map[string]string{} + if input.ClassNamespace != nil { + variables["CLUSTER_CLASS_NAMESPACE"] = *input.ClassNamespace + } + + By("Creating a cluster referencing a clusterClass from another namespace") clusterctl.ApplyClusterTemplateAndWait(ctx, clusterctl.ApplyClusterTemplateAndWaitInput{ ClusterProxy: input.BootstrapClusterProxy, ConfigCluster: clusterctl.ConfigClusterInput{ LogFolder: filepath.Join(input.ArtifactFolder, "clusters", input.BootstrapClusterProxy.GetName()), ClusterctlConfigPath: input.ClusterctlConfigPath, + ClusterctlVariables: variables, KubeconfigPath: input.BootstrapClusterProxy.GetKubeconfigPath(), InfrastructureProvider: infrastructureProvider, Flavor: flavor, @@ -154,11 +172,18 @@ func QuickStartSpec(ctx context.Context, inputGetter func() QuickStartSpecInput) } }, }, clusterResources) + By("PASSED!") }) AfterEach(func() { // Dumps all the resources in the spec namespace, then cleanups the cluster object and the spec namespace itself. framework.DumpSpecResourcesAndCleanup(ctx, specName, input.BootstrapClusterProxy, input.ArtifactFolder, namespace, cancelWatches, clusterResources.Cluster, input.E2EConfig.GetIntervals, input.SkipCleanup) + if input.ClassNamespace != nil { + framework.DeleteNamespace(ctx, framework.DeleteNamespaceInput{ + Deleter: input.BootstrapClusterProxy.GetClient(), + Name: clusterClassNamespace.Name, + }) + } }) } diff --git a/test/e2e/quick_start_test.go b/test/e2e/quick_start_test.go index 9d859929a85a..fb6f77ce0d35 100644 --- a/test/e2e/quick_start_test.go +++ b/test/e2e/quick_start_test.go @@ -20,6 +20,8 @@ limitations under the License. package e2e import ( + "fmt" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "k8s.io/utils/ptr" @@ -27,6 +29,7 @@ import ( clusterctlcluster "sigs.k8s.io/cluster-api/cmd/clusterctl/client/cluster" "sigs.k8s.io/cluster-api/test/framework" "sigs.k8s.io/cluster-api/test/framework/kubetest" + "sigs.k8s.io/cluster-api/util" ) var _ = Describe("When following the Cluster API quick-start", func() { @@ -125,17 +128,16 @@ var _ = Describe("When following the Cluster API quick-start with ClusterClass [ }) var _ = Describe("When following the Cluster API quick-start with a cross-ns referenced ClusterClass [PR-Blocking] [ClusterClass]", func() { - CrossNsSpecQuickstart(ctx, func() CrossNsSpecInput { - return CrossNsSpecInput{ - QuickStartSpecInput: QuickStartSpecInput{ - E2EConfig: e2eConfig, - ClusterctlConfigPath: clusterctlConfigPath, - BootstrapClusterProxy: bootstrapClusterProxy, - ArtifactFolder: artifactFolder, - SkipCleanup: skipCleanup, - Flavor: ptr.To("cross-ns-topology"), - InfrastructureProvider: ptr.To("docker"), - }, + QuickStartSpec(ctx, func() QuickStartSpecInput { + return QuickStartSpecInput{ + E2EConfig: e2eConfig, + ClusterctlConfigPath: clusterctlConfigPath, + BootstrapClusterProxy: bootstrapClusterProxy, + ArtifactFolder: artifactFolder, + SkipCleanup: skipCleanup, + Flavor: ptr.To("topology"), + InfrastructureProvider: ptr.To("docker"), + ClassNamespace: ptr.To(fmt.Sprintf("quick-start-%s", util.RandomString(6))), } }) }) diff --git a/test/framework/clusterctl/clusterctl_helpers.go b/test/framework/clusterctl/clusterctl_helpers.go index 130bb717767a..370429a79b89 100644 --- a/test/framework/clusterctl/clusterctl_helpers.go +++ b/test/framework/clusterctl/clusterctl_helpers.go @@ -433,7 +433,7 @@ func ApplyCustomClusterTemplateAndWait(ctx context.Context, input ApplyCustomClu if result.Cluster.Spec.Topology != nil { result.ClusterClass = framework.GetClusterClassByName(ctx, framework.GetClusterClassByNameInput{ Getter: input.ClusterProxy.GetClient(), - Namespace: result.Cluster.GetInfrastructureNamespace(), + Namespace: result.Cluster.GetClassKey().Namespace, Name: result.Cluster.Spec.Topology.Class, }) }