diff --git a/api/v1alpha4/clusterclass_types.go b/api/v1alpha4/clusterclass_types.go index 0bf6dfdc56e0..40219af0bb75 100644 --- a/api/v1alpha4/clusterclass_types.go +++ b/api/v1alpha4/clusterclass_types.go @@ -44,7 +44,7 @@ type ClusterClassSpec struct { // ControlPlane is a reference to a local struct that holds the details // for provisioning the Control Plane for the Cluster. - ControlPlane LocalObjectTemplate `json:"controlPlane,omitempty"` + ControlPlane ControlPlaneClass `json:"controlPlane,omitempty"` // Workers describes the worker nodes for the cluster. // It is a collection of node types which can be used to create @@ -53,6 +53,22 @@ type ClusterClassSpec struct { Workers WorkersClass `json:"workers,omitempty"` } +type ControlPlaneClass struct { + Metadata ObjectMeta `json:"metadata,omitempty"` + + // LocalObjectTemplate contains the reference to the control plane provider. + LocalObjectTemplate `json:",inline"` + + // MachineTemplate defines the metadata and infrastructure information + // for control plane machines. + // + // This field is supported if and only if the control plane provider template + // referenced above is Machine based and supports setting replicas. + // + // +optional + MachineInfrastructure *LocalObjectTemplate `json:"machineInfrastructure,omitempty"` +} + // WorkersClass is a collection of deployment classes. type WorkersClass struct { // MachineDeployments is a list of machine deployment classes that can be used to create diff --git a/api/v1alpha4/clusterclass_webhook_test.go b/api/v1alpha4/clusterclass_webhook_test.go index ed3535cce536..a969ff2fc406 100644 --- a/api/v1alpha4/clusterclass_webhook_test.go +++ b/api/v1alpha4/clusterclass_webhook_test.go @@ -45,7 +45,9 @@ func TestClusterClassDefaultNamespaces(t *testing.T) { }, Spec: ClusterClassSpec{ Infrastructure: LocalObjectTemplate{Ref: ref}, - ControlPlane: LocalObjectTemplate{Ref: ref}, + ControlPlane: ControlPlaneClass{ + LocalObjectTemplate: LocalObjectTemplate{Ref: ref}, + }, Workers: WorkersClass{ MachineDeployments: []MachineDeploymentClass{ { @@ -96,7 +98,9 @@ func TestClusterClassValidationFeatureGated(t *testing.T) { }, Spec: ClusterClassSpec{ Infrastructure: LocalObjectTemplate{Ref: ref}, - ControlPlane: LocalObjectTemplate{Ref: ref}, + ControlPlane: ControlPlaneClass{ + LocalObjectTemplate: LocalObjectTemplate{Ref: ref}, + }, Workers: WorkersClass{ MachineDeployments: []MachineDeploymentClass{ { @@ -120,7 +124,9 @@ func TestClusterClassValidationFeatureGated(t *testing.T) { }, Spec: ClusterClassSpec{ Infrastructure: LocalObjectTemplate{Ref: ref}, - ControlPlane: LocalObjectTemplate{Ref: ref}, + ControlPlane: ControlPlaneClass{ + LocalObjectTemplate: LocalObjectTemplate{Ref: ref}, + }, Workers: WorkersClass{ MachineDeployments: []MachineDeploymentClass{ { @@ -140,7 +146,9 @@ func TestClusterClassValidationFeatureGated(t *testing.T) { }, Spec: ClusterClassSpec{ Infrastructure: LocalObjectTemplate{Ref: ref}, - ControlPlane: LocalObjectTemplate{Ref: ref}, + ControlPlane: ControlPlaneClass{ + LocalObjectTemplate: LocalObjectTemplate{Ref: ref}, + }, Workers: WorkersClass{ MachineDeployments: []MachineDeploymentClass{ { @@ -202,7 +210,9 @@ func TestClusterClassValidation(t *testing.T) { }, Spec: ClusterClassSpec{ Infrastructure: LocalObjectTemplate{Ref: ref}, - ControlPlane: LocalObjectTemplate{Ref: ref}, + ControlPlane: ControlPlaneClass{ + LocalObjectTemplate: LocalObjectTemplate{Ref: ref}, + }, Workers: WorkersClass{ MachineDeployments: []MachineDeploymentClass{ { @@ -233,7 +243,9 @@ func TestClusterClassValidation(t *testing.T) { }, Spec: ClusterClassSpec{ Infrastructure: LocalObjectTemplate{Ref: refInAnotherNamespace}, - ControlPlane: LocalObjectTemplate{Ref: ref}, + ControlPlane: ControlPlaneClass{ + LocalObjectTemplate: LocalObjectTemplate{Ref: ref}, + }, Workers: WorkersClass{ MachineDeployments: []MachineDeploymentClass{ { @@ -257,7 +269,9 @@ func TestClusterClassValidation(t *testing.T) { }, Spec: ClusterClassSpec{ Infrastructure: LocalObjectTemplate{Ref: ref}, - ControlPlane: LocalObjectTemplate{Ref: refInAnotherNamespace}, + ControlPlane: ControlPlaneClass{ + LocalObjectTemplate: LocalObjectTemplate{Ref: refInAnotherNamespace}, + }, Workers: WorkersClass{ MachineDeployments: []MachineDeploymentClass{ { @@ -281,7 +295,9 @@ func TestClusterClassValidation(t *testing.T) { }, Spec: ClusterClassSpec{ Infrastructure: LocalObjectTemplate{Ref: ref}, - ControlPlane: LocalObjectTemplate{Ref: ref}, + ControlPlane: ControlPlaneClass{ + LocalObjectTemplate: LocalObjectTemplate{Ref: ref}, + }, Workers: WorkersClass{ MachineDeployments: []MachineDeploymentClass{ { @@ -305,7 +321,9 @@ func TestClusterClassValidation(t *testing.T) { }, Spec: ClusterClassSpec{ Infrastructure: LocalObjectTemplate{Ref: ref}, - ControlPlane: LocalObjectTemplate{Ref: ref}, + ControlPlane: ControlPlaneClass{ + LocalObjectTemplate: LocalObjectTemplate{Ref: ref}, + }, Workers: WorkersClass{ MachineDeployments: []MachineDeploymentClass{ { @@ -329,7 +347,9 @@ func TestClusterClassValidation(t *testing.T) { }, Spec: ClusterClassSpec{ Infrastructure: LocalObjectTemplate{Ref: ref}, - ControlPlane: LocalObjectTemplate{Ref: ref}, + ControlPlane: ControlPlaneClass{ + LocalObjectTemplate: LocalObjectTemplate{Ref: ref}, + }, Workers: WorkersClass{ MachineDeployments: []MachineDeploymentClass{ { @@ -360,7 +380,9 @@ func TestClusterClassValidation(t *testing.T) { }, Spec: ClusterClassSpec{ Infrastructure: LocalObjectTemplate{Ref: ref}, - ControlPlane: LocalObjectTemplate{Ref: ref}, + ControlPlane: ControlPlaneClass{ + LocalObjectTemplate: LocalObjectTemplate{Ref: ref}, + }, Workers: WorkersClass{ MachineDeployments: []MachineDeploymentClass{ { @@ -380,7 +402,9 @@ func TestClusterClassValidation(t *testing.T) { }, Spec: ClusterClassSpec{ Infrastructure: LocalObjectTemplate{Ref: ref}, - ControlPlane: LocalObjectTemplate{Ref: ref}, + ControlPlane: ControlPlaneClass{ + LocalObjectTemplate: LocalObjectTemplate{Ref: ref}, + }, Workers: WorkersClass{ MachineDeployments: []MachineDeploymentClass{ { @@ -405,7 +429,9 @@ func TestClusterClassValidation(t *testing.T) { }, Spec: ClusterClassSpec{ Infrastructure: LocalObjectTemplate{Ref: ref}, - ControlPlane: LocalObjectTemplate{Ref: ref}, + ControlPlane: ControlPlaneClass{ + LocalObjectTemplate: LocalObjectTemplate{Ref: ref}, + }, Workers: WorkersClass{ MachineDeployments: []MachineDeploymentClass{ { @@ -431,7 +457,9 @@ func TestClusterClassValidation(t *testing.T) { Name: "bazx", Namespace: "default", }}, - ControlPlane: LocalObjectTemplate{Ref: ref}, + ControlPlane: ControlPlaneClass{ + LocalObjectTemplate: LocalObjectTemplate{Ref: ref}, + }, Workers: WorkersClass{ MachineDeployments: []MachineDeploymentClass{ { @@ -456,7 +484,9 @@ func TestClusterClassValidation(t *testing.T) { }, Spec: ClusterClassSpec{ Infrastructure: LocalObjectTemplate{Ref: ref}, - ControlPlane: LocalObjectTemplate{Ref: ref}, + ControlPlane: ControlPlaneClass{ + LocalObjectTemplate: LocalObjectTemplate{Ref: ref}, + }, Workers: WorkersClass{ MachineDeployments: []MachineDeploymentClass{ { @@ -477,12 +507,14 @@ func TestClusterClassValidation(t *testing.T) { }, Spec: ClusterClassSpec{ Infrastructure: LocalObjectTemplate{Ref: ref}, - ControlPlane: LocalObjectTemplate{Ref: &corev1.ObjectReference{ - APIVersion: "foox", - Kind: "barx", - Name: "bazx", - Namespace: "default", - }}, + ControlPlane: ControlPlaneClass{ + LocalObjectTemplate: LocalObjectTemplate{Ref: &corev1.ObjectReference{ + APIVersion: "foox", + Kind: "barx", + Name: "bazx", + Namespace: "default", + }}, + }, Workers: WorkersClass{ MachineDeployments: []MachineDeploymentClass{ { @@ -507,7 +539,9 @@ func TestClusterClassValidation(t *testing.T) { }, Spec: ClusterClassSpec{ Infrastructure: LocalObjectTemplate{Ref: ref}, - ControlPlane: LocalObjectTemplate{Ref: ref}, + ControlPlane: ControlPlaneClass{ + LocalObjectTemplate: LocalObjectTemplate{Ref: ref}, + }, Workers: WorkersClass{ MachineDeployments: []MachineDeploymentClass{ { @@ -528,7 +562,9 @@ func TestClusterClassValidation(t *testing.T) { }, Spec: ClusterClassSpec{ Infrastructure: LocalObjectTemplate{Ref: ref}, - ControlPlane: LocalObjectTemplate{Ref: ref}, + ControlPlane: ControlPlaneClass{ + LocalObjectTemplate: LocalObjectTemplate{Ref: ref}, + }, Workers: WorkersClass{ MachineDeployments: []MachineDeploymentClass{ { @@ -558,7 +594,9 @@ func TestClusterClassValidation(t *testing.T) { }, Spec: ClusterClassSpec{ Infrastructure: LocalObjectTemplate{Ref: ref}, - ControlPlane: LocalObjectTemplate{Ref: ref}, + ControlPlane: ControlPlaneClass{ + LocalObjectTemplate: LocalObjectTemplate{Ref: ref}, + }, Workers: WorkersClass{ MachineDeployments: []MachineDeploymentClass{ { @@ -578,7 +616,9 @@ func TestClusterClassValidation(t *testing.T) { }, Spec: ClusterClassSpec{ Infrastructure: LocalObjectTemplate{Ref: ref}, - ControlPlane: LocalObjectTemplate{Ref: ref}, + ControlPlane: ControlPlaneClass{ + LocalObjectTemplate: LocalObjectTemplate{Ref: ref}, + }, Workers: WorkersClass{ MachineDeployments: []MachineDeploymentClass{ { @@ -609,7 +649,9 @@ func TestClusterClassValidation(t *testing.T) { }, Spec: ClusterClassSpec{ Infrastructure: LocalObjectTemplate{Ref: ref}, - ControlPlane: LocalObjectTemplate{Ref: ref}, + ControlPlane: ControlPlaneClass{ + LocalObjectTemplate: LocalObjectTemplate{Ref: ref}, + }, Workers: WorkersClass{ MachineDeployments: []MachineDeploymentClass{ { @@ -629,7 +671,9 @@ func TestClusterClassValidation(t *testing.T) { }, Spec: ClusterClassSpec{ Infrastructure: LocalObjectTemplate{Ref: ref}, - ControlPlane: LocalObjectTemplate{Ref: ref}, + ControlPlane: ControlPlaneClass{ + LocalObjectTemplate: LocalObjectTemplate{Ref: ref}, + }, Workers: WorkersClass{ MachineDeployments: []MachineDeploymentClass{ { @@ -660,7 +704,9 @@ func TestClusterClassValidation(t *testing.T) { }, Spec: ClusterClassSpec{ Infrastructure: LocalObjectTemplate{Ref: ref}, - ControlPlane: LocalObjectTemplate{Ref: ref}, + ControlPlane: ControlPlaneClass{ + LocalObjectTemplate: LocalObjectTemplate{Ref: ref}, + }, Workers: WorkersClass{ MachineDeployments: []MachineDeploymentClass{ { @@ -687,7 +733,9 @@ func TestClusterClassValidation(t *testing.T) { }, Spec: ClusterClassSpec{ Infrastructure: LocalObjectTemplate{Ref: ref}, - ControlPlane: LocalObjectTemplate{Ref: ref}, + ControlPlane: ControlPlaneClass{ + LocalObjectTemplate: LocalObjectTemplate{Ref: ref}, + }, Workers: WorkersClass{ MachineDeployments: []MachineDeploymentClass{ { diff --git a/api/v1alpha4/zz_generated.deepcopy.go b/api/v1alpha4/zz_generated.deepcopy.go index 81ede96092ef..87229abce7f9 100644 --- a/api/v1alpha4/zz_generated.deepcopy.go +++ b/api/v1alpha4/zz_generated.deepcopy.go @@ -345,6 +345,28 @@ func (in Conditions) DeepCopy() Conditions { return *out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ControlPlaneClass) DeepCopyInto(out *ControlPlaneClass) { + *out = *in + in.Metadata.DeepCopyInto(&out.Metadata) + in.LocalObjectTemplate.DeepCopyInto(&out.LocalObjectTemplate) + if in.MachineInfrastructure != nil { + in, out := &in.MachineInfrastructure, &out.MachineInfrastructure + *out = new(LocalObjectTemplate) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControlPlaneClass. +func (in *ControlPlaneClass) DeepCopy() *ControlPlaneClass { + if in == nil { + return nil + } + out := new(ControlPlaneClass) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ControlPlaneTopology) DeepCopyInto(out *ControlPlaneTopology) { *out = *in diff --git a/cmd/clusterctl/config/manifest/clusterctl-api.yaml b/cmd/clusterctl/config/manifest/clusterctl-api.yaml index e673cc38fd2d..433b65798ff8 100644 --- a/cmd/clusterctl/config/manifest/clusterctl-api.yaml +++ b/cmd/clusterctl/config/manifest/clusterctl-api.yaml @@ -32,10 +32,14 @@ spec: description: Provider defines an entry in the provider inventory. properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' type: string kind: - description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' type: string metadata: type: object @@ -43,13 +47,18 @@ spec: description: ProviderName indicates the name of the provider. type: string type: - description: Type indicates the type of the provider. See ProviderType for a list of supported values + description: Type indicates the type of the provider. See ProviderType + for a list of supported values type: string version: description: Version indicates the component version. type: string watchedNamespace: - description: 'WatchedNamespace indicates the namespace where the provider controller is is watching. if empty the provider controller is watching for objects in all namespaces. Deprecated: in clusterctl v1alpha4 all the providers watch all the namespaces; this field will be removed in a future version of this API' + description: 'WatchedNamespace indicates the namespace where the provider + controller is is watching. if empty the provider controller is watching + for objects in all namespaces. Deprecated: in clusterctl v1alpha4 all + the providers watch all the namespaces; this field will be removed in + a future version of this API' type: string type: object served: true diff --git a/config/crd/bases/cluster.x-k8s.io_clusterclasses.yaml b/config/crd/bases/cluster.x-k8s.io_clusterclasses.yaml index d40fefbe4a89..28df5710cb0d 100644 --- a/config/crd/bases/cluster.x-k8s.io_clusterclasses.yaml +++ b/config/crd/bases/cluster.x-k8s.io_clusterclasses.yaml @@ -45,6 +45,95 @@ spec: description: ControlPlane is a reference to a local struct that holds the details for provisioning the Control Plane for the Cluster. properties: + machineInfrastructure: + description: "MachineTemplate defines the metadata and infrastructure + information for control plane machines. \n This field is supported + if and only if the control plane provider template referenced + above is Machine based and supports setting replicas." + properties: + ref: + description: Ref is a required reference to a custom resource + offered by a provider. + properties: + apiVersion: + description: API version of the referent. + type: string + fieldPath: + description: 'If referring to a piece of an object instead + of an entire object, this string should contain a valid + JSON/Go field access statement, such as desiredState.manifest.containers[2]. + For example, if the object reference is to a container + within a pod, this would take on a value like: "spec.containers{name}" + (where "name" refers to the name of the container that + triggered the event) or if no container name is specified + "spec.containers[2]" (container with index 2 in this + pod). This syntax is chosen only to have some well-defined + way of referencing a part of an object. TODO: this design + is not final and this field is subject to change in + the future.' + type: string + kind: + description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + namespace: + description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' + type: string + resourceVersion: + description: 'Specific resourceVersion to which this reference + is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency' + type: string + uid: + description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids' + type: string + type: object + required: + - ref + type: object + metadata: + description: "ObjectMeta is metadata that all persisted resources + must have, which includes all objects users must create. This + is a copy of customizable fields from metav1.ObjectMeta. \n + ObjectMeta is embedded in `Machine.Spec`, `MachineDeployment.Template` + and `MachineSet.Template`, which are not top-level Kubernetes + objects. Given that metav1.ObjectMeta has lots of special cases + and read-only fields which end up in the generated CRD validation, + having it as a subset simplifies the API and some issues that + can impact user experience. \n During the [upgrade to controller-tools@v2](https://github.com/kubernetes-sigs/cluster-api/pull/1054) + for v1alpha2, we noticed a failure would occur running Cluster + API test suite against the new CRDs, specifically `spec.metadata.creationTimestamp + in body must be of type string: \"null\"`. The investigation + showed that `controller-tools@v2` behaves differently than its + previous version when handling types from [metav1](k8s.io/apimachinery/pkg/apis/meta/v1) + package. \n In more details, we found that embedded (non-top + level) types that embedded `metav1.ObjectMeta` had validation + properties, including for `creationTimestamp` (metav1.Time). + The `metav1.Time` type specifies a custom json marshaller that, + when IsZero() is true, returns `null` which breaks validation + because the field isn't marked as nullable. \n In future versions, + controller-tools@v2 might allow overriding the type and validation + for embedded types. When that happens, this hack should be revisited." + properties: + annotations: + additionalProperties: + type: string + description: 'Annotations is an unstructured key value map + stored with a resource that may be set by external tools + to store and retrieve arbitrary metadata. They are not queryable + and should be preserved when modifying objects. More info: + http://kubernetes.io/docs/user-guide/annotations' + type: object + labels: + additionalProperties: + type: string + description: 'Map of string keys and values that can be used + to organize and categorize (scope and select) objects. May + match selectors of replication controllers and services. + More info: http://kubernetes.io/docs/user-guide/labels' + type: object + type: object ref: description: Ref is a required reference to a custom resource offered by a provider.