@@ -27,8 +27,11 @@ import (
2727 . "github.com/onsi/ginkgo/v2"
2828 . "github.com/onsi/gomega"
2929 corev1 "k8s.io/api/core/v1"
30+ "k8s.io/apimachinery/pkg/api/errors"
31+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3032 "k8s.io/utils/ptr"
3133
34+ "sigs.k8s.io/cluster-api/test/e2e/internal/log"
3235 "sigs.k8s.io/cluster-api/test/framework"
3336 "sigs.k8s.io/cluster-api/test/framework/clusterctl"
3437 "sigs.k8s.io/cluster-api/util"
@@ -111,156 +114,183 @@ func QuickStartSpec(ctx context.Context, inputGetter func() QuickStartSpecInput)
111114 clusterResources * clusterctl.ApplyClusterTemplateAndWaitResult
112115 )
113116
114- BeforeEach (func () {
115- Expect (ctx ).NotTo (BeNil (), "ctx is required for %s spec" , specName )
116- input = inputGetter ()
117- Expect (input .E2EConfig ).ToNot (BeNil (), "Invalid argument. input.E2EConfig can't be nil when calling %s spec" , specName )
118- Expect (input .ClusterctlConfigPath ).To (BeAnExistingFile (), "Invalid argument. input.ClusterctlConfigPath must be an existing file when calling %s spec" , specName )
119- Expect (input .BootstrapClusterProxy ).ToNot (BeNil (), "Invalid argument. input.BootstrapClusterProxy can't be nil when calling %s spec" , specName )
120- Expect (os .MkdirAll (input .ArtifactFolder , 0750 )).To (Succeed (), "Invalid argument. input.ArtifactFolder can't be created for %s spec" , specName )
117+ for i := 0 ; i < 15 ; i ++ {
121118
122- Expect (input .E2EConfig .Variables ).To (HaveKey (KubernetesVersion ))
119+ BeforeEach (func () {
120+ Expect (ctx ).NotTo (BeNil (), "ctx is required for %s spec" , specName )
121+ input = inputGetter ()
122+ Expect (input .E2EConfig ).ToNot (BeNil (), "Invalid argument. input.E2EConfig can't be nil when calling %s spec" , specName )
123+ Expect (input .ClusterctlConfigPath ).To (BeAnExistingFile (), "Invalid argument. input.ClusterctlConfigPath must be an existing file when calling %s spec" , specName )
124+ Expect (input .BootstrapClusterProxy ).ToNot (BeNil (), "Invalid argument. input.BootstrapClusterProxy can't be nil when calling %s spec" , specName )
125+ Expect (os .MkdirAll (input .ArtifactFolder , 0750 )).To (Succeed (), "Invalid argument. input.ArtifactFolder can't be created for %s spec" , specName )
123126
124- if input .ExtensionServiceNamespace != "" && input .ExtensionServiceName != "" {
125- if input .ExtensionConfigName == "" {
126- input .ExtensionConfigName = specName
127+ Expect (input .E2EConfig .Variables ).To (HaveKey (KubernetesVersion ))
128+
129+ if input .ExtensionServiceNamespace != "" && input .ExtensionServiceName != "" {
130+ if input .ExtensionConfigName == "" {
131+ input .ExtensionConfigName = specName
132+ }
127133 }
128- }
129134
130- // Setup a Namespace where to host objects for this spec and create a watcher for the namespace events.
131- namespace , cancelWatches = framework .SetupSpecNamespace (ctx , specName , input .BootstrapClusterProxy , input .ArtifactFolder , input .PostNamespaceCreated )
135+ // Setup a Namespace where to host objects for this spec and create a watcher for the namespace events.
136+ namespace , cancelWatches = framework .SetupSpecNamespace (ctx , specName , input .BootstrapClusterProxy , input .ArtifactFolder , input .PostNamespaceCreated )
132137
133- if input .DeployClusterClassInSeparateNamespace {
134- clusterClassNamespace = framework .CreateNamespace (ctx , framework.CreateNamespaceInput {Creator : input .BootstrapClusterProxy .GetClient (), Name : fmt .Sprintf ("%s-clusterclass" , namespace .Name )}, "40s" , "10s" )
135- Expect (clusterClassNamespace ).ToNot (BeNil (), "Failed to create namespace" )
136- }
138+ if input .DeployClusterClassInSeparateNamespace {
139+ clusterClassNamespace = framework .CreateNamespace (ctx , framework.CreateNamespaceInput {Creator : input .BootstrapClusterProxy .GetClient (), Name : fmt .Sprintf ("%s-clusterclass" , namespace .Name )}, "40s" , "10s" )
140+ Expect (clusterClassNamespace ).ToNot (BeNil (), "Failed to create namespace" )
141+ }
137142
138- clusterResources = new (clusterctl.ApplyClusterTemplateAndWaitResult )
139- })
143+ clusterResources = new (clusterctl.ApplyClusterTemplateAndWaitResult )
144+ })
140145
141- It ("Should create a workload cluster" , func () {
142- By ("Creating a workload cluster" )
146+ It ("Should create a workload cluster" , func () {
147+ By ("Creating a workload cluster" )
143148
144- infrastructureProvider := clusterctl .DefaultInfrastructureProvider
145- if input .InfrastructureProvider != nil {
146- infrastructureProvider = * input .InfrastructureProvider
147- }
149+ infrastructureProvider := clusterctl .DefaultInfrastructureProvider
150+ if input .InfrastructureProvider != nil {
151+ infrastructureProvider = * input .InfrastructureProvider
152+ }
148153
149- flavor := clusterctl .DefaultFlavor
150- if input .Flavor != nil {
151- flavor = * input .Flavor
152- }
154+ flavor := clusterctl .DefaultFlavor
155+ if input .Flavor != nil {
156+ flavor = * input .Flavor
157+ }
153158
154- controlPlaneMachineCount := ptr.To [int64 ](1 )
155- if input .ControlPlaneMachineCount != nil {
156- controlPlaneMachineCount = input .ControlPlaneMachineCount
157- }
159+ controlPlaneMachineCount := ptr.To [int64 ](1 )
160+ if input .ControlPlaneMachineCount != nil {
161+ controlPlaneMachineCount = input .ControlPlaneMachineCount
162+ }
158163
159- workerMachineCount := ptr.To [int64 ](1 )
160- if input .WorkerMachineCount != nil {
161- workerMachineCount = input .WorkerMachineCount
162- }
164+ workerMachineCount := ptr.To [int64 ](1 )
165+ if input .WorkerMachineCount != nil {
166+ workerMachineCount = input .WorkerMachineCount
167+ }
163168
164- clusterName := fmt .Sprintf ("%s-%s" , specName , util .RandomString (6 ))
165- if input .ClusterName != nil {
166- clusterName = * input .ClusterName
167- }
169+ clusterName := fmt .Sprintf ("%s-%s" , specName , util .RandomString (6 ))
170+ if input .ClusterName != nil {
171+ clusterName = * input .ClusterName
172+ }
173+
174+ if input .ExtensionServiceNamespace != "" && input .ExtensionServiceName != "" {
175+ // NOTE: test extension is already deployed in the management cluster. If for any reason in future we want
176+ // to make this test more self-contained this test should be modified in order to create an additional
177+ // management cluster; also the E2E test configuration should be modified introducing something like
178+ // optional:true allowing to define which providers should not be installed by default in
179+ // a management cluster.
180+ By ("Deploy Test Extension ExtensionConfig" )
181+
182+ // In this test we are defaulting all handlers to non-blocking because we don't expect the handlers to block the
183+ // cluster lifecycle by default. Setting defaultAllHandlersToBlocking to false enforces that the test-extension
184+ // automatically creates the ConfigMap with non-blocking preloaded responses.
185+ defaultAllHandlersToBlocking := false
186+ // select on the current namespace
187+ // This is necessary so in CI this test doesn't influence other tests by enabling lifecycle hooks
188+ // in other test namespaces.
189+ namespaces := []string {namespace .Name }
190+ if input .DeployClusterClassInSeparateNamespace {
191+ // Add the ClusterClass namespace, if the ClusterClass is deployed in a separate namespace.
192+ namespaces = append (namespaces , clusterClassNamespace .Name )
193+ }
194+ extensionConfig := extensionConfig (input .ExtensionConfigName , input .ExtensionServiceNamespace , input .ExtensionServiceName , defaultAllHandlersToBlocking , namespaces ... )
195+ Expect (input .BootstrapClusterProxy .GetClient ().Create (ctx ,
196+ extensionConfig )).
197+ To (Succeed (), "Failed to create the ExtensionConfig" )
198+ }
199+
200+ variables := map [string ]string {
201+ // This is used to template the name of the ExtensionConfig into the ClusterClass.
202+ "EXTENSION_CONFIG_NAME" : input .ExtensionConfigName ,
203+ }
204+ maps .Copy (variables , input .ClusterctlVariables )
168205
169- if input .ExtensionServiceNamespace != "" && input .ExtensionServiceName != "" {
170- // NOTE: test extension is already deployed in the management cluster. If for any reason in future we want
171- // to make this test more self-contained this test should be modified in order to create an additional
172- // management cluster; also the E2E test configuration should be modified introducing something like
173- // optional:true allowing to define which providers should not be installed by default in
174- // a management cluster.
175- By ("Deploy Test Extension ExtensionConfig" )
176-
177- // In this test we are defaulting all handlers to non-blocking because we don't expect the handlers to block the
178- // cluster lifecycle by default. Setting defaultAllHandlersToBlocking to false enforces that the test-extension
179- // automatically creates the ConfigMap with non-blocking preloaded responses.
180- defaultAllHandlersToBlocking := false
181- // select on the current namespace
182- // This is necessary so in CI this test doesn't influence other tests by enabling lifecycle hooks
183- // in other test namespaces.
184- namespaces := []string {namespace .Name }
185206 if input .DeployClusterClassInSeparateNamespace {
186- // Add the ClusterClass namespace, if the ClusterClass is deployed in a separate namespace.
187- namespaces = append ( namespaces , clusterClassNamespace . Name )
207+ variables [ "CLUSTER_CLASS_NAMESPACE" ] = clusterClassNamespace . Name
208+ By ( "Creating a cluster referencing a ClusterClass from another namespace" )
188209 }
189- extensionConfig := extensionConfig (input .ExtensionConfigName , input .ExtensionServiceNamespace , input .ExtensionServiceName , defaultAllHandlersToBlocking , namespaces ... )
190- Expect (input .BootstrapClusterProxy .GetClient ().Create (ctx ,
191- extensionConfig )).
192- To (Succeed (), "Failed to create the ExtensionConfig" )
193- }
194210
195- variables := map [string ]string {
196- // This is used to template the name of the ExtensionConfig into the ClusterClass.
197- "EXTENSION_CONFIG_NAME" : input .ExtensionConfigName ,
198- }
199- maps .Copy (variables , input .ClusterctlVariables )
211+ clusterctl .ApplyClusterTemplateAndWait (ctx , clusterctl.ApplyClusterTemplateAndWaitInput {
212+ ClusterProxy : input .BootstrapClusterProxy ,
213+ ConfigCluster : clusterctl.ConfigClusterInput {
214+ LogFolder : filepath .Join (input .ArtifactFolder , "clusters" , input .BootstrapClusterProxy .GetName ()),
215+ ClusterctlConfigPath : input .ClusterctlConfigPath ,
216+ ClusterctlVariables : variables ,
217+ KubeconfigPath : input .BootstrapClusterProxy .GetKubeconfigPath (),
218+ InfrastructureProvider : infrastructureProvider ,
219+ Flavor : flavor ,
220+ Namespace : namespace .Name ,
221+ ClusterName : clusterName ,
222+ KubernetesVersion : input .E2EConfig .MustGetVariable (KubernetesVersion ),
223+ ControlPlaneMachineCount : controlPlaneMachineCount ,
224+ WorkerMachineCount : workerMachineCount ,
225+ },
226+ ControlPlaneWaiters : input .ControlPlaneWaiters ,
227+ WaitForClusterIntervals : input .E2EConfig .GetIntervals (specName , "wait-cluster" ),
228+ WaitForControlPlaneIntervals : input .E2EConfig .GetIntervals (specName , "wait-control-plane" ),
229+ WaitForMachineDeployments : input .E2EConfig .GetIntervals (specName , "wait-worker-nodes" ),
230+ PostMachinesProvisioned : func () {
231+ if input .PostMachinesProvisioned != nil {
232+ input .PostMachinesProvisioned (input .BootstrapClusterProxy , namespace .Name , clusterName )
233+ }
234+ },
235+ }, clusterResources )
236+
237+ Byf ("Verify Cluster Available condition is true" )
238+ framework .VerifyClusterAvailable (ctx , framework.VerifyClusterAvailableInput {
239+ Getter : input .BootstrapClusterProxy .GetClient (),
240+ Name : clusterResources .Cluster .Name ,
241+ Namespace : clusterResources .Cluster .Namespace ,
242+ })
243+
244+ Byf ("Verify Machines Ready condition is true" )
245+ framework .VerifyMachinesReady (ctx , framework.VerifyMachinesReadyInput {
246+ Lister : input .BootstrapClusterProxy .GetClient (),
247+ Name : clusterResources .Cluster .Name ,
248+ Namespace : clusterResources .Cluster .Namespace ,
249+ })
250+
251+ By ("PASSED!" )
200252
201- if input .DeployClusterClassInSeparateNamespace {
202- variables ["CLUSTER_CLASS_NAMESPACE" ] = clusterClassNamespace .Name
203- By ("Creating a cluster referencing a ClusterClass from another namespace" )
204- }
253+ })
205254
206- clusterctl .ApplyClusterTemplateAndWait (ctx , clusterctl.ApplyClusterTemplateAndWaitInput {
207- ClusterProxy : input .BootstrapClusterProxy ,
208- ConfigCluster : clusterctl.ConfigClusterInput {
209- LogFolder : filepath .Join (input .ArtifactFolder , "clusters" , input .BootstrapClusterProxy .GetName ()),
210- ClusterctlConfigPath : input .ClusterctlConfigPath ,
211- ClusterctlVariables : variables ,
212- KubeconfigPath : input .BootstrapClusterProxy .GetKubeconfigPath (),
213- InfrastructureProvider : infrastructureProvider ,
214- Flavor : flavor ,
215- Namespace : namespace .Name ,
216- ClusterName : clusterName ,
217- KubernetesVersion : input .E2EConfig .MustGetVariable (KubernetesVersion ),
218- ControlPlaneMachineCount : controlPlaneMachineCount ,
219- WorkerMachineCount : workerMachineCount ,
220- },
221- ControlPlaneWaiters : input .ControlPlaneWaiters ,
222- WaitForClusterIntervals : input .E2EConfig .GetIntervals (specName , "wait-cluster" ),
223- WaitForControlPlaneIntervals : input .E2EConfig .GetIntervals (specName , "wait-control-plane" ),
224- WaitForMachineDeployments : input .E2EConfig .GetIntervals (specName , "wait-worker-nodes" ),
225- PostMachinesProvisioned : func () {
226- if input .PostMachinesProvisioned != nil {
227- input .PostMachinesProvisioned (input .BootstrapClusterProxy , namespace .Name , clusterName )
255+ AfterEach (func () {
256+ // Dumps all the resources in the spec namespace, then cleanups the cluster object and the spec namespace itself.
257+ framework .DumpSpecResourcesAndCleanup (ctx , specName , input .BootstrapClusterProxy , input .ClusterctlConfigPath , input .ArtifactFolder , namespace , cancelWatches , clusterResources .Cluster , input .E2EConfig .GetIntervals , input .SkipCleanup )
258+ if ! input .SkipCleanup {
259+ if input .ExtensionServiceNamespace != "" && input .ExtensionServiceName != "" {
260+ Eventually (func () error {
261+ return input .BootstrapClusterProxy .GetClient ().Delete (ctx , extensionConfig (input .ExtensionConfigName , input .ExtensionServiceNamespace , input .ExtensionServiceName , true ))
262+ }, 10 * time .Second , 1 * time .Second ).Should (Succeed (), "Deleting ExtensionConfig failed" )
263+ }
264+ if input .DeployClusterClassInSeparateNamespace {
265+ DeleteNamespace11 (ctx , framework.DeleteNamespaceInput {
266+ Deleter : input .BootstrapClusterProxy .GetClient (),
267+ Name : clusterClassNamespace .Name ,
268+ })
228269 }
229- },
230- }, clusterResources )
231-
232- Byf ("Verify Cluster Available condition is true" )
233- framework .VerifyClusterAvailable (ctx , framework.VerifyClusterAvailableInput {
234- Getter : input .BootstrapClusterProxy .GetClient (),
235- Name : clusterResources .Cluster .Name ,
236- Namespace : clusterResources .Cluster .Namespace ,
270+ }
237271 })
238272
239- Byf ("Verify Machines Ready condition is true" )
240- framework .VerifyMachinesReady (ctx , framework.VerifyMachinesReadyInput {
241- Lister : input .BootstrapClusterProxy .GetClient (),
242- Name : clusterResources .Cluster .Name ,
243- Namespace : clusterResources .Cluster .Namespace ,
244- })
273+ }
274+ }
245275
246- By ("PASSED!" )
247- })
276+ // DeleteNamespace is used to delete namespace object.
277+ func DeleteNamespace11 (ctx context.Context , input framework.DeleteNamespaceInput , intervals ... interface {}) {
278+ Expect (ctx ).NotTo (BeNil (), "ctx is required for DeleteNamespace" )
279+ Expect (input .Deleter ).NotTo (BeNil (), "input.Deleter is required for DeleteNamespace" )
280+ Expect (input .Name ).NotTo (BeEmpty (), "input.Name is required for DeleteNamespace" )
281+ ns := & corev1.Namespace {
282+ ObjectMeta : metav1.ObjectMeta {
283+ Name : input .Name ,
284+ },
285+ }
286+ log .Logf ("Deleting namespace %s" , input .Name )
287+ Eventually (func () error {
288+ err := input .Deleter .Delete (ctx , ns )
289+ if err != nil && ! errors .IsNotFound (err ) {
290+
291+ return err
248292
249- AfterEach (func () {
250- // Dumps all the resources in the spec namespace, then cleanups the cluster object and the spec namespace itself.
251- framework .DumpSpecResourcesAndCleanup (ctx , specName , input .BootstrapClusterProxy , input .ClusterctlConfigPath , input .ArtifactFolder , namespace , cancelWatches , clusterResources .Cluster , input .E2EConfig .GetIntervals , input .SkipCleanup )
252- if ! input .SkipCleanup {
253- if input .ExtensionServiceNamespace != "" && input .ExtensionServiceName != "" {
254- Eventually (func () error {
255- return input .BootstrapClusterProxy .GetClient ().Delete (ctx , extensionConfig (input .ExtensionConfigName , input .ExtensionServiceNamespace , input .ExtensionServiceName , true ))
256- }, 10 * time .Second , 1 * time .Second ).Should (Succeed (), "Deleting ExtensionConfig failed" )
257- }
258- if input .DeployClusterClassInSeparateNamespace {
259- framework .DeleteNamespace (ctx , framework.DeleteNamespaceInput {
260- Deleter : input .BootstrapClusterProxy .GetClient (),
261- Name : clusterClassNamespace .Name ,
262- })
263- }
264293 }
265- })
294+ return nil
295+ }, intervals ... ).Should (Succeed (), "Failed to delete namespace %s" , input .Name )
266296}
0 commit comments