diff --git a/docs/book/src/tasks/experimental-features/cluster-class/write-clusterclass.md b/docs/book/src/tasks/experimental-features/cluster-class/write-clusterclass.md index 6ddb621c7abd..1c722cfcf5f9 100644 --- a/docs/book/src/tasks/experimental-features/cluster-class/write-clusterclass.md +++ b/docs/book/src/tasks/experimental-features/cluster-class/write-clusterclass.md @@ -535,19 +535,20 @@ referenced in patches: - `builtin.cluster.{name,namespace,uid}` - `builtin.cluster.topology.{version,class}` - `builtin.cluster.network.{serviceDomain,services,pods,ipFamily}` -- `builtin.controlPlane.{replicas,version,name}` + - Note: ipFamily is deprecated and will be removed in a future release. see https://github.com/kubernetes-sigs/cluster-api/issues/7521. +- `builtin.controlPlane.{replicas,version,name,metadata.labels,metadata.annotations}` - Please note, these variables are only available when patching control plane or control plane machine templates. - `builtin.controlPlane.machineTemplate.infrastructureRef.name` - Please note, these variables are only available when using a control plane with machines and when patching control plane or control plane machine templates. -- `builtin.machineDeployment.{replicas,version,class,name,topologyName}` +- `builtin.machineDeployment.{replicas,version,class,name,topologyName,metadata.labels,metadata.annotations}` - Please note, these variables are only available when patching the templates of a MachineDeployment and contain the values of the current `MachineDeployment` topology. - `builtin.machineDeployment.{infrastructureRef.name,bootstrap.configRef.name}` - Please note, these variables are only available when patching the templates of a MachineDeployment and contain the values of the current `MachineDeployment` topology. -- `builtin.machinePool.{replicas,version,class,name,topologyName}` +- `builtin.machinePool.{replicas,version,class,name,topologyName,metadata.labels,metadata.annotations}` - Please note, these variables are only available when patching the templates of a MachinePool and contain the values of the current `MachinePool` topology. - `builtin.machinePool.{infrastructureRef.name,bootstrap.configRef.name}` diff --git a/exp/runtime/hooks/api/v1alpha1/topologymutation_variable_types.go b/exp/runtime/hooks/api/v1alpha1/topologymutation_variable_types.go index 701499d8104a..4a6c40254c87 100644 --- a/exp/runtime/hooks/api/v1alpha1/topologymutation_variable_types.go +++ b/exp/runtime/hooks/api/v1alpha1/topologymutation_variable_types.go @@ -16,7 +16,11 @@ limitations under the License. package v1alpha1 -import "k8s.io/apimachinery/pkg/types" +import ( + "k8s.io/apimachinery/pkg/types" + + clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" +) // BuiltinsName is the name of the builtin variable. const BuiltinsName = "builtin" @@ -81,6 +85,9 @@ type ControlPlaneBuiltins struct { // being orchestrated. Version string `json:"version,omitempty"` + // Metadata is the metadata set on the ControlPlane object. + Metadata *clusterv1.ObjectMeta `json:"metadata,omitempty"` + // Name is the name of the ControlPlane, // to which the current template belongs to. Name string `json:"name,omitempty"` @@ -115,6 +122,9 @@ type MachineDeploymentBuiltins struct { // being orchestrated. Version string `json:"version,omitempty"` + // Metadata is the metadata set on the MachineDeployment. + Metadata *clusterv1.ObjectMeta `json:"metadata,omitempty"` + // Class is the class name of the MachineDeployment, // to which the current template belongs to. Class string `json:"class,omitempty"` @@ -148,6 +158,9 @@ type MachinePoolBuiltins struct { // being orchestrated. Version string `json:"version,omitempty"` + // Metadata is the metadata set on the MachinePool. + Metadata *clusterv1.ObjectMeta `json:"metadata,omitempty"` + // Class is the class name of the MachinePool, // to which the current template belongs to. Class string `json:"class,omitempty"` diff --git a/exp/runtime/hooks/api/v1alpha1/zz_generated.deepcopy.go b/exp/runtime/hooks/api/v1alpha1/zz_generated.deepcopy.go index f25c65e4d168..93d6edc69111 100644 --- a/exp/runtime/hooks/api/v1alpha1/zz_generated.deepcopy.go +++ b/exp/runtime/hooks/api/v1alpha1/zz_generated.deepcopy.go @@ -492,6 +492,11 @@ func (in *CommonRetryResponse) DeepCopy() *CommonRetryResponse { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ControlPlaneBuiltins) DeepCopyInto(out *ControlPlaneBuiltins) { *out = *in + if in.Metadata != nil { + in, out := &in.Metadata, &out.Metadata + *out = new(v1beta1.ObjectMeta) + (*in).DeepCopyInto(*out) + } if in.Replicas != nil { in, out := &in.Replicas, &out.Replicas *out = new(int64) @@ -867,6 +872,11 @@ func (in *MachineBootstrapConfigRefBuiltins) DeepCopy() *MachineBootstrapConfigR // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *MachineDeploymentBuiltins) DeepCopyInto(out *MachineDeploymentBuiltins) { *out = *in + if in.Metadata != nil { + in, out := &in.Metadata, &out.Metadata + *out = new(v1beta1.ObjectMeta) + (*in).DeepCopyInto(*out) + } if in.Replicas != nil { in, out := &in.Replicas, &out.Replicas *out = new(int64) @@ -912,6 +922,11 @@ func (in *MachineInfrastructureRefBuiltins) DeepCopy() *MachineInfrastructureRef // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *MachinePoolBuiltins) DeepCopyInto(out *MachinePoolBuiltins) { *out = *in + if in.Metadata != nil { + in, out := &in.Metadata, &out.Metadata + *out = new(v1beta1.ObjectMeta) + (*in).DeepCopyInto(*out) + } if in.Replicas != nil { in, out := &in.Replicas, &out.Replicas *out = new(int64) diff --git a/exp/runtime/hooks/api/v1alpha1/zz_generated.openapi.go b/exp/runtime/hooks/api/v1alpha1/zz_generated.openapi.go index c8d991286cb1..28e0900b7e7d 100644 --- a/exp/runtime/hooks/api/v1alpha1/zz_generated.openapi.go +++ b/exp/runtime/hooks/api/v1alpha1/zz_generated.openapi.go @@ -1005,6 +1005,12 @@ func schema_runtime_hooks_api_v1alpha1_ControlPlaneBuiltins(ref common.Reference Format: "", }, }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Description: "Metadata is the metadata set on the ControlPlane object.", + Ref: ref("sigs.k8s.io/cluster-api/api/v1beta1.ObjectMeta"), + }, + }, "name": { SchemaProps: spec.SchemaProps{ Description: "Name is the name of the ControlPlane, to which the current template belongs to.", @@ -1029,7 +1035,7 @@ func schema_runtime_hooks_api_v1alpha1_ControlPlaneBuiltins(ref common.Reference }, }, Dependencies: []string{ - "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1.ControlPlaneMachineTemplateBuiltins"}, + "sigs.k8s.io/cluster-api/api/v1beta1.ObjectMeta", "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1.ControlPlaneMachineTemplateBuiltins"}, } } @@ -1683,6 +1689,12 @@ func schema_runtime_hooks_api_v1alpha1_MachineDeploymentBuiltins(ref common.Refe Format: "", }, }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Description: "Metadata is the metadata set on the MachineDeployment.", + Ref: ref("sigs.k8s.io/cluster-api/api/v1beta1.ObjectMeta"), + }, + }, "class": { SchemaProps: spec.SchemaProps{ Description: "Class is the class name of the MachineDeployment, to which the current template belongs to.", @@ -1727,7 +1739,7 @@ func schema_runtime_hooks_api_v1alpha1_MachineDeploymentBuiltins(ref common.Refe }, }, Dependencies: []string{ - "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1.MachineBootstrapBuiltins", "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1.MachineInfrastructureRefBuiltins"}, + "sigs.k8s.io/cluster-api/api/v1beta1.ObjectMeta", "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1.MachineBootstrapBuiltins", "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1.MachineInfrastructureRefBuiltins"}, } } @@ -1765,6 +1777,12 @@ func schema_runtime_hooks_api_v1alpha1_MachinePoolBuiltins(ref common.ReferenceC Format: "", }, }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Description: "Metadata is the metadata set on the MachinePool.", + Ref: ref("sigs.k8s.io/cluster-api/api/v1beta1.ObjectMeta"), + }, + }, "class": { SchemaProps: spec.SchemaProps{ Description: "Class is the class name of the MachinePool, to which the current template belongs to.", @@ -1809,7 +1827,7 @@ func schema_runtime_hooks_api_v1alpha1_MachinePoolBuiltins(ref common.ReferenceC }, }, Dependencies: []string{ - "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1.MachineBootstrapBuiltins", "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1.MachineInfrastructureRefBuiltins"}, + "sigs.k8s.io/cluster-api/api/v1beta1.ObjectMeta", "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1.MachineBootstrapBuiltins", "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1.MachineInfrastructureRefBuiltins"}, } } diff --git a/internal/controllers/topology/cluster/patches/engine_test.go b/internal/controllers/topology/cluster/patches/engine_test.go index 563c5731c951..ae51b0ad144a 100644 --- a/internal/controllers/topology/cluster/patches/engine_test.go +++ b/internal/controllers/topology/cluster/patches/engine_test.go @@ -1139,7 +1139,7 @@ func setupTestObjects() (*scope.ClusterBlueprint, *scope.ClusterState) { Workers: &clusterv1.WorkersTopology{ MachineDeployments: []clusterv1.MachineDeploymentTopology{ { - Metadata: clusterv1.ObjectMeta{}, + Metadata: clusterv1.ObjectMeta{Labels: map[string]string{"foo": "bar"}, Annotations: map[string]string{"fizz": "buzz"}}, Class: "default-worker", Name: "default-worker-topo1", Variables: &clusterv1.MachineDeploymentVariables{ @@ -1161,7 +1161,7 @@ func setupTestObjects() (*scope.ClusterBlueprint, *scope.ClusterState) { }, MachinePools: []clusterv1.MachinePoolTopology{ { - Metadata: clusterv1.ObjectMeta{}, + Metadata: clusterv1.ObjectMeta{Labels: map[string]string{"foo": "bar"}, Annotations: map[string]string{"fizz": "buzz"}}, Class: "default-mp-worker", Name: "default-mp-worker-topo1", Variables: &clusterv1.MachinePoolVariables{ diff --git a/internal/controllers/topology/cluster/patches/variables/variables.go b/internal/controllers/topology/cluster/patches/variables/variables.go index f5ca9b110220..e12200718b29 100644 --- a/internal/controllers/topology/cluster/patches/variables/variables.go +++ b/internal/controllers/topology/cluster/patches/variables/variables.go @@ -129,6 +129,12 @@ func ControlPlane(cpTopology *clusterv1.ControlPlaneTopology, cp, cpInfrastructu } builtin.ControlPlane.Replicas = replicas } + if cp.GetLabels() != nil || cp.GetAnnotations() != nil { + builtin.ControlPlane.Metadata = &clusterv1.ObjectMeta{ + Annotations: cp.GetAnnotations(), + Labels: cp.GetLabels(), + } + } version, err := contract.ControlPlane().Version().Get(cp) if err != nil { @@ -182,6 +188,12 @@ func MachineDeployment(mdTopology *clusterv1.MachineDeploymentTopology, md *clus if md.Spec.Replicas != nil { builtin.MachineDeployment.Replicas = ptr.To[int64](int64(*md.Spec.Replicas)) } + if md.Labels != nil || md.Annotations != nil { + builtin.MachineDeployment.Metadata = &clusterv1.ObjectMeta{ + Annotations: md.Annotations, + Labels: md.Labels, + } + } if mdBootstrapTemplate != nil { builtin.MachineDeployment.Bootstrap = &runtimehooksv1.MachineBootstrapBuiltins{ @@ -235,6 +247,12 @@ func MachinePool(mpTopology *clusterv1.MachinePoolTopology, mp *expv1.MachinePoo if mp.Spec.Replicas != nil { builtin.MachinePool.Replicas = ptr.To[int64](int64(*mp.Spec.Replicas)) } + if mp.Labels != nil || mp.Annotations != nil { + builtin.MachinePool.Metadata = &clusterv1.ObjectMeta{ + Annotations: mp.Annotations, + Labels: mp.Labels, + } + } if mpBootstrapObject != nil { builtin.MachinePool.Bootstrap = &runtimehooksv1.MachineBootstrapBuiltins{ diff --git a/internal/controllers/topology/cluster/patches/variables/variables_test.go b/internal/controllers/topology/cluster/patches/variables/variables_test.go index 1e3c0286dd27..434a27e9ac4d 100644 --- a/internal/controllers/topology/cluster/patches/variables/variables_test.go +++ b/internal/controllers/topology/cluster/patches/variables/variables_test.go @@ -445,6 +445,8 @@ func TestControlPlane(t *testing.T) { controlPlane: builder.ControlPlane(metav1.NamespaceDefault, "controlPlane1"). WithReplicas(3). WithVersion("v1.21.1"). + WithLabels(map[string]string{"foo": "bar"}). + WithAnnotations(map[string]string{"fizz": "buzz"}). Build(), want: []runtimehooksv1.Variable{ { @@ -460,6 +462,7 @@ func TestControlPlane(t *testing.T) { Value: toJSONCompact(`{ "controlPlane":{ "version": "v1.21.1", + "metadata": {"labels":{"foo":"bar"}, "annotations":{"fizz":"buzz"}}, "name":"controlPlane1", "replicas":3 }}`), @@ -503,6 +506,7 @@ func TestControlPlane(t *testing.T) { controlPlane: builder.ControlPlane(metav1.NamespaceDefault, "controlPlane1"). WithReplicas(3). WithVersion("v1.21.1"). + WithLabels(map[string]string{"foo": "bar"}). Build(), want: []runtimehooksv1.Variable{ { @@ -518,6 +522,7 @@ func TestControlPlane(t *testing.T) { Value: toJSONCompact(`{ "controlPlane":{ "version": "v1.21.1", + "metadata": {"labels":{"foo":"bar"}}, "name":"controlPlane1", "replicas":3 }}`), @@ -684,6 +689,8 @@ func TestMachineDeployment(t *testing.T) { md: builder.MachineDeployment(metav1.NamespaceDefault, "md1"). WithReplicas(3). WithVersion("v1.21.1"). + WithLabels(map[string]string{"foo": "bar"}). + WithAnnotations(map[string]string{"fizz": "buzz"}). Build(), want: []runtimehooksv1.Variable{ { @@ -699,6 +706,7 @@ func TestMachineDeployment(t *testing.T) { Value: toJSONCompact(`{ "machineDeployment":{ "version": "v1.21.1", + "metadata": {"labels":{"foo":"bar"}, "annotations":{"fizz":"buzz"}}, "class": "md-class", "name": "md1", "topologyName": "md-topology", @@ -1051,6 +1059,8 @@ func TestMachinePool(t *testing.T) { mp: builder.MachinePool(metav1.NamespaceDefault, "mp1"). WithReplicas(3). WithVersion("v1.21.1"). + WithLabels(map[string]string{"foo": "bar"}). + WithAnnotations(map[string]string{"fizz": "buzz"}). Build(), want: []runtimehooksv1.Variable{ { @@ -1066,6 +1076,7 @@ func TestMachinePool(t *testing.T) { Value: toJSONCompact(`{ "machinePool":{ "version": "v1.21.1", + "metadata": {"labels":{"foo":"bar"}, "annotations":{"fizz":"buzz"}}, "class": "mp-class", "name": "mp1", "topologyName": "mp-topology", diff --git a/internal/test/builder/builders.go b/internal/test/builder/builders.go index fbb932312a4b..b9429d0dd3a1 100644 --- a/internal/test/builder/builders.go +++ b/internal/test/builder/builders.go @@ -1451,6 +1451,18 @@ func (c *TestControlPlaneBuilder) WithVersion(version string) *TestControlPlaneB return c } +// WithLabels adds the passed labels to the ControlPlaneBuilder. +func (c *ControlPlaneBuilder) WithLabels(labels map[string]string) *ControlPlaneBuilder { + c.obj.SetLabels(labels) + return c +} + +// WithAnnotations adds the passed annotations to the ControlPlaneBuilder. +func (c *ControlPlaneBuilder) WithAnnotations(annotations map[string]string) *ControlPlaneBuilder { + c.obj.SetAnnotations(annotations) + return c +} + // 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. // @@ -1522,6 +1534,7 @@ type MachinePoolBuilder struct { clusterName string replicas *int32 labels map[string]string + annotations map[string]string status *expv1.MachinePoolStatus minReadySeconds *int32 } @@ -1552,6 +1565,12 @@ func (m *MachinePoolBuilder) WithLabels(labels map[string]string) *MachinePoolBu return m } +// WithAnnotations adds the given annotations to the MachinePoolBuilder. +func (m *MachinePoolBuilder) WithAnnotations(annotations map[string]string) *MachinePoolBuilder { + m.annotations = annotations + return m +} + // WithVersion sets the passed version on the MachinePool spec. func (m *MachinePoolBuilder) WithVersion(version string) *MachinePoolBuilder { m.version = &version @@ -1590,9 +1609,10 @@ func (m *MachinePoolBuilder) Build() *expv1.MachinePool { APIVersion: expv1.GroupVersion.String(), }, ObjectMeta: metav1.ObjectMeta{ - Name: m.name, - Namespace: m.namespace, - Labels: m.labels, + Name: m.name, + Namespace: m.namespace, + Labels: m.labels, + Annotations: m.annotations, }, Spec: expv1.MachinePoolSpec{ ClusterName: m.clusterName, @@ -1630,6 +1650,7 @@ type MachineDeploymentBuilder struct { replicas *int32 generation *int64 labels map[string]string + annotations map[string]string status *clusterv1.MachineDeploymentStatus minReadySeconds *int32 } @@ -1672,6 +1693,12 @@ func (m *MachineDeploymentBuilder) WithLabels(labels map[string]string) *Machine return m } +// WithAnnotations adds the given annotations to the MachineDeploymentBuilder. +func (m *MachineDeploymentBuilder) WithAnnotations(annotations map[string]string) *MachineDeploymentBuilder { + m.annotations = annotations + return m +} + // WithVersion sets the passed version on the machine deployment spec. func (m *MachineDeploymentBuilder) WithVersion(version string) *MachineDeploymentBuilder { m.version = &version @@ -1710,9 +1737,10 @@ func (m *MachineDeploymentBuilder) Build() *clusterv1.MachineDeployment { APIVersion: clusterv1.GroupVersion.String(), }, ObjectMeta: metav1.ObjectMeta{ - Name: m.name, - Namespace: m.namespace, - Labels: m.labels, + Name: m.name, + Namespace: m.namespace, + Labels: m.labels, + Annotations: m.annotations, }, } if m.generation != nil { diff --git a/internal/test/builder/zz_generated.deepcopy.go b/internal/test/builder/zz_generated.deepcopy.go index 77a9c44bf04d..82ec7cc5c320 100644 --- a/internal/test/builder/zz_generated.deepcopy.go +++ b/internal/test/builder/zz_generated.deepcopy.go @@ -445,6 +445,13 @@ func (in *MachineDeploymentBuilder) DeepCopyInto(out *MachineDeploymentBuilder) (*out)[key] = val } } + if in.annotations != nil { + in, out := &in.annotations, &out.annotations + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } if in.status != nil { in, out := &in.status, &out.status *out = new(v1beta1.MachineDeploymentStatus) @@ -637,6 +644,13 @@ func (in *MachinePoolBuilder) DeepCopyInto(out *MachinePoolBuilder) { (*out)[key] = val } } + if in.annotations != nil { + in, out := &in.annotations, &out.annotations + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } if in.status != nil { in, out := &in.status, &out.status *out = new(apiv1beta1.MachinePoolStatus) diff --git a/internal/webhooks/patch_validation.go b/internal/webhooks/patch_validation.go index 2fee9ea73913..fd068bd4d6a4 100644 --- a/internal/webhooks/patch_validation.go +++ b/internal/webhooks/patch_validation.go @@ -490,6 +490,8 @@ var builtinVariables = sets.Set[string]{}.Insert( "builtin.controlPlane.name", "builtin.controlPlane.replicas", "builtin.controlPlane.version", + "builtin.controlPlane.metadata.labels", + "builtin.controlPlane.metadata.annotations", // ControlPlane ref builtins. "builtin.controlPlane.machineTemplate.infrastructureRef.name", @@ -500,6 +502,8 @@ var builtinVariables = sets.Set[string]{}.Insert( "builtin.machineDeployment.replicas", "builtin.machineDeployment.topologyName", "builtin.machineDeployment.version", + "builtin.machineDeployment.metadata.labels", + "builtin.machineDeployment.metadata.annotations", // MachineDeployment ref builtins. "builtin.machineDeployment.bootstrap.configRef.name", "builtin.machineDeployment.infrastructureRef.name", @@ -511,6 +515,8 @@ var builtinVariables = sets.Set[string]{}.Insert( "builtin.machinePool.replicas", "builtin.machinePool.topologyName", "builtin.machinePool.version", + "builtin.machinePool.metadata.labels", + "builtin.machinePool.metadata.annotations", // MachinePool ref builtins. "builtin.machinePool.bootstrap.configRef.name", "builtin.machinePool.infrastructureRef.name",