From 78df6a602587625abcc54254793d0358af5708d4 Mon Sep 17 00:00:00 2001 From: fabriziopandini Date: Wed, 22 Jun 2022 15:29:17 +0200 Subject: [PATCH] migrate more test to test CRD --- .../cluster/cluster_controller_test.go | 22 +- internal/test/builder/bootstrap.go | 124 ++++---- internal/test/builder/builders.go | 102 ++++++ internal/test/builder/controlplane.go | 208 +++++++----- internal/test/builder/infrastructure.go | 298 ++++++++++-------- internal/test/envtest/environment.go | 2 + 6 files changed, 475 insertions(+), 281 deletions(-) diff --git a/internal/controllers/topology/cluster/cluster_controller_test.go b/internal/controllers/topology/cluster/cluster_controller_test.go index d0b534e44b17..e0d92dc43097 100644 --- a/internal/controllers/topology/cluster/cluster_controller_test.go +++ b/internal/controllers/topology/cluster/cluster_controller_test.go @@ -547,19 +547,19 @@ func setupTestEnvForIntegrationTests(ns *corev1.Namespace) (func() error, error) // Cluster given a skeletal Cluster object and a ClusterClass. The objects include: // 1) Templates for Machine, Cluster, ControlPlane and Bootstrap. - infrastructureMachineTemplate1 := builder.InfrastructureMachineTemplate(ns.Name, infrastructureMachineTemplateName1).Build() - infrastructureMachineTemplate2 := builder.InfrastructureMachineTemplate(ns.Name, infrastructureMachineTemplateName2). + infrastructureMachineTemplate1 := builder.TestInfrastructureMachineTemplate(ns.Name, infrastructureMachineTemplateName1).Build() + infrastructureMachineTemplate2 := builder.TestInfrastructureMachineTemplate(ns.Name, infrastructureMachineTemplateName2). WithSpecFields(map[string]interface{}{"spec.template.spec.fakeSetting": true}). Build() - infrastructureClusterTemplate1 := builder.InfrastructureClusterTemplate(ns.Name, "infraclustertemplate1"). + infrastructureClusterTemplate1 := builder.TestInfrastructureClusterTemplate(ns.Name, "infraclustertemplate1"). Build() - infrastructureClusterTemplate2 := builder.InfrastructureClusterTemplate(ns.Name, "infraclustertemplate2"). + infrastructureClusterTemplate2 := builder.TestInfrastructureClusterTemplate(ns.Name, "infraclustertemplate2"). WithSpecFields(map[string]interface{}{"spec.template.spec.alteredSetting": true}). Build() - controlPlaneTemplate := builder.ControlPlaneTemplate(ns.Name, "cp1"). + controlPlaneTemplate := builder.TestControlPlaneTemplate(ns.Name, "cp1"). WithInfrastructureMachineTemplate(infrastructureMachineTemplate1). Build() - bootstrapTemplate := builder.BootstrapTemplate(ns.Name, "bootstraptemplate").Build() + bootstrapTemplate := builder.TestBootstrapTemplate(ns.Name, "bootstraptemplate").Build() // 2) ClusterClass definitions including definitions of MachineDeploymentClasses used inside the ClusterClass. machineDeploymentClass1 := builder.MachineDeploymentClass(workerClassName1). @@ -676,14 +676,14 @@ func assertClusterReconcile(cluster *clusterv1.Cluster) error { // Check if InfrastructureRef exists and is of the expected Kind and APIVersion. if err := referenceExistsWithCorrectKindAndAPIVersion(cluster.Spec.InfrastructureRef, - builder.GenericInfrastructureClusterKind, + builder.TestInfrastructureClusterKind, builder.InfrastructureGroupVersion); err != nil { return err } // Check if ControlPlaneRef exists is of the expected Kind and APIVersion. if err := referenceExistsWithCorrectKindAndAPIVersion(cluster.Spec.ControlPlaneRef, - builder.GenericControlPlaneKind, + builder.TestControlPlaneKind, builder.ControlPlaneGroupVersion); err != nil { return err } @@ -742,7 +742,7 @@ func assertControlPlaneReconcile(cluster *clusterv1.Cluster) error { return err } if err := referenceExistsWithCorrectKindAndAPIVersion(cpInfra, - builder.GenericInfrastructureMachineTemplateKind, + builder.TestInfrastructureMachineTemplateKind, builder.InfrastructureGroupVersion); err != nil { return err } @@ -824,7 +824,7 @@ func assertMachineDeploymentsReconcile(cluster *clusterv1.Cluster) error { // Check if the InfrastructureReference exists. if err := referenceExistsWithCorrectKindAndAPIVersion(&md.Spec.Template.Spec.InfrastructureRef, - builder.GenericInfrastructureMachineTemplateKind, + builder.TestInfrastructureMachineTemplateKind, builder.InfrastructureGroupVersion); err != nil { return err } @@ -836,7 +836,7 @@ func assertMachineDeploymentsReconcile(cluster *clusterv1.Cluster) error { // Check if the Bootstrap reference has the expected Kind and APIVersion. if err := referenceExistsWithCorrectKindAndAPIVersion(md.Spec.Template.Spec.Bootstrap.ConfigRef, - builder.GenericBootstrapConfigTemplateKind, + builder.TestBootstrapConfigTemplateKind, builder.BootstrapGroupVersion); err != nil { return err } diff --git a/internal/test/builder/bootstrap.go b/internal/test/builder/bootstrap.go index f68d79a31858..d58e1c6118f4 100644 --- a/internal/test/builder/bootstrap.go +++ b/internal/test/builder/bootstrap.go @@ -17,78 +17,88 @@ limitations under the License. package builder import ( - apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" - "k8s.io/apimachinery/pkg/runtime/schema" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "k8s.io/apimachinery/pkg/runtime/schema" ) var ( - // BootstrapGroupVersion is group version used for bootstrap objects. - BootstrapGroupVersion = schema.GroupVersion{Group: "bootstrap.cluster.x-k8s.io", Version: "v1beta1"} + // BootstrapGroupVersion is group version used for bootstrap objects. + BootstrapGroupVersion = schema.GroupVersion{Group: "bootstrap.cluster.x-k8s.io", Version: "v1beta1"} - // GenericBootstrapConfigKind is the Kind for the GenericBootstrapConfig. - GenericBootstrapConfigKind = "GenericBootstrapConfig" - // GenericBootstrapConfigCRD is a generic boostrap CRD. - GenericBootstrapConfigCRD = untypedCRD(BootstrapGroupVersion.WithKind(GenericBootstrapConfigKind)) + // GenericBootstrapConfigKind is the Kind for the GenericBootstrapConfig. + GenericBootstrapConfigKind = "GenericBootstrapConfig" + // GenericBootstrapConfigCRD is a generic boostrap CRD. + GenericBootstrapConfigCRD = untypedCRD(BootstrapGroupVersion.WithKind(GenericBootstrapConfigKind)) - // GenericBootstrapConfigTemplateKind is the Kind for the GenericBoostrapConfigTemplate. - GenericBootstrapConfigTemplateKind = "GenericBootstrapConfigTemplate" - // GenericBootstrapConfigTemplateCRD is a generic boostrap template CRD. - GenericBootstrapConfigTemplateCRD = untypedCRD(BootstrapGroupVersion.WithKind(GenericBootstrapConfigTemplateKind)) + // GenericBootstrapConfigTemplateKind is the Kind for the GenericBoostrapConfigTemplate. + GenericBootstrapConfigTemplateKind = "GenericBootstrapConfigTemplate" + // GenericBootstrapConfigTemplateCRD is a generic boostrap template CRD. + GenericBootstrapConfigTemplateCRD = untypedCRD(BootstrapGroupVersion.WithKind(GenericBootstrapConfigTemplateKind)) - // TODO: drop generic CRDs in favour of typed test CRDs. + // TODO: drop generic CRDs in favour of typed test CRDs. - // TestBootstrapConfigTemplateKind is the kind for the TestBootstrapConfigTemplate type. - TestBootstrapConfigTemplateKind = "TestBootstrapConfigTemplate" - // TestBootstrapConfigTemplateCRD is a test bootstrap config template CRD. - TestBootstrapConfigTemplateCRD = testBootstrapConfigTemplateCRD(BootstrapGroupVersion.WithKind(TestBootstrapConfigTemplateKind)) + // TestBootstrapConfigTemplateKind is the kind for the TestBootstrapConfigTemplate type. + TestBootstrapConfigTemplateKind = "TestBootstrapConfigTemplate" + // TestBootstrapConfigTemplateCRD is a test bootstrap config template CRD. + TestBootstrapConfigTemplateCRD = testBootstrapConfigTemplateCRD(BootstrapGroupVersion.WithKind(TestBootstrapConfigTemplateKind)) - // TestBootstrapConfigKind is the kind for the TestBootstrapConfig type. - TestBootstrapConfigKind = "TestBootstrapConfig" - // TestBootstrapConfigCRD is a test bootstrap config CRD. - TestBootstrapConfigCRD = testBootstrapConfigCRD(BootstrapGroupVersion.WithKind(TestBootstrapConfigKind)) + // TestBootstrapConfigKind is the kind for the TestBootstrapConfig type. + TestBootstrapConfigKind = "TestBootstrapConfig" + // TestBootstrapConfigCRD is a test bootstrap config CRD. + TestBootstrapConfigCRD = testBootstrapConfigCRD(BootstrapGroupVersion.WithKind(TestBootstrapConfigKind)) ) func testBootstrapConfigTemplateCRD(gvk schema.GroupVersionKind) *apiextensionsv1.CustomResourceDefinition { - return generateCRD(gvk, map[string]apiextensionsv1.JSONSchemaProps{ - "spec": { - Type: "object", - Properties: map[string]apiextensionsv1.JSONSchemaProps{ - // Mandatory field from the Cluster API contract - "template": { - Type: "object", - Properties: map[string]apiextensionsv1.JSONSchemaProps{ - "spec": bootstrapConfigSpecSchema, - }, - }, - }, - }, - }) + return generateCRD(gvk, map[string]apiextensionsv1.JSONSchemaProps{ + "metadata": { + // NOTE: in CRD there is only a partial definition of metadata schema. + // Ref https://github.com/kubernetes-sigs/controller-tools/blob/59485af1c1f6a664655dad49543c474bb4a0d2a2/pkg/crd/gen.go#L185 + Type: "object", + }, + "spec": { + Type: "object", + Properties: map[string]apiextensionsv1.JSONSchemaProps{ + // Mandatory field from the Cluster API contract + "template": { + Type: "object", + Properties: map[string]apiextensionsv1.JSONSchemaProps{ + "spec": bootstrapConfigSpecSchema, + }, + }, + }, + }, + }) } func testBootstrapConfigCRD(gvk schema.GroupVersionKind) *apiextensionsv1.CustomResourceDefinition { - return generateCRD(gvk, map[string]apiextensionsv1.JSONSchemaProps{ - "spec": bootstrapConfigSpecSchema, - "status": { - Type: "object", - Properties: map[string]apiextensionsv1.JSONSchemaProps{ - // mandatory field from the Cluster API contract - "ready": {Type: "boolean"}, - "dataSecretName": {Type: "string"}, - // General purpose fields to be used in different test scenario. - "foo": {Type: "string"}, - "bar": {Type: "string"}, - }, - }, - }) + return generateCRD(gvk, map[string]apiextensionsv1.JSONSchemaProps{ + "metadata": { + // NOTE: in CRD there is only a partial definition of metadata schema. + // Ref https://github.com/kubernetes-sigs/controller-tools/blob/59485af1c1f6a664655dad49543c474bb4a0d2a2/pkg/crd/gen.go#L185 + Type: "object", + }, + "spec": bootstrapConfigSpecSchema, + "status": { + Type: "object", + Properties: map[string]apiextensionsv1.JSONSchemaProps{ + // mandatory field from the Cluster API contract + "ready": {Type: "boolean"}, + "dataSecretName": {Type: "string"}, + // General purpose fields to be used in different test scenario. + "foo": {Type: "string"}, + "bar": {Type: "string"}, + }, + }, + }) } var ( - bootstrapConfigSpecSchema = apiextensionsv1.JSONSchemaProps{ - Type: "object", - Properties: map[string]apiextensionsv1.JSONSchemaProps{ - // General purpose fields to be used in different test scenario. - "foo": {Type: "string"}, - "bar": {Type: "string"}, - }, - } + bootstrapConfigSpecSchema = apiextensionsv1.JSONSchemaProps{ + Type: "object", + Properties: map[string]apiextensionsv1.JSONSchemaProps{ + // General purpose fields to be used in different test scenario. + "foo": {Type: "string"}, + "bar": {Type: "string"}, + }, + } ) diff --git a/internal/test/builder/builders.go b/internal/test/builder/builders.go index dc04df51d005..cbcbcd1f212c 100644 --- a/internal/test/builder/builders.go +++ b/internal/test/builder/builders.go @@ -613,6 +613,51 @@ func (i *InfrastructureClusterTemplateBuilder) Build() *unstructured.Unstructure return obj } +// TestInfrastructureClusterTemplateBuilder holds the variables needed to build a generic TestInfrastructureClusterTemplate. +// +kubebuilder:object:generate=false +type TestInfrastructureClusterTemplateBuilder struct { + namespace string + name string + specFields map[string]interface{} +} + +// TestInfrastructureClusterTemplate returns an TestInfrastructureClusterTemplateBuilder with the given name and namespace. +func TestInfrastructureClusterTemplate(namespace, name string) *TestInfrastructureClusterTemplateBuilder { + return &TestInfrastructureClusterTemplateBuilder{ + namespace: namespace, + name: name, + } +} + +// WithSpecFields sets a map of spec fields on the unstructured object. The keys in the map represent the path and the value corresponds +// to the value of the spec field. +// +// Note: all the paths should start with "spec."; the path should correspond to a field defined in the CRD. +// +// Example map: map[string]interface{}{ +// "spec.version": "v1.2.3", +// }. +func (i *TestInfrastructureClusterTemplateBuilder) WithSpecFields(fields map[string]interface{}) *TestInfrastructureClusterTemplateBuilder { + i.specFields = fields + return i +} + +// Build creates a new Unstructured object with the variables passed to the InfrastructureClusterTemplateBuilder. +func (i *TestInfrastructureClusterTemplateBuilder) Build() *unstructured.Unstructured { + obj := &unstructured.Unstructured{} + obj.SetAPIVersion(InfrastructureGroupVersion.String()) + obj.SetKind(TestInfrastructureClusterTemplateKind) + obj.SetNamespace(i.namespace) + obj.SetName(i.name) + + // Initialize the spec.template.spec to make the object valid in reconciliation. + setSpecFields(obj, map[string]interface{}{"spec.template.spec": map[string]interface{}{}}) + + setSpecFields(obj, i.specFields) + + return obj +} + // ControlPlaneTemplateBuilder holds the variables and objects needed to build a generic ControlPlane template. // +kubebuilder:object:generate=false type ControlPlaneTemplateBuilder struct { @@ -670,6 +715,63 @@ func (c *ControlPlaneTemplateBuilder) Build() *unstructured.Unstructured { return obj } +// TestControlPlaneTemplateBuilder holds the variables and objects needed to build a generic ControlPlane template. +// +kubebuilder:object:generate=false +type TestControlPlaneTemplateBuilder struct { + namespace string + name string + infrastructureMachineTemplate *unstructured.Unstructured + specFields map[string]interface{} +} + +// TestControlPlaneTemplate creates a NewControlPlaneTemplate builder with the given name and namespace. +func TestControlPlaneTemplate(namespace, name string) *TestControlPlaneTemplateBuilder { + return &TestControlPlaneTemplateBuilder{ + namespace: namespace, + name: name, + } +} + +// WithSpecFields sets a map of spec fields on the unstructured object. The keys in the map represent the path and the value corresponds +// to the value of the spec field. +// +// Note: all the paths should start with "spec."; the path should correspond to a field defined in the CRD. +// +// Example map: map[string]interface{}{ +// "spec.version": "v1.2.3", +// }. +func (c *TestControlPlaneTemplateBuilder) WithSpecFields(fields map[string]interface{}) *TestControlPlaneTemplateBuilder { + c.specFields = fields + return c +} + +// WithInfrastructureMachineTemplate adds the given Unstructured object to the ControlPlaneTemplateBuilder as its InfrastructureMachineTemplate. +func (c *TestControlPlaneTemplateBuilder) WithInfrastructureMachineTemplate(t *unstructured.Unstructured) *TestControlPlaneTemplateBuilder { + c.infrastructureMachineTemplate = t + return c +} + +// Build creates an Unstructured object from the variables passed to the ControlPlaneTemplateBuilder. +func (c *TestControlPlaneTemplateBuilder) Build() *unstructured.Unstructured { + obj := &unstructured.Unstructured{} + obj.SetAPIVersion(ControlPlaneGroupVersion.String()) + obj.SetKind(TestControlPlaneTemplateKind) + obj.SetNamespace(c.namespace) + obj.SetName(c.name) + + // Initialize the spec.template.spec to make the object valid in reconciliation. + setSpecFields(obj, map[string]interface{}{"spec.template.spec": map[string]interface{}{}}) + + setSpecFields(obj, c.specFields) + + if c.infrastructureMachineTemplate != nil { + if err := setNestedRef(obj, c.infrastructureMachineTemplate, "spec", "template", "spec", "machineTemplate", "infrastructureRef"); err != nil { + panic(err) + } + } + return obj +} + // InfrastructureClusterBuilder holds the variables and objects needed to build a generic InfrastructureCluster. // +kubebuilder:object:generate=false type InfrastructureClusterBuilder struct { diff --git a/internal/test/builder/controlplane.go b/internal/test/builder/controlplane.go index ed01b2e75faa..a5890a109ee9 100644 --- a/internal/test/builder/controlplane.go +++ b/internal/test/builder/controlplane.go @@ -17,100 +17,136 @@ limitations under the License. package builder import ( - apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" - "k8s.io/apimachinery/pkg/runtime/schema" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "k8s.io/apimachinery/pkg/runtime/schema" ) var ( - // ControlPlaneGroupVersion is group version used for control plane objects. - ControlPlaneGroupVersion = schema.GroupVersion{Group: "controlplane.cluster.x-k8s.io", Version: "v1beta1"} + // ControlPlaneGroupVersion is group version used for control plane objects. + ControlPlaneGroupVersion = schema.GroupVersion{Group: "controlplane.cluster.x-k8s.io", Version: "v1beta1"} - // GenericControlPlaneKind is the Kind for the GenericControlPlane. - GenericControlPlaneKind = "GenericControlPlane" - // GenericControlPlaneCRD is a generic control plane CRD. - GenericControlPlaneCRD = untypedCRD(ControlPlaneGroupVersion.WithKind(GenericControlPlaneKind)) + // GenericControlPlaneKind is the Kind for the GenericControlPlane. + GenericControlPlaneKind = "GenericControlPlane" + // GenericControlPlaneCRD is a generic control plane CRD. + GenericControlPlaneCRD = untypedCRD(ControlPlaneGroupVersion.WithKind(GenericControlPlaneKind)) - // GenericControlPlaneTemplateKind is the Kind for the GenericControlPlaneTemplate. - GenericControlPlaneTemplateKind = "GenericControlPlaneTemplate" - // GenericControlPlaneTemplateCRD is a generic control plane template CRD. - GenericControlPlaneTemplateCRD = untypedCRD(ControlPlaneGroupVersion.WithKind(GenericControlPlaneTemplateKind)) + // GenericControlPlaneTemplateKind is the Kind for the GenericControlPlaneTemplate. + GenericControlPlaneTemplateKind = "GenericControlPlaneTemplate" + // GenericControlPlaneTemplateCRD is a generic control plane template CRD. + GenericControlPlaneTemplateCRD = untypedCRD(ControlPlaneGroupVersion.WithKind(GenericControlPlaneTemplateKind)) - // TODO: drop generic CRDs in favour of typed test CRDs. + // TODO: drop generic CRDs in favour of typed test CRDs. - // TestControlPlaneKind is the Kind for the TestControlPlane. - TestControlPlaneKind = "TestControlPlane" - // TestControlPlaneCRD is a test control plane CRD. - TestControlPlaneCRD = testControlPlaneCRD(ControlPlaneGroupVersion.WithKind(TestControlPlaneKind)) + // TestControlPlaneTemplateKind is the Kind for the TestControlPlaneTemplate. + TestControlPlaneTemplateKind = "TestControlPlaneTemplate" + // TestControlPlaneTemplateCRD is a test control plane template CRD. + TestControlPlaneTemplateCRD = testControlPlaneTemplateCRD(ControlPlaneGroupVersion.WithKind(TestControlPlaneTemplateKind)) + + // TestControlPlaneKind is the Kind for the TestControlPlane. + TestControlPlaneKind = "TestControlPlane" + // TestControlPlaneCRD is a test control plane CRD. + TestControlPlaneCRD = testControlPlaneCRD(ControlPlaneGroupVersion.WithKind(TestControlPlaneKind)) ) +func testControlPlaneTemplateCRD(gvk schema.GroupVersionKind) *apiextensionsv1.CustomResourceDefinition { + return generateCRD(gvk, map[string]apiextensionsv1.JSONSchemaProps{ + "metadata": { + // NOTE: in CRD there is only a partial definition of metadata schema. + // Ref https://github.com/kubernetes-sigs/controller-tools/blob/59485af1c1f6a664655dad49543c474bb4a0d2a2/pkg/crd/gen.go#L185 + Type: "object", + }, + "spec": { + Type: "object", + Properties: map[string]apiextensionsv1.JSONSchemaProps{ + // Mandatory field from the Cluster API contract + "template": { + Type: "object", + Properties: map[string]apiextensionsv1.JSONSchemaProps{ + "spec": controPlaneSpecSchema, + }, + }, + }, + }, + }) +} + func testControlPlaneCRD(gvk schema.GroupVersionKind) *apiextensionsv1.CustomResourceDefinition { - return generateCRD(gvk, map[string]apiextensionsv1.JSONSchemaProps{ - "spec": { - Type: "object", - Properties: map[string]apiextensionsv1.JSONSchemaProps{ - // Mandatory field from the Cluster API contract - version support - "version": { - Type: "string", - }, - // mandatory field from the Cluster API contract - replicas support - "replicas": { - Type: "integer", - Format: "int32", - }, - // mandatory field from the Cluster API contract - using Machines support - "machineTemplate": { - Type: "object", - Properties: map[string]apiextensionsv1.JSONSchemaProps{ - "metadata": metadataSchema, - "infrastructureRef": refSchema, - "nodeDeletionTimeout": {Type: "string"}, - "nodeDrainTimeout": {Type: "string"}, - }, - }, - // General purpose fields to be used in different test scenario. - "foo": {Type: "string"}, - "bar": {Type: "string"}, - // Copy of a subset of KCP spec fields to test server side apply on deep nested structs - "kubeadmConfigSpec": { - Type: "object", - Properties: map[string]apiextensionsv1.JSONSchemaProps{ - "clusterConfiguration": { - Type: "object", - Properties: map[string]apiextensionsv1.JSONSchemaProps{ - "controllerManager": { - Type: "object", - Properties: map[string]apiextensionsv1.JSONSchemaProps{ - "extraArgs": { - Type: "object", - AdditionalProperties: &apiextensionsv1.JSONSchemaPropsOrBool{ - Schema: &apiextensionsv1.JSONSchemaProps{Type: "string"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - "status": { - Type: "object", - Properties: map[string]apiextensionsv1.JSONSchemaProps{ - // mandatory field from the Cluster API contract - "ready": {Type: "boolean"}, - // mandatory field from the Cluster API contract - replicas support - "replicas": {Type: "integer", Format: "int32"}, - "selector": {Type: "string"}, - "readyReplicas": {Type: "integer", Format: "int32"}, - "unavailableReplicas": {Type: "integer", Format: "int32"}, - "updatedReplicas": {Type: "integer", Format: "int32"}, - // Mandatory field from the Cluster API contract - version support - "version": {Type: "string"}, - // General purpose fields to be used in different test scenario. - "foo": {Type: "string"}, - "bar": {Type: "string"}, - }, - }, - }) + return generateCRD(gvk, map[string]apiextensionsv1.JSONSchemaProps{ + "metadata": { + // NOTE: in CRD there is only a partial definition of metadata schema. + // Ref https://github.com/kubernetes-sigs/controller-tools/blob/59485af1c1f6a664655dad49543c474bb4a0d2a2/pkg/crd/gen.go#L185 + Type: "object", + }, + "spec": controPlaneSpecSchema, + "status": { + Type: "object", + Properties: map[string]apiextensionsv1.JSONSchemaProps{ + // mandatory field from the Cluster API contract + "ready": {Type: "boolean"}, + // mandatory field from the Cluster API contract - replicas support + "replicas": {Type: "integer", Format: "int32"}, + "selector": {Type: "string"}, + "readyReplicas": {Type: "integer", Format: "int32"}, + "unavailableReplicas": {Type: "integer", Format: "int32"}, + "updatedReplicas": {Type: "integer", Format: "int32"}, + // Mandatory field from the Cluster API contract - version support + "version": {Type: "string"}, + // General purpose fields to be used in different test scenario. + "foo": {Type: "string"}, + "bar": {Type: "string"}, + }, + }, + }) } + +var ( + controPlaneSpecSchema = apiextensionsv1.JSONSchemaProps{ + Type: "object", + Properties: map[string]apiextensionsv1.JSONSchemaProps{ + // Mandatory field from the Cluster API contract - version support + "version": { + Type: "string", + }, + // mandatory field from the Cluster API contract - replicas support + "replicas": { + Type: "integer", + Format: "int32", + }, + // mandatory field from the Cluster API contract - using Machines support + "machineTemplate": { + Type: "object", + Properties: map[string]apiextensionsv1.JSONSchemaProps{ + "metadata": metadataSchema, + "infrastructureRef": refSchema, + "nodeDeletionTimeout": {Type: "string"}, + "nodeDrainTimeout": {Type: "string"}, + }, + }, + // General purpose fields to be used in different test scenario. + "foo": {Type: "string"}, + "bar": {Type: "string"}, + // Copy of a subset of KCP spec fields to test server side apply on deep nested structs + "kubeadmConfigSpec": { + Type: "object", + Properties: map[string]apiextensionsv1.JSONSchemaProps{ + "clusterConfiguration": { + Type: "object", + Properties: map[string]apiextensionsv1.JSONSchemaProps{ + "controllerManager": { + Type: "object", + Properties: map[string]apiextensionsv1.JSONSchemaProps{ + "extraArgs": { + Type: "object", + AdditionalProperties: &apiextensionsv1.JSONSchemaPropsOrBool{ + Schema: &apiextensionsv1.JSONSchemaProps{Type: "string"}, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } +) diff --git a/internal/test/builder/infrastructure.go b/internal/test/builder/infrastructure.go index 1f2857d39b0b..afe631ea2b93 100644 --- a/internal/test/builder/infrastructure.go +++ b/internal/test/builder/infrastructure.go @@ -17,146 +17,190 @@ limitations under the License. package builder import ( - apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" - "k8s.io/apimachinery/pkg/runtime/schema" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "k8s.io/apimachinery/pkg/runtime/schema" ) var ( - // InfrastructureGroupVersion is group version used for infrastructure objects. - InfrastructureGroupVersion = schema.GroupVersion{Group: "infrastructure.cluster.x-k8s.io", Version: "v1beta1"} - - // GenericInfrastructureMachineKind is the Kind for the GenericInfrastructureMachine. - GenericInfrastructureMachineKind = "GenericInfrastructureMachine" - // GenericInfrastructureMachineCRD is a generic infrastructure machine CRD. - GenericInfrastructureMachineCRD = untypedCRD(InfrastructureGroupVersion.WithKind(GenericInfrastructureMachineKind)) - - // GenericInfrastructureMachineTemplateKind is the Kind for the GenericInfrastructureMachineTemplate. - GenericInfrastructureMachineTemplateKind = "GenericInfrastructureMachineTemplate" - // GenericInfrastructureMachineTemplateCRD is a generic infrastructure machine template CRD. - GenericInfrastructureMachineTemplateCRD = untypedCRD(InfrastructureGroupVersion.WithKind(GenericInfrastructureMachineTemplateKind)) - - // GenericInfrastructureClusterKind is the kind for the GenericInfrastructureCluster type. - GenericInfrastructureClusterKind = "GenericInfrastructureCluster" - // GenericInfrastructureClusterCRD is a generic infrastructure machine CRD. - GenericInfrastructureClusterCRD = untypedCRD(InfrastructureGroupVersion.WithKind(GenericInfrastructureClusterKind)) - - // GenericInfrastructureClusterTemplateKind is the kind for the GenericInfrastructureClusterTemplate type. - GenericInfrastructureClusterTemplateKind = "GenericInfrastructureClusterTemplate" - // GenericInfrastructureClusterTemplateCRD is a generic infrastructure machine template CRD. - GenericInfrastructureClusterTemplateCRD = untypedCRD(InfrastructureGroupVersion.WithKind(GenericInfrastructureClusterTemplateKind)) - - // TODO: drop generic CRDs in favour of typed test CRDs. - - // TestInfrastructureClusterKind is the kind for the TestInfrastructureCluster type. - TestInfrastructureClusterKind = "TestInfrastructureCluster" - // TestInfrastructureClusterCRD is a test infrastructure machine CRD. - TestInfrastructureClusterCRD = testInfrastructureClusterCRD(InfrastructureGroupVersion.WithKind(TestInfrastructureClusterKind)) - - // TestInfrastructureMachineTemplateKind is the kind for the TestInfrastructureMachineTemplate type. - TestInfrastructureMachineTemplateKind = "TestInfrastructureMachineTemplate" - // TestInfrastructureMachineTemplateCRD is a test infrastructure machine template CRD. - TestInfrastructureMachineTemplateCRD = testInfrastructureMachineTemplateCRD(InfrastructureGroupVersion.WithKind(TestInfrastructureMachineTemplateKind)) - - // TestInfrastructureMachineKind is the kind for the TestInfrastructureMachine type. - TestInfrastructureMachineKind = "TestInfrastructureMachine" - // TestInfrastructureMachineCRD is a test infrastructure machine CRD. - TestInfrastructureMachineCRD = testInfrastructureMachineCRD(InfrastructureGroupVersion.WithKind(TestInfrastructureMachineKind)) + // InfrastructureGroupVersion is group version used for infrastructure objects. + InfrastructureGroupVersion = schema.GroupVersion{Group: "infrastructure.cluster.x-k8s.io", Version: "v1beta1"} + + // GenericInfrastructureMachineKind is the Kind for the GenericInfrastructureMachine. + GenericInfrastructureMachineKind = "GenericInfrastructureMachine" + // GenericInfrastructureMachineCRD is a generic infrastructure machine CRD. + GenericInfrastructureMachineCRD = untypedCRD(InfrastructureGroupVersion.WithKind(GenericInfrastructureMachineKind)) + + // GenericInfrastructureMachineTemplateKind is the Kind for the GenericInfrastructureMachineTemplate. + GenericInfrastructureMachineTemplateKind = "GenericInfrastructureMachineTemplate" + // GenericInfrastructureMachineTemplateCRD is a generic infrastructure machine template CRD. + GenericInfrastructureMachineTemplateCRD = untypedCRD(InfrastructureGroupVersion.WithKind(GenericInfrastructureMachineTemplateKind)) + + // GenericInfrastructureClusterKind is the kind for the GenericInfrastructureCluster type. + GenericInfrastructureClusterKind = "GenericInfrastructureCluster" + // GenericInfrastructureClusterCRD is a generic infrastructure machine CRD. + GenericInfrastructureClusterCRD = untypedCRD(InfrastructureGroupVersion.WithKind(GenericInfrastructureClusterKind)) + + // GenericInfrastructureClusterTemplateKind is the kind for the GenericInfrastructureClusterTemplate type. + GenericInfrastructureClusterTemplateKind = "GenericInfrastructureClusterTemplate" + // GenericInfrastructureClusterTemplateCRD is a generic infrastructure machine template CRD. + GenericInfrastructureClusterTemplateCRD = untypedCRD(InfrastructureGroupVersion.WithKind(GenericInfrastructureClusterTemplateKind)) + + // TODO: drop generic CRDs in favour of typed test CRDs. + + // TestInfrastructureClusterTemplateKind is the kind for the TestInfrastructureClusterTemplate type. + TestInfrastructureClusterTemplateKind = "TestInfrastructureClusterTemplate" + // TestInfrastructureClusterTemplateCRD is a test infrastructure machine template CRD. + TestInfrastructureClusterTemplateCRD = testInfrastructureClusterTemplateCRD(InfrastructureGroupVersion.WithKind(TestInfrastructureClusterTemplateKind)) + + // TestInfrastructureClusterKind is the kind for the TestInfrastructureCluster type. + TestInfrastructureClusterKind = "TestInfrastructureCluster" + // TestInfrastructureClusterCRD is a test infrastructure machine CRD. + TestInfrastructureClusterCRD = testInfrastructureClusterCRD(InfrastructureGroupVersion.WithKind(TestInfrastructureClusterKind)) + + // TestInfrastructureMachineTemplateKind is the kind for the TestInfrastructureMachineTemplate type. + TestInfrastructureMachineTemplateKind = "TestInfrastructureMachineTemplate" + // TestInfrastructureMachineTemplateCRD is a test infrastructure machine template CRD. + TestInfrastructureMachineTemplateCRD = testInfrastructureMachineTemplateCRD(InfrastructureGroupVersion.WithKind(TestInfrastructureMachineTemplateKind)) + + // TestInfrastructureMachineKind is the kind for the TestInfrastructureMachine type. + TestInfrastructureMachineKind = "TestInfrastructureMachine" + // TestInfrastructureMachineCRD is a test infrastructure machine CRD. + TestInfrastructureMachineCRD = testInfrastructureMachineCRD(InfrastructureGroupVersion.WithKind(TestInfrastructureMachineKind)) ) +func testInfrastructureClusterTemplateCRD(gvk schema.GroupVersionKind) *apiextensionsv1.CustomResourceDefinition { + return generateCRD(gvk, map[string]apiextensionsv1.JSONSchemaProps{ + "metadata": { + // NOTE: in CRD there is only a partial definition of metadata schema. + // Ref https://github.com/kubernetes-sigs/controller-tools/blob/59485af1c1f6a664655dad49543c474bb4a0d2a2/pkg/crd/gen.go#L185 + Type: "object", + }, + "spec": { + Type: "object", + Properties: map[string]apiextensionsv1.JSONSchemaProps{ + // Mandatory field from the Cluster API contract + "template": { + Type: "object", + Properties: map[string]apiextensionsv1.JSONSchemaProps{ + "spec": clusterSpecSchema, + }, + }, + }, + }, + }) +} + func testInfrastructureClusterCRD(gvk schema.GroupVersionKind) *apiextensionsv1.CustomResourceDefinition { - return generateCRD(gvk, map[string]apiextensionsv1.JSONSchemaProps{ - "spec": { - Type: "object", - Properties: map[string]apiextensionsv1.JSONSchemaProps{ - // Mandatory field from the Cluster API contract - "controlPlaneEndpoint": { - Type: "object", - Properties: map[string]apiextensionsv1.JSONSchemaProps{ - "host": {Type: "string"}, - "port": {Type: "integer"}, - }, - Required: []string{"host", "port"}, - }, - // General purpose fields to be used in different test scenario. - "foo": {Type: "string"}, - "bar": {Type: "string"}, - "fooMap": { - Type: "object", - Properties: map[string]apiextensionsv1.JSONSchemaProps{ - "foo": {Type: "string"}, - }, - }, - "fooList": { - Type: "array", - Items: &apiextensionsv1.JSONSchemaPropsOrArray{ - Schema: &apiextensionsv1.JSONSchemaProps{ - Type: "object", - Properties: map[string]apiextensionsv1.JSONSchemaProps{ - "foo": {Type: "string"}, - }, - }, - }, - }, - // Field for testing - }, - }, - "status": { - Type: "object", - Properties: map[string]apiextensionsv1.JSONSchemaProps{ - // mandatory field from the Cluster API contract - "ready": {Type: "boolean"}, - // General purpose fields to be used in different test scenario. - "foo": {Type: "string"}, - "bar": {Type: "string"}, - }, - Required: []string{"ready"}, - }, - }) + return generateCRD(gvk, map[string]apiextensionsv1.JSONSchemaProps{ + "metadata": { + // NOTE: in CRD there is only a partial definition of metadata schema. + // Ref https://github.com/kubernetes-sigs/controller-tools/blob/59485af1c1f6a664655dad49543c474bb4a0d2a2/pkg/crd/gen.go#L185 + Type: "object", + }, + "spec": clusterSpecSchema, + "status": { + Type: "object", + Properties: map[string]apiextensionsv1.JSONSchemaProps{ + // mandatory field from the Cluster API contract + "ready": {Type: "boolean"}, + // General purpose fields to be used in different test scenario. + "foo": {Type: "string"}, + "bar": {Type: "string"}, + }, + Required: []string{"ready"}, + }, + }) } func testInfrastructureMachineTemplateCRD(gvk schema.GroupVersionKind) *apiextensionsv1.CustomResourceDefinition { - return generateCRD(gvk, map[string]apiextensionsv1.JSONSchemaProps{ - "spec": { - Type: "object", - Properties: map[string]apiextensionsv1.JSONSchemaProps{ - // Mandatory field from the Cluster API contract - "template": { - Type: "object", - Properties: map[string]apiextensionsv1.JSONSchemaProps{ - "metadata": metadataSchema, - "spec": machineSpecSchema, - }, - }, - }, - }, - }) + return generateCRD(gvk, map[string]apiextensionsv1.JSONSchemaProps{ + "metadata": { + // NOTE: in CRD there is only a partial definition of metadata schema. + // Ref https://github.com/kubernetes-sigs/controller-tools/blob/59485af1c1f6a664655dad49543c474bb4a0d2a2/pkg/crd/gen.go#L185 + Type: "object", + }, + "spec": { + Type: "object", + Properties: map[string]apiextensionsv1.JSONSchemaProps{ + // Mandatory field from the Cluster API contract + "template": { + Type: "object", + Properties: map[string]apiextensionsv1.JSONSchemaProps{ + "metadata": metadataSchema, + "spec": machineSpecSchema, + }, + }, + }, + }, + }) } func testInfrastructureMachineCRD(gvk schema.GroupVersionKind) *apiextensionsv1.CustomResourceDefinition { - return generateCRD(gvk, map[string]apiextensionsv1.JSONSchemaProps{ - "spec": machineSpecSchema, - "status": { - Type: "object", - Properties: map[string]apiextensionsv1.JSONSchemaProps{ - // mandatory field from the Cluster API contract - "ready": {Type: "boolean"}, - // General purpose fields to be used in different test scenario. - "foo": {Type: "string"}, - "bar": {Type: "string"}, - }, - }, - }) + return generateCRD(gvk, map[string]apiextensionsv1.JSONSchemaProps{ + "metadata": { + // NOTE: in CRD there is only a partial definition of metadata schema. + // Ref https://github.com/kubernetes-sigs/controller-tools/blob/59485af1c1f6a664655dad49543c474bb4a0d2a2/pkg/crd/gen.go#L185 + Type: "object", + }, + "spec": machineSpecSchema, + "status": { + Type: "object", + Properties: map[string]apiextensionsv1.JSONSchemaProps{ + // mandatory field from the Cluster API contract + "ready": {Type: "boolean"}, + // General purpose fields to be used in different test scenario. + "foo": {Type: "string"}, + "bar": {Type: "string"}, + }, + }, + }) } var ( - machineSpecSchema = apiextensionsv1.JSONSchemaProps{ - Type: "object", - Properties: map[string]apiextensionsv1.JSONSchemaProps{ - // Mandatory field from the Cluster API contract - "providerID": {Type: "string"}, - // General purpose fields to be used in different test scenario. - "foo": {Type: "string"}, - "bar": {Type: "string"}, - }, - } + clusterSpecSchema = apiextensionsv1.JSONSchemaProps{ + Type: "object", + Properties: map[string]apiextensionsv1.JSONSchemaProps{ + // Mandatory field from the Cluster API contract + "controlPlaneEndpoint": { + Type: "object", + Properties: map[string]apiextensionsv1.JSONSchemaProps{ + "host": {Type: "string"}, + "port": {Type: "integer"}, + }, + Required: []string{"host", "port"}, + }, + // General purpose fields to be used in different test scenario. + "foo": {Type: "string"}, + "bar": {Type: "string"}, + "fooMap": { + Type: "object", + Properties: map[string]apiextensionsv1.JSONSchemaProps{ + "foo": {Type: "string"}, + }, + }, + "fooList": { + Type: "array", + Items: &apiextensionsv1.JSONSchemaPropsOrArray{ + Schema: &apiextensionsv1.JSONSchemaProps{ + Type: "object", + Properties: map[string]apiextensionsv1.JSONSchemaProps{ + "foo": {Type: "string"}, + }, + }, + }, + }, + // Field for testing + }, + } + + machineSpecSchema = apiextensionsv1.JSONSchemaProps{ + Type: "object", + Properties: map[string]apiextensionsv1.JSONSchemaProps{ + // Mandatory field from the Cluster API contract + "providerID": {Type: "string"}, + // General purpose fields to be used in different test scenario. + "foo": {Type: "string"}, + "bar": {Type: "string"}, + }, + } ) diff --git a/internal/test/envtest/environment.go b/internal/test/envtest/environment.go index c2bd921b8543..42f9ade73566 100644 --- a/internal/test/envtest/environment.go +++ b/internal/test/envtest/environment.go @@ -188,11 +188,13 @@ func newEnvironment(uncachedObjs ...client.Object) *Environment { builder.GenericInfrastructureClusterTemplateCRD.DeepCopy(), builder.GenericRemediationCRD.DeepCopy(), builder.GenericRemediationTemplateCRD.DeepCopy(), + builder.TestInfrastructureClusterTemplateCRD.DeepCopy(), builder.TestInfrastructureClusterCRD.DeepCopy(), builder.TestInfrastructureMachineTemplateCRD.DeepCopy(), builder.TestInfrastructureMachineCRD.DeepCopy(), builder.TestBootstrapConfigTemplateCRD.DeepCopy(), builder.TestBootstrapConfigCRD.DeepCopy(), + builder.TestControlPlaneTemplateCRD.DeepCopy(), builder.TestControlPlaneCRD.DeepCopy(), }, // initialize webhook here to be able to test the envtest install via webhookOptions