diff --git a/api/v1beta1/common_types.go b/api/v1beta1/common_types.go index 6edc7e5bed48..a0afb91894de 100644 --- a/api/v1beta1/common_types.go +++ b/api/v1beta1/common_types.go @@ -18,7 +18,10 @@ package v1beta1 import ( corev1 "k8s.io/api/core/v1" + apivalidation "k8s.io/apimachinery/pkg/api/validation" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + metav1validation "k8s.io/apimachinery/pkg/apis/meta/v1/validation" + "k8s.io/apimachinery/pkg/util/validation/field" ) const ( @@ -297,3 +300,16 @@ type ObjectMeta struct { // +optional Annotations map[string]string `json:"annotations,omitempty"` } + +// Validate validates the labels and annotations in ObjectMeta. +func (metadata *ObjectMeta) Validate(parent *field.Path) field.ErrorList { + allErrs := metav1validation.ValidateLabels( + metadata.Labels, + parent.Child("labels"), + ) + allErrs = append(allErrs, apivalidation.ValidateAnnotations( + metadata.Annotations, + parent.Child("annotations"), + )...) + return allErrs +} diff --git a/api/v1beta1/common_validate.go b/api/v1beta1/common_validate.go deleted file mode 100644 index de776e4a23fb..000000000000 --- a/api/v1beta1/common_validate.go +++ /dev/null @@ -1,36 +0,0 @@ -/* -Copyright 2023 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package v1beta1 - -import ( - apivalidation "k8s.io/apimachinery/pkg/api/validation" - metav1validation "k8s.io/apimachinery/pkg/apis/meta/v1/validation" - "k8s.io/apimachinery/pkg/util/validation/field" -) - -// Validate validates the labels and annotations in ObjectMeta. -func (metadata *ObjectMeta) Validate(parent *field.Path) field.ErrorList { - allErrs := metav1validation.ValidateLabels( - metadata.Labels, - parent.Child("labels"), - ) - allErrs = append(allErrs, apivalidation.ValidateAnnotations( - metadata.Annotations, - parent.Child("annotations"), - )...) - return allErrs -} diff --git a/internal/webhooks/cluster.go b/internal/webhooks/cluster.go index 9bce93a80e7a..2e0da4f579c7 100644 --- a/internal/webhooks/cluster.go +++ b/internal/webhooks/cluster.go @@ -255,6 +255,9 @@ func (webhook *Cluster) validateTopology(ctx context.Context, oldCluster, newClu ) } + // metadata in topology should be valid + allErrs = append(allErrs, validateTopologyMetadata(newCluster.Spec.Topology, fldPath)...) + // upgrade concurrency should be a numeric value. if concurrency, ok := newCluster.Annotations[clusterv1.ClusterTopologyUpgradeConcurrencyAnnotation]; ok { concurrencyAnnotationField := field.NewPath("metadata", "annotations", clusterv1.ClusterTopologyUpgradeConcurrencyAnnotation) @@ -629,3 +632,16 @@ func clusterClassIsReconciled(clusterClass *clusterv1.ClusterClass) error { } return nil } + +func validateTopologyMetadata(topology *clusterv1.Topology, fldPath *field.Path) field.ErrorList { + var allErrs field.ErrorList + allErrs = append(allErrs, topology.ControlPlane.Metadata.Validate(fldPath.Child("controlPlane", "metadata"))...) + if topology.Workers != nil { + for idx, md := range topology.Workers.MachineDeployments { + allErrs = append(allErrs, md.Metadata.Validate( + fldPath.Child("workers", "machineDeployments").Index(idx).Child("metadata"), + )...) + } + } + return allErrs +} diff --git a/internal/webhooks/clusterclass.go b/internal/webhooks/clusterclass.go index d802691d99b3..8c905c3f9f02 100644 --- a/internal/webhooks/clusterclass.go +++ b/internal/webhooks/clusterclass.go @@ -179,6 +179,10 @@ func (webhook *ClusterClass) validate(ctx context.Context, oldClusterClass, newC // Ensure no MachineHealthCheck currently in use has been removed from the ClusterClass. allErrs = append(allErrs, validateUpdatesToMachineHealthCheckClasses(clusters, oldClusterClass, newClusterClass)...) + + // Ensure Topology metadata in every clusters is valid. + allErrs = append(allErrs, + validateClustersTopologyMetadata(clusters)...) } if len(allErrs) > 0 { @@ -382,3 +386,14 @@ func validateClusterClassMetadata(clusterClass *clusterv1.ClusterClass) field.Er func validateMachineDeploymentMetadata(m clusterv1.MachineDeploymentClass, fldPath *field.Path) field.ErrorList { return m.Template.Metadata.Validate(fldPath.Child("template", "metadata")) } + +func validateClustersTopologyMetadata(clusters []clusterv1.Cluster) field.ErrorList { + var allErrs field.ErrorList + for _, c := range clusters { + if c.Spec.Topology != nil { + allErrs = append(allErrs, + validateTopologyMetadata(c.Spec.Topology, field.NewPath("spec", "topology"))...) + } + } + return allErrs +}