From 3af88fa05a62e3f658f1aee2031a0c451f04ac48 Mon Sep 17 00:00:00 2001 From: willie-yao Date: Wed, 24 Jan 2024 21:32:09 +0000 Subject: [PATCH 1/4] Cluster webhook test --- internal/webhooks/cluster_test.go | 265 +++++++++++++++++++++++++++++- 1 file changed, 258 insertions(+), 7 deletions(-) diff --git a/internal/webhooks/cluster_test.go b/internal/webhooks/cluster_test.go index 663d09be99c8..53f66fb2d90b 100644 --- a/internal/webhooks/cluster_test.go +++ b/internal/webhooks/cluster_test.go @@ -204,6 +204,9 @@ func TestClusterDefaultAndValidateVariables(t *testing.T) { WithWorkerMachineDeploymentClasses( *builder.MachineDeploymentClass("default-worker").Build(), ). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("default-worker").Build(), + ). WithStatusVariables(clusterv1.ClusterClassStatusVariable{ Name: "location", Definitions: []clusterv1.ClusterClassStatusVariableDefinition{ @@ -228,6 +231,12 @@ func TestClusterDefaultAndValidateVariables(t *testing.T) { Name: "md-1", }, }, + MachinePools: []clusterv1.MachinePoolTopology{ + { + Class: "default-worker", + Name: "mp-1", + }, + }, }, }, expect: &clusterv1.Topology{ @@ -239,6 +248,13 @@ func TestClusterDefaultAndValidateVariables(t *testing.T) { // "location" has not been added to .variables.overrides. }, }, + MachinePools: []clusterv1.MachinePoolTopology{ + { + Class: "default-worker", + Name: "mp-1", + // "location" has not been added to .variables.overrides. + }, + }, }, Variables: []clusterv1.ClusterVariable{ { @@ -256,6 +272,9 @@ func TestClusterDefaultAndValidateVariables(t *testing.T) { WithWorkerMachineDeploymentClasses( *builder.MachineDeploymentClass("default-worker").Build(), ). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("default-worker").Build(), + ). WithStatusVariables(clusterv1.ClusterClassStatusVariable{ Name: "httpProxy", Definitions: []clusterv1.ClusterClassStatusVariableDefinition{ @@ -296,6 +315,20 @@ func TestClusterDefaultAndValidateVariables(t *testing.T) { }, }, }, + MachinePools: []clusterv1.MachinePoolTopology{ + { + Class: "default-worker", + Name: "md-1", + Variables: &clusterv1.MachinePoolVariables{ + Overrides: []clusterv1.ClusterVariable{ + { + Name: "httpProxy", + Value: apiextensionsv1.JSON{Raw: []byte(`{"enabled":true}`)}, + }, + }, + }, + }, + }, }, Variables: []clusterv1.ClusterVariable{ { @@ -321,6 +354,21 @@ func TestClusterDefaultAndValidateVariables(t *testing.T) { }, }, }, + MachinePools: []clusterv1.MachinePoolTopology{ + { + Class: "default-worker", + Name: "md-1", + Variables: &clusterv1.MachinePoolVariables{ + Overrides: []clusterv1.ClusterVariable{ + { + Name: "httpProxy", + // url has been added by defaulting. + Value: apiextensionsv1.JSON{Raw: []byte(`{"enabled":true,"url":"http://localhost:3128"}`)}, + }, + }, + }, + }, + }, }, Variables: []clusterv1.ClusterVariable{ { @@ -606,6 +654,13 @@ func TestClusterDefaultAndValidateVariables(t *testing.T) { Value: apiextensionsv1.JSON{Raw: []byte(`"text"`)}, }). Build()). + WithMachinePool(builder.MachinePoolTopology("workers1"). + WithClass("aa"). + WithVariables(clusterv1.ClusterVariable{ + Name: "cpu", + Value: apiextensionsv1.JSON{Raw: []byte(`"text"`)}, + }). + Build()). Build(), expect: builder.ClusterTopology().Build(), wantErr: true, @@ -633,7 +688,7 @@ func TestClusterDefaultAndValidateVariables(t *testing.T) { Name: "cpu", Value: apiextensionsv1.JSON{Raw: []byte(`2`)}, }). - // Variable is not required in MachineDeployment topologies. + // Variable is not required in MachineDeployment or MachinePool topologies. Build(), expect: builder.ClusterTopology(). WithClass("foo"). @@ -642,13 +697,14 @@ func TestClusterDefaultAndValidateVariables(t *testing.T) { Name: "cpu", Value: apiextensionsv1.JSON{Raw: []byte(`2`)}, }). - // Variable is not required in MachineDeployment topologies. + // Variable is not required in MachineDeployment or MachinePool topologies. Build(), }, { name: "should pass when top-level variable and override are valid", clusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). WithWorkerMachineDeploymentClasses(*builder.MachineDeploymentClass("md1").Build()). + WithWorkerMachinePoolClasses(*builder.MachinePoolClass("mp1").Build()). WithStatusVariables(clusterv1.ClusterClassStatusVariable{ Name: "cpu", Definitions: []clusterv1.ClusterClassStatusVariableDefinition{ @@ -676,6 +732,13 @@ func TestClusterDefaultAndValidateVariables(t *testing.T) { Value: apiextensionsv1.JSON{Raw: []byte(`2`)}, }). Build()). + WithMachinePool(builder.MachinePoolTopology("workers1"). + WithClass("mp1"). + WithVariables(clusterv1.ClusterVariable{ + Name: "cpu", + Value: apiextensionsv1.JSON{Raw: []byte(`2`)}, + }). + Build()). Build(), expect: builder.ClusterTopology(). WithClass("foo"). @@ -691,12 +754,20 @@ func TestClusterDefaultAndValidateVariables(t *testing.T) { Value: apiextensionsv1.JSON{Raw: []byte(`2`)}, }). Build()). + WithMachinePool(builder.MachinePoolTopology("workers1"). + WithClass("mp1"). + WithVariables(clusterv1.ClusterVariable{ + Name: "cpu", + Value: apiextensionsv1.JSON{Raw: []byte(`2`)}, + }). + Build()). Build(), }, { name: "should pass even when variable override is missing the corresponding top-level variable", clusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). WithWorkerMachineDeploymentClasses(*builder.MachineDeploymentClass("md1").Build()). + WithWorkerMachinePoolClasses(*builder.MachinePoolClass("mp1").Build()). WithStatusVariables(clusterv1.ClusterClassStatusVariable{ Name: "cpu", Definitions: []clusterv1.ClusterClassStatusVariableDefinition{ @@ -720,6 +791,13 @@ func TestClusterDefaultAndValidateVariables(t *testing.T) { Value: apiextensionsv1.JSON{Raw: []byte(`2`)}, }). Build()). + WithMachinePool(builder.MachinePoolTopology("workers1"). + WithClass("mp1"). + WithVariables(clusterv1.ClusterVariable{ + Name: "cpu", + Value: apiextensionsv1.JSON{Raw: []byte(`2`)}, + }). + Build()). Build(), expect: builder.ClusterTopology(). WithClass("foo"). @@ -732,6 +810,13 @@ func TestClusterDefaultAndValidateVariables(t *testing.T) { Value: apiextensionsv1.JSON{Raw: []byte(`2`)}, }). Build()). + WithMachinePool(builder.MachinePoolTopology("workers1"). + WithClass("mp1"). + WithVariables(clusterv1.ClusterVariable{ + Name: "cpu", + Value: apiextensionsv1.JSON{Raw: []byte(`2`)}, + }). + Build()). Build(), }, } @@ -1160,6 +1245,24 @@ func TestClusterTopologyValidation(t *testing.T) { Build()). Build(), }, + { + name: "should return error when duplicated MachinePools names exists in a Topology", + expectErr: true, + in: builder.Cluster("fooboo", "cluster1"). + WithTopology(builder.ClusterTopology(). + WithClass("foo"). + WithVersion("v1.19.1"). + WithMachinePool( + builder.MachinePoolTopology("workers1"). + WithClass("aa"). + Build()). + WithMachinePool( + builder.MachinePoolTopology("workers1"). + WithClass("bb"). + Build()). + Build()). + Build(), + }, { name: "should pass when MachineDeployments names in a Topology are unique", expectErr: false, @@ -1178,6 +1281,24 @@ func TestClusterTopologyValidation(t *testing.T) { Build()). Build(), }, + { + name: "should pass when MachinePools names in a Topology are unique", + expectErr: false, + in: builder.Cluster("fooboo", "cluster1"). + WithTopology(builder.ClusterTopology(). + WithClass("foo"). + WithVersion("v1.19.1"). + WithMachinePool( + builder.MachinePoolTopology("workers1"). + WithClass("aa"). + Build()). + WithMachinePool( + builder.MachinePoolTopology("workers2"). + WithClass("bb"). + Build()). + Build()). + Build(), + }, { name: "should update", expectErr: false, @@ -1193,6 +1314,14 @@ func TestClusterTopologyValidation(t *testing.T) { builder.MachineDeploymentTopology("workers2"). WithClass("bb"). Build()). + WithMachinePool( + builder.MachinePoolTopology("workers1"). + WithClass("aa"). + Build()). + WithMachinePool( + builder.MachinePoolTopology("workers2"). + WithClass("bb"). + Build()). Build()). Build(), in: builder.Cluster("fooboo", "cluster1"). @@ -1207,6 +1336,14 @@ func TestClusterTopologyValidation(t *testing.T) { builder.MachineDeploymentTopology("workers2"). WithClass("bb"). Build()). + WithMachinePool( + builder.MachinePoolTopology("workers1"). + WithClass("aa"). + Build()). + WithMachinePool( + builder.MachinePoolTopology("workers2"). + WithClass("bb"). + Build()). Build()). Build(), }, @@ -1258,6 +1395,10 @@ func TestClusterTopologyValidation(t *testing.T) { *builder.MachineDeploymentClass("bb").Build(), *builder.MachineDeploymentClass("aa").Build(), ). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("bb").Build(), + *builder.MachinePoolClass("aa").Build(), + ). WithStatusVariables(tt.clusterClassStatusVariables...). Build() @@ -1829,9 +1970,9 @@ func TestClusterTopologyValidationForTopologyClassChange(t *testing.T) { wantErr: true, }, - // MachineDeploymentClass changes + // MachineDeploymentClass & MachinePoolClass changes { - name: "Accept cluster.topology.class change with a compatible MachineDeploymentClass InfrastructureTemplate", + name: "Accept cluster.topology.class change with a compatible MachineDeploymentClass and MachinePoolClass InfrastructureTemplate", firstClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). WithInfrastructureClusterTemplate(refToUnstructured(ref)). WithControlPlaneTemplate(refToUnstructured(ref)). @@ -1842,6 +1983,12 @@ func TestClusterTopologyValidationForTopologyClassChange(t *testing.T) { WithBootstrapTemplate(refToUnstructured(ref)). Build(), ). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate(refToUnstructured(ref)). + WithBootstrapTemplate(refToUnstructured(ref)). + Build(), + ). Build(), secondClass: builder.ClusterClass(metav1.NamespaceDefault, "class2"). WithInfrastructureClusterTemplate(refToUnstructured(ref)). @@ -1853,11 +2000,17 @@ func TestClusterTopologyValidationForTopologyClassChange(t *testing.T) { WithBootstrapTemplate(refToUnstructured(ref)). Build(), ). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate(refToUnstructured(compatibleNameChangeRef)). + WithBootstrapTemplate(refToUnstructured(ref)). + Build(), + ). Build(), wantErr: false, }, { - name: "Accept cluster.topology.class change with an incompatible MachineDeploymentClass BootstrapTemplate", + name: "Accept cluster.topology.class change with an incompatible MachineDeploymentClass and MachinePoolClass BootstrapTemplate", firstClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). WithInfrastructureClusterTemplate(refToUnstructured(ref)). WithControlPlaneTemplate(refToUnstructured(ref)). @@ -1868,6 +2021,12 @@ func TestClusterTopologyValidationForTopologyClassChange(t *testing.T) { WithBootstrapTemplate(refToUnstructured(ref)). Build(), ). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate(refToUnstructured(ref)). + WithBootstrapTemplate(refToUnstructured(ref)). + Build(), + ). Build(), secondClass: builder.ClusterClass(metav1.NamespaceDefault, "class2"). WithInfrastructureClusterTemplate(refToUnstructured(ref)). @@ -1879,11 +2038,17 @@ func TestClusterTopologyValidationForTopologyClassChange(t *testing.T) { WithBootstrapTemplate(refToUnstructured(incompatibleKindRef)). Build(), ). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate(refToUnstructured(compatibleNameChangeRef)). + WithBootstrapTemplate(refToUnstructured(incompatibleKindRef)). + Build(), + ). Build(), wantErr: false, }, { - name: "Accept cluster.topology.class change with a deleted MachineDeploymentClass", + name: "Accept cluster.topology.class change with a deleted MachineDeploymentClass and MachinePoolClass", firstClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). WithInfrastructureClusterTemplate(refToUnstructured(ref)). WithControlPlaneTemplate(refToUnstructured(ref)). @@ -1898,6 +2063,16 @@ func TestClusterTopologyValidationForTopologyClassChange(t *testing.T) { WithBootstrapTemplate(refToUnstructured(ref)). Build(), ). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate(refToUnstructured(ref)). + WithBootstrapTemplate(refToUnstructured(ref)). + Build(), + *builder.MachinePoolClass("bb"). + WithInfrastructureTemplate(refToUnstructured(ref)). + WithBootstrapTemplate(refToUnstructured(ref)). + Build(), + ). Build(), secondClass: builder.ClusterClass(metav1.NamespaceDefault, "class2"). WithInfrastructureClusterTemplate(refToUnstructured(ref)). @@ -1909,11 +2084,17 @@ func TestClusterTopologyValidationForTopologyClassChange(t *testing.T) { WithBootstrapTemplate(refToUnstructured(ref)). Build(), ). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate(refToUnstructured(ref)). + WithBootstrapTemplate(refToUnstructured(ref)). + Build(), + ). Build(), wantErr: false, }, { - name: "Accept cluster.topology.class change with an added MachineDeploymentClass", + name: "Accept cluster.topology.class change with an added MachineDeploymentClass and MachinePoolClass", firstClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). WithInfrastructureClusterTemplate(refToUnstructured(ref)). WithControlPlaneTemplate(refToUnstructured(ref)). @@ -1924,6 +2105,12 @@ func TestClusterTopologyValidationForTopologyClassChange(t *testing.T) { WithBootstrapTemplate(refToUnstructured(ref)). Build(), ). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate(refToUnstructured(ref)). + WithBootstrapTemplate(refToUnstructured(ref)). + Build(), + ). Build(), secondClass: builder.ClusterClass(metav1.NamespaceDefault, "class2"). WithInfrastructureClusterTemplate(refToUnstructured(ref)). @@ -1939,6 +2126,16 @@ func TestClusterTopologyValidationForTopologyClassChange(t *testing.T) { WithBootstrapTemplate(refToUnstructured(ref)). Build(), ). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate(refToUnstructured(ref)). + WithBootstrapTemplate(refToUnstructured(ref)). + Build(), + *builder.MachinePoolClass("bb"). + WithInfrastructureTemplate(refToUnstructured(ref)). + WithBootstrapTemplate(refToUnstructured(ref)). + Build(), + ). Build(), wantErr: false, }, @@ -1994,6 +2191,60 @@ func TestClusterTopologyValidationForTopologyClassChange(t *testing.T) { Build(), wantErr: true, }, + + // MachinePoolClass reject changes + { + name: "Reject cluster.topology.class change with an incompatible Kind change to MachinePoolClass InfrastructureTemplate", + firstClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). + WithInfrastructureClusterTemplate(refToUnstructured(ref)). + WithControlPlaneTemplate(refToUnstructured(ref)). + WithControlPlaneInfrastructureMachineTemplate(refToUnstructured(ref)). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate(refToUnstructured(ref)). + WithBootstrapTemplate(refToUnstructured(ref)). + Build(), + ). + Build(), + secondClass: builder.ClusterClass(metav1.NamespaceDefault, "class2"). + WithInfrastructureClusterTemplate(refToUnstructured(ref)). + WithControlPlaneTemplate(refToUnstructured(ref)). + WithControlPlaneInfrastructureMachineTemplate(refToUnstructured(ref)). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate(refToUnstructured(incompatibleKindRef)). + WithBootstrapTemplate(refToUnstructured(ref)). + Build(), + ). + Build(), + wantErr: true, + }, + { + name: "Reject cluster.topology.class change with an incompatible APIGroup change to MachinePoolClass InfrastructureTemplate", + firstClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). + WithInfrastructureClusterTemplate(refToUnstructured(ref)). + WithControlPlaneTemplate(refToUnstructured(ref)). + WithControlPlaneInfrastructureMachineTemplate(refToUnstructured(ref)). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate(refToUnstructured(ref)). + WithBootstrapTemplate(refToUnstructured(ref)). + Build(), + ). + Build(), + secondClass: builder.ClusterClass(metav1.NamespaceDefault, "class2"). + WithInfrastructureClusterTemplate(refToUnstructured(ref)). + WithControlPlaneTemplate(refToUnstructured(ref)). + WithControlPlaneInfrastructureMachineTemplate(refToUnstructured(ref)). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate(refToUnstructured(incompatibleAPIGroupRef)). + WithBootstrapTemplate(refToUnstructured(ref)). + Build(), + ). + Build(), + wantErr: true, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { From efb041d00c794f4d7658ebc45878e4c7f9579000 Mon Sep 17 00:00:00 2001 From: willie-yao Date: Wed, 24 Jan 2024 21:54:05 +0000 Subject: [PATCH 2/4] Add mp to clusterclass_test.go --- internal/webhooks/clusterclass_test.go | 621 ++++++++++++++++++++++++- 1 file changed, 616 insertions(+), 5 deletions(-) diff --git a/internal/webhooks/clusterclass_test.go b/internal/webhooks/clusterclass_test.go index c9f02d5310a4..3e3088d3f62a 100644 --- a/internal/webhooks/clusterclass_test.go +++ b/internal/webhooks/clusterclass_test.go @@ -70,6 +70,13 @@ func TestClusterClassDefaultNamespaces(t *testing.T) { WithBootstrapTemplate( builder.BootstrapTemplate("", "bootstrap1").Build()). Build()). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + builder.InfrastructureMachinePoolTemplate("", "infra1").Build()). + WithBootstrapTemplate( + builder.BootstrapTemplate("", "bootstrap1").Build()). + Build()). Build() fakeClient := fake.NewClientBuilder(). @@ -92,6 +99,10 @@ func TestClusterClassDefaultNamespaces(t *testing.T) { g.Expect(in.Spec.Workers.MachineDeployments[i].Template.Bootstrap.Ref.Namespace).To(Equal(namespace)) g.Expect(in.Spec.Workers.MachineDeployments[i].Template.Infrastructure.Ref.Namespace).To(Equal(namespace)) } + for i := range in.Spec.Workers.MachinePools { + g.Expect(in.Spec.Workers.MachinePools[i].Template.Bootstrap.Ref.Namespace).To(Equal(namespace)) + g.Expect(in.Spec.Workers.MachinePools[i].Template.Infrastructure.Ref.Namespace).To(Equal(namespace)) + } } func TestClusterClassValidationFeatureGated(t *testing.T) { @@ -121,6 +132,13 @@ func TestClusterClassValidationFeatureGated(t *testing.T) { WithBootstrapTemplate( builder.BootstrapTemplate("", "bootstrap1").Build()). Build()). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + builder.InfrastructureMachinePoolTemplate("", "infra1").Build()). + WithBootstrapTemplate( + builder.BootstrapTemplate("", "bootstrap1").Build()). + Build()). Build(), expectErr: true, }, @@ -142,6 +160,13 @@ func TestClusterClassValidationFeatureGated(t *testing.T) { WithBootstrapTemplate( builder.BootstrapTemplate("", "bootstrap1").Build()). Build()). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + builder.InfrastructureMachinePoolTemplate("", "infra1").Build()). + WithBootstrapTemplate( + builder.BootstrapTemplate("", "bootstrap1").Build()). + Build()). Build(), in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). WithInfrastructureClusterTemplate( @@ -159,6 +184,13 @@ func TestClusterClassValidationFeatureGated(t *testing.T) { WithBootstrapTemplate( builder.BootstrapTemplate("", "bootstrap1").Build()). Build()). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + builder.InfrastructureMachinePoolTemplate("", "infra1").Build()). + WithBootstrapTemplate( + builder.BootstrapTemplate("", "bootstrap1").Build()). + Build()). Build(), expectErr: true, }, @@ -249,6 +281,19 @@ func TestClusterClassValidation(t *testing.T) { WithBootstrapTemplate( builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). Build()). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithBootstrapTemplate( + builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). + Build(), + *builder.MachinePoolClass("bb"). + WithInfrastructureTemplate( + builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithBootstrapTemplate( + builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). + Build()). Build(), expectErr: false, }, @@ -332,6 +377,48 @@ func TestClusterClassValidation(t *testing.T) { Build(), expectErr: true, }, + { + name: "create fail machinePool Bootstrap has empty name", + in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). + WithInfrastructureClusterTemplate( + builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithControlPlaneTemplate( + builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). + Build()). + WithControlPlaneInfrastructureMachineTemplate( + builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). + Build()). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithBootstrapTemplate( + builder.BootstrapTemplate(metav1.NamespaceDefault, "").Build()). + Build()). + Build(), + expectErr: true, + }, + { + name: "create fail machinePool Infrastructure has empty name", + in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). + WithInfrastructureClusterTemplate( + builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithControlPlaneTemplate( + builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). + Build()). + WithControlPlaneInfrastructureMachineTemplate( + builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). + Build()). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "").Build()). + WithBootstrapTemplate( + builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap").Build()). + Build()). + Build(), + expectErr: true, + }, // inconsistent namespace in ref tests { @@ -418,6 +505,48 @@ func TestClusterClassValidation(t *testing.T) { Build(), expectErr: true, }, + { + name: "create fail if machinePool / bootstrap has inconsistent namespace", + in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). + WithInfrastructureClusterTemplate( + builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithControlPlaneTemplate( + builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). + Build()). + WithControlPlaneInfrastructureMachineTemplate( + builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). + Build()). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithBootstrapTemplate( + builder.BootstrapTemplate("WrongNamespace", "bootstrap1").Build()). + Build()). + Build(), + expectErr: true, + }, + { + name: "create fail if machinePool / infrastructure has inconsistent namespace", + in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). + WithInfrastructureClusterTemplate( + builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithControlPlaneTemplate( + builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). + Build()). + WithControlPlaneInfrastructureMachineTemplate( + builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). + Build()). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + builder.InfrastructureMachinePoolTemplate("WrongNamespace", "infra1").Build()). + WithBootstrapTemplate( + builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). + Build()). + Build(), + expectErr: true, + }, // bad template in ref tests { @@ -508,6 +637,51 @@ func TestClusterClassValidation(t *testing.T) { old: nil, expectErr: true, }, + { + name: "create fail if bad template in machinePool Bootstrap", + + in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). + WithInfrastructureClusterTemplate( + builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithControlPlaneTemplate( + builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). + Build()). + WithControlPlaneInfrastructureMachineTemplate( + builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). + Build()). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithBootstrapTemplate( + refToUnstructured(refBadTemplate)). + Build()). + Build(), + old: nil, + expectErr: true, + }, + { + name: "create fail if bad template in machinePool Infrastructure", + in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). + WithInfrastructureClusterTemplate( + builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithControlPlaneTemplate( + builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). + Build()). + WithControlPlaneInfrastructureMachineTemplate( + builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). + Build()). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + refToUnstructured(refBadTemplate)). + WithBootstrapTemplate( + builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). + Build()). + Build(), + old: nil, + expectErr: true, + }, // bad apiVersion in ref tests { @@ -597,6 +771,50 @@ func TestClusterClassValidation(t *testing.T) { old: nil, expectErr: true, }, + { + name: "create fail with a bad APIVersion for template in machinePool Bootstrap", + in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). + WithInfrastructureClusterTemplate( + builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithControlPlaneTemplate( + builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). + Build()). + WithControlPlaneInfrastructureMachineTemplate( + builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). + Build()). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithBootstrapTemplate( + refToUnstructured(refBadAPIVersion)). + Build()). + Build(), + old: nil, + expectErr: true, + }, + { + name: "create fail with a bad APIVersion for template in machinePool Infrastructure", + in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). + WithInfrastructureClusterTemplate( + builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithControlPlaneTemplate( + builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). + Build()). + WithControlPlaneInfrastructureMachineTemplate( + builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). + Build()). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + refToUnstructured(refBadAPIVersion)). + WithBootstrapTemplate( + builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). + Build()). + Build(), + old: nil, + expectErr: true, + }, // create test { @@ -625,6 +843,32 @@ func TestClusterClassValidation(t *testing.T) { Build(), expectErr: true, }, + { + name: "create fail if duplicated machinePoolClasses", + in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). + WithInfrastructureClusterTemplate( + builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithControlPlaneTemplate( + builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). + Build()). + WithControlPlaneInfrastructureMachineTemplate( + builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). + Build()). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithBootstrapTemplate( + builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).Build(), + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithBootstrapTemplate( + builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). + Build()). + Build(), + expectErr: true, + }, { name: "create pass if valid machineHealthCheck defined for ControlPlane with MachineInfrastructure set", in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). @@ -780,6 +1024,13 @@ func TestClusterClassValidation(t *testing.T) { WithBootstrapTemplate( builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). Build()). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithBootstrapTemplate( + builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). + Build()). Build(), in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). WithInfrastructureClusterTemplate( @@ -797,6 +1048,13 @@ func TestClusterClassValidation(t *testing.T) { WithBootstrapTemplate( builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). Build()). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithBootstrapTemplate( + builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). + Build()). Build(), expectErr: false, }, @@ -818,6 +1076,13 @@ func TestClusterClassValidation(t *testing.T) { WithBootstrapTemplate( builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). Build()). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithBootstrapTemplate( + builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). + Build()). Build(), in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). WithInfrastructureClusterTemplate( @@ -835,6 +1100,13 @@ func TestClusterClassValidation(t *testing.T) { WithBootstrapTemplate( builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). Build()). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithBootstrapTemplate( + builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). + Build()). Build(), expectErr: false, }, @@ -892,6 +1164,13 @@ func TestClusterClassValidation(t *testing.T) { WithBootstrapTemplate( builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). Build()). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithBootstrapTemplate( + builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). + Build()). Build(), in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). WithInfrastructureClusterTemplate( @@ -907,6 +1186,13 @@ func TestClusterClassValidation(t *testing.T) { WithBootstrapTemplate( builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). Build()). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithBootstrapTemplate( + builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). + Build()). Build(), expectErr: false, }, @@ -926,6 +1212,13 @@ func TestClusterClassValidation(t *testing.T) { WithBootstrapTemplate( builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). Build()). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithBootstrapTemplate( + builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). + Build()). Build(), in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). WithInfrastructureClusterTemplate( @@ -941,6 +1234,13 @@ func TestClusterClassValidation(t *testing.T) { WithBootstrapTemplate( builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). Build()). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithBootstrapTemplate( + builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). + Build()). Build(), expectErr: true, }, @@ -960,6 +1260,13 @@ func TestClusterClassValidation(t *testing.T) { WithBootstrapTemplate( builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). Build()). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithBootstrapTemplate( + builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). + Build()). Build(), in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). WithInfrastructureClusterTemplate( @@ -975,11 +1282,18 @@ func TestClusterClassValidation(t *testing.T) { WithBootstrapTemplate( builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). Build()). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithBootstrapTemplate( + builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). + Build()). Build(), expectErr: true, }, { - name: "update pass if a machine deployment changes in a compatible way", + name: "update pass if a machine deployment and machine pool changes in a compatible way", old: builder.ClusterClass(metav1.NamespaceDefault, "class1"). WithInfrastructureClusterTemplate( builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). @@ -996,6 +1310,13 @@ func TestClusterClassValidation(t *testing.T) { WithBootstrapTemplate( builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). Build()). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + refToUnstructured(ref)). + WithBootstrapTemplate( + builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). + Build()). Build(), in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). WithInfrastructureClusterTemplate( @@ -1013,6 +1334,13 @@ func TestClusterClassValidation(t *testing.T) { WithBootstrapTemplate( refToUnstructured(incompatibleRef)). Build()). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + refToUnstructured(compatibleRef)). + WithBootstrapTemplate( + refToUnstructured(incompatibleRef)). + Build()). Build(), expectErr: false, }, @@ -1055,7 +1383,45 @@ func TestClusterClassValidation(t *testing.T) { expectErr: true, }, { - name: "update pass if a machine deployment class gets added", + name: "update fails a machine pool changes in an incompatible way", + old: builder.ClusterClass(metav1.NamespaceDefault, "class1"). + WithInfrastructureClusterTemplate( + builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithControlPlaneTemplate( + builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). + Build()). + WithControlPlaneInfrastructureMachineTemplate( + builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). + Build()). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + refToUnstructured(ref)). + WithBootstrapTemplate( + builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). + Build()). + Build(), + in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). + WithInfrastructureClusterTemplate( + builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithControlPlaneTemplate( + builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). + Build()). + WithControlPlaneInfrastructureMachineTemplate( + builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). + Build()). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + refToUnstructured(incompatibleRef)). + WithBootstrapTemplate( + builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). + Build()). + Build(), + expectErr: true, + }, + { + name: "update pass if a machine deployment or machine pool class gets added", old: builder.ClusterClass(metav1.NamespaceDefault, "class1"). WithInfrastructureClusterTemplate( builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). @@ -1072,6 +1438,13 @@ func TestClusterClassValidation(t *testing.T) { WithBootstrapTemplate( builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). Build()). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithBootstrapTemplate( + builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). + Build()). Build(), in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). WithInfrastructureClusterTemplate( @@ -1095,11 +1468,24 @@ func TestClusterClassValidation(t *testing.T) { WithBootstrapTemplate( builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). Build()). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithBootstrapTemplate( + builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). + Build(), + *builder.MachinePoolClass("BB"). + WithInfrastructureTemplate( + builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithBootstrapTemplate( + builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). + Build()). Build(), expectErr: false, }, { - name: "update fails if a duplicated deployment class gets added", + name: "update fails if a duplicated machine deployment class gets added", old: builder.ClusterClass(metav1.NamespaceDefault, "class1"). WithInfrastructureClusterTemplate( builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). @@ -1142,7 +1528,50 @@ func TestClusterClassValidation(t *testing.T) { expectErr: true, }, { - name: "should return error for invalid labels and annotations", + name: "update fails if a duplicated machine pool class gets added", + old: builder.ClusterClass(metav1.NamespaceDefault, "class1"). + WithInfrastructureClusterTemplate( + builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithControlPlaneTemplate( + builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). + Build()). + WithControlPlaneInfrastructureMachineTemplate( + builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). + Build()). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithBootstrapTemplate( + builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). + Build()). + Build(), + in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). + WithInfrastructureClusterTemplate( + builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithControlPlaneTemplate( + builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). + Build()). + WithControlPlaneInfrastructureMachineTemplate( + builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). + Build()). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithBootstrapTemplate( + builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).Build(), + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithBootstrapTemplate( + builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). + Build()). + Build(), + expectErr: true, + }, + { + name: "should return error for invalid machine deployment labels and annotations", in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). WithInfrastructureClusterTemplate( builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). @@ -1165,6 +1594,30 @@ func TestClusterClassValidation(t *testing.T) { Build(), expectErr: true, }, + { + name: "should return error for invalid machine pool labels and annotations", + in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). + WithInfrastructureClusterTemplate( + builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithControlPlaneTemplate( + builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). + Build()). + WithControlPlaneInfrastructureMachineTemplate( + builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1"). + Build()). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithBootstrapTemplate( + builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). + WithLabels(invalidLabels()). + WithAnnotations(invalidAnnotations()). + Build()). + WithControlPlaneMetadata(invalidLabels(), invalidAnnotations()). + Build(), + expectErr: true, + }, { name: "should not return error for valid namingStrategy.template", in: builder.ClusterClass(metav1.NamespaceDefault, "class1"). @@ -1351,7 +1804,7 @@ func TestClusterClassValidationWithClusterAwareChecks(t *testing.T) { expectErr bool }{ { - name: "pass if a MachineDeploymentClass not in use gets removed", + name: "pass if a MachineDeploymentClass or MachinePoolClass not in use gets removed", clusters: []client.Object{ builder.Cluster(metav1.NamespaceDefault, "cluster1"). WithLabels(map[string]string{clusterv1.ClusterTopologyOwnedLabel: ""}). @@ -1385,6 +1838,19 @@ func TestClusterClassValidationWithClusterAwareChecks(t *testing.T) { WithBootstrapTemplate( builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). Build()). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithBootstrapTemplate( + builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). + Build(), + *builder.MachinePoolClass("bb"). + WithInfrastructureTemplate( + builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithBootstrapTemplate( + builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). + Build()). Build(), newClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). WithInfrastructureClusterTemplate( @@ -1399,6 +1865,13 @@ func TestClusterClassValidationWithClusterAwareChecks(t *testing.T) { WithBootstrapTemplate( builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). Build()). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("bb"). + WithInfrastructureTemplate( + builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithBootstrapTemplate( + builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). + Build()). Build(), expectErr: false, }, @@ -1454,6 +1927,58 @@ func TestClusterClassValidationWithClusterAwareChecks(t *testing.T) { Build(), expectErr: true, }, + { + name: "error if a MachinePoolClass in use gets removed", + clusters: []client.Object{ + builder.Cluster(metav1.NamespaceDefault, "cluster1"). + WithLabels(map[string]string{clusterv1.ClusterTopologyOwnedLabel: ""}). + WithTopology( + builder.ClusterTopology(). + WithClass("class1"). + WithMachinePool( + builder.MachinePoolTopology("workers1"). + WithClass("bb"). + Build(), + ). + Build()). + Build(), + }, + oldClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). + WithInfrastructureClusterTemplate( + builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()). + WithControlPlaneTemplate( + builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). + Build()). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithBootstrapTemplate( + builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). + Build(), + *builder.MachinePoolClass("bb"). + WithInfrastructureTemplate( + builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithBootstrapTemplate( + builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). + Build()). + Build(), + newClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). + WithInfrastructureClusterTemplate( + builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()). + WithControlPlaneTemplate( + builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). + Build()). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithBootstrapTemplate( + builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). + Build()). + Build(), + expectErr: true, + }, { name: "error if many MachineDeploymentClasses, used in multiple Clusters using the modified ClusterClass, are removed", clusters: []client.Object{ @@ -1540,6 +2065,92 @@ func TestClusterClassValidationWithClusterAwareChecks(t *testing.T) { Build(), expectErr: true, }, + { + name: "error if many MachinePoolClasses, used in multiple Clusters using the modified ClusterClass, are removed", + clusters: []client.Object{ + builder.Cluster(metav1.NamespaceDefault, "cluster1"). + WithLabels(map[string]string{clusterv1.ClusterTopologyOwnedLabel: ""}). + WithTopology( + builder.ClusterTopology(). + WithClass("class1"). + WithMachinePool( + builder.MachinePoolTopology("workers1"). + WithClass("bb"). + Build(), + ). + WithMachinePool( + builder.MachinePoolTopology("workers2"). + WithClass("aa"). + Build(), + ). + Build()). + Build(), + builder.Cluster(metav1.NamespaceDefault, "cluster2"). + WithLabels(map[string]string{clusterv1.ClusterTopologyOwnedLabel: ""}). + WithTopology( + builder.ClusterTopology(). + WithClass("class1"). + WithMachinePool( + builder.MachinePoolTopology("workers1"). + WithClass("aa"). + Build(), + ). + WithMachinePool( + builder.MachinePoolTopology("workers2"). + WithClass("aa"). + Build(), + ). + Build()). + Build(), + builder.Cluster(metav1.NamespaceDefault, "cluster3"). + WithLabels(map[string]string{clusterv1.ClusterTopologyOwnedLabel: ""}). + WithTopology( + builder.ClusterTopology(). + WithClass("class1"). + WithMachinePool( + builder.MachinePoolTopology("workers1"). + WithClass("bb"). + Build(), + ). + Build()). + Build(), + }, + oldClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). + WithInfrastructureClusterTemplate( + builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()). + WithControlPlaneTemplate( + builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). + Build()). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithBootstrapTemplate( + builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). + Build(), + *builder.MachinePoolClass("bb"). + WithInfrastructureTemplate( + builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithBootstrapTemplate( + builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). + Build()). + Build(), + newClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). + WithInfrastructureClusterTemplate( + builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()). + WithControlPlaneTemplate( + builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1"). + Build()). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("bb"). + WithInfrastructureTemplate( + builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). + WithBootstrapTemplate( + builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). + Build()). + Build(), + expectErr: true, + }, { name: "error if a control plane MachineHealthCheck that is in use by a cluster is removed", clusters: []client.Object{ From 483f7388cdd972c6288b6e1a18bf20916b344cdb Mon Sep 17 00:00:00 2001 From: willie-yao Date: Wed, 24 Jan 2024 22:11:27 +0000 Subject: [PATCH 3/4] Add mp to patch_validation_test.go --- internal/webhooks/patch_validation_test.go | 239 ++++++++++++++++++++- 1 file changed, 238 insertions(+), 1 deletion(-) diff --git a/internal/webhooks/patch_validation_test.go b/internal/webhooks/patch_validation_test.go index a7a7b7cfc8e3..57468e913cb0 100644 --- a/internal/webhooks/patch_validation_test.go +++ b/internal/webhooks/patch_validation_test.go @@ -1547,6 +1547,7 @@ func Test_validateSelectors(t *testing.T) { ControlPlane: false, InfrastructureCluster: false, MachineDeploymentClass: &clusterv1.PatchSelectorMatchMachineDeploymentClass{}, + MachinePoolClass: &clusterv1.PatchSelectorMatchMachinePoolClass{}, }, }, clusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). @@ -1692,7 +1693,7 @@ func Test_validateSelectors(t *testing.T) { wantErr: true, }, { - name: "pass if selector targets an existing MachineDeploymentClass BootstrapTemplate", + name: "pass if selector targets an existing MachineDeploymentClass and MachinePoolClass BootstrapTemplate", selector: clusterv1.PatchSelector{ APIVersion: "bootstrap.cluster.x-k8s.io/v1beta1", Kind: "BootstrapTemplate", @@ -1700,6 +1701,9 @@ func Test_validateSelectors(t *testing.T) { MachineDeploymentClass: &clusterv1.PatchSelectorMatchMachineDeploymentClass{ Names: []string{"aa"}, }, + MachinePoolClass: &clusterv1.PatchSelectorMatchMachinePoolClass{ + Names: []string{"aa"}, + }, }, }, clusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). @@ -1717,6 +1721,20 @@ func Test_validateSelectors(t *testing.T) { })). Build(), ). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + refToUnstructured(&corev1.ObjectReference{ + APIVersion: "infrastructure.cluster.x-k8s.io/v1beta1", + Kind: "InfrastructureMachinePoolTemplate", + })). + WithBootstrapTemplate( + refToUnstructured(&corev1.ObjectReference{ + APIVersion: "bootstrap.cluster.x-k8s.io/v1beta1", + Kind: "BootstrapTemplate", + })). + Build(), + ). Build(), }, { @@ -1747,6 +1765,34 @@ func Test_validateSelectors(t *testing.T) { ). Build(), }, + { + name: "pass if selector targets an existing MachinePoolClass InfrastructureTemplate", + selector: clusterv1.PatchSelector{ + APIVersion: "infrastructure.cluster.x-k8s.io/v1beta1", + Kind: "InfrastructureMachinePoolTemplate", + MatchResources: clusterv1.PatchSelectorMatch{ + MachinePoolClass: &clusterv1.PatchSelectorMatchMachinePoolClass{ + Names: []string{"aa"}, + }, + }, + }, + clusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + refToUnstructured(&corev1.ObjectReference{ + APIVersion: "infrastructure.cluster.x-k8s.io/v1beta1", + Kind: "InfrastructureMachinePoolTemplate", + })). + WithBootstrapTemplate( + refToUnstructured(&corev1.ObjectReference{ + APIVersion: "bootstrap.cluster.x-k8s.io/v1beta1", + Kind: "BootstrapTemplate", + })). + Build(), + ). + Build(), + }, { name: "error if selector targets a non-existing MachineDeploymentClass InfrastructureTemplate", selector: clusterv1.PatchSelector{ @@ -1788,6 +1834,47 @@ func Test_validateSelectors(t *testing.T) { Build(), wantErr: true, }, + { + name: "error if selector targets a non-existing MachinePoolClass InfrastructureTemplate", + selector: clusterv1.PatchSelector{ + APIVersion: "infrastructure.cluster.x-k8s.io/v1beta1", + Kind: "InfrastructureMachinePoolTemplate", + MatchResources: clusterv1.PatchSelectorMatch{ + MachinePoolClass: &clusterv1.PatchSelectorMatchMachinePoolClass{ + Names: []string{"bb"}, + }, + }, + }, + clusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + refToUnstructured(&corev1.ObjectReference{ + APIVersion: "infrastructure.cluster.x-k8s.io/v1beta1", + Kind: "InfrastructureMachinePoolTemplate", + })). + WithBootstrapTemplate( + refToUnstructured(&corev1.ObjectReference{ + APIVersion: "bootstrap.cluster.x-k8s.io/v1beta1", + Kind: "BootstrapTemplate", + })). + Build(), + *builder.MachinePoolClass("bb"). + WithInfrastructureTemplate( + refToUnstructured(&corev1.ObjectReference{ + APIVersion: "infrastructure.cluster.x-k8s.io/v1beta1", + Kind: "NonMatchingInfrastructureMachinePoolTemplate", + })). + WithBootstrapTemplate( + refToUnstructured(&corev1.ObjectReference{ + APIVersion: "bootstrap.cluster.x-k8s.io/v1beta1", + Kind: "BootstrapTemplate", + })). + Build(), + ). + Build(), + wantErr: true, + }, { name: "fail if selector targets ControlPlane Machine Infrastructure but does not have MatchResources.ControlPlane enabled", selector: clusterv1.PatchSelector{ @@ -1848,6 +1935,43 @@ func Test_validateSelectors(t *testing.T) { Build(), wantErr: true, }, + { + name: "error if selector targets an empty MachinePoolClass InfrastructureTemplate", + selector: clusterv1.PatchSelector{ + APIVersion: "infrastructure.cluster.x-k8s.io/v1beta1", + Kind: "InfrastructureMachinePoolTemplate", + MatchResources: clusterv1.PatchSelectorMatch{}, + }, + clusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("aa"). + WithInfrastructureTemplate( + refToUnstructured(&corev1.ObjectReference{ + APIVersion: "infrastructure.cluster.x-k8s.io/v1beta1", + Kind: "InfrastructureMachinePoolTemplate", + })). + WithBootstrapTemplate( + refToUnstructured(&corev1.ObjectReference{ + APIVersion: "bootstrap.cluster.x-k8s.io/v1beta1", + Kind: "BootstrapTemplate", + })). + Build(), + *builder.MachinePoolClass("bb"). + WithInfrastructureTemplate( + refToUnstructured(&corev1.ObjectReference{ + APIVersion: "infrastructure.cluster.x-k8s.io/v1beta1", + Kind: "NonMatchingInfrastructureMachinePoolTemplate", + })). + WithBootstrapTemplate( + refToUnstructured(&corev1.ObjectReference{ + APIVersion: "bootstrap.cluster.x-k8s.io/v1beta1", + Kind: "BootstrapTemplate", + })). + Build(), + ). + Build(), + wantErr: true, + }, { name: "error if selector targets a bad pattern for matching MachineDeploymentClass InfrastructureTemplate", selector: clusterv1.PatchSelector{ @@ -1877,6 +2001,35 @@ func Test_validateSelectors(t *testing.T) { Build(), wantErr: true, }, + { + name: "error if selector targets a bad pattern for matching MachinePoolClass InfrastructureTemplate", + selector: clusterv1.PatchSelector{ + APIVersion: "infrastructure.cluster.x-k8s.io/v1beta1", + Kind: "InfrastructureMachinePoolTemplate", + MatchResources: clusterv1.PatchSelectorMatch{ + MachinePoolClass: &clusterv1.PatchSelectorMatchMachinePoolClass{ + Names: []string{"a*a"}, + }, + }, + }, + clusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("a-something-a"). + WithInfrastructureTemplate( + refToUnstructured(&corev1.ObjectReference{ + APIVersion: "infrastructure.cluster.x-k8s.io/v1beta1", + Kind: "InfrastructureMachinePoolTemplate", + })). + WithBootstrapTemplate( + refToUnstructured(&corev1.ObjectReference{ + APIVersion: "bootstrap.cluster.x-k8s.io/v1beta1", + Kind: "BootstrapTemplate", + })). + Build(), + ). + Build(), + wantErr: true, + }, { name: "pass if selector targets an existing MachineDeploymentClass InfrastructureTemplate with prefix *", selector: clusterv1.PatchSelector{ @@ -1905,6 +2058,34 @@ func Test_validateSelectors(t *testing.T) { ). Build(), }, + { + name: "pass if selector targets an existing MachinePoolClass InfrastructureTemplate with prefix *", + selector: clusterv1.PatchSelector{ + APIVersion: "infrastructure.cluster.x-k8s.io/v1beta1", + Kind: "InfrastructureMachinePoolTemplate", + MatchResources: clusterv1.PatchSelectorMatch{ + MachinePoolClass: &clusterv1.PatchSelectorMatchMachinePoolClass{ + Names: []string{"a-*"}, + }, + }, + }, + clusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("a-something-a"). + WithInfrastructureTemplate( + refToUnstructured(&corev1.ObjectReference{ + APIVersion: "infrastructure.cluster.x-k8s.io/v1beta1", + Kind: "InfrastructureMachinePoolTemplate", + })). + WithBootstrapTemplate( + refToUnstructured(&corev1.ObjectReference{ + APIVersion: "bootstrap.cluster.x-k8s.io/v1beta1", + Kind: "BootstrapTemplate", + })). + Build(), + ). + Build(), + }, { name: "pass if selector targets an existing MachineDeploymentClass InfrastructureTemplate with suffix *", selector: clusterv1.PatchSelector{ @@ -1933,6 +2114,34 @@ func Test_validateSelectors(t *testing.T) { ). Build(), }, + { + name: "pass if selector targets an existing MachinePoolClass InfrastructureTemplate with suffix *", + selector: clusterv1.PatchSelector{ + APIVersion: "infrastructure.cluster.x-k8s.io/v1beta1", + Kind: "InfrastructureMachinePoolTemplate", + MatchResources: clusterv1.PatchSelectorMatch{ + MachinePoolClass: &clusterv1.PatchSelectorMatchMachinePoolClass{ + Names: []string{"*-a"}, + }, + }, + }, + clusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("a-something-a"). + WithInfrastructureTemplate( + refToUnstructured(&corev1.ObjectReference{ + APIVersion: "infrastructure.cluster.x-k8s.io/v1beta1", + Kind: "InfrastructureMachinePoolTemplate", + })). + WithBootstrapTemplate( + refToUnstructured(&corev1.ObjectReference{ + APIVersion: "bootstrap.cluster.x-k8s.io/v1beta1", + Kind: "BootstrapTemplate", + })). + Build(), + ). + Build(), + }, { name: "pass if selector targets all existing MachineDeploymentClass InfrastructureTemplate with *", selector: clusterv1.PatchSelector{ @@ -1961,6 +2170,34 @@ func Test_validateSelectors(t *testing.T) { ). Build(), }, + { + name: "pass if selector targets all existing MachinePoolClass InfrastructureTemplate with *", + selector: clusterv1.PatchSelector{ + APIVersion: "infrastructure.cluster.x-k8s.io/v1beta1", + Kind: "InfrastructureMachinePoolTemplate", + MatchResources: clusterv1.PatchSelectorMatch{ + MachinePoolClass: &clusterv1.PatchSelectorMatchMachinePoolClass{ + Names: []string{"*"}, + }, + }, + }, + clusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). + WithWorkerMachinePoolClasses( + *builder.MachinePoolClass("a-something-a"). + WithInfrastructureTemplate( + refToUnstructured(&corev1.ObjectReference{ + APIVersion: "infrastructure.cluster.x-k8s.io/v1beta1", + Kind: "InfrastructureMachinePoolTemplate", + })). + WithBootstrapTemplate( + refToUnstructured(&corev1.ObjectReference{ + APIVersion: "bootstrap.cluster.x-k8s.io/v1beta1", + Kind: "BootstrapTemplate", + })). + Build(), + ). + Build(), + }, // The following tests have selectors which match multiple resources at the same time. { name: "fail if selector targets a matching infrastructureCluster reference and a not matching control plane", From 5c0758afe01142f71c9e4836040f380a06c5cf0c Mon Sep 17 00:00:00 2001 From: willie-yao Date: Wed, 24 Jan 2024 23:46:44 +0000 Subject: [PATCH 4/4] Add mp to clusterclass_controller_test.go --- .../clusterclass_controller_test.go | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/internal/controllers/clusterclass/clusterclass_controller_test.go b/internal/controllers/clusterclass/clusterclass_controller_test.go index 6301b56eeeae..ce7ed5a95ad2 100644 --- a/internal/controllers/clusterclass/clusterclass_controller_test.go +++ b/internal/controllers/clusterclass/clusterclass_controller_test.go @@ -65,6 +65,7 @@ func TestClusterClassReconciler_reconcile(t *testing.T) { // InfraMachineTemplates for the workers and the control plane. infraMachineTemplateControlPlane := builder.InfrastructureMachineTemplate(ns.Name, "inframachinetemplate-control-plane").Build() infraMachineTemplateWorker := builder.InfrastructureMachineTemplate(ns.Name, "inframachinetemplate-worker").Build() + infraMachinePoolTemplateWorker := builder.InfrastructureMachinePoolTemplate(ns.Name, "inframachinepooltemplate-worker").Build() // Control plane template. controlPlaneTemplate := builder.ControlPlaneTemplate(ns.Name, "controlplanetemplate").Build() @@ -82,12 +83,23 @@ func TestClusterClassReconciler_reconcile(t *testing.T) { WithInfrastructureTemplate(infraMachineTemplateWorker). Build() + // MachinePoolClasses that will be part of the ClusterClass. + machinePoolClass1 := builder.MachinePoolClass(workerClassName1). + WithBootstrapTemplate(bootstrapTemplate). + WithInfrastructureTemplate(infraMachinePoolTemplateWorker). + Build() + machinePoolClass2 := builder.MachinePoolClass(workerClassName2). + WithBootstrapTemplate(bootstrapTemplate). + WithInfrastructureTemplate(infraMachinePoolTemplateWorker). + Build() + // ClusterClass. clusterClass := builder.ClusterClass(ns.Name, clusterClassName). WithInfrastructureClusterTemplate(infraClusterTemplate). WithControlPlaneTemplate(controlPlaneTemplate). WithControlPlaneInfrastructureMachineTemplate(infraMachineTemplateControlPlane). WithWorkerMachineDeploymentClasses(*machineDeploymentClass1, *machineDeploymentClass2). + WithWorkerMachinePoolClasses(*machinePoolClass1, *machinePoolClass2). WithVariables( clusterv1.ClusterClassVariable{ Name: "hdd", @@ -112,6 +124,7 @@ func TestClusterClassReconciler_reconcile(t *testing.T) { initObjs := []client.Object{ bootstrapTemplate, infraMachineTemplateWorker, + infraMachinePoolTemplateWorker, infraMachineTemplateControlPlane, controlPlaneTemplate, infraClusterTemplate, @@ -137,6 +150,8 @@ func TestClusterClassReconciler_reconcile(t *testing.T) { g.Expect(assertMachineDeploymentClasses(ctx, actualClusterClass, ns)).Should(Succeed()) + g.Expect(assertMachinePoolClasses(ctx, actualClusterClass, ns)).Should(Succeed()) + g.Expect(assertStatusVariables(actualClusterClass)).Should(Succeed()) return nil }, timeout).Should(Succeed()) @@ -290,6 +305,55 @@ func assertMachineDeploymentClass(ctx context.Context, actualClusterClass *clust builder.BootstrapGroupVersion) } +func assertMachinePoolClasses(ctx context.Context, actualClusterClass *clusterv1.ClusterClass, ns *corev1.Namespace) error { + for _, mpClass := range actualClusterClass.Spec.Workers.MachinePools { + if err := assertMachinePoolClass(ctx, actualClusterClass, mpClass, ns); err != nil { + return err + } + } + return nil +} + +func assertMachinePoolClass(ctx context.Context, actualClusterClass *clusterv1.ClusterClass, mpClass clusterv1.MachinePoolClass, ns *corev1.Namespace) error { + // Assert the infrastructure machinepool template in the MachinePoolClass has an owner reference to the ClusterClass. + actualInfrastructureMachinePoolTemplate := builder.InfrastructureMachinePoolTemplate("", "").Build() + actualInfrastructureMachinePoolTemplateKey := client.ObjectKey{ + Namespace: ns.Name, + Name: mpClass.Template.Infrastructure.Ref.Name, + } + if err := env.Get(ctx, actualInfrastructureMachinePoolTemplateKey, actualInfrastructureMachinePoolTemplate); err != nil { + return err + } + if err := assertHasOwnerReference(actualInfrastructureMachinePoolTemplate, *ownerReferenceTo(actualClusterClass, clusterv1.GroupVersion.WithKind("ClusterClass"))); err != nil { + return err + } + + // Assert the MachinePoolClass has the expected APIVersion and Kind to the infrastructure machinepool template + if err := referenceExistsWithCorrectKindAndAPIVersion(mpClass.Template.Infrastructure.Ref, + builder.GenericInfrastructureMachinePoolTemplateKind, + builder.InfrastructureGroupVersion); err != nil { + return err + } + + // Assert the bootstrap template in the MachinePoolClass has an owner reference to the ClusterClass. + actualBootstrapTemplate := builder.BootstrapTemplate("", "").Build() + actualBootstrapTemplateKey := client.ObjectKey{ + Namespace: ns.Name, + Name: mpClass.Template.Bootstrap.Ref.Name, + } + if err := env.Get(ctx, actualBootstrapTemplateKey, actualBootstrapTemplate); err != nil { + return err + } + if err := assertHasOwnerReference(actualBootstrapTemplate, *ownerReferenceTo(actualClusterClass, clusterv1.GroupVersion.WithKind("ClusterClass"))); err != nil { + return err + } + + // Assert the MachinePoolClass has the expected APIVersion and Kind to the bootstrap template + return referenceExistsWithCorrectKindAndAPIVersion(mpClass.Template.Bootstrap.Ref, + builder.GenericBootstrapConfigTemplateKind, + builder.BootstrapGroupVersion) +} + func assertHasOwnerReference(obj client.Object, ownerRef metav1.OwnerReference) error { found := false for _, ref := range obj.GetOwnerReferences() {